[{"content":"1. 项目概览 clash-party（https://github.com/zdltech8989/clash-party）是一套 Electron + Vue3（或 React） 的跨平台桌面客户端，用来可视化管理 Clash（代理）规则、订阅等功能。\n项目的目录结构大致如下（以官方仓库为准）：\nclash-party/ ├─ public/ # 静态资源（图标、网页入口文件等） ├─ src/ # 前端代码（Vue/React + TypeScript） │ ├─ renderer/ # 渲染进程（UI） │ └─ main/ # 主进程（Electron 主入口） ├─ build/ # 打包脚本、electron-builder 配置 ├─ electron-builder.yml # electron‑builder 配置文件 ├─ package.json └─ ... # 其他 核心技术栈\nElectron（负责创建跨平台的原生窗口、系统托盘、文件系统 API） Vite / Webpack（编译前端资源） electron‑builder（把 Electron 项目打包成 Windows .exe、macOS .dmg/.pkg、Linux .AppImage/.deb/.rpm 等可分发文件） 下面会一步步讲解 如何把源码编译并打包成可运行的桌面客户端，并分别说明在 Windows、macOS、Linux 三个平台上需要的工具与注意事项。\n2. 打包前的准备工作 环境 必装软件 说明 通用 - Node.js ≥ 18（LTS）\n- npm（或 yarn、pnpm）\n- Git 项目本身的依赖管理与构建脚本都基于 Node。 Windows 本机打包 - Windows 10/11\n- VS Build Tools（包含 windows-build-tools）\n- （可选） wine 用来在 Linux 上交叉编译 Windows Electron‑builder 会调用 nsis 生成安装程序，需要本机或交叉的 wine。 macOS 本机打包 - macOS 12+（推荐最新）\n- Xcode Command Line Tools (xcode-select --install) 生成 .dmg/.app 需要 codesign 与 productsign，如果要做 notarization（苹果公证），还需要 Apple Developer 账号并配置 APPLE_ID、APPLE_APP_SPECIFIC_PASSWORD 环境变量。 Linux 本机打包 - Ubuntu 22.04 / Debian 12 / Fedora 39 等（64‑bit）\n- fakeroot、dpkg、rpm、snapcraft（取决于要生成的包格式） Linux 打包相对直接，只要系统支持对应的打包工具。 交叉编译（可选） - wine（Linux → Windows）\n- electron-builder 内置的 electron-osx-zip（macOS 包必须在 macOS 环境下生成） Linux/macOS 可以用 wine 生成 Windows 安装包；但 macOS 包只能在 macOS 上生成（除非使用 CI/CD/macOS 虚拟机）。 Tip：如果你只想快速生成可执行文件而不在意安装器（.exe、.dmg），可以直接使用 electron-builder 的 --dir 选项生成 \u0026ldquo;解压即用\u0026rdquo;(portable) 的文件夹。\n3. 项目源码克隆与依赖安装 # 1. 克隆仓库 git clone https://github.com/zdltech8989/clash-party.git cd clash-party # 2. 安装依赖。这里推荐使用 pnpm（速度更快），也可以用 npm/yarn # 如果系统没有 pnpm，先装一下： npm i -g pnpm # 安装项目依赖 pnpm install 注意\n项目中会有 devDependencies 里指定的 Electron 版本（如 electron@29.x）。确保 Node 版本与之兼容，否则会在编译阶段报错。 如果出现 node-gyp 编译错误，先在系统里装好对应的 C/C++ 编译工具链（Windows → windows-build-tools，Linux → build-essential，macOS → Xcode CLI）。 4. 前端资源的构建（Renderer） 项目使用 Vite（或 Webpack）来打包前端 UI。构建过程会把 src/renderer 下的 Vue/React 代码转成纯静态文件（HTML、CSS、JS），这些文件随后会被 Electron 主进程作为渲染页面加载。\n# 生产环境构建（默认输出到 dist/renderer） pnpm run build:renderer # 也可能是： # pnpm run build # 如果 package.json 中只有一个 build 脚本 构建完成后，你可以在 dist/renderer（或 build）目录看到 index.html、*.js、*.css 等文件。\n为什么要先构建？\nElectron 打包时会把渲染进程的入口指向这些已经编译好的文件。如果直接用 npm start（开发模式），会启动 Vite dev server，这在生成安装包时是不适用的。\n5. Electron 主进程的打包 5.1 electron-builder 配置文件 项目根目录下有一个 electron-builder.yml（或 .json）文件，用来告诉 electron-builder 如何生成各种平台的安装包。下面摘录关键字段（实际文件请自行打开查看）：\nappId: com.zdltech.clash-party productName: Clash Party copyright: © 2024 zdltech directories: output: release # 打包产物的输出目录 buildResources: build # 图标、NSIS 脚本等资源所在目录 files: - dist/** # 前端编译产物 - src/main/** # Electron 主进程源码 - node_modules/** # 依赖 - package.json - !**/*.map # 可选：不打包 source map - !test/** # 不打包测试代码 win: target: - nsis - zip icon: build/icon.ico mac: target: - dmg - zip icon: build/icon.icns linux: target: - AppImage - deb - rpm icon: build/icon.png 关键点\nfiles 列表决定哪些文件会被打进去。通常只需要 dist/renderer、src/main、package.json 四大块。 win.target 包括 NSIS（生成交互式安装向导）和 ZIP（压缩包）。 mac.target 包括 DMG（常规安装磁盘镜像）和 ZIP。 linux.target 常用 AppImage（免安装）或 deb/rpm（发行版包）。 5.2 打包命令 package.json 中已经预定义了几个常用脚本（示例）：\n{ \u0026#34;scripts\u0026#34;: { \u0026#34;build\u0026#34;: \u0026#34;pnpm run build:renderer \u0026amp;\u0026amp; electron-builder\u0026#34;, \u0026#34;build:win\u0026#34;: \u0026#34;pnpm run build \u0026amp;\u0026amp; electron-builder --win\u0026#34;, \u0026#34;build:mac\u0026#34;: \u0026#34;pnpm run build \u0026amp;\u0026amp; electron-builder --mac\u0026#34;, \u0026#34;build:linux\u0026#34;: \u0026#34;pnpm run build \u0026amp;\u0026amp; electron-builder --linux\u0026#34;, \u0026#34;publish\u0026#34;: \u0026#34;electron-builder --publish always\u0026#34; } } 5.2.1 Windows（在 Windows 本机或 Linux + wine） # 1. 完整构建（自动执行 renderer 构建 + electron-builder） pnpm run build:win # 或者逐步： pnpm run build:renderer # 只编译前端 pnpm run build:win # 只执行 electron-builder 输出：release/Clash Party Setup 1.0.0.exe（NSIS 安装程序）以及 release/Clash-Party-Setup-1.0.0.zip（压缩包）。 常见报错： Error: cannot find nsis- → 需要先在 Windows 上安装 NSIS，或让 electron-builder 自动下载（默认会下载）。 wine not found → 在 Linux 上交叉编译时，请确保 wine 已安装（sudo apt install wine64）。 5.2.2 macOS（只能在 macOS 主机上） pnpm run build:mac 输出：release/Clash Party-1.0.0.dmg、release/Clash Party-1.0.0.zip。 代码签名（可选） # 配置环境变量 export CSC_LINK=/path/to/your/cert.p12 export CSC_KEY_PASSWORD=your_cert_password # 再次运行打包 pnpm run build:mac 公证（Notarization）（强烈推荐） export APPLE_ID=\u0026#34;your-apple-id@example.com\u0026#34; export APPLE_APP_SPECIFIC_PASSWORD=\u0026#34;xxxx-xxxx-xxxx-xxxx\u0026#34; export APPLE_TEAM_ID=\u0026#34;YOUR_TEAM_ID\u0026#34; pnpm run build:mac # electron-builder 会自动调用 altool/notarytool 5.2.3 Linux（在 Linux 主机上） pnpm run build:linux 输出（取决于 electron-builder.yml 的 linux.target）\nClash Party-1.0.0.AppImage（一键运行） clash-party_1.0.0_amd64.deb（Debian/Ubuntu） clash-party-1.0.0.x86_64.rpm（Fedora/RedHat） 常见依赖（以 Ubuntu 为例）：\nsudo apt install -y \\ libgtk-3-0 libnotify4 libnss3 libxss1 libasound2 \\ libx11-xcb1 libxkbfile1 libsecret-1-0 \\ fakeroot rpm # 若要生成 .deb/.rpm 6. CI/CD 自动化（可选） 如果你希望在 GitHub Actions 或其他 CI 环境里自动生成四个平台的产物，可以参考下面的示例工作流（基于 GitHub Actions）：\nname: Build \u0026amp; Release on: push: tags: - \u0026#34;v*\u0026#34; jobs: build-windows: runs-on: windows-latest steps: - uses: actions/checkout@v4 - name: Set up Node uses: actions/setup-node@v4 with: node-version: \u0026#39;20\u0026#39; cache: \u0026#39;pnpm\u0026#39; - name: Install pnpm run: npm i -g pnpm - name: Install deps run: pnpm install - name: Build \u0026amp; Package run: pnpm run build:win - name: Upload artifact uses: actions/upload-artifact@v4 with: name: windows path: release/* build-mac: runs-on: macos-14 # Apple Silicon, 仍然可以运行 Intel 二进制 steps: - uses: actions/checkout@v4 - name: Set up Node uses: actions/setup-node@v4 with: node-version: \u0026#39;20\u0026#39; cache: \u0026#39;pnpm\u0026#39; - name: Install pnpm run: npm i -g pnpm - name: Install deps run: pnpm install - name: Build \u0026amp; Package env: CSC_LINK: ${{ secrets.MAC_CERT_P12 }} CSC_KEY_PASSWORD: ${{ secrets.MAC_CERT_PASSWORD }} APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} run: pnpm run build:mac - uses: actions/upload-artifact@v4 with: name: macos path: release/* build-linux: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Node uses: actions/setup-node@v4 with: node-version: \u0026#39;20\u0026#39; cache: \u0026#39;pnpm\u0026#39; - name: Install pnpm run: npm i -g pnpm - name: Install deps run: pnpm install - name: Install Linux build tools run: | sudo apt-get update sudo apt-get install -y libgtk-3-0 libnotify4 libnss3 libxss1 libasound2 fakeroot rpm - name: Build \u0026amp; Package run: pnpm run build:linux - uses: actions/upload-artifact@v4 with: name: linux path: release/* 要点\n签名：macOS 必须提供 .p12 证书（放在 GitHub Secrets），否则只能生成未签名的 .dmg，在某些系统会弹出安全警告。 Notarization：同样需要 Apple ID 与专用密码。 Windows：不需要额外证书（除非你想对 exe 进行 Authenticode 签名）。 7. 常见问题排查（FAQ） 现象 可能原因 解决办法 打包后运行报 Cannot find module 'resource://app.asar/…' electron-builder 没有把 dist/renderer 的文件复制进去 检查 electron-builder.yml 中的 files 段，确保 dist/** 包含在内；或手动执行 pnpm run build:renderer 再打包。 macOS 打包时报 Error: code signing failed (0xE8008015) 代码签名证书路径或密码错误，或证书不在系统钥匙串 确认 CSC_LINK 指向的 .p12 正确，密码无误；在本机 Keychain Access 中手动导入一次看看是否有信任提示。 Linux 生成的 AppImage 双击无响应 缺少运行时依赖（如 glibc）或 fuse 未启用 确保系统已装 fuse（sudo apt install fuse），或使用 --one-dir 生成解压即用的文件夹。 Windows 安装包在 7‑zip 解压后缺少 resources 文件夹 NSIS 脚本中 include、exclude 配置错误 检查 build/nsis/ 里自定义的 nsis 脚本，尤其是 !include 与 !define 是否引用了错误路径。 希望生成\u0026quot;免安装\u0026quot;单文件（portable）但只能得到安装器 没有设置 --portable 参数 运行 electron-builder --dir（只输出解压即用的目录）或者 electron-builder -p portable（会生成 *.exe portable） 8. 完整步骤回顾（示例） 以下以 在 Windows 机器上 打包全部平台（Windows + macOS（交叉 via wine） + Linux）为例，展示一条 全自动脚本：\n# 1️⃣ 克隆仓库 git clone https://github.com/zdltech8989/clash-party.git cd clash-party # 2️⃣ 安装 pnpm + 依赖 npm i -g pnpm pnpm install # 3️⃣ 前端编译（一次即可，所有平台共用） pnpm run build:renderer # 4️⃣ 打包 Windows （本机） pnpm run build:win # 5️⃣ 打包 macOS（交叉，需 wine） sudo apt-get install -y wine64 pnpm run build:mac --win # 6️⃣ 打包 Linux（本机） pnpm run build:linux # 7️⃣ 查看产物 ls release/ 注意：第 5 步（macOS 打包）只能在 macOS 环境里完成完整签名与 notarization。如果你只想得到一个未签名的 .dmg，可以在 Linux 上使用 wine 生成，但它会缺少苹果的代码签名，某些用户在高安全设置的 macOS 上可能会收到 \u0026ldquo;来自未识别开发者\u0026quot;的警告。\n9. 小结 核心技术：Electron + 前端框架（Vue/React） + electron‑builder。 打包流程 pnpm install → 安装依赖 pnpm run build:renderer → 编译前端资源 electron-builder（通过 pnpm run build:* 脚本） → 根据 electron-builder.yml 生成平台特定的安装包。 平台需求 Windows：Node、VS Build Tools、NSIS（或 wine），生成 .exe、.zip。 macOS：Xcode CLI、代码签名证书、Apple ID（公证），生成 .dmg、.zip。 Linux：各种发行版打包工具（fakeroot、dpkg、rpm），生成 AppImage / .deb / .rpm。 CI/CD：使用 GitHub Actions（或 GitLab CI）可以自动在对应 runner 上产出四个平台的产物。 掌握上面的步骤后，你就能够 本地或在 CI 环境中 为 clash-party 项目生成 Windows、macOS、Linux 三大平台的完整桌面客户端了。如果还有其他细节（比如自定义图标、修改 NSIS 安装向导、加入 auto‑update 功能等），随时告诉我，我可以继续补充。祝你打包顺利 🚀!\n","permalink":"https://blog.zdltech.com/posts/clash-party-build-guide/","summary":"\u003ch2 id=\"1-项目概览\"\u003e1. 项目概览\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eclash-party\u003c/code\u003e（\u003ca href=\"https://github.com/zdltech8989/clash-party\"\u003ehttps://github.com/zdltech8989/clash-party\u003c/a\u003e）是一套 \u003cstrong\u003eElectron + Vue3（或 React）\u003c/strong\u003e 的跨平台桌面客户端，用来可视化管理 \u003cstrong\u003eClash\u003c/strong\u003e（代理）规则、订阅等功能。\u003cbr\u003e\n项目的目录结构大致如下（以官方仓库为准）：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eclash-party/\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e├─ public/                # 静态资源（图标、网页入口文件等）\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e├─ src/                   # 前端代码（Vue/React + TypeScript）\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e│   ├─ renderer/          # 渲染进程（UI）\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e│   └─ main/              # 主进程（Electron 主入口）\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e├─ build/                 # 打包脚本、electron-builder 配置\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e├─ electron-builder.yml   # electron‑builder 配置文件\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e├─ package.json\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e└─ ...                    # 其他\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e核心技术栈\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eElectron\u003c/strong\u003e（负责创建跨平台的原生窗口、系统托盘、文件系统 API）\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eVite / Webpack\u003c/strong\u003e（编译前端资源）\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eelectron‑builder\u003c/strong\u003e（把 Electron 项目打包成 Windows \u003ccode\u003e.exe\u003c/code\u003e、macOS \u003ccode\u003e.dmg/.pkg\u003c/code\u003e、Linux \u003ccode\u003e.AppImage/.deb/.rpm\u003c/code\u003e 等可分发文件）\u003c/li\u003e\n\u003c/ul\u003e\u003c/blockquote\u003e\n\u003cp\u003e下面会一步步讲解 \u003cstrong\u003e如何把源码编译并打包成可运行的桌面客户端\u003c/strong\u003e，并分别说明在 \u003cstrong\u003eWindows、macOS、Linux\u003c/strong\u003e 三个平台上需要的工具与注意事项。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"2-打包前的准备工作\"\u003e2. 打包前的准备工作\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e环境\u003c/th\u003e\n          \u003cth\u003e必装软件\u003c/th\u003e\n          \u003cth\u003e说明\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e通用\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e- Node.js ≥ 18（LTS）\u003cbr\u003e- npm（或 yarn、pnpm）\u003cbr\u003e- Git\u003c/td\u003e\n          \u003ctd\u003e项目本身的依赖管理与构建脚本都基于 Node。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eWindows 本机打包\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e- Windows 10/11\u003cbr\u003e- VS Build Tools（包含 \u003ccode\u003ewindows-build-tools\u003c/code\u003e）\u003cbr\u003e- （可选） \u003ccode\u003ewine\u003c/code\u003e 用来在 Linux 上交叉编译 Windows\u003c/td\u003e\n          \u003ctd\u003eElectron‑builder 会调用 \u003ccode\u003ensis\u003c/code\u003e 生成安装程序，需要本机或交叉的 \u003ccode\u003ewine\u003c/code\u003e。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003emacOS 本机打包\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e- macOS 12+（推荐最新）\u003cbr\u003e- Xcode Command Line Tools (\u003ccode\u003excode-select --install\u003c/code\u003e)\u003c/td\u003e\n          \u003ctd\u003e生成 \u003ccode\u003e.dmg/.app\u003c/code\u003e 需要 \u003ccode\u003ecodesign\u003c/code\u003e 与 \u003ccode\u003eproductsign\u003c/code\u003e，如果要做 notarization（苹果公证），还需要 Apple Developer 账号并配置 \u003ccode\u003eAPPLE_ID\u003c/code\u003e、\u003ccode\u003eAPPLE_APP_SPECIFIC_PASSWORD\u003c/code\u003e 环境变量。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eLinux 本机打包\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e- Ubuntu 22.04 / Debian 12 / Fedora 39 等（64‑bit）\u003cbr\u003e- \u003ccode\u003efakeroot\u003c/code\u003e、\u003ccode\u003edpkg\u003c/code\u003e、\u003ccode\u003erpm\u003c/code\u003e、\u003ccode\u003esnapcraft\u003c/code\u003e（取决于要生成的包格式）\u003c/td\u003e\n          \u003ctd\u003eLinux 打包相对直接，只要系统支持对应的打包工具。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e交叉编译（可选）\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e- \u003ccode\u003ewine\u003c/code\u003e（Linux → Windows）\u003cbr\u003e- \u003ccode\u003eelectron-builder\u003c/code\u003e 内置的 \u003ccode\u003eelectron-osx-zip\u003c/code\u003e（macOS 包必须在 macOS 环境下生成）\u003c/td\u003e\n          \u003ctd\u003eLinux/macOS 可以用 \u003ccode\u003ewine\u003c/code\u003e 生成 Windows 安装包；但 macOS 包只能在 macOS 上生成（除非使用 CI/CD/macOS 虚拟机）。\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eTip\u003c/strong\u003e：如果你只想快速生成可执行文件而不在意安装器（\u003ccode\u003e.exe\u003c/code\u003e、\u003ccode\u003e.dmg\u003c/code\u003e），可以直接使用 \u003ccode\u003eelectron-builder\u003c/code\u003e 的 \u003ccode\u003e--dir\u003c/code\u003e 选项生成 \u003cstrong\u003e\u0026ldquo;解压即用\u0026rdquo;(portable)\u003c/strong\u003e 的文件夹。\u003c/p\u003e","title":"Clash Party 桌面客户端打包指南：从源码到全平台安装包"},{"content":"开源工具 · 代码分析 · 图数据库\n📌 **开源地址：**github.com/colbymchenry/codegraph（⭐ 971 Stars）\n📜 **语言：**Python\n🏷️ **标签：**code-analysis · dependency-graph · tree-sitter · Neo4j\n⚠️ **状态：**Pre-alpha（开发中，欢迎尝鲜）\n你有没有过这种经历？\n入职第一天，前辈丢给你一个 10 万行 的项目源码，说：\u0026ldquo;先熟悉一下代码。\u0026rdquo; 你打开文件夹，几百个文件、几千个函数，谁调谁、谁依赖谁、改一处会不会崩十处——完全看不懂。\n又或者你在做 Code Review，看到一个函数 processData() 被改了，你想知道：\u0026ldquo;还有哪些地方在调用它？改了会不会影响其他模块？\u0026rdquo;\n传统的解决方案是全局搜索 + 人工梳理，费时费力还容易漏。要是能把整个代码库变成一张「关系网」，点点鼠标就能查到所有调用链，那该多好？\n💡 **这就是 CodeGraph 想做的事：**把你的代码解析成一张可查询的图谱，函数、文件、类型是「节点」，调用、导入、包含关系是「边」。用图数据库的强大查询能力，秒级回答各种代码关系问题。\nCodeGraph 是一个基于图数据库的代码分析工具。它能把你的代码仓库（Python、C、C++、Go、JavaScript）解析成结构化的图谱数据，存入 Neo4j 图数据库，然后通过 REST API 进行高效查询。\n它能回答这些问题：\n哪些函数调用了 foo？ foo 又调用了哪些函数？ 函数的完整「调用树」是什么？（递归展开） 谁使用了 foo 的返回值？ foo 的定义在哪里？在哪些地方被调用？ 哪些文件导入了 foo？ foo 的类型是什么？还有哪些函数是同一类型？ 三、核心能力详解 🌐 多语言支持 基于 tree-sitter 解析引擎（和 Neovim、Helix 等编辑器用的是同一个），统一支持 5 种主流语言： 语言解析器状态Pythontree-sitter-python✅Ctree-sitter-c✅C++tree-sitter-cpp✅Gotree-sitter-go✅JavaScripttree-sitter-javascript✅\n📊 Neo4j 图数据库驱动 为什么不直接用 SQL？因为代码关系天然就是图结构——函数A调用函数B，函数B又调用函数C和D，这种多层嵌套的调用关系，用图数据库查询比传统关系型数据库快几个数量级。\n在 Neo4j 中：\n**节点（Nodes）：**函数、文件、类型 **边（Edges）：**调用关系（CALLS）、导入关系（IMPORTS）、包含关系（CONTAINS） 🔍 REST API 查询 启动服务后，通过 HTTP 请求就能查代码关系：\n查询谁调用了 processData 函数 GET /api/callers?function=processData\n查询 processData 调用了谁 GET /api/callees?function=processData\n获取完整调用树 GET /api/calltree?function=processData\u0026amp;depth=5\n查找函数定义位置 GET /api/definition?function=processData\n### 🐳 Docker 一键部署 项目自带 Dockerfile 和 docker-compose.yml，Neo4j + CodeGraph 一个命令全拉起来，不用折腾环境配置。 ![](https://mmbiz.qpic.cn/mmbiz_jpg/fv2vjp5wtzgfK0ibpjzo7RcxDzrthPLuwjpib75mmibfgtYdyO6JicJ8fKnfJOMAiagGOMS2grD0kxDPH3bzJhlJDWqnV9KHdfcuL6njU3STPeZc/640?wx_fmt=jpeg) ## 四、Docker Compose 从零搭建（保姆级） ### 📦 步骤一：安装 Docker 已安装 Docker 的跳过这步。 # macOS brew install --cask docker # Ubuntu / Debian sudo apt-get update sudo apt-get install docker.io docker-compose-plugin # 验证 docker --version docker compose version 📋 步骤二：克隆项目 git clone https://github.com/colbymchenry/codegraph.git cd codegraph\n项目结构 ├── codegraph/ 核心代码 ├── docker-compose.yml Docker 编排 ├── Dockerfile 构建镜像 ├── requirements.txt Python 依赖 └── setup.py 安装配置 ### 🚀 步骤三：一键启动 # 一键启动 Neo4j + CodeGraph docker compose up -d # 查看服务状态 docker compose ps # 期望：neo4b Running 7474,7687 / codegraph Running 5000 🎯 **就这三步！**Docker Compose 自动拉取 Neo4j 镜像、安装依赖、启动服务。整个过程约 2-3 分钟。\n🔎 步骤四：解析代码 进入容器 docker compose exec codegraph bash\n解析你的代码库 python -m codegraph parse /path/to/your/project\n导入 Neo4j python -m codegraph index\n启动查询服务 python -m codegraph serve\n访问 API http://localhost:5000/api/callers?function=main ### 🎮 步骤五：查询代码关系 # 用 curl 查询 curl \u0026#34;http://localhost:5000/api/callers?function=processData\u0026#34; # 返回：所有调用 processData 的函数 curl \u0026#34;http://localhost:5000/api/calltree?function=main\u0026amp;depth=3\u0026#34; # 返回：从 main 出发的调用树 # 也可以在 Neo4j 浏览器（http://localhost:7474）用 Cypher 查询： # MATCH (f:Function {name: \u0026#34;processData\u0026#34;})-[:CALLS]-\u0026gt;(c) # RETURN f, c 💡 不想用 Docker？手动安装也行：\n前提：Python 3.6+ 和 Neo4j 数据库 pip install -r requirements.txt\npython -m codegraph parse /path/to/project python -m codegraph index python -m codegraph serve\n![](https://mmbiz.qpic.cn/mmbiz_jpg/fv2vjp5wtzg17RzZt6p0qeH9tiaed7GLM3YwDACt0xfozhyicrCOwibCzl2iciczEUYRAiabdMIUmeGh2E60CLL2wJWHV5Sn0tjQwib3ASFG0AJNos/640?wx_fmt=jpeg) ## 五、实际使用场景 ### 🔍 代码审查（Code Review） 审查 PR 时，快速了解修改函数的影响范围。改了一个工具函数？一键查出所有调用方，确认不会引入 Bug。 ### 🏗️ 项目重构 / 迁移 要把一个模块从项目 A 迁移到项目 B？先查清楚它的完整依赖图谱——导入了哪些外部模块、被哪些函数调用——做到心中有数再动手。 ### 🔒 安全审计 发现一个不安全的函数？立即追溯所有调用链，定位可能受影响的入口点。从数据流入到流出，完整的值追踪。 ### 👋 新人上手 新加入团队的成员，不用再逐文件翻代码。通过调用树，**5 分钟就能理解项目的核心架构和数据流**。 ![](https://mmbiz.qpic.cn/sz_mmbiz_jpg/fv2vjp5wtzjibrqD8nMngzY119eiauCjWFJoCpHS56NKqelOVCNblM29OOfQ0htGqebImD6UEEGv33ooMLXlIL7JSBVXribp6Smq7ibGIQZQClk/640?wx_fmt=jpeg) ## 六、技术架构揭秘 CodeGraph 的架构非常清晰，分为**三层**： ### Phase 1：Parse（解析） 使用 **tree-sitter** 将源代码解析为通用 AST，提取： - 函数定义（类方法、Lambda） - 函数调用（构造函数、方法调用） - 变量赋值（类字段） - 导入语句（import、#include、from...import） - 导出语句（module.exports、export） - 类型注解和定义（类、接口、类型别名） 每个节点都带有**位置元数据**（文件路径、行号、列偏移）。 ### Phase 2：Index（索引） 将解析结果导入 **Neo4j 图数据库**： - **节点：**Function、File、Type - **边：**CALLS、IMPORTS、CONTAINS、RETURNS_TO ### Phase 3：Serve（服务） **Flask** 提供 REST API，对外暴露查询接口。你可以在任何语言、任何工具中调用。 🧩 **模块化设计：**解析器、索引器、服务器各自独立。想支持新语言（如 Rust、TypeScript），只需新增一个 tree-sitter 解析器，其他部分完全复用。 ![](https://mmbiz.qpic.cn/sz_mmbiz_jpg/fv2vjp5wtziapQnuEhlPJEE0OQdLR9xicPUqtmdeneNiaQyOHpAPOKWf29EGSFsCJYyv2mIaXI11mIsmUyVqiauqJLdQgkysgJ1aXmpbEa3jHHg/640?wx_fmt=jpeg) ## 七、优缺点 \u0026amp; 总结 ### ✅ 优点 - **多语言支持**——一套工具覆盖 Python/C/C++/Go/JS - **图数据库**——天然适合代码关系查询，性能远超文本搜索 - **REST API**——可编程集成到 CI/CD、IDE 插件等场景 - **Docker 部署**——环境零配置，docker compose up 即用 - **可扩展架构**——模块化设计，新增语言解析器成本低 ### ⚠️ 不足 - **Pre-alpha 阶段**——API 可能随时变动，不建议直接用于生产 - **依赖 Neo4j**——需要额外运行图数据库服务（Docker 已简化） - **无 GUI**——目前只有 API，可视化需配合 Neo4j Browser - **无正式 License**——开源但未声明许可证，商用需注意 ### 📝 一句话总结 CodeGraph 把「读懂代码」从**人肉翻文件**变成**数据库查询**。虽然还在早期阶段，但思路非常值得借鉴。经常阅读大型代码库的同学，强烈推荐试一试。 🔗 **项目地址：**github.com/colbymchenry/codegraph ⭐ 觉得有用，给个 Star 支持开发者！ ![](https://mmbiz.qpic.cn/sz_mmbiz_jpg/fv2vjp5wtzg7ibStBQg3qt2zO9OuASXrhc7zGmajWf6K6hugdUParpT7UTsG10nJTYqGCTibffX9Xr3WkyxrImm2bmXQM97bpbGQ6rZ8eykuE/640?wx_fmt=jpeg) ","permalink":"https://blog.zdltech.com/posts/article-2-20260528/","summary":"\u003cp\u003e开源工具 · 代码分析 · 图数据库\u003c/p\u003e\n\u003cp\u003e📌 **开源地址：**github.com/colbymchenry/codegraph（⭐ 971 Stars）\u003c/p\u003e\n\u003cp\u003e📜 **语言：**Python\u003c/p\u003e\n\u003cp\u003e🏷️ **标签：**code-analysis · dependency-graph · tree-sitter · Neo4j\u003c/p\u003e\n\u003cp\u003e⚠️ **状态：**Pre-alpha（开发中，欢迎尝鲜）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://mmbiz.qpic.cn/mmbiz_jpg/fv2vjp5wtzhQjX33EDf5zMficJjKfLxoP8xPlGVOr1F2fWeia0XGXuibib3EbYZGFhq71fyGjKpnMYFCz2aQ701BO2cibGCyJvq0HGibhurIaicD40/640?wx_fmt=jpeg\"\u003e\u003c/p\u003e\n\u003cp\u003e你有没有过这种经历？\u003c/p\u003e\n\u003cp\u003e入职第一天，前辈丢给你一个 \u003cstrong\u003e10 万行\u003c/strong\u003e 的项目源码，说：\u0026ldquo;先熟悉一下代码。\u0026rdquo; 你打开文件夹，几百个文件、几千个函数，\u003cstrong\u003e谁调谁、谁依赖谁、改一处会不会崩十处\u003c/strong\u003e——完全看不懂。\u003c/p\u003e\n\u003cp\u003e又或者你在做 Code Review，看到一个函数 \u003ccode\u003eprocessData()\u003c/code\u003e 被改了，你想知道：\u003cstrong\u003e\u0026ldquo;还有哪些地方在调用它？改了会不会影响其他模块？\u0026rdquo;\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e传统的解决方案是全局搜索 + 人工梳理，费时费力还容易漏。\u003cstrong\u003e要是能把整个代码库变成一张「关系网」，点点鼠标就能查到所有调用链，那该多好？\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e💡 **这就是 CodeGraph 想做的事：**把你的代码解析成一张可查询的图谱，函数、文件、类型是「节点」，调用、导入、包含关系是「边」。用图数据库的强大查询能力，秒级回答各种代码关系问题。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://mmbiz.qpic.cn/mmbiz_jpg/fv2vjp5wtzhib0iaX1SjTADib6tO4V8rZDFJSGUuXlz9VHCicT9tmZ5uSfbZVzrqTK8cVnptWhq3v076OWUkruZtDsrvfbCiceSf9IesZNCo8oc4/640?wx_fmt=jpeg\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eCodeGraph\u003c/strong\u003e 是一个基于图数据库的代码分析工具。它能把你的代码仓库（Python、C、C++、Go、JavaScript）解析成结构化的图谱数据，存入 \u003cstrong\u003eNeo4j\u003c/strong\u003e 图数据库，然后通过 REST API 进行高效查询。\u003c/p\u003e\n\u003cp\u003e它能回答这些问题：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e哪些函数调用了 \u003ccode\u003efoo\u003c/code\u003e？\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efoo\u003c/code\u003e 又调用了哪些函数？\u003c/li\u003e\n\u003cli\u003e函数的完整「调用树」是什么？（递归展开）\u003c/li\u003e\n\u003cli\u003e谁使用了 \u003ccode\u003efoo\u003c/code\u003e 的返回值？\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efoo\u003c/code\u003e 的定义在哪里？在哪些地方被调用？\u003c/li\u003e\n\u003cli\u003e哪些文件导入了 \u003ccode\u003efoo\u003c/code\u003e？\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efoo\u003c/code\u003e 的类型是什么？还有哪些函数是同一类型？\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://mmbiz.qpic.cn/mmbiz_jpg/fv2vjp5wtziagOc8DZDBWAURTGic6ccBrEu4OG4SoUOqMCkSTJpicSqwmMHfBHC4O1IDcicH0lvsEqd0qGY6jh8bo3LdiaIwoyfHmiapkRQoKLqibo/640?wx_fmt=jpeg\"\u003e\u003c/p\u003e\n\u003ch2 id=\"三核心能力详解\"\u003e三、核心能力详解\u003c/h2\u003e\n\u003ch3 id=\"-多语言支持\"\u003e🌐 多语言支持\u003c/h3\u003e\n\u003cp\u003e基于 \u003cstrong\u003etree-sitter\u003c/strong\u003e 解析引擎（和 Neovim、Helix 等编辑器用的是同一个），统一支持 5 种主流语言：\n语言解析器状态Pythontree-sitter-python✅Ctree-sitter-c✅C++tree-sitter-cpp✅Gotree-sitter-go✅JavaScripttree-sitter-javascript✅\u003c/p\u003e","title":"CodeGraph：把代码变成可查询图谱"},{"content":"开源 AI 新闻雷达 · 自动聚合 · 智能打分 · 双语日报\n📌 **开源地址：**github.com/Thysrael/Horizon\n🌐 **在线演示：**thysrael.github.io/Horizon\n📜 **许可证：**MIT（完全免费）| ⭐ 4,800+ Stars\n信息焦虑时代 你有没有这种感觉——\n每天刷 Hacker News、Reddit、RSS、公众号……刷了半天，真正有价值的内容没几条，反而被标题党和重复信息淹没。\n好新闻分散在各处，坏信息却源源不断。\n💡 你需要的不是更多的信息源，而是一个帮你\u0026quot;先筛一遍\u0026quot;的工具。\nHorizon 是什么 Horizon 是一个开源的 AI 新闻雷达工具，核心理念：\n🌅 你只需享受新闻，剩下交给 Horizon。\n它能从 Hacker News、Reddit、RSS、Telegram、Twitter/X、GitHub 等 7 大平台自动抓取内容，用 AI 给每条新闻打分（0-10），去掉重复的，补上背景知识，最后生成一份排版精美的中英双语日报。\n项目在 GitHub 上已获得 4,800+ Star，被 HelloGitHub 推荐，非常活跃。\n核心功能详解 📡 7 大信息源一网打尽 Horizon 支持从以下平台抓取信息，覆盖了开发者日常关注的大部分渠道：\n📰 Hacker News\n抓取内容：热门技术故事\n✅ 支持 Top N 评论摘要\n💬 Reddit\n抓取内容：子版块帖子 + 用户动态\n✅ 支持 Top N 评论摘要\n📡 RSS / Atom\n抓取内容：任意 RSS 或 Atom 源\n✈️ Telegram\n抓取内容：公开频道消息\n🐦 Twitter / X\n抓取内容：指定用户的推文\n✅ 支持 Top N 回复\n🐬 GitHub\n抓取内容：用户动态 \u0026amp; 项目 Release\n💹 OpenBB\n抓取内容：金融公司新闻观察列表\n▲ Horizon 中文日报总览页面\n🤖 AI 打分过滤 每条内容会被 AI 打 0-10 分，你可以设置阈值（比如只看 6 分以上的），低于阈值的内容直接过滤掉。支持的 AI 模型：\nClaude · GPT · Gemini · DeepSeek · 豆包 · MiniMax · OpenClaw · Ollama（本地模型）\n也可以接入任意 OpenAI 兼容 API，灵活性拉满。\n🔗 自动去重 同一条新闻在 Hacker News 和 Reddit 同时出现？Horizon 会自动合并，不会重复推送。\n🔍 背景知识补全 遇到不熟悉的公司、项目、技术术语？Horizon 会自动搜索网络，补充背景解释。\n▲ 新闻详情页：背景、摘要、社区讨论\n💬 社区评论摘要 自动收集 Hacker News、Reddit 上的热门评论并生成摘要，快速了解社区观点。\n🌐 中英双语日报 基于同一组信息源，自动生成中文和英文两份日报。\n输出与分发方式 Horizon 生成的日报可以通过多种方式推送给你：\n🌐 GitHub Pages\n自动发布为静态网站，每天更新，可以当个人新闻站用\n📧 邮件订阅\n自建邮件列表，支持自动订阅/退订，像 Newsletter 一样推送\n🔔 Webhook 推送\n飞书、钉钉、Slack、Discord 等聊天工具实时通知\n🧩 MCP 集成\n让 AI 助手直接调用新闻管道，按需查询\n▲ 飞书通知（左）和邮件推送（右）效果\n快速上手教程 📥 第一步：安装 两种安装方式，推荐本地安装：\ngit clone https://github.com/Thysrael/Horizon.git cd Horizon uv sync\n也可以用 **Docker** 一键启动，不需要本地安装 Python 环境。 🎯 **新手推荐：**如果电脑上有 Python 环境，直接用本地安装最快。 ### ⚙️ 第二步：配置 新手推荐用**交互式向导**，几步搞定： uv run horizon-wizard 向导会问你感兴趣的方向（比如\u0026quot;LLM 推理\u0026quot;、\u0026ldquo;前端开发\u0026rdquo;、\u0026ldquo;网络安全\u0026rdquo;），自动生成配置文件。\n进阶用户可以手动编辑 data/config.json，自定义信息源、AI 模型、评分阈值、输出方式等。\n🚀 第三步：运行 uv run horizon # 默认抓取过去 24 小时 uv run horizon \u0026ndash;hours 48 # 抓取过去 48 小时\n生成的日报保存在 `data/summaries/` 目录。 ![](https://mmbiz.qpic.cn/mmbiz_jpg/fv2vjp5wtzjO8EkYqE5YwwL7wfEic7ojDQvuqUiaI2slVDibapQ6hJRR2OSybAiajmTYYHZaE5PX4UQE9M8riaIKhhQCIYIDWffUiazDlRO0lfNas/640?wx_fmt=jpeg) ▲ 终端运行日志，全程可视化进度 ### 🔄 进阶：全自动化 配合 **GitHub Actions**，可以设置定时任务，每天自动生成日报并发布到 GitHub Pages，**完全无人值守**。 💡 **工作流：**配置 → 抓取 → 去重 → AI 打分 → 内容丰富 → 生成摘要 → 自动分发 ![](https://mmbiz.qpic.cn/mmbiz_jpg/fv2vjp5wtzhBoP6mZ8wpawfJNTSl31p0TywAkeChlqqXbOnkn66QaahCdaricu8VXgrzSzYXIyBr5VqoxhlS9fwt95vId5HxJB9sn9zESSN0/640?wx_fmt=jpeg) ## 适合谁用？ **🔧 开发者 / 程序员** 追踪技术动态、开源项目更新、社区热点 **📊 技术管理者 / CTO** 快速了解行业趋势，把握技术方向 **📰 信息焦虑者** 不想被信息流绑架，想要精选而非全部 **🌍 双语需求者** 需要同时关注中英文信息源的人 ## 写在最后 Horizon 最大的价值在于：**把\u0026#34;筛选信息\u0026#34;这件耗时的事交给 AI，你只需要读最终的精选日报。** 配置灵活、支持多种 AI 模型、多种分发方式，而且**完全开源免费**（MIT 协议），值得一试。 🔗 相关链接 📦 GitHub：github.com/Thysrael/Horizon 🌐 在线演示：thysrael.github.io/Horizon 📋 配置指南：thysrael.github.io/Horizon/configuration ![](https://mmbiz.qpic.cn/sz_mmbiz_jpg/fv2vjp5wtzjFHu3FLlrPI6BjkCZEAUHhCqlqYsyyBlVNQZbXCriaCdiaXnIN46REHbQPiajTtVOOhhKoz43PtAiaqLTHSOz40czZ8q2ibWN2tPsI/640?wx_fmt=jpeg) ","permalink":"https://blog.zdltech.com/posts/article-1-20260528/","summary":"\u003cp\u003e开源 AI 新闻雷达 · 自动聚合 · 智能打分 · 双语日报\u003c/p\u003e\n\u003cp\u003e📌 **开源地址：**github.com/Thysrael/Horizon\u003c/p\u003e\n\u003cp\u003e🌐 **在线演示：**thysrael.github.io/Horizon\u003c/p\u003e\n\u003cp\u003e📜 **许可证：**MIT（完全免费）| ⭐ 4,800+ Stars\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://mmbiz.qpic.cn/mmbiz_jpg/fv2vjp5wtzgichpmVowL09aSB2uv9ib6Tib2NKibSKqEvr53dexK8fyqUrCLGybViasoV54dZBuGtC6HnfniahzyEUj78HnibnRPym5Eicw4ITgjI1Y/640?wx_fmt=jpeg\"\u003e\u003c/p\u003e\n\u003ch2 id=\"信息焦虑时代\"\u003e信息焦虑时代\u003c/h2\u003e\n\u003cp\u003e你有没有这种感觉——\u003c/p\u003e\n\u003cp\u003e每天刷 \u003cstrong\u003eHacker News\u003c/strong\u003e、\u003cstrong\u003eReddit\u003c/strong\u003e、\u003cstrong\u003eRSS\u003c/strong\u003e、\u003cstrong\u003e公众号\u003c/strong\u003e……刷了半天，真正有价值的内容没几条，反而被标题党和重复信息淹没。\u003c/p\u003e\n\u003cp\u003e好新闻分散在各处，坏信息却源源不断。\u003c/p\u003e\n\u003cp\u003e💡 \u003cstrong\u003e你需要的不是更多的信息源，而是一个帮你\u0026quot;先筛一遍\u0026quot;的工具。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://mmbiz.qpic.cn/mmbiz_jpg/fv2vjp5wtzhKaLSpFK9Q7dFY7eCuibGQbqRbEssrML7icVEENn5W9mE9IV9WbOXHy9t49xOPJzQb7GicvknNO1t2v2snDz0ljLwBI35V62ia9CE/640?wx_fmt=jpeg\"\u003e\u003c/p\u003e\n\u003ch2 id=\"horizon-是什么\"\u003eHorizon 是什么\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eHorizon\u003c/strong\u003e 是一个开源的 \u003cstrong\u003eAI 新闻雷达\u003c/strong\u003e工具，核心理念：\u003c/p\u003e\n\u003cp\u003e🌅 \u003cstrong\u003e你只需享受新闻，剩下交给 Horizon。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e它能从 \u003cstrong\u003eHacker News、Reddit、RSS、Telegram、Twitter/X、GitHub\u003c/strong\u003e 等 7 大平台自动抓取内容，用 AI 给每条新闻打分（0-10），去掉重复的，补上背景知识，最后生成一份排版精美的\u003cstrong\u003e中英双语日报\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e项目在 GitHub 上已获得 \u003cstrong\u003e4,800+ Star\u003c/strong\u003e，被 \u003cstrong\u003eHelloGitHub\u003c/strong\u003e 推荐，非常活跃。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://mmbiz.qpic.cn/mmbiz_jpg/fv2vjp5wtzg7Zh31OThgDAIVaMPoEawA2SD2pDwzeAfjWvTO2sjjBeuMicghvic4L3bH3ia6SDBtcMc8YMorHa9OODZj3ichuAXVxkk3ibT6mCjs/640?wx_fmt=jpeg\"\u003e\u003c/p\u003e\n\u003ch2 id=\"核心功能详解\"\u003e核心功能详解\u003c/h2\u003e\n\u003ch3 id=\"-7-大信息源一网打尽\"\u003e📡 7 大信息源一网打尽\u003c/h3\u003e\n\u003cp\u003eHorizon 支持从以下平台抓取信息，覆盖了开发者日常关注的大部分渠道：\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e📰 Hacker News\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e抓取内容：热门技术故事\u003c/p\u003e\n\u003cp\u003e✅ 支持 Top N 评论摘要\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e💬 Reddit\u003c/strong\u003e\u003c/p\u003e","title":"Horizon：让AI帮你读完HN、Reddit、RSS"},{"content":"本地优先 · 完全开源 · Claude Design 的最佳替代方案\n📌 **开源地址：**github.com/nexu-io/open-design（⭐ 40k+ Stars）\n🌐 **官网：**open-design.ai\n📥 **下载：**Releases 页面\n📜 **许可证：**Apache 2.0\n一、Open Design 是什么？ 2026年4月，Anthropic 发布了 Claude Design（基于 Opus 4.7），展示了 LLM 从「写文字」到「出设计稿」的飞跃。它一度爆火——但始终闭源、付费、纯云端、绑定 Anthropic 模型，无法自部署、无法切换 Agent、无法定制。\n**Open Design（OD）**就是开源界的回答：同样的设计循环，同样的 Artifacts-first 理念，零锁定。\n它的核心思路是：不造 Agent，只做连接。你电脑上已经装好的编程 Agent（Claude Code、Codex、Gemini CLI 等），Open Design 会自动检测并将它们转化为设计引擎，配合 31 种可组合技能和 129 套品牌级设计系统，驱动整个设计流程。\n💡 **一句话概括：**告诉 AI「帮我做一个 SaaS 落地页」，它会先弹出问卷锁定需求，再选出视觉方向，然后自动生成带交互效果的完整页面——整个过程 1-3 分钟。\n二、核心能力详解 🤖 16 种 Agent 自动检测 Open Design 不绑定任何单一模型。它会自动扫描你 PATH 中已安装的 Agent CLI，一键切换：\nAnthropic 系： Claude Code\nOpenAI 系： Codex CLI\nGoogle 系： Gemini CLI\nCursor 系： Cursor Agent\nDevin： Devin for Terminal\n国产系： Qwen Code、Qoder CLI、Kimi CLI、DeepSeek TUI\n其他： OpenCode、GitHub Copilot CLI、Hermes、Pi、Kiro、Kilo、Mistral Vibe CLI\n没有安装任何 CLI？Open Design 还提供了 BYOK（Bring Your Own Key）代理，支持 Anthropic / OpenAI / Azure / Google Gemini / Ollama / SenseAudio 等多种 API 接入，粘贴 baseUrl + apiKey 即可使用。\n🎨 129 套品牌级设计系统 内置 129 套设计系统，涵盖全球顶级产品风格： Linear · Stripe · Vercel · Airbnb · Tesla · Notion\nAnthropic · Apple · Cursor · Supabase · Figma\n小红书（Xiaohongshu）等本土化风格\n2 套手写入门模板 + 70 套产品系统 + 57 套设计技能系统\n一键切换设计风格，生成的设计稿自动匹配对应品牌调性。\n🛠️ 31 种可组合技能（Skills） 技能分两大类，覆盖设计、营销、运营、工程、产品、财务、HR、销售、个人等 9 大场景：\n原型类（27 种）： web-prototype — 单页 HTML 原型\nsaas-landing — SaaS 营销落地页\ndashboard — 后台管理界面\nmobile-app — 移动 APP 屏幕\ngamified-app — 游戏化应用\nsocial-carousel — 社交轮播图\nmagazine-poster — 杂志海报\ndating-web — 约会网站\nsprite-animation — 精灵动画\nmotion-frames — 动效帧\nwireframe-sketch — 线框草图\nfinance-report — 财务报告\nhr-onboarding — HR 入职页面\nkanban-board — 看板\nteam-okrs — 团队 OKR 页面\n……等\n演示文稿类（4 种）： guizang-ppt — 杂志风格 PPT（WebGL 特效）\nsimple-deck — 简约演示文稿\nreplit-deck — Replit 风格演示\nweekly-update — 周报演示\n🎬 媒体生成能力 不仅是静态页面！Open Design 还支持图片、视频、音频的生成：\ngpt-image-2 （Azure / OpenAI）— 海报、头像、信息图、插画地图\nSeedance 2.0 （字节跳动）— 15 秒电影级文生视频和图生视频\nHyperFrames （HeyGen）— HTML→MP4 动效视频（产品展示、动态排版、数据图表）\n内置 93 个现成的 Prompt 模板（43 图片 + 39 视频 + 11 动效帧），带预览缩略图，开箱即用。\n🎨 5 大视觉方向 每次生成前，AI 会让你从 5 个精心策展的视觉方向中选择：\nEditorial Monocle — 编辑杂志风\nModern Minimal — 现代极简风\nWarm Soft — 温暖柔和风\nTech Utility — 科技实用风\nBrutalist Experimental — 粗野实验风\n每个方向自带确定性的 OKLch 色板和字体栈，确保输出一致且专业。\n📐 设备框架 + Claude Design 导入 内置像素级精确的设备框架（iPhone 15 Pro、Pixel、iPad Pro、MacBook、Chrome），让设计稿看起来像真实产品截图。\n还支持直接导入 Claude Design 的导出 ZIP，自动解析为可编辑项目——无缝迁移，之前的工作不白费。\n💾 本地持久化 使用 SQLite 数据库（.od/app.sqlite）存储项目、对话、消息、标签页和模板。关掉明天再打开，所有进度和文件状态原封不动。\n三、保姆级使用教程（10 步完成第一个设计） 步骤一：安装 Open Design 方式 A：桌面版（推荐非技术用户） 访问 open-design.ai 下载安装包\nmacOS：下载 .dmg → 拖入 Applications（首次运行在「隐私与安全性」中允许）\nWindows：下载 .exe → 安装（SmartScreen 选「更多信息→运行」）\n方式 B：源码部署（推荐开发者） 安装 Node.js 24.x 和 pnpm（corepack enable）\ngit clone https://github.com/nexu-io/open-design.git cd open-design \u0026amp;\u0026amp; pnpm install pnpm tools-dev run web 浏览器自动打开 http://localhost:7457\n步骤二：配置 AI 引擎 方式 1：使用已安装的 Agent CLI（推荐 ✅）\n如果已安装 Claude Code / Gemini CLI / Codex 等，Open Design 会自动检测，直接点击「开始使用」。免费且速度快。\n方式 2：使用 API 密钥（备用）\n输入 Anthropic / OpenAI / Gemini 等 API 密钥即可。密钥获取：console.anthropic.com/settings/keys\n步骤三：选择设计技能 点击顶部「技能」下拉菜单，选择设计类型。\n🎯 **新手推荐：**先选择 saas-landing（SaaS 落地页），最常用也最容易出效果。\n步骤四：选择设计系统 点击「设计系统」下拉菜单，推荐新手先用 Neutral Modern。\n步骤五：输入设计提示词 示例提示词：\n帮我做一个 AI 写作工具的 SaaS 落地页，产品叫「智写AI」。 主要功能：AI 文章生成、多语言翻译、内容润色、SEO 优化。 目标用户：自媒体创作者、内容营销人员。 页面风格：简洁现代，主色调蓝色。 需要包含：导航栏、英雄区、功能介绍、用户评价、定价表、注册按钮。\n步骤六：填写发现问卷 AI 自动弹出问卷，填写 5 个关键字段：表面类型、目标受众、品牌语气、品牌背景、设计规模。30 秒问卷，避免 30 分钟返工。\n步骤七：选择视觉方向 AI 展示 5 个视觉方向（Editorial / Minimal / Warm / Tech / Brutalist），每个带色板和字体预览。选择最符合品牌调性的方向。\n步骤八：等待生成（1-3 分钟） 实时任务进度：分析需求 → 制定设计计划 → 生成代码 → 五维度自我审查 → 自动优化。完成后预览区展示最终效果，可直接点击、滚动交互。\n步骤九：修改和迭代 直接聊天告诉 AI 要改什么：「把主色调改成绿色」「在英雄区加一张图」——AI 自动更新，无需从头开始。\n步骤十：导出设计 支持 5 种格式导出：HTML（浏览器直接打开）· PDF（打印归档）· PPTX（PowerPoint 编辑）· ZIP（打包文件）· Markdown（文档记录）\n四、进阶技巧 自定义设计系统： 在 design-systems/ 文件夹创建自己的设计系统，团队输出保持品牌一致性\n添加新技能： 在 skills/ 文件夹创建自定义技能，扩展能力边界\n部署到服务器：pnpm build \u0026amp;\u0026amp; OD_HOST=0.0.0.0 pnpm tools-dev run --prod ，团队共用\n导入 Claude Design： 拖入 ZIP 自动解析，闭源到开源无缝迁移\n五、Open Design vs Claude Design 对比 对比项\nOpen Design\nClaude Design\n开源\n✅ Apache 2.0\n❌ 闭源\n价格\n✅ 免费\n❌ 付费\n数据\n✅ 100% 本地\n☁️ 云端\n模型支持\n16 种 Agent + BYOK\n仅 Anthropic\n设计系统\n129 套\n有限\n技能\n31 种 + 可扩展\n固定\n自部署\n✅ Vercel / 本地\n❌\n导出格式\nHTML/PDF/PPTX/ZIP/MD\n有限\n六、技术架构 本地守护进程（Daemon）： 唯一特权进程，管理 Agent 生命周期和文件系统访问\nWeb 应用层： 可部署到 Vercel，浏览器端设计界面\n桌面版（Electron）： 沙箱化渲染器 + Sidecar IPC\nAgent 运行时： 项目文件夹中启动 CLI，拥有真实的 Read/Write/Bash/WebFetch 能力\nSQLite 持久化： 全部数据本地存储\n⚠️ 系统要求： macOS：Apple Silicon（M1/M2/M3），macOS 11+\nWindows：x64，Windows 10/11\nLinux：AppImage 可用（稳定版尚未完全开放）\n源码部署需要 Node.js 24.x + pnpm\n总结 Open Design 证明了开源同样可以做出顶级的设计工具。16 种 Agent 支持、129 套设计系统、31 种技能、媒体生成能力——功能不仅不逊于 Claude Design，在开放性和可定制性上更是全面碾压。\n更重要的是，你的数据永远留在自己电脑上。在这个 AI 工具都在抢数据的时代，这份坚持本身就值得尊重。\n🔗 相关链接\nGitHub 开源仓库 · 官网下载\n","permalink":"https://blog.zdltech.com/posts/article-6-20260528/","summary":"\u003cp\u003e本地优先 · 完全开源 · Claude Design 的最佳替代方案\u003c/p\u003e\n\u003cp\u003e📌 **开源地址：**github.com/nexu-io/open-design（⭐ 40k+ Stars）\u003c/p\u003e\n\u003cp\u003e🌐 **官网：**open-design.ai\u003c/p\u003e\n\u003cp\u003e📥 **下载：**Releases 页面\u003c/p\u003e\n\u003cp\u003e📜 **许可证：**Apache 2.0\u003c/p\u003e\n\u003ch2 id=\"一open-design-是什么\"\u003e一、Open Design 是什么？\u003c/h2\u003e\n\u003cp\u003e2026年4月，Anthropic 发布了 \u003cstrong\u003eClaude Design\u003c/strong\u003e（基于 Opus 4.7），展示了 LLM 从「写文字」到「出设计稿」的飞跃。它一度爆火——但始终\u003cstrong\u003e闭源、付费、纯云端、绑定 Anthropic 模型\u003c/strong\u003e，无法自部署、无法切换 Agent、无法定制。\u003c/p\u003e\n\u003cp\u003e**Open Design（OD）**就是开源界的回答：同样的设计循环，同样的 Artifacts-first 理念，\u003cstrong\u003e零锁定\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://mmbiz.qpic.cn/sz_mmbiz_jpg/ALOLkAWfuB4JahOlibTF0icaFCoda9zH98BbztM7ajiaO8gw3l6huaeDribfoR1hmMplceuE1DfodTHLlbHSZl9vE40yvS1Q0hKUBpBnBYT4vbo/640?from=appmsg\"\u003e\u003c/p\u003e\n\u003cp\u003e它的核心思路是：\u003cstrong\u003e不造 Agent，只做连接\u003c/strong\u003e。你电脑上已经装好的编程 Agent（Claude Code、Codex、Gemini CLI 等），Open Design 会自动检测并将它们转化为设计引擎，配合 31 种可组合技能和 129 套品牌级设计系统，驱动整个设计流程。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://mmbiz.qpic.cn/sz_mmbiz_jpg/ALOLkAWfuB5icIXbQhyWicZs5bPOic07t57Go0sibZtM4CC7qkWaaTIsgng1wCnpoSWu5uxficJTGGqToewhCUQDqt7SYeFNof29b1Oian1uarhFQ/640?from=appmsg\"\u003e\u003c/p\u003e\n\u003cp\u003e💡 **一句话概括：**告诉 AI「帮我做一个 SaaS 落地页」，它会先弹出问卷锁定需求，再选出视觉方向，然后自动生成带交互效果的完整页面——整个过程 1-3 分钟。\u003c/p\u003e\n\u003ch2 id=\"二核心能力详解\"\u003e二、核心能力详解\u003c/h2\u003e\n\u003ch3 id=\"-16-种-agent-自动检测\"\u003e🤖 16 种 Agent 自动检测\u003c/h3\u003e\n\u003cp\u003eOpen Design 不绑定任何单一模型。它会\u003cstrong\u003e自动扫描你 PATH 中已安装的 Agent CLI\u003c/strong\u003e，一键切换：\u003c/p\u003e","title":"Open Design：开源免费的全能 AI 设计工具，16种Agent+129套设计系统+31种技能"},{"content":"在AI Agent飞速发展的今天，大模型越来越聪明，但它们有一个共同的短板——上不了网。无法实时搜索信息、无法浏览网页、无法自动操作网站，这让AI Agent的能力被大大限制。\nTinyFish 就是为了解决这个问题而生的。它提供了一套企业级的 Web API，让任何 AI Agent 都能获得搜索、浏览、提取网页内容甚至自动操作网站的能力。\n一个API Key，四大核心能力 TinyFish 的核心设计理念是「简单集成」。一个 API Key，统一的 credit 池，四个独立的 API 覆盖从搜索到自动化操作的全链路场景。\n1. Search API — 网页搜索 输入查询关键词，返回结构化的搜索结果（标题、摘要、URL），直接可供 LLM 消费或程序化处理。\n核心特性：\n支持地区和语言偏好设置，获取本地化搜索结果 完全免费，不消耗 credits 速率限制：60次/分钟 使用示例（Python）：\n`from tinyfish import TinyFish\nclient = TinyFish() response = client.search.query( query=\u0026ldquo;2024年最佳AI编程工具\u0026rdquo;, location=\u0026ldquo;CN\u0026rdquo;, language=\u0026ldquo;zh\u0026rdquo; ) for r in response.results: print(r.title, \u0026ldquo;→\u0026rdquo;, r.url)`\n**cURL 调用：** `curl \u0026#34;https://api.search.tinyfish.ai?query=2024年最佳AI编程工具\u0026amp;location=CN\u0026amp;language=zh\u0026#34; \\ -H \u0026#34;X-API-Key: $TINYFISH_API_KEY\u0026#34;` 2. Fetch API — 网页内容提取 用真实浏览器渲染网页（包括 JS 动态渲染的 SPA 页面），提取干净的页面内容。单次请求最多支持 10 个 URL，每个 URL 独立处理。\n核心特性：\n完全免费，不消耗 credits 速率限制：300个URL/分钟 支持三种输出格式：Markdown、HTML、JSON 支持 PDF 文本提取、代理请求 基础使用：\n`from tinyfish import TinyFish\nclient = TinyFish() result = client.fetch.get_contents( urls=[ \u0026ldquo;https://example.com/article1\u0026rdquo;, \u0026ldquo;https://example.com/article2\u0026rdquo;, ] )\nfor page in result.results: print(page.url, \u0026ldquo;→\u0026rdquo;, page.title) print(page.text) # 干净的 Markdown 格式`\n### 3. Agent API — 自然语言驱动的网页自动化 这是 TinyFish 最核心的能力。用自然语言描述任务目标，TinyFish 会在真实的浏览器中自动执行操作——点击、输入、导航、提取数据，全程自动化。 **三种调用模式：** - `/run` — 同步模式，适合简单快速的任务 - `/run-async` — 异步模式，适合长时间任务和批量处理 - `/run-sse` — SSE实时事件流，适合需要实时反馈的应用 **数据提取示例：** `from tinyfish import TinyFish, CompleteEvent client = TinyFish() with client.agent.stream( url=\u0026#34;https://scrapeme.live/shop\u0026#34;, goal=\u0026#34;提取前2个商品名称和价格，返回JSON格式\u0026#34;, ) as stream: for event in stream: if isinstance(event, CompleteEvent): print(event.result_json)` 多步骤工作流：\nwith client.agent.stream( url=\u0026quot;https://example.com/login\u0026quot;, goal=\u0026quot;\u0026quot;\u0026quot; 1. 在登录页面输入用户名和密码 2. 点击登录按钮 3. 等待仪表盘加载完成 4. 提取页面上的账户余额信息 5. 返回JSON格式的余额数据 \u0026quot;\u0026quot;\u0026quot;, ) as stream: for event in stream: print(event)\n### 4. Browser API — 远程浏览器会话 创建一个远程 Chrome 浏览器实例，通过 CDP WebSocket 连接，可以用 Playwright、Puppeteer 等工具直接驱动。 `from tinyfish import TinyFish import asyncio from playwright.async_api import async_playwright client = TinyFish() session = client.browser.sessions.create(url=\u0026#34;https://example.com\u0026#34;) async def main(): async with async_playwright() as p: browser = await p.chromium.connect_over_cdp(session.cdp_url) page = browser.contexts[0].pages[0] await page.wait_for_load_state(\u0026#34;domcontentloaded\u0026#34;) print(await page.title()) asyncio.run(main())` Goal 编写指南：如何写出高质量的任务指令 Agent API 的核心参数是 goal（目标）。TinyFish 官方测试数据显示，精确的 goal 比模糊的 goal 执行速度快 4.9 倍，返回数据量减少 16 倍。\n一个好 goal 的七个要素：\n目标 — 要完成什么 对象 — 关注哪个区域 字段 — 要哪些数据 格式 — 输出结构 步骤 — 操作顺序 约束 — 不要做什么 异常处理 — 遇到意外怎么办 生产级 Goal 示例：\n`从该产品页面提取以下信息：\n产品名称（页面显示的完整标题） 当前价格（仅数字，不含货币符号） 如有原价则提取，否则设为null 货币代码 是否有库存（true/false） 如果出现cookie弹窗，先关闭它。 不要点击任何\u0026quot;加入购物车\u0026quot;或\u0026quot;立即购买\u0026quot;按钮。\n返回以下结构的JSON： { \u0026ldquo;product_name\u0026rdquo;: \u0026ldquo;string\u0026rdquo;, \u0026ldquo;current_price\u0026rdquo;: number或null, \u0026ldquo;original_price\u0026rdquo;: number或null, \u0026ldquo;currency\u0026rdquo;: \u0026ldquo;string\u0026rdquo;, \u0026ldquo;in_stock\u0026rdquo;: boolean }`\n## 实战教程：5分钟从零开始 **Step 1：注册账号** 访问 agent.tinyfish.ai/sign-up，注册即送 500 免费 credits。 **Step 2：获取 API Key** 进入 agent.tinyfish.ai/api-keys，点击「Create API Key」： `export TINYFISH_API_KEY=\u0026#34;你的API密钥\u0026#34;` Step 3：安装 SDK\n`# Python pip install tinyfish\nNode.js / TypeScript npm install @tiny-fish/sdk`\n**Step 4：运行第一个自动化任务** `from tinyfish import TinyFish, CompleteEvent client = TinyFish() with client.agent.stream( url=\u0026#34;https://scrapeme.live/shop\u0026#34;, goal=\u0026#34;提取前2个商品名称和价格，返回JSON格式\u0026#34;, ) as stream: for event in stream: if isinstance(event, CompleteEvent): print(event.result_json)` 运行后你会看到实时事件流：\n{'type': 'STARTED', 'run_id': 'abc123'} {'type': 'PROGRESS', 'purpose': 'Visit the page'} {'type': 'COMPLETE', 'result': { \u0026quot;products\u0026quot;: [ {\u0026quot;name\u0026quot;: \u0026quot;Bulbasaur\u0026quot;, \u0026quot;price\u0026quot;: \u0026quot;$63.00\u0026quot;}, {\u0026quot;name\u0026quot;: \u0026quot;Ivysaur\u0026quot;, \u0026quot;price\u0026quot;: \u0026quot;$87.00\u0026quot;} ] }}\n## 与主流 AI Agent 框架集成 ### 与 OpenClaw 集成：让 AI 助手具备联网能力 ![](https://mmbiz.qpic.cn/sz_mmbiz_png/ALOLkAWfuB6yfu2KTpxqrEC86SoTaS1XiccwiaEibGnyNkONYrBHBGx028ETO86X2Exw6xhDeD0LLO8NhOM9ZPiarRbFemkgQWaU8hEDI9jNRy0/640?from=appmsg) OpenClaw 是一个开源的多通道 AI Agent 网关，支持 Discord、Telegram、WhatsApp、飞书、iMessage 等十多个聊天平台。通过集成 TinyFish，可以让 AI 助手直接获得搜索和网页浏览能力。 **配置方法：**在 `openclaw.json` 中添加： `{ \u0026#34;plugins\u0026#34;: { \u0026#34;entries\u0026#34;: { \u0026#34;tinyfish\u0026#34;: { \u0026#34;enabled\u0026#34;: true, \u0026#34;config\u0026#34;: { \u0026#34;apiKey\u0026#34;: \u0026#34;你的TinyFish API Key\u0026#34; } } } } }` 实际使用场景：\n用户在飞书问「帮我查一下xxx的最新消息」→ 调用 Search API 用户说「帮我看看这个网页讲了什么」→ 调用 Fetch API 用户说「帮我自动填写这个表单」→ 调用 Agent API 与 Hermes Agent 集成：给自主Agent装上\u0026quot;眼睛和手\u0026quot; Hermes Agent 是由 Nous Research 开发的开源自主 AI Agent（MIT 协议）。它的核心理念是\u0026quot;一个能成长的Agent\u0026quot;——具备持久记忆、自动技能创建、多平台网关等能力。\n集成方式一：通过 API Key 直接调用\n`export TINYFISH_API_KEY=\u0026ldquo;你的TinyFish API Key\u0026rdquo;\nfrom tinyfish import TinyFish\nclient = TinyFish() results = client.search.query(query=\u0026ldquo;最新AI研究进展\u0026rdquo;) content = client.fetch.get_contents(urls=[\u0026ldquo;https://arxiv.org/abs/\u0026hellip;\u0026rdquo;])`\n**集成方式二：通过 MCP 协议** TinyFish 原生提供 MCP Server，Hermes Agent 可通过 MCP 集成以下工具： - `search` — 网页搜索 - `fetch_content` — 网页内容提取 - `run_web_automation` — 多步骤网页自动化 - `create_browser_session` — 远程浏览器会话 **集成方式三：利用 Hermes 的自动技能创建** 当你首次通过 TinyFish 完成某个复杂任务后，Hermes 会自动生成 SKILL.md 记录这个能力。下次遇到类似任务直接复用——**Hermes + TinyFish 的组合会越用越强**。 ### 与 MCP 兼容工具集成 一行命令即可接入 Claude、Cursor、Windsurf： `# Claude Code npx -y install-mcp@latest https://agent.tinyfish.ai/mcp --client claude-code # Cursor npx -y install-mcp@latest https://agent.tinyfish.ai/mcp --client cursor # Windsurf npx -y install-mcp@latest https://agent.tinyfish.ai/mcp --client windsurf` 与低代码平台集成 **Dify：**在 Plugin Marketplace 安装 TinyFish Web Agent 插件，输入 API Key 授权即可使用。\n**n8n：**在 Community Nodes 搜索安装 n8n-nodes-tinyfish，添加节点配置 URL 和 Goal 即可。\n价格方案 方案价格包含适合免费试用$0500 credits体验和测试按量付费$0.015/credit无上限低频使用Starter$13/月1,650 credits日常开发工作流Pro$132/月16,500 credits团队高强度使用Enterprise定制定制+SLA+私有部署企业级需求\n注意：Search API 和 Fetch API 完全免费，只有 Agent API 和 Browser API 消耗 credits。\n总结 TinyFish 的定位非常清晰：为 AI Agent 提供企业级的 Web 基础设施。\n核心优势：\n简单 — 一个 API Key，四行代码跑通 免费起步 — Search 和 Fetch 永远免费，注册送 500 credits 生态丰富 — 原生支持 MCP、Python/Node SDK、CLI、Dify、n8n 企业级 — 隐身浏览器、反Bot、代理、密钥管理一应俱全 无论你是想给 Claude 加上搜索能力，还是在 OpenClaw 里构建多平台 AI 助手，或是搭配 Hermes Agent 打造持续进化的自主Agent——TinyFish 都是值得认真尝试的 Web 基础设施。\n🔗 官网：www.tinyfish.ai 📄 文档：docs.tinyfish.ai\n","permalink":"https://blog.zdltech.com/posts/article-5-20260528/","summary":"\u003cp\u003e在AI Agent飞速发展的今天，大模型越来越聪明，但它们有一个共同的短板——\u003cstrong\u003e上不了网\u003c/strong\u003e。无法实时搜索信息、无法浏览网页、无法自动操作网站，这让AI Agent的能力被大大限制。\u003c/p\u003e\n\u003cp\u003eTinyFish 就是为了解决这个问题而生的。它提供了一套企业级的 Web API，让任何 AI Agent 都能获得搜索、浏览、提取网页内容甚至自动操作网站的能力。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://mmbiz.qpic.cn/sz_mmbiz_png/ALOLkAWfuB6Y5YP09VnhcqOqMrJL1fWuNqpvowOqosWbZTyCaPpWHbafyDicBrLRvSl7Y1f53xRhU31Cr6p6QVqWDOh3y9slPuvkibIldWmZ0/640?from=appmsg\"\u003e\u003c/p\u003e\n\u003ch2 id=\"一个api-key四大核心能力\"\u003e一个API Key，四大核心能力\u003c/h2\u003e\n\u003cp\u003eTinyFish 的核心设计理念是「简单集成」。一个 API Key，统一的 credit 池，四个独立的 API 覆盖从搜索到自动化操作的全链路场景。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://mmbiz.qpic.cn/mmbiz_png/ALOLkAWfuB62vBvUnzeZDe7Yol9H0yphibXmO7fZeQBMj0Buqgfd7oL9BsT0INiakVF0ByPXX9ul5Og2Ou2v8556E8gBibVtmRHzQIedAvFxcw/640?from=appmsg\"\u003e\u003c/p\u003e\n\u003ch3 id=\"1-search-api--网页搜索\"\u003e1. Search API — 网页搜索\u003c/h3\u003e\n\u003cp\u003e输入查询关键词，返回结构化的搜索结果（标题、摘要、URL），直接可供 LLM 消费或程序化处理。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e核心特性：\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e支持地区和语言偏好设置，获取本地化搜索结果\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e完全免费\u003c/strong\u003e，不消耗 credits\u003c/li\u003e\n\u003cli\u003e速率限制：60次/分钟\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e使用示例（Python）：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e`from tinyfish import TinyFish\u003c/p\u003e\n\u003cp\u003eclient = TinyFish()\nresponse = client.search.query(\nquery=\u0026ldquo;2024年最佳AI编程工具\u0026rdquo;,\nlocation=\u0026ldquo;CN\u0026rdquo;,\nlanguage=\u0026ldquo;zh\u0026rdquo;\n)\nfor r in response.results:\nprint(r.title, \u0026ldquo;→\u0026rdquo;, r.url)`\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e**cURL 调用：**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`curl \u0026#34;https://api.search.tinyfish.ai?query=2024年最佳AI编程工具\u0026amp;location=CN\u0026amp;language=zh\u0026#34; \\\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  -H \u0026#34;X-API-Key: $TINYFISH_API_KEY\u0026#34;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"2-fetch-api--网页内容提取\"\u003e2. Fetch API — 网页内容提取\u003c/h3\u003e\n\u003cp\u003e用真实浏览器渲染网页（包括 JS 动态渲染的 SPA 页面），提取干净的页面内容。单次请求最多支持 10 个 URL，每个 URL 独立处理。\u003c/p\u003e","title":"TinyFish：给AI Agent装上「上网能力」的企业级基础设施"},{"content":"当所有 AI 编程工具都在\u0026quot;帮你决定一切\u0026quot;的时候，Pi 走了完全相反的路：给你一个最小核心，剩下的你自己组装。3000+ 社区包、50+ 扩展示例、30+ LLM 供应商——这不是一个产品，这是一个生态。\n🔗 **项目主页：**pi.dev\n📂 **GitHub：**earendil-works/pi\n📜 **开源协议：**MIT\n一、Pi 是什么？ Pi 是一个极简主义的开源 AI 编程 Agent 框架，核心理念只有八个字：\u0026ldquo;提供原语，而非功能\u0026rdquo;（Primitives, not features）。\n什么意思？Cursor 帮你内建了 Tab 补全、Windsurf 帮你内建了 Cascade 流程、Copilot 帮你内建了 Chat 面板——Pi 什么都不内建。它只给你四个工具（读、写、编辑、运行命令），然后说：\n\u0026ldquo;你需要什么功能，自己搭。搭不了？让我帮你搭。\u0026rdquo;\n这就是 Pi 最特别的地方——它可以自己改造自己。你让 Pi 构建一个子代理系统，它写完代码后 /reload 立刻生效，Pi 就有了子代理能力。\n二、三个独特优势 🎯 优势一：30+ LLM 供应商，想用谁用谁 Pi 支持 Anthropic、OpenAI、Google Gemini、Azure、Bedrock、Mistral、Groq、Cerebras、xAI、DeepSeek、Hugging Face、Kimi、MiniMax、小米 MiMo、OpenRouter、Ollama 等 30+ 供应商。\n认证方式灵活： API Key：export ANTHROPIC_API_KEY=***\nOAuth 订阅：/login 直接登录 Claude Pro/Max、ChatGPT Plus/Pro、GitHub Copilot\n自定义供应商：通过 models.json 或扩展实现任意 API\n会话中随时切换模型： /model 或 Ctrl+L → 打开模型选择器\nCtrl+P → 在收藏模型间快速循环\nShift+Tab → 切换思考深度\n💡 **实战场景：**你可以让 Pi 先用便宜快速的模型（如 Groq + Llama）做初步代码分析，遇到复杂逻辑时一句话切到 Claude Sonnet 4 深度推理——同一个会话，无需重启。\n🌳 优势二：树状会话——AI 对话的\u0026quot;存档系统\u0026quot; Pi 的会话不是线性列表，而是一棵树。你可以从任何历史节点分叉，探索不同方案后随时回溯——就像游戏的存档系统。\n/tree → 跳转到任意历史节点\n/fork → 从某个消息分叉出新会话\n/share → 上传到 GitHub Gist 分享\n/export → 导出为 HTML\n📎 **示例会话：**在线体验\n🧠 优势三：上下文工程——专业玩家的控制权 **AGENTS.md：**全局 + 项目级指令，启动时自动加载\n**SYSTEM.md：**按项目替换或追加系统提示词\n**自动压缩（Compaction）：**接近上下文限制时自动摘要\n**技能（Skills）：**按需加载，渐进式揭示，不浪费 token\n**动态上下文注入：**扩展可以注入消息、过滤历史、实现 RAG\n三、四层积木架构 包名职责 pi-coding-agent交互式编程 Agent CLI + TUI pi-agent-coreAgent 运行时（工具调用、状态管理） pi-ai统一多供应商 LLM API pi-tui终端 UI 库（差量渲染）\n💡 **关键洞察：**每一个包都可以单独使用。只想用统一 LLM API？装 pi-ai 就行。这种分层设计让 Pi 不只是工具，更是构建块。\n四、扩展系统：让 Pi 成为\u0026quot;任何东西\u0026quot; 五行代码写一个危险操作守卫扩展：\n`// ~/.pi/agent/extensions/danger-guard.ts import type { ExtensionAPI } from \u0026ldquo;@earendil-works/pi-coding-agent\u0026rdquo;;\nexport default function (pi: ExtensionAPI) { pi.on(\u0026ldquo;tool_call\u0026rdquo;, async (event, ctx) =\u0026gt; { if (event.toolName === \u0026ldquo;bash\u0026rdquo; \u0026amp;\u0026amp; event.input.command?.includes(\u0026ldquo;rm -rf\u0026rdquo;)) { const ok = await ctx.ui.confirm(\u0026ldquo;Dangerous!\u0026rdquo;, \u0026ldquo;Allow rm -rf?\u0026rdquo;); if (!ok) return { block: true, reason: \u0026ldquo;Blocked by user\u0026rdquo; }; } }); }`\n保存后 `/reload` 立即生效。AI 执行 `rm -rf` 前会弹窗让你确认。 **官方 50+ 扩展示例：** - - **subagent** — 子代理 - - **plan-mode** — 计划模式（先规划再执行） - - **permission-gate** — 权限门控 - - **protected-paths** — 路径保护 - - **ssh** — 远程 SSH 执行 - - **sandbox** — 沙箱隔离 ### 技能系统（Skills） 技能是**按需加载**的能力包，遵循 Agent Skills 标准。启动时只有 name 和 description 在上下文中，当任务匹配时才加载完整指令。 ## 五、社区生态：3000+ 包 `# 子代理系统 pi install npm:pi-subagents # 网络搜索 + 网页抓取 + PDF 提取 pi install npm:pi-web-access # MCP 协议适配器 pi install npm:pi-mcp-adapter # 持久记忆 pi install npm:@samfp/pi-memory # 从 Git 安装 pi install git:github.com/badlogic/pi-doom` 包名功能月下载 context-modeMCP 插件，节省 98% 上下文窗口117K pi-subagents子代理：链式/并行执行99.8K pi-mcp-adapterMCP 协议适配88.9K pi-web-access网络搜索、URL 抓取、PDF 提取59.8K\n六、pi-mainframe：5 分钟搭 Web 服务 `npx pi-mainframe\n打开 http://127.0.0.1:8888` 你得到：Web UI、REST API、SSE 实时流、Daytona 沙箱、xAI TTS 语音播报、定时任务。 ## 七、手把手教程 ### 第一步：安装 `npm install -g --ignore-scripts @earendil-works/pi-coding-agent # 或者 curl（Linux/macOS） curl -fsSL https://pi.dev/install.sh | sh` 第二步：认证 `export ANTHROPIC_API_KEY=sk-ant\u0026hellip;here pi\n或者 OAuth 订阅登录 pi\n输入 /login 选择供应商` ### 第三步：开始对话 `cd your-project pi` 默认提供四个工具：read（读文件）、write（写文件）、edit（编辑文件）、bash（执行命令）。\n第四步：添加项目指令 在项目根目录创建 AGENTS.md：\n`# 项目指令\n代码修改后运行 npm run check 不要在本地运行生产环境迁移 回复保持简洁` 修改后 `/reload` 即生效。 ### 第五步：安装扩展 `pi install npm:pi-web-access pi install npm:pi-subagents /reload` 第六步：写自定义扩展 创建 ~/.pi/agent/extensions/my-first-extension.ts：\n`import type { ExtensionAPI } from \u0026ldquo;@earendil-works/pi-coding-agent\u0026rdquo;; import { Type } from \u0026ldquo;typebox\u0026rdquo;;\nexport default function (pi: ExtensionAPI) { pi.registerTool({ name: \u0026ldquo;timestamp\u0026rdquo;, label: \u0026ldquo;时间戳\u0026rdquo;, description: \u0026ldquo;获取当前时间戳\u0026rdquo;, parameters: Type.Object({}), async execute(id, params, sig, upd, ctx) { return { content: [{ type: \u0026ldquo;text\u0026rdquo;, text: 当前时间: ${new Date().toISOString()} }], details: {}, }; }, }); pi.registerCommand(\u0026ldquo;hello\u0026rdquo;, { description: \u0026ldquo;打个招呼\u0026rdquo;, handler: async (args, ctx) =\u0026gt; { ctx.ui.notify(Hello ${args || \u0026quot;world\u0026quot;}!, \u0026ldquo;info\u0026rdquo;); }, }); }`\n`/reload # 重载扩展 /hello 世界 # 测试命令` 八、四种运行模式 模式命令适用场景 交互模式pi日常编程 单次执行pi -p query脚本/CI JSON 事件流--mode json程序集成 SDKimport { Pi }嵌入应用\n💡 **真实案例：**OpenClaw 通过 Pi SDK 将编程 Agent 嵌入自己的系统，实现了跨平台的消息驱动编程能力。\n九、Pi 的哲学：为什么\u0026quot;少\u0026quot;是\u0026quot;多\u0026quot; 维度传统工具Pi 功能内建、固定用户自建、按需加载 模型绑定供应商30+ 供应商自由切换 扩展等官方更新写个 TS 文件即刻生效 上下文黑箱管理完全可控 会话线性历史树状分支，任意回溯\n十、总结 适合你，如果你： 是专业开发者，想要对 AI 编程工具的完全控制权\n需要在多个 LLM 模型间灵活切换\n想要构建自定义的 AI 编程工作流\n希望将 AI 编程能力嵌入到自己的产品中\n喜欢终端，享受\u0026quot;一切皆可定制\u0026quot;的体验\nPi 代表了 AI 编程工具的另一种可能——不是产品定义用户，而是用户定义产品。\n🔗 相关链接\n官网 · GitHub · 包市场（3128+） · Discord · 文档\n","permalink":"https://blog.zdltech.com/posts/article-3-20260528/","summary":"\u003cp\u003e当所有 AI 编程工具都在\u0026quot;帮你决定一切\u0026quot;的时候，\u003cstrong\u003ePi\u003c/strong\u003e 走了完全相反的路：给你一个最小核心，剩下的你自己组装。3000+ 社区包、50+ 扩展示例、30+ LLM 供应商——这不是一个产品，这是一个\u003cstrong\u003e生态\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e🔗 **项目主页：**pi.dev\u003c/p\u003e\n\u003cp\u003e📂 **GitHub：**earendil-works/pi\u003c/p\u003e\n\u003cp\u003e📜 **开源协议：**MIT\u003c/p\u003e\n\u003ch2 id=\"一pi-是什么\"\u003e一、Pi 是什么？\u003c/h2\u003e\n\u003cp\u003ePi 是一个极简主义的开源 AI 编程 Agent 框架，核心理念只有八个字：\u003cstrong\u003e\u0026ldquo;提供原语，而非功能\u0026rdquo;\u003c/strong\u003e（Primitives, not features）。\u003c/p\u003e\n\u003cp\u003e什么意思？Cursor 帮你内建了 Tab 补全、Windsurf 帮你内建了 Cascade 流程、Copilot 帮你内建了 Chat 面板——Pi 什么都不内建。它只给你四个工具（读、写、编辑、运行命令），然后说：\u003c/p\u003e\n\u003cp\u003e\u0026ldquo;你需要什么功能，自己搭。搭不了？让我帮你搭。\u0026rdquo;\u003c/p\u003e\n\u003cp\u003e这就是 Pi 最特别的地方——\u003cstrong\u003e它可以自己改造自己\u003c/strong\u003e。你让 Pi 构建一个子代理系统，它写完代码后 \u003ccode\u003e/reload\u003c/code\u003e 立刻生效，Pi 就有了子代理能力。\u003c/p\u003e\n\u003ch2 id=\"二三个独特优势\"\u003e二、三个独特优势\u003c/h2\u003e\n\u003ch3 id=\"-优势一30-llm-供应商想用谁用谁\"\u003e🎯 优势一：30+ LLM 供应商，想用谁用谁\u003c/h3\u003e\n\u003cp\u003ePi 支持 Anthropic、OpenAI、Google Gemini、Azure、Bedrock、Mistral、Groq、Cerebras、xAI、DeepSeek、Hugging Face、Kimi、MiniMax、小米 MiMo、OpenRouter、Ollama 等 30+ 供应商。\u003c/p\u003e\n\u003ch2 id=\"认证方式灵活\"\u003e\u003cstrong\u003e认证方式灵活：\u003c/strong\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eAPI Key：\u003ccode\u003eexport ANTHROPIC_API_KEY=***\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eOAuth 订阅：\u003ccode\u003e/login\u003c/code\u003e 直接登录 Claude Pro/Max、ChatGPT Plus/Pro、GitHub Copilot\u003c/p\u003e","title":"别再被 AI 编程工具绑架了——Pi 让 Agent 自己改造自己"},{"content":"你有没有过这种经历？\n刚入职一家新公司，领导丢过来一个20万行的代码库说：\u0026ldquo;这是咱们的核心系统，你先熟悉一下。\u0026rdquo;\n然后你打开IDE，面对几百个文件夹、几千个文件，完全不知道从哪看起。看哪个文件？谁调谁？这个模块干嘛的？那个接口跟谁对接？\n一整天下来，除了眼睛疼，啥也没看明白。\n更惨的是接手\u0026quot;祖传代码\u0026quot;——前人已离职，文档不存在，注释是乱码，你只能一个函数一个函数地跟踪跳转，像在黑暗的迷宫里摸墙走。\n今天介绍的这款开源工具，就是来终结这种痛苦的。\n一、Understand Anything 是什么？ Understand Anything 是一个 Claude Code 插件，它能用多 Agent 协作的方式，把你的整个代码库变成一个可交互的知识图谱。\n不是简单的文件依赖树，而是一个你能点、能搜、能问的智能知识网络。每个文件、函数、类都是图上的节点，点击就能看到依赖关系、自然语言解释、架构分层。\nGitHub 地址：https://github.com/Lum1104/Understand-Anything\n截至目前：29k+ Star，2400+ Fork，上线不到两个月就冲上 GitHub Trending 榜首，热度可见一斑。\n一句话总结：它不只是展示代码结构，它教你理解代码库。\n二、核心功能拆解 1️⃣ 一键生成代码知识图谱 运行 /understand，工具会启动5个专业 Agent 协作：\nproject-scanner：扫描项目，识别语言和框架\nfile-analyzer：提取函数、类、依赖关系，构建图谱节点和边\narchitecture-analyzer：识别架构分层（API / Service / Data / UI）\ntour-builder：生成架构导览路线\ngraph-reviewer：校验图谱完整性和一致性\n最终输出一个 JSON 格式的知识图谱，并可通过 Dashboard 可视化展示。\n支持 26+ 文件类型，不只是代码——Dockerfile、Terraform、SQL、Markdown 都能纳入图谱。\n2️⃣ 交互式 Dashboard 运行 /understand-dashboard，浏览器自动打开一个交互式可视化面板：\n🎨 按架构分层颜色编码（API 层蓝色、Service 层绿色、数据层橙色……）\n🔍 支持模糊搜索和语义搜索，搜\u0026quot;认证相关的代码\u0026quot;就能定位\n🖱️ 点击任意节点查看代码、依赖关系和自然语言解释\n📤 支持导出 PNG / SVG / JSON\n3️⃣ 自然语言问答 /understand-chat 用户注册的完整流程是怎样的？\n直接用中文问，它会基于知识图谱给你一个结构化的回答。不是简单的代码搜索，而是基于整个项目上下文的深度理解。 ### 4️⃣ 变更影响分析 改代码之前先跑一下： `/understand-diff` 它会分析你当前的修改会影响哪些模块、哪些函数，提前告诉你\u0026quot;改这里可能会炸那里\u0026quot;。上线前必跑，比同事的 code review 更快。\n5️⃣ 业务域映射 /understand-domain\n这个功能非常独特——它会把代码映射到真实的**业务流程**上。比如： - - 认证域 → 登录、Token验证、会话管理 - - 支付域 → 订单创建、支付网关、回调处理 - - 用户生命周期 → 注册、资料管理、权限分配 - 不再是冷冰冰的代码结构，而是你能跟产品经理聊明白的\u0026#34;业务地图\u0026#34;。 ### 6️⃣ 新人 Onboarding 自动生成 `/understand-onboard` 自动生成一份新人上手指南，按依赖顺序排列，从基础模块到核心业务，循序渐进。以后再也不用写入职文档了。\n7️⃣ 知识库图谱 /understand-knowledge ~/path/to/wiki\n支持把 Karpathy 风格的 LLM Wiki 知识库也变成知识图谱，提取实体、关系和隐含连接。不只是代码，你的知识笔记也能图谱化。 ## 三、实操案例 ### 📌 案例1：接手一个陌生的微服务项目 **场景：**你刚入职，需要接手一个包含 15 个微服务的电商平台后端。 **操作步骤：** `# Step 1: 安装插件 /plugin marketplace add Lum1104/Understand-Anything /plugin install understand-anything # Step 2: 一键生成知识图谱 /understand --language zh` 等待几分钟，5 个 Agent 会并行扫描整个项目，最终生成 .understand-anything/knowledge-graph.json。\n# Step 3: 打开 Dashboard /understand-dashboard\n打开浏览器，你会看到： - - 15 个微服务各自的节点和调用关系 - - 每个服务内部的 API / Service / Data 分层 - - 颜色编码一目了然——网关层、业务层、数据层清晰可见 - `# Step 4: 深入了解支付服务 /understand-explain services/payment/` 得到一份自然语言的支付服务架构说明：哪些接口对外暴露、内部调用了哪些下游服务、数据库表结构关系。\n**结果：**别人花一周才能搞明白的项目结构，你半天就建立了全局认知。\n📌 案例2：改代码前的安全检查 **场景：**你要修改用户认证模块的 Token 生成逻辑，但不确定会影响哪些地方。\n/understand-diff\n分析结果显示： - - ⚠️ `auth/token.ts` → 被 12 个文件引用 - - ⚠️ 影响链路：认证中间件 → API 网关 → 3 个业务服务的鉴权 - - ⚠️ `session/manager.ts` 强依赖 Token 格式，修改后需要同步更新 - 提前知道雷区，改起来心里有底，不用提心吊胆等测试报 bug。 ### 📌 案例3：团队协作——图谱即文档 **场景：**你的团队有 8 个人，经常有人问\u0026#34;XX 功能在哪里实现的\u0026#34;。 `# 首次生成 /understand # 开启自动更新——每次 commit 自动刷新图谱 /understand --auto-update` 然后把 .understand-anything/ 目录提交到 Git（排除 intermediate/ 和 diff-overlay.json）。\n效果：\n新人 clone 代码后直接打开 Dashboard，不用重新跑分析\n每次提交自动更新图谱，文档永远跟代码同步\n大项目可以用 git-lfs 管理（图谱超过 10MB 时）\nPR Review 时可以直观看到改动的影响范围\n📌 案例4：梳理业务流程 **场景：**产品经理问你\u0026quot;咱们的退款流程是怎样的\u0026quot;，你需要快速梳理出技术实现链路。\n/understand-domain\n输出一份业务流程图： `退款域 (Refund Domain) ├── 退款申请流程 │ ├── 用户提交退款请求 → refund/submit.ts │ ├── 订单状态校验 → order/validate.ts │ └── 退款单创建 → refund/create.ts ├── 退款审批流程 │ ├── 风控检查 → risk/check.ts │ ├── 金额核算 → refund/calculate.ts │ └── 审批决策 → refund/approve.ts └── 退款执行流程 ├── 支付渠道退款 → payment/refund.ts └── 状态回调通知 → refund/callback.ts` 直接拿去跟产品经理对齐，代码和业务一一对应，沟通效率拉满。\n四、安装使用（3步搞定） Claude Code（推荐） /plugin marketplace add Lum1104/Understand-Anything /plugin install understand-anything /understand\n### Cursor 直接 clone 仓库到项目目录，Cursor 自动识别插件，无需手动安装。 ### VS Code + GitHub Copilot 同样 clone 即可自动识别，或通过命令安装： `copilot plugin install Lum1104/Understand-Anything:understand-anything-plugin` 其他平台 支持 Codex、Gemini CLI、OpenCode、Cline、KIMI CLI 等13个平台，一行命令安装：\n`# macOS / Linux curl -fsSL https://raw.githubusercontent.com/Lum1104/Understand-Anything/main/install.sh | bash\nWindows (PowerShell) iwr -useb https://raw.githubusercontent.com/Lum1104/Understand-Anything/main/install.ps1 | iex`\n## 五、技术原理：为什么它这么强？ Understand Anything 的核心是**静态分析 + LLM 语义理解**的混合架构： - - **Tree-sitter（确定性）**：负责语法解析，提取 imports、exports、函数定义、调用关系、继承结构。同样的代码永远生成同样的结构，可复现、可增量。 - - **LLM（语义理解）**：在静态结构的基础上，生成自然语言摘要、标签、架构分层判断、业务域映射、导览说明——这些是纯解析器做不到的。 - 两者分工明确：Tree-sitter 保证结构准确，LLM 赋予语义深度。 另外，文件分析支持**并行处理**（最多5个并发，每批20-30个文件），并支持**增量更新**——只重新分析变更的文件，大型项目也不用每次从头跑。 ## 六、适用场景总结 场景用哪个命令 快速了解项目全貌`/understand` + `/understand-dashboard` 深入某个模块`/understand-explain` 改代码前评估影响`/understand-diff` 自然语言提问`/understand-chat` 新人上手`/understand-onboard` 梳理业务流程`/understand-domain` 知识库图谱化`/understand-knowledge` ## 写在最后 理解一个陌生代码库，一直是程序员最痛苦、最耗时的工作之一。Understand Anything 不是又一个代码搜索工具，它是一个真正帮你**建立认知框架**的助手。 29k Star 不是吹出来的，确实是解决了一个真实痛点。 项目还在快速迭代中，MIT 开源协议，社区活跃。建议每个人都试一试，尤其是经常接手新项目或者维护祖传代码的同学。 **仓库地址：**https://github.com/Lum1104/Understand-Anything **在线 Demo：**https://understand-anything.com/demo/ 觉得有用？转发给你那个还在啃源码的同事吧 🫡 ","permalink":"https://blog.zdltech.com/posts/article-4-20260528/","summary":"\u003cp\u003e你有没有过这种经历？\u003c/p\u003e\n\u003cp\u003e刚入职一家新公司，领导丢过来一个20万行的代码库说：\u003cstrong\u003e\u0026ldquo;这是咱们的核心系统，你先熟悉一下。\u0026rdquo;\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e然后你打开IDE，面对几百个文件夹、几千个文件，完全不知道从哪看起。看哪个文件？谁调谁？这个模块干嘛的？那个接口跟谁对接？\u003c/p\u003e\n\u003cp\u003e一整天下来，除了眼睛疼，啥也没看明白。\u003c/p\u003e\n\u003cp\u003e更惨的是接手\u0026quot;祖传代码\u0026quot;——前人已离职，文档不存在，注释是乱码，你只能一个函数一个函数地跟踪跳转，像在黑暗的迷宫里摸墙走。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e今天介绍的这款开源工具，就是来终结这种痛苦的。\u003c/strong\u003e\u003c/p\u003e\n\u003ch2 id=\"一understand-anything-是什么\"\u003e一、Understand Anything 是什么？\u003c/h2\u003e\n\u003cp\u003eUnderstand Anything 是一个 Claude Code 插件，它能用多 Agent 协作的方式，把你的整个代码库变成一个\u003cstrong\u003e可交互的知识图谱\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e不是简单的文件依赖树，而是一个你能\u003cstrong\u003e点、能搜、能问\u003c/strong\u003e的智能知识网络。每个文件、函数、类都是图上的节点，点击就能看到依赖关系、自然语言解释、架构分层。\u003c/p\u003e\n\u003cp\u003eGitHub 地址：https://github.com/Lum1104/Understand-Anything\u003c/p\u003e\n\u003cp\u003e截至目前：\u003cstrong\u003e29k+ Star，2400+ Fork\u003c/strong\u003e，上线不到两个月就冲上 GitHub Trending 榜首，热度可见一斑。\u003c/p\u003e\n\u003cp\u003e一句话总结：\u003cstrong\u003e它不只是展示代码结构，它教你理解代码库。\u003c/strong\u003e\u003c/p\u003e\n\u003ch2 id=\"二核心功能拆解\"\u003e二、核心功能拆解\u003c/h2\u003e\n\u003ch3 id=\"1-一键生成代码知识图谱\"\u003e1️⃣ 一键生成代码知识图谱\u003c/h3\u003e\n\u003cp\u003e运行 \u003ccode\u003e/understand\u003c/code\u003e，工具会启动5个专业 Agent 协作：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eproject-scanner\u003c/strong\u003e：扫描项目，识别语言和框架\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003efile-analyzer\u003c/strong\u003e：提取函数、类、依赖关系，构建图谱节点和边\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003earchitecture-analyzer\u003c/strong\u003e：识别架构分层（API / Service / Data / UI）\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003etour-builder\u003c/strong\u003e：生成架构导览路线\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003egraph-reviewer\u003c/strong\u003e：校验图谱完整性和一致性\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e最终输出一个 JSON 格式的知识图谱，并可通过 Dashboard 可视化展示。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e支持 26+ 文件类型\u003c/strong\u003e，不只是代码——Dockerfile、Terraform、SQL、Markdown 都能纳入图谱。\u003c/p\u003e\n\u003ch3 id=\"2-交互式-dashboard\"\u003e2️⃣ 交互式 Dashboard\u003c/h3\u003e\n\u003cp\u003e运行 \u003ccode\u003e/understand-dashboard\u003c/code\u003e，浏览器自动打开一个交互式可视化面板：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e🎨 按架构分层\u003cstrong\u003e颜色编码\u003c/strong\u003e（API 层蓝色、Service 层绿色、数据层橙色……）\u003c/p\u003e","title":"别再跪着啃源码了！Understand Anything 让你10分钟看透20万行代码"},{"content":"2026年5月，谷歌I/O大会重磅发布\n📌 官网地址： antigravity.google\n📥 下载地址： antigravity.google/download\n📚 官方教程： Getting Started 教程\n一、Antigravity 是什么？ 2025年11月，谷歌随 Gemini 3 一同发布了 Antigravity——一个「Agent 优先」的敏捷开发平台。它基于 VS Code 内核重构，整合了谷歌以 24亿美元 收购的 Windsurf 团队技术，将 IDE 从「AI 辅助编码」推进到 「Agent 自主执行 + 开发者审核」 的新范式。\n简单来说：传统 AI 工具是帮你写代码，Antigravity 是 AI 帮你 规划、编码、测试、运行，你只负责审核和决策。\n2026年5月的谷歌 I/O 大会上，谷歌发布了 Antigravity 2.0，定位从「开发者的 AI IDE」全面升级为 「通用智能体优先工作平台」，可以作为统一中枢管理多个数字智能体。\n💡 核心理念： 「Agent 做事，开发者审核」——Agent 不仅能写代码，还能启动应用、在浏览器中测试、验证功能是否正常。通过 Tasks 和 Artifacts 进行更高层次的沟通。\n二、Antigravity 2.0 核心更新 1️⃣ 多智能体协同 Antigravity 2.0 最大的亮点之一是 多智能体并行。你可以同时部署多个子智能体，分别处理不同的编程任务，互不干扰，多任务并行效率大幅提升。\n以前开发需求要等一个任务完成才能开始下一个，中间只能盯着屏幕发呆。现在，你可以在 Agent Manager 中同时跑多个 Agent，在不同工作区处理多个不同任务，真正解放双手。\n2️⃣ 定时任务（Scheduled Tasks） 通过 /schedule 命令设置一次性或周期性调度，让智能体按预设时间自动执行，真正实现 无人值守。例如定时运行测试、定时部署、定时检查代码质量等。\n3️⃣ 项目管理升级 2.0 版本取消了智能体与代码仓库的强绑定，从按 workspace 组织改为按 project 管理。一个项目可对应多个文件夹，拥有独立的智能体设置和权限边界，更灵活也更安全。\n4️⃣ 斜杠命令体系 新增多条实用斜杠命令，大幅提升可控性：\n/goal — 连续执行模式 /grill-me — 先澄清需求再执行 /browser — 显式调用浏览器能力 /schedule — 设置定时任务 /workflow名称 — 触发预设工作流 5️⃣ Antigravity CLI 同步推出命令行版本，轻量高速。谷歌建议旧版 Gemini CLI 用户迁移到这个全新的命令行系统，更加高效。\n6️⃣ Managed Agents（云端智能体） 通过 Gemini API，一次请求 即可启动在隔离的 Linux 环境中的智能体。环境状态持久保存——即使关闭后再次返回，已编译文件、记忆日志和项目状态仍然存在。这对于持续集成、自动化部署等场景非常实用。\n7️⃣ 移动端支持 Google AI Studio 移动应用已开放预注册。你可以在手机上整理想法，回到桌面端查看可运行原型。更厉害的是，平台新增了 面向 Android 的原生编译能力，通过提示词就能生成完整的 Android 应用，并直接导出到 Google Play Console 测试轨道，大大缩短从构想到测试的链路。\n三、三大核心界面 Editor： 功能完备的 AI 驱动 IDE，映射到单个工作区。支持多模型切换、代码补全、内联编辑等\nAgent Manager： 全新的智能体管理视图，「无代码」方式启动和查看任务，聚焦对话和 Artifacts 交付物。可同时管理多个并行 Agent\nBrowser： 内置浏览器能力，Agent 可操控浏览器完成 UI 测试、数据读取、自动化操作等。拥有专门的浏览器子 Agent\n⌨️ 快捷键提示： Cmd/Ctrl + E 切换 Editor ↔ Agent Manager；Cmd/Ctrl + L 打开 AI 对话框；Cmd/Ctrl + I 编辑选中代码\n四、Artifacts 交付系统（核心创新） 这是 Antigravity 最大的创新之一。Agent 完成任务后会产出 可验证的交付物（Artifacts），而不是一段让你自己看的代码：\n📋 Task List — 任务列表，自动拆分并追踪进度 📐 Implementation Plan — 实现计划，架构代码库变更以完成任务 📝 Walkthrough — 工作总结，完成任务后的变更摘要 📸 Screenshots — 屏幕截图，用于审核页面状态 🎬 Browser Recordings — 浏览器操作录制回放 🔄 Diff Views — 代码变更对比 🏗️ Architecture Diagrams — 架构图 工作流程：\nAgent 生成 Implementation Plan，请求你审核 你可以点击「Proceed」继续，或在计划上添加评论提供反馈 Agent 执行完成后，生成 Walkthrough 报告 你逐项审核 Artifacts，确认无误后签收 ✅ Artifacts 的价值： 透明度（清楚了解 Agent 的思考过程）+ 可验证（每个变更都有记录）+ 可回溯（出问题快速定位）+ 协作式（可在 Artifacts 上评论反馈）\n五、强大的自定义能力 📜 Rules（规则） 为 Agent 定义约束和行为指南。支持全局和工作区两个级别，可按文件类型自动激活。例如设置「始终使用中文回复」「遵循团队的代码规范」等。\n规则的激活方式灵活多样：\nAlways On： 始终应用 Manual： 通过 @ 提及手动激活 Model Decision： 模型根据描述自动决定是否应用 Glob： 基于文件匹配模式自动激活（如 *.js, src/**/*.ts） 🔄 Workflows（工作流） 定义重复性任务的标准流程，如部署、测试、代码审核。用 /deploy 一键触发。工作流支持嵌套调用，还能标记 // turbo 让特定步骤自动跳过确认。\n🛠️ Skills（技能） 基于开放标准（agentskills.io），Skills 是可复用的知识包，包含处理特定任务的指令、最佳实践和脚本。你可以创建自己的 Skills，也可以从社区获取，让 Agent 能力持续扩展。\n🔌 MCP 支持 Antigravity 支持 MCP（Model Context Protocol）集成，允许 Agent 安全地连接本地工具、数据库和外部服务。这意味着 AI 可以获取 实时上下文信息，不再局限于编辑器中打开的文件。\n六、支持的多模型矩阵 Antigravity 通过 Google Vertex Model Garden 提供一系列前沿模型：\nGemini 3 Pro — 主力模型，SWE-bench 76.2%，Terminal-Bench 54.2% Gemini 3 Pro + Deep Think — 长链推理模式，适合复杂架构任务 Gemini 3 Flash — 快速响应，低延迟 Claude Sonnet 4.6 — Anthropic 模型，带思考链版本可选 Claude Opus 4.6 — 高级推理模型 GPT-OSS-120B — OpenAI 开源变体 🔥 重点： 以上顶级大模型 个人用户公测期间免费使用！Gemini 3 Pro / Flash 和 Claude Sonnet / Opus 4.5 等模型免费用，这在其他 AI 编程工具中几乎不可能。\n七、浏览器子代理 当主 Agent 需要与浏览器交互时，它会调用一个专门的 浏览器子 Agent。这个子 Agent：\n运行专门针对页面操作优化的模型 拥有点击、滚动、输入、读取控制台日志等工具 通过 DOM 捕获、截图或 Markdown 解析读取页面 可以录制操作视频 在后台标签页默默干活，不影响你的其他操作 Agent 控制页面时，页面会显示 蓝色边框覆盖层 和操作描述面板，这时用户无法与页面交互，避免干扰 Agent 的操作。这个功能对于前端开发、UI 测试、自动化操作等场景非常实用。\n八、性能表现 公测期间，Antigravity 在权威基准测试中表现亮眼：\n76.2% SWE-bench Verified 54.2% Terminal-Bench 2.0（超越 GPT-5.1 的 47.6%） 九、适用人群 👨‍💻 全栈开发者： 从原型到部署一站式完成，告别多 IDE 切换 👨‍💼 技术团队负责人： 用 Workflows 标准化团队流程，提升整体效率 🧑‍💻 独立开发者： 一个 Agent 顶半个团队，原型快速验证 📱 Android 开发者： 提示词生成完整应用，直通 Google Play 🔬 研究人员： Planning 模式适合深度研究和复杂任务分析 十、快速上手指南 下载安装： 访问 antigravity.google/download 下载对应平台版本\n系统要求：\nmacOS：支持 Apple 安全更新的版本（最低 macOS 12 Monterey），不支持 x86 Windows：Windows 10 64位 Linux：glibc \u0026gt;= 2.28（如 Ubuntu 20+, Debian 10+, Fedora 36+） 登录 Google 账户 即可开始使用\n公测期间个人免费，直接上手体验\n⚠️ 注意事项：\n国内使用需要解决网络问题 需要 Google 账户 稳定性仍在持续优化中 建议搭配其他 AI 编程工具作为兜底方案 总结 从 1.0 到 2.0，Antigravity 已经从一个 AI 编程工具进化为 通用智能体工作平台。多智能体并行、定时任务、Artifacts 交付、浏览器子代理、丰富的自定义能力——这套组合拳把「写代码」这件事从体力活，往自动化、流程化又推了一大步。\nAI 不会淘汰程序员，但 不会用 AI 的程序员 会被淘汰。Antigravity 2.0 值得每个开发者认真体验。\n🔗 相关链接： 官网 · 下载 · 官方教程 · Skills 开放标准\n","permalink":"https://blog.zdltech.com/posts/google-antigravity-2-deep-dive/","summary":"\u003cp\u003e2026年5月，谷歌I/O大会重磅发布\u003c/p\u003e\n\u003cp\u003e📌 \u003cstrong\u003e官网地址：\u003c/strong\u003e antigravity.google\u003c/p\u003e\n\u003cp\u003e📥 \u003cstrong\u003e下载地址：\u003c/strong\u003e antigravity.google/download\u003c/p\u003e\n\u003cp\u003e📚 \u003cstrong\u003e官方教程：\u003c/strong\u003e Getting Started 教程\u003c/p\u003e\n\u003ch2 id=\"一antigravity-是什么\"\u003e一、Antigravity 是什么？\u003c/h2\u003e\n\u003cp\u003e2025年11月，谷歌随 Gemini 3 一同发布了 \u003cstrong\u003eAntigravity\u003c/strong\u003e——一个「Agent 优先」的敏捷开发平台。它基于 VS Code 内核重构，整合了谷歌以 \u003cstrong\u003e24亿美元\u003c/strong\u003e 收购的 Windsurf 团队技术，将 IDE 从「AI 辅助编码」推进到 \u003cstrong\u003e「Agent 自主执行 + 开发者审核」\u003c/strong\u003e 的新范式。\u003c/p\u003e\n\u003cp\u003e简单来说：传统 AI 工具是帮你写代码，Antigravity 是 AI 帮你 \u003cstrong\u003e规划、编码、测试、运行\u003c/strong\u003e，你只负责审核和决策。\u003c/p\u003e\n\u003cp\u003e2026年5月的谷歌 I/O 大会上，谷歌发布了 \u003cstrong\u003eAntigravity 2.0\u003c/strong\u003e，定位从「开发者的 AI IDE」全面升级为 \u003cstrong\u003e「通用智能体优先工作平台」\u003c/strong\u003e，可以作为统一中枢管理多个数字智能体。\u003c/p\u003e\n\u003cp\u003e💡 \u003cstrong\u003e核心理念：\u003c/strong\u003e 「Agent 做事，开发者审核」——Agent 不仅能写代码，还能启动应用、在浏览器中测试、验证功能是否正常。通过 Tasks 和 Artifacts 进行更高层次的沟通。\u003c/p\u003e\n\u003ch2 id=\"二antigravity-20-核心更新\"\u003e二、Antigravity 2.0 核心更新\u003c/h2\u003e\n\u003ch3 id=\"1-多智能体协同\"\u003e1️⃣ 多智能体协同\u003c/h3\u003e\n\u003cp\u003eAntigravity 2.0 最大的亮点之一是 \u003cstrong\u003e多智能体并行\u003c/strong\u003e。你可以同时部署多个子智能体，分别处理不同的编程任务，互不干扰，多任务并行效率大幅提升。\u003c/p\u003e\n\u003cp\u003e以前开发需求要等一个任务完成才能开始下一个，中间只能盯着屏幕发呆。现在，你可以在 Agent Manager 中同时跑多个 Agent，在不同工作区处理多个不同任务，真正解放双手。\u003c/p\u003e","title":"谷歌 Antigravity 2.0 深度解读：从 AI 编程工具到通用智能体工作平台"},{"content":" 在最近的一次项目中，使用split方法分割字符串后得到的数组与预期不符。\n查找原因后发现，使用默认的split方法时，会默认丢弃字符串末尾的空值，而字符串中间的空值则\u0026gt;会作为数组中的一项数据，不会被丢弃。\n查询相关资料得知java中的split方法有两个参数，第一个参数是被分割的字符串，第二个参数则是一个int值，此值默认为0，丢弃末尾空数据。\n而当第二个参数值大于0时，代表分割字符串后数组的最大长度，当它小于0时，代表获取数组所有值，不会丢弃末尾空值。\n`String a=\u0026#34;a,\u0026#34;; String[] charsArr=a.split(\u0026#34;,\u0026#34;); System.out.println(charsArr.length); 代码输出的是1 ` `String a=\u0026#34;a,\u0026#34;; String[] charsArr=a.split(\u0026#34;,\u0026#34;,-1); System.out.println(charsArr.length); 代码输出的是2 ` ","permalink":"https://blog.zdltech.com/posts/guan-yujava-zhong-shi-yongsplit-fang-fa-mo-wei-kon/","summary":"\u003cblockquote\u003e\n\u003cp\u003e在最近的一次项目中，使用split方法分割字符串后得到的数组与预期不符。\u003cbr\u003e\n查找原因后发现，使用默认的split方法时，会默认丢弃字符串末尾的空值，而字符串中间的空值则\u0026gt;会作为数组中的一项数据，不会被丢弃。\u003cbr\u003e\n查询相关资料得知java中的split方法有两个参数，第一个参数是被分割的字符串，第二个参数则是一个int值，此值默认为0，丢弃末尾空数据。\u003cbr\u003e\n而当第二个参数值大于0时，代表分割字符串后数组的最大长度，当它小于0时，代表获取数组所有值，不会丢弃末尾空值。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`String a=\u0026#34;a,\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String[] charsArr=a.split(\u0026#34;,\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System.out.println(charsArr.length);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e代码输出的是1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`String a=\u0026#34;a,\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String[] charsArr=a.split(\u0026#34;,\u0026#34;,-1);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System.out.println(charsArr.length);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e代码输出的是2\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"关于java中使用split方法末尾空值被丢弃的问题"},{"content":"网站在部署到服务器的这个过程，有时候会非常麻烦，以前SEO禅都是用FTP或者用rsync命令，现在因为Github私有仓库免费了，就直接使用Git来部署，修改后的源码只要Push到仓库里，再在服务器Pull下来，别说有多方便有多爽了，要是再使用Docker去部署服务器程序，那就是分分种搞定网站部署的事，以前要部署一个网站少说要个把小时，这篇文章主要是分享下在阿里云的ECS服务器如何更新Git到2.x版本。\n更新方法 默认在Centos上使用YUM命令安装的Git版本是1.8x，在使用的时候会有些问题，有很多种更新办法，这里只分享最简单方便的一种，先运行如下命令看看Git的版本信息：\n`git --version git version 1.8.3.1 ` 如果这不是你想要的版本，那我们第一步要做的就是先移除Git，运行如下命令：\n`sudo yum remove git* ` 之后安装相关的RPM仓库，运行如下命令：\n`sudo yum -y install https://packages.endpoint.com/rhel/7/os/x86_64/endpoint-repo-1.7-1.x86_64.rpm ` 再重新安装一遍Git，运行如下命令：\n`sudo yum install git ` 当出现提示的时候，输入y，完成安装\n再看看安装后的Git版本：\n`git --version ` ","permalink":"https://blog.zdltech.com/posts/%E5%9C%A8centos7%E4%B8%8A%E4%BD%BF%E7%94%A8yum%E5%8D%87%E7%BA%A7%E6%9B%B4%E6%96%B0git%E7%89%88%E6%9C%ACgit-2-x/","summary":"\u003cp\u003e网站在部署到服务器的这个过程，有时候会非常麻烦，以前SEO禅都是用FTP或者用rsync命令，现在因为Github私有仓库免费了，就直接使用Git来部署，修改后的源码只要Push到仓库里，再在服务器Pull下来，别说有多方便有多爽了，要是再使用Docker去部署服务器程序，那就是分分种搞定网站部署的事，以前要部署一个网站少说要个把小时，这篇文章主要是分享下在阿里云的ECS服务器如何更新Git到2.x版本。\u003c/p\u003e\n\u003ch3 id=\"更新方法\"\u003e更新方法\u003c/h3\u003e\n\u003cp\u003e默认在Centos上使用YUM命令安装的Git版本是1.8x，在使用的时候会有些问题，有很多种更新办法，这里只分享最简单方便的一种，先运行如下命令看看Git的版本信息：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`git --version\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit version 1.8.3.1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e如果这不是你想要的版本，那我们第一步要做的就是先移除Git，运行如下命令：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`sudo yum remove git*\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e之后安装相关的RPM仓库，运行如下命令：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`sudo yum -y install https://packages.endpoint.com/rhel/7/os/x86_64/endpoint-repo-1.7-1.x86_64.rpm\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e再重新安装一遍Git，运行如下命令：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`sudo yum install git\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e当出现提示的时候，输入y，完成安装\u003cbr\u003e\n再看看安装后的Git版本：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`git --version\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"在Centos7上使用YUM升级更新Git版本(Git 2.x )"},{"content":"ab安装 ab 是什么？\nApache Benchmark(简称ab) 是Apache安装包中自带的压力测试工具 ，简单易用。 使用起来非常的简单和方便。\n安装ab 可以通过安装apche web服务器，apache web服务器默认带有ab命令 centOS7 下的安装yum -y install httpd-tools 使用 `#使用：-n 表示请求数，-c 表示并发数. ab -n 100 -c 10 http://www.baidu.com/s #返回内容： ​ Server Software: BWS/1.1 ##服务器软件和版本 Server Hostname: www.baidu.com ##请求的地址/域名 Server Port: 80 ##端口 Document Path: /s ##请求的路径 Document Length: 112435 bytes ##页面数据/返回的数据量 Concurrency Level: 10 ##并发数 Time taken for tests: 4.764 seconds ##共使用了多少时间 Complete requests: 100 ##请求数 Failed requests: 99 ##失败请求 百度为什么失败这么多，应该是百度做了防范 (Connect: 0, Receive: 0, Length: 99, Exceptions: 0) Total transferred: 11342771 bytes ##总共传输字节数，包含http的头信息等 HTML transferred: 11247622 bytes ##html字节数，实际的页面传递字节数 Requests per second: 20.99 [#/sec] (mean) ##每秒多少请求，这个是非常重要的参数数值，服务器的吞吐量 Time per request: 476.427 [ms] (mean) ##用户平均请求等待时间 Time per request: 47.643 [ms] (mean, across all concurrent requests) ##服务器平均处理时间，也就是服务器吞吐量的倒数 Transfer rate: 2325.00 [Kbytes/sec] received ##每秒获取的数据长度 ​ Connection Times (ms) min mean[+/-sd] median max Connect: 22 41 12.4 39 82 ##连接的最小时间，平均值，中值，最大值 Processing: 113 386 211.1 330 1246 ##处理时间 Waiting: 25 80 43.9 73 266 ##等待时间 Total: 152 427 210.1 373 1283 ##合计时间 ​ Percentage of the requests served within a certain time (ms) 50% 373 ## 50%的请求在373ms内返回 66% 400 ## 60%的请求在400ms内返回 75% 426 80% 465 90% 761 95% 930 98% 1192 99% 1283 100% 1283 (longest request) ` 参数介绍 `-n 即requests，用于指定压力测试总共的执行次数。 -c 即concurrency，用于指定的并发数。 -t 即timelimit，等待响应的最大时间(单位：秒)。 -b 即windowsize，TCP发送/接收的缓冲大小(单位：字节)。 -p 即postfile，发送POST请求时需要上传的文件，此外还必须设置-T参数。 -u 即putfile，发送PUT请求时需要上传的文件，此外还必须设置-T参数。 -T 即content-type，用于设置Content-Type请求头信息，例如：application/x-www-form-urlencoded，默认值为text/plain。 -v 即verbosity，指定打印帮助信息的冗余级别。 -w 以HTML表格形式打印结果。 -i 使用HEAD请求代替GET请求。 -x 插入字符串作为table标签的属性。 -y 插入字符串作为tr标签的属性。 -z 插入字符串作为td标签的属性。 -C 添加cookie信息，例如：\u0026#34;Apache=1234\u0026#34;(可以重复该参数选项以添加多个)。 -H 添加任意的请求头，例如：\u0026#34;Accept-Encoding: gzip\u0026#34;，请求头将会添加在现有的多个请求头之后(可以重复该参数选项以添加多个)。 -A 添加一个基本的网络认证信息，用户名和密码之间用英文冒号隔开。 -P 添加一个基本的代理认证信息，用户名和密码之间用英文冒号隔开。 -X 指定使用的和端口号，例如:\u0026#34;126.10.10.3:88\u0026#34;。 -V 打印版本号并退出。 -k 使用HTTP的KeepAlive特性。 -d 不显示百分比。 -S 不显示预估和警告信息。 -g 输出结果信息到gnuplot格式的文件中。 -e 输出结果信息到CSV格式的文件中。 -r 指定接收到错误信息时不退出程序。 -h 显示用法信息，其实就是ab -help。 ` ","permalink":"https://blog.zdltech.com/posts/ab%E5%91%BD%E4%BB%A4%E4%BD%BF%E7%94%A8/","summary":"\u003ch1 id=\"ab安装\"\u003eab安装\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003eab 是什么？\u003cbr\u003e\nApache Benchmark(简称ab) 是Apache安装包中自带的压力测试工具 ，简单易用。 使用起来非常的简单和方便。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"安装ab\"\u003e安装ab\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003col\u003e\n\u003cli\u003e可以通过安装apche web服务器，apache web服务器默认带有ab命令\u003c/li\u003e\n\u003cli\u003ecentOS7 下的安装yum -y install httpd-tools\u003c/li\u003e\n\u003c/ol\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"使用\"\u003e使用\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`#使用：-n 表示请求数，-c 表示并发数.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eab -n 100 -c 10 http://www.baidu.com/s\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#返回内容：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e​\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eServer Software:        BWS/1.1   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##服务器软件和版本\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eServer Hostname:        www.baidu.com  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##请求的地址/域名\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eServer Port:            80   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##端口\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eDocument Path:          /s  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##请求的路径\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eDocument Length:        112435 bytes  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##页面数据/返回的数据量\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eConcurrency Level:      10   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##并发数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eTime taken for tests:   4.764 seconds  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##共使用了多少时间 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eComplete requests:      100  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##请求数 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eFailed requests:        99  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##失败请求  百度为什么失败这么多，应该是百度做了防范  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   (Connect: 0, Receive: 0, Length: 99, Exceptions: 0)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eTotal transferred:      11342771 bytes  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##总共传输字节数，包含http的头信息等 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eHTML transferred:       11247622 bytes  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##html字节数，实际的页面传递字节数 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eRequests per second:    20.99 [#/sec] (mean) \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e ##每秒多少请求，这个是非常重要的参数数值，服务器的吞吐量 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eTime per request:       476.427 [ms] (mean)   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##用户平均请求等待时间 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eTime per request:       47.643 [ms] (mean, across all concurrent requests)  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##服务器平均处理时间，也就是服务器吞吐量的倒数 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eTransfer rate:          2325.00 [Kbytes/sec] received\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e ##每秒获取的数据长度\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e​\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eConnection Times (ms)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              min  mean[+/-sd] median   max\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eConnect:       22   41  12.4     39      82\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##连接的最小时间，平均值，中值，最大值\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eProcessing:   113  386 211.1    330    1246\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##处理时间\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWaiting:       25   80  43.9     73     266\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##等待时间\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eTotal:        152  427 210.1    373    1283\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e##合计时间\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e​\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ePercentage of the requests served within a certain time (ms)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  50%    373   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e## 50%的请求在373ms内返回 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  66%    400   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e## 60%的请求在400ms内返回 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  75%    426\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  80%    465\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  90%    761\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  95%    930\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  98%   1192\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  99%   1283\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e 100%   1283 (longest request)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"参数介绍\"\u003e\u003cstrong\u003e参数介绍\u003c/strong\u003e\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`-n  即requests，用于指定压力测试总共的执行次数。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-c  即concurrency，用于指定的并发数。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-t  即timelimit，等待响应的最大时间(单位：秒)。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-b  即windowsize，TCP发送/接收的缓冲大小(单位：字节)。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-p  即postfile，发送POST请求时需要上传的文件，此外还必须设置-T参数。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-u  即putfile，发送PUT请求时需要上传的文件，此外还必须设置-T参数。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-T  即content-type，用于设置Content-Type请求头信息，例如：application/x-www-form-urlencoded，默认值为text/plain。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-v  即verbosity，指定打印帮助信息的冗余级别。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-w  以HTML表格形式打印结果。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-i  使用HEAD请求代替GET请求。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-x  插入字符串作为table标签的属性。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-y  插入字符串作为tr标签的属性。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-z  插入字符串作为td标签的属性。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-C  添加cookie信息，例如：\u0026#34;Apache=1234\u0026#34;(可以重复该参数选项以添加多个)。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-H  添加任意的请求头，例如：\u0026#34;Accept-Encoding: gzip\u0026#34;，请求头将会添加在现有的多个请求头之后(可以重复该参数选项以添加多个)。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-A  添加一个基本的网络认证信息，用户名和密码之间用英文冒号隔开。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-P  添加一个基本的代理认证信息，用户名和密码之间用英文冒号隔开。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-X  指定使用的和端口号，例如:\u0026#34;126.10.10.3:88\u0026#34;。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-V  打印版本号并退出。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-k  使用HTTP的KeepAlive特性。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-d  不显示百分比。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-S  不显示预估和警告信息。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-g  输出结果信息到gnuplot格式的文件中。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-e  输出结果信息到CSV格式的文件中。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-r  指定接收到错误信息时不退出程序。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-h  显示用法信息，其实就是ab -help。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"ab命令使用"},{"content":"1、横向流程图源码格式（mermaid） graph LR A[方形] --\u0026gt;B(圆角) B --\u0026gt; C{条件a} C --\u0026gt;|a=1| D[结果1] C --\u0026gt;|a=2| E[结果2] A--\u0026gt;F[横向流程图] G[横向流程图]\n例如 graph LR A[方形] --\u0026amp;gt; B(圆角) B --\u0026amp;gt; C{条件a} C --\u0026amp;gt; |a=1| D[结果1] C --\u0026amp;gt; |a==2| E[结果2] A --\u0026amp;gt; F[横向流程图] G[横向流程图]\n### 2、竖向流程图源码格式（mermaid） \u0026gt; ``` `graph TD A[方形] --\u0026gt; B(圆角) B --\u0026gt; C{条件a} C --\u0026gt; |a=1| D[结果1] C --\u0026gt; |a=2| E[结果2] A --\u0026gt; F[竖向流程图]` 例如：\n`graph TD A[方形] --\u0026amp;gt; B(圆角) B --\u0026amp;gt; C{条件a} C --\u0026amp;gt; |a=1| D[结果1] C --\u0026amp;gt; |a=2| E[结果2] A --\u0026amp;gt; F[竖向流程图] ` 3、标准流程图源码格式（flow) st=\u0026gt;start: 开始框:\u0026gt;https://www.baidu.com op=\u0026gt;operation: 处理框 cond=\u0026gt;condition: 判断框（是或否？） sub1=subroutine: 子流程 io=\u0026gt;inputoutput: 输入输出框 e=\u0026gt;end: 结束框 st-\u0026gt;op-\u0026gt;cond cond(yes)-\u0026gt;io-\u0026gt;e cond(no)-\u0026gt;sub1(right)-\u0026gt;op 例如：\n`st=\u0026amp;gt;start: 开始框:\u0026amp;gt;http://www.baidu.com op=\u0026amp;gt;operation: 处理框 cond=\u0026amp;gt;condition: 判断框（是或否？） sub1=\u0026amp;gt;subroutine: 子流程 io=\u0026amp;gt;inputoutput: 输入输出框 e=\u0026amp;gt;end: 结束框 st-\u0026amp;gt;op-\u0026amp;gt;cond cond(yes)-\u0026amp;gt;io-\u0026amp;gt;e cond(no)-\u0026amp;gt;sub1(right)-\u0026amp;gt;op` 4、标准流程图源码格式（横向）(flow) st=\u0026gt;start: 开始框 op=\u0026gt;operation: 处理框 cond=\u0026gt;condition: 判断框（是或否？） sub1=\u0026gt;subroutine: 子流程 io=\u0026gt;inputoutput: 输入输出框 e=\u0026gt;end: 结束 st(right)-\u0026gt;op(right)-\u0026gt;cond cond(yes)-\u0026gt;io(bottom)-\u0026gt;e cond(no)-\u0026gt;sub1(right)-\u0026gt;op 例如：\n`st=\u0026amp;gt;start: 开始 op=\u0026amp;gt;operation: 处理框 cond=\u0026amp;gt;condition: 判断框（是或否？） sub1=\u0026amp;gt;subroutine: 子流程 io=\u0026amp;gt;inputoutput: 输入输出框 e=\u0026amp;gt;end: 结束 st(right)-\u0026amp;gt;op(right)-\u0026amp;gt;cond cond(yes)-\u0026amp;gt;io(bottom)-\u0026amp;gt;e cond(no)-\u0026amp;gt;sub1(right)-\u0026amp;gt;op` 5、UML时序图源码格式（sequence) 对象A-\u0026gt;对象B: 对象B你好吗？（请求） Note right of 对象B: 对象B的描述 Note left of 对象A: 对象A的描述（提示） 对象B--\u0026gt;对象A: 我很好（响应） 对象A-\u0026gt;对象B: 你真的好吗？ 对象B-\u0026gt;对象A: 真的好 例如：\n`对象A-\u0026amp;gt;对象B: 对象B你好吗？(请求) Note right of 对象B: 对象B的描述 Note left of 对象A: 对象A的描述（提示） 对象B--\u0026amp;gt;对象A: 我很好（响应） 对象A-\u0026amp;gt;对象B: 你真的好吗？ 对象B-\u0026amp;gt;对象A: 真的好` 6、UML时序图源码复杂样例（sequence） Title: 标题： 复杂使用 对象A-\u0026gt;对象B: 对象B你好吗？（请求） Note right of 对象B: 对象B的描述 Note left of 对象A: 对象A的描述（提示） 对象B--\u0026gt;对象A: 我很好（响应） 对象B-\u0026gt;小三： 你好吗？ 小三--\u0026gt;\u0026gt;对象A: 对象B找我了 对象A-\u0026gt;对象B: 你真的好吗？ Note over 小三，对象B: 我们是朋友 participant C Note right of C: 没人陪我玩 例如：\n`Title: 标题：复杂使用 对象A-\u0026amp;gt;对象B: 对象B你好吗？（请求） Note right of 对象B: 对象B的描述 Note left of 对象A: 对象A的描述（提示） 对象B--\u0026amp;gt;对象A: 我很好（响应） 对象B-\u0026amp;gt;小三: 你好吗？ 小三--\u0026amp;gt;\u0026amp;gt;对象A: 对象B找我了 对象A-\u0026amp;gt;对象B: 你真的好吗？ Note over 小三,对象B: 我们是朋友 participant C Note right of C: 没人陪我完成` 7、UML标准时序图源码格式（mermaid） %% 时序图例子，-\u0026gt;直线，--\u0026gt;虚线,-\u0026gt;\u0026gt;实线箭头 sequenceDiagram participant 张三 participant 李四 张三-\u0026gt;王五: 王五你好吗？ loop 健康检查 王五-\u0026gt;王五: 与疾病战斗 end Note right of 王五: 合理 食物 看医生\u0026hellip;\n李四--\u0026gt;\u0026gt;张三: 很好！ 王五-\u0026gt;李四: 你怎么样? 李四--\u0026gt;王五: 很好！ 例如：\n`%% 时序图例子， -\u0026amp;gt;直线， --\u0026amp;gt;虚线， -\u0026amp;gt;\u0026amp;gt;实线箭头 sequenceDiagram participant 张三 participant 李四 张三-\u0026amp;gt;王五: 王五你好吗？ loop 健康检查 王五-\u0026amp;gt;王五: 与疾病战斗 end Note right of 王五: 合理 食物 \u0026amp;lt;br/\u0026amp;gt; 看医生... 李四--\u0026amp;gt;\u0026amp;gt;张三: 很好！ 王五-\u0026amp;gt;李四: 你怎么样? 李四--\u0026amp;gt;王五: 很好！ ` 8、甘特图源码样例（mermaid） ​```mermaid %% 语法示例 gantt dateFormat YYYY-MM-DD title 软件开发甘特图 section 设计 需求 :done, des1, 2014-01-06,2014-01-08 原型 :active, des2, 2014-01-09, 3d UI设计 : des3, after des2, 5d 未来任务 : des4, after des3, 5d section 开发 学习准备理解需求 :crit, done, 2014-01-06,24h 设计框架 :crit, done, after des2, 2d 开发 :crit, active, 3d 未来任务 :crit, 5d 耍 :2d section 测试 功能测试 :active, a1, after des3, 3d 压力测试 :after a1 , 20h 测试报告 : 48h ​``` 例如：\n`%% 语法示例 gantt dateFormat YYYY-MM-DD title 软件开发甘特图 section 设计 需求 :done, des1, 2014-01-06,2014-01-08 原型 :active, des2, 2014-01-09, 3d UI设计 : des3, after des2, 5d 未来任务 : des4, after des3, 5d section 开发 学习准备理解需求 :crit, done, 2014-01-06,24h 设计框架 :crit, done, after des2, 2d 开发 :crit, active, 3d 未来任务 :crit, 5d 耍 :2d section 测试 功能测试 :active, a1, after des3, 3d 压力测试 :after a1 , 20h 测试报告 : 48h` 其它说明 1、graph 说明 方向： TB -top bottom\nBT -bottom top\nRL-right left\nTD -top bottom\n节点形状 矩形: [内容]\n圆角矩形：(内容)\n圆形：((内容))\n菱形：{内容}\n旗帜: \u0026gt;内容]\n连接线 实线直线： —\n虚线箭头: -.-\u0026gt;\n虚线实线: -.-\n粗实线箭头: ==\u0026gt;\n粗实线直线：===\n标签 箭头或直线后跟|标签|：A--\u0026gt;|标签|B\n在箭头或直线中打标签：A--标签--\u0026gt;B\n资料 mermaid官网\nhttp://flowchart.js.org/\nhttps://github.com/adrai/flowchart.js\nhttp://cncounter.github.io/flowchart/\nhttps://d3js.org/\n","permalink":"https://blog.zdltech.com/posts/%E7%AE%80%E5%8D%95%E8%AF%A6%E7%BB%86%E7%9A%84typora-%E6%B5%81%E7%A8%8B%E5%9B%BE%E4%BD%BF%E7%94%A8/","summary":"\u003ch3 id=\"1横向流程图源码格式mermaid\"\u003e1、横向流程图源码格式（mermaid）\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003ccode\u003egraph LR A[方形] --\u0026gt;B(圆角) B --\u0026gt; C{条件a} C --\u0026gt;|a=1| D[结果1] C --\u0026gt;|a=2| E[结果2] A--\u0026gt;F[横向流程图] G[横向流程图]\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e例如\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003egraph LR A[方形] --\u0026amp;gt; B(圆角) B --\u0026amp;gt; C{条件a} C --\u0026amp;gt; |a=1| D[结果1] C --\u0026amp;gt; |a==2| E[结果2] A --\u0026amp;gt; F[横向流程图] G[横向流程图]\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e### 2、竖向流程图源码格式（mermaid）\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`graph TD\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eA[方形] --\u0026gt; B(圆角)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    B --\u0026gt; C{条件a}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    C --\u0026gt; |a=1| D[结果1]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    C --\u0026gt; |a=2| E[结果2]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    A --\u0026gt; F[竖向流程图]`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e例如：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`graph TD\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eA[方形] --\u0026amp;gt; B(圆角)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    B --\u0026amp;gt; C{条件a}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    C --\u0026amp;gt; |a=1| D[结果1]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    C --\u0026amp;gt; |a=2| E[结果2]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    A --\u0026amp;gt; F[竖向流程图]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"3标准流程图源码格式flow\"\u003e3、标准流程图源码格式（flow)\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003est=\u0026gt;start: 开始框:\u0026gt;https://www.baidu.com\nop=\u0026gt;operation: 处理框\ncond=\u0026gt;condition: 判断框（是或否？）\nsub1=subroutine: 子流程\nio=\u0026gt;inputoutput: 输入输出框\ne=\u0026gt;end: 结束框\nst-\u0026gt;op-\u0026gt;cond\ncond(yes)-\u0026gt;io-\u0026gt;e\ncond(no)-\u0026gt;sub1(right)-\u0026gt;op\n\u003c/code\u003e\u003c/pre\u003e\u003c/blockquote\u003e\n\u003cp\u003e例如：\u003c/p\u003e","title":"简单详细的Typora 流程图使用"},{"content":" Typora 流程图 ## Typora 流程图 1、横向流程图源码格式（mermaid） ``` x\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-measure\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026#34;position: relative; z-index: 1;\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-code\u0026#34; role=\u0026#34;presentation\u0026#34; style=\u0026#34;\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-activeline\u0026#34; style=\u0026#34;position: relative;\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-activeline-background CodeMirror-linebackground\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-gutter-background CodeMirror-activeline-gutter\u0026#34; style=\u0026#34;left: 0px; width: 0px;\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span role=\u0026#34;presentation\u0026#34; style=\u0026#34;padding-right: 0.1px;\u0026#34;\u0026gt;graph LR\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;\u0026quot; style=\u0026quot;position: relative;\u0026quot;\u0026gt; ``` A[方形] \u0026ndash;\u0026gt;B(圆角)\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;\u0026#34; style=\u0026#34;position: relative;\u0026#34;\u0026gt; ``` \u0026lt;span role=\u0026#34;presentation\u0026#34; style=\u0026#34;padding-right: 0.1px;\u0026#34;\u0026gt; \u0026amp;nbsp; B --\u0026amp;gt; C{条件a}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;\u0026quot; style=\u0026quot;position: relative;\u0026quot;\u0026gt; ``` C \u0026ndash;\u0026gt;|a=1| D[结果1]\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;\u0026#34; style=\u0026#34;position: relative;\u0026#34;\u0026gt; ``` \u0026lt;span role=\u0026#34;presentation\u0026#34; style=\u0026#34;padding-right: 0.1px;\u0026#34;\u0026gt; \u0026amp;nbsp; C --\u0026amp;gt;|a=2| E[结果2]\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;\u0026quot; style=\u0026quot;position: relative;\u0026quot;\u0026gt; ``` A\u0026ndash;\u0026gt;F[横向流程图]\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;\u0026#34; style=\u0026#34;position: relative;\u0026#34;\u0026gt; ``` \u0026lt;span role=\u0026#34;presentation\u0026#34; style=\u0026#34;padding-right: 0.1px;\u0026#34;\u0026gt; \u0026amp;nbsp; G[横向流程图]\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 140px;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;CodeMirror-gutters\u0026quot; style=\u0026quot;display: none; height: 140px;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; 例如\n\u0026lt;g\u0026gt;\u0026lt;g class=\u0026quot;output\u0026quot;\u0026gt;\u0026lt;g class=\u0026quot;clusters\u0026quot;\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;g class=\u0026quot;edgePaths\u0026quot;\u0026gt;\u0026lt;g class=\u0026quot;edgePath LS-A LE-B\u0026quot; id=\u0026quot;L-A-B\u0026quot; style=\u0026quot;opacity: 1;\u0026quot;\u0026gt; \u0026lt;g class=\u0026quot;edgeLabel\u0026quot; transform=\u0026quot;\u0026quot; style=\u0026quot;opacity: 1;\u0026quot;\u0026gt;\u0026lt;g transform=\u0026quot;translate(0,0)\u0026quot; class=\u0026quot;label\u0026quot;\u0026gt;\u0026lt;rect rx=\u0026quot;0\u0026quot; ry=\u0026quot;0\u0026quot; width=\u0026quot;0\u0026quot; height=\u0026quot;0\u0026quot;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;foreignobject width=\u0026quot;0\u0026quot; height=\u0026quot;0\u0026quot;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; \u0026lt;g class=\u0026quot;edgeLabel\u0026quot; transform=\u0026quot;translate(444.6546859741211,30.5)\u0026quot; style=\u0026quot;opacity: 1;\u0026quot;\u0026gt;\u0026lt;g transform=\u0026quot;translate(-12.59375,-12.5)\u0026quot; class=\u0026quot;label\u0026quot;\u0026gt;\u0026lt;rect rx=\u0026quot;0\u0026quot; ry=\u0026quot;0\u0026quot; width=\u0026quot;25.1875\u0026quot; height=\u0026quot;25\u0026quot;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;foreignobject width=\u0026quot;25.1875\u0026quot; height=\u0026quot;25\u0026quot;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; a=1 \u0026lt;g class=\u0026quot;edgeLabel\u0026quot; transform=\u0026quot;translate(444.6546859741211,125.5)\u0026quot; style=\u0026quot;opacity: 1;\u0026quot;\u0026gt;\u0026lt;g transform=\u0026quot;translate(-16.7890625,-12.5)\u0026quot; class=\u0026quot;label\u0026quot;\u0026gt;\u0026lt;rect rx=\u0026quot;0\u0026quot; ry=\u0026quot;0\u0026quot; width=\u0026quot;33.578125\u0026quot; height=\u0026quot;25\u0026quot;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;foreignobject width=\u0026quot;33.578125\u0026quot; height=\u0026quot;25\u0026quot;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; a==2 \u0026lt;g class=\u0026quot;edgeLabel\u0026quot; transform=\u0026quot;\u0026quot; style=\u0026quot;opacity: 1;\u0026quot;\u0026gt;\u0026lt;g transform=\u0026quot;translate(0,0)\u0026quot; class=\u0026quot;label\u0026quot;\u0026gt;\u0026lt;rect rx=\u0026quot;0\u0026quot; ry=\u0026quot;0\u0026quot; width=\u0026quot;0\u0026quot; height=\u0026quot;0\u0026quot;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;foreignobject width=\u0026quot;0\u0026quot; height=\u0026quot;0\u0026quot;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; \u0026lt;g class=\u0026quot;nodes\u0026quot;\u0026gt;\u0026lt;g class=\u0026quot;node default\u0026quot; id=\u0026quot;flowchart-A-717\u0026quot; transform=\u0026quot;translate(58,125.5)\u0026quot; style=\u0026quot;opacity: 1;\u0026quot;\u0026gt;\u0026lt;rect rx=\u0026quot;0\u0026quot; ry=\u0026quot;0\u0026quot; x=\u0026quot;-26\u0026quot; y=\u0026quot;-22.5\u0026quot; width=\u0026quot;52\u0026quot; height=\u0026quot;45\u0026quot; class=\u0026quot;label-container\u0026quot;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;g class=\u0026quot;label\u0026quot; transform=\u0026quot;translate(0,0)\u0026quot;\u0026gt;\u0026lt;g transform=\u0026quot;translate(-16,-12.5)\u0026quot;\u0026gt;\u0026lt;foreignobject width=\u0026quot;32\u0026quot; height=\u0026quot;25\u0026quot;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; 方形 \u0026lt;g class=\u0026quot;node default\u0026quot; id=\u0026quot;flowchart-B-718\u0026quot; transform=\u0026quot;translate(208,78)\u0026quot; style=\u0026quot;opacity: 1;\u0026quot;\u0026gt;\u0026lt;rect rx=\u0026quot;5\u0026quot; ry=\u0026quot;5\u0026quot; x=\u0026quot;-26\u0026quot; y=\u0026quot;-22.5\u0026quot; width=\u0026quot;52\u0026quot; height=\u0026quot;45\u0026quot; class=\u0026quot;label-container\u0026quot;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;g class=\u0026quot;label\u0026quot; transform=\u0026quot;translate(0,0)\u0026quot;\u0026gt;\u0026lt;g transform=\u0026quot;translate(-16,-12.5)\u0026quot;\u0026gt;\u0026lt;foreignobject width=\u0026quot;32\u0026quot; height=\u0026quot;25\u0026quot;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; 圆角 \u0026lt;g class=\u0026quot;node default\u0026quot; id=\u0026quot;flowchart-C-720\u0026quot; transform=\u0026quot;translate(355.43281173706055,78)\u0026quot; style=\u0026quot;opacity: 1;\u0026quot;\u0026gt; 条件a \u0026lt;g class=\u0026quot;node default\u0026quot; id=\u0026quot;flowchart-D-722\u0026quot; transform=\u0026quot;translate(516.6390609741211,30.5)\u0026quot; style=\u0026quot;opacity: 1;\u0026quot;\u0026gt;\u0026lt;rect rx=\u0026quot;0\u0026quot; ry=\u0026quot;0\u0026quot; x=\u0026quot;-30.1953125\u0026quot; y=\u0026quot;-22.5\u0026quot; width=\u0026quot;60.390625\u0026quot; height=\u0026quot;45\u0026quot; class=\u0026quot;label-container\u0026quot;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;g class=\u0026quot;label\u0026quot; transform=\u0026quot;translate(0,0)\u0026quot;\u0026gt;\u0026lt;g transform=\u0026quot;translate(-20.1953125,-12.5)\u0026quot;\u0026gt;\u0026lt;foreignobject width=\u0026quot;40.390625\u0026quot; height=\u0026quot;25\u0026quot;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; 结果1 \u0026lt;g class=\u0026quot;node default\u0026quot; id=\u0026quot;flowchart-E-724\u0026quot; transform=\u0026quot;translate(516.6390609741211,125.5)\u0026quot; style=\u0026quot;opacity: 1;\u0026quot;\u0026gt;\u0026lt;rect rx=\u0026quot;0\u0026quot; ry=\u0026quot;0\u0026quot; x=\u0026quot;-30.1953125\u0026quot; y=\u0026quot;-22.5\u0026quot; width=\u0026quot;60.390625\u0026quot; height=\u0026quot;45\u0026quot; class=\u0026quot;label-container\u0026quot;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;g class=\u0026quot;label\u0026quot; transform=\u0026quot;translate(0,0)\u0026quot;\u0026gt;\u0026lt;g transform=\u0026quot;translate(-20.1953125,-12.5)\u0026quot;\u0026gt;\u0026lt;foreignobject width=\u0026quot;40.390625\u0026quot; height=\u0026quot;25\u0026quot;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; 结果2 \u0026lt;g class=\u0026quot;node default\u0026quot; id=\u0026quot;flowchart-F-726\u0026quot; transform=\u0026quot;translate(208,173)\u0026quot; style=\u0026quot;opacity: 1;\u0026quot;\u0026gt;\u0026lt;rect rx=\u0026quot;0\u0026quot; ry=\u0026quot;0\u0026quot; x=\u0026quot;-50\u0026quot; y=\u0026quot;-22.5\u0026quot; width=\u0026quot;100\u0026quot; height=\u0026quot;45\u0026quot; class=\u0026quot;label-container\u0026quot;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;g class=\u0026quot;label\u0026quot; transform=\u0026quot;translate(0,0)\u0026quot;\u0026gt;\u0026lt;g transform=\u0026quot;translate(-40,-12.5)\u0026quot;\u0026gt;\u0026lt;foreignobject width=\u0026quot;80\u0026quot; height=\u0026quot;25\u0026quot;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; 横向流程图 \u0026lt;g class=\u0026quot;node default\u0026quot; id=\u0026quot;flowchart-G-727\u0026quot; transform=\u0026quot;translate(58,220.5)\u0026quot; style=\u0026quot;opacity: 1;\u0026quot;\u0026gt;\u0026lt;rect rx=\u0026quot;0\u0026quot; ry=\u0026quot;0\u0026quot; x=\u0026quot;-50\u0026quot; y=\u0026quot;-22.5\u0026quot; width=\u0026quot;100\u0026quot; height=\u0026quot;45\u0026quot; class=\u0026quot;label-container\u0026quot;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;g class=\u0026quot;label\u0026quot; transform=\u0026quot;translate(0,0)\u0026quot;\u0026gt;\u0026lt;g transform=\u0026quot;translate(-40,-12.5)\u0026quot;\u0026gt;\u0026lt;foreignobject width=\u0026quot;80\u0026quot; height=\u0026quot;25\u0026quot;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; 横向流程图 2、竖向流程图源码格式（mermaid） ``` xxxxxxxxxx\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-measure\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026#34;position: relative; z-index: 1;\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-code\u0026#34; role=\u0026#34;presentation\u0026#34; style=\u0026#34;\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-activeline\u0026#34; style=\u0026#34;position: relative;\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-activeline-background CodeMirror-linebackground\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-gutter-background CodeMirror-activeline-gutter\u0026#34; style=\u0026#34;left: 0px; width: 0px;\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span role=\u0026#34;presentation\u0026#34; style=\u0026#34;padding-right: 0.1px;\u0026#34;\u0026gt;graph TD\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;\u0026quot; style=\u0026quot;position: relative;\u0026quot;\u0026gt; ``` A[方形] \u0026ndash;\u0026gt; B(圆角)\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;\u0026#34; style=\u0026#34;position: relative;\u0026#34;\u0026gt; ``` \u0026lt;span role=\u0026#34;presentation\u0026#34; style=\u0026#34;padding-right: 0.1px;\u0026#34;\u0026gt; \u0026amp;nbsp; B --\u0026amp;gt; C{条件a}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;\u0026quot; style=\u0026quot;position: relative;\u0026quot;\u0026gt; ``` C \u0026ndash;\u0026gt; |a=1| D[结果1]\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;\u0026#34; style=\u0026#34;position: relative;\u0026#34;\u0026gt; ``` \u0026lt;span role=\u0026#34;presentation\u0026#34; style=\u0026#34;padding-right: 0.1px;\u0026#34;\u0026gt; \u0026amp;nbsp; C --\u0026amp;gt; |a=2| E[结果2]\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;\u0026quot; style=\u0026quot;position: relative;\u0026quot;\u0026gt; ``` A \u0026ndash;\u0026gt; F[竖向流程图]\n\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026#34;position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 120px;\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-gutters\u0026#34; style=\u0026#34;display: none; height: 120px;\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/blockquote\u0026gt; \u0026lt;span\u0026gt;例如：\u0026lt;/span\u0026gt; \u0026lt;div class=\u0026#34;md-diagram-panel\u0026#34;\u0026gt; \u0026lt;svg id=\u0026#34;mermaidChart163\u0026#34; width=\u0026#34;100%\u0026#34; xmlns=\u0026#34;http://www.w3.org/2000/svg\u0026#34; xmlns:xlink=\u0026#34;http://www.w3.org/1999/xlink\u0026#34; height=\u0026#34;420.8656311035156\u0026#34; style=\u0026#34;max-width: 277.391px; height: 460.866px;\u0026#34; viewBox=\u0026#34;0 0 277.390625 420.8656311035156\u0026#34; class=\u0026#34;md-require-zoom-fix\u0026#34;\u0026gt;\u0026lt;/svg\u0026gt; \u0026lt;g\u0026gt;\u0026lt;g class=\u0026#34;output\u0026#34;\u0026gt;\u0026lt;g class=\u0026#34;clusters\u0026#34;\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;g class=\u0026#34;edgePaths\u0026#34;\u0026gt;\u0026lt;g class=\u0026#34;edgePath LS-A LE-B\u0026#34; id=\u0026#34;L-A-B\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt; \u0026lt;/path\u0026gt;\u0026lt;defs\u0026gt;\u0026lt;marker id=\u0026#34;arrowhead894\u0026#34; viewbox=\u0026#34;0 0 10 10\u0026#34; refx=\u0026#34;9\u0026#34; refy=\u0026#34;5\u0026#34; markerunits=\u0026#34;strokeWidth\u0026#34; markerwidth=\u0026#34;8\u0026#34; markerheight=\u0026#34;6\u0026#34; orient=\u0026#34;auto\u0026#34;\u0026gt; \u0026lt;/path\u0026gt;\u0026lt;/marker\u0026gt;\u0026lt;/defs\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;g class=\u0026#34;edgePath LS-B LE-C\u0026#34; id=\u0026#34;L-B-C\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt; \u0026lt;/path\u0026gt;\u0026lt;defs\u0026gt;\u0026lt;marker id=\u0026#34;arrowhead895\u0026#34; viewbox=\u0026#34;0 0 10 10\u0026#34; refx=\u0026#34;9\u0026#34; refy=\u0026#34;5\u0026#34; markerunits=\u0026#34;strokeWidth\u0026#34; markerwidth=\u0026#34;8\u0026#34; markerheight=\u0026#34;6\u0026#34; orient=\u0026#34;auto\u0026#34;\u0026gt; \u0026lt;/path\u0026gt;\u0026lt;/marker\u0026gt;\u0026lt;/defs\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;g class=\u0026#34;edgePath LS-C LE-D\u0026#34; id=\u0026#34;L-C-D\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt; \u0026lt;/path\u0026gt;\u0026lt;defs\u0026gt;\u0026lt;marker id=\u0026#34;arrowhead896\u0026#34; viewbox=\u0026#34;0 0 10 10\u0026#34; refx=\u0026#34;9\u0026#34; refy=\u0026#34;5\u0026#34; markerunits=\u0026#34;strokeWidth\u0026#34; markerwidth=\u0026#34;8\u0026#34; markerheight=\u0026#34;6\u0026#34; orient=\u0026#34;auto\u0026#34;\u0026gt; \u0026lt;/path\u0026gt;\u0026lt;/marker\u0026gt;\u0026lt;/defs\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;g class=\u0026#34;edgePath LS-C LE-E\u0026#34; id=\u0026#34;L-C-E\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt; \u0026lt;/path\u0026gt;\u0026lt;defs\u0026gt;\u0026lt;marker id=\u0026#34;arrowhead897\u0026#34; viewbox=\u0026#34;0 0 10 10\u0026#34; refx=\u0026#34;9\u0026#34; refy=\u0026#34;5\u0026#34; markerunits=\u0026#34;strokeWidth\u0026#34; markerwidth=\u0026#34;8\u0026#34; markerheight=\u0026#34;6\u0026#34; orient=\u0026#34;auto\u0026#34;\u0026gt; \u0026lt;/path\u0026gt;\u0026lt;/marker\u0026gt;\u0026lt;/defs\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;g class=\u0026#34;edgePath LS-A LE-F\u0026#34; id=\u0026#34;L-A-F\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt; \u0026lt;/path\u0026gt;\u0026lt;defs\u0026gt;\u0026lt;marker id=\u0026#34;arrowhead898\u0026#34; viewbox=\u0026#34;0 0 10 10\u0026#34; refx=\u0026#34;9\u0026#34; refy=\u0026#34;5\u0026#34; markerunits=\u0026#34;strokeWidth\u0026#34; markerwidth=\u0026#34;8\u0026#34; markerheight=\u0026#34;6\u0026#34; orient=\u0026#34;auto\u0026#34;\u0026gt; \u0026lt;/path\u0026gt;\u0026lt;/marker\u0026gt;\u0026lt;/defs\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;g class=\u0026#34;edgeLabels\u0026#34;\u0026gt;\u0026lt;g class=\u0026#34;edgeLabel\u0026#34; transform=\u0026#34;\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt;\u0026lt;g transform=\u0026#34;translate(0,0)\u0026#34; class=\u0026#34;label\u0026#34;\u0026gt;\u0026lt;rect rx=\u0026#34;0\u0026#34; ry=\u0026#34;0\u0026#34; width=\u0026#34;0\u0026#34; height=\u0026#34;0\u0026#34;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;foreignobject width=\u0026#34;0\u0026#34; height=\u0026#34;0\u0026#34;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; \u0026lt;div xmlns=\u0026#34;http://www.w3.org/1999/xhtml\u0026#34; style=\u0026#34;display: inline-block; white-space: nowrap;\u0026#34;\u0026gt; \u0026lt;span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;g class=\u0026#34;edgeLabel\u0026#34; transform=\u0026#34;\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt;\u0026lt;g transform=\u0026#34;translate(0,0)\u0026#34; class=\u0026#34;label\u0026#34;\u0026gt;\u0026lt;rect rx=\u0026#34;0\u0026#34; ry=\u0026#34;0\u0026#34; width=\u0026#34;0\u0026#34; height=\u0026#34;0\u0026#34;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;foreignobject width=\u0026#34;0\u0026#34; height=\u0026#34;0\u0026#34;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; \u0026lt;div xmlns=\u0026#34;http://www.w3.org/1999/xhtml\u0026#34; style=\u0026#34;display: inline-block; white-space: nowrap;\u0026#34;\u0026gt; \u0026lt;span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;g class=\u0026#34;edgeLabel\u0026#34; transform=\u0026#34;translate(38.1953125,330.3656234741211)\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt;\u0026lt;g transform=\u0026#34;translate(-12.59375,-12.5)\u0026#34; class=\u0026#34;label\u0026#34;\u0026gt;\u0026lt;rect rx=\u0026#34;0\u0026#34; ry=\u0026#34;0\u0026#34; width=\u0026#34;25.1875\u0026#34; height=\u0026#34;25\u0026#34;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;foreignobject width=\u0026#34;25.1875\u0026#34; height=\u0026#34;25\u0026#34;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; \u0026lt;div xmlns=\u0026#34;http://www.w3.org/1999/xhtml\u0026#34; style=\u0026#34;display: inline-block; white-space: nowrap;\u0026#34;\u0026gt; \u0026lt;span\u0026gt;a=1\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;g class=\u0026#34;edgeLabel\u0026#34; transform=\u0026#34;translate(148.5859375,330.3656234741211)\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt;\u0026lt;g transform=\u0026#34;translate(-12.59375,-12.5)\u0026#34; class=\u0026#34;label\u0026#34;\u0026gt;\u0026lt;rect rx=\u0026#34;0\u0026#34; ry=\u0026#34;0\u0026#34; width=\u0026#34;25.1875\u0026#34; height=\u0026#34;25\u0026#34;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;foreignobject width=\u0026#34;25.1875\u0026#34; height=\u0026#34;25\u0026#34;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; \u0026lt;div xmlns=\u0026#34;http://www.w3.org/1999/xhtml\u0026#34; style=\u0026#34;display: inline-block; white-space: nowrap;\u0026#34;\u0026gt; \u0026lt;span\u0026gt;a=2\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;g class=\u0026#34;edgeLabel\u0026#34; transform=\u0026#34;\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt;\u0026lt;g transform=\u0026#34;translate(0,0)\u0026#34; class=\u0026#34;label\u0026#34;\u0026gt;\u0026lt;rect rx=\u0026#34;0\u0026#34; ry=\u0026#34;0\u0026#34; width=\u0026#34;0\u0026#34; height=\u0026#34;0\u0026#34;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;foreignobject width=\u0026#34;0\u0026#34; height=\u0026#34;0\u0026#34;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; \u0026lt;div xmlns=\u0026#34;http://www.w3.org/1999/xhtml\u0026#34; style=\u0026#34;display: inline-block; white-space: nowrap;\u0026#34;\u0026gt; \u0026lt;span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;g class=\u0026#34;nodes\u0026#34;\u0026gt;\u0026lt;g class=\u0026#34;node default\u0026#34; id=\u0026#34;flowchart-A-1548\u0026#34; transform=\u0026#34;translate(156.390625,30.5)\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt;\u0026lt;rect rx=\u0026#34;0\u0026#34; ry=\u0026#34;0\u0026#34; x=\u0026#34;-26\u0026#34; y=\u0026#34;-22.5\u0026#34; width=\u0026#34;52\u0026#34; height=\u0026#34;45\u0026#34; class=\u0026#34;label-container\u0026#34;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;g class=\u0026#34;label\u0026#34; transform=\u0026#34;translate(0,0)\u0026#34;\u0026gt;\u0026lt;g transform=\u0026#34;translate(-16,-12.5)\u0026#34;\u0026gt;\u0026lt;foreignobject width=\u0026#34;32\u0026#34; height=\u0026#34;25\u0026#34;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; \u0026lt;div xmlns=\u0026#34;http://www.w3.org/1999/xhtml\u0026#34; style=\u0026#34;display: inline-block; white-space: nowrap;\u0026#34;\u0026gt; 方形 \u0026lt;/div\u0026gt; \u0026lt;g class=\u0026#34;node default\u0026#34; id=\u0026#34;flowchart-B-1549\u0026#34; transform=\u0026#34;translate(93.390625,125.5)\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt;\u0026lt;rect rx=\u0026#34;5\u0026#34; ry=\u0026#34;5\u0026#34; x=\u0026#34;-26\u0026#34; y=\u0026#34;-22.5\u0026#34; width=\u0026#34;52\u0026#34; height=\u0026#34;45\u0026#34; class=\u0026#34;label-container\u0026#34;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;g class=\u0026#34;label\u0026#34; transform=\u0026#34;translate(0,0)\u0026#34;\u0026gt;\u0026lt;g transform=\u0026#34;translate(-16,-12.5)\u0026#34;\u0026gt;\u0026lt;foreignobject width=\u0026#34;32\u0026#34; height=\u0026#34;25\u0026#34;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; \u0026lt;div xmlns=\u0026#34;http://www.w3.org/1999/xhtml\u0026#34; style=\u0026#34;display: inline-block; white-space: nowrap;\u0026#34;\u0026gt; 圆角 \u0026lt;/div\u0026gt; \u0026lt;g class=\u0026#34;node default\u0026#34; id=\u0026#34;flowchart-C-1551\u0026#34; transform=\u0026#34;translate(93.390625,245.43281173706055)\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt; \u0026lt;/polygon\u0026gt;\u0026lt;g class=\u0026#34;label\u0026#34; transform=\u0026#34;translate(0,0)\u0026#34;\u0026gt;\u0026lt;g transform=\u0026#34;translate(-20.203125,-12.5)\u0026#34;\u0026gt;\u0026lt;foreignobject width=\u0026#34;40.40625\u0026#34; height=\u0026#34;25\u0026#34;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; \u0026lt;div xmlns=\u0026#34;http://www.w3.org/1999/xhtml\u0026#34; style=\u0026#34;display: inline-block; white-space: nowrap;\u0026#34;\u0026gt; 条件a \u0026lt;/div\u0026gt; \u0026lt;g class=\u0026#34;node default\u0026#34; id=\u0026#34;flowchart-D-1553\u0026#34; transform=\u0026#34;translate(38.1953125,390.3656234741211)\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt;\u0026lt;rect rx=\u0026#34;0\u0026#34; ry=\u0026#34;0\u0026#34; x=\u0026#34;-30.1953125\u0026#34; y=\u0026#34;-22.5\u0026#34; width=\u0026#34;60.390625\u0026#34; height=\u0026#34;45\u0026#34; class=\u0026#34;label-container\u0026#34;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;g class=\u0026#34;label\u0026#34; transform=\u0026#34;translate(0,0)\u0026#34;\u0026gt;\u0026lt;g transform=\u0026#34;translate(-20.1953125,-12.5)\u0026#34;\u0026gt;\u0026lt;foreignobject width=\u0026#34;40.390625\u0026#34; height=\u0026#34;25\u0026#34;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; \u0026lt;div xmlns=\u0026#34;http://www.w3.org/1999/xhtml\u0026#34; style=\u0026#34;display: inline-block; white-space: nowrap;\u0026#34;\u0026gt; 结果1 \u0026lt;/div\u0026gt; \u0026lt;g class=\u0026#34;node default\u0026#34; id=\u0026#34;flowchart-E-1555\u0026#34; transform=\u0026#34;translate(148.5859375,390.3656234741211)\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt;\u0026lt;rect rx=\u0026#34;0\u0026#34; ry=\u0026#34;0\u0026#34; x=\u0026#34;-30.1953125\u0026#34; y=\u0026#34;-22.5\u0026#34; width=\u0026#34;60.390625\u0026#34; height=\u0026#34;45\u0026#34; class=\u0026#34;label-container\u0026#34;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;g class=\u0026#34;label\u0026#34; transform=\u0026#34;translate(0,0)\u0026#34;\u0026gt;\u0026lt;g transform=\u0026#34;translate(-20.1953125,-12.5)\u0026#34;\u0026gt;\u0026lt;foreignobject width=\u0026#34;40.390625\u0026#34; height=\u0026#34;25\u0026#34;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; \u0026lt;div xmlns=\u0026#34;http://www.w3.org/1999/xhtml\u0026#34; style=\u0026#34;display: inline-block; white-space: nowrap;\u0026#34;\u0026gt; 结果2 \u0026lt;/div\u0026gt; \u0026lt;g class=\u0026#34;node default\u0026#34; id=\u0026#34;flowchart-F-1557\u0026#34; transform=\u0026#34;translate(219.390625,125.5)\u0026#34; style=\u0026#34;opacity: 1;\u0026#34;\u0026gt;\u0026lt;rect rx=\u0026#34;0\u0026#34; ry=\u0026#34;0\u0026#34; x=\u0026#34;-50\u0026#34; y=\u0026#34;-22.5\u0026#34; width=\u0026#34;100\u0026#34; height=\u0026#34;45\u0026#34; class=\u0026#34;label-container\u0026#34;\u0026gt;\u0026lt;/rect\u0026gt;\u0026lt;g class=\u0026#34;label\u0026#34; transform=\u0026#34;translate(0,0)\u0026#34;\u0026gt;\u0026lt;g transform=\u0026#34;translate(-40,-12.5)\u0026#34;\u0026gt;\u0026lt;foreignobject width=\u0026#34;80\u0026#34; height=\u0026#34;25\u0026#34;\u0026gt;\u0026lt;/foreignobject\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt;\u0026lt;/g\u0026gt; \u0026lt;div xmlns=\u0026#34;http://www.w3.org/1999/xhtml\u0026#34; style=\u0026#34;display: inline-block; white-space: nowrap;\u0026#34;\u0026gt; 竖向流程图 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026#34;3标准流程图源码格式flow\u0026#34; class=\u0026#34;md-header-anchor\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;\u0026lt;span\u0026gt;3、标准流程图源码格式（flow)\u0026lt;/span\u0026gt; \u0026lt;blockquote\u0026gt; x\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-measure\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026#34;position: relative; z-index: 1;\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-code\u0026#34; role=\u0026#34;presentation\u0026#34; style=\u0026#34;\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-activeline\u0026#34; style=\u0026#34;position: relative;\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-activeline-background CodeMirror-linebackground\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;CodeMirror-gutter-background CodeMirror-activeline-gutter\u0026#34; style=\u0026#34;left: 0px; width: 0px;\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span role=\u0026#34;presentation\u0026#34; style=\u0026#34;padding-right: 0.1px;\u0026#34;\u0026gt;st=\u0026amp;gt;start: 开始框:\u0026amp;gt;https://www.baidu.com\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;\u0026quot; style=\u0026quot;position: relative;\u0026quot;\u0026gt; ``` op=\u0026gt;operation: 处理框\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;\u0026#34; style=\u0026#34;position: relative;\u0026#34;\u0026gt; ``` \u0026lt;span role=\u0026#34;presentation\u0026#34; style=\u0026#34;padding-right: 0.1px;\u0026#34;\u0026gt;cond=\u0026amp;gt;condition: 判断框（是或否？）\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;\u0026quot; style=\u0026quot;position: relative;\u0026quot;\u0026gt; ``` sub1=subroutine: 子流程\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;\u0026#34; style=\u0026#34;position: relative;\u0026#34;\u0026gt; ``` \u0026lt;span role=\u0026#34;presentation\u0026#34; style=\u0026#34;padding-right: 0.1px;\u0026#34;\u0026gt;io=\u0026amp;gt;inputoutput: 输入输出框\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;\u0026quot; style=\u0026quot;position: relative;\u0026quot;\u0026gt; ``` e=\u0026gt;end: 结束框\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;\u0026#34; style=\u0026#34;position: relative;\u0026#34;\u0026gt; ``` \u0026lt;span role=\u0026#34;presentation\u0026#34; style=\u0026#34;padding-right: 0.1px;\u0026#34;\u0026gt;st-\u0026amp;gt;op-\u0026amp;gt;cond\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;\u0026quot; style=\u0026quot;position: relative;\u0026quot;\u0026gt; ``` cond(yes)-\u0026gt;io-\u0026gt;e\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;\u0026#34; style=\u0026#34;position: relative;\u0026#34;\u0026gt; ``` \u0026lt;span role=\u0026#34;presentation\u0026#34; style=\u0026#34;padding-right: 0.1px;\u0026#34;\u0026gt;cond(no)-\u0026amp;gt;sub1(right)-\u0026amp;gt;op\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 180px;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;CodeMirror-gutters\u0026quot; style=\u0026quot;display: none; height: 180px;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; 例如：\nCreated with Raphaël 2.2.0 [](http://www.baidu.com)[","permalink":"https://blog.zdltech.com/posts/2021-01-28-/","summary":"\u003cmeta charset=\"UTF-8\" /\u003e\n\u003cmeta name=\"viewport\" content=\"width=device-width initial-scale=1\" /\u003e\n\u003ctitle\u003e\n  Typora 流程图\n\u003c/title\u003e\n\u003cdiv id=\"write\" class=\"\"\u003e\n  ## \u003ca name=\"typora-流程图\" class=\"md-header-anchor\"\u003e\u003c/a\u003e\u003cspan\u003eTypora 流程图\u003c/span\u003e\n\u003ch3 id=\"1横向流程图源码格式mermaid\"\u003e\u003ca name=\"1横向流程图源码格式mermaid）\" class=\"md-header-anchor\"\u003e\u003c/a\u003e\u003cspan\u003e1、横向流程图源码格式（mermaid）\u003c/span\u003e\u003c/h3\u003e\n  \u003cblockquote\u003e\n    ```\n\u003cdiv class=\"CodeMirror cm-s-inner CodeMirror-wrap\" lang=\"text\"\u003e\n  \u003cdiv style=\"overflow: hidden; position: relative; width: 3px; height: 0px; top: 7px; left: 8px;\"\u003e\n    \u003ctextarea autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" tabindex=\"0\" style=\"position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;\"\u003e\u003c/textarea\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"CodeMirror-scrollbar-filler\" cm-not-content=\"true\"\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"CodeMirror-gutter-filler\" cm-not-content=\"true\"\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"CodeMirror-scroll\" tabindex=\"-1\"\u003e\n    \u003cdiv class=\"CodeMirror-sizer\" style=\"margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;\"\u003e\n      \u003cdiv style=\"position: relative; top: 0px;\"\u003e\n        \u003cdiv class=\"CodeMirror-lines\" role=\"presentation\"\u003e\n          \u003cdiv role=\"presentation\" style=\"position: relative; outline: none;\"\u003e\n            \u003cdiv class=\"CodeMirror-measure\"\u003e\n\u003cp\u003ex\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026lt;div class=\u0026#34;CodeMirror-measure\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026lt;div style=\u0026#34;position: relative; z-index: 1;\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026lt;div class=\u0026#34;CodeMirror-code\u0026#34; role=\u0026#34;presentation\u0026#34; style=\u0026#34;\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u0026lt;div class=\u0026#34;CodeMirror-activeline\u0026#34; style=\u0026#34;position: relative;\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026lt;div class=\u0026#34;CodeMirror-activeline-background CodeMirror-linebackground\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026lt;div class=\u0026#34;CodeMirror-gutter-background CodeMirror-activeline-gutter\u0026#34; style=\u0026#34;left: 0px; width: 0px;\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span role=\u0026#34;presentation\u0026#34; style=\u0026#34;padding-right: 0.1px;\u0026#34;\u0026gt;graph LR\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e          \u0026lt;/div\u0026gt;\n          \n          \n          \u0026lt;div class=\u0026quot;\u0026quot; style=\u0026quot;position: relative;\u0026quot;\u0026gt;\n            ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cspan role=\"presentation\" style=\"padding-right: 0.1px;\"\u003eA[方形] \u0026ndash;\u0026gt;B(圆角)\u003c/span\u003e\u003c/p\u003e","title":"Typora 流程图使用"},{"content":"题目描述： Mortgage Calculator – Calculate the monthly payments of a fixed term mortgage over given Nth terms at a given interest rate. Also figure out how long it will take the user to pay back the loan.\n题目翻译： 按揭贷款计算器——在给定利率下，计算固定期限按揭贷款在第N期的月还款。同时计算用户需要多长时间来偿还贷款。\n按揭贷款的相关概念(Mortgage) 什么是按揭贷款 抵押贷款是指提供私人资产作为债务担保进行借款，多发生于购买房地产时英航借出的抵押贷款。\n抵押贷款的类型 抵押贷款的类型有多种，主要通过一下几个因素来定义抵押贷款的类型。\n利率(interest) ：分为固定利率和浮动利率\n期限(Term) ：按揭贷款通常拥有最大还款期限\n还款数额与还款频率(Payment amount and frequency) ：规定两次还款之间的时间间隔以及在每个周期内需要还款的数目\n预付款（PrePayment):贷款方提前支付的预付款\n还款方式 按揭贷款一般采用分期还款，在固定汇率的情况下，规定一个还款期限，然后每月按时还一定数额。 常见的两种还款方式：等额本息还款和等额本金还款 两种还款方案每月还款金额计算如下： 假定贷款的年利率为r,还款年限为Y年，贷款本金为P，每月还款金额为A 贷款的月利率R=r/12R=r/12, 还款期数为N=12YN=12Y\n等额本息还款： 等额本息还款是指在还款时，每个月总的还款金额是相同的。每月所还本金和所还利息是变化的 假定第t个还款月还款后，剩余的总还款金额为 p(t)p(t).p(0)=Pp(1)=p(0)(1+R)−A=P(1+R)−Ap(2)=P(1)(1+R)−A=P(1+R)−A−A=P(1+R)2−(1+R)A−A…p(t)=P(1+R)t−A(1+R)t−1−A(1+R)t−2−…−A(1+R)−Ap(0)=Pp(1)=p(0)(1+R)−A=P(1+R)−Ap(2)=P(1)(1+R)−A=P(1+R)−A−A=P(1+R)2−(1+R)A−A…p(t)=P(1+R)t−A(1+R)t−1−A(1+R)t−2−…−A(1+R)−A我们可以得到每月还款后剩余还款金额p(t)p(t)的表达式：p(t)=P(1+R)t−A∑i=0t−1(1+R)i=P(1+R)t−A1−(1+R)t1−（1+R)=P(1+R)t−A(1+R)t−1Rp(t)=P(1+R)t−A∑i=0t−1(1+R)i=P(1+R)t−A1−(1+R)t1−（1+R)=P(1+R)t−A(1+R)t−1R我们给定的还款期数为N，也就是说p(N)=0p(N)=0,我们可以求出每月还款数额A。 由方程P(n)=P(1+R)N−A(1+R)N−1R=0P(n)=P(1+R)N−A(1+R)N−1R=0可以得到A=PR(1+R)N(1+R)N−1A=PR(1+R)N(1+R)N−1也就是说，如果采用等额本息的方式来还款，每月需要还款的数额为PR(1+R)N(1+R)N−1PR(1+R)N(1+R)N−1虽然每个月的还款数额相同，每月所还得利息和本金是变化的 第t+1个还款月需要还的利息i(t+1)i(t+1),为该月还款前的剩余还款金额p(t)p(t)乘以月利率Ri(t+1)=p(t)R=PR(1+R)t−A(1+R)t+A=(PR−A)(1+R)t+A=((PR−A)(1+R)t−1+A)(1+R)−A(1+R)+A=i(t)(1+R)−ARi(t+1)=p(t)R=PR(1+R)t−A(1+R)t+A=(PR−A)(1+R)t+A=((PR−A)(1+R)t−1+A)(1+R)−A(1+R)+A=i(t)(1+R)−AR因为(PR−A)\u0026lt;0(PR−A)\u0026lt;0,所以i(t)i(t)是关于t的减函数，也就是说每个月的还款金额中，利息所占的比重是降低的，而本金所占的比重是上升的\n等额本金还款： 在等额本金还款方式中，每个月还款的本金是相同，但是每个月所还的利息不同，所以每个月的还款总金额是变化的。 每个月需要还得本金pr为总本金除以总的还款月数。pr=PNpr=PN每个月需要还得利息pi(t)pi(t) = (本金-已归还的本金之和)*每月利率pi(t)=(P−pr(t−1))R=−prAt+(A+P)R=−PRNt+(PN+P)Rpi(t)=(P−pr(t−1))R=−prAt+(A+P)R=−PRNt+(PN+P)R可以看到，每个月所还利息pi(t)pi(t)是关于t的减函数，说明每个月所还的利息是逐渐减少的。由于每个月所还的本金数额不变，所以每个月所还贷款总额是递减的。\n程序实现 用户输入贷款汇率，贷款总金额，还款的年限和选择的还款方式。\n程序输出用户每个月需要还款的总金额以及需要偿还的本金和利息数额。\n`import java.util.Scanner; public class MortgageCalculator{ public static void mortgageCalcute(double P,double interest,int Y,int type){ //输入参数贷款总额P，贷款利率interest，还款年限Y，还款类型type(0表示等额本息还款方式，1表示等额本金还款方式) switch(type){ case 0: equalLoanPayment(P,interest,Y); break; case 1: equalPrincipalPayment(P,interest,Y); break; } } public static void equalLoanPayment(double P,double interest,int Y){ //等额本息还款计算函数 int N = Y*12; double R = interest/12; double A = P*R*Math.pow(1+R,N)/(Math.pow(1+R,N)-1); System.out.printf(\u0026#34;每月偿还的本息%7.2f\\n\u0026#34;,A*10000); double\u0026amp;#91;] pi = new double\u0026amp;#91;N]; pi\u0026amp;#91;0] = P*R; System.out.printf(\u0026#34;第1个月需要偿还的利息:%8.2f 第1个月需要偿还的本金为:%7.2f\\n\u0026#34;,pi\u0026amp;#91;0]*10000,(A-pi\u0026amp;#91;0])*10000); for(int i=1;i\u0026amp;lt;N;i++){ pi\u0026amp;#91;i] = pi\u0026amp;#91;i-1]*(1+R)-A*R; System.out.printf(\u0026#34;第%d个月需要偿还的利息:%7.2f 第%d个月需要偿还的本金为:%7.2f\\n\u0026#34;,i+1,pi\u0026amp;#91;i]*10000,i+1,(A-pi\u0026amp;#91;i])*10000); } } public static void equalPrincipalPayment(double P,double interest,int Y){ //等额本金还款计算函数 int N = Y*12; //还款的总月份 double R = interest/12; //还款的月利率 double A = P*1.0/N; //每月需要还得本金 System.out.printf(\u0026#34;每月需要偿还的本金%7.2f\\n\u0026#34;,A*10000); double\u0026amp;#91;] pi = new double\u0026amp;#91;N+1]; for(int i=1;i\u0026amp;lt;=N;i++){ pi\u0026amp;#91;i] = -P*R*1.0/N*i+(P/N+P)*R; System.out.printf(\u0026#34;第%d个月需要偿还的利息:%7.2f.第%d个月需要偿还的本息:%7.2f\\n\u0026#34;,i+1,pi\u0026amp;#91;i]*10000,i+1,(pi\u0026amp;#91;i]+A)*10000); } } public static void main(String\u0026amp;#91;] args){ //equalPrincipalPayment(45.4, 3.25/100, 15); Scanner sc = new Scanner(System.in); System.out.println(\u0026#34;选择还款方式: 0 等额本息，1 等额本金\u0026#34;); int PaymentType = sc.nextInt(); System.out.println(\u0026#34;输入还款总额(单位:万),还款年利率（百分数）与还款年限，用空格隔开\u0026#34;); double Payment = sc.nextDouble(); double interest = sc.nextDouble(); int years = sc.nextInt(); sc.close(); System.out.println(\u0026#34;还款总额:\u0026#34;+Payment+\u0026#34;还款年利率:\u0026#34;+interest+\u0026#34;% \u0026#34;+\u0026#34;还款年限:\u0026#34;+years+\u0026#34;年\u0026#34;); mortgageCalcute(Payment,interest/100,years,PaymentType); } }` ","permalink":"https://blog.zdltech.com/posts/%E6%8C%89%E6%8F%AD%E8%B4%B7%E6%AC%BE%E7%9A%84%E8%AE%A1%E7%AE%97%E5%8E%9F%E7%90%86%E4%B8%8Ejava%E5%AE%9E%E7%8E%B0/","summary":"\u003ch4 id=\"题目描述：.wp-block-heading\"\u003e题目描述：\u003c/h4\u003e\n\u003cp\u003eMortgage Calculator – Calculate the monthly payments of a fixed term mortgage over given Nth terms at a given interest rate. Also figure out how long it will take the user to pay back the loan.\u003c/p\u003e\n\u003ch4 id=\"题目翻译：.wp-block-heading\"\u003e题目翻译：\u003c/h4\u003e\n\u003cp\u003e按揭贷款计算器——在给定利率下，计算固定期限按揭贷款在第N期的月还款。同时计算用户需要多长时间来偿还贷款。\u003c/p\u003e\n\u003ch4 id=\"按揭贷款的相关概念mortgage.wp-block-heading\"\u003e按揭贷款的相关概念(Mortgage)\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e什么是按揭贷款\u003c/strong\u003e\n抵押贷款是指提供私人资产作为债务担保进行借款，多发生于购买房地产时英航借出的抵押贷款。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e抵押贷款的类型\u003c/strong\u003e\n抵押贷款的类型有多种，主要通过一下几个因素来定义抵押贷款的类型。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e利率(interest)\u003c/strong\u003e ：分为固定利率和浮动利率\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e期限(Term)\u003c/strong\u003e ：按揭贷款通常拥有最大还款期限\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e还款数额与还款频率(Payment amount and frequency)\u003c/strong\u003e ：规定两次还款之间的时间间隔以及在每个周期内需要还款的数目\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e预付款（PrePayment)\u003c/strong\u003e:贷款方提前支付的预付款\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e还款方式\u003c/strong\u003e\n按揭贷款一般采用分期还款，在固定汇率的情况下，规定一个还款期限，然后每月按时还一定数额。\n常见的两种还款方式：\u003cstrong\u003e等额本息还款和等额本金还款\u003c/strong\u003e\n两种还款方案每月还款金额计算如下：\n假定贷款的年利率为r,还款年限为Y年，贷款本金为P，每月还款金额为A\n贷款的月利率R=r/12R=r/12, 还款期数为N=12YN=12Y\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e等额本息还款：\u003c/strong\u003e\n等额本息还款是指在还款时，每个月总的还款金额是相同的。每月所还本金和所还利息是变化的\n假定第t个还款月还款后，剩余的总还款金额为 p(t)p(t).p(0)=Pp(1)=p(0)(1+R)−A=P(1+R)−Ap(2)=P(1)(1+R)−A=\u003ca href=\"1+R\"\u003eP(1+R)−A\u003c/a\u003e−A=P(1+R)2−(1+R)A−A…p(t)=P(1+R)t−A(1+R)t−1−A(1+R)t−2−…−A(1+R)−Ap(0)=Pp(1)=p(0)(1+R)−A=P(1+R)−Ap(2)=P(1)(1+R)−A=\u003ca href=\"1+R\"\u003eP(1+R)−A\u003c/a\u003e−A=P(1+R)2−(1+R)A−A…p(t)=P(1+R)t−A(1+R)t−1−A(1+R)t−2−…−A(1+R)−A我们可以得到每月还款后剩余还款金额p(t)p(t)的表达式：p(t)=P(1+R)t−A∑i=0t−1(1+R)i=P(1+R)t−A1−(1+R)t1−（1+R)=P(1+R)t−A(1+R)t−1Rp(t)=P(1+R)t−A∑i=0t−1(1+R)i=P(1+R)t−A1−(1+R)t1−（1+R)=P(1+R)t−A(1+R)t−1R我们给定的还款期数为N，也就是说p(N)=0p(N)=0,我们可以求出每月还款数额A。\n由方程P(n)=P(1+R)N−A(1+R)N−1R=0P(n)=P(1+R)N−A(1+R)N−1R=0可以得到A=PR(1+R)N(1+R)N−1A=PR(1+R)N(1+R)N−1也就是说，如果采用等额本息的方式来还款，每月需要还款的数额为PR(1+R)N(1+R)N−1PR(1+R)N(1+R)N−1虽然每个月的还款数额相同，每月所还得利息和本金是变化的\n第t+1个还款月需要还的利息i(t+1)i(t+1),为该月还款前的剩余还款金额p(t)p(t)乘以月利率Ri(t+1)=p(t)R=PR(1+R)t−A(1+R)t+A=(PR−A)(1+R)t+A=((PR−A)(1+R)t−1+A)(1+R)−A(1+R)+A=i(t)(1+R)−ARi(t+1)=p(t)R=PR(1+R)t−A(1+R)t+A=(PR−A)(1+R)t+A=((PR−A)(1+R)t−1+A)(1+R)−A(1+R)+A=i(t)(1+R)−AR因为(PR−A)\u0026lt;0(PR−A)\u0026lt;0,所以i(t)i(t)是关于t的减函数，也就是说每个月的还款金额中，利息所占的比重是降低的，而本金所占的比重是上升的\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e等额本金还款：\u003c/strong\u003e\n在等额本金还款方式中，每个月还款的本金是相同，但是每个月所还的利息不同，所以每个月的还款总金额是变化的。\n每个月需要还得本金pr为总本金除以总的还款月数。pr=PNpr=PN每个月需要还得利息pi(t)pi(t) = (本金-已归还的本金之和)*每月利率pi(t)=(P−pr(t−1))R=−prAt+(A+P)R=−PRNt+(PN+P)Rpi(t)=(P−pr(t−1))R=−prAt+(A+P)R=−PRNt+(PN+P)R可以看到，每个月所还利息pi(t)pi(t)是关于t的减函数，说明每个月所还的利息是逐渐减少的。由于每个月所还的本金数额不变，所以每个月所还贷款总额是递减的。\u003c/p\u003e","title":"按揭贷款的计算原理与java实现"},{"content":"ElasticSearch安装与配置 centos 7 安装 ElasticSearch\n安装elasticsearch之前 先要安装java jdk 8\n这里提供下载地址：链接: https://pan.baidu.com/s/1ZIJc0JWKMyLl4Iivh-YlBw 密码: gr08\n`# 进入opt目录 cd /opt/ # 创建 soft文件夹 用来存储所有的软件 如果你有自己的目录，可以不创建这个目录 mkdir soft cd soft # 执行下载 ElasticSearch 这里使用目前最新的 7.10.1 如果没有wget命令 执行 yum install wget 进行安装 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.10.1-linux-x86_64.tar.gz # 解压文件 tar -zxvf elasticsearch-7.10.1-linux-x86_64.tar.gz # 修改文件夹名称和移动目录 mv elasticsearch-7.10.1 /opt/elasticsearch # 进入elasticsearch目录 cd /opt/elasticsearch # 默认为了安全，不要使用root进行启动，这里创建一个 elasticsearch 用户和组 # 添加 elasticsearch 组 groupadd elasticsearch # 添加 elasticsearch 用户 并添加到elasticsearch组中 -g 后表示组 useradd elasticsearch -g elasticsearch # 修改文件夹拥有者 表示把elasticsearch文件夹 给elasticsearch用户和elasticsearch组 # 修改这个组之前 先退到elasticsearch的目标文件夹上一级 chown -R elasticsearch:elasticsearch elasticsearch # 修改elasticsearch配置文件 # 进入elasticsearch 的config目录 cd elasticsearch/config/ # 编辑配置文件 参考下面配置文件 vi elasticsearch.yml ## 启动 # 进入 elasticsearch/bin目录 cd bin/ # 使用elasticsearch用户进行启动 sudo -u elasticsearch ./elasticsearch -d # 查询是否启动成功 ps -ef|grep elasticsearch # 查看启动日志 tail -f /opt/elasticsearch/logs/yqzl-service.log # 验证是否成功 curl http://localhost:9200 #出现这个表示成功 :` { \u0026#34;name\u0026#34; : \u0026#34;yqzl-node-1\u0026#34;, \u0026#34;cluster_name\u0026#34; : \u0026#34;yqzl-service\u0026#34;, \u0026#34;cluster_uuid\u0026#34; : \u0026#34;3wrpP4wwTFCBHdCboBqQfQ\u0026#34;, \u0026#34;version\u0026#34; : { \u0026#34;number\u0026#34; : \u0026#34;7.10.1\u0026#34;, \u0026#34;build_flavor\u0026#34; : \u0026#34;default\u0026#34;, \u0026#34;build_type\u0026#34; : \u0026#34;tar\u0026#34;, \u0026#34;build_hash\u0026#34; : \u0026#34;1c34507e66d7db1211f66f3513706fdf548736aa\u0026#34;, \u0026#34;build_date\u0026#34; : \u0026#34;2020-12-05T01:00:33.671820Z\u0026#34;, \u0026#34;build_snapshot\u0026#34; : false, \u0026#34;lucene_version\u0026#34; : \u0026#34;8.7.0\u0026#34;, \u0026#34;minimum_wire_compatibility_version\u0026#34; : \u0026#34;6.8.0\u0026#34;, \u0026#34;minimum_index_compatibility_version\u0026#34; : \u0026#34;6.0.0-beta1\u0026#34; }, \u0026#34;tagline\u0026#34; : \u0026#34;You Know, for Search\u0026#34; } ` ` elasticsearch.yml `# ======================== Elasticsearch Configuration ========================= # # NOTE: Elasticsearch comes with reasonable defaults for most settings. # Before you set out to tweak and tune the configuration, make sure you # understand what are you trying to accomplish and the consequences. # # The primary way of configuring a node is via this file. This template lists # the most important settings you may want to configure for a production cluster. # # Please consult the documentation for further information on configuration options: # https://www.elastic.co/guide/en/elasticsearch/reference/index.html # # ---------------------------------- Cluster ----------------------------------- # # Use a descriptive name for your cluster: 集群名称 # cluster.name: yqzl-service # # ------------------------------------ Node ------------------------------------ # # Use a descriptive name for the node: 节点名称 # node.name: yqzl-node-1 # # Add custom attributes to the node: # #node.attr.rack: r1 # # ----------------------------------- Paths ------------------------------------ # # Path to directory where to store the data (separate multiple locations by comma): # #path.data: /path/to/data # # Path to log files: # #path.logs: /path/to/logs # # ----------------------------------- Memory ----------------------------------- # # Lock the memory on startup: # #bootstrap.memory_lock: true # # Make sure that the heap size is set to about half the memory available # on the system and that the owner of the process is allowed to use this # limit. # # Elasticsearch performs poorly when the system is swapping the memory. # # ---------------------------------- Network ----------------------------------- # # Set the bind address to a specific IP (IPv4 or IPv6): 运行访问的ip 0.0.0.0 表示都可以访问 # network.host: 0.0.0.0 # # Set a custom port for HTTP: # #http.port: 9200 # # For more information, consult the network module documentation. # # --------------------------------- Discovery ---------------------------------- # # Pass an initial list of hosts to perform discovery when this node is started: # The default list of hosts is [\u0026#34;127.0.0.1\u0026#34;, \u0026#34;[::1]\u0026#34;] # #discovery.seed_hosts: [\u0026#34;host1\u0026#34;, \u0026#34;host2\u0026#34;] # # Bootstrap the cluster using an initial set of master-eligible nodes: 初始化主节点 # cluster.initial_master_nodes: [\u0026#34;yqzl-node-1\u0026#34;] # # For more information, consult the discovery and cluster formation module documentation. # # ---------------------------------- Gateway ----------------------------------- # # Block initial recovery after a full cluster restart until N nodes are started: # #gateway.recover_after_nodes: 3 # # For more information, consult the gateway module documentation. # # ---------------------------------- Various ----------------------------------- # # Require explicit names when deleting indices: # #action.destructive_requires_name: true ` 安装遇到问题 `elasticsearch启动时遇到的错误 elasticsearch用户拥有的内存权限太小，至少需要262144；\n解决方法：\n切换到root用户\n执行命令：\nsysctl -w vm.max_map_count=262144\n查看结果：\nsysctl -a|grep vm.max_map_count\n显示：\nvm.max_map_count = 262144\n上述方法修改之后，如果重启虚拟机将失效，所以：\n解决办法：\n在 /etc/sysctl.conf文件最后添加一行\nvm.max_map_count=262144\n即可永久修改\n使用ElasticSearch-head的时候，如果是在不同的服务器上，出现跨越的问题\n`\n//编辑配置文件\n# vi elasticsearch/elasticsearch.yml\n//增加下面两项\nhttp.cors.enabled: true\nhttp.cors.allow-origin: “*”\n重启ElasticSearch就OK 了\n其它资料 https://github.com/medcl/elasticsearch-analysis-ik/releases\nhttps://github.com/medcl/elasticsearch-analysis-pinyin\nhttps://elastic-search-in-action.medcl.com/\n","permalink":"https://blog.zdltech.com/posts/elasticsearch-an-zhuang-yu-pei-zhi/","summary":"\u003ch2 id=\"toc_0\"\u003eElasticSearch安装与配置\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003ecentos 7 安装 ElasticSearch\u003c/p\u003e\n\u003cp\u003e安装elasticsearch之前 先要安装java jdk 8\u003c/p\u003e\n\u003cp\u003e这里提供下载地址：链接: \u003ca href=\"https://pan.baidu.com/s/1ZIJc0JWKMyLl4Iivh-YlBw\"\u003ehttps://pan.baidu.com/s/1ZIJc0JWKMyLl4Iivh-YlBw\u003c/a\u003e 密码: gr08\u003c/p\u003e\u003c/blockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u003cspan style=\"color:#6272a4\"\u003e# 进入opt目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecd \u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eopt\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 创建 soft文件夹 用来存储所有的软件  如果你有自己的目录，可以不创建这个目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emkdir soft\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecd soft\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 执行下载 ElasticSearch 这里使用目前最新的 7.10.1 如果没有wget命令 执行 yum install wget 进行安装\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewget https:\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003eartifacts\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eelastic\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eco\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edownloads\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eelasticsearch\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eelasticsearch\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e7.10\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003elinux\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ex86_64\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etar\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egz\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 解压文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etar \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ezxvf elasticsearch\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e7.10\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003elinux\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ex86_64\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etar\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egz \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 修改文件夹名称和移动目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emv elasticsearch\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e7.10\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eopt\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eelasticsearch\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 进入elasticsearch目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecd \u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eopt\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eelasticsearch\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 默认为了安全，不要使用root进行启动，这里创建一个 elasticsearch 用户和组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 添加 elasticsearch 组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egroupadd elasticsearch\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 添加 elasticsearch 用户 并添加到elasticsearch组中 -g 后表示组 \u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003euseradd elasticsearch \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eg elasticsearch \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 修改文件夹拥有者 表示把elasticsearch文件夹 给elasticsearch用户和elasticsearch组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 修改这个组之前 先退到elasticsearch的目标文件夹上一级\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003echown \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eR elasticsearch:elasticsearch elasticsearch\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 修改elasticsearch配置文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 进入elasticsearch 的config目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecd elasticsearch\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003econfig\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 编辑配置文件 参考下面配置文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003evi elasticsearch\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eyml \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e## 启动\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 进入 elasticsearch/bin目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecd bin\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 使用elasticsearch用户进行启动\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eu elasticsearch \u003cspan style=\"color:#ff79c6\"\u003e./\u003c/span\u003eelasticsearch \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ed\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 查询是否启动成功\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eps \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eef\u003cspan style=\"color:#ff79c6\"\u003e|\u003c/span\u003egrep elasticsearch\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 查看启动日志\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etail \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ef \u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eopt\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eelasticsearch\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003elogs\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eyqzl\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eservice\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 验证是否成功\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecurl http:\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003elocalhost:\u003cspan style=\"color:#bd93f9\"\u003e9200\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#出现这个表示成功\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e:`\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e : \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;yqzl-node-1\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cluster_name\u0026#34;\u003c/span\u003e : \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;yqzl-service\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cluster_uuid\u0026#34;\u003c/span\u003e : \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;3wrpP4wwTFCBHdCboBqQfQ\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;version\u0026#34;\u003c/span\u003e : {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;number\u0026#34;\u003c/span\u003e : \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;7.10.1\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;build_flavor\u0026#34;\u003c/span\u003e : \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;default\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;build_type\u0026#34;\u003c/span\u003e : \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;tar\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;build_hash\u0026#34;\u003c/span\u003e : \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;1c34507e66d7db1211f66f3513706fdf548736aa\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;build_date\u0026#34;\u003c/span\u003e : \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;2020-12-05T01:00:33.671820Z\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;build_snapshot\u0026#34;\u003c/span\u003e : \u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;lucene_version\u0026#34;\u003c/span\u003e : \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;8.7.0\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;minimum_wire_compatibility_version\u0026#34;\u003c/span\u003e : \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;6.8.0\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;minimum_index_compatibility_version\u0026#34;\u003c/span\u003e : \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;6.0.0-beta1\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;tagline\u0026#34;\u003c/span\u003e : \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;You Know, for Search\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"toc_1\"\u003eelasticsearch.yml\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`# ======================== Elasticsearch Configuration =========================\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# NOTE: Elasticsearch comes with reasonable defaults for most settings.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#       Before you set out to tweak and tune the configuration, make sure you\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#       understand what are you trying to accomplish and the consequences.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# The primary way of configuring a node is via this file. This template lists\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# the most important settings you may want to configure for a production cluster.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Please consult the documentation for further information on configuration options:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# https://www.elastic.co/guide/en/elasticsearch/reference/index.html\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# ---------------------------------- Cluster -----------------------------------\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Use a descriptive name for your cluster: 集群名称\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecluster.name: yqzl-service\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# ------------------------------------ Node ------------------------------------\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Use a descriptive name for the node: 节点名称\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enode.name: yqzl-node-1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Add custom attributes to the node:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#node.attr.rack: r1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# ----------------------------------- Paths ------------------------------------\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Path to directory where to store the data (separate multiple locations by comma):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#path.data: /path/to/data\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Path to log files:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#path.logs: /path/to/logs\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# ----------------------------------- Memory -----------------------------------\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Lock the memory on startup:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#bootstrap.memory_lock: true\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Make sure that the heap size is set to about half the memory available\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# on the system and that the owner of the process is allowed to use this\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# limit.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Elasticsearch performs poorly when the system is swapping the memory.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# ---------------------------------- Network -----------------------------------\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Set the bind address to a specific IP (IPv4 or IPv6): 运行访问的ip 0.0.0.0 表示都可以访问\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enetwork.host: 0.0.0.0 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Set a custom port for HTTP:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#http.port: 9200\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# For more information, consult the network module documentation.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# --------------------------------- Discovery ----------------------------------\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Pass an initial list of hosts to perform discovery when this node is started:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# The default list of hosts is [\u0026#34;127.0.0.1\u0026#34;, \u0026#34;[::1]\u0026#34;]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#discovery.seed_hosts: [\u0026#34;host1\u0026#34;, \u0026#34;host2\u0026#34;]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Bootstrap the cluster using an initial set of master-eligible nodes: 初始化主节点\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecluster.initial_master_nodes: [\u0026#34;yqzl-node-1\u0026#34;]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# For more information, consult the discovery and cluster formation module documentation.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# ---------------------------------- Gateway -----------------------------------\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Block initial recovery after a full cluster restart until N nodes are started:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#gateway.recover_after_nodes: 3\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# For more information, consult the gateway module documentation.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# ---------------------------------- Various -----------------------------------\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# Require explicit names when deleting indices:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#action.destructive_requires_name: true\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"toc_2\"\u003e安装遇到问题\u003c/h4\u003e\n\u003ch5 id=\"elasticsearch启动时遇到的错误\"\u003e`elasticsearch启动时遇到的错误\u003c/h5\u003e\n\u003cp\u003eelasticsearch用户拥有的内存权限太小，至少需要262144；\u003c/p\u003e","title":"ElasticSearch安装与配置"},{"content":"**\n\u0026lt;strong\u0026gt;域名系统**（[英文](https://baike.baidu.com/item/英文)：**D**omain **N**ame **S**ystem，[缩写](https://baike.baidu.com/item/缩写)：**DNS**）是[互联网](https://baike.baidu.com/item/互联网)的一项服务。它作为将[域名](https://baike.baidu.com/item/域名)和[IP地址](https://baike.baidu.com/item/IP地址)相互[映射](https://baike.baidu.com/item/映射)的一个[分布式数据库](https://baike.baidu.com/item/分布式数据库)，能够使人更方便地访问[互联网](https://baike.baidu.com/item/互联网)。DNS使用[TCP](https://baike.baidu.com/item/TCP)和[UDP](https://baike.baidu.com/item/UDP)[端口](https://baike.baidu.com/item/端口)53。当前，对于每一级域名长度的限制是63个字符，域名总长度则不能超过253个字符。 [域名系统_百度百科 (baidu.com)](https://baike.baidu.com/item/域名系统/2251573) DNSmasq [DNSmasq_百度百科 (baidu.com)](https://baike.baidu.com/item/DNSmasq/7811792) dnsmasq原理 dnsmasq提供DNS缓存和DHCP服务、Tftp服务功能。 作为域名解析服务器，dnsmasq可以通过缓存DNS请求来提供对访问过的网址的的连接速度； 作为DHCP服务器，dnsmasq可以用于为局域网电脑分配内网IP地址和提供路由； DNS和DHCP两个功能可以同时或分别单独实现，此处只做DNS的配置； 当接受到一个DNS请求时，Dnsmasq首先会查找/etc/hosts这个文件，然后查找/etc/resolv.conf中定义的外部DNS。所以说Dnsmasq是一个很不错的外部DNS中继。 ​ 配置dnsmasq为DNS缓存服务器，同时在/etc/hosts文件中加入本地内网解析，这样一来每当内网机器查询时就会优先查询hosts文件，这就等于将/etc/hosts共享给全内网机器使用，从而解决内网机器互相识别的问题。 使用场景 构建私有DNS。例如： 我们有这么一个使用场景，在公司内网开发及测试的时候，我们会把部署好的服务，部署好，然后发送服务对应的IP给开发或者测试人员，开发或者测试通过IP进行访问，但是当IP变的是，我们还要在通知一次，当我们在一台服务器上部署了很多的服务的时候，我们还要指定端口，随着服务的越来越多，发现我们维护IP也越来越多，需要记住的端口也越来越多，怎么办，有没有好的解决方法，可能有人说配置本机Host啊，让公司内外全员配置HOST，下次IP修改或者新增IP的的时候，大家在修改HOST文件，发现工作量还是没有少。有没有更好的方式呢？这时大家想到DNS，内外构建私有DNS，大家只要配置一次DNS，下次测试使用的时候，直接使用域名（域名没有在域名服务商没有注册也可以），感觉和线上使用没有区别。 安装与配置dnsmasq 安装\nyum install dnsmasq -y\nsystemctl start dnsmasq.service 启动\nsystemctl enable dnsmasq.service # 开机启动\nnetstat -lnp|grep dnsmasq 查看是否执行 如果没有netstat命令，需要安装 yum install net-tools\nvi /etc/resolv.dnsmasq 创建resolve.dnsmasq 文件 添加上游dns服务器地址\n`nameserver 114.114.114.114 nameserver 8.8.8.8` 这个文件配置上游dns，要不可能有些有些内网打不开\nvi /etc/dnsmasqhosts 创建dnsmasqhosts文件，这个是域名和服务ip的映射关系文件\n`192.168.1.148 admin.5188888.com` vi /etc/dnsmasq.conf 编辑配置文件，把上面的两个文件配置到这个配置文件中\n`cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak 修改之前先备份一下` `# If you don\u0026#39;t want dnsmasq to read /etc/hosts, uncomment the # following line. #no-hosts # or if you want it to read another file, as well as /etc/hosts, use # this. 找到这里配置下面 addn-hosts addn-hosts=/etc/dnsmasqhosts # Change this line if you want dns to get its upstream servers from # somewhere other that /etc/resolv.conf 这里配置resolv.dnsmasq文件 resolv-file=/etc/resolv.dnsmasq` service dnsmasq restart 重启 dnsmasq文件\n配置电脑DNS 安装完成dnsmasq之后，怎么使用呢？怎么配置？实际上很简单，大家平时都设置过 dns 114.114.114.114 windows电脑配置 控制面板\\网络和 Internet\\网络和共享中心 ，找到更改适配器设置，右击你的连接 网络的 适配器，选择属性，找到 Internet 协议版本4（TCP/IPv4) ,点击进这项，配置使用下面的DNS，在DNS中输入 安装dnsmasq服务的对应的IP地址，到此完成，大家 就可以使用dnsmasqhosts中配置的 域名访问下，是不是可以访问到服务啦。 Mac 电脑配置 和Window类似，找到WIFI，在WiFi的DNS中配置 系统偏好设置 \u0026gt; 网络 \u0026gt; 高级 \u0026gt; DNS 添加为当前配置的机器的ip即可 注意事项 需要开放dnsmasq的端口 53 ，如果服务器配置有防火墙，需要把这个防火墙放开53端口\n大家不知道端口的时候，可以用netstat -lnp|grep dnsmasq 查询\n`[root@localhost ~]# netstat -lnp|grep dnsmasq tcp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN 128993/dnsmasq tcp6 0 0 :::53 :::* LISTEN 128993/dnsmasq udp 0 0 0.0.0.0:53 0.0.0.0:* 128993/dnsmasq udp6 0 0 :::53 :::* 128993/dnsmasq ` 不推荐大家修改dns的端口，我们电脑默认使用的DNS端口是53，修改之后，可能访问不了自己构建的dns服务器\n每次添加新域名的时候，需要重启下 dnsmasq服务 ### 修改iptables配置 允许本机的53端口可对外访问 \u0026gt;\niptables -A INPUT -p udp -m udp –dport 53 -j ACCEPT \u0026gt; \u0026gt; iptables -A INPUT -p tcp -m tcp –dport 53 -j ACCEPT ### 转发DNS请求 ###### 开启流量转发功能 \u0026gt;echo ‘1’ \u0026gt; /proc/sys/net/ipv4/ip_forward \u0026gt; \u0026gt; echo ‘1’ \u0026gt; /proc/sys/net/ipv6/ip_forward # IPv6 用户选用 ###### 添加流量转发规则，将外部到53的端口的请求映射到Dnsmasq服务器的53端口 \u0026gt;iptables -t nat -A PREROUTING -p udp –dport 53 -j REDIRECT –to-ports 53 \u0026gt; \u0026gt; iptables -t nat -A PREROUTING -p tcp –dport 53 -j REDIRECT –to-ports 53 ###### 如果要限制只允许内网的请求，方法如下 \u0026gt; iptables -t nat -A PREROUTING -i eth1 -p upd –dport 53 -j REDIRECT –to-port 53 保存规则并重启 \u0026gt; service iptables save \u0026gt; \u0026gt;$ service iptables restart\n","permalink":"https://blog.zdltech.com/posts/dnsmasq%E5%AE%89%E8%A3%85%E5%8F%8A%E4%BD%BF%E7%94%A8/","summary":"\u003cp\u003e**\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;strong\u0026gt;域名系统**（[英文](https://baike.baidu.com/item/英文)：**D**omain **N**ame **S**ystem，[缩写](https://baike.baidu.com/item/缩写)：**DNS**）是[互联网](https://baike.baidu.com/item/互联网)的一项服务。它作为将[域名](https://baike.baidu.com/item/域名)和[IP地址](https://baike.baidu.com/item/IP地址)相互[映射](https://baike.baidu.com/item/映射)的一个[分布式数据库](https://baike.baidu.com/item/分布式数据库)，能够使人更方便地访问[互联网](https://baike.baidu.com/item/互联网)。DNS使用[TCP](https://baike.baidu.com/item/TCP)和[UDP](https://baike.baidu.com/item/UDP)[端口](https://baike.baidu.com/item/端口)53。当前，对于每一级域名长度的限制是63个字符，域名总长度则不能超过253个字符。\n\n\n\n\n\n[域名系统_百度百科 (baidu.com)](https://baike.baidu.com/item/域名系统/2251573)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"dnsmasq\"\u003eDNSmasq\u003c/h3\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e[DNSmasq_百度百科 (baidu.com)](https://baike.baidu.com/item/DNSmasq/7811792)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"dnsmasq原理\"\u003ednsmasq原理\u003c/h3\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e　　dnsmasq提供DNS缓存和DHCP服务、Tftp服务功能。\n\n\n\n\n\n　　作为域名解析服务器，dnsmasq可以通过缓存DNS请求来提供对访问过的网址的的连接速度；\n\n\n\n\n\n　　作为DHCP服务器，dnsmasq可以用于为局域网电脑分配内网IP地址和提供路由；\n\n\n\n\n\n　　DNS和DHCP两个功能可以同时或分别单独实现，此处只做DNS的配置；\n\n\n\n\n\n　　当接受到一个DNS请求时，Dnsmasq首先会查找/etc/hosts这个文件，然后查找/etc/resolv.conf中定义的外部DNS。所以说Dnsmasq是一个很不错的外部DNS中继。\n\n\n\n\n\n​ 配置dnsmasq为DNS缓存服务器，同时在/etc/hosts文件中加入本地内网解析，这样一来每当内网机器查询时就会优先查询hosts文件，这就等于将/etc/hosts共享给全内网机器使用，从而解决内网机器互相识别的问题。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"使用场景\"\u003e使用场景\u003c/h3\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e构建私有DNS。例如： 我们有这么一个使用场景，在公司内网开发及测试的时候，我们会把部署好的服务，部署好，然后发送服务对应的IP给开发或者测试人员，开发或者测试通过IP进行访问，但是当IP变的是，我们还要在通知一次，当我们在一台服务器上部署了很多的服务的时候，我们还要指定端口，随着服务的越来越多，发现我们维护IP也越来越多，需要记住的端口也越来越多，怎么办，有没有好的解决方法，可能有人说配置本机Host啊，让公司内外全员配置HOST，下次IP修改或者新增IP的的时候，大家在修改HOST文件，发现工作量还是没有少。有没有更好的方式呢？这时大家想到DNS，内外构建私有DNS，大家只要配置一次DNS，下次测试使用的时候，直接使用域名（域名没有在域名服务商没有注册也可以），感觉和线上使用没有区别。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"安装与配置dnsmasq\"\u003e安装与配置dnsmasq\u003c/h3\u003e\n\u003cp\u003e安装\u003c/p\u003e\n\u003cp\u003eyum install dnsmasq -y\u003c/p\u003e\n\u003cp\u003esystemctl start dnsmasq.service 启动\u003c/p\u003e\n\u003cp\u003esystemctl enable dnsmasq.service # 开机启动\u003c/p\u003e\n\u003cp\u003enetstat -lnp|grep dnsmasq 查看是否执行 如果没有netstat命令，需要安装 yum install net-tools\u003c/p\u003e\n\u003cp\u003evi /etc/resolv.dnsmasq 创建resolve.dnsmasq 文件 添加上游dns服务器地址\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`nameserver 114.114.114.114\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enameserver 8.8.8.8`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这个文件配置上游dns，要不可能有些有些内网打不开\u003c/p\u003e\n\u003cp\u003evi /etc/dnsmasqhosts 创建dnsmasqhosts文件，这个是域名和服务ip的映射关系文件\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`192.168.1.148  admin.5188888.com`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003evi /etc/dnsmasq.conf 编辑配置文件，把上面的两个文件配置到这个配置文件中\u003c/p\u003e","title":"DNSMasq安装及使用"},{"content":"很多时候会发现好多，异常流量，处理这些异常流量，通常是封禁IP\n`# deny_ip_o.sh 文件内容 #!/bin/bash max=500 #我们设定的最大值，当访问量大于这个值得时候，封锁 logdir=/opt/nginx/logs/access.log #nginx 访问日志文件路径 confdir=/opt/nginx/logs/nginx_deny.log #检测文件 test -e \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{confdir} || touch\u0026amp;lt;/span\u0026gt;{confdir} port=443 drop_Ip=\u0026#34;\u0026#34; #循环遍历日志文件取出访问量大于 500 的 ip for drop_Ip in \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(tail -n500000\u0026amp;lt;/span\u0026gt;logdir | awk \u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1}\u0026#39; | sort | uniq -c | sort -rn | awk \u0026#39;{if (\u0026amp;lt;/span\u0026gt;1\u0026gt;500) print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2}\u0026#39;) do echo \u0026#34;\u0026amp;lt;/span\u0026gt;{drop_Ip}---\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{drop_ip}\u0026#34; grep -q \u0026#34;\u0026amp;lt;/span\u0026gt;{drop_Ip}\u0026#34; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{confdir} \u0026amp;\u0026amp; eg=1 || eg=0; if ((\u0026amp;lt;/span\u0026gt;{eg}==0 ));then iptables -I INPUT -p tcp --dport \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{port} -s\u0026amp;lt;/span\u0026gt;{drop_Ip} -j DROP echo \u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{drop_Ip} \u0026#34; \u0026gt;\u0026gt; /opt/nginx/logs/nginx_deny.log #记录 log fi done #################################################################### #!/bin/bash #_日志位置 _log_Path=\u0026#34;/data0/nginx/weblogs/\u0026#34; #_日志文件名称 _log_FileName=\u0026#34;access_blog.kinggoo.com.log\u0026#34; #_要被屏蔽的ip访问端口，默认80 _port=\u0026#34;80\u0026#34; _nginx_deny=\u0026#34;/opt/webserver/nginx/conf/deny.conf\u0026#34; _nginx_bin=\u0026#34;/opt/webserver/nginx/sbin/nginx\u0026#34; _logfilepath=\u0026amp;lt;/span\u0026gt;{_log_Path}\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{_log_FileName} #初始化被禁ip变量 _drop_Ip=\u0026#34;\u0026#34; #检测文件 test -e\u0026amp;lt;/span\u0026gt;{_nginx_deny} || touch \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{_nginx_deny} for _drop_Ip in\u0026amp;lt;/span\u0026gt;( tail -n50000 \u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{_logfilepath}\u0026#34; |awk \u0026#39;{print\u0026amp;lt;/span\u0026gt;1,\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;12}\u0026#39; |grep -i -v -E \u0026#34;google|yahoo|baidu|msnbot|FeedSky|sogou|WordPress\u0026#34; |awk \u0026#39;{print\u0026amp;lt;/span\u0026gt;1}\u0026#39;|sort|uniq -c|sort -rn |awk \u0026#39;{if(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026gt;1000)print \u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;2\u0026#34;\u0026#34;}\u0026#39; ); do grep -q \u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{_drop_Ip}\u0026#34;\u0026amp;lt;/span\u0026gt;{_nginx_deny} \u0026amp;\u0026amp; eg=1 || eg=0 ; if (( \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{eg}==0 ));then echo \u0026#34;deny\u0026amp;lt;/span\u0026gt;{_drop_Ip};\u0026#34; \u0026gt;\u0026gt; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{_nginx_deny}\u0026amp;lt;/span\u0026gt;{_nginx_bin} -s reload iptables -I INPUT -p tcp -dport \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{_port} -s\u0026amp;lt;/span\u0026gt;{_drop_Ip} -j DROP echo \u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{_drop_Ip} \u0026#34; \u0026gt;\u0026gt; /tmp/nginx_deny.log; echo \u0026#34;iptables -I INPUT -p tcp --dport\u0026amp;lt;/span\u0026gt;{_port} -s \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{_drop_Ip} -j DROP\u0026#34; \u0026gt;\u0026gt; /tmp/nginx_deny.log fi done 使用 nginx 封锁 ... -封锁 IP #!/bin/bash max=500 #我们设定的最大值，当访问量大于这个值得时候，封锁 confdir=/usr/local/data/nginx/conf/blockip.conf #nginx 封锁配置文件路径 logdir=/usr/local/data/nginx/logs/access_huke88.log #nginx 访问日志文件路径 #检测文件 test -e\u0026amp;lt;/span\u0026gt;{confdir} || touch \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{confdir} drop_ip=\u0026#34;\u0026#34; #循环遍历日志文件取出访问量大于 500 的 ip for drop_ip in\u0026amp;lt;/span\u0026gt;(cat \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;logdir | awk \u0026#39;{print\u0026amp;lt;/span\u0026gt;1}\u0026#39; | sort | uniq -c | sort -rn | awk \u0026#39;{if (\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026gt;500) print\u0026amp;lt;/span\u0026gt;2}\u0026#39;) do grep -q \u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{drop_Ip}\u0026#34;\u0026amp;lt;/span\u0026gt;{confdir} \u0026amp;\u0026amp; eg=1 || eg=0; if (( \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{eg}==0 ));then echo \u0026#34;deny\u0026amp;lt;/span\u0026gt;{drop_Ip};\u0026#34;\u0026gt;\u0026gt;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;confdir #把“ deny IP ；”语句写入封锁配置文件中 echo \u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt;\u0026amp;lt;/span\u0026gt;{drop_Ip} \u0026#34; \u0026gt;\u0026gt; /usr/local/data/nginx/logs/nginx_deny.log #记录 log fi done service nginx reload -解锁 IP #！/bin/bash sed -i \u0026#39;s/^/#\u0026amp;/g\u0026#39; /usr/local/nginx/conf/blockip.conf #把 nginx 封锁配置文件中的内容注释掉 service nginx reload #重置 nginx 服务，这样就做到了解锁 IP 使用 iptables 封锁 ... -封锁 IP 脚本 #!/bin/bash max=500 #我们设定的最大值，当访问量大于这个值得时候，封锁 logdir=/usr/local/data/nginx/logs/access_huke88.log #nginx 访问日志文件路径 confdir=/usr/local/data/nginx/conf/blockip.conf #nginx 封锁配置文件路径 #检测文件 test -e \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{confdir} || touch\u0026amp;lt;/span\u0026gt;{confdir} port=80 drop_ip=\u0026#34;\u0026#34; #循环遍历日志文件取出访问量大于 500 的 ip for drop_ip in \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(cat\u0026amp;lt;/span\u0026gt;logdir | awk \u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1}\u0026#39; | sort | uniq -c | sort -rn | awk \u0026#39;{if (\u0026amp;lt;/span\u0026gt;1\u0026gt;500) print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2}\u0026#39;) do grep -q \u0026#34;\u0026amp;lt;/span\u0026gt;{drop_Ip}\u0026#34; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{confdir} \u0026amp;\u0026amp; eg=1 || eg=0; if ((\u0026amp;lt;/span\u0026gt;{eg}==0 ));then iptables -I INPUT -p tcp --dport \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{port} -s\u0026amp;lt;/span\u0026gt;{drop_Ip} -j DROP echo \u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{drop_Ip} \u0026#34; \u0026gt;\u0026gt; /usr/local/data/nginx/logs/nginx_deny.log #记录 log fi done ... 加入计划任务每五分钟执行一次 chmod +x /home/scripts/deny_ip.sh #####nginx 封 ip###### */5 * * * * /bin/sh /home/scripts/deny_ip.sh \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 ### 添加定时任务 */5 * * * * /bin/sh /opt/nginx/logs/deny_ip_o.sh \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 tail -n 500000 access.log | awk \u0026#39;{print\u0026amp;lt;/span\u0026gt;1,\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;13,\u0026amp;lt;/span\u0026gt;8}\u0026#39;|awk \u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1}\u0026#39;|sort|uniq -c |sort -rn | awk \u0026#39;{if(\u0026amp;lt;/span\u0026gt;1\u0026gt;100)print \u0026#34;deny \u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1,\u0026amp;lt;/span\u0026gt;2\u0026#34;;\u0026#34;}\u0026#39; tail -n 500000000 access.log | awk \u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1,\u0026amp;lt;/span\u0026gt;13,\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;8}\u0026#39;|awk \u0026#39;{print\u0026amp;lt;/span\u0026gt;1}\u0026#39;|sort|uniq -c |sort -rn | awk \u0026#39;{if(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026gt;100)print \u0026#34;deny \u0026#34;\u0026amp;lt;/span\u0026gt;2\u0026#34;;\u0026#34;}\u0026#39; \u0026gt; blockip.conf tail -n 500000 access.log | awk \u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1,\u0026amp;lt;/span\u0026gt;13,\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;8}\u0026#39;|awk \u0026#39;{print\u0026amp;lt;/span\u0026gt;1}\u0026#39;|sort|uniq -c |sort -rn | awk \u0026#39;{if(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026gt;100)print \u0026#34;deny \u0026#34;\u0026amp;lt;/span\u0026gt;2\u0026#34;;\u0026#34;}\u0026#39; \u0026gt;\u0026gt; blockip.conf #if (\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;http_referer ~* \u0026#34;top1top1.top\u0026#34;) { # rewrite ^/ http://top.top1top1.top/CallHelper/client/main.jsp; #} if (\u0026amp;lt;/span\u0026gt;http_referer ~* \u0026#34;top1top1.top\u0026#34;) { return 404; } if (\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;http_referer ~* \u0026#34;shandiandxshop.xyz\u0026#34;){ rewrite ^/ http://tt.shandiandxshop.xyz/CallHelper/client/index.jsp; } https:\u0026amp;#47;\u0026amp;#47;blog.csdn.net/qq_41018743/article/details/105491785 http://www.siwei.me/blog/posts/linux-nginx-ip-ip #################################################################### #!/bin/bash num=100\t# 每秒某个ip的访问上限 list=`netstat -an |grep ^tcp.*:80|egrep -v \u0026#39;LISTEN|127.0.0.1\u0026#39;|awk -F\u0026#34;\u0026amp;#91; ]+|\u0026amp;#91;:]\u0026#34; \u0026#39;{print\u0026amp;lt;/span\u0026gt;6}\u0026#39;|sort|uniq -c|sort -rn|awk \u0026#39;{if (\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026gt;\u0026amp;lt;/span\u0026gt;num){print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2}}\u0026#39;` for i in\u0026amp;lt;/span\u0026gt;list do iptables -I INPUT -s \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;i --dport 80 -j DROP echo \u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt;\u0026amp;lt;/span\u0026gt;{\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;i} \u0026#34; \u0026gt;\u0026gt; /opt/nginx/logs/nginx_deny80.log #记录 log done ##################################################################### #!/bin/bash num=100 list=`netstat -an |grep ^tcp.*:80|egrep -v \u0026#39;LISTEN|127.0.0.1\u0026#39;|awk -F\u0026#34;\u0026amp;#91; ]+|\u0026amp;#91;:]\u0026#34; \u0026#39;{print\u0026amp;lt;/span\u0026gt;6}\u0026#39;|sort|uniq -c|sort -rn|awk \u0026#39;{if (\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026gt;\u0026amp;lt;/span\u0026gt;num){print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2}}\u0026#39;` for i in\u0026amp;lt;/span\u0026gt;list do iptables -I INPUT -p tcp --dport 80 -s \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{i} -j DROP echo \u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt;\u0026amp;lt;/span\u0026gt;{i} \u0026#34; \u0026gt;\u0026gt; /opt/nginx/logs/nginx_deny80.log done ####################################################################### #!/bin/bash max=500 #我们设定的最大值，当访问量大于这个值得时候，封锁 logdir=/opt/nginx/logs/access.log #nginx 访问日志文件路径 confdir=/opt/nginx/logs/nginx_deny.log #检测文件 test -e \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{confdir} || touch\u0026amp;lt;/span\u0026gt;{confdir} port=80 drop_ip=\u0026#34;\u0026#34; #循环遍历日志文件取出访问量大于 500 的 ip for drop_ip in \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(tail -n5000000\u0026amp;lt;/span\u0026gt;logdir | awk \u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1}\u0026#39; | sort | uniq -c | sort -rn | awk \u0026#39;{if (\u0026amp;lt;/span\u0026gt;1\u0026gt;500) print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2}\u0026#39;) do grep -q \u0026#34;\u0026amp;lt;/span\u0026gt;{drop_Ip}\u0026#34; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{confdir} \u0026amp;\u0026amp; eg=1 || eg=0; if ((\u0026amp;lt;/span\u0026gt;{eg}==0 ));then iptables -I INPUT -p tcp --dport \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{port} -s\u0026amp;lt;/span\u0026gt;{drop_Ip} -j DROP echo \u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{drop_Ip} \u0026#34; \u0026gt;\u0026gt; /opt/nginx/logs/nginx_deny.log #记录 log fi done #################################################################### #!/usr/bin/env bash echo \u0026#34;\u0026#34; echo \u0026#34; ========================================================= \u0026#34; echo \u0026#34; \\ Nginx日志安全分析脚本 V1.0 / \u0026#34; echo \u0026#34; ========================================================= \u0026#34; echo \u0026#34; # 支持Nginx日志分析，攻击告警分析等 \u0026#34; echo \u0026#34; # author：al0ne \u0026#34; echo \u0026#34; # https://github.com/al0ne \u0026#34; echo -e \u0026#34;\\n\u0026#34; #此脚本是参考nmgxy/klionsec修改而来,重新添加了一些特征，只用来临时救急，还是推荐到ELK或者Splunk中分析 #功能 ###统计Top 20 地址 ###SQL注入分析 ###SQL注入 FROM查询统计 ###扫描器/常用黑客工具 ###漏洞利用检测 ###敏感路径访问 ###文件包含攻击 ###HTTP Tunnel ###Webshell ###寻找响应长度的url Top 20 ###寻找罕见的脚本文件访问 ###寻找302跳转的脚本文件 #如果存在多个access文件或者有多个access.x.gz 建议先zcat access*.gz \u0026gt;\u0026gt; access.log文件中 #设置分析结果存储目录,结尾不能加/ outfile=/tmp/logs #如果目录以存在则清空，未存在则新建目录 if \u0026amp;#91; -d\u0026amp;lt;/span\u0026gt;outfile ]; then rm -rf \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;outfile/* else mkdir -p\u0026amp;lt;/span\u0026gt;outfile fi #设置nginx日志目录，结尾必须加/ access_dir=/var/log/nginx/ #设置文件名，如果文件名为access那么匹配的是access*文件 access_log=access #判断日志文件是否存在 num=\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(ls\u0026amp;lt;/span\u0026gt;{access_dir}\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{access_log}* | wc -l) \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 if \u0026amp;#91;\u0026amp;lt;/span\u0026gt;num -eq 0 ]; then echo \u0026#39;日志文件不存在\u0026#39; exit 1 fi echo -e \u0026#34;\\n\u0026#34; # 验证操作系统是debian系还是centos OS=\u0026#39;None\u0026#39; if \u0026amp;#91; -e \u0026#34;/etc/os-release\u0026#34; ]; then source /etc/os-release case \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{ID} in \u0026#34;debian\u0026#34; | \u0026#34;ubuntu\u0026#34; | \u0026#34;devuan\u0026#34;) OS=\u0026#39;Debian\u0026#39; ;; \u0026#34;centos\u0026#34; | \u0026#34;rhel fedora\u0026#34; | \u0026#34;rhel\u0026#34;) OS=\u0026#39;Centos\u0026#39; ;; *) ;; esac fi if \u0026amp;#91;\u0026amp;lt;/span\u0026gt;OS = \u0026#39;None\u0026#39; ]; then if command -v apt-get \u0026gt;/dev/null 2\u0026gt;\u0026amp;1; then OS=\u0026#39;Debian\u0026#39; elif command -v yum \u0026gt;/dev/null 2\u0026gt;\u0026amp;1; then OS=\u0026#39;Centos\u0026#39; else echo -e \u0026#34;\\n不支持这个系统\\n\u0026#34; echo -e \u0026#34;已退出\u0026#34; exit 1 fi fi # 检测ag软件有没有安装 if ag -V \u0026gt;/dev/null 2\u0026gt;\u0026amp;1; then echo -e \u0026#34;\\e\u0026amp;#91;00;32msilversearcher-ag已安装 \\e\u0026amp;#91;00m\u0026#34; else if \u0026amp;#91; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;OS = \u0026#39;Centos\u0026#39; ]; then yum -y install the_silver_searcher \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 else apt-get -y install silversearcher-ag \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 fi fi #如果检测别的日志请手动替换偏移，例如awk的\u0026amp;lt;/span\u0026gt;7代表url，\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9代表状态码，\u0026amp;lt;/span\u0026gt;10代表长度,本脚本是以nginx日志为基础 echo \u0026#34;分析结果日志：\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{outfile}\u0026#34; echo \u0026#34;Nginx日志目录：\u0026amp;lt;/span\u0026gt;{access_dir}\u0026#34; echo \u0026#34;Nginx文件名：\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{access_log}\u0026#34; echo -e \u0026#34;\\n\u0026#34; echo -e \u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]TOP 20 IP 地址\\e\u0026amp;#91;00m\u0026#34; ag -a -o --nofilename \u0026#39;\\d+\\.\\d+\\.\\d+\\.\\d+\u0026#39;\u0026amp;lt;/span\u0026gt;{access_dir}\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{access_log}* | sort | uniq -c | sort -nr | head -n 20 | tee -a\u0026amp;lt;/span\u0026gt;{outfile}/top20.log echo -e \u0026#34;\\n\u0026#34; echo -e \u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]SQL注入攻击分析\\e\u0026amp;#91;00m\u0026#34; #在SQL注入中排除掉了一些扫描css/js/png图片类等无用告警，并且重点筛选状态码200或者500的告警 ag -a \u0026#34;xp_cmdshell|%20xor|%20and|%20AND|%20or|%20OR|select%20|%20and%201=1|%20and%201=2|%20from|%27exec|information_schema.tables|load_file|benchmark|substring|table_name|table_schema|%20where%20|%20union%20|%20UNION%20|concat\\(|concat_ws\\(|%20group%20|0x5f|0x7e|0x7c|0x27|%20limit|\\bcurrent_user\\b|%20LIMIT|version%28|version\\(|database%28|database\\(|user%28|user\\(|%20extractvalue|%updatexml|rand\\(0\\)\\*2|%20group%20by%20x|%20NULL%2C|sqlmap\u0026#34; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{access_dir}\u0026amp;lt;/span\u0026gt;{access_log}* | ag -v \u0026#39;/\\w+\\.(?:js|css|html|jpg|jpeg|png|htm|swf)(?:\\?| )\u0026#39; | awk \u0026#39;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==200)||(\u0026amp;lt;/span\u0026gt;9==500) {print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;0}\u0026#39; \u0026gt;\u0026amp;lt;/span\u0026gt;{outfile}/sql.log awk \u0026#39;{print \u0026#34;SQL注入攻击\u0026#34; NR\u0026#34;次\u0026#34;}\u0026#39; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{outfile}/sql.log | tail -n1 echo \u0026#34;SQL注入 TOP 20 IP地址\u0026#34; ag -o \u0026#39;(?\u0026amp;lt;=:)\\d+\\.\\d+\\.\\d+\\.\\d+\u0026#39;\u0026amp;lt;/span\u0026gt;{outfile}/sql.log | sort | uniq -c | sort -nr | head -n 20 | tee -a \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{outfile}/sql_top20.log # 重点关注from查询，是否存在脱裤行为，排除扫描行为 echo \u0026#34;SQL注入 FROM 查询\u0026#34; cat\u0026amp;lt;/span\u0026gt;{outfile}/sql.log | ag \u0026#39;\\bfrom\\b\u0026#39; | ag -v \u0026#39;information_schema\u0026#39; \u0026gt;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{outfile}/sql_from_query.log awk \u0026#39;{print \u0026#34;SQL注入FROM查询\u0026#34; NR\u0026#34;次\u0026#34;}\u0026#39;\u0026amp;lt;/span\u0026gt;{outfile}/sql_from_query.log | tail -n1 echo -e \u0026#34;\\n\u0026#34; echo -e \u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]扫描器scan \u0026amp; 黑客工具\\e\u0026amp;#91;00m\u0026#34; ag -a \u0026#34;acunetix|by_wvs|nikto|netsparker|HP404|nsfocus|WebCruiser|owasp|nmap|nessus|HEAD /|AppScan|burpsuite|w3af|ZAP|openVAS|.+avij|.+angolin|360webscan|webscan|XSS@HERE|XSS%40HERE|NOSEC.JSky|wwwscan|wscan|antSword|WebVulnScan|WebInspect|ltx71|masscan|python-requests|Python-urllib|WinHttpRequest\u0026#34; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{access_dir}\u0026amp;lt;/span\u0026gt;{access_log}* | ag -v \u0026#39;/\\w+\\.(?:js|css|jpg|jpeg|png|swf)(?:\\?| )\u0026#39; | awk \u0026#39;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==200)||(\u0026amp;lt;/span\u0026gt;9==500) {print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;0}\u0026#39; \u0026gt;\u0026amp;lt;/span\u0026gt;{outfile}/scan.log awk \u0026#39;{print \u0026#34;共检测到扫描攻击\u0026#34; NR\u0026#34;次\u0026#34;}\u0026#39; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{outfile}/scan.log | tail -n1 echo \u0026#34;扫描工具流量 TOP 20\u0026#34; ag -o \u0026#39;(?\u0026amp;lt;=:)\\d+\\.\\d+\\.\\d+\\.\\d+\u0026#39;\u0026amp;lt;/span\u0026gt;{outfile}/scan.log | sort | uniq -c | sort -nr | head -n 20 | tee -a \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{outfile}/scan_top20.log echo -e \u0026#34;\\n\u0026#34; echo -e \u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]敏感路径访问\\e\u0026amp;#91;00m\u0026#34; ag -a \u0026#34;/_cat/|/_config/|include=|phpinfo|info\\.php|/web-console|JMXInvokerServlet|/manager/html|axis2-admin|axis2-web|phpMyAdmin|phpmyadmin|/admin-console|/jmx-console|/console/|\\.tar.gz|\\.tar|\\.tar.xz|\\.xz|\\.zip|\\.rar|\\.mdb|\\.inc|\\.sql|/\\.config\\b|\\.bak|/.svn/|/\\.git/|\\.hg|\\.DS_Store|\\.htaccess|nginx\\.conf|\\.bash_history|/CVS/|\\.bak|wwwroot|备份|/Web.config|/web.config|/1.txt|/test.txt\u0026#34;\u0026amp;lt;/span\u0026gt;{access_dir}\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{access_log}* | awk \u0026#39;(\u0026amp;lt;/span\u0026gt;9==200)||(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==500) {print\u0026amp;lt;/span\u0026gt;0}\u0026#39; \u0026gt;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{outfile}/dir.log awk \u0026#39;{print \u0026#34;共检测到针对敏感文件扫描\u0026#34; NR\u0026#34;次\u0026#34;}\u0026#39;\u0026amp;lt;/span\u0026gt;{outfile}/dir.log | tail -n1 echo \u0026#34;敏感文件访问流量 TOP 20\u0026#34; ag -o \u0026#39;(?\u0026amp;lt;=:)\\d+\\.\\d+\\.\\d+\\.\\d+\u0026#39; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{outfile}/dir.log | sort | uniq -c | sort -nr | head -n 20 | tee -a\u0026amp;lt;/span\u0026gt;{outfile}/dir_top20.log echo -e \u0026#34;\\n\u0026#34; echo -e \u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]漏洞利用检测\\e\u0026amp;#91;00m\u0026#34; ag -a \u0026#34;%00|/win.ini|/my.ini|\\.\\./\\.\\./|/etc/shadow|%0D%0A|file:/|gopher:/|dict:/|WindowsPowerShell|/wls-wsat/|call_user_func_array|uddiexplorer|@DEFAULT_MEMBER_ACCESS|@java\\.lang\\.Runtime|OgnlContext|/bin/bash|cmd\\.exe|wget\\s|curl\\s|s=/index/\\think\u0026#34; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{access_dir}\u0026amp;lt;/span\u0026gt;{access_log}* | awk \u0026#39;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==200)||(\u0026amp;lt;/span\u0026gt;9==500) {print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;0}\u0026#39; \u0026gt;\u0026amp;lt;/span\u0026gt;{outfile}/exploit.log awk \u0026#39;{print \u0026#34;漏洞利用探测\u0026#34; NR\u0026#34;次\u0026#34;}\u0026#39; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{outfile}/exploit.log | tail -n1 echo \u0026#34;漏洞利用检测 TOP 20\u0026#34; ag -o \u0026#39;(?\u0026amp;lt;=:)\\d+\\.\\d+\\.\\d+\\.\\d+\u0026#39;\u0026amp;lt;/span\u0026gt;{outfile}/exploit.log | sort | uniq -c | sort -nr | head -n 20 | tee -a \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{outfile}/exploit_top20.log echo -e \u0026#34;\\n\u0026#34; echo -e \u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]webshell\\e\u0026amp;#91;00m\u0026#34; ag -a \u0026#34;=whoami|dbname=|exec=|cmd=|\\br57\\b|\\bc99\\b|\\bc100\\b|\\bb374k\\b|adminer.php|eval\\(|assert\\(|%eval|%execute|tunnel\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|makewebtaski|ma\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|\\bup\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|cmd\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|201\\d\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|xiaoma\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|shell\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|404\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|tom\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|k8cmd\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|ver\u0026amp;#91;0-9]{3,4}\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|\\.aar|\u0026amp;#91;asp|php|jsp|aspx]{3,4}spy\\.|o=vLogin|aioshell|admine|ghost\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|r00ts|90sec|t00ls|editor\\.aspx|wso\\.\u0026amp;#91;asp|aspx]{3,4}\u0026#34;\u0026amp;lt;/span\u0026gt;{access_dir}\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{access_log}* | awk \u0026#39;(\u0026amp;lt;/span\u0026gt;9==200)||(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==500) {print\u0026amp;lt;/span\u0026gt;0}\u0026#39; \u0026gt;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{outfile}/webshell.log awk \u0026#39;{print \u0026#34;共检测到webshell行为\u0026#34; NR \u0026#34;次\u0026#34;}\u0026#39;\u0026amp;lt;/span\u0026gt;{outfile}/webshell.log | tail -n1 echo \u0026#34;Webshell TOP 20\u0026#34; ag -o \u0026#39;(?\u0026amp;lt;=:)\\d+\\.\\d+\\.\\d+\\.\\d+\u0026#39; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{outfile}/webshell.log | sort | uniq -c | sort -nr | head -n 20 | tee -a\u0026amp;lt;/span\u0026gt;{outfile}/webshell_top20.log echo -e \u0026#34;\\n\u0026#34; echo -e \u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]HTTP Tunnel\\e\u0026amp;#91;00m\u0026#34; #Regeorg代理特征 ag -a \u0026#34;cmd=disconnect|cmd=read|cmd=forward|cmd=connect|127.0.0.1\u0026#34; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{access_dir}\u0026amp;lt;/span\u0026gt;{access_log}* | awk \u0026#39;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==200)||(\u0026amp;lt;/span\u0026gt;9==500) {print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;0}\u0026#39; | tee -a\u0026amp;lt;/span\u0026gt;{outfile}/tunnel.log awk \u0026#39;{print \u0026#34;共检测到隧道行为\u0026#34; NR \u0026#34;次\u0026#34;}\u0026#39; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{outfile}/tunnel.log | tail -n1 echo -e \u0026#34;\\n\u0026#34; echo -e \u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]Top 20 url响应长度\\e\u0026amp;#91;00m\u0026#34; # 查找url响应长度最长的url排序，目的是有没有下载服务器的一些打包文件 len=\u0026amp;lt;/span\u0026gt;(cat \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{access_dir}\u0026amp;lt;/span\u0026gt;{access_log}* | awk \u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;10}\u0026#39; | sort -nr | head -n 20) echo\u0026amp;lt;/span\u0026gt;len | awk \u0026#39;BEGIN{ RS=\u0026#34; \u0026#34; }{ print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;0 }\u0026#39; | xargs -i{} ag -a --nocolor \u0026#39;\\d+\\s{}\\s\u0026#39;\u0026amp;lt;/span\u0026gt;{access_dir}\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{access_log}* | awk \u0026#39;{print\u0026amp;lt;/span\u0026gt;7,\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;10}\u0026#39; | sort | uniq | sort -k 2 -nr | tee -a\u0026amp;lt;/span\u0026gt;{outfile}/url_rsp_len.log echo -e \u0026#34;\\n\u0026#34; echo -e \u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]罕见的脚本文件访问\\e\u0026amp;#91;00m\u0026#34; echo \u0026#34;访问量特别特别少的脚本文件极有可能是webshell\u0026#34; cat \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{access_dir}\u0026amp;lt;/span\u0026gt;{access_log}* | awk \u0026#39;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==200)||(\u0026amp;lt;/span\u0026gt;9==500) {print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;7}\u0026#39; | sort | uniq -c | sort -n | ag -v \u0026#39;\\?\u0026#39; | ag \u0026#39;\\.php|\\.jsp|\\.asp|\\.aspx\u0026#39; | head -n 20 | tee -a\u0026amp;lt;/span\u0026gt;{outfile}/rare_url.log echo -e \u0026#34;\\n\u0026#34; echo -e \u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]302跳转\\e\u0026amp;#91;00m\u0026#34; echo \u0026#34;此目的是寻找一些登录成功的脚本文件\u0026#34; cat \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{access_dir}\u0026amp;lt;/span\u0026gt;{access_log}* | awk \u0026#39;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==302)||(\u0026amp;lt;/span\u0026gt;9==301) {print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;7}\u0026#39; | sort | uniq -c | sort -n | ag -v \u0026#39;\\?\u0026#39; | ag \u0026#39;\\.php|\\.jsp|\\.asp|\\.aspx\u0026#39; | head -n 20 | tee -a\u0026amp;lt;/span\u0026gt;{outfile}/302_goto.log echo -e \u0026#34;\\n\u0026#34; ###################################################################### #!/bin/bash echo \u0026#34;##########################################################################\u0026#34; echo \u0026#34;# nginx日志分析小工具,author:william,https://github.com/xiucaiwu #\u0026#34; echo \u0026#34;# 本工具暂时不支持跨天日志分析,Nginx日志格式为默认格式 #\u0026#34; echo \u0026#34;# 请输入要分析的时段(为空则分析全部日志): #\u0026#34; echo \u0026#34;# 分析今天3点10分到5点的数据:03:10-05:00 \u0026#34;-\u0026#34;前后没有空格 #\u0026#34; echo \u0026#34;# 分析2018年8月20号3点到5点的数据:2018-08-20 03:00-05:00 #\u0026#34; echo \u0026#34;##########################################################################\u0026#34; # 默认存放切割后的Nginx日志目录 default_parse_ngx_dir_path=\u0026#39;/opt/log/nginx\u0026#39; # 生成的切割后的Nginx日志路径 parse_ngx_path=\u0026#34;\u0026#34; # 默认Nginx日志路径 #default_ngx_path=\u0026#34;/usr/local/nginx/logs/host.access.145.`date \u0026#34;+%Y%m%d\u0026#34;`.log\u0026#34; default_ngx_path=\u0026#34;/root/wwwlog/access.log\u0026#34; # 记录用户手动输入Nginx日志路径的字符串长度 ngx_path_len=0 # 记录用户手动输入切割后的Nginx日志目录字符串长度 ngx_dir_path_len=0 # 一个空数组 array=() # 一个字符串分割另一个字符串 function str_split(){ # 分割字符串 delimiter=\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1 # 目标字符串 string=\u0026amp;lt;/span\u0026gt;2 # 注意后面有个空格 array=(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{string//\u0026amp;lt;/span\u0026gt;delimiter/ }) # return 只能返回int型数值 #\treturn \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;arr } read -p \u0026#34;请输入nginx日志文件路径:\u0026#34; ngx_path ngx_path_len=`echo\u0026amp;lt;/span\u0026gt;ngx_path | wc -L` if \u0026amp;#91; `echo \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;ngx_path | wc -L` == 0 ];then ngx_path=\u0026amp;lt;/span\u0026gt;default_ngx_path fi if \u0026amp;#91; ! -f \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;ngx_path ];then echo \u0026#34;日志不存在\u0026#34; #\texit fi read -p \u0026#34;请输入存放分析后的nginx日志文件夹路径,默认为/opt/log/nginx:\u0026#34; ngx_parse_dir_path if \u0026amp;#91; `echo\u0026amp;lt;/span\u0026gt;ngx_dir_path | wc -L` == 0 ];then ngx_parse_dir_path=\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;default_parse_ngx_dir_path fi if \u0026amp;#91; ! -d\u0026amp;lt;/span\u0026gt;ngx_parse_dir_path ];then echo \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;ngx_parse_dir_path \u0026#34;不存在\u0026#34; #\texit fi read -p \u0026#34;请输入要分析的时段(24小时制):\u0026#34; ngx_time # 统计输入的字符串长度 len=`echo\u0026amp;lt;/span\u0026gt;ngx_time | wc -L` if \u0026amp;#91; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;len == 0 ];then # 当前是几时几分 hour_minute=`date +%H:%I` filename=`date +%Y%m%d`\u0026#34;.log\u0026#34; mydate=`date +%d/%b/%Y` parse_ngx_path=\u0026amp;lt;/span\u0026gt;ngx_parse_dir_path/\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;filename echo -e \u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;/span\u0026gt;{parse_ngx_path}正在生成... \\033\u0026amp;#91;0m\u0026#34; awk -v mydate=\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;mydate -v arr=\u0026amp;lt;/span\u0026gt;hour_minute -F \u0026#34;\u0026amp;#91; /:]\u0026#34; \u0026#39;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026#34;/\u0026#34;\u0026amp;lt;/span\u0026gt;2\u0026#34;/\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;3==mydate \u0026amp;\u0026amp;\u0026amp;lt;/span\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;5\u0026gt;=\u0026#34;00:00\u0026#34; \u0026amp;\u0026amp;\u0026amp;lt;/span\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;5\u0026amp;lt;=arr\u0026#39;\u0026amp;lt;/span\u0026gt;ngx_path \u0026gt; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;parse_ngx_path echo -e \u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;/span\u0026gt;{parse_ngx_path}生成成功!!! \\033\u0026amp;#91;0m\u0026#34; elif \u0026amp;#91; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;len == 11 ];then # 统计\u0026#34;-\u0026#34;出现的次数 if \u0026amp;#91; `echo\u0026amp;lt;/span\u0026gt;ngx_time | grep -o \u0026#39;-\u0026#39; | wc -l` == 1 ];then # 当前日期 current_date=`date \u0026#34;+%Y-%m-%d %H:%M\u0026#34;` # 当前日期对应的时间戳 current_timestamp=`date -d \u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;current_date\u0026#34; +%s` str_split \u0026#34;-\u0026#34;\u0026amp;lt;/span\u0026gt;ngx_time # 用户输入的日期 user_date=\u0026#34;`date \\\u0026#34;+%Y-%m-%d\\\u0026#34;` \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{array\u0026amp;#91;0]}\u0026#34; # 用户输入的日期对应的时间戳 user_timestamp=`date -d \u0026#34;\u0026amp;lt;/span\u0026gt;user_date\u0026#34; +%s` filename=`date +%Y%m%d`\u0026#34;\u0026amp;#91;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{array\u0026amp;#91;0]}-\u0026amp;lt;/span\u0026gt;{array\u0026amp;#91;1]}].log\u0026#34; mydate=`date +%d/%b/%Y` parse_ngx_path=\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;ngx_parse_dir_path/\u0026amp;lt;/span\u0026gt;filename if \u0026amp;#91; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;user_timestamp ==\u0026amp;lt;/span\u0026gt;current_timestamp ];then echo -e \u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{parse_ngx_path}正在生成... \\033\u0026amp;#91;0m\u0026#34; awk -v mydate=\u0026amp;lt;/span\u0026gt;mydate -v arr1=\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{array\u0026amp;#91;0]} -v arr2=\u0026amp;lt;/span\u0026gt;{array\u0026amp;#91;1]} -F \u0026#34;\u0026amp;#91; /:]\u0026#34; \u0026#39;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026#34;/\u0026#34;\u0026amp;lt;/span\u0026gt;2\u0026#34;/\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;3==mydate \u0026amp;\u0026amp;\u0026amp;lt;/span\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;5\u0026gt;=arr1 \u0026amp;\u0026amp;\u0026amp;lt;/span\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;5\u0026amp;lt;=arr2\u0026#39;\u0026amp;lt;/span\u0026gt;ngx_path \u0026gt; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;parse_ngx_path echo -e \u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;/span\u0026gt;{parse_ngx_path}生成成功!!! \\033\u0026amp;#91;0m\u0026#34; elif \u0026amp;#91; ! -f \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;parse_ngx_path ];then echo -e \u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;/span\u0026gt;{parse_ngx_path}正在生成... \\033\u0026amp;#91;0m\u0026#34; awk -v mydate=\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;mydate -v arr1=\u0026amp;lt;/span\u0026gt;{array\u0026amp;#91;0]} -v arr2=\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{array\u0026amp;#91;1]} -F \u0026#34;\u0026amp;#91; /:]\u0026#34; \u0026#39;\u0026amp;lt;/span\u0026gt;1\u0026#34;/\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2\u0026#34;/\u0026#34;\u0026amp;lt;/span\u0026gt;3==mydate \u0026amp;\u0026amp; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;/span\u0026gt;5\u0026gt;=arr1 \u0026amp;\u0026amp; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;/span\u0026gt;5\u0026amp;lt;=arr2\u0026#39; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;ngx_path \u0026gt;\u0026amp;lt;/span\u0026gt;parse_ngx_path echo -e \u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{parse_ngx_path}生成成功!!! \\033\u0026amp;#91;0m\u0026#34; fi else echo \u0026#34;格式输入不正确\u0026#34; exit fi elif \u0026amp;#91;\u0026amp;lt;/span\u0026gt;len == 22 ];then\t# 统计\u0026#34;-\u0026#34;出现的次数 if \u0026amp;#91; `echo \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;ngx_time | grep -o \u0026#39;-\u0026#39; | wc -l` == 3 ];then str_split \u0026#34; \u0026#34; \u0026#34;\u0026amp;lt;/span\u0026gt;ngx_time\u0026#34; # 自定义日期格式 mydate1=`date -d \u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{array\u0026amp;#91;0]}\u0026#34; +%d/%b/%Y` # 日期转时间戳 timestamp=`date -d \u0026#34;\u0026amp;lt;/span\u0026gt;{array\u0026amp;#91;0]}\u0026#34; +%s` # 时间戳转日期 mydate2=`date -d @\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;timestamp \u0026#34;+%Y%m%d\u0026#34;` str_split \u0026#34;-\u0026#34;\u0026amp;lt;/span\u0026gt;{array\u0026amp;#91;1]} filename=\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;mydate2\u0026#34;\u0026amp;#91;\u0026amp;lt;/span\u0026gt;{array\u0026amp;#91;0]}-\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{array\u0026amp;#91;1]}].log\u0026#34; parse_ngx_path=\u0026amp;lt;/span\u0026gt;ngx_parse_dir_path/\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;filename if \u0026amp;#91; ! -f\u0026amp;lt;/span\u0026gt;parse_ngx_path ];then echo -e \u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{parse_ngx_path}正在生成... \\033\u0026amp;#91;0m\u0026#34; awk -v mydate=\u0026amp;lt;/span\u0026gt;mydate1 -v arr1=\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{array\u0026amp;#91;0]} -v arr2=\u0026amp;lt;/span\u0026gt;{array\u0026amp;#91;1]} -F \u0026#34;\u0026amp;#91; /:]\u0026#34; \u0026#39;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026#34;/\u0026#34;\u0026amp;lt;/span\u0026gt;2\u0026#34;/\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;3==mydate \u0026amp;\u0026amp;\u0026amp;lt;/span\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;5\u0026gt;=arr1 \u0026amp;\u0026amp;\u0026amp;lt;/span\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;5\u0026amp;lt;=arr2\u0026#39;\u0026amp;lt;/span\u0026gt;ngx_path \u0026gt; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;parse_ngx_path echo -e \u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;/span\u0026gt;{parse_ngx_path}生成成功!!! \\033\u0026amp;#91;0m\u0026#34; fi else echo \u0026#34;格式输入不正确\u0026#34; exit fi else echo \u0026#34;格式输入不正确\u0026#34; exit fi # 开始解析切割后的Nginx日志 if \u0026amp;#91; ! -f \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;parse_ngx_path ];then echo -e \u0026#34;\\033\u0026amp;#91;31m 文件\u0026amp;lt;/span\u0026gt;{parse_ngx_path}不存在 \\033\u0026amp;#91;0m\u0026#34; fi # 统计访问最多的ip echo -e \u0026#34;\\033\u0026amp;#91;31m 访问TOP10的IP: \\033\u0026amp;#91;0m\u0026#34; awk \u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1}\u0026#39;\u0026amp;lt;/span\u0026gt;parse_ngx_path | sort | uniq -c | sort -n -k 1 -r | head -n 10 ip_array=`(awk \u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1}\u0026#39;\u0026amp;lt;/span\u0026gt;parse_ngx_path | sort | uniq -c | sort -n -k 1 -r | head -n 10 | awk \u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2}\u0026#39;)` # 统计访问最多的url echo -e \u0026#34;\\033\u0026amp;#91;31m 访问TOP10的URL: \\033\u0026amp;#91;0m\u0026#34; awk \u0026#39;{print\u0026amp;lt;/span\u0026gt;7}\u0026#39; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;parse_ngx_path | sort |uniq -c | sort -rn | head -n 10 # 统计ip对应的url for i in\u0026amp;lt;/span\u0026gt;{ip_array\u0026amp;#91;@]};do echo -e \u0026#34;\\033\u0026amp;#91;31m IP(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{i})访问TOP10的URL: \\033\u0026amp;#91;0m\u0026#34; cat access.log | grep\u0026amp;lt;/span\u0026gt;i |awk \u0026#39;{print $7}\u0026#39;| sort | uniq -c | sort -rn | head -10 | more done` ","permalink":"https://blog.zdltech.com/posts/%E9%85%8D%E7%BD%AE%E6%9F%A5%E8%AF%A2nginx%E4%B8%AD%E5%BC%82%E5%B8%B8ip%E5%A4%84%E7%90%86/","summary":"\u003cp\u003e很多时候会发现好多，异常流量，处理这些异常流量，通常是封禁IP\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\u003cspan style=\"color:#6272a4\"\u003e# deny_ip_o.sh  文件内容\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#!/bin/bash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003emax\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e500\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#我们设定的最大值，当访问量大于这个值得时候，封锁\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003elogdir\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e/opt/nginx/logs/access.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#nginx 访问日志文件路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003econfdir\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e/opt/nginx/logs/nginx_deny.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#检测文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etest\u003c/span\u003e -e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003econfdir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e touch\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003econfdir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eport\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e443\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003edrop_Ip\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#循环遍历日志文件取出访问量大于 500 的 ip\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e drop_Ip  in \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e(\u003c/span\u003etail -n500000\u0026amp;lt;/span\u0026gt;logdir | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1}\u0026#39;\u003c/span\u003e | sort | uniq -c | sort -rn  | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{if (\u0026amp;lt;/span\u0026gt;1\u0026gt;500) print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2}\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/span\u0026gt;{drop_Ip}---\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{drop_ip}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  grep  -q  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/span\u0026gt;{drop_Ip}\u0026#34;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003econfdir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eeg\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eeg\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e((\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eeg\u003cspan style=\"color:#ff79c6\"\u003e}==\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e))\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tiptables -I INPUT -p tcp --dport \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eport\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e -s\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003edrop_Ip\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e -j DROP\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt;  \u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{drop_Ip} \u0026#34;\u003c/span\u003e \u0026gt;\u0026gt; /opt/nginx/logs/nginx_deny.log  \u003cspan style=\"color:#6272a4\"\u003e#记录 log\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e####################################################################\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#!/bin/bash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#_日志位置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003e_log_Path\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/data0/nginx/weblogs/\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#_日志文件名称\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003e_log_FileName\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;access_blog.kinggoo.com.log\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#_要被屏蔽的ip访问端口，默认80\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003e_port\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;80\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003e_nginx_deny\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/opt/webserver/nginx/conf/deny.conf\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003e_nginx_bin\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/opt/webserver/nginx/sbin/nginx\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003e_logfilepath\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003e_log_Path\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003e_log_FileName\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#初始化被禁ip变量 \u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003e_drop_Ip\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#检测文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etest\u003c/span\u003e -e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003e_nginx_deny\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e touch \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003e_nginx_deny\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e _drop_Ip in\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e(\u003c/span\u003e tail -n50000 \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{_logfilepath}\u0026#34;\u003c/span\u003e |awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print\u0026amp;lt;/span\u0026gt;1,\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;12}\u0026#39;\u003c/span\u003e |grep -i -v -E \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;google|yahoo|baidu|msnbot|FeedSky|sogou|WordPress\u0026#34;\u003c/span\u003e |awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print\u0026amp;lt;/span\u0026gt;1}\u0026#39;\u003c/span\u003e|sort|uniq -c|sort -rn  |awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{if(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026gt;1000)print \u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;2\u0026#34;\u0026#34;}\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e)\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         grep  -q  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{_drop_Ip}\u0026#34;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003e_nginx_deny\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eeg\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eeg\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e ;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e((\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eeg\u003cspan style=\"color:#ff79c6\"\u003e}==\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e))\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;deny\u0026amp;lt;/span\u0026gt;{_drop_Ip};\u0026#34;\u003c/span\u003e \u0026gt;\u0026gt; \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003e_nginx_deny\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003e_nginx_bin\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e -s  reload\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                iptables -I INPUT -p tcp -dport \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003e_port\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e -s\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003e_drop_Ip\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e -j DROP\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt;  \u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{_drop_Ip} \u0026#34;\u003c/span\u003e \u0026gt;\u0026gt; /tmp/nginx_deny.log;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;iptables -I INPUT -p tcp --dport\u0026amp;lt;/span\u0026gt;{_port} -s \u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{_drop_Ip} -j DROP\u0026#34;\u003c/span\u003e \u0026gt;\u0026gt; /tmp/nginx_deny.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         \u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e使用 nginx 封锁\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e...\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-封锁 IP\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#!/bin/bash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003emax\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e500\u003c/span\u003e    \u003cspan style=\"color:#6272a4\"\u003e#我们设定的最大值，当访问量大于这个值得时候，封锁\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003econfdir\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e/usr/local/data/nginx/conf/blockip.conf \u003cspan style=\"color:#6272a4\"\u003e#nginx 封锁配置文件路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003elogdir\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e/usr/local/data/nginx/logs/access_huke88.log  \u003cspan style=\"color:#6272a4\"\u003e#nginx 访问日志文件路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#检测文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etest\u003c/span\u003e -e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003econfdir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e touch \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003econfdir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003edrop_ip\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#循环遍历日志文件取出访问量大于 500 的 ip\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e drop_ip  in\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e(\u003c/span\u003ecat \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;logdir | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print\u0026amp;lt;/span\u0026gt;1}\u0026#39;\u003c/span\u003e | sort | uniq -c | sort -rn  | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{if (\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026gt;500) print\u0026amp;lt;/span\u0026gt;2}\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  grep  -q  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{drop_Ip}\u0026#34;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003econfdir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eeg\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eeg\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e((\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eeg\u003cspan style=\"color:#ff79c6\"\u003e}==\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e))\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;deny\u0026amp;lt;/span\u0026gt;{drop_Ip};\u0026#34;\u003c/span\u003e\u0026gt;\u0026gt;\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;confdir  \u003cspan style=\"color:#6272a4\"\u003e#把“ deny IP ；”语句写入封锁配置文件中\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt;\u0026amp;lt;/span\u0026gt;{drop_Ip} \u0026#34;\u003c/span\u003e \u0026gt;\u0026gt; /usr/local/data/nginx/logs/nginx_deny.log  \u003cspan style=\"color:#6272a4\"\u003e#记录 log\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eservice nginx reload\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-解锁 IP\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#！/bin/bash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esed -i \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;s/^/#\u0026amp;/g\u0026#39;\u003c/span\u003e /usr/local/nginx/conf/blockip.conf  \u003cspan style=\"color:#6272a4\"\u003e#把 nginx 封锁配置文件中的内容注释掉\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eservice nginx reload   \u003cspan style=\"color:#6272a4\"\u003e#重置 nginx 服务，这样就做到了解锁 IP\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e使用 iptables 封锁\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e...\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-封锁 IP 脚本\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#!/bin/bash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003emax\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e500\u003c/span\u003e    \u003cspan style=\"color:#6272a4\"\u003e#我们设定的最大值，当访问量大于这个值得时候，封锁\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003elogdir\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e/usr/local/data/nginx/logs/access_huke88.log  \u003cspan style=\"color:#6272a4\"\u003e#nginx 访问日志文件路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003econfdir\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e/usr/local/data/nginx/conf/blockip.conf \u003cspan style=\"color:#6272a4\"\u003e#nginx 封锁配置文件路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#检测文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etest\u003c/span\u003e -e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003econfdir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e touch\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003econfdir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eport\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e80\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003edrop_ip\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#循环遍历日志文件取出访问量大于 500 的 ip\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e drop_ip  in \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e(\u003c/span\u003ecat\u0026amp;lt;/span\u0026gt;logdir | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1}\u0026#39;\u003c/span\u003e | sort | uniq -c | sort -rn  | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{if (\u0026amp;lt;/span\u0026gt;1\u0026gt;500) print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2}\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  grep  -q  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/span\u0026gt;{drop_Ip}\u0026#34;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003econfdir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eeg\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eeg\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e((\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eeg\u003cspan style=\"color:#ff79c6\"\u003e}==\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e))\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     iptables -I INPUT -p tcp --dport \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eport\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e -s\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003edrop_Ip\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e -j DROP\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt;  \u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{drop_Ip} \u0026#34;\u003c/span\u003e \u0026gt;\u0026gt; /usr/local/data/nginx/logs/nginx_deny.log  \u003cspan style=\"color:#6272a4\"\u003e#记录 log\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e...\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e加入计划任务每五分钟执行一次\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003echmod +x /home/scripts/deny_ip.sh\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#####nginx 封 ip######\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e*/5 * * * * /bin/sh /home/scripts/deny_ip.sh \u0026gt;/dev/null 2\u0026gt;\u0026amp;\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e### 添加定时任务\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e*/5 * * * * /bin/sh /opt/nginx/logs/deny_ip_o.sh \u0026gt;/dev/null 2\u0026gt;\u0026amp;\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etail -n \u003cspan style=\"color:#bd93f9\"\u003e500000\u003c/span\u003e access.log | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print\u0026amp;lt;/span\u0026gt;1,\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;13,\u0026amp;lt;/span\u0026gt;8}\u0026#39;\u003c/span\u003e|awk  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1}\u0026#39;\u003c/span\u003e|sort|uniq -c |sort -rn | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{if(\u0026amp;lt;/span\u0026gt;1\u0026gt;100)print \u0026#34;deny \u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1,\u0026amp;lt;/span\u0026gt;2\u0026#34;;\u0026#34;}\u0026#39;\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etail -n \u003cspan style=\"color:#bd93f9\"\u003e500000000\u003c/span\u003e access.log | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1,\u0026amp;lt;/span\u0026gt;13,\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;8}\u0026#39;\u003c/span\u003e|awk  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print\u0026amp;lt;/span\u0026gt;1}\u0026#39;\u003c/span\u003e|sort|uniq -c |sort -rn | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{if(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026gt;100)print \u0026#34;deny \u0026#34;\u0026amp;lt;/span\u0026gt;2\u0026#34;;\u0026#34;}\u0026#39;\u003c/span\u003e \u0026gt; blockip.conf\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etail -n \u003cspan style=\"color:#bd93f9\"\u003e500000\u003c/span\u003e access.log | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1,\u0026amp;lt;/span\u0026gt;13,\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;8}\u0026#39;\u003c/span\u003e|awk  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print\u0026amp;lt;/span\u0026gt;1}\u0026#39;\u003c/span\u003e|sort|uniq -c |sort -rn | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{if(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026gt;100)print \u0026#34;deny \u0026#34;\u0026amp;lt;/span\u0026gt;2\u0026#34;;\u0026#34;}\u0026#39;\u003c/span\u003e \u0026gt;\u0026gt; blockip.conf\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#6272a4\"\u003e#if (\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;http_referer ~* \u0026#34;top1top1.top\u0026#34;) {\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#6272a4\"\u003e#      rewrite ^/ http://top.top1top1.top/CallHelper/client/main.jsp;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#6272a4\"\u003e#}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e(\u003c/span\u003e\u0026amp;lt;/span\u0026gt;http_referer ~* \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;top1top1.top\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e 404;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e(\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;http_referer ~* \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;shandiandxshop.xyz\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                 rewrite ^/ http://tt.shandiandxshop.xyz/CallHelper/client/index.jsp;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehttps:\u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#47;\u0026amp;#47;blog.csdn.net/qq_41018743/article/details/105491785\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehttp://www.siwei.me/blog/posts/linux-nginx-ip-ip\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e####################################################################\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#!/bin/bash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003enum\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e100\t\u003cspan style=\"color:#6272a4\"\u003e#  每秒某个ip的访问上限\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003elist\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003enetstat -an |grep ^tcp.*:80|egrep -v \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;LISTEN|127.0.0.1\u0026#39;\u003c/span\u003e|awk -F\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;#91; ]+|\u0026amp;#91;:]\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print\u0026amp;lt;/span\u0026gt;6}\u0026#39;\u003c/span\u003e|sort|uniq -c|sort -rn|awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{if (\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026gt;\u0026amp;lt;/span\u0026gt;num){print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2}}\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e i in\u0026amp;lt;/span\u0026gt;list\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tiptables -I INPUT -s \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;i --dport \u003cspan style=\"color:#bd93f9\"\u003e80\u003c/span\u003e -j DROP\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt;\u0026amp;lt;/span\u0026gt;{\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;i} \u0026#34;\u003c/span\u003e \u0026gt;\u0026gt; /opt/nginx/logs/nginx_deny80.log  \u003cspan style=\"color:#6272a4\"\u003e#记录 log\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#####################################################################\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#!/bin/bash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003enum\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e100\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003elist\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003enetstat -an |grep ^tcp.*:80|egrep -v \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;LISTEN|127.0.0.1\u0026#39;\u003c/span\u003e|awk -F\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;#91; ]+|\u0026amp;#91;:]\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print\u0026amp;lt;/span\u0026gt;6}\u0026#39;\u003c/span\u003e|sort|uniq -c|sort -rn|awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{if (\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026gt;\u0026amp;lt;/span\u0026gt;num){print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2}}\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e i in\u0026amp;lt;/span\u0026gt;list\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        iptables -I INPUT -p tcp --dport \u003cspan style=\"color:#bd93f9\"\u003e80\u003c/span\u003e -s \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003ei\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e -j DROP\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt;\u0026amp;lt;/span\u0026gt;{i} \u0026#34;\u003c/span\u003e \u0026gt;\u0026gt; /opt/nginx/logs/nginx_deny80.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#######################################################################\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#!/bin/bash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003emax\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e500\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#我们设定的最大值，当访问量大于这个值得时候，封锁\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003elogdir\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e/opt/nginx/logs/access.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#nginx 访问日志文件路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003econfdir\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e/opt/nginx/logs/nginx_deny.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#检测文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etest\u003c/span\u003e -e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003econfdir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e touch\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003econfdir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eport\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e80\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003edrop_ip\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#循环遍历日志文件取出访问量大于 500 的 ip\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e drop_ip  in \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e(\u003c/span\u003etail -n5000000\u0026amp;lt;/span\u0026gt;logdir | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1}\u0026#39;\u003c/span\u003e | sort | uniq -c | sort -rn  | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{if (\u0026amp;lt;/span\u0026gt;1\u0026gt;500) print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2}\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  grep  -q  \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/span\u0026gt;{drop_Ip}\u0026#34;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003econfdir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eeg\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eeg\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e((\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eeg\u003cspan style=\"color:#ff79c6\"\u003e}==\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e))\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     iptables -I INPUT -p tcp --dport \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eport\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e -s\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003edrop_Ip\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e -j DROP\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; `date \u0026#39;+%Y-%m-%d %H%M%S\u0026#39;` - 发现攻击源地址 -\u0026gt;  \u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{drop_Ip} \u0026#34;\u003c/span\u003e \u0026gt;\u0026gt; /opt/nginx/logs/nginx_deny.log  \u003cspan style=\"color:#6272a4\"\u003e#记录 log\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e####################################################################\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#!/usr/bin/env bash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; ========================================================= \u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; \\                 Nginx日志安全分析脚本 V1.0            / \u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; ========================================================= \u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; # 支持Nginx日志分析，攻击告警分析等                    \u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; # author：al0ne                    \u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; # https://github.com/al0ne                    \u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#此脚本是参考nmgxy/klionsec修改而来,重新添加了一些特征，只用来临时救急，还是推荐到ELK或者Splunk中分析\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#功能\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e###统计Top 20 地址\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e###SQL注入分析\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e###SQL注入 FROM查询统计\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e###扫描器/常用黑客工具\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e###漏洞利用检测\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e###敏感路径访问\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e###文件包含攻击\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e###HTTP Tunnel\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e###Webshell\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e###寻找响应长度的url Top 20\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e###寻找罕见的脚本文件访问\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e###寻找302跳转的脚本文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#如果存在多个access文件或者有多个access.x.gz 建议先zcat access*.gz \u0026gt;\u0026gt; access.log文件中\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#设置分析结果存储目录,结尾不能加/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eoutfile\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e/tmp/logs\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#如果目录以存在则清空，未存在则新建目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; -d\u0026amp;lt;/span\u0026gt;outfile ]; then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    rm -rf \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;outfile/*\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    mkdir -p\u0026amp;lt;/span\u0026gt;outfile\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#设置nginx日志目录，结尾必须加/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eaccess_dir\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e/var/log/nginx/\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#设置文件名，如果文件名为access那么匹配的是access*文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eaccess_log\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eaccess\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#判断日志文件是否存在\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003enum\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e(\u003c/span\u003els\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_dir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_log\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e* | wc -l\u003cspan style=\"color:#ff79c6\"\u003e)\u003c/span\u003e \u0026gt;/dev/null 2\u0026gt;\u0026amp;\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91;\u0026amp;lt;/span\u0026gt;num -eq 0 ]; then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;日志文件不存在\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eexit\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 验证操作系统是debian系还是centos\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eOS\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;None\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; -e \u0026#34;/etc/os-release\u0026#34; ]; then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003esource\u003c/span\u003e /etc/os-release\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003ecase\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eID\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e in\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;debian\u0026#34;\u003c/span\u003e | \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;ubuntu\u0026#34;\u003c/span\u003e | \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;devuan\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eOS\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Debian\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;centos\u0026#34;\u003c/span\u003e | \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;rhel fedora\u0026#34;\u003c/span\u003e | \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;rhel\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eOS\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Centos\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    *\u003cspan style=\"color:#ff79c6\"\u003e)\u003c/span\u003e ;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eesac\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91;\u0026amp;lt;/span\u0026gt;OS = \u0026#39;None\u0026#39; ]; then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003ecommand\u003c/span\u003e -v apt-get \u0026gt;/dev/null 2\u0026gt;\u0026amp;1; \u003cspan style=\"color:#ff79c6\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eOS\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Debian\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eelif\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003ecommand\u003c/span\u003e -v yum \u0026gt;/dev/null 2\u0026gt;\u0026amp;1; \u003cspan style=\"color:#ff79c6\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eOS\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Centos\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n不支持这个系统\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;已退出\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eexit\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 检测ag软件有没有安装\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e ag -V \u0026gt;/dev/null 2\u0026gt;\u0026amp;1; \u003cspan style=\"color:#ff79c6\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\e\u0026amp;#91;00;32msilversearcher-ag已安装 \\e\u0026amp;#91;00m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;OS = \u0026#39;Centos\u0026#39; ]; then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        yum -y install the_silver_searcher \u0026gt;/dev/null 2\u0026gt;\u0026amp;\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        apt-get -y install silversearcher-ag \u0026gt;/dev/null 2\u0026gt;\u0026amp;\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#如果检测别的日志请手动替换偏移，例如awk的\u0026amp;lt;/span\u0026gt;7代表url，\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9代表状态码，\u0026amp;lt;/span\u0026gt;10代表长度,本脚本是以nginx日志为基础\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;分析结果日志：\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{outfile}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Nginx日志目录：\u0026amp;lt;/span\u0026gt;{access_dir}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Nginx文件名：\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{access_log}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]TOP 20 IP 地址\\e\u0026amp;#91;00m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eag -a -o --nofilename \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\\d+\\.\\d+\\.\\d+\\.\\d+\u0026#39;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_dir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_log\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e* | sort | uniq -c | sort -nr | head -n \u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e | tee -a\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/top20.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]SQL注入攻击分析\\e\u0026amp;#91;00m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#在SQL注入中排除掉了一些扫描css/js/png图片类等无用告警，并且重点筛选状态码200或者500的告警\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eag -a \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;xp_cmdshell|%20xor|%20and|%20AND|%20or|%20OR|select%20|%20and%201=1|%20and%201=2|%20from|%27exec|information_schema.tables|load_file|benchmark|substring|table_name|table_schema|%20where%20|%20union%20|%20UNION%20|concat\\(|concat_ws\\(|%20group%20|0x5f|0x7e|0x7c|0x27|%20limit|\\bcurrent_user\\b|%20LIMIT|version%28|version\\(|database%28|database\\(|user%28|user\\(|%20extractvalue|%updatexml|rand\\(0\\)\\*2|%20group%20by%20x|%20NULL%2C|sqlmap\u0026#34;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_dir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_log\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e* | ag -v \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/\\w+\\.(?:js|css|html|jpg|jpeg|png|htm|swf)(?:\\?| )\u0026#39;\u003c/span\u003e | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==200)||(\u0026amp;lt;/span\u0026gt;9==500) {print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;0}\u0026#39;\u003c/span\u003e \u0026gt;\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/sql.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eawk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026#34;SQL注入攻击\u0026#34; NR\u0026#34;次\u0026#34;}\u0026#39;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/sql.log | tail -n1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;SQL注入 TOP 20 IP地址\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eag -o \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;(?\u0026amp;lt;=:)\\d+\\.\\d+\\.\\d+\\.\\d+\u0026#39;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/sql.log | sort | uniq -c | sort -nr | head -n \u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e | tee -a \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/sql_top20.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 重点关注from查询，是否存在脱裤行为，排除扫描行为\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;SQL注入 FROM 查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecat\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/sql.log | ag \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\\bfrom\\b\u0026#39;\u003c/span\u003e | ag -v \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;information_schema\u0026#39;\u003c/span\u003e \u0026gt;\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/sql_from_query.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eawk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026#34;SQL注入FROM查询\u0026#34; NR\u0026#34;次\u0026#34;}\u0026#39;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/sql_from_query.log | tail -n1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]扫描器scan \u0026amp; 黑客工具\\e\u0026amp;#91;00m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eag -a \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;acunetix|by_wvs|nikto|netsparker|HP404|nsfocus|WebCruiser|owasp|nmap|nessus|HEAD /|AppScan|burpsuite|w3af|ZAP|openVAS|.+avij|.+angolin|360webscan|webscan|XSS@HERE|XSS%40HERE|NOSEC.JSky|wwwscan|wscan|antSword|WebVulnScan|WebInspect|ltx71|masscan|python-requests|Python-urllib|WinHttpRequest\u0026#34;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_dir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_log\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e* | ag -v \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/\\w+\\.(?:js|css|jpg|jpeg|png|swf)(?:\\?| )\u0026#39;\u003c/span\u003e | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==200)||(\u0026amp;lt;/span\u0026gt;9==500) {print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;0}\u0026#39;\u003c/span\u003e \u0026gt;\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/scan.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eawk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026#34;共检测到扫描攻击\u0026#34; NR\u0026#34;次\u0026#34;}\u0026#39;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/scan.log | tail -n1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;扫描工具流量 TOP 20\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eag -o \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;(?\u0026amp;lt;=:)\\d+\\.\\d+\\.\\d+\\.\\d+\u0026#39;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/scan.log | sort | uniq -c | sort -nr | head -n \u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e | tee -a \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/scan_top20.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]敏感路径访问\\e\u0026amp;#91;00m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eag -a \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/_cat/|/_config/|include=|phpinfo|info\\.php|/web-console|JMXInvokerServlet|/manager/html|axis2-admin|axis2-web|phpMyAdmin|phpmyadmin|/admin-console|/jmx-console|/console/|\\.tar.gz|\\.tar|\\.tar.xz|\\.xz|\\.zip|\\.rar|\\.mdb|\\.inc|\\.sql|/\\.config\\b|\\.bak|/.svn/|/\\.git/|\\.hg|\\.DS_Store|\\.htaccess|nginx\\.conf|\\.bash_history|/CVS/|\\.bak|wwwroot|备份|/Web.config|/web.config|/1.txt|/test.txt\u0026#34;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_dir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_log\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e* | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;(\u0026amp;lt;/span\u0026gt;9==200)||(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==500) {print\u0026amp;lt;/span\u0026gt;0}\u0026#39;\u003c/span\u003e \u0026gt;\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/dir.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eawk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026#34;共检测到针对敏感文件扫描\u0026#34; NR\u0026#34;次\u0026#34;}\u0026#39;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/dir.log | tail -n1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;敏感文件访问流量 TOP 20\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eag -o \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;(?\u0026amp;lt;=:)\\d+\\.\\d+\\.\\d+\\.\\d+\u0026#39;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/dir.log | sort | uniq -c | sort -nr | head -n \u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e | tee -a\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/dir_top20.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]漏洞利用检测\\e\u0026amp;#91;00m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eag -a \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;%00|/win.ini|/my.ini|\\.\\./\\.\\./|/etc/shadow|%0D%0A|file:/|gopher:/|dict:/|WindowsPowerShell|/wls-wsat/|call_user_func_array|uddiexplorer|@DEFAULT_MEMBER_ACCESS|@java\\.lang\\.Runtime|OgnlContext|/bin/bash|cmd\\.exe|wget\\s|curl\\s|s=/index/\\think\u0026#34;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_dir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_log\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e* | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==200)||(\u0026amp;lt;/span\u0026gt;9==500) {print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;0}\u0026#39;\u003c/span\u003e \u0026gt;\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/exploit.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eawk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026#34;漏洞利用探测\u0026#34; NR\u0026#34;次\u0026#34;}\u0026#39;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/exploit.log | tail -n1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;漏洞利用检测 TOP 20\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eag -o \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;(?\u0026amp;lt;=:)\\d+\\.\\d+\\.\\d+\\.\\d+\u0026#39;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/exploit.log | sort | uniq -c | sort -nr | head -n \u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e | tee -a \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/exploit_top20.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]webshell\\e\u0026amp;#91;00m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eag -a \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;=whoami|dbname=|exec=|cmd=|\\br57\\b|\\bc99\\b|\\bc100\\b|\\bb374k\\b|adminer.php|eval\\(|assert\\(|%eval|%execute|tunnel\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|makewebtaski|ma\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|\\bup\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|cmd\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|201\\d\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|xiaoma\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|shell\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|404\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|tom\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|k8cmd\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|ver\u0026amp;#91;0-9]{3,4}\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|\\.aar|\u0026amp;#91;asp|php|jsp|aspx]{3,4}spy\\.|o=vLogin|aioshell|admine|ghost\\.\u0026amp;#91;asp|php|jsp|aspx]{3,4}|r00ts|90sec|t00ls|editor\\.aspx|wso\\.\u0026amp;#91;asp|aspx]{3,4}\u0026#34;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_dir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_log\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e* | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;(\u0026amp;lt;/span\u0026gt;9==200)||(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==500) {print\u0026amp;lt;/span\u0026gt;0}\u0026#39;\u003c/span\u003e \u0026gt;\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/webshell.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eawk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026#34;共检测到webshell行为\u0026#34; NR \u0026#34;次\u0026#34;}\u0026#39;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/webshell.log | tail -n1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Webshell TOP 20\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eag -o \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;(?\u0026amp;lt;=:)\\d+\\.\\d+\\.\\d+\\.\\d+\u0026#39;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/webshell.log | sort | uniq -c | sort -nr | head -n \u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e | tee -a\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/webshell_top20.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]HTTP Tunnel\\e\u0026amp;#91;00m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#Regeorg代理特征\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eag -a \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cmd=disconnect|cmd=read|cmd=forward|cmd=connect|127.0.0.1\u0026#34;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_dir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_log\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e* | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==200)||(\u0026amp;lt;/span\u0026gt;9==500) {print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;0}\u0026#39;\u003c/span\u003e | tee -a\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/tunnel.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eawk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026#34;共检测到隧道行为\u0026#34; NR \u0026#34;次\u0026#34;}\u0026#39;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/tunnel.log | tail -n1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]Top 20 url响应长度\\e\u0026amp;#91;00m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 查找url响应长度最长的url排序，目的是有没有下载服务器的一些打包文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003elen\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e(\u003c/span\u003ecat \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_dir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_log\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e* | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;10}\u0026#39;\u003c/span\u003e | sort -nr | head -n 20\u003cspan style=\"color:#ff79c6\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eecho\u0026amp;lt;/span\u0026gt;len | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;BEGIN{ RS=\u0026#34; \u0026#34; }{ print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;0 }\u0026#39;\u003c/span\u003e | xargs -i\u003cspan style=\"color:#ff79c6\"\u003e{}\u003c/span\u003e ag -a --nocolor \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\\d+\\s{}\\s\u0026#39;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_dir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_log\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e* | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print\u0026amp;lt;/span\u0026gt;7,\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;10}\u0026#39;\u003c/span\u003e | sort | uniq | sort -k \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e -nr | tee -a\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/url_rsp_len.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]罕见的脚本文件访问\\e\u0026amp;#91;00m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;访问量特别特别少的脚本文件极有可能是webshell\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecat \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_dir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_log\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e* | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==200)||(\u0026amp;lt;/span\u0026gt;9==500) {print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;7}\u0026#39;\u003c/span\u003e | sort | uniq -c | sort -n | ag -v \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\\?\u0026#39;\u003c/span\u003e | ag \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\\.php|\\.jsp|\\.asp|\\.aspx\u0026#39;\u003c/span\u003e | head -n \u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e | tee -a\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/rare_url.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\e\u0026amp;#91;00;31m\u0026amp;#91;+]302跳转\\e\u0026amp;#91;00m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;此目的是寻找一些登录成功的脚本文件\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecat \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_dir\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eaccess_log\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e* | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;9==302)||(\u0026amp;lt;/span\u0026gt;9==301) {print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;7}\u0026#39;\u003c/span\u003e | sort | uniq -c | sort -n | ag -v \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\\?\u0026#39;\u003c/span\u003e | ag \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\\.php|\\.jsp|\\.asp|\\.aspx\u0026#39;\u003c/span\u003e | head -n \u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e | tee -a\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eoutfile\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e/302_goto.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e######################################################################\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#!/bin/bash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;##########################################################################\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;#   nginx日志分析小工具,author:william,https://github.com/xiucaiwu       #\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;#   本工具暂时不支持跨天日志分析,Nginx日志格式为默认格式                 #\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;#   请输入要分析的时段(为空则分析全部日志):                              #\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;#   分析今天3点10分到5点的数据:03:10-05:00 \u0026#34;\u003c/span\u003e-\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;前后没有空格               #\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;#   分析2018年8月20号3点到5点的数据:2018-08-20 03:00-05:00               #\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;##########################################################################\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 默认存放切割后的Nginx日志目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003edefault_parse_ngx_dir_path\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/opt/log/nginx\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 生成的切割后的Nginx日志路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eparse_ngx_path\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 默认Nginx日志路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#default_ngx_path=\u0026#34;/usr/local/nginx/logs/host.access.145.`date \u0026#34;+%Y%m%d\u0026#34;`.log\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003edefault_ngx_path\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/root/wwwlog/access.log\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 记录用户手动输入Nginx日志路径的字符串长度\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003engx_path_len\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 记录用户手动输入切割后的Nginx日志目录字符串长度\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003engx_dir_path_len\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 一个空数组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003earray\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 一个字符串分割另一个字符串\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efunction\u003c/span\u003e str_split\u003cspan style=\"color:#ff79c6\"\u003e(){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#6272a4\"\u003e# 分割字符串\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003edelimiter\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#6272a4\"\u003e# 目标字符串\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003estring\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;/span\u0026gt;2\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#6272a4\"\u003e# 注意后面有个空格\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003earray\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=(\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003estring//\u0026amp;lt;/span\u0026gt;delimiter/ \u003cspan style=\"color:#ff79c6\"\u003e})\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#6272a4\"\u003e# return 只能返回int型数值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#\treturn \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;arr\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eread\u003c/span\u003e -p \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;请输入nginx日志文件路径:\u0026#34;\u003c/span\u003e ngx_path\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003engx_path_len\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003eecho\u0026amp;lt;/span\u0026gt;ngx_path | wc -L\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; `echo \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;ngx_path | wc -L` == 0 ];then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003engx_path\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;/span\u0026gt;default_ngx_path\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; ! -f \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;ngx_path ];then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;日志不存在\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#\texit\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eread\u003c/span\u003e -p \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;请输入存放分析后的nginx日志文件夹路径,默认为/opt/log/nginx:\u0026#34;\u003c/span\u003e ngx_parse_dir_path\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; `echo\u0026amp;lt;/span\u0026gt;ngx_dir_path | wc -L` == 0 ];then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003engx_parse_dir_path\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;default_parse_ngx_dir_path\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; ! -d\u0026amp;lt;/span\u0026gt;ngx_parse_dir_path ];then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;ngx_parse_dir_path \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;不存在\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e#\texit\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eread\u003c/span\u003e -p \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;请输入要分析的时段(24小时制):\u0026#34;\u003c/span\u003e ngx_time\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 统计输入的字符串长度\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003elen\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003eecho\u0026amp;lt;/span\u0026gt;ngx_time | wc -L\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;len == 0 ];then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#6272a4\"\u003e# 当前是几时几分\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003ehour_minute\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003edate +%H:%I\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003efilename\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003edate +%Y%m%d\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;.log\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003emydate\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003edate +%d/%b/%Y\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eparse_ngx_path\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;/span\u0026gt;ngx_parse_dir_path/\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;filename\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;/span\u0026gt;{parse_ngx_path}正在生成... \\033\u0026amp;#91;0m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tawk -v \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003emydate\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;mydate -v \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003earr\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;/span\u0026gt;hour_minute -F \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;#91; /:]\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026#34;/\u0026#34;\u0026amp;lt;/span\u0026gt;2\u0026#34;/\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;3==mydate \u0026amp;\u0026amp;\u0026amp;lt;/span\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;5\u0026gt;=\u0026#34;00:00\u0026#34; \u0026amp;\u0026amp;\u0026amp;lt;/span\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;5\u0026amp;lt;=arr\u0026#39;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;ngx_path \u0026gt; \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;parse_ngx_path\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;/span\u0026gt;{parse_ngx_path}生成成功!!! \\033\u0026amp;#91;0m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eelif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;len == 11 ];then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#6272a4\"\u003e# 统计\u0026#34;-\u0026#34;出现的次数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; `echo\u0026amp;lt;/span\u0026gt;ngx_time | grep -o \u0026#39;-\u0026#39; | wc -l` == 1 ];then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#6272a4\"\u003e# 当前日期\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003ecurrent_date\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003edate \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;+%Y-%m-%d %H:%M\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#6272a4\"\u003e# 当前日期对应的时间戳\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003ecurrent_timestamp\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003edate -d \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;current_date\u0026#34;\u003c/span\u003e +%s\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tstr_split \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;-\u0026#34;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;ngx_time\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#6272a4\"\u003e# 用户输入的日期\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003euser_date\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;`date \\\u0026#34;+%Y-%m-%d\\\u0026#34;` \u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{array\u0026amp;#91;0]}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#6272a4\"\u003e# 用户输入的日期对应的时间戳\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003euser_timestamp\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003edate -d \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/span\u0026gt;user_date\u0026#34;\u003c/span\u003e +%s\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003efilename\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003edate +%Y%m%d\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;#91;\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{array\u0026amp;#91;0]}-\u0026amp;lt;/span\u0026gt;{array\u0026amp;#91;1]}].log\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003emydate\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003edate +%d/%b/%Y\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eparse_ngx_path\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;ngx_parse_dir_path/\u0026amp;lt;/span\u0026gt;filename\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;user_timestamp ==\u0026amp;lt;/span\u0026gt;current_timestamp ];then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{parse_ngx_path}正在生成... \\033\u0026amp;#91;0m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tawk -v \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003emydate\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;/span\u0026gt;mydate -v \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003earr1\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003earray\u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91;0]} -v arr2=\u0026amp;lt;/span\u0026gt;{array\u0026amp;#91;1]} -F \u0026#34;\u0026amp;#91; /:]\u0026#34; \u0026#39;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026#34;/\u0026#34;\u0026amp;lt;/span\u0026gt;2\u0026#34;/\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;3==mydate \u0026amp;\u0026amp;\u0026amp;lt;/span\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;5\u0026gt;=arr1 \u0026amp;\u0026amp;\u0026amp;lt;/span\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;5\u0026amp;lt;=arr2\u0026#39;\u0026amp;lt;/span\u0026gt;ngx_path \u0026gt; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;parse_ngx_path\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;/span\u0026gt;{parse_ngx_path}生成成功!!! \\033\u0026amp;#91;0m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003eelif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; ! -f \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;parse_ngx_path ];then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;/span\u0026gt;{parse_ngx_path}正在生成... \\033\u0026amp;#91;0m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tawk -v \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003emydate\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;mydate -v \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003earr1\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003earray\u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91;0]} -v arr2=\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{array\u0026amp;#91;1]} -F \u0026#34;\u0026amp;#91; /:]\u0026#34; \u0026#39;\u0026amp;lt;/span\u0026gt;1\u0026#34;/\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2\u0026#34;/\u0026#34;\u0026amp;lt;/span\u0026gt;3==mydate \u0026amp;\u0026amp; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;/span\u0026gt;5\u0026gt;=arr1 \u0026amp;\u0026amp; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;/span\u0026gt;5\u0026amp;lt;=arr2\u0026#39; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;ngx_path \u0026gt;\u0026amp;lt;/span\u0026gt;parse_ngx_path\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{parse_ngx_path}生成成功!!! \\033\u0026amp;#91;0m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;格式输入不正确\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eexit\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eelif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91;\u0026amp;lt;/span\u0026gt;len == 22 ];then\t\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#6272a4\"\u003e# 统计\u0026#34;-\u0026#34;出现的次数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; `echo \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;ngx_time | grep -o \u0026#39;-\u0026#39; | wc -l` == 3 ];then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tstr_split \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; \u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/span\u0026gt;ngx_time\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#6272a4\"\u003e# 自定义日期格式\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003emydate1\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003edate -d \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{array\u0026amp;#91;0]}\u0026#34;\u003c/span\u003e +%d/%b/%Y\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#6272a4\"\u003e# 日期转时间戳\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etimestamp\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003edate -d \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/span\u0026gt;{array\u0026amp;#91;0]}\u0026#34;\u003c/span\u003e +%s\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#6272a4\"\u003e# 时间戳转日期\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003emydate2\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003edate -d @\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;timestamp \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;+%Y%m%d\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tstr_split \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;-\u0026#34;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003earray\u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91;1]}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003efilename\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;mydate2\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;#91;\u0026amp;lt;/span\u0026gt;{array\u0026amp;#91;0]}-\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{array\u0026amp;#91;1]}].log\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eparse_ngx_path\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;/span\u0026gt;ngx_parse_dir_path/\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;filename\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; ! -f\u0026amp;lt;/span\u0026gt;parse_ngx_path ];then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{parse_ngx_path}正在生成... \\033\u0026amp;#91;0m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tawk -v \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003emydate\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;/span\u0026gt;mydate1 -v \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003earr1\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003earray\u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91;0]} -v arr2=\u0026amp;lt;/span\u0026gt;{array\u0026amp;#91;1]} -F \u0026#34;\u0026amp;#91; /:]\u0026#34; \u0026#39;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1\u0026#34;/\u0026#34;\u0026amp;lt;/span\u0026gt;2\u0026#34;/\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;3==mydate \u0026amp;\u0026amp;\u0026amp;lt;/span\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;5\u0026gt;=arr1 \u0026amp;\u0026amp;\u0026amp;lt;/span\u0026gt;4\u0026#34;:\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;5\u0026amp;lt;=arr2\u0026#39;\u0026amp;lt;/span\u0026gt;ngx_path \u0026gt; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;parse_ngx_path\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\033\u0026amp;#91;32m 文件\u0026amp;lt;/span\u0026gt;{parse_ngx_path}生成成功!!! \\033\u0026amp;#91;0m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;格式输入不正确\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eexit\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;格式输入不正确\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eexit\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 开始解析切割后的Nginx日志\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91; ! -f \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;parse_ngx_path ];then\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\033\u0026amp;#91;31m 文件\u0026amp;lt;/span\u0026gt;{parse_ngx_path}不存在 \\033\u0026amp;#91;0m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 统计访问最多的ip\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\033\u0026amp;#91;31m 访问TOP10的IP: \\033\u0026amp;#91;0m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eawk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1}\u0026#39;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;parse_ngx_path | sort | uniq -c | sort -n -k \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e -r | head -n \u003cspan style=\"color:#bd93f9\"\u003e10\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eip_array\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e(\u003c/span\u003eawk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1}\u0026#39;\u003c/span\u003e\u0026amp;lt;/span\u0026gt;parse_ngx_path | sort | uniq -c | sort -n -k \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e -r | head -n \u003cspan style=\"color:#bd93f9\"\u003e10\u003c/span\u003e | awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;2}\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 统计访问最多的url\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\033\u0026amp;#91;31m 访问TOP10的URL: \\033\u0026amp;#91;0m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eawk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print\u0026amp;lt;/span\u0026gt;7}\u0026#39;\u003c/span\u003e \u0026amp;lt;span \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u0026gt;parse_ngx_path | sort |uniq -c | sort -rn | head -n \u003cspan style=\"color:#bd93f9\"\u003e10\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 统计ip对应的url\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e i in\u0026amp;lt;/span\u0026gt;\u003cspan style=\"color:#ff79c6\"\u003e{\u003c/span\u003eip_array\u0026amp;\u003cspan style=\"color:#6272a4\"\u003e#91;@]};do \u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eecho\u003c/span\u003e -e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\\033\u0026amp;#91;31m IP(\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ekatex math inline\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;{i})访问TOP10的URL: \\033\u0026amp;#91;0m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tcat access.log | grep\u0026amp;lt;/span\u0026gt;i |awk \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;{print $7}\u0026#39;\u003c/span\u003e| sort | uniq -c | sort -rn | head -10 | more \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edone\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"配置查询Nginx中异常IP处理"},{"content":"什么是SaaS SaaS平台是运营saas软件的平台。SaaS提供商为企业搭建信息化所需要的所有网络基础设施及软件、硬件运作平台，并负责所有前期的实施、后期的维护等一系列服务，企业无需购买软硬件、建设机房、招聘IT人员，即可通过互联网使用信息系统。SaaS 是一种软件布局模型，其应用专为网络交付而设计，便于用户通过互联网托管、部署及接入。也就是说，我只需要能连接上互联网，并且给saas平台交租金，我就能用saas平台给我提供的系统服务。 多租户技术或称多重租赁技术，是一种软件架构技术，是实现如何在多用户环境下共用相同的系统或程序组件，并且可确保各用户间数据的隔离性。多租户架构的重点就是同一套程序下多个租户数据的隔离 SaaS 数据隔离方案 目前saas多租户系统的数据隔离有三种解决方案，即为每个租户提供独立的数据库、独立的表空间、按字段区分租户，每种方案都有其各自的适用情况 独立数据库 即一个租户一个数据库，这种方案的用户数据隔离级别最高，安全性最好，但成本较高。\n优点 为不同的租户提供独立的数据库，有助于简化数据模型的扩展设计，满足不同租户的独特需求，如果出现故障，恢复数据比较简单。 缺点 增多了数据库的数量，随之带来维护成本或购置成本的增加。这种方案与传统的一个客户、一套数据、一套部署类似。差别只在于软件统一部署在运营商那里。如果面对的是银行、医院等需要非常高数据隔离级别的租户、可以选择这种模式，提高租用的定价。如果定价较低，产品走低价路线，这种方案一般对运营商来说是无法承受的。 共享数据库，隔离数据架构（独立表空间） 这种方案实现，就是所有租户共享同一个应用，应用后端连接同一个数据库系统，所有租户共享这个数据库系统，每个租户在数据库系统中拥有一个独立的表空间 优点 为安全性要求较高的租户提供了一定程度的逻辑数据隔离，并不是完全隔离。每个数据库可支持更多的租户数量 缺点 如果出现故障，数据恢复比较困难，因为恢复数据库将牵涉到其他租户的数据；如果需要跨租户统计数据，存在一定困难。 共享数据库，共享数据架构（表空间-按租户id字段区分租户） 即租户共享同一个数据库，同一个表空间，但是表中增加TenantID多租户的数据字段。这是共享程度最高，隔离级别最低的模式。通过TenantID来标识每一条数据属于哪个租户，所有操作的时候都要注意添加上TenantID作为过滤条件。 优点 三种方案中，这个方案的维护和购置成本最低，允许每个数据库支持的租户数量最多。 缺点 隔离级别最低，安全性最低，需要在设计开发的时候加大对安全的开发量。数据备份和恢复最困难，需要逐表备份和还原。如果希望以最少的服务器为最多的租户提供服务，并且租户接受牺牲隔离级别换取降低成本，这种方案最合适。 衡量要素 衡量三种模式主要考虑的因素是隔离还是共享。\n成本角度 隔离性越好，设计和实现的难度和成本越高。共享性越好，同一运营成本下支持的用户越多，运营成本越低。 安全角度 要考虑业务和客户的安全方面的要求。安全性要求越高，越要倾向于隔离。 租户数量角度 系统要支持多少租户？上百？上千还是上完？可能的租户越多，越倾向于共享。平均每个租户要存储数据需要的空间大小。存储的数据越多，越倾向于隔离。每个租户的同时访问系统的最终用户数量。需要支持的越多，越倾向于隔离。是否想针对每一个租户提供附加的服务，例如数据的备份和恢复等。这方面的需求越多，越倾向于隔离。 信息监管因素 要考虑政府，机关，企业，公司的安全和信息监管的一些政策和规定。 技术成本 共享性越好，对技术的要求越高。 ","permalink":"https://blog.zdltech.com/posts/saas%E7%B3%BB%E7%BB%9F%E5%A4%9A%E7%A7%9F%E6%88%B7%E6%95%B0%E6%8D%AE%E9%9A%94%E7%A6%BB%E7%9A%84%E5%AE%9E%E7%8E%B0/","summary":"\u003ch4 class=\"wp-block-heading\" id=\"什么是saas\"\u003e什么是SaaS\u003c/h4\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003eSaaS平台是运营saas软件的平台。SaaS提供商为企业搭建信息化所需要的所有网络基础设施及软件、硬件运作平台，并负责所有前期的实施、后期的维护等一系列服务，企业无需购买软硬件、建设机房、招聘IT人员，即可通过互联网使用信息系统。SaaS 是一种软件布局模型，其应用专为网络交付而设计，便于用户通过互联网托管、部署及接入。也就是说，我只需要能连接上互联网，并且给saas平台交租金，我就能用saas平台给我提供的系统服务。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e多租户技术或称多重租赁技术，是一种软件架构技术，是实现如何在多用户环境下共用相同的系统或程序组件，并且可确保各用户间数据的隔离性。多租户架构的重点就是同一套程序下多个租户数据的隔离\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch2 class=\"wp-block-heading\" id=\"saas-数据隔离方案\"\u003e\u003cstrong\u003eSaaS 数据隔离方案\u003c/strong\u003e\u003c/h2\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e目前saas多租户系统的数据隔离有三种解决方案，即为每个租户提供独立的数据库、独立的表空间、按字段区分租户，每种方案都有其各自的适用情况\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"独立数据库\"\u003e独立数据库\u003c/h3\u003e\n\u003cp\u003e即一个租户一个数据库，这种方案的用户数据隔离级别最高，安全性最好，但成本较高。\u003c/p\u003e\n\u003ch4 class=\"wp-block-heading\" id=\"优点\"\u003e优点\u003c/h4\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e为不同的租户提供独立的数据库，有助于简化数据模型的扩展设计，满足不同租户的独特需求，如果出现故障，恢复数据比较简单。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch4 class=\"wp-block-heading\" id=\"缺点\"\u003e缺点\u003c/h4\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e增多了数据库的数量，随之带来维护成本或购置成本的增加。这种方案与传统的一个客户、一套数据、一套部署类似。差别只在于软件统一部署在运营商那里。如果面对的是银行、医院等需要非常高数据隔离级别的租户、可以选择这种模式，提高租用的定价。如果定价较低，产品走低价路线，这种方案一般对运营商来说是无法承受的。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"共享数据库隔离数据架构独立表空间\"\u003e共享数据库，隔离数据架构（独立表空间）\u003c/h3\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e这种方案实现，就是所有租户共享同一个应用，应用后端连接同一个数据库系统，所有租户共享这个数据库系统，每个租户在数据库系统中拥有一个独立的表空间\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch4 class=\"wp-block-heading\" id=\"优点-1\"\u003e优点\u003c/h4\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e为安全性要求较高的租户提供了一定程度的逻辑数据隔离，并不是完全隔离。每个数据库可支持更多的租户数量\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch4 class=\"wp-block-heading\" id=\"缺点-1\"\u003e缺点\u003c/h4\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e如果出现故障，数据恢复比较困难，因为恢复数据库将牵涉到其他租户的数据；如果需要跨租户统计数据，存在一定困难。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"共享数据库共享数据架构表空间-按租户id字段区分租户\"\u003e共享数据库，共享数据架构（表空间-按租户id字段区分租户）\u003c/h3\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e即租户共享同一个数据库，同一个表空间，但是表中增加TenantID多租户的数据字段。这是共享程度最高，隔离级别最低的模式。通过TenantID来标识每一条数据属于哪个租户，所有操作的时候都要注意添加上TenantID作为过滤条件。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch4 class=\"wp-block-heading\" id=\"优点-2\"\u003e优点\u003c/h4\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e三种方案中，这个方案的维护和购置成本最低，允许每个数据库支持的租户数量最多。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch4 class=\"wp-block-heading\" id=\"缺点-2\"\u003e缺点\u003c/h4\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e隔离级别最低，安全性最低，需要在设计开发的时候加大对安全的开发量。数据备份和恢复最困难，需要逐表备份和还原。如果希望以最少的服务器为最多的租户提供服务，并且租户接受牺牲隔离级别换取降低成本，这种方案最合适。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch2 class=\"wp-block-heading\" id=\"衡量要素\"\u003e\u003cstrong\u003e衡量要素\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e衡量三种模式主要考虑的因素是隔离还是共享。\u003c/p\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"成本角度\"\u003e成本角度\u003c/h3\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e隔离性越好，设计和实现的难度和成本越高。共享性越好，同一运营成本下支持的用户越多，运营成本越低。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"安全角度\"\u003e安全角度\u003c/h3\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e要考虑业务和客户的安全方面的要求。安全性要求越高，越要倾向于隔离。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"租户数量角度\"\u003e租户数量角度\u003c/h3\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e系统要支持多少租户？上百？上千还是上完？可能的租户越多，越倾向于共享。平均每个租户要存储数据需要的空间大小。存储的数据越多，越倾向于隔离。每个租户的同时访问系统的最终用户数量。需要支持的越多，越倾向于隔离。是否想针对每一个租户提供附加的服务，例如数据的备份和恢复等。这方面的需求越多，越倾向于隔离。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"信息监管因素\"\u003e信息监管因素\u003c/h3\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e要考虑政府，机关，企业，公司的安全和信息监管的一些政策和规定。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"技术成本\"\u003e技术成本\u003c/h3\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e共享性越好，对技术的要求越高。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e","title":"SaaS系统多租户数据隔离的实现"},{"content":"Reid 使用指南一 问题一 OOM command not allowed when used memory \u0026gt; \u0026lsquo;maxmemory\u0026rsquo; 这里表示使用内存超过了设置的最大内存。\nredis.conf中的maxmemory定义REdis可用最大物理内存，有多种书写方式，以下均为合法：\nmaxmemory 1048576\nmaxmemory 1048576B\nmaxmemory 1000KB\nmaxmemory 100MB\nmaxmemory 1GB\nmaxmemory 1000K\nmaxmemory 100M\nmaxmemory 1G\n没有带单位尾巴的为字节数，以B结尾的表示相应的大小。但需要注意KB和K、MB和M、GB和G是不同的，如1K表示1000字节，而1KB则为1024字节。如果maxmemory值为0，表示不做限制。\n如果是32位系统，当maxmemory值为0时，redis启动时会记录WARN日志\nWarning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with \u0026rsquo;noeviction\u0026rsquo; policy now.\nserver.maxmemory = 3072LL_(1024_1024); /* 3 GB */\nserver.maxmemory_policy = MAXMEMORY_NO_EVICTION;\n相关的源代码如下：\n/* Convert a string representing an amount of memory into the number of\nbytes, so for instance memtoll(\u0026ldquo;1Gb\u0026rdquo;) will return 1073741824 that is\n(1024_1024_1024).\n* On parsing error, if *err is not NULL, it\u0026rsquo;s set to 1, otherwise it\u0026rsquo;s\nset to 0. On error the function return value is 0, regardless of the * fact \u0026rsquo;err\u0026rsquo; is NULL or not. */\nlong long memtoll(const char *p, int *err) {\nconst char *u;\nchar buf[128];\nlong mul; /* unit multiplier */\nlong long val;\nunsigned int digits;\nif (err) *err = 0;\n/* Search the first non digit character. */\nu = p;\nif (*u == \u0026lsquo;-\u0026rsquo;) u++;\nwhile(_u \u0026amp;\u0026amp; isdigit(_u)) u++;\nif (*u == \u0026lsquo;\\0\u0026rsquo; || !strcasecmp(u,\u0026ldquo;b\u0026rdquo;)) { // 调用strcasecmp不区分大小比较\n​ mul = 1;\n} else if (!strcasecmp(u,\u0026ldquo;k\u0026rdquo;)) {\n​ mul = 1000; // 不带尾巴B或b的\n} else if (!strcasecmp(u,\u0026ldquo;kb\u0026rdquo;)) {\n​ mul = 1024; // 带尾巴B或b的\n} else if (!strcasecmp(u,\u0026ldquo;m\u0026rdquo;)) {\n​ mul = 1000*1000; // 不带尾巴B或b的\n} else if (!strcasecmp(u,\u0026ldquo;mb\u0026rdquo;)) {\n​ mul = 1024*1024; // 带尾巴B或b的\n} else if (!strcasecmp(u,\u0026ldquo;g\u0026rdquo;)) {\n​ mul = 1000L_1000_1000; // 不带尾巴B或b的\n} else if (!strcasecmp(u,\u0026ldquo;gb\u0026rdquo;)) {\n​ mul = 1024L_1024_1024; // 带尾巴B或b的\n} else {\n​ if (err) *err = 1;\n​ return 0;\n}\n/* Copy the digits into a buffer, we\u0026rsquo;ll use strtoll() to convert\n* the digit (without the unit) into a number. */\ndigits = u-p;\nif (digits \u0026gt;= sizeof(buf)) {\n​ if (err) *err = 1;\n​ return 0;\n}\nmemcpy(buf,p,digits);\nbuf[digits] = \u0026lsquo;\\0\u0026rsquo;;\nchar *endptr;\nerrno = 0;\nval = strtoll(buf,\u0026amp;endptr,10);\nif ((val == 0 \u0026amp;\u0026amp; errno == EINVAL) || *endptr != \u0026lsquo;\\0\u0026rsquo;) {\n​ if (err) *err = 1;\n​ return 0;\n}\nreturn val*mul;\n}\n如果要查看maxmemory的值，有如下三种方法：\nredis-cli -h ip地址 -p 6379 config get maxmemory\nredis-cli -h ip地址 -p 6379 info memory | grep maxmemory\n3.1. 登陆redis客户端：./redis-cli -h IP -p port -a passwd 3.2. 执行命令：redis\u0026gt;info memory 若配置文件中，最大内存的策略设置为 maxmemory-policy volatile-lru 此配置只是清楚设置过期时间的key值，然而本应用并没有设置过期时间。\n可以修改为maxmemory-policy allkeys-lru，指明非活跃近期很少用的key值清除。\n如果清理完redis还不行，就需要考虑扩容\n问题二 redis中java.io.IOException: 远程主机强迫关闭了一个现有的连接 现象：\n登录系统后，隔一段时间后再操作出现java.io.IOException: 远程主机强迫关闭了一个现有的连接\n原因：\nredis服务器配置了timeout超时时间，spring serivice层中注入StringRedisTemplate，过了超时时间后该service对象持有的连接是无效的。\n解决方案\n1.配置redis连接池\nspring.redis.lettuce.pool.max-idle: 30\nspring.redis.lettuce.pool.min-idle: 10\nspring.redis.lettuce.pool.max-active: 30\nspring.redis.lettuce.pool.max-wait: 10000\n检查tcp-keepalive配置 配置后重启redis tcp-keepalive配置为60 在redis的配置文件redis.conf中设置tcp-keepalive时间为60s(据说3.2.1默认为300，我设置60后上述问题不在出现) 查看链接客户端 进入redis客户端执行 client list 查看\n127.0.0.1:6379\u0026gt; CLIENT LIST\n","permalink":"https://blog.zdltech.com/posts/wen-ti-yi/","summary":"\u003ch1 id=\"toc_0\"\u003eReid 使用指南一\u003c/h1\u003e\n\u003ch2 id=\"toc_1\"\u003e问题一\u003c/h2\u003e\n\u003ch3 id=\"toc_2\"\u003eOOM command not allowed when used memory \u0026gt; \u0026lsquo;maxmemory\u0026rsquo;\u003c/h3\u003e\n\u003cp\u003e这里表示使用内存超过了设置的最大内存。\u003c/p\u003e\n\u003cp\u003eredis.conf中的maxmemory定义REdis可用最大物理内存，有多种书写方式，以下均为合法：\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003emaxmemory 1048576\u003c/p\u003e\n\u003cp\u003emaxmemory 1048576B\u003c/p\u003e\n\u003cp\u003emaxmemory 1000KB\u003c/p\u003e\n\u003cp\u003emaxmemory 100MB\u003c/p\u003e\n\u003cp\u003emaxmemory 1GB\u003c/p\u003e\n\u003cp\u003emaxmemory 1000K\u003c/p\u003e\n\u003cp\u003emaxmemory 100M\u003c/p\u003e\n\u003cp\u003emaxmemory 1G\u003c/p\u003e\n\u003cp\u003e没有带单位尾巴的为字节数，以B结尾的表示相应的大小。但需要注意KB和K、MB和M、GB和G是不同的，如1K表示1000字节，而1KB则为1024字节。如果maxmemory值为0，表示不做限制。\u003c/p\u003e\n\u003cp\u003e如果是32位系统，当maxmemory值为0时，redis启动时会记录WARN日志\u003c/p\u003e\n\u003cp\u003eWarning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with \u0026rsquo;noeviction\u0026rsquo; policy now.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eserver.maxmemory = 3072LL_(1024_1024); /* 3 GB */\u003c/p\u003e\n\u003cp\u003eserver.maxmemory_policy = MAXMEMORY_NO_EVICTION;\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e相关的源代码如下：\u003c/p\u003e\n\u003cp\u003e/* Convert a string representing an amount of memory into the number of\u003c/p\u003e","title":"Redis使用问题一"},{"content":"1 root用户也干不了的事情 授权某文件时,提示 chmod: changing permissions of ‘log’: Operation not permitted错误.\n可能的原因: 此文件正在被锁定,不允许操作或更改.chmod命令底层的实现是chattr命令,使用此命令后,可以使此文件被锁定,无法进行添加/删除/写入等操作,就算root用户也无法例外,熟悉chattr及lsattr命令即可解决此问题.\n`\u0026amp;#91;root@web01 ~]# chattr +i /etc/passwd #\u0026amp;lt;==防止系统关键文件被篡改,就算是root也不例外 \u0026amp;#91;root@web01 ~]# lsattr /etc/passwd #\u0026amp;lt;==查看此文件带i,就是被锁定了 ----i----------- /etc/passwd \u0026amp;#91;root@web01 ~]# chattr -i /etc/passwd #\u0026amp;lt;==解锁 \u0026amp;#91;root@web01 ~]# lsattr /etc/passwd #\u0026amp;lt;==正常文件,root可以做任何操作 ---------------- /etc/passwd \u0026amp;#91;root@web01 ~]# chattr +a /etc/passwd #\u0026amp;lt;==仅仅允许此文件进行追加操作,通常用于日志,如log \u0026amp;#91;root@web01 ~]# lsattr /etc/passwd -----a---------- /etc/passwd \u0026amp;#91;root@web01 ~]# chattr -a /etc/passwd \u0026amp;#91;root@web01 ~]# lsattr /etc/passwd ---------------- /etc/passwd ` 2 小结 chattr , lsattr 在实际应用中对于服务器安全有重要的意义. ","permalink":"https://blog.zdltech.com/posts/chmod-changing-permissions-of-xxx-operation-not-permittedroot%E9%83%BD%E6%B2%A1%E6%9C%89%E6%9D%83%E9%99%90%E7%9A%84%E6%97%B6%E5%80%99%E4%BD%BF%E7%94%A8%E8%BF%99%E4%B8%AA/","summary":"\u003ch2 class=\"wp-block-heading\" id=\"1-root用户也干不了的事情\"\u003e1 root用户也干不了的事情\u003c/h2\u003e\n\u003cp\u003e授权某文件时,提示 chmod: changing permissions of ‘log’: Operation not permitted错误.\u003c/p\u003e\n\u003cp\u003e　　可能的原因: 此文件正在被锁定,不允许操作或更改.chmod命令底层的实现是chattr命令,使用此命令后,可以使此文件被锁定,无法进行添加/删除/写入等操作,就算root用户也无法例外,熟悉chattr及lsattr命令即可解决此问题.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;#91;root@web01 ~]# chattr +i /etc/passwd    #\u0026amp;lt;==防止系统关键文件被篡改,就算是root也不例外\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;#91;root@web01 ~]# lsattr /etc/passwd       #\u0026amp;lt;==查看此文件带i,就是被锁定了\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e----i----------- /etc/passwd                    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;#91;root@web01 ~]# chattr -i /etc/passwd    #\u0026amp;lt;==解锁\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;#91;root@web01 ~]# lsattr /etc/passwd       #\u0026amp;lt;==正常文件,root可以做任何操作\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e---------------- /etc/passwd\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;#91;root@web01 ~]# chattr +a /etc/passwd    #\u0026amp;lt;==仅仅允许此文件进行追加操作,通常用于日志,如log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;#91;root@web01 ~]# lsattr /etc/passwd\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-----a---------- /etc/passwd\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;#91;root@web01 ~]# chattr -a /etc/passwd\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;#91;root@web01 ~]# lsattr /etc/passwd\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e---------------- /etc/passwd   `\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 class=\"wp-block-heading\" id=\"2小结\"\u003e2 小结\u003c/h2\u003e\n\u003cp\u003e　　chattr , lsattr 在实际应用中对于服务器安全有重要的意义. \u003c/p\u003e","title":"chmod: changing permissions of ‘xxx’: Operation not permitted，root都没有权限的时候，使用这个试试"},{"content":"HTML5服务器推送事件（Server-sent-event） 在前端开发中，实现界面推送的方式，这里大概总结下三种方式\n轮询（ajax），比较耗费服务器资源。COMET方式（COMET 技术并不是 HTML 5 ） websocket 双向数据推送，灵活，功能强大 Server-sent-event(简称SSE)，单项数据推送（Server-sent Events 规范是 HTML 5 规范的一个组成部分） 这里我们只讨论SSE\nSSE的本质：严格地说，HTTP协议无法做到服务器主动推送信息。但是有一种变通的发光法，就是服务器向客户端声明，接下来要发送的是流信息，也就是说，发送的不是一次性的数据包，而是一个数据流，会连续不断的发送过来。这是客户端不会关闭连接，会一直等待服务器发过来的数据流，视频播放就是这样的例子。本质上这种通信就是以流信息的方式，完成一次用时很长的下载。\nSSE就是利用这种机制，使用流信息想浏览器推送信息。它基于HTTP协议，除了IE/Edge，其他浏览器都支持\n闲谈 在Web开发中，浏览器和服务器之间使用请求/响应的交互模式。浏览器发出请求，服务器根据请求来生成响应。这种交互方式，服务器端产生数据变化后不能及时的通知给浏览，只能在浏览器下次请求的时候，才能获取（对于某些对数据实时性要求很高的应用，这种延迟是不能接受的）。\n使用浏览器原生的EventSource对象的一个比较大的问题是IE并不支持（为实现在IE上COMET或轮询，第二种使用polyfill技术）\nSSE的客户端API部署在EventSource对象上，使用之前检测浏览器是否支持SSE\nif(typeof(EventSource)!==\u0026quot;undefined\u0026quot;) { // 浏览器支持 Server-Sent // 一些代码..... } else { // 浏览器不支持 Server-Sent.. } var source = new EventSource(url); // url可以在当前网址同域，也可以跨域，跨域时可以指定第二个参数withCredentials 表示是否一起发送Cookies \u0026gt; \u0026gt; EventSource的readyState 表明连接的当前状态，该属性只读 \u0026gt; \u0026gt; * 0: 相当于常量EventSource.CONNECTIONG 表示连接还未建立，或者断线正在重连 \u0026gt; * 1:相当于常量EventSource.OPEN 表示连接已经建立，可以接受数据 \u0026gt; * 2:相当于常量EventSource.CLOSED 表示连接已断，且不会重连 ### Server-sent Events {#toc_2} \u0026gt; Server-sent Events 规范是 HTML 5 规范的一个组成部分,该规范比较简单，主要由两部分组成： \u0026gt; \u0026gt; 第一部分：服务器端与浏览器之间的通讯协议 \u0026gt; \u0026gt; 第二部分：浏览器端可以提供JavaScript中使用EventSource对象。 \u0026gt; \u0026gt; 通讯协议是基于纯文本的简单协议 \u0026gt; \u0026gt; 服务器端响应的内容类型为：text/event-stream，响应文本内容可以看成是一个事件流，有不同的事件组成。 \u0026gt; \u0026gt; 每个事件由类型和数据两个部分组成，同时每个事件可以有一个可选的标识符。不同事件的内容之间通过仅包含回车符和换行符的空行来分隔。每个事件的数据可能由多行组成。 \u0026gt; \u0026gt; 清单1 \u0026gt; \u0026gt; \u0026gt; ``` `data: first event data: second event id: 100 event: myevent data: third event id: 101 : this is a comment data: fourth event data: fourth event continue ` 每个事件之间通过空行来分隔。对于每行来说，冒号（：）前面表示的该行的类型，冒号后面则是对应的值。\n可能的类型包括：\n类型为空白，表示该行是注释，会在处理时被忽略 类型为data，表示该行包含的是数据。以data开头的行可以出现多次。所有这些行都是该事件的数据。 类型为event，表示该行用来声明事件的类型。浏览器在收到数据时，会产生对应类型的事件。 类型 为id，表示该行用来声明事件的标识符 类型为retry，表示该行用来声明浏览器在连接断开后检修 再次连接之前的等待时间 清单1，第一个事件只包含数据“first event”，会产生默认的事件，第二个事件的标识符是100，数据为“secondEvent”，第三个事件会产生类型为“myevent”的事件，最后一个事件的数据为“fourthevent \\n fourth event continue”,当有多行数据时，实际的数据由每行数据以换行符连接而成\n如果服务器端返回的数据中包含了事件的标识符，浏览器会记录最后一次接收到的事件的标识符，如果与服务器多连接中断，当浏览器端再次进行连接时，会通过HTTP头“Last-Event-ID”来声明最后一次接收到的事件的标识符，服务器端可以通过浏览器发送的事件标识符来确定从哪个事件开始来继续连接。\n对于服务器端返回的响应，浏览器端需要通过JavaScript的EventSource对象来 处理，EventSource使用的是标准的事件监听器方式，只需要在对象上添加相应的事件处理方式即可。\nEventSource对象提供的标准事件\n名称 说明 事件处理方法 open 当成功与服务器建立连接时产生 onopen message 当收到服务器发送的事件时产生 onmessage error 当出现错误时产生 onerror 服务器端可以返回自定义类型的事件，可以使用addEventListenner方法来添加相应的事件处理方法\nvar es = new EventSource(\u0026amp;#39;events\u0026amp;#39;); es.onmessage = function(e){ console.log(e.data); } es.addEventListener(\u0026amp;#39;myevent\u0026amp;#39;,function(e){ console.log(e.data); }) \u0026gt; \u0026gt; \u0026gt; \u0026gt; 在指定URL创建出EventSource对象之后，可以通过onmessage和addEventListener方法来添加事件处理方法，当服务器端有新的事件产生，相应的事件处理方法会被调用。EventSource对象的onmessage属性的作用类似于addEventListerner(\u0026#39;message\u0026#39;),不过onmessage属性只支持一个事件处理方法 \u0026gt; \u0026gt; \u0026gt; \u0026gt; 默认情况下，服务器发来的数据，总是触发浏览器EventSource实例的message事件。 ### 常见实现方式对比 {#toc_3} | | （短）轮询 | 长轮询/Comet | SSE | WebSocket | | ------ | -------- | --------- | -------- | --------- | | 浏览器支持 | 全部 | 全部 | 除IE/Edge | 现代浏览器 | | 是否独立协议 | HTTP | HTTP | HTTP | WS | | 是否轻量 | 是 | 是 | 是 | 否 | | 断线重连 | 否 | 否 | 是 | 否 | | 负载压力 | 占用内存/请求数 | 同（短）轮询 | 一般 | 一般 | | 数据延迟 | 取决于请求间隔 | 同（短）轮询 | 实时 | 实时 | ## Demo 实现方式一（Spring boot） {#toc_4} \u0026gt; **踩坑总结** \u0026gt; \u0026gt; * 在连接的时候，前端连接是否跨域了，如果跨域先解决跨域 \u0026gt; \u0026gt; * 如果服务器端调用sseEmitter.complete();前端就执行连接关闭，再次发送前端数据的时候，重新连接回打开（一般我们处理完成的时候执行） \u0026gt; \u0026gt; * 同一个用户在连接到后台的时候，后台的SseEmitter对象需要移除在重新添加，否则后台推送不过来 \u0026gt; \u0026gt;![image-20200819175021176](https://tva1.sinaimg.cn/large/007S8ZIlly1ghw9nmabulj30k00bkta2.jpg) ### 精简版 {#toc_5} \u0026gt; 服务器代码 \u0026gt; \u0026gt; ``` `package com.zdltech.javaexercise.ssedemo.controller; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.io.IOException; import java.util.HashMap; import java.util.Map; @Controller @CrossOrigin public class IndexController { private Map\u0026amp;lt;String,SseEmitter\u0026amp;gt; pushSseEmitterMap = new HashMap\u0026amp;lt;\u0026amp;gt;(); @GetMapping(path = \u0026#34;/push/{id}\u0026#34;,produces = MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter pushSse(@PathVariable(\u0026#34;id\u0026#34;) String uid){ System.out.println(\u0026#34;pushSse is run\u0026#34;); SseEmitter sseEmitter = new SseEmitter(0L); sseEmitter.onCompletion(()-\u0026amp;gt;{pushSseEmitterMap.remove(uid);}); sseEmitter.onTimeout(()-\u0026amp;gt;{pushSseEmitterMap.remove(uid);}); sseEmitter.onError(throwable-\u0026amp;gt;{ System.out.println(\u0026#34;onError is run\u0026#34;); throwable.printStackTrace(); pushSseEmitterMap.remove(uid); }); if (!pushSseEmitterMap.containsKey(uid)){ pushSseEmitterMap.remove(uid); } pushSseEmitterMap.put(uid,sseEmitter); return sseEmitter; } // @Scheduled(fixedDelay = 2*1000) // public void scheduledMsgEmitter() throws IOException // { // pushSseEmitterMap.keySet().forEach(key -\u0026amp;gt; { // SseEmitter emitter = pushSseEmitterMap.get(key); // if (null != emitter){ // try { // System.out.println(\u0026#34;Timeout : \u0026#34;+ emitter.getTimeout()); // emitter.send(\u0026#34;: \u0026#34; + Calendar.getInstance().getTime()); // } catch (IOException e) { // e.printStackTrace(); // } // } // // }); // } @RequestMapping(\u0026#34;/push/send\u0026#34;) @ResponseBody public String push(@RequestParam String uid,@RequestParam String value){ System.out.println(\u0026#34;push is run\u0026#34;); SseEmitter sseEmitter = pushSseEmitterMap.get(uid); if (sseEmitter!=null){ try { sseEmitter.send(value,MediaType.APPLICATION_JSON); } catch (IOException e) { e.printStackTrace(); return \u0026#34;fail\u0026#34;; } } return \u0026#34;ok\u0026#34;; } @RequestMapping(\u0026#34;/push/finish\u0026#34;) @ResponseBody public String finish(@RequestParam String uid,@RequestParam String value){ System.out.println(\u0026#34;finish is run\u0026#34;); SseEmitter sseEmitter = pushSseEmitterMap.get(uid); if (sseEmitter!=null){ try { sseEmitter.send(value,MediaType.APPLICATION_JSON); sseEmitter.complete(); } catch (IOException e) { e.printStackTrace(); return \u0026#34;fail\u0026#34;; } } return \u0026#34;ok\u0026#34;; } } ` 前端：\n`\u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026ldquo;utf-8\u0026rdquo;\u0026gt; \u0026lt;meta name=\u0026ldquo;viewport\u0026rdquo; content=\u0026ldquo;width=device-width\u0026rdquo;\u0026gt; \u0026lt;title\u0026gt;JS Bin\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;div id=\u0026ldquo;example\u0026rdquo;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;script\u0026gt; var source = new EventSource('http://127.0.0.1:8844/push/a123456'); // var source = new EventSource('http://127.0.0.1:8844/sse/connect/a123456'); var div = document.getElementById('example');\nsource.onopen = function (event) { div.innerHTML += '\u0026lt;p\u0026gt;Connection open \u0026hellip;\u0026lt;/p\u0026gt;'; };\nsource.onerror = function (event) { div.innerHTML += '\u0026lt;p\u0026gt;Connection close.\u0026lt;/p\u0026gt;'; };\nsource.addEventListener('connecttime', function (event) { div.innerHTML += ('\u0026lt;p\u0026gt;Start time: ' + event.data + '\u0026lt;/p\u0026gt;'); }, false);\nsource.onmessage = function (event) { div.innerHTML += ('\u0026lt;p\u0026gt;Ping: ' + event.data + '\u0026lt;/p\u0026gt;'); };\n\u0026lt;/script\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; `\n\u0026gt; \u0026gt; 执行结果： \u0026gt; \u0026gt;![image-20200819175320871](https://tva1.sinaimg.cn/large/007S8ZIlly1ghw9qofz2fj30uu0o6mys.jpg) ### 简单封装版 {#toc_6} \u0026gt; ### SseEmitter {#toc_7} \u0026gt; \u0026gt; SseEmitter是SpringMVC(4.2+)提供的一种技术,它是基于**Http协议**的，相比WebSocket，它更轻量，但是它只能从服务端向客户端**单向**发送信息。在SpringBoot中我们无需引用其他jar就可以使用 \u0026gt; \u0026gt; * 创建`AtomicInteger`用于记录连接数 \u0026gt; * 创建`ConcurrentHashMap`用于存放连接信息 \u0026gt; * 建立连接：创建并返回一个带有超时时间的`SseEmitter`给前端。超时间设为0表示永不过期 \u0026gt; * 设置连接结束的回调方法`completionCallBack` \u0026gt; * 设置连接超时的回调方法`timeoutCallBack` \u0026gt; * 设置连接异常的回调方法`errorCallBack` \u0026gt; * 创建推送信息的方法`SseEmitter.send()` \u0026gt; * 创建移除连接的方法 \u0026gt; \u0026gt; 服务器端 \u0026gt; \u0026gt; ``` `import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; @RestController @RequestMapping(\u0026#34;/sse\u0026#34;) @CrossOrigin public class SseEmitterController { /** * 用于创建连接 */ @GetMapping(\u0026#34;/connect/{userId}\u0026#34;) public SseEmitter connect(@PathVariable String userId) { return SseEmitterServer.connect(userId); } @GetMapping(\u0026#34;/push/{message}\u0026#34;) public ResponseEntity\u0026amp;lt;String\u0026amp;gt; push(@PathVariable(name = \u0026#34;message\u0026#34;) String message) { SseEmitterServer.batchSendMessage(message); return ResponseEntity.ok(\u0026#34;WebSocket 推送消息给所有人\u0026#34;); } } ` ` import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;\nimport java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer;\npublic class SseEmitterServer {\nprivate static final Logger logger = LoggerFactory.getLogger(SseEmitterServer.class); /** * 当前连接数 */ private static AtomicInteger count = new AtomicInteger(0); /** * 使用map对象，便于根据userId来获取对应的SseEmitter，或者放redis里面 */ private static Map\u0026amp;lt;String, SseEmitter\u0026amp;gt; sseEmitterMap = new ConcurrentHashMap\u0026amp;lt;\u0026amp;gt;(); /** * 创建用户连接并返回 SseEmitter * * @param userId 用户ID * @return SseEmitter */ public static SseEmitter connect(String userId) { if (sseEmitterMap.containsKey(userId)){//在连接的时候，如果存在就移除原来连接，生产新的连接 removeUser(userId); } // 设置超时时间，0表示不过期。默认30秒，超过时间未完成会抛出异常：AsyncRequestTimeoutException SseEmitter sseEmitter = new SseEmitter(0L); // 注册回调 sseEmitter.onCompletion(completionCallBack(userId)); sseEmitter.onError(errorCallBack(userId)); sseEmitter.onTimeout(timeoutCallBack(userId)); sseEmitterMap.put(userId, sseEmitter); // 数量+1 count.getAndIncrement(); logger.info(\u0026quot;创建新的sse连接，当前用户：{}\u0026quot;, userId); return sseEmitter; } /** * 给指定用户发送信息 */ public static void sendMessage(String userId, String message) { if (sseEmitterMap.containsKey(userId)) { try { // sseEmitterMap.get(userId).send(message, MediaType.APPLICATION_JSON); sseEmitterMap.get(userId).send(message); } catch (IOException e) { logger.error(\u0026quot;用户[{}]推送异常:{}\u0026quot;, userId, e.getMessage()); removeUser(userId); } } } /** * 群发消息 */ public static void batchSendMessage(String wsInfo, List\u0026amp;lt;String\u0026amp;gt; ids) { ids.forEach(userId -\u0026amp;gt; sendMessage(wsInfo, userId)); } /** * 群发所有人 */ public static void batchSendMessage(String wsInfo) { sseEmitterMap.forEach((k, v) -\u0026amp;gt; { try { v.send(wsInfo, MediaType.APPLICATION_JSON); } catch (IOException e) { logger.error(\u0026quot;用户[{}]推送异常:{}\u0026quot;, k, e.getMessage()); removeUser(k); } }); } /** * 移除用户连接 */ public static void removeUser(String userId) { sseEmitterMap.remove(userId); // 数量-1 count.getAndDecrement(); logger.info(\u0026quot;移除用户：{}\u0026quot;, userId); } /** * 获取当前连接信息 */ public static List\u0026amp;lt;String\u0026amp;gt; getIds() { return new ArrayList\u0026amp;lt;\u0026amp;gt;(sseEmitterMap.keySet()); } /** * 获取当前连接数量 */ public static int getUserCount() { return count.intValue(); } private static Runnable completionCallBack(String userId) { return () -\u0026amp;gt; { logger.info(\u0026quot;结束连接：{}\u0026quot;, userId); removeUser(userId); }; } private static Runnable timeoutCallBack(String userId) { return () -\u0026amp;gt; { logger.info(\u0026quot;连接超时：{}\u0026quot;, userId); removeUser(userId); }; } private static Consumer\u0026amp;lt;Throwable\u0026amp;gt; errorCallBack(String userId) { return throwable -\u0026amp;gt; { logger.info(\u0026quot;连接异常：{}\u0026quot;, userId); removeUser(userId); }; } }\n`\n\u0026gt; \u0026gt; 前端二： \u0026gt; \u0026gt; ``` `\u0026amp;lt;!DOCTYPE html\u0026amp;gt; \u0026amp;lt;html lang=\u0026#34;en\u0026#34;\u0026amp;gt; \u0026amp;lt;head\u0026amp;gt; \u0026amp;lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026amp;gt; \u0026amp;lt;title\u0026amp;gt;SseEmitter\u0026amp;lt;/title\u0026amp;gt; \u0026amp;lt;/head\u0026amp;gt; \u0026amp;lt;body\u0026amp;gt; \u0026amp;lt;button onclick=\u0026#34;closeSse()\u0026#34;\u0026amp;gt;关闭连接\u0026amp;lt;/button\u0026amp;gt; \u0026amp;lt;div id=\u0026#34;message\u0026#34;\u0026amp;gt;\u0026amp;lt;/div\u0026amp;gt; \u0026amp;lt;/body\u0026amp;gt; \u0026amp;lt;script\u0026amp;gt; let source = null; // 用时间戳模拟登录用户 const userId = new Date().getTime(); if (!!window.EventSource) { // 建立连接 source = new EventSource(\u0026amp;#39;http://127.0.0.1:8844/sse/connect/\u0026amp;#39; + userId); /** * 连接一旦建立，就会触发open事件 * 另一种写法：source.onopen = function (event) {} */ source.addEventListener(\u0026amp;#39;open\u0026amp;#39;, function (e) { setMessageInnerHTML(\u0026#34;建立连接。。。\u0026#34;); }, false); /** * 客户端收到服务器发来的数据 * 另一种写法：source.onmessage = function (event) {} */ source.addEventListener(\u0026amp;#39;message\u0026amp;#39;, function (e) { setMessageInnerHTML(e.data); }); /** * 如果发生通信错误（比如连接中断），就会触发error事件 * 或者： * 另一种写法：source.onerror = function (event) {} */ source.addEventListener(\u0026amp;#39;error\u0026amp;#39;, function (e) { if (e.readyState === EventSource.CLOSED) { setMessageInnerHTML(\u0026#34;连接关闭\u0026#34;); } else { console.log(e); } }, false); } else { setMessageInnerHTML(\u0026#34;你的浏览器不支持SSE\u0026#34;); } // 监听窗口关闭事件，主动去关闭sse连接，如果服务端设置永不过期，浏览器关闭后手动清理服务端数据 window.onbeforeunload = function () { closeSse(); }; // 关闭Sse连接 function closeSse() { source.close(); const httpRequest = new XMLHttpRequest(); httpRequest.open(\u0026amp;#39;GET\u0026amp;#39;, \u0026amp;#39;http://127.0.0.1:8844/sse/close/\u0026amp;#39; + userId, true); httpRequest.send(); console.log(\u0026#34;close\u0026#34;); } // 将消息显示在网页上 function setMessageInnerHTML(innerHTML) { document.getElementById(\u0026amp;#39;message\u0026amp;#39;).innerHTML += innerHTML + \u0026amp;#39;\u0026amp;lt;br/\u0026amp;gt;\u0026amp;#39;; } \u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;/html\u0026amp;gt; ` Demo实现二(Node) Node 服务器实例（如果自己想实现SSE服务端参考这个，主要是实现协议）\nSSE要求服务器与浏览器保持连接，对于不同的服务器软件来说，所消耗的资源也不一样的。Node则是所有连接都使用同一个线程，因此消耗的资源会小很多，但是这个要求每个连接不能包含很耗时的操作（比如磁盘IO的读写）\n`var http = require(\u0026ldquo;http\u0026rdquo;);\nhttp.createServer(function(req,res){ var fileName = \u0026ldquo;.\u0026quot;+req.url; if(fileName===\u0026rdquo;./stream\u0026quot;){ res.writeHead(200,{ \u0026ldquo;Content-Type\u0026rdquo;:\u0026ldquo;text/event-stream\u0026rdquo;, \u0026ldquo;Cache-Control\u0026rdquo;:\u0026ldquo;no-cache\u0026rdquo;, \u0026ldquo;Connection\u0026rdquo;:\u0026ldquo;keep-alive\u0026rdquo;, \u0026ldquo;Access-Control-Allow-Origin\u0026rdquo;:\u0026quot;*\u0026quot; }); res.write(\u0026ldquo;retry:10000\\n\u0026rdquo;); res.write(\u0026ldquo;event:connecttime\\n\u0026rdquo;); res.write(\u0026ldquo;data:\u0026quot;+(new Date())+\u0026quot;\\n\\n\u0026rdquo;); res.write(\u0026ldquo;data:\u0026quot;+(new Date())+\u0026quot;\\n\\n\u0026rdquo;); interval = setInterval(function(){ res.write(\u0026ldquo;data:\u0026quot;+(new Date())+\u0026quot;\\n\\n\u0026rdquo;); } ); req.connection.addListener(\u0026ldquo;close\u0026rdquo;,function(){ clearInterval(interval); },fase); } }).listen(8888,\u0026ldquo;127.0.0.1\u0026rdquo;); `\n\u0026gt; \u0026gt; 前端代码 \u0026gt; \u0026gt; ``` `\u0026amp;lt;!DOCTYPE html\u0026amp;gt; \u0026amp;lt;html\u0026amp;gt; \u0026amp;lt;head\u0026amp;gt; \u0026amp;lt;meta charset=\u0026#34;utf-8\u0026#34;\u0026amp;gt; \u0026amp;lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width\u0026#34;\u0026amp;gt; \u0026amp;lt;title\u0026amp;gt;JS Bin\u0026amp;lt;/title\u0026amp;gt; \u0026amp;lt;/head\u0026amp;gt; \u0026amp;lt;body\u0026amp;gt; \u0026amp;lt;div id=\u0026#34;example\u0026#34;\u0026amp;gt;\u0026amp;lt;/div\u0026amp;gt; \u0026amp;lt;script\u0026amp;gt; var source = new EventSource(\u0026amp;#39;http://127.0.0.1:8844/stream\u0026amp;#39;); var div = document.getElementById(\u0026amp;#39;example\u0026amp;#39;); source.onopen = function (event) { div.innerHTML += \u0026amp;#39;\u0026amp;lt;p\u0026amp;gt;Connection open ...\u0026amp;lt;/p\u0026amp;gt;\u0026amp;#39;; }; source.onerror = function (event) { div.innerHTML += \u0026amp;#39;\u0026amp;lt;p\u0026amp;gt;Connection close.\u0026amp;lt;/p\u0026amp;gt;\u0026amp;#39;; }; source.addEventListener(\u0026amp;#39;connecttime\u0026amp;#39;, function (event) { div.innerHTML += (\u0026amp;#39;\u0026amp;lt;p\u0026amp;gt;Start time: \u0026amp;#39; + event.data + \u0026amp;#39;\u0026amp;lt;/p\u0026amp;gt;\u0026amp;#39;); }, false); source.onmessage = function (event) { div.innerHTML += (\u0026amp;#39;\u0026amp;lt;p\u0026amp;gt;Ping: \u0026amp;#39; + event.data + \u0026amp;#39;\u0026amp;lt;/p\u0026amp;gt;\u0026amp;#39;); }; \u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;/body\u0026amp;gt; \u0026amp;lt;/html\u0026amp;gt; ` Demo实现三(PHP) Php实现SSE\n`\u0026lt;?php date_default_timezone_set(\u0026ldquo;America/New_York\u0026rdquo;); header(\u0026ldquo;Content-Type: text/event-stream\u0026rdquo;);\n\u0026lt;span class=\u0026ldquo;katex math inline\u0026rdquo;\u0026gt;counter = rand(1, 10); // a random counter while (1) { // 1 is always true, so repeat the while loop forever (aka event-loop)\u0026lt;/span\u0026gt;curDate = date(DATE_ISO8601); echo \u0026ldquo;event: ping\\n\u0026rdquo;, 'data: {\u0026ldquo;time\u0026rdquo;: \u0026ldquo;' . \u0026lt;span class=\u0026ldquo;katex math inline\u0026rdquo;\u0026gt;curDate . '\u0026rdquo;}', \u0026ldquo;\\n\\n\u0026rdquo;;\n// Send a simple message at random intervals.\u0026lt;/span\u0026gt;counter\u0026ndash;;\nif (!\u0026lt;span class=\u0026ldquo;katex math inline\u0026rdquo;\u0026gt;counter) { echo 'data: This is a message at time ' .\u0026lt;/span\u0026gt;curDate, \u0026ldquo;\\n\\n\u0026rdquo;; $counter = rand(1, 10); // reset random counter }\n// flush the output buffer and send echoed messages to the browser\nwhile (ob_get_level() \u0026gt; 0) { ob_end_flush(); } flush();\n// break the loop if the client aborted the connection (closed the page)\nif ( connection_aborted() ) break;\n// sleep for 1 second before running the loop again\nsleep(1);\n} `\n## Demo实现四 {#toc_10} ### 服务器端实现 {#toc_11} \u0026gt; 服务器端实现Server-sent Events，服务器端的 实现由两部分组成：一部分用来产生数据的org.eclipse.jetty.servlets.EventSource,另一部分作为浏览器访问端点的继承自org.eclipse.jetty.servlet.EventSourceServlet类的Servlet实现。 \u0026gt; \u0026gt; 实现EventsSource接口MovenmentEventSource \u0026gt; \u0026gt; ``` `public class MovenmentEventSource implements EventSource{ private int width =800; private int height = 600; private int stepMax =5; private int x=0; private int y = 0; private Random random = new Random(); public MovennmentEventSource(int width,int height,int stepMax){ this.width = width; this.height = height; this.stepMax = stepMax; this.x = random.nextInt(width); this.y = random.nextInt(height); } @Override public void onOpen(Emitter emitter) throws IOException{ query(emitter);//开始生产位置信息 } @Override public void onResume(Emitter emitter,String lastEventId){ updatePosition(lastEventId);//更新起始位置 query(emitter);//开始生成位置信息 } //根据Last-Event-Id来更新起始位置 private void updatePosition(String id){ if(id!=null){ String[] pos = id.split(\u0026#34;,\u0026#34;); if(pos.length\u0026amp;gt;1){ int xPos =-1,yPos = -1; try{ xPos = Integer.parseInt(pos[0],10); yPos = Integer.parseInt(pos[1],10); }catch(NumberFormatException e){ } if(isValidMove(xPos,yPos)){ xPos = xPos; yPos = yPos; } } } } private void query(Emitter emitter) throws IOException{ emitter.comment(\u0026#34;Start sending movement information.\u0026#34;); while(true){ emitter.comment(\u0026#34;\u0026#34;); move();//移动位置 String id = String.format(\u0026#34;%s,%s\u0026#34;,x,y); emitter.id(id);//根据位置生成时间 标识符 emitter.data(id);//发送位置信息数据 try{ Thread.sleep(2000); }catch(InterruptedException e){ break; } } } @Override public void onClose(){ } //获取下一个合法的移动位置 private void move(){ while(true){ int[] move = getMove(); int xNext = x+move[0]; int yNext = y+move[1]; if(isValidMove(xNext,yNext)){ x = xNext; y = yNext; break; } } } //判断当前的移动位置是否合法 private boolean inValidMove(int x,int y){ return x \u0026amp;gt;=0 \u0026amp;\u0026amp; x\u0026amp;lt;=width \u0026amp;\u0026amp; y\u0026amp;gt;=0 \u0026amp;\u0026amp; y \u0026amp;lt;= height; } //随机生成下一个移动位置 private int[] getMove(){ int[] xDir = new int[]{-1,0,1,0}; int[] yDir = new int[]{0,-1,0,1}; int dir = random,nextInt(4); return new int[]{xDir[dir]*random.nextInt(stepMax),yDir[dir]*random.nextInt(stepMax)}; } } ` onOpen方法在浏览器端的连接打开的时候被调用，onResume方法在浏览器重新建立连接的时候被调用，onClose方法则在浏览器关闭连接的时候被调用。\npubic class MovementServlet extends EventSourceServlet{ @Override protected Event Source newEventSource(HttpServletRequest request,String clientId){ return new MovenmentEventSource(800,600,20); } } ### 浏览器端实现 {#toc_12} \u0026gt; 浏览器端的实现比较简单，只需要创建出EventSource对象，并添加相应的事件处理方法即可。 \u0026gt; \u0026gt; ``` `var es = new EventSource(\u0026amp;#39;sse/movement\u0026amp;#39;); es.addEventListener(\u0026amp;#39;message\u0026amp;#39;,function(e){ var pos = e.data.split(\u0026amp;#39;,\u0026amp;#39;),x = pos[0], y = pos[1]; $(\u0026#34;#box\u0026#34;).css( left: x+\u0026amp;#39;px\u0026amp;#39;, top: y+\u0026amp;#39;px\u0026amp;#39; ); }); ` 参考 https://www.ibm.com/developerworks/cn/web/1307_chengfu_serversentevent/index.html\nhttp://www.ruanyifeng.com/blog/2017/05/server-sent_events.html\nhttps://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events\nhttps://blog.csdn.net/superylcfly/article/details/103979799\n","permalink":"https://blog.zdltech.com/posts/html5fu-wu-qi-tui-song-shi-jian-serversentevent/","summary":"\u003ch1 id=\"toc_0\"\u003eHTML5服务器推送事件（Server-sent-event）\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e在前端开发中，实现界面推送的方式，这里大概总结下三种方式\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e轮询（ajax），比较耗费服务器资源。COMET方式（COMET 技术并不是 HTML 5 ）\u003c/li\u003e\n\u003cli\u003ewebsocket 双向数据推送，灵活，功能强大\u003c/li\u003e\n\u003cli\u003eServer-sent-event(简称SSE)，单项数据推送（Server-sent Events 规范是 HTML 5 规范的一个组成部分）\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e这里我们只讨论SSE\u003c/p\u003e\n\u003cp\u003eSSE的本质：严格地说，HTTP协议无法做到服务器主动推送信息。但是有一种变通的发光法，就是服务器向客户端声明，接下来要发送的是流信息，也就是说，发送的不是一次性的数据包，而是一个数据流，会连续不断的发送过来。这是客户端不会关闭连接，会一直等待服务器发过来的数据流，视频播放就是这样的例子。本质上这种通信就是以流信息的方式，完成一次用时很长的下载。\u003c/p\u003e\n\u003cp\u003eSSE就是利用这种机制，使用流信息想浏览器推送信息。它基于HTTP协议，除了IE/Edge，其他浏览器都支持\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"toc_1\"\u003e闲谈\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e在Web开发中，浏览器和服务器之间使用请求/响应的交互模式。浏览器发出请求，服务器根据请求来生成响应。这种交互方式，服务器端产生数据变化后不能及时的通知给浏览，只能在浏览器下次请求的时候，才能获取（对于某些对数据实时性要求很高的应用，这种延迟是不能接受的）。\u003c/p\u003e\n\u003cp\u003e使用浏览器原生的EventSource对象的一个比较大的问题是IE并不支持（为实现在IE上COMET或轮询，第二种使用polyfill技术）\u003c/p\u003e\n\u003cp\u003eSSE的客户端API部署在EventSource对象上，使用之前检测浏览器是否支持SSE\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003ccode\u003eif(typeof(EventSource)!==\u0026quot;undefined\u0026quot;) { // 浏览器支持 Server-Sent // 一些代码..... } else { // 浏览器不支持 Server-Sent.. } var source = new EventSource(url); // url可以在当前网址同域，也可以跨域，跨域时可以指定第二个参数withCredentials 表示是否一起发送Cookies \u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; EventSource的readyState 表明连接的当前状态，该属性只读\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt;   * 0: 相当于常量EventSource.CONNECTIONG 表示连接还未建立，或者断线正在重连\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt;   * 1:相当于常量EventSource.OPEN 表示连接已经建立，可以接受数据\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt;   * 2:相当于常量EventSource.CLOSED 表示连接已断，且不会重连\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e### Server-sent Events {#toc_2}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; Server-sent Events 规范是 HTML 5 规范的一个组成部分,该规范比较简单，主要由两部分组成：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; 第一部分：服务器端与浏览器之间的通讯协议\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; 第二部分：浏览器端可以提供JavaScript中使用EventSource对象。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; 通讯协议是基于纯文本的简单协议\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; 服务器端响应的内容类型为：text/event-stream，响应文本内容可以看成是一个事件流，有不同的事件组成。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; 每个事件由类型和数据两个部分组成，同时每个事件可以有一个可选的标识符。不同事件的内容之间通过仅包含回车符和换行符的空行来分隔。每个事件的数据可能由多行组成。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; 清单1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \u0026gt; ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`data: first event\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edata: second event\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eid: 100\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eevent: myevent\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edata: third event\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eid: 101\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e: this is a comment\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edata: fourth event\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edata: fourth event continue\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e每个事件之间通过空行来分隔。对于每行来说，冒号（：）前面表示的该行的类型，冒号后面则是对应的值。\u003c/p\u003e","title":"HTML5服务器推送事件（Server-sent-event）"},{"content":"adb常用命令\n1.adb devices , 获取设备列表及设备状态(adb -s 设备号 其他指令 adb -s devicel install xxx.apk)\n2.adb get-state , 获取设备的状态\n3.adb install 用于安装（此时需要用 -r 参数来重新安装。）\n4.adb uninstall 用于卸载（adb uninstall 后面带的是应用的包名，而不是应用名。adb uninstall -k 表示保留数据）\n5.adb shell pm list packages –f （查看系统所有应用的包名）\n6.adb push 命令将PC机上的文件推到 DLT-RK3288 机器上；\n7.adb pull 命令将DLT-RK3288机器上的文件拉到PC机上；\n{\n例如：\nadb push d:/new.txt /sdcard/\n将D盘下new.txt文件 推到内部存储器\nadb pull /sdcard/new.txt d:\\\n将DLT-RK3288 内部存储器根目录下的new.txt 拉到D盘\n}\nadb shell pm list package Package Manager , 可以用获取到一些安装在 Android 设备上得应用信息 -s：列出系统应用 -f：列出应用包名及对应的apk名及存放位置 9.adb shell { 通过adb shell 命令，就可以进入设备或者模拟器的shell环境了，在这个Linux shell中，我们就可以执行各种Linux命令了。 如果只想执行一条shell命令，就可以采用：adb shell [shell_command]，在实际使用中，经常与grep或findstr一起使用，起到过滤作用，查看自己需要的关键信息。 常见命令： 如 ls, cd, rm, mkdir, touch, pwd, cp, mv, ifconfig, netstat, ping, ps, top等，进入adb shell即可执行，与linux相似 } 10.adb logcat { 一.在cmd窗口查看手机的Log日志 `有时候我们在手机程序上的日志要在其他地方调试，然后要看里面的Log日志。在cmd窗口中输入如下命令： //格式1：打印默认日志数据\nadb logcat\n//格式2：需要打印日志详细时间的简单数据\nadb logcat -v time\n//格式3：需要打印级别为Error的信息\nadb logcat *:E\n//格式4：需要打印时间和级别是Error的信息\nadb logcat -v time *:E\n//格式5：将日志保存到电脑固定的位置，比如D:\\log.txt\nadb logcat -v time \u0026gt;D:\\log.txt\n这时手机日志更新什么日志，cmd窗口也会同步更新数据。\n但是这样没有过滤条件，如果Log日志很多，很难找到我们想要的信息，\n当然也可以复制cmd中的数据到一个文本中慢慢处理的，就是效率不高。\n下面介绍adb logcat中的详细参数命令以及如何才能高效的打印日志，或者把日志保存到我们指定的位置。\n二.adb logcat 详解\nadb logcat如果用过，但是具体命令又不记得，可以输入adb logcat -help，查看一下一些简单的数据格式： 日志过滤：adb logcat \u0026lt;tag\u0026gt;[:priority]\ntag表示标签，priority输出的级别，日志默认级别是V，如果错误日志我们选择E就可以。\nAndroid 的日志分为如下几个优先级（priority）：\nV —— Verbose（最低，输出得最多）\nD —— Debug\nI —— Info\nW —— Warning\nE —— Error\nF —— Fatal\nS —— Silent（最高，啥也不输出）\n按某级别过滤日志则会将该级别及以上的日志输出。比如，命令：adb logcat *:W\n其实*可以是某个tag，如果没有指明，就表示所有。\ntag可以由多个 [:priority] 组成。比如，命令：\nadb logcat ActivityManager:I MyApp:D *:S\n表示输出 tag ActivityManager 的 Info 以上级别日志，输出 tag MyApp 的 Debug 以上级别日志，及其它 tag 的 Silent 级别日志（即屏蔽其它 tag 日志）。\nadb logcat选项解析\n\u0026ndash;\u0026quot;-s\u0026quot;选项 : 设置输出日志*：s的标签, 只显示该标签的日志;\n\u0026ndash;\u0026quot;-f\u0026quot;选项 : 将日志输出到文件, 默认输出到标准输出流中, -f 参数执行不成功;\n\u0026ndash;\u0026quot;-r\u0026quot;选项 : 按照每千字节输出日志, 需要 -f 参数, 不过这个命令没有执行成功;\n\u0026ndash;\u0026quot;-n\u0026quot;选项 : 设置日志输出的最大数目, 需要 -r 参数, 这个执行 感觉 跟 adb logcat 效果一样;\n\u0026ndash;\u0026quot;-v\u0026quot;选项 : 设置日志的输出格式, 注意只能设置一项;\n\u0026ndash;\u0026quot;-c\u0026quot;选项 : 清空所有的日志缓存信息;\n\u0026ndash;\u0026quot;-d\u0026quot;选项 : 将缓存的日志输出到屏幕上, 并且不会阻塞;\n\u0026ndash;\u0026quot;-t\u0026quot;选项 : 输出最近的几行日志, 输出完退出, 不阻塞;\n\u0026ndash;\u0026quot;-g\u0026quot;选项 : 查看日志缓冲区信息;\n\u0026ndash;\u0026quot;-B\u0026quot;选项 : 以二进制形式输出日志;\n把日志信息保存到电脑中\nadb logcat最后添加” \u0026gt; 保存文件的地址，比如需要将的信息保存到电脑中使用下面的命令： adb logcat -v time \u0026gt; D:\\log.txt }`\n查看顶部Activity: win adb shell dumpsys activity | findstr “mFocusedActivity” linux adb shell dumpsys activity | grep “mFocusedActivity”\n启动Activity: adb shell am start 包名/完整Activity路径 { adb shell am start com.zhy.aaa/com.zhy.aaa.MainActivity 如果需要携带参数(携带一个Intent,Key 为name): adb shell am start com.zhy.aaa/com.zhy.aaa.MainActivity -e name zhy } 13.启动一个隐式的Intent: adb shell am start -a “android.intent.action,VIEW” -d “https://www.google.com” 14.发送广播： adb shell am broadcast -a “broadcastactionfilter” -如果需要携带参数（携带一个Intent,key为name）: adb shell am broadcast -a “broadcastactionfilter” -e name zhy 15.启动服务： adb shell am startservice “com.zhy.aaa/com.zhy.aaa.MyService” 16.屏幕截图： 可以使用screencap命令来进行手机屏幕截图 adb shell screencap /sdcard/screen.png 17.录制视频： 可以使用screenrecord[options] filename命令来录制屏幕视频，例如： adb shell screenrecord /sdcard/demo.mp4 18.事件输入： 18.1 input 使用adb shell input命令向屏幕输入一些信息 adb shell input text “insert%stext%shere”(注意：%s表示空格) 使用adb shell input tap命令来模拟屏幕点击事件 adb shell input tap 500 1450(表示在屏幕上（500，1450）的坐标点上进行一次点击) 使用adb shell input swipe命令来模拟手势滑动事件 adb shell input swipe 100 500 100 1450 100(表示从屏幕坐标（100，500）开始，滑动到(100,1450)结束，整个过程耗时100ms) 使用上面的命令还可以模拟”长按（long press）操作，也就是2个坐标点相同，耗时超过500ms. adb shell input swipe 100 500 100 500 500 使用adb shell input keyevent命令来模拟点按实体按钮的命令 adb shell input keyevent 25(该命令表示调低音量。数字25是在AOSP源码中的KeyEvent类里卖弄定义的一个事件常量。该类定义了将近300个事件常量。) 18.2 am am(Activity Manager)命令来启动一个APP、启动Activity、启动广播和服务等等。 启动一个activity，最简单的命令可以使用adb shell am start com.package.name/com.package.name.ActivityName 如果启动带有参数，则使用-e标签 { class SecondActivity : AppCompatActivity() { ` companion object { private val ARGUS_NAME = \u0026ldquo;argus_name\u0026rdquo; fun launch(activity: Activity, content: String): Intent { val intent = Intent(activity, SecondActivity::class.java) intent.putExtra(ARGUS_NAME, content) return intent } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_second)\nval name = intent.getStringExtra(ARGUS_NAME) nameTv.text = \u0026quot;Hello, $name\u0026quot; } } adb shell am start com.example.crime/com.example.crime.SecondActivity -e argus_name QiuShui 除了默认启动的activity外，打开其他的activity时，需要在清单文件中添加android:exported=\u0026ldquo;true\u0026quot;属性。} 要启动一个隐式的Intent，也就是说需要传入action等参数，在ADB调试桥中可以得知Intent的参数规范，比如**-a表示action**,-c表示category,-d表示data_uri,-e表示添加额外Key-Value信息。 adb shell am start -a \u0026ldquo;android.intent.action.VIEW\u0026rdquo; -d \u0026ldquo;https://www.google.com\u0026rdquo;(上面这个命令会启动浏览器打开谷歌网址页面。) am 也能发送广播和启动服务 adb shell am broadcast -a \u0026ldquo;our.specified.action\u0026rdquo; 还可以在上述命令后面添加**-e来添加额外的信息 使用下面的命令可以直接让手机重启 adb shell am broadcast -a android.intent.action.BOOT_COMPILETED 启动一个服务也是类似 adb shell am startservice \u0026ldquo;com.example.crime/com.example.crime.MyService\u0026rdquo; (https://blog.csdn.net/qq_39969226/article/details/87897863)` 19.事件输出 19.1 日志信息adb logcat 19.2 dumpsys dumpsys命令可以提供非常多的系统信息(可以通过adb shell service list来查看dumpsys能提供查询信息的服务) 19.3 屏幕截图： 使用screencap 命令来进行手机屏幕截图(adb shell screencap /sdcard/screen.png) 19.4 录制视频： 使用screenrecord [options] filename命令来录制屏幕视频(adb shell screenrecord /sdcard/demo.mp4){注：此命令适用于Android 4.4及以上的设备中。 20.系统命令 20.1 查看进程信息： 使用adb shell ps命令查看进程信息。可以在该命令后加包名，来查看某个应用程序的进程信息。 20.2 查看CPU使用情况： 使用adb shell top **命令来查看系统CPU使用情况。（ctrl+c结束） https://www.wanandroid.com/blog/show/2310 https://developer.android.com/studio/command-line/adb.html https://github.com/mzlogin/awesome-adb https://blog.csdn.net/wang18323834864/article/details/78618748\n21.查看当前adb版本\nadb version\n22.adb-server 的开启与关闭\nadb kill-server adb start-server\n手机重启 adb reboot\n获得应用的apk所在路径 adb shell pm path 应用的包名\nadb shell input keycode 指令 HOME 键 adb shell input keycode 3 返回键 adb shell input keycode 4 打开浏览器 adb shell input keycode 64\nadb shell wm 指令 屏幕分辨率 adb shell wm size 屏幕密度 adb shell wm density adb shell wm density 320/480/640 可修改屏幕密度查看效果，对应Launcher图标会缩放\nadb shell ifconfig 命令 IP 地址 adb shell ifconfig “| grep Mask” WIFI 地址 adb shell ifconfig wlan0\n状态栏和导航栏的显示隐藏 adb shell settings put global policy_control ( 可由如下几种键及其对应的值组成，格式为 key1=value1:key2=value2。) immersive.full 同时隐藏 immersive.status 隐藏状态栏 immersive.navigation 隐藏导航栏 immersive.preconfirms 同时显示 { adb shell settings put global policy_control immersive.full=* 表示设置在所有界面下都同时隐藏状态栏和导航栏。（重启也不会失效，恢复需调用下面的命令） `adb shell settings put global policy_control immersive.preconfirms=* 表示恢复显示\nadb shell settings put global policy_control immersive.status=com.package1,com.package2:immersive.navigation=apps,-com.package3 表示设置在包名为 com.package1 和 com.package2 的应用里隐藏状态栏，在除了包名为 com.package3 的所有应用里隐藏导航栏。` }\n关闭指定包名的应用程序 （force-stop ） adb shell am force-stop com.some.package\n杀死与应用程序的包名称相关联的所有进程。该命令只会杀死安全的进程，不会影响用户体验。 （kill [options] ） adb shell am kill com.some.package\n","permalink":"https://blog.zdltech.com/posts/adb%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/","summary":"\u003cp\u003eadb常用命令\u003cbr\u003e\n1.adb devices , 获取设备列表及设备状态(adb -s 设备号 其他指令 adb -s devicel install xxx.apk)\u003cbr\u003e\n2.adb get-state , 获取设备的状态\u003cbr\u003e\n3.adb install 用于安装（此时需要用 -r 参数来重新安装。）\u003cbr\u003e\n4.adb uninstall 用于卸载（adb uninstall 后面带的是应用的包名，而不是应用名。adb uninstall -k 表示保留数据）\u003cbr\u003e\n5.adb shell pm list packages –f （查看系统所有应用的包名）\u003cbr\u003e\n6.adb push 命令将PC机上的文件推到 DLT-RK3288 机器上；\u003cbr\u003e\n7.adb pull 命令将DLT-RK3288机器上的文件拉到PC机上；\u003cbr\u003e\n{\u003cbr\u003e\n例如：\u003cbr\u003e\nadb push d:/new.txt /sdcard/\u003cbr\u003e\n将D盘下new.txt文件 推到内部存储器\u003cbr\u003e\nadb pull /sdcard/new.txt d:\\\u003cbr\u003e\n将DLT-RK3288 内部存储器根目录下的new.txt 拉到D盘\u003cbr\u003e\n}\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eadb shell pm list package\nPackage Manager , 可以用获取到一些安装在 Android 设备上得应用信息\n-s：列出系统应用\n-f：列出应用包名及对应的apk名及存放位置\n9.adb shell\n{\n通过adb shell 命令，就可以进入设备或者模拟器的shell环境了，在这个Linux shell中，我们就可以执行各种Linux命令了。\n如果只想执行一条shell命令，就可以采用：adb shell [shell_command]，在实际使用中，经常与grep或findstr一起使用，起到过滤作用，查看自己需要的关键信息。\n常见命令：\n如 ls, cd, rm, mkdir, touch, pwd, cp, mv, ifconfig, netstat, ping, ps, top等，进入adb shell即可执行，与linux相似\n}\n10.adb logcat\n{\n一.在cmd窗口查看手机的Log日志 `有时候我们在手机程序上的日志要在其他地方调试，然后要看里面的Log日志。在cmd窗口中输入如下命令：\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e//格式1：打印默认日志数据\u003c/p\u003e","title":"adb常用命令"},{"content":"Spring boot 自定义处理404 500等 有时候我们会遇到一些问题，需要我们自定义一些异常，例如404、403、502、500等，我们这里就说说Springboot 修改自定义这些。\n处理方式一 我们重写ErrorController接口，重写handleError方法\n`import javax.servlet.http.HttpServletRequest;\nimport org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;\n@Controller public class MainsiteErrorController implements ErrorController{\n@RequestMapping(\u0026quot;/error\u0026quot;) public ModelAndView handleError(HttpServletRequest request,HttpServletResponse response){ //获取statusCode:401,404,500 //Integer statusCode = (Integer) request.getAttribute(\u0026ldquo;javax.servlet.error.status_code\u0026rdquo;); Integer statusCode =response.getStatus(); ModelAndView model = new ModelAndView(); if(statusCode == 401){ model.setViewName(\u0026ldquo;401.html\u0026rdquo;); }else if(statusCode == 404){ model.setViewName(\u0026ldquo;404.html\u0026rdquo;); }else if(statusCode == 403){ model.setViewName(\u0026ldquo;403.html\u0026rdquo;); }else{ model.setViewName(\u0026ldquo;500.html\u0026rdquo;); } return model; } @Override public String getErrorPath() { return \u0026ldquo;/error\u0026rdquo;; }\n} `\n\u0026gt; \u0026gt; 这里可以使用 \u0026gt; \u0026gt; request.getAttribute(\u0026#34;javax.servlet.error.status_code\u0026#34;)或者response.getStatus() \u0026gt; \u0026gt; 使用哪个取决于你个人处理 \u0026gt; \u0026gt; 如果你在你自己的业务逻辑中自己通过 response.sendError(404)（或者用request的转发处理）来自定义处理，就有用response.getStatus()处理 \u0026gt; \u0026gt; 至于request.getAttribute(\u0026#34;javax.servlet.error.status_code\u0026#34;)笔者没有使用（请小伙伴们自己试试） ### 方式二 {#toc_2} \u0026gt;![img](http://andaily.com/blog/images/2019/06/error-view-resolver.jpg) \u0026gt; \u0026gt; 这种笔者也没有试试，小伙伴们可以试试 ### 方式三 {#toc_3} \u0026gt; springboot 在 BasicErrorController 类里实现了默认的错误处理。只需要将对应的错误提示文件放到 resources/static/error 目录，支持模糊匹配，如 \u0026gt; \u0026gt; static/error/4xx.html \u0026gt; static/error/5xx.html \u0026gt; static/error/404.html \u0026gt; static/error/error.html \u0026gt; \u0026gt; \u0026gt;![在这里插入图片描述](https://tva1.sinaimg.cn/large/007S8ZIlly1gho0n6pwuej307w0530sn.jpg) \u0026gt; \u0026gt; 这这完全交由系统处理 ### 方式四 {#toc_4} \u0026gt; 这种方式原理就是我们通过ErrorPage自定义错误界面，这个配置的实际上就是我们的访问路径，这个路径需要我们自己通过Controller配置（和配置普通的方法一样，只是这个方法的名字是404或者其他） 1. 添加AppErrorPagesConfiguration \u0026gt; ``` `@Configuration public class AppErrorPagesConfiguration { @Bean public MyErrorPageRegistrar errorPageRegistrar(){ return new MyErrorPageRegistrar(); } private class MyErrorPageRegistrar implements ErrorPageRegistrar { @Override public void registerErrorPages(ErrorPageRegistry errorPageRegistry) { ErrorPage page404 = new ErrorPage(HttpStatus.NOT_FOUND, \u0026#34;/404\u0026#34;); ErrorPage page500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, \u0026#34;/500\u0026#34;); errorPageRegistry.addErrorPages(page404, page500); } } ` \u0026gt; \u0026gt; 这里面的404 和500 实际上就是我们自定义的访问路径 \u0026gt; \u0026gt; HttpStatus是系统提供给我们的错误码，我们可以根据自己项目需求，使用里面的错误码 添加AppErrorController \u0026gt; ``` `@Controller public class AppErrorController{\n@RequestMapping(value = \u0026quot;/404\u0026quot;,produces = {\u0026quot;text/html\u0026quot;}) public ModelAndView errorPage404(){ return new ModelAndView(\u0026quot;/404\u0026quot;); } @RequestMapping(\u0026quot;/404\u0026quot;) @ResponseBody public ResponseEntity error404(){ return ResponseEntity.status(404).build(); } @RequestMapping(value=\u0026quot;/500\u0026quot;,produces = {\u0026quot;text/html\u0026quot;}) public ModelAndView errorPage500(){ return new ModelAndView(\u0026quot;/500\u0026quot;); } @RequestMapping(value = \u0026quot;/500\u0026quot;) @ResponseBody public ResponseEntity error500(){ return ResponseEntity.status(500).build(); } `\n\u0026gt; \u0026gt; 这个和普通的Controller没有区别 ","permalink":"https://blog.zdltech.com/posts/spring-boot-zi-ding-yi-chu-li404-500deng/","summary":"\u003ch2 id=\"toc_0\"\u003eSpring boot 自定义处理404 500等\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e有时候我们会遇到一些问题，需要我们自定义一些异常，例如404、403、502、500等，我们这里就说说Springboot 修改自定义这些。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"toc_1\"\u003e处理方式一\u003c/h3\u003e\n\u003cp\u003e我们重写ErrorController接口，重写handleError方法\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e`import javax.servlet.http.HttpServletRequest;\u003c/p\u003e\n\u003cp\u003eimport org.springframework.boot.web.servlet.error.ErrorController;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\u003c/p\u003e\n\u003cp\u003e@Controller\npublic class MainsiteErrorController implements ErrorController{\u003c/p\u003e\n\u003cp\u003e@RequestMapping(\u0026quot;/error\u0026quot;)\npublic ModelAndView handleError(HttpServletRequest request,HttpServletResponse response){\n//获取statusCode:401,404,500\n//Integer statusCode = (Integer) request.getAttribute(\u0026ldquo;javax.servlet.error.status_code\u0026rdquo;);\nInteger statusCode =response.getStatus();\nModelAndView model = new ModelAndView();\nif(statusCode == 401){\nmodel.setViewName(\u0026ldquo;401.html\u0026rdquo;);\n}else if(statusCode == 404){\nmodel.setViewName(\u0026ldquo;404.html\u0026rdquo;);\n}else if(statusCode == 403){\nmodel.setViewName(\u0026ldquo;403.html\u0026rdquo;);\n}else{\nmodel.setViewName(\u0026ldquo;500.html\u0026rdquo;);\n}\nreturn model;\n}\n@Override\npublic String getErrorPath() {\nreturn \u0026ldquo;/error\u0026rdquo;;\n}\u003c/p\u003e","title":"Spring boot 自定义处理404 500等"},{"content":"Gitea 安装配置 在很多时候，我们希望有自己的git仓库管理，把我们隐私的一点点工程，放在里面。大家也可以去使用目前网上免费的，例如 github、gitee 、gitlab、 coding.net、gogs、gitea等\nCentos 安装Gitea 下载gitea wget -O gitea https://dl.gitea.io/gitea/1.12.1/gitea-1.12.1-linux-amd64 下载下来的gitea是没有 执行权限的，我们需要给他执行权限 chmod a+x gitea 复制gitea到 /usr/log/bin 方便我们之间执行 cp gitea /usr/local/bin/ 执行 启动 gitea web 根据gitea 页面信息，进行初始化配置，配置最后所在文件地址 cat /usr/local/bin/custom/conf/app.ini 如果需要后台运行 使用 nohup gitea \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 \u0026amp; 命令 完成 开心的使用Gitea吧 通过 ps -ef |grep gitea |grep -v \u0026ldquo;grep\u0026rdquo;|wc -l 查询是否运行 返回1 表示运行\n通过 ps -ef |grep gitea |grep -v \u0026ldquo;grep\u0026rdquo; 查询具体的执行信息\n","permalink":"https://blog.zdltech.com/posts/gitea-an-zhuang-pei-zhi-ji-shi-yong/","summary":"\u003ch2 id=\"toc_0\"\u003eGitea 安装配置\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e在很多时候，我们希望有自己的git仓库管理，把我们隐私的一点点工程，放在里面。大家也可以去使用目前网上免费的，例如 github、gitee 、gitlab、 coding.net、gogs、gitea等\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"toc_1\"\u003eCentos 安装Gitea\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003col\u003e\n\u003cli\u003e下载gitea wget -O gitea \u003ca href=\"https://dl.gitea.io/gitea/1.12.1/gitea-1.12.1-linux-amd64\"\u003ehttps://dl.gitea.io/gitea/1.12.1/gitea-1.12.1-linux-amd64\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e下载下来的gitea是没有 执行权限的，我们需要给他执行权限 \u003cmark\u003echmod a+x gitea\u003c/mark\u003e\u003c/li\u003e\n\u003cli\u003e复制gitea到 /usr/log/bin 方便我们之间执行 \u003cmark\u003ecp gitea /usr/local/bin/\u003c/mark\u003e\u003c/li\u003e\n\u003cli\u003e执行 启动 \u003cmark\u003egitea web\u003c/mark\u003e\u003c/li\u003e\n\u003cli\u003e根据gitea 页面信息，进行初始化配置，配置最后所在文件地址 \u003cmark\u003ecat /usr/local/bin/custom/conf/app.ini\u003c/mark\u003e\u003c/li\u003e\n\u003cli\u003e如果需要后台运行 使用 \u003cmark\u003enohup gitea \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 \u0026amp;\u003c/mark\u003e 命令\u003c/li\u003e\n\u003cli\u003e完成 开心的使用Gitea吧\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e通过 \u003cmark\u003eps -ef |grep gitea |grep -v \u0026ldquo;grep\u0026rdquo;|wc -l\u003c/mark\u003e 查询是否运行 返回1 表示运行\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e通过 \u003cmark\u003eps -ef |grep gitea |grep -v \u0026ldquo;grep\u0026rdquo;\u003c/mark\u003e 查询具体的执行信息\u003c/p\u003e\u003c/blockquote\u003e\u003c/blockquote\u003e","title":"Gitea 安装配置及使用"},{"content":"PDF转图片 在开发过程中，我们遇到PDF 转图片的需求，这里主要介绍下Java（Apache pdfbox）\nJava Apache PdfBox使用 首先我们要引入Apache Pdfbox的包\ngradle\ncompile \u0026lsquo;org.apache.pdfbox:pdfbox:2.0.14\u0026rsquo;\nmaven\n\u0026amp;lt;!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox --\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.apache.pdfbox\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;pdfbox\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;2.0.14\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026gt; \u0026gt; 接下来几行代码搞定 \u0026gt; \u0026gt; ``` ` import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPageTree; import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.PDFRenderer; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; public class App { public static void main(String[] args) { Long currentTimeMillis = System.currentTimeMillis(); File dir = new File(\u0026#34;.\u0026#34;); File[] filesList = dir.listFiles(); if (filesList != null) { for (File file : filesList) { if (file.isFile() \u0026amp;\u0026amp; getFileExtension(file.getName()).equalsIgnoreCase(\u0026#34;pdf\u0026#34;)) { convert(file); } } } long diff = System.currentTimeMillis() - currentTimeMillis; System.out.print(diff); } private static String getFileExtension(String fileName) { if (fileName == null || fileName.equals(\u0026#34;\u0026#34;)) return \u0026#34;undefined\u0026#34;; int dotIndex = fileName.lastIndexOf(\u0026#34;.\u0026#34;); return (dotIndex == -1) ? \u0026#34;\u0026#34; : fileName.substring(dotIndex + 1); } private static void convert(File sourceFile) { try { String destinationDir = sourceFile.getName().replace(\u0026#34;.pdf\u0026#34;, \u0026#34;\u0026#34;) + \u0026#34;/\u0026#34;; // converted images from pdf document are saved here File destinationFile = new File(destinationDir); if (!destinationFile.exists()) { boolean fileCreated = destinationFile.mkdir(); if (fileCreated) System.out.println(\u0026#34;Folder Created -\u0026amp;gt; \u0026#34;+ destinationFile.getAbsolutePath()); } if (sourceFile.exists()) { System.out.println(\u0026#34;Images copied to Folder: \u0026#34;+ destinationFile.getName()); PDDocument document = PDDocument.load(sourceFile); PDPageTree pdPageTree = document.getDocumentCatalog().getPages(); System.out.println(\u0026#34;Total files to be converted -\u0026amp;gt; \u0026#34;+ pdPageTree.getCount()); PDFRenderer pdfRenderer = new PDFRenderer(document); String fileName = sourceFile.getName().replace(\u0026#34;.pdf\u0026#34;, \u0026#34;\u0026#34;); int pageNumber = 1; for (int page = 0; page \u0026amp;lt; document.getNumberOfPages(); ++page) { BufferedImage image = pdfRenderer.renderImageWithDPI(page, 150, ImageType.RGB); File outputFile = new File(destinationDir + fileName +\u0026#34;_\u0026#34;+ pageNumber +\u0026#34;.jpg\u0026#34;); System.out.println(\u0026#34;Image Created -\u0026amp;gt; \u0026#34;+ outputFile.getName()); ImageIO.write(image, \u0026#34;jpg\u0026#34;, outputFile); pageNumber++; } document.close(); System.out.println(\u0026#34;Converted Images are saved at -\u0026amp;gt; \u0026#34;+ destinationFile.getAbsolutePath()); } else { System.err.println(sourceFile.getName() +\u0026#34; File not exists\u0026#34;); } } catch (Exception e) { e.printStackTrace(); } } } ` 这里主要使用了BufferedImage与ImageIO输出图片，通Pdfbox获取到PDF的内容\n","permalink":"https://blog.zdltech.com/posts/pdf-zhuan-tu-pian/","summary":"\u003ch2 id=\"toc_0\"\u003ePDF转图片\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e在开发过程中，我们遇到PDF 转图片的需求，这里主要介绍下Java（Apache pdfbox）\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"toc_1\"\u003eJava Apache PdfBox使用\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e首先我们要引入Apache Pdfbox的包\u003c/p\u003e\n\u003cp\u003egradle\u003c/p\u003e\n\u003cp\u003ecompile \u0026lsquo;org.apache.pdfbox:pdfbox:2.0.14\u0026rsquo;\u003c/p\u003e\n\u003cp\u003emaven\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003ccode\u003e\u0026amp;lt;!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox --\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.apache.pdfbox\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;pdfbox\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;2.0.14\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e 接下来几行代码搞定\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport org\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapache\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epdfbox\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epdmodel\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ePDDocument;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport org\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapache\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epdfbox\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epdmodel\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ePDPageTree;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport org\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapache\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epdfbox\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003erendering\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eImageType;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport org\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapache\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epdfbox\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003erendering\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ePDFRenderer;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport javax\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eimageio\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eImageIO;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eawt\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eimage\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBufferedImage;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eio\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eFile;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e App {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e void main(String[] args) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       Long currentTimeMillis \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecurrentTimeMillis();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       File dir \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new File(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;.\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       File[] filesList \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e dir\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elistFiles();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (filesList \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           \u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e (File file : filesList) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (file\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eisFile() \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e getFileExtension(file\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetName())\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eequalsIgnoreCase(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;pdf\u0026#34;\u003c/span\u003e)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                   \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003econvert\u003c/span\u003e(file);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       long diff \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecurrentTimeMillis() \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e currentTimeMillis;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprint(diff);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   private \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e String getFileExtension(String fileName) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (fileName \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e null \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e fileName\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eequals(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;undefined\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       int dotIndex \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e fileName\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elastIndexOf(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;.\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e (dotIndex \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e) ? \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e : fileName\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esubstring(dotIndex \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   private \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e void \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003econvert\u003c/span\u003e(File sourceFile) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       try {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           String destinationDir \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e sourceFile\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetName()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ereplace(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;.pdf\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e) \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/\u0026#34;\u003c/span\u003e; \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e converted images from pdf document are saved here\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           File destinationFile \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new File(destinationDir);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003edestinationFile\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eexists()) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               boolean fileCreated \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e destinationFile\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emkdir();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (fileCreated)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                   System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Folder Created -\u0026amp;gt; \u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e destinationFile\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetAbsolutePath());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (sourceFile\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eexists()) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Images copied to Folder: \u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e destinationFile\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetName());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               PDDocument document \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e PDDocument\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eload(sourceFile);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               PDPageTree pdPageTree \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e document\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetDocumentCatalog()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetPages();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Total files to be converted -\u0026amp;gt; \u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e pdPageTree\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetCount());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               PDFRenderer pdfRenderer \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new PDFRenderer(document);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               String fileName \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e sourceFile\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetName()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ereplace(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;.pdf\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               int pageNumber \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               \u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e (int page \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e; page \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt; document\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetNumberOfPages(); \u003cspan style=\"color:#ff79c6\"\u003e++\u003c/span\u003epage) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                   BufferedImage image \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e pdfRenderer\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003erenderImageWithDPI(page, \u003cspan style=\"color:#bd93f9\"\u003e150\u003c/span\u003e, ImageType\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eRGB);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                   File outputFile \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new File(destinationDir \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e fileName \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;_\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e pageNumber \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;.jpg\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                   System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Image Created -\u0026amp;gt; \u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e outputFile\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetName());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                   ImageIO\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewrite(image, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;jpg\u0026#34;\u003c/span\u003e, outputFile);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                   pageNumber\u003cspan style=\"color:#ff79c6\"\u003e++\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               document\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eclose();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Converted Images are saved at -\u0026amp;gt; \u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e destinationFile\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetAbsolutePath());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           } \u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eerr\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(sourceFile\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetName() \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; File not exists\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       } catch (Exception e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintStackTrace();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003e这里主要使用了BufferedImage与ImageIO输出图片，通Pdfbox获取到PDF的内容\u003c/p\u003e","title":"PDF转图片"},{"content":"select DATE_FORMAT(NOW(),’%Y-%m-%d %T’) — 日期格式化 2020-06-30 11:03:26\nselect DATE_FORMAT(NOW(),’%Y-%c’) — 日期格式化 2020-6\nselect YEAR(NOW()) — 获取年2020\nselect DAY(NOW()) — 获取日30\nselect FLOOR(25.96) — 向下取整 25\nselect UNIX_TIMESTAMP(‘2020-06-30’) — 获取时间戳 1593446400\nselect CONCAT(‘zhang’,’-‘,’dong’,’-‘,’ling’) — 字符串拼接zhang-dong-ling\nselect MOD(89,9) — 取余 8\n","permalink":"https://blog.zdltech.com/posts/mysql%E5%87%BD%E6%95%B0%E4%BD%BF%E7%94%A8/","summary":"\u003cp\u003eselect DATE_FORMAT(NOW(),’%Y-%m-%d %T’) — 日期格式化 2020-06-30 11:03:26\u003cbr\u003e\nselect DATE_FORMAT(NOW(),’%Y-%c’) — 日期格式化 2020-6\u003cbr\u003e\nselect YEAR(NOW()) — 获取年2020\u003cbr\u003e\nselect DAY(NOW()) — 获取日30\u003cbr\u003e\nselect FLOOR(25.96) — 向下取整 25\u003cbr\u003e\nselect UNIX_TIMESTAMP(‘2020-06-30’) — 获取时间戳 1593446400\u003c/p\u003e\n\u003cp\u003eselect CONCAT(‘zhang’,’-‘,’dong’,’-‘,’ling’) — 字符串拼接zhang-dong-ling\u003c/p\u003e\n\u003cp\u003eselect MOD(89,9) — 取余 8\u003c/p\u003e","title":"MySql函数使用"},{"content":" Spring boot 集成ElasticSearch\n* [第一步Spring boot集成ELasticSearch][2] * [第二步Spring boot中配置ElasticSearch][3] * [第三步 创建操作的实体Bean（我创建的是UserItemBean）][4] * [第四步 使用ElasticSearch的API进行测试][5] Spring boot 集成ElasticSearch 第一步Spring boot集成ELasticSearch `\u0026lt;dependencies\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-data-elasticsearch\u0026lt;/artifactId\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-web\u0026lt;/artifactId\u0026gt; \u0026lt;/dependency\u0026gt;\n\u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-test\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;scope\u0026amp;gt;test\u0026amp;lt;/scope\u0026amp;gt; \u0026amp;lt;exclusions\u0026amp;gt; \u0026amp;lt;exclusion\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.junit.vintage\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;junit-vintage-engine\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/exclusion\u0026amp;gt; \u0026amp;lt;/exclusions\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;com.alibaba\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;fastjson\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;1.2.68\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026lt;/dependencies\u0026gt; `\n\u0026gt; \u0026gt; Spring boot集成ElasticSearch主要依赖 \u0026gt; \u0026gt; ``` `spring-boot-starter-data-elasticsearch ` 这里需要大家特别注意自己使用的ElasticSearch的版本 是否和自己的版本一致\n我这里是使用的最新的ElasticSearch 7.8.0\n需要配置版本\n\u0026amp;lt;properties\u0026amp;gt; \u0026amp;lt;java.version\u0026amp;gt;1.8\u0026amp;lt;/java.version\u0026amp;gt; \u0026amp;lt;elasticsearch.version\u0026amp;gt;7.8.0\u0026amp;lt;/elasticsearch.version\u0026amp;gt; \u0026amp;lt;/properties\u0026amp;gt; ### 第二步Spring boot中配置ElasticSearch {#toc_2} \u0026gt; 创建一个\u0026lt;mark\u0026gt;ElasticSearchConfig\u0026lt;/mark\u0026gt;的类，配置在下ElasticSearch的高级客户端api \u0026gt; \u0026gt; ``` `import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Elasticsearch 配置 */ @Configuration public class ElasticSearchConfig { @Bean public RestHighLevelClient restHighLevelClient(){//配置rest客户端 RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( new HttpHost(\u0026#34;192.168.1.187\u0026#34;, 9200, \u0026#34;http\u0026#34;))); return client; } } ` 注意：这里可以配置多个ElasticSearch 只需要创建多个HttpPost即可\n第三步 创建操作的实体Bean（我创建的是UserItemBean） 这个实体主要是使用ElasticSearch进行接口操作的实体\n`import org.springframework.stereotype.Component;\n@Component public class UserItemBean { //用户名 private String userName; //age private int age;\npublic UserItemBean() { } public UserItemBean(String name, int age) { this.userName = name; this.age = age; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return \u0026quot;UserItemBean{\u0026quot; + \u0026quot;userName=\u0026amp;#39;\u0026quot; + userName + \u0026amp;#39;\\\u0026amp;#39;\u0026amp;#39; + \u0026quot;, age=\u0026amp;#39;\u0026quot; + age + \u0026amp;#39;\\\u0026amp;#39;\u0026amp;#39; + \u0026amp;#39;}\u0026amp;#39;; } } `\n### 第四步 使用ElasticSearch的API进行测试 {#toc_4} \u0026gt; 我这里为了方便简单，我这里直接在Springboot的test中进行测试 \u0026gt; \u0026gt; ``` `import com.alibaba.fastjson.JSON; import com.zdltech.zdlesapi.bean.UserItemBean; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.client.indices.GetIndexRequest; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.TermsQueryBuilder; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException; import java.util.ArrayList; /** * API 7.8.0 api接口测试 */ @SpringBootTest class ZdlEsApiApplicationTests { @Autowired private RestHighLevelClient restHighLevelClient; @Test void contextLoads() { } /** * 索引创建 Request */ @Test void testCreateIndex() { //创建请求 CreateIndexRequest createIndexRequest = new CreateIndexRequest(\u0026#34;zdljava1\u0026#34;); // 客户端执行请求 try { CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT); System.out.println(createIndexResponse); } catch (IOException e) { e.printStackTrace(); } } /** * 获取索引 */ @Test void testExistIndex() { //创建索引请求 GetIndexRequest getIndexRequest = new GetIndexRequest(\u0026#34;zdljava1\u0026#34;); // 客户端执行请求 boolean exists = false; try { exists = restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT); } catch (IOException e) { e.printStackTrace(); } System.out.println(exists); } /** * 删除索引 */ @Test void testDeleteIndex() { //创建删除索引请求 DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(\u0026#34;zdljava1\u0026#34;); //客户端执行请求 try { AcknowledgedResponse delete = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT); System.out.println(delete.isAcknowledged()); } catch (IOException e) { e.printStackTrace(); } } /** * 添加文档 */ @Test void testAddDocument() { //创建对象 UserItemBean itemBean = new UserItemBean(\u0026#34;张东领\u0026#34;, 30); //创建请求 IndexRequest indexRequest = new IndexRequest(\u0026#34;zdljava1\u0026#34;);//相当于数据库 //设置规格 indexRequest.id(\u0026#34;1\u0026#34;);//文档 相当于 表 indexRequest.timeout(TimeValue.timeValueSeconds(1)); //设置数据 indexRequest.source(JSON.toJSONString(itemBean), XContentType.JSON); // 客户端执行请求 try { IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT); System.out.println(indexResponse); System.out.println(JSON.toJSONString(indexResponse)); } catch (IOException e) { e.printStackTrace(); } } /** * 获取文档 */ @Test void testGetDocument() { //构建请求参数 GetRequest getRequest = new GetRequest(\u0026#34;zdljava1\u0026#34;, \u0026#34;1\u0026#34;); try { boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT); System.out.println(exists); GetResponse documentFields = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT); System.out.println(JSON.toJSONString(documentFields)); } catch (IOException e) { e.printStackTrace(); } } /** * 更新文档 */ @Test void testUpdateDocument() { //构建请求 UpdateRequest updateRequest = new UpdateRequest(\u0026#34;zdljava1\u0026#34;, \u0026#34;1\u0026#34;); updateRequest.timeout(\u0026#34;1s\u0026#34;); UserItemBean userItemBean = new UserItemBean(\u0026#34;张东领01\u0026#34;, 33); updateRequest.doc(JSON.toJSONString(userItemBean), XContentType.JSON); try { UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT); System.out.println(JSON.toJSONString(updateResponse)); } catch (IOException e) { e.printStackTrace(); } } /** * 删除文档 */ @Test void testDeleteDocument() { //构建请求 DeleteRequest request = new DeleteRequest(\u0026#34;zdljava1\u0026#34;); request.id(\u0026#34;1\u0026#34;); request.timeout(\u0026#34;1s\u0026#34;); //客户端执行请求 try { DeleteResponse deleteResponse = restHighLevelClient.delete(request, RequestOptions.DEFAULT); System.out.println(JSON.toJSONString(deleteResponse)); } catch (IOException e) { e.printStackTrace(); } } /** * 批量 */ @Test void testBRequest() { BulkRequest request = new BulkRequest(); request.timeout(\u0026#34;10s\u0026#34;); ArrayList\u0026amp;lt;UserItemBean\u0026amp;gt; data = new ArrayList\u0026amp;lt;\u0026amp;gt;(); data.add(new UserItemBean(\u0026#34;zhangsan\u0026#34;, 6)); data.add(new UserItemBean(\u0026#34;lisi\u0026#34;, 18)); data.add(new UserItemBean(\u0026#34;wangwu\u0026#34;, 1000)); data.add(new UserItemBean(\u0026#34;liuche\u0026#34;, 890)); for (int i = 0; i \u0026amp;lt; data.size(); i++) { request.add( new IndexRequest(\u0026#34;zdljava1\u0026#34;).id(\u0026#34;\u0026#34; + (i + 5)).source(JSON.toJSONString(data.get(i)), XContentType.JSON) ); } try { BulkResponse bulkItemResponses = restHighLevelClient.bulk(request, RequestOptions.DEFAULT); System.out.println(JSON.toJSONString(bulkItemResponses)); } catch (IOException e) { e.printStackTrace(); } } /** * 查询 */ @Test void testSearchRequest(){ SearchRequest searchRequest = new SearchRequest(\u0026#34;zdljava1\u0026#34;); //构建搜索条件 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.highlighter(); // 搜索Query TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery(\u0026#34;userName.keyword\u0026#34;, \u0026#34;张三\u0026#34;,\u0026#34;李四\u0026#34;); // TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery(\u0026#34;userName\u0026#34;, \u0026#34;zhangsan\u0026#34;,\u0026#34;lisi\u0026#34;); // QueryBuilders.matchAllQuery(); searchSourceBuilder.query(termsQueryBuilder); searchSourceBuilder.timeout(TimeValue.timeValueSeconds(60)); searchRequest.source(searchSourceBuilder); try { SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); System.out.println(JSON.toJSONString(searchResponse)); for (SearchHit item: searchResponse.getHits().getHits()) { System.out.println(\u0026#34;================\u0026#34;); System.out.println(item.getSourceAsMap()); } } catch (IOException e) { e.printStackTrace(); } } } ` 这里就是整个Spring boot集成ElasticSearch，并使用API进行ElasticSearch的数据操作\n","permalink":"https://blog.zdltech.com/posts/spring-boot-ji-chengelasticsearch/","summary":"\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"#toc_0\"\u003eSpring boot 集成ElasticSearch\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e* [第一步Spring boot集成ELasticSearch][2] \n* [第二步Spring boot中配置ElasticSearch][3] \n* [第三步 创建操作的实体Bean（我创建的是UserItemBean）][4] \n* [第四步 使用ElasticSearch的API进行测试][5] \n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"toc_0\"\u003eSpring boot 集成ElasticSearch\u003c/h2\u003e\n\u003ch3 id=\"toc_1\"\u003e第一步Spring boot集成ELasticSearch\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e`\u0026lt;dependencies\u0026gt;\n\u0026lt;dependency\u0026gt;\n\u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt;\n\u0026lt;artifactId\u0026gt;spring-boot-starter-data-elasticsearch\u0026lt;/artifactId\u0026gt;\n\u0026lt;/dependency\u0026gt;\n\u0026lt;dependency\u0026gt;\n\u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt;\n\u0026lt;artifactId\u0026gt;spring-boot-starter-web\u0026lt;/artifactId\u0026gt;\n\u0026lt;/dependency\u0026gt;\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026amp;lt;dependency\u0026amp;gt;\n    \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n    \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-test\u0026amp;lt;/artifactId\u0026amp;gt;\n    \u0026amp;lt;scope\u0026amp;gt;test\u0026amp;lt;/scope\u0026amp;gt;\n    \u0026amp;lt;exclusions\u0026amp;gt;\n        \u0026amp;lt;exclusion\u0026amp;gt;\n            \u0026amp;lt;groupId\u0026amp;gt;org.junit.vintage\u0026amp;lt;/groupId\u0026amp;gt;\n            \u0026amp;lt;artifactId\u0026amp;gt;junit-vintage-engine\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;/exclusion\u0026amp;gt;\n    \u0026amp;lt;/exclusions\u0026amp;gt;\n\u0026amp;lt;/dependency\u0026amp;gt;\n\u0026amp;lt;dependency\u0026amp;gt;\n    \u0026amp;lt;groupId\u0026amp;gt;com.alibaba\u0026amp;lt;/groupId\u0026amp;gt;\n    \u0026amp;lt;artifactId\u0026amp;gt;fastjson\u0026amp;lt;/artifactId\u0026amp;gt;\n    \u0026amp;lt;version\u0026amp;gt;1.2.68\u0026amp;lt;/version\u0026amp;gt;\n\u0026amp;lt;/dependency\u0026amp;gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u0026lt;/dependencies\u0026gt;\n`\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; Spring boot集成ElasticSearch主要依赖\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`spring-boot-starter-data-elasticsearch    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003e\u003cmark\u003e这里需要大家特别注意自己使用的ElasticSearch的版本 是否和自己的版本一致\u003c/mark\u003e\u003c/p\u003e\n\u003cp\u003e我这里是使用的最新的ElasticSearch 7.8.0\u003c/p\u003e\n\u003cp\u003e需要配置版本\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003ccode\u003e\u0026amp;lt;properties\u0026amp;gt; \u0026amp;lt;java.version\u0026amp;gt;1.8\u0026amp;lt;/java.version\u0026amp;gt; \u0026amp;lt;elasticsearch.version\u0026amp;gt;7.8.0\u0026amp;lt;/elasticsearch.version\u0026amp;gt; \u0026amp;lt;/properties\u0026amp;gt; \u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e### 第二步Spring boot中配置ElasticSearch {#toc_2}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; 创建一个\u0026lt;mark\u0026gt;ElasticSearchConfig\u0026lt;/mark\u0026gt;的类，配置在下ElasticSearch的高级客户端api\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`import org.apache.http.HttpHost;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport org.elasticsearch.client.RestClient;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport org.elasticsearch.client.RestHighLevelClient;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport org.springframework.context.annotation.Bean;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport org.springframework.context.annotation.Configuration;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e * Elasticsearch 配置\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@Configuration\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic class ElasticSearchConfig {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Bean\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public RestHighLevelClient restHighLevelClient(){//配置rest客户端\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        RestHighLevelClient client = new RestHighLevelClient(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                RestClient.builder(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        new HttpHost(\u0026#34;192.168.1.187\u0026#34;, 9200, \u0026#34;http\u0026#34;)));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return client;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003e注意：这里可以配置多个ElasticSearch 只需要创建多个HttpPost即可\u003c/p\u003e","title":"Spring boot 集成ElasticSearch"},{"content":"使用window.open进行postmessage处理 打开新页面和监听界面的界面\n`\u0026amp;lt;!DOCTYPE html\u0026gt; \u0026amp;lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026amp;lt;head\u0026gt; \u0026amp;lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026gt; \u0026amp;lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34;\u0026gt; \u0026amp;lt;title\u0026gt;Document\u0026amp;lt;/title\u0026gt; \u0026amp;lt;/head\u0026gt; 我是监听界面 \u0026amp;lt;body\u0026gt; \u0026amp;lt;script\u0026gt; window.onload = function(){ console.log(\u0026#34;onload finish\u0026#34;); if(window.addEventListener){ console.log(\u0026#34;onload addEventListener\u0026#34;); window.addEventListener(\u0026#39;message\u0026#39;, function (e) { console.log(\u0026#34;addEventListener我监听到了\u0026#34;); // if (e.data.act == \u0026#39;response\u0026#39;) { // alert(e.data.msg.answer); // } else { // alert(\u0026#39;未定义的消息: \u0026#39; + e.data.act); // } console.log(e.data); }); }else{ window.attachEvent(\u0026#39;onmessage\u0026#39;, function (e) { console.log(\u0026#34;attachEvent我监听到了\u0026#34;); // if (e.data.act == \u0026#39;response\u0026#39;) { // alert(e.data.msg.answer); // } else { // alert(\u0026#39;未定义的消息: \u0026#39; + e.data.act); // } console.log(e.data); }); } } var popup = window.open(\u0026#34;indexopen.html\u0026#34;); popup.onload = function(){ // popup.postMessage(\u0026#34;hello there!\u0026#34;, \u0026#34;*\u0026#34;); console.log(\u0026#34;popup 设置监听\u0026#34;); popup.addEventListener(\u0026#39;message\u0026#39;, function (e) { console.log(\u0026#34;popup addEventListener我监听到了\u0026#34;); console.log(e.data); },false); popup.mydataFunction = function(){ console.log(\u0026#34;自定义的函数！\u0026#34;); } } \u0026amp;lt;/script\u0026gt; \u0026amp;lt;/body\u0026gt; \u0026amp;lt;/html\u0026gt;` 子界面及发送postmessage界面\n`\u0026amp;lt;!DOCTYPE html\u0026gt; \u0026amp;lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026amp;lt;head\u0026gt; \u0026amp;lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026gt; \u0026amp;lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34;\u0026gt; \u0026amp;lt;title\u0026gt;Document\u0026amp;lt;/title\u0026gt; \u0026amp;lt;/head\u0026gt; \u0026amp;lt;body\u0026gt; 我是发送界面 \u0026amp;lt;button id=\u0026#34;sendmsg\u0026#34; onclick=\u0026#34;sendMsg()\u0026#34;\u0026gt;发送监听\u0026amp;lt;/button\u0026gt; \u0026amp;lt;script\u0026gt; var targetPost; function sendMsg(){ console.log(\u0026#34;我来发送\u0026#34;); window.postMessage({ act: \u0026#39;myresponse\u0026#39;, msg:{ name:\u0026#39;zhang\u0026#39; } },\u0026#34;*\u0026#34;); window.postMessage({ act: \u0026#39;response\u0026#39;, msg: { type:\u0026#39;EOPEN_NOMAL_AGREE_2.0_PC\u0026#39;, answer: \u0026#39;成功\u0026#39; } }, \u0026#39;*\u0026#39;); mydataFunction(); } document.onreadystatechange = function(e){ if(document.readyState == \u0026#39;complete\u0026#39;){ window.addEventListener(\u0026#39;message\u0026#39;,function(event){ console.log(\u0026#34;index openheml addevent is run\u0026#34;); console.log(event.origin); console.log(event.data); console.log(event); },false); } } // document.onreadystatechange = function(e) { // if (document.readyState === \u0026#39;complete\u0026#39;) { // window.addEventListener(\u0026#39;message\u0026#39;, receiveMessage, false); // } // }; // function receiveMessage(event) { // if (event.origin !== \u0026#34;http://127.0.0.1:5500/indexopen.html\u0026#34;) { // return; // } // console.log(\u0026#39;message\u0026#39;, event.data); // console.log(\u0026#39;origin\u0026#39;, event.source); // targetPost = event; // // document.write(event.data); // // 假设你已经验证了所受到信息的origin (任何时候你都应该这样做), 一个很方便的方式就是把enent.source // // 作为回信的对象，并且把event.origin作为targetOrigin // // event.source.postMessage(\u0026#34;hi there yourself! the secret response \u0026#34; + \u0026#34;is: rheeeeet!\u0026#34;, event.origin); // } \u0026amp;lt;/script\u0026gt; \u0026amp;lt;/body\u0026gt; \u0026amp;lt;/html\u0026gt;` 使用iframe打开界面进行postmessage `\u0026amp;lt;!DOCTYPE html\u0026gt; \u0026amp;lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026amp;lt;head\u0026gt; \u0026amp;lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026gt; \u0026amp;lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34;\u0026gt; \u0026amp;lt;title\u0026gt;Document\u0026amp;lt;/title\u0026gt; \u0026amp;lt;/head\u0026gt; 我是监听界面 \u0026amp;lt;iframe src=\u0026#34;index.html\u0026#34;\u0026gt;\u0026amp;lt;/iframe\u0026gt; \u0026amp;lt;body\u0026gt; \u0026amp;lt;script\u0026gt; window.onload = function(){ console.log(\u0026#34;onload finish\u0026#34;); if(window.addEventListener){ console.log(\u0026#34;onload addEventListener\u0026#34;); window.addEventListener(\u0026#39;message\u0026#39;, function (e) { console.log(\u0026#34;addEventListener我监听到了\u0026#34;); // if (e.data.act == \u0026#39;response\u0026#39;) { // alert(e.data.msg.answer); // } else { // alert(\u0026#39;未定义的消息: \u0026#39; + e.data.act); // } console.log(e.data); }); }else{ window.attachEvent(\u0026#39;onmessage\u0026#39;, function (e) { console.log(\u0026#34;attachEvent我监听到了\u0026#34;); // if (e.data.act == \u0026#39;response\u0026#39;) { // alert(e.data.msg.answer); // } else { // alert(\u0026#39;未定义的消息: \u0026#39; + e.data.act); // } console.log(e.data); }); } } \u0026amp;lt;/script\u0026gt; \u0026amp;lt;/body\u0026gt; \u0026amp;lt;/html\u0026gt;` `\u0026amp;lt;!DOCTYPE html\u0026gt; \u0026amp;lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026amp;lt;head\u0026gt; \u0026amp;lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026gt; \u0026amp;lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34;\u0026gt; \u0026amp;lt;title\u0026gt;Document\u0026amp;lt;/title\u0026gt; \u0026amp;lt;/head\u0026gt; \u0026amp;lt;body\u0026gt; 我是发送界面 \u0026amp;lt;button id=\u0026#34;sendmsg\u0026#34; onclick=\u0026#34;sendMsg()\u0026#34;\u0026gt;发送监听\u0026amp;lt;/button\u0026gt; \u0026amp;lt;script\u0026gt; function sendMsg(){ console.log(\u0026#34;我来发送\u0026#34;); window.parent.postMessage({ act: \u0026#39;myresponse\u0026#39;, msg:{ name:\u0026#39;zhang\u0026#39; } },\u0026#34;*\u0026#34;); window.parent.postMessage({ act: \u0026#39;response\u0026#39;, msg: { type:\u0026#39;EOPEN_NOMAL_AGREE_2.0_PC\u0026#39;, answer: \u0026#39;成功\u0026#39; } }, \u0026#39;*\u0026#39;); } \u0026amp;lt;/script\u0026gt; \u0026amp;lt;/body\u0026gt; \u0026amp;lt;/html\u0026gt;` ","permalink":"https://blog.zdltech.com/posts/window-postmessage%E4%BD%BF%E7%94%A8demo/","summary":"\u003ch2 class=\"wp-block-heading\" id=\"使用windowopen进行postmessage处理\"\u003e使用window.open进行postmessage处理\u003c/h2\u003e\n\u003cp\u003e打开新页面和监听界面的界面\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003eDOCTYPE html\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;html lang\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;en\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;head\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;meta charset\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;UTF-8\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;meta name\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;viewport\u0026#34;\u003c/span\u003e content\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;width=device-width, initial-scale=1.0\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;title\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eDocument\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003etitle\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ehead\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    我是监听界面\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;body\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;script\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        window\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonload \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e function(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;onload finish\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e(window\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddEventListener){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;onload addEventListener\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                window\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddEventListener(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;message\u0026#39;\u003c/span\u003e, function (e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;addEventListener我监听到了\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edata\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eact \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;response\u0026#39;\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e     alert(e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edata\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emsg\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eanswer);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e } \u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e     alert(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;未定义的消息: \u0026#39;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edata\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eact);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edata);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                });\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                window\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eattachEvent(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;onmessage\u0026#39;\u003c/span\u003e, function (e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;attachEvent我监听到了\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edata\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eact \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;response\u0026#39;\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e     alert(e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edata\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emsg\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eanswer);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e } \u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e     alert(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;未定义的消息: \u0026#39;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edata\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eact);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edata);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                });\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003evar\u003c/span\u003e popup \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e  window\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eopen(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;indexopen.html\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        popup\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonload \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e function(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e popup\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epostMessage(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hello there!\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;*\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;popup 设置监听\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            popup\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddEventListener(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;message\u0026#39;\u003c/span\u003e, function (e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;popup addEventListener我监听到了\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edata);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                },\u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            popup\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emydataFunction \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e function(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;自定义的函数！\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003escript\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ebody\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ehtml\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e子界面及发送postmessage界面\u003c/p\u003e","title":"window postMessage使用Demo"},{"content":"ELK 是Elasticsearch， Logstash，Kibana三个组件的首字母组合,这种方案最初的做法是：使用Logstash 去服务上采集日志文件, 然后做一些过滤处理后发送给 Elasticsearch, 在Elasticsearch中创建相应的索引，由Kibana提供统计分析的页面访问。但是Logstash 本身资源消耗较大,如果把它放到业务系统的服务器上会对系统造成不小的影响，一般的做法采用beats来替代(beats是一个更轻量级的收集器)，参考如下图-1,此外也会有在数据量比较大时引入消息队列来环节组件压力。\n详细的关于各组件的介绍建议参考Elastic 提供的官方文档\n（图-1）\n(图-2)\n本文将基于上图-2的架构来介绍ELK日志系统的搭建。由于环境限制，这里各组件均部署在同一服务器上。\n1）搭建elasticsearch\nelasticsearch的下载安装配置在所有组件中相对是最复杂的，但是它依然可以很简单的按照如下几个步骤顺利完成：\n① 官网下载地址 ：https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.1.1-linux-x86_64.tar.gz\n② 解压之后配置 elasticsearch-7.1.1/config/elasticsearch.yml 文件,如下\n[][1]\n# ---------------------------------- Cluster ----------------------------------- # 指定集群名 cluster.name: customer-service # ------------------------------------ Node ------------------------------------ # 在集群名为customer-service 的集群下的 node-1 节点 node.name: node-1 # ---------------------------------- Network ----------------------------------- # 开启本质之外的网络访问 network.host: 0.0.0.0 # --------------------------------- Discovery ---------------------------------- # 定义初始主机点 cluster.initial_master_nodes: [\u0026#34;node-1\u0026#34;] ```\u0026lt;figure class=\u0026#34;wp-block-image\u0026#34;\u0026gt; [![复制代码](https://common.cnblogs.com/images/copycode.gif)][1]\u0026lt;/figure\u0026gt; ③ 启动elasticsearch\u0026amp;nbsp; (处于安全考虑 elasticsearch 只能非root用户启动，需要将elasticsearch解压文件切换所属用户)\u0026amp;nbsp; 解压路径下 ./bin/elasticsearch\n④ 验证elasticsearch是否启动成功 curl http://localhost:9200\n如果看到如下结果,代表启动成功\u0026lt;figure class=\u0026#34;wp-block-image\u0026#34;\u0026gt; [![复制代码](https://common.cnblogs.com/images/copycode.gif)][1]\u0026lt;/figure\u0026gt; { \u0026ldquo;name\u0026rdquo; : \u0026ldquo;node-1\u0026rdquo;, \u0026ldquo;cluster_name\u0026rdquo; : \u0026ldquo;elasticsearch\u0026rdquo;, \u0026ldquo;cluster_uuid\u0026rdquo; : \u0026ldquo;tYgc-2l3ThqcEfFKfeWgBQ\u0026rdquo;, \u0026ldquo;version\u0026rdquo; : { \u0026ldquo;number\u0026rdquo; : \u0026ldquo;7.1.1\u0026rdquo;, \u0026ldquo;build_flavor\u0026rdquo; : \u0026ldquo;default\u0026rdquo;, \u0026ldquo;build_type\u0026rdquo; : \u0026ldquo;tar\u0026rdquo;, \u0026ldquo;build_hash\u0026rdquo; : \u0026ldquo;7a013de\u0026rdquo;, \u0026ldquo;build_date\u0026rdquo; : \u0026ldquo;2019-05-23T14:04:00.380842Z\u0026rdquo;, \u0026ldquo;build_snapshot\u0026rdquo; : false, \u0026ldquo;lucene_version\u0026rdquo; : \u0026ldquo;8.0.0\u0026rdquo;, \u0026ldquo;minimum_wire_compatibility_version\u0026rdquo; : \u0026ldquo;6.8.0\u0026rdquo;, \u0026ldquo;minimum_index_compatibility_version\u0026rdquo; : \u0026ldquo;6.0.0-beta1\u0026rdquo; }, \u0026ldquo;tagline\u0026rdquo; : \u0026ldquo;You Know, for Search\u0026rdquo; }\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)][1]\u0026lt;/figure\u0026gt; **2）Kibana的安装** ① 官网下载:https://artifacts.elastic.co/downloads/kibana/kibana-7.1.1-linux-x86_64.tar.gz ② 配置解压路径下的/kibana-7.1.1-linux-x86_64/config/kibana.yml文件: 将server.host 改为所有IP, 这样以便不同主机可以访问到kibana页面 server.host: 0.0.0.0\n③ 浏览器访问 http://ip:5601 （默认5601端口,可以在kibana.yml中配置) 得到如下页面表示启动成功\u0026lt;figure class=\u0026#34;wp-block-image\u0026#34;\u0026gt; ![](https://img2018.cnblogs.com/blog/941183/201906/941183-20190609165206863-306678276.png) \u0026lt;/figure\u0026gt; （图-3） 3**）Filebeat 的安装** ① 官方下载：https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.1.1-linux-x86_64.tar.gz ② 配置解压路径下的配置文件 filebeat.yml 如下:\u0026lt;figure class=\u0026#34;wp-block-image\u0026#34;\u0026gt; [![复制代码](https://common.cnblogs.com/images/copycode.gif)][1]\u0026lt;/figure\u0026gt; #=========================== Filebeat inputs ============================= filebeat.inputs:\nEach - is an input. Most options can be set at the input level, so you can use different inputs for various configurations. Below are the input specific configurations. type: log\nChange to true to enable this input configuration. enabled: true\n需要被采集的日志文件的路径 paths:\n/app/applogs/provider/info/dubbo-info.log #\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026ndash; Logstash output \u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026ndash; output.logstash:\n指定logstash的地址和端口 hosts: [\u0026ldquo;127.0.0.1:5044\u0026rdquo;]\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)][1]\u0026lt;/figure\u0026gt; ③ 启动 filebeat 注意使用root用户登录, 准确的说是注意用户对文件所拥有的权限 -e 让日志打印到控制台, -c 重新指定启动的配置文件, -d 指定调试选择者器 ./filebeat -e -c filebeat.yml -d \u0026ldquo;publish\u0026rdquo;\n4**）Logstash 的安装** ① 官网下载：https://artifacts.elastic.co/downloads/logstash/logstash-7.1.1.tar.gz ② 配置logstash，增加customer-service-logstash.yml 的配置文件，文件配置内容如下:\u0026lt;figure class=\u0026#34;wp-block-image\u0026#34;\u0026gt; [![复制代码](https://common.cnblogs.com/images/copycode.gif)][1]\u0026lt;/figure\u0026gt; logstash 输入配置，这里我们采用beat采集日志 input { beats { port =\u0026gt; \u0026ldquo;5044\u0026rdquo; } }\nThe filter part of this file is commented out to indicate that it is optional. filter { grok { match =\u0026gt; { \u0026ldquo;message\u0026rdquo; =\u0026gt; \u0026ldquo;%{COMBINEDAPACHELOG}\u0026rdquo;} } # 此外还可以添加其他过滤器插件 }\noutput { # 输出到控制台打印 stdout { codec =\u0026gt; rubydebug }\n# 输出到elasticsearch ，并指定索引名称 elasticsearch { hosts =\u0026gt; [ \u0026ldquo;127.0.0.1:9200\u0026rdquo; ] index =\u0026gt; \u0026ldquo;logstash-customer-service-log\u0026rdquo; }\n}\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)][1]\u0026lt;/figure\u0026gt; ③ 启动logstash -f 从指定路径获取logstash启动的yml配置文件 \u0026ndash;config.reload.automatic 监听配置文件 如果有改动自动加载 bin/logstash -f first-pipeline.conf \u0026ndash;config.reload.automatic\n\u0026amp;nbsp;所有上述组件配置启动成功后，我们可以到kibana界面, 在侧边栏 management 下按下图-4方式创建 索引模式后，然后在图-5中可以获取到实时的日志记录。\u0026lt;figure class=\u0026#34;wp-block-image\u0026#34;\u0026gt; ![](https://img2018.cnblogs.com/blog/941183/201906/941183-20190609173429130-966131108.png) \u0026lt;/figure\u0026gt; （图-4）\u0026lt;figure class=\u0026#34;wp-block-image\u0026#34;\u0026gt; ![](https://img2018.cnblogs.com/blog/941183/201906/941183-20190609173943878-2033422780.png) \u0026lt;/figure\u0026gt; （图-5） 我们在logstash中增加对error级别日志的过滤处理，将这些日志统一放到 logstash-customer-service-error 索引中,然后在 kibana 中创建该索引同名的pattern, 这样在discover页签下可以直观的通过 时间段的筛选来定位error日志，并在下面的 expanded document 下查看日志的具体内容，这样一来就不需要挨个连接到服务器去手动查看日志了。 [1]: javascript:void(0); ","permalink":"https://blog.zdltech.com/posts/elk%E6%97%A5%E5%BF%97%E5%88%86%E6%9E%90%E7%B3%BB%E7%BB%9F%E6%90%AD%E5%BB%BA/","summary":"\u003cp\u003eELK 是Elasticsearch， Logstash，Kibana三个组件的首字母组合,这种方案最初的做法是：使用Logstash 去服务上采集日志文件, 然后做一些过滤处理后发送给 Elasticsearch, 在Elasticsearch中创建相应的索引，由Kibana提供统计分析的页面访问。但是Logstash 本身资源消耗较大,如果把它放到业务系统的服务器上会对系统造成不小的影响，一般的做法采用beats来替代(beats是一个更轻量级的收集器)，参考如下图-1,此外也会有在数据量比较大时引入消息队列来环节组件压力。\u003c/p\u003e\n\u003cp\u003e　　详细的关于各组件的介绍建议参考Elastic 提供的\u003ca href=\"https://www.elastic.co/guide/index.html\"\u003e官方文档\u003c/a\u003e\u003cfigure class=\"wp-block-image\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img2018.cnblogs.com/blog/941183/201906/941183-20190609155227891-806799646.png\"\u003e \u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e　　　　　　　　　　　　　　　　              （图-1）\u003cfigure class=\"wp-block-image\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img2018.cnblogs.com/blog/941183/201906/941183-20190609161936586-753210046.png\"\u003e \u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e　　　　　　　　　　　　　　　　　　　　　　(图-2)\u003c/p\u003e\n\u003cp\u003e　　本文将基于上图-2的架构来介绍ELK日志系统的搭建。由于环境限制，这里各组件均部署在同一服务器上。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1）搭建elasticsearch\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e elasticsearch的下载安装配置在所有组件中相对是最复杂的，但是它依然可以很简单的按照如下几个步骤顺利完成：\u003c/p\u003e\n\u003cp\u003e① 官网下载地址 ：https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.1.1-linux-x86_64.tar.gz\u003c/p\u003e\n\u003cp\u003e② 解压之后配置 elasticsearch-7.1.1/config/elasticsearch.yml 文件,如下\u003cfigure class=\"wp-block-image\"\u003e\u003c/p\u003e\n\u003cp\u003e[\u003cimg alt=\"复制代码\" loading=\"lazy\" src=\"https://common.cnblogs.com/images/copycode.gif\"\u003e][1]\u003c/figure\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# ---------------------------------- Cluster -----------------------------------\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# 指定集群名\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecluster.name: customer-service\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# ------------------------------------ Node ------------------------------------\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# 在集群名为customer-service 的集群下的 node-1 节点\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enode.name: node-1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# ---------------------------------- Network -----------------------------------\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# 开启本质之外的网络访问\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enetwork.host: 0.0.0.0\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# --------------------------------- Discovery ----------------------------------\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# 定义初始主机点\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecluster.initial_master_nodes: [\u0026#34;node-1\u0026#34;]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e```\u0026lt;figure class=\u0026#34;wp-block-image\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[![复制代码](https://common.cnblogs.com/images/copycode.gif)][1]\u0026lt;/figure\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e③ 启动elasticsearch\u0026amp;nbsp; (处于安全考虑 elasticsearch 只能非root用户启动，需要将elasticsearch解压文件切换所属用户)\u0026amp;nbsp;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch1 id=\"解压路径下\"\u003e解压路径下\u003c/h1\u003e\n\u003cp\u003e./bin/elasticsearch\u003c/p\u003e","title":"ELK日志分析系统搭建"},{"content":"`package com.zdltech.test.pdf; import com.lowagie.text.pdf.BaseFont; import org.xhtmlrenderer.pdf.ITextFontResolver; import org.xhtmlrenderer.pdf.ITextRenderer; import java.io.*; public class PDFUtils6 { /** * 获取对应pageName的html内容（生产环境java -jar直接run） */ private static String getHtmlByPageName2(String filePath) throws IOException { // /BOOT-INF/classes/templates/dashboard.html // 返回读取指定资源的输入流 InputStream is = new FileInputStream(new File(filePath)); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String s = \u0026#34;\u0026#34;; StringBuffer sb = new StringBuffer(); while ((s = br.readLine()) != null) { sb.append(s).append(\u0026#34;\\n\u0026#34;); } return sb.toString(); } /** * 将HTML转成PD格式的文件。html文件的格式比较严格 * @param htmlFile * @param pdfFile * @throws Exception */ // \u0026amp;lt;!DOCTYPE html PUBLIC \u0026#34;-//W3C//DTD XHTML 1.0 Transitional//EN\u0026#34; \u0026#34;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd \u0026#34;\u0026gt; public static void html2pdf(String htmlFile, String pdfFile) throws Exception { // step 1 String url = new File(htmlFile).toURI().toURL().getPath(); System.out.println(url); // step 2 OutputStream os = new FileOutputStream(pdfFile); ITextRenderer renderer = new ITextRenderer(); String result = getHtmlByPageName2(url); // System.out.println(result.substring(1)); System.out.println(result); renderer.setDocumentFromString(result); // renderer.setDocumentFromString(result.substring(1)); // renderer.setDocumentFromString(getXmlString()); // renderer.setDocument(url); // step 3 解决中文支持 ITextFontResolver fontResolver = renderer.getFontResolver(); if(\u0026#34;linux\u0026#34;.equals(getCurrentOperatingSystem())){ fontResolver.addFont(\u0026#34;/Users/jason/Desktop/test/simsun.ttc\u0026#34;, BaseFont.IDENTITY_H, BaseFont.EMBEDDED); }else{ fontResolver.addFont(\u0026#34;/Users/jason/Desktop/test/simsun.ttc\u0026#34;, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); fontResolver.addFont(\u0026#34;/Users/jason/Desktop/test/simkai.ttf\u0026#34;, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); } renderer.layout(); renderer.createPDF(os); os.close(); System.out.println(\u0026#34;create pdf done!!\u0026#34;); } public static String getCurrentOperatingSystem(){ String os = System.getProperty(\u0026#34;os.name\u0026#34;).toLowerCase(); System.out.println(\u0026#34;---------当前操作系统是-----------\u0026#34; + os); return os; } public static String getXmlString() { String xmlString=\u0026#34;\u0026amp;lt;!DOCTYPE html PUBLIC \\\u0026#34;-//W3C//DTD XHTML 1.0 Transitional//EN\\\u0026#34; \\\u0026#34;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34;\u0026amp;lt;html lang=\\\u0026#34;en\\\u0026#34; xmlns=\\\u0026#34;http://www.w3.org/1999/xhtml\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34;\u0026amp;lt;head\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;meta charset=\\\u0026#34;UTF-8\\\u0026#34;/\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;title\u0026gt;Hello World\u0026amp;lt;/title\u0026gt;\\n\u0026#34; + \u0026#34;\\t\u0026amp;lt;style\u0026gt;\\n\u0026#34; + \u0026#34;\\t table.table-separate th{\\n\u0026#34; + \u0026#34; font-weight:bold;\\n\u0026#34; + \u0026#34; font-size:14px;\\n\u0026#34; + \u0026#34; border-top:1px solid #F3EDE9 !important;\\n\u0026#34; + \u0026#34; }\\n\u0026#34; + \u0026#34; table.table-separate td{\\n\u0026#34; + \u0026#34; padding: 13px 0;\\n\u0026#34; + \u0026#34; font-weight:100;\\n\u0026#34; + \u0026#34; }\\n\u0026#34; + \u0026#34; .table-separate td.tit{\\n\u0026#34; + \u0026#34; background-color: #f4f9fe;\\n\u0026#34; + \u0026#34; font-weight:normal;\\n\u0026#34; + \u0026#34; padding:22px 0;\\n\u0026#34; + \u0026#34; width:15%;\\n\u0026#34; + \u0026#34; }\\n\u0026#34; + \u0026#34; .table-separate td.cont{\\n\u0026#34; + \u0026#34; text-align: left;\\n\u0026#34; + \u0026#34; padding:16px 22px;\\n\u0026#34; + \u0026#34; width:85%;\\n\u0026#34; + \u0026#34; line-height:175%;\\n\u0026#34; + \u0026#34; }\\n\u0026#34; + \u0026#34; .table-separate.no-border th{\\n\u0026#34; + \u0026#34; border:none;\\n\u0026#34; + \u0026#34; text-align: left;\\n\u0026#34; + \u0026#34; }\\n\u0026#34; + \u0026#34; .table-separate.no-border td{\\n\u0026#34; + \u0026#34; text-align: left;\\n\u0026#34; + \u0026#34; border:none;\\n\u0026#34; + \u0026#34; }\\n\u0026#34; + \u0026#34;\\t@page {\\n\u0026#34; + \u0026#34;\\tsize:210mm 297mm;//纸张大小A4\\n\u0026#34; + \u0026#34;\\tmargin: 0.25in;\\n\u0026#34; + \u0026#34;\\t-fs-flow-bottom: \\\u0026#34;footer\\\u0026#34;;\\n\u0026#34; + \u0026#34;\\t-fs-flow-left: \\\u0026#34;left\\\u0026#34;;\\n\u0026#34; + \u0026#34;\\t-fs-flow-right: \\\u0026#34;right\\\u0026#34;;\\n\u0026#34; + \u0026#34;\\tborder: thin solid black;\\n\u0026#34; + \u0026#34;\\tpadding: 1em;\\n\u0026#34; + \u0026#34;\\t}\\n\u0026#34; + \u0026#34;\\t#footer {\\n\u0026#34; + \u0026#34;\\tfont-size: 90%; font-style: italic;\\n\u0026#34; + \u0026#34;\\tposition: absolute; top: 0; left: 0;\\n\u0026#34; + \u0026#34;\\t-fs-move-to-flow: \\\u0026#34;footer\\\u0026#34;;\\n\u0026#34; + \u0026#34;\\t}\\n\u0026#34; + \u0026#34;\\t#pagenumber:before {\\n\u0026#34; + \u0026#34;\\tcontent: counter(page);\\n\u0026#34; + \u0026#34;\\t}\\n\u0026#34; + \u0026#34;\\t#pagecount:before {content: counter(pages);\\n\u0026#34; + \u0026#34;\\t}\\n\u0026#34; + \u0026#34;\\ttable {\\n\u0026#34; + \u0026#34;\\t\\t\\tborder-collapse: collapse;\\n\u0026#34; + \u0026#34;\\t\\t\\ttable-layout: fixed;\\n\u0026#34; + \u0026#34;\\t\\t\\tword-break:break-all;\\n\u0026#34; + \u0026#34;\\t\\t\\tfont-size: 10px;\\n\u0026#34; + \u0026#34;\\t\\t\\twidth: 100%;\\n\u0026#34; + \u0026#34;\\t\\t\\ttext-align: center;\\n\u0026#34; + \u0026#34;\\t}\\n\u0026#34; + \u0026#34;\\ttd {\\n\u0026#34; + \u0026#34;\\t\\tword-break:break-all;\\n\u0026#34; + \u0026#34;\\t\\tword-wrap : break-word;\\n\u0026#34; + \u0026#34;\\t}\\n\u0026#34; + \u0026#34;\\t\u0026amp;lt;/style\u0026gt;\\n\u0026#34; + \u0026#34;\\t\u0026amp;lt;/head\u0026gt;\\n\u0026#34; + \u0026#34;\u0026amp;lt;body style = \\\u0026#34;font-family: SimSun;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34;\u0026amp;lt;div id=\\\u0026#34;footer\\\u0026#34; style=\\\u0026#34;\\\u0026#34;\u0026gt; Page \u0026amp;lt;span id=\\\u0026#34;pagenumber\\\u0026#34;/\u0026gt; of \u0026amp;lt;span id=\\\u0026#34;pagecount\\\u0026#34;/\u0026gt; \u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34;\u0026amp;lt;div id=\\\u0026#34;main\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div style=\\\u0026#34;max-width:600px;margin:0 auto;padding:10px;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div style=\\\u0026#34;text-align: center; padding: 5mm 0;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div style=\\\u0026#34;font-weight: bold; font-size: 30px;\\\u0026#34;\u0026gt; HI Fudi\u0026amp;amp;More\u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div\u0026gt; THANK YOU FOR SHOPPING WITH Fudi\u0026amp;amp;More!\u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div style=\\\u0026#34;border: 1px solid black; background-color: #f8f8f8; padding: 4mm;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div style=\\\u0026#34;font-size: 17px; font-weight: bold; border-bottom: 1px solid black; padding-bottom: 5mm;\\\u0026#34;\u0026gt; ORDER DETAILS\u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div style=\\\u0026#34;padding-top: 10px;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div\u0026gt;\u0026amp;lt;strong\u0026gt;Order:\u0026amp;nbsp;\u0026amp;lt;/strong\u0026gt;D-8C2Y Placed on 29/09/2019 10:04\u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div\u0026gt;\u0026amp;lt;strong\u0026gt;Carrier:\u0026amp;nbsp;\u0026amp;lt;/strong\u0026gt;Delivery\u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div\u0026gt;\u0026amp;lt;strong\u0026gt;Payment:\u0026amp;nbsp;\u0026amp;lt;/strong\u0026gt;Cash Payment\u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div style=\\\u0026#34;margin-top: 4mm;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;table class=\\\u0026#34;table-separate\\\u0026#34; cellpadding=\\\u0026#34;0\\\u0026#34; cellspacing=\\\u0026#34;0\\\u0026#34; style=\\\u0026#34;max-width:600px;margin:0 auto;padding:10px;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;thead\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;tr style=\\\u0026#34;text-align: center; height: 40px;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;th style=\\\u0026#34;width: 90px; background-color: #f8f8f8; border-top: 1px solid black; border-left: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; Reference\\n\u0026#34; + \u0026#34; \u0026amp;lt;/th\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;th colspan=\\\u0026#34;2\\\u0026#34; style=\\\u0026#34;background-color: #f8f8f8; border-top: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;Product\u0026amp;lt;/th\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;th style=\\\u0026#34;width: 110px; background-color: #f8f8f8; border-top: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;Unit price\u0026amp;lt;/th\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;th style=\\\u0026#34;width: 80px; background-color: #f8f8f8; border-top: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;Quantity\u0026amp;lt;/th\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;th style=\\\u0026#34;width: 90px; background-color: #f8f8f8; border-top: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;Total price\u0026amp;lt;/th\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/tr\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/thead\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;tbody\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;tr style=\\\u0026#34;text-align: center; \\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;border-top: 1px solid black; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; Main\\n\u0026#34; + \u0026#34; \u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td colspan=\\\u0026#34;2\\\u0026#34;\\n\u0026#34; + \u0026#34; style=\\\u0026#34;border-top: 1px solid black; border-bottom:1px solid black; border-right: 1px solid black; text-align: left; padding: 010px;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; SweetSour Chicken\\n\u0026#34; + \u0026#34; \u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;border-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;\u0026amp;euro; 7.00\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;border-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;1\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;border-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;\u0026amp;euro; 7.00\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/tr\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;tr style=\\\u0026#34;text-align: center; \\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;border-top: 1px solid black; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; Main\\n\u0026#34; + \u0026#34; \u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td colspan=\\\u0026#34;2\\\u0026#34;\\n\u0026#34; + \u0026#34; style=\\\u0026#34;border-top: 1px solid black; border-bottom:1px solid black; border-right: 1px solid black; text-align: left; padding: 010px;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; Black Bean Stir Fry\\n\u0026#34; + \u0026#34; \u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;border-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;\u0026amp;euro; 9.00\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;border-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;1\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;border-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;\u0026amp;euro; 9.00\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/tr\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;tr style=\\\u0026#34;text-align: center; \\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;border-top: 1px solid black; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; Pizzas\\n\u0026#34; + \u0026#34; \u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td colspan=\\\u0026#34;2\\\u0026#34;\\n\u0026#34; + \u0026#34; style=\\\u0026#34;border-top: 1px solid black; border-bottom:1px solid black; border-right: 1px solid black; text-align: left; padding: 010px;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; Test Design Your Own 8\\\u0026#34; Pizza\\n\u0026#34; + \u0026#34; \u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;border-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;\u0026amp;euro; 6.00\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;border-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;1\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;border-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;\u0026amp;euro; 6.00\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/tr\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/tbody\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;tfoot\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;tr style=\\\u0026#34;text-align: center; height: 8mm;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td colspan=\\\u0026#34;5\\\u0026#34;\\n\u0026#34; + \u0026#34; style=\\\u0026#34;text-align: right; width: 90px; background-color: #f8f8f8; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; padding: 0 10px;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; Item:\\n\u0026#34; + \u0026#34; \u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;background-color: #f8f8f8; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;3\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/tr\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;tr style=\\\u0026#34;text-align: center; height: 8mm;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td colspan=\\\u0026#34;5\\\u0026#34;\\n\u0026#34; + \u0026#34; style=\\\u0026#34;text-align: right; width: 90px; background-color: #f8f8f8; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; padding: 0 10px;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; Subtotal:\\n\u0026#34; + \u0026#34; \u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;background-color: #f8f8f8; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;\u0026amp;euro;24.00\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/tr\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;tr style=\\\u0026#34;text-align: center; height: 8mm;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td colspan=\\\u0026#34;5\\\u0026#34;\\n\u0026#34; + \u0026#34; style=\\\u0026#34;text-align: right; width: 90px; background-color: #f8f8f8; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; padding: 0 10px;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; Deliver Fee:\\n\u0026#34; + \u0026#34; \u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;background-color: #f8f8f8; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;+\u0026amp;euro;2.00\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/tr\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;tr style=\\\u0026#34;text-align: center; height: 8mm;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td colspan=\\\u0026#34;5\\\u0026#34;\\n\u0026#34; + \u0026#34; style=\\\u0026#34;text-align: right; width: 90px; background-color: #f8f8f8; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; padding: 0 10px;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; Discount:\\n\u0026#34; + \u0026#34; \u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;background-color: #f8f8f8; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;-\u0026amp;euro;0.00\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/tr\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;tr style=\\\u0026#34;text-align: center; height: 8mm;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td colspan=\\\u0026#34;5\\\u0026#34;\\n\u0026#34; + \u0026#34; style=\\\u0026#34;text-align: right; width: 90px; background-color: #f8f8f8; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; padding: 0 10px;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; Total:\\n\u0026#34; + \u0026#34; \u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;td style=\\\u0026#34;background-color: #f8f8f8; border-bottom: 1px solid black; border-right: 1px solid black;\\\u0026#34;\u0026gt;\u0026amp;euro;24.00\u0026amp;lt;/td\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/tr\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/tfoot\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/table\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div style=\\\u0026#34;border: 1px solid black; background-color: #f8f8f8; padding:5mm; margin-top: 5mm;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div style=\\\u0026#34;font-size: 17px; font-weight: bold; border-bottom: 1px solid black; padding-bottom: 15px;\\\u0026#34;\u0026gt; DELIVERY ADDRESS\u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div style=\\\u0026#34;padding-top: 10px;\\\u0026#34;\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div\u0026gt;\u0026amp;lt;strong\u0026gt;guan\u0026amp;lt;/strong\u0026gt; \u0026amp;#9742; \u0026amp;lt;strong\u0026gt;13656690321\u0026amp;lt;/strong\u0026gt;\u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div\u0026gt; 1024/ Edenhall,ModelFarmRd,Cork,爱尔兰,A 2048\u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div style=\\\u0026#34;font-size: 13px;\\\u0026#34;\u0026gt;\u0026amp;lt;p\u0026gt;You can review your order and download your invoice from the \\\u0026#34;\u0026amp;lt;a target=\\\u0026#34;_blank\\\u0026#34;\\n\u0026#34; + \u0026#34; href=\\\u0026#34;http://www.fudiandmore.ie/#/FudiIndex/Order1\\\u0026#34;\u0026gt;Order\\n\u0026#34; + \u0026#34; history\u0026amp;lt;/a\u0026gt;\\\u0026#34;section of your customer account by clicking \\\u0026#34;\u0026amp;lt;a target=\\\u0026#34;_blank\\\u0026#34; href=\\\u0026#34;http://www.fudiandmore.ie/#/FudiIndex/Personalcenter1\\\u0026#34;\u0026gt;My\\n\u0026#34; + \u0026#34; account\u0026amp;lt;/a\u0026gt;\\\u0026#34; on ourshop.\u0026amp;lt;/p\u0026gt;\u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;hr style=\\\u0026#34;border-width: 5px;\\\u0026#34;/\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;div\u0026gt; Fudi,More powered by \u0026amp;lt;a target=\\\u0026#34;_blank\\\u0026#34; href=\\\u0026#34;http://www.fudiandmore.ie\\\u0026#34;\u0026gt;A2BLiving\u0026amp;lt;/a\u0026gt;\u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34; \u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34;\u0026amp;lt;/div\u0026gt;\\n\u0026#34; + \u0026#34;\u0026amp;lt;/body\u0026gt;\\n\u0026#34; + \u0026#34;\u0026amp;lt;/html\u0026gt;\u0026#34;; StringBuffer stringBuffer=new StringBuffer(); return xmlString; } public static void main(String\u0026amp;#91;] args) { // String htmlFile = \u0026#34;/home/lbj/sign.jsp\u0026#34;; // String pdfFile = \u0026#34;/home/lbj/sign.pdf\u0026#34;; String htmlFile = \u0026#34;/Users/jason/Desktop/test/aaa/aaa.html\u0026#34;; // String htmlFile = \u0026#34;/Users/jason/Desktop/test/pdftest.html\u0026#34;; String pdfFile = \u0026#34;/Users/jason/Desktop/test/pdftest30.pdf\u0026#34;; try { PDFUtils6.html2pdf(htmlFile, pdfFile); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } } ` `\u0026amp;lt;dependency\u0026gt; \u0026amp;lt;groupId\u0026gt;com.itextpdf\u0026amp;lt;/groupId\u0026gt; \u0026amp;lt;artifactId\u0026gt;itextpdf\u0026amp;lt;/artifactId\u0026gt; \u0026amp;lt;version\u0026gt;5.5.9\u0026amp;lt;/version\u0026gt; \u0026amp;lt;/dependency\u0026gt; \u0026amp;lt;dependency\u0026gt; \u0026amp;lt;groupId\u0026gt;com.itextpdf.tool\u0026amp;lt;/groupId\u0026gt; \u0026amp;lt;artifactId\u0026gt;xmlworker\u0026amp;lt;/artifactId\u0026gt; \u0026amp;lt;version\u0026gt;5.5.9\u0026amp;lt;/version\u0026gt; \u0026amp;lt;/dependency\u0026gt; \u0026amp;lt;dependency\u0026gt; \u0026amp;lt;groupId\u0026gt;com.itextpdf\u0026amp;lt;/groupId\u0026gt; \u0026amp;lt;artifactId\u0026gt;itext-asian\u0026amp;lt;/artifactId\u0026gt; \u0026amp;lt;version\u0026gt;5.2.0\u0026amp;lt;/version\u0026gt; \u0026amp;lt;/dependency\u0026gt; \u0026amp;lt;dependency\u0026gt; \u0026amp;lt;groupId\u0026gt;org.xhtmlrenderer\u0026amp;lt;/groupId\u0026gt; \u0026amp;lt;artifactId\u0026gt;flying-saucer-pdf-itext5\u0026amp;lt;/artifactId\u0026gt; \u0026amp;lt;version\u0026gt;9.0.3\u0026amp;lt;/version\u0026gt; \u0026amp;lt;/dependency\u0026gt;` `\u0026amp;lt;!DOCTYPE html PUBLIC \u0026#34;-//W3C//DTD XHTML 1.0 Transitional//EN\u0026#34; \u0026#34;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\u0026#34;\u0026gt; \u0026amp;lt;html lang=\u0026#34;en\u0026#34; xmlns=\u0026#34;http://www.w3.org/1999/xhtml\u0026#34;\u0026gt; \u0026amp;lt;head\u0026gt; \u0026amp;lt;meta charset=\u0026#34;UTF-8\u0026#34; /\u0026gt; \u0026amp;lt;meta http-equiv=\u0026#34;Content-Type\u0026#34; content=\u0026#34;text/html; charset=utf-8\u0026#34; /\u0026gt; \u0026amp;lt;meta http-equiv=\u0026#34;X-UA-Compatible\u0026#34; content=\u0026#34;IE=edge,chrome=1\u0026#34; /\u0026gt; \u0026amp;lt;meta http-equiv=\u0026#34;X-UA-Compatible\u0026#34; content=\u0026#34;IE=9\u0026#34; /\u0026gt; \u0026amp;lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0, maximum-scale=1.0\u0026#34; /\u0026gt; \u0026amp;lt;style\u0026gt; @page { size: A4; margin: 0; } body{ zoom:0.8; transform: scale(0.8); } .fontSize16 { font-size: 16px !important; } .cllor3B7 { color: #3B76B5 !important; } .posAbsolute { position: absolute !important; } .posRelative { position: relative !important; } .textAlignLeft { text-align: left } .textAlignRight { text-align: right } .voucher_body { /* position: relative;width: 954px;height: 424px;margin-left: -477px;margin-top: -212px;top: 50%;left: 50%; */ position: relative; } .voucher { position: relative; width: 954px; height: 424px; background-size: 82% 82% !important; z-index: 999; } .printBtn { position: absolute; left: 50%; margin-left: -100px !important; } .voucherPrint { position: fixed; width: 954px; height: 424px; top: 50%; left: 50%; transform: translate(-50%, -50%); background: initial !important; z-index: 99999; display: none; } .voucherPDF { position: fixed; width: 954px; height: 424px; top: 50%; left: 50%; transform: translate(-50%, -50%); background: initial !important; z-index: 999999; display: none; } .openBg { background: url(\u0026#39;https://www.zchfax.com/data/temp/0_15723304043.jpg\u0026#39;) no-repeat !important; } .openBg2 { background: url(\u0026#39;/Users/jason/Desktop/test/aaa/open@2x.png\u0026#39;) no-repeat !important; } .financingBg { background: url(\u0026#39;financing@2x.png\u0026#39;) no-repeat !important; } .trasterBg { background: url(\u0026#39;transter@2x.png\u0026#39;) no-repeat !important; } .vouStatus { left: 124px; top: 65px; } .vouStatus\u0026gt;span { color: #EA2A41 !important; } .voucher .voNumber { right: 25%; top: 50px; color: #EA2A41 !important; } .voucher .voNumber2 { left: 120px; bottom: 16px; color: #EA2A41 !important; } .voucherContent .gsName { top: 98px; } .voucherContent .skName { top: 98px; } .voucherDer { width: 296px; } .voucherContent .openDer { width: 288px; } .voucherContent .shNumber { top: 129px; } .voucherContent .shNumber2 { top: 129px; } .voucherContent .moneyNumber { top: 169px; } .moneyALL { right: 23.5%; top: 184px; height: 30px; width: 296px; } /* width: 100%; height: 100%; */ .monyList { width: 100%; height: 100%; align-items: center; } .monyList\u0026gt;div { float: left; width: 8.33%; height: 30px; padding: 5px 0; text-align: center; color: #3B76B5 !important; } .voucherContent .openDate { top: 209px; } .voucherContent .openEleName { top: 241px; } .voucherContent .payDate { top: 209px; } .voucherContent .voucherLeft { left: 124px; } .voucherContent .voucherRight { right: 121px; } \u0026amp;lt;/style\u0026gt; \u0026amp;lt;/head\u0026gt; \u0026amp;lt;body style=\u0026#34;font-family: SimSun;line-height:1;font-size:10.0pt;\u0026#34;\u0026gt; \u0026amp;lt;div class=\u0026#34;textAlignCenter masking_alt\u0026#34; id=\u0026#34;forPrint\u0026#34;\u0026gt; \u0026amp;lt;div class=\u0026#34;voucher openBg office\u0026#34;\u0026gt; \u0026amp;lt;div class=\u0026#34;voucherDer vouStatus textAlignLeft voucherLeft fontSize16 posAbsolute\u0026#34;\u0026gt;\u0026amp;lt;span\u0026gt;已签收\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;p class=\u0026#34;voNumber fontSize16 posAbsolute\u0026#34;\u0026gt;BL20200615101522932\u0026amp;lt;/p\u0026gt; \u0026amp;lt;div class=\u0026#34;voucherContent\u0026#34;\u0026gt; \u0026amp;lt;div class=\u0026#34;gsName voucherDer posAbsolute textAlignLeft voucherLeft\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;fontSize16 cllor3B7\u0026#34;\u0026gt;泽诚控股有限公司\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;skName posAbsolute textAlignLeft voucherDer voucherRight\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;fontSize16 cllor3B7\u0026#34;\u0026gt;陕西泽诚置业有限公司\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;shNumber posAbsolute textAlignLeft voucherDer voucherLeft\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;fontSize16 color2B2\u0026#34;\u0026gt;91610132MA6X53QN7L\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;shNumber2 posAbsolute textAlignLeft voucherDer voucherRight\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;fontSize16 color2B2\u0026#34;\u0026gt;8351515313513852\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyNumber posAbsolute textAlignLeft openDer voucherLeft\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;fontSize16 cllor3B7\u0026#34;\u0026gt;（大写）伍拾万元\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyALL posAbsolute textAlignLeft\u0026#34;\u0026gt; \u0026amp;lt;div class=\u0026#34;monyList\u0026#34;\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;$\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;6\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;0\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;5\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;0\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;0\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;0\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;0\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;0\u0026amp;lt;/div\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;openDate posAbsolute textAlignLeft voucherDer voucherLeft\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;fontSize16 cllor3B7\u0026#34;\u0026gt;2020-06-15\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;openEleName posAbsolute textAlignLeft voucherDer voucherLeft\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;fontSize16 cllor3B7\u0026#34;\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;payDate posAbsolute textAlignLeft voucherDer voucherRight\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;fontSize16 cllor3B7\u0026#34;\u0026gt;2025-06-30\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;fontSize16 posAbsolute voNumber2 textAlignLeft voucherDer\u0026#34;\u0026gt;\u0026amp;lt;span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;/body\u0026gt; \u0026amp;lt;/html\u0026gt;` 这就完了.直接运行没问题。还有比如 \u0026amp; 在正文中的要转义 \u0026amp; 要不然报错，格式一定要正确，\u0026lt;/\u0026gt;结束符一定要有，标准也要有\n\u0026amp;lt;!DOCTYPE html PUBLIC \\\u0026#34;-//W3C//DTD XHTML 1.0 Transitional//EN\\\u0026#34; \\\u0026#34;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\\\u0026#34;\u0026amp;gt; \u0026amp;lt;html lang=\\\u0026#34;en\\\u0026#34; xmlns=\\\u0026#34;http://www.w3.org/1999/xhtml\\\u0026#34;\u0026amp;gt; 这个缺了你可以试试，出了问题你自己该，还有一点很重要，body 中指定字体，不指定的，中文你就不要想它出现了。还有一些 分页啥的，样式里写好就行，要是超宽了，那就自己看着实例的样式改改，大概就好了。 如果HTML中有图片，注意使用 网络图片（http://xxxxxx.png等），Mac下面图片可以使用绝对路径，Win上面不行，故推荐大家使用网络地址图片\nHTML中注意：开始要设置，并且一定要设置字体\n","permalink":"https://blog.zdltech.com/posts/itext-html%E8%BD%ACpdf%E8%A7%A3%E5%86%B3%E4%B8%AD%E6%96%87%E4%B8%8D%E6%98%BE%E7%A4%BA%E4%B8%8E%E6%A0%B7%E5%BC%8F%E9%97%AE%E9%A2%98/","summary":"\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`package com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ezdltech\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etest\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epdf;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elowagie\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etext\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epdf\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBaseFont;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport org\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003exhtmlrenderer\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epdf\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eITextFontResolver;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport org\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003exhtmlrenderer\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epdf\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eITextRenderer;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eio\u003cspan style=\"color:#ff79c6\"\u003e.*\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e PDFUtils6 {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 获取对应pageName的html内容（生产环境java \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ejar直接run）\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e String getHtmlByPageName2(String filePath) throws IOException {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eBOOT\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003eINF\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eclasses\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003etemplates\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edashboard\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ehtml\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 返回读取指定资源的输入流\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        InputStream is \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new FileInputStream(new File(filePath));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        BufferedReader br \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new BufferedReader(new InputStreamReader(is));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String s \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        StringBuffer sb \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new StringBuffer();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ewhile\u003c/span\u003e ((s \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e br\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ereadLine()) \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            sb\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eappend(s)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eappend(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e sb\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etoString();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 将HTML转成PD格式的文件。html文件的格式比较严格\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @param htmlFile\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @param pdfFile\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @throws Exception\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003eDOCTYPE html PUBLIC \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;-//W3C//DTD XHTML 1.0 Transitional//EN\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd \u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e void html2pdf(String htmlFile, String pdfFile) throws Exception {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e step \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String url \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new File(htmlFile)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etoURI()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etoURL()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetPath();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(url);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e step \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        OutputStream os \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new FileOutputStream(pdfFile);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ITextRenderer renderer \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new ITextRenderer();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String result \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e getHtmlByPageName2(url);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(result\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esubstring(\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(result);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        renderer\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetDocumentFromString(result);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        renderer\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetDocumentFromString(result\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esubstring(\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        renderer\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetDocumentFromString(getXmlString());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        renderer\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetDocument(url);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e step \u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e 解决中文支持\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ITextFontResolver fontResolver \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e renderer\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetFontResolver();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;linux\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eequals(getCurrentOperatingSystem())){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            fontResolver\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddFont(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/Users/jason/Desktop/test/simsun.ttc\u0026#34;\u003c/span\u003e, BaseFont\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eIDENTITY_H, BaseFont\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eEMBEDDED);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            fontResolver\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddFont(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/Users/jason/Desktop/test/simsun.ttc\u0026#34;\u003c/span\u003e, BaseFont\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eIDENTITY_H, BaseFont\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eNOT_EMBEDDED);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            fontResolver\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddFont(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/Users/jason/Desktop/test/simkai.ttf\u0026#34;\u003c/span\u003e, BaseFont\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eIDENTITY_H, BaseFont\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eNOT_EMBEDDED);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        renderer\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elayout();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        renderer\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecreatePDF(os);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        os\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eclose();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;create pdf done!!\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e String getCurrentOperatingSystem(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String os \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetProperty(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;os.name\u0026#34;\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etoLowerCase();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;---------当前操作系统是-----------\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e os);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e os;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e String getXmlString() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String xmlString\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;!DOCTYPE html PUBLIC \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e-//W3C//DTD XHTML 1.0 Transitional//EN\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ehttp://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;html lang=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003een\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e xmlns=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ehttp://www.w3.org/1999/xhtml\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;head\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    \u0026amp;lt;meta charset=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eUTF-8\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e/\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    \u0026amp;lt;title\u0026gt;Hello World\u0026amp;lt;/title\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026amp;lt;style\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e  table.table-separate th{\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    font-weight:bold;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    font-size:14px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    border-top:1px solid #F3EDE9 !important;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;  }\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;  table.table-separate td{\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    padding: 13px 0;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    font-weight:100;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;  }\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;  .table-separate td.tit{\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    background-color: #f4f9fe;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    font-weight:normal;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    padding:22px 0;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    width:15%;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;  }\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;  .table-separate td.cont{\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    text-align: left;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    padding:16px 22px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    width:85%;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    line-height:175%;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;  }\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;  .table-separate.no-border th{\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    border:none;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    text-align: left;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;  }\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;  .table-separate.no-border td{\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    text-align: left;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    border:none;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;  }\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e@page {\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003esize:210mm 297mm;//纸张大小A4\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003emargin: 0.25in;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e-fs-flow-bottom: \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003efooter\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e-fs-flow-left: \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eleft\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e-fs-flow-right: \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eright\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder: thin solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003epadding: 1em;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e#footer {\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003efont-size: 90%; font-style: italic;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eposition: absolute; top: 0; left: 0;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e-fs-move-to-flow: \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003efooter\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e#pagenumber:before {\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003econtent: counter(page);\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e#pagecount:before {content: counter(pages);\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etable {\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\\t\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-collapse: collapse;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\\t\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etable-layout: fixed;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\\t\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eword-break:break-all;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\\t\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003efont-size: 10px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\\t\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ewidth: 100%;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\\t\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: center;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etd {\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eword-break:break-all;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eword-wrap : break-word;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026amp;lt;/style\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\t\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026amp;lt;/head\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;body style = \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003efont-family: SimSun;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;div id=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003efooter\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;  Page \u0026amp;lt;span id=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003epagenumber\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e/\u0026gt; of \u0026amp;lt;span id=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003epagecount\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e/\u0026gt; \u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;div id=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003emain\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    \u0026amp;lt;div style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003emax-width:600px;margin:0 auto;padding:10px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;        \u0026amp;lt;div style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: center; padding: 5mm 0;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;            \u0026amp;lt;div style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003efont-weight: bold; font-size: 30px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt; HI Fudi\u0026amp;amp;More\u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;            \u0026amp;lt;div\u0026gt; THANK YOU FOR SHOPPING WITH Fudi\u0026amp;amp;More!\u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;        \u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;        \u0026amp;lt;div style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder: 1px solid black; background-color: #f8f8f8; padding: 4mm;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;            \u0026amp;lt;div style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003efont-size: 17px; font-weight: bold; border-bottom: 1px solid black; padding-bottom: 5mm;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt; ORDER DETAILS\u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;            \u0026amp;lt;div style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003epadding-top: 10px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;div\u0026gt;\u0026amp;lt;strong\u0026gt;Order:\u0026amp;nbsp;\u0026amp;lt;/strong\u0026gt;D-8C2Y Placed on 29/09/2019 10:04\u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;div\u0026gt;\u0026amp;lt;strong\u0026gt;Carrier:\u0026amp;nbsp;\u0026amp;lt;/strong\u0026gt;Delivery\u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;div\u0026gt;\u0026amp;lt;strong\u0026gt;Payment:\u0026amp;nbsp;\u0026amp;lt;/strong\u0026gt;Cash Payment\u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;            \u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;        \u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;        \u0026amp;lt;div style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003emargin-top: 4mm;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;            \u0026amp;lt;table class=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etable-separate\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e cellpadding=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e cellspacing=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003emax-width:600px;margin:0 auto;padding:10px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;thead\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;tr style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: center; height: 40px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;th style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ewidth: 90px; background-color: #f8f8f8; border-top: 1px solid black; border-left: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        Reference\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;/th\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;th colspan=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ebackground-color: #f8f8f8; border-top: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;Product\u0026amp;lt;/th\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;th style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ewidth: 110px; background-color: #f8f8f8; border-top: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;Unit price\u0026amp;lt;/th\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;th style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ewidth: 80px; background-color: #f8f8f8; border-top: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;Quantity\u0026amp;lt;/th\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;th style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ewidth: 90px; background-color: #f8f8f8; border-top: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;Total price\u0026amp;lt;/th\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;/tr\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;/thead\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;tbody\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;tr style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: center; \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        Main\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td colspan=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom:1px solid black; border-right: 1px solid black; text-align: left; padding: 010px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        SweetSour Chicken\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u0026amp;euro; 7.00\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;1\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u0026amp;euro; 7.00\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;/tr\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;tr style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: center; \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        Main\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td colspan=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom:1px solid black; border-right: 1px solid black; text-align: left; padding: 010px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        Black Bean Stir Fry\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u0026amp;euro; 9.00\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;1\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u0026amp;euro; 9.00\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;/tr\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;tr style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: center; \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        Pizzas\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td colspan=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom:1px solid black; border-right: 1px solid black; text-align: left; padding: 010px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        Test Design Your Own 8\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e Pizza\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u0026amp;euro; 6.00\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;1\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-top: 1px solid black; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u0026amp;euro; 6.00\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;/tr\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;/tbody\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;tfoot\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;tr style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: center; height: 8mm;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td colspan=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: right; width: 90px; background-color: #f8f8f8; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; padding: 0 10px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        Item:\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ebackground-color: #f8f8f8; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;3\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;/tr\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;tr style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: center; height: 8mm;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td colspan=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: right; width: 90px; background-color: #f8f8f8; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; padding: 0 10px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        Subtotal:\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ebackground-color: #f8f8f8; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u0026amp;euro;24.00\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;/tr\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;tr style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: center; height: 8mm;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td colspan=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: right; width: 90px; background-color: #f8f8f8; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; padding: 0 10px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        Deliver Fee:\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ebackground-color: #f8f8f8; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;+\u0026amp;euro;2.00\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;/tr\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;tr style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: center; height: 8mm;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td colspan=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: right; width: 90px; background-color: #f8f8f8; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; padding: 0 10px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        Discount:\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ebackground-color: #f8f8f8; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;-\u0026amp;euro;0.00\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;/tr\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;tr style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: center; height: 8mm;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td colspan=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003etext-align: right; width: 90px; background-color: #f8f8f8; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; padding: 0 10px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                        Total:\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;td style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ebackground-color: #f8f8f8; border-bottom: 1px solid black; border-right: 1px solid black;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u0026amp;euro;24.00\u0026amp;lt;/td\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;/tr\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;/tfoot\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;            \u0026amp;lt;/table\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;        \u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;        \u0026amp;lt;div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;            \u0026amp;lt;div style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder: 1px solid black; background-color: #f8f8f8; padding:5mm; margin-top: 5mm;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;div style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003efont-size: 17px; font-weight: bold; border-bottom: 1px solid black; padding-bottom: 15px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt; DELIVERY ADDRESS\u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;div style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003epadding-top: 10px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;div\u0026gt;\u0026amp;lt;strong\u0026gt;guan\u0026amp;lt;/strong\u0026gt; \u0026amp;#9742; \u0026amp;lt;strong\u0026gt;13656690321\u0026amp;lt;/strong\u0026gt;\u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                    \u0026amp;lt;div\u0026gt; 1024/ Edenhall,ModelFarmRd,Cork,爱尔兰,A 2048\u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                \u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;            \u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;        \u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;        \u0026amp;lt;div style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003efont-size: 13px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;\u0026amp;lt;p\u0026gt;You can review your order and download your invoice from the \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026amp;lt;a target=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e_blank\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;                                                                                                          href=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ehttp://www.fudiandmore.ie/#/FudiIndex/Order1\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;Order\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;            history\u0026amp;lt;/a\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003esection of your customer account by clicking \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026amp;lt;a target=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e_blank\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e href=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ehttp://www.fudiandmore.ie/#/FudiIndex/Personalcenter1\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;My\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;            account\u0026amp;lt;/a\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e on ourshop.\u0026amp;lt;/p\u0026gt;\u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;        \u0026amp;lt;hr style=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eborder-width: 5px;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e/\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;        \u0026amp;lt;div\u0026gt; Fudi,More powered by \u0026amp;lt;a target=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e_blank\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e href=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003ehttp://www.fudiandmore.ie\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026gt;A2BLiving\u0026amp;lt;/a\u0026gt;\u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;    \u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/div\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/body\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/html\u0026gt;\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        StringBuffer stringBuffer\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003enew StringBuffer();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e xmlString;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e void main(String\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003e\u003cspan style=\"color:#6272a4\"\u003e#91;] args) {\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        String htmlFile \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/home/lbj/sign.jsp\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        String pdfFile \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/home/lbj/sign.pdf\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String htmlFile \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/Users/jason/Desktop/test/aaa/aaa.html\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        String htmlFile \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/Users/jason/Desktop/test/pdftest.html\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String pdfFile \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/Users/jason/Desktop/test/pdftest30.pdf\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        try {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            PDFUtils6\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ehtml2pdf(htmlFile, pdfFile);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } catch (FileNotFoundException e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintStackTrace();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } catch (Exception e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintStackTrace();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;dependency\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;groupId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ecom\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eitextpdf\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003egroupId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;artifactId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eitextpdf\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eartifactId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;version\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e5.5\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e9\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eversion\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edependency\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;dependency\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;groupId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ecom\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eitextpdf\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003etool\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003egroupId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;artifactId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003exmlworker\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eartifactId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;version\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e5.5\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e9\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eversion\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edependency\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;dependency\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;groupId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ecom\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eitextpdf\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003egroupId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;artifactId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eitext\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003easian\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eartifactId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;version\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e5.2\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eversion\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edependency\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;dependency\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;groupId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eorg\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003exhtmlrenderer\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003egroupId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;artifactId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eflying\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003esaucer\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003epdf\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eitext5\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eartifactId\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;version\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e9.0\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eversion\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edependency\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;!DOCTYPE html\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    PUBLIC \u0026#34;-//W3C//DTD XHTML 1.0 Transitional//EN\u0026#34; \u0026#34;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;html lang=\u0026#34;en\u0026#34; xmlns=\u0026#34;http://www.w3.org/1999/xhtml\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;head\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;meta charset=\u0026#34;UTF-8\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;meta http-equiv=\u0026#34;Content-Type\u0026#34; content=\u0026#34;text/html; charset=utf-8\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;meta http-equiv=\u0026#34;X-UA-Compatible\u0026#34; content=\u0026#34;IE=edge,chrome=1\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;meta http-equiv=\u0026#34;X-UA-Compatible\u0026#34; content=\u0026#34;IE=9\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0, maximum-scale=1.0\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;style\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        @page {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            size: A4;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            margin: 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        body{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            zoom:0.8;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            transform: scale(0.8);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .fontSize16 {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            font-size: 16px !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .cllor3B7 {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            color: #3B76B5 !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .posAbsolute {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            position: absolute !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .posRelative {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            position: relative !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .textAlignLeft {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            text-align: left\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .textAlignRight {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            text-align: right\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucher_body {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            /* position: relative;width: 954px;height: 424px;margin-left: -477px;margin-top: -212px;top: 50%;left: 50%; */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            position: relative;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucher {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            position: relative;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            width: 954px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            height: 424px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            background-size: 82% 82% !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            z-index: 999;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .printBtn {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            position: absolute;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            left: 50%;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            margin-left: -100px !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherPrint {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            position: fixed;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            width: 954px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            height: 424px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            top: 50%;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            left: 50%;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            transform: translate(-50%, -50%);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            background: initial !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            z-index: 99999;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            display: none;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherPDF {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            position: fixed;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            width: 954px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            height: 424px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            top: 50%;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            left: 50%;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            transform: translate(-50%, -50%);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            background: initial !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            z-index: 999999;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            display: none;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .openBg {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            background: url(\u0026#39;https://www.zchfax.com/data/temp/0_15723304043.jpg\u0026#39;) no-repeat !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .openBg2 {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            background: url(\u0026#39;/Users/jason/Desktop/test/aaa/open@2x.png\u0026#39;) no-repeat !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .financingBg {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            background: url(\u0026#39;financing@2x.png\u0026#39;) no-repeat !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .trasterBg {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            background: url(\u0026#39;transter@2x.png\u0026#39;) no-repeat !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .vouStatus {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            left: 124px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            top: 65px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .vouStatus\u0026gt;span {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            color: #EA2A41 !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucher .voNumber {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            right: 25%;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            top: 50px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            color: #EA2A41 !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucher .voNumber2 {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            left: 120px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            bottom: 16px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            color: #EA2A41 !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherContent .gsName {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            top: 98px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherContent .skName {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            top: 98px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherDer {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            width: 296px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherContent .openDer {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            width: 288px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherContent .shNumber {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            top: 129px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherContent .shNumber2 {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            top: 129px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherContent .moneyNumber {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            top: 169px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .moneyALL {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            right: 23.5%;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            top: 184px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            height: 30px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            width: 296px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        /* width: 100%;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            height: 100%;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .monyList {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            width: 100%;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            height: 100%;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            align-items: center;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .monyList\u0026gt;div {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            float: left;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            width: 8.33%;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            height: 30px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            padding: 5px 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            text-align: center;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            color: #3B76B5 !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherContent .openDate {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            top: 209px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherContent .openEleName {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            top: 241px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherContent .payDate {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            top: 209px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherContent .voucherLeft {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            left: 124px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        .voucherContent .voucherRight {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            right: 121px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;/style\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/head\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;body style=\u0026#34;font-family: SimSun;line-height:1;font-size:10.0pt;\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;div class=\u0026#34;textAlignCenter masking_alt\u0026#34; id=\u0026#34;forPrint\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;div class=\u0026#34;voucher openBg office\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;div class=\u0026#34;voucherDer vouStatus textAlignLeft voucherLeft fontSize16 posAbsolute\u0026#34;\u0026gt;\u0026amp;lt;span\u0026gt;已签收\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;p class=\u0026#34;voNumber fontSize16 posAbsolute\u0026#34;\u0026gt;BL20200615101522932\u0026amp;lt;/p\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;div class=\u0026#34;voucherContent\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;div class=\u0026#34;gsName voucherDer posAbsolute textAlignLeft voucherLeft\u0026#34;\u0026gt;\u0026amp;lt;span\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        class=\u0026#34;fontSize16  cllor3B7\u0026#34;\u0026gt;泽诚控股有限公司\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;div class=\u0026#34;skName posAbsolute textAlignLeft voucherDer voucherRight\u0026#34;\u0026gt;\u0026amp;lt;span\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        class=\u0026#34;fontSize16  cllor3B7\u0026#34;\u0026gt;陕西泽诚置业有限公司\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;div class=\u0026#34;shNumber posAbsolute textAlignLeft voucherDer voucherLeft\u0026#34;\u0026gt;\u0026amp;lt;span\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        class=\u0026#34;fontSize16 color2B2\u0026#34;\u0026gt;91610132MA6X53QN7L\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;div class=\u0026#34;shNumber2 posAbsolute textAlignLeft voucherDer voucherRight\u0026#34;\u0026gt;\u0026amp;lt;span\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        class=\u0026#34;fontSize16  color2B2\u0026#34;\u0026gt;8351515313513852\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;div class=\u0026#34;moneyNumber posAbsolute textAlignLeft openDer voucherLeft\u0026#34;\u0026gt;\u0026amp;lt;span\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        class=\u0026#34;fontSize16  cllor3B7\u0026#34;\u0026gt;（大写）伍拾万元\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;div class=\u0026#34;moneyALL posAbsolute textAlignLeft\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u0026amp;lt;div class=\u0026#34;monyList\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;$\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;6\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;0\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;5\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;0\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;0\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;0\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;0\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u0026amp;lt;div class=\u0026#34;moneyOne\u0026#34;\u0026gt;0\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;div class=\u0026#34;openDate posAbsolute textAlignLeft voucherDer voucherLeft\u0026#34;\u0026gt;\u0026amp;lt;span\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        class=\u0026#34;fontSize16  cllor3B7\u0026#34;\u0026gt;2020-06-15\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;div class=\u0026#34;openEleName posAbsolute textAlignLeft voucherDer voucherLeft\u0026#34;\u0026gt;\u0026amp;lt;span\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        class=\u0026#34;fontSize16  cllor3B7\u0026#34;\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;div class=\u0026#34;payDate posAbsolute textAlignLeft voucherDer voucherRight\u0026#34;\u0026gt;\u0026amp;lt;span\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        class=\u0026#34;fontSize16  cllor3B7\u0026#34;\u0026gt;2025-06-30\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;div class=\u0026#34;fontSize16 posAbsolute voNumber2 textAlignLeft voucherDer\u0026#34;\u0026gt;\u0026amp;lt;span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/body\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/html\u0026gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这就完了.直接运行没问题。还有比如 \u0026amp; 在正文中的要转义 \u0026amp; 要不然报错，格式一定要正确，\u0026lt;/\u0026gt;结束符一定要有，标准也要有\u003c/p\u003e","title":"Itext html转PDF，解决中文不显示与样式问题"},{"content":"一、MySQL 获得当前日期时间 函数\n1.1 获得当前日期 + 时间（date + time）\n1.2 获得当前日期 + 时间（date + time）\n1.3 获得当前日期（date）\n1.4 获得当前时间（time）\n1.5 获得当前 UTC 日期时间\n二、MySQL 日期时间 Extract（选取） 函数\n2.1 选取日期时间的各个部分：\n2.2 MySQL Extract() 函数\n2.3 MySQL dayof…\n2.4 MySQL week…\n2.5 MySQL 返回星期和月份名称\n2.6 返回月份中的最后一天\n三、MySQL 日期时间计算函数\n3.1 MySQL 为日期增加一个时间间隔\n3.2 MySQL 为日期减去一个时间间隔\n3.3 MySQL 另类日期\n3.4 MySQL 日期、时间相减\n四、MySQL 日期转换函数、时间转换函数\n4.1 MySQL （时间、秒）转换\n4.2 MySQL （日期、天数）转换\n4.3 MySQL Str to Date （字符串转换为日期）\n4.4 MySQL Date/Time to Str（日期/时间转换为字符串）\n4.5 MySQL 获得国家地区时间格式\n4.6 MySQL 拼凑日期、时间\n五、MySQL 时间戳（Timestamp）函数\n5.1 MySQL 获得当前时间戳\n5.2 MySQL （Unix 时间戳、日期）转换函数：\n5.3 MySQL 时间戳（timestamp）转换、增、减函数：\n六、MySQL 时区（timezone）转换函数\n一、MySQL 获得当前日期时间 函数\n1.1 获得当前日期 + 时间（date + time）\n函数：now()\nmysql\u0026gt; select now();\n+———————+\n| now() |\n+———————+\n| 2008-08-08 22:20:46 |\n+———————+\n除了 now()函数能获得当前的日期时间外，MySQL 中还有下面的函数：\ncurrent_timestamp()\ncurrent_timestamp\nlocaltime()\nlocaltime\nlocaltimestamp — (v4.0.6)\nlocaltimestamp() — (v4.0.6)\nmysql\u0026gt; select localtime();\n+———————+\n| localtime() |\n+———————+\n| 2015-07-07 17:01:38 |\n+———————+\nmysql\u0026gt; select localtime;\n+———————+\n| localtime |\n+———————+\n| 2015-07-07 17:01:41 |\n+———————+\n这些日期时间函数，都等同于 now()。\n鉴于 now() 函数简短易记，建议总是使用 now() 来替代上面列出的函数。\n1.2 获得当前日期 + 时间（date + time）\n函数：sysdate()\nsysdate() 日期时间函数跟 now() 类似，不同之处在于：now() 在执行开始时值就得到了， sysdate() 在函数执行时动态得到值。看下面的例子就明白了：\nmysql\u0026gt; select now(), sleep(3), now();\n+———————+———-+———————+\n| now() | sleep(3) | now() |\n+———————+———-+———————+\n| 2008-08-08 22:28:21 | 0 | 2008-08-08 22:28:21 |\n+———————+———-+———————+\nmysql\u0026gt; select sysdate(), sleep(3), sysdate();\n+———————+———-+———————+\n| sysdate() | sleep(3) | sysdate() |\n+———————+———-+———————+\n| 2008-08-08 22:28:41 | 0 | 2008-08-08 22:28:44 |\n+———————+———-+———————+\n可以看到，虽然中途 sleep 3 秒，但 now() 函数两次的时间值是相同的； sysdate() 函数两次得到的时间值相差 3 秒。MySQL Manual 中是这样描述 sysdate() 的：Return the time at which the function executes。\nsysdate() 日期时间函数，一般情况下很少用到。\n1.3 获得当前日期（date）\n函数：curdate()\nmysql\u0026gt; select curdate();\n+————+\n| curdate() |\n+————+\n| 2008-08-08 |\n+————+\n其中，下面的两个日期函数等同于 curdate()：\ncurrent_date()\ncurrent_date\n1.4 获得当前时间（time）\n函数：curtime()\nmysql\u0026gt; select curtime();\n+———–+\n| curtime() |\n+———–+\n| 22:41:30 |\n+———–+\n其中，下面的两个时间函数等同于 curtime()：\ncurrent_time()\ncurrent_time\n1.5 获得当前 UTC 日期时间\n函数：utc_date(), utc_time(), utc_timestamp()\nmysql\u0026gt; select utc_timestamp(), utc_date(), utc_time(), now()\n+———————+————+————+———————+\n| utc_timestamp() | utc_date() | utc_time() | now() |\n+———————+————+————+———————+\n| 2008-08-08 14:47:11 | 2008-08-08 | 14:47:11 | 2008-08-08 22:47:11 |\n+———————+————+————+———————+\n因为我国位于东八时区，所以本地时间 = UTC 时间 + 8 小时。UTC 时间在业务涉及多个国家和地区的时候，非常有用。\n二、MySQL 日期时间 Extract（选取） 函数\n2.1 选取日期时间的各个部分：\n日期、时间、年、季度、月、日、小时、分钟、秒、微秒\nset @dt = ‘2008-09-10 07:15:30.123456′;\nselect date(@dt); — 2008-09-10\nselect time(@dt); — 07:15:30.123456\nselect year(@dt); — 2008\nselect quarter(@dt); — 3\nselect month(@dt); — 9\nselect week(@dt); — 36\nselect day(@dt); — 10\nselect hour(@dt); — 7\nselect minute(@dt); — 15\nselect second(@dt); — 30\nselect microsecond(@dt); — 123456\n2.2 MySQL Extract() 函数\n可以上面实现类似的功能：\nset @dt = ‘2008-09-10 07:15:30.123456′;\nselect extract(year from @dt); — 2008\nselect extract(quarter from @dt); — 3\nselect extract(month from @dt); — 9\nselect extract(week from @dt); — 36\nselect extract(day from @dt); — 10\nselect extract(hour from @dt); — 7\nselect extract(minute from @dt); — 15\nselect extract(second from @dt); — 30\nselect extract(microsecond from @dt); — 123456\nselect extract(year_month from @dt); — 200809\nselect extract(day_hour from @dt); — 1007\nselect extract(day_minute from @dt); — 100715\nselect extract(day_second from @dt); — 10071530\nselect extract(day_microsecond from @dt); — 10071530123456\nselect extract(hour_minute from @dt); — 715\nselect extract(hour_second from @dt); — 71530\nselect extract(hour_microsecond from @dt); — 71530123456\nselect extract(minute_second from @dt); — 1530\nselect extract(minute_microsecond from @dt); — 1530123456\nselect extract(second_microsecond from @dt); — 30123456\nMySQL Extract() 函数除了没有date(),time() 的功能外，其他功能一应具全。并且还具有选取‘day_microsecond’ 等功能。注意这里不是只选取 day 和 microsecond，而是从日期的 day 部分一直选取到 microsecond 部分。够强悍的吧！\nMySQL Extract() 函数唯一不好的地方在于：你需要多敲几次键盘。\n2.3 MySQL dayof…\n函数：dayofweek(), dayofmonth(), dayofyear()\n分别返回日期参数，在一周、一月、一年中的位置。\nset @dt = ‘2008-08-08′;\nselect dayofweek(@dt); — 6\nselect dayofmonth(@dt); — 8\nselect dayofyear(@dt); — 221\n日期 ‘2008-08-08′ 是一周中的第 6 天（1 = Sunday, 2 = Monday, …, 7 = Saturday）；一月中的第 8 天；一年中的第 221 天。\n2.4 MySQL week…\n函数：week(), weekofyear(), dayofweek(), weekday(), yearweek()\nset @dt = ‘2008-08-08′;\nselect week(@dt); — 31\nselect week(@dt,3); — 32\nselect weekofyear(@dt); — 32\nselect dayofweek(@dt); — 6\nselect weekday(@dt); — 4\nselect yearweek(@dt); — 200831\nMySQL week() 函数，可以有两个参数，具体可看手册。 weekofyear()和week()一样，都是计算“某天”是位于一年中的第几周。 weekofyear(@dt)等价于week(@dt,3)。\nMySQL weekday()函数和dayofweek() 类似，都是返回“某天”在一周中的位置。不同点在于参考的标准：\nweekday：(0 = Monday, 1 = Tuesday, …, 6 = Sunday)；\ndayofweek：（1 = Sunday, 2 = Monday, …, 7 = Saturday）\nMySQL yearweek() 函数，返回 year(2008) + week位置(31)。\n2.5 MySQL 返回星期和月份名称\n函数：dayname(), monthname()\nset @dt = ‘2008-08-08′;\nselect dayname(@dt); — Friday\nselect monthname(@dt); — August\n思考，如何返回中文的名称呢？\n2.6 返回月份中的最后一天\nMySQL 函数： last_day()\nselect last_day(‘2008-02-01′); — 2008-02-29\nselect last_day(‘2008-08-08′); — 2008-08-31\nMySQL last_day()函数非常有用，比如我想得到当前月份中有多少天，可以这样来计算：\nmysql\u0026gt; select now(), day(last_day(now())) as days;\n+———————+——+\n| now() | days |\n+———————+——+\n| 2008-08-09 11:45:45 | 31 |\n+———————+——+\n三、MySQL 日期时间计算函数\n3.1 MySQL 为日期增加一个时间间隔\n函数：date_add()\nset @dt = now();\nselect date_add(@dt, interval 1 day); — add 1 day\nselect date_add(@dt, interval 1 hour); — add 1 hour\nselect date_add(@dt, interval 1 minute); — …\nselect date_add(@dt, interval 1 second);\nselect date_add(@dt, interval 1 microsecond);\nselect date_add(@dt, interval 1 week);\nselect date_add(@dt, interval 1 month);\nselect date_add(@dt, interval 1 quarter);\nselect date_add(@dt, interval 1 year);\nselect date_add(@dt, interval -1 day); — sub 1 day\nMySQL adddate(), addtime()函数，可以用 date_add()来替代。下面是 date_add() 实现 addtime() 功能示例：\nmysql\u0026gt; set @dt = ‘2008-08-09 12:12:33′;\nmysql\u0026gt; select date_add(@dt, interval ’01:15:30′ hour_second);\n+————————————————+\n| date_add(@dt, interval ’01:15:30′ hour_second) |\n+————————————————+\n| 2008-08-09 13:28:03 |\n+————————————————+\nmysql\u0026gt; select date_add(@dt, interval ‘1 01:15:30′ day_second);\n+————————————————-+\n| date_add(@dt, interval ‘1 01:15:30′ day_second) |\n+————————————————-+\n| 2008-08-10 13:28:03 |\n+————————————————-+\ndate_add()函数，分别为 @dt 增加了“1小时 15分 30秒” 和 “1天 1小时 15分 30秒”。建议：总是使用 date_add()日期时间函数来替代adddate(), addtime()。\n3.2 MySQL 为日期减去一个时间间隔\n函数：date_sub()\nmysql\u0026gt; select date_sub(‘1998-01-01 00:00:00′, interval ‘1 1:1:1′ day_second);\n+—————————————————————-+\n| date_sub(‘1998-01-01 00:00:00′, interval ‘1 1:1:1′ day_second) |\n+—————————————————————-+\n| 1997-12-30 22:58:59 |\n+—————————————————————-+\nMySQL date_sub() 日期时间函数 和 date_add() 用法一致，不再赘述。另外，MySQL 中还有两个函数 subdate(), subtime()，建议，用 date_sub() 来替代。\n3.3 MySQL 另类日期\n函数：period_add(P,N), period_diff(P1,P2)\n函数参数“P” 的格式为“YYYYMM” 或者 “YYMM”，第二个参数“N” 表示增加或减去 N month（月）。\nMySQL period_add(P,N)：日期加/减去N月。\nmysql\u0026gt; select period_add(200808,2), period_add(20080808,-2)\n+———————-+————————-+\n| period_add(200808,2) | period_add(20080808,-2) |\n+———————-+————————-+\n| 200810 | 20080806 |\n+———————-+————————-+\nMySQL period_diff(P1,P2)：日期 P1-P2，返回 N 个月。\nmysql\u0026gt; select period_diff(200808, 200801);\n+—————————–+\n| period_diff(200808, 200801) |\n+—————————–+\n| 7 |\n+—————————–+\n在 MySQL 中，这两个日期函数，一般情况下很少用到。\n3.4 MySQL 日期、时间相减\n函数：datediff(date1,date2), timediff(time1,time2)\nMySQL datediff(date1,date2)：两个日期相减 date1 – date2，返回天数。\nselect datediff(‘2008-08-08′, ‘2008-08-01′); — 7\nselect datediff(‘2008-08-01′, ‘2008-08-08′); — -7\nMySQL timediff(time1,time2)：两个日期相减 time1 – time2，返回 time 差值。\nselect timediff(‘2008-08-08 08:08:08′, ‘2008-08-08 00:00:00′); — 08:08:08\nselect timediff(’08:08:08′, ’00:00:00′); — 08:08:08\n注意：timediff(time1,time2) 函数的两个参数类型必须相同。\n四、MySQL 日期转换函数、时间转换函数\n4.1 MySQL （时间、秒）转换\n函数：time_to_sec(time), sec_to_time(seconds)\nselect time_to_sec(’01:00:05′); — 3605\nselect sec_to_time(3605); — ’01:00:05′\n4.2 MySQL （日期、天数）转换\n函数：to_days(date), from_days(days)\nselect to_days(‘0000-00-00′); — 0\nselect to_days(‘2008-08-08′); — 733627\nselect from_days(0); — ‘0000-00-00′\nselect from_days(733627); — ‘2008-08-08′\n4.3 MySQL Str to Date （字符串转换为日期）\n函数：str_to_date(str, format)\nselect str_to_date(’08/09/2008′, ‘%m/%d/%Y’); — 2008-08-09\nselect str_to_date(’08/09/08′ , ‘%m/%d/%y’); — 2008-08-09\nselect str_to_date(‘08.09.2008′, ‘%m.%d.%Y’); — 2008-08-09\nselect str_to_date(’08:09:30′, ‘%h:%i:%s’); — 08:09:30\nselect str_to_date(‘08.09.2008 08:09:30′, ‘%m.%d.%Y %h:%i:%s’); — 2008-08-09 08:09:30\n可以看到，str_to_date(str,format) 转换函数，可以把一些杂乱无章的字符串转换为日期格式。另外，它也可以转换为时间。“format” 可以参看 MySQL 手册。\n4.4 MySQL Date/Time to Str（日期/时间转换为字符串）\n函数：date_format(date,format), time_format(time,format)\nmysql\u0026gt; select date_format(‘2008-08-08 22:23:00′, ‘%W %M %Y’);\n+————————————————+\n| date_format(‘2008-08-08 22:23:00′, ‘%W %M %Y’) |\n+————————————————+\n| Friday August 2008 |\n+————————————————+\nmysql\u0026gt; select date_format(‘2008-08-08 22:23:01′, ‘%Y%m%d%H%i%s’);\n+—————————————————-+\n| date_format(‘2008-08-08 22:23:01′, ‘%Y%m%d%H%i%s’) |\n+—————————————————-+\n| 20080808222301 |\n+—————————————————-+\nmysql\u0026gt; select time_format(’22:23:01′, ‘%H.%i.%s’);\n+————————————-+\n| time_format(’22:23:01′, ‘%H.%i.%s’) |\n+————————————-+\n| 22.23.01 |\n+————————————-+\nMySQL 日期、时间转换函数：date_format(date,format), time_format(time,format) 能够把一个日期/时间转换成各种各样的字符串格式。它是 str_to_date(str,format) 函数的 一个逆转换。\n4.5 MySQL 获得国家地区时间格式\n函数：get_format()\nMySQL get_format() 语法：\nget_format(date|time|datetime, ‘eur’|’usa’|’jis’|’iso’|’internal’\nMySQL get_format() 用法的全部示例：\nselect get_format(date,’usa’) ; — ‘%m.%d.%Y’\nselect get_format(date,’jis’) ; — ‘%Y-%m-%d’\nselect get_format(date,’iso’) ; — ‘%Y-%m-%d’\nselect get_format(date,’eur’) ; — ‘%d.%m.%Y’\nselect get_format(date,’internal’) ; — ‘%Y%m%d’\nselect get_format(datetime,’usa’) ; — ‘%Y-%m-%d %H.%i.%s’\nselect get_format(datetime,’jis’) ; — ‘%Y-%m-%d %H:%i:%s’\nselect get_format(datetime,’iso’) ; — ‘%Y-%m-%d %H:%i:%s’\nselect get_format(datetime,’eur’) ; — ‘%Y-%m-%d %H.%i.%s’\nselect get_format(datetime,’internal’) ; — ‘%Y%m%d%H%i%s’\nselect get_format(time,’usa’) ; — ‘%h:%i:%s %p’\nselect get_format(time,’jis’) ; — ‘%H:%i:%s’\nselect get_format(time,’iso’) ; — ‘%H:%i:%s’\nselect get_format(time,’eur’) ; — ‘%H.%i.%s’\nselect get_format(time,’internal’) ; — ‘%H%i%s’\nMySQL get_format() 函数在实际中用到机会的比较少。\n4.6 MySQL 拼凑日期、时间\n函数：makdedate(year,dayofyear), maketime(hour,minute,second)\nselect makedate(2001,31); — ‘2001-01-31′\nselect makedate(2001,32); — ‘2001-02-01′\nselect maketime(12,15,30); — ’12:15:30′\n五、MySQL 时间戳（Timestamp）函数\n5.1 MySQL 获得当前时间戳\n函数：current_timestamp, current_timestamp()\nmysql\u0026gt; select current_timestamp, current_timestamp();\n+———————+———————+\n| current_timestamp | current_timestamp() |\n+———————+———————+\n| 2008-08-09 23:22:24 | 2008-08-09 23:22:24 |\n+———————+———————+\n5.2 MySQL （Unix 时间戳、日期）转换函数：\nunix_timestamp(),\nunix_timestamp(date),\nfrom_unixtime(unix_timestamp),\nfrom_unixtime(unix_timestamp,format)\n下面是示例：\nselect unix_timestamp(); — 1218290027\nselect unix_timestamp(‘2008-08-08′); — 1218124800\nselect unix_timestamp(‘2008-08-08 12:30:00′); — 1218169800\nselect from_unixtime(1218290027); — ‘2008-08-09 21:53:47′\nselect from_unixtime(1218124800); — ‘2008-08-08 00:00:00′\nselect from_unixtime(1218169800); — ‘2008-08-08 12:30:00′\nselect from_unixtime(1218169800, ‘%Y %D %M %h:%i:%s %x’); — ‘2008 8th August 12:30:00 2008′\n5.3 MySQL 时间戳（timestamp）转换、增、减函数：\ntimestamp(date) — date to timestamp\ntimestamp(dt,time) — dt + time\ntimestampadd(unit,interval,datetime_expr) –\ntimestampdiff(unit,datetime_expr1,datetime_expr2) –\n请看示例部分：\nselect timestamp(‘2008-08-08′); — 2008-08-08 00:00:00\nselect timestamp(‘2008-08-08 08:00:00′, ’01:01:01′); — 2008-08-08 09:01:01\nselect timestamp(‘2008-08-08 08:00:00′, ’10 01:01:01′); — 2008-08-18 09:01:01\nselect timestampadd(day, 1, ‘2008-08-08 08:00:00′); — 2008-08-09 08:00:00\nselect date_add(‘2008-08-08 08:00:00′, interval 1 day); — 2008-08-09 08:00:00\nMySQL timestampadd() 函数类似于 date_add()。\nselect timestampdiff(year,’2002-05-01′,’2001-01-01′); — -1\nselect timestampdiff(day ,’2002-05-01′,’2001-01-01′); — -485\nselect timestampdiff(hour,’2008-08-08 12:00:00′,’2008-08-08 00:00:00′); — -12\nselect datediff(‘2008-08-08 12:00:00′, ‘2008-08-01 00:00:00′); — 7\nMySQL timestampdiff() 函数就比 datediff() 功能强多了，datediff() 只能计算两个日期（date）之间相差的天数。\n六、MySQL 时区（timezone）转换函数\nconvert_tz(dt,from_tz,to_tz)\nselect convert_tz(‘2008-08-08 12:00:00′, ‘+08:00′, ‘+00:00′); — 2008-08-08 04:00:00\n1\n时区转换也可以通过date_add, date_sub, timestampadd 来实现。\nselect date_add(‘2008-08-08 12:00:00′, interval -8 hour); — 2008-08-08 04:00:00\nselect date_sub(‘2008-08-08 12:00:00′, interval 8 hour); — 2008-08-08 04:00:00\nselect timestampadd(hour, -8, ‘2008-08-08 12:00:00′); — 2008-08-08 04:00:00\nselect timediff(’23:40:00′, ‘ 18:30:00′); — 两时间相减\nSELECT substring( timediff(’23:40:00′, ‘ 18:30:00′),1,5) —-“05：10”相减返回小时：分钟\nselect datediff(‘2008-08-08′, ‘2008-08-01′); — 7 —–两日期相减\nselect TO_DAYS(‘2008-09-08′)-TO_DAYS(‘2008-08-08′) —–两日期相减\nSELECT substring( ‘2009-06-17 10:00:00′, 1, 10 ) —-从datetime中提取“日期”\n时间戳是从1970年1月1日开始到目标时间所经过的秒数.\n可以进行两个datetime时间间隔的运算。\n转自：https://blog.csdn.net/qq_38486203/article/details/80654040\n","permalink":"https://blog.zdltech.com/posts/mysql-%E6%97%B6%E9%97%B4%E5%87%BD%E6%95%B0%E5%8A%A0%E5%87%8F%E8%AE%A1%E7%AE%97/","summary":"\u003cp\u003e一、MySQL 获得当前日期时间 函数\u003cbr\u003e\n1.1 获得当前日期 + 时间（date + time）\u003cbr\u003e\n1.2 获得当前日期 + 时间（date + time）\u003cbr\u003e\n1.3 获得当前日期（date）\u003cbr\u003e\n1.4 获得当前时间（time）\u003cbr\u003e\n1.5 获得当前 UTC 日期时间\u003cbr\u003e\n二、MySQL 日期时间 Extract（选取） 函数\u003cbr\u003e\n2.1 选取日期时间的各个部分：\u003cbr\u003e\n2.2 MySQL Extract() 函数\u003cbr\u003e\n2.3 MySQL dayof…\u003cbr\u003e\n2.4 MySQL week…\u003cbr\u003e\n2.5 MySQL 返回星期和月份名称\u003cbr\u003e\n2.6 返回月份中的最后一天\u003cbr\u003e\n三、MySQL 日期时间计算函数\u003cbr\u003e\n3.1 MySQL 为日期增加一个时间间隔\u003cbr\u003e\n3.2 MySQL 为日期减去一个时间间隔\u003cbr\u003e\n3.3 MySQL 另类日期\u003cbr\u003e\n3.4 MySQL 日期、时间相减\u003cbr\u003e\n四、MySQL 日期转换函数、时间转换函数\u003cbr\u003e\n4.1 MySQL （时间、秒）转换\u003cbr\u003e\n4.2 MySQL （日期、天数）转换\u003cbr\u003e\n4.3 MySQL Str to Date （字符串转换为日期）\u003cbr\u003e\n4.4 MySQL Date/Time to Str（日期/时间转换为字符串）\u003cbr\u003e\n4.5 MySQL 获得国家地区时间格式\u003cbr\u003e\n4.6 MySQL 拼凑日期、时间\u003cbr\u003e\n五、MySQL 时间戳（Timestamp）函数\u003cbr\u003e\n5.1 MySQL 获得当前时间戳\u003cbr\u003e\n5.2 MySQL （Unix 时间戳、日期）转换函数：\u003cbr\u003e\n5.3 MySQL 时间戳（timestamp）转换、增、减函数：\u003cbr\u003e\n六、MySQL 时区（timezone）转换函数\u003cbr\u003e\n一、MySQL 获得当前日期时间 函数\u003cbr\u003e\n1.1 获得当前日期 + 时间（date + time）\u003cbr\u003e\n函数：now()\u003c/p\u003e","title":"MySQL 时间函数加减计算"},{"content":"我们常用的curl这个命令，curl可以查看服务器web server的banner信息：\n如：\nC:Documents and SettingsAdministrator\u0026gt;curl -I www.dangdang.com\nHTTP/1.1 200 OK\nServer: nginx/0.7.61（当当到目前为止用的还是nginx/0.7.61）\nC:Documents and SettingsAdministrator\u0026gt;curl -I www.360buy.com\nHTTP/1.0 200 OK\nServer: jdws （几个月前我就看还是nginx，做手脚啦！）\n来个猛一点的\nC:Documents and SettingsAdministrator\u0026gt;curl -I www.google.com\nHTTP/1.1 302 Found\nServer: gws （google自己开发的ws）\n我们可以看清每家公司的web—server，当然也为黑客入侵提供了信息。如果你的这版ws存在一个致命bug，那可就惨啦。哪有没有一种办法可以修改ws信息哪？答案自然是有。下面介绍一种修改nginx的banner信息的方法。\n方法很简单：\n安装nginx时，在./configure后不要马上安装。而是进到安装文件的../src/core/目录下找到nginx.h用vi编辑器进行修改，如下：\n#define NGINX_VERSION “1.1.1”\n#define NGINX_VER “nginx/” NGINX_VERSION\n#define NGINX_VAR “NGINX”\n改为（自定义）\n#define NGINX_VERSION “0.0.1”\n#define NGINX_VER “zhuzhu/” NGINX_VERSION\n#define NGINX_VAR “zhuzhu”\n然后再执行make \u0026amp;\u0026amp; make install\n这回来看看我们自己的nginx ws显示成啥样\nC:Documents and SettingsAdministrator\u0026gt;curl -I 192.168.0.111\nHTTP/1.1 200 OK\nServer: zhuzhu/0.0.1\n这下别人还以为你自己开发了新的ws哪！哈哈\n转自：https://www.mfisp.com/wap/help/server/2016/0525/1264.html\n","permalink":"https://blog.zdltech.com/posts/%E5%A6%82%E4%BD%95%E4%BC%AA%E8%A3%85nginx%E7%9A%84banner%E5%86%85%E5%AE%B9/","summary":"\u003cp\u003e我们常用的curl这个命令，curl可以查看服务器web server的banner信息：\u003c/p\u003e\n\u003cp\u003e如：\u003c/p\u003e\n\u003cp\u003eC:Documents and SettingsAdministrator\u0026gt;curl -I \u003ca href=\"https://www.dangdang.com\"\u003ewww.dangdang.com\u003c/a\u003e\u003cbr\u003e\nHTTP/1.1 200 OK\u003cbr\u003e\nServer: nginx/0.7.61（当当到目前为止用的还是nginx/0.7.61）\u003c/p\u003e\n\u003cp\u003eC:Documents and SettingsAdministrator\u0026gt;curl -I \u003ca href=\"https://www.360buy.com\"\u003ewww.360buy.com\u003c/a\u003e\u003cbr\u003e\nHTTP/1.0 200 OK\u003cbr\u003e\nServer: jdws  （几个月前我就看还是nginx，做手脚啦！）\u003c/p\u003e\n\u003cp\u003e来个猛一点的\u003c/p\u003e\n\u003cp\u003eC:Documents and SettingsAdministrator\u0026gt;curl -I \u003ca href=\"https://www.google.com\"\u003ewww.google.com\u003c/a\u003e\u003cbr\u003e\nHTTP/1.1 302 Found\u003cbr\u003e\nServer: gws （google自己开发的ws）\u003c/p\u003e\n\u003cp\u003e我们可以看清每家公司的web—server，当然也为黑客入侵提供了信息。如果你的这版ws存在一个致命bug，那可就惨啦。哪有没有一种办法可以修改ws信息哪？答案自然是有。下面介绍一种修改nginx的banner信息的方法。\u003c/p\u003e\n\u003cp\u003e方法很简单：\u003c/p\u003e\n\u003cp\u003e安装nginx时，在./configure后不要马上安装。而是进到安装文件的../src/core/目录下找到nginx.h用vi编辑器进行修改，如下：\u003c/p\u003e\n\u003cp\u003e#define NGINX_VERSION      “1.1.1”\u003cbr\u003e\n#define NGINX_VER          “nginx/” NGINX_VERSION\u003c/p\u003e\n\u003cp\u003e#define NGINX_VAR          “NGINX”\u003c/p\u003e\n\u003cp\u003e改为（自定义）\u003c/p\u003e\n\u003cp\u003e#define NGINX_VERSION      “0.0.1”\u003cbr\u003e\n#define NGINX_VER          “zhuzhu/” NGINX_VERSION\u003c/p\u003e\n\u003cp\u003e#define NGINX_VAR          “zhuzhu”\u003c/p\u003e\n\u003cp\u003e然后再执行make \u0026amp;\u0026amp; make install\u003c/p\u003e\n\u003cp\u003e这回来看看我们自己的nginx ws显示成啥样\u003c/p\u003e\n\u003cp\u003eC:Documents and SettingsAdministrator\u0026gt;curl -I 192.168.0.111\u003cbr\u003e\nHTTP/1.1 200 OK\u003cbr\u003e\nServer: zhuzhu/0.0.1\u003c/p\u003e","title":"如何伪装Nginx的banner内容"},{"content":"对于H-ui的体验与下载，大家可以直接访问他的官方网站：http://www.h-ui.net/H-ui.admin.shtml。\n第一步下载H-UI admin\n第二步 在Springboot 项目中的 static、templates 目录下面创建 admin文件夹 如下图\n注意 把H-ui.admin所使用到的静态资源放到 static/admin下\n第三步 配置controller\n` import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Controller @RequestMapping(\u0026#34;/admin/index\u0026#34;) public class MainController { //日志 private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired SysDictService sysDictService;//字典服务 @Autowired PjBankService pjBankService;//银行列表服务 /** * * @return */ @RequestMapping(\u0026#34;/index\u0026#34;) public String index(){ logger.info(\u0026#34;后台首页\u0026#34;); return \u0026#34;/admin/index\u0026#34;; } /** * * @return */ @RequestMapping(\u0026#34;/articlelist\u0026#34;) public String articleList(){ logger.info(\u0026#34;文字列表界面\u0026#34;); return \u0026#34;/admin/articlelist\u0026#34;; } /** * * @return */ @RequestMapping(\u0026#34;/adminrole\u0026#34;) public String adminrole(){ logger.info(\u0026#34;角色管理\u0026#34;); return \u0026#34;/admin/admin-role\u0026#34;; } /** * * @return */ @RequestMapping(\u0026#34;/admin-permission\u0026#34;) public String adminpermission(){ logger.info(\u0026#34;权限管理\u0026#34;); return \u0026#34;/admin/admin-permission\u0026#34;; } /** * * @return */ @RequestMapping(\u0026#34;/admin-list\u0026#34;) public String adminlist(){ logger.info(\u0026#34;管理员管理\u0026#34;); return \u0026#34;/admin/admin-list\u0026#34;; } /** * * @return */ @RequestMapping(\u0026#34;/member-list\u0026#34;) public String memberlist(){ logger.info(\u0026#34;管理员管理\u0026#34;); return \u0026#34;/admin/member-list\u0026#34;; } /** * * @return */ @RequestMapping(\u0026#34;/admin-role-add\u0026#34;) public String adminRoleAdd(){ logger.info(\u0026#34;管理员管理\u0026#34;); return \u0026#34;/admin/admin-role-add\u0026#34;; } /** * * @return */ @RequestMapping(value = \u0026#34;/login\u0026#34;,method = {RequestMethod.GET}) public String login(Model model){ logger.info(\u0026#34;登录界面\u0026#34;); model.addAttribute(\u0026#34;errorMsg\u0026#34;,\u0026#34;\u0026#34;); return \u0026#34;/admin/login\u0026#34;; } /** * * @return */ @PostMapping(\u0026#34;/login\u0026#34;) public String loginPost(Model model,HttpServletRequest request, HttpServletResponse response){ logger.info(\u0026#34;登录用户名，密码验证\u0026#34;); String username = request.getParameter(\u0026#34;username\u0026#34;); String password = request.getParameter(\u0026#34;password\u0026#34;); String yzm = request.getParameter(\u0026#34;yzmcode\u0026#34;); String pwd = new String(Base64.decodeBase64(password)); logger.info(username); logger.info(password); logger.info(pwd); logger.info(yzm); logger.info(\u0026#34;session yzm=\u0026gt;\u0026#34;+request.getSession().getAttribute(VerifyUtil.RANDOMCODEKEY)); if (username.equals(\u0026#34;zhangdl\u0026#34;)\u0026amp;\u0026amp;pwd.equals(\u0026#34;123456\u0026#34;)){ return \u0026#34;redirect:/admin/index/welcome\u0026#34;; }else{ model.addAttribute(\u0026#34;errorMsg\u0026#34;,\u0026#34;登录失败,用户名密码错误！\u0026#34;); return \u0026#34;/admin/login\u0026#34;; } } //创建方法 @RequestMapping(\u0026#34;/welcome\u0026#34;) public String welcome(){ logger.info(\u0026#34;欢迎页\u0026#34;); return \u0026#34;/admin/welcome\u0026#34;; } /** * @desc 图形验证码生成 */ @RequestMapping(\u0026#34;/createImg\u0026#34;) public void createImg(HttpServletRequest request, HttpServletResponse response) throws Exception { try { response.setContentType(\u0026#34;image/jpeg\u0026#34;);//设置相应类型,告诉浏览器输出的内容为图片 response.setHeader(\u0026#34;Pragma\u0026#34;, \u0026#34;No-cache\u0026#34;);//设置响应头信息，告诉浏览器不要缓存此内容 response.setHeader(\u0026#34;Cache-Control\u0026#34;, \u0026#34;no-cache\u0026#34;); response.setDateHeader(\u0026#34;Expire\u0026#34;, 0); VerifyUtil randomValidateCode = new VerifyUtil(); randomValidateCode.getRandCode(request, response);//输出验证码图片 }catch (Exception e){ logger.error(\u0026#34;获取验证码失败！\u0026#34;); } } } ` 这个时候，基本上就集成完成。但是如果项目配置 server.servlet.context-path=/abc 这个时候，我们在开发的过程中 会出现路径问题。这个时候需要我们配置 界面中静态资源路径\n例如 登录界面：\n`\u0026amp;lt;!DOCTYPE HTML\u0026gt; \u0026amp;lt;html xmlns:th=\u0026#34;http://www.thymeleaf.org\u0026#34;\u0026gt; \u0026amp;lt;head\u0026gt; \u0026amp;lt;meta charset=\u0026#34;utf-8\u0026#34;\u0026gt; \u0026amp;lt;meta name=\u0026#34;renderer\u0026#34; content=\u0026#34;webkit|ie-comp|ie-stand\u0026#34;\u0026gt; \u0026amp;lt;meta http-equiv=\u0026#34;X-UA-Compatible\u0026#34; content=\u0026#34;IE=edge,chrome=1\u0026#34;\u0026gt; \u0026amp;lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no\u0026#34;/\u0026gt; \u0026amp;lt;meta http-equiv=\u0026#34;Cache-Control\u0026#34; content=\u0026#34;no-siteapp\u0026#34;/\u0026gt; \u0026amp;lt;base th:href=\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{#httpServletRequest.getContextPath()+\u0026#39;/\u0026#39;}\u0026#34;/\u0026gt; \u0026amp;lt;!--\u0026amp;#91;if lt IE 9]\u0026gt; \u0026amp;lt;script type=\u0026#34;text/javascript\u0026#34; th:src=\u0026#34;@{/admin/lib/html5shiv.js}\u0026#34;\u0026gt;\u0026amp;lt;/script\u0026gt; \u0026amp;lt;script type=\u0026#34;text/javascript\u0026#34; th:src=\u0026#34;@{/admin/lib/respond.min.js}\u0026#34;\u0026gt;\u0026amp;lt;/script\u0026gt; \u0026amp;lt;!\u0026amp;#91;endif]--\u0026gt; \u0026amp;lt;link th:href=\u0026#34;@{/admin/static/h-ui/css/H-ui.min.css}\u0026#34; rel=\u0026#34;stylesheet\u0026#34; type=\u0026#34;text/css\u0026#34;/\u0026gt; \u0026amp;lt;link th:href=\u0026#34;@{/admin/static/h-ui.admin/css/H-ui.login.css}\u0026#34; rel=\u0026#34;stylesheet\u0026#34; type=\u0026#34;text/css\u0026#34;/\u0026gt; \u0026amp;lt;link th:href=\u0026#34;@{/admin/static/h-ui.admin/css/style.css}\u0026#34; rel=\u0026#34;stylesheet\u0026#34; type=\u0026#34;text/css\u0026#34;/\u0026gt; \u0026amp;lt;link th:href=\u0026#34;@{/admin/lib/Hui-iconfont/1.0.8/iconfont.css}\u0026#34; rel=\u0026#34;stylesheet\u0026#34; type=\u0026#34;text/css\u0026#34;/\u0026gt; \u0026amp;lt;!--\u0026amp;#91;if IE 6]\u0026gt; \u0026amp;lt;script type=\u0026#34;text/javascript\u0026#34; th:src=\u0026#34;@{/admin/lib/DD_belatedPNG_0.0.8a-min.js}\u0026#34;\u0026gt;\u0026amp;lt;/script\u0026gt; \u0026amp;lt;script\u0026gt;DD_belatedPNG.fix(\u0026#39;*\u0026#39;);\u0026amp;lt;/script\u0026gt; \u0026amp;lt;!\u0026amp;#91;endif]--\u0026gt; \u0026amp;lt;title\u0026gt;后台登录 - 硕硕管理系统\u0026amp;lt;/title\u0026gt; \u0026amp;lt;meta name=\u0026#34;keywords\u0026#34; content=\u0026#34;\u0026#34;\u0026gt; \u0026amp;lt;meta name=\u0026#34;description\u0026#34; content=\u0026#34;\u0026#34;\u0026gt; \u0026amp;lt;/head\u0026gt; \u0026amp;lt;body\u0026gt; \u0026amp;lt;input type=\u0026#34;hidden\u0026#34; id=\u0026#34;TenantId\u0026#34; name=\u0026#34;TenantId\u0026#34; value=\u0026#34;\u0026#34;/\u0026gt; \u0026amp;lt;div class=\u0026#34;header\u0026#34;\u0026gt;\u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;loginWraper\u0026#34;\u0026gt; \u0026amp;lt;div id=\u0026#34;loginform\u0026#34; class=\u0026#34;loginBox\u0026#34;\u0026gt; \u0026amp;lt;form class=\u0026#34;form form-horizontal\u0026#34; th:action=\u0026#34;@{/admin/index/login}\u0026#34; method=\u0026#34;post\u0026#34; onsubmit=\u0026#34;return onSubmitCheck()\u0026#34;\u0026gt; \u0026amp;lt;div class=\u0026#34;row cl\u0026#34;\u0026gt; \u0026amp;lt;label class=\u0026#34;form-label col-xs-3\u0026#34;\u0026gt;\u0026amp;lt;i class=\u0026#34;Hui-iconfont\u0026#34;\u0026gt;\u0026amp;#xe60d;\u0026amp;lt;/i\u0026gt;\u0026amp;lt;/label\u0026gt; \u0026amp;lt;div class=\u0026#34;formControls col-xs-8\u0026#34;\u0026gt; \u0026amp;lt;input id=\u0026#34;username\u0026#34; name=\u0026#34;username\u0026#34; type=\u0026#34;text\u0026#34; placeholder=\u0026#34;账户\u0026#34; class=\u0026#34;input-text size-L\u0026#34;\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;row cl\u0026#34;\u0026gt; \u0026amp;lt;label class=\u0026#34;form-label col-xs-3\u0026#34;\u0026gt;\u0026amp;lt;i class=\u0026#34;Hui-iconfont\u0026#34;\u0026gt;\u0026amp;#xe60e;\u0026amp;lt;/i\u0026gt;\u0026amp;lt;/label\u0026gt; \u0026amp;lt;div class=\u0026#34;formControls col-xs-8\u0026#34;\u0026gt; \u0026amp;lt;input id=\u0026#34;passworda\u0026#34; type=\u0026#34;password\u0026#34; placeholder=\u0026#34;密码\u0026#34; class=\u0026#34;input-text size-L\u0026#34;\u0026gt; \u0026amp;lt;img th:src=\u0026#34;@{/admin/eye_open.png}\u0026#34; id=\u0026#34;changeshowhide_img\u0026#34; onclick=\u0026#34;changeShowHide()\u0026#34; style=\u0026#34;position: absolute;left: 350px;top: 10px;width: 20px;height: 20px;\u0026#34;\u0026gt; \u0026amp;lt;input id=\u0026#34;password\u0026#34; name=\u0026#34;password\u0026#34; type=\u0026#34;hidden\u0026#34; placeholder=\u0026#34;密码\u0026#34; class=\u0026#34;input-text size-L\u0026#34;\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;row cl\u0026#34;\u0026gt; \u0026amp;lt;div class=\u0026#34;formControls col-xs-8 col-xs-offset-3\u0026#34;\u0026gt; \u0026amp;lt;input class=\u0026#34;input-text size-L\u0026#34; id=\u0026#34;yzmcode\u0026#34; name=\u0026#34;yzmcode\u0026#34; type=\u0026#34;text\u0026#34; placeholder=\u0026#34;验证码\u0026#34; onblur=\u0026#34;if(this.value==\u0026#39;\u0026#39;){this.value=\u0026#39;验证码:\u0026#39;}\u0026#34; onclick=\u0026#34;if(this.value==\u0026#39;验证码:\u0026#39;){this.value=\u0026#39;\u0026#39;;}\u0026#34; value=\u0026#34;验证码:\u0026#34; style=\u0026#34;width:150px;\u0026#34;\u0026gt; \u0026amp;lt;img th:src=\u0026#34;@{/admin/index/createImg}\u0026#34; id=\u0026#34;yzmimage\u0026#34; onclick=\u0026#34;createImg()\u0026#34;\u0026gt; \u0026amp;lt;a id=\u0026#34;kanbuq\u0026#34; href=\u0026#34;javascript:void (0);\u0026#34; onclick=\u0026#34;createImg()\u0026#34;\u0026gt;看不清，换一张\u0026amp;lt;/a\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;div\u0026gt; \u0026amp;lt;div class=\u0026#34;form-label col-xs-11\u0026#34; style=\u0026#34;margin-left: 25%;\u0026#34;\u0026gt; \u0026amp;lt;p style=\u0026#34;color: red; text-align: left;\u0026#34; id=\u0026#34;errormsg\u0026#34; th:value=\u0026#34;\u0026amp;lt;/span\u0026gt;{errorMsg}\u0026#34; th:text=\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{errorMsg}\u0026#34;\u0026gt;\u0026amp;lt;/p\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;row cl\u0026#34;\u0026gt; \u0026amp;lt;div class=\u0026#34;formControls col-xs-8 col-xs-offset-3\u0026#34;\u0026gt; \u0026amp;lt;label for=\u0026#34;online\u0026#34;\u0026gt; \u0026amp;lt;input type=\u0026#34;checkbox\u0026#34; name=\u0026#34;online\u0026#34; id=\u0026#34;online\u0026#34; value=\u0026#34;\u0026#34;\u0026gt; 使我保持登录状态\u0026amp;lt;/label\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;row cl\u0026#34;\u0026gt; \u0026amp;lt;div class=\u0026#34;formControls col-xs-8 col-xs-offset-3\u0026#34;\u0026gt; \u0026amp;lt;input name=\u0026#34;\u0026#34; type=\u0026#34;submit\u0026#34; class=\u0026#34;btn btn-success radius size-L\u0026#34; value=\u0026#34;\u0026amp;nbsp;登\u0026amp;nbsp;\u0026amp;nbsp;\u0026amp;nbsp;\u0026amp;nbsp;录\u0026amp;nbsp;\u0026#34;\u0026gt; \u0026amp;lt;input name=\u0026#34;\u0026#34; type=\u0026#34;reset\u0026#34; class=\u0026#34;btn btn-default radius size-L\u0026#34; value=\u0026#34;\u0026amp;nbsp;取\u0026amp;nbsp;\u0026amp;nbsp;\u0026amp;nbsp;\u0026amp;nbsp;消\u0026amp;nbsp;\u0026#34; style=\u0026#34;margin-left: 20px;\u0026#34;\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;/form\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;footer\u0026#34;\u0026gt;Copyright 泽诚数字科技 by 银企智链\u0026amp;lt;/div\u0026gt; \u0026amp;lt;script type=\u0026#34;text/javascript\u0026#34; th:src=\u0026#34;@{/admin/lib/jquery/1.9.1/jquery.min.js}\u0026#34;\u0026gt;\u0026amp;lt;/script\u0026gt; \u0026amp;lt;script type=\u0026#34;text/javascript\u0026#34; th:src=\u0026#34;@{/admin/lib/base64.js}\u0026#34;\u0026gt;\u0026amp;lt;/script\u0026gt; \u0026amp;lt;script type=\u0026#34;text/javascript\u0026#34; th:src=\u0026#34;@{/admin/static/h-ui/js/H-ui.min.js}\u0026#34;\u0026gt;\u0026amp;lt;/script\u0026gt; \u0026amp;lt;script type=\u0026#34;text/javascript\u0026#34; th:inline=\u0026#34;javascript\u0026#34;\u0026gt; /*\u0026amp;lt;!\u0026amp;#91;CDATA\u0026amp;#91;*/ function createImg() {// 刷新验证码 var v = new Date().getTime(); var path =/*\u0026amp;#91;\u0026amp;#91;@{/admin/index/createImg}]]*/\u0026#34;\u0026#34;; path = path + \u0026#34;?t=\u0026#34; + v; console.log(path); document.getElementById(\u0026#34;yzmimage\u0026#34;).src = path; } function onSubmitCheck() {//数据验证 var username =\u0026amp;lt;/span\u0026gt;(\u0026#34;#username\u0026#34;).val(); var passworda = \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(\u0026#34;#passworda\u0026#34;).val(); var yzmcode =\u0026amp;lt;/span\u0026gt;(\u0026#34;#yzmcode\u0026#34;).val(); if (username == null || username.trim() == \u0026#39;\u0026#39; || username == undefined) { \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(\u0026#34;#errormsg\u0026#34;).text(\u0026#34;用户名必须输入\u0026#34;); return false; } if (passworda == null || passworda == undefined || passworda.trim() == \u0026#39;\u0026#39;) {\u0026amp;lt;/span\u0026gt;(\u0026#34;#errormsg\u0026#34;).text(\u0026#34;密码必须输入\u0026#34;); return false; } if (yzmcode == null || yzmcode == undefined || yzmcode.trim() == \u0026#39;\u0026#39; || yzmcode.trim() == \u0026#39;验证码:\u0026#39;) { \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(\u0026#34;#errormsg\u0026#34;).text(\u0026#34;验证码必须输入\u0026#34;); return false; } var base64 = new BASE64();\u0026amp;lt;/span\u0026gt;(\u0026#34;#password\u0026#34;).val(base64.encode(passworda));//数据加密 return true; } function changeShowHide() {//显示隐藏图片 var eye = document.getElementById(\u0026#34;changeshowhide_img\u0026#34;); var eyeSrc = eye.src; var path = /*\u0026amp;#91;\u0026amp;#91;@{/admin/}]]*/\u0026#34;\u0026#34;; console.log(eyeSrc); if (eyeSrc != undefined \u0026amp;\u0026amp; eyeSrc.indexOf(\u0026#34;eye_off.png\u0026#34;) != -1) {//关 eye.src = path + \u0026#34;eye_open.png\u0026#34;; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(\u0026#34;#passworda\u0026#34;).attr(\u0026#34;type\u0026#34;, \u0026#34;password\u0026#34;); } else if (eyeSrc != undefined \u0026amp;\u0026amp; eyeSrc.indexOf(\u0026#34;eye_open.png\u0026#34;) != -1) {//开 eye.src = path + \u0026#34;eye_off.png\u0026#34;;\u0026amp;lt;/span\u0026gt;(\u0026#34;#passworda\u0026#34;).attr(\u0026#34;type\u0026#34;, \u0026#34;text\u0026#34;); } } /*]]\u0026gt;*/ \u0026amp;lt;/script\u0026gt; \u0026amp;lt;/body\u0026gt; \u0026amp;lt;/html\u0026gt;` ","permalink":"https://blog.zdltech.com/posts/springboot%E5%9F%BA%E4%BA%8Ethymeleaf%E9%9B%86%E6%88%90h-ui%E5%90%8E%E5%8F%B0/","summary":"\u003cp\u003e对于H-ui的体验与下载，大家可以直接访问他的官方网站：\u003ca href=\"http://www.h-ui.net/H-ui.admin.shtml\"\u003ehttp://www.h-ui.net/H-ui.admin.shtml\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e第一步下载H-UI admin\u003c/p\u003e\n\u003cp\u003e第二步 在Springboot 项目中的 static、templates 目录下面创建 admin文件夹 如下图\u003cfigure class=\"wp-block-image size-large\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://www.zdltech.com/images/2020/05/image.png\"\u003e \u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e注意 把H-ui.admin所使用到的静态资源放到 static/admin下\u003c/p\u003e\n\u003cp\u003e第三步 配置controller\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport javax.servlet.http.HttpServletRequest;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport javax.servlet.http.HttpServletResponse;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@Controller\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@RequestMapping(\u0026#34;/admin/index\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic class MainController {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    //日志\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private Logger logger = LoggerFactory.getLogger(getClass());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Autowired\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    SysDictService sysDictService;//字典服务\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Autowired\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    PjBankService pjBankService;//银行列表服务\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * @return\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @RequestMapping(\u0026#34;/index\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public String index(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(\u0026#34;后台首页\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return \u0026#34;/admin/index\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * @return\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @RequestMapping(\u0026#34;/articlelist\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public String articleList(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(\u0026#34;文字列表界面\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return \u0026#34;/admin/articlelist\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * @return\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @RequestMapping(\u0026#34;/adminrole\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public String adminrole(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(\u0026#34;角色管理\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return \u0026#34;/admin/admin-role\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * @return\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @RequestMapping(\u0026#34;/admin-permission\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public String adminpermission(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(\u0026#34;权限管理\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return \u0026#34;/admin/admin-permission\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * @return\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @RequestMapping(\u0026#34;/admin-list\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public String adminlist(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(\u0026#34;管理员管理\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return \u0026#34;/admin/admin-list\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * @return\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @RequestMapping(\u0026#34;/member-list\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public String memberlist(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(\u0026#34;管理员管理\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return \u0026#34;/admin/member-list\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * @return\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @RequestMapping(\u0026#34;/admin-role-add\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public String adminRoleAdd(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(\u0026#34;管理员管理\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return \u0026#34;/admin/admin-role-add\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * @return\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @RequestMapping(value = \u0026#34;/login\u0026#34;,method = {RequestMethod.GET})\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public String login(Model model){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(\u0026#34;登录界面\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        model.addAttribute(\u0026#34;errorMsg\u0026#34;,\u0026#34;\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return \u0026#34;/admin/login\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * @return\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @PostMapping(\u0026#34;/login\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public String loginPost(Model model,HttpServletRequest request, HttpServletResponse response){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(\u0026#34;登录用户名，密码验证\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String username = request.getParameter(\u0026#34;username\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String password = request.getParameter(\u0026#34;password\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String yzm =  request.getParameter(\u0026#34;yzmcode\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String pwd = new String(Base64.decodeBase64(password));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(username);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(password);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(pwd);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(yzm);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(\u0026#34;session yzm=\u0026gt;\u0026#34;+request.getSession().getAttribute(VerifyUtil.RANDOMCODEKEY));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        if (username.equals(\u0026#34;zhangdl\u0026#34;)\u0026amp;\u0026amp;pwd.equals(\u0026#34;123456\u0026#34;)){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            return \u0026#34;redirect:/admin/index/welcome\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }else{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            model.addAttribute(\u0026#34;errorMsg\u0026#34;,\u0026#34;登录失败,用户名密码错误！\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            return \u0026#34;/admin/login\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    //创建方法\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @RequestMapping(\u0026#34;/welcome\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public String welcome(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        logger.info(\u0026#34;欢迎页\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return \u0026#34;/admin/welcome\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * @desc 图形验证码生成\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @RequestMapping(\u0026#34;/createImg\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public void createImg(HttpServletRequest request, HttpServletResponse response) throws Exception {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        try {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            response.setContentType(\u0026#34;image/jpeg\u0026#34;);//设置相应类型,告诉浏览器输出的内容为图片\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            response.setHeader(\u0026#34;Pragma\u0026#34;, \u0026#34;No-cache\u0026#34;);//设置响应头信息，告诉浏览器不要缓存此内容\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            response.setHeader(\u0026#34;Cache-Control\u0026#34;, \u0026#34;no-cache\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            response.setDateHeader(\u0026#34;Expire\u0026#34;, 0);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            VerifyUtil randomValidateCode = new VerifyUtil();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            randomValidateCode.getRandCode(request, response);//输出验证码图片\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }catch (Exception e){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            logger.error(\u0026#34;获取验证码失败！\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这个时候，基本上就集成完成。但是如果项目配置 server.servlet.context-path=/abc 这个时候，我们在开发的过程中 会出现路径问题。这个时候需要我们配置 界面中静态资源路径\u003c/p\u003e","title":"springBoot基于thymeleaf集成H-ui后台"},{"content":"`express是一个基于node.js平台的，快速，开放，极简的web开发框架。 一、安装 express npm install express --save 二、简单使用 express //引入express const express = require(\u0026#39;express\u0026#39;); //创建一个应用 let app = express(); //匹配GET请求路径设置回调函数 app.get(\u0026#39;/hello\u0026#39;, function (req, res) { res.end(\u0026#39;hello\u0026#39;); }); //监听端口 app.listen(8888, function () { console.log(\u0026#39;port : 8888\u0026#39;); }); 通过访问 localhost:8888/hello 我们就可以看到内容输出了。 当然 express 还支持其他的一些请求方法，比如 app.post()，app.put()，app.delete()，app.head() 等。 //引入express const express = require(\u0026#39;express\u0026#39;); //创建一个应用 let app = express(); //匹配POST请求 app.post(\u0026#39;/hello\u0026#39;, function (req, res) { res.end(\u0026#39;post hello\u0026#39;); }); //监听端口 app.listen(8888, function () { console.log(\u0026#39;port : 8888\u0026#39;); }); 如果我们想要匹配所有的请求路径，可以使用通配符 * 号。 //引入express const express = require(\u0026#39;express\u0026#39;); //创建一个应用 let app = express(); app.get(\u0026#39;/hello\u0026#39;, function (req, res) { res.end(\u0026#39;hello\u0026#39;); }); //*号匹配所有路径 app.get(\u0026#39;*\u0026#39;, function (req, res) { res.end(\u0026#39;not found\u0026#39;); }); //监听端口 app.listen(8888, function () { console.log(\u0026#39;port : 8888\u0026#39;); }); express 还提供了 all() 方法，可以匹配所有请求方法。 //引入express const express = require(\u0026#39;express\u0026#39;); //创建一个应用 let app = express(); //匹配所有请求方法 app.all(\u0026#39;/hello\u0026#39;, function (req, res) { res.end(\u0026#39;all hello\u0026#39;); }); //监听端口 app.listen(8888, function () { console.log(\u0026#39;port : 8888\u0026#39;); }); 三、express 中间件的概念 express中间件就是处理http请求的函数，用来完成一些特定的操作，比如登陆检查，权限控制等等。 1、一个中间件处理完请求和响应，可以把数据传递给下一个中间件。 2、在回调函数中使用 next()，就可以让请求继续向下传递。 3、通过不同路径，分别执行不同的中间件。 我们可以使用 use() ，在路由数组中添加一个中间件。注意我们设置的路由路径最终会存放在一个数组里，由上到下的把路径加入这个数组中。 //引入express const express = require(\u0026#39;express\u0026#39;); //创建一个应用 let app = express(); //如果没有设置路径，则会匹配全部 app.use(function (req, res, next) { console.log(\u0026#39;匹配全部路径\u0026#39;); //注意这里如果不调用next()，则请求并不会向下传递。 next(); }); app.use(\u0026#39;/hello\u0026#39;, function (req, res, next) { console.log(\u0026#39;use hello\u0026#39;); next(); }); app.get(\u0026#39;/hello\u0026#39;, function (req, res, next) { console.log(\u0026#39;get hello\u0026#39;); next(); }); //监听端口 app.listen(8888, function () { console.log(\u0026#39;port : 8888\u0026#39;); }); next() 函数可以传入一个参数，表示错误信息，默认将执行错误中间件。 //引入express const express = require(\u0026#39;express\u0026#39;); //创建一个应用 let app = express(); app.get(\u0026#39;/hello\u0026#39;, function (req, res, next) { console.log(\u0026#39;get hello\u0026#39;); next(\u0026#39;error!!!\u0026#39;); }); //注意错误处理中间件的参数是4个 app.use(function (err, req, res, next) { console.log(err); res.end(err); }); //监听端口 app.listen(8888, function () { console.log(\u0026#39;port : 8888\u0026#39;); }); 四、express中的request对象 在express中对原生的req请求对象进行了扩展，添加了一些属性和方法。 //引入express const express = require(\u0026#39;express\u0026#39;); //创建一个应用 let app = express(); app.get(\u0026#39;/hello\u0026#39;, function (req, res, next) { //主机名 res.write(\u0026#39;req.hostname : \u0026#39; + req.hostname + \u0026#39;\\r\\n\u0026#39;); //请求URL的路径 res.write(\u0026#39;req.path : \u0026#39; + req.path + \u0026#39;\\r\\n\u0026#39;); //查询字符串对象 res.write(\u0026#39;req.query : \u0026#39; + JSON.stringify(req.query) + \u0026#39;\\r\\n\u0026#39;); //请求的远程IP地址 res.write(\u0026#39;req.ip : \u0026#39; + req.ip + \u0026#39;\\r\\n\u0026#39;); //请求方法 res.write(\u0026#39;req.method : \u0026#39; + req.method + \u0026#39;\\r\\n\u0026#39;); res.end(); }); //监听端口 app.listen(8888, function () { console.log(\u0026#39;port : 8888\u0026#39;); }); 通过 req.params 获取路径里的参数 //引入express const express = require(\u0026#39;express\u0026#39;); //创建一个应用 let app = express(); app.get(\u0026#39;/list/:key/:page/:size\u0026#39;, function (req, res, next) { //注意，设置了多少参数，地址就需要传入多少参数 res.end(JSON.stringify(req.params)); }); //监听端口 app.listen(8888, function () { console.log(\u0026#39;port : 8888\u0026#39;); }); 五、express中的response对象 express中也对原生的res对象进行了扩展，添加了一些属性和方法。 const path = require(\u0026#39;path\u0026#39;); //引入express const express = require(\u0026#39;express\u0026#39;); //创建一个应用 let app = express(); app.get(\u0026#39;/send/str\u0026#39;, function (req, res, next) { //send方法会自动判断数据类型，并进行相应的head信息设置 //如果参数是字符串，则Content-Type为 text/html res.send(\u0026#39;hello, world\u0026#39;); }); app.get(\u0026#39;/send/arr\u0026#39;, function (req, res, next) { //如果参数是一个数组，则返回json res.send(\u0026amp;#91;1, 2, 3]); }); app.get(\u0026#39;/send/obj\u0026#39;, function (req, res, next) { //如果参数是一个对象，则返回json res.send({name: \u0026#39;xiaoxu\u0026#39;, age: 24}); }); app.get(\u0026#39;/send/number\u0026#39;, function (req, res, next) { //如果是一个数字，则返回相应状态码短语 res.send(404); }); app.get(\u0026#39;/download\u0026#39;, function (req, res, next) { //提示下载文件 res.download(\u0026#39;./1.txt\u0026#39;); }); app.get(\u0026#39;/json\u0026#39;, function (req, res, next) { //响应json对象 res.json({name: \u0026#39;xiaoxu\u0026#39;}); }); app.get(\u0026#39;/jsonp\u0026#39;, function (req, res, next) { //客户端请求时，需要带上callback=test res.jsonp(\u0026#39;hello\u0026#39;); }); app.get(\u0026#39;/redirect\u0026#39;, function (req, res, next) { //重定向到一个地址 res.redirect(\u0026#39;http://www.baidu.com\u0026#39;); }); app.get(\u0026#39;/sendfile\u0026#39;, function (req, res, next) { //发送一个文件 res.sendFile(path.resolve(\u0026#39;./1.txt\u0026#39;)); }); app.get(\u0026#39;/sendstatus\u0026#39;, function (req, res, next) { //发送一个状态码 res.sendStatus(302); }); //监听端口 app.listen(8888, function () { console.log(\u0026#39;port : 8888\u0026#39;); }); 六、ejs模板的使用 支持express的模板有很多种，这里我们使用ejs作为模板引擎。 安装ejs: npm install ejs 使用ejs模板 const path = require(\u0026#39;path\u0026#39;); const express = require(\u0026#39;express\u0026#39;); //创建一个应用 let app = express(); //设置模板引擎 app.set(\u0026#39;view engine\u0026#39;, \u0026#39;ejs\u0026#39;); //设置模板目录 app.set(\u0026#39;views\u0026#39;, path.join(__dirname, \u0026#39;views\u0026#39;)); //监听 app.listen(8888); 如果我们希望，ejs能够渲染html页面，可以使用如下 const path = require(\u0026#39;path\u0026#39;); const express = require(\u0026#39;express\u0026#39;); let app = express(); //设置视图引擎为html引擎 app.set(\u0026#39;view engine\u0026#39;, \u0026#39;html\u0026#39;); //设置视图的路径 app.set(\u0026#39;views\u0026#39;, path.join(__dirname, \u0026#39;views\u0026#39;)); //配置html引擎 app.engine(\u0026#39;html\u0026#39;, require(\u0026#39;ejs\u0026#39;).__express); app.listen(8888); 渲染视图，输出内容。 const path = require(\u0026#39;path\u0026#39;); const express = require(\u0026#39;express\u0026#39;); let app = express(); app.set(\u0026#39;view engine\u0026#39;, \u0026#39;html\u0026#39;); app.set(\u0026#39;views\u0026#39;, path.join(__dirname, \u0026#39;views\u0026#39;)); app.engine(\u0026#39;html\u0026#39;, require(\u0026#39;ejs\u0026#39;).__express); app.get(\u0026#39;/hello\u0026#39;, function (req, res, next) { //参数一表示模板的名称，会在当前项目目录下的views目录查找 //参数二表示传入模板中的数据 res.render(\u0026#39;hello\u0026#39;, { name: \u0026#39;xiaoxu\u0026#39;, age: 24 }); }); app.listen(8888); hello.html的代码： \u0026amp;lt;!doctype html\u0026gt; \u0026amp;lt;html lang=\u0026#34;zh-CN\u0026#34;\u0026gt; \u0026amp;lt;head\u0026gt; \u0026amp;lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026gt; \u0026amp;lt;title\u0026gt;Document\u0026amp;lt;/title\u0026gt; \u0026amp;lt;/head\u0026gt; \u0026amp;lt;body\u0026gt; \u0026amp;lt;%= name %\u0026gt; \u0026amp;lt;%= age %\u0026gt; \u0026amp;lt;/body\u0026gt; \u0026amp;lt;/html\u0026gt; 七、静态文件服务器 有些时候我们需要在页面上加载css，js，img等静态资源，指定存放静态资源的目录，浏览器发出非html文件请求时，服务器会到这个目录下找对应的资源。 const path = require(\u0026#39;path\u0026#39;); const express = require(\u0026#39;express\u0026#39;); let app = express(); app.set(\u0026#39;view engine\u0026#39;, \u0026#39;html\u0026#39;); app.set(\u0026#39;views\u0026#39;, path.join(__dirname, \u0026#39;views\u0026#39;)); app.engine(\u0026#39;html\u0026#39;, require(\u0026#39;ejs\u0026#39;).__express); //注意express.static这个中间件是express内置的 app.use(express.static(path.join(__dirname, \u0026#39;public\u0026#39;))); app.get(\u0026#39;/hello\u0026#39;, function (req, res, next) { //参数一表示模板的名称，会在当前项目目录下的views目录查找 //参数二表示传入模板中的数据 res.render(\u0026#39;hello\u0026#39;, { name: \u0026#39;xiaoxu\u0026#39;, age: 24 }); }); app.listen(8888); 八、使用body-parser中间件解析post过来的数据 安装body-parser npm install body-parser 使用body-parser const path = require(\u0026#39;path\u0026#39;); const express = require(\u0026#39;express\u0026#39;); const bodyParser = require(\u0026#39;body-parser\u0026#39;); let app = express(); app.set(\u0026#39;view engine\u0026#39;, \u0026#39;html\u0026#39;); app.set(\u0026#39;views\u0026#39;, path.join(__dirname, \u0026#39;views\u0026#39;)); app.engine(\u0026#39;html\u0026#39;, require(\u0026#39;ejs\u0026#39;).__express); //解析 application/json app.use(bodyParser.json()); //解析 application/x-www-form-urlencoded app.use(bodyParser.urlencoded({extended:false})); app.post(\u0026#39;/form\u0026#39;, function (req, res) { console.log(req.body); }); app.listen(8888);` ","permalink":"https://blog.zdltech.com/posts/node-js%E4%B8%ADexpress%E6%A1%86%E6%9E%B6%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/","summary":"\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`express是一个基于node\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ejs平台的，快速，开放，极简的web开发框架。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e一、安装 express\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enpm install express \u003cspan style=\"color:#ff79c6\"\u003e--\u003c/span\u003esave\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e二、简单使用 express\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e引入express\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e创建一个应用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e匹配GET请求路径设置回调函数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/hello\u0026#39;\u003c/span\u003e, function (req, res) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eend(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;hello\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e监听端口\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e, function () {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;port : 8888\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e通过访问 localhost:\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ehello 我们就可以看到内容输出了。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e当然 express 还支持其他的一些请求方法，比如 app\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epost()，app\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eput()，app\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edelete()，app\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ehead() 等。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e引入express\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e创建一个应用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e匹配POST请求\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epost(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/hello\u0026#39;\u003c/span\u003e, function (req, res) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eend(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;post hello\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e监听端口\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e, function () {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;port : 8888\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e如果我们想要匹配所有的请求路径，可以使用通配符 \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 号。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e引入express\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e创建一个应用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/hello\u0026#39;\u003c/span\u003e, function (req, res) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eend(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;hello\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//*\u003c/span\u003e号匹配所有路径\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;*\u0026#39;\u003c/span\u003e, function (req, res) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eend(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;not found\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e监听端口\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e, function () {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;port : 8888\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eexpress 还提供了 all() 方法，可以匹配所有请求方法。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e引入express\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e创建一个应用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e匹配所有请求方法\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eall(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/hello\u0026#39;\u003c/span\u003e, function (req, res) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eend(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;all hello\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e监听端口\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e, function () {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;port : 8888\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e　　\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e三、express 中间件的概念\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eexpress中间件就是处理http请求的函数，用来完成一些特定的操作，比如登陆检查，权限控制等等。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e、一个中间件处理完请求和响应，可以把数据传递给下一个中间件。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e、在回调函数中使用 next()，就可以让请求继续向下传递。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e、通过不同路径，分别执行不同的中间件。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e我们可以使用 use() ，在路由数组中添加一个中间件。注意我们设置的路由路径最终会存放在一个数组里，由上到下的把路径加入这个数组中。 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e引入express\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e创建一个应用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e如果没有设置路径，则会匹配全部\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003euse(function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;匹配全部路径\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e注意这里如果不调用next()，则请求并不会向下传递。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    next();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003euse(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/hello\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;use hello\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    next();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/hello\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;get hello\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    next();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e监听端口\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e, function () {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;port : 8888\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enext() 函数可以传入一个参数，表示错误信息，默认将执行错误中间件。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e引入express\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e创建一个应用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/hello\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;get hello\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    next(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;error!!!\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e注意错误处理中间件的参数是\u003cspan style=\"color:#bd93f9\"\u003e4\u003c/span\u003e个\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003euse(function (err, req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(err);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eend(err);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e监听端口\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e, function () {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;port : 8888\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e　　\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e四、express中的request对象\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e在express中对原生的req请求对象进行了扩展，添加了一些属性和方法。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e引入express\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e创建一个应用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/hello\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e主机名\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewrite(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;req.hostname : \u0026#39;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e req\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ehostname \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\r\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e请求URL的路径\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewrite(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;req.path : \u0026#39;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e req\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epath \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\r\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e查询字符串对象\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewrite(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;req.query : \u0026#39;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e JSON\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003estringify(req\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003equery) \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\r\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e请求的远程IP地址\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewrite(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;req.ip : \u0026#39;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e req\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eip \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\r\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e请求方法\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewrite(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;req.method : \u0026#39;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e req\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emethod \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\r\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eend();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e监听端口\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e, function () {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;port : 8888\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e通过 req\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eparams 获取路径里的参数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e引入express\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e创建一个应用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/list/:key/:page/:size\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e注意，设置了多少参数，地址就需要传入多少参数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eend(JSON\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003estringify(req\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eparams));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e监听端口\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e, function () {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;port : 8888\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e　　\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e五、express中的response对象\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eexpress中也对原生的res对象进行了扩展，添加了一些属性和方法。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e path \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;path\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e引入express\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e创建一个应用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/send/str\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003esend方法会自动判断数据类型，并进行相应的head信息设置\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e如果参数是字符串，则Content\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eType为 text\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ehtml\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esend(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;hello, world\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/send/arr\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e如果参数是一个数组，则返回json\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esend(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003e\u003cspan style=\"color:#6272a4\"\u003e#91;1, 2, 3]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/send/obj\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e如果参数是一个对象，则返回json\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esend({name: \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;xiaoxu\u0026#39;\u003c/span\u003e, age: \u003cspan style=\"color:#bd93f9\"\u003e24\u003c/span\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/send/number\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e如果是一个数字，则返回相应状态码短语\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esend(\u003cspan style=\"color:#bd93f9\"\u003e404\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/download\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e提示下载文件\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edownload(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;./1.txt\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/json\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e响应json对象\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ejson({name: \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;xiaoxu\u0026#39;\u003c/span\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/jsonp\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e客户端请求时，需要带上callback\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003etest\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ejsonp(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;hello\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/redirect\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e重定向到一个地址\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eredirect(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;http://www.baidu.com\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/sendfile\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e发送一个文件\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esendFile(path\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eresolve(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;./1.txt\u0026#39;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/sendstatus\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e发送一个状态码\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esendStatus(\u003cspan style=\"color:#bd93f9\"\u003e302\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e监听端口\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e, function () {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;port : 8888\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e　　\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e六、ejs模板的使用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e支持express的模板有很多种，这里我们使用ejs作为模板引擎。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e安装ejs:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enpm install ejs\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e使用ejs模板\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e path \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;path\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e创建一个应用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e设置模板引擎\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;view engine\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;ejs\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e设置模板目录\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;views\u0026#39;\u003c/span\u003e, path\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ejoin(__dirname, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;views\u0026#39;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e监听\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e如果我们希望，ejs能够渲染html页面，可以使用如下\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e path \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;path\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e设置视图引擎为html引擎\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;view engine\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;html\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e设置视图的路径\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;views\u0026#39;\u003c/span\u003e, path\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ejoin(__dirname, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;views\u0026#39;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e配置html引擎\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eengine(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;html\u0026#39;\u003c/span\u003e, require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;ejs\u0026#39;\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e__express);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e渲染视图，输出内容。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e path \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;path\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;view engine\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;html\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;views\u0026#39;\u003c/span\u003e, path\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ejoin(__dirname, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;views\u0026#39;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eengine(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;html\u0026#39;\u003c/span\u003e, require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;ejs\u0026#39;\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e__express);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/hello\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e参数一表示模板的名称，会在当前项目目录下的views目录查找\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e参数二表示传入模板中的数据\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003erender(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;hello\u0026#39;\u003c/span\u003e, {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        name: \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;xiaoxu\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        age: \u003cspan style=\"color:#bd93f9\"\u003e24\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    });\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehello\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ehtml的代码：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003edoctype html\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;html lang\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;zh-CN\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;head\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;meta charset\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;UTF-8\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;title\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eDocument\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003etitle\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ehead\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;body\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e%=\u003c/span\u003e name \u003cspan style=\"color:#ff79c6\"\u003e%\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e%=\u003c/span\u003e age \u003cspan style=\"color:#ff79c6\"\u003e%\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ebody\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ehtml\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e　　\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e七、静态文件服务器\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e有些时候我们需要在页面上加载css，js，img等静态资源，指定存放静态资源的目录，浏览器发出非html文件请求时，服务器会到这个目录下找对应的资源。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e path \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;path\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;view engine\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;html\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;views\u0026#39;\u003c/span\u003e, path\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ejoin(__dirname, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;views\u0026#39;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eengine(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;html\u0026#39;\u003c/span\u003e, require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;ejs\u0026#39;\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e__express);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e注意express\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003estatic这个中间件是express内置的\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003euse(express\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e(path\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ejoin(__dirname, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;public\u0026#39;\u003c/span\u003e)));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/hello\u0026#39;\u003c/span\u003e, function (req, res, next) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e参数一表示模板的名称，会在当前项目目录下的views目录查找\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e参数二表示传入模板中的数据\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003erender(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;hello\u0026#39;\u003c/span\u003e, {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        name: \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;xiaoxu\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        age: \u003cspan style=\"color:#bd93f9\"\u003e24\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    });\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e　　\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e八、使用body\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eparser中间件解析post过来的数据\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e安装body\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eparser\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enpm install body\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eparser\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e使用body\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eparser\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e path \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;path\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e express \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;express\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e bodyParser \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;body-parser\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elet app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e express();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;view engine\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;html\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;views\u0026#39;\u003c/span\u003e, path\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ejoin(__dirname, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;views\u0026#39;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eengine(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;html\u0026#39;\u003c/span\u003e, require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;ejs\u0026#39;\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e__express);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e解析 application\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ejson\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003euse(bodyParser\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ejson());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e解析 application\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ex\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ewww\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eform\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eurlencoded\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003euse(bodyParser\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eurlencoded({extended:\u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e}));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epost(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;/form\u0026#39;\u003c/span\u003e, function (req, res) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(req\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ebody);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e8888\u003c/span\u003e);`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"node.js中express框架的基本使用"},{"content":"Java版本 `import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Signature; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public class CreateSecretKey { public static final String KEY_ALGORITHM = \u0026#34;RSA\u0026#34;; private static final String PUBLIC_KEY = \u0026#34;RSAPublicKey\u0026#34;; private static final String PRIVATE_KEY = \u0026#34;RSAPrivateKey\u0026#34;; public static final String SIGNATURE_ALGORITHM=\u0026#34;MD5withRSA\u0026#34;; /** * RSA最大加密明文大小 */ private static final int MAX_ENCRYPT_BLOCK = 117; /** * RSA最大解密密文大小 */ private static final int MAX_DECRYPT_BLOCK = 128; //获得公钥字符串 public static String getPublicKeyStr(Map\u0026amp;lt;String, Object\u0026gt; keyMap) throws Exception { //获得map中的公钥对象 转为key对象 Key key = (Key) keyMap.get(PUBLIC_KEY); //编码返回字符串 return encryptBASE64(key.getEncoded()); } //获得私钥字符串 public static String getPrivateKeyStr(Map\u0026amp;lt;String, Object\u0026gt; keyMap) throws Exception { //获得map中的私钥对象 转为key对象 Key key = (Key) keyMap.get(PRIVATE_KEY); //编码返回字符串 return encryptBASE64(key.getEncoded()); } //获取公钥 public static PublicKey getPublicKey(String key) throws Exception { byte\u0026amp;#91;] keyBytes; keyBytes = (new BASE64Decoder()).decodeBuffer(key); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PublicKey publicKey = keyFactory.generatePublic(keySpec); return publicKey; } //获取私钥 public static PrivateKey getPrivateKey(String key) throws Exception { byte\u0026amp;#91;] keyBytes; keyBytes = (new BASE64Decoder()).decodeBuffer(key); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PrivateKey privateKey = keyFactory.generatePrivate(keySpec); return privateKey; } //解码返回byte public static byte\u0026amp;#91;] decryptBASE64(String key) throws Exception { return (new BASE64Decoder()).decodeBuffer(key); } //编码返回字符串 public static String encryptBASE64(byte\u0026amp;#91;] key) throws Exception { return (new BASE64Encoder()).encodeBuffer(key); } //***************************签名和验证******************************* public static byte\u0026amp;#91;] sign(byte\u0026amp;#91;] data,String privateKeyStr) throws Exception{ PrivateKey priK = getPrivateKey(privateKeyStr); Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM); sig.initSign(priK); sig.update(data); return sig.sign(); } public static boolean verify(byte\u0026amp;#91;] data,byte\u0026amp;#91;] sign,String publicKeyStr) throws Exception{ PublicKey pubK = getPublicKey(publicKeyStr); Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM); sig.initVerify(pubK); sig.update(data); return sig.verify(sign); } //************************加密解密************************** public static byte\u0026amp;#91;] encrypt(byte\u0026amp;#91;] plainText,String publicKeyStr)throws Exception{ PublicKey publicKey = getPublicKey(publicKeyStr); Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, publicKey); int inputLen = plainText.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; int i = 0; byte\u0026amp;#91;] cache; while (inputLen - offSet \u0026gt; 0) { if (inputLen - offSet \u0026gt; MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(plainText, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(plainText, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } byte\u0026amp;#91;] encryptText = out.toByteArray(); out.close(); return encryptText; } public static byte\u0026amp;#91;] decrypt(byte\u0026amp;#91;] encryptText,String privateKeyStr)throws Exception{ PrivateKey privateKey = getPrivateKey(privateKeyStr); Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, privateKey); int inputLen = encryptText.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte\u0026amp;#91;] cache; int i = 0; // 对数据分段解密 while (inputLen - offSet \u0026gt; 0) { if (inputLen - offSet \u0026gt; MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptText, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptText, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte\u0026amp;#91;] plainText = out.toByteArray(); out.close(); return plainText; } public static void main(String\u0026amp;#91;] args) { Map\u0026amp;lt;String, Object\u0026gt; keyMap; byte\u0026amp;#91;] cipherText; String input = \u0026#34;Hello World!\u0026#34;; try { keyMap = initKey(); String publicKey = getPublicKeyStr(keyMap); System.out.println(\u0026#34;公钥------------------\u0026#34;); System.out.println(publicKey); String privateKey = getPrivateKeyStr(keyMap); System.out.println(\u0026#34;私钥------------------\u0026#34;); System.out.println(privateKey); System.out.println(\u0026#34;测试可行性-------------------\u0026#34;); System.out.println(\u0026#34;明文=======\u0026#34;+input); cipherText = encrypt(input.getBytes(),publicKey); //加密后的东西 System.out.println(\u0026#34;密文=======\u0026#34;+new String(cipherText)); //开始解密 byte\u0026amp;#91;] plainText = decrypt(cipherText,privateKey); System.out.println(\u0026#34;解密后明文===== \u0026#34; + new String(plainText)); System.out.println(\u0026#34;验证签名-----------\u0026#34;); String str=\u0026#34;被签名的内容\u0026#34;; System.out.println(\u0026#34;\\n原文:\u0026#34;+str); byte\u0026amp;#91;] signature=sign(str.getBytes(),privateKey); boolean status=verify(str.getBytes(), signature,publicKey); System.out.println(\u0026#34;验证情况：\u0026#34;+status); } catch (Exception e) { e.printStackTrace(); } } }` Python `import rsa # 生成密钥 (pubkey, privkey) = rsa.newkeys(1024) # 保存密钥 with open(\u0026#39;public.pem\u0026#39;,\u0026#39;w+\u0026#39;) as f: f.write(pubkey.save_pkcs1().decode()) with open(\u0026#39;private.pem\u0026#39;,\u0026#39;w+\u0026#39;) as f: f.write(privkey.save_pkcs1().decode()) # 导入密钥 with open(\u0026#39;public.pem\u0026#39;,\u0026#39;r\u0026#39;) as f: pubkey = rsa.PublicKey.load_pkcs1(f.read().encode()) with open(\u0026#39;private.pem\u0026#39;,\u0026#39;r\u0026#39;) as f: privkey = rsa.PrivateKey.load_pkcs1(f.read().encode()) # 明文 message = \u0026#39;hello\u0026#39; # 公钥加密 crypto = rsa.encrypt(message.encode(), pubkey) # 私钥解密 message = rsa.decrypt(crypto, privkey).decode() print(message) # 私钥签名 signature = rsa.sign(message.encode(), privkey, \u0026#39;SHA-1\u0026#39;) # 公钥验证 rsa.verify(message.encode(), signature, pubkey)` ","permalink":"https://blog.zdltech.com/posts/%E5%A6%82%E4%BD%95%E7%94%A8-rsa%E7%94%9F%E6%88%90%E7%94%9F%E6%88%90%E5%85%AC%E9%92%A5%E7%A7%81%E9%92%A5%E9%9D%9E%E5%AF%B9%E7%A7%B0%E5%8A%A0%E5%AF%86/","summary":"\u003ch4 class=\"wp-block-heading\" id=\"java版本\"\u003eJava版本\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`import java.security.Key;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.KeyFactory;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.KeyPair;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.KeyPairGenerator;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.PrivateKey;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.PublicKey;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.SecureRandom;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.Signature;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.interfaces.RSAPrivateKey;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.interfaces.RSAPublicKey;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.spec.PKCS8EncodedKeySpec;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.spec.X509EncodedKeySpec;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.util.Date;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.util.HashMap;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.util.Map;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport javax.crypto.Cipher;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport sun.misc.BASE64Decoder;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport sun.misc.BASE64Encoder;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic class CreateSecretKey {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static final String KEY_ALGORITHM = \u0026#34;RSA\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private static final String PUBLIC_KEY = \u0026#34;RSAPublicKey\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private static final String PRIVATE_KEY = \u0026#34;RSAPrivateKey\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static final String SIGNATURE_ALGORITHM=\u0026#34;MD5withRSA\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * RSA最大加密明文大小\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private static final int MAX_ENCRYPT_BLOCK = 117;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * RSA最大解密密文大小\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private static final int MAX_DECRYPT_BLOCK = 128;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    //获得公钥字符串\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static String getPublicKeyStr(Map\u0026amp;lt;String, Object\u0026gt; keyMap) throws Exception {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        //获得map中的公钥对象 转为key对象\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Key key = (Key) keyMap.get(PUBLIC_KEY);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        //编码返回字符串\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return encryptBASE64(key.getEncoded());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    //获得私钥字符串\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static String getPrivateKeyStr(Map\u0026amp;lt;String, Object\u0026gt; keyMap) throws Exception {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        //获得map中的私钥对象 转为key对象\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Key key = (Key) keyMap.get(PRIVATE_KEY);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        //编码返回字符串\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return encryptBASE64(key.getEncoded());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    //获取公钥\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static PublicKey getPublicKey(String key) throws Exception {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        byte\u0026amp;#91;] keyBytes;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        keyBytes = (new BASE64Decoder()).decodeBuffer(key);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        PublicKey publicKey = keyFactory.generatePublic(keySpec);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return publicKey;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    //获取私钥\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static PrivateKey getPrivateKey(String key) throws Exception {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        byte\u0026amp;#91;] keyBytes;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        keyBytes = (new BASE64Decoder()).decodeBuffer(key);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return privateKey;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    //解码返回byte\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static byte\u0026amp;#91;] decryptBASE64(String key) throws Exception {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return (new BASE64Decoder()).decodeBuffer(key);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    //编码返回字符串\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static String encryptBASE64(byte\u0026amp;#91;] key) throws Exception {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return (new BASE64Encoder()).encodeBuffer(key);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    //***************************签名和验证*******************************  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static byte\u0026amp;#91;] sign(byte\u0026amp;#91;] data,String privateKeyStr) throws Exception{  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      PrivateKey priK = getPrivateKey(privateKeyStr);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      sig.initSign(priK);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      sig.update(data);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      return sig.sign();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static boolean verify(byte\u0026amp;#91;] data,byte\u0026amp;#91;] sign,String publicKeyStr) throws Exception{  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      PublicKey pubK = getPublicKey(publicKeyStr);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      sig.initVerify(pubK);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      sig.update(data);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      return sig.verify(sign);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  //************************加密解密**************************  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static byte\u0026amp;#91;] encrypt(byte\u0026amp;#91;] plainText,String publicKeyStr)throws Exception{  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        PublicKey publicKey = getPublicKey(publicKeyStr);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        cipher.init(Cipher.ENCRYPT_MODE, publicKey);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        int inputLen = plainText.length;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ByteArrayOutputStream out = new ByteArrayOutputStream();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        int offSet = 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        int i = 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        byte\u0026amp;#91;] cache;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        while (inputLen - offSet \u0026gt; 0) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            if (inputLen - offSet \u0026gt; MAX_ENCRYPT_BLOCK) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                cache = cipher.doFinal(plainText, offSet, MAX_ENCRYPT_BLOCK);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            } else {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                cache = cipher.doFinal(plainText, offSet, inputLen - offSet);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            out.write(cache, 0, cache.length);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            i++;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            offSet = i * MAX_ENCRYPT_BLOCK;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        byte\u0026amp;#91;] encryptText = out.toByteArray();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        out.close();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return encryptText;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static byte\u0026amp;#91;] decrypt(byte\u0026amp;#91;] encryptText,String privateKeyStr)throws Exception{  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        PrivateKey privateKey = getPrivateKey(privateKeyStr);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        cipher.init(Cipher.DECRYPT_MODE, privateKey);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        int inputLen = encryptText.length;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ByteArrayOutputStream out = new ByteArrayOutputStream();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        int offSet = 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        byte\u0026amp;#91;] cache;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        int i = 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        // 对数据分段解密\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        while (inputLen - offSet \u0026gt; 0) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            if (inputLen - offSet \u0026gt; MAX_DECRYPT_BLOCK) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                cache = cipher.doFinal(encryptText, offSet, MAX_DECRYPT_BLOCK);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            } else {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                cache = cipher.doFinal(encryptText, offSet, inputLen - offSet);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            out.write(cache, 0, cache.length);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            i++;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            offSet = i * MAX_DECRYPT_BLOCK;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        byte\u0026amp;#91;] plainText = out.toByteArray();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        out.close();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return plainText;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static void main(String\u0026amp;#91;] args) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Map\u0026amp;lt;String, Object\u0026gt; keyMap;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        byte\u0026amp;#91;] cipherText;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String input = \u0026#34;Hello World!\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        try {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            keyMap = initKey();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            String publicKey = getPublicKeyStr(keyMap);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            System.out.println(\u0026#34;公钥------------------\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            System.out.println(publicKey);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            String privateKey = getPrivateKeyStr(keyMap);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            System.out.println(\u0026#34;私钥------------------\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            System.out.println(privateKey);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            System.out.println(\u0026#34;测试可行性-------------------\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            System.out.println(\u0026#34;明文=======\u0026#34;+input);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            cipherText = encrypt(input.getBytes(),publicKey); \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            //加密后的东西 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            System.out.println(\u0026#34;密文=======\u0026#34;+new String(cipherText));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            //开始解密 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            byte\u0026amp;#91;] plainText = decrypt(cipherText,privateKey); \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            System.out.println(\u0026#34;解密后明文===== \u0026#34; + new String(plainText));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            System.out.println(\u0026#34;验证签名-----------\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            String str=\u0026#34;被签名的内容\u0026#34;;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            System.out.println(\u0026#34;\\n原文:\u0026#34;+str);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            byte\u0026amp;#91;] signature=sign(str.getBytes(),privateKey);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            boolean status=verify(str.getBytes(), signature,publicKey);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            System.out.println(\u0026#34;验证情况：\u0026#34;+status);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } catch (Exception e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            e.printStackTrace();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 class=\"wp-block-heading\" id=\"python\"\u003ePython \u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`import rsa\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 生成密钥\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e(pubkey, privkey) \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rsa\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003enewkeys(\u003cspan style=\"color:#bd93f9\"\u003e1024\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 保存密钥\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewith open(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;public.pem\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;w+\u0026#39;\u003c/span\u003e) as f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    f\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewrite(pubkey\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esave_pkcs1()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edecode())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewith open(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;private.pem\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;w+\u0026#39;\u003c/span\u003e) as f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    f\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewrite(privkey\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esave_pkcs1()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edecode())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 导入密钥\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewith open(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;public.pem\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e) as f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    pubkey \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rsa\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ePublicKey\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eload_pkcs1(f\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eread()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eencode())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewith open(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;private.pem\u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e) as f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    privkey \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rsa\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ePrivateKey\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eload_pkcs1(f\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eread()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eencode())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 明文\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emessage \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;hello\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 公钥加密\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecrypto \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rsa\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eencrypt(message\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eencode(), pubkey)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 私钥解密\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emessage \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rsa\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edecrypt(crypto, privkey)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edecode()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(message)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 私钥签名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esignature \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rsa\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esign(message\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eencode(), privkey, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;SHA-1\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# 公钥验证\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ersa\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003everify(message\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eencode(), signature, pubkey)`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"如何用 RSA生成生成公钥私钥（非对称加密）"},{"content":"java保留两位小数\n1.使用java类库中自带的DecimalFormat类，使数字输出结果保留2位小数\n代码如下:\n运行结果如下:\n2.\n输出结果为:\nString.format表示字符串的格式化\n3.使用BigDecimal四舍五入方法\n需要导入BigDecimal类:import java.math.BigDecimal;\n输出结果为:\n1：scale指的是你小数点后的位数。比如123.456则score就是3.\nscore()就是BigDecimal类中的方法啊。\n比如:BigDecimal b = new BigDecimal(“123.456”);\nb.scale(),返回的就是3.\n2：roundingMode是小数的保留模式。它们都是BigDecimal中的常量字段,有很多种。\n比如：BigDecimal.ROUND_HALF_UP表示的就是4舍5入。\nsetScale(1)表示保留一位小数，默认用四舍五入方式\nsetScale(1,BigDecimal.ROUND_DOWN)直接删除多余的小数位，如2.35会变成2.3\nsetScale(1,BigDecimal.ROUND_UP)进位处理，2.35变成2.4\nsetScale(1,BigDecimal.ROUND_HALF_UP)四舍五入，2.35变成2.4\nsetScaler(1,BigDecimal.ROUND_HALF_DOWN)四舍五入，2.35变成2.3，如果是5则向下舍\nBigDecimal的用法详解(保留两位小数,四舍五入,数字格式化，科学计数法转数字，数字里的逗号处理） 一、简介\nJava在java.math包中提供的API类BigDecimal，用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中，需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算，在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象，我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算，而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法，专门用来创建对象，特别是带有参数的对象。\n二、构造器描述\nBigDecimal(int) 创建一个具有参数所指定整数值的对象。\nBigDecimal(double) 创建一个具有参数所指定双精度值的对象。\nBigDecimal(long) 创建一个具有参数所指定长整数值的对象。\nBigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。\n三、方法描述\nadd(BigDecimal) BigDecimal对象中的值相加，然后返回这个对象。\nsubtract(BigDecimal) BigDecimal对象中的值相减，然后返回这个对象。\nmultiply(BigDecimal) BigDecimal对象中的值相乘，然后返回这个对象。\ndivide(BigDecimal) BigDecimal对象中的值相除，然后返回这个对象。\ntoString() 将BigDecimal对象的数值转换成字符串。\ndoubleValue() 将BigDecimal对象中的值以双精度数返回。\nfloatValue() 将BigDecimal对象中的值以单精度数返回。\nlongValue() 将BigDecimal对象中的值以长整数返回。\nintValue() 将BigDecimal对象中的值以整数返回。\n四、常用方法\n4.1、保留两位小数\n/**\n保留两位小数\n*/\n@org.junit.Test\npublic void formatTest() {\ndouble num=13.154215; ` //方式一 DecimalFormat df1 = new DecimalFormat(\u0026#34;0.00\u0026#34;); String str = df1.format(num); System.out.println(str); //13.15 //方式二 // #.00 表示两位小数 #.0000四位小数 DecimalFormat df2 =new DecimalFormat(\u0026#34;#.00\u0026#34;); String str2 =df2.format(num); System.out.println(str2); //13.15 //方式三 //%.2f %. 表示 小数点前任意位数 2 表示两位小数 格式后的结果为f 表示浮点型 String result = String.format(\u0026#34;%.2f\u0026#34;, num); System.out.println(result); //13.15 }` String.formate用法详解：\n`@Test public void test1() { //4.1541483776749997E9 double a = 4887233385.5; double b = 0.85; System.out.println(\u0026#34;result1--\u0026gt;\u0026#34;+a*b); // result1--\u0026gt;4.1541483776749997E9 BigDecimal a1 = new BigDecimal(a); BigDecimal b1 = new BigDecimal(b); System.out.println(\u0026#34;result2--\u0026gt;\u0026#34;+a1.multiply(b1));//result2--\u0026gt;4154148377.674999891481619无限不循环 BigDecimal aBigDecimal = new BigDecimal(String.valueOf(a)); BigDecimal bBigDecimal = new BigDecimal(String.valueOf(b)); // 或者下面这种写法` // BigDecimal aBigDecimal = new BigDecimal(Double.toString(a));\n// BigDecimal bBigDecimal = new BigDecimal(Double.toString(b));\n` System.out.println(\u0026#34;result3--\u0026gt;\u0026#34;+aBigDecimal.multiply(bBigDecimal)); //result3--\u0026gt;4154148377.675 }` 4.2、四舍五入\n/**\n四舍五入\n*/\n@Test\npublic void test2() {\ndouble num = 111231.5585;\nBigDecimal b = new BigDecimal(num);\n//保留2位小数\ndouble result = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();\nSystem.out.println(result); //111231.56\n}\nBigDecimal.setScale()方法用于格式化小数点\nsetScale(1)表示保留一位小数，默认用四舍五入方式 setScale(1,BigDecimal.ROUND_DOWN)直接删除多余的小数位，如2.35会变成2.3 setScale(1,BigDecimal.ROUND_UP)进位处理，2.35变成2.4 setScale(1,BigDecimal.ROUND_HALF_UP)四舍五入，2.35变成2.4 setScaler(1,BigDecimal.ROUND_HALF_DOWN)四舍五入，2.35变成2.3，如果是5则向下舍\nsetScaler(1,BigDecimal.ROUND_CEILING)接近正无穷大的舍入\nsetScaler(1,BigDecimal.ROUND_FLOOR)接近负无穷大的舍入，数字\u0026gt;0和ROUND_UP作用一样，数字\u0026lt;0和ROUND_DOWN作用一样\nsetScaler(1,BigDecimal.ROUND_HALF_EVEN)向最接近的数字舍入，如果与两个相邻数字的距离相等，则向相邻的偶数舍入。\n注释：\n1：scale指的是你小数点后的位数。比如123.456则score就是3.\nscore()就是BigDecimal类中的方法啊。\n比如:BigDecimal b = new BigDecimal(“123.456”);\nb.scale(),返回的就是3.\n2：roundingMode是小数的保留模式。它们都是BigDecimal中的常量字段,有很多种。\n比如：BigDecimal.ROUND_HALF_UP表示的就是4舍5入。\n3：pubilc BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)\n的意思是说：我用一个BigDecimal对象除以divisor后的结果，并且要求这个结果保留有scale个小数位，roundingMode表示的就是保留模式是什么，是四舍五入啊还是其它的，你可以自己选！\n4：对于一般add、subtract、multiply方法的小数位格式化如下：\nBigDecimal mData = new BigDecimal(“9.655”).setScale(2, BigDecimal.ROUND_HALF_UP);\nSystem.out.println(“mData=” + mData);\n—-结果：—– mData=9.66\n4.3、格式化\n由于NumberFormat类的format()方法可以使用BigDecimal对象作为其参数，可以利用BigDecimal对超出16位有效数字的货币值，百分值，以及一般数值进行格式化控制。\n`/** * 格式化 */ @Test public void test3() { NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立货币格式化引用 NumberFormat percent = NumberFormat.getPercentInstance(); //建立百分比格式化引用 percent.setMaximumFractionDigits(3); //百分比小数点最多3位 BigDecimal loanAmount = new BigDecimal(\u0026#34;150.48\u0026#34;); //贷款金额 BigDecimal interestRate = new BigDecimal(\u0026#34;0.008\u0026#34;); //利率 BigDecimal interest = loanAmount.multiply(interestRate); //相乘 System.out.println(\u0026#34;贷款金额:\\t\u0026#34; + currency.format(loanAmount)); //贷款金额: ￥150.48 System.out.println(\u0026#34;利率:\\t\u0026#34; + percent.format(interestRate)); //利率: 0.8% System.out.println(\u0026#34;利息:\\t\u0026#34; + currency.format(interest)); //利息: ￥1.20 } @Test public void test3() { DecimalFormat df = new DecimalFormat(); double data = 1234.56789; //格式化之前的数字 //1、定义要显示的数字的格式（这种方式会四舍五入） String style = \u0026#34;0.0\u0026#34;; df.applyPattern(style); System.out.println(\u0026#34;1--\u0026gt;\u0026#34; + df.format(data)); //1234.6 //2、在格式后添加诸如单位等字符 style = \u0026#34;00000.000 kg\u0026#34;; df.applyPattern(style); System.out.println(\u0026#34;2--\u0026gt;\u0026#34; + df.format(data)); //01234.568 kg //3、 模式中的\u0026#34;#\u0026#34;表示如果该位存在字符，则显示字符，如果不存在，则不显示。 style = \u0026#34;##000.000 kg\u0026#34;; df.applyPattern(style); System.out.println(\u0026#34;3--\u0026gt;\u0026#34; + df.format(data)); //1234.568 kg //4、 模式中的\u0026#34;-\u0026#34;表示输出为负数，要放在最前面 style = \u0026#34;-000.000\u0026#34;; df.applyPattern(style); System.out.println(\u0026#34;4--\u0026gt;\u0026#34; + df.format(data)); //-1234.568 //5、 模式中的\u0026#34;,\u0026#34;在数字中添加逗号，方便读数字 style = \u0026#34;-0,000.0#\u0026#34;; df.applyPattern(style); System.out.println(\u0026#34;5--\u0026gt;\u0026#34; + df.format(data)); //5--\u0026gt;-1,234.57 //6、模式中的\u0026#34;E\u0026#34;表示输出为指数，\u0026#34;E\u0026#34;之前的字符串是底数的格式， // \u0026#34;E\u0026#34;之后的是字符串是指数的格式 style = \u0026#34;0.00E000\u0026#34;; df.applyPattern(style); System.out.println(\u0026#34;6--\u0026gt;\u0026#34; + df.format(data)); //6--\u0026gt;1.23E003 //7、 模式中的\u0026#34;%\u0026#34;表示乘以100并显示为百分数，要放在最后。 style = \u0026#34;0.00%\u0026#34;; df.applyPattern(style); System.out.println(\u0026#34;7--\u0026gt;\u0026#34; + df.format(data)); //7--\u0026gt;123456.79% //8、 模式中的\u0026#34;\\u2030\u0026#34;表示乘以1000并显示为千分数，要放在最后。 style = \u0026#34;0.00\\u2030\u0026#34;; //在构造函数中设置数字格式 DecimalFormat df1 = new DecimalFormat(style); //df.applyPattern(style); System.out.println(\u0026#34;8--\u0026gt;\u0026#34; + df1.format(data)); //8--\u0026gt;1234567.89‰ }` 4.4、BigDecimal比较\nBigDecimal是通过使用compareTo(BigDecimal)来比较的，具体比较情况如下：\n`/** * 注意不能使用equals方法来比较大小。 * * 使用BigDecimal的坏处是性能比double和float差，在处理庞大，复杂的运算时尤为明显，因根据实际需求决定使用哪种类型。 */ @Test public void test4() { BigDecimal a = new BigDecimal(\u0026#34;1\u0026#34;); BigDecimal b = new BigDecimal(\u0026#34;2\u0026#34;); BigDecimal c = new BigDecimal(\u0026#34;1\u0026#34;); int result1 = a.compareTo(b); int result2 = a.compareTo(c); int result3 = b.compareTo(a); System.out.println(result1); //-1 System.out.println(result2); //0 System.out.println(result3); //1 }` 4.5、科学计数法\n有些项目可能会涉及到从Excel导入数据，但如果Excel里单元格类型为数值，但内容数据太长时（如银行账号），导入时，会默认读取为科学计数法，用以下代码便轻松解决。\n`@Test public void test5() { BigDecimal bd = new BigDecimal(\u0026#34;3.40256010353E11\u0026#34;); String result = bd.toPlainString(); System.out.println(result); //340256010353 }` 4.6、java中价格的数字中间有逗号的处理\n@Test\npublic void test1() {\njava.util.StringTokenizer st = new StringTokenizer( “123,456,789”, “,”);\nStringBuffer sb = new StringBuffer();\nwhile(st.hasMoreTokens()) {\nsb.append(st.nextToken());\n}\nSystem.out.println(sb); //123456789\n}\n`@Test public void test2() { String str = \u0026#34;123,456,789\u0026#34;; str = str.replace(\u0026#34;,\u0026#34;, \u0026#34;\u0026#34;); System.out.println(str); //123456789 }` 4.7.精确计算\ndouble value1=1.00;\nString value2 = “1.00”;\nBigDecimal b1 = new BigDecimal(Double.valueOf(value1));\nBigDecimal b1 = new BigDecimal(String.valueOf(value2));\npublic BigDecimal add(BigDecimal value); //加法\npublic BigDecimal subtract(BigDecimal value); //减法\npublic BigDecimal multiply(BigDecimal value); //乘法\npublic BigDecimal divide(BigDecimal value); //除法\n下面是一个工具类，该工具类提供加，减，乘，除运算。\npublic class Arith {\n/**\n提供精确加法计算的add方法 @param value1 被加数 @param value2 加数 @return 两个参数的和\n*/\npublic static double add(double value1,double value2){\nBigDecimal b1 = new BigDecimal(Double.valueOf(value1));\nBigDecimal b2 = new BigDecimal(Double.valueOf(value2));\nreturn b1.add(b2).doubleValue();\n} `/** * 提供精确减法运算的sub方法 * @param value1 被减数 * @param value2 减数 * @return 两个参数的差 */ public static double sub(double value1,double value2){ BigDecimal b1 = new BigDecimal(Double.valueOf(value1)); BigDecimal b2 = new BigDecimal(Double.valueOf(value2)); return b1.subtract(b2).doubleValue(); } /** * 提供精确乘法运算的mul方法 * @param value1 被乘数 * @param value2 乘数 * @return 两个参数的积 */ public static double mul(double value1,double value2){ BigDecimal b1 = new BigDecimal(Double.valueOf(value1)); BigDecimal b2 = new BigDecimal(Double.valueOf(value2)); return b1.multiply(b2).doubleValue(); } /** * 提供精确的除法运算方法div * @param value1 被除数 * @param value2 除数 * @param scale 精确范围 * @return 两个参数的商 * @throws IllegalAccessException */ public static double div(double value1,double value2,int scale) throws IllegalAccessException{ //如果精确范围小于0，抛出异常信息 if(scale\u0026amp;lt;0){ throw new IllegalAccessException(\u0026#34;精确度不能小于0\u0026#34;); } BigDecimal b1 = new BigDecimal(Double.valueOf(value1)); BigDecimal b2 = new BigDecimal(Double.valueOf(value2)); return b1.divide(b2, scale).doubleValue(); }` }\n转自：https://blog.csdn.net/ochangwen/article/details/51531866\nhttps://blog.csdn.net/SUNNY_PLAY/article/details/98944159\n","permalink":"https://blog.zdltech.com/posts/java%E4%BF%9D%E7%95%99%E4%B8%A4%E4%BD%8D%E5%B0%8F%E6%95%B0/","summary":"\u003cp\u003ejava保留两位小数\u003cbr\u003e\n1.使用java类库中自带的DecimalFormat类，使数字输出结果保留2位小数\u003cbr\u003e\n代码如下:\u003cfigure class=\"wp-block-image\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"在这里插入图片描述\" loading=\"lazy\" src=\"https://img-blog.csdnimg.cn/20190809104600398.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1NVTk5ZX1BMQVk=,size_16,color_FFFFFF,t_70\"\u003e \u003c/figure\u003e \u003cfigure class=\"wp-block-image\"\u003e\u003cimg alt=\"在这里插入图片描述\" loading=\"lazy\" src=\"https://img-blog.csdnimg.cn/20190809104954136.png\"\u003e\u003c/figure\u003e \u003cfigure class=\"wp-block-image\"\u003e\u003cimg alt=\"在这里插入图片描述\" loading=\"lazy\" src=\"https://img-blog.csdnimg.cn/20190809110011565.png\"\u003e\u003c/figure\u003e \u003cfigure class=\"wp-block-image\"\u003e\u003cimg alt=\"在这里插入图片描述\" loading=\"lazy\" src=\"https://img-blog.csdnimg.cn/20190809110027678.png\"\u003e\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e运行结果如下:\u003cbr\u003e\n2.\u003c/p\u003e\n\u003cp\u003e输出结果为:\u003c/p\u003e\n\u003cp\u003eString.format表示字符串的格式化\u003cfigure class=\"wp-block-image\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"在这里插入图片描述\" loading=\"lazy\" src=\"https://img-blog.csdnimg.cn/20190809111408131.png\"\u003e \u003c/figure\u003e \u003cfigure class=\"wp-block-image\"\u003e\u003cimg alt=\"在这里插入图片描述\" loading=\"lazy\" src=\"https://img-blog.csdnimg.cn/20190809111426325.png\"\u003e\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e3.使用BigDecimal四舍五入方法\u003c/p\u003e\n\u003cp\u003e需要导入BigDecimal类:import java.math.BigDecimal;\u003cbr\u003e\n输出结果为:\u003c/p\u003e\n\u003cp\u003e1：scale指的是你小数点后的位数。比如123.456则score就是3.\u003cbr\u003e\nscore()就是BigDecimal类中的方法啊。\u003cbr\u003e\n比如:BigDecimal b = new BigDecimal(“123.456”);\u003cbr\u003e\nb.scale(),返回的就是3.\u003cbr\u003e\n2：roundingMode是小数的保留模式。它们都是BigDecimal中的常量字段,有很多种。\u003cbr\u003e\n比如：BigDecimal.ROUND_HALF_UP表示的就是4舍5入。\u003cbr\u003e\nsetScale(1)表示保留一位小数，默认用四舍五入方式\u003cbr\u003e\nsetScale(1,BigDecimal.ROUND_DOWN)直接删除多余的小数位，如2.35会变成2.3\u003cbr\u003e\nsetScale(1,BigDecimal.ROUND_UP)进位处理，2.35变成2.4\u003cbr\u003e\nsetScale(1,BigDecimal.ROUND_HALF_UP)四舍五入，2.35变成2.4\u003cbr\u003e\nsetScaler(1,BigDecimal.ROUND_HALF_DOWN)四舍五入，2.35变成2.3，如果是5则向下舍\u003c/p\u003e\n\u003ch4 class=\"wp-block-heading\" id=\"bigdecimal的用法详解保留两位小数四舍五入数字格式化科学计数法转数字数字里的逗号处理\"\u003eBigDecimal的用法详解(保留两位小数,四舍五入,数字格式化，科学计数法转数字，数字里的逗号处理）\u003c/h4\u003e\n\u003cp\u003e一、简介\u003cbr\u003e\n    Java在java.math包中提供的API类BigDecimal，用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中，需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算，在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象，我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算，而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法，专门用来创建对象，特别是带有参数的对象。\u003c/p\u003e\n\u003cp\u003e二、构造器描述\u003cbr\u003e\nBigDecimal(int)       创建一个具有参数所指定整数值的对象。\u003cbr\u003e\nBigDecimal(double) 创建一个具有参数所指定双精度值的对象。\u003cbr\u003e\nBigDecimal(long)    创建一个具有参数所指定长整数值的对象。\u003cbr\u003e\nBigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。\u003c/p\u003e\n\u003cp\u003e三、方法描述\u003cbr\u003e\nadd(BigDecimal)        BigDecimal对象中的值相加，然后返回这个对象。\u003cbr\u003e\nsubtract(BigDecimal) BigDecimal对象中的值相减，然后返回这个对象。\u003cbr\u003e\nmultiply(BigDecimal)  BigDecimal对象中的值相乘，然后返回这个对象。\u003cbr\u003e\ndivide(BigDecimal)     BigDecimal对象中的值相除，然后返回这个对象。\u003cbr\u003e\ntoString()                将BigDecimal对象的数值转换成字符串。\u003cbr\u003e\ndoubleValue()          将BigDecimal对象中的值以双精度数返回。\u003cbr\u003e\nfloatValue()             将BigDecimal对象中的值以单精度数返回。\u003cbr\u003e\nlongValue()             将BigDecimal对象中的值以长整数返回。\u003cbr\u003e\nintValue()               将BigDecimal对象中的值以整数返回。\u003c/p\u003e\n\u003cp\u003e四、常用方法\u003cbr\u003e\n4.1、保留两位小数\u003cbr\u003e\n/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e保留两位小数\u003cbr\u003e\n*/\u003cbr\u003e\n@org.junit.Test\u003cbr\u003e\npublic void formatTest() {\u003cbr\u003e\ndouble num=13.154215;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`    //方式一\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    DecimalFormat df1 = new DecimalFormat(\u0026#34;0.00\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    String str = df1.format(num);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    System.out.println(str);  //13.15\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    //方式二\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    // #.00 表示两位小数 #.0000四位小数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    DecimalFormat df2 =new DecimalFormat(\u0026#34;#.00\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    String str2 =df2.format(num);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    System.out.println(str2);  //13.15\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    //方式三\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    //%.2f %. 表示 小数点前任意位数   2 表示两位小数 格式后的结果为f 表示浮点型\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    String result = String.format(\u0026#34;%.2f\u0026#34;, num);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    System.out.println(result);  //13.15\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eString.formate用法详解：\u003c/p\u003e","title":"java保留两位小数"},{"content":"koa2 中间件 koa2的中间件是通过 async await 实现的，中间件执行顺序是“洋葱圈”模型。\n中间件之间通过next函数联系,当一个中间件调用 next() 后，会将控制权交给下一个中间件, 直到下一个中间件不再执行 next() 后, 将会沿路折返,将控制权依次交换给前一个中间件。\n如图：\nkoa2 中间件实例 app.js:\n`const Koa = require(\u0026#39;koa\u0026#39;); const app = new Koa(); // logger app.use(async (ctx, next) =\u0026gt; { console.log(\u0026#39;第一层 - 开始\u0026#39;) await next(); const rt = ctx.response.get(\u0026#39;X-Response-Time\u0026#39;); console.log(`\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{ctx.method} -----------\u0026amp;lt;/span\u0026gt;{ctx.url} ----------- \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{rt}`); console.log(\u0026#39;第一层 - 结束\u0026#39;) }); // x-response-time app.use(async (ctx, next) =\u0026gt; { console.log(\u0026#39;第二层 - 开始\u0026#39;) const start = Date.now(); await next(); const ms = Date.now() - start; ctx.set(\u0026#39;X-Response-Time\u0026#39;, `\u0026amp;lt;/span\u0026gt;{ms}ms`); console.log(\u0026#39;第二层 - 结束\u0026#39;) }); // response app.use(async ctx =\u0026gt; { console.log(\u0026#39;第三层 - 开始\u0026#39;) ctx.body = \u0026#39;Hello World\u0026#39;; console.log(\u0026#39;第三层 - 结束\u0026#39;) }); app.listen(3000); ` 执行app.js后，浏览器访问 http://localhost:3000/text , 控制台输出结果：\n`第一层 - 开始 第二层 - 开始 第三层 - 开始 第三层 - 结束 第二层 - 结束 打印第一次执行的结果： GET -------- /text ------ 4ms 第一层 - 结束 ` koa2 中间件应用 下面是一个登陆验证的中间件：\nloginCheck.js:\n`module.exports = async (ctx, next) =\u0026gt; { if (ctx.session.username) { // 登陆成功，需执行 await next()，以继续执行下一步 await next() return } // 登陆失败，禁止继续执行，所以不需要执行 next() ctx.body = { code: -1, msg: \u0026#39;登陆失败\u0026#39; } } ` 在删除操作中使用 loginCheck.js :\n`router.post(\u0026#39;/delete\u0026#39;, loginCheck, async (ctx, next) =\u0026gt; { const author = ctx.session.username const id = ctx.query.id // handleDelete() 是一个处理删除的方法，返回一个 promise const result = await handleDelete(id, author) if (result) { ctx.body = { code: 0, msg: \u0026#39;删除成功\u0026#39; } } else { ctx.body = { code: -1, msg: \u0026#39;删除失败\u0026#39; } } }) ` express 中间件 与 koa2 中间件不同的是，express中间件一个接一个的顺序执行, 通常会将 response 响应写在最后一个中间件中\n主要特点： app.use 用来注册中间件\n遇到 http 请求，根据 path 和 method 判断触发哪些中间件\n实现 next 机制，即上一个中间件会通过 next 触发下一个中间件\nexpress 中间件实例 `const express = require(\u0026#39;express\u0026#39;) const app = express() app.use((req, res, next) =\u0026gt; { console.log(\u0026#39;第一层 - 开始\u0026#39;) setTimeout(() =\u0026gt; { next() }, 0) console.log(\u0026#39;第一层 - 结束\u0026#39;) }) app.use((req, res, next) =\u0026gt; { console.log(\u0026#39;第二层 - 开始\u0026#39;) setTimeout(() =\u0026gt; { next() }, 0) console.log(\u0026#39;第二层 - 结束\u0026#39;) }) app.use(\u0026#39;/api\u0026#39;, (req, res, next) =\u0026gt; { console.log(\u0026#39;第三层 - 开始\u0026#39;) res.json({ code: 0 }) console.log(\u0026#39;第三层 - 结束\u0026#39;) }) app.listen(3000, () =\u0026gt; { console.log(\u0026#39;server is running on port 3000\u0026#39;) }) ` 执行app.js后，浏览器访问 http://localhost:3000/api , 控制台输出结果：\n`第一层 - 开始 第一层 - 结束 第二层 - 开始 第二层 - 结束 第三层 - 开始 第三层 - 结束 ` 因为上面各个中间件中的 next() 是异步执行的，所以 打印结果是线行输出的。\n如果取消上面next()的异步执行，直接按如下方式：\n`const express = require(\u0026#39;express\u0026#39;) const app = express() app.use((req, res, next) =\u0026gt; { console.log(\u0026#39;第一层 - 开始\u0026#39;) next() console.log(\u0026#39;第一层 - 结束\u0026#39;) }) app.use((req, res, next) =\u0026gt; { console.log(\u0026#39;第二层 - 开始\u0026#39;) next() console.log(\u0026#39;第二层 - 结束\u0026#39;) }) app.use(\u0026#39;/api\u0026#39;, (req, res, next) =\u0026gt; { console.log(\u0026#39;第三层 - 开始\u0026#39;) res.json({ code: 0 }) console.log(\u0026#39;第三层 - 结束\u0026#39;) }) app.listen(3000, () =\u0026gt; { console.log(\u0026#39;server is running on port 3000\u0026#39;) }) ` 执行app.js后，浏览器访问 http://localhost:3000/api , 控制台输出结果：\n`第一层 - 开始 第二层 - 开始 第三层 - 开始 第三层 - 结束 第二层 - 结束 第一层 - 结束 ` 可见，express 的中间件也可以形成“洋葱圈”模型，但是一般在express中不会这么做，因为 express 的 response 一般在最后一个中间件，所以其它中间件 next() 后的代码影响不到最终结果。\nexpress 中间件应用 下面是一个登陆验证的中间件：\nloginCheck.js:\n`module.exports = (req, res, next) =\u0026gt; { if (req.session.username) { // 登陆成功，需执行 next()，以继续执行下一步 next() return } // 登陆失败，禁止继续执行，所以不需要执行 next() ctx.body = { code: -1, msg: \u0026#39;登陆失败\u0026#39; } } ` 在删除操作中使用 loginCheck.js :\n`router.post(\u0026#39;/delete\u0026#39;, loginCheck, (req, res, next) =\u0026gt; { const author = req.session.username const id = req.query.id // handleDelete() 是一个处理删除的方法，返回一个 promise const result = handleDelete(id, author) return result.then(val =\u0026gt; { if (val) { ctx.body = { code: 0, msg: \u0026#39;删除成功\u0026#39; } } else { ctx.body = { code: -1, msg: \u0026#39;删除失败\u0026#39; } } }) }) ` 转自：[https://www.cnblogs.com/cckui/p/10991062.html](https://www.cnblogs.com/cckui/p/10991062.html) ","permalink":"https://blog.zdltech.com/posts/koa2-%E5%92%8C-express-%E4%B8%AD%E9%97%B4%E4%BB%B6%E5%AF%B9%E6%AF%94/","summary":"\u003ch1 id=\"koa2-中间件.wp-block-heading\"\u003ekoa2 中间件\u003c/h1\u003e\n\u003cp\u003ekoa2的中间件是通过 \u003ccode\u003easync await\u003c/code\u003e 实现的，中间件执行顺序是“洋葱圈”模型。\u003c/p\u003e\n\u003cp\u003e中间件之间通过next函数联系,当一个中间件调用 \u003ccode\u003enext()\u003c/code\u003e 后，会将控制权交给下一个中间件, 直到下一个中间件不再执行 \u003ccode\u003enext()\u003c/code\u003e 后, 将会沿路折返,将控制权依次交换给前一个中间件。\u003c/p\u003e\n\u003cp\u003e如图：\u003c/p\u003e\n\u003cfigure class=\"wp-block-image\"\u003e\n\u003cp\u003e\u003cimg alt=\"image\" loading=\"lazy\" src=\"https://www.cnblogs.com/images/cnblogs_com/cckui/1341537/o_onion.png\"\u003e \u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"koa2-中间件实例.wp-block-heading\"\u003ekoa2 中间件实例\u003c/h2\u003e\n\u003cp\u003eapp.js:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e Koa \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e require(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;koa\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e app \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new Koa();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e logger\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003euse(async (ctx, next) \u003cspan style=\"color:#ff79c6\"\u003e=\u0026gt;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;第一层 - 开始\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    await next();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e rt \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e ctx\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eresponse\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;X-Response-Time\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(`\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{ctx\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emethod} \u003cspan style=\"color:#ff79c6\"\u003e-----------\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{ctx\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eurl} \u003cspan style=\"color:#ff79c6\"\u003e-----------\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{rt}`);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;第一层 - 结束\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e x\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eresponse\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003etime\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003euse(async (ctx, next) \u003cspan style=\"color:#ff79c6\"\u003e=\u0026gt;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;第二层 - 开始\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e start \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Date\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003enow();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    await next();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003econst\u003c/span\u003e ms \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Date\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003enow() \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e start;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ctx\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;X-Response-Time\u0026#39;\u003c/span\u003e, `\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{ms}ms`);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;第二层 - 结束\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e response\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003euse(async ctx \u003cspan style=\"color:#ff79c6\"\u003e=\u0026gt;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;第三层 - 开始\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ctx\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ebody \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Hello World\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    console\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elog(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;第三层 - 结束\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#bd93f9\"\u003e3000\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e执行app.js后，浏览器访问 \u003ca href=\"http://localhost:3000/text\"\u003ehttp://localhost:3000/text\u003c/a\u003e , 控制台输出结果：\u003c/p\u003e","title":"Koa2 和 Express 中间件对比"},{"content":"刚刚出现了一个奇怪的问题，我执行以下命令\n后，程序在后台开始执行，但是当我直接关闭终端后，程序在后台停止执行了。网上查了查，以下方法试了试，成功了\nnohup命令执行后，不要直接关闭终端，使用exit命令退出会话\nmark下。\n如果还是解决不了使用\nScreen是一款由GNU计划开发的用于命令行终端切换的自由软件\nScreen参考：https://blog.csdn.net/han0373/article/details/81352663\nhttps://www.jianshu.com/p/0702a451dd0c\n","permalink":"https://blog.zdltech.com/posts/nohup%E4%B8%8D%E8%B5%B7%E4%BD%9C%E7%94%A8/","summary":"\u003cp\u003e刚刚出现了一个奇怪的问题，我执行以下命令\u003c/p\u003e\n\u003cp\u003e后，程序在后台开始执行，但是当我直接关闭终端后，程序在后台停止执行了。网上查了查，以下方法试了试，成功了\u003c/p\u003e\n\u003cp\u003enohup命令执行后，不要直接关闭终端，使用exit命令退出会话\u003cbr\u003e\nmark下。\u003c/p\u003e\n\u003cp\u003e如果还是解决不了使用\u003c/p\u003e\n\u003cp\u003eScreen是一款由GNU计划开发的用于命令行终端切换的自由软件\u003c/p\u003e\n\u003cp\u003eScreen参考：\u003ca href=\"https://blog.csdn.net/han0373/article/details/81352663\"\u003ehttps://blog.csdn.net/han0373/article/details/81352663\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"https://www.jianshu.com/p/0702a451dd0c\"\u003ehttps://www.jianshu.com/p/0702a451dd0c\u003c/a\u003e\u003c/p\u003e","title":"nohup不起作用？"},{"content":"针对移动端 Android 的测试， adb 命令是很重要的一个点，必须将常用的 adb 命令熟记于心， 将会为 Android 测试带来很大的方便，其中很多命令将会用于自动化测试的脚本当中。\nAndroid Debug Bridge\nadb 其实就是 Android Debug Bridge, Android 调试桥的缩写，adb 是一个 C/S 架构的命令行工具，用于通过电脑端与模拟器或者真实设备交互。在某些特殊的情况下进入不了系统，adb就派上用场啦！主要由 3 部分组成：\n· 运行在 PC 端的 Client : 可以通过它对 Android 应用进行安装、卸载及调试\n· 运行在 PC 端的 Service : 其管理客户端到 Android 设备上 adb 后台进程的连接\nadb 服务启动后，Windows 可以在任务管理器中找到 adb.exe 这个进程\n· 运行在 Android 设备上的 adb 后台进程\n执行 adb shell ps | grep adbd ，可以找到该后台进程，windows 请使用 findstr 替代 grep\n通过adb操作android设备\n连接上数据线，然后把手机开发者模式打开，打开usb调试。\nadb 命令 在开发或者测试的过程中，我们可以通过 adb 来管理多台设备，其一般的格式为：\nadb [-e | -d | -s \u003c设备序列号\u003e] \u003c子命令\u003e 在配好环境变量的前提下，在命令窗口当中输入 adb help 或者直接输入 adb ，将会列出所有的选项说明及子命令。\n这里介绍一些里面常用的命令： 1.adb devices , 获取设备列表及设备状态\n2.adb get-state , 获取设备的状态\n设备的状态有 3 钟，device , offline , unknown\ndevice：设备正常连接\noffline：连接出现异常，设备无响应\nunknown：没有连接设备\n**3.**安装卸载应用程序\n**adb install **用于安装\n安装成功，返回成功提示 “Success”；\n安装失败，会返回以下：\nINSTALL_FAILED_ALREADY_EXISTS\n此时需要用 -r 参数来重新安装。\nINSTALL_FAILED_SIGNATURE_ERROR\n应用的签名不一致，可能是发布版和调试版签名不同所致。也有可能是没卸载旧应用导致。\nINSTALL_FAILED_INSUFFICIENT_STORAGE\n存储空间不足，需要检查设备存储情况。\n**adb uninstall **用于卸载\nadb uninstall 后面带的是应用的包名，而不是应用名。\n查看系统所有应用的包名：\nadb shell pm list packages –f\n4**．上传、下载文件**\nadb push 命令将PC机上的文件推到 DLT-RK3288 机器上；\nadb pull 命令将DLT-RK3288机器上的文件拉到PC机上；\n例如：\nadb push d:/new.txt /sdcard/ 将D盘下new.txt文件 推到内部存储器\nadb pull /sdcard/new.txt d:\\\n将DLT-RK3288 内部存储器根目录下的new.txt 拉到D盘\n5. adb shell pm list package\nPackage Manager , 可以用获取到一些安装在 Android 设备上得应用信息\n-s：列出系统应用\n-f：列出应用包名及对应的apk名及存放位置\n过滤应用\n5.adb shell\n通过adb shell 命令，就可以进入设备或者模拟器的shell环境了，在这个Linux shell中，我们就可以执行各种Linux命令了。\n如果只想执行一条shell命令，就可以采用：adb shell [shell_command]，在实际使用中，经常与grep或findstr一起使用，起到过滤作用，查看自己需要的关键信息。\n**6.**常见命令：\n如 ls, cd, rm, mkdir, touch, pwd, cp, mv, ifconfig, netstat, ping, ps, top等，进入adb shell即可执行，与linux相似\n7. adb logcat\n一.在cmd窗口查看手机的Log****日志\n有时候我们在手机程序上的日志要在其他地方调试，然后要看里面的Log日志。在cmd窗口中输入如下命令：\n//格式1：打印默认日志数据adb logcat//格式2：需要打印日志详细时间的简单数据adb logcat -v time//格式3：需要打印级别为Error的信息adb logcat *:E//格式4：需要打印时间和级别是Error的信息adb logcat -v time *:E//格式5：将日志保存到电脑固定的位置，比如D:\\log.txtadb logcat -v time \u003eD:\\log.txt 这时手机日志更新什么日志，cmd窗口也会同步更新数据。\n但是这样没有过滤条件，如果Log日志很多，很难找到我们想要的信息，\n当然也可以复制cmd中的数据到一个文本中慢慢处理的，就是效率不高。\n下面介绍adb logcat中的详细参数命令以及如何才能高效的打印日志，或者把日志保存到我们指定的位置。\n**二.adb logcat **详解\nadb logcat如果用过，但是具体命令又不记得，可以输入adb logcat -help，查看一下一些简单的数据格式：\n日志过滤：adb logcat [:priority]\ntag表示标签，priority输出的级别，日志默认级别是V，如果错误日志我们选择E就可以。\nAndroid 的日志分为如下几个优先级（priority）：\nV —— Verbose（最低，输出得最多）\nD —— Debug\nI —— Info\nW —— Warning\nE —— Error\nF —— Fatal\nS —— Silent（最高，啥也不输出）\n按某级别过滤日志则会将该级别及以上的日志输出。比如，命令：adb logcat *:W\n其实*可以是某个tag，如果没有指明，就表示所有。\ntag可以由多个 [:priority] 组成。比如，命令：\nadb logcat ActivityManager:I MyApp:D *:S\n表示输出 tag ActivityManager 的 Info 以上级别日志，输出 tag MyApp 的 Debug 以上级别日志，及其它 tag 的 Silent 级别日志（即屏蔽其它 tag 日志）。\nadb logcat****选项解析\n–“-s”选项 : 设置输出日志*：s的标签, 只显示该标签的日志;\n–“-f”选项 : 将日志输出到文件, 默认输出到标准输出流中, -f 参数执行不成功;\n–“-r”选项 : 按照每千字节输出日志, 需要 -f 参数, 不过这个命令没有执行成功;\n–“-n”选项 : 设置日志输出的最大数目, 需要 -r 参数, 这个执行 感觉 跟 adb logcat 效果一样;\n–“-v”选项 : 设置日志的输出格式, 注意只能设置一项;\n–“-c”选项 : 清空所有的日志缓存信息;\n–“-d”选项 : 将缓存的日志输出到屏幕上, 并且不会阻塞;\n–“-t”选项 : 输出最近的几行日志, 输出完退出, 不阻塞;\n–“-g”选项 : 查看日志缓冲区信息;\n–“-B”选项 : 以二进制形式输出日志;\n把日志信息保存到电脑中\nadb logcat最后添加” \u0026gt; 保存文件的地址，比如需要将的信息保存到电脑中使用下面的命令： adb logcat -v time \u0026gt; D:\\log.txt\n8.monkey****测试\n一、Monkey****测试简介\nMonkey测试是Android平台自动化测试的一种手段，通过Monkey程序模拟用户触摸屏幕、滑动Trackball、按键等操作来对设备上的程序进行压\n二、Monkey****命令的简单帮助\n要获取Monkey命令自带的简单帮助，在CMD中执行命令：\nadb shell monkey –help\n四、Monkey****命令参数介绍\n说明：第一个-s指定设备，如果只连接了一台设备，可不用该参数。\n-p \u0026lt;apk包名\u0026gt;只允许系统启动指定的app，如果不指定，将允许系统启动设备中的所有app，也可指定多个包。\n–throttle \u0026lt;毫秒数\u0026gt; 指定用户操作（事件）间的时延。\n–ignore-crashes 指定当应用程序崩溃时，Monkey依然发送事件，直到事件计数完成。\n–ignore-timeouts 当应用程序发生ANR错误时，Monkey依然会发送事件，直到事件计数完成。\n第2个-s，用于指定伪随机数生成器的seed值，如果seed相同，则两次Monkey测试所产生的事件序列也相同的。\n-v 用于指定反馈信息级别，总共分为level 0、level 1、level 2三个级别，级别越高，输出的日志越详细。\n**日志级别 Level0 **示例 adb shellmonkey -p com.amaker.mp –v 100\n说明 缺省值，仅提供启动提示、测试完成和最终结果等少量信息\n**日志级别 Level 1 **示例 adb shellmonkey -p com.amaker.mp –v -v 100\n说明 提供较为详细的日志，包括每个发送到Activity的事件信息\n日志级别 Level 2 示例 adb shellmonkey -p com.amaker.mp –v -v –v 100\n说明 最详细的日志，包括了测试中选中/未选中的Activity信息\n最后的数字（这里是500）：表示Monkey程序模拟500次随机用户操作事件。\n输出测试结果到D:\\monkeylog.txt\n转自：https://www.cnblogs.com/laoluoits/p/10985442.html\n更多参考：\nhttps://www.wanandroid.com/blog/show/2310\nhttps://developer.android.com/studio/command-line/adb.html\n","permalink":"https://blog.zdltech.com/posts/adb%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E6%80%BB%E7%BB%93/","summary":"\u003cp\u003e针对移动端 Android 的测试， adb 命令是很重要的一个点，必须将常用的 adb 命令熟记于心， 将会为 Android 测试带来很大的方便，其中很多命令将会用于自动化测试的脚本当中。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAndroid Debug Bridge\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eadb 其实就是 Android Debug Bridge, Android 调试桥的缩写，adb 是一个 \u003cem\u003eC/S\u003c/em\u003e 架构的命令行工具，用于通过电脑端与模拟器或者真实设备交互。在某些特殊的情况下进入不了系统，adb就派上用场啦！主要由 3 部分组成：\u003c/p\u003e\n\u003cp\u003e· 运行在 PC 端的 Client : 可以通过它对 Android 应用进行安装、卸载及调试\u003c/p\u003e\n\u003cp\u003e· 运行在 PC 端的 Service : 其管理客户端到 Android 设备上 adb 后台进程的连接\u003c/p\u003e\n\u003cp\u003eadb 服务启动后，Windows 可以在任务管理器中找到 adb.exe 这个进程\u003c/p\u003e\n\u003cp\u003e· 运行在 Android 设备上的 adb 后台进程\u003c/p\u003e\n\u003cp\u003e执行 adb shell ps | grep adbd ，可以找到该后台进程，windows 请使用 findstr 替代 grep\u003cfigure class=\"wp-block-image size-large\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://img2018.cnblogs.com/blog/465934/201906/465934-20190606155428238-1085192595.png\"\u003e\u003cimg alt=\"image\" loading=\"lazy\" src=\"https://www.zdltech.com/images/2020/02/1.png\"\u003e\u003c/a\u003e\u003c/figure\u003e\u003c/p\u003e","title":"adb常用命令总结"},{"content":"知识点:\nlayer-list : 简单来说layer-list就是图层列表的意思,是用来创建LayerDrawable的,LayerDrawable是DrawableResource的一种,所以,layer-list创建出来的是”图层列表”,也就是一个drawable图形\nshape:这个老哥说的挺仔细的(https://www.jianshu.com/p/d97fcdde1fc6)\n上效果:\nimage.png\n直接在drawable文件夹下面创建文件夹gradual.xml__\n`\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026gt; \u0026amp;lt;layer-list xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026gt; \u0026amp;lt;item\u0026gt; \u0026amp;lt;shape android:shape=\u0026#34;rectangle\u0026#34;\u0026gt; \u0026amp;lt;padding android:bottom=\u0026#34;3dp\u0026#34; android:left=\u0026#34;3dp\u0026#34; android:right=\u0026#34;3dp\u0026#34; android:top=\u0026#34;3dp\u0026#34; /\u0026gt; \u0026amp;lt;solid android:color=\u0026#34;#0DCCCCCC\u0026#34; /\u0026gt; \u0026amp;lt;corners android:radius=\u0026#34;10dp\u0026#34; /\u0026gt; \u0026amp;lt;/shape\u0026gt; \u0026amp;lt;/item\u0026gt; \u0026amp;lt;item\u0026gt; \u0026amp;lt;shape android:shape=\u0026#34;rectangle\u0026#34;\u0026gt; \u0026amp;lt;padding android:bottom=\u0026#34;3dp\u0026#34; android:left=\u0026#34;3dp\u0026#34; android:right=\u0026#34;3dp\u0026#34; android:top=\u0026#34;3dp\u0026#34; /\u0026gt; \u0026amp;lt;solid android:color=\u0026#34;#10CCCCCC\u0026#34; /\u0026gt; \u0026amp;lt;corners android:radius=\u0026#34;10dp\u0026#34; /\u0026gt; \u0026amp;lt;/shape\u0026gt; \u0026amp;lt;/item\u0026gt; \u0026amp;lt;item\u0026gt; \u0026amp;lt;shape android:shape=\u0026#34;rectangle\u0026#34;\u0026gt; \u0026amp;lt;padding android:bottom=\u0026#34;3dp\u0026#34; android:left=\u0026#34;3dp\u0026#34; android:right=\u0026#34;3dp\u0026#34; android:top=\u0026#34;3dp\u0026#34; /\u0026gt; \u0026amp;lt;solid android:color=\u0026#34;#15CCCCCC\u0026#34; /\u0026gt; \u0026amp;lt;corners android:radius=\u0026#34;10dp\u0026#34; /\u0026gt; \u0026amp;lt;/shape\u0026gt; \u0026amp;lt;/item\u0026gt; \u0026amp;lt;item\u0026gt; \u0026amp;lt;shape android:shape=\u0026#34;rectangle\u0026#34;\u0026gt; \u0026amp;lt;padding android:bottom=\u0026#34;3dp\u0026#34; android:left=\u0026#34;3dp\u0026#34; android:right=\u0026#34;3dp\u0026#34; android:top=\u0026#34;3dp\u0026#34; /\u0026gt; \u0026amp;lt;solid android:color=\u0026#34;#20CCCCCC\u0026#34; /\u0026gt; \u0026amp;lt;corners android:radius=\u0026#34;10dp\u0026#34; /\u0026gt; \u0026amp;lt;/shape\u0026gt; \u0026amp;lt;/item\u0026gt; \u0026amp;lt;item\u0026gt; \u0026amp;lt;shape android:shape=\u0026#34;rectangle\u0026#34;\u0026gt; \u0026amp;lt;padding android:bottom=\u0026#34;3dp\u0026#34; android:left=\u0026#34;3dp\u0026#34; android:right=\u0026#34;3dp\u0026#34; android:top=\u0026#34;3dp\u0026#34; /\u0026gt; \u0026amp;lt;solid android:color=\u0026#34;#30CCCCCC\u0026#34; /\u0026gt; \u0026amp;lt;corners android:radius=\u0026#34;10dp\u0026#34; /\u0026gt; \u0026amp;lt;/shape\u0026gt; \u0026amp;lt;/item\u0026gt; \u0026amp;lt;item\u0026gt; \u0026amp;lt;shape\u0026gt; \u0026amp;lt;solid android:color=\u0026#34;#FFFFFF\u0026#34; /\u0026gt; \u0026amp;lt;corners android:radius=\u0026#34;6dp\u0026#34; /\u0026gt; \u0026amp;lt;/shape\u0026gt; \u0026amp;lt;/item\u0026gt; \u0026amp;lt;/layer-list\u0026gt; ` 在上面代码大概可以理解到,就是用若干个渐浅色的图层叠加在一起,实现渐变的阴影效果,想要效果更好可以把间隔缩小,图层再增加几个就可以了,我觉得上面代码效果就挺好的了,刚好\n转自：https://www.jianshu.com/p/d2aa65a91a42\n","permalink":"https://blog.zdltech.com/posts/android-shape-layer-list%E5%AE%9E%E7%8E%B0%E6%B8%90%E5%8F%98%E9%98%B4%E5%BD%B1%E6%95%88%E6%9E%9C/","summary":"\u003cp\u003e知识点:\u003cbr\u003e\nlayer-list : 简单来说layer-list就是图层列表的意思,是用来创建LayerDrawable的,LayerDrawable是DrawableResource的一种,所以,layer-list创建出来的是”图层列表”,也就是一个drawable图形\u003cbr\u003e\nshape:这个老哥说的挺仔细的(\u003ca href=\"https://www.jianshu.com/p/d97fcdde1fc6\"\u003ehttps://www.jianshu.com/p/d97fcdde1fc6\u003c/a\u003e)\u003c/p\u003e\n\u003cp\u003e上效果:\u003c/p\u003e\n\u003cfigure class=\"wp-block-image\"\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"//upload-images.jianshu.io/upload_images/11681276-1ccca9748640acea.png?imageMogr2/auto-orient/strip|imageView2/2/w/706/format/webp\"\u003e \u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003eimage.png\u003c/p\u003e\n\u003cp\u003e直接在drawable文件夹下面创建文件夹gradual.xml__\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;layer-list xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;item\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;shape android:shape=\u0026#34;rectangle\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;padding\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:bottom=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:left=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:right=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:top=\u0026#34;3dp\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;solid android:color=\u0026#34;#0DCCCCCC\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;corners android:radius=\u0026#34;10dp\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;/shape\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;/item\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;item\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;shape android:shape=\u0026#34;rectangle\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;padding\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:bottom=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:left=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:right=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:top=\u0026#34;3dp\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;solid android:color=\u0026#34;#10CCCCCC\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;corners android:radius=\u0026#34;10dp\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;/shape\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;/item\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;item\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;shape android:shape=\u0026#34;rectangle\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;padding\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:bottom=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:left=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:right=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:top=\u0026#34;3dp\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;solid android:color=\u0026#34;#15CCCCCC\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;corners android:radius=\u0026#34;10dp\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;/shape\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;/item\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;item\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;shape android:shape=\u0026#34;rectangle\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;padding\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:bottom=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:left=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:right=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:top=\u0026#34;3dp\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;solid android:color=\u0026#34;#20CCCCCC\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;corners android:radius=\u0026#34;10dp\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;/shape\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;/item\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;item\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;shape android:shape=\u0026#34;rectangle\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;padding\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:bottom=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:left=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:right=\u0026#34;3dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                android:top=\u0026#34;3dp\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;solid android:color=\u0026#34;#30CCCCCC\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;corners android:radius=\u0026#34;10dp\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;/shape\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;/item\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;item\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;shape\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;solid android:color=\u0026#34;#FFFFFF\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;corners android:radius=\u0026#34;6dp\u0026#34; /\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;/shape\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;/item\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/layer-list\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e在上面代码大概可以理解到,就是用若干个渐浅色的图层叠加在一起,实现渐变的阴影效果,想要效果更好可以把间隔缩小,图层再增加几个就可以了,我觉得上面代码效果就挺好的了,刚好\u003c/p\u003e","title":"Android shape/layer-list实现(渐变阴影)效果"},{"content":" 开发系统的时候，我们避免不了要发送邮件，在php中使用phpmailer可以快速的实现邮件的发送 `请自行引用phpmailer模块，放下面这个文件和phpmailer同级 配置号里面的发送邮箱内容，执行php sendMail.php文件就可以测试发送邮件了 这个文件名称为sendMail.php \u0026amp;lt;?php use phpmailer\\phpmailer\\PHPMailer; use phpmailer\\phpmailer\\Exception; //引入项目 require \u0026#39;./phpmailer/src/Exception.php\u0026#39;; require \u0026#39;./phpmailer/src/PHPMailer.php\u0026#39;; require \u0026#39;./phpmailer/src/SMTP.php\u0026#39;; //实例化PHPMail类 \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;mail = new PHPMailer(true); try { //Server settings\u0026amp;lt;/span\u0026gt;mail-\u0026gt;SMTPDebug = 2; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;mail-\u0026gt;isSMTP();\u0026amp;lt;/span\u0026gt;mail-\u0026gt;Host = \u0026#39;smtp.163.com\u0026#39;; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;mail-\u0026gt;SMTPAuth = true;\u0026amp;lt;/span\u0026gt;mail-\u0026gt;Username = \u0026#39;hn_zhangdl@163.com\u0026#39;; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;mail-\u0026gt;Password = \u0026#39;xxxx\u0026#39;;#跟上边一样的授权码\u0026amp;lt;/span\u0026gt;mail-\u0026gt;SMTPSecure = \u0026#39;ssl\u0026#39;; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;mail-\u0026gt;Port = 994;\u0026amp;lt;/span\u0026gt;mail-\u0026gt;CharSet=\u0026#39;UTF-8\u0026#39;; //发件人 \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;mail-\u0026gt;setFrom(\u0026#39;hn_zhangdl@163.com\u0026#39;, \u0026#39;Mailer\u0026#39;); //收件人。多收件人可设置多个addAddress\u0026amp;lt;/span\u0026gt;mail-\u0026gt;addAddress(\u0026#39;411437734@qq.com\u0026#39;, \u0026#39;zhangdl\u0026#39;);//收件人邮箱地址，收件人姓名（选填） //发送附件 //#\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;mail-\u0026gt;addAttachment(\u0026#39;/var/tmp/file.tar.gz\u0026#39;); // 添加附件 //#\u0026amp;lt;/span\u0026gt;mail-\u0026gt;addAttachment(\u0026#39;/tmp/image.jpg\u0026#39;, \u0026#39;new.jpg\u0026#39;); // 设置附件以及附件名称 //邮件内容 \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;mail-\u0026gt;isHTML(true); // 发送html格式邮件\u0026amp;lt;/span\u0026gt;mail-\u0026gt;Subject = \u0026#39;标题\u0026#39;; //邮件标题 \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;mail-\u0026gt;Body = \u0026#39;邮件测试内容 hello.\u0026#39;;\u0026amp;lt;/span\u0026gt;mail-\u0026gt;send(); echo \u0026#39;Message has been sent\u0026#39;; } catch (Exception \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;e) { echo \u0026#39;Message could not be sent. Mailer Error: \u0026#39;,\u0026amp;lt;/span\u0026gt;mail-\u0026gt;ErrorInfo; } ?\u0026gt;` ","permalink":"https://blog.zdltech.com/posts/phpmailer%E5%8F%91%E9%80%81%E9%82%AE%E4%BB%B6demo/","summary":"\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e开发系统的时候，我们避免不了要发送邮件，在php中使用phpmailer可以快速的实现邮件的发送\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`请自行引用phpmailer模块，放下面这个文件和phpmailer同级 配置号里面的发送邮箱内容，执行php sendMail\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ephp文件就可以测试发送邮件了\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e这个文件名称为sendMail\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ephp\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;?php\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003euse phpmailer\\phpmailer\\PHPMailer;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003euse phpmailer\\phpmailer\\Exception;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e引入项目\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003erequire \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;./phpmailer/src/Exception.php\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003erequire \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;./phpmailer/src/PHPMailer.php\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003erequire \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;./phpmailer/src/SMTP.php\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e实例化PHPMail类\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new PHPMailer(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etry {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003eServer settings\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003eSMTPDebug \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003eisSMTP();\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003eHost \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;smtp.163.com\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003eSMTPAuth \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003eUsername \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;hn_zhangdl@163.com\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003ePassword \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;xxxx\u0026#39;\u003c/span\u003e;\u003cspan style=\"color:#6272a4\"\u003e#跟上边一样的授权码\u0026amp;lt;/span\u0026gt;mail-\u0026gt;SMTPSecure = \u0026#39;ssl\u0026#39;;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003ePort \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e994\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003eCharSet\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;UTF-8\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e发件人\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003esetFrom(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;hn_zhangdl@163.com\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Mailer\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e收件人。多收件人可设置多个addAddress\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003eaddAddress(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;411437734@qq.com\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;zhangdl\u0026#39;\u003c/span\u003e);\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e收件人邮箱地址，收件人姓名（选填）\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e发送附件\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e\u003cspan style=\"color:#6272a4\"\u003e#\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;mail-\u0026gt;addAttachment(\u0026#39;/var/tmp/file.tar.gz\u0026#39;); // 添加附件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e\u003cspan style=\"color:#6272a4\"\u003e#\u0026amp;lt;/span\u0026gt;mail-\u0026gt;addAttachment(\u0026#39;/tmp/image.jpg\u0026#39;, \u0026#39;new.jpg\u0026#39;); // 设置附件以及附件名称\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e邮件内容\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003eisHTML(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e); \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 发送html格式邮件\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003eSubject \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;标题\u0026#39;\u003c/span\u003e; \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e邮件标题\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003eBody    \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;邮件测试内容 hello.\u0026#39;\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003esend();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    echo \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Message has been sent\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e} catch (Exception \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;katex math inline\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ee) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    echo \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Message could not be sent. Mailer Error: \u0026#39;\u003c/span\u003e,\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003email\u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003eErrorInfo;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e?\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"PHPmailer发送邮件demo"},{"content":"下面的文章有thymeleaf 拼接字符串的写法和处理字符串太长显示部分的方法\n下面的方法是显示指定的字符：\n` th:text=\u0026#34;${#strings.abbreviate(t.signTitle,25)}\u0026#34; ` 参考：[https://blog.csdn.net/qq_37599827/article/details/93362132](https://blog.csdn.net/qq_37599827/article/details/93362132) ","permalink":"https://blog.zdltech.com/posts/thymeleaf-%E8%A7%A3%E5%86%B3%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%A4%AA%E9%95%BF%E6%98%BE%E7%A4%BA%E9%97%AE%E9%A2%98%E6%88%AA%E5%8F%96%E6%98%BE%E7%A4%BA%E9%83%A8%E5%88%86%E5%AD%97%E7%AC%A6%E4%B8%B2/","summary":"\u003cp\u003e下面的文章有thymeleaf 拼接字符串的写法和处理字符串太长显示部分的方法\u003c/p\u003e\n\u003cp\u003e下面的方法是显示指定的字符：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e` th:text=\u0026#34;${#strings.abbreviate(t.signTitle,25)}\u0026#34;  `\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e参考：[https://blog.csdn.net/qq_37599827/article/details/93362132](https://blog.csdn.net/qq_37599827/article/details/93362132)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e","title":"thymeleaf 解决字符串太长显示问题（截取显示部分字符串）"},{"content":"html中表格标签css固定列方案，table固定最后一列，table固定第一列\nCSS样式： \u0026amp;lt;style\u0026gt; table { table-layout: auto !important; word-break: keep-all !important; } td,th{ padding: 0 5px; } table tr:nth-child(even){ background:white; } table tr th:nth-last-child(2), table tr td:nth-last-child(2){ padding-right: 170px; } table th:last-child, table tr td:last-child { background: inherit; border-left:1px solid #ddd; width:150px ; text-align: center; position: fixed; right: 0; z-index: 2; } table tr th:nth-child(2), table tr td:nth-child(2){ padding-left: 170px; } table th:first-child,table tr td:first-child{ background: red; border-left:1px solid #ddd; width:150px ; text-align: center; position: fixed; left: 0; z-index: 2; } \u0026amp;lt;/style\u0026gt; 所有HTML代码： ` \u0026amp;lt;!DOCTYPE html\u0026gt; \u0026amp;lt;html\u0026gt; \u0026amp;lt;head\u0026gt; \u0026amp;lt;meta http-equiv=\u0026#34;Content-Type\u0026#34; content=\u0026#34;text/html; charset=UTF-8\u0026#34;/\u0026gt; \u0026amp;lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;/admin/css/common.css\u0026#34;\u0026gt; \u0026amp;lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;/admin//css/news/news.css\u0026#34;\u0026gt; \u0026amp;lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;/admin//css/font-awesome.min.css\u0026#34;\u0026gt; \u0026amp;lt;script src=\u0026#34;/admin//js/jquery.min.js\u0026#34;\u0026gt;\u0026amp;lt;/script\u0026gt; \u0026amp;lt;script src=\u0026#34;/admin//js/news.js\u0026#34;\u0026gt;\u0026amp;lt;/script\u0026gt; \u0026amp;lt;/head\u0026gt; \u0026amp;lt;style\u0026gt; table { table-layout: auto !important; word-break: keep-all !important; } td,th{ padding: 0 5px; } table tr:nth-child(even){ background:white; } table tr th:nth-last-child(2), table tr td:nth-last-child(2){ padding-right: 170px; } table th:last-child, table tr td:last-child { background: inherit; border-left:1px solid #ddd; width:150px ; text-align: center; position: fixed; right: 0; z-index: 2; } table tr th:nth-child(2), table tr td:nth-child(2){ padding-left: 170px; } table th:first-child,table tr td:first-child{ background: red; border-left:1px solid #ddd; width:150px ; text-align: center; position: fixed; left: 0; z-index: 2; } \u0026amp;lt;/style\u0026gt; \u0026amp;lt;body\u0026gt; \u0026amp;lt;div class=\u0026#34;list-content\u0026#34; style=\u0026#34;overflow:auto;\u0026#34;\u0026gt; \u0026amp;lt;table\u0026gt; \u0026amp;lt;tr\u0026gt; \u0026amp;lt;th width=\u0026#34;50px\u0026#34;\u0026gt;序号\u0026amp;lt;/th\u0026gt; \u0026amp;lt;th\u0026gt;应用名\u0026amp;lt;/th\u0026gt; \u0026amp;lt;th\u0026gt;app_id\u0026amp;lt;/th\u0026gt; \u0026amp;lt;th\u0026gt;secret_key\u0026amp;lt;/th\u0026gt; \u0026amp;lt;th\u0026gt;绑定学校\u0026amp;lt;/th\u0026gt; \u0026amp;lt;th\u0026gt;教务系统\u0026amp;lt;/th\u0026gt; \u0026amp;lt;th\u0026gt;联系人\u0026amp;lt;/th\u0026gt; \u0026amp;lt;th\u0026gt;联系电话\u0026amp;lt;/th\u0026gt; \u0026amp;lt;th\u0026gt;状态\u0026amp;lt;/th\u0026gt; \u0026amp;lt;th\u0026gt;创建日期\u0026amp;lt;/th\u0026gt; \u0026amp;lt;th\u0026gt;更新日期\u0026amp;lt;/th\u0026gt; \u0026amp;lt;th width=\u0026#34;200\u0026#34;\u0026gt;操作\u0026amp;lt;/th\u0026gt; \u0026amp;lt;/tr\u0026gt; \u0026amp;lt;tr\u0026gt; \u0026amp;lt;td align=\u0026#34;center\u0026#34;\u0026gt;1\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;请打的\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;1542081125346835\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;29f7a4edd04af7f558870636b6689781\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;青岛大学\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;URP综合教务\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;水电费\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;1\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;2018-11-13 11:52:05\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;2018-11-13 11:52:05\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt; \u0026amp;lt;span class=\u0026#34;edit-btn\u0026#34; οnclick=\u0026#34;parent.showUrlDialog(\u0026#39;edit/id/8\u0026#39;)\u0026#34;\u0026gt;\u0026amp;lt;li class=\u0026#34;fa fa-edit\u0026#34;\u0026gt;\u0026amp;lt;/li\u0026gt; 编辑\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;delete-btn\u0026#34; οnclick=\u0026#34;delAppClient(\u0026#39;8\u0026#39;)\u0026#34;\u0026gt;\u0026amp;lt;li class=\u0026#34;fa fa-ban\u0026#34;\u0026gt;\u0026amp;lt;/li\u0026gt; 删除\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/td\u0026gt; \u0026amp;lt;/tr\u0026gt; \u0026amp;lt;tr\u0026gt; \u0026amp;lt;td align=\u0026#34;center\u0026#34;\u0026gt;2\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;看手机\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;1542036973909802\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;7ce5dc0272e2482acf8c37ef9f0d1582\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;青岛大学\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;URP综合教务\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;万洲\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;0\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;2018-11-12 23:36:13\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt;2018-11-13 00:14:13\u0026amp;lt;/td\u0026gt; \u0026amp;lt;td\u0026gt; \u0026amp;lt;span class=\u0026#34;edit-btn\u0026#34; οnclick=\u0026#34;parent.showUrlDialog(\u0026#39;app_client/edit/id/7\u0026#39;)\u0026#34;\u0026gt;\u0026amp;lt;li class=\u0026#34;fa fa-edit\u0026#34;\u0026gt;\u0026amp;lt;/li\u0026gt; 编辑\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;delete-btn\u0026#34; οnclick=\u0026#34;delAppClient(\u0026#39;7\u0026#39;)\u0026#34;\u0026gt;\u0026amp;lt;li class=\u0026#34;fa fa-ban\u0026#34;\u0026gt;\u0026amp;lt;/li\u0026gt; 删除\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/td\u0026gt; \u0026amp;lt;/tr\u0026gt; \u0026amp;lt;/table\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;div class=\u0026#34;page\u0026#34;\u0026gt; \u0026amp;lt;/div\u0026gt; \u0026amp;lt;/body\u0026gt; \u0026amp;lt;/html\u0026gt;` 参考：[https://developer.mozilla.org/zh-CN/docs/Web/CSS/:nth-child](https://developer.mozilla.org/zh-CN/docs/Web/CSS/:nth-child) 了解更多属性 参考：[https://blog.csdn.net/veloi/article/details/84027505](https://blog.csdn.net/veloi/article/details/84027505) ","permalink":"https://blog.zdltech.com/posts/%E8%A1%A8%E6%A0%BC%E6%A0%87%E7%AD%BEcss%E5%9B%BA%E5%AE%9A%E5%88%97%E7%9A%84%E6%96%B9%E6%A1%88/","summary":"\u003cp\u003ehtml中\u003ctable\u003e表格标签css固定列方案，table固定最后一列，table固定第一列\u003cfigure class=\"wp-block-image\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img-blog.csdnimg.cn/2018111312575770.gif\"\u003e \u003c/figure\u003e\u003c/p\u003e\n\u003ch4 class=\"wp-block-heading\" id=\"css样式\"\u003e\u003cstrong\u003eCSS样式\u003c/strong\u003e：\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;style\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        table-layout: auto !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        word-break: keep-all !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    td,th{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        padding: 0 5px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table tr:nth-child(even){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        background:white;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table tr th:nth-last-child(2), table tr td:nth-last-child(2){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        padding-right: 170px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table th:last-child,  table tr td:last-child {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       background: inherit;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       border-left:1px solid #ddd;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       width:150px ;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       text-align: center;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       position: fixed;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       right: 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       z-index: 2;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table tr th:nth-child(2), table tr td:nth-child(2){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        padding-left: 170px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table th:first-child,table tr td:first-child{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       background: red;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       border-left:1px solid #ddd;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       width:150px ;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       text-align: center;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       position: fixed;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       left: 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       z-index: 2;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/style\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 class=\"wp-block-heading\" id=\"所有html代码\"\u003e所有HTML代码：\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;!DOCTYPE html\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;html\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;head\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;meta http-equiv=\u0026#34;Content-Type\u0026#34; content=\u0026#34;text/html; charset=UTF-8\u0026#34;/\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;/admin/css/common.css\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;/admin//css/news/news.css\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;/admin//css/font-awesome.min.css\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;script src=\u0026#34;/admin//js/jquery.min.js\u0026#34;\u0026gt;\u0026amp;lt;/script\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;script src=\u0026#34;/admin//js/news.js\u0026#34;\u0026gt;\u0026amp;lt;/script\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/head\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;style\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        table-layout: auto !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        word-break: keep-all !important;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    td,th{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        padding: 0 5px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table tr:nth-child(even){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        background:white;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table tr th:nth-last-child(2), table tr td:nth-last-child(2){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        padding-right: 170px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table th:last-child,  table tr td:last-child {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       background: inherit;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       border-left:1px solid #ddd;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       width:150px ;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       text-align: center;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       position: fixed;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       right: 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       z-index: 2;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table tr th:nth-child(2), table tr td:nth-child(2){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        padding-left: 170px;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table th:first-child,table tr td:first-child{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       background: red;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       border-left:1px solid #ddd;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       width:150px ;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       text-align: center;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       position: fixed;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       left: 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       z-index: 2;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/style\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;body\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;div class=\u0026#34;list-content\u0026#34; style=\u0026#34;overflow:auto;\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;table\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;tr\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;th width=\u0026#34;50px\u0026#34;\u0026gt;序号\u0026amp;lt;/th\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;th\u0026gt;应用名\u0026amp;lt;/th\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;th\u0026gt;app_id\u0026amp;lt;/th\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;th\u0026gt;secret_key\u0026amp;lt;/th\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;th\u0026gt;绑定学校\u0026amp;lt;/th\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;th\u0026gt;教务系统\u0026amp;lt;/th\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;th\u0026gt;联系人\u0026amp;lt;/th\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;th\u0026gt;联系电话\u0026amp;lt;/th\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;th\u0026gt;状态\u0026amp;lt;/th\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;th\u0026gt;创建日期\u0026amp;lt;/th\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;th\u0026gt;更新日期\u0026amp;lt;/th\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;th width=\u0026#34;200\u0026#34;\u0026gt;操作\u0026amp;lt;/th\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;/tr\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;tr\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td align=\u0026#34;center\u0026#34;\u0026gt;1\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;请打的\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;1542081125346835\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;29f7a4edd04af7f558870636b6689781\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;青岛大学\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;URP综合教务\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;水电费\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;1\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;2018-11-13 11:52:05\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;2018-11-13 11:52:05\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;span class=\u0026#34;edit-btn\u0026#34; οnclick=\u0026#34;parent.showUrlDialog(\u0026#39;edit/id/8\u0026#39;)\u0026#34;\u0026gt;\u0026amp;lt;li class=\u0026#34;fa fa-edit\u0026#34;\u0026gt;\u0026amp;lt;/li\u0026gt; 编辑\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;span class=\u0026#34;delete-btn\u0026#34; οnclick=\u0026#34;delAppClient(\u0026#39;8\u0026#39;)\u0026#34;\u0026gt;\u0026amp;lt;li class=\u0026#34;fa fa-ban\u0026#34;\u0026gt;\u0026amp;lt;/li\u0026gt; 删除\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;/tr\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;tr\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td align=\u0026#34;center\u0026#34;\u0026gt;2\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;看手机\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;1542036973909802\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;7ce5dc0272e2482acf8c37ef9f0d1582\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;青岛大学\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;URP综合教务\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;万洲\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;0\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;2018-11-12 23:36:13\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;2018-11-13 00:14:13\u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;span class=\u0026#34;edit-btn\u0026#34; οnclick=\u0026#34;parent.showUrlDialog(\u0026#39;app_client/edit/id/7\u0026#39;)\u0026#34;\u0026gt;\u0026amp;lt;li class=\u0026#34;fa fa-edit\u0026#34;\u0026gt;\u0026amp;lt;/li\u0026gt; 编辑\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;span class=\u0026#34;delete-btn\u0026#34; οnclick=\u0026#34;delAppClient(\u0026#39;7\u0026#39;)\u0026#34;\u0026gt;\u0026amp;lt;li class=\u0026#34;fa fa-ban\u0026#34;\u0026gt;\u0026amp;lt;/li\u0026gt; 删除\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;/tr\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;/table\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;div class=\u0026#34;page\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/body\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/html\u0026gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e参考：[https://developer.mozilla.org/zh-CN/docs/Web/CSS/:nth-child](https://developer.mozilla.org/zh-CN/docs/Web/CSS/:nth-child) 了解更多属性\n\n\n\n\n\n参考：[https://blog.csdn.net/veloi/article/details/84027505](https://blog.csdn.net/veloi/article/details/84027505)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e","title":"表格标签css固定列的方案"},{"content":"LayUI实战之layui.layer.open使用 有时候我们有这么一种需求，在开发表单界面的时候，有一行指定用户需求时，需要查询用户，由于用户是独立的表和模块，数据量大的时候，\n我们不能一次查找所有数据，放到Select中供用户进行选择，这时候基本上都会需要弹出一个界面，让用户进行查询及选择，选择之后，把选择的数据在传递到上一个打开的界面；\n…\n没错就是通过layui.layer.open进行实现\n_layer_是一款近年来备受青睐的web弹层组件，她具备全方位的解决方案，致力于服务各水平段的开发人员，您的页面会轻松地拥有丰富友好的操作体验。\n接下来一步一步进行操作\n第一步 创建工程 根据自己的爱好，选择顺手的开发工具，进行创建web项目。这里我创建一个空项目\n第二步 添加Layui js和css 通过官网 进行下载 https://www.layui.com/\n下载之后进行解压 把layui文件夹添加到项目中（参考下图）\n第三步 添加2个html文件 index.html\n`\u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026ldquo;en\u0026rdquo;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026ldquo;UTF-8\u0026rdquo;\u0026gt; \u0026lt;title\u0026gt;LayUI测试\u0026lt;/title\u0026gt; \u0026lt;link href=\u0026ldquo;layui/css/layui.css\u0026rdquo;/\u0026gt;\n\u0026lt;script src=\u0026ldquo;layui/layui.all.js\u0026rdquo;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;div class=\u0026ldquo;layui-form-item \u0026quot; \u0026gt; \u0026lt;label class=\u0026ldquo;layui-form-label\u0026rdquo;\u0026gt;选择\u0026lt;/label\u0026gt; \u0026lt;div class=\u0026ldquo;layui-input-block\u0026rdquo; \u0026gt; \u0026lt;button style=\u0026ldquo;width: 15%\u0026rdquo; class=\u0026ldquo;layui-btn layui-btn-radius layui-btn-warm\u0026rdquo; type=\u0026ldquo;button\u0026rdquo; id=\u0026ldquo;sel_good\u0026rdquo; lay-filter=\u0026ldquo;sel_good\u0026rdquo;\u0026gt;点击选择\u0026lt;/button\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026ldquo;layui-form-item selectGood\u0026rdquo; \u0026gt; \u0026lt;label class=\u0026ldquo;layui-form-label\u0026rdquo;\u0026gt;所选\u0026lt;/label\u0026gt; \u0026lt;div class=\u0026ldquo;layui-input-block\u0026rdquo; id=\u0026ldquo;good\u0026rdquo; \u0026gt; \u0026lt;input type=\u0026ldquo;text\u0026rdquo; id=\u0026ldquo;goodName\u0026rdquo; autocomplete=\u0026ldquo;off\u0026rdquo; class=\u0026ldquo;layui-input\u0026rdquo;\u0026gt; \u0026lt;input type=\u0026ldquo;hidden\u0026rdquo; id=\u0026ldquo;goodId\u0026rdquo; name=\u0026ldquo;goodId\u0026rdquo; autocomplete=\u0026ldquo;off\u0026rdquo; class=\u0026ldquo;layui-input\u0026rdquo;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;script src=\u0026ldquo;https://code.jquery.com/jquery-3.4.1.min.js\u0026quot;\u0026amp;gt;\u0026amp;lt;/script\u0026gt; \u0026lt;script\u0026gt; $(\u0026quot;#sel_good\u0026rdquo;).on(\u0026ldquo;click\u0026rdquo;, function () { var e = layui.layer.open({ title: \u0026ldquo;选择\u0026rdquo;, type: 2, move: false, anim: 1, skin: \u0026ldquo;larry-green\u0026rdquo;, offset: '10px', area: [10240.9 + \u0026ldquo;px\u0026rdquo;, 8000.9 + \u0026ldquo;px\u0026rdquo;], content: \u0026ldquo;one.html\u0026rdquo;,//后台请求地址 success: function (layero, index) { console.log(layero, index); console.log(\u0026quot;==============================================\u0026rdquo;); var body = layui.layer.getChildFrame('body', index); console.log(body); }, btn: ['按钮一', '按钮二', '按钮三'],//默认 按钮一 执行的yes btn2 是按钮2 btn3是按钮三 yes: function(index, layero){ console.log(layero, index); //do something layer.close(index); //如果设定了yes回调，需进行手工关闭 } }); }); //https://www.layui.com/doc/modules/layer.html#btn \u0026lt;/script\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; `\n\u0026gt; \u0026gt; one.html \u0026gt; \u0026gt; ``` `\u0026amp;lt;!DOCTYPE html\u0026amp;gt; \u0026amp;lt;html lang=\u0026#34;en\u0026#34;\u0026amp;gt; \u0026amp;lt;head\u0026amp;gt; \u0026amp;lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026amp;gt; \u0026amp;lt;title\u0026amp;gt;Title\u0026amp;lt;/title\u0026amp;gt; \u0026amp;lt;link href=\u0026#34;layui/css/layui.css\u0026#34;/\u0026amp;gt; \u0026amp;lt;script src=\u0026#34;layui/layui.all.js\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;/head\u0026amp;gt; \u0026amp;lt;body\u0026amp;gt; \u0026amp;lt;button id=\u0026#34;sel_good\u0026#34;\u0026amp;gt;这是选择子界面\u0026amp;lt;/button\u0026amp;gt; \u0026amp;lt;script src=\u0026#34;https://code.jquery.com/jquery-3.4.1.min.js\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;script\u0026amp;gt; $(\u0026#34;#sel_good\u0026#34;).on(\u0026#34;click\u0026#34;, function () { window.parent.document.getElementById(\u0026#34;goodName\u0026#34;).value=\u0026amp;#39;MacBook pro 笔记本\u0026amp;#39;; window.parent.document.getElementById(\u0026#34;goodId\u0026#34;).value=1; var index = parent.layer.getFrameIndex(window.name); //当前iframe层的索引 // parent.layer.close(index); //再执行关闭 // layer.close(index); var e = layui.layer.open({ title: \u0026#34;选择\u0026#34;, type: 1, move: false, anim: 1, skin: \u0026#34;larry-green\u0026#34;, offset: \u0026amp;#39;10px\u0026amp;#39;, area: [400 + \u0026#34;px\u0026#34;, 300+ \u0026#34;px\u0026#34;], content: \u0026#34;再弹出一个试试！！！\u0026#34;,//后台请求地址 btn: [\u0026amp;#39;确定\u0026amp;#39;],//默认 按钮一 执行的yes btn2 是按钮2 btn3是按钮三 yes: function(index, layero){ console.log(layero, index); //do something layer.close(index); //如果设定了yes回调，需进行手工关闭 } }); }); \u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;/body\u0026amp;gt; \u0026amp;lt;/html\u0026amp;gt; ` 自己copy文件运行先看看效果是否是这样\n第四步 相关说明 $(\u0026quot;#sel_good\u0026quot;).on(\u0026quot;click\u0026quot;, function () { var e = layui.layer.open({ title: \u0026quot;选择\u0026quot;, type: 2, move: false, anim: 1, skin: \u0026quot;larry-green\u0026quot;, offset: \u0026amp;#39;10px\u0026amp;#39;, area: [1024*0.9 + \u0026quot;px\u0026quot;, 800*0.9 + \u0026quot;px\u0026quot;], content: \u0026quot;one.html\u0026quot;,//后台请求地址 success: function (layero, index) { console.log(layero, index); console.log(\u0026quot;==============================================\u0026quot;); var body = layui.layer.getChildFrame(\u0026amp;#39;body\u0026amp;#39;, index); console.log(body); }, btn: [\u0026amp;#39;按钮一\u0026amp;#39;, \u0026amp;#39;按钮二\u0026amp;#39;, \u0026amp;#39;按钮三\u0026amp;#39;],//默认 按钮一 执行的yes btn2 是按钮2 btn3是按钮三 yes: function(index, layero){ console.log(layero, index); //do something layer.close(index); //如果设定了yes回调，需进行手工关闭 } }); }); \u0026gt; \u0026gt; 这里的type=2表示已iframe的方式进行打开文件 \u0026gt; \u0026gt; content: \u0026#34;one.html\u0026#34;, 表示要打开的界面 \u0026gt; \u0026gt; success表示成功打开界面执行的方法 \u0026gt; \u0026gt; btn是表示打开界面时下面显示的按钮 //默认 按钮一 执行的yes btn2 是按钮2 btn3是按钮三 \u0026gt; \u0026gt; yes表是第一个按钮执行的方法 \u0026gt; \u0026gt; 更多说明请参考官网\u0026lt;https://www.layui.com/doc/modules/layer.html\u0026gt; \u0026gt; \u0026gt; ``` `$(\u0026#34;#sel_good\u0026#34;).on(\u0026#34;click\u0026#34;, function () { window.parent.document.getElementById(\u0026#34;goodName\u0026#34;).value=\u0026amp;#39;MacBook pro 笔记本\u0026amp;#39;; window.parent.document.getElementById(\u0026#34;goodId\u0026#34;).value=1; var index = parent.layer.getFrameIndex(window.name); //当前iframe层的索引 // parent.layer.close(index); //再执行关闭 // layer.close(index); var e = layui.layer.open({ title: \u0026#34;选择\u0026#34;, type: 1, move: false, anim: 1, skin: \u0026#34;larry-green\u0026#34;, offset: \u0026amp;#39;10px\u0026amp;#39;, area: [400 + \u0026#34;px\u0026#34;, 300+ \u0026#34;px\u0026#34;], content: \u0026#34;再弹出一个试试！！！\u0026#34;,//后台请求地址 btn: [\u0026amp;#39;确定\u0026amp;#39;],//默认 按钮一 执行的yes btn2 是按钮2 btn3是按钮三 yes: function(index, layero){ console.log(layero, index); //do something layer.close(index); //如果设定了yes回调，需进行手工关闭 } }); }); ` typpe = 1 layer提供了5种层类型。可传入的值有：__（信息框，默认）1（页面层）2（iframe层）3（加载层）4（tips层）。 若你采用_layer.open({type: 1})_方式调用，则type为必填项（信息框除外）\nwindow.parent.document.getElementById(\u0026ldquo;goodName\u0026rdquo;).value=\u0026lsquo;MacBook pro 笔记本\u0026rsquo;;\nwindow.parent.document.getElementById(\u0026ldquo;goodId\u0026rdquo;).value=1;\n这里对上一个界面的数据的回填\nvar index = parent.layer.getFrameIndex(window.name); //当前iframe层的索引\nparent.layer.close(index); 这个表示关闭子界面\nlayer.close(index);表示关闭当前界面\n","permalink":"https://blog.zdltech.com/posts/layui-shi-zhan-zhilayuilayeropen-shi-yong/","summary":"\u003ch3 id=\"toc_0\"\u003eLayUI实战之layui.layer.open使用\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e有时候我们有这么一种需求，在开发表单界面的时候，有一行指定用户需求时，需要查询用户，由于用户是独立的表和模块，数据量大的时候，\u003c/p\u003e\n\u003cp\u003e我们不能一次查找所有数据，放到Select中供用户进行选择，这时候基本上都会需要弹出一个界面，让用户进行查询及选择，选择之后，把选择的数据在传递到上一个打开的界面；\u003c/p\u003e\n\u003cp\u003e…\u003c/p\u003e\n\u003cp\u003e没错就是通过layui.layer.open进行实现\u003c/p\u003e\n\u003cp\u003e_layer_是一款近年来备受青睐的web弹层组件，她具备全方位的解决方案，致力于服务各水平段的开发人员，您的页面会轻松地拥有丰富友好的操作体验。\u003c/p\u003e\n\u003cp\u003e接下来一步一步进行操作\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch4 id=\"toc_1\"\u003e第一步 创建工程\u003c/h4\u003e\n\u003cblockquote\u003e\n\u003cp\u003e根据自己的爱好，选择顺手的开发工具，进行创建web项目。这里我创建一个空项目\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003cimg alt=\"image-20200103150452118\" loading=\"lazy\" src=\"https://tva1.sinaimg.cn/large/006tNbRwly1gajdyx064kj30lp0dl0tv.jpg\"\u003e\u003cimg alt=\"image-20200103150528226\" loading=\"lazy\" src=\"https://tva1.sinaimg.cn/large/006tNbRwly1gajdzfv8gij30sf0g575h.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"toc_2\"\u003e第二步 添加Layui js和css\u003c/h4\u003e\n\u003cblockquote\u003e\n\u003cp\u003e通过官网 进行下载 \u003ca href=\"https://www.layui.com/\"\u003ehttps://www.layui.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e下载之后进行解压 把layui文件夹添加到项目中（参考下图）\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003cimg alt=\"image-20200103150745298\" loading=\"lazy\" src=\"https://tva1.sinaimg.cn/large/006tNbRwly1gaje1svyk9j309z03rweg.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"toc_3\"\u003e第三步 添加2个html文件\u003c/h4\u003e\n\u003cblockquote\u003e\n\u003cp\u003eindex.html\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e`\u0026lt;!DOCTYPE html\u0026gt;\n\u0026lt;html lang=\u0026ldquo;en\u0026rdquo;\u0026gt;\n\u0026lt;head\u0026gt;\n\u0026lt;meta charset=\u0026ldquo;UTF-8\u0026rdquo;\u0026gt;\n\u0026lt;title\u0026gt;LayUI测试\u0026lt;/title\u0026gt;\n\u0026lt;link href=\u0026ldquo;layui/css/layui.css\u0026rdquo;/\u0026gt;\u003c/p\u003e\n\u003cp\u003e\u0026lt;script src=\u0026ldquo;layui/layui.all.js\u0026rdquo;\u0026gt;\u0026lt;/script\u0026gt;\n\u0026lt;/head\u0026gt;\n\u0026lt;body\u0026gt;\n\u0026lt;div class=\u0026ldquo;layui-form-item \u0026quot; \u0026gt;\n\u0026lt;label class=\u0026ldquo;layui-form-label\u0026rdquo;\u0026gt;选择\u0026lt;/label\u0026gt;\n\u0026lt;div class=\u0026ldquo;layui-input-block\u0026rdquo; \u0026gt;\n\u0026lt;button style=\u0026ldquo;width: 15%\u0026rdquo; class=\u0026ldquo;layui-btn layui-btn-radius layui-btn-warm\u0026rdquo;   type=\u0026ldquo;button\u0026rdquo; id=\u0026ldquo;sel_good\u0026rdquo;  lay-filter=\u0026ldquo;sel_good\u0026rdquo;\u0026gt;点击选择\u0026lt;/button\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div class=\u0026ldquo;layui-form-item selectGood\u0026rdquo; \u0026gt;\n\u0026lt;label class=\u0026ldquo;layui-form-label\u0026rdquo;\u0026gt;所选\u0026lt;/label\u0026gt;\n\u0026lt;div class=\u0026ldquo;layui-input-block\u0026rdquo; id=\u0026ldquo;good\u0026rdquo; \u0026gt;\n\u0026lt;input type=\u0026ldquo;text\u0026rdquo; id=\u0026ldquo;goodName\u0026rdquo;   autocomplete=\u0026ldquo;off\u0026rdquo;  class=\u0026ldquo;layui-input\u0026rdquo;\u0026gt;\n\u0026lt;input type=\u0026ldquo;hidden\u0026rdquo; id=\u0026ldquo;goodId\u0026rdquo; name=\u0026ldquo;goodId\u0026rdquo;  autocomplete=\u0026ldquo;off\u0026rdquo;  class=\u0026ldquo;layui-input\u0026rdquo;\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;script src=\u0026ldquo;\u003ca href=\"https://code.jquery.com/jquery-3.4.1.min.js%22\u0026amp;gt;\u0026amp;lt;/script\"\u003ehttps://code.jquery.com/jquery-3.4.1.min.js\u0026quot;\u0026amp;gt;\u0026amp;lt;/script\u003c/a\u003e\u0026gt;\n\u0026lt;script\u0026gt;\n$(\u0026quot;#sel_good\u0026rdquo;).on(\u0026ldquo;click\u0026rdquo;, function () {\nvar e = layui.layer.open({\ntitle: \u0026ldquo;选择\u0026rdquo;,\ntype: 2,\nmove: false,\nanim: 1,\nskin: \u0026ldquo;larry-green\u0026rdquo;,\noffset: '10px',\narea: [1024\u003cem\u003e0.9 + \u0026ldquo;px\u0026rdquo;, 800\u003c/em\u003e0.9 + \u0026ldquo;px\u0026rdquo;],\ncontent: \u0026ldquo;one.html\u0026rdquo;,//后台请求地址\nsuccess: function (layero, index) {\nconsole.log(layero, index);\nconsole.log(\u0026quot;==============================================\u0026rdquo;);\nvar body = layui.layer.getChildFrame('body', index);\nconsole.log(body);\n},\nbtn: ['按钮一', '按钮二', '按钮三'],//默认 按钮一 执行的yes  btn2 是按钮2  btn3是按钮三\nyes: function(index, layero){\nconsole.log(layero, index);\n//do something\nlayer.close(index); //如果设定了yes回调，需进行手工关闭\n}\n});\n});\n//https://www.layui.com/doc/modules/layer.html#btn\n\u0026lt;/script\u0026gt;\n\u0026lt;/body\u0026gt;\n\u0026lt;/html\u0026gt;\n`\u003c/p\u003e","title":"LayUI实战之layui-layer.open使用"},{"content":" 第一类：请求路径参数\n1、@PathVariable\n获取路径参数。即url/{id}这种形式。\n2、@RequestParam\n获取查询参数。即url?name=这种形式\n例子\nGET\nhttp://localhost:8080/demo/123?name=suki_rong\n对应的java代码：\n@GetMapping(\u0026#34;/demo/{id}\u0026#34;) public void demo(@PathVariable(name = \u0026#34;id\u0026#34;) String id, @RequestParam(name = \u0026#34;name\u0026#34;) String name) { System.out.println(\u0026#34;id=\u0026#34;+id); System.out.println(\u0026#34;name=\u0026#34;+name); } 输出结果：\nid=123\nname=suki_rong\n第二类：Body参数 因为是POST请求，这里用Postman的截图结合代码说明\n1、@RequestBody 例子：\n对应的java代码：\n@PostMapping(path = \u0026#34;/demo1\u0026#34;) public void demo1(@RequestBody Person person) { System.out.println(person.toString()); } 输出结果：\nname:suki_rong;age=18;hobby:programing\n也可以是这样\n@PostMapping(path = \u0026#34;/demo1\u0026#34;) public void demo1(@RequestBody Map\u0026amp;lt;String, String\u0026amp;gt; person) { System.out.println(person.get(\u0026#34;name\u0026#34;)); } 输出结果：\nsuki_rong\n2、无注解 例子 {#例子-2.wp-block-heading} 对应的java代码：\n@PostMapping(path = \u0026#34;/demo2\u0026#34;) public void demo2(Person person) { System.out.println(person.toString()); } 输出结果：\nname:suki_rong;age=18;hobby:programing\nPerson类 {#person类.wp-block-heading} public class Person { private long id; private String name; private int age; private String hobby; @Override public String toString(){ return \u0026#34;name:\u0026#34;+name+\u0026#34;;age=\u0026#34;+age+\u0026#34;;hobby:\u0026#34;+hobby; } // getters and setters } 第三类：请求头参数以及Cookie 1、@RequestHeader 2、@CookieValue 例子 java代码：\n@GetMapping(\u0026#34;/demo3\u0026#34;) public void demo3(@RequestHeader(name = \u0026#34;myHeader\u0026#34;) String myHeader, @CookieValue(name = \u0026#34;myCookie\u0026#34;) String myCookie) { System.out.println(\u0026#34;myHeader=\u0026#34; + myHeader); System.out.println(\u0026#34;myCookie=\u0026#34; + myCookie); } 也可以这样：\n@GetMapping(\u0026#34;/demo3\u0026#34;) public void demo3(HttpServletRequest request) { System.out.println(request.getHeader(\u0026#34;myHeader\u0026#34;)); for (Cookie cookie : request.getCookies()) { if (\u0026#34;myCookie\u0026#34;.equals(cookie.getName())) { System.out.println(cookie.getValue()); } } } 地址传值\n@PathVariable\n获取路径参数。即url/{id}这种形式。\n? 传值\n@RequestParam\n获取查询参数。即url?name=这种形式\n用注解@RequestParam绑定请求参数到方法入参\n当请求参数username不存在时会有异常发生,可以通过设置属性required=false解决,例如: @RequestParam(value=“username”, required=false)\nBody参数\n//application/jason\n@PostMapping(path = “/demo1”)\npublic void demo1(@RequestBody Person person) {\n无注解（form提交）\n//form-data\n@PostMapping(path = “/demo1”)\npublic void demo1(Person person) {\n请求头参数以及Cookie\n@RequestHeader\n2、@CookieValue\n例子\njava代码：\n@GetMapping(“/demo3”)\npublic void demo3(@RequestHeader(name = “myHeader”) String myHeader,\n@CookieValue(name = “myCookie”) String myCookie) {\nSystem.out.println(“myHeader=” + myHeader);\nSystem.out.println(“myCookie=” + myCookie);\n也可以这样\n@GetMapping(“/demo3”)\npublic void demo3(HttpServletRequest request) {\nSystem.out.println(request.getHeader(“myHeader”));\nfor (Cookie cookie : request.getCookies()) {\nif (“myCookie”.equals(cookie.getName())) {\nSystem.out.println(cookie.getValue());\n//请求头参数以及Cookie\n@RequestMapping(“request5”)\npublic String test5(@RequestHeader(name =”Header”) String Header,\n@CookieValue(name =”cookie1″) String cookie1,\n@CookieValue(name =”cookie2″) String cookie2){\nreturn “Header:”+Header+”cookie1:”+cookie1+”cookie2″+cookie2;\n}\n//Cookie\n@GetMapping(“/ee”)\npublic String ee(@RequestHeader(name=”myHeader”) String myHeader,@CookieValue(name=”myCookie”) String myCookie){\nSystem.out.println(“myHeader=” + myHeader);\nSystem.out.println(“myCookie=” + myCookie);\nreturn “———“+myHeader+”=============”+myCookie;\n}\n表单的参数写在Controller相应的方法的形参中\n适用于get方式提交，不适用于post方式提交。\n/**\n1.直接把表单的参数写在Controller相应的方法的形参中\n@param username\n@param password\n@return */ @RequestMapping(“/addUser1”) public String addUser1(String username,String password) { System.out.println(“username is:”+username);\n@ModelAttribute注解获取POST请求的FORM表单数据\n/**\n使用@ModelAttribute注解获取POST请求的FORM表单数据\n@param user\n@return */ @RequestMapping(value=”/addUser5″,method=RequestMethod.POST) public String addUser5(@ModelAttribute(“user”) UserModel user) { System.out.println(“username is:”+user.getUsername()); System.out.println(“password is:”+user.getPassword()); return “demo/index”;\n测试代码\nController\npackage com.zz.controller;\nimport java.util.HashMap;\nimport java.util.Map;\nimport com.zz.entity.User;\nimport org.springframework.web.bind.annotation.*;\n@RestController\n@RequestMapping(“test”)\npublic class TestController {\n`//路径传值 @RequestMapping(\u0026#34;t1/{p1}\u0026#34;) public Map t1(@PathVariable(\u0026#34;p1\u0026#34;) String paramter1){ Map map=new HashMap(); map.put(\u0026#34;rs\u0026#34;,paramter1); return map; } //? 传值 @RequestMapping(\u0026#34;t2\u0026#34;) public Map t2(@RequestParam(\u0026#34;p1\u0026#34;) String paramter1) { System.out.println(paramter1); Map map=new HashMap(); map.put(\u0026#34;rs\u0026#34;,paramter1); return map; } //Body参数` //application/jason\n@RequestMapping(“t3”)\npublic Map t3(@RequestBody User person){\n` Map map=new HashMap(); map.put(\u0026#34;rs\u0026#34;,person.getName()); return map; }` // 无注解（form提交）\n//form-data\n@RequestMapping(“t4”)\npublic Map t4(User person){\n` Map map=new HashMap(); map.put(\u0026#34;rs\u0026#34;,person.getName()); return map; }` // 请求头参数以及Cookie\n@RequestMapping(“t5”)\npublic Map t5(@RequestHeader(name =”myHeader”) String myHeader,\n@CookieValue(name = “myCookie”) String myCookie){\nSystem.out.println(“myHeader=” + myHeader);\nSystem.out.println(“myCookie=” + myCookie);\nMap map=new HashMap();\nmap.put(“rs”,myHeader);\nreturn map;\n}\n// 表单的参数写在Controller相应的方法的形参中\n// 适用于get方式提交，不适用于post方式提交。\n@RequestMapping(“t6”)\npublic Map t6(String name,String pwd){\n` Map map=new HashMap(); map.put(\u0026#34;rs\u0026#34;,name); return map; }` Bootstrap 实例\n测试 SpringBoot Form post 提交 跳转失败 解决办法\n报错日志：tSupportedException: Request method ‘POST’ not supported\n解决： post controller方法里面 通过 return “redirect:/index/toIndex”; 执行get的跳转controller\npackage com.zz.controller;/**\n@Description: 描述\n@Author: Bsea\n@CreateDate: ${Date} */\nimport com.zz.config.DataValidationException;\nimport com.zz.entity.Member;\nimport com.zz.form.MemberForm;\nimport com.zz.service.MemberService;\nimport com.zz.util.FormUtil;\nimport com.zz.util.ResultVOUtil;\nimport com.zz.vo.ResultVO;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport io.swagger.annotations.ApiOperation;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.data.domain.Page;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.web.bind.annotation.*;\nimport javax.annotation.Resource;\nimport javax.validation.Valid;\n/**\n@Description: java类作用描述\n@Author: Bsea\n@CreateDate: 2019/10/1621:27 */ @Api(value = “会员控制器”) @Controller @RequestMapping(“index”) public class IndexController { @Resource MemberService memberService; @ApiOperation(value = “添加会员”, notes = “根据名字查找会员”) @ApiImplicitParam(name = “name”, value = “会员名字”, required = true, dataType = “String”,paramType = “path”) @PostMapping(“add”) public String add(@Valid MemberForm member, BindingResult bindingResult){ System.out.println(member); if(bindingResult.hasErrors()){ throw new DataValidationException(“验证错误”); } Member member1=new Member(); BeanUtils.copyProperties(member,member1); if(memberService.add(member1)!=null){ return “redirect:/index/toIndex”; }else{ return “redirect:/index/toIndex”; } } @RequestMapping(“toIndex”) public String toIndex(){ return “/index2.html”; } }\n","permalink":"https://blog.zdltech.com/posts/springboot-controller%E6%8E%A5%E6%94%B6%E5%8F%82%E6%95%B0%E7%9A%84%E5%87%A0%E7%A7%8D%E5%B8%B8%E7%94%A8%E6%96%B9%E5%BC%8F/","summary":"\u003cp\u003e\u003cstrong\u003e 第一类：请求路径参数\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1、@PathVariable\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e获取路径参数。即url/{id}这种形式。\u003cbr\u003e\n\u003cstrong\u003e2、@RequestParam\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e获取查询参数。即url?name=这种形式\u003cbr\u003e\n\u003cstrong\u003e例子\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eGET\u003cbr\u003e\nhttp://localhost:8080/demo/123?name=suki_rong\u003cbr\u003e\n对应的java代码：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@GetMapping(\u0026#34;/demo/{id}\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public void demo(@PathVariable(name = \u0026#34;id\u0026#34;) String id, @RequestParam(name = \u0026#34;name\u0026#34;) String name) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System.out.println(\u0026#34;id=\u0026#34;+id);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System.out.println(\u0026#34;name=\u0026#34;+name);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输出结果：\u003cbr\u003e\nid=123\u003cbr\u003e\nname=suki_rong\u003c/p\u003e\n\u003ch1 id=\"第二类body参数.wp-block-heading\"\u003e第二类：Body参数\u003c/h1\u003e\n\u003cp\u003e因为是POST请求，这里用Postman的截图结合代码说明\u003c/p\u003e\n\u003ch2 id=\"1requestbody.wp-block-heading\"\u003e1、@RequestBody\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e例子：\u003c/strong\u003e\u003cfigure class=\"wp-block-image\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img2018.cnblogs.com/blog/1593395/201905/1593395-20190530161322597-1719734558.jpg\"\u003e \u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e对应的java代码：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@PostMapping(path = \u0026#34;/demo1\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic void demo1(@RequestBody Person person) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    System.out.println(person.toString());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输出结果：\u003cbr\u003e\nname:suki_rong;age=18;hobby:programing\u003c/p\u003e\n\u003cp\u003e也可以是这样\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@PostMapping(path = \u0026#34;/demo1\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic void demo1(@RequestBody Map\u0026amp;lt;String, String\u0026amp;gt; person) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    System.out.println(person.get(\u0026#34;name\u0026#34;));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输出结果：\u003cbr\u003e\nsuki_rong\u003c/p\u003e","title":"SpringBoot Controller接收参数的几种常用方式"},{"content":"webpack 简单使用 webpack是目前前端开发最流行的打包工具之一，今天就一步一步构建\n初始化npm工程 npm init 创建npm 工程 根据自己的需求进行配置项目\n添加webpack 依赖 npm i webpack –save-dev\n安装webpack\n安装成功之后，在package.json中在 devDependencies中有 webpack\n使用webpack打包 js 创建js文件\n创建module.js 创建app.js module.js 文件内容\nexport const log = function(){\n​ // document.write(\u0026lsquo;module.js loaded\u0026rsquo;);\n​ console.log(\u0026lsquo;module.js loaded\u0026rsquo;);\n}\napp.js\nimport moduleLog from \u0026lsquo;./module.js\u0026rsquo;;\nimport \u0026lsquo;./style.css\u0026rsquo;;\nmoduleLog();\ndocument.write(\u0026lsquo;app.js loaded\u0026rsquo;);\n创建index.html \u003c!DOCTYPE html\u003e \u0026lt;script src=\u0026quot;dist/bundle.js\u0026quot;\u0026gt;\u0026lt;/script\u0026gt; 创建完成之后，我们开始webpack打包 app.js\n./node_modules/.bin/webpack app.js -o dist/bundle.js\n执行完成 直接运行index.html 查看运行结果\napp.js loadedmodule.js loaded\n配置webpack.config.js 通常我们使用webpack命令行进行打包的时候，简单的话，还没有关系，要是想实现更多的功能的时候，我们不能一直添加很长很长的命令行吧，每次打包，你记得住吗？为此我们需要创建 webpack.config.js\nconst path = require(\u0026lsquo;path\u0026rsquo;);\nconst UglifyJsPlugin = require(\u0026lsquo;uglifyjs-webpack-plugin\u0026rsquo;);\nmodule.exports = {\n​ entry: \u0026lsquo;./app.js\u0026rsquo;,\n​ output: {\n​ path: path.join(__dirname,\u0026lsquo;dist\u0026rsquo;),\n​ publicPath: \u0026lsquo;./dist/\u0026rsquo;,\n​ filename: \u0026lsquo;bundle.js\u0026rsquo;\n​ },\n​ devServer: {\n​ port: 3000,//服务端口\n​ publicPath: \u0026lsquo;dist\u0026rsquo;//打包后资源路径，后面会详细解释\n​ },\n​ module: {\n​ rules: [\n​ {\n​ test: /.css$/,\n​ loader: style-loader!css-loader\n​ }\n​ ]\n​ },\n​ plugins: [\n​ new UglifyJsPlugin()\n​ ]\n}\nentry： 打包入口\noutput: 输出配置\n​ path: 路径配置\n​ publicPath: 公共路径\n​ filename：打包后的文件名称\ndevServer： 测试开发服务-可以选的，建议配置，可以实时编译\nmodules: 配置加载自定义loader\n​ rules：表示loader的数组\n​ test： loader处理文件的正则表达式\n​ loader： loader的名称，通过npm i xxx-loader 安装的各种文件解析的loader\nplugins： 工程使用到的插件\npackage.json\n{\n\u0026ldquo;name\u0026rdquo;: \u0026ldquo;webpack_test\u0026rdquo;,\n\u0026ldquo;version\u0026rdquo;: \u0026ldquo;1.0.0\u0026rdquo;,\n\u0026ldquo;description\u0026rdquo;: \u0026ldquo;\u0026rdquo;,\n\u0026ldquo;main\u0026rdquo;: \u0026ldquo;index.js\u0026rdquo;,\n\u0026ldquo;scripts\u0026rdquo;: {\n​ \u0026ldquo;test\u0026rdquo;: \u0026ldquo;echo \u0026ldquo;Error: no test specified\u0026rdquo; \u0026amp;\u0026amp; exit 1\u0026rdquo;\n},\n\u0026ldquo;author\u0026rdquo;: \u0026ldquo;\u0026rdquo;,\n\u0026ldquo;license\u0026rdquo;: \u0026ldquo;ISC\u0026rdquo;,\n\u0026ldquo;devDependencies\u0026rdquo;: {\n​ \u0026ldquo;css-loader\u0026rdquo;: \u0026ldquo;3.3.2\u0026rdquo;,\n​ \u0026ldquo;style-loader\u0026rdquo;: \u0026ldquo;1.0.1\u0026rdquo;,\n​ \u0026ldquo;uglifyjs-webpack-plugin\u0026rdquo;: \u0026ldquo;2.2.0\u0026rdquo;,\n​ \u0026ldquo;webpack\u0026rdquo;: \u0026ldquo;4.41.2\u0026rdquo;,\n​ \u0026ldquo;webpack-cli\u0026rdquo;: \u0026ldquo;3.3.10\u0026rdquo;,\n​ \u0026ldquo;webpack-dev-server\u0026rdquo;: \u0026ldquo;3.9.0\u0026rdquo;\n}\n}\n这个是整个工程的package.json文件\nbody{\n​ text-align: center;\n​ padding: 100px;\n​ color: #fff;\n​ background-color: #09c;\n}\nstyle.css 文件\n","permalink":"https://blog.zdltech.com/posts/webpack-jian-dan-shi-yong/","summary":"\u003ch3 id=\"toc_0\"\u003ewebpack 简单使用\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003ewebpack是目前前端开发最流行的打包工具之一，今天就一步一步构建\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch4 id=\"toc_1\"\u003e初始化npm工程\u003c/h4\u003e\n\u003cblockquote\u003e\n\u003cp\u003enpm init 创建npm 工程 根据自己的需求进行配置项目\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch4 id=\"toc_2\"\u003e添加webpack 依赖\u003c/h4\u003e\n\u003cblockquote\u003e\n\u003cp\u003enpm i webpack –save-dev\u003c/p\u003e\n\u003cp\u003e安装webpack\u003c/p\u003e\n\u003cp\u003e安装成功之后，在package.json中在 devDependencies中有 webpack\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch4 id=\"toc_3\"\u003e使用webpack打包 js\u003c/h4\u003e\n\u003cblockquote\u003e\n\u003cp\u003e创建js文件\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e创建module.js\u003c/li\u003e\n\u003cli\u003e创建app.js\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003emodule.js 文件内容\u003c/p\u003e\n\u003cp\u003eexport const log = function(){\u003c/p\u003e\n\u003cp\u003e​ // document.write(\u0026lsquo;module.js loaded\u0026rsquo;);\u003c/p\u003e\n\u003cp\u003e​ console.log(\u0026lsquo;module.js loaded\u0026rsquo;);\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003eapp.js\u003c/p\u003e\n\u003cp\u003eimport moduleLog from \u0026lsquo;./module.js\u0026rsquo;;\u003c/p\u003e\n\u003cp\u003eimport \u0026lsquo;./style.css\u0026rsquo;;\u003c/p\u003e\n\u003cp\u003emoduleLog();\u003c/p\u003e\n\u003cp\u003edocument.write(\u0026lsquo;app.js loaded\u0026rsquo;);\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e创建index.html\u003c/li\u003e\n\u003c/ol\u003e\n\u003c!DOCTYPE html\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;script src=\u0026quot;dist/bundle.js\u0026quot;\u0026gt;\u0026lt;/script\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n\u003cp\u003e创建完成之后，我们开始webpack打包 app.js\u003c/p\u003e\n\u003cp\u003e./node_modules/.bin/webpack app.js -o dist/bundle.js\u003c/p\u003e\n\u003cp\u003e执行完成 直接运行index.html 查看运行结果\u003c/p\u003e\n\u003cp\u003eapp.js loadedmodule.js loaded\u003c/blockquote\u003e\u003c/p\u003e\n\u003ch4 id=\"toc_4\"\u003e配置webpack.config.js\u003c/h4\u003e\n\u003cblockquote\u003e\n\u003cp\u003e通常我们使用webpack命令行进行打包的时候，简单的话，还没有关系，要是想实现更多的功能的时候，我们不能一直添加很长很长的命令行吧，每次打包，你记得住吗？为此我们需要创建 webpack.config.js\u003c/p\u003e","title":"webpack 简单使用"},{"content":"Spring boot+mybatis+Sqlite+mybatis-generator环境配置 有的时候 我们开发不需要一定要用到mysql、oracle等数据库，Sqlite也是我们的一种选择。\nSqlite使用场景 小型网站\nSQLite适用于中小规模流量的网站.\n日访问在10万以下的网站可以很好的支持,适用于读多写少的操作,如管理员在后台添加数据,其他访客多为浏览.\n10万/天是一个临界值,事实上在100万的数据量之下,SQLite的表现还是可以的,在往上就不适合了.\n使用它无需单独购买数据库服务,无需服务器进程,配置成本几乎为零,加上数据的导入导出都是复制文件,维护难度也几乎为零,迁移到别的服务器无需任何配置即可支持,加上其读取的速度非常快,省去了远程数据库的链接,能够极大提升网站访问速度.\n嵌入式设备 SQLite适用于手机, PDA, 机顶盒, 以及其他嵌入式设备. 作为一个嵌入式数据库它也能够很好的应用于客户端程序.\n因为其轻量,小巧,不怎么占用内存,数据的读写性能好,加上嵌入式设备数据量并不大,不需要频繁的维护,所以比较适合.\n数据库教学 SQLite 支持 SQL92（SQL2）标准的大多数查询语言的功能。\n其无配置,无依赖,小巧,单一文件的特性让它的安装和使用非常简单,非常适合用来讲解SQL语句.\n学生可以在很短的时候使用并操作SQLite,不受系统和商业限制等影响,学习的结果可以通过邮件或者云文件等形式发送给老师进行评分.\n可以通过它快速实现一个最小化应用,适合学生快速了解SQLite,以及SQL语法,从而实现数据库的触类旁通,了解其他数据库系统的设计实现原则.\n本地应用程序 其单一磁盘文件的特性,并且不支持远程连接,使其适用于本地的应用程序,如PC客户端软件.\n常用的应用类型为金融分析工具、CAD 包、档案管理程序等等. (手机上的通讯录也是用此开发的)\n没有远程,意味着适用于内部或者临时的数据库,用来处理一些数据,让程序更加灵活.\n不适用场景 很明显其适合小型网站,相对的就不适合高流量网站.,也不适合超大的数据集,在其缺点也提到,不适合高并发访问.\nPOM.xm配置 `\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;UTF-8\u0026rdquo;?\u0026gt; \u0026lt;project xmlns=\u0026ldquo;http://maven.apache.org/POM/4.0.0\u0026quot; xmlns:xsi=\u0026ldquo;http://www.w3.org/2001/XMLSchema-instance\u0026quot; xsi:schemaLocation=\u0026ldquo;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\u0026quot;\u0026gt; \u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt; \u0026lt;parent\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-parent\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.2.1.RELEASE\u0026lt;/version\u0026gt; \u0026lt;relativePath/\u0026gt; \u0026lt;!\u0026ndash; lookup parent from repository \u0026ndash;\u0026gt; \u0026lt;/parent\u0026gt; \u0026lt;groupId\u0026gt;com.zdltech.test\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;sqlitetest\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;0.0.1-SNAPSHOT\u0026lt;/version\u0026gt; \u0026lt;name\u0026gt;sqlitetest\u0026lt;/name\u0026gt; \u0026lt;description\u0026gt;Demo project for Spring Boot\u0026lt;/description\u0026gt;\n\u0026amp;lt;properties\u0026amp;gt; \u0026amp;lt;java.version\u0026amp;gt;1.8\u0026amp;lt;/java.version\u0026amp;gt; \u0026amp;lt;/properties\u0026amp;gt; \u0026amp;lt;dependencies\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-jdbc\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-thymeleaf\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-web\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.mybatis.spring.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;mybatis-spring-boot-starter\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;2.1.1\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-test\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;scope\u0026amp;gt;test\u0026amp;lt;/scope\u0026amp;gt; \u0026amp;lt;exclusions\u0026amp;gt; \u0026amp;lt;exclusion\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.junit.vintage\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;junit-vintage-engine\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/exclusion\u0026amp;gt; \u0026amp;lt;/exclusions\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;!-- https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc --\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.xerial\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;sqlite-jdbc\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;3.28.0\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;!-- druid--\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;com.alibaba\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;druid\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;1.1.14\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;/dependencies\u0026amp;gt; \u0026amp;lt;build\u0026amp;gt; \u0026amp;lt;plugins\u0026amp;gt; \u0026amp;lt;plugin\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-maven-plugin\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/plugin\u0026amp;gt; \u0026amp;lt;plugin\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.mybatis.generator\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;mybatis-generator-maven-plugin\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;1.3.7\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;/plugin\u0026amp;gt; \u0026amp;lt;/plugins\u0026amp;gt; \u0026amp;lt;/build\u0026amp;gt; \u0026lt;/project\u0026gt; `\n### application.properties配置 {#toc_7} \u0026gt; ``` `server.port=19999 server.servlet.context-path=/sqlite # thymeleaf spring.thymeleaf.cache=false spring.thymeleaf.encoding=utf-8 spring.thymeleaf.prefix=classpath:templates/ spring.thymeleaf.servlet.content-type=text/html spring.thymeleaf.suffix=.html spring.thymeleaf.mode=HTML5 # Sqlite数据库配置 spring.datasource.driver-class-name=org.sqlite.JDBC spring.datasource.url=jdbc:sqlite:./sqlite_db.db spring.datasource.username= spring.datasource.password= # H2数据库配置 # spring.datasource.driver-class-name=org.h2.Driver #spring.datasource.url=jdbc:h2:file:/Users/jason/Desktop/DemoWorkspace/sqlitetest/zdl #spring.datasource.username=sa #spring.datasource.password= spring.h2.console.path=/h2-consle spring.h2.console.enabled=true spring.h2.console.settings.web-allow-others=true spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.tomcat.validation-query=select 1 spring.datasource.tomcat.initial-size=1 spring.datasource.tomcat.min-idle=3 spring.datasource.tomcat.max-active=20 # 配置mapper文件路径 mybatis.mapper-locations=classpath:mapper/**/*.xml ` generatorConfig.xml配置 `\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;UTF-8\u0026rdquo;?\u0026gt; \u0026lt;!DOCTYPE generatorConfiguration PUBLIC \u0026ldquo;-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN\u0026rdquo; \u0026ldquo;http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd\u0026quot;\u0026gt;\n\u0026lt;!\u0026ndash; classPath:数据库的JDBC驱动\u0026ndash;\u0026gt; \u0026lt;generatorConfiguration\u0026gt; \u0026lt;classPathEntry location=\u0026quot;/Users/jason/.m2/repository/org/xerial/sqlite-jdbc/3.28.0/sqlite-jdbc-3.28.0.jar\u0026rdquo;/\u0026gt;\n\u0026amp;lt;!-- \u0026amp;lt;classPathEntry--\u0026amp;gt; \u0026amp;lt;!-- location=\u0026quot;/Users/jason/.m2/repository/com/h2database/h2/1.4.200/h2-1.4.200.jar\u0026quot;/\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;context id=\u0026quot;default\u0026quot; targetRuntime=\u0026quot;MyBatis3\u0026quot;\u0026amp;gt; \u0026amp;lt;commentGenerator\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;suppressDate\u0026quot; value=\u0026quot;false\u0026quot;/\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;suppressAllComments\u0026quot; value=\u0026quot;true\u0026quot;/\u0026amp;gt; \u0026amp;lt;/commentGenerator\u0026amp;gt; \u0026amp;lt;jdbcConnection driverClass=\u0026quot;org.sqlite.JDBC\u0026quot;--\u0026amp;gt; \u0026amp;lt;!--connectionURL=\u0026quot;jdbc:sqlite:./sqlite_db.db\u0026quot;--\u0026amp;gt; \u0026amp;lt;!--userId=\u0026quot;\u0026quot;--\u0026amp;gt; \u0026amp;lt;!--password=\u0026quot;\u0026quot;/\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;jdbcConnection driverClass=\u0026quot;org.h2.Driver\u0026quot; connectionURL=\u0026quot;jdbc:h2:file:/Users/jason/Desktop/DemoWorkspace/sqlitetest/zdl\u0026quot; userId=\u0026quot;sa\u0026quot; password=\u0026quot;\u0026quot;/\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--Java Entity生成器 --\u0026amp;gt; \u0026amp;lt;javaModelGenerator targetPackage=\u0026quot;com.zdltech.test.sqlitetest.entity\u0026quot; targetProject=\u0026quot;./src/main/java\u0026quot;\u0026amp;gt; \u0026amp;lt;!-- TODO enableSubPackages:是否让schema作为包的后缀--\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;enableSubPackages\u0026quot; value=\u0026quot;false\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- 从数据库返回的值被清理前后的空格--\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;trimStrings\u0026quot; value=\u0026quot;true\u0026quot;/\u0026amp;gt; \u0026amp;lt;/javaModelGenerator\u0026amp;gt; \u0026amp;lt;!--map xml生成器 --\u0026amp;gt; \u0026amp;lt;sqlMapGenerator targetPackage=\u0026quot;mapper\u0026quot; targetProject=\u0026quot;./src/main/resources\u0026quot;\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;enableSubPackages\u0026quot; value=\u0026quot;false\u0026quot;/\u0026amp;gt; \u0026amp;lt;/sqlMapGenerator\u0026amp;gt; \u0026amp;lt;!-- dao生成器--\u0026amp;gt; \u0026amp;lt;javaClientGenerator targetPackage=\u0026quot;com.zdltech.test.sqlitetest.dao\u0026quot; targetProject=\u0026quot;./src/main/java\u0026quot; type=\u0026quot;XMLMAPPER\u0026quot;\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;enableSubPackages\u0026quot; value=\u0026quot;false\u0026quot;/\u0026amp;gt; \u0026amp;lt;/javaClientGenerator\u0026amp;gt; \u0026amp;lt;!-- 数据表与Bean的映射 --\u0026amp;gt; \u0026amp;lt;table tableName=\u0026quot;tb_user\u0026quot; domainObjectName=\u0026quot;UserEntityMap\u0026quot; enableCountByExample=\u0026quot;false\u0026quot; enableUpdateByExample=\u0026quot;false\u0026quot; enableDeleteByExample=\u0026quot;false\u0026quot; enableSelectByExample=\u0026quot;false\u0026quot; selectByExampleQueryId=\u0026quot;false\u0026quot; \u0026amp;gt; \u0026amp;lt;!-- 如果设置为true，生成的model类会直接使用column本身的名字，而不会再使用驼峰命名方法，比如BORN_DATE，生成的属性名字就是BORN_DATE,而不会是bornDate --\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;useActualColumnNames\u0026quot; value=\u0026quot;true\u0026quot;/\u0026amp;gt; \u0026amp;lt;/table\u0026amp;gt; \u0026amp;lt;/context\u0026amp;gt; \u0026lt;/generatorConfiguration\u0026gt; `\n### 测试Controller 是否正常连接数据库 {#toc_9} \u0026gt; ``` `import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; @Controller @RequestMapping(\u0026#34;/index\u0026#34;) public class IndexController { @Autowired DataSource dataSource; /** * * @return */ @ResponseBody @RequestMapping(\u0026#34;index\u0026#34;) public String index(){ try { Connection conn = dataSource.getConnection(); System.out.println(\u0026#34;*************************\u0026#34;); System.out.println(conn); DruidDataSource dss = (DruidDataSource) dataSource; System.out.println(dss.getName()); System.out.println(dss.getValidationQuery()); System.out.println(dss.getTimeBetweenEvictionRunsMillis()); System.out.println(dss.getMinEvictableIdleTimeMillis()); System.out.println(dataSource.getClass().getName()); System.out.println(dss); System.out.println(\u0026#34;**************************\u0026#34;); conn.close(); } catch (SQLException e) { e.printStackTrace(); } return \u0026#34;index is run\u0026#34;; } } ` ","permalink":"https://blog.zdltech.com/posts/spring-bootmybatissqlite-huan-jing-pei-zhi/","summary":"\u003ch2 id=\"toc_0\"\u003eSpring boot+mybatis+Sqlite+mybatis-generator环境配置\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e有的时候 我们开发不需要一定要用到mysql、oracle等数据库，Sqlite也是我们的一种选择。\u003c/p\u003e\n\u003ch3 id=\"toc_1\"\u003eSqlite使用场景\u003c/h3\u003e\n\u003cp\u003e小型网站\u003c/p\u003e\n\u003cp\u003eSQLite适用于中小规模流量的网站.\u003c/p\u003e\n\u003cp\u003e日访问在10万以下的网站可以很好的支持,适用于读多写少的操作,如管理员在后台添加数据,其他访客多为浏览.\u003c/p\u003e\n\u003cp\u003e10万/天是一个临界值,事实上在100万的数据量之下,SQLite的表现还是可以的,在往上就不适合了.\u003c/p\u003e\n\u003cp\u003e使用它无需单独购买数据库服务,无需服务器进程,配置成本几乎为零,加上数据的导入导出都是复制文件,维护难度也几乎为零,迁移到别的服务器无需任何配置即可支持,加上其读取的速度非常快,省去了远程数据库的链接,能够极大提升网站访问速度.\u003c/p\u003e\n\u003ch3 id=\"toc_2\"\u003e嵌入式设备\u003c/h3\u003e\n\u003cp\u003eSQLite适用于手机, PDA, 机顶盒, 以及其他嵌入式设备. 作为一个嵌入式数据库它也能够很好的应用于客户端程序.\u003c/p\u003e\n\u003cp\u003e因为其轻量,小巧,不怎么占用内存,数据的读写性能好,加上嵌入式设备数据量并不大,不需要频繁的维护,所以比较适合.\u003c/p\u003e\n\u003ch3 id=\"toc_3\"\u003e数据库教学\u003c/h3\u003e\n\u003cp\u003eSQLite 支持 SQL92（SQL2）标准的大多数查询语言的功能。\u003c/p\u003e\n\u003cp\u003e其无配置,无依赖,小巧,单一文件的特性让它的安装和使用非常简单,非常适合用来讲解SQL语句.\u003c/p\u003e\n\u003cp\u003e学生可以在很短的时候使用并操作SQLite,不受系统和商业限制等影响,学习的结果可以通过邮件或者云文件等形式发送给老师进行评分.\u003c/p\u003e\n\u003cp\u003e可以通过它快速实现一个最小化应用,适合学生快速了解SQLite,以及SQL语法,从而实现数据库的触类旁通,了解其他数据库系统的设计实现原则.\u003c/p\u003e\n\u003ch3 id=\"toc_4\"\u003e本地应用程序\u003c/h3\u003e\n\u003cp\u003e其单一磁盘文件的特性,并且不支持远程连接,使其适用于本地的应用程序,如PC客户端软件.\u003c/p\u003e\n\u003cp\u003e常用的应用类型为金融分析工具、CAD 包、档案管理程序等等. (手机上的通讯录也是用此开发的)\u003c/p\u003e\n\u003cp\u003e没有远程,意味着适用于内部或者临时的数据库,用来处理一些数据,让程序更加灵活.\u003c/p\u003e\n\u003ch1 id=\"toc_5\"\u003e不适用场景\u003c/h1\u003e\n\u003cp\u003e很明显其适合小型网站,相对的就不适合高流量网站.,也不适合超大的数据集,在其缺点也提到,不适合高并发访问.\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"toc_6\"\u003ePOM.xm配置\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e`\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;UTF-8\u0026rdquo;?\u0026gt;\n\u0026lt;project xmlns=\u0026ldquo;\u003ca href=\"http://maven.apache.org/POM/4.0.0%22\"\u003ehttp://maven.apache.org/POM/4.0.0\u0026quot;\u003c/a\u003e xmlns:xsi=\u0026ldquo;\u003ca href=\"http://www.w3.org/2001/XMLSchema-instance%22\"\u003ehttp://www.w3.org/2001/XMLSchema-instance\u0026quot;\u003c/a\u003e\nxsi:schemaLocation=\u0026ldquo;\u003ca href=\"http://maven.apache.org/POM/4.0.0\"\u003ehttp://maven.apache.org/POM/4.0.0\u003c/a\u003e \u003ca href=\"https://maven.apache.org/xsd/maven-4.0.0.xsd%22\"\u003ehttps://maven.apache.org/xsd/maven-4.0.0.xsd\u0026quot;\u003c/a\u003e\u0026gt;\n\u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt;\n\u0026lt;parent\u0026gt;\n\u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt;\n\u0026lt;artifactId\u0026gt;spring-boot-starter-parent\u0026lt;/artifactId\u0026gt;\n\u0026lt;version\u0026gt;2.2.1.RELEASE\u0026lt;/version\u0026gt;\n\u0026lt;relativePath/\u0026gt; \u0026lt;!\u0026ndash; lookup parent from repository \u0026ndash;\u0026gt;\n\u0026lt;/parent\u0026gt;\n\u0026lt;groupId\u0026gt;com.zdltech.test\u0026lt;/groupId\u0026gt;\n\u0026lt;artifactId\u0026gt;sqlitetest\u0026lt;/artifactId\u0026gt;\n\u0026lt;version\u0026gt;0.0.1-SNAPSHOT\u0026lt;/version\u0026gt;\n\u0026lt;name\u0026gt;sqlitetest\u0026lt;/name\u0026gt;\n\u0026lt;description\u0026gt;Demo project for Spring Boot\u0026lt;/description\u0026gt;\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026amp;lt;properties\u0026amp;gt;\n    \u0026amp;lt;java.version\u0026amp;gt;1.8\u0026amp;lt;/java.version\u0026amp;gt;\n\u0026amp;lt;/properties\u0026amp;gt;\n\n\u0026amp;lt;dependencies\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-jdbc\u0026amp;lt;/artifactId\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-thymeleaf\u0026amp;lt;/artifactId\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-web\u0026amp;lt;/artifactId\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.mybatis.spring.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;mybatis-spring-boot-starter\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;version\u0026amp;gt;2.1.1\u0026amp;lt;/version\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-test\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;scope\u0026amp;gt;test\u0026amp;lt;/scope\u0026amp;gt;\n        \u0026amp;lt;exclusions\u0026amp;gt;\n            \u0026amp;lt;exclusion\u0026amp;gt;\n                \u0026amp;lt;groupId\u0026amp;gt;org.junit.vintage\u0026amp;lt;/groupId\u0026amp;gt;\n                \u0026amp;lt;artifactId\u0026amp;gt;junit-vintage-engine\u0026amp;lt;/artifactId\u0026amp;gt;\n            \u0026amp;lt;/exclusion\u0026amp;gt;\n        \u0026amp;lt;/exclusions\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;!-- https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc --\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.xerial\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;sqlite-jdbc\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;version\u0026amp;gt;3.28.0\u0026amp;lt;/version\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;!-- druid--\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;com.alibaba\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;druid\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;version\u0026amp;gt;1.1.14\u0026amp;lt;/version\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n\u0026amp;lt;/dependencies\u0026amp;gt;\n\n\u0026amp;lt;build\u0026amp;gt;\n    \u0026amp;lt;plugins\u0026amp;gt;\n        \u0026amp;lt;plugin\u0026amp;gt;\n            \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n            \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-maven-plugin\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;/plugin\u0026amp;gt;\n        \u0026amp;lt;plugin\u0026amp;gt;\n            \u0026amp;lt;groupId\u0026amp;gt;org.mybatis.generator\u0026amp;lt;/groupId\u0026amp;gt;\n            \u0026amp;lt;artifactId\u0026amp;gt;mybatis-generator-maven-plugin\u0026amp;lt;/artifactId\u0026amp;gt;\n            \u0026amp;lt;version\u0026amp;gt;1.3.7\u0026amp;lt;/version\u0026amp;gt;\n        \u0026amp;lt;/plugin\u0026amp;gt;\n    \u0026amp;lt;/plugins\u0026amp;gt;\n\u0026amp;lt;/build\u0026amp;gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u0026lt;/project\u0026gt;\n`\u003c/p\u003e","title":"Spring boot+mybatis+Sqlite环境配置"},{"content":"Element-UI 入门使用 Element，一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库 [Element UI官网][1]\n如何在Html文件中使用ElementUI 在网页中引入element ui css和js ，由于Element是具有Vue的，所以需引入Vue的js \u0026gt; \u0026gt; - \u0026gt; \u0026gt; \u0026gt; \u0026lt;script src=\u0026quot;https://unpkg.com/vue@2.6.10/dist/vue.js\u0026quot;\u0026gt;\u0026lt;/script\u0026gt; \u0026gt; \u0026gt; \u0026gt; \u0026lt;!-- 引入组件库 --\u0026gt; \u0026gt; \u0026gt; 在Script中创建Vue对象管理界面元素 \u0026gt; ``` \u0026amp;lt;script\u0026amp;gt; new Vue({ el: \u0026amp;#39;#app\u0026amp;#39;, data: function () { return { visible: false } }, }); \u0026amp;lt;/script\u0026amp;gt; 3. 接下来就可以使用Element中的元素了 \u0026gt; ``` `\u0026amp;lt;div id=\u0026#34;app\u0026#34;\u0026amp;gt; \u0026amp;lt;el-button @click=\u0026#34;visible = true\u0026#34;\u0026amp;gt;Button\u0026amp;lt;/el-button\u0026amp;gt; \u0026amp;lt;el-dialog :visible.sync=\u0026#34;visible\u0026#34; title=\u0026#34;Hello World\u0026#34;\u0026amp;gt; \u0026amp;lt;p\u0026amp;gt;Try Element\u0026amp;lt;/p\u0026amp;gt; \u0026amp;lt;/el-dialog\u0026amp;gt; \u0026amp;lt;/div\u0026amp;gt; ` 完整示例 \u0026gt; ``` `\u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026ldquo;en\u0026rdquo;\u0026gt;\n\u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026ldquo;UTF-8\u0026rdquo;\u0026gt; \u0026lt;meta name=\u0026ldquo;viewport\u0026rdquo; content=\u0026ldquo;width=device-width, initial-scale=1.0\u0026rdquo;\u0026gt; \u0026lt;meta http-equiv=\u0026ldquo;X-UA-Compatible\u0026rdquo; content=\u0026ldquo;ie=edge\u0026rdquo;\u0026gt; \u0026lt;title\u0026gt;Element第一个\u0026lt;/title\u0026gt; \u0026lt;!\u0026ndash; 引入样式 \u0026ndash;\u0026gt; \u0026lt;link rel=\u0026ldquo;stylesheet\u0026rdquo; href=\u0026ldquo;https://unpkg.com/element-ui@2.12.0/lib/theme-chalk/index.css\u0026quot;\u0026gt; \u0026lt;script src=\u0026ldquo;https://unpkg.com/vue@2.6.10/dist/vue.js\u0026quot;\u0026amp;gt;\u0026amp;lt;/script\u0026gt; \u0026lt;/head\u0026gt;\n\u0026lt;body\u0026gt; \u0026lt;div id=\u0026ldquo;app\u0026rdquo;\u0026gt; \u0026lt;el-button @click=\u0026ldquo;visible = true\u0026rdquo;\u0026gt;Button\u0026lt;/el-button\u0026gt; \u0026lt;el-dialog :visible.sync=\u0026ldquo;visible\u0026rdquo; title=\u0026ldquo;Hello World\u0026rdquo;\u0026gt; \u0026lt;p\u0026gt;Try Element\u0026lt;/p\u0026gt; \u0026lt;/el-dialog\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;!\u0026ndash; 引入组件库 \u0026ndash;\u0026gt; \u0026lt;script src=\u0026ldquo;https://unpkg.com/element-ui@2.12.0/lib/index.js\u0026quot;\u0026amp;gt;\u0026amp;lt;/script\u0026gt;\n\u0026amp;lt;script\u0026amp;gt; new Vue({ el: \u0026amp;#39;#app\u0026amp;#39;, data: function () { return { visible: false } }, }); \u0026amp;lt;/script\u0026amp;gt; \u0026lt;/body\u0026gt;\n\u0026lt;/html\u0026gt; `\n5. 登录界面完成示例 \u0026gt; ``` `\u0026amp;lt;!DOCTYPE html\u0026amp;gt; \u0026amp;lt;html lang=\u0026#34;en\u0026#34;\u0026amp;gt; \u0026amp;lt;head\u0026amp;gt; \u0026amp;lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026amp;gt; \u0026amp;lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34;\u0026amp;gt; \u0026amp;lt;meta http-equiv=\u0026#34;X-UA-Compatible\u0026#34; content=\u0026#34;ie=edge\u0026#34;\u0026amp;gt; \u0026amp;lt;title\u0026amp;gt;登录\u0026amp;lt;/title\u0026amp;gt; \u0026amp;lt;!-- 引入样式 --\u0026amp;gt; \u0026amp;lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;https://unpkg.com/element-ui@2.12.0/lib/theme-chalk/index.css\u0026#34;\u0026amp;gt; \u0026amp;lt;script src=\u0026#34;https://unpkg.com/vue@2.6.10/dist/vue.js\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;!-- 引入组件库 --\u0026amp;gt; \u0026amp;lt;script src=\u0026#34;https://unpkg.com/element-ui@2.12.0/lib/index.js\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;script src=\u0026#34;https://unpkg.com/axios@0.19.0/dist/axios.min.js\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;/head\u0026amp;gt; \u0026amp;lt;body\u0026amp;gt; \u0026amp;lt;div id=\u0026#34;app\u0026#34;\u0026amp;gt; \u0026amp;lt;el-row type=\u0026#34;flex\u0026#34; class=\u0026#34;row-bg\u0026#34; justify=\u0026#34;center\u0026#34;\u0026amp;gt; \u0026amp;lt;el-col :xs=\u0026#34;24\u0026#34; :sm=\u0026#34;12\u0026#34; :md=\u0026#34;12\u0026#34; :lg=\u0026#34;6\u0026#34; :xl=\u0026#34;6\u0026#34;\u0026amp;gt; \u0026amp;lt;el-card class=\u0026#34;box-card\u0026#34; style=\u0026#34;margin-top: 50%;\u0026#34;\u0026amp;gt; \u0026amp;lt;el-container\u0026amp;gt; \u0026amp;lt;el-main\u0026amp;gt; \u0026amp;lt;el-form ref=\u0026#34;form\u0026#34; label-position=\u0026#34;right\u0026#34; label-width=\u0026#34;80px\u0026#34;\u0026amp;gt; \u0026amp;lt;el-form-item label=\u0026#34;用户名\u0026#34;\u0026amp;gt; \u0026amp;lt;el-input v-model=\u0026#34;form.name\u0026#34; prefix-icon=\u0026#34;el-icon-user\u0026#34; clearable\u0026amp;gt;\u0026amp;lt;/el-input\u0026amp;gt; \u0026amp;lt;/el-form-item\u0026amp;gt; \u0026amp;lt;el-form-item label=\u0026#34;密码\u0026#34;\u0026amp;gt; \u0026amp;lt;el-input v-model=\u0026#34;form.pwd\u0026#34; show-password prefix-icon=\u0026#34;el-icon-lock\u0026#34; clearable\u0026amp;gt;\u0026amp;lt;/el-input\u0026amp;gt; \u0026amp;lt;/el-form-item\u0026amp;gt; \u0026amp;lt;div style=\u0026#34;text-align: center;\u0026#34;\u0026amp;gt;\u0026amp;lt;el-button type=\u0026#34;primary\u0026#34; round style=\u0026#34;width: 50%;\u0026#34; @click=\u0026#34;onSubmit\u0026#34;\u0026amp;gt; 登录 \u0026amp;lt;/el-button\u0026amp;gt;\u0026amp;lt;/div\u0026amp;gt; \u0026amp;lt;el-form-item label=\u0026#34;\u0026#34; style=\u0026#34;text-align:right;\u0026#34;\u0026amp;gt; \u0026amp;lt;el-link type=\u0026#34;primary\u0026#34; :underline=\u0026#34;false\u0026#34;\u0026amp;gt; 找回密码 \u0026amp;lt;/el-link\u0026amp;gt;\u0026amp;lt;/el-form-item\u0026amp;gt; \u0026amp;lt;/el-form\u0026amp;gt; \u0026amp;lt;/el-main\u0026amp;gt; \u0026amp;lt;/el-container\u0026amp;gt; \u0026amp;lt;/el-card\u0026amp;gt; \u0026amp;lt;/el-col\u0026amp;gt; \u0026amp;lt;/el-row\u0026amp;gt; \u0026amp;lt;/div\u0026amp;gt; \u0026amp;lt;script\u0026amp;gt; new Vue({ el: \u0026amp;#39;#app\u0026amp;#39;, data: function () { return { form: { name: \u0026amp;#39;\u0026amp;#39;, pwd: \u0026amp;#39;\u0026amp;#39; } } }, mounted() { // axios.get(\u0026amp;#39;https://api.apiopen.top/getJoke?page=1\u0026amp;count=2\u0026amp;type=video\u0026amp;#39;).then(function(response){ // console.log(response); // }); }, methods: { onSubmit(){//提交 console.log(this.$data); } }, }); \u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;/body\u0026amp;gt; \u0026amp;lt;/html\u0026amp;gt; ` Socket.io 完整Demo \u0026gt; ``` `\u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta http-equiv=\u0026ldquo;Content-Type\u0026rdquo; content=\u0026ldquo;text/html; charset=utf-8\u0026rdquo;/\u0026gt; \u0026lt;title\u0026gt;NETTY SOCKET.IO DEMO\u0026lt;/title\u0026gt; \u0026lt;base\u0026gt; \u0026lt;script src=\u0026ldquo;https://cdn.bootcss.com/jquery/3.4.0/jquery.min.js\u0026quot;\u0026amp;gt;\u0026amp;lt;/script\u0026gt; \u0026lt;script src=\u0026ldquo;https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js\u0026quot;\u0026amp;gt;\u0026amp;lt;/script\u0026gt; \u0026lt;style\u0026gt; body { padding: 20px; } #console { height: 450px; overflow: auto; } .username-msg { color: orange; } .connect-msg { color: green; } .disconnect-msg { color: red; } \u0026lt;/style\u0026gt; \u0026lt;/head\u0026gt;\n\u0026lt;body\u0026gt; \u0026lt;div id=\u0026ldquo;console\u0026rdquo; class=\u0026ldquo;well\u0026rdquo;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;button id=\u0026ldquo;btnSend\u0026rdquo; onclick=\u0026ldquo;send()\u0026quot;\u0026gt;发送数据\u0026lt;/button\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;script type=\u0026ldquo;text/javascript\u0026rdquo;\u0026gt; var socket; connect();\nfunction connect() { var loginUserNum = \u0026amp;#39;79\u0026amp;#39;; var opts = { query: \u0026amp;#39;loginUserNum=\u0026amp;#39; + loginUserNum }; socket = io.connect(\u0026amp;#39;http://192.168.1.30:9099\u0026amp;#39;, opts); socket.on(\u0026amp;#39;connect\u0026amp;#39;, function () { console.log(\u0026quot;连接成功\u0026quot;); serverOutput(\u0026amp;#39;\u0026amp;lt;span class=\u0026quot;connect-msg\u0026quot;\u0026amp;gt;连接成功\u0026amp;lt;/span\u0026amp;gt;\u0026amp;#39;); }); socket.on(\u0026amp;#39;push_event\u0026amp;#39;, function (data) { output(\u0026amp;#39;\u0026amp;lt;span class=\u0026quot;username-msg\u0026quot;\u0026amp;gt;\u0026amp;#39; + data + \u0026amp;#39; \u0026amp;lt;/span\u0026amp;gt;\u0026amp;#39;); console.log(data); }); socket.on(\u0026amp;#39;disconnect\u0026amp;#39;, function () { serverOutput(\u0026amp;#39;\u0026amp;lt;span class=\u0026quot;disconnect-msg\u0026quot;\u0026amp;gt;\u0026amp;#39; + \u0026amp;#39;已下线! \u0026amp;lt;/span\u0026amp;gt;\u0026amp;#39;); }); } function output(message) { var element = \u0026amp;lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;(\u0026quot;\u0026amp;lt;div\u0026amp;gt;\u0026quot; +\u0026quot;\u0026quot; + message + \u0026quot;\u0026amp;lt;/div\u0026amp;gt;\u0026quot;);\u0026amp;lt;/span\u0026gt;(\u0026amp;#39;#console\u0026amp;#39;).prepend(element); } function serverOutput(message) { var element = \u0026amp;lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;(\u0026quot;\u0026amp;lt;div\u0026amp;gt;\u0026quot; + message + \u0026quot;\u0026amp;lt;/div\u0026amp;gt;\u0026quot;);\u0026amp;lt;/span\u0026gt;(\u0026amp;#39;#console\u0026amp;#39;).prepend(element); } function send() { console.log(\u0026amp;#39;发送数据\u0026amp;#39;); socket.emit(\u0026amp;#39;text\u0026amp;#39;,\u0026amp;#39;你好\u0026amp;#39;); } \u0026lt;/script\u0026gt; \u0026lt;/html\u0026gt; `\n[1]: https://element.eleme.io/#/zh-CN ","permalink":"https://blog.zdltech.com/posts/elementui-ru-men-shi-yong/","summary":"\u003ch3 id=\"toc_0\"\u003eElement-UI 入门使用\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003eElement，一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库 [Element UI官网][1]\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch4 id=\"toc_1\"\u003e如何在Html文件中使用ElementUI\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e在网页中引入element ui css和js ，由于Element是具有Vue的，所以需引入Vue的js\u003c/strong\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026gt; \n\u0026gt; - \u0026gt; \n\u0026gt; \n\u0026gt;     \u0026lt;script src=\u0026quot;https://unpkg.com/vue@2.6.10/dist/vue.js\u0026quot;\u0026gt;\u0026lt;/script\u0026gt;\n\u0026gt;     \n\u0026gt; \n\u0026gt; \u0026lt;!-- 引入组件库 --\u0026gt;\n\u0026gt; \n\u0026gt; \n\u003c/code\u003e\u003c/pre\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e在Script中创建Vue对象管理界面元素\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026gt; ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003e\u0026amp;lt;script\u0026amp;gt; new Vue({ el: \u0026amp;#39;#app\u0026amp;#39;, data: function () { return { visible: false } }, }); \u0026amp;lt;/script\u0026amp;gt; \u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  3. 接下来就可以使用Element中的元素了\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026gt; ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;div id=\u0026#34;app\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;el-button @click=\u0026#34;visible = true\u0026#34;\u0026amp;gt;Button\u0026amp;lt;/el-button\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;el-dialog :visible.sync=\u0026#34;visible\u0026#34; title=\u0026#34;Hello World\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;p\u0026amp;gt;Try Element\u0026amp;lt;/p\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;/el-dialog\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/div\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"4\"\u003e\n\u003cli\u003e完整示例\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026gt; ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e`\u0026lt;!DOCTYPE html\u0026gt;\n\u0026lt;html lang=\u0026ldquo;en\u0026rdquo;\u0026gt;\u003c/p\u003e","title":"Element-UI 入门使用"},{"content":"Redis 安装及使用 Redis是一个开源的使用ANSI [C语言][1]编写、支持网络、可基于内存亦可持久化的日志型、Key-Value[数据库][2]，并提供多种语言的API\nredis是一个key-value[存储系统][3]。和Memcached类似，它支持存储的value类型相对更多，包括string(字符串)、list([链表][4])、set(集合)、zset(sorted set –有序集合)和hash（哈希类型）。这些[数据类型][5]都支持push/pop、add/remove及取交集并集和差集及更丰富的操作，而且这些操作都是原子性的。在此基础上，redis支持各种不同方式的排序。与memcached一样，为了保证效率，数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件，并且在此基础上实现了master-slave(主从)同步。\nRedis 是一个高性能的key-value数据库。 redis的出现，很大程度补偿了[memcached][6]这类key/value存储的不足，在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java，C/C++，C#，PHP，JavaScript，Perl，Object-C，Python，Ruby，Erlang等客户端，使用很方便。\nRedis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步，从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制，使得从数据库在任何地方同步树时，可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。\nRedis应用场景 缓存（数据查询、短连接、新闻内容、商品内容等等）。(使用最多)\n分布式集群架构中的session分离。\n聊天室的在线好友列表。\n任务队列。（秒杀、抢购、12306等等） 应用排行榜。 网站访问统计。 数据过期处理（可以精确到毫秒）\n安装Redis 这里通过源码编译安装，大家也可以使用其他打包好的直接安装\n进入服务器\nwget 和tar要是没有 通过yum install wget tar来进行安装\n执行下载源码命令\nwget http://download.redis.io/releases/redis-5.0.5.tar.gz \u0026gt; \u0026gt; 解压 \u0026gt; \u0026gt; ``` `tar xzf redis-5.0.5.tar.gz ` 进入解压目录\ncd redis-5.0.5 \u0026gt; \u0026gt; 编译 \u0026gt; \u0026gt; ``` `make ` make[1]: Entering directory `/opt/redis-5.0.5/src'\nCC Makefile.dep make[1]: Leaving directory`/opt/redis-5.0.5/src'\nmake[1]: Entering directory `/opt/redis-5.0.5/src'\nrm -rf redis-server redis-sentinel redis-cli redis-benchmark redis-check-rdb redis-check-aof *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep dict-benchmark\n(cd ../deps \u0026amp;\u0026amp; make distclean)\nmake[2]: Entering directory`/opt/redis-5.0.5/deps'\n(cd hiredis \u0026amp;\u0026amp; make clean) \u0026gt; /dev/null || true\n(cd linenoise \u0026amp;\u0026amp; make clean) \u0026gt; /dev/null || true\n(cd lua \u0026amp;\u0026amp; make clean) \u0026gt; /dev/null || true\n(cd jemalloc \u0026amp;\u0026amp; [ -f Makefile ] \u0026amp;\u0026amp; make distclean) \u0026gt; /dev/null || true\n(rm -f .make-_)\nmake[2]: Leaving directory `/opt/redis-5.0.5/deps'\n(rm -f .make-*)\necho STD=-std=c99 -pedantic -DREDIS_STATIC='' \u0026raquo; .make-settings\necho WARN=-Wall -W -Wno-missing-field-initializers \u0026raquo; .make-settings\necho OPT=-O2 \u0026raquo; .make-settings\necho MALLOC=jemalloc \u0026raquo; .make-settings\necho CFLAGS= \u0026raquo; .make-settings\necho LDFLAGS= \u0026raquo; .make-settings\necho REDIS_CFLAGS= \u0026raquo; .make-settings\necho REDIS_LDFLAGS= \u0026raquo; .make-settings\necho PREV_FINAL_CFLAGS=-std=c99 -pedantic -DREDIS_STATIC='' -Wall -W -Wno-missing-field-initializers -O2 -g -ggdb -I../deps/hiredis -I../deps/linenoise -I../deps/lua/src -DUSE_JEMALLOC -I../deps/jemalloc/include \u0026raquo; .make-settings\necho PREV_FINAL_LDFLAGS= -g -ggdb -rdynamic \u0026raquo; .make-settings\n(cd ../deps \u0026amp;\u0026amp; make hiredis linenoise lua jemalloc)\nmake[2]: Entering directory`/opt/redis-5.0.5/deps'\n(cd hiredis \u0026amp;\u0026amp; make clean) \u0026gt; /dev/null || true\n(cd linenoise \u0026amp;\u0026amp; make clean) \u0026gt; /dev/null || true\n(cd lua \u0026amp;\u0026amp; make clean) \u0026gt; /dev/null || true\n(cd jemalloc \u0026amp;\u0026amp; [ -f Makefile ] \u0026amp;\u0026amp; make distclean) \u0026gt; /dev/null || true\n(rm -f .make-_)\n(echo \u0026quot;\u0026quot; \u0026gt; .make-cflags)\n(echo \u0026quot;\u0026quot; \u0026gt; .make-ldflags)\nMAKE hiredis\ncd hiredis \u0026amp;\u0026amp; make static\nmake[3]: Entering directory `/opt/redis-5.0.5/deps/hiredis'\ngcc -std=c99 -pedantic -c -O3 -fPIC -Wall -W -Wstrict-prototypes -Wwrite-strings -g -ggdb net.c\nmake[3]: gcc: Command not found\nmake[3]: *** [net.o] Error 127\nmake[3]: Leaving directory`/opt/redis-5.0.5/deps/hiredis'\nmake[2]: *** [hiredis] Error 2\nmake[2]: Leaving directory `/opt/redis-5.0.5/deps'\nmake[1]: [persist-settings] Error 2 (ignored)\nCC adlist.o /bin/sh: cc: command not found\nmake[1]: *** [adlist.o] Error 127\nmake[1]: Leaving directory`/opt/redis-5.0.5/src'\nmake: *** [all] Error 2\n错误信息 需要我们安装gcc\n执行命令 yum install gcc -y\nmake报错 zmalloc.h:50:31: 错误：jemalloc/jemalloc.h：没有那个文件或目录 执行 make MALLOC=libc进行编译\n安装redis到/usr/local/redis中\nmake PREFIX=/usr/local/redis MALLOC=libc install\n进入/usr/local/redis\ncd /usr/local/redis\n进入bin\ncd bin\nredis-benchmark redis性能测试工具 redis-check-aof AOF文件修复工具 redis-check-rdb RDB文件修复工具 redis-cli redis命令行客户端 redis.conf redis配置文件 redis-sentinal redis集群管理工具 redis-server redis服务进程 运行Redis 1.前端模式启动\n直接运行 ./redis-server将以前端模式启动，前端模式启动的缺点是ssh命令窗口关闭则redis-server程序结束，故不推荐使用此方法。\n2.后端模式启动\n修改redis.conf配置文件， daemonize yes 以后端模式启动\nvim /usr/local/redis/bin/redis.conf\n启动\n./redis-server ./redis.conf\n[root@localhost bin]# ./redis-server ./redis.conf\n30387:C 26 Sep 2019 19:15:50.676 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo\n30387:C 26 Sep 2019 19:15:50.676 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=30387, just started\n30387:C 26 Sep 2019 19:15:50.676 # Configuration loaded\n表示启动成功\n验证Redis 通过运行redis-cli redis客户端进行服务的验证\n[root@localhost bin]# ./redis-cli\n127.0.0.1:6379\u0026gt; set foo bar\nOK\n127.0.0.1:6379\u0026gt; get foo\n\u0026ldquo;bar\u0026rdquo;\n127.0.0.1:6379\u0026gt;\n出现上面表示Redis安装和启动成功\nRedis关闭 强行终止redis进程可能会导致redis持久化数据丢失。\n正确停止Redis的方式应该是向Redis发送SHUTDOWN命令，\n命令为：\ncd /usr/local/redis\n./bin/redis-cli shutdown\n强行终止redis\npkill redis-server ### Redis 开启重启 {#toc_7} \u0026gt; vim /etc/rc.local \u0026gt; //添加 \u0026gt; /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis-conf ### 常用配置 {#toc_8} \u0026gt; redis-server \u0026amp;#8211;maxclients 100000 -f /etc/redis.conf \u0026gt; \u0026gt; 配置redis的最大连接数 \u0026gt; \u0026gt; 在config中配置 \u0026gt; \u0026gt; bind 0.0.0.0 表示所有的ip \u0026gt; \u0026gt; requirepass xxxx 表示设置密码 \u0026gt; \u0026gt; 只有配置了bind和requirepass之后 就可以通过redis的客户端访问数据了 ### 其他 {#toc_9} \u0026gt; 官网试用redis \u0026gt; \u0026gt; \u0026lt;http://try.redis.io/\u0026gt; \u0026gt; \u0026gt; 官网地址 \u0026gt; \u0026gt; [https://redis.io][7] \u0026gt; \u0026gt; redis使用命令 \u0026gt; \u0026gt; \u0026lt;https://redis.io/commands\u0026gt; \u0026gt; \u0026gt; redis配置文件 \u0026gt; \u0026gt; \u0026lt;https://raw.githubusercontent.com/antirez/redis/4.0/redis.conf\u0026gt; \u0026gt; \u0026gt; \u0026lt;https://raw.githubusercontent.com/antirez/redis/5.0/redis.conf\u0026gt; [1]: https://baike.baidu.com/item/C%E8%AF%AD%E8%A8%80 [2]: https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E5%BA%93/103728 [3]: https://baike.baidu.com/item/%E5%AD%98%E5%82%A8%E7%B3%BB%E7%BB%9F [4]: https://baike.baidu.com/item/%E9%93%BE%E8%A1%A8 [5]: https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B [6]: https://baike.baidu.com/item/memcached [7]: https://redis.io/ ","permalink":"https://blog.zdltech.com/posts/redis-an-zhuang-ji-shi-yong/","summary":"\u003ch2 id=\"toc_0\"\u003eRedis 安装及使用\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003eRedis是一个开源的使用ANSI [C语言][1]编写、支持网络、可基于内存亦可持久化的日志型、Key-Value[数据库][2]，并提供多种语言的API\u003c/p\u003e\n\u003cp\u003eredis是一个key-value[存储系统][3]。和Memcached类似，它支持存储的value类型相对更多，包括string(字符串)、list([链表][4])、set(集合)、zset(sorted set –有序集合)和hash（哈希类型）。这些[数据类型][5]都支持push/pop、add/remove及取交集并集和差集及更丰富的操作，而且这些操作都是原子性的。在此基础上，redis支持各种不同方式的排序。与memcached一样，为了保证效率，数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件，并且在此基础上实现了master-slave(主从)同步。\u003c/p\u003e\n\u003cp\u003eRedis 是一个高性能的key-value数据库。 redis的出现，很大程度补偿了[memcached][6]这类key/value存储的不足，在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java，C/C++，C#，PHP，JavaScript，Perl，Object-C，Python，Ruby，Erlang等客户端，使用很方便。\u003c/p\u003e\n\u003cp\u003eRedis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步，从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制，使得从数据库在任何地方同步树时，可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"toc_1\"\u003eRedis应用场景\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e缓存（数据查询、短连接、新闻内容、商品内容等等）。(使用最多)\u003cbr\u003e\n分布式集群架构中的session分离。\u003cbr\u003e\n聊天室的在线好友列表。\u003cbr\u003e\n任务队列。（秒杀、抢购、12306等等） \u003cbr\u003e\n应用排行榜。 \u003cbr\u003e\n网站访问统计。 \u003cbr\u003e\n数据过期处理（可以精确到毫秒）\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"toc_2\"\u003e安装Redis\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e这里通过源码编译安装，大家也可以使用其他打包好的直接安装\u003c/p\u003e\n\u003cp\u003e进入服务器\u003c/p\u003e\n\u003cp\u003ewget 和tar要是没有 通过yum install wget tar来进行安装\u003c/p\u003e\n\u003cp\u003e执行下载源码命令\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003ccode\u003ewget http://download.redis.io/releases/redis-5.0.5.tar.gz  \u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; 解压\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`tar xzf redis-5.0.5.tar.gz\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003e进入解压目录\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003ccode\u003ecd redis-5.0.5 \u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; 编译\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026gt; ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`make\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003emake[1]: Entering directory `/opt/redis-5.0.5/src'\u003c/p\u003e\u003c/blockquote\u003e\n\u003cpre\u003e\u003ccode\u003eCC Makefile.dep\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003emake[1]: Leaving directory`/opt/redis-5.0.5/src'\u003c/p\u003e","title":"Redis 安装及使用"},{"content":"Shiro 简单入门 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。\n三个核心组件：Subject, SecurityManager 和 Realms.\nSubject：即“当前操作用户”。但是，在Shiro中，Subject这一概念并不仅仅指人，也可以是第三方进程、后台帐户（Daemon Account）或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。\nSubject代表了当前用户的安全操作，SecurityManager则管理所有用户的安全操作。\nSecurityManager：它是Shiro框架的核心，典型的Facade模式，Shiro通过SecurityManager来管理内部组件实例，并通过它来提供安全管理的各种服务。\nRealm： Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说，当对用户执行认证（登录）和授权（访问控制）验证时，Shiro会从应用配置的Realm中查找用户及其权限信息。\n从这个意义上讲，Realm实质上是一个安全相关的DAO：它封装了数据源的连接细节，并在需要时将相关数据提供给Shiro。当配置Shiro时，你必须至少指定一个Realm，用于认证和（或）授权。配置多个Realm是可以的，但是至少需要一个。\nShiro内置了可以连接大量安全数据源（又名目录）的Realm，如LDAP、关系数据库（JDBC）、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求，你还可以插入代表自定义数据源的自己的Realm实现。\n第一步创建Springboot项目 通过自己熟悉的工具，创建一个Springboot项目\npom.xml\n`\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;UTF-8\u0026rdquo;?\u0026gt; \u0026lt;project xmlns=\u0026ldquo;http://maven.apache.org/POM/4.0.0\u0026quot; xmlns:xsi=\u0026ldquo;http://www.w3.org/2001/XMLSchema-instance\u0026quot; xsi:schemaLocation=\u0026ldquo;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\u0026quot;\u0026gt; \u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt; \u0026lt;parent\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-parent\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.1.7.RELEASE\u0026lt;/version\u0026gt; \u0026lt;relativePath/\u0026gt; \u0026lt;!\u0026ndash; lookup parent from repository \u0026ndash;\u0026gt; \u0026lt;/parent\u0026gt; \u0026lt;groupId\u0026gt;com.zdltech.demo\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;shiro\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;0.0.1-SNAPSHOT\u0026lt;/version\u0026gt; \u0026lt;name\u0026gt;shiro\u0026lt;/name\u0026gt; \u0026lt;description\u0026gt;shiro demo\u0026lt;/description\u0026gt;\n\u0026amp;lt;properties\u0026amp;gt; \u0026amp;lt;java.version\u0026amp;gt;1.8\u0026amp;lt;/java.version\u0026amp;gt; \u0026amp;lt;/properties\u0026amp;gt; \u0026amp;lt;dependencies\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-thymeleaf\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-web\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-test\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;scope\u0026amp;gt;test\u0026amp;lt;/scope\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;!--shiro 依赖添加--\u0026amp;gt; \u0026amp;lt;!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring --\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.apache.shiro\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;shiro-spring\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;1.4.1\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;/dependencies\u0026amp;gt; \u0026amp;lt;build\u0026amp;gt; \u0026amp;lt;plugins\u0026amp;gt; \u0026amp;lt;plugin\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-maven-plugin\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/plugin\u0026amp;gt; \u0026amp;lt;/plugins\u0026amp;gt; \u0026amp;lt;/build\u0026amp;gt; \u0026lt;/project\u0026gt; `\n### 配置Shiro {#toc_2} \u0026gt; 创建一个ShiroConfig进行配置 \u0026gt; \u0026gt; ``` `import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig { private Logger logger = LoggerFactory.getLogger(ShiroConfig.class); @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){ logger.info(\u0026#34;ShiroConfig initalized\u0026#34;); // 初始化ShiroFilterFactoryBean ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //必须设置SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); //拦截器 Map\u0026amp;lt;String,String\u0026amp;gt; filterChainDefinitionMap = new LinkedHashMap\u0026amp;lt;\u0026amp;gt;(); //退出 filterChainDefinitionMap.put(\u0026#34;/logout\u0026#34;,\u0026#34;logout\u0026#34;); // 过滤链定义，从上向下顺序执行，一般将/** 放到最下面 filterChainDefinitionMap.put(\u0026#34;/admin/**\u0026#34;,\u0026#34;authc\u0026#34;); filterChainDefinitionMap.put(\u0026#34;/**\u0026#34;,\u0026#34;anon\u0026#34;); // 如果不设置默认会自动寻找Web工程更目录下的“login.jsp”页面 shiroFilterFactoryBean.setLoginUrl(\u0026#34;/login\u0026#34;); // 登录成功后要跳转的连接 shiroFilterFactoryBean.setSuccessUrl(\u0026#34;/success\u0026#34;); // 未授权界面 shiroFilterFactoryBean.setUnauthorizedUrl(\u0026#34;/403\u0026#34;); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(){ System.out.println(\u0026#34;securityManager is run\u0026#34;); SecurityManager securityManager = new DefaultWebSecurityManager(); ((DefaultWebSecurityManager) securityManager).setRealm(new MyRealm()); return securityManager; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){ System.out.println(\u0026#34;authorizationAttributeSourceAdvisor is run\u0026#34;); AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){ System.out.println(\u0026#34;defaultAdvisorAutoProxyCreator is run\u0026#34;); DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); return defaultAdvisorAutoProxyCreator; } } ` `import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory;\nimport javax.annotation.PostConstruct;\npublic class MyRealm extends AuthorizingRealm { private Logger logger = LoggerFactory.getLogger(MyRealm.class); @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {//权限认证，即登录过后，每个身份不一定，对应的所能看的页面也不一样。 //认证 并且获取角色及权限 logger.info(\u0026rdquo;#################执行Shiro权限认证#######################\u0026rdquo;); String userName = (String) principalCollection.getPrimaryPrincipal(); if (userName.equals(\u0026ldquo;admin\u0026rdquo;)){ SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermission(\u0026ldquo;admin:\u0026rdquo;); info.addStringPermission(\u0026ldquo;index:\u0026rdquo;); info.addRole(\u0026ldquo;admin\u0026rdquo;); return info; }else if (userName != null\u0026amp;\u0026amp; userName.length()\u0026gt;0){ SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermission(\u0026ldquo;index:*\u0026rdquo;); info.addRole(\u0026ldquo;index\u0026rdquo;); return info; }else{ return null; }\n} @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { logger.info(\u0026quot;#################执行doGetAuthenticationInfo认证#######################\u0026quot;); UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; logger.info(\u0026quot;user==\u0026amp;gt;\u0026quot;+token.getUsername()); if (\u0026quot;admin\u0026quot;.equals(token.getUsername())){ return new SimpleAuthenticationInfo(token.getUsername(),\u0026quot;123456\u0026quot;,token.getUsername()); }else if (token.getUsername() != null\u0026amp;\u0026amp; token.getUsername().length()\u0026amp;gt;0){ return new SimpleAuthenticationInfo(token.getUsername(),\u0026quot;111111\u0026quot;,token.getUsername()); }else{ return null; } } @PostConstruct public void initCredentialsMatcher(){ setCredentialsMatcher(new CredentialsMatcher()); } } `\n\u0026gt; \u0026gt; ``` `import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.SimpleCredentialsMatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CredentialsMatcher extends SimpleCredentialsMatcher { private Logger logger = LoggerFactory.getLogger(CredentialsMatcher.class); @Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { System.out.println(\u0026#34;doCredentialsMatch is run!!!\u0026#34;); UsernamePasswordToken authToken = (UsernamePasswordToken) token; if (\u0026#34;admin\u0026#34;.equals(authToken.getUsername())){ return getCredentials(info).equals(\u0026#34;123456\u0026#34;); }else if( authToken.getUsername()!=null \u0026amp;\u0026amp; authToken.getUsername().length()\u0026amp;gt;0){ return getCredentials(info).equals(\u0026#34;111111\u0026#34;); }else { return false; } } } ` 通过这些我们配置完成Shiro\n测试Shiro 最简单的基础的Shiro配置完成，下面我们来创建一个Controller测试下\n`import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;\n@Controller @RequestMapping(\u0026rdquo;\u0026quot;) public class IndexController {\n@GetMapping @ResponseBody public String defaultMethod(){ return \u0026quot;ok\u0026quot;; } @GetMapping(\u0026quot;index\u0026quot;) @ResponseBody public String index(){ return \u0026quot;index is run ! please continue\u0026quot;; } @GetMapping(\u0026quot;login\u0026quot;) public String login(){ return \u0026quot;login\u0026quot;; } @GetMapping(\u0026quot;admin\u0026quot;) @ResponseBody public String adminindex(){ System.out.println(\u0026quot;admin IS run !\u0026quot;); Subject subject = SecurityUtils.getSubject(); subject.checkPermission(\u0026quot;admin:*\u0026quot;); boolean has = subject.isPermitted(\u0026quot;admin:*\u0026quot;); System.out.println(\u0026quot;是否有权限：\u0026quot;+has); return \u0026quot;admin index is in\u0026quot;; } @GetMapping(\u0026quot;loginrequest\u0026quot;) @ResponseBody public String loginRequest(String userName,String password){ System.out.println(\u0026quot;loginrequest IS run !\u0026quot;); if (userName.equals(\u0026quot;admin\u0026quot;)\u0026amp;\u0026amp;password.equals(\u0026quot;123456\u0026quot;)){ UsernamePasswordToken token =new UsernamePasswordToken(); token.setUsername(userName); token.setPassword(password.toCharArray()); System.out.println(\u0026quot;登录成功!!!\u0026quot;); Subject subject = SecurityUtils.getSubject(); subject.login(token); }else if (userName!=null\u0026amp;\u0026amp;userName.length()\u0026amp;gt;0){ UsernamePasswordToken token =new UsernamePasswordToken(); token.setUsername(userName); token.setPassword(password.toCharArray()); Subject subject = SecurityUtils.getSubject(); subject.login(token); }else{ System.out.println(\u0026quot;登录失败!!!\u0026quot;); } return \u0026quot; index is in\u0026quot;; } } `\n\u0026gt; \u0026gt; 对应的login.html为 \u0026gt; \u0026gt; ``` `\u0026amp;lt;!DOCTYPE html\u0026amp;gt; \u0026amp;lt;html lang=\u0026#34;en\u0026#34;\u0026amp;gt; \u0026amp;lt;head\u0026amp;gt; \u0026amp;lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026amp;gt; \u0026amp;lt;title\u0026amp;gt;登录\u0026amp;lt;/title\u0026amp;gt; \u0026amp;lt;/head\u0026amp;gt; \u0026amp;lt;body\u0026amp;gt; \u0026amp;lt;form action=\u0026#34;/loginrequest\u0026#34;\u0026amp;gt; 用户名： \u0026amp;lt;input name=\u0026#34;userName\u0026#34;/\u0026amp;gt;\u0026amp;lt;br\u0026amp;gt; 密码：\u0026amp;lt;input name=\u0026#34;password\u0026#34;/\u0026amp;gt; \u0026amp;lt;button type=\u0026#34;submit\u0026#34;\u0026amp;gt;提交\u0026amp;lt;/button\u0026amp;gt; \u0026amp;lt;/form\u0026amp;gt; \u0026amp;lt;/body\u0026amp;gt; \u0026amp;lt;/html\u0026amp;gt; ` SpringBoot 集成Shiro实现前后端分离 shiro从cookie中读取sessionId以此来维持会话，在前后端分离的项目中（也可在移动APP项目使用），我们选择在ajax的请求头中传递sessionId，因此需要重写shiro获取sessionId的方式。自定义MySessionManager类继承DefaultWebSessionManager类，重写getSessionId方法\nimport org.apache.shiro.web.servlet.ShiroHttpServletRequest;\nimport org.apache.shiro.web.session.mgt.DefaultWebSessionManager;\nimport org.apache.shiro.web.util.WebUtils;\nimport org.springframework.util.StringUtils;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport java.io.Serializable;\npublic class MySessionManager extends DefaultWebSessionManager {\nprivate static final String AUTHORIZATION = \u0026ldquo;Authorization\u0026rdquo;;\nprivate static final String REFERENCED_SESSION_ID_SOURCE = \u0026ldquo;Stateless request\u0026rdquo;;\npublic MySessionManager() {\nsuper();\n}\n@Override\nprotected Serializable getSessionId(ServletRequest request, ServletResponse response) {\nString id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);\n//如果请求头中有 Authorization 则其值为sessionId\nif (!StringUtils.isEmpty(id)) {\nrequest.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);\nrequest.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);\nrequest.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);\nreturn id;\n} else {\n//否则按默认规则从cookie取sessionId\nreturn super.getSessionId(request, response);\n}\n}\n}\n使用自定义的SessionManager，在Shiro的config中\n@Bean\npublic SecurityManager securityManager() {\nDefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();\nsecurityManager.setRealm(myShiroRealm());\n// 自定义session管理 使用redis\nsecurityManager.setSessionManager(sessionManager());\n// 自定义缓存实现 使用redis\nsecurityManager.setCacheManager(cacheManager());\nreturn securityManager;\n}\n//自定义sessionManager @Bean public SessionManager sessionManager() { MySessionManager mySessionManager = new MySessionManager(); mySessionManager.setSessionDAO(redisSessionDAO());//此处是使用redis中的Session return mySessionManager; } 参考 在前后端分离的SpringBoot项目中集成Shiro权限框架\nhttps://blog.csdn.net/u013615903/article/details/78781166\n","permalink":"https://blog.zdltech.com/posts/shiro-jian-dan-ru-men/","summary":"\u003ch2 id=\"toc_0\"\u003eShiro 简单入门\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003eApache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。\u003c/p\u003e\n\u003cp\u003e三个核心组件：Subject, SecurityManager 和 Realms.\u003c/p\u003e\n\u003cp\u003eSubject：即“当前操作用户”。但是，在Shiro中，Subject这一概念并不仅仅指人，也可以是第三方进程、后台帐户（Daemon Account）或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。\u003c/p\u003e\n\u003cp\u003eSubject代表了当前用户的安全操作，SecurityManager则管理所有用户的安全操作。\u003c/p\u003e\n\u003cp\u003eSecurityManager：它是Shiro框架的核心，典型的Facade模式，Shiro通过SecurityManager来管理内部组件实例，并通过它来提供安全管理的各种服务。\u003c/p\u003e\n\u003cp\u003eRealm： Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说，当对用户执行认证（登录）和授权（访问控制）验证时，Shiro会从应用配置的Realm中查找用户及其权限信息。\u003c/p\u003e\n\u003cp\u003e从这个意义上讲，Realm实质上是一个安全相关的DAO：它封装了数据源的连接细节，并在需要时将相关数据提供给Shiro。当配置Shiro时，你必须至少指定一个Realm，用于认证和（或）授权。配置多个Realm是可以的，但是至少需要一个。\u003cbr\u003e\nShiro内置了可以连接大量安全数据源（又名目录）的Realm，如LDAP、关系数据库（JDBC）、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求，你还可以插入代表自定义数据源的自己的Realm实现。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"toc_1\"\u003e第一步创建Springboot项目\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e通过自己熟悉的工具，创建一个Springboot项目\u003c/p\u003e\n\u003cp\u003epom.xml\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e`\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;UTF-8\u0026rdquo;?\u0026gt;\n\u0026lt;project xmlns=\u0026ldquo;\u003ca href=\"http://maven.apache.org/POM/4.0.0%22\"\u003ehttp://maven.apache.org/POM/4.0.0\u0026quot;\u003c/a\u003e xmlns:xsi=\u0026ldquo;\u003ca href=\"http://www.w3.org/2001/XMLSchema-instance%22\"\u003ehttp://www.w3.org/2001/XMLSchema-instance\u0026quot;\u003c/a\u003e\nxsi:schemaLocation=\u0026ldquo;\u003ca href=\"http://maven.apache.org/POM/4.0.0\"\u003ehttp://maven.apache.org/POM/4.0.0\u003c/a\u003e \u003ca href=\"https://maven.apache.org/xsd/maven-4.0.0.xsd%22\"\u003ehttps://maven.apache.org/xsd/maven-4.0.0.xsd\u0026quot;\u003c/a\u003e\u0026gt;\n\u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt;\n\u0026lt;parent\u0026gt;\n\u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt;\n\u0026lt;artifactId\u0026gt;spring-boot-starter-parent\u0026lt;/artifactId\u0026gt;\n\u0026lt;version\u0026gt;2.1.7.RELEASE\u0026lt;/version\u0026gt;\n\u0026lt;relativePath/\u0026gt; \u0026lt;!\u0026ndash; lookup parent from repository \u0026ndash;\u0026gt;\n\u0026lt;/parent\u0026gt;\n\u0026lt;groupId\u0026gt;com.zdltech.demo\u0026lt;/groupId\u0026gt;\n\u0026lt;artifactId\u0026gt;shiro\u0026lt;/artifactId\u0026gt;\n\u0026lt;version\u0026gt;0.0.1-SNAPSHOT\u0026lt;/version\u0026gt;\n\u0026lt;name\u0026gt;shiro\u0026lt;/name\u0026gt;\n\u0026lt;description\u0026gt;shiro demo\u0026lt;/description\u0026gt;\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026amp;lt;properties\u0026amp;gt;\n    \u0026amp;lt;java.version\u0026amp;gt;1.8\u0026amp;lt;/java.version\u0026amp;gt;\n\u0026amp;lt;/properties\u0026amp;gt;\n\n\u0026amp;lt;dependencies\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-thymeleaf\u0026amp;lt;/artifactId\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-web\u0026amp;lt;/artifactId\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-test\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;scope\u0026amp;gt;test\u0026amp;lt;/scope\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n\n    \u0026amp;lt;!--shiro 依赖添加--\u0026amp;gt;\n    \u0026amp;lt;!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring --\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.apache.shiro\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;shiro-spring\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;version\u0026amp;gt;1.4.1\u0026amp;lt;/version\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n\n\u0026amp;lt;/dependencies\u0026amp;gt;\n\n\u0026amp;lt;build\u0026amp;gt;\n    \u0026amp;lt;plugins\u0026amp;gt;\n        \u0026amp;lt;plugin\u0026amp;gt;\n            \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n            \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-maven-plugin\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;/plugin\u0026amp;gt;\n    \u0026amp;lt;/plugins\u0026amp;gt;\n\u0026amp;lt;/build\u0026amp;gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u0026lt;/project\u0026gt;\n`\u003c/p\u003e","title":"Shiro 简单入门"},{"content":"MyBatis及MyBatisPlus简单使用 在做java开发的时候，我们经常会使用Mybatis来作为我们操作数据库的工具库，今天一步步带领大家集成到Spring boot中，本篇主要实现Spring boot+mybatis+MybatisPlus的基础使用\n第一步创建Spring boot项目 大家使用自己熟悉的开发工具创建Spring boot项目。例如Idea、eclipse及SpringToolSuite4等工具，这里默认大家都已成功创建Springboot项目\n配置pom.xml 这里使用的是mysql，大家根据自己情况配置相关的数据源\npom.xm\n`\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;UTF-8\u0026rdquo;?\u0026gt; \u0026lt;project xmlns=\u0026ldquo;http://maven.apache.org/POM/4.0.0\u0026quot; xmlns:xsi=\u0026ldquo;http://www.w3.org/2001/XMLSchema-instance\u0026quot; xsi:schemaLocation=\u0026ldquo;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\u0026quot;\u0026gt; \u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt; \u0026lt;parent\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-parent\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.1.8.RELEASE\u0026lt;/version\u0026gt; \u0026lt;relativePath/\u0026gt; \u0026lt;!\u0026ndash; lookup parent from repository \u0026ndash;\u0026gt; \u0026lt;/parent\u0026gt; \u0026lt;groupId\u0026gt;com.zdltech.test\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;mybatis\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;0.0.1-SNAPSHOT\u0026lt;/version\u0026gt; \u0026lt;name\u0026gt;mybatis\u0026lt;/name\u0026gt; \u0026lt;description\u0026gt;mybatis的测试\u0026lt;/description\u0026gt;\n\u0026amp;lt;properties\u0026amp;gt; \u0026amp;lt;java.version\u0026amp;gt;1.8\u0026amp;lt;/java.version\u0026amp;gt; \u0026amp;lt;/properties\u0026amp;gt; \u0026amp;lt;dependencies\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-data-jpa\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-jdbc\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-thymeleaf\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-web\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.mybatis.spring.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;mybatis-spring-boot-starter\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;2.1.0\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-test\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;scope\u0026amp;gt;test\u0026amp;lt;/scope\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;mysql\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;mysql-connector-java\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;scope\u0026amp;gt;runtime\u0026amp;lt;/scope\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;!-- 下面这个mysbatis-plus-boot-starter是配置Mybatis和MybatisPlus的依赖--\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;com.baomidou\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;mybatis-plus-boot-starter\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;3.1.0\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.projectlombok\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;lombok\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;com.alibaba\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;druid-spring-boot-starter\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;1.1.13\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;/dependencies\u0026amp;gt; \u0026amp;lt;build\u0026amp;gt; \u0026amp;lt;plugins\u0026amp;gt; \u0026amp;lt;plugin\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-maven-plugin\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/plugin\u0026amp;gt; \u0026amp;lt;/plugins\u0026amp;gt; \u0026amp;lt;/build\u0026amp;gt; \u0026lt;/project\u0026gt; `\n#### 配置properties文件 {#toc_3} \u0026gt; ``` `server.port=18899 server.servlet.context-path=/ mybatis-plus.mapper-locations=classpath:/mapper/*Mapper.xml spring.datasource.druid.url=jdbc:mysql://xxxxx:3306/xxxx?useUnicode=true\u0026amp;characterEncoding=UTF-8\u0026amp;serverTimezone=UTC\u0026amp;allowPublicKeyRetrieval=true\u0026amp;verifyServerCertificate=false\u0026amp;useSSL=false spring.datasource.druid.username=root spring.datasource.druid.password=root spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.druid.initial-size=10 spring.datasource.druid.max-active=50 spring.datasource.druid.min-idle=10 spring.datasource.druid.max-wait=60000 spring.datasource.druid.pool-prepared-statements=true spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20 spring.datasource.druid.validation-query= select 1 from dual spring.datasource.druid.test-on-borrow=false spring.datasource.druid.test-on-return=false spring.datasource.druid.test-while-idle=false spring.datasource.druid.time-between-eviction-runs-millis=60000 spring.datasource.druid.filters=stat,wall # mybatis日志配置 mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl logging.level.com.zdltech.test.mybatis.mapper=debug ` 配置logback日志文件 ``\n### 第二步配置Mybatis {#toc_5} #### 配置MyBatisConfig {#toc_6} \u0026gt; 创建MybatisPlus的配置文件 \u0026gt; \u0026gt; ``` `import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Configuration; @Configuration @MapperScan(\u0026#34;这里是你的Mapper对应的包名\u0026#34;) public class MyBatisConfig {//实际上里面什么都不需要配置就可以，这里主要配置MapperScan } ` 创建业务实体Entity 根据自己的业务需求创建业务实体（程序员都知道，就是普通 的JavaBean，但是里面要有MybatisPlus的关于表的注解）\n`\nimport com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data;\nimport java.util.Date;\n@Data @TableName(\u0026ldquo;sys_user\u0026rdquo;) public class UserEntity { @TableId(value = \u0026ldquo;id\u0026rdquo;) private Long userId; @TableField(\u0026ldquo;username\u0026rdquo;) private String userName; @TableField(\u0026ldquo;nickname\u0026rdquo;) private String nickName; @TableField(\u0026ldquo;password\u0026rdquo;) private String password; private String salt; private Long deptId; private String picture; private String sex; private String email; private String phone; private String remark; private Date createDate; private Date updateDate; private int status; }\n`\n\u0026gt; \u0026gt; @Data是为了省去写javabean中get和set方法 \u0026gt; \u0026gt; @TableName表示映射的数据库的表的名称\u0026amp;#8211;注意要是mybatisplus下的注解哦 \u0026gt; \u0026gt; @TableId是数据库表中主键对应的注解 \u0026gt; \u0026gt; @TableField是数据库中标字段 \u0026gt; \u0026gt; 大伙可能看到 我有的添加@TableField有的没有添加，是因为默认情况下 字段的名称和数据一样的时候可以不用写 \u0026gt; \u0026gt; 但是默认情况下你如果没有添加@TableField的时候 你写成nickName 对应数据库字段为 nick_name \u0026gt; \u0026gt; 其他需求例如某个字段不想作为数据库字段的时候(\u0026lt;https://mybatis.plus/guide/annotation.html#tablefield\u0026gt;) 更多 请参考mybatisplus官网\u0026lt;https://mp.baomidou.com/\u0026gt; \u0026gt; \u0026gt; [https://mybatis.plus][1] #### 配置Mapper {#toc_8} \u0026gt; 这里更简单 只要创建接口继承BaseMapper 就实现 了相关数据库的 增删改查等功能 \u0026gt; \u0026gt; ``` `import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.zdltech.test.mybatis.domain.UserEntity; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Component; @Component public interface UserMapper extends BaseMapper\u0026amp;lt;UserEntity\u0026amp;gt; { } ` 不要忘记添加@Component注解哦，让Spring管理实体对象\n引入的BaseMapper要是mybatisplus包下的\n测试mybatisplus是否成功配置完成 到此简单的配置MybatisPlus完成\n`import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.zdltech.test.mybatis.domain.UserEntity; import com.zdltech.test.mybatis.mapper.UserMapper; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner;\nimport java.util.List;\n@RunWith(SpringRunner.class) @SpringBootTest public class MybatisApplicationTests { @Autowired private UserMapper userMapper;\n@Test public void contextLoads() { } @Test public void testSelect(){ System.out.println(\u0026quot;-----------Select All Data-----------\u0026quot;); List\u0026amp;lt;UserEntity\u0026amp;gt; userList = userMapper.selectList(null); userList.forEach(System.out::println); Assert.assertEquals(5,5); Wrapper\u0026amp;lt;UserEntity\u0026amp;gt; wrapper = new QueryWrapper(); } } `\n\u0026gt; \u0026gt; 运行下测试类 如果能正常打印出来数据库中的数据，表示整个mybatisplus的配置正确完成 ### 配置Mybatis {#toc_10} \u0026gt; 实际上MybatisPlus是对Mybatis的扩展，完全兼容Mybatis的相关操作，所以我们可以通过Mybatisplus快速实现我们的增删改查的单表操作，相对复杂的已查询我们还是习惯使用Mybatis的sql语句 \u0026gt; \u0026gt; 下面我们配置下Mybatis \u0026gt; \u0026gt; 需要在properties文件中配置 \u0026gt; \u0026gt; mybatis.config-location=classpath:mybatis-config.xml \u0026gt; mybatis.type-aliases-package=对应的实体包 \u0026gt; mybatis.mapper-locations=classpath:mybatis/*.xml \u0026gt; #### 配置mybatis-gennerator(mybatis-generator-maven-plugin) {#toc_11} \u0026gt; generator帮助我们快速生成对应的Mapper的XMl文件 \u0026gt; \u0026gt; 配置pom.xml中的build下的plugins \u0026gt; \u0026gt; ``` `\u0026amp;lt;plugin\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.mybatis.generator\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;mybatis-generator-maven-plugin\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;1.3.7\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;configuration\u0026amp;gt; \u0026amp;lt;configurationFile\u0026amp;gt; mybatis-generator/generatorConfig.xml \u0026amp;lt;/configurationFile\u0026amp;gt; \u0026amp;lt;overwrite\u0026amp;gt;true\u0026amp;lt;/overwrite\u0026amp;gt; \u0026amp;lt;verbose\u0026amp;gt;true\u0026amp;lt;/verbose\u0026amp;gt; \u0026amp;lt;/configuration\u0026amp;gt; \u0026amp;lt;dependencies\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;mysql\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;mysql-connector-java\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;5.1.46\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;/dependencies\u0026amp;gt; \u0026amp;lt;/plugin\u0026amp;gt; ` generatorCofig.xml 配置，通过Maven插件生成Mapper xml `\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;UTF-8\u0026rdquo;?\u0026gt; \u0026lt;!DOCTYPE generatorConfiguration PUBLIC \u0026ldquo;-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN\u0026rdquo; \u0026ldquo;http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd\u0026quot;\u0026gt;\n\u0026lt;generatorConfiguration\u0026gt; \u0026lt;!\u0026ndash;导入属性配置，前面我们写的一个配置文件，你也可以直接使用mybatis的jdbc的配置文件 \u0026ndash;\u0026gt; \u0026lt;!\u0026ndash;\u0026lt;properties resource=\u0026ldquo;application.properties\u0026rdquo;\u0026gt;\u0026lt;/properties\u0026gt;\u0026ndash;\u0026gt; \u0026lt;!\u0026ndash; 数据库驱动，注意，这里必须要修改成你的数据库的驱动地址, 如果在plugin中添加依赖的话不需要设置这个\u0026ndash;\u0026gt; \u0026lt;!\u0026ndash;\u0026lt;classPathEntry location=\u0026ldquo;C:\\Users\\Administrator.m2\\repository\\mysql\\mysql-connector-java\\8.0.15\\mysql-connector-java-8.0.15.jar\u0026rdquo;/\u0026gt;\u0026ndash;\u0026gt; \u0026lt;context id=\u0026ldquo;mysqlgenerator\u0026rdquo; targetRuntime=\u0026ldquo;MyBatis3\u0026rdquo;\u0026gt; \u0026lt;!\u0026ndash;覆盖生成XML文件\u0026ndash;\u0026gt; \u0026lt;plugin type=\u0026ldquo;org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin\u0026rdquo; /\u0026gt;\n\u0026amp;lt;property name=\u0026quot;autoDelimitKeywords\u0026quot; value=\u0026quot;true\u0026quot;/\u0026amp;gt; \u0026amp;lt;!--可以使用``包括字段名，避免字段名与sql保留字冲突报错--\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;beginningDelimiter\u0026quot; value=\u0026quot;`\u0026quot;/\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;endingDelimiter\u0026quot; value=\u0026quot;`\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- 自动生成toString方法 --\u0026amp;gt; \u0026amp;lt;plugin type=\u0026quot;org.mybatis.generator.plugins.ToStringPlugin\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- 自动生成equals方法和hashcode方法 --\u0026amp;gt; \u0026amp;lt;plugin type=\u0026quot;org.mybatis.generator.plugins.EqualsHashCodePlugin\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- 非官方插件 https://github.com/itfsw/mybatis-generator-plugin --\u0026amp;gt; \u0026amp;lt;!-- 查询单条数据插件 --\u0026amp;gt; \u0026amp;lt;plugin type=\u0026quot;com.itfsw.mybatis.generator.plugins.SelectOneByExamplePlugin\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- 查询结果选择性返回插件 --\u0026amp;gt; \u0026amp;lt;plugin type=\u0026quot;com.itfsw.mybatis.generator.plugins.SelectSelectivePlugin\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- Example Criteria 增强插件 --\u0026amp;gt; \u0026amp;lt;plugin type=\u0026quot;com.itfsw.mybatis.generator.plugins.ExampleEnhancedPlugin\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- 数据Model属性对应Column获取插件 --\u0026amp;gt; \u0026amp;lt;plugin type=\u0026quot;com.itfsw.mybatis.generator.plugins.ModelColumnPlugin\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- 逻辑删除插件 --\u0026amp;gt; \u0026amp;lt;plugin type=\u0026quot;com.itfsw.mybatis.generator.plugins.LogicalDeletePlugin\u0026quot;\u0026amp;gt; \u0026amp;lt;!-- 这里配置的是全局逻辑删除列和逻辑删除值，当然在table中配置的值会覆盖该全局配置 --\u0026amp;gt; \u0026amp;lt;!-- 逻辑删除列类型只能为数字、字符串或者布尔类型 --\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;logicalDeleteColumn\u0026quot; value=\u0026quot;deleted\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- 逻辑删除-已删除值 --\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;logicalDeleteValue\u0026quot; value=\u0026quot;1\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- 逻辑删除-未删除值 --\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;logicalUnDeleteValue\u0026quot; value=\u0026quot;0\u0026quot;/\u0026amp;gt; \u0026amp;lt;/plugin\u0026amp;gt; \u0026amp;lt;!--代码上面的注释规则--\u0026amp;gt; \u0026amp;lt;commentGenerator\u0026amp;gt; \u0026amp;lt;!--false时打开时间标志，true时关闭.--\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;suppressDate\u0026quot; value=\u0026quot;true\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- 是否去除自动生成的注释 true：是 ： false:否 --\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;property name=\u0026quot;suppressAllComments\u0026quot; value=\u0026quot;true\u0026quot;/\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;/commentGenerator\u0026amp;gt; \u0026amp;lt;!--数据库连接信息--\u0026amp;gt; \u0026amp;lt;jdbcConnection driverClass=\u0026quot;com.mysql.jdbc.Driver\u0026quot; connectionURL=\u0026quot;jdbc:mysql://127.0.0.1:3306/xxxxx?useUnicode=true\u0026amp;amp;characterEncoding=UTF-8\u0026amp;amp;serverTimezone=UTC\u0026amp;amp;verifyServerCertificate=false\u0026amp;amp;useSSL=false\u0026quot; userId=\u0026quot;root\u0026quot; password=\u0026quot;root\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- 在javaTypeResolver结点中加入属性useJSR310Types，当useJSR310Types为true时，就会jdbc对应的日期类型会转成java8中的LocateDateTime类型，如果useJSR310Types为false，则还是转成java.util.Date类型 --\u0026amp;gt; \u0026amp;lt;javaTypeResolver\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;useJSR310Types\u0026quot; value=\u0026quot;false\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- true生成之后的实体中number类型转换成JAVA类型还是会被转换为BigDecimal类型。 --\u0026amp;gt; \u0026amp;lt;!-- \u0026amp;lt;property name=\u0026quot;forceBigDecimals\u0026quot; value=\u0026quot;false\u0026quot;/\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;/javaTypeResolver\u0026amp;gt; \u0026amp;lt;javaModelGenerator targetPackage=\u0026quot;实体包名位置\u0026quot; targetProject=\u0026quot;src/main/java\u0026quot;\u0026amp;gt; \u0026amp;lt;!-- enableSubPackages:是否让schema作为包的后缀 --\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;enableSubPackages\u0026quot; value=\u0026quot;true\u0026quot;/\u0026amp;gt; \u0026amp;lt;!-- 从数据库返回的值被清理前后的空格 --\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;trimStrings\u0026quot; value=\u0026quot;true\u0026quot;/\u0026amp;gt; \u0026amp;lt;/javaModelGenerator\u0026amp;gt; \u0026amp;lt;sqlMapGenerator targetPackage=\u0026quot;mapper对应目录\u0026quot; targetProject=\u0026quot;src/main/resources\u0026quot;\u0026amp;gt; \u0026amp;lt;!-- enableSubPackages:是否让schema作为包的后缀 --\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;enableSubPackages\u0026quot; value=\u0026quot;true\u0026quot;/\u0026amp;gt; \u0026amp;lt;/sqlMapGenerator\u0026amp;gt; \u0026amp;lt;javaClientGenerator type=\u0026quot;XMLMAPPER\u0026quot; targetPackage=\u0026quot;Mapper对应的包名\u0026quot; targetProject=\u0026quot;src/main/java\u0026quot;\u0026amp;gt; \u0026amp;lt;!-- enableSubPackages:是否让schema作为包的后缀 --\u0026amp;gt; \u0026amp;lt;property name=\u0026quot;enableSubPackages\u0026quot; value=\u0026quot;true\u0026quot;/\u0026amp;gt; \u0026amp;lt;/javaClientGenerator\u0026amp;gt; \u0026amp;lt;!---表名 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名，这里举例，只配置了一个table，你可以配置多个--\u0026amp;gt; \u0026amp;lt;table tableName=\u0026quot;litemall_ad\u0026quot;\u0026amp;gt; \u0026amp;lt;generatedKey column=\u0026quot;id\u0026quot; sqlStatement=\u0026quot;MySql\u0026quot; identity=\u0026quot;true\u0026quot;/\u0026amp;gt; \u0026amp;lt;/table\u0026amp;gt; \u0026amp;lt;table tableName=\u0026quot;litemall_admin\u0026quot;\u0026amp;gt; \u0026amp;lt;generatedKey column=\u0026quot;id\u0026quot; sqlStatement=\u0026quot;MySql\u0026quot; identity=\u0026quot;true\u0026quot;/\u0026amp;gt; \u0026amp;lt;columnOverride column=\u0026quot;role_ids\u0026quot; javaType=\u0026quot;java.lang.Integer[]\u0026quot; typeHandler=\u0026quot;org.linlinjava.litemall.db.mybatis.JsonIntegerArrayTypeHandler\u0026quot;/\u0026amp;gt; \u0026amp;lt;/table\u0026amp;gt; \u0026amp;lt;!-- \u0026amp;lt;table tableName=\u0026quot;tb_apr_count\u0026quot; enableCountByExample=\u0026quot;false\u0026quot; enableUpdateByExample=\u0026quot;false\u0026quot; enableDeleteByExample=\u0026quot;false\u0026quot; enableSelectByExample=\u0026quot;false\u0026quot; selectByExampleQueryId=\u0026quot;false\u0026quot;/\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;/context\u0026amp;gt; \u0026lt;/generatorConfiguration\u0026gt; `\n\u0026gt; \u0026gt; ``` `JsonIntegerArrayTypeHandler import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /* \u0026amp;lt;columnOverride column=\u0026#34;ids\u0026#34; javaType=\u0026#34;java.lang.Integer[]\u0026#34; typeHandler=\u0026#34;JsonIntegerArrayTypeHandler\u0026#34;/\u0026amp;gt; */ public class JsonIntegerArrayTypeHandler extends BaseTypeHandler\u0026amp;lt;Integer[]\u0026amp;gt; { private static final ObjectMapper mapper = new ObjectMapper(); @Override public void setNonNullParameter(PreparedStatement ps, int i, Integer[] parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, toJson(parameter)); } @Override public Integer[] getNullableResult(ResultSet rs, String columnName) throws SQLException { return this.toObject(rs.getString(columnName)); } @Override public Integer[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return this.toObject(rs.getString(columnIndex)); } @Override public Integer[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return this.toObject(cs.getString(columnIndex)); } private String toJson(Integer[] params) { try { return mapper.writeValueAsString(params); } catch (Exception e) { e.printStackTrace(); } return \u0026#34;[]\u0026#34;; } private Integer[] toObject(String content) { if (content != null \u0026amp;\u0026amp; !content.isEmpty()) { try { return (Integer[]) mapper.readValue(content, Integer[].class); } catch (Exception e) { throw new RuntimeException(e); } } else { return null; } } } ` JsonStringArrayTypeHandler `import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType;\nimport java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException;\n/* \u0026lt;columnOverride column=\u0026ldquo;urls\u0026rdquo; javaType=\u0026ldquo;java.lang.String[]\u0026rdquo; typeHandler=\u0026ldquo;JsonStringArrayTypeHandler\u0026rdquo;/\u0026gt; */ public class JsonStringArrayTypeHandler extends BaseTypeHandler\u0026lt;String[]\u0026gt; { private static final ObjectMapper mapper = new ObjectMapper();\n@Override public void setNonNullParameter(PreparedStatement ps, int i, String[] parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, toJson(parameter)); } @Override public String[] getNullableResult(ResultSet rs, String columnName) throws SQLException { return this.toObject(rs.getString(columnName)); } @Override public String[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return this.toObject(rs.getString(columnIndex)); } @Override public String[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return this.toObject(cs.getString(columnIndex)); } private String toJson(String[] params) { try { return mapper.writeValueAsString(params); } catch (Exception e) { e.printStackTrace(); } return \u0026quot;[]\u0026quot;; } private String[] toObject(String content) { if (content != null \u0026amp;\u0026amp; !content.isEmpty()) { try { return (String[]) mapper.readValue(content, String[].class); } catch (Exception e) { throw new RuntimeException(e); } } else { return null; } } } `\n\u0026gt; \u0026gt; 关于BaseTypeHandler还可以参数 \u0026gt; \u0026lt;https://www.cnblogs.com/wangjuns8/p/8688815.html\u0026gt; \u0026gt; \u0026gt; \u0026lt;https://www.jianshu.com/p/6172c7f6e27e\u0026gt; \u0026gt; \u0026gt; 如果使用到了自定义的TypeHandler 需要在mybatis生成的mapper.xml文件中 resultMap中的对应字段中添加typeHandler \u0026gt; \u0026gt; 例如： \u0026gt; \u0026gt; \u0026lt;result column=\u0026#34;specifications\u0026#34; jdbcType=\u0026#34;VARCHAR\u0026#34; property=\u0026#34;specifications\u0026#34; typeHandler=\u0026#34;org.linlinjava.litemall.db.mybatis.JsonStringArrayTypeHandler\u0026#34; /\u0026gt; \u0026gt; #### 执行Maven plugin下的mybatis-generaor {#toc_13} \u0026gt; 配置完上面之后，需要我们执行mybatis的maven插件了 \u0026gt; \u0026gt; 执行mybatis-generator:generate等待相关数据生成 [1]: https://mybatis.plus/ ","permalink":"https://blog.zdltech.com/posts/mybatis-jimybatisplus-jian-dan-shi-yong/","summary":"\u003ch2 id=\"toc_0\"\u003eMyBatis及MyBatisPlus简单使用\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e在做java开发的时候，我们经常会使用Mybatis来作为我们操作数据库的工具库，今天一步步带领大家集成到Spring boot中，本篇主要实现Spring boot+mybatis+MybatisPlus的基础使用\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"toc_1\"\u003e第一步创建Spring boot项目\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e大家使用自己熟悉的开发工具创建Spring boot项目。例如Idea、eclipse及SpringToolSuite4等工具，这里默认大家都已成功创建Springboot项目\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch4 id=\"toc_2\"\u003e配置pom.xml\u003c/h4\u003e\n\u003cblockquote\u003e\n\u003cp\u003e这里使用的是mysql，大家根据自己情况配置相关的数据源\u003c/p\u003e\n\u003cp\u003epom.xm\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e`\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;UTF-8\u0026rdquo;?\u0026gt;\n\u0026lt;project xmlns=\u0026ldquo;\u003ca href=\"http://maven.apache.org/POM/4.0.0%22\"\u003ehttp://maven.apache.org/POM/4.0.0\u0026quot;\u003c/a\u003e xmlns:xsi=\u0026ldquo;\u003ca href=\"http://www.w3.org/2001/XMLSchema-instance%22\"\u003ehttp://www.w3.org/2001/XMLSchema-instance\u0026quot;\u003c/a\u003e\nxsi:schemaLocation=\u0026ldquo;\u003ca href=\"http://maven.apache.org/POM/4.0.0\"\u003ehttp://maven.apache.org/POM/4.0.0\u003c/a\u003e \u003ca href=\"https://maven.apache.org/xsd/maven-4.0.0.xsd%22\"\u003ehttps://maven.apache.org/xsd/maven-4.0.0.xsd\u0026quot;\u003c/a\u003e\u0026gt;\n\u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt;\n\u0026lt;parent\u0026gt;\n\u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt;\n\u0026lt;artifactId\u0026gt;spring-boot-starter-parent\u0026lt;/artifactId\u0026gt;\n\u0026lt;version\u0026gt;2.1.8.RELEASE\u0026lt;/version\u0026gt;\n\u0026lt;relativePath/\u0026gt; \u0026lt;!\u0026ndash; lookup parent from repository \u0026ndash;\u0026gt;\n\u0026lt;/parent\u0026gt;\n\u0026lt;groupId\u0026gt;com.zdltech.test\u0026lt;/groupId\u0026gt;\n\u0026lt;artifactId\u0026gt;mybatis\u0026lt;/artifactId\u0026gt;\n\u0026lt;version\u0026gt;0.0.1-SNAPSHOT\u0026lt;/version\u0026gt;\n\u0026lt;name\u0026gt;mybatis\u0026lt;/name\u0026gt;\n\u0026lt;description\u0026gt;mybatis的测试\u0026lt;/description\u0026gt;\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026amp;lt;properties\u0026amp;gt;\n    \u0026amp;lt;java.version\u0026amp;gt;1.8\u0026amp;lt;/java.version\u0026amp;gt;\n\u0026amp;lt;/properties\u0026amp;gt;\n\n\u0026amp;lt;dependencies\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-data-jpa\u0026amp;lt;/artifactId\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-jdbc\u0026amp;lt;/artifactId\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-thymeleaf\u0026amp;lt;/artifactId\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-web\u0026amp;lt;/artifactId\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.mybatis.spring.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;mybatis-spring-boot-starter\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;version\u0026amp;gt;2.1.0\u0026amp;lt;/version\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-test\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;scope\u0026amp;gt;test\u0026amp;lt;/scope\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;mysql\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;mysql-connector-java\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;scope\u0026amp;gt;runtime\u0026amp;lt;/scope\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n  \n  \u0026amp;lt;!-- 下面这个mysbatis-plus-boot-starter是配置Mybatis和MybatisPlus的依赖--\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;com.baomidou\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;mybatis-plus-boot-starter\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;version\u0026amp;gt;3.1.0\u0026amp;lt;/version\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;org.projectlombok\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;lombok\u0026amp;lt;/artifactId\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n    \u0026amp;lt;dependency\u0026amp;gt;\n        \u0026amp;lt;groupId\u0026amp;gt;com.alibaba\u0026amp;lt;/groupId\u0026amp;gt;\n        \u0026amp;lt;artifactId\u0026amp;gt;druid-spring-boot-starter\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;version\u0026amp;gt;1.1.13\u0026amp;lt;/version\u0026amp;gt;\n    \u0026amp;lt;/dependency\u0026amp;gt;\n\u0026amp;lt;/dependencies\u0026amp;gt;\n\n\u0026amp;lt;build\u0026amp;gt;\n    \u0026amp;lt;plugins\u0026amp;gt;\n        \u0026amp;lt;plugin\u0026amp;gt;\n            \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt;\n            \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-maven-plugin\u0026amp;lt;/artifactId\u0026amp;gt;\n        \u0026amp;lt;/plugin\u0026amp;gt;\n    \u0026amp;lt;/plugins\u0026amp;gt;\n\u0026amp;lt;/build\u0026amp;gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u0026lt;/project\u0026gt;\n`\u003c/p\u003e","title":"MyBatis及MyBatisPlus简单使用"},{"content":" ​ Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发，如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等，都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子，它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来，通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理，最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。\nSpring Cloud Netflix\n是对Netflix开发的一套分布式服务框架的封装，包括服务的发现和注册，负载均衡、断路器、REST客户端、请求路由等。\nSpring Cloud Config\n将配置信息中央化保存, 配置Spring Cloud Bus可以实现动态修改配置文件\nSpring Cloud Bus\n分布式消息队列，是对Kafka, MQ的封装\nSpring Cloud Security\n对Spring Security的封装，并能配合Netflix使用\nSpring Cloud Zookeeper\n对Zookeeper的封装，使之能配置其它Spring Cloud的子项目使用\nSpring Cloud Eureka\nSpring Cloud Eureka 是 Spring Cloud Netflix 微服务套件中的一部分，它基于Netflix Eureka 做了二次封装，主要负责完成微服务架构中的服务治理功能\n​ Spring cloud 是微服务架构的集大成者,将一系列优秀的组件进行了整合。\n本章Spring cloud 使用，一步一步带你构建Spring cloud整个应用\n构建Spring cloud服务端 构建Spring cloud 服务提供端 构建Spring cloud 消费端（服务调用端） 一、Spring Cloud 服务端 POM.xml 配置\n`\u0026lt;project xmlns=\u0026ldquo;http://maven.apache.org/POM/4.0.0\u0026quot; xmlns:xsi=\u0026ldquo;http://www.w3.org/2001/XMLSchema-instance\u0026quot; xsi:schemaLocation=\u0026ldquo;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\u0026quot;\u0026gt; \u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt; \u0026lt;parent\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-parent\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.1.6.RELEASE\u0026lt;/version\u0026gt; \u0026lt;relativePath/\u0026gt; \u0026lt;!\u0026ndash; lookup parent from repository \u0026ndash;\u0026gt; \u0026lt;/parent\u0026gt; \u0026lt;groupId\u0026gt;com.test.cloud\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;demo\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;0.0.1-SNAPSHOT\u0026lt;/version\u0026gt; \u0026lt;name\u0026gt;demo\u0026lt;/name\u0026gt; \u0026lt;description\u0026gt;Demo project for Spring Boot\u0026lt;/description\u0026gt;\n\u0026amp;lt;properties\u0026amp;gt; \u0026amp;lt;java.version\u0026amp;gt;1.8\u0026amp;lt;/java.version\u0026amp;gt; \u0026amp;lt;spring-cloud.version\u0026amp;gt;Greenwich.SR2\u0026amp;lt;/spring-cloud.version\u0026amp;gt; \u0026amp;lt;/properties\u0026amp;gt; \u0026amp;lt;dependencies\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.cloud\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-cloud-starter-netflix-eureka-server\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-test\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;scope\u0026amp;gt;test\u0026amp;lt;/scope\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-security\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;/dependencies\u0026amp;gt; \u0026amp;lt;dependencyManagement\u0026amp;gt; \u0026amp;lt;dependencies\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.cloud\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-cloud-dependencies\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;${spring-cloud.version}\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;type\u0026amp;gt;pom\u0026amp;lt;/type\u0026amp;gt; \u0026amp;lt;scope\u0026amp;gt;import\u0026amp;lt;/scope\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;/dependencies\u0026amp;gt; \u0026amp;lt;/dependencyManagement\u0026amp;gt; \u0026amp;lt;build\u0026amp;gt; \u0026amp;lt;plugins\u0026amp;gt; \u0026amp;lt;plugin\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-maven-plugin\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/plugin\u0026amp;gt; \u0026amp;lt;/plugins\u0026amp;gt; \u0026amp;lt;/build\u0026amp;gt; \u0026lt;/project\u0026gt; `\n\u0026gt; \u0026gt; application.properties配置 \u0026gt; \u0026gt; ``` `server.port=8761 eureka.instance.hostname=127.0.0.1 eureka.client.register-with-eureka=false eureka.client.fetch-registry=false eureka.client.service-url.defaultZone=http://\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{spring.security.user.name}:\u0026amp;lt;/span\u0026gt;{spring.security.user.password}@\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{eureka.instance.hostname}:\u0026amp;lt;/span\u0026gt;{server.port}/eureka/ # suppress inspection \u0026#34;SpringBootApplicationProperties\u0026#34; spring.security.basic.enabled=true spring.security.user.name=user spring.security.user.password=123456 ` 项目入口Application配置\n添加 @EnableEurekaServer 注解 在Application中 如果遇到csrf问题的时候，需要实现WebSecurityConfigurerAdapter的configure 方法\n`import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\n@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); super.configure(http); } } `\n\u0026gt; \u0026gt; 直接运行项目 出现下面表示项目启动成功 \u0026gt; \u0026gt; [ Thread-46] o.s.c.n.e.server.EurekaServerBootstrap : Initialized server context \u0026gt; [ Thread-46] c.n.e.r.PeerAwareInstanceRegistryImpl : Got 1 instances from neighboring DS node \u0026gt; [ Thread-46] c.n.e.r.PeerAwareInstanceRegistryImpl : Renew threshold is: 1 \u0026gt; [ Thread-46] c.n.e.r.PeerAwareInstanceRegistryImpl : Changing status to UP \u0026gt; [ Thread-46] e.s.EurekaServerInitializerConfiguration : Started Eureka Server \u0026gt; [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8761 (http) with context path \u0026#39;\u0026#39; \u0026gt; [ main] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 8761 \u0026gt; [ main] com.test.cloud.demo.DemoApplication : Started DemoApplication in 18.421 seconds (JVM running for 26.067) \u0026gt; [on(2)-127.0.0.1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet \u0026#39;dispatcherServlet\u0026#39; \u0026gt; [on(2)-127.0.0.1] o.s.web.servlet.DispatcherServlet : Initializing Servlet \u0026#39;dispatcherServlet\u0026#39; \u0026gt; [on(2)-127.0.0.1] o.s.web.servlet.DispatcherServlet : Completed initialization in 16 ms \u0026gt; \u0026gt; 在浏览器输入 127.0.0.1：8761 出现 输入我们在application.properties中配置的用户名和密码, 出现下面界面，表示服务注册中心启动成功，等待服务注册。 \u0026gt; \u0026gt;![image-20190827132029270](https://tva1.sinaimg.cn/large/006y8mN6ly1g6e60ioamjj30v20ly755.jpg) \u0026gt; \u0026gt;![image-20190827132220517](https://tva1.sinaimg.cn/large/006y8mN6ly1g6e62eawd3j31ji0u0th3.jpg) ### 二、构建Spring cloud 服务提供端 {#toc_1} \u0026gt; pom.xml 配置 \u0026gt; \u0026gt; ``` `\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026amp;gt; \u0026amp;lt;project xmlns=\u0026#34;http://maven.apache.org/POM/4.0.0\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xsi:schemaLocation=\u0026#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\u0026#34;\u0026amp;gt; \u0026amp;lt;modelVersion\u0026amp;gt;4.0.0\u0026amp;lt;/modelVersion\u0026amp;gt; \u0026amp;lt;parent\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-parent\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;2.1.6.RELEASE\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;relativePath/\u0026amp;gt; \u0026amp;lt;!-- lookup parent from repository --\u0026amp;gt; \u0026amp;lt;/parent\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;com.example\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;clientdemo\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;0.0.1-SNAPSHOT\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;name\u0026amp;gt;clientdemo\u0026amp;lt;/name\u0026amp;gt; \u0026amp;lt;description\u0026amp;gt;Demo project for Spring Boot\u0026amp;lt;/description\u0026amp;gt; \u0026amp;lt;properties\u0026amp;gt; \u0026amp;lt;java.version\u0026amp;gt;1.8\u0026amp;lt;/java.version\u0026amp;gt; \u0026amp;lt;spring-cloud.version\u0026amp;gt;Greenwich.SR2\u0026amp;lt;/spring-cloud.version\u0026amp;gt; \u0026amp;lt;/properties\u0026amp;gt; \u0026amp;lt;dependencies\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-web\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.cloud\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-cloud-starter-netflix-eureka-client\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-test\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;scope\u0026amp;gt;test\u0026amp;lt;/scope\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;/dependencies\u0026amp;gt; \u0026amp;lt;dependencyManagement\u0026amp;gt; \u0026amp;lt;dependencies\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.cloud\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-cloud-dependencies\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;${spring-cloud.version}\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;type\u0026amp;gt;pom\u0026amp;lt;/type\u0026amp;gt; \u0026amp;lt;scope\u0026amp;gt;import\u0026amp;lt;/scope\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;/dependencies\u0026amp;gt; \u0026amp;lt;/dependencyManagement\u0026amp;gt; \u0026amp;lt;build\u0026amp;gt; \u0026amp;lt;plugins\u0026amp;gt; \u0026amp;lt;plugin\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-maven-plugin\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/plugin\u0026amp;gt; \u0026amp;lt;/plugins\u0026amp;gt; \u0026amp;lt;/build\u0026amp;gt; \u0026amp;lt;/project\u0026amp;gt; ` application.properties配置，注意名称不能包含下划线（—）\nserver.port=8762 eureka.client.service-url.defaultZone=http://user:123456@127.0.0.1:8761/eureka/ spring.application.name=client-test-demo spring.security.user.name=user spring.security.user.password=123456 \u0026gt; \u0026gt; 入口Application配置 \u0026gt; \u0026gt; 服务提供者需要在Application添加@EnableEurekaClient 注解 \u0026gt; \u0026gt; 添加一个测试的Controller \u0026gt; \u0026gt; ``` `import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping(\u0026#34;index\u0026#34;) public class IndexController { @GetMapping(\u0026#34;test\u0026#34;) @ResponseBody public String test(){ return \u0026#34;测试-服务提供者\u0026#34;; } } ` 启动服务提供者，出现如下表示启动成功，可以通过接口调用下上面写的Controller的测试方法是否成功。\nscoveryClient : Starting heartbeat executor: renew interval is: 30\n[ main] c.n.discovery.InstanceInfoReplicator : InstanceInfoReplicator onDemand update allowed rate per min is 4\n[ main] com.netflix.discovery.DiscoveryClient : Discovery Client initialized at timestamp 1566883730293 with initial instances count: 0\n[ main] o.s.c.n.e.s.EurekaServiceRegistry : Registering application CLIENT-TEST-DEMO with eureka with status UP\n[ main] com.netflix.discovery.DiscoveryClient : Saw local status change event StatusChangeEvent [timestamp=1566883730299, current=UP, previous=STARTING]\n[nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_CLIENT-TEST-DEMO/192.168.1.78:client-test-demo:8762: registering service…\n[ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8762 (http) with context path \u0026rsquo;\u0026rsquo;\n[ main] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 8762\n[ main] c.e.clientdemo.ClientdemoApplication : Started ClientdemoApplication in 14.831 seconds (JVM running for 21.023)\n查看服务注册中心是否有启动的注册的服务\n三、构建Spring cloud 消费端（服务调用端） pom.xml配置\n`\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;UTF-8\u0026rdquo;?\u0026gt; \u0026lt;project xmlns=\u0026ldquo;http://maven.apache.org/POM/4.0.0\u0026quot; xmlns:xsi=\u0026ldquo;http://www.w3.org/2001/XMLSchema-instance\u0026quot; xsi:schemaLocation=\u0026ldquo;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\u0026quot;\u0026gt; \u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt; \u0026lt;parent\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-parent\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.1.6.RELEASE\u0026lt;/version\u0026gt; \u0026lt;relativePath/\u0026gt; \u0026lt;!\u0026ndash; lookup parent from repository \u0026ndash;\u0026gt; \u0026lt;/parent\u0026gt; \u0026lt;groupId\u0026gt;com.example\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;springxiaofeidemo\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;0.0.1-SNAPSHOT\u0026lt;/version\u0026gt; \u0026lt;name\u0026gt;springxiaofeidemo\u0026lt;/name\u0026gt; \u0026lt;description\u0026gt;Demo project for Spring Boot\u0026lt;/description\u0026gt;\n\u0026amp;lt;properties\u0026amp;gt; \u0026amp;lt;java.version\u0026amp;gt;1.8\u0026amp;lt;/java.version\u0026amp;gt; \u0026amp;lt;spring-cloud.version\u0026amp;gt;Greenwich.SR2\u0026amp;lt;/spring-cloud.version\u0026amp;gt; \u0026amp;lt;/properties\u0026amp;gt; \u0026amp;lt;dependencies\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-web\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.cloud\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-cloud-starter-netflix-eureka-client\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.cloud\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-cloud-starter-netflix-ribbon\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.cloud\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-cloud-starter-openfeign\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-test\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;scope\u0026amp;gt;test\u0026amp;lt;/scope\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;!-- 添加Actuator监控 --\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-starter-actuator\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;/dependencies\u0026amp;gt; \u0026amp;lt;dependencyManagement\u0026amp;gt; \u0026amp;lt;dependencies\u0026amp;gt; \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.cloud\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-cloud-dependencies\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;\u0026amp;lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;{spring-cloud.version}\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;type\u0026amp;gt;pom\u0026amp;lt;/type\u0026amp;gt; \u0026amp;lt;scope\u0026amp;gt;import\u0026amp;lt;/scope\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; \u0026amp;lt;/dependencies\u0026amp;gt; \u0026amp;lt;/dependencyManagement\u0026amp;gt; \u0026amp;lt;build\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;finalName\u0026amp;gt;\u0026amp;lt;/span\u0026gt;{project.artifactId}\u0026amp;lt;/finalName\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;resources\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;resource\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;directory\u0026amp;gt;src/main/resources\u0026amp;lt;/directory\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;filtering\u0026amp;gt;true\u0026amp;lt;/filtering\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;/resource\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;/resources\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;plugins\u0026amp;gt; \u0026amp;lt;plugin\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;org.springframework.boot\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;spring-boot-maven-plugin\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;/plugin\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;plugin\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;groupId\u0026amp;gt;org.apache.maven.plugins\u0026amp;lt;/groupId\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;artifactId\u0026amp;gt;maven-resources-plugin\u0026amp;lt;/artifactId\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;configuration\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;delimiters\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;delimit\u0026amp;gt;$\u0026amp;lt;/delimit\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;/delimiters\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;/configuration\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;!--\u0026amp;lt;/plugin\u0026amp;gt;--\u0026amp;gt; \u0026amp;lt;/plugins\u0026amp;gt; \u0026amp;lt;/build\u0026amp;gt; \u0026lt;/project\u0026gt; `\n\u0026gt; \u0026gt; application.properties配置 \u0026gt; \u0026gt; ``` `server.port=8763 eureka.client.service-url.defaultZone=http://user:123456@127.0.0.1:8761/eureka/ spring.application.name=client-request-demo spring.security.user.name=user spring.security.user.password=123456 feign.hystrix.enabled=true ` 入口Application中添加@EnableEurekaClient和@EnableFeignClients 注解 FeignClients是用来服务间调用的。\n`@EnableEurekaClient @SpringBootApplication @EnableFeignClients public class SpringxiaofeidemoApplication {\npublic static void main(String[] args) { SpringApplication.run(SpringxiaofeidemoApplication.class, args); } @Bean @LoadBalanced RestTemplate restTemplate(){ return new RestTemplate(); } } `\n\u0026gt; \u0026gt; 添加测试Controller类 \u0026gt; \u0026gt; ``` `import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController @RequestMapping(\u0026#34;/index\u0026#34;) public class IndexController { @Autowired HelloService helloService; @Autowired RestTemplate restTemplate; @GetMapping(\u0026#34;test\u0026#34;) public String indexTest(){// 通过HelloService中的注解绑定调用 参考 Helloservice return this.helloService.hello(); } @GetMapping(\u0026#34;test1\u0026#34;) public String ribbonTest(){ //注解@HystrixCommand 不能加在控制器层,而应该加在Service 层 使用Hystrix进行容错和服务降级 return restTemplate.getForObject(\u0026#34;http://CLIENT-TEST-DEMO/index/test\u0026#34;,String.class); } } ` `HelloService接口 import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping;\n@FeignClient(value = \u0026ldquo;CLIENT-TEST-DEMO\u0026rdquo;,fallback = HelloServiceFallback.class) public interface HelloService { @GetMapping(value = \u0026ldquo;index/test\u0026rdquo;) String hello(); } `\n\u0026gt; \u0026gt; HelloServiceFallback 类 \u0026gt; \u0026gt; ``` `import org.springframework.stereotype.Component; @Component public class HelloServiceFallback implements HelloService{ @Override public String hello() { return \u0026#34;测试-服务降权容错提供者\u0026#34;; } } ` 启动服务\n[ main] com.netflix.discovery.DiscoveryClient : Getting all instance registry info from the eureka server\n[ main] com.netflix.discovery.DiscoveryClient : The response status is 200\n[ main] com.netflix.discovery.DiscoveryClient : Starting heartbeat executor: renew interval is: 30\n[ main] c.n.discovery.InstanceInfoReplicator : InstanceInfoReplicator onDemand update allowed rate per min is 4\n[ main] com.netflix.discovery.DiscoveryClient : Discovery Client initialized at timestamp 1566884583081 with initial instances count: 1\n[ main] o.s.c.n.e.s.EurekaServiceRegistry : Registering application CLIENT-REQUEST-DEMO with eureka with status UP\n[ main] com.netflix.discovery.DiscoveryClient : Saw local status change event StatusChangeEvent [timestamp=1566884583086, current=UP, previous=STARTING]\n[nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_CLIENT-REQUEST-DEMO/192.168.1.78:client-request-demo:8763: registering service…\n[ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8763 (http) with context path \u0026rsquo;\u0026rsquo;\n[ main] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 8763\n[ main] c.e.s.SpringxiaofeidemoApplication : Started SpringxiaofeidemoApplication in 17.69 seconds (JVM running for 23.897)\n[on(6)-127.0.0.1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet \u0026lsquo;dispatcherServlet\u0026rsquo;\n[on(6)-127.0.0.1] o.s.web.servlet.DispatcherServlet : Initializing Servlet \u0026lsquo;dispatcherServlet\u0026rsquo;\n[on(6)-127.0.0.1] o.s.web.servlet.DispatcherServlet : Completed initialization in 15 ms\n在浏览器中输入\nhttp://127.0.0.1:8763/index/test\n结果：测试-服务提供者\nhttp://127.0.0.1:8763/index/test1\n结果：测试-服务提供者\n如果我们关闭服务提供者会是什么情况呢？\n关闭服务提供者\n输入：http://127.0.0.1:8763/index/test\n结果：测试-服务降权容错提供者\n输入：http://127.0.0.1:8763/index/test1\n结果：Whitelabel Error Page\nThis application has no explicit mapping for /error, so you are seeing this as a fallback.\nTue Aug 27 13:48:14 CST 2019\nThere was an unexpected error (type=Internal Server Error, status=500).\nNo instances available for CLIENT-TEST-DEMO\n项目控制台输出java.lang.IllegalStateException: No instances available for CLIENT-TEST-DEMO\n如果服务都启动之后关闭注册中心请大家自己试试？\n四、其他 上面的3个工程打包为zip放到百度云盘\n链接: https://pan.baidu.com/s/1IOWaF_uUzL65_6GQWf6pDA 提取码: kuw8\n背景介绍：eureka默认开启了自我保护机制，导致实际上已经停止服务的实例无法从注册中心剔除！\n解决方案：\n在注册中心(eureka-server端，而不是eureka-client端)添加如下配置：\n以下配置仅在开发环境中使用\n关闭注册中心的自我保护机制，防止已关闭的实例无法从注册中心剔除\neureka.server.enable-self-preservation=false\n背景：由于Eureka拥有自我保护机制，当其注册表里服务因为网络或其他原因出现故障而关停时，Eureka不会剔除服务注册，而是等待其修复。这是AP的一种实现。\n为了让其有精准的 CP健康检查，可以采取让其剔除不健康节点。\nserver端:\neureka.server.enable-self-preservation//（设为false，关闭自我保护主要）\neureka.server.eviction-interval-timer-in-ms//清理间隔（单位毫秒，默认是60*1000）\nclient端：\neureka.client.healthcheck.enabled = true//开启健康检查（需要spring-boot-starter-actuator依赖）\neureka.instance.lease-renewal-interval-in-seconds =10//租期更新时间间隔（默认30秒）\neureka.instance.lease-expiration-duration-in-seconds =30//租期到期时间（默认90秒）\n实例：\nserver端配置：\neureka:\nserver:\nenableSelfPreservation: false\nevictionIntervalTimerInMs: 4000\nclient配置：\neureka:\ninstance:\nleaseRenewalIntervalInSeconds: 10\nleaseExpirationDurationInSeconds: 30\nlease-renewal-interval-in-seconds 每间隔10s，向服务端发送一次心跳，证明自己依然”存活“\nlease-expiration-duration-in-seconds 告诉服务端，如果我30s之内没有给你发心跳，就代表我“死”了，将我踢出掉。\n注意：更改Eureka更新频率将打破服务器的自我保护功能\n参考 https://zhuanlan.zhihu.com/p/26472547\n","permalink":"https://blog.zdltech.com/posts/yi-bu-yi-bu-dai-ni-gou-jianspring-cloud/","summary":"\u003cblockquote\u003e\n\u003cp\u003e​ Spring Cloud是一系列框架的有序集合。它利用\u003ca href=\"https://baike.baidu.com/item/Spring%20Boot/20249767\"\u003eSpring Boot\u003c/a\u003e的开发便利性巧妙地简化了分布式系统基础设施的开发，如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等，都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子，它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来，通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理，最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eSpring Cloud Netflix\u003cbr\u003e\n　　是对Netflix开发的一套分布式服务框架的封装，包括服务的发现和注册，负载均衡、断路器、REST客户端、请求路由等。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSpring Cloud Config\u003cbr\u003e\n　　将配置信息中央化保存, 配置Spring Cloud Bus可以实现动态修改配置文件\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSpring Cloud Bus\u003cbr\u003e\n　　分布式消息队列，是对Kafka, MQ的封装\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSpring Cloud Security\u003cbr\u003e\n　　对Spring Security的封装，并能配合Netflix使用\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSpring Cloud Zookeeper\u003cbr\u003e\n　　对Zookeeper的封装，使之能配置其它Spring Cloud的子项目使用\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSpring Cloud Eureka\u003c/p\u003e\n\u003cp\u003eSpring Cloud Eureka 是 Spring Cloud Netflix 微服务套件中的一部分，它基于Netflix Eureka 做了二次封装，主要负责完成微服务架构中的服务治理功能\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e​ Spring cloud 是微服务架构的集大成者,将一系列优秀的组件进行了整合。\u003c/p\u003e\n\u003cp\u003e本章Spring cloud 使用，一步一步带你构建Spring cloud整个应用\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e构建Spring cloud服务端\u003c/li\u003e\n\u003cli\u003e构建Spring cloud 服务提供端\u003c/li\u003e\n\u003cli\u003e构建Spring cloud 消费端（服务调用端）\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cimg alt=\"img\" loading=\"lazy\" src=\"https://tva1.sinaimg.cn/large/006y8mN6ly1g6e7a1lrtjj30k00azt94.jpg\"\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"toc_0\"\u003e一、Spring Cloud 服务端\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003ePOM.xml 配置\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e`\u0026lt;project xmlns=\u0026ldquo;\u003ca href=\"http://maven.apache.org/POM/4.0.0%22\"\u003ehttp://maven.apache.org/POM/4.0.0\u0026quot;\u003c/a\u003e xmlns:xsi=\u0026ldquo;\u003ca href=\"http://www.w3.org/2001/XMLSchema-instance%22\"\u003ehttp://www.w3.org/2001/XMLSchema-instance\u0026quot;\u003c/a\u003e\nxsi:schemaLocation=\u0026ldquo;\u003ca href=\"http://maven.apache.org/POM/4.0.0\"\u003ehttp://maven.apache.org/POM/4.0.0\u003c/a\u003e \u003ca href=\"http://maven.apache.org/xsd/maven-4.0.0.xsd%22\"\u003ehttp://maven.apache.org/xsd/maven-4.0.0.xsd\u0026quot;\u003c/a\u003e\u0026gt;\n\u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt;\n\u0026lt;parent\u0026gt;\n\u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt;\n\u0026lt;artifactId\u0026gt;spring-boot-starter-parent\u0026lt;/artifactId\u0026gt;\n\u0026lt;version\u0026gt;2.1.6.RELEASE\u0026lt;/version\u0026gt;\n\u0026lt;relativePath/\u0026gt; \u0026lt;!\u0026ndash; lookup parent from repository \u0026ndash;\u0026gt;\n\u0026lt;/parent\u0026gt;\n\u0026lt;groupId\u0026gt;com.test.cloud\u0026lt;/groupId\u0026gt;\n\u0026lt;artifactId\u0026gt;demo\u0026lt;/artifactId\u0026gt;\n\u0026lt;version\u0026gt;0.0.1-SNAPSHOT\u0026lt;/version\u0026gt;\n\u0026lt;name\u0026gt;demo\u0026lt;/name\u0026gt;\n\u0026lt;description\u0026gt;Demo project for Spring Boot\u0026lt;/description\u0026gt;\u003c/p\u003e","title":"一步一步带你构建Spring Cloud"},{"content":"开发人员之环境配置 由于系统崩溃，造成平时积累的软件工具及开发常用插件丢失，好记性不如记录下来，方便以后查阅。 Android Studio插件 `1. GsonFormat 2. ADB Idea 3. Android Develop Templates 4. Android Dialog 5. Android Drawable Importer 6. Android Drawable Viewer 7. Android Parcelable code generator 8. Android Selectors Generate 9. Android String.xml To CSV Converter 10. dash 11. Database Navigator 12. JSON TO Kotlin Class 13. Markdown Navigator 14. Parcelable Code Generator (for kotlin) 15. Generator Android Resource` sublime Text3 数据恢复 `复制 /Users/用户/Library/Application\\ Support/Sublime\\ Text\\ 3/Local/Session.sublime_session 这个就是之前没有保存的数据，通过复制/Users/用户/Library/Application\\ Support/Sublime\\ Text\\ 3/下面的所有内容，来恢复插件等等！！` ","permalink":"https://blog.zdltech.com/posts/%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7%E9%85%8D%E7%BD%AE/","summary":"\u003ch1 class=\"wp-block-heading\" id=\"开发人员之环境配置\"\u003e开发人员之环境配置\u003c/h1\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e由于系统崩溃，造成平时积累的软件工具及开发常用插件丢失，好记性不如记录下来，方便以后查阅。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch2 class=\"wp-block-heading\" id=\"android-studio插件\"\u003eAndroid Studio插件\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`1. GsonFormat\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e2. ADB Idea\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e3. Android Develop Templates\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e4. Android Dialog\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e5. Android Drawable Importer\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e6. Android Drawable Viewer\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e7. Android Parcelable code generator\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e8. Android Selectors Generate\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e9. Android String.xml To  CSV Converter\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e10. dash\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e11. Database Navigator\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e12. JSON TO Kotlin Class\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e13. Markdown Navigator\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e14. Parcelable Code Generator (for kotlin)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e15. Generator Android Resource`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 class=\"wp-block-heading\" id=\"sublime-text3-数据恢复\"\u003esublime Text3 数据恢复\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`复制 /Users/用户/Library/Application\\ Support/Sublime\\ Text\\ 3/Local/Session.sublime_session 这个就是之前没有保存的数据，通过复制/Users/用户/Library/Application\\ Support/Sublime\\ Text\\ 3/下面的所有内容，来恢复插件等等！！`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"常用工具配置"},{"content":"!/bin/bash Author: zhangdongling Copyright(C) Script follows here: echo “What is your name?”\nread PERSON\necho “Hello ,$PERSON”\nvariableName=”zhangdl”\nname=dong\necho “variableName,$variableName”\necho “name,$name”\necho “1.”$0 #当前脚本的文件名\necho “2.”$1 #传递给脚本或函数的参数\necho “3.”$# #传递给脚本或函数的参数个数。\necho “4.”$* #传递给脚本或函数的所有参数。\necho “5.”@ #传递给脚本或函数的所有参数。被双引号(” “)包含时，与* 稍有不同，下面将会讲到。\necho “6.”$? #上个命令的退出状态，或函数的返回值。大部分命令执行成功会返回0，失败返回1\necho “8.\u0026amp;#8221;$@\u0026amp;#8221;”\necho “9.\u0026amp;#8221;$*\u0026amp;#8221;”\necho -e “pid is $$ \\n”\necho “pid is $$ \\n”\nDATE=date\necho -e “DATE is $DATE \\n”\nUSERS=who | wc -l\necho -e “Logged in user are $USERS \\n”\nUP=date;uptime\necho -e “Uptime is $UP \\n”\nval=expr 2 + 2\necho “Total value:$val”\na=10\nb=20\nval=expr \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;a +\u0026lt;/span\u0026gt;b\necho “a + b :$val”\nval=expr \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;a -\u0026lt;/span\u0026gt;b\nval=expr \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;a \\*\u0026lt;/span\u0026gt;b\necho “a * b :$val”\nval=expr \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;a /\u0026lt;/span\u0026gt;b\necho “a / b :$val”\nval=expr \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;a %\u0026lt;/span\u0026gt;b\necho “a % b :$val”\nif [ a ==b ]\nthen\necho ” a is equal to b”\nfi\nif [ a !=b ]\nthen\necho “a is not equal to b”\nfi\na=10\nb=20\nif [ a -eqb ]\nthen\necho “a -eqb : a is equal to b”\nelse\necho “a -eqb : a is not equal to b”\nfi\nif [ a -neb ]\nthen\necho “a -neb : a is not equal to b”\nelse\necho “a -neb : a is equal to b”\nfi\nif [ a -gtb ]\nthen\necho “a -gtb : a is less than b”\nelse\necho “a -gtb : a is not less than b”\nfi\nif [ a -ltb ]\nthen\necho “a -ltb :a is less than b”\nelse\necho “a -ltb : a is not less than b”\nfi\nif [ a -geb ]\nthen\necho “a -geb : a is greater or equal to b”\nelse\necho “a -geb : a is not greater or equal to b “\nfi\nif [ a -leb ]\nthen\necho “a -leb : a is less or equal to b”\nelse\necho “a -leb : a is not less or equal to b”\nfi\nfile=”/xxxx.sh”\nif [ -r $file ]\nthen\necho “File has read access”\nelse\necho “File does not have read access”\nfi\nif [ -w $file ]\nthen\necho “File has write permission”\nelse\necho “File does not have write permission”\nfi\nif [ -x $file ]\nthen\necho “File has execute permission”\nelse\necho “File does not have execute permission”\nfi\nif [ -f $file ]\nthen\necho “File is an ordinary file”\nelse\necho “This is sepcial file”\nfi\nif [ -d $file ]\nthen\necho “File is a directory”\nelse\necho “This is not a direactory”\nfi\nif [ -s $file ]\nthen\necho “File size is zero”\nelse\necho “File size is not zero”\nfi\nif [ -e $file ]\nthen\necho “File exists”\nelse\necho “File does not exist”\nfi\nval=(a b c d e)\necho ${val[]} echo {val[@]} len={#val[]}\necho $len\nfor item in a b c d e\ndo\necho $item\ndone\nfunction Hello(){\necho “Hello world”\n}\nHello\necho $?\nprintf “Hello.shell \\n”\nprintf “%d,%s\\n” 1 zhangdl\nstr=”abcd”\necho ${#str} # 字符串长度\nstr=”alibaba is a great company”\necho ${str:1:4} # 提取字符串（数字表示字符串中字符对应下标）\nstring=”alibaba is a great company”\nval=expr length $string\necho $val\n","permalink":"https://blog.zdltech.com/posts/shell-%E8%84%9A%E6%9C%ACdemo/","summary":"\u003ch1 class=\"wp-block-heading\" id=\"binbash\"\u003e!/bin/bash\u003c/h1\u003e\n\u003ch1 class=\"wp-block-heading\" id=\"author-zhangdongling\"\u003eAuthor: zhangdongling\u003c/h1\u003e\n\u003ch1 class=\"wp-block-heading\" id=\"copyrightc\"\u003eCopyright(C)\u003c/h1\u003e\n\u003ch1 class=\"wp-block-heading\" id=\"script-follows-here\"\u003eScript follows here:\u003c/h1\u003e\n\u003cp\u003eecho “What is your name?”\u003cbr\u003e\nread PERSON\u003cbr\u003e\necho “Hello ,$PERSON”\u003c/p\u003e\n\u003chr class=\"wp-block-separator\" /\u003e\n\u003cp\u003evariableName=”zhangdl”\u003cbr\u003e\nname=dong\u003cbr\u003e\necho “variableName,$variableName”\u003cbr\u003e\necho “name,$name”\u003c/p\u003e\n\u003chr class=\"wp-block-separator\" /\u003e\n\u003cp\u003eecho “1.”$0 #当前脚本的文件名\u003cbr\u003e\necho “2.”$1 #传递给脚本或函数的参数\u003cbr\u003e\necho “3.”$# #传递给脚本或函数的参数个数。\u003cbr\u003e\necho “4.”$* #传递给脚本或函数的所有参数。\u003cbr\u003e\necho “5.”\u003cspan class=\"katex math inline\"\u003e@ #传递给脚本或函数的所有参数。被双引号(” “)包含时，与\u003c/span\u003e* 稍有不同，下面将会讲到。\u003cbr\u003e\necho “6.”$? #上个命令的退出状态，或函数的返回值。大部分命令执行成功会返回0，失败返回1\u003c/p\u003e\n\u003cp\u003eecho “8.\u0026amp;#8221;$@\u0026amp;#8221;”\u003cbr\u003e\necho “9.\u0026amp;#8221;$*\u0026amp;#8221;”\u003cbr\u003e\necho -e “pid is $$ \\n”\u003cbr\u003e\necho “pid is $$ \\n”\u003c/p\u003e\n\u003chr class=\"wp-block-separator\" /\u003e\n\u003cp\u003eDATE=\u003ccode\u003edate\u003c/code\u003e\u003cbr\u003e\necho -e “DATE is $DATE \\n”\u003cbr\u003e\nUSERS=\u003ccode\u003ewho | wc -l\u003c/code\u003e\u003cbr\u003e\necho -e “Logged in user are $USERS \\n”\u003cbr\u003e\nUP=\u003ccode\u003edate;uptime\u003c/code\u003e\u003cbr\u003e\necho -e “Uptime is $UP \\n”\u003c/p\u003e","title":"shell 脚本Demo"},{"content":"## Spring boot 读取properties\n在开发中我们需要通过属性文件配置常用属性，例如数据库相关、日志相关、测试相关等。\n自定义properties文件获取属性 application.properties获取属性 ### 自定义properties文件获取属性\n使用@configurationProperties((prefix=”xxx.yyy”)) 和 @PropertySource(“classpath:xxxconfig.properties”)\nxxx.yyy表示的是属性文件中的前缀（有时候我们希望可以分的更清楚）\n使用自定义的时候需要给类添加@Component 让Spring管理类的生命周期\n在使用的地方使用@Autowired 让系统进行初始化\n// PropertySource默认取application.properties // @PropertySource(value = “xxxconfig.properties”) 例如\n“`\n@Component\n@ConfigurationProperties(prefix = “com.xxx”)\n@PropertySource(“classpath:myconfig.properties”)\npublic class TestBean {\nprivate String host;\npublic String getHost() {\nreturn host;\n}\npublic void setHost(String host) {\nthis.host = host;\n}\n}\n//使用地方\n@Autowired\nprivate TestBean testBean\n“`\n### application.properties获取属性\n共有三种\n参考上面自定义 只是不用设置PropertySource PropertySource默认取application.properties 使用@Value注解 使用Environment #### 使用@Value\n“`\nimport java.io.UnsupportedEncodingException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n@SpringBootApplication\n@RestController\npublic class Applaction {\n@Value(“{com.zyd.type}”) private String type; @Value(“{com.zyd.title}”) private String title;\n/** * * 第二种方式：使用`@Value(“${propertyName}”)`注解 *\n* @throws UnsupportedEncodingException * @since JDK 1.7 */\n@RequestMapping(“/value”) public Map\u0026lt;String, Object\u0026gt; value() throws UnsupportedEncodingException {\nMap\u0026lt;String, Object\u0026gt; map = new HashMap\u0026lt;String, Object\u0026gt;();\nmap.put(“type”, type);\n// *.properties文件中的中文默认以ISO-8859-1方式编码，因此需要对中文内容进行重新编码\nmap.put(“title”, new String(title.getBytes(“ISO-8859-1”), “UTF-8”));\nreturn map;\n}\npublic static void main(String[] args) throws Exception {\nSpringApplication application = new SpringApplication(Applaction.class);\napplication.run(args);\n}\n}\n“`\n#### 使用Environment\n“`\n方式一 通过Context获取Environment\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.Logger;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.scheduling.annotation.EnableScheduling;\n@SpringBootApplication\n@EnableScheduling\npublic class Application {\nstatic Logger logger = LogManager.getLogger(WljcbaseApplication.class);\npublic static void main(String[] args) {\nConfigurableApplicationContext context = SpringApplication.run(WljcbaseApplication.class, args);\nlogger.info(“启动成功！”);\nlogger.trace(“这是trace日志…”);\nlogger.debug(“这是debug日志…”);\n// Springboot默认给我们使用的是info级别的，没有指定级别的就用SpringBoot默认规定的级别，root级别\nlogger.info(“这是info日志…”);\nlogger.warn(“这是warn日志…”);\nlogger.error(“这是error日志…”);\nString host = context.getEnvironment().getProperty(“host”);\nlogger.error(“host is ” + host);\n}\n}\n方式二 通过注解获取Environment\n@SpringBootApplication\n@RestController\npublic class Applaction {\n@Autowired private Environment env;\n@RequestMapping(“/env”) public Map\u0026lt;String, Object\u0026gt; env() throws UnsupportedEncodingException {\nMap\u0026lt;String, Object\u0026gt; map = new HashMap\u0026lt;String, Object\u0026gt;();\nmap.put(“type”, env.getProperty(“com.zyd.type2”));\nmap.put(“title”, new String(env.getProperty(“com.zyd.title2”).getBytes(“ISO-8859-1”), “UTF-8”));\nreturn map;\n}\npublic static void main(String[] args) throws Exception {\nSpringApplication application = new SpringApplication(Applaction.class);\napplication.run(args);\n}\n}\n“`\n","permalink":"https://blog.zdltech.com/posts/spring-boot-du-quproperties/","summary":"\u003cp\u003e## Spring boot 读取properties\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e在开发中我们需要通过属性文件配置常用属性，例如数据库相关、日志相关、测试相关等。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e自定义properties文件获取属性\u003c/li\u003e\n\u003cli\u003eapplication.properties获取属性\u003c/li\u003e\n\u003c/ol\u003e\u003c/blockquote\u003e\n\u003cp\u003e### 自定义properties文件获取属性\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e使用@configurationProperties((prefix=”xxx.yyy”)) 和 @PropertySource(“classpath:xxxconfig.properties”)\u003c/p\u003e\n\u003cp\u003exxx.yyy表示的是属性文件中的前缀（有时候我们希望可以分的更清楚）\u003c/p\u003e\n\u003cp\u003e使用自定义的时候需要给类添加@Component 让Spring管理类的生命周期\u003c/p\u003e\n\u003cp\u003e在使用的地方使用@Autowired 让系统进行初始化\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e// PropertySource默认取application.properties\u003c/li\u003e\n\u003cli\u003e// @PropertySource(value = “xxxconfig.properties”)\u003c/li\u003e\n\u003c/ol\u003e\u003c/blockquote\u003e\n\u003cp\u003e例如\u003c/p\u003e\n\u003cp\u003e“`\u003cbr\u003e\n@Component\u003cbr\u003e\n@ConfigurationProperties(prefix = “com.xxx”)\u003cbr\u003e\n@PropertySource(“classpath:myconfig.properties”)\u003cbr\u003e\npublic class TestBean {\u003cbr\u003e\nprivate String host;\u003c/p\u003e\n\u003cp\u003epublic String getHost() {\u003cbr\u003e\nreturn host;\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003epublic void setHost(String host) {\u003cbr\u003e\nthis.host = host;\u003cbr\u003e\n}\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e//使用地方\u003c/p\u003e\n\u003cp\u003e@Autowired\u003cbr\u003e\nprivate TestBean testBean\u003cbr\u003e\n“`\u003c/p\u003e\n\u003cp\u003e### application.properties获取属性\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e共有三种\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e参考上面自定义 只是不用设置PropertySource PropertySource默认取application.properties\u003c/li\u003e\n\u003cli\u003e使用@Value注解\u003c/li\u003e\n\u003cli\u003e使用Environment\u003c/li\u003e\n\u003c/ol\u003e\u003c/blockquote\u003e\n\u003cp\u003e#### 使用@Value\u003c/p\u003e","title":"Spring boot 读取properties"},{"content":" 有时候我们需要在系统自动启动的时候，把我们希望的服务也启动了，不需要我一个一个手动打开。 服务创建 使用 sc create 服务名称 binPath= \u0026amp;#8220;执行文件路径\u0026amp;#8221; start= auto displayName= \u0026amp;#8220;服务描述\u0026amp;#8221; 在window服务中 可以看到 在win+r 之后运行services.msc 查下服务，可以通过这里启动服务（对于部分没有办法做成服务的，我们可以做成批处理文件） 批处理脚本 通过创建批处理脚本，来运行我们的服务，先通过dos命令运行下写的脚本文件，看是否可以正常运行，如果可以正常运行，把脚本放到 C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\StartUp 中 通过组策略\nWindows+R运行，输入gpedit.msc进入组策略编辑器，选中windows设置-启动，然后点击添加脚本即可，这里也可以选择用户配置中的window配置下的脚本配置\n重启下试试吧！！！ ","permalink":"https://blog.zdltech.com/posts/window-%E5%88%9B%E5%BB%BA%E8%87%AA%E5%8A%A8%E5%90%AF%E5%8A%A8/","summary":"\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e有时候我们需要在系统自动启动的时候，把我们希望的服务也启动了，不需要我一个一个手动打开。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e服务创建\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e使用 sc create 服务名称 binPath= \u0026amp;#8220;执行文件路径\u0026amp;#8221; start= auto displayName= \u0026amp;#8220;服务描述\u0026amp;#8221; 在window服务中 可以看到 在win+r 之后运行services.msc 查下服务，可以通过这里启动服务（对于部分没有办法做成服务的，我们可以做成批处理文件）\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e批处理脚本\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e通过创建批处理脚本，来运行我们的服务，先通过dos命令运行下写的脚本文件，看是否可以正常运行，如果可以正常运行，把脚本放到 C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\StartUp 中\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e通过组策略\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cblockquote\u003e\n\u003cp\u003eWindows+R运行，输入gpedit.msc进入组策略编辑器，选中windows设置-启动，然后点击添加脚本即可，这里也可以选择用户配置中的window配置下的脚本配置\u003c/p\u003e\u003c/blockquote\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e重启下试试吧！！！\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e","title":"window 创建自动启动"},{"content":" 在Controller中添加 @Transactional 自己捕获异常之后事务不能回滚 原因： 默认spring事务只在发生未被捕获的 RuntimeException 时才回滚 spring aop 异常捕获原理：被拦截的方法需显式抛出异常，并不能经任何处理，这样aop代理才能捕获到方法的异常，才能进行回滚，默认情况下aop只捕获 RuntimeException 的异常，但可以通过配置来捕获特定的异常并回滚 换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion（），这样程序异常时才能被aop捕获进而回滚\n解决方案 例如service层处理事务，那么service中的方法中不做异常捕获，或者在catch语句中最后增加throw new RuntimeException()语句，以便让aop捕获异常再去回滚，并且在service上层（webservice客户端，view层action）要继续捕获这个异常并处理\n在controller层方法的catch语句中增加：TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句，手动回滚，这样上层就无需去处理异常\n例如 try{ *//出现异常* } catch (Exception e){ e.printStackTrace(); //设置手动回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); }\n","permalink":"https://blog.zdltech.com/posts/spring-boot-%E4%BA%8B%E5%8A%A1%E5%9B%9E%E6%BB%9A/","summary":"\u003ch3 class=\"wp-block-heading\"\u003e\u003c/h3\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e在Controller中添加 @Transactional 自己捕获异常之后事务不能回滚\n\n\n\n\n\n原因：\n\n\n\n\n\n默认spring事务只在发生未被捕获的 RuntimeException 时才回滚\n\n\n\n\n\nspring aop 异常捕获原理：被拦截的方法需显式抛出异常，并不能经任何处理，这样aop代理才能捕获到方法的异常，才能进行回滚，默认情况下aop只捕获 RuntimeException 的异常，但可以通过配置来捕获特定的异常并回滚 \n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion（），这样程序异常时才能被aop捕获进而回滚\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch4 class=\"wp-block-heading\" id=\"解决方案\"\u003e解决方案\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e例如service层处理事务，那么service中的方法中不做异常捕获，或者在catch语句中最后增加throw new RuntimeException()语句，以便让aop捕获异常再去回滚，并且在service上层（webservice客户端，view层action）要继续捕获这个异常并处理\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在controller层方法的catch语句中增加：TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句，手动回滚，这样上层就无需去处理异常\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 class=\"wp-block-heading\" id=\"例如\"\u003e例如\u003c/h4\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003etry{ *//出现异常* \n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e} catch (Exception e){\ne.printStackTrace(); \u003cem\u003e//设置手动回滚\u003c/em\u003e\nTransactionAspectSupport.currentTransactionStatus().setRollbackOnly();\n}\u003c/p\u003e\n\u003c/blockquote\u003e","title":"Spring boot 事务回滚"},{"content":"过滤器Filter **\n过滤器是基于Servlet的拦截，是在Web容器进行拦截。常用的场景有登录、权限判断、tonken过滤等。当然使用拦截器也可以，拦截器是基于Spring的拦截，可以作用于Controller等的方法中。如果是Web的话，没有特别要求，还是使用过滤器吧(本人观点) 编写过滤器 新建过滤器 需要实现javax.servlet.Filter接口，并重新其中的方法 public class LoginFilter implements Filter {\n` @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { } @Override public void destroy() { } }` HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; 可以转换为我们平时使用的HttpServletRequest 和 HttpServletResponse 如果不需要过滤 直接调用 filterChain.doFilter(servletRequest, servletResponse); 如果需要过滤 根据自己的业务处理 例如：判断token、ip等，直接通过HttpServletResponse 返回异常处理 重定向跳转 response.sendRedirect(request.getContextPath()+\u0026amp;#8221;/*.html\u0026amp;#8221;); 界面返回response.getWriter().write(this.NO_LOGIN); String requestType = request.getHeader(\u0026amp;#8220;X-Requested-With\u0026amp;#8221;); //判断是否是ajax请求 if(requestType!=null \u0026amp;\u0026amp; \u0026amp;#8220;XMLHttpRequest\u0026amp;#8221;.equals(requestType)) 过滤器配置 配置方式有2中，一种是通过注解，一种是通过过滤器配置 一、注解方式配置 在过滤器上添加WebFilter注解\n启动类上添加ServletComponentScan注解\nfilterName 为过滤器的名称，urlPatterns表示过滤的url的规则 @WebFilter(filterName = \u0026amp;#8220;loginFilter\u0026amp;#8221;,urlPatterns = {\u0026amp;#8220;/*\u0026amp;#8221;}) public class LoginFilter implements Filter {….} @SpringBootApplication @ServletComponentScan public class FileUploadApplication {…}\n二、通过过滤器注册配置类使用过滤器 @Configuration public class WebComponent2Config { @Bean public FilterRegistrationBean someFilterRegistration1() { //新建过滤器注册类 FilterRegistrationBean registration = new FilterRegistrationBean(); // 添加我们写好的过滤器 registration.setFilter( new LoginFilter()); // 设置过滤器的URL模式 registration.addUrlPatterns(“/*”); return registration; }\n} 扩展 当有多个过滤器需要按顺序执行时怎么办? 使用注解的配置方法不能配置顺序,但是可以通过过滤器名字的字典顺序实现顺序过滤（比如AFilter就会在BFilter前执行），显然这种方法看起来不怎么正经。 但是我们可以使用第二种配置方法.\n通过给注册类设置order,order越小,执行优先级越高 @Bean public FilterRegistrationBean someFilterRegistration1() { //新建过滤器注册类 FilterRegistrationBean registration = new FilterRegistrationBean(); // 添加我们写好的过滤器 registration.setFilter( new LoginFilter()); // 设置过滤器的URL模式 registration.addUrlPatterns(“/*”); //设置过滤器顺序 registration.setOrder(1);** return registration;\n} ","permalink":"https://blog.zdltech.com/posts/spring-boot%E8%BF%87%E6%BB%A4%E5%99%A8-filter%E4%BD%BF%E7%94%A8/","summary":"\u003ch3 class=\"wp-block-heading\" id=\"过滤器filter\"\u003e过滤器Filter\u003c/h3\u003e\n\u003cp\u003e**\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e过滤器是基于Servlet的拦截，是在Web容器进行拦截。常用的场景有登录、权限判断、tonken过滤等。当然使用拦截器也可以，拦截器是基于Spring的拦截，可以作用于Controller等的方法中。如果是Web的话，没有特别要求，还是使用过滤器吧(本人观点)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"编写过滤器\"\u003e编写过滤器\u003c/h3\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e新建过滤器 需要实现javax.servlet.Filter接口，并重新其中的方法\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003ccode\u003epublic class LoginFilter implements Filter {\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`  @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  public void init(FilterConfig filterConfig) throws ServletException {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  public void destroy() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003eHttpServletRequest request = (HttpServletRequest) servletRequest;\n\n\n\n\n\nHttpServletResponse response = (HttpServletResponse) servletResponse;\n\n\n\n\n\n可以转换为我们平时使用的HttpServletRequest 和 HttpServletResponse\n\n\n\n\n\n如果不需要过滤 直接调用\n\n\n\n\n\nfilterChain.doFilter(servletRequest, servletResponse);\n\n\n\n\n\n如果需要过滤 根据自己的业务处理\n\n\n\n\n\n例如：判断token、ip等，直接通过HttpServletResponse 返回异常处理\n\n\n\n\n\n重定向跳转 response.sendRedirect(request.getContextPath()+\u0026amp;#8221;/*.html\u0026amp;#8221;);\n\n\n\n\n\n界面返回response.getWriter().write(this.NO_LOGIN);\n\n\n\n\n\nString requestType = request.getHeader(\u0026amp;#8220;X-Requested-With\u0026amp;#8221;);\n\n\n\n\n\n//判断是否是ajax请求\n\n\n\n\n\nif(requestType!=null \u0026amp;\u0026amp; \u0026amp;#8220;XMLHttpRequest\u0026amp;#8221;.equals(requestType))\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"过滤器配置\"\u003e过滤器配置\u003c/h3\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e配置方式有2中，一种是通过注解，一种是通过过滤器配置\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch4 class=\"wp-block-heading\" id=\"一注解方式配置\"\u003e一、注解方式配置\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e在过滤器上添加WebFilter注解\u003c/p\u003e","title":"Spring boot过滤器 Filter使用"},{"content":" == 普通的英文半角空格\n== == == no-break space （普通的英文半角空格但不换行）\n== 中文全角空格 （一个中文宽度）\n== == en空格 （半个中文宽度）\n== == em空格 （一个中文宽度）\n== 四分之一em空格 （四分之一中文宽度）\n相比平时的空格（ ），\u0026amp;nbsp拥有不间断（non-breaking）特性。即连续的\u0026amp;nbsp会在同一行内显示。即使有100个连续的\u0026amp;nbsp，浏览器也不会把它们拆成两行。\n参考：https://blog.csdn.net/sforiz/article/details/43937237\n","permalink":"https://blog.zdltech.com/posts/html%E7%A9%BA%E6%A0%BC%E5%8D%A0%E4%BD%8D%E7%AC%A6/","summary":"\u003cp\u003e  == 普通的英文半角空格\u003c/p\u003e\n\u003cp\u003e  ==   ==   == no-break space （普通的英文半角空格但不换行）\u003c/p\u003e\n\u003cp\u003e　 == 中文全角空格 （一个中文宽度）\u003c/p\u003e\n\u003cp\u003e  ==   == en空格 （半个中文宽度）\u003c/p\u003e\n\u003cp\u003e  ==   == em空格 （一个中文宽度）\u003c/p\u003e\n\u003cp\u003e  == 四分之一em空格 （四分之一中文宽度）\u003c/p\u003e\n\u003cp\u003e相比平时的空格（ ），\u0026amp;nbsp拥有不间断（non-breaking）特性。即连续的\u0026amp;nbsp会在同一行内显示。即使有100个连续的\u0026amp;nbsp，浏览器也不会把它们拆成两行。\u003c/p\u003e\n\u003cp\u003e参考：\u003ca href=\"https://blog.csdn.net/sforiz/article/details/43937237\"\u003ehttps://blog.csdn.net/sforiz/article/details/43937237\u003c/a\u003e\u003c/p\u003e","title":"HTML空格占位符"},{"content":"![请输入图片描述][1]### 拦截器与过滤器的区别\n过滤器和拦截器触发时机不一样，过滤器是在请求进入容器后，但请求进入servlet之前进行预处理的。请求结束返回也是，是在servlet处理完后，返回给前端之前。\n拦截器可以获取IOC容器中的各个bean，而过滤器就不行，因为拦截器是spring提供并管理的，spring的功能可以被拦截器使用，在拦截器里注入一个service，可以调用业务逻辑。而过滤器是JavaEE标准，只需依赖servlet api ，不需要依赖spring。\nSpringMVC的机制是由DispaterServlet来分发请求给不同的Controller，其实这一步是在Servlet的service()方法中执行的.\n过滤器的实现基于回调函数。而拦截器（代理模式）的实现基于反射，代理分静态代理和动态代理，动态代理是拦截器的简单实现。\n**\n过滤器就是过滤的作用，在web开发中过滤一些我们指定的url 那么它能帮我们过滤什么呢？ 那功能可就多了： 比如过拦截掉我们不需要的接口请求 修改请求（request）和响应（response）内容 完成CORS跨域请求等等\n最简单明了的区别就是 \u0026lt;strong\u0026gt;过滤器可以修改request，而拦截器不能过滤器需要在servlet容器中实现，拦截器可以适用于javaEE，javaSE等各种环境拦截器可以调用IOC容器中的各种依赖，而过滤器不能过滤器只能在请求的前后使用，而拦截器可以详细到每个方法** 过滤器就是筛选出你要的东西，比如requeset中你要的那部分 拦截器在做安全方面用的比较多，比如终止一些流程\n何时使用拦截器？何时使用过滤器？ 如果是非spring项目，那么拦截器不能用，只能使用过滤器。\n如果是处理controller前后，既可以使用拦截器也可以使用过滤器。\n如果是处理dispaterServlet前后，只能使用过滤器。\n过滤器：它依赖于servlet容器。在实现上，基于函数回调，它可以对几乎所有请求进行过滤，但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的，是用来做一些过滤操作，获取我们想要获取的数据，比如：在Javaweb中，对传入的request、response提前过滤掉一些信息，或者提前设置一些参数，然后再传入servlet或者Controller进行业务逻辑操作。通常用的场景是：在过滤器中修改字符编码（CharacterEncodingFilter）、在过滤器中修改HttpServletRequest的一些参数（XSSFilter(自定义过滤器)），如：过滤低俗文字、危险字符等 拦截器：它依赖于web框架，在SpringMVC中就是依赖于SpringMVC框架。在实现上,基于Java的反射机制，属于面向切面编程（AOP）的一种运用，就是在service或者一个方法前，调用一个方法，或者在方法后，调用一个方法，比如动态代理就是拦截器的简单实现，在调用方法前打印出字符串（或者做其它业务逻辑的操作），也可以在调用方法后打印出字符串，甚至在抛出异常的时候做业务逻辑的操作。由于拦截器是基于web框架的调用，因此可以使用Spring的依赖注入（DI）进行一些业务操作，同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是直接访问静态资源的请求则没办法进行拦截处理。 两者的本质区别：拦截器（Interceptor）是基于Java的反射机制，而过滤器（Filter）是基于函数回调。从灵活性上说拦截器功能更强大些，Filter能做的事情，都能做，而且可以在请求前，请求后执行，比较灵活。Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验（比较泛的，比如登录不登录之类），太细的话，还是建议用interceptor。不过还是根据不同情况选择合适的。 Spring boot使用过滤器 使用spring boot提供的FilterRegistrationBean注册Filter\n使用原生servlet注解定义Filter 两种方式的本质都是一样的，都是去FilterRegistrationBean注册自定义Filter\n方式一 先定义Filter ` import javax.servlet.*; import java.io.IOException; public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // do something 处理request 或response System.out.println(\u0026#34;filter1\u0026#34;); // 调用filter链中的下一个filter filterChain.doFilter(servletRequest,servletResponse); //如果过滤通过，执行filterChain.doFilter(servletRequest,servletResponse); 不通过就执行直接返回 } @Override public void destroy() { } }` 注册自定义Filter `@Configuration public class FilterConfig { @Bean public FilterRegistrationBean registrationBean() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter()); filterRegistrationBean.addUrlPatterns(\u0026#34;/*\u0026#34;); return filterRegistrationBean; } }` 方式二 `@Component // 定义filterName 和过滤的url @WebFilter(filterName = \u0026#34;my2Filter\u0026#34; ,urlPatterns = \u0026#34;/*\u0026#34;) public class My2Filter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println(\u0026#34;filter2\u0026#34;); filterChain.doFilter(servletRequest,servletResponse); //如果过滤通过，执行filterChain.doFilter(servletRequest,servletResponse); 不通过就执行直接返回 } @Override public void destroy() { } }` Spring boot 拦截器的使用 定义拦截器： `public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println(\u0026#34;preHandle\u0026#34;); return true;////如果false，停止流程，api被拦截 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { System.out.println(\u0026#34;postHandle\u0026#34;); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { System.out.println(\u0026#34;afterCompletion\u0026#34;); } }` 配置拦截器： `@Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()); } }` Controller演示： `@RestController public class UController { @GetMapping(\u0026#34;/home\u0026#34;) public String home(){ System.out.println(\u0026#34;home\u0026#34;); return \u0026#34;myhome\u0026#34;; } } 输出： preHandle home postHandle afterCompletion` ","permalink":"https://blog.zdltech.com/posts/spring-boot-%E8%BF%87%E6%BB%A4%E5%99%A8%E5%92%8C%E6%8B%A6%E6%88%AA%E5%99%A8%E6%80%BB%E7%BB%93/","summary":"\u003cp\u003e![请输入图片描述][1]### 拦截器与过滤器的区别\u003cfigure class=\"wp-block-image\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://www.zdltech.com/usr/uploads/2019/05/2120521969.png\"\u003e \u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e过滤器和拦截器触发时机不一样，过滤器是在请求进入容器后，但请求进入servlet之前进行预处理的。请求结束返回也是，是在servlet处理完后，返回给前端之前。\u003cfigure class=\"wp-block-image\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://www.zdltech.com/usr/uploads/2019/05/3498349191.png\"\u003e \u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e拦截器可以获取IOC容器中的各个bean，而过滤器就不行，因为拦截器是spring提供并管理的，spring的功能可以被拦截器使用，在拦截器里注入一个service，可以调用业务逻辑。而过滤器是JavaEE标准，只需依赖servlet api ，不需要依赖spring。\u003cfigure class=\"wp-block-image\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://www.zdltech.com/usr/uploads/2019/05/3913346238.png\"\u003e \u003c/figure\u003e \u003cfigure class=\"wp-block-image\"\u003e\u003cimg loading=\"lazy\" src=\"https://www.zdltech.com/usr/uploads/2019/05/24649700.png\"\u003e\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003eSpringMVC的机制是由DispaterServlet来分发请求给不同的Controller，其实这一步是在Servlet的service()方法中执行的.\u003c/p\u003e\n\u003cp\u003e过滤器的实现基于回调函数。而拦截器（代理模式）的实现基于反射，代理分静态代理和动态代理，动态代理是拦截器的简单实现。\u003c/p\u003e\n\u003cp\u003e**\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e过滤器就是过滤的作用，在web开发中过滤一些我们指定的url\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e那么它能帮我们过滤什么呢？\n那功能可就多了：\n比如过拦截掉我们不需要的接口请求\n修改请求（request）和响应（response）内容\n完成CORS跨域请求等等\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e最简单明了的区别就是 \u0026lt;strong\u0026gt;过滤器可以修改request，而拦截器不能过滤器需要在servlet容器中实现，拦截器可以适用于javaEE，javaSE等各种环境拦截器可以调用IOC容器中的各种依赖，而过滤器不能过滤器只能在请求的前后使用，而拦截器可以详细到每个方法**\n\n\n\n\n\n过滤器就是筛选出你要的东西，比如requeset中你要的那部分\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e拦截器在做安全方面用的比较多，比如终止一些流程\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch4 class=\"wp-block-heading\" id=\"何时使用拦截器何时使用过滤器\"\u003e何时使用拦截器？何时使用过滤器？\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e如果是非spring项目，那么拦截器不能用，只能使用过滤器。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果是处理controller前后，既可以使用拦截器也可以使用过滤器。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果是处理dispaterServlet前后，只能使用过滤器。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"\u003e\n\u003cpre\u003e\u003ccode\u003e过滤器：它依赖于servlet容器。在实现上，基于函数回调，它可以对几乎所有请求进行过滤，但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的，是用来做一些过滤操作，获取我们想要获取的数据，比如：在Javaweb中，对传入的request、response提前过滤掉一些信息，或者提前设置一些参数，然后再传入servlet或者Controller进行业务逻辑操作。通常用的场景是：在过滤器中修改字符编码（CharacterEncodingFilter）、在过滤器中修改HttpServletRequest的一些参数（XSSFilter(自定义过滤器)），如：过滤低俗文字、危险字符等\n\n\n\n\n\n拦截器：它依赖于web框架，在SpringMVC中就是依赖于SpringMVC框架。在实现上,基于Java的反射机制，属于面向切面编程（AOP）的一种运用，就是在service或者一个方法前，调用一个方法，或者在方法后，调用一个方法，比如动态代理就是拦截器的简单实现，在调用方法前打印出字符串（或者做其它业务逻辑的操作），也可以在调用方法后打印出字符串，甚至在抛出异常的时候做业务逻辑的操作。由于拦截器是基于web框架的调用，因此可以使用Spring的依赖注入（DI）进行一些业务操作，同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是直接访问静态资源的请求则没办法进行拦截处理。\n\n\n\n\n\n两者的本质区别：拦截器（Interceptor）是基于Java的反射机制，而过滤器（Filter）是基于函数回调。从灵活性上说拦截器功能更强大些，Filter能做的事情，都能做，而且可以在请求前，请求后执行，比较灵活。Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验（比较泛的，比如登录不登录之类），太细的话，还是建议用interceptor。不过还是根据不同情况选择合适的。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003ch3 class=\"wp-block-heading\" id=\"spring-boot使用过滤器\"\u003eSpring boot使用过滤器\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e使用spring boot提供的FilterRegistrationBean注册Filter\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e使用原生servlet注解定义Filter 两种方式的本质都是一样的，都是去FilterRegistrationBean注册自定义Filter\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 class=\"wp-block-heading\" id=\"方式一\"\u003e方式一\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e先定义Filter\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`    import javax.servlet.*;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    import java.io.IOException;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public class MyFilter implements Filter {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        public void init(FilterConfig filterConfig) throws ServletException {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            // do something 处理request 或response\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            System.out.println(\u0026#34;filter1\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            // 调用filter链中的下一个filter\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            filterChain.doFilter(servletRequest,servletResponse);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            //如果过滤通过，执行filterChain.doFilter(servletRequest,servletResponse); 不通过就执行直接返回\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        public void destroy() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e注册自定义Filter\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`@Configuration\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e public class FilterConfig {   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  @Bean\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     public FilterRegistrationBean registrationBean() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         filterRegistrationBean.addUrlPatterns(\u0026#34;/*\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         return filterRegistrationBean;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 class=\"wp-block-heading\" id=\"方式二\"\u003e方式二\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`@Component\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e// 定义filterName 和过滤的url\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@WebFilter(filterName = \u0026#34;my2Filter\u0026#34; ,urlPatterns = \u0026#34;/*\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic class My2Filter implements Filter {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public void init(FilterConfig filterConfig) throws ServletException {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System.out.println(\u0026#34;filter2\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        filterChain.doFilter(servletRequest,servletResponse);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        //如果过滤通过，执行filterChain.doFilter(servletRequest,servletResponse); 不通过就执行直接返回\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public void destroy() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 class=\"wp-block-heading\" id=\"spring-boot-拦截器的使用\"\u003eSpring boot 拦截器的使用\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e定义拦截器：\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`public class MyInterceptor implements HandlerInterceptor {     \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         System.out.println(\u0026#34;preHandle\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         return true;////如果false，停止流程，api被拦截\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         System.out.println(\u0026#34;postHandle\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         System.out.println(\u0026#34;afterCompletion\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e配置拦截器：\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`@Configuration\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e public class InterceptorConfig implements WebMvcConfigurer {       @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       public void addInterceptors(InterceptorRegistry registry) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           registry.addInterceptor(new MyInterceptor());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003eController演示：\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`@RestController\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e public class UController {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       @GetMapping(\u0026#34;/home\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       public String home(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           System.out.println(\u0026#34;home\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           return \u0026#34;myhome\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   输出： \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   preHandle \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   home \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   postHandle \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   afterCompletion`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"Spring Boot 过滤器和拦截器总结"},{"content":"测试的3个网址分别为：\nString uri1 = “https://mportal.tianjihuifu.com/tjhf/loginRegist/login?uname=13265468238\u0026amp;pwd=123456”;\nString uri2 = “https://mportal.tjhf.com/tjhf/loginRegist/login?uname=13265468238\u0026amp;pwd=123456”;\nString uri = “https://www.baidu.com/”;\n中间用到的证书为cer_test.crt，证书信息为：CN=console.haitest.com, C=CN。分别测试了加载证书与不加载证书请求3个不同的网址的日志。\n证书为cer_test.crt，没有HostnameVerifier\nE/==####DROXY####===: (**)发送请求(get):https://mportal.haitest.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\nE/==####DROXY####===: (**)响应结果:{“data”:72771,”result”:true,”resultCode”:2000}\nE/==####DROXY####===: (**)发送请求(get):https://mportal.hai.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\nW/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.\nE/==####DROXY####===: (**)发送请求(get):https://www.baidu.com/\nW/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.\n证书为cer_test.crt，HostnameVerifier ：return true\nE/==####DROXY####===: (**)发送请求(get):https://mportal.haitest.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\nE/==####DROXY####===: (**)响应结果:{“data”:72771,”result”:true,”resultCode”:2000}\nE/==####DROXY####===: (**)发送请求(get):https://mportal.hai.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\nW/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.\nE/==####DROXY####===: (**)发送请求(get):https://www.baidu.com/\nW/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.\n证书为cer_test.crt，HostnameVerifier ：return hostname.equals(session.getPeerHost())\nE/==####DROXY####===: (**)发送请求(get):https://mportal.haitest.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\nE/==####DROXY####===: (**)响应结果:{“data”:72771,”result”:true,”resultCode”:2000}\nE/==####DROXY####===: (**)发送请求(get):https://mportal.hai.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\nW/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.\nE/==####DROXY####===: (**)发送请求(get):https://www.baidu.com/\nW/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.\n证书为null，没有HostnameVerifier\nE/==####DROXY####===: (**)发送请求(get):https://mportal.haitest.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\nE/==####DROXY####===: (**)发送请求(get):https://mportal.hai.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\nE/==####DROXY####===: (**)响应结果:{“data”:72771,”result”:true,”resultCode”:2000}\nE/==####DROXY####===: (**)发送请求(get):https://www.baidu.com/\nE/==####DROXY####===: (*_*)响应结果:\n测试结果总结得出：HttpURLConnection连接网络\n无加载证书，可以请求任何https网址，\n加载证书,且信任证书密钥，则只能请求和证书网址一致的网址，不管HostnameVerifier返回的是true or false\n加载证书,且信任所有证书，则可以请求任何https网址，\n只要是https网址，不管有没有使用sslSocketFactory，传输的都是加密密文\n下面给出网络请求的主要部分代码\n/**\nCreated by 黄海 on 2016/10/8.\n*/\npublic class HttpUtils {\nprivate static final String BOUNDARY = “——WebKitFormBoundaryXt9bHBmce2A1Qt0j”;\nprivate static final int CONNECTION_TIMEOUT = 7 * 1000;\nprivate static final int SOCKET_TIMEOUT = 7 * 1000;\nprivate static SSLSocketFactory sslSocketFactory;\nprivate static CookieManager cookieManager;\nprivate static final String COOKIES_HEADER = “Set-Cookie”;\nprivate static Map\u0026lt;String, String\u0026gt; requestHeader = new HashMap\u0026lt;\u0026gt;(); public static void init(Context context) {\ncookieManager = new CookieManager();\nCookieHandler.setDefault(cookieManager);//如果这里设置了，就不需要手动管理cookie了\nKeyStore keyStore = null;\nInputStream is = null;\nCertificateFactory cf = null;\ntry {\ncf = CertificateFactory.getInstance(“X.509”);\nis = context.getResources().getAssets().open(“cer_test.crt”);\nCertificate ca = cf.generateCertificate(is);\nLogger.e(“ca=” + ((X509Certificate) ca).getSubjectDN());\n// Create a KeyStore containing our trusted CAs\nkeyStore = KeyStore.getInstance(KeyStore.getDefaultType());\nkeyStore.load(null, null);\nkeyStore.setCertificateEntry(“ca”, ca);\n// Create a TrustManager that trusts the CAs in our KeyStore\nString defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm();\nTrustManagerFactory tmf = TrustManagerFactory.getInstance(defaultAlgorithm);\ntmf.init(keyStore);\n// Create an SSLContext that uses our TrustManager\nSSLContext sslContext = SSLContext.getInstance(“TLS”);\nsslContext.init(null, tmf.getTrustManagers(), null);//信任证书密钥\n// sslContext.init(null, new TrustManager[]{new UnSafeTrustManager()}, null);//信任所有\nsslSocketFactory = sslContext.getSocketFactory();\n} catch (Exception e) {\ne.printStackTrace();\n}\n}\npublic static String get(String uri) {\ntry {\nbyte[] bytes = performRequest(new URL(uri), null, null, Method.GET);\nif (bytes != null \u0026amp;\u0026amp; bytes.length \u0026gt; 0) {\nString result = new String(bytes);\nLogger.e(“响应结果:” + result);\nreturn result;\n} else {\nLogger.e(“请求出错:请检查好网络设置”);\n}\n} catch (Exception e) {\ne.printStackTrace();\n}\nreturn null;\n}\npublic static String post(String url, Map\u0026lt;String, File\u0026gt; files) {\ntry {\nbyte[] bytes = performRequest(new URL(url), null, files, Method.POST);\nif (bytes != null \u0026amp;\u0026amp; bytes.length \u0026gt; 0) {\nString result = new String(bytes);\nLogger.e(“响应结果:” + result);\nreturn result;\n} else {\nLogger.e(“请求出错:请检查好网络设置”);\n}\n} catch (Exception e) {\nLogger.e(“请求出错:请检查好网络设置”);\ne.printStackTrace();\n}\nreturn null;\n}\nprivate static byte[] performRequest(URL url, byte[] params, Map\u0026lt;String, File\u0026gt; files, int method) throws Exception {\nHttpURLConnection connection = (HttpURLConnection) url.openConnection();\nconnection.setConnectTimeout(CONNECTION_TIMEOUT);\nconnection.setReadTimeout(SOCKET_TIMEOUT);\nconnection.setUseCaches(false);\nconnection.setDoInput(true);\nif (“https”.equals(url.getProtocol()) \u0026amp;\u0026amp; sslSocketFactory != null) {\n((HttpsURLConnection) connection).setSSLSocketFactory(sslSocketFactory);\n((HttpsURLConnection) connection).setHostnameVerifier(new HostnameVerifier() {\n@Override\npublic boolean verify(String hostname, SSLSession session) {\nLog.e(“hhp”, “verify: ” + hostname + “|” + session.getPeerHost());\nreturn hostname.equals(session.getPeerHost());\n// return true;\n}\n});\n}\n//设置请求头\nfor (String headerName : getRequestHeader().keySet()) {\nconnection.addRequestProperty(headerName, getRequestHeader().get(headerName));\n}\n//设置cookie\n// if (cookieManager.getCookieStore().getCookies().size() \u0026gt; 0) {\n// connection.setRequestProperty(“Cookie”,\n// TextUtils.join(“;”, cookieManager.getCookieStore().getCookies()));\n// Logger.i(“Cookie=” + connection.getRequestProperty(“Cookie”));\n// }\nsetConnectionParametersForRequest(connection, params, method);\n// setConnectionParametersForRequest(connection, files);\nint responseCode = connection.getResponseCode();\nif (responseCode != 200) {\nLogger.e(“请求出错:responseCode=” + responseCode);\nthrow new IOException(“Could not retrieve response code from HttpUrlConnection.”);\n}\nif (hasResponseBody(method, responseCode)) {\n// readResponseCookies(url, connection);\nInputStream inputStream;\ntry {\ninputStream = connection.getInputStream();\n} catch (IOException ioe) {\ninputStream = connection.getErrorStream();\n}\nif (inputStream != null) {\nint length = connection.getContentLength();\nbyte[] buffer = new byte[length];\ninputStream.read(buffer);\nreturn buffer;\n}\n}\nreturn new byte[0];\n}\n/**\n设置请求参数 @param connection @param postBody @param method @throws IOException\n*/\nprivate static void setConnectionParametersForRequest(HttpURLConnection connection, byte[] postBody, int method) throws IOException {\nswitch (method) {\ncase Method.POST:\nbyte[] body = postBody;\nif (body != null) {\nconnection.setDoOutput(true);\nconnection.setRequestMethod(“POST”);\nconnection.setRequestProperty(“Content-Type”, “application/x-www-form-urlencoded; charset=utf-8”);\nDataOutputStream out = new DataOutputStream(connection.getOutputStream());\nout.write(postBody);\nout.close();\n}\nbreak;\ncase Method.GET:\nconnection.setRequestMethod(“GET”);\nLogger.e(“发送请求(get):” + connection.getURL().toString());\nbreak;\n}\n} /**\n上传文件 @param connection @param files @throws IOException\n*/\nprivate static void setConnectionParametersForRequest(HttpURLConnection connection, Map\u0026lt;String, File\u0026gt; files) throws IOException {\nString contentType = “application/octet-stream”;\n// String contentType=”image/jpeg”;\nif (files != null \u0026amp;\u0026amp; files.size() \u0026gt; 0) {\nconnection.setDoOutput(true);\nconnection.setRequestMethod(“POST”);\nconnection.setRequestProperty(“Content-Type”, “multipart/form-data; boundary=” + BOUNDARY);\nDataOutputStream out = new DataOutputStream(connection.getOutputStream());\nIterator\u0026lt;Map.Entry\u0026lt;String, File\u0026raquo; iterator = files.entrySet().iterator();\nwhile (iterator.hasNext()) {\nMap.Entry\u0026lt;String, File\u0026gt; next = iterator.next();\nString name = next.getKey();\nFile value = next.getValue();\nif (value == null)\nreturn;\nStringBuilder strBuf = new StringBuilder();\nstrBuf.append(“\\r\\n”).append(“–“).append(BOUNDARY).append(“\\r\\n”);\nstrBuf.append(“Content-Disposition: form-data; name=\u0026amp;#8221;” + name + “\u0026amp;#8221;; filename=\u0026amp;#8221;” + value.getName() + “\u0026amp;#8221;\\r\\n”);\nstrBuf.append(“Content-Type:” + contentType + “\\r\\n\\r\\n”);\nout.write(strBuf.toString().getBytes());\nDataInputStream dis = new DataInputStream(new FileInputStream(value));\nint bytes = -1;\nbyte[] buffer = new byte[1024 * 4];\nwhile ((bytes = dis.read(buffer)) != -1) {\nout.write(buffer);\n}\ndis.close();\n}\nbyte[] endData = (“\\r\\n–” + BOUNDARY + “–\\r\\n”).getBytes();\nout.write(endData);\nout.flush();\nout.close();\n}\nLogger.e(“发送请求(post):” + connection.getURL().toString());\nif (files != null) {\nfor (File file : files.values()) {\nLogger.e(“发送文件:” + new String(file.getName()));\n}\n}\n} private static Map\u0026lt;String, String\u0026gt; getRequestHeader() {\nrequestHeader.put(“Connection”, “Keep-Alive”);\nrequestHeader.put(“Accept-Encoding”, “identity”);//高版本避免conn.getContentLength()＝＝－１;\nrequestHeader.put(“X-Flag”, “TJHF”);\nrequestHeader.put(“Channel”, “tjhf”);\nreturn requestHeader;\n}\npublic interface Method {\nint GET = 1;\nint POST = 2;\nint HEAD = 4;\n}\n/**\n存储cookies @param url @param connection @throws URISyntaxException\n*/\nprivate static void readResponseCookies(URL url, HttpURLConnection connection) throws URISyntaxException {\nMap\u0026lt;String, List\u0026gt; headerFields = connection.getHeaderFields();\nfinal List cookiesHeader = headerFields.get(COOKIES_HEADER);\nif (cookiesHeader != null) {\nfor (String cookie : cookiesHeader) {\ncookieManager.getCookieStore().add(url.toURI(), HttpCookie.parse(cookie).get(0));\n}\n}\n} private static boolean hasResponseBody(int requestMethod, int responseCode) {\nreturn requestMethod != Method.HEAD\n\u0026amp;\u0026amp; !(HttpStatus.SC_CONTINUE \u0026lt;= responseCode \u0026amp;\u0026amp; responseCode \u0026lt; HttpStatus.SC_OK)\n\u0026amp;\u0026amp; responseCode != HttpStatus.SC_NO_CONTENT\n\u0026amp;\u0026amp; responseCode != HttpStatus.SC_NOT_MODIFIED;\n}\n}\n自定义的信任规则管理器\npackage hai.com.android_test.mixed;\nimport javax.net.ssl.X509TrustManager;\n/**\n不安全的信任管理\n*/\npublic class UnSafeTrustManager implements X509TrustManager {\n@Override\npublic void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {\n}\n@Override\npublic void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {\n}\n@Override\npublic java.security.cert.X509Certificate[] getAcceptedIssuers() {\nreturn new java.security.cert.X509Certificate[0];\n}\n} 转自：https://blog.csdn.net/u014763302/article/details/53582073\n参考：https://blog.csdn.net/lwang_it/article/details/78886186\nhttps://blog.csdn.net/u013766436/article/details/51095514\nhttps://www.cnblogs.com/wlm-boke/p/8516046.html\nhttps://www.cnblogs.com/DONGb/p/7844123.html\n","permalink":"https://blog.zdltech.com/posts/%E5%85%B3%E4%BA%8Ehttpurlconnection%E8%AF%B7%E6%B1%82%E7%BD%91%E7%BB%9C%E5%8A%A0%E8%BD%BD%E8%AF%81%E4%B9%A6%E4%B8%8E%E4%B8%8D%E5%8A%A0%E8%BD%BD%E8%AF%81%E4%B9%A6%E7%9A%84%E5%8C%BA%E5%88%AB/","summary":"\u003cp\u003e测试的3个网址分别为：\u003c/p\u003e\n\u003cp\u003eString uri1 = “https://mportal.tianjihuifu.com/tjhf/loginRegist/login?uname=13265468238\u0026amp;pwd=123456”;\u003c/p\u003e\n\u003cp\u003eString uri2 = “https://mportal.tjhf.com/tjhf/loginRegist/login?uname=13265468238\u0026amp;pwd=123456”;\u003c/p\u003e\n\u003cp\u003eString uri = “https://www.baidu.com/”;\u003c/p\u003e\n\u003cp\u003e中间用到的证书为cer_test.crt，证书信息为：CN=console.haitest.com, C=CN。分别测试了加载证书与不加载证书请求3个不同的网址的日志。\u003c/p\u003e\n\u003cp\u003e证书为cer_test.crt，没有HostnameVerifier\u003cbr\u003e\nE/==####DROXY####===: (*\u003cem\u003e*)发送请求(get):https://mportal.haitest.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\u003cbr\u003e\nE/==####DROXY####===: (*\u003c/em\u003e*)响应结果:{“data”:72771,”result”:true,”resultCode”:2000}\u003cbr\u003e\nE/==####DROXY####===: (*\u003cem\u003e*)发送请求(get):https://mportal.hai.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\u003cbr\u003e\nW/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.\u003cbr\u003e\nE/==####DROXY####===: (*\u003c/em\u003e*)发送请求(get):https://www.baidu.com/\u003cbr\u003e\nW/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.\u003cbr\u003e\n证书为cer_test.crt，HostnameVerifier ：return true\u003cbr\u003e\nE/==####DROXY####===: (*\u003cem\u003e*)发送请求(get):https://mportal.haitest.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\u003cbr\u003e\nE/==####DROXY####===: (*\u003c/em\u003e*)响应结果:{“data”:72771,”result”:true,”resultCode”:2000}\u003cbr\u003e\nE/==####DROXY####===: (*\u003cem\u003e*)发送请求(get):https://mportal.hai.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\u003cbr\u003e\nW/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.\u003cbr\u003e\nE/==####DROXY####===: (*\u003c/em\u003e*)发送请求(get):https://www.baidu.com/\u003cbr\u003e\nW/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.\u003cbr\u003e\n证书为cer_test.crt，HostnameVerifier ：return hostname.equals(session.getPeerHost())\u003cbr\u003e\nE/==####DROXY####===: (*\u003cem\u003e*)发送请求(get):https://mportal.haitest.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\u003cbr\u003e\nE/==####DROXY####===: (*\u003c/em\u003e*)响应结果:{“data”:72771,”result”:true,”resultCode”:2000}\u003cbr\u003e\nE/==####DROXY####===: (*\u003cem\u003e*)发送请求(get):https://mportal.hai.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\u003cbr\u003e\nW/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.\u003cbr\u003e\nE/==####DROXY####===: (*\u003c/em\u003e*)发送请求(get):https://www.baidu.com/\u003cbr\u003e\nW/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.\u003cbr\u003e\n证书为null，没有HostnameVerifier\u003cbr\u003e\nE/==####DROXY####===: (*\u003cem\u003e*)发送请求(get):https://mportal.haitest.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\u003cbr\u003e\nE/==####DROXY####===: (*\u003c/em\u003e*)发送请求(get):https://mportal.hai.com/hai/loginRegist/login?uname=13265468238\u0026amp;pwd=123456\u003cbr\u003e\nE/==####DROXY####===: (*\u003cem\u003e*)响应结果:{“data”:72771,”result”:true,”resultCode”:2000}\u003cbr\u003e\nE/==####DROXY####===: (*\u003c/em\u003e*)发送请求(get):https://www.baidu.com/\u003cbr\u003e\nE/==####DROXY####===: (*_*)响应结果:\u003c/p\u003e","title":"关于HttpUrlConnection请求网络加载证书与不加载证书的区别"},{"content":"1.时间格式：在这个项目中，或许是由不同的人建立的数据库表结构吧，对时间的格式步统一，有的表中存储的long类型的时间戳，有的表中是存储的日期，有的表中存储的是时间，同时格式有20171225，2017-12-25等，一点都不统一。这样做，会对项目增加一些额外的工作量，同时会衍生出一些问题出来。比如，在写后台代码时，需要对时间做出处理，以适应数据库的时间格式；在进行夺标联合查询时，时间格式不统一，又会对sql语句进行时间格式转换，造成sql语句臃肿的情况。所以，在同一个项目中，时间格式应该保持统一。个人觉得long 类型的时间戳，以及String类型的yyyy-MM-dd HH:mm:ss 这两种方式时比较不错的。\nlong类型的时间戳，是因为后台java代码将date类型的时间转化为时间戳很容易。\nString类型时因为，我们假如经常使用时间这个字段，在应用时不需要额外将Date类型转化为String类型，使用起来比较直观，方便。\n2.常用时间语句\nSELECT CURDATE()：2017-12-25　//此时日期\nSELECT NOW() : 2017-12-25 22:20:21　//此刻时间\nSELECT YEAR(‘2017-12-25 22:27:45’): 2017　//获取时间的年份\nSELECT MONTH(‘2017-12-25 22:27:45’): 12　//获取时间的月份\nSELECT DAY(‘2017-12-25 22:27:45’)：25　//获取时间的天数\nSELECT HOUR(‘2017-12-25 22:27:45’)：22　//获取时间的小时\nSELECT MINUTE(‘2017-12-25 22:27:45’)：27　//获取时间的分钟\nSELECT SECOND(‘2017-12-25 22:27:45’)：45　//获取时间的秒数\nSELECT DATE_SUB(NOW(),INTERVAL 1 YEAR)　//在目前的时间减去一年，该语句可以进行多种操作，指定时间下减去x年：DATE_SUB(“2017-12-25”,INTERVAL x YEAR),同时可以减去 x month/day/hour/minute/second等\nSELECT ** DATE_ADD**(NOW(),INTERVAL 1 YEAR)　//同上，在目前的时间上加上一年\nSELECT CONCAT(‘2017′,’-12-12′)：2017-12-12　//组装字符串，可以组装成任何时间格式，也可以使用如上语句，例如：SELECT CONCAT(YEAR(NOW()),’-12-12′) ：2017-12-12 ；\nSELECT UNIX_TIMESTAMP(‘2017-12-25’)：1514131200　//字符串转换成时间戳\nSELECT FROM_UNIXTIME(1514131200) ：2017-12-25 00:00:00　//时间戳转化为时间\nSELECT DATE_FORMAT(‘2017-12-25 22:23:01’, ‘%Y-%m-%d %H:%i:%s’); //字符串转化为时间格式（date），也可以时间格式转化为字符串格式\nMySQL 获得当前日期时间 函数 获得当前日期+时间（date + time）函数：now()\nselect now(); +---------------------+ | now() | +---------------------+ | 2008-08-08 22:20:46 | +---------------------+\u0026#34; data-snippet-id=\u0026#34;ext.d179cbb272525cdbac1048c0c9f64b43\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;mysql\u0026amp;gt; select now(); +---------------------+ | now() | +---------------------+ | 2008-08-08 22:20:46 | +---------------------+ 获得当前日期+时间（date + time）函数：sysdate()\nsysdate() 日期时间函数跟 now() 类似，不同之处在于：now() 在执行开始时值就得到了， sysdate() 在函数执行时动态得到值。看下面的例子就明白了：\nselect now(), sleep(3), now(); +---------------------+----------+---------------------+ | now() | sleep(3) | now() | +---------------------+----------+---------------------+ | 2008-08-08 22:28:21 | 0 | 2008-08-08 22:28:21 | +---------------------+----------+---------------------+\u0026#34; data-snippet-id=\u0026#34;ext.186ca328fd363d4aa049a0e799f33faa\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;mysql\u0026amp;gt; select now(), sleep(3), now(); +---------------------+----------+---------------------+ | now() | sleep(3) | now() | +---------------------+----------+---------------------+ | 2008-08-08 22:28:21 | 0 | 2008-08-08 22:28:21 | +---------------------+----------+---------------------+ sysdate() 日期时间函数，一般情况下很少用到。\nMySQL 获得当前时间戳函数：current_timestamp, current_timestamp()\nselect current_timestamp, current_timestamp(); +---------------------+---------------------+ | current_timestamp | current_timestamp() | +---------------------+---------------------+ | 2008-08-09 23:22:24 | 2008-08-09 23:22:24 | +---------------------+---------------------+\u0026#34; data-snippet-id=\u0026#34;ext.1f72d3646d7f963000226288f19e76ee\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;mysql\u0026amp;gt; select current_timestamp, current_timestamp(); +---------------------+---------------------+ | current_timestamp | current_timestamp() | +---------------------+---------------------+ | 2008-08-09 23:22:24 | 2008-08-09 23:22:24 | +---------------------+---------------------+ MySQL 日期转换函数、时间转换函数 MySQL Date/Time to Str（日期/时间转换为字符串）函数：date_format(date,format), time_format(time,format)\nselect date_format(\u0026#39;2008-08-08 22:23:01\u0026#39;, \u0026#39;%Y%m%d%H%i%s\u0026#39;); +----------------------------------------------------+ | date_format(\u0026#39;2008-08-08 22:23:01\u0026#39;, \u0026#39;%Y%m%d%H%i%s\u0026#39;) | +----------------------------------------------------+ | 20080808222301 | +----------------------------------------------------+\u0026#34; data-snippet-id=\u0026#34;ext.a31e504be944e6ef2610e9f49156849d\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;mysql\u0026amp;gt; select date_format(\u0026#39;2008-08-08 22:23:01\u0026#39;, \u0026#39;%Y%m%d%H%i%s\u0026#39;); +----------------------------------------------------+ | date_format(\u0026#39;2008-08-08 22:23:01\u0026#39;, \u0026#39;%Y%m%d%H%i%s\u0026#39;) | +----------------------------------------------------+ | 20080808222301 | +----------------------------------------------------+ MySQL 日期、时间转换函数：date_format(date,format), time_format(time,format) 能够把一个日期/时间转换成各种各样的字符串格式。它是 str_to_date(str,format) 函数的 一个逆转换。\nMySQL Str to Date （字符串转换为日期）函数：str_to_date(str, format)\nselect str_to_date(\u0026#39;08/09/2008\u0026#39;, \u0026#39;%m/%d/%Y\u0026#39;); -- 2008-08-09 select str_to_date(\u0026#39;08/09/08\u0026#39; , \u0026#39;%m/%d/%y\u0026#39;); -- 2008-08-09 select str_to_date(\u0026#39;08.09.2008\u0026#39;, \u0026#39;%m.%d.%Y\u0026#39;); -- 2008-08-09 select str_to_date(\u0026#39;08:09:30\u0026#39;, \u0026#39;%h:%i:%s\u0026#39;); -- 08:09:30 select str_to_date(\u0026#39;08.09.2008 08:09:30\u0026#39;, \u0026#39;%m.%d.%Y %h:%i:%s\u0026#39;); -- 2008-08-09 08:09:30 可以看到，str_to_date(str,format) 转换函数，可以把一些杂乱无章的字符串转换为日期格式。另外，它也可以转换为时间。“format” 可以参看 MySQL 手册。\nMySQL （日期、天数）转换函数：to_days(date), from_days(days)\nselect to_days(\u0026#39;0000-00-00\u0026#39;); -- 0 select to_days(\u0026#39;2008-08-08\u0026#39;); -- 733627 MySQL （时间、秒）转换函数：time_to_sec(time), sec_to_time(seconds)\nselect time_to_sec(\u0026#39;01:00:05\u0026#39;); -- 3605 select sec_to_time(3605); -- \u0026#39;01:00:05\u0026#39; MySQL 拼凑日期、时间函数：makdedate(year,dayofyear), maketime(hour,minute,second)\nselect makedate(2001,31); -- \u0026#39;2001-01-31\u0026#39; select makedate(2001,32); -- \u0026#39;2001-02-01\u0026#39; select maketime(12,15,30); -- \u0026#39;12:15:30\u0026#39; MySQL （Unix 时间戳、日期）转换函数\nunix_timestamp(), unix_timestamp(date), from_unixtime(unix_timestamp), from_unixtime(unix_timestamp,format) 下面是示例：\nselect unix_timestamp(); -- 1218290027 select unix_timestamp(\u0026#39;2008-08-08\u0026#39;); -- 1218124800 select unix_timestamp(\u0026#39;2008-08-08 12:30:00\u0026#39;); -- 1218169800 select from_unixtime(1218290027); -- \u0026#39;2008-08-09 21:53:47\u0026#39; select from_unixtime(1218124800); -- \u0026#39;2008-08-08 00:00:00\u0026#39; select from_unixtime(1218169800); -- \u0026#39;2008-08-08 12:30:00\u0026#39; select from_unixtime(1218169800, \u0026#39;%Y %D %M %h:%i:%s %x\u0026#39;); -- \u0026#39;2008 8th August 12:30:00 2008\u0026#39; MySQL 日期时间计算函数\nMySQL 为日期增加一个时间间隔：date_add()\n``` set @dt = now(); select date_add(@dt, interval 1 day); \u0026ndash; add 1 day select date_add(@dt, interval 1 hour); \u0026ndash; add 1 hour select date_add(@dt, interval 1 minute); \u0026ndash; \u0026hellip; select date_add(@dt, interval 1 second); select date_add(@dt, interval 1 microsecond); select date_add(@dt, interval 1 week); select date_add(@dt, interval 1 month); select date_add(@dt, interval 1 quarter); select date_add(@dt, interval 1 year);\nselect date_add(@dt, interval -1 day); \u0026ndash; sub 1 day\n\u0026lt;/div\u0026gt; MySQL adddate(), addtime()函数，可以用 date\\_add() 来替代。下面是 date\\_add() 实现 addtime() 功能示例： \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; set @dt = \u0026lsquo;2008-08-09 12:12:33\u0026rsquo;;\nmysql\u0026gt; mysql\u0026gt; select date_add(@dt, interval \u0026lsquo;01:15:30\u0026rsquo; hour_second);\n+\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;+ | date_add(@dt, interval \u0026lsquo;01:15:30\u0026rsquo; hour_second) | +\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;+ | 2008-08-09 13:28:03 | +\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;+\nmysql\u0026gt; select date_add(@dt, interval \u0026lsquo;1 01:15:30\u0026rsquo; day_second);\n+\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-+ | date_add(@dt, interval \u0026lsquo;1 01:15:30\u0026rsquo; day_second) | +\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-+ | 2008-08-10 13:28:03 | +\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-+\u0026quot; data-snippet-id=\u0026ldquo;ext.efb34afaaabb8ce6dc652a2c245a4fa6\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;mysql\u0026gt; set @dt = \u0026lsquo;2008-08-09 12:12:33\u0026rsquo;;\nmysql\u0026gt; mysql\u0026gt; select date_add(@dt, interval \u0026lsquo;01:15:30\u0026rsquo; hour_second);\n+\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;+ | date_add(@dt, interval \u0026lsquo;01:15:30\u0026rsquo; hour_second) | +\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;+ | 2008-08-09 13:28:03 | +\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;+\nmysql\u0026gt; select date_add(@dt, interval \u0026lsquo;1 01:15:30\u0026rsquo; day_second);\n+\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-+ | date_add(@dt, interval \u0026lsquo;1 01:15:30\u0026rsquo; day_second) | +\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-+ | 2008-08-10 13:28:03 | +\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-+\n\u0026lt;/div\u0026gt; \u0026amp;nbsp; MySQL 为日期减去一个时间间隔：date_sub() \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; select date_sub(\u0026lsquo;1998-01-01 00:00:00\u0026rsquo;, interval \u0026lsquo;1 1:1:1\u0026rsquo; day_second);\n+\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-+ | date_sub(\u0026lsquo;1998-01-01 00:00:00\u0026rsquo;, interval \u0026lsquo;1 1:1:1\u0026rsquo; day_second) | +\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-+ | 1997-12-30 22:58:59 | +\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-+\u0026quot; data-snippet-id=\u0026ldquo;ext.ed7be3f463a80a614900317ee6b87600\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;mysql\u0026gt; select date_sub(\u0026lsquo;1998-01-01 00:00:00\u0026rsquo;, interval \u0026lsquo;1 1:1:1\u0026rsquo; day_second);\n+\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-+ | date_sub(\u0026lsquo;1998-01-01 00:00:00\u0026rsquo;, interval \u0026lsquo;1 1:1:1\u0026rsquo; day_second) | +\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-+ | 1997-12-30 22:58:59 | +\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-+\n\u0026lt;/div\u0026gt; MySQL date\\_sub() 日期时间函数 和 date\\_add() 用法一致，不再赘述。 \u0026amp;nbsp; MySQL 日期、时间相减函数：datediff(date1,date2), timediff(time1,time2) \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; MySQL datediff(date1,date2)：两个日期相减 date1 - date2，返回天数。 select datediff(\u0026lsquo;2008-08-08\u0026rsquo;, \u0026lsquo;2008-08-01\u0026rsquo;); \u0026ndash; 7 select datediff(\u0026lsquo;2008-08-01\u0026rsquo;, \u0026lsquo;2008-08-08\u0026rsquo;); \u0026ndash; -7\n\u0026lt;/div\u0026gt; MySQL timediff(time1,time2)：两个日期相减 time1 \u0026amp;#8211; time2，返回 time 差值。 \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; select timediff(\u0026lsquo;2008-08-08 08:08:08\u0026rsquo;, \u0026lsquo;2008-08-08 00:00:00\u0026rsquo;); \u0026ndash; 08:08:08 select timediff(\u0026lsquo;08:08:08\u0026rsquo;, \u0026lsquo;00:00:00\u0026rsquo;); \u0026ndash; 08:08:08\n\u0026lt;/div\u0026gt; 注意：timediff(time1,time2) 函数的两个参数类型必须相同。 \u0026amp;nbsp; MySQL 时间戳（timestamp）转换、增、减函数： \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; timestamp(date) \u0026ndash; date to timestamp timestamp(dt,time) \u0026ndash; dt + time timestampadd(unit,interval,datetime_expr) \u0026ndash; timestampdiff(unit,datetime_expr1,datetime_expr2) \u0026ndash;\n\u0026lt;/div\u0026gt; 请看示例部分： \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; select timestamp(\u0026lsquo;2008-08-08\u0026rsquo;); \u0026ndash; 2008-08-08 00:00:00 select timestamp(\u0026lsquo;2008-08-08 08:00:00\u0026rsquo;, \u0026lsquo;01:01:01\u0026rsquo;); \u0026ndash; 2008-08-08 09:01:01 select timestamp(\u0026lsquo;2008-08-08 08:00:00\u0026rsquo;, \u0026lsquo;10 01:01:01\u0026rsquo;); \u0026ndash; 2008-08-18 09:01:01\nselect timestampadd(day, 1, \u0026lsquo;2008-08-08 08:00:00\u0026rsquo;); \u0026ndash; 2008-08-09 08:00:00 select date_add(\u0026lsquo;2008-08-08 08:00:00\u0026rsquo;, interval 1 day); \u0026ndash; 2008-08-09 08:00:00\nMySQL timestampadd() 函数类似于 date_add()。 select timestampdiff(year,\u0026lsquo;2002-05-01\u0026rsquo;,\u0026lsquo;2001-01-01\u0026rsquo;); \u0026ndash; -1 select timestampdiff(day ,\u0026lsquo;2002-05-01\u0026rsquo;,\u0026lsquo;2001-01-01\u0026rsquo;); \u0026ndash; -485 select timestampdiff(hour,\u0026lsquo;2008-08-08 12:00:00\u0026rsquo;,\u0026lsquo;2008-08-08 00:00:00\u0026rsquo;); \u0026ndash; -12\nselect datediff(\u0026lsquo;2008-08-08 12:00:00\u0026rsquo;, \u0026lsquo;2008-08-01 00:00:00\u0026rsquo;); \u0026ndash; 7\n\u0026lt;/div\u0026gt; MySQL timestampdiff() 函数就比 datediff() 功能强多了，datediff() 只能计算两个日期（date）之间相差的天数。 \u0026amp;nbsp; ## **MySQL 时区（timezone）转换函数** \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; convert_tz(dt,from_tz,to_tz)\nselect convert_tz(\u0026lsquo;2008-08-08 12:00:00\u0026rsquo;, \u0026lsquo;+08:00\u0026rsquo;, \u0026lsquo;+00:00\u0026rsquo;); \u0026ndash; 2008-08-08 04:00:00\n\u0026lt;/div\u0026gt; 时区转换也可以通过 date\\_add, date\\_sub, timestampadd 来实现。 \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; select date_add(\u0026lsquo;2008-08-08 12:00:00\u0026rsquo;, interval -8 hour); \u0026ndash; 2008-08-08 04:00:00 select date_sub(\u0026lsquo;2008-08-08 12:00:00\u0026rsquo;, interval 8 hour); \u0026ndash; 2008-08-08 04:00:00 select timestampadd(hour, -8, \u0026lsquo;2008-08-08 12:00:00\u0026rsquo;); \u0026ndash; 2008-08-08 04:00:00\n\u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/mysql%E6%97%A5%E6%9C%9F%E5%A4%84%E7%90%86/","summary":"\u003cp\u003e\u003cstrong\u003e1.时间格式\u003c/strong\u003e：在这个项目中，或许是由不同的人建立的数据库表结构吧，对时间的格式步统一，有的表中存储的long类型的时间戳，有的表中是存储的日期，有的表中存储的是时间，同时格式有20171225，2017-12-25等，一点都不统一。这样做，会对项目增加一些额外的工作量，同时会衍生出一些问题出来。比如，在写后台代码时，需要对时间做出处理，以适应数据库的时间格式；在进行夺标联合查询时，时间格式不统一，又会对sql语句进行时间格式转换，造成sql语句臃肿的情况。所以，在同一个项目中，时间格式应该保持统一。个人觉得long 类型的时间戳，以及String类型的yyyy-MM-dd HH:mm:ss 这两种方式时比较不错的。\u003c/p\u003e\n\u003cp\u003elong类型的时间戳，是因为后台java代码将date类型的时间转化为时间戳很容易。\u003c/p\u003e\n\u003cp\u003eString类型时因为，我们假如经常使用时间这个字段，在应用时不需要额外将Date类型转化为String类型，使用起来比较直观，方便。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2.常用时间语句\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eSELECT  CURDATE()：2017-12-25　　//此时日期\u003c/p\u003e\n\u003cp\u003eSELECT  NOW() : 2017-12-25 22:20:21　　//此刻时间\u003c/p\u003e\n\u003cp\u003eSELECT  YEAR(‘2017-12-25 22:27:45’): 2017　　//获取时间的年份\u003c/p\u003e\n\u003cp\u003eSELECT  MONTH(‘2017-12-25 22:27:45’): 12　　//获取时间的月份\u003c/p\u003e\n\u003cp\u003eSELECT  DAY(‘2017-12-25 22:27:45’)：25　　//获取时间的天数\u003c/p\u003e\n\u003cp\u003eSELECT  HOUR(‘2017-12-25 22:27:45’)：22　　//获取时间的小时\u003c/p\u003e\n\u003cp\u003eSELECT  MINUTE(‘2017-12-25 22:27:45’)：27　　//获取时间的分钟\u003c/p\u003e\n\u003cp\u003eSELECT  SECOND(‘2017-12-25 22:27:45’)：45　　//获取时间的秒数\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eSELECT  \u003cstrong\u003eDATE_SUB\u003c/strong\u003e(NOW(),INTERVAL   1   YEAR)　　//在目前的时间减去一年，该语句可以进行多种操作，指定时间下减去x年：DATE_SUB(“2017-12-25”,INTERVAL \u003cstrong\u003ex\u003c/strong\u003e YEAR),同时可以减去 x month/day/hour/minute/second等\u003c/p\u003e\n\u003cp\u003eSELECT ** DATE_ADD**(NOW(),INTERVAL 1 YEAR)　　//同上，在目前的时间上加上一年\u003c/p\u003e\n\u003cp\u003eSELECT  \u003cstrong\u003eCONCAT\u003c/strong\u003e(‘2017′,’-12-12′)：2017-12-12　　//组装字符串，可以组装成任何时间格式，也可以使用如上语句，例如：SELECT CONCAT(YEAR(NOW()),’-12-12′) ：2017-12-12 ；\u003c/p\u003e\n\u003cp\u003eSELECT \u003cstrong\u003eUNIX_TIMESTAMP\u003c/strong\u003e(‘2017-12-25’)：1514131200　　//字符串转换成时间戳\u003c/p\u003e\n\u003cp\u003eSELECT \u003cstrong\u003eFROM_UNIXTIME\u003c/strong\u003e(1514131200) ：2017-12-25 00:00:00　　//时间戳转化为时间\u003c/p\u003e","title":"Mysql日期处理"},{"content":"购买kindle之后，自然欣喜万分，不来自于工具本身，而来自于发现自己能够静下心来阅读长篇和复杂的文字了，可喜可贺。更重要的是，kindle减轻了我眼睛的莫大的压力。但马上就出现几个问题：\n不是所有的电子书都有kindle，最常见的是扫描PDF 大量的论文无法阅读,这和上面的问题一致 网络上很多精彩的博客，新闻，都是没法阅读的 可能有人说，用手机看不就得了？用手机看花边娱乐新闻当然很好，可是当看数学推导时，推送栏上面妹子发来的消息，会直接把你的思路全部打乱。没用过kindle的人，是有些难以体会那种接近于纸张的质感的。OK，既然是程序员，我们就尝试解决这些问题。\n有关kindlegen和HTML kindlegen是亚马逊官方出品的一个电子书生成工具。但它明显就没打算让普通用户使用，命令行界面，几乎没有任何像样的文档。只是在实例样例里给了几个生成电子书的文件。我就因为没有文档兜了大弯，翻遍国外各大网站，才慢慢摸清kindlegen的使用细节。\n可以这么理解,KG是将一组HTML和相关文件，打包成mobi文件的工具。\n最简单的例子，随意编写一个HTML文件，送给KG，会生成对应的mobi。基本有title,h1,h2,正文，kindle渲染就差不多了。如果需要修改样式，可以提供CSS文件。\n但是，这样的做法，没有图片，没有超链接，无法提供目录，如果输入单一的大型HTML文件，kindle的渲染性能就不足了。\n因此，需要生成层级化，多文件形式的html文件夹，然而kg并不能直接识别html文件夹，还是需要一些元数据描述。\n编写元数据文件 要想解决这个问题，就需要编写两个文件,opf和ncx, 他们可以理解为KG的makefile, KG通过这两个文件索引HTML，目录和其他多媒体资源。介绍如下：\n[][1]\n值得注意的是，所有的文件都应该保存在本地，尤其是jpg, html中的图片超链接，需要重定向到本地的jpg文件，如果依然在服务器上，据我所知，kg是不负责渲染下载的。\n资源聚合文件: opf和ncx 由于opf文件非常重要，我们下面就讲解opf的格式：\n![复制代码](https://common.cnblogs.com/images/copycode.gif) \u0026lt;metadata xmlns:dc=\u0026amp;quot;http://purl.org/dc/elements/1.1/\u0026amp;quot; xmlns:opf=\u0026amp;quot;http://www.idpf.org/2007/opf\u0026amp;quot;\u0026gt; \u0026lt;dc:title\u0026gt;电子书标题\u0026lt;/dc:title\u0026gt; \u0026lt;dc:language\u0026gt;en-us\u0026lt;/dc:language\u0026gt; \u0026lt;/metadata\u0026gt; \u0026lt;manifest\u0026gt; \u0026lt;!-- table of contents [mandatory] --\u0026gt; \u0026lt;item id=\u0026amp;quot;tochtml\u0026amp;quot; media-type=\u0026amp;quot;application/xhtml+xml\u0026amp;quot; href=\u0026amp;quot;toc.html\u0026amp;quot;/\u0026gt; \u0026lt;item id=\u0026amp;quot;item0\u0026amp;quot; media-type=\u0026amp;quot;application/xhtml+xml\u0026amp;quot; href=\u0026amp;quot;Artical-1277621753.html\u0026amp;quot;/\u0026gt; ... \u0026lt;!--下面是图片--\u0026gt; \u0026lt;item id=\u0026amp;quot;0.368541311142\u0026amp;quot; media-type=\u0026amp;quot;image/jpg\u0026amp;quot; href=\u0026amp;quot;Images/-1720404282.jpg\u0026amp;quot;/\u0026gt; \u0026lt;/manifest\u0026gt; \u0026lt;spine toc=\u0026amp;quot;desertfire\u0026amp;quot;\u0026gt; \u0026lt;!-- 下面描述了KG生成电子书后文本的顺序 --\u0026gt; \u0026lt;itemref idref=\u0026amp;quot;toc\u0026amp;quot;/\u0026gt; \u0026lt;itemref idref=\u0026amp;quot;tochtml\u0026amp;quot;/\u0026gt; \u0026lt;itemref idref=\u0026amp;quot;item31\u0026amp;quot;/\u0026gt; \u0026lt;/spine\u0026gt; \u0026lt;guide\u0026gt; \u0026lt;reference type=\u0026amp;quot;toc\u0026amp;quot; title=\u0026amp;quot;Table of Contents\u0026amp;quot; href=\u0026amp;quot;toc.html\u0026amp;quot;\u0026gt;\u0026lt;/reference\u0026gt; \u0026lt;reference type=\u0026amp;quot;text\u0026amp;quot; title=\u0026amp;quot;Welcome\u0026amp;quot; href=\u0026amp;quot;toc.html\u0026amp;quot;\u0026gt;\u0026lt;/reference\u0026gt; \u0026lt;/guide\u0026gt; \u0026lt;/package\u0026gt; \u0026amp;#96;\u0026amp;#96;\u0026amp;#96;\u0026#34; data-snippet-id=\u0026#34;ext.b091e89925c72be7b07f9caa16092df4\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;\u0026amp;lt;package xmlns=\u0026#34;http://www.idpf.org/2007/opf\u0026#34; version=\u0026#34;2.0\u0026#34; unique-identifier=\u0026#34;BookId\u0026#34;\u0026amp;gt; \u0026amp;lt;metadata xmlns:dc=\u0026#34;http://purl.org/dc/elements/1.1/\u0026#34; xmlns:opf=\u0026#34;http://www.idpf.org/2007/opf\u0026#34;\u0026amp;gt; \u0026amp;lt;dc:title\u0026amp;gt;电子书标题\u0026amp;lt;/dc:title\u0026amp;gt; \u0026amp;lt;dc:language\u0026amp;gt;en-us\u0026amp;lt;/dc:language\u0026amp;gt; \u0026amp;lt;/metadata\u0026amp;gt; \u0026amp;lt;manifest\u0026amp;gt; \u0026amp;lt;!-- table of contents [mandatory] --\u0026amp;gt; \u0026amp;lt;item id=\u0026#34;tochtml\u0026#34; media-type=\u0026#34;application/xhtml+xml\u0026#34; href=\u0026#34;toc.html\u0026#34;/\u0026amp;gt; \u0026amp;lt;item id=\u0026#34;item0\u0026#34; media-type=\u0026#34;application/xhtml+xml\u0026#34; href=\u0026#34;Artical-1277621753.html\u0026#34;/\u0026amp;gt; ... \u0026amp;lt;!--下面是图片--\u0026amp;gt; \u0026amp;lt;item id=\u0026#34;0.368541311142\u0026#34; media-type=\u0026#34;image/jpg\u0026#34; href=\u0026#34;Images/-1720404282.jpg\u0026#34;/\u0026amp;gt; \u0026amp;lt;/manifest\u0026amp;gt; \u0026amp;lt;spine toc=\u0026#34;desertfire\u0026#34;\u0026amp;gt; \u0026amp;lt;!-- 下面描述了KG生成电子书后文本的顺序 --\u0026amp;gt; \u0026amp;lt;itemref idref=\u0026#34;toc\u0026#34;/\u0026amp;gt; \u0026amp;lt;itemref idref=\u0026#34;tochtml\u0026#34;/\u0026amp;gt; \u0026amp;lt;itemref idref=\u0026#34;item31\u0026#34;/\u0026amp;gt; \u0026amp;lt;/spine\u0026amp;gt; \u0026amp;lt;guide\u0026amp;gt; \u0026amp;lt;reference type=\u0026#34;toc\u0026#34; title=\u0026#34;Table of Contents\u0026#34; href=\u0026#34;toc.html\u0026#34;\u0026amp;gt;\u0026amp;lt;/reference\u0026amp;gt; \u0026amp;lt;reference type=\u0026#34;text\u0026#34; title=\u0026#34;Welcome\u0026#34; href=\u0026#34;toc.html\u0026#34;\u0026amp;gt;\u0026amp;lt;/reference\u0026amp;gt; \u0026amp;lt;/guide\u0026amp;gt; \u0026amp;lt;/package\u0026amp;gt; \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](https://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; [![image](https://images2015.cnblogs.com/blog/287060/201603/287060-20160307103012038-1762823801.png)][2] 需要注意的有以下几点： * 所有资源都需要一个id,命名任意，但不能重复 * media-type描述了资源的类型，记住两类基本就够用了，\u0026amp;#8221;application/xhtml+xml\u0026amp;#8221;代表HTML文件，\u0026amp;#8221;image/jpg\u0026amp;#8221;或 \u0026amp;#8220;image/png\u0026amp;#8221;代表图片。 * 其他都可以省略，只是会影响电子书完整性。 由于这两个文件内部其实都是html,所以修改编辑都很容易。 **最终，KG的命令行目标，不是目录HTML,而是OPF文件！**将所有的文件放入一个文件夹后，启动KG命令行，最后KG会在该目录下生成你心仪已久的mobi! ## 编辑HTML和OPF文件 知道其原理后，主要的任务是填充HTML和OPF文件，几页内容还好，如果内容繁多，不论是手工**( ⊙ o ⊙ )**,还是编程字符串拼接，都会变得异常低效。 此时，就需要**模板引擎**出手了，python推荐使用Jinja2, 资料众多，功能强大，性能尚可。生成opf的模板文件，基本就长下面这个样子： \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](https://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; {{ title }} en-us {% for item in navigation %} {% endfor %} {% for item in media %} {% endfor %} {% for item in navigation %} {% endfor %} \" data-snippet-id=\"ext.1564f86c79babcc6b8778ebad334ce3f\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003e\u0026lt;package xmlns=\"http://www.idpf.org/2007/opf\" version=\"2.0\" unique-identifier=\"BookId\"\u0026gt; \u0026lt;metadata xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:opf=\"http://www.idpf.org/2007/opf\"\u0026gt; \u0026lt;dc:title\u0026gt;{{ title }}\u0026lt;/dc:title\u0026gt; \u0026lt;dc:language\u0026gt;en-us\u0026lt;/dc:language\u0026gt; \u0026lt;/metadata\u0026gt; \u0026lt;manifest\u0026gt; \u0026lt;!-- table of contents [mandatory] --\u0026gt; \u0026lt;item id=\"toc\" media-type=\"application/x-dtbncx+xml\" href=\"toc.ncx\"/\u0026gt; \u0026lt;item id=\"tochtml\" media-type=\"application/xhtml+xml\" href=\"toc.html\"/\u0026gt; {% for item in navigation %} \u0026lt;item id=\"{{ item.id }}\" media-type=\"application/xhtml+xml\" href=\"{{ item.href }}\"/\u0026gt; {% endfor %} {% for item in media %} \u0026lt;item id=\"{{ item.id }}\" media-type=\"image/{{ item.format}}\" href=\"{{ item.href}}\"/\u0026gt; {% endfor %} \u0026lt;/manifest\u0026gt; \u0026lt;spine toc=\u0026quot;{{ title }}\u0026quot;\u0026gt; \u0026lt;!\u0026ndash; the spine defines the linear reading order of the book \u0026ndash;\u0026gt; \u0026lt;itemref idref=\u0026ldquo;toc\u0026rdquo;/\u0026gt;\n\u0026lt;itemref idref=\u0026ldquo;tochtml\u0026rdquo;/\u0026gt;\n{% for item in navigation %} \u0026lt;itemref idref=\u0026quot;{{ item.id }}\u0026quot;/\u0026gt; {% endfor %} \u0026lt;/spine\u0026gt; \u0026lt;guide\u0026gt; \u0026lt;reference type=\u0026ldquo;toc\u0026rdquo; title=\u0026ldquo;Table of Contents\u0026rdquo; href=\u0026ldquo;toc.html\u0026rdquo;\u0026gt;\u0026lt;/reference\u0026gt; \u0026lt;reference type=\u0026ldquo;text\u0026rdquo; title=\u0026ldquo;Welcome\u0026rdquo; href=\u0026ldquo;toc.html\u0026rdquo;\u0026gt;\u0026lt;/reference\u0026gt; \u0026lt;/guide\u0026gt; \u0026lt;/package\u0026gt;\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](https://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 我在此处就不费事讲解jinja2的语法了。这样，就能解决阅读网页新闻和HTML资源的问题了。 ## 生成扫描版MOBI 下一个问题，是如何阅读扫描版的PDF，如电子书和论文。有以下几类初始想法： [![image](https://images2015.cnblogs.com/blog/287060/201603/287060-20160307103013007-1788172288.png)][3] 权衡之后，我们选用第二种方案。PDF分为两类，一种是一页一栏，如电子书，另一种是一页两栏，如论文。 那么，为了保证质量，有以下的步骤： ### 将PDF转换为图片 如果使用python，则有一些类库可以使用，如imagemagick和一系列相关类库。 但这些类库安装比较麻烦，因此笔者使用了软件生成，此处强烈推荐一款软件： **AP PDF to IMAGE** 国产软件？的骄傲！不需要其他任何类库，体积小，性能稳定，生成图片尺寸可调，可批量处理，非常清晰！ 百度可搜索各类绿色版下载，我都想给作者支付宝捐钱了。 ### 图片处理 如果你是PS大神，当然可以使用宏和批量命令完成这些，此处我们用的还是python，使用著名的PIL类库，下面贴出代码： \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](https://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; coding=utf-8 import os\nimport Image as img import jinja2 as jj\nimport extends import libs.kindlestrip as kp\n要PDF转JPG时，如果用python的方案，则需要安装一堆库 用现成的工具，则难以与Python集成，而且速度很慢，目前还是采用现成的工具吧 当生成论文时，第一页的上半部分，单独抽出，剩下的分为四页导出。设置如下 horizon = 2 vertic = 2 firstpage = True\n生成普通横版PDF时，则为如下设置： horizon = 1 vertic = 2 firstpage=False topblood = 0.05; sideblood = 0.06; booktitle = u\u0026quot;Paper\u0026quot;; author = \u0026ldquo;zhaoyiming\u0026rdquo; outputfolder = \u0026ldquo;pdf2mobi/\u0026rdquo;; imgTypes = [\u0026rsquo;.png\u0026rsquo;, \u0026lsquo;.jpg\u0026rsquo;, \u0026lsquo;.bmp\u0026rsquo;] kindlegen = r\u0026quot;Tools/kindlegen.exe\u0026quot; # kindlegen position shouldsplit = True; imagefolders = outputfolder + \u0026lsquo;raw\u0026rsquo;; splitfolder = outputfolder + \u0026lsquo;split\u0026rsquo;\ndocs = []; pageindex = 0;\nif shouldsplit == True: for root, dirs, files in os.walk(imagefolders): index = 0; for currentFile in files: crtFile = root + \u0026lsquo;\\\u0026rsquo; + currentFile format = crtFile[crtFile.rindex(\u0026rsquo;.\u0026rsquo;):].lower();\nif format not in imgTypes: continue; crtIm = img.open(crtFile) crtW, crtH = crtIm.size hStep = crtW * (1 - 2 * sideblood) // horizon vStep = crtH * (1 - 2 * topblood) // vertic hstart = crtW * sideblood vstart = crtH * topblood; if (firstpage == True and pageindex == 0): crtOutFileName = 'pdf2mobi/split/' + str(index) + format, box = (hstart, vstart, crtW, crtH // 3) box = list((int(x) for x in box)); cropped = crtIm.crop(box) cropped.save(crtOutFileName[0]) myimg = {}; myimg[\u0026quot;href\u0026quot;] = \u0026quot;split/\u0026quot; + str(index) + format; myimg[\u0026quot;id\u0026quot;] = index; myimg[\u0026quot;format\u0026quot;] = format; myimg[\u0026quot;width\u0026quot;] = box[2] - box[0]; myimg[\u0026quot;height\u0026quot;] = box[3] - box[1]; docs.append(myimg) index += 1; for j in range(horizon): for i in range(vertic): crtOutFileName = 'pdf2mobi/split/' + str(index) + format, box = (hstart + j * hStep, vstart + i * vStep, hstart + (j + 1) * hStep, vstart + (i + 1) * vStep) box = (int(x) for x in box); cropped = crtIm.crop(box) cropped.save(crtOutFileName[0]) myimg = {}; myimg[\u0026quot;href\u0026quot;] = \u0026quot;split/\u0026quot; + str(index) + format; myimg[\u0026quot;id\u0026quot;] = index; myimg[\u0026quot;format\u0026quot;] = format; myimg[\u0026quot;width\u0026quot;] = hStep; myimg[\u0026quot;height\u0026quot;] = vStep; docs.append(myimg) index += 1; pageindex += 1; else: for root, dirs, files in os.walk(imagefolders): index = 0; for currentFile in files: crtFile = root + \u0026lsquo;\\\u0026rsquo; + currentFile format = crtFile[crtFile.rindex(\u0026rsquo;.\u0026rsquo;):].lower(); if format not in imgTypes: continue; myimg = {}; myimg[\u0026ldquo;href\u0026rdquo;] = \u0026ldquo;split/\u0026rdquo; + str(index) + format; myimg[\u0026ldquo;id\u0026rdquo;] = index; myimg[\u0026ldquo;format\u0026rdquo;] = format; myimg[\u0026ldquo;width\u0026rdquo;] = \u0026ldquo;1347\u0026rdquo;; myimg[\u0026ldquo;height\u0026rdquo;] = \u0026ldquo;1023\u0026rdquo;; docs.append(myimg) index += 1; images = []; env = jj.Environment(loader=jj.FileSystemLoader([r\u0026quot;templates/\u0026quot;])) articaltemplate = env.get_template(\u0026lsquo;jpgs.html\u0026rsquo;)\nopftemplate = env.get_template(\u0026lsquo;opf.html\u0026rsquo;) ncxtemplate = env.get_template(\u0026rsquo;ncx.html\u0026rsquo;)\nextends.SaveFile(outputfolder + \u0026ldquo;toc.html\u0026rdquo;, articaltemplate.render(navigation=docs, title=booktitle, author=author)); extends.SaveFile(outputfolder + booktitle + \u0026ldquo;.opf\u0026rdquo;, opftemplate.render(navigation=docs, title=booktitle, author=author, media=images)); extends.SaveFile(outputfolder + \u0026ldquo;toc.ncx\u0026rdquo;, ncxtemplate.render(navigation=docs, title=booktitle, author=author));\ncurrentPath = os.getcwd() + \u0026ldquo;\\\u0026rdquo; + outputfolder.replace(\u0026quot;/\u0026quot;, \u0026ldquo;\\\u0026rdquo;) + booktitle + \u0026ldquo;.opf\u0026rdquo;; mobipath = outputfolder.replace(\u0026quot;/\u0026quot;, \u0026ldquo;\\\u0026rdquo;) + booktitle + \u0026ldquo;.mobi\u0026rdquo;; kindlepath = os.getcwd() + \u0026ldquo;\\\u0026rdquo; + kindlegen.replace(\u0026quot;/\u0026quot;, \u0026ldquo;\\\u0026rdquo;); cmd = kindlepath + \u0026quot; \u0026quot; + currentPath; cmd = cmd.encode(); print cmd; os.system(cmd); kp.Convert(mobipath, mobipath)\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](https://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; （我觉得我应该把代码上传到github上，恩，一会再说） 这样，就能生成可读的漂亮的PDF转mobi了。 ## 最终效果 这些代码花了我一个下午的时间，不过与爬虫配合，生成各位大神的博客，效果真是非常赞！ [![image](https://images2015.cnblogs.com/blog/287060/201603/287060-20160307103017210-1383420280.png)][4] [![image](https://images2015.cnblogs.com/blog/287060/201603/287060-20160307103023194-253815208.png)][5] [![image](https://images2015.cnblogs.com/blog/287060/201603/287060-20160307103028507-9009866.png)][6] 转自：https://www.cnblogs.com/buptzym/p/5249662.html [1]: http://images2015.cnblogs.com/blog/287060/201603/287060-20160307103010366-1904378733.png [2]: http://images2015.cnblogs.com/blog/287060/201603/287060-20160307103011335-1351277383.png [3]: http://images2015.cnblogs.com/blog/287060/201603/287060-20160307103012491-565994533.png [4]: http://images2015.cnblogs.com/blog/287060/201603/287060-20160307103014975-1772613163.png [5]: http://images2015.cnblogs.com/blog/287060/201603/287060-20160307103019960-1840843224.png [6]: http://images2015.cnblogs.com/blog/287060/201603/287060-20160307103025741-1801716572.png ","permalink":"https://blog.zdltech.com/posts/%E7%94%9F%E6%88%90kindle%E5%8F%AF%E8%AF%BB%E7%9A%84mobi%E5%92%8Cpdf%E7%94%B5%E5%AD%90%E4%B9%A6/","summary":"\u003cp\u003e购买kindle之后，自然欣喜万分，不来自于工具本身，而来自于发现自己能够静下心来阅读长篇和复杂的文字了，可喜可贺。更重要的是，kindle减轻了我眼睛的莫大的压力。但马上就出现几个问题：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e不是所有的电子书都有kindle，最常见的是扫描PDF\u003c/li\u003e\n\u003cli\u003e大量的论文无法阅读,这和上面的问题一致\u003c/li\u003e\n\u003cli\u003e网络上很多精彩的博客，新闻，都是没法阅读的\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e可能有人说，用手机看不就得了？用手机看花边娱乐新闻当然很好，可是当看数学推导时，推送栏上面妹子发来的消息，会直接把你的思路全部打乱。没用过kindle的人，是有些难以体会那种接近于纸张的质感的。OK，既然是程序员，我们就尝试解决这些问题。\u003c/p\u003e\n\u003ch2 id=\"有关kindlegen和html\"\u003e有关kindlegen和HTML\u003c/h2\u003e\n\u003cp\u003ekindlegen是亚马逊官方出品的一个电子书生成工具。但它明显就没打算让普通用户使用，命令行界面，几乎没有任何像样的文档。只是在实例样例里给了几个生成电子书的文件。我就因为没有文档兜了大弯，翻遍国外各大网站，才慢慢摸清kindlegen的使用细节。\u003cbr\u003e\n可以这么理解,KG是将一组HTML和相关文件，打包成mobi文件的工具。\u003c/p\u003e\n\u003cp\u003e最简单的例子，随意编写一个HTML文件，送给KG，会生成对应的mobi。基本有title,h1,h2,正文，kindle渲染就差不多了。如果需要修改样式，可以提供CSS文件。\u003cbr\u003e\n但是，这样的做法，没有图片，没有超链接，无法提供目录，如果输入单一的大型HTML文件，kindle的渲染性能就不足了。\u003c/p\u003e\n\u003cp\u003e因此，需要生成层级化，多文件形式的html文件夹，然而kg并不能直接识别html文件夹，还是需要一些元数据描述。\u003c/p\u003e\n\u003ch2 id=\"编写元数据文件\"\u003e编写元数据文件\u003c/h2\u003e\n\u003cp\u003e要想解决这个问题，就需要编写两个文件,opf和ncx, 他们可以理解为KG的makefile, KG通过这两个文件索引HTML，目录和其他多媒体资源。介绍如下：\u003c/p\u003e\n\u003cp\u003e[\u003cimg alt=\"image\" loading=\"lazy\" src=\"https://images2015.cnblogs.com/blog/287060/201603/287060-20160307103010788-489336141.png\"\u003e][1]\u003c/p\u003e\n\u003cp\u003e值得注意的是，所有的文件都应该保存在本地，尤其是jpg, html中的图片超链接，需要重定向到本地的jpg文件，如果依然在服务器上，据我所知，kg是不负责渲染下载的。\u003c/p\u003e\n\u003ch2 id=\"资源聚合文件-opf和ncx\"\u003e资源聚合文件: opf和ncx\u003c/h2\u003e\n\u003cp\u003e由于opf文件非常重要，我们下面就讲解opf的格式：\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](https://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n    \u003cdiv class=\"alert-info\"\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-go\" data-lang=\"go\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;metadata xmlns:dc=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;http:\u003cspan style=\"color:#6272a4\"\u003e//purl.org/dc/elements/1.1/\u0026amp;quot; xmlns:opf=\u0026amp;quot;http://www.idpf.org/2007/opf\u0026amp;quot;\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;dc:title\u0026gt;电子书标题\u0026lt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edc:title\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;dc:language\u0026gt;en\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eus\u0026lt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edc:language\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003emetadata\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;manifest\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \u0026lt;!\u003cspan style=\"color:#ff79c6\"\u003e--\u003c/span\u003e table of contents [mandatory] \u003cspan style=\"color:#ff79c6\"\u003e--\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;item id=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;tochtml\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; media\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etype\u003c/span\u003e=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;application\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003exhtml\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003exml\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; href=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;toc.html\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;item id=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;item0\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; media\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etype\u003c/span\u003e=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;application\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003exhtml\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003exml\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; href=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;Artical\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1277621753.\u003c/span\u003ehtml\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;!\u003cspan style=\"color:#ff79c6\"\u003e--\u003c/span\u003e下面是图片\u003cspan style=\"color:#ff79c6\"\u003e--\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \u0026lt;item id=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;\u003cspan style=\"color:#bd93f9\"\u003e0.368541311142\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; media\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etype\u003c/span\u003e=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;image\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ejpg\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; href=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;Images\u003cspan style=\"color:#ff79c6\"\u003e/-\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1720404282.\u003c/span\u003ejpg\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003emanifest\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;spine toc=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;desertfire\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;!\u003cspan style=\"color:#ff79c6\"\u003e--\u003c/span\u003e 下面描述了KG生成电子书后文本的顺序 \u003cspan style=\"color:#ff79c6\"\u003e--\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;itemref idref=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;toc\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u0026gt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;itemref idref=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;tochtml\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u0026gt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;itemref idref=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;item31\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espine\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;guide\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;reference \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etype\u003c/span\u003e=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;toc\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; title=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;Table of Contents\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; href=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;toc.html\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;\u0026gt;\u0026lt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ereference\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;reference \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etype\u003c/span\u003e=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;text\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; title=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;Welcome\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; href=\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;toc.html\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot;\u0026gt;\u0026lt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ereference\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eguide\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003epackage\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003e#\u003cspan style=\"color:#bd93f9\"\u003e96\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003e#\u003cspan style=\"color:#bd93f9\"\u003e96\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003e#\u003cspan style=\"color:#bd93f9\"\u003e96\u003c/span\u003e;\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-snippet-id=\u0026#34;\u003c/span\u003eext.b091e89925c72be7b07f9caa16092df4\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-snippet-saved=\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-codota-status=\u0026#34;\u003c/span\u003edone\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026amp;lt;package xmlns=\u0026#34;\u003c/span\u003ehttp:\u003cspan style=\"color:#6272a4\"\u003e//www.idpf.org/2007/opf\u0026#34; version=\u0026#34;2.0\u0026#34; unique-identifier=\u0026#34;BookId\u0026#34;\u0026amp;gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;metadata xmlns:dc=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://purl.org/dc/elements/1.1/\u0026#34;\u003c/span\u003e xmlns:opf=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://www.idpf.org/2007/opf\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;dc:title\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;电子书标题\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edc:title\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;dc:language\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;en\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eus\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edc:language\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003emetadata\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;manifest\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;!\u003cspan style=\"color:#ff79c6\"\u003e--\u003c/span\u003e table of contents [mandatory] \u003cspan style=\"color:#ff79c6\"\u003e--\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;item id=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;tochtml\u0026#34;\u003c/span\u003e media\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etype\u003c/span\u003e=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;application/xhtml+xml\u0026#34;\u003c/span\u003e href=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;toc.html\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;item id=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;item0\u0026#34;\u003c/span\u003e media\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etype\u003c/span\u003e=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;application/xhtml+xml\u0026#34;\u003c/span\u003e href=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Artical-1277621753.html\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;!\u003cspan style=\"color:#ff79c6\"\u003e--\u003c/span\u003e下面是图片\u003cspan style=\"color:#ff79c6\"\u003e--\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;item id=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;0.368541311142\u0026#34;\u003c/span\u003e media\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etype\u003c/span\u003e=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;image/jpg\u0026#34;\u003c/span\u003e href=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Images/-1720404282.jpg\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003emanifest\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;spine toc=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;desertfire\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;!\u003cspan style=\"color:#ff79c6\"\u003e--\u003c/span\u003e 下面描述了KG生成电子书后文本的顺序 \u003cspan style=\"color:#ff79c6\"\u003e--\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;itemref idref=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;toc\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;itemref idref=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;tochtml\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;itemref idref=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;item31\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espine\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;guide\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;reference \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etype\u003c/span\u003e=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;toc\u0026#34;\u003c/span\u003e title=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Table of Contents\u0026#34;\u003c/span\u003e href=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;toc.html\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ereference\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;reference \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003etype\u003c/span\u003e=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;text\u0026#34;\u003c/span\u003e title=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Welcome\u0026#34;\u003c/span\u003e href=\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;toc.html\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ereference\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eguide\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003epackage\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003ediv \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cnblogs_code_toolbar\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cnblogs_code_copy\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003ea title\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;复制代码\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;!\u003c/span\u003e[复制代码](https:\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003ecommon\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecnblogs\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecom\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eimages\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ecopycode\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egif)\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ea\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ediv\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ediv\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003e[image](https:\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003eimages2015\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecnblogs\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecom\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eblog\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e287060\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e201603\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e287060\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e20160307103012038\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1762823801.\u003c/span\u003epng)][\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e需要注意的有以下几点：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 所有资源都需要一个id,命名任意，但不能重复\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e media\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003etype描述了资源的类型，记住两类基本就够用了，\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003e\u003cspan style=\"color:#6272a4\"\u003e#8221;application/xhtml+xml\u0026amp;#8221;代表HTML文件，\u0026amp;#8221;image/jpg\u0026amp;#8221;或 \u0026amp;#8220;image/png\u0026amp;#8221;代表图片。\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 其他都可以省略，只是会影响电子书完整性。  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    由于这两个文件内部其实都是html,所以修改编辑都很容易。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e**\u003c/span\u003e最终，KG的命令行目标，不是目录HTML,而是OPF文件！\u003cspan style=\"color:#ff79c6\"\u003e**\u003c/span\u003e将所有的文件放入一个文件夹后，启动KG命令行，最后KG会在该目录下生成你心仪已久的mobi\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e## 编辑HTML和OPF文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e知道其原理后，主要的任务是填充HTML和OPF文件，几页内容还好，如果内容繁多，不论是手工\u003cspan style=\"color:#ff79c6\"\u003e**\u003c/span\u003e( ⊙ o ⊙ )\u003cspan style=\"color:#ff79c6\"\u003e**\u003c/span\u003e,还是编程字符串拼接，都会变得异常低效。  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e此时，就需要\u003cspan style=\"color:#ff79c6\"\u003e**\u003c/span\u003e模板引擎\u003cspan style=\"color:#ff79c6\"\u003e**\u003c/span\u003e出手了，python推荐使用Jinja2, 资料众多，功能强大，性能尚可。生成opf的模板文件，基本就长下面这个样子：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003ediv \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cnblogs_code\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003ediv \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cnblogs_code_toolbar\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cnblogs_code_copy\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003ea title\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;复制代码\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;!\u003c/span\u003e[复制代码](https:\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003ecommon\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecnblogs\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecom\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eimages\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ecopycode\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egif)\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ea\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ediv\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003ediv \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;top-box hide\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003ediv \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;alert-info\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ediv\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ediv\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cmetadata xmlns:dc=\u0026quot;http://purl.org/dc/elements/1.1/\u0026quot; xmlns:opf=\u0026quot;http://www.idpf.org/2007/opf\u0026quot;\u003e\n\u003cdc:title\u003e{{ title }}\u003c/dc:title\u003e\n\u003cdc:language\u003een-us\u003c/dc:language\u003e\n\u003c/metadata\u003e\n\u003cmanifest\u003e\n      \u003c!-- table of contents [mandatory] --\u003e\n    \u003citem id=\u0026quot;toc\u0026quot; media-type=\u0026quot;application/x-dtbncx+xml\u0026quot; href=\u0026quot;toc.ncx\u0026quot;/\u003e\n    \u003citem id=\u0026quot;tochtml\u0026quot; media-type=\u0026quot;application/xhtml+xml\u0026quot; href=\u0026quot;toc.html\u0026quot;/\u003e\n{% for item in navigation %}\n    \u003citem id=\u0026quot;{{ item.id }}\u0026quot; media-type=\u0026quot;application/xhtml+xml\u0026quot; href=\u0026quot;{{ item.href }}\u0026quot;/\u003e\n{% endfor %}\n {% for item in media %}\n   \u003citem id=\u0026quot;{{ item.id }}\u0026quot; media-type=\u0026quot;image/{{ item.format}}\u0026quot; href=\u0026quot;{{ item.href}}\u0026quot;/\u003e\n{% endfor %}\n\u003c/manifest\u003e\n\u003cspine toc=\u0026quot;{{ title }}\u0026quot;\u003e\n  \u003c!-- the spine defines the linear reading order of the book --\u003e\n    \u003citemref idref=\u0026quot;toc\u0026quot;/\u003e  \n    \u003citemref idref=\u0026quot;tochtml\u0026quot;/\u003e  \n  {% for item in navigation %}\n    \u003citemref idref=\u0026quot;{{ item.id }}\u0026quot;/\u003e\n  {% endfor %}\n\u003c/spine\u003e\n\u003cguide\u003e\n    \u003creference type=\u0026quot;toc\u0026quot; title=\u0026quot;Table of Contents\u0026quot; href=\u0026quot;toc.html\u0026quot;\u003e\u003c/reference\u003e\n    \u003creference type=\u0026quot;text\u0026quot; title=\u0026quot;Welcome\u0026quot; href=\u0026quot;toc.html\u0026quot;\u003e\u003c/reference\u003e\n\u003c/guide\u003e\n\u003c/package\u003e\" data-snippet-id=\"ext.1564f86c79babcc6b8778ebad334ce3f\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003e\u0026lt;package xmlns=\"http://www.idpf.org/2007/opf\" version=\"2.0\" unique-identifier=\"BookId\"\u0026gt;\n\u0026lt;metadata xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:opf=\"http://www.idpf.org/2007/opf\"\u0026gt;\n\u0026lt;dc:title\u0026gt;{{ title }}\u0026lt;/dc:title\u0026gt;\n\u0026lt;dc:language\u0026gt;en-us\u0026lt;/dc:language\u0026gt;\n\u0026lt;/metadata\u0026gt;\n\u0026lt;manifest\u0026gt;\n      \u0026lt;!-- table of contents [mandatory] --\u0026gt;\n    \u0026lt;item id=\"toc\" media-type=\"application/x-dtbncx+xml\" href=\"toc.ncx\"/\u0026gt;\n    \u0026lt;item id=\"tochtml\" media-type=\"application/xhtml+xml\" href=\"toc.html\"/\u0026gt;\n{% for item in navigation %}\n    \u0026lt;item id=\"{{ item.id }}\" media-type=\"application/xhtml+xml\" href=\"{{ item.href }}\"/\u0026gt;\n{% endfor %}\n {% for item in media %}\n   \u0026lt;item id=\"{{ item.id }}\" media-type=\"image/{{ item.format}}\" href=\"{{ item.href}}\"/\u0026gt;\n{% endfor %}\n\u003cp\u003e\u0026lt;/manifest\u0026gt;\n\u0026lt;spine toc=\u0026quot;{{ title }}\u0026quot;\u0026gt;\n\u0026lt;!\u0026ndash; the spine defines the linear reading order of the book \u0026ndash;\u0026gt;\n\u0026lt;itemref idref=\u0026ldquo;toc\u0026rdquo;/\u0026gt;\u003cbr\u003e\n\u0026lt;itemref idref=\u0026ldquo;tochtml\u0026rdquo;/\u0026gt;\u003cbr\u003e\n{% for item in navigation %}\n\u0026lt;itemref idref=\u0026quot;{{ item.id }}\u0026quot;/\u0026gt;\n{% endfor %}\n\u0026lt;/spine\u0026gt;\n\u0026lt;guide\u0026gt;\n\u0026lt;reference type=\u0026ldquo;toc\u0026rdquo; title=\u0026ldquo;Table of Contents\u0026rdquo; href=\u0026ldquo;toc.html\u0026rdquo;\u0026gt;\u0026lt;/reference\u0026gt;\n\u0026lt;reference type=\u0026ldquo;text\u0026rdquo; title=\u0026ldquo;Welcome\u0026rdquo; href=\u0026ldquo;toc.html\u0026rdquo;\u0026gt;\u0026lt;/reference\u0026gt;\n\u0026lt;/guide\u0026gt;\n\u0026lt;/package\u0026gt;\u003c/p\u003e","title":"生成Kindle可读的mobi和PDF电子书"},{"content":"一、创建podspec索引仓库，创建源文件仓库\n在自己私有git分别创建上述两个仓库，如果有则不用创建\n二、将podspec索引仓库添加到本地pod repo\n在终端执行下述命令即可\npod repo add xxxSpecs 仓库地址\n注：** 1.**其中xxxSpecs为本地资源文件夹名称，建议与仓库名称一致\n2.仓库地址是自己在第一步创建的索引仓库地址\n三、克隆源文件仓库并编写项目源码\n四.在工程目录下创建podspec文件（注：需在同级目录下创建一个LICENSE文件）\n创建podspec文件\n1.移动到源文件工程目录 cd XXX/XXXX/XXXXX\n2.在该目录下执行创建podspec文件命令\npod spec create [name] 注：[name]就是项目名称\n3.在远程仓库的同级目录下创建LICENSE文件 注：使用MIT模板\n4.在本地仓库进行更新刚才在远程仓库创建的文件\n五、podspec文件每个字段的含义\nPod::Spec.new do |s|\ns.name = “xxx” 开源库的名称\ns.version = “0.0.17″ 开源库版本\ns.summary = “xxxx” 摘要\ns.description = \u0026laquo;-DESC 描述\n天利和工具类，里面具有时间，弹框，视图等处理方法\nDESC\ns.homepage = “http://xxxx/ios/xxxxProduct” 开源库首页\ns.license = “MIT” 开源库协议文件\n# s.license = { :type =\u0026gt; “MIT”, :file =\u0026gt; “FILE_LICENSE” } s.author = { “xx” =\u0026gt; “xx@qq.com” } 开源库作者\ns.platform = :ios, “9.0″ 开源库平台以及版本\ns.source = { :git =\u0026gt; “http://xxxx/ios/xxxxProduct.git”, :tag =\u0026gt; “#{s.version}” } 开源库源码地址\n# s.public_header_files = “Classes/**/*.h” 源码需要的头文件\ns.subspec ‘UtilityClass’ do |utilityClass| 定义一个子模块\nutilityClass.source_files = ‘xxxxClass/xxxxxClass/UtilityClass/*.{swift}’ 开源库(子模块)源文件\nend\ns.subspec ‘LoginMoudle’ do |loginMoudle|\nloginMoudle.source_files = ‘xxxxClass/xxxxClass/LoginMoudle/*.{swift}’\nloginMoudle.dependency ‘xxxxxClass/UtilityClass’ 需要依赖的第三方库\nloginMoudle.resource_bundles = {‘xxxxClass’ =\u0026gt; [“xxxxClass/xxxxClass/LoginMoudle/LoginMoudle.bundle”,”xxxxClass/xxxxClass/LoginMoudle/*.{storyboard}”]} 开源库(子模块)资源文件\nend\nend\n六、提交源文件，podpsec,并打上tag（该tag与podspec里面的版本一致）\n七、检验podspec是否合格\n1.移动到podspec所在目录 cd XXX/XXXX/XXXXX\n2.执行命令：pod spec lint [name].podspec —verbose\n3.出现下述字样就是合格\n八、发布podspec到私有仓库\n在第七步完成之后继续执行命令\npod repo push xxxSpecs xxxx.podspec\nxxxSpecs是第二步添加到本地的repo文件夹名称\n","permalink":"https://blog.zdltech.com/posts/pod%E7%A7%81%E6%9C%89%E5%BA%93%E5%88%B6%E4%BD%9C%E8%BF%87%E7%A8%8B/","summary":"\u003cp\u003e\u003cspan class=\"s1\"\u003e一、创建\u003c/span\u003e\u003cspan class=\"s2\"\u003epodspec\u003c/span\u003e\u003cspan class=\"s1\"\u003e索引仓库，创建源文件仓库\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e在自己私有\u003c/span\u003e\u003cspan class=\"s2\"\u003egit\u003c/span\u003e\u003cspan class=\"s1\"\u003e分别创建上述两个仓库，如果有则不用创建\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e二、将\u003c/span\u003e\u003cspan class=\"s2\"\u003epodspec\u003c/span\u003e\u003cspan class=\"s1\"\u003e索引仓库添加到本地\u003c/span\u003e\u003cspan class=\"s2\"\u003epod repo\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e在终端执行下述命令即可\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003epod repo add xxxSpecs \u003c/span\u003e\u003cspan class=\"s1\"\u003e仓库地址\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s3\"\u003e\u003cstrong\u003e注：\u003c/strong\u003e\u003c/span\u003e\u003cspan class=\"s4\"\u003e** 1.**\u003c/span\u003e\u003cspan class=\"s3\"\u003e\u003cstrong\u003e其中\u003c/strong\u003e\u003c/span\u003e\u003cspan class=\"s4\"\u003e\u003cstrong\u003exxxSpecs\u003c/strong\u003e\u003c/span\u003e\u003cspan class=\"s3\"\u003e\u003cstrong\u003e为本地资源文件夹名称，建议与仓库名称一致\u003c/strong\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s4\"\u003e\u003cstrong\u003e2.\u003c/strong\u003e\u003c/span\u003e\u003cspan class=\"s3\"\u003e\u003cstrong\u003e仓库地址是自己在第一步创建的索引仓库地址\u003c/strong\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e三、克隆源文件仓库并编写项目源码\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e四.\u003c/span\u003e\u003cspan class=\"s2\"\u003e在工程目录下创建\u003c/span\u003e\u003cspan class=\"s1\"\u003epodspec\u003c/span\u003e\u003cspan class=\"s2\"\u003e文件（注：需在同级目录下创建一个\u003c/span\u003e\u003cspan class=\"s1\"\u003eLICENSE\u003c/span\u003e\u003cspan class=\"s2\"\u003e文件）\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e创建\u003c/span\u003e\u003cspan class=\"s2\"\u003epodspec\u003c/span\u003e\u003cspan class=\"s1\"\u003e文件\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e1.\u003c/span\u003e\u003cspan class=\"s1\"\u003e移动到源文件工程目录\u003c/span\u003e\u003cspan class=\"s2\"\u003e cd XXX/XXXX/XXXXX\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s3\"\u003e2.\u003c/span\u003e\u003cspan class=\"s2\"\u003e在该目录下执行创建\u003c/span\u003e\u003cspan class=\"s3\"\u003epodspec\u003c/span\u003e\u003cspan class=\"s2\"\u003e文件命令\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003epod spec create [name]\u003cspan class=\"Apple-converted-space\"\u003e    \u003c/span\u003e\u003c/span\u003e\u003cspan class=\"s1\"\u003e注：\u003c/span\u003e\u003cspan class=\"s4\"\u003e\u003cstrong\u003e[name]\u003c/strong\u003e\u003c/span\u003e\u003cspan class=\"s5\"\u003e\u003cstrong\u003e就是项目名称\u003c/strong\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s3\"\u003e3.\u003c/span\u003e\u003cspan class=\"s2\"\u003e在远程仓库的同级目录下创建\u003c/span\u003e\u003cspan class=\"s3\"\u003eLICENSE\u003c/span\u003e\u003cspan class=\"s2\"\u003e文件\u003c/span\u003e\u003cspan class=\"s3\"\u003e\u003cspan class=\"Apple-converted-space\"\u003e    \u003c/span\u003e\u003c/span\u003e\u003cspan class=\"s2\"\u003e注：\u003c/span\u003e\u003cspan class=\"s6\"\u003e\u003cstrong\u003e使用\u003c/strong\u003e\u003c/span\u003e\u003cspan class=\"s7\"\u003e\u003cstrong\u003eMIT\u003c/strong\u003e\u003c/span\u003e\u003cspan class=\"s6\"\u003e\u003cstrong\u003e模板\u003c/strong\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s3\"\u003e4.\u003c/span\u003e\u003cspan class=\"s2\"\u003e在本地仓库进行更新刚才在远程仓库创建的文件\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e五、\u003c/span\u003e\u003cspan class=\"s2\"\u003epodspec\u003c/span\u003e\u003cspan class=\"s1\"\u003e文件每个字段的含义\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003ePod::Spec.new do |s|\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e\u003cspan class=\"Apple-converted-space\"\u003e  \u003c/span\u003es.name \u003cspan class=\"Apple-converted-space\"\u003e        \u003c/span\u003e= “xxx”\u003cspan class=\"Apple-converted-space\"\u003e                   \u003c/span\u003e\u003c/span\u003e \u003cspan class=\"s4\"\u003e开源库的名称\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e\u003cspan class=\"Apple-converted-space\"\u003e  \u003c/span\u003es.version\u003cspan class=\"Apple-converted-space\"\u003e      \u003c/span\u003e= “0.0.17″\u003cspan class=\"Apple-converted-space\"\u003e                                      \u003c/span\u003e\u003c/span\u003e\u003cspan class=\"s5\"\u003e开源库版本\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e\u003cspan class=\"Apple-converted-space\"\u003e  \u003c/span\u003es.summary\u003cspan class=\"Apple-converted-space\"\u003e      \u003c/span\u003e= “\u003c/span\u003e\u003cspan class=\"s6\"\u003exxxx\u003c/span\u003e\u003cspan class=\"s1\"\u003e” \u003cspan class=\"Apple-converted-space\"\u003e                      \u003c/span\u003e\u003c/span\u003e\u003cspan class=\"s7\"\u003e摘要\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e\u003cspan class=\"Apple-converted-space\"\u003e  \u003c/span\u003es.description\u003cspan class=\"Apple-converted-space\"\u003e  \u003c/span\u003e= \u0026laquo;-DESC \u003cspan class=\"Apple-converted-space\"\u003e                               \u003c/span\u003e\u003c/span\u003e \u003cspan class=\"s9\"\u003e描述\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s10\"\u003e\u003cspan class=\"Apple-converted-space\"\u003e                    \u003c/span\u003e\u003c/span\u003e\u003cspan class=\"s1\"\u003e天利和工具类，里面具有时间，弹框，视图等处理方法\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e\u003cspan class=\"Apple-converted-space\"\u003e                   \u003c/span\u003eDESC\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e\u003cspan class=\"Apple-converted-space\"\u003e  \u003c/span\u003es.homepage \u003cspan class=\"Apple-converted-space\"\u003e    \u003c/span\u003e= “http://xxxx/ios/xxxxProduct”\u003cspan class=\"Apple-converted-space\"\u003e              \u003c/span\u003e\u003c/span\u003e\u003cspan class=\"s11\"\u003e开源库首页\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e\u003cspan class=\"Apple-converted-space\"\u003e  \u003c/span\u003es.license\u003cspan class=\"Apple-converted-space\"\u003e      \u003c/span\u003e= “MIT”\u003cspan class=\"Apple-converted-space\"\u003e                                            \u003c/span\u003e\u003c/span\u003e\u003cspan class=\"s12\"\u003e开源库协议文件\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e\u003cspan class=\"Apple-converted-space\"\u003e  \u003c/span\u003e# s.license\u003cspan class=\"Apple-converted-space\"\u003e      \u003c/span\u003e= { :type =\u0026gt; “MIT”, :file =\u0026gt; “FILE_LICENSE” } \u003cspan class=\"Apple-converted-space\"\u003e                     \u003c/span\u003e\u003c/span\u003e\u003c/p\u003e","title":"pod私有库制作过程"},{"content":" ### 1.无处不在的跳转 注：这里的快捷键是自己定义的，并非大家的都一样，可以通过findAction查找相应的快捷键。 菜单栏选择”帮助/help”→FindAction(ctrl+shift+A)快速搜索想要查找命令。 我这里只演示windows平台使用的快捷键(eclipse版本KeyMap)。\n1.1 项目窗口间的跳转 - 菜单栏选择window →Previous Project Window(ctrl+alt+左方括号) 1.2 文件之间的跳转 - 查看近期浏览文件 findaction(ctrl+shift+A) →输入recent files - Ctrl+E - 查看近期改动文件 recent changed files ⇔ ctrl+shift+e - 修改位置跳转 - 菜单栏\u0026amp;#8221;Navigate\u0026amp;#8221;→last edit location(ctrl+Q) - 反之 next edit location 可以自定义快捷键。 - 浏览位置跳转(光标停留位置) navigate →back(alt+向左箭头) 1.3 项目区与代码编辑区的相应跳转 - 项目区跳到右边代码编辑区 - 按ESC键 - 代码编辑区跳到左边项目区 - Alt+数字1 1.4 书签之间的跳转 - 利用书签跳转 - findaction→bookmarks→toggle bookmark(ctrl+shift+F11) - 带标记书签 bookmarks→toggle bookmarks with Mnemonic(ctrl+alt+shift+F11) - 标签间跳转 用ctrl+作标记的数字(这里有个坑我按小键盘数字没反应，得按大键盘的数字才行) 1.5 收藏夹 - 查看收藏夹 findaction→favorites(alt+2) - 可以看到我们的书签、收藏夹。 - 单独添加到收藏夹（自定义收藏夹） - findaction → add to favorites(Alt+shift+F) - 我们可以光标定位到某个函数、或是某个类添加到自定义的收藏夹中（add to new favorites list) 1.6 插件 - 调插件页面 findaction→输入plugins - 1.神器 emacsIdeas 安装 - browse repositories →emacIdeas→install→restart idea(重启Idea) - 配置emacsIdeas快捷键 settings/keymap/emacIdeas文件夹下AceJumpWord添加对应的快捷键。 - 按下刚配置的快捷键比如我这里shift+alt+K →按下要找的数字→输入任意高亮位置就跳转到对应位置了。 1.7 编辑区分屏 - 垂直分屏 - IntelliJ IDEA 支持对代码进行垂直或是水平分组，在打开的文件Tab上打开鼠标右键菜单，选择对应的split vertically功能即可 - 水平分屏 - 设为split horizontally即可。 1.8 代码格式化★ - 部分代码格式化 - 选中要格式化代码 ctrl+shift+F - 全部 - 直接ctrl+shift+F 2.高速定位代码 2.1 精准搜索 - 类 - 菜单栏 →Navigate →Class(Ctrl+shift+T) 其中include none..勾上就可以关联到Jar包里所依赖的类。 - 文件 - 菜单栏 navigate →file(ctrl+shift+r) - 符号 - 菜单栏 navigate →symbol(ctrl+alt+shift+n) - 字符串 - 菜单栏 edit→find→find in path(ctrl+H) 3.代码小助手 3.1 列操作 - 移动到当前单词尾部 - findaction →输入move caret to next word(ctrl+向右箭头) - 选中到当前单词尾部 （ctrl+shift+向右箭头） - 当前单词设置大小写切换 - edit→toggle case(ctrl+shift+u) - 移动到当前行首 - findaction→输入move caret to line start(Home键) - 移动到当前行尾 - findaction→输入move caret to line end(End键) - 将当前行的操作应用到相似行进行批量操作★ - 菜单栏edit→find→select all occurrences(ctrl+alt+Y) - 格式化下代码 - 菜单栏code→reformat code 3.2 live Template★ - main - findaction→输入live templates→点击右上角“+” - 输入缩写main 简介public static void main - 输入方法体 \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;main\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(String[] args)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;END\u0026amp;lt;/span\u0026gt; }\n- 点击define→勾选java - 输入main敲下回车即可。 - psfi - 输入最终模板(右边var1、var2确保输入一个参数回车后跳到另一参数输入) ``` `\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;var1\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;var2\u0026amp;lt;/span\u0026gt;; ` - 点击define→勾选java - psfs - 输入最终模板(右边var1、var2确保输入一个参数回车后跳到另一参数输入) ``` \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;final\u0026amp;lt;/span\u0026gt; String \u0026amp;lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;var1\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;\u0026amp;lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;var2\u0026amp;lt;/span\u0026gt;\u0026quot;\u0026amp;lt;/span\u0026gt;; - 点击define→勾选java - pic - 输入模板 pic(private int 带有注释) \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` ` \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;var1\u0026amp;lt;/span\u0026gt; **/\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;var2\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;End\u0026amp;lt;/span\u0026gt; ` - 点击define→勾选java - pi、ps（private int ..和private String..)设置同上，略。 3.3 postfix★ - 使用此功能（神器,输入一些东西加上\u0026amp;#8221;.\u0026amp;#8221;后自动转换成想要的模板） - findaction→postfix completion→勾选enable postfix completion. - 找到java→fori可以查看实现原理(下面仅列出几种常用的)。 - for循环(fori) - 打印(sout) - field - 构造方法中.field会自动补充不存在的字段(详见wqjavase项目idea包下的B.java)。 - return - nn(判断是否为空) 3.4 alt+enter智能提示 - 快捷键 - findaction→show intention actions(alt+anter) - list replace - 字符串format或者build - 实现接口 - 新建接口→UserService→光标定位到接口名称→按下alt+anter - 选择implement interface→输入实现类名称+选择创建位置 - 选择实现接口中的方法即可生成。 - 单词拼写 - 如果单词不记得如何拼写可以选中再按下alt+anter选择type change to它提示的英文单词进行矫正。 - 导包 ★ - 通过提示手动导包 - 按下alt+anter即可(我喜欢这种) - 自动导包 - Settings→Editor→general→勾上auto import Optimize\u0026amp;#8230; 4.编写高质量代码 4.1 重构 - 重构变量 - 选中要重构的变量→菜单栏选择refactor→rename(alt+shift+r) - 重构方法 - 选择要重构的方法名→菜单栏选择refactor→change signature→输入相关参数配置即可。 - 另一种通过alt anter - 直接在调用时输入要添加的参数→alt+anter→add 相应参数至方法即可。 - 抽取 - 抽取变量 - 选中字符串中的变量→refactor→extract→variable(alt+shift+L); - 抽取静态变量 - 选中字符串中变量→refactor→extract→Constant(ctrl+alt+c) - 抽取方法参数 - 如果方法中有用到成员变量（如this.name)→refactor→extract→parameter(alt+ctrl+p)就可以将成员变量以入参的形式传进来。 - 抽取函数 - 将方法中的逻辑抽取为一个函数。refactor→extract→Method（shift+alt+m) 5.寻找修改轨迹 5.1 git集成 - annotate - 找出某行代码作者是谁 - 在代码行左侧右击annotate - 移动所有改动之处 - findaction→previous changes(ctrl+alt+shift+向上箭头) - 撤销操作 - findaction→revert(ctrl+z) 5.2 local history★ - 显示本地修改历史记录 - findaction→local history→show history - 点击箭头可撤销。 - put label(类似commit提交注释的功能) 6.关联一切 6.1 与Spring的关联 - [视频学习链接](https://link.jianshu.com?t=https%3A%2F%2Fwww.imooc.com%2Fvideo%2F16226) - 操作流程 - file→project structure→facets→点击“+”→Spring到项目→点左下角加号→再勾上Spring配置文件即可（可以看到Springbean被哪里定义等信息）。 6.2 与数据库的关联 - 数据库连接 - view→tool windows→database - 按“+”→datasource→mysql→输入数据库名；用户名、密码测试连接出现Suqcessful即可。 - 关联sqlmap我就略过了。 7.调试程序 7.1 断点调试 - 打断点 - run→toggle line breakpoint(ctrl+shift+B) - 运行Debug模式 - run→debug\u0026amp;#8230;(alt+shift+F9)或者按小虫子 - 按步运行 - step over(F6) - 跳过断点 - resume program(f8) - 查看所有断点 - run→view breakpoints(ctrl+shift+F8) - 禁止所有断点 - debug窗口中左侧找到禁止标志（mute breakpoints)→F8跳过所有断点 - 条件断点 - 在断点上右击出现 condition 输入条件(如s.equals(\u0026amp;#8220;wuqingvika\u0026amp;#8221;)) - 表达式求值 - 查看值★ - run→evaluate expression - 运行到指定行 - 在Debug窗口找到有个光标图标 run to cursor(ctrl+R) - setValue★ - 在debug中只要选中要设置的变量按下F2设定想要设定的值即可。 7.2 任一处运行 - 运行当前上下文 - findaction→debug context 就会运行光标就近处的方法 - 注：如果光标在中间 那么两个都会运行 - 在当前可运行列表中选择一个运行 - alt+shift+F9 - 编辑当前运行 - run→edit configurations→application→选择某个应用程序→在program arguments输入参数信息 8.其他操作 8.1 文本操作 - 复制文件名 - 直接点击文件名 Ctrl+c在文本编辑区ctrl+v即可。 - 复制文件全名 - shift+ctrl+c 再ctrl+v即可。 - 复制多个文件名 - 多次ctrl+c 再shift+ctrl+v选择要复制哪些文件名即可。 - 结构图 - 查看当前field、method大纲 - navigate→File Structure(ctrl+F3) - 查看maven依赖★ - pom.xml→右击Maven→show dependencies可以看到所有的依赖关系。 - 可以按Ctrl+f进行搜索 - 可以右击exclude进行排除 - 查看类图★ - 普通的子类名右击Diagrams→Show diagram即可出现类图。 - 查看类继承结构★ - findaction→hierarchy actions→hierarchy(alt+8) - 方法调用层次★ - findaction→call hierarchy(ctrl+alt+H) ","permalink":"https://blog.zdltech.com/posts/idea%E5%B7%A5%E5%85%B7%E5%B8%B8%E7%94%A8%E6%8A%80%E5%B7%A7%E6%80%BB%E7%BB%93/","summary":"\u003cdiv\u003e\n  ### 1.无处不在的跳转\n  \u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003e  注：这里的快捷键是自己定义的，并非大家的都一样，可以通过findAction查找相应的快捷键。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e菜单栏选择”帮助/help”→FindAction(ctrl+shift+A)快速搜索想要查找命令。\n我这里只演示windows平台使用的快捷键(eclipse版本KeyMap)。\u003c/p\u003e\n  \u003c/blockquote\u003e\n\u003ch4 id=\"11-项目窗口间的跳转\"\u003e1.1 项目窗口间的跳转\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- 菜单栏选择window →Previous Project Window(ctrl+alt+左方括号)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4 id=\"12-文件之间的跳转\"\u003e1.2 文件之间的跳转\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- 查看近期浏览文件 findaction(ctrl+shift+A) →输入recent files \n    - Ctrl+E\n    \n  \n\n\n- 查看近期改动文件 recent changed files ⇔ ctrl+shift+e\n\n- 修改位置跳转 \n    - 菜单栏\u0026amp;#8221;Navigate\u0026amp;#8221;→last edit location(ctrl+Q)\n    \n    - 反之 next edit location 可以自定义快捷键。\n    \n  \n\n\n- 浏览位置跳转(光标停留位置) navigate →back(alt+向左箭头)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4 id=\"13-项目区与代码编辑区的相应跳转\"\u003e1.3 项目区与代码编辑区的相应跳转\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- 项目区跳到右边代码编辑区 \n    - 按ESC键\n    \n  \n\n\n- 代码编辑区跳到左边项目区 \n    - Alt+数字1\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4 id=\"14-书签之间的跳转\"\u003e1.4 书签之间的跳转\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- 利用书签跳转 \n    - findaction→bookmarks→toggle bookmark(ctrl+shift+F11)\n    \n    - 带标记书签 bookmarks→toggle bookmarks with Mnemonic(ctrl+alt+shift+F11)\n    \n    - 标签间跳转 用ctrl+作标记的数字(这里有个坑我按小键盘数字没反应，得按大键盘的数字才行)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4 id=\"15-收藏夹\"\u003e1.5 收藏夹\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- 查看收藏夹 findaction→favorites(alt+2) \n    - 可以看到我们的书签、收藏夹。\n    \n    - 单独添加到收藏夹（自定义收藏夹） \n        - findaction → add to favorites(Alt+shift+F)\n        \n        - 我们可以光标定位到某个函数、或是某个类添加到自定义的收藏夹中（add to new favorites list)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4 id=\"16-插件\"\u003e1.6 插件\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- 调插件页面 findaction→输入plugins\n\n- 1.神器 emacsIdeas 安装 \n    - browse repositories →emacIdeas→install→restart idea(重启Idea)\n    \n    - 配置emacsIdeas快捷键 settings/keymap/emacIdeas文件夹下AceJumpWord添加对应的快捷键。 \n        - 按下刚配置的快捷键比如我这里shift+alt+K →按下要找的数字→输入任意高亮位置就跳转到对应位置了。\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4 id=\"17-编辑区分屏\"\u003e1.7 编辑区分屏\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- 垂直分屏 \n    - IntelliJ IDEA 支持对代码进行垂直或是水平分组，在打开的文件Tab上打开鼠标右键菜单，选择对应的split vertically功能即可\n    \n  \n\n\n- 水平分屏 \n    - 设为split horizontally即可。\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4 id=\"18-代码格式化\"\u003e1.8 代码格式化★\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- 部分代码格式化 \n    - 选中要格式化代码 ctrl+shift+F\n    \n  \n\n\n- 全部 \n    - 直接ctrl+shift+F\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3 id=\"2高速定位代码\"\u003e2.高速定位代码\u003c/h3\u003e\n\u003ch4 id=\"21-精准搜索\"\u003e2.1 精准搜索\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- 类 \n    - 菜单栏 →Navigate →Class(Ctrl+shift+T) 其中include none..勾上就可以关联到Jar包里所依赖的类。\n    \n  \n\n\n- 文件 \n    - 菜单栏 navigate →file(ctrl+shift+r)\n    \n  \n\n\n- 符号 \n    - 菜单栏 navigate →symbol(ctrl+alt+shift+n)\n    \n  \n\n\n- 字符串 \n    - 菜单栏 edit→find→find in path(ctrl+H)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3 id=\"3代码小助手\"\u003e3.代码小助手\u003c/h3\u003e\n\u003ch4 id=\"31-列操作\"\u003e3.1 列操作\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- 移动到当前单词尾部 \n    - findaction →输入move caret to next word(ctrl+向右箭头)\n    \n  \n\n\n- 选中到当前单词尾部 （ctrl+shift+向右箭头）\n\n- 当前单词设置大小写切换 \n    - edit→toggle case(ctrl+shift+u)\n    \n  \n\n\n- 移动到当前行首 \n    - findaction→输入move caret to line start(Home键)\n    \n  \n\n\n- 移动到当前行尾 \n    - findaction→输入move caret to line end(End键)\n    \n  \n\n\n- 将当前行的操作应用到相似行进行批量操作★ \n    - 菜单栏edit→find→select all occurrences(ctrl+alt+Y)\n    \n  \n\n\n- 格式化下代码 \n    - 菜单栏code→reformat code\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4 id=\"32-live-template\"\u003e3.2 live Template★\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- main \n    - findaction→输入live templates→点击右上角“+”\n    \n    - 输入缩写main 简介public static void main\n    \n    - 输入方法体 \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003e\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;main\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(String[] args)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;END\u0026amp;lt;/span\u0026gt; }\u003c/code\u003e\u003c/p\u003e","title":"Idea工具常用技巧总结"},{"content":"Filter 过滤器作为web.xml中重要的一部分，有着相当高的出场率，SpringBoot会默认注册几个Filter\nApplicationContextHeaderFilter\nCharacterEncodingFilter\n如果添加了Security依赖的话会加入SpringSecurityFilterChain\n如果加入Actuator依赖的话就会加入WebRequestTraceFilter\n实现自己的Filter JavaConfig注册Bean 我们如果自己要实现自己的Filter的话，需要实现Filter并实现其中的方法\n同时要利用JavaConfig的方法来配置，一般情况下需要编写@Bean注解的返回值为FilterRegistrationBean的方法来实现JavaBean的注册\n具体实现如下\n需要注意的是此方法需要在被@Configuration注解的配置类中\n@WebFilter+@ServletComponentScan 如果觉得Java代码的方式比较繁琐的话可以采用注解方式注册Filter，具体实现方式是在Filter实现类加入@WebFilter注解\n例如\n然后在SpringBootApplication类上添加@ServletComponentScan\nFilter的注册原理 我们采用JavaConfig的形式实现了Filter的注册，通过向上追溯得知FilterRegistrationBean的层级结构如下\nServletContextInitializer\nRegistrationBean\nAbstractFilterRegistrationBean\nFilterRegistrationBean\n经查阅SpringBoot文档发现针对ServletContextInitializer的描述如下\nInterface used to configure a Servlet 3.0+ context programmatically. Unlike WebApplicationInitializer, classes that implement this interface (and do not implement WebApplicationInitializer) will not be detected by SpringServletContainerInitializer and hence will not be automatically bootstrapped by the Servlet container.\nThis interface is primarily designed to allow ServletContextInitializers to be managed by Spring and not the Servlet container.\nFor configuration examples see WebApplicationInitializer.\n既然是由SpringBoot进行管理而不是由Servlet容器管理，那么基本可以确定是由SpringBoot进行管理\n在org.springframework.boot.context.embedded.tomcat包中我们找到了答案\nTomcatEmbeddedServletContainerFactory的一直向上继承了AbstractConfigurableEmbeddedServletContainer\n并且维护了一个私有的List变量，我们不难猜出，正是因为FilterRegistrationBean继承了ServletContextInitializer而实现了Filter的注册\n为了进一步验证我们的猜测，在注册Filter的JavaConfig代码中打了断点跟踪一下\n可以看到在启动过程中会获取类型为ServletContextInitializer的Bean\n继续向下看在SpringBoot内嵌的Tomcat中的TomcatStarter类中也同样实现了ServletContextInitializer\n并且在实现方法中执行了AbstractFilterRegistrationBean实现的onStartup方法\n至此Filter注册成功\nServlet和Listener Servlet与Listener的支持与Filter大同小异，同样也是支持两种方法进行注册\nJavaConfig的话不同的是Servlet需要的是ServletRegistrationBean，而Listener需要的是ServletListenerRegistrationBean\n注解的话则分别是通过@WebServlet、@WebListener进行注解\n至于注册管理过程则基本与Filter相同\n参考：https://www.cnblogs.com/jpfss/p/9045916.html\n","permalink":"https://blog.zdltech.com/posts/springboot%E6%B6%88%E5%A4%B1%E7%9A%84web-xml/","summary":"\u003ch1 id=\"filter\"\u003eFilter\u003c/h1\u003e\n\u003cp\u003e过滤器作为web.xml中重要的一部分，有着相当高的出场率，SpringBoot会默认注册几个Filter\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eApplicationContextHeaderFilter\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eCharacterEncodingFilter\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e如果添加了Security依赖的话会加入\u003cstrong\u003eSpringSecurityFilterChain\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e如果加入Actuator依赖的话就会加入\u003cstrong\u003eWebRequestTraceFilter\u003c/strong\u003e\u003c/p\u003e\n\u003ch3 id=\"实现自己的filter\"\u003e\u003cstrong\u003e实现自己的Filter\u003c/strong\u003e\u003c/h3\u003e\n\u003ch4 id=\"javaconfig注册bean\"\u003eJavaConfig注册Bean\u003c/h4\u003e\n\u003cp\u003e我们如果自己要实现自己的Filter的话，需要实现Filter并实现其中的方法\u003c/p\u003e\n\u003cp\u003e同时要利用JavaConfig的方法来配置，一般情况下需要编写@Bean注解的返回值为FilterRegistrationBean的方法来实现JavaBean的注册\u003c/p\u003e\n\u003cp\u003e具体实现如下\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"confluence-embedded-file-wrapper\"\u003e\u003cimg loading=\"lazy\" src=\"http://wiki.vipkid.com.cn/download/attachments/8587168/image2017-3-2%2019%3A31%3A31.png?version=1\u0026modificationDate=1488454484000\u0026api=v2\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e需要注意的是此方法需要在被@Configuration注解的配置类中\u003c/p\u003e\n\u003ch4 id=\"webfilterservletcomponentscan\"\u003e@WebFilter+@ServletComponentScan\u003c/h4\u003e\n\u003cp\u003e如果觉得Java代码的方式比较繁琐的话可以采用注解方式注册Filter，具体实现方式是在Filter实现类加入@WebFilter注解\u003c/p\u003e\n\u003cp\u003e例如\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"confluence-embedded-file-wrapper\"\u003e\u003cimg loading=\"lazy\" src=\"http://wiki.vipkid.com.cn/download/attachments/8587168/image2017-3-3%2011%3A36%3A54.png?version=1\u0026modificationDate=1488512224000\u0026api=v2\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e然后在SpringBootApplication类上添加@ServletComponentScan\u003c/p\u003e\n\u003ch3 id=\"filter的注册原理\"\u003eFilter的注册原理\u003c/h3\u003e\n\u003cp\u003e我们采用JavaConfig的形式实现了Filter的注册，通过向上追溯得知FilterRegistrationBean的层级结构如下\u003c/p\u003e\n\u003cp\u003eServletContextInitializer\u003c/p\u003e\n\u003cp\u003eRegistrationBean\u003c/p\u003e\n\u003cp\u003eAbstractFilterRegistrationBean\u003c/p\u003e\n\u003cp\u003eFilterRegistrationBean\u003c/p\u003e\n\u003cp\u003e经查阅SpringBoot文档发现针对ServletContextInitializer的描述如下\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eInterface used to configure a Servlet 3.0+ \u003ca href=\"https://docs.oracle.com/javaee/7/api/javax/servlet/ServletContext.html?is-external=true\"\u003e\u003ccode\u003econtext\u003c/code\u003e\u003c/a\u003e programmatically. Unlike \u003ca href=\"http://docs.spring.io/spring-framework/docs/4.3.6.RELEASE/javadoc-api/org/springframework/web/WebApplicationInitializer.html?is-external=true\"\u003e\u003ccode\u003eWebApplicationInitializer\u003c/code\u003e\u003c/a\u003e, classes that implement this interface (and do not implement \u003ca href=\"http://docs.spring.io/spring-framework/docs/4.3.6.RELEASE/javadoc-api/org/springframework/web/WebApplicationInitializer.html?is-external=true\"\u003e\u003ccode\u003eWebApplicationInitializer\u003c/code\u003e\u003c/a\u003e) will \u003cstrong\u003enot\u003c/strong\u003e be detected by \u003ca href=\"http://docs.spring.io/spring-framework/docs/4.3.6.RELEASE/javadoc-api/org/springframework/web/SpringServletContainerInitializer.html?is-external=true\"\u003e\u003ccode\u003eSpringServletContainerInitializer\u003c/code\u003e\u003c/a\u003e and hence will not be automatically bootstrapped by the Servlet container.\u003c/p\u003e\n\u003cp\u003eThis interface is primarily designed to allow \u003ca href=\"http://docs.spring.io/spring-boot/docs/1.5.1.RELEASE/api/org/springframework/boot/web/servlet/ServletContextInitializer.html\"\u003e\u003ccode\u003eServletContextInitializer\u003c/code\u003e\u003c/a\u003es to be managed by Spring and not the Servlet container.\u003c/p\u003e","title":"SpringBoot消失的Web.xml"},{"content":"nginx配置\n设置代理 upstream ossproxy{\nserver zcpcimgs.oss-cn-beijing.aliyuncs.com;\n}\n配置代理 server {\nlisten 80;\nserver_name zc2019.com;\nlocation /data {\nproxy_pass http://ossproxy;\nproxy_redirect off;\nproxy_set_header Host zcpcimgs.oss-cn-beijing.aliyuncs.com;\nproxy_set_header X-Real-IP remote_addr; proxy_set_header X-Forwarded-Forproxy_add_x_forwarded_for;\nproxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;\nproxy_max_temp_file_size 0;\nproxy_connect_timeout 90;\nproxy_send_timeout 90;\nproxy_read_timeout 90;\nproxy_buffer_size 4k;\nproxy_buffers 4 32k;\nproxy_busy_buffers_size 64k;\nproxy_temp_file_write_size 64k;\n}\nlocation / {\n# root html;\n# index index.html index.htm;\nproxy_pass http://zcjfweb;\n# 真实信息\nproxy_set_header Host host; proxy_set_header X-Real-IPremote_addr;\nproxy_set_header X-Forwarded-For proxy_add_x_forwarded_for; client_max_body_size 100M; proxy_read_timeout 30000; proxy_send_timeout 75s; #proxy_redirect off; #proxy_pass_header Set-Cookie; #proxy_hide_header X-Powered-By; #proxy_hide_header X-Mod-Pagespeed; #proxy_ignore_client_abort off; #proxy_cache_valid any 10m; #proxy_connect_timeout 75s; #proxy_read_timeout 75s; #proxy_send_timeout 75s; }\n#error_page 404 /404.html;\nredirect server error pages to the static page /50x.html #error_page 500 502 503 504 /50x.html; #location = /50x.html {\nroot html; // proxy_pass https://www.baidu.com/; #}\nerror_page 500 502 503 504 /no_server.html; location = /no_server.html {\nroot html; proxy_pass http://127.0.0.1:88/; }\nproxy the PHP scripts to Apache listening on 127.0.0.1:80 #location ~ .php {\nproxy_pass http://127.0.0.1; #}\npass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 #location ~ .php{\nroot html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /scriptsfastcgi_script_name; include fastcgi_params; #}\ndeny access to .htaccess files, if Apache’s document root concurs with nginx’s one #location ~ /.ht {\ndeny all; #}\n}\n其他\nlocation ^~ /resource/images/oss { proxy_pass http://bucket名.oss-cn-shenzhen-internal.aliyuncs.com; }\n意思就是匹配到链接里有/resource/images/oss这样的后缀以后直接去相应的oss域名上请求资源\n#配置Nginx动静分离，定义的静态页面直接从Nginx发布目录读取。\nlocation ~ .*\\.(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ { root /usr/upload; # 你自己的静态地址 #expires定义用户浏览器缓存的时间为7天，如果静态页面不常更新，可以设置更长，这样可以节省带宽和缓解服务器的压力 expires 7d; } 更多Nginx配置参考： https://www.cnblogs.com/sign-ptk/p/6723048.html https://blog.csdn.net/qq_33862644/article/details/79337348 https://www.cnblogs.com/coder-yoyo/p/6346595.html https://www.cnblogs.com/onmyway20xx/p/3664302.html https://www.cnblogs.com/gpfeisoft/p/4823919.html ","permalink":"https://blog.zdltech.com/posts/%E9%98%BF%E9%87%8C%E4%BA%91oss%E4%B9%8Bnginx%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%E9%85%8D%E7%BD%AE/","summary":"\u003cp\u003enginx配置\u003c/p\u003e\n\u003ch3 id=\"设置代理\"\u003e\u003cstrong\u003e设置代理\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003eupstream ossproxy{\u003cbr\u003e\nserver zcpcimgs.oss-cn-beijing.aliyuncs.com;\u003cbr\u003e\n}\u003c/p\u003e\n\u003ch3 id=\"配置代理\"\u003e配置代理\u003c/h3\u003e\n\u003cp\u003eserver {\u003cbr\u003e\nlisten 80;\u003cbr\u003e\nserver_name zc2019.com;\u003c/p\u003e\n\u003cp\u003elocation /data {\u003cbr\u003e\nproxy_pass http://ossproxy;\u003cbr\u003e\nproxy_redirect off;\u003cbr\u003e\nproxy_set_header Host zcpcimgs.oss-cn-beijing.aliyuncs.com;\u003cbr\u003e\nproxy_set_header X-Real-IP \u003cspan class=\"katex math inline\"\u003eremote_addr;\nproxy_set_header X-Forwarded-For\u003c/span\u003eproxy_add_x_forwarded_for;\u003cbr\u003e\nproxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;\u003cbr\u003e\nproxy_max_temp_file_size 0;\u003cbr\u003e\nproxy_connect_timeout 90;\u003cbr\u003e\nproxy_send_timeout 90;\u003cbr\u003e\nproxy_read_timeout 90;\u003cbr\u003e\nproxy_buffer_size 4k;\u003cbr\u003e\nproxy_buffers 4 32k;\u003cbr\u003e\nproxy_busy_buffers_size 64k;\u003cbr\u003e\nproxy_temp_file_write_size 64k;\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003elocation / {\u003cbr\u003e\n# root html;\u003cbr\u003e\n# index index.html index.htm;\u003cbr\u003e\nproxy_pass http://zcjfweb;\u003cbr\u003e\n# 真实信息\u003cbr\u003e\nproxy_set_header Host \u003cspan class=\"katex math inline\"\u003ehost;\nproxy_set_header X-Real-IP\u003c/span\u003eremote_addr;\u003cbr\u003e\nproxy_set_header X-Forwarded-For \u003cspan class=\"katex math inline\"\u003eproxy_add_x_forwarded_for;\nclient_max_body_size 100M;\nproxy_read_timeout 30000;\nproxy_send_timeout 75s;\n#proxy_redirect off;\n#proxy_pass_header Set-Cookie;\n#proxy_hide_header X-Powered-By;\n#proxy_hide_header X-Mod-Pagespeed;\n#proxy_ignore_client_abort off;\n#proxy_cache_valid any 10m;\n#proxy_connect_timeout 75s;\n#proxy_read_timeout 75s;\n#proxy_send_timeout 75s;\n}\u003c/p\u003e","title":"阿里云OSS之Nginx反向代理配置"},{"content":"一、微信内分享 在微信内打开链接后，点右上角【…】选择【发送给朋友】或【分享到朋友圈】，这种分享方式获取缩略图的方法：\n方法一：在页面 body 最上方添加 300*300 像素的 img 如该图片不需要显示，可以用 css 隐藏，但不能直接对 img 设置 display: none;。\n可以在父层 div 上设置 display: none; 或者对 img 设置 position: absolute; visibility: hidden;。\n\u0026lt;img src=\u0026amp;quot;/img/thumbnail.png\u0026amp;quot; alt=\u0026amp;quot;\u0026amp;quot;\u0026gt;\u0026lt;/div\u0026gt; 1 \u0026#34; data-snippet-id=\u0026#34;ext.2607b3963245b14ba18790d96be6e596\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;div style=\u0026#34;display:none;\u0026#34;\u0026amp;gt;\u0026amp;lt;img src=\u0026#34;/img/thumbnail.png\u0026#34; alt=\u0026#34;\u0026#34;\u0026amp;gt;\u0026amp;lt;/div\u0026amp;gt;` 方法二：通过微信 JS-SDK 的分享接口 这种方法需要一个微信公众号的 app_id，同时需要一个后端服务生成 signature。好处是可以定制分享的标题、缩略图、描述。\n二、从浏览器分享 在浏览器打开链接后，点分享图标，选择【微信】，这种分享方式获取缩略图的方法：\n在页面的 head 部分添加 Open Graph Metadata：\n\u0026lt;meta property=\u0026amp;quot;og:title\u0026amp;quot; content=\u0026amp;quot;页面标题\u0026amp;quot;\u0026gt; \u0026lt;meta property=\u0026amp;quot;og:description\u0026amp;quot; content=\u0026amp;quot;页面描述\u0026amp;quot;\u0026gt; \u0026lt;meta property=\u0026amp;quot;og:image\u0026amp;quot; content=\u0026amp;quot;http://www.example.com/img/thumbnail.png\u0026amp;quot;\u0026gt; \u0026lt;meta property=\u0026amp;quot;og:url\u0026amp;quot; content=\u0026amp;quot;http://www.example.com/\u0026amp;quot;\u0026gt; 1 2 3 4 5 \u0026#34; data-snippet-id=\u0026#34;ext.d5f2b073507882789543238b1b2f0a2b\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;meta property=\u0026#34;og:type\u0026#34; content=\u0026#34;website\u0026#34; /\u0026amp;gt; \u0026amp;lt;meta property=\u0026#34;og:title\u0026#34; content=\u0026#34;页面标题\u0026#34;\u0026amp;gt; \u0026amp;lt;meta property=\u0026#34;og:description\u0026#34; content=\u0026#34;页面描述\u0026#34;\u0026amp;gt; \u0026amp;lt;meta property=\u0026#34;og:image\u0026#34; content=\u0026#34;http://www.example.com/img/thumbnail.png\u0026#34;\u0026amp;gt; \u0026amp;lt;meta property=\u0026#34;og:url\u0026#34; content=\u0026#34;http://www.example.com/\u0026#34;\u0026amp;gt;` 其中 og:image 影响浏览器分享时的图标，需要指定图片的完整路径。\nhttps://github.com/thedaviddias/Front-End-Checklist\nH5分享带缩略图，描述，微信内分享到好友，朋友圈等 准备工作\n需要一个认证的微信公众号，一定要确定认证\n在登录微信公众平台https://mp.weixin.qq.com\n在公众号设置–\u0026gt;功能设置，填写设置Js接口安全域名\nJs安全域名是需要把微信提供的文件，放在指定域名或者目录下面可以访问的。\n配置信息\n下载微信参考代码，主要是获取signature\nhttp://demo.open.weixin.qq.com/jssdk/sample.zip在获取signature之前，需要获取accessToken 和 对应的Ticket，这两个方式都比较简单，不在列举\n生成签名的方式，就在微信的实例代码里面，不在赘述。\n注意\n获取签名等信息，必须通过服务器返回，不能再前端js生成\n对应生成的ticket，accessToken，注意要缓存，也有有效期，如果不缓存，访问量大的情况下，微信有可能封号。\n生成signature所需要的url必须是前端传入的模式，不能写死，写死的话，微信似乎有检测机制，不能正常的分享成功。\n前端配置信息\n引入微信分享的JS_SDK https://res.wx.qq.com/open/js/jweixin-1.2.0.js\n注意，如果自己的域名模式是https模式，要使用https模式，不然会出现mixed content block，微信js不会执行\nJS-sdk中的方法要在获取signature之后再执行，不然有可能会执行错误等，同时分享的调用要在wx.ready方法体里面执行，即微信配置都okay的情况下在执行。\n示例代码\n$.get(“获取微信signature的接口”,\n{“url”:location.href.split(‘#’).toString()}).done(function (data) {\n// 注意这里的url，一定要这样写，也就是动态获取，不然也不会成功的。\nconsole.log(data);\nif (data.header.code == 200) {\nvar wx_info = data.body.result.wx_info;\nif (wx_info.signature != null) {\n// 配置\nwx.config({\ndebug: false, // 测试阶段，可以写为true，主要是为了测试是否配置成功\nappId: wx_info.appId,\ntimestamp: wx_info.timestamp,\nnonceStr: wx_info.nonceStr,\nsignature: wx_info.signature,\njsApiList: [‘checkJsApi’, ‘onMenuShareTimeline’, ‘onMenuShareAppMessage’, ‘onMenuShareQQ’,\n‘onMenuShareQZone’]\n});\nvar title = “”;\nvar desc = “”;\n// 分享的图片，最好是正方形，不是也没关系，但是一定是http模式，即绝对路径，而不是服务器路劲\nvar imgUrl = “”;\n// 这里的地址可以写死，也可以动态获取，但是一定不能带有微信分享后的参数，不然分享也是失败的\nvar link = “”;\n// 分享给朋友、QQ、微博\nvar shareData = {\n“imgUrl”: imgUrl,\n“title”: title,\n“desc”: desc,\n‘link’: link\n};\n// 分享到朋友圈\nvar shareToTimeline = {\n“imgUrl”: imgUrl,\n“title”: title,\n‘link’: link,\n“desc”: desc\n}\nwx.ready(function() {\nwx.onMenuShareTimeline(shareToTimeline);\nwx.onMenuShareAppMessage(shareData);\nwx.onMenuShareQQ(shareData);\nwx.onMenuShareQZone(shareData);\nwx.error(function(res) {\nalert(res.errMsg);\n});\n});\n}\n}\n}).fail(function (msg) {\nconsole.log(“error:” + msg);\n});\nhttps://blog.csdn.net/weixin_41829196/article/details/83383426\n","permalink":"https://blog.zdltech.com/posts/%E5%BE%AE%E4%BF%A1%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E7%9A%84%E7%BC%A9%E7%95%A5%E5%9B%BE%E5%92%8C%E6%A0%87%E9%A2%98/","summary":"\u003ch2 id=\"一微信内分享\"\u003e一、微信内分享\u003c/h2\u003e\n\u003chr\u003e\n\u003cp\u003e在微信内打开链接后，点右上角【…】选择【发送给朋友】或【分享到朋友圈】，这种分享方式获取缩略图的方法：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e方法一：在页面 body 最上方添加 300*300 像素的 img\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e如该图片不需要显示，可以用 css 隐藏，但不能直接对 img 设置 \u003ccode\u003edisplay: none;\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e可以在父层 div 上设置 \u003ccode\u003edisplay: none;\u003c/code\u003e 或者对 img 设置 \u003ccode\u003eposition: absolute; visibility: hidden;\u003c/code\u003e。\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n  \u003cdiv class=\"alert-info\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;img src=\u0026amp;quot;/img/thumbnail.png\u0026amp;quot; alt=\u0026amp;quot;\u0026amp;quot;\u0026gt;\u0026lt;/div\u0026gt; 1 \u0026#34; data-snippet-id=\u0026#34;ext.2607b3963245b14ba18790d96be6e596\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;div style=\u0026#34;display:none;\u0026#34;\u0026amp;gt;\u0026amp;lt;img src=\u0026#34;/img/thumbnail.png\u0026#34; alt=\u0026#34;\u0026#34;\u0026amp;gt;\u0026amp;lt;/div\u0026amp;gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e方法二：通过微信 JS-SDK 的分享接口\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这种方法需要一个微信公众号的 app_id，同时需要一个后端服务生成 signature。好处是可以定制分享的标题、缩略图、描述。\u003c/p\u003e\n\u003ch2 id=\"二从浏览器分享\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e\u003ca id=\"_19\" target=\"_blank\"\u003e\u003c/a\u003e二、从浏览器分享\u003c/h2\u003e\n\u003chr\u003e\n\u003cp\u003e在浏览器打开链接后，点分享图标，选择【微信】，这种分享方式获取缩略图的方法：\u003c/p\u003e\n\u003cp\u003e在页面的 head 部分添加 \u003ca href=\"http://ogp.me/\"\u003eOpen Graph Metadata\u003c/a\u003e：\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n  \u003cdiv class=\"alert-info\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u0026lt;meta property=\u0026amp;quot;og:title\u0026amp;quot; content=\u0026amp;quot;页面标题\u0026amp;quot;\u0026gt; \u0026lt;meta property=\u0026amp;quot;og:description\u0026amp;quot; content=\u0026amp;quot;页面描述\u0026amp;quot;\u0026gt; \u0026lt;meta property=\u0026amp;quot;og:image\u0026amp;quot; content=\u0026amp;quot;http://www.example.com/img/thumbnail.png\u0026amp;quot;\u0026gt; \u0026lt;meta property=\u0026amp;quot;og:url\u0026amp;quot; content=\u0026amp;quot;http://www.example.com/\u0026amp;quot;\u0026gt; 1 2 3 4 5 \u0026#34; data-snippet-id=\u0026#34;ext.d5f2b073507882789543238b1b2f0a2b\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;meta property=\u0026#34;og:type\u0026#34; content=\u0026#34;website\u0026#34; /\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;meta property=\u0026#34;og:title\u0026#34; content=\u0026#34;页面标题\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;meta property=\u0026#34;og:description\u0026#34; content=\u0026#34;页面描述\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;meta property=\u0026#34;og:image\u0026#34; content=\u0026#34;http://www.example.com/img/thumbnail.png\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;meta property=\u0026#34;og:url\u0026#34; content=\u0026#34;http://www.example.com/\u0026#34;\u0026amp;gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其中 og:image 影响浏览器分享时的图标，需要指定图片的完整路径。\u003c/p\u003e","title":"微信分享链接的缩略图和标题"},{"content":"方法一 监听界面元素 监听界面\n//–创建页面监听，等待微信端页面加载完毕 触发音频播放\ndocument.addEventListener(‘DOMContentLoaded’, function () {\nfunction audioAutoPlay() {\nvar audio = document.getElementById(‘audio’);\naudio.play();\ndocument.addEventListener(“WeixinJSBridgeReady”, function () {\naudio.play();\n}, false);\n}\naudioAutoPlay();\n});\n//–创建触摸监听，当浏览器打开页面时，触摸屏幕触发事件，进行音频播放\ndocument.addEventListener(‘touchstart’, function () {\nfunction audioAutoPlay() {\nvar audio = document.getElementById(‘audio’);\naudio.play();\n}\naudioAutoPlay();\n});\n// var firstTouch = true; $(\u0026ldquo;body\u0026rdquo;).bind(\u0026ldquo;touchstart\u0026rdquo;,function(e) { if ( firstTouch ) { firstTouch = false; document.getElementById(\u0026lsquo;audio\u0026rsquo;).play(); }else{ return; } }); // $(\u0026ldquo;body\u0026rdquo;).one(\u0026ldquo;touchstart\u0026rdquo;,function() { document.getElementById(\u0026lsquo;audio\u0026rsquo;).play(); });\n### \u0026lt;span class=\u0026#34;\u0026#34;\u0026gt;方法二微信提供\u0026lt;/span\u0026gt; \u0026gt; \u0026gt; \u0026lt;span class=\u0026#34;\u0026#34;\u0026gt;在微信中可以使用微信提供的解决方案\u0026lt;/span\u0026gt; \u0026gt; \u0026gt; \u0026gt; 引入js \u0026gt; \u0026gt; \u0026gt; \u0026lt;div class=\u0026#34;md-htmlblock md-rawblock md-end-block\u0026#34; spellcheck=\u0026#34;false\u0026#34;\u0026gt; \u0026gt; \u0026lt;div class=\u0026#34;md-htmlblock-container md-rawblock-container md-raw-html-src\u0026#34;\u0026gt; \u0026gt; \u0026lt;div class=\u0026#34;md-raw-html-src-content\u0026#34;\u0026gt; \u0026gt; \u0026lt;script src=\u0026amp;#8221;http://res.wx.qq.com/open/js/jweixin-1.0.0.js\u0026amp;#8221;\u0026gt;\u0026lt;/script\u0026gt; \u0026gt; \u0026lt;/div\u0026gt; \u0026gt; \u0026lt;/div\u0026gt; \u0026gt; \u0026lt;/div\u0026gt; \u0026gt; \u0026gt; \u0026lt;div class=\u0026#34;md-htmlblock md-rawblock md-end-block\u0026#34; spellcheck=\u0026#34;false\u0026#34;\u0026gt; \u0026gt; \u0026lt;div class=\u0026#34;md-htmlblock-container md-rawblock-container md-raw-html-src\u0026#34;\u0026gt; \u0026gt; \u0026lt;div class=\u0026#34;md-raw-html-src-content\u0026#34;\u0026gt; \u0026gt; \u0026lt;script\u0026gt; \u0026gt; \u0026lt;/div\u0026gt; \u0026gt; \u0026lt;/div\u0026gt; \u0026gt; \u0026lt;/div\u0026gt; \u0026gt; \u0026gt; \u0026gt; function autoPlayVideo(){ \u0026gt; \u0026gt; \u0026gt; \u0026gt; wx.config({ \u0026gt; \u0026gt; \u0026gt; \u0026gt; debug:false, \u0026gt; \u0026gt; \u0026gt; \u0026gt; appId:\u0026amp;#8221;\u0026amp;#8221;, \u0026gt; \u0026gt; \u0026gt; \u0026gt; timestamp:1, \u0026gt; \u0026gt; \u0026gt; \u0026gt; nonceStr:\u0026amp;#8221;\u0026amp;#8221;, \u0026gt; \u0026gt; \u0026gt; \u0026gt; signature:\u0026amp;#8221;\u0026amp;#8221;, \u0026gt; \u0026gt; \u0026gt; \u0026gt; jsApiList:[] \u0026gt; \u0026gt; \u0026gt; \u0026gt; }); \u0026gt; \u0026gt; \u0026gt; \u0026gt; wx.ready(function(){ \u0026gt; \u0026gt; \u0026gt; \u0026gt; var autoplayVideo=document.getElementById(\u0026amp;#8220;audio\u0026amp;#8221;); \u0026gt; \u0026gt; \u0026gt; \u0026gt; autoplayVideo.play() \u0026gt; \u0026gt; \u0026gt; \u0026gt; }) \u0026gt; \u0026gt; \u0026gt; \u0026gt; }; \u0026gt; \u0026gt; \u0026gt; \u0026gt; autoPlayVideo(); \u0026gt; \u0026gt; \u0026gt; \u0026gt; \u0026lt;span class=\u0026#34;md-tag md-raw-inline\u0026#34; spellcheck=\u0026#34;false\u0026#34;\u0026gt;\u0026lt;/script\u0026gt;\u0026lt;/span\u0026gt; \u0026gt; \u0026gt; \u0026gt; ``` \u0026lt;span role=\u0026#34;presentation\u0026#34;\u0026gt; //一般情况下，这样就可以自动播放了，但是一些奇葩iPhone机不可以\u0026lt;/span\u0026gt; \u0026lt;span role=\u0026#34;presentation\u0026#34;\u0026gt; document.getElementById(\u0026#39;car_audio\u0026#39;).play();\u0026lt;/span\u0026gt; \u0026lt;span role=\u0026#34;presentation\u0026#34;\u0026gt; //必须在微信Weixin JSAPI的WeixinJSBridgeReady才能生效\u0026lt;/span\u0026gt; \u0026lt;span role=\u0026#34;presentation\u0026#34;\u0026gt; document.addEventListener(\u0026#34;WeixinJSBridgeReady\u0026#34;, function () {\u0026lt;/span\u0026gt; \u0026lt;span role=\u0026#34;presentation\u0026#34;\u0026gt; document.getElementById(\u0026#39;audio\u0026#39;).play();\u0026lt;/span\u0026gt; \u0026lt;span role=\u0026#34;presentation\u0026#34;\u0026gt; document.getElementById(\u0026#39;video\u0026#39;).play();\u0026lt;/span\u0026gt; \u0026lt;span role=\u0026#34;presentation\u0026#34;\u0026gt; }, false);\u0026lt;/span\u0026gt; \u0026lt;span role=\u0026#34;presentation\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; 其他思路 原理就是通过new一张图片，监听一张图片的onload事件，结束后回调执行音频播放audio.play()即可，原理相当于执行了一次交互。\n\u0026lt;!DOCTYPE HTML\u0026gt; \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026ldquo;utf-8\u0026rdquo;\u0026gt; \u0026lt;title\u0026gt;img - load event\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;img id=\u0026ldquo;img1\u0026rdquo; src=\u0026ldquo;http://pic1.win4000.com/wallpaper/f/51c3bb99a21ea.jpg\u0026quot;\u0026gt; \u0026lt;p id=\u0026ldquo;p1\u0026rdquo;\u0026gt;loading\u0026hellip;\u0026lt;/p\u0026gt; \u0026lt;script type=\u0026ldquo;text/javascript\u0026rdquo;\u0026gt; img1.onload = function() { p1.innerHTML = \u0026rsquo;loaded\u0026rsquo; } \u0026lt;/script\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt;\n\u0026gt; \u0026gt; \u0026gt; 实现参考\u0026lt;span class=\u0026#34;md-link\u0026#34; spellcheck=\u0026#34;false\u0026#34;\u0026gt;[https://www.cnblogs.com/mq0036/p/6278498.html](https://www.cnblogs.com/mq0036/p/6278498.html)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;md-link\u0026#34; spellcheck=\u0026#34;false\u0026#34;\u0026gt;[https://www.cnblogs.com/snandy/p/3704938.html](https://www.cnblogs.com/snandy/p/3704938.html)\u0026lt;/span\u0026gt; \u0026gt; ### \u0026lt;span class=\u0026#34;\u0026#34;\u0026gt;其他参数\u0026lt;/span\u0026gt; \u0026gt; \u0026gt; \u0026lt;span class=\u0026#34;md-link\u0026#34; spellcheck=\u0026#34;false\u0026#34;\u0026gt;[https://www.cnblogs.com/yangwenzhi/p/7678188.html](https://www.cnblogs.com/yangwenzhi/p/7678188.html)\u0026lt;/span\u0026gt; \u0026gt; \u0026gt; \u0026gt; \u0026gt; \u0026lt;span class=\u0026#34;md-link md-expand\u0026#34; spellcheck=\u0026#34;false\u0026#34;\u0026gt;[https://www.cnblogs.com/xiongdahei/p/7144700.html](https://www.cnblogs.com/xiongdahei/p/7144700.html)\u0026lt;/span\u0026gt; \u0026gt; ","permalink":"https://blog.zdltech.com/posts/h5%E8%87%AA%E5%8A%A8%E6%92%AD%E6%94%BE%E9%9F%B3%E9%A2%91/","summary":"\u003ch3 id=\"方法一-监听界面元素\"\u003e\u003cspan class=\"md-expand\"\u003e方法一 监听界面元素\u003c/span\u003e\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cspan class=\"\"\u003e监听界面\u003c/span\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e//–创建页面监听，等待微信端页面加载完毕 触发音频播放\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003edocument.addEventListener(‘DOMContentLoaded’, function () {\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003efunction audioAutoPlay() {\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cspan class=\"\"\u003e var audio = document.getElementById(‘audio’);\u003c/span\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eaudio.play();\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003edocument.addEventListener(“WeixinJSBridgeReady”, function () {\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eaudio.play();\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e}, false);\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cspan class=\"md-expand\"\u003e }\u003c/span\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eaudioAutoPlay();\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e});\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e//–创建触摸监听，当浏览器打开页面时，触摸屏幕触发事件，进行音频播放\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003edocument.addEventListener(‘touchstart’, function () {\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003efunction audioAutoPlay() {\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003evar audio = document.getElementById(‘audio’);\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eaudio.play();\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e}\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eaudioAutoPlay();\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e});\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003cspan role=\"presentation\"\u003e//\u003c/span\u003e\n\u003cspan role=\"presentation\"\u003evar firstTouch = true;\u003c/span\u003e\n\u003cspan role=\"presentation\"\u003e$(\u0026ldquo;body\u0026rdquo;).bind(\u0026ldquo;touchstart\u0026rdquo;,function(e) {\u003c/span\u003e\n\u003cspan role=\"presentation\"\u003e    if ( firstTouch ) {\u003c/span\u003e\n\u003cspan role=\"presentation\"\u003e        firstTouch = false;\u003c/span\u003e\n\u003cspan role=\"presentation\"\u003e        document.getElementById(\u0026lsquo;audio\u0026rsquo;).play();\u003c/span\u003e\n\u003cspan role=\"presentation\"\u003e    }else{\u003c/span\u003e\n\u003cspan role=\"presentation\"\u003e        return;\u003c/span\u003e\n\u003cspan role=\"presentation\"\u003e    }\u003c/span\u003e\n\u003cspan role=\"presentation\"\u003e});\u003c/span\u003e\n\u003cspan role=\"presentation\"\u003e//\u003c/span\u003e\n\u003cspan role=\"presentation\"\u003e$(\u0026ldquo;body\u0026rdquo;).one(\u0026ldquo;touchstart\u0026rdquo;,function() {     \u003c/span\u003e\n\u003cspan role=\"presentation\"\u003e    document.getElementById(\u0026lsquo;audio\u0026rsquo;).play();\u003c/span\u003e\n\u003cspan role=\"presentation\"\u003e});\u003c/span\u003e\u003c/p\u003e","title":"H5自动播放音频"},{"content":"#/bin/bash\nwhile true;\ndo\ncount=`ps -ef | grep test.jar | grep -v grep|wc -l`\nif [ ${count} -lt 1 ]; then\nnohup java -jar xxx.jar \u0026gt;log.out 2\u0026gt;\u0026amp;1 \u0026amp;\nelse\necho “process is running”\nfi\nsleep 3\ndone\nLinux Shell脚本：自动读取pid并关闭进程 查询进程信息\nps -ef|grep elasticsearch\n过滤掉grep进程\nps -ef|grep elasticsearch|grep -v grep\n提取pid(awk以空格分割，显示第二个变量即为pid)\nps -ef|grep elasticsearch|grep -v grep|awk ‘{print $2}’\n根据pid kill掉该进程\n完整脚本如下所示\n","permalink":"https://blog.zdltech.com/posts/linux%E4%B8%ADjava%E6%89%A7%E8%A1%8C%E8%84%9A%E6%9C%AC%E5%AE%88%E6%8A%A4%E8%84%9A%E6%9C%AC/","summary":"\u003cp\u003e#/bin/bash\u003cbr\u003e\nwhile true;\u003cbr\u003e\ndo\u003cbr\u003e\ncount=`ps -ef | grep test.jar | grep -v grep|wc -l`\u003cbr\u003e\nif [ ${count} -lt 1 ]; then\u003cbr\u003e\nnohup java -jar xxx.jar \u0026gt;log.out 2\u0026gt;\u0026amp;1  \u0026amp;\u003cbr\u003e\nelse\u003cbr\u003e\necho “process is running”\u003cbr\u003e\nfi\u003cbr\u003e\nsleep 3\u003cbr\u003e\ndone\u003c/p\u003e\n\u003ch1 class=\"title-article\" id=\"linux-shell脚本自动读取pid并关闭进程\"\u003eLinux Shell脚本：自动读取pid并关闭进程\u003c/h1\u003e\n\u003cp\u003e查询进程信息\u003c/p\u003e\n\u003cp\u003eps -ef|grep elasticsearch\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img-blog.csdn.net/20180619185935360?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2V2YW54dWhl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70\"\u003e\u003c/p\u003e\n\u003cp\u003e过滤掉grep进程\u003c/p\u003e\n\u003cp\u003eps -ef|grep elasticsearch|grep -v grep\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img-blog.csdn.net/20180619185908877?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2V2YW54dWhl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70\"\u003e\u003c/p\u003e\n\u003cp\u003e提取pid(awk以空格分割，显示第二个变量即为pid)\u003c/p\u003e\n\u003cp\u003eps -ef|grep elasticsearch|grep -v grep|awk ‘{print $2}’\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img-blog.csdn.net/20180619190056895?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2V2YW54dWhl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70\"\u003e\u003c/p\u003e\n\u003cp\u003e根据pid kill掉该进程\u003c/p\u003e\n\u003cp\u003e完整脚本如下所示\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img-blog.csdn.net/20180619190500135?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2V2YW54dWhl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.zdltech.com/images/2019/02/aaa.png\"\u003e\u003cimg loading=\"lazy\" src=\"http://www.zdltech.com/images/2019/02/aaa-300x297.png\"\u003e\u003c/a\u003e\u003c/p\u003e","title":"linux中java执行脚本守护脚本"},{"content":"问题现象：\n最近因为一张表新加了字段，重新使用 mybatis-generator 生成了一下mapper文件，结果发现新生成的文件比之前少了xxxByPrimaryKey 的几个方法，对应的xml文件中同样也少了这几个, 并且xml文件中的resultMap节点里主键id使用的是result标签，而不是id标签。\n排查原因：\n首先想到的是：难道表没有主键了，于是赶紧检查了一下我的表结构，发现主键没有问题呀！表结构并没有大的变化，我仅仅是加了一个普通字段而已，那怎么会这样呢？\n然后我又检查了generatorConfig.xml中table项中的属性\nenableSelectByPrimaryKey=”true”\nenableUpdateByPrimaryKey=”true”\nenableDeleteByPrimaryKey=”true”\n看看这几个属性是否被设置成了false，默认的值是true。\n发现也没有问题，这里配置也没有改动过！\n唯一想到的变化是mysql连接器版本进行了升级：\nmysql mysql-connector-java 5.1.35 /** 升级版本 **/\nmysql mysql-connector-java 8.0.11 将版本改回去重新试了下果然就可以了。那么可以确信就是 mysql-connector-java 版本升级造成的问题！ 解决方法：\n很纳闷为什么升级了高版本反而有问题了呢，想到这既然是普遍问题，那应该别人早就遇到过这个问题了，网上搜了下，果然很多人在问这个问题。\n最终看到一篇文章找到了解决方法：\n在jdbcConnection节点里配置useInformationSchema属性，可以解决mybatis-generator不识别主键问题：\n参考文章：https://my.oschina.net/u/2289161/blog/1589630 另外还看到有人说：如果使用的mysql驱动5.x版本的就可以生成，使用6.x 及以上的，那就无法生成了，必须显式设置：useInformationSchema=”true”\n说明一下，我使用的maven插件版本是 1.3.5\norg.mybatis.generator\nmybatis-generator-maven-plugin\n1.3.5\nsrc/test/resources/generatorConfig.xml\ntrue\n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212; 参考：https://blog.csdn.net/rchm8519/article/details/81949916","permalink":"https://blog.zdltech.com/posts/mybatis-generator-%E6%97%A0%E6%B3%95%E7%94%9F%E6%88%90selectbyprimarykeydeletebyprimarykeyupdatebyprimarykey-mysql/","summary":"\u003cp\u003e问题现象：\u003cbr\u003e\n最近因为一张表新加了字段，重新使用 mybatis-generator 生成了一下mapper文件，结果发现新生成的文件比之前少了xxxByPrimaryKey 的几个方法，对应的xml文件中同样也少了这几个, 并且xml文件中的resultMap节点里主键id使用的是result标签，而不是id标签。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img-blog.csdn.net/20180822195720583?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3JjaG04NTE5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70\"\u003e\u003c/p\u003e\n\u003cp\u003e排查原因：\u003cbr\u003e\n首先想到的是：难道表没有主键了，于是赶紧检查了一下我的表结构，发现主键没有问题呀！表结构并没有大的变化，我仅仅是加了一个普通字段而已，那怎么会这样呢？\u003c/p\u003e\n\u003cp\u003e然后我又检查了generatorConfig.xml中table项中的属性\u003cbr\u003e\nenableSelectByPrimaryKey=”true”\u003cbr\u003e\nenableUpdateByPrimaryKey=”true”\u003cbr\u003e\nenableDeleteByPrimaryKey=”true”\u003cbr\u003e\n看看这几个属性是否被设置成了false，默认的值是true。\u003c/p\u003e\n\u003cp\u003e发现也没有问题，这里配置也没有改动过！\u003c/p\u003e\n\u003cp\u003e唯一想到的变化是mysql连接器版本进行了升级：\u003c/p\u003e\n\u003cdependency\u003e  \n\u003cgroupId\u003emysql\u003c/groupId\u003e  \n\u003cartifactId\u003emysql-connector-java\u003c/artifactId\u003e  \n\u003cversion\u003e5.1.35\u003c/version\u003e  \n\u003c/dependency\u003e\n\u003cp\u003e/** 升级版本 **/\u003c/p\u003e\n\u003cdependency\u003e  \n\u003cgroupId\u003emysql\u003c/groupId\u003e  \n\u003cartifactId\u003emysql-connector-java\u003c/artifactId\u003e  \n\u003cversion\u003e8.0.11\u003c/version\u003e  \n\u003c/dependency\u003e  \n将版本改回去重新试了下果然就可以了。那么可以确信就是 mysql-connector-java 版本升级造成的问题！\n\u003cp\u003e解决方法：\u003cbr\u003e\n很纳闷为什么升级了高版本反而有问题了呢，想到这既然是普遍问题，那应该别人早就遇到过这个问题了，网上搜了下，果然很多人在问这个问题。\u003c/p\u003e\n\u003cp\u003e最终看到一篇文章找到了解决方法：\u003c/p\u003e\n\u003cp\u003e在jdbcConnection节点里配置useInformationSchema属性，可以解决mybatis-generator不识别主键问题：\u003c/p\u003e\n\u003cp\u003e\u003cjdbcConnection driverClass=\u0026#8221;com.mysql.jdbc.Driver\u0026#8221; connectionURL=\u0026#8221;jdbc:mysql://localhost:3306/test\u0026#8221;  \nuserId=\u0026#8221;root\u0026#8221; password=\u0026#8221;rootroot\u0026#8221;\u003e\u003c/p\u003e\n\u003c/jdbcConnection\u003e  \n参考文章：https://my.oschina.net/u/2289161/blog/1589630\n\u003cp\u003e另外还看到有人说：如果使用的mysql驱动5.x版本的就可以生成，使用6.x 及以上的，那就无法生成了，必须显式设置：useInformationSchema=”true”\u003c/p\u003e\n\u003cp\u003e说明一下，我使用的maven插件版本是 1.3.5\u003c/p\u003e\n\u003cp\u003e\u003cgroupId\u003eorg.mybatis.generator\u003c/groupId\u003e\u003cbr\u003e\n\u003cartifactId\u003emybatis-generator-maven-plugin\u003c/artifactId\u003e\u003cbr\u003e\n\u003cversion\u003e1.3.5\u003c/version\u003e\u003cbr\u003e\n\u003cconfiguration\u003e\u003cbr\u003e\n\u003cconfigurationFile\u003esrc/test/resources/generatorConfig.xml\u003c/configurationFile\u003e\u003cbr\u003e\n\u003cverbose\u003etrue\u003c/verbose\u003e\u003cbr\u003e\n\u003c/configuration\u003e\u003cbr\u003e\n\u003cdependencies\u003e\u003c/p\u003e\n\u003c/dependencies\u003e  \n\u003c/plugin\u003e  \n\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;  \n参考：https://blog.csdn.net/rchm8519/article/details/81949916","title":"Mybatis Generator 无法生成selectByPrimaryKey、deleteByPrimaryKey、updateByPrimaryKey MySQL"},{"content":"如题：禁用、询问的权限，居然还返回权限获取成功\n推荐一个很好的项目：AndPermission\n不用回来感谢了喂！\n这个问题在项目中，一直存在，\n主要是第三方厂商各种改，返回的状态不正常；\n主要解决思路：\n在第三方成功获取权限时，\n再用系统原生的api去判断一下，是否真正获取了权限：\n/**\n系统层的权限判断 @param context 上下文 @param permissions 申请的权限 Manifest.permission.READ_CONTACTS @return 是否有权限 ：其中有一个获取不了就是失败了\n*/\npublic static boolean hasPermission(@NonNull Context context, @NonNull List permissions) {\nif (Build.VERSION.SDK_INT \u0026lt; Build.VERSION_CODES.M) return true;\nfor (String permission : permissions) {\nString op = AppOpsManagerCompat.permissionToOp(permission);\nif (TextUtils.isEmpty(op)) continue;\nint result = AppOpsManagerCompat.noteProxyOp(context, op, context.getPackageName());\nif (result == AppOpsManagerCompat.MODE_IGNORED) return false;\nresult = ContextCompat.checkSelfPermission(context, permission);\nif (result != PackageManager.PERMISSION_GRANTED) return false;\n}\nreturn true;\n} ###### 描述:适配6.0以下和6.0以上动态权限,并可以解决6.0以上个别手机点拒绝权限后会返回权限允许的回调的问题,例如:OnePlus3T（一加） A3010 7.1.1系统 以拨打电话为例:(注:直接拨打电话需要动态权限判断,唤起拨打电话界面不需要) #### 一.在build.gradle中添加依赖: \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//RxPermissions\u0026amp;lt;/span\u0026gt; compile \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'com.tbruyelle.rxpermissions2:rxpermissions:0.9.3@aar'\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//RxJava2\u0026amp;lt;/span\u0026gt; implementation \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;io.reactivex.rxjava2:rxjava:2.0.0\u0026quot;\u0026amp;lt;/span\u0026gt; 另外用到了JDK1.8的新特性,也需要在build.gradle中android节点下配置 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` `android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } ` #### 二.工具类 \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` { if (granted) { if (hasOpsPermission(context, permissions)) { iPermissionListener.permissionGranted(); } else { iPermissionListener.permissionDenied(); ToastUtil.showToast(context, toastDetails); } } else { iPermissionListener.permissionDenied(); ToastUtil.showToast(context, toastDetails); } }); } }\n/** * Android6.0权限申请后再判断原生的权限是否真的被授权--适配部分国产机型（小米、华为、vivo、oppo等） * * @param context * @param permissions * @return */ private static boolean hasOpsPermission(@NonNull Context context, @NonNull String... permissions) { for (String permission : permissions) { String op = AppOpsManagerCompat.permissionToOp(permission); int result = AppOpsManagerCompat.noteProxyOp(context, op, context.getPackageName()); if (result == AppOpsManagerCompat.MODE_ALLOWED) return true; } return false; } } \u0026quot; data-snippet-id=\u0026ldquo;ext.8edff023d0f945ba3a72d6f6bd23625e\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;`\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;/**\nCreated by caoshiyao on 2018/9/6.\nAndroid6.0权限申请工具类 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-class\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;PermissionUtil\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-class\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;interface\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;IPermissionListener\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//权限被授权\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;permissionGranted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//权限被拒绝\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;permissionDenied\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;; }\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;/**\n申请获取相关权限 \u0026lt;span class=\u0026ldquo;hljs-doctag\u0026rdquo;\u0026gt;@param\u0026lt;/span\u0026gt; context \u0026lt;span class=\u0026ldquo;hljs-doctag\u0026rdquo;\u0026gt;@param\u0026lt;/span\u0026gt; iPermissionListener \u0026lt;span class=\u0026ldquo;hljs-doctag\u0026rdquo;\u0026gt;@param\u0026lt;/span\u0026gt; toastDetails \u0026lt;span class=\u0026ldquo;hljs-doctag\u0026rdquo;\u0026gt;@param\u0026lt;/span\u0026gt; permissions */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;requestPermission\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;(@NonNull Context context, @NonNull IPermissionListener iPermissionListener, @NonNull String toastDetails, @NonNull String\u0026hellip; permissions)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt; (Build.VERSION.SDK_INT \u0026lt; Build.VERSION_CODES.M) { iPermissionListener.permissionGranted(); } \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt; RxPermissions((Activity) context) .request(permissions) .subscribe(granted -\u0026gt; { \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt; (granted) { \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt; (hasOpsPermission(context, permissions)) { iPermissionListener.permissionGranted(); } \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;else\u0026lt;/span\u0026gt; { iPermissionListener.permissionDenied(); ToastUtil.showToast(context, toastDetails); } } \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;else\u0026lt;/span\u0026gt; { iPermissionListener.permissionDenied(); ToastUtil.showToast(context, toastDetails); } }); } } \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;/**\nAndroid6.0权限申请后再判断原生的权限是否真的被授权\u0026ndash;适配部分国产机型（小米、华为、vivo、oppo等） \u0026lt;span class=\u0026ldquo;hljs-doctag\u0026rdquo;\u0026gt;@param\u0026lt;/span\u0026gt; context \u0026lt;span class=\u0026ldquo;hljs-doctag\u0026rdquo;\u0026gt;@param\u0026lt;/span\u0026gt; permissions \u0026lt;span class=\u0026ldquo;hljs-doctag\u0026rdquo;\u0026gt;@return\u0026lt;/span\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;hasOpsPermission\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;(@NonNull Context context, @NonNull String\u0026hellip; permissions)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;for\u0026lt;/span\u0026gt; (String permission : permissions) { String op = AppOpsManagerCompat.permissionToOp(permission); \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; result = AppOpsManagerCompat.noteProxyOp(context, op, context.getPackageName()); \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt; (result == AppOpsManagerCompat.MODE_ALLOWED) \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;true\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;false\u0026lt;/span\u0026gt;; } } `\n#### 三.使用方法: \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` ` \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 检查权限 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;checkPermission\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ PermissionUtil.requestPermission(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; PermissionUtil.IPermissionListener() { \u0026amp;lt;span class=\u0026#34;hljs-meta\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;permissionGranted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ call(); } \u0026amp;lt;span class=\u0026#34;hljs-meta\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;permissionDenied\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ ToastUtil.showToast(PermissionActivity.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;权限被拒绝\u0026#34;\u0026amp;lt;/span\u0026gt;); } },\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;权限被拒绝,请设置应用权限\u0026#34;\u0026amp;lt;/span\u0026gt;,Manifest.permission.CALL_PHONE); } ` \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` ` \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;/** * 拨打电话,直接拨打出去 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;call\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;try\u0026lt;/span\u0026gt; { Intent intent = \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt; Intent(Intent.ACTION_CALL); Uri uri = Uri.parse(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;tel:\u0026quot;\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;10086\u0026rdquo;\u0026lt;/span\u0026gt;); intent.setData(uri); startActivity(intent); } \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;catch\u0026lt;/span\u0026gt; (SecurityException e) { e.printStackTrace(); } }\nhttps://www.cnblogs.com/bugly/p/7344275.html `\n\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android6-0%E8%BF%90%E8%A1%8C%E6%97%B6%E6%9D%83%E9%99%90%E6%8B%92%E7%BB%9D%E4%BA%86%E6%9D%83%E9%99%90%E8%BF%98%E8%BF%94%E5%9B%9E%E8%8E%B7%E5%8F%96%E6%88%90%E5%8A%9F/","summary":"\u003cp\u003e如题：禁用、询问的权限，居然还返回权限获取成功\u003cbr\u003e\n推荐一个很好的项目：AndPermission\u003cbr\u003e\n不用回来感谢了喂！\u003c/p\u003e\n\u003cp\u003e这个问题在项目中，一直存在，\u003cbr\u003e\n主要是第三方厂商各种改，返回的状态不正常；\u003cbr\u003e\n主要解决思路：\u003cbr\u003e\n在第三方成功获取权限时，\u003cbr\u003e\n再用系统原生的api去判断一下，是否真正获取了权限：\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e系统层的权限判断\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e@param context 上下文\u003c/li\u003e\n\u003cli\u003e@param permissions 申请的权限 Manifest.permission.READ_CONTACTS\u003c/li\u003e\n\u003cli\u003e@return 是否有权限 ：其中有一个获取不了就是失败了\u003cbr\u003e\n*/\u003cbr\u003e\npublic static boolean hasPermission(@NonNull Context context, @NonNull List\u003cString\u003e permissions) {\u003cbr\u003e\nif (Build.VERSION.SDK_INT \u0026lt; Build.VERSION_CODES.M) return true;\u003cbr\u003e\nfor (String permission : permissions) {\u003cbr\u003e\nString op = AppOpsManagerCompat.permissionToOp(permission);\u003cbr\u003e\nif (TextUtils.isEmpty(op)) continue;\u003cbr\u003e\nint result = AppOpsManagerCompat.noteProxyOp(context, op, context.getPackageName());\u003cbr\u003e\nif (result == AppOpsManagerCompat.MODE_IGNORED) return false;\u003cbr\u003e\nresult = ContextCompat.checkSelfPermission(context, permission);\u003cbr\u003e\nif (result != PackageManager.PERMISSION_GRANTED) return false;\u003cbr\u003e\n}\u003cbr\u003e\nreturn true;\u003cbr\u003e\n}\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android6.0运行时权限，拒绝了权限还返回获取成功"},{"content":"利用mvn deploy命令上传包\nmvn安装\napache官方网站可以下载。\nhttps://maven.apache.org/download.cgi\n在PATH里加入maven的bin的路径\n配置完毕后，在Windows命令提示符下，输入mvn -v测试一下。是否安装成功。\nmvn:deploy在整合或者发布环境下执行，将最终版本的包拷贝到远程的repository，使得其他的开发者或者工程可以共享。\n以将ojdbc14传到nexus中的releases为例\n一 配置settings.xml\n因为nexus是需要登陆操作，当然可以通过配置免登陆，这是后话。\n在settings.xml的\nreleases deployment 123456\nsnapshots\ndeployment\n123456\n当然如果你要上传包去其他仓库，可依照此例设置相应的参数，如\ncentral admin admin123\n如果进行deploy时返回Return code is: 401错误，则需要进行用户验证或者你已经验证的信息有误。\n如果进行deploy时返回Return code is: 400, ReasonPhrase: Bad Request错误，这里的原因是往往是没有部署到nexus的仓库中切换Durl路径\n二 cmd输入命令 最好进入到jar包的绝对路径\nmvn deploy:deploy-file -DgroupId=zhongjin -DartifactId=API4BDS -Dversion=2.3 -Dpackaging=jar -Dfile=G:\\p2p\\API4BDS-2.3.jar -Durl=http://192.168.34.35:81/nexus/content/repositories/releases -DrepositoryId=releases\nDgroupId和DartifactId构成了该jar包在pom.xml的坐标，项目就是依靠这两个属性定位。自己起名字也行。\nDfile表示需要上传的jar包的绝对路径。\nDurl私服上仓库的位置，打开nexus——\u0026gt;repositories菜单，可以看到该路径。\nDrepositoryId服务器的表示id，在nexus的configuration可以看到。\nDversion表示版本信息，怎样得到一个jar包准确的版本呢？\n解压该包，会发现一个叫MANIFEST.MF的文件，这个文件就有描述该包的版本信息。\n比如Manifest-Version: 1.0可以知道该包的版本了。\n上传成功后，在nexus界面点击3rd party仓库可以看到这包。\n今天deploy项目时，maven报错401，百度了一下，找到以下文章，解决了问题，所以就考了过来。\n源地址是：http://www.netingcn.com/maven-deploy-nexus.html\n首先在Nexus中创建一个自己私有的仓库，步骤为Repositories –\u0026gt; Add –\u0026gt; Hosted Repository，在页面的下半部分输入框中填入Repository ID和Repository Name即可，比如分别填入myrepo和 my repository，点击save就创建完成了。\n如果要把构建部署至私服中，需要在构建的 pom.xml 文件增加 distributionManagement 配置项，有多种协议可以用来部署构建，这里主要讲两种。\n第一种配置如下：\n[…]\nmyrep\nmy repository\nfile:/usr/local/mvn-private-server/nexus-oss-webapp-1.9.2.3/./../sonatype-work/nexus/storage/myrep/\n[…]\n说明：其中id就是需要部署构建的仓库Id，name似乎不重要，可以随便输入，url就是仓库的configuration中Default Local Storage Location项的对应的信息。采用此种方法，服务器不会对部署操作进行认证，同时配置也把仓库的物理存储地址完全暴露，感觉不是太好。\n第二种配置如下：\n[…]\ntagphi\nhttp://nexus-server-ip:8081/nexus/content/repositories/myrep\n[…]\n说明：上述的distributionManagement信息可以在对于的仓库的Summary中找到。\n配置好后，此时执行mvn deploy，部署应该不会成功，根据提示信息，重新执行 mvn deploy -e 或 mvn deploy -X，此时能看到具体的错误信息，报Return code is: 401错，这个是因为发布者没有权限，需要把用户认证信息配置在maven的settings.xml中，该文件在mavne安装包下的conf目录下，这是一个全局配置，同时可以把该文件复制到 userdir/.m2 目录下，这样配置就只对当前用户生效。在settings.xml文件中servers段中添加如下信息\nmyrep deployment password\n其中id就是部署仓库的id，username是作为部署用户，Nexus系统默认的deployment，密码为deployment123，可以在security — users中找到，如果需要设置密码，在用户列表中找到该用户，在该用户上点击右键，会出来一个菜单供重置密码或修改密码。此时在执行 mvn deploy，应该可以看到成功发布了。当第二次执行 mvn deploy 又失败，这次失败原因是Return code is: 400，该错误的原因是在创建仓库时在configuration中的Deployment Policy设置为了Disable Redeploy，修改为Allow Redeploy即可。\n私服搭建\n1.确定已安装maven和jdk环境\n2.下载nexus http://www.sonatype.org/nexus/go\n3.解压后进入/bin/jsw目录\n4.根据本机操作系统选择相应版本，此处以64位windows为例\n5.双击install-nexus.bat安装nexus服务，然后双击start-nexus.bat启动服务\n6，访问http://localhost:8081/nexus/，出现下面页面表示安装成功\n7.点击右上角的Log in，输入默认账号，密码\n8.点击Server配置服务器信息，勾选Http Proxy Settings，并设置代理服务器\n9.添加第三方jar包，nexus提供了3rd party、Snapshots、Releases这三个目录存放第三方jar包\n10.上传第三方jar包\n11.确定填写无误后，点击Add Artifact（可添加多个），然后点击Upload Artifact上传所有jar包\n12.上传成功后在可在Releases中查看\n13.在其他项目的pom.xml中引用\npublic public http://192.168.34.35:81/nexus/content/groups/public/ snapshots Internal Snapshots http://192.168.34.35:81/nexus/content/repositories/snapshots/ releases Internal Releases http://192.168.34.35:81/nexus/content/repositories/releases/ nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public spring-milestones Spring Milestones http://repo.spring.io/milestone false spring-snapshots Spring Snapshots http://repo.spring.io/snapshot true 从Maven项目中导出项目依赖的jar包 一、导出到默认目录 targed/dependency 从Maven项目中导出项目依赖的jar包：进入工程pom.xml 所在的目录下，执行如下命令： 1、mvn dependency:copy-dependencies或在eclipse中，选择项目的pom.xml文件，点击右键菜单中的Run As,见下图红框中，在弹出的Configuration窗口中，输入 dependency:copy-dependencies后，点击运行； 2、maven项目所依赖的jar包会导出到targed/dependency目录中。 二、导出到自定义目录中 在maven项目下创建lib文件夹，输入以下命令： 1、mvn dependency:copy-dependencies -DoutputDirectory=lib； 2、maven项目所依赖的jar包都会复制到项目目录下的lib目录下。 三、设置依赖级别 同时可以设置依赖级别，通常使用compile级别 mvn dependency:copy-dependencies -DoutputDirectory=lib -DincludeScope=compile 参考：https://blog.csdn.net/u013308504/article/details/78952221\n","permalink":"https://blog.zdltech.com/posts/%E5%88%A9%E7%94%A8mvn-deploy%E5%91%BD%E4%BB%A4%E4%B8%8A%E4%BC%A0%E5%8C%85-%E5%88%B0%E7%A7%81%E6%9C%8D/","summary":"\u003cp\u003e利用mvn deploy命令上传包\u003cbr\u003e\nmvn安装\u003cbr\u003e\napache官方网站可以下载。\u003cbr\u003e\n\u003ca href=\"https://maven.apache.org/download.cgi\"\u003ehttps://maven.apache.org/download.cgi\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e在PATH里加入maven的bin的路径\u003c/p\u003e\n\u003cp\u003e配置完毕后，在Windows命令提示符下，输入mvn -v测试一下。是否安装成功。\u003c/p\u003e\n\u003cp\u003emvn:deploy在整合或者发布环境下执行，将最终版本的包拷贝到远程的repository，使得其他的开发者或者工程可以共享。\u003c/p\u003e\n\u003cp\u003e以将ojdbc14传到nexus中的releases为例\u003c/p\u003e\n\u003cp\u003e一 配置settings.xml\u003c/p\u003e\n\u003cp\u003e因为nexus是需要登陆操作，当然可以通过配置免登陆，这是后话。\u003cbr\u003e\n在settings.xml的\u003c/p\u003e\n\u003cservers\u003e  \n\u003cserver\u003e  \n\u003cid\u003ereleases\u003c/id\u003e  \n\u003cusername\u003edeployment\u003c/username\u003e  \n\u003cp\u003e123456\u003c/password\u003e\u003cbr\u003e\n\u003c/server\u003e\u003cbr\u003e\n\u003cserver\u003e\u003cbr\u003e\n\u003cid\u003esnapshots\u003c/id\u003e\u003cbr\u003e\n\u003cusername\u003edeployment\u003c/username\u003e\u003c/p\u003e\n\u003cp\u003e123456\u003c/password\u003e\u003cbr\u003e\n\u003c/server\u003e\u003cbr\u003e\n\u003c/servers\u003e\u003cbr\u003e\n当然如果你要上传包去其他仓库，可依照此例设置相应的参数，如\u003c/p\u003e\n\u003cserver\u003e  \n\u003cid\u003ecentral\u003c/id\u003e  \n\u003cusername\u003eadmin\u003c/username\u003e  \n\u003cp\u003eadmin123\u003c/password\u003e\u003cbr\u003e\n\u003c/server\u003e\u003cbr\u003e\n如果进行deploy时返回Return code is: 401错误，则需要进行用户验证或者你已经验证的信息有误。\u003c/p\u003e\n\u003cp\u003e如果进行deploy时返回Return code is: 400, ReasonPhrase: Bad Request错误，这里的原因是往往是没有部署到nexus的仓库中切换Durl路径\u003c/p\u003e\n\u003cp\u003e二 cmd输入命令  最好进入到jar包的绝对路径\u003c/p\u003e\n\u003cp\u003emvn deploy:deploy-file -DgroupId=zhongjin -DartifactId=API4BDS -Dversion=2.3 -Dpackaging=jar -Dfile=G:\\p2p\\API4BDS-2.3.jar -Durl=http://192.168.34.35:81/nexus/content/repositories/releases -DrepositoryId=releases\u003c/p\u003e\n\u003cp\u003eDgroupId和DartifactId构成了该jar包在pom.xml的坐标，项目就是依靠这两个属性定位。自己起名字也行。\u003cbr\u003e\nDfile表示需要上传的jar包的绝对路径。\u003cbr\u003e\nDurl私服上仓库的位置，打开nexus——\u0026gt;repositories菜单，可以看到该路径。\u003cbr\u003e\nDrepositoryId服务器的表示id，在nexus的configuration可以看到。\u003cbr\u003e\nDversion表示版本信息，怎样得到一个jar包准确的版本呢？\u003cbr\u003e\n解压该包，会发现一个叫MANIFEST.MF的文件，这个文件就有描述该包的版本信息。\u003cbr\u003e\n比如Manifest-Version: 1.0可以知道该包的版本了。\u003c/p\u003e\n\u003cp\u003e上传成功后，在nexus界面点击3rd party仓库可以看到这包。\u003c/p\u003e\n\u003cp\u003e今天deploy项目时，maven报错401，百度了一下，找到以下文章，解决了问题，所以就考了过来。\u003cbr\u003e\n源地址是：http://www.netingcn.com/maven-deploy-nexus.html\u003c/p\u003e\n\u003cp\u003e首先在Nexus中创建一个自己私有的仓库，步骤为Repositories –\u0026gt; Add –\u0026gt; Hosted Repository，在页面的下半部分输入框中填入Repository ID和Repository Name即可，比如分别填入myrepo和 my repository，点击save就创建完成了。\u003c/p\u003e","title":"利用mvn deploy命令上传包 到私服"},{"content":" 最近开发一直在使用Xcode10 beta版本的，今天升级到Xcode10 beta3，但是在编译项目时编译失败，报错内容: \u0026lt;div class=\u0026quot;image-view\u0026quot; data-width=\u0026quot;1326\u0026quot; data-height=\u0026quot;390\u0026quot;\u0026gt; ![](//upload-images.jianshu.io/upload_images/2135374-e38dfa85c14dbcd3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; 屏幕快照 2018-07-09 上午10.28.06.png \u0026lt;/div\u0026gt; `error: Multiple commands produce \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;/Users/xiaoyuan/Library/Developer/Xcode/DerivedData/Boobuz-gnxeuntgkenwgdgycqnvabqubafh/Build/Products/Debug-iphoneos/Boobuz.app\u0026#39;\u0026amp;lt;/span\u0026gt;: 1) Target \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Boobuz\u0026#39;\u0026amp;lt;/span\u0026gt; has create directory \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;command\u0026amp;lt;/span\u0026gt; with output \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;/Users/xiaoyuan/Library/Developer/Xcode/DerivedData/Boobuz-gnxeuntgkenwgdgycqnvabqubafh/Build/Products/Debug-iphoneos/Boobuz.app\u0026#39;\u0026amp;lt;/span\u0026gt; 2) That \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;command\u0026amp;lt;/span\u0026gt; depends on \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;command\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;in\u0026amp;lt;/span\u0026gt; Target \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Boobuz\u0026#39;\u0026amp;lt;/span\u0026gt;: script phase “[CP] Copy Pods Resources” ` 引用简友[guifu_tang](/u/3b14b90a886f)的一句话原因是Xcode 10 默认使用的build system是New build system，与Xcode9不同导致。 - 第一种方法 不修改build system 分析build error 日志，错误发生在Copy Pods Resources，而且与output有关，应该是使用了cocoapods导致的，尝试删除该项目target-Copy Pods Resources-Output Files，成功解决问题。\nBuild phase -\u0026gt; Copy Pods Resources -\u0026gt; Output Files -\u0026gt; 移除${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH} -\u0026gt; Build \u0026#34; data-snippet-id=\u0026#34;ext.56fe38509dd0748880ce2c86d42c91e7\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`选中项目target -\u0026amp;gt; Build phase -\u0026amp;gt; Copy Pods Resources -\u0026amp;gt; Output Files -\u0026amp;gt; 移除\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;${TARGET_BUILD_DIR}\u0026amp;lt;/span\u0026gt;/\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;${UNLOCALIZED_RESOURCES_FOLDER_PATH}\u0026amp;lt;/span\u0026gt; -\u0026amp;gt; Build ` \u0026lt;div class=\u0026quot;image-view\u0026quot; data-width=\u0026quot;1075\u0026quot; data-height=\u0026quot;790\u0026quot;\u0026gt; ![](//upload-images.jianshu.io/upload_images/2135374-a3b8e4e79a8bdeca.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; 屏幕快照 2018-07-09 上午10.39.03.png \u0026lt;/div\u0026gt; - 第二种方法 修改build system 在Xcode菜单栏 -\u0026gt; File -\u0026gt; Workspace Setting，将build system修改为legacy build system，然后clean后编译。\n\u0026lt;div class=\u0026quot;image-view\u0026quot; data-width=\u0026quot;534\u0026quot; data-height=\u0026quot;470\u0026quot;\u0026gt; ![](//upload-images.jianshu.io/upload_images/2135374-f5f227a9fb314d58.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/534/format/webp) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; 在xcode 10中png图片问题的话，设置下compile png为no就可以了\n转自：https://www.jianshu.com/p/8a8444acdca5\n","permalink":"https://blog.zdltech.com/posts/xcode-10-beta3-error-multiple-commands-produce/","summary":"\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e最近开发一直在使用Xcode10 beta版本的，今天升级到Xcode10 beta3，但是在编译项目时编译失败，报错内容:\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-package\"\u003e\n    \u003cdiv class=\"image-container\"\u003e\n      \u003cdiv class=\"image-container-fill\"\u003e\n      \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div class=\u0026quot;image-view\u0026quot; data-width=\u0026quot;1326\u0026quot; data-height=\u0026quot;390\u0026quot;\u0026gt;\n    ![](//upload-images.jianshu.io/upload_images/2135374-e38dfa85c14dbcd3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp)\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt;\n  屏幕快照 2018-07-09 上午10.28.06.png\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n    \u003cdiv class=\"alert-info\"\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`error: Multiple commands produce \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;/Users/xiaoyuan/Library/Developer/Xcode/DerivedData/Boobuz-gnxeuntgkenwgdgycqnvabqubafh/Build/Products/Debug-iphoneos/Boobuz.app\u0026#39;\u0026amp;lt;/span\u0026gt;:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e1) Target \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Boobuz\u0026#39;\u0026amp;lt;/span\u0026gt; has create directory \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;command\u0026amp;lt;/span\u0026gt; with output \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;/Users/xiaoyuan/Library/Developer/Xcode/DerivedData/Boobuz-gnxeuntgkenwgdgycqnvabqubafh/Build/Products/Debug-iphoneos/Boobuz.app\u0026#39;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e2) That \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;command\u0026amp;lt;/span\u0026gt; depends on \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;command\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;in\u0026amp;lt;/span\u0026gt; Target \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Boobuz\u0026#39;\u0026amp;lt;/span\u0026gt;: script phase “[CP] Copy Pods Resources”\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e引用简友[guifu_tang](/u/3b14b90a886f)的一句话原因是Xcode 10 默认使用的build system是New build system，与Xcode9不同导致。\n\n\n\n\n- 第一种方法 不修改build system\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e分析build error 日志，错误发生在\u003ccode\u003eCopy Pods Resources\u003c/code\u003e，而且与\u003ccode\u003eoutput\u003c/code\u003e有关，应该是使用了cocoapods导致的，尝试删除\u003ccode\u003e该项目target-Copy Pods Resources-Output Files\u003c/code\u003e，成功解决问题。\u003c/p\u003e","title":"Xcode 10 beta3 Error: Multiple commands produce"},{"content":" 根据自己项目的真实情况需要注意配置jdk环境，如果jdk环境不同可能造成打出的war包不能正常运行。例如 项目使用jdk1.7 打包使用javac必须为jdk1.7中的javac命令，tomcat需要配置执行的jdk环境为1.7。如果电脑使用的和项目使用的是同一个jdk，配置路径可以省略，其他情况不能省略。\n命令行打包 war文件\necho 准备java文件\ndir *.java/s/b \u0026gt; source.txt\nif exist out\\classes (\necho 清理中…\nrd /S/Q out\n)\necho 清理中完成\nmd out\\classes\nmd out\\webapp\necho 编译源码\nset JAVA_HOME=D:\\Program Files\\Java\\jdk1.7.0_75\n%JAVA_HOME%\\bin\\javac -cp .;E:\\apache-tomcat-8.5.35\\lib*;E:\\apache-tomcat-8.5.35\\bin*;E:\\auto_test\\zchfaxgb\\src\\main\\webapp\\WEB-INF\\lib* -d out\\classes -encoding utf-8 @source.txt\necho 复制webapp目录\nxcopy src\\main\\webapp out\\webapp /s/e/i/y\necho 创建编译源码路径\nmd out\\webapp\\WEB-INF\\classes\necho 复制classes目录\nxcopy out\\classes out\\webapp\\WEB-INF\\classes /s/e/i/y\necho 复制resources目录\nxcopy src\\main\\resources out\\webapp\\WEB-INF\\classes /s/e/i/y\necho 开始打包\ncd out\\webapp\necho 打包中\njar -cvf zcjf.war *\nmove zcjf.war ../../\necho 打包完成\npause\n由于使用的是jdk1.7 所以需要配置环境路径、tomcat也需要配置jdk为1.7\nset JAVA_HOME=D:\\Program Files\\Java\\jdk1.7.0_75\nset JRE_HOME=D:\\Program Files\\Java\\jdk1.7.0_75\\jre\n参考文件\njavac -cp .;E:\\apache-tomcat-8.5.35\\lib*;E:\\apache-tomcat-8.5.35\\bin*;E:\\Java_Workspace\\zchfax_web\\zchfaxgb\\src\\main\\webapp\\WEB-INF\\lib* -d E://temp/classes -encoding utf-8 E:\\Java_Workspace\\zchfax_web\\zchfaxgb\\src\\main\\java*.java\njavac -cp .;E:\\apache-tomcat-8.5.35\\lib*;E:\\apache-tomcat-8.5.35\\bin*;E:\\Java_Workspace\\zchfax_web\\zchfaxgb\\src\\main\\webapp\\WEB-INF\\lib* -d E:\\Java_Workspace\\zchfax_web\\zchfaxgb\\src -encoding utf-8 ./*.java\n生产编译的source.txt的说明文件\ncd src\ndir *.java/s/b \u0026gt; source.txt\njavac -cp .;E:\\apache-tomcat-8.5.35\\lib*;E:\\apache-tomcat-8.5.35\\bin*;E:\\Java_Workspace\\zchfax_web\\zchfaxgb\\src\\main\\webapp\\WEB-INF\\lib* -d cn @source.txt\n//这句话是说编译java文件，并且把编译文件放到-d指定的文件夹\njavac -cp .;E:\\apache-tomcat-8.5.35\\lib*;E:\\apache-tomcat-8.5.35\\bin*;E:\\Java_Workspace\\zchfax_web\\zchfaxgb\\src\\main\\webapp\\WEB-INF\\lib*;D:\\Program Files\\Java\\jdk1.7.0_75\\lib* -d classes -encoding utf-8 @source.txt\njavac -cp .;E:\\apache-tomcat-8.5.35\\lib*;E:\\apache-tomcat-8.5.35\\bin*;E:\\Java_Workspace\\zchfax_web\\zchfaxgb\\src\\main\\webapp\\WEB-INF\\lib*;”D:\\Program Files\\Java\\jdk1.7.0_75\\lib*” -d ./main/webapp/WEB-INF/classes -encoding utf-8 @source.txt\n2.拷贝资源文件\n拷贝配置文件。有时我们会将配置文件（如spring、数据库的配置文件）放在src目录下，此时需要将这些配置文件拷贝到classes文件夹中，要保持原有的包结构。\n拷贝classes文件夹。将整个classes文件夹拷贝至WebContent/WEB-INF目录里面\n3.生成war包\njar -cvf Log.war F:\\log\\WebContent*\n","permalink":"https://blog.zdltech.com/posts/%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%89%93%E5%8C%85-war%E6%96%87%E4%BB%B6/","summary":"\u003cblockquote\u003e\n\u003cp\u003e根据自己项目的真实情况需要注意配置jdk环境，如果jdk环境不同可能造成打出的war包不能正常运行。例如 项目使用jdk1.7 打包使用javac必须为jdk1.7中的javac命令，tomcat需要配置执行的jdk环境为1.7。如果电脑使用的和项目使用的是同一个jdk，配置路径可以省略，其他情况不能省略。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e命令行打包 war文件\u003cbr\u003e\necho 准备java文件\u003cbr\u003e\ndir *.java/s/b \u0026gt; source.txt\u003c/p\u003e\n\u003cp\u003eif exist out\\classes (\u003cbr\u003e\necho 清理中…\u003cbr\u003e\nrd /S/Q out\u003cbr\u003e\n)\u003cbr\u003e\necho 清理中完成\u003cbr\u003e\nmd out\\classes\u003cbr\u003e\nmd out\\webapp\u003cbr\u003e\necho 编译源码\u003cbr\u003e\nset JAVA_HOME=D:\\Program Files\\Java\\jdk1.7.0_75\u003cbr\u003e\n%JAVA_HOME%\\bin\\javac -cp .;E:\\apache-tomcat-8.5.35\\lib*;E:\\apache-tomcat-8.5.35\\bin*;E:\\auto_test\\zchfaxgb\\src\\main\\webapp\\WEB-INF\\lib* -d out\\classes -encoding utf-8 @source.txt\u003cbr\u003e\necho 复制webapp目录\u003cbr\u003e\nxcopy src\\main\\webapp out\\webapp /s/e/i/y\u003cbr\u003e\necho 创建编译源码路径\u003cbr\u003e\nmd out\\webapp\\WEB-INF\\classes\u003cbr\u003e\necho 复制classes目录\u003cbr\u003e\nxcopy out\\classes out\\webapp\\WEB-INF\\classes /s/e/i/y\u003cbr\u003e\necho 复制resources目录\u003cbr\u003e\nxcopy src\\main\\resources out\\webapp\\WEB-INF\\classes /s/e/i/y\u003cbr\u003e\necho 开始打包\u003cbr\u003e\ncd out\\webapp\u003cbr\u003e\necho 打包中\u003cbr\u003e\njar -cvf zcjf.war *\u003cbr\u003e\nmove zcjf.war ../../\u003cbr\u003e\necho 打包完成\u003cbr\u003e\npause\u003c/p\u003e","title":"命令行打包 war文件"},{"content":" # 概述 图片格式概述: BMP:高质量绘图 保证原图质量，用于相机等 BMP格式图片是有一个一个的像素点组成,每一个像素都是一个颜色.而每一个像素显示的颜色用的二进制位也不相同，这个像素位称之为位深，位深越大，表示每一个像素点所用的二进制位越多，显示的图像也就越清晰。 png：较高质量绘图 体积小，适用于网络传输 png图片是将bmp图片进行压缩，其压缩格式类似于rar压缩——将相同的byte信息合并表示。png图片可以还原，是无损的压缩方式。 jpg：良好的绘图质量 体积小，便于传输 jpg格式图片也是对bmp图片进行压缩，因为眼睛的精度是有限的，jpg利用这一点将很多颜色相近的用同一颜色标识，而对于一大块相同的颜色，则用一个值表示。jpg格式图片不能被还原。\n## 加载大图 \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` hr \u0026amp;\u0026amp; wr\u0026gt;1){ r = wr; } if(hr\u0026gt;wr \u0026amp;\u0026amp; hr\u0026gt;1){ r = hr; } //压缩图片 options.inSampleSize = r;//设置压缩比 options.inJustDecodeBounds = false;//设置加载图片内容 Bitmap bm = BitmapFactory.decodeFile(path,options); iv.setImageBitmap(bm); \u0026quot; data-snippet-id=\u0026ldquo;ext.f5fc8efb9581248b791731039403eb80\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;`ImageView iv = (ImageView) findViewById(R.id.iv); \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;/**\n在Android中,每一个应用程序所占用的内存空间大小都会有一个固定的大小限制 假设此处加载的图片是2560*1440像素,图片位深是24的jpg格式图像 虽然此图占用的磁盘空间是1.3M,但图片在加载到内存中时,实际上会先转换成位图图像 那么这张图片加载到内存中的大小就是2560144032(位深24,windows系统中,使用24位字节表示一个颜色值:#000000, 但在Android中,每一个颜色值是用32位字节表示一个颜色值:#00000000),因此,这张图片加载到内存中所需要占用的内存 大小约为:14M,因此,占用内存是极大的.若是直接将图片加载到内存中,容易造成内存溢出 解决方案:按比例压缩图片 *按比例压缩图片首先就是要获取图片的大小 */\u0026lt;/span\u0026gt; String path = \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;mnt/sdcard/1.jpg\u0026rdquo;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//用于设置图片渲染器参数\u0026lt;/span\u0026gt; BitmapFactory.Options options = \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt; Options(); \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//设置图片加载属性:不加载图片内容,只获取图片信息\u0026lt;/span\u0026gt; options.inJustDecodeBounds = \u0026lt;span class=\u0026ldquo;hljs-literal\u0026rdquo;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//加载图片信息\u0026lt;/span\u0026gt; BitmapFactory.decodeFile(path,options); \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//获取图片宽高\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; picwidth = options.outWidth; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; picheight = options.outHeight; \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//获取屏幕大小\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//获取窗口管理器\u0026lt;/span\u0026gt; WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//获取默认显示设备\u0026lt;/span\u0026gt; Display dis =wm.getDefaultDisplay(); \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//获取屏幕宽高\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//dis.getSize(outSize);此方法适用于新版本Android系统\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; diswidth = dis.getWidth(); \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; disheight = dis.getHeight(); \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//计算压缩比\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; wr = picwidth/diswidth; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; hr = picheight/disheight; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; r = \u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;1\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt;(wr\u0026gt;hr \u0026amp;\u0026amp; wr\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;1\u0026lt;/span\u0026gt;){ r = wr; } \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt;(hr\u0026gt;wr \u0026amp;\u0026amp; hr\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;1\u0026lt;/span\u0026gt;){ r = hr; } \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//压缩图片\u0026lt;/span\u0026gt; options.inSampleSize = r;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//设置压缩比\u0026lt;/span\u0026gt; options.inJustDecodeBounds = \u0026lt;span class=\u0026ldquo;hljs-literal\u0026rdquo;\u0026gt;false\u0026lt;/span\u0026gt;;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//设置加载图片内容\u0026lt;/span\u0026gt; Bitmap bm = BitmapFactory.decodeFile(path,options); iv.setImageBitmap(bm); `\n## 复制图像 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` `ImageView iv = (ImageView) findViewById(R.id.iv); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 复制图片:作用 * 在Android中,直接从资源文件加载到的图片是不能进行操作的,只能进行显示 * 想要进行操作,可以复制一张图片到内存,然后操作复制到的图片 * */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//加载原图\u0026amp;lt;/span\u0026gt; Bitmap bitmap = BitmapFactory.decodeFile(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;/mnt/sdcard/1.jpg\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//搞一个一样大小一样样式的复制图\u0026amp;lt;/span\u0026gt; Bitmap copybm = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获取复制图的画布\u0026amp;lt;/span\u0026gt; Canvas canvas = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Canvas(copybm); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获取一个画笔,设置颜色\u0026amp;lt;/span\u0026gt; Paint paint = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Paint(); paint.setColor(Color.RED); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//向画布绘制,绘制原图内容\u0026amp;lt;/span\u0026gt; canvas.drawBitmap(bitmap, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Matrix(), paint); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//canvas.drawPoint(10, 10, paint); 向指定位置画一个点\u0026amp;lt;/span\u0026gt; iv.setImageBitmap(copybm); ` ## 图片旋转 \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` `ImageView iv = (ImageView) findViewById(R.id.iv); \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;/**\n图片旋转: *Android中原图是不能进行操作的,必须要先复制一张图到内存,然后再操作 *旋转是在绘制过程中进行的\n/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//加载原图\u0026lt;/span\u0026gt; Bitmap bitmap = BitmapFactory.decodeFile(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026quot;/mnt/sdcard/1.jpg\u0026quot;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//搞一个一样大小一样样式的复制图\u0026lt;/span\u0026gt; Bitmap copybm = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//获取复制图的画布\u0026lt;/span\u0026gt; Canvas canvas = \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt; Canvas(copybm); \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//获取一个画笔,设置颜色\u0026lt;/span\u0026gt; Paint paint = \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt; Paint(); paint.setColor(Color.RED); \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//设置图片绘制角度——设置矩阵\u0026lt;/span\u0026gt; Matrix matrix = \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt; Matrix(); \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;/* matrix.setValues(new float[]{//这是矩阵的默认值 1.5f,0,0, 0,1,0, 0,0,1 }); 而旋转其实是将每个点坐标和sinx cosx进行计算\u0026hellip; */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//安卓提供了便捷方法\u0026lt;/span\u0026gt; matrix.setRotate(\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;30\u0026lt;/span\u0026gt;,bitmap.getWidth()/\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;2\u0026lt;/span\u0026gt;,bitmap.getHeight()/\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;2\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//向画布绘制,绘制原图内容\u0026lt;/span\u0026gt; canvas.drawBitmap(bitmap, matrix, paint); \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//canvas.drawPoint(10, 10, paint); 向指定位置画一个点\u0026lt;/span\u0026gt; iv.setImageBitmap(copybm); ` ## 改变图片大小和位置 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` `ImageView iv = (ImageView) findViewById(R.id.iv); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//加载原图\u0026amp;lt;/span\u0026gt; Bitmap bitmap = BitmapFactory.decodeFile(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;/mnt/sdcard/1.jpg\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//搞一个一样大小一样样式的复制图\u0026amp;lt;/span\u0026gt; Bitmap copybm = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获取复制图的画布\u0026amp;lt;/span\u0026gt; Canvas canvas = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Canvas(copybm); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获取一个画笔,设置颜色\u0026amp;lt;/span\u0026gt; Paint paint = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Paint(); paint.setColor(Color.RED); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置图片绘制角度——设置矩阵\u0026amp;lt;/span\u0026gt; Matrix matrix = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Matrix(); matrix.setValues(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;[]{\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//这是矩阵的默认值\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt; }); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** 位置矩阵计算公式(以默认值为例,计算x、y、z轴的值): x = 1x+0y+0z; y = 0x+1y+0z; z = 0x+0y+1z; 通过改变矩阵值可以修改图片 //图像的缩放也可以使用Android中自带的方法进行设置 matrix.setScale(0.5f, 0.5f); */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//向画布绘制,绘制原图内容\u0026amp;lt;/span\u0026gt; canvas.drawBitmap(bitmap, matrix, paint); iv.setImageBitmap(copybm); ` ## 镜像 \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` Matrix matrix = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; Matrix(); matrix.setValues(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026amp;lt;/span\u0026gt;[]{\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//这是矩阵的默认值\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;-1\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1\u0026amp;lt;/span\u0026gt; }); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//镜像完还要平移回来\u0026amp;lt;/span\u0026gt; matrix.postTranslate(bitmap.getWidth(), \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//向画布绘制,绘制原图内容\u0026amp;lt;/span\u0026gt; canvas.drawBitmap(bitmap, matrix, paint); ## 倒影 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` `Matrix matrix = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Matrix(); matrix.setValues(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;[]{\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//这是矩阵的默认值\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;-1\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt; }); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//镜像完还要平移回来\u0026amp;lt;/span\u0026gt; matrix.postTranslate(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, bitmap.getHeight()); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//向画布绘制,绘制原图内容\u0026amp;lt;/span\u0026gt; canvas.drawBitmap(bitmap, matrix, paint); iv.setImageBitmap(copybm); ` ## 颜色处理 \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//加载原图\u0026amp;lt;/span\u0026gt; Bitmap bitmap = BitmapFactory.decodeFile(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;/mnt/sdcard/1.jpg\u0026quot;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//搞一个一样大小一样样式的复制图\u0026amp;lt;/span\u0026gt; Bitmap copybm = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//获取复制图的画布\u0026amp;lt;/span\u0026gt; Canvas canvas = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; Canvas(copybm); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//获取一个画笔,设置颜色\u0026amp;lt;/span\u0026gt; Paint paint = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; Paint(); paint.setColor(Color.RED); ColorMatrix cm = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; ColorMatrix(); cm.\u0026amp;lt;span class=\u0026quot;hljs-built_in\u0026quot;\u0026gt;set\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//默认颜色矩阵,通过修改rgba来对图片颜色进行处理\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026amp;lt;/span\u0026gt;[]{ \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, } ); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;/* 颜色矩阵计算公式: red = 1*128 + 0*128 + 0*128 + 0*0 +0 blue = 0*128 + 1*128 + 0*128 + 0*0 +0 green = 0*128 + 0*128 + 1*128 + 0*0 +0 alpha = 0*128 + 0*128 + 0*128 + 1*0 +0 透明度 */\u0026amp;lt;/span\u0026gt; paint.setColorFilter(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; ColorMatrixColorFilter(cm)); canvas.drawBitmap(bitmap,\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; Matrix(), paint); iv.setImageBitmap(copybm); ## 圆角图 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; Bitmap \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getRoundedCornerBitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Bitmap bitmap, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; roundPx)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); Canvas canvas = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Canvas(output); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; color = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0xff424242\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; Paint paint = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Paint(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; Rect rect = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Rect(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, bitmap.getWidth(), bitmap.getHeight()); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; RectF rectF = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; RectF(rect); paint.setAntiAlias(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;); canvas.drawARGB(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; output; } ` ## 图片添加倒影效果 \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` `\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;/** * 获得带倒影的图片方法 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;static\u0026lt;/span\u0026gt; Bitmap \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;createReflectionImageWithOrigin\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;(Bitmap bitmap)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; reflectionGap = \u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;4\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; width = bitmap.getWidth(); \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; height = bitmap.getHeight();\nMatrix matrix = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; Matrix(); matrix.preScale(\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1\u0026amp;lt;/span\u0026gt;, -\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1\u0026amp;lt;/span\u0026gt;); Bitmap reflectionImage = Bitmap.createBitmap(bitmap, \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, height / \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;2\u0026amp;lt;/span\u0026gt;, width, height / \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;2\u0026amp;lt;/span\u0026gt;, matrix, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;); Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + height / \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;2\u0026amp;lt;/span\u0026gt;), Config.ARGB_8888); Canvas canvas = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; Canvas(bitmapWithReflection); canvas.drawBitmap(bitmap, \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;); Paint deafalutPaint = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; Paint(); canvas.drawRect(\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, height, width, height + reflectionGap, deafalutPaint); canvas.drawBitmap(reflectionImage, \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, height + reflectionGap, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;); Paint paint = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; Paint(); LinearGradient shader = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; LinearGradient(\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, bitmap.getHeight(), \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, bitmapWithReflection.getHeight() + reflectionGap, \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0x70ffffff\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0x00ffffff\u0026amp;lt;/span\u0026gt;, TileMode.CLAMP); paint.setShader(shader); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// Set the Transfer mode to be porter duff and destination in\u0026amp;lt;/span\u0026gt; paint.setXfermode(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; PorterDuffXfermode(Mode.DST_IN)); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// Draw a rectangle using the paint with our linear gradient\u0026amp;lt;/span\u0026gt; canvas.drawRect(\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, height, width, bitmapWithReflection.getHeight() + reflectionGap, paint); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; bitmapWithReflection; } `\n## 添加水印 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` ` \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * create the bitmap from a byte array 生成水印图片 * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; src * 要添加水印的图片 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; 水印 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; 添加了水印的图片 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; Bitmap \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;createBitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Bitmap src, Bitmap watermark)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ String tag = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;createBitmap\u0026#34;\u0026amp;lt;/span\u0026gt;; Log.d(tag, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;create a new bitmap\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (src == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; w = src.getWidth(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; h = src.getHeight(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; ww = watermark.getWidth(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; wh = watermark.getHeight(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// create the new blank bitmap\u0026amp;lt;/span\u0026gt; Bitmap newb = Bitmap.createBitmap(w, h, Config.ARGB_8888);\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 创建一个新的和SRC长度宽度一样的位图\u0026amp;lt;/span\u0026gt; Canvas cv = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Canvas(newb); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// draw src into\u0026amp;lt;/span\u0026gt; cv.drawBitmap(src, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;);\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 在 0，0坐标开始画入src\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// draw watermark into\u0026amp;lt;/span\u0026gt; cv.drawBitmap(watermark, w - ww + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;, h - wh + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;);\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 在src的右下角画入水印\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// save all clip\u0026amp;lt;/span\u0026gt; cv.save(Canvas.ALL_SAVE_FLAG);\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 保存\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// store\u0026amp;lt;/span\u0026gt; cv.restore();\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 存储\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; newb; } ` ## View转成Bitmap \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` ` \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;/** * 把一个View的对象转换成bitmap */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;static\u0026lt;/span\u0026gt; Bitmap \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;getViewBitmap\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;(View v)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\nv.clearFocus(); v.setPressed(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 能画缓存就返回false\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; willNotCache = v.willNotCacheDrawing(); v.setWillNotCacheDrawing(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; color = v.getDrawingCacheBackgroundColor(); v.setDrawingCacheBackgroundColor(\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt; (color != \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { v.destroyDrawingCache(); } v.buildDrawingCache(); Bitmap cacheBitmap = v.getDrawingCache(); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt; (cacheBitmap == \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { Log.e(TAG, \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;failed getViewBitmap(\u0026quot;\u0026amp;lt;/span\u0026gt; + v + \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;)\u0026quot;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; RuntimeException()); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;; } Bitmap bitmap = Bitmap.createBitmap(cacheBitmap); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// Restore the view\u0026amp;lt;/span\u0026gt; v.destroyDrawingCache(); v.setWillNotCacheDrawing(willNotCache); v.setDrawingCacheBackgroundColor(color); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; bitmap; } `\n\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;!-- 如果是付费文章，未购买，则显示购买按钮 --\u0026gt; \u0026lt;!-- 连载目录项 --\u0026gt; \u0026lt;!-- 如果是付费文章 --\u0026gt; \u0026lt;!-- 如果是付费连载，已购买，且作者允许赞赏，则显示付费信息和赞赏 --\u0026gt; \u0026lt;div id=\u0026#34;free-reward-panel\u0026#34; class=\u0026#34;support-author\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 转自：https://www.jianshu.com/p/fe1955cdbc1f \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android%E5%9B%BE%E7%89%87%E4%B9%8B%E5%A4%84%E7%90%86%E5%9C%86%E5%BD%A2%E5%9C%86%E8%A7%92/","summary":"\u003cdiv\u003e\n  \u003cdiv\u003e\n    \u003cdiv class=\"article\"\u003e\n      \u003cdiv class=\"show-content\" data-note-content=\"\"\u003e\n        \u003cdiv class=\"show-content-free\"\u003e\n\u003cpre\u003e\u003ccode\u003e        # 概述\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"图片格式概述\"\u003e图片格式概述:\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e        BMP:高质量绘图 保证原图质量，用于相机等\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eBMP格式图片是有一个一个的像素点组成,每一个像素都是一个颜色.而每一个像素显示的颜色用的二进制位也不相同，这个像素位称之为位深，位深越大，表示每一个像素点所用的二进制位越多，显示的图像也就越清晰。\npng：较高质量绘图 体积小，适用于网络传输\npng图片是将bmp图片进行压缩，其压缩格式类似于rar压缩——将相同的byte信息合并表示。png图片可以还原，是无损的压缩方式。\njpg：良好的绘图质量 体积小，便于传输\njpg格式图片也是对bmp图片进行压缩，因为眼睛的精度是有限的，jpg利用这一点将很多颜色相近的用同一颜色标识，而对于一大块相同的颜色，则用一个值表示。jpg格式图片不能被还原。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e        ## 加载大图\n      \n\n      \n      \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003ehr \u0026amp;\u0026amp; wr\u0026gt;1){\nr = wr;\n}\nif(hr\u0026gt;wr \u0026amp;\u0026amp; hr\u0026gt;1){\nr = hr;\n}\n//压缩图片\noptions.inSampleSize = r;//设置压缩比\noptions.inJustDecodeBounds = false;//设置加载图片内容\nBitmap bm = BitmapFactory.decodeFile(path,options);\niv.setImageBitmap(bm);\n\u0026quot; data-snippet-id=\u0026ldquo;ext.f5fc8efb9581248b791731039403eb80\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;`ImageView iv = (ImageView) findViewById(R.id.iv);\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e在Android中,每一个应用程序所占用的内存空间大小都会有一个固定的大小限制\u003c/li\u003e\n\u003cli\u003e假设此处加载的图片是2560*1440像素,图片位深是24的jpg格式图像\u003c/li\u003e\n\u003cli\u003e虽然此图占用的磁盘空间是1.3M,但图片在加载到内存中时,实际上会先转换成位图图像\u003c/li\u003e\n\u003cli\u003e那么这张图片加载到内存中的大小就是2560\u003cem\u003e1440\u003c/em\u003e32(位深24,windows系统中,使用24位字节表示一个颜色值:#000000,\u003c/li\u003e\n\u003cli\u003e但在Android中,每一个颜色值是用32位字节表示一个颜色值:#00000000),因此,这张图片加载到内存中所需要占用的内存\u003c/li\u003e\n\u003cli\u003e大小约为:14M,因此,占用内存是极大的.若是直接将图片加载到内存中,容易造成内存溢出\u003c/li\u003e\n\u003cli\u003e解决方案:按比例压缩图片\n*按比例压缩图片首先就是要获取图片的大小\u003c/li\u003e\n\u003cli\u003e*/\u0026lt;/span\u0026gt;\nString path = \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;mnt/sdcard/1.jpg\u0026rdquo;\u0026lt;/span\u0026gt;;\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//用于设置图片渲染器参数\u0026lt;/span\u0026gt;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eBitmapFactory.Options options = \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt; Options();\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//设置图片加载属性:不加载图片内容,只获取图片信息\u0026lt;/span\u0026gt;\noptions.inJustDecodeBounds = \u0026lt;span class=\u0026ldquo;hljs-literal\u0026rdquo;\u0026gt;true\u0026lt;/span\u0026gt;;\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//加载图片信息\u0026lt;/span\u0026gt;\nBitmapFactory.decodeFile(path,options);\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//获取图片宽高\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; picwidth = options.outWidth;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; picheight = options.outHeight;\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//获取屏幕大小\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//获取窗口管理器\u0026lt;/span\u0026gt;\nWindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);\u003cbr\u003e\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//获取默认显示设备\u0026lt;/span\u0026gt;\nDisplay dis =wm.getDefaultDisplay();\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//获取屏幕宽高\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//dis.getSize(outSize);此方法适用于新版本Android系统\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; diswidth = dis.getWidth();\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; disheight = dis.getHeight();\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//计算压缩比\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; wr = picwidth/diswidth;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; hr = picheight/disheight;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt;  r = \u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;1\u0026lt;/span\u0026gt;;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt;(wr\u0026gt;hr \u0026amp;\u0026amp; wr\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;1\u0026lt;/span\u0026gt;){\nr = wr;\n}\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt;(hr\u0026gt;wr \u0026amp;\u0026amp; hr\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;1\u0026lt;/span\u0026gt;){\nr = hr;\n}\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//压缩图片\u0026lt;/span\u0026gt;\noptions.inSampleSize = r;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//设置压缩比\u0026lt;/span\u0026gt;\noptions.inJustDecodeBounds = \u0026lt;span class=\u0026ldquo;hljs-literal\u0026rdquo;\u0026gt;false\u0026lt;/span\u0026gt;;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//设置加载图片内容\u0026lt;/span\u0026gt;\nBitmap bm = BitmapFactory.decodeFile(path,options);\niv.setImageBitmap(bm);\n`\u003c/p\u003e","title":"Android图片之处理圆形圆角"},{"content":" ## 为何要使用301重定向 在网站建设中需要网页重定向的情况很多：如网页目录结构变动，网页重命名、网页的扩展名改变、网站域名改变等。如果不做重定向，用户的收藏和搜索引擎数据库中的旧地址只能让访客得到一个404错误信息页面，访问流量白白丧失。不仅如此，之前该页面的一切积累（比如PR值）就都白费了。 301重定向不仅能使页面实现自动跳转，对于搜索引擎来说，也可能可以传递PR值。 \u0026amp;nbsp; **nginx重定向规则详细介绍** \u0026amp;nbsp; [http://www.jefflei.com/post/1015.html](http://www.jefflei.com/post/1015.html) **rewrite命令** nginx的rewrite相当于apache的rewriterule(大多数情况下可以把原有apache的rewrite规则加上引号就可以直接使用)，它可以用在server,location 和IF条件判断块中,命令格式如下： rewrite 正则表达式 替换目标 flag标记 flag标记可以用以下几种格式： last – 基本上都用这个Flag。 break – 中止Rewirte，不在继续匹配 redirect – 返回临时重定向的HTTP状态302 permanent – 返回永久重定向的HTTP状态301 例如下面这段设定nginx将某个目录下面的文件重定向到另一个目录,2对应第二个括号(.)中对应的字符串： location /download/ { rewrite ^(/download/.)/m/(.).. 1/nginx-rewrite/2.gz break; }\n**nginx重定向的IF条件判断** 在server和location两种情况下可以使用nginx的IF条件判断，条件可以为以下几种： 正则表达式\n如： 匹配判断 ~ 为区分大小写匹配; !~为区分大小写不匹配 ~* 为不区分大小写匹配；!~为不区分大小写不匹配 例如下面设定nginx在用户使用ie的使用重定向到/nginx-ie目录下： if (http_user_agent ~ MSIE) { rewrite ^(.*) /nginx-ie/$1 break; } **文件和目录判断 ** -f和!-f判断是否存在文件 -d和!-d判断是否存在目录 -e和!-e判断是否存在文件或目录 -x和!-x判断文件是否可执行 例如下面设定nginx在文件和目录不存在的时候重定向： if (!-e $request_filename) { proxy_pass http://127.0.0.1/; }\n**return** 返回http代码，例如设置nginx防盗链： location ~* .(gif|jpg|png|swf|flv)$ { valid_referers none blocked http://www.jefflei.com/ http://www.leizhenfang.com/; if ($invalid_referer) { return 404; } }\n**set** 设置nginx变量\n\u0026amp;nbsp; \u0026amp;nbsp; **301重定向方法** 进行了301重定向，把www .jefflei.com和jefflei.com合并，并把之前的域名也一并合并. 有两种实现方法,第一种方法是判断nginx核心变量host(老版本是http_host)： `server {\u0026amp;lt;br /\u0026gt; server_name www.jefflei.com jefflei.com ;\u0026lt;br /\u0026gt; if (\u0026lt;span class=\u0026ldquo;katex math inline\u0026rdquo;\u0026gt;host != \u0026lsquo;www.jefflei.com\u0026rsquo; ) {\u0026lt;br /\u0026gt; rewrite ^/(.*)\u0026lt;/span\u0026gt; http://www.jefflei.com/$1 permanent;\u0026lt;br /\u0026gt; }\u0026lt;br /\u0026gt; \u0026hellip;\u0026lt;br /\u0026gt; }` 第二种方法：\n`server {\u0026amp;lt;br /\u0026gt; server_name jefflei.com;\u0026lt;br /\u0026gt; rewrite ^/(.*) http://www.jefflei.com/$1 permanent;\u0026lt;br /\u0026gt; }``测试了`第一种方法ok，这两种方法中， permanent是关键，详细说明见nginx重定向规则说明。\nlast – 基本上都用这个Flag。 break – 中止Rewirte，不在继续匹配 redirect – 返回临时重定向的HTTP状态302 permanent – 返回永久重定向的HTTP状态301\n好了,现在可以检查结果，这里可以看返回的HTTP头信息： [http://www.seoconsultants.com/tools/headers.asp](http://www.seoconsultants.com/tools/headers.asp) 第二种方法没有测试成功\u0026amp;#8230; \u0026amp;nbsp; \u0026amp;nbsp; **测试是否定向成功** [http://qinfy.net/301-redirect-for-nginx/](http://qinfy.net/301-redirect-for-nginx/) 输入指令~ **\n/usr/local/nginx/sbin/nginx -t 提示： the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok configuration file /usr/local/nginx/conf/nginx.conf test is successful**\n测试成功~ 重启nginx~ 输入指令~ **\n/usr/local/nginx/sbin/nginx -s reload 重启之后测试一下~是否成功设定完成！ 输入指令~ curl -I imcat.tk \u0026amp;nbsp; 会输出： \u0026lt;strong\u0026gt;HTTP/1.1 301 Moved Permanently Server: nginx/0.7.65 Date: Tue, 03 Aug 2010 01:12:37 GMT Content-Type: text/html Content-Length: 185 Connection: keep-alive Location: http://qinfy.net/**\n\u0026amp;nbsp; \u0026amp;nbsp; **nginx rewrite 伪静态配置参数详细说明（转）** [http://hi.baidu.com/hx10/blog/item/942a0ad784f3ffd0a144df94.html](http://hi.baidu.com/hx10/blog/item/942a0ad784f3ffd0a144df94.html) nginx rewrite 伪静态配置参数和使用例子 附正则使用说明 **正则表达式匹配，其中：** * ~ 为区分大小写匹配 ~* 为不区分大小写匹配\n!和!*分别为区分大小写不匹配及不区分大小写不匹配\n文件及目录匹配，其中：\n-f和!-f用来判断是否存在文件 -d和!-d用来判断是否存在目录\n-e和!-e用来判断是否存在文件或目录\n-x和!-x用来判断文件是否可执行 flag标记有：\nlast 相当于Apache里的[L]标记，表示完成rewrite break 终止匹配, 不再匹配后面的规则\nredirect 返回302临时重定向 地址栏会显示跳转后的地址\npermanent 返回301永久重定向 地址栏会显示跳转后的地址 一些可用的全局变量有，可以用做条件判断(待补全)\nargscontent_length content_typedocument_root document_urihost http_user_agenthttp_cookie limit_raterequest_body_file request_methodremote_addr remote_portremote_user request_filenamerequest_uri query_stringscheme server_protocolserver_addr server_nameserver_port uri 结合QeePHP的例子\nif (!-drequest_filename) { rewrite ^/([a-z-A-Z]+)/([a-z-A-Z]+)/?(.*)/index.php?namespace=user\u0026amp;controller=1\u0026amp;action=2\u0026amp;3 last; rewrite ^/([a-z-A-Z]+)/?/index.php?namespace=user\u0026amp;controller=1 last; break; **多目录转成参数 **abc.domian.com/sort/2 =\u0026gt; abc.domian.com/index.php?act=sort\u0026amp;name=abc\u0026amp;id=2\nif (host ~* (.*).domain.com) { setsub_name 1; rewrite ^/sort/(\\d+)/? /index.php?act=sort\u0026amp;cid=sub_name\u0026amp;id=1 last; } **目录对换 **/123456/xxxx -\u0026gt; /xxxx?id=123456\nrewrite ^/(\\d+)/(.+)/ /2?id=1 last; 例如下面设定nginx在用户使用ie的使用重定向到/nginx-ie目录下：\nif (http_user_agent ~ MSIE) { rewrite ^(.*) /nginx-ie/$1 break; } 目录自动加“/”\nif (-d request_filename){ rewrite ^/(.*)([^/]) http://host/1$2/ permanent; } 禁止htaccess\nlocation ~/.ht { deny all; } 禁止多个目录\nlocation ~ ^/(cron|templates)/ { deny all; break; } 禁止以/data开头的文件 可以禁止/data/下多级目录下.log.txt等请求;\nlocation ~ ^/data { deny all; } 禁止单个目录 不能禁止.log.txt能请求\nlocation /searchword/cron/ { deny all; } 禁止单个文件\nlocation ~ /data/sql/data.sql { deny all; } 给favicon.ico和robots.txt设置过期时间; 这里为favicon.ico为99 天,robots.txt为7天并不记录404错误日志\nlocation ~(favicon.ico) { log_not_found off; expires 99d; break; }\nlocation ~(robots.txt) { log_not_found off; expires 7d; break; } 设定某个文件的过期时间;这里为600秒，并不记录访问日志\nlocation ^~ /html/scripts/loadhead_1.js { access_log off; root /opt/lampp/htdocs/web; expires 600; break; } 文件反盗链并设置过期时间 这里的return 412 为自定义的http状态码，默认为403，方便找出正确的盗链的请求 “rewrite ^/ http://leech.c1gstudio.com/leech.gif;”显示一张防盗链图片 “access_log off;”不记录访问日志，减轻压力 “expires 3d”所有文件3天的浏览器缓存\nlocation ~* ^.+.(jpg|jpeg|gif|png|swf|rar|zip|css|js){ valid_referers none blocked *.c1gstudio.com *.c1gstudio.net localhost 208.97.167.194; if (invalid_referer) { rewrite ^/ http://leech.c1gstudio.com/leech.gif; return 412; break; } access_log off; root /opt/lampp/htdocs/web; expires 3d; break; } 只充许固定ip访问网站，并加上密码\nroot /opt/htdocs/www; allow 208.97.167.194; allow 222.33.1.2; allow 231.152.49.4; deny all; auth_basic “C1G_ADMIN”; auth_basic_user_file htpasswd; 将多级目录下的文件转成一个文件，增强seo效果 /job-123-456-789.html 指向/job/123/456/789.html\nrewrite ^/job-([0-9]+)-([0-9]+)-([0-9]+).html/job/1/2/jobshow_3.html last; 将根目录下某个文件夹指向2级目录 如/shanghaijob/ 指向 /area/shanghai/ 如果你将last改成permanent，那么浏览器地址栏显是 /location/shanghai/\nrewrite ^/([0-9a-z]+)job/(.*)/area/1/$2 last; 上面例子有个问题是访问/shanghai 时将不会匹配\nrewrite ^/([0-9a-z]+)job/area/1/ last; rewrite ^/([0-9a-z]+)job/(.*)/area/1/2 last; 这样/shanghai 也可以访问了，但页面中的相对链接无法使用， 如./list_1.html真实地址是/area /shanghia/list_1.html会变成/list_1.html,导至无法访问。\n那我加上自动跳转也是不行咯 (-drequest_filename)它有个条件是必需为真实目录，而我的rewrite不是的，所以没有效果\nif (-d \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;request_filename){ rewrite ^/(.*)([^/]) http://host/1$2/ permanent; } 知道原因后就好办了，让我手动跳转吧\nrewrite ^/([0-9a-z]+)job\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;1job/ permanent; rewrite ^/([0-9a-z]+)job/(.*)/area/1/2 last; 文件和目录不存在的时候重定向：\nif (!-e\u0026lt;/span\u0026gt;request_filename) { proxy_pass http://127.0.0.1/; } 域名跳转\nserver { listen 80; server_name jump.c1gstudio.com; index index.html index.htm index.php; root /opt/lampp/htdocs/www; rewrite ^/ http://www.c1gstudio.com/; access_log off; } 多域名转向\nserver_name [http://www.c1gstudio.com/](http://www.c1gstudio.com/) [http://www.c1gstudio.net/](http://www.c1gstudio.net/); index index.html index.htm index.php; root /opt/lampp/htdocs; if ($host ~ “c1gstudio.net”) { rewrite ^(.*) http://www.c1gstudio.com$1/ permanent; } 三级域名跳转\nif (\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;http_host ~* \u0026amp;#8220;^(.*)\\.i\\.c1gstudio\\.com\u0026lt;/span\u0026gt;\u0026amp;#8220;) { rewrite ^(.*) http://top.yingjiesheng.com$1/; break; } 域名镜向\nserver { listen 80; server_name mirror.c1gstudio.com; index index.html index.htm index.php; root /opt/lampp/htdocs/www; rewrite ^/(.*) http://www.c1gstudio.com/$1 last; access_log off; } 某个子目录作镜向\nlocation ^~ /zhaopinhui { rewrite ^.+ http://zph.c1gstudio.com/ last; break; } discuz ucenter home (uchome) rewrite\nrewrite ^/(space|network)-(.+)\\.html\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;1.php?rewrite=\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;2 last; rewrite ^/(space|network).html /1.php last; rewrite ^/([0-9]+) /space.php?uid=1 last; discuz 7 rewrite\nrewrite ^(.*)/archiver/((fid|tid)-[\\w\\-]+\\.html)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;1/archiver/index.php?\u0026lt;/span\u0026gt;2 last; rewrite ^(.)/forum-([0-9]+)-([0-9]+).html1/forumdisplay.php?fid=2\u0026amp;page=3 last; rewrite ^(.)/thread-([0-9]+)-([0-9]+)-([0-9]+).html1/viewthread.php?tid=2\u0026amp;extra=page%3D4\u0026amp;page=3 last; rewrite ^(.)/profile-(username|uid)-(.+).html 1/viewpro.php?2=3 last; rewrite ^(.)/space-(username|uid)-(.+).html 1/space.php?2=3 last; rewrite ^(.*)/tag-(.+).html 1/tag.php?name=2 last; 给discuz某版块单独配置域名\nserver_name bbs.c1gstudio.com news.c1gstudio.com; location = / { if (http_host ~ news.c1gstudio.com) { rewrite ^.+ http://news.c1gstudio.com/forum-831-1.html last; break; } } discuz ucenter 头像 rewrite 优化\nlocation ^~ /ucenter { location ~ .*.php?{ #fastcgi_pass unix:/tmp/php-cgi.sock; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fcgi.conf; }\nlocation /ucenter/data/avatar { log_not_found off; access_log off; location ~ /(.)_big.jpg { error_page 404 /ucenter/images/noavatar_big.gif; } location ~ /(.)_middle.jpg{ error_page 404 /ucenter/images/noavatar_middle.gif; } location ~ /(.*)_small.jpg { error_page 404 /ucenter/images/noavatar_small.gif; } expires 300; break; } } jspace rewrite\nlocation ~ .*\\.php?\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;{ #fastcgi_pass unix:/tmp/php-cgi.sock; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fcgi.conf; }\nlocation ~* ^/index.php/ { rewrite ^/index.php/(.*) /index.php?1 break; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fcgi.conf; }\n\u0026lt;div class=\u0026quot;clear\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;blog_post_info_block\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 修改nginx.conf 的server_name部分 \u0026lt;div id=\u0026quot;crayon-5c0dc060872db938929751\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-mac print-yes notranslate\u0026quot; data-settings=\u0026quot; minimize scroll-mouseover\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt; \u0026lt;table class=\u0026quot;crayon-table\u0026quot;\u0026gt; \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;crayon-nums \u0026quot; data-settings=\u0026quot;show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-5c0dc060872db938929751-1\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-5c0dc060872db938929751-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-5c0dc060872db938929751-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-5c0dc060872db938929751-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-5c0dc060872db938929751-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;server_name \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;findname\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;cc \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;www\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;findname\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;cc\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-5c0dc060872db938929751-2\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;$\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;host\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;~\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;www\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;findname\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;cc\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-5c0dc060872db938929751-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;rewrite\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;^\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;$\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;http\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;//findname.cc/$1 permanent; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-5c0dc060872db938929751-4\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; ![](http://www.nginx.cn/images/2013/01/servername.gif) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/nginx-301%E9%87%8D%E5%AE%9A%E5%90%91%E5%9F%9F%E5%90%8D/","summary":"\u003cdiv id=\"cnblogs_post_body\" class=\"blogpost-body\"\u003e\n  ## 为何要使用301重定向\n\u003cpre\u003e\u003ccode\u003e在网站建设中需要网页重定向的情况很多：如网页目录结构变动，网页重命名、网页的扩展名改变、网站域名改变等。如果不做重定向，用户的收藏和搜索引擎数据库中的旧地址只能让访客得到一个404错误信息页面，访问流量白白丧失。不仅如此，之前该页面的一切积累（比如PR值）就都白费了。\n\n\n\n\n\n301重定向不仅能使页面实现自动跳转，对于搜索引擎来说，也可能可以传递PR值。\n\n\n\n\n\n\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003chr /\u003e\n\u003cpre\u003e\u003ccode\u003e**nginx重定向规则详细介绍**\n\n\n\n\n\n\u0026amp;nbsp;\n\n\n\n\n\n[http://www.jefflei.com/post/1015.html](http://www.jefflei.com/post/1015.html)\n\n\n\n\n\n**rewrite命令**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003enginx的rewrite相当于apache的rewriterule(大多数情况下可以把原有apache的rewrite规则加上引号就可以直接使用)，它可以用在server,location 和IF条件判断块中,命令格式如下：\nrewrite 正则表达式 替换目标 flag标记\nflag标记可以用以下几种格式：\nlast – 基本上都用这个Flag。\nbreak – 中止Rewirte，不在继续匹配\nredirect – 返回临时重定向的HTTP状态302\npermanent – 返回永久重定向的HTTP状态301\n例如下面这段设定nginx将某个目录下面的文件重定向到另一个目录,\u003cspan class=\"katex math inline\"\u003e2对应第二个括号(.\u003cem\u003e)中对应的字符串：\nlocation /download/ {\nrewrite ^(/download/.\u003c/em\u003e)/m/(.\u003cem\u003e)..\u003c/em\u003e\u003c/span\u003e \u003cspan class=\"katex math inline\"\u003e1/nginx-rewrite/\u003c/span\u003e2.gz break;\n}\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**nginx重定向的IF条件判断**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在server和location两种情况下可以使用nginx的IF条件判断，条件可以为以下几种：\n\u003cstrong\u003e正则表达式\u003c/strong\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e如：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cstrong\u003e匹配判断\u003c/strong\u003e\n~  为区分大小写匹配; !~为区分大小写不匹配\n~* 为不区分大小写匹配；!~为不区分大小写不匹配\n例如下面设定nginx在用户使用ie的使用重定向到/nginx-ie目录下：\nif (\u003cspan class=\"katex math inline\"\u003ehttp_user_agent ~ MSIE) {\nrewrite ^(.*)\u003c/span\u003e /nginx-ie/$1 break;\n}\n**文件和目录判断\n**  -f和!-f判断是否存在文件\n-d和!-d判断是否存在目录\n-e和!-e判断是否存在文件或目录\n-x和!-x判断文件是否可执行\n例如下面设定nginx在文件和目录不存在的时候重定向：\nif (!-e $request_filename) {\nproxy_pass \u003ca href=\"http://127.0.0.1/\"\u003ehttp://127.0.0.1/\u003c/a\u003e;\n}\u003c/p\u003e","title":"Nginx 301重定向域名"},{"content":"tomcat默认情况下不带www的域名是不会跳转到带www的域名的，而且也无法像apache那样通过配置.htaccess来实现。如果想要把不带“www’的域名重定向到带”www”域名下，又不想写代码，可以使用UrlRewriteFilter来实现。\n1.简介 urlRewriteFilter是一个用于改写URL的Web过滤器，类似于Apache的mod_rewrite。适用于任何Web应用服务器（如 Tomcat,jboss,jetty,Resin，Orion等）。其典型应用就把动态URL静态化，便于搜索引擎爬虫抓取你的动态网页。\n2.下载 下载UrlRewriteFilter\nwget http://urlrewritefilter.googlecode.com/files/urlrewritefilter-4.0.3.jar 并放入tomcat的 WEB-INF/lib下\n3.配置tomcat 编辑WEB-INF/web.xml 在其它servlet mapping前加入\n\u0026lt;filter-name\u0026gt;UrlRewriteFilter\u0026lt;/filter-name\u0026gt; \u0026lt;filter-class\u0026gt;org.tuckey.web.filters.urlrewrite.UrlRewriteFilter\u0026lt;/filter-class\u0026gt; \u0026lt;/filter\u0026gt; \u0026lt;filter-mapping\u0026gt; \u0026lt;filter-name\u0026gt;UrlRewriteFilter\u0026lt;/filter-name\u0026gt; \u0026lt;url-pattern\u0026gt;/*\u0026lt;/url-pattern\u0026gt; \u0026lt;dispatcher\u0026gt;REQUEST\u0026lt;/dispatcher\u0026gt; \u0026lt;dispatcher\u0026gt;FORWARD\u0026lt;/dispatcher\u0026gt; \u0026lt;/filter-mapping\u0026gt;\u0026#34; data-snippet-id=\u0026#34;ext.d9335c889eb8c29f7d0586484daf2dcb\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;\u0026amp;lt;filter\u0026amp;gt; \u0026amp;lt;filter-name\u0026amp;gt;UrlRewriteFilter\u0026amp;lt;/filter-name\u0026amp;gt; \u0026amp;lt;filter-class\u0026amp;gt;org.tuckey.web.filters.urlrewrite.UrlRewriteFilter\u0026amp;lt;/filter-class\u0026amp;gt; \u0026amp;lt;/filter\u0026amp;gt; \u0026amp;lt;filter-mapping\u0026amp;gt; \u0026amp;lt;filter-name\u0026amp;gt;UrlRewriteFilter\u0026amp;lt;/filter-name\u0026amp;gt; \u0026amp;lt;url-pattern\u0026amp;gt;/*\u0026amp;lt;/url-pattern\u0026amp;gt; \u0026amp;lt;dispatcher\u0026amp;gt;REQUEST\u0026amp;lt;/dispatcher\u0026amp;gt; \u0026amp;lt;dispatcher\u0026amp;gt;FORWARD\u0026amp;lt;/dispatcher\u0026amp;gt; \u0026amp;lt;/filter-mapping\u0026amp;gt; 4.添加跳转规则 在WEB-INF下新建urlrewite.xml文件，加入跳转规则\n\u0026lt;rule\u0026gt; \u0026lt;name\u0026gt;seo redirect\u0026lt;/name\u0026gt; \u0026lt;condition name=\u0026amp;quot;host\u0026amp;quot; operator=\u0026amp;quot;notequal\u0026amp;quot;\u0026gt;^www.example.com\u0026lt;/condition\u0026gt; \u0026lt;condition name=\u0026amp;quot;host\u0026amp;quot; operator=\u0026amp;quot;notequal\u0026amp;quot;\u0026gt;^localhost\u0026lt;/condition\u0026gt; \u0026lt;from\u0026gt;^/(.*)\u0026lt;/from\u0026gt; \u0026lt;to type=\u0026amp;quot;permanent-redirect\u0026amp;quot; last=\u0026amp;quot;true\u0026amp;quot;\u0026gt;http://www.example.com/$1\u0026lt;/to\u0026gt; \u0026lt;/rule\u0026gt; \u0026lt;/urlrewrite\u0026gt;\u0026#34; data-snippet-id=\u0026#34;ext.8be7c6714e65fa3f79b0e1c6c6215563\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;\u0026amp;lt;urlrewrite\u0026amp;gt; \u0026amp;lt;rule\u0026amp;gt; \u0026amp;lt;name\u0026amp;gt;seo redirect\u0026amp;lt;/name\u0026amp;gt; \u0026amp;lt;condition name=\u0026#34;host\u0026#34; operator=\u0026#34;notequal\u0026#34;\u0026amp;gt;^www.example.com\u0026amp;lt;/condition\u0026amp;gt; \u0026amp;lt;condition name=\u0026#34;host\u0026#34; operator=\u0026#34;notequal\u0026#34;\u0026amp;gt;^localhost\u0026amp;lt;/condition\u0026amp;gt; \u0026amp;lt;from\u0026amp;gt;^/(.*)\u0026amp;lt;/from\u0026amp;gt; \u0026amp;lt;to type=\u0026#34;permanent-redirect\u0026#34; last=\u0026#34;true\u0026#34;\u0026amp;gt;http://www.example.com/$1\u0026amp;lt;/to\u0026amp;gt; \u0026amp;lt;/rule\u0026amp;gt; \u0026amp;lt;/urlrewrite\u0026amp;gt; 参考文章 http://nematodes.org/martin/2010/02/04/301-permanent-redirect-with-tomcat-howto/\nhttp://tuckey.org/urlrewrite/\n","permalink":"https://blog.zdltech.com/posts/tomcat%E9%85%8D%E7%BD%AE301%E9%87%8D%E5%AE%9A%E5%90%91/","summary":"\u003cp\u003etomcat默认情况下不带www的域名是不会跳转到带www的域名的，而且也无法像apache那样通过配置.htaccess来实现。如果想要把不带“www’的域名重定向到带”www”域名下，又不想写代码，可以使用UrlRewriteFilter来实现。\u003c/p\u003e\n\u003ch2 id=\"1简介\"\u003e1.简介\u003c/h2\u003e\n\u003cp\u003eurlRewriteFilter是一个用于改写URL的Web过滤器，类似于Apache的mod_rewrite。适用于任何Web应用服务器（如 Tomcat,jboss,jetty,Resin，Orion等）。其典型应用就把动态URL静态化，便于搜索引擎爬虫抓取你的动态网页。\u003c/p\u003e\n\u003ch2 id=\"2下载\"\u003e2.下载\u003c/h2\u003e\n\u003cp\u003e下载UrlRewriteFilter\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n  \u003cdiv class=\"alert-info\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewget http://urlrewritefilter.googlecode.com/files/urlrewritefilter-4.0.3.jar\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e并放入tomcat的 WEB-INF/lib下\u003c/p\u003e\n\u003ch2 id=\"3配置tomcat\"\u003e3.配置tomcat\u003c/h2\u003e\n\u003cp\u003e编辑WEB-INF/web.xml 在其它servlet mapping前加入\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n  \u003cdiv class=\"alert-info\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;filter-name\u0026gt;UrlRewriteFilter\u0026lt;/filter-name\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;filter-class\u0026gt;org.tuckey.web.filters.urlrewrite.UrlRewriteFilter\u0026lt;/filter-class\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/filter\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;filter-mapping\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;filter-name\u0026gt;UrlRewriteFilter\u0026lt;/filter-name\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;url-pattern\u0026gt;/*\u0026lt;/url-pattern\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;dispatcher\u0026gt;REQUEST\u0026lt;/dispatcher\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;dispatcher\u0026gt;FORWARD\u0026lt;/dispatcher\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/filter-mapping\u0026gt;\u0026#34; data-snippet-id=\u0026#34;ext.d9335c889eb8c29f7d0586484daf2dcb\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;\u0026amp;lt;filter\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026amp;lt;filter-name\u0026amp;gt;UrlRewriteFilter\u0026amp;lt;/filter-name\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026amp;lt;filter-class\u0026amp;gt;org.tuckey.web.filters.urlrewrite.UrlRewriteFilter\u0026amp;lt;/filter-class\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/filter\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;filter-mapping\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026amp;lt;filter-name\u0026amp;gt;UrlRewriteFilter\u0026amp;lt;/filter-name\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026amp;lt;url-pattern\u0026amp;gt;/*\u0026amp;lt;/url-pattern\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026amp;lt;dispatcher\u0026amp;gt;REQUEST\u0026amp;lt;/dispatcher\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026amp;lt;dispatcher\u0026amp;gt;FORWARD\u0026amp;lt;/dispatcher\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/filter-mapping\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"4添加跳转规则\"\u003e4.添加跳转规则\u003c/h2\u003e\n\u003cp\u003e在WEB-INF下新建urlrewite.xml文件，加入跳转规则\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n  \u003cdiv class=\"alert-info\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;rule\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;name\u0026gt;seo redirect\u0026lt;/name\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;condition name=\u0026amp;quot;host\u0026amp;quot; operator=\u0026amp;quot;notequal\u0026amp;quot;\u0026gt;^www.example.com\u0026lt;/condition\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;condition name=\u0026amp;quot;host\u0026amp;quot; operator=\u0026amp;quot;notequal\u0026amp;quot;\u0026gt;^localhost\u0026lt;/condition\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;from\u0026gt;^/(.*)\u0026lt;/from\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;to type=\u0026amp;quot;permanent-redirect\u0026amp;quot; last=\u0026amp;quot;true\u0026amp;quot;\u0026gt;http://www.example.com/$1\u0026lt;/to\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;/rule\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/urlrewrite\u0026gt;\u0026#34; data-snippet-id=\u0026#34;ext.8be7c6714e65fa3f79b0e1c6c6215563\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;\u0026amp;lt;urlrewrite\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026amp;lt;rule\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026amp;lt;name\u0026amp;gt;seo redirect\u0026amp;lt;/name\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026amp;lt;condition name=\u0026#34;host\u0026#34; operator=\u0026#34;notequal\u0026#34;\u0026amp;gt;^www.example.com\u0026amp;lt;/condition\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026amp;lt;condition name=\u0026#34;host\u0026#34; operator=\u0026#34;notequal\u0026#34;\u0026amp;gt;^localhost\u0026amp;lt;/condition\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026amp;lt;from\u0026amp;gt;^/(.*)\u0026amp;lt;/from\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026amp;lt;to type=\u0026#34;permanent-redirect\u0026#34; last=\u0026#34;true\u0026#34;\u0026amp;gt;http://www.example.com/$1\u0026amp;lt;/to\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026amp;lt;/rule\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/urlrewrite\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"参考文章\"\u003e参考文章\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://nematodes.org/martin/2010/02/04/301-permanent-redirect-with-tomcat-howto/\"\u003ehttp://nematodes.org/martin/2010/02/04/301-permanent-redirect-with-tomcat-howto/\u003c/a\u003e\u003c/p\u003e","title":"tomcat配置301重定向"},{"content":"import it.sauronsoftware.base64.Base64;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SecureRandom;\nimport java.security.Security;\nimport javax.crypto.Cipher;\nimport javax.crypto.KeyGenerator;\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.SecretKeySpec;\nimport org.bouncycastle.jce.provider.BouncyCastleProvider;\n/**\njava实现AES256加密解密 依赖说明： bcprov-jdk15-133.jar：PKCS7Padding javabase64-1.3.1.jar：base64 local_policy.jar 和 US_export_policy.jar需添加到%JAVE_HOME%\\jre\\lib\\security中（lib中版本适合jdk1.7）\n*/ public class AES256 {\npublic static byte[] encrypt(String content, String password) {\ntry {\n//”AES”：请求的密钥算法的标准名称\nKeyGenerator kgen = KeyGenerator.getInstance(“AES”);\n//256：密钥生成参数；securerandom：密钥生成器的随机源\nSecureRandom securerandom = new SecureRandom(tohash256Deal(password));\nkgen.init(256, securerandom);\n//生成秘密（对称）密钥\nSecretKey secretKey = kgen.generateKey();\n//返回基本编码格式的密钥\nbyte[] enCodeFormat = secretKey.getEncoded();\n//根据给定的字节数组构造一个密钥。enCodeFormat：密钥内容；”AES”：与给定的密钥内容相关联的密钥算法的名称\nSecretKeySpec key = new SecretKeySpec(enCodeFormat, “AES”);\n//将提供程序添加到下一个可用位置\nSecurity.addProvider(new BouncyCastleProvider());\n//创建一个实现指定转换的 Cipher对象，该转换由指定的提供程序提供。\n//”AES/ECB/PKCS7Padding”：转换的名称；”BC”：提供程序的名称\nCipher cipher = Cipher.getInstance(“AES/ECB/PKCS7Padding”, “BC”);\ncipher.init(Cipher.ENCRYPT_MODE, key);\nbyte[] byteContent = content.getBytes(“utf-8”);\nbyte[] cryptograph = cipher.doFinal(byteContent);\nreturn Base64.encode(cryptograph);\n} catch (Exception e) {\ne.printStackTrace();\n}\nreturn null;\n}\npublic static String decrypt(byte[] cryptograph, String password) {\ntry {\nKeyGenerator kgen = KeyGenerator.getInstance(“AES”);\nSecureRandom securerandom = new SecureRandom(tohash256Deal(password));\nkgen.init(256, securerandom);\nSecretKey secretKey = kgen.generateKey();\nbyte[] enCodeFormat = secretKey.getEncoded();\nSecretKeySpec key = new SecretKeySpec(enCodeFormat, “AES”);\nSecurity.addProvider(new BouncyCastleProvider());\nCipher cipher = Cipher.getInstance(“AES/ECB/PKCS7Padding”, “BC”);\ncipher.init(Cipher.DECRYPT_MODE, key);\nbyte[] content = cipher.doFinal(Base64.decode(cryptograph));\nreturn new String(content);\n} catch (Exception e) {\ne.printStackTrace();\n}\nreturn null;\n}\nprivate static String parseByte2HexStr(byte buf[]) {\nStringBuffer sb = new StringBuffer();\nfor (int i = 0; i \u0026lt; buf.length; i++) {\nString hex = Integer.toHexString(buf[i] \u0026amp; 0xFF);\nif (hex.length() == 1) {\nhex = ‘0’ + hex;\n}\nsb.append(hex.toUpperCase());\n}\nreturn sb.toString();\n}\n/private static byte[] parseHexStr2Byte(String hexStr) {\nif (hexStr.length() \u0026lt; 1)\nreturn null;\nbyte[] result = new byte[hexStr.length()/2];\nfor (int i = 0;i\u0026lt; hexStr.length()/2; i++) {\nint high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);\nint low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);\nresult[i] = (byte) (high * 16 + low);\n}\nreturn result;\n}/\nprivate static byte[] tohash256Deal(String datastr) {\ntry {\nMessageDigest digester=MessageDigest.getInstance(“SHA-256”);\ndigester.update(datastr.getBytes());\nbyte[] hex=digester.digest();\nreturn hex;\n} catch (NoSuchAlgorithmException e) {\nthrow new RuntimeException(e.getMessage());\n}\n}\npublic static void main(String[] args) {\nString content = “0f607264fc6318a92b9e13c65db7cd3c”;\nString password = “zsyy”;\nSystem.out.println(“明文：” + content);\nSystem.out.println(“key：” + password);\nbyte[] encryptResult = AES256.encrypt(content, password);\nSystem.out.println(“密文：” + AES256.parseByte2HexStr(encryptResult));\nString decryptResult = AES256.decrypt(encryptResult, password);\nSystem.out.println(“解密：” + decryptResult);\n}\n}\n","permalink":"https://blog.zdltech.com/posts/java-aes256%E5%8A%A0%E5%AF%86%E8%A7%A3%E5%AF%86%E5%AE%9E%E7%8E%B0/","summary":"\u003cp\u003eimport it.sauronsoftware.base64.Base64;\u003c/p\u003e\n\u003cp\u003eimport java.security.MessageDigest;\u003cbr\u003e\nimport java.security.NoSuchAlgorithmException;\u003cbr\u003e\nimport java.security.SecureRandom;\u003cbr\u003e\nimport java.security.Security;\u003c/p\u003e\n\u003cp\u003eimport javax.crypto.Cipher;\u003cbr\u003e\nimport javax.crypto.KeyGenerator;\u003cbr\u003e\nimport javax.crypto.SecretKey;\u003cbr\u003e\nimport javax.crypto.spec.SecretKeySpec;\u003c/p\u003e\n\u003cp\u003eimport org.bouncycastle.jce.provider.BouncyCastleProvider;\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ejava实现AES256加密解密\u003c/li\u003e\n\u003cli\u003e依赖说明：\u003c/li\u003e\n\u003cli\u003ebcprov-jdk15-133.jar：PKCS7Padding\u003c/li\u003e\n\u003cli\u003ejavabase64-1.3.1.jar：base64\u003c/li\u003e\n\u003cli\u003elocal_policy.jar 和 US_export_policy.jar需添加到%JAVE_HOME%\\jre\\lib\\security中（lib中版本适合jdk1.7）\u003cbr\u003e\n*/\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003epublic class AES256 {\u003c/p\u003e\n\u003cp\u003epublic static byte[] encrypt(String content, String password) {\u003cbr\u003e\ntry {\u003cbr\u003e\n//”AES”：请求的密钥算法的标准名称\u003cbr\u003e\nKeyGenerator kgen = KeyGenerator.getInstance(“AES”);\u003cbr\u003e\n//256：密钥生成参数；securerandom：密钥生成器的随机源\u003cbr\u003e\nSecureRandom securerandom = new SecureRandom(tohash256Deal(password));\u003cbr\u003e\nkgen.init(256, securerandom);\u003cbr\u003e\n//生成秘密（对称）密钥\u003cbr\u003e\nSecretKey secretKey = kgen.generateKey();\u003cbr\u003e\n//返回基本编码格式的密钥\u003cbr\u003e\nbyte[] enCodeFormat = secretKey.getEncoded();\u003cbr\u003e\n//根据给定的字节数组构造一个密钥。enCodeFormat：密钥内容；”AES”：与给定的密钥内容相关联的密钥算法的名称\u003cbr\u003e\nSecretKeySpec key = new SecretKeySpec(enCodeFormat, “AES”);\u003cbr\u003e\n//将提供程序添加到下一个可用位置\u003cbr\u003e\nSecurity.addProvider(new BouncyCastleProvider());\u003cbr\u003e\n//创建一个实现指定转换的 Cipher对象，该转换由指定的提供程序提供。\u003cbr\u003e\n//”AES/ECB/PKCS7Padding”：转换的名称；”BC”：提供程序的名称\u003cbr\u003e\nCipher cipher = Cipher.getInstance(“AES/ECB/PKCS7Padding”, “BC”);\u003c/p\u003e","title":"Java AES256加密解密实现"},{"content":" 设置用户组和用户、并设置密码 groupadd sftp #创建sftp用户组\nuseradd -g sftp -s /bin/false mysftp # 创建mysftp用户\npasswd mysftp #设置mysftp密码\n创建并设置mysftp的主目录 mkdir mydata #创建mydata文件夹\ncd mydata #进入mydata\nmkdir uploads #创建uploads文件夹\nusermod -d /mydata/uploads/ mysftp #设置mysftp的主目录\n配置sshd_config vi /etc/ssh/sshd_config\n#这个要放到最后（至少保证在’UseDNS’ 后面否则可能出现错误）\n# Subsystem sftp /usr/libexec/openssh/sftp-server\nSubsystem sftp internal-sftp\nMatch Group sftp\nChrootDirectory /mydata\nForceCommand internal-sftp\nAllowTcpForwarding no\nX11Forwarding no\n配置文件权限（至少为755权限） chown root:sftp /mydata\nchmod 755 /mydata\nchown mysftp:sftp /mydata/uploads\nchmod 755 /mydata/uploads\n检查sshd_config配置文件 sshd -T\n运行之前执行sshd -T 配置问题是否合\n重启ssh服务 systemctl restart sshd.service\n可能出现的错误：\nDirective ‘UseDNS’ is not allowed within a Match block （参考第三步配置）\n参考：https://www.cnblogs.com/flyback/p/6492059.html\nhttps://www.jb51.net/article/135573.htm\n其他：配置linuxjdk环境\nexport JAVA_HOME=/opt/soft/jdk1.7.0_75\nexport JRE_HOME={JAVA_HOME}/jre export CLASSPATH=.:{JAVA_HOME}/lib:{JRE_HOME}/lib export PATH={JAVA_HOME}/bin:$PATH\n配置网络\n虚拟机桥接模式 修改网卡信息（添加IPADDR GATEWAY，修改BOOT为yes） 1、关闭firewall：\nsystemctl stop firewalld.service #停止firewall\nsystemctl disable firewalld.service #禁止firewall开机启动\n2、iptables防火墙（这里iptables已经安装，下面进行配置）\nvi/etc/sysconfig/iptables #编辑防火墙配置文件\n# sampleconfiguration for iptables service\n","permalink":"https://blog.zdltech.com/posts/%E9%85%8D%E7%BD%AE%E7%8B%AC%E7%AB%8Bsftp%E8%B4%A6%E5%8F%B7/","summary":"\u003ch3 id=\"设置用户组和用户并设置密码\"\u003e 设置用户组和用户、并设置密码\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003egroupadd sftp #创建sftp用户组\u003cbr\u003e\nuseradd -g sftp -s /bin/false mysftp  # 创建mysftp用户\u003cbr\u003e\npasswd mysftp #设置mysftp密码\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"创建并设置mysftp的主目录\"\u003e 创建并设置mysftp的主目录\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003emkdir  mydata #创建mydata文件夹\u003c/p\u003e\n\u003cp\u003ecd mydata #进入mydata\u003c/p\u003e\n\u003cp\u003emkdir uploads #创建uploads文件夹\u003c/p\u003e\n\u003cp\u003eusermod -d /mydata/uploads/ mysftp #设置mysftp的主目录\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"配置sshd_config\"\u003e配置sshd_config\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003evi /etc/ssh/sshd_config\u003c/p\u003e\n\u003cp\u003e#这个要放到最后（至少保证在’UseDNS’ 后面否则可能出现错误）\u003cbr\u003e\n# Subsystem sftp /usr/libexec/openssh/sftp-server\u003cbr\u003e\nSubsystem sftp internal-sftp\u003cbr\u003e\nMatch Group sftp\u003cbr\u003e\nChrootDirectory /mydata\u003cbr\u003e\nForceCommand internal-sftp\u003cbr\u003e\nAllowTcpForwarding no\u003cbr\u003e\nX11Forwarding no\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"配置文件权限至少为755权限\"\u003e配置文件权限（至少为755权限）\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003echown root:sftp /mydata\u003cbr\u003e\nchmod 755 /mydata\u003cbr\u003e\nchown  mysftp:sftp /mydata/uploads\u003cbr\u003e\nchmod 755 /mydata/uploads\u003c/p\u003e","title":"配置独立sftp账号"},{"content":"Retortfit2\nRetrofit是由Square公司出品的针对于Android和Java的类型安全的Http客户端，网络服务基于OkHttp 。 个人觉得更为准确的说法是，Retrofit是OkHttp的一个包装工具类，可以更加方便的调用Restful API。\nRetrofit2 默认提供的Converter\nGson: com.squareup.retrofit2:converter-gson\nJackson: com.squareup.retrofit2:converter-jackson\nMoshi: com.squareup.retrofit2:converter-moshi\nProtobuf: com.squareup.retrofit2:converter-protobuf\nWire: com.squareup.retrofit2:converter-wire\nSimple XML: com.squareup.retrofit2:converter-simplexml\nScalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars\n下面就来讲解如何扩展Converter\n首先创建FastJsonConverterFactory 类，并继承Converter.Factory，重写其中的responseBodyConverter方法与requestBodyConverter方法。\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Type;\nimport okhttp3.RequestBody;\nimport okhttp3.ResponseBody;\nimport retrofit2.Converter;\nimport retrofit2.Retrofit;\npublic class FastJsonConverterFactory extends Converter.Factory{\npublic static FastJsonConverterFactory create() {\nreturn new FastJsonConverterFactory();\n}\n/**\n需要重写父类中responseBodyConverter，该方法用来转换服务器返回数据\n*/\n@Override\npublic Converter\u0026lt;ResponseBody, ?\u0026gt; responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {\nreturn new FastJsonResponseBodyConverter\u0026lt;\u0026gt;(type);\n} /**\n需要重写父类中responseBodyConverter，该方法用来转换发送给服务器的数据\n*/\n@Override\npublic Converter\u0026lt;?, RequestBody\u0026gt; requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {\nreturn new FastJsonRequestBodyConverter\u0026lt;\u0026gt;();\n} }\n创建FastJsonResponseBodyConverter 类\nimport okhttp3.ResponseBody;\nimport okio.BufferedSource;\nimport okio.Okio;\nimport retrofit2.Converter;\npublic class FastJsonResponseBodyConverter implements Converter\u0026lt;ResponseBody, T\u0026gt; {\nprivate final Type type;\npublic FastJsonResponseBodyConverter(Type type) {\nthis.type = type;\n}\n/*\n转换方法\n*/\n@Override\npublic T convert(ResponseBody value) throws IOException {\nBufferedSource bufferedSource = Okio.buffer(value.source());\nString tempStr = bufferedSource.readUtf8();\nbufferedSource.close();\nreturn JSON.parseObject(tempStr, type); }\n}\n创建FastJsonRequestBodyConverter\nimport com.alibaba.fastjson.JSON;\nimport java.io.IOException;\nimport okhttp3.MediaType;\nimport okhttp3.RequestBody;\nimport retrofit2.Converter;\npublic class FastJsonRequestBodyConverter implements Converter\u0026lt;T, RequestBody\u0026gt; {\nprivate static final MediaType MEDIA_TYPE = MediaType.parse(“application/json; charset=UTF-8”);\n@Override\npublic RequestBody convert(T value) throws IOException {\nreturn RequestBody.create(MEDIA_TYPE, JSON.toJSONBytes(value));\n}\n}\n使用方法\nretrofit = new Retrofit.Builder()\n.baseUrl(BASE_URL)\n.client(CustomerOkHttpClient.getClient())\n.addCallAdapterFactory(RxJavaCallAdapterFactory.create())\n//在此处声明使用FastJsonConverter做为转换器\n.addConverterFactory(FastJsonConverterFactory.create())\n.build()\n转自：https://blog.csdn.net/suyimin2010/article/details/79877775\n","permalink":"https://blog.zdltech.com/posts/retrofit2-%E4%BD%BF%E7%94%A8fastjson%E4%BD%9C%E4%B8%BAconverter/","summary":"\u003cp\u003eRetortfit2\u003cbr\u003e\nRetrofit是由Square公司出品的针对于Android和Java的类型安全的Http客户端，网络服务基于OkHttp 。 个人觉得更为准确的说法是，Retrofit是OkHttp的一个包装工具类，可以更加方便的调用Restful API。\u003c/p\u003e\n\u003cp\u003eRetrofit2 默认提供的Converter\u003cbr\u003e\nGson: com.squareup.retrofit2:converter-gson\u003cbr\u003e\nJackson: com.squareup.retrofit2:converter-jackson\u003cbr\u003e\nMoshi: com.squareup.retrofit2:converter-moshi\u003cbr\u003e\nProtobuf: com.squareup.retrofit2:converter-protobuf\u003cbr\u003e\nWire: com.squareup.retrofit2:converter-wire\u003c/p\u003e\n\u003cp\u003eSimple XML: com.squareup.retrofit2:converter-simplexml\u003c/p\u003e\n\u003cp\u003eScalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars\u003c/p\u003e\n\u003cp\u003e下面就来讲解如何扩展Converter\u003c/p\u003e\n\u003cp\u003e首先创建FastJsonConverterFactory 类，并继承Converter.Factory，重写其中的responseBodyConverter方法与requestBodyConverter方法。\u003cbr\u003e\nimport java.lang.annotation.Annotation;\u003cbr\u003e\nimport java.lang.reflect.Type;\u003c/p\u003e\n\u003cp\u003eimport okhttp3.RequestBody;\u003cbr\u003e\nimport okhttp3.ResponseBody;\u003cbr\u003e\nimport retrofit2.Converter;\u003cbr\u003e\nimport retrofit2.Retrofit;\u003c/p\u003e\n\u003cp\u003epublic class FastJsonConverterFactory extends Converter.Factory{\u003c/p\u003e\n\u003cp\u003epublic static FastJsonConverterFactory create() {\u003cbr\u003e\nreturn new FastJsonConverterFactory();\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e需要重写父类中responseBodyConverter，该方法用来转换服务器返回数据\u003cbr\u003e\n*/\u003cbr\u003e\n@Override\u003cbr\u003e\npublic Converter\u0026lt;ResponseBody, ?\u0026gt; responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {\u003cbr\u003e\nreturn new FastJsonResponseBodyConverter\u0026lt;\u0026gt;(type);\u003cbr\u003e\n}\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e/**\u003c/p\u003e","title":"Retrofit2 使用FastJson作为Converter"},{"content":"下载Mysql 下载地址 \u0026lt;span class=\u0026quot;md-link\u0026quot; spellcheck=\u0026quot;false\u0026quot;\u0026gt;[https://dev.mysql.com/downloads/mysql/](https://dev.mysql.com/downloads/mysql/)\u0026lt;/span\u0026gt; 选择tar压缩文件 配置环境 解压文件放到你希望的目录中 配置环境变量 例如： vi ~/.bash_profile export PATH=$PATH:/usr/local/mysql/bin 使其生效：source ~/.bash_profile 初始化mysql mysql 8.0 执行 scripts 目录下的 mysql_install_db 脚本完成一些默认的初始化(创建默认配置文件、授权表等) cd /usr/local/mysql sudo scripts/mysql_install_db\n\u0026lt;span class=\u0026quot;md-image md-img-loaded\u0026quot; contenteditable=\u0026quot;false\u0026quot; data-src=\u0026quot;https://ws2.sinaimg.cn/large/006tNbRwly1fx9xmzyphej31m6074jti.jpg\u0026quot;\u0026gt;![](https://ws2.sinaimg.cn/large/006tNbRwly1fx9xmzyphej31m6074jti.jpg)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;为了快速启动和停止mysql 我配置了别名\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;md-image md-img-loaded\u0026quot; contenteditable=\u0026quot;false\u0026quot; data-src=\u0026quot;https://ws4.sinaimg.cn/large/006tNbRwly1fx9xkpfh6oj30x603wwfa.jpg\u0026quot;\u0026gt;![](https://ws4.sinaimg.cn/large/006tNbRwly1fx9xkpfh6oj30x603wwfa.jpg)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;检测mysql的status 执行mysqlstatus\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;启动mysql 执行 \u0026lt;/span\u0026gt; 出现这个错误\n是权限的问题，把mysql的权限直接修改为777(由于本地安全性相对不用考虑，所有给出全部权限，服务器端请慎重)\nsudo chmod -R 777 mysql/\n修改root秘密\nALTER USER ‘root’@’%’ IDENTIFIED WITH mysql_native_password BY ‘root’; 执行flush privileges; 之后，客户端就支持远程连接mysql了\n问题汇总 \u0026lt;span class=\u0026quot;md-image md-img-loaded\u0026quot; contenteditable=\u0026quot;false\u0026quot; data-src=\u0026quot;https://ws1.sinaimg.cn/large/006tNbRwly1fx9ypt6t5jj30ps0900zp.jpg\u0026quot;\u0026gt;![](https://ws1.sinaimg.cn/large/006tNbRwly1fx9ypt6t5jj30ps0900zp.jpg)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot; md-link\u0026quot;\u0026gt;[参考](http://www.cnblogs.com/uoar/p/9328027.html)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot; md-link\u0026quot;\u0026gt;[参考2](https://blog.csdn.net/u010026255/article/details/80062153)\u0026lt;/span\u0026gt; 修改 root 用户密码： \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;mysql\u0026gt;ALTER USER \u0026amp;#8216;root\u0026amp;#8217;@\u0026amp;#8217;%\u0026amp;#8217; IDENTIFIED WITH mysql_native_password BY \u0026amp;#8216;root\u0026amp;#8217;; \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;配置指定用户权限\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;md-link\u0026quot;\u0026gt;[参考](https://www.cnblogs.com/testway/p/9289827.html)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;其他参考 \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;md-link md-expand\u0026quot; spellcheck=\u0026quot;false\u0026quot;\u0026gt;[https://blog.csdn.net/g15738290530/article/details/80956389](https://blog.csdn.net/g15738290530/article/details/80956389)\u0026lt;/span\u0026gt; ","permalink":"https://blog.zdltech.com/posts/mac%E5%AE%89%E8%A3%85mysql-8-0-13%E6%AD%A5%E9%AA%A4/","summary":"\u003ch3 id=\"下载mysql\"\u003e\u003cspan class=\"md-expand\"\u003e下载Mysql\u003c/span\u003e\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  下载地址 \u0026lt;span class=\u0026quot;md-link\u0026quot; spellcheck=\u0026quot;false\u0026quot;\u0026gt;[https://dev.mysql.com/downloads/mysql/](https://dev.mysql.com/downloads/mysql/)\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  选择tar压缩文件\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3 id=\"配置环境\"\u003e配置环境\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  解压文件放到你希望的目录中\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  配置环境变量 例如： vi ~/.bash_profile export PATH=$PATH:/usr/local/mysql/bin 使其生效：source ~/.bash_profile\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3 id=\"初始化mysql-mysql-80\"\u003e\u003cspan class=\"\"\u003e初始化mysql mysql 8.0\u003c/span\u003e\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e执行 scripts 目录下的 mysql_install_db 脚本完成一些默认的初始化(创建默认配置文件、授权表等) \u003cspan class=\"\"\u003ecd /usr/local/mysql\u003c/span\u003e sudo scripts/mysql_install_db\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;span class=\u0026quot;md-image md-img-loaded\u0026quot; contenteditable=\u0026quot;false\u0026quot; data-src=\u0026quot;https://ws2.sinaimg.cn/large/006tNbRwly1fx9xmzyphej31m6074jti.jpg\u0026quot;\u0026gt;![](https://ws2.sinaimg.cn/large/006tNbRwly1fx9xmzyphej31m6074jti.jpg)\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;为了快速启动和停止mysql 我配置了别名\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;span class=\u0026quot;md-image md-img-loaded\u0026quot; contenteditable=\u0026quot;false\u0026quot; data-src=\u0026quot;https://ws4.sinaimg.cn/large/006tNbRwly1fx9xkpfh6oj30x603wwfa.jpg\u0026quot;\u0026gt;![](https://ws4.sinaimg.cn/large/006tNbRwly1fx9xkpfh6oj30x603wwfa.jpg)\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;检测mysql的status 执行mysqlstatus\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;启动mysql 执行 \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e出现这个错误\u003c/p\u003e","title":"Mac安装mysql 8.0.13步骤"},{"content":"度娘了一圈发现基本上都是TabLayout或者其他的导航栏添加角标，所以写这篇博客记录下来。\n先来看下实现的效果图：\n代码也是很简单的\nBottomNavigationMenuView中的每一个Tab就是一个FrameLayout，所以我们可以在上面随意添加View、这样也就可以实现我们的角标了。\n//获取整个的NavigationView\nBottomNavigationMenuView menuView = (BottomNavigationMenuView) navigationView.getChildAt(0);\n//这里就是获取所添加的每一个Tab(或者叫menu)，\nView tab = menuView.getChildAt(3);\nBottomNavigationItemView itemView = (BottomNavigationItemView) tab;\n//加载我们的角标View，新创建的一个布局\nView badge = LayoutInflater.from(this).inflate(R.layout.menu_badge, menuView, false);\n//添加到Tab上\nitemView.addView(badge);\nmenu_badge.xml file:\n这里这个布局的大小，其实也就是每一个Tab的大小了。把显示数量的TextView水平居中，这样也就刚好在Tab的中间了(剩下就看你自己想怎么放了….)\n\u003c?xml version=\u0026#8221;1.0\u0026#8243; encoding=\u0026#8221;utf-8\u0026#8243;?\u003e \u0026lt;LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”\nandroid:layout_width=”match_parent”\nandroid:layout_height=”match_parent”\nandroid:orientation=”vertical”\u0026gt;\n\u0026lt;TextView\nandroid:id=”@+id/tv_msg_count”\nandroid:layout_width=”15dp”\nandroid:layout_height=”15dp”\nandroid:layout_gravity=”center”\nandroid:layout_marginLeft=”@dimen/dp_10″\nandroid:layout_marginTop=”@dimen/dp_3″\nandroid:background=”@drawable/bg_red_circle_10″\nandroid:gravity=”center”\nandroid:textColor=”@color/white”\nandroid:textSize=”@dimen/sp_12″\nandroid:visibility=”gone” /\u0026gt;\n设置角标的数量\nTextView count = (TextView) badge.findViewById(R.id.tv_msg_count);\ncount.setText(String.valueOf(1));\n//如果没有消息，不需要显示的时候那只需要将它隐藏即可\ncount.setVisibility(View.GONE);\n- 在点击事件中完成各个menu的点击事件，实现Fragment的替换，另外三个点击事件内容类似 \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` `\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;// 去掉menu大于3个后的动画\u0026lt;/span\u0026gt; BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;// 导航 menu 点击事件\u0026lt;/span\u0026gt; bottomNavigationView.setOnNavigationItemSelectedListener(\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt; BottomNavigationView.OnNavigationItemSelectedListener() { \u0026lt;span class=\u0026ldquo;hljs-meta\u0026rdquo;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;onNavigationItemSelected\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;(@NonNull MenuItem item)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;switch\u0026lt;/span\u0026gt; (item.getItemId()){ \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;case\u0026lt;/span\u0026gt; R.id.download: \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt;(lastShowFragment!=\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;0\u0026lt;/span\u0026gt;){ replaceFragment(lastShowFragment,\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;0\u0026lt;/span\u0026gt;); lastShowFragment=\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;0\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;case\u0026lt;/span\u0026gt; R.id.game: \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;case\u0026lt;/span\u0026gt; R.id.search: \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;case\u0026lt;/span\u0026gt; R.id.shopping: \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;break\u0026lt;/span\u0026gt;; }\n\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 默认 false \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// false 的话 下面颜色不会变化\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } }); `\n- 在 Activity 中 的 onCreate 中完成 Fragment 数组的装填，并在 Activity 中显示第一个 Fragment \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` (); for(int i=0;i\u0026lt;4;i++){ fragments.add(FruitFragment. newFragment()); } lastShowFragment=0; /** * 在 Activity 中加载第一个 Fragment */ getSupportFragmentManager() .beginTransaction() .add(R.id.relative_layout,fragments.get(0)) .show(fragments.get(0)) .commit(); Log.d(TAG,\u0026amp;quot;initFragment over\u0026amp;quot;); } \u0026#34; data-snippet-id=\u0026#34;ext.c7cfe07c5cc0181afa3ec78bde2dd5c6\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 初始化 Fragment 并在 Activity 中显示第一个 Fragment */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initFragment\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ fragments=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i=\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;;i\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;;i++){ fragments.add(FruitFragment. newFragment()); } lastShowFragment=\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 在 Activity 中加载第一个 Fragment */\u0026amp;lt;/span\u0026gt; getSupportFragmentManager() .beginTransaction() .add(R.id.relative_layout,fragments.get(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;)) .show(fragments.get(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;)) .commit(); Log.d(TAG,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;initFragment over\u0026#34;\u0026amp;lt;/span\u0026gt;); } ` - 根据记录最后在 Activity 中显示的 Fragment 的变量 lastShowFragment ，和 menu 需要的 Fragment 完成替换 \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` ` \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;/** * 替换 Activity 中的 Fragment * \u0026lt;span class=\u0026ldquo;hljs-doctag\u0026rdquo;\u0026gt;@param\u0026lt;/span\u0026gt; lastShowFragment * \u0026lt;span class=\u0026ldquo;hljs-doctag\u0026rdquo;\u0026gt;@param\u0026lt;/span\u0026gt; index */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;replaceFragment\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;(\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; lastShowFragment,\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; index)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;{ FragmentTransaction transaction=getSupportFragmentManager().beginTransaction(); transaction.hide(fragments.get(lastShowFragment));\n\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 确认需要的 Fragment 是否已添加\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;(!fragments.get(index).isAdded()){ transaction.add(R.id.relative_layout, fragments.get(index)); } transaction.show(fragments.get(index)).commitAllowingStateLoss(); Log.d(TAG,\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;replaceFragment lastShowFragment : \u0026quot;\u0026amp;lt;/span\u0026gt;+lastShowFragment+\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot; index : \u0026quot;\u0026amp;lt;/span\u0026gt;+index); } `\n- 效果 \u0026lt;div class=\u0026#34;image-package\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;image-container\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;image-container-fill\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;image-view\u0026#34; data-width=\u0026#34;1440\u0026#34; data-height=\u0026#34;2560\u0026#34;\u0026gt; ![](//upload-images.jianshu.io/upload_images/10671242-47f3a38801caf349.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;image-caption\u0026#34;\u0026gt; Screenshot_1519977714.png \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;image-package\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;image-container\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;image-container-fill\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;image-view\u0026#34; data-width=\u0026#34;1440\u0026#34; data-height=\u0026#34;2560\u0026#34;\u0026gt; ![](//upload-images.jianshu.io/upload_images/10671242-39f2d3916b5158ac.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;image-caption\u0026#34;\u0026gt; Screenshot_1519977720.png \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;image-package\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;image-container\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;image-container-fill\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;image-view\u0026#34; data-width=\u0026#34;1440\u0026#34; data-height=\u0026#34;2560\u0026#34;\u0026gt; ![](//upload-images.jianshu.io/upload_images/10671242-454d7c2a6953af6a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;image-caption\u0026#34;\u0026gt; Screenshot_1519977726.png \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;image-package\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;image-container\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;image-container-fill\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;image-view\u0026#34; data-width=\u0026#34;1440\u0026#34; data-height=\u0026#34;2560\u0026#34;\u0026gt; ![](//upload-images.jianshu.io/upload_images/10671242-aa014eb5d55a09bb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;image-caption\u0026#34;\u0026gt; Screenshot_1519977732.png \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;hr /\u0026gt; #### 小结 [BottomBarLayout 第三方 可实现角标](https://link.jianshu.com?t=http%3A%2F%2Fblog.csdn.net%2Fchay_chan%2Farticle%2Fdetails%2F73715607) BottomNavigationViewHelper [参考博客](https://www.jianshu.com/p/e2a8791e80d6) BottomNavigationView + Fragment [参考博客](https://link.jianshu.com?t=http%3A%2F%2Fblog.csdn.net%2Fqq_35366908%2Farticle%2Fdetails%2F72457909) 转自：https://www.jianshu.com/p/0bdcd16c4d68 转自：https://blog.csdn.net/a_zhon/article/details/78334515 参考: https://www.jianshu.com/p/e2a8791e80d6 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/%E4%BD%BF%E7%94%A8bottomnavigationview%E5%BA%95%E9%83%A8%E5%AF%BC%E8%88%AA%E6%A0%8F%E6%B7%BB%E5%8A%A0%E6%95%B0%E9%87%8F%E8%A7%92%E6%A0%87%E6%8F%90%E9%86%92/","summary":"\u003cp\u003e度娘了一圈发现基本上都是TabLayout或者其他的导航栏添加角标，所以写这篇博客记录下来。\u003cbr\u003e\n先来看下实现的效果图：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img-blog.csdn.net/20171024202709271?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYV96aG9u/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003cbr\u003e\n代码也是很简单的\u003cbr\u003e\nBottomNavigationMenuView中的每一个Tab就是一个FrameLayout，所以我们可以在上面随意添加View、这样也就可以实现我们的角标了。\u003c/p\u003e\n\u003cp\u003e//获取整个的NavigationView\u003cbr\u003e\nBottomNavigationMenuView menuView = (BottomNavigationMenuView) navigationView.getChildAt(0);\u003c/p\u003e\n\u003cp\u003e//这里就是获取所添加的每一个Tab(或者叫menu)，\u003cbr\u003e\nView tab = menuView.getChildAt(3);\u003cbr\u003e\nBottomNavigationItemView itemView = (BottomNavigationItemView) tab;\u003c/p\u003e\n\u003cp\u003e//加载我们的角标View，新创建的一个布局\u003cbr\u003e\nView badge = LayoutInflater.from(this).inflate(R.layout.menu_badge, menuView, false);\u003c/p\u003e\n\u003cp\u003e//添加到Tab上\u003cbr\u003e\nitemView.addView(badge);\u003c/p\u003e\n\u003cp\u003emenu_badge.xml file:\u003cbr\u003e\n这里这个布局的大小，其实也就是每一个Tab的大小了。把显示数量的TextView水平居中，这样也就刚好在Tab的中间了(剩下就看你自己想怎么放了….)\u003c/p\u003e\n\u003c?xml version=\u0026#8221;1.0\u0026#8243; encoding=\u0026#8221;utf-8\u0026#8243;?\u003e  \n\u003cp\u003e\u0026lt;LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”\u003cbr\u003e\nandroid:layout_width=”match_parent”\u003cbr\u003e\nandroid:layout_height=”match_parent”\u003cbr\u003e\nandroid:orientation=”vertical”\u0026gt;\u003c/p\u003e\n\u003cp\u003e\u0026lt;TextView\u003cbr\u003e\nandroid:id=”@+id/tv_msg_count”\u003cbr\u003e\nandroid:layout_width=”15dp”\u003cbr\u003e\nandroid:layout_height=”15dp”\u003cbr\u003e\nandroid:layout_gravity=”center”\u003cbr\u003e\nandroid:layout_marginLeft=”@dimen/dp_10″\u003cbr\u003e\nandroid:layout_marginTop=”@dimen/dp_3″\u003cbr\u003e\nandroid:background=”@drawable/bg_red_circle_10″\u003cbr\u003e\nandroid:gravity=”center”\u003cbr\u003e\nandroid:textColor=”@color/white”\u003cbr\u003e\nandroid:textSize=”@dimen/sp_12″\u003cbr\u003e\nandroid:visibility=”gone” /\u0026gt;\u003c/p\u003e\n\u003c/LinearLayout\u003e\n\u003cp\u003e设置角标的数量\u003cbr\u003e\nTextView count = (TextView) badge.findViewById(R.id.tv_msg_count);\u003cbr\u003e\ncount.setText(String.valueOf(1));\u003c/p\u003e\n\u003cp\u003e//如果没有消息，不需要显示的时候那只需要将它隐藏即可\u003cbr\u003e\ncount.setVisibility(View.GONE);\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e  - 在点击事件中完成各个menu的点击事件，实现Fragment的替换，另外三个点击事件内容类似\n  \n\n\n\u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e`\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;// 去掉menu大于3个后的动画\u0026lt;/span\u0026gt;\nBottomNavigationViewHelper.disableShiftMode(bottomNavigationView);\u003c/p\u003e","title":"使用BottomNavigationView底部导航栏、添加数量角标提醒"},{"content":"基础汇总 require引用的文件中不要有内部调用，否则可能有未知隐患（内存泄漏、或者直接崩溃） Buffer 是Node特有的数据类型（固有属性、不需要require），主要用来处理二进制数据（Buffer通常表现为十六进制的字符串），新Node API Buffer()方法为Deprecated，推荐使用Buffer.form来初始化一个Buffer对象 \u0026lt;blockquote\u0026gt; buffer.toString([encoding],[start],[end]) buffer 支持编码类型 ASCII Base64 Binary Hex UTF-8 UTF-16LE/UCS-2 Buffer一个常用的场景就是HTTP的POST请求，例如 var body = \u0026amp;#8221; req.setEncoding(\u0026amp;#8216;utf-8\u0026amp;#8217;); req.on(\u0026amp;#8216;data\u0026amp;#8217;,function(chumk){ body += chunk; }) req.on(\u0026amp;#8216;end\u0026amp;#8217;,function(){ }) \u0026lt;/blockquote\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;Fill System 是Node中使用最为频繁的模块之一，该模块提供了读写文件的能力，是借助于底层的linuv的C++ API实现的。\u0026lt;/span\u0026gt; \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; 常用API readFile writeFile stat \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;fs.stat获取文件的状态（可以用来判断文件还是文件夹）\u0026lt;/span\u0026gt; \u0026lt;/blockquote\u0026gt; HTTP服务 是Node的核心模块。 \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; var http = require(\u0026amp;#8220;http\u0026amp;#8221;) var server = http.createServer(function(req,res){ // req.url 获取访问的路径 //req.method 请求方法 req.on(\u0026amp;#8220;data\u0026amp;#8221;,function(chunk){ }).on(\u0026amp;#8220;end\u0026amp;#8221;,function(){ }); res.writeHead(200,{\u0026amp;#8216;Content-Type\u0026amp;#8217;:\u0026amp;#8217;text/plain\u0026amp;#8217;,\u0026amp;#8221;Content-Length\u0026amp;#8221;:Buffer.byteLength(body)}); res.end(\u0026amp;#8216;Hello Node!!!\u0026amp;#8217;);//每个HTTP请求的最后都会被调用，当客户端的请求完成后，开发者应该调用该方法结束HTTP请求 }); server.on(\u0026amp;#8220;connection\u0026amp;#8221;,function(req,res){ }); server.on(\u0026amp;#8220;request\u0026amp;#8221;,function(req,res){ }) server.listen(3000) //处理异常 process.on(\u0026amp;#8220;uncaughtException\u0026amp;#8221;,function(){ }) // req.headesr 表示head信息 POST上传文件 表单类型设置为： enctype=\u0026amp;#8221;multipart/form-data\u0026amp;#8221; 服务器处理上传文件通常基于stream来实现，这里比较流行的第三方库formidable function dealUpload(req,res){ var form = new formidable.IncomingForm(); \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;form.eekpExtension = true;\u0026lt;/span\u0026gt; form.uploadDir =__dirname; from.parse(req,function(err,fields.files){ if(err)throw err; console.log(fields); console.log(files); res.writeHead(200,{\u0026amp;#8220;Content-type\u0026amp;#8221;:\u0026amp;#8217;text/plain\u0026amp;#8217;}); \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;res.end(\u0026amp;#8216;upload finished\u0026amp;#8217;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;})\u0026lt;/span\u0026gt; } HTTP 客户端服务 var http=require(\u0026amp;#8220;http\u0026amp;#8221;); http.get(\u0026amp;#8220;\u0026lt;span class=\u0026quot;md-link\u0026quot; spellcheck=\u0026quot;false\u0026quot;\u0026gt;[http://www.baidu.com](http://www.baidu.com)\u0026lt;/span\u0026gt;\u0026amp;#8220;,function(res){ var statusCode = res.statusCode; if(statusCode==200){ res.on(\u0026amp;#8220;data\u0026amp;#8221;,function(chunk){ }); res.on(\u0026amp;#8220;end\u0026amp;#8221;,function(){ }); res.on(\u0026amp;#8220;error\u0026amp;#8221;,function(e){ \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;})\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; }); //代理服务器 var http =require(\u0026amp;#8220;http\u0026amp;#8221;); var url = require(\u0026amp;#8220;url\u0026amp;#8221;); http.createServer(function(req,res){ var url = req.url.substring(1,req.url.length);//去掉最前面的/ var proxyRequest = http.request(url,function(pres){ res.writhHead(pres.statusCode,pres.headers); pres.on(\u0026amp;#8220;data\u0026amp;#8221;,function(data){ \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;res.write(data);\u0026lt;/span\u0026gt; }); pres.on(\u0026amp;#8220;end\u0026amp;#8221;,function(){ \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;res.end();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;})\u0026lt;/span\u0026gt; }); req.on(\u0026amp;#8220;data\u0026amp;#8221;,function(data){ \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;proxyRequest.write(data);\u0026lt;/span\u0026gt; }); req.on(\u0026amp;#8220;end\u0026amp;#8221;,function(){ \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;proxyReques.end();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;});\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;}).listen(8080);\u0026lt;/span\u0026gt; \u0026lt;/blockquote\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;WebSocekt (比较出名的WebSocket模块还有Socket.IO)\u0026lt;/span\u0026gt; \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; Node 实现WebSocket var WebSocketServer = require(\u0026amp;#8220;ws\u0026amp;#8221;).Server; var wss = new WebScoketServer({port:3304}); wss.on(\u0026amp;#8220;connection\u0026amp;#8221;,function(ws){ ws.on(\u0026amp;#8220;message\u0026amp;#8221;,function(message){ \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;console.log(message);\u0026lt;/span\u0026gt; }); \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;ws.send(\u0026amp;#8220;Node Hello WebSocket\u0026amp;#8221;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;})\u0026lt;/span\u0026gt; \u0026lt;/blockquote\u0026gt; Events 在Node中只定义了一个类EventEmitter \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; var eventEmitter = require(\u0026amp;#8220;events\u0026amp;#8221;); var myEmitter = new eventEmitter(); \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;myEmitter.on(\u0026amp;#8220;begin\u0026amp;#8221;,function(){//注册一个begin事件\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;console.log(\u0026amp;#8220;begin\u0026amp;#8221;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;});\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;myEmitter.emit(\u0026amp;#8220;begin\u0026amp;#8221;);//触发begin事件\u0026lt;/span\u0026gt; \u0026lt;/blockquote\u0026gt; 多进程服务 \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; child_process模块中包括很多创建子进程的方法，包括fork、spawn、exec、execFile \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;Cluster是Node 0.6之后新增模块（Cluster可以看做是做了封装的child_process模块）\u0026lt;/span\u0026gt; \u0026lt;/blockquote\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;Proces对象是一个全局的对象，每个Node进程都有独立的process对象，该对象中存储了当前的环境变量，也定义了一些事件\u0026lt;/span\u0026gt; \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; process.getuid();//用户id process.argv;//Node的命令行参数列表 process.pid;//进程id process.cwd();//当前目录 process.versoin;//Node版本 \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;process.env;//\u0026lt;/span\u0026gt; \u0026lt;/blockquote\u0026gt; Timer setTimeout setInterval nvm \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; nvm install version 安装某个版本的node nvm use veresion 切换到某个版本 nvm ls 列出当前安装的所有的Node版本 let关键字 会创建一个块级作用域 const变量不可以再被修改 \u0026lt;/blockquote\u0026gt; 函数 \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; 参数可以设置默认值 function gred(x=\u0026amp;#8221;a\u0026amp;#8221;,y=\u0026amp;#8221;b\u0026amp;#8221;){ } Spread运算符（\u0026amp;#8230;）展开运算符 var ab=[\u0026amp;#8220;ab\u0026amp;#8221;,\u0026amp;#8221;cd\u0026amp;#8221;] gred(..ab); 箭头函数（ES6） var func= a=\u0026gt;a;等价于 var func = function(a){ \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;return a;\u0026lt;/span\u0026gt; } 多个参数 var func=(a,b)=\u0026gt;{ \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;console.log(a,b);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/blockquote\u0026gt; Promise 异步处理 \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; var promis = new Promise(function(resolve.reject){ //执行相关异步操作 //resolve(data) // reject(err) }),then(res=\u0026gt;{}).catch(err=\u0026gt;{}); \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;promise.all 多个promise需要执行封装为一个\u0026lt;/span\u0026gt; \u0026lt;/blockquote\u0026gt; 回调的终点\u0026amp;#8211;async/await \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; node 7.6.0之后原生支持 var asyncReadFile = async function(){ var result1 = await readFile(\u0026amp;#8216;a.txt\u0026amp;#8217;); var result 2 = await readFile(\u0026amp;#8216;b.txt\u0026amp;#8217;); console.log(result1); \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;console.log(result2);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/blockquote\u0026gt; Koa2 构建web站点 \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; koa-static 静态文件服务 koa-router 路由服务 koa-bodyparse \u0026lt;/blockquote\u0026gt; MongoDB (Mongoose) \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; npm install mongoose var mongoose = require(\u0026amp;#8220;mongoose\u0026amp;#8221;) mongoose.connect(\u0026amp;#8220;mongodb://xxx/test\u0026amp;#8221;); var db = mongose.connection; db.on(\u0026amp;#8220;error\u0026amp;#8221;,console.error.bind(console.\u0026amp;#8217;conection error:\u0026amp;#8217;)) db.on(\u0026amp;#8216;open\u0026amp;#8217;.function(callback){ }) var loginSchema = new mongoose.Schema({ username:String, \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;password:String\u0026lt;/span\u0026gt; }) \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;var login = db.model(\u0026amp;#8220;login\u0026amp;#8221;,loginSchema,\u0026amp;#8221;login\u0026amp;#8221;)//第一个名称是创建实例使用的名称，第二个是表结构参数，第三个是数据库显示的结合的名称不填的话默认是实例名称的复数s\u0026lt;/span\u0026gt; var user1 = new login({username:\u0026amp;#8221;zhang\u0026amp;#8221;,password:\u0026amp;#8217;test\u0026amp;#8217;}) user1.save(function(err){ \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;if(err) return handleError(err)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;})\u0026lt;/span\u0026gt; \u0026lt;/blockquote\u0026gt; Redis \u0026lt;blockquote\u0026gt; npm install redis var redis = require(\u0026amp;#8220;redis\u0026amp;#8221;) var client = redis.createClient(\u0026amp;#8216;6379\u0026amp;#8242;,\u0026amp;#8217;127.0.0.1\u0026amp;#8217;) client.on(\u0026amp;#8220;error\u0026amp;#8221;,function(error){ }) client.on(\u0026amp;#8220;ready\u0026amp;#8221;,funciont(){ }) \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;client.set(\u0026amp;#8220;name\u0026amp;#8221;,\u0026amp;#8221;zhang\u0026amp;#8221;,redis.print)\u0026lt;/span\u0026gt; client.get(\u0026amp;#8220;name\u0026amp;#8221;,function(err,reply){ }) client.publish(\u0026amp;#8216;test\u0026amp;#8217;,\u0026amp;#8221;hello,Node\u0026amp;#8221;) client.subscribe(\u0026amp;#8216;test\u0026amp;#8217;) client.on(\u0026amp;#8220;message\u0026amp;#8221;,function(channel,message){ \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;})\u0026lt;/span\u0026gt; \u0026lt;/blockquote\u0026gt; Localtunnel \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; localtunnel是一个有名的第三方模块 localtunnel.me \u0026lt;/blockquote\u0026gt; 爬虫 \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; robot.txt是爬虫默认规则 PHelper cheerio request.js //node第三方的HTTP请求 \u0026lt;span class=\u0026quot;md-link\u0026quot; spellcheck=\u0026quot;false\u0026quot;\u0026gt;[https://github.com/request/request](https://github.com/request/request)\u0026lt;/span\u0026gt; cheerio 网页解析 \u0026lt;span class=\u0026quot;md-link\u0026quot; spellcheck=\u0026quot;false\u0026quot;\u0026gt;[https://github.com/cheeriojs/cheerio](https://github.com/cheeriojs/cheerio)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;selenium\u0026lt;/span\u0026gt; MongoDB存储数据 Redis消息队列 \u0026lt;/blockquote\u0026gt; 测试与调试 \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; 使用Assert模块 Jasmine Ava.js nyc代码覆盖率 Travis \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;node-inspector v8-inspector\u0026lt;/span\u0026gt; \u0026lt;/blockquote\u0026gt; package.json \u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt; package.json常用字段 name项目名称 verion项目版本号 scripts项目不同阶段的命令 version字段说明 version：完全匹配 \u0026lt;span spellcheck=\u0026quot;false\u0026quot;\u0026gt;`\u0026amp;gt;`\u0026lt;/span\u0026gt;version 大于这个版本 \u0026lt;span spellcheck=\u0026quot;false\u0026quot;\u0026gt;`\u0026amp;gt;=`\u0026lt;/span\u0026gt;version 大于登录这个版本 ~version 非常接近这个版本 ^version与这个版本不兼容 1.2.x 这个符号1.2.x的版本 x是任意数字 *或者“” 任何版本都可以 \u0026lt;span class=\u0026quot;md-expand\u0026quot;\u0026gt;version1-version2 版本在version1和version2之间（包括version1和version2）\u0026lt;/span\u0026gt; \u0026lt;/blockquote\u0026gt; ","permalink":"https://blog.zdltech.com/posts/%E6%96%B0%E6%97%B6%E6%9C%9F%E7%9A%84node-js%E5%85%A5%E9%97%A8%E6%80%BB%E7%BB%93/","summary":"\u003ch2 id=\"基础汇总\"\u003e\u003cspan class=\"md-expand\"\u003e基础汇总\u003c/span\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  require引用的文件中不要有内部调用，否则可能有未知隐患（内存泄漏、或者直接崩溃）\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  Buffer 是Node特有的数据类型（固有属性、不需要require），主要用来处理二进制数据（Buffer通常表现为十六进制的字符串），新Node API Buffer()方法为Deprecated，推荐使用Buffer.form来初始化一个Buffer对象\n\n\n\n\u0026lt;blockquote\u0026gt;\n  \n\n    buffer.toString([encoding],[start],[end]) buffer 支持编码类型 ASCII Base64 Binary Hex UTF-8 UTF-16LE/UCS-2\n  \n\n  \n  \n\n    Buffer一个常用的场景就是HTTP的POST请求，例如\n  \n\n  \n  \n\n    var body = \u0026amp;#8221;\n  \n\n  \n  \n\n    req.setEncoding(\u0026amp;#8216;utf-8\u0026amp;#8217;);\n  \n\n  \n  \n\n    req.on(\u0026amp;#8216;data\u0026amp;#8217;,function(chumk){\n  \n\n  \n  \n\n    body += chunk;\n  \n\n  \n  \n\n    })\n  \n\n  \n  \n\n    req.on(\u0026amp;#8216;end\u0026amp;#8217;,function(){\n  \n\n  \n  \n\n    })\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;Fill System 是Node中使用最为频繁的模块之一，该模块提供了读写文件的能力，是借助于底层的linuv的C++ API实现的。\u0026lt;/span\u0026gt;\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    常用API\n  \n\n  \n  \n\n    readFile writeFile stat\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;fs.stat获取文件的状态（可以用来判断文件还是文件夹）\u0026lt;/span\u0026gt;\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  HTTP服务 是Node的核心模块。\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    var http = require(\u0026amp;#8220;http\u0026amp;#8221;)\n  \n\n  \n  \n\n    var server = http.createServer(function(req,res){\n  \n\n  \n  \n\n    // req.url 获取访问的路径\n  \n\n  \n  \n\n    //req.method 请求方法\n  \n\n  \n  \n\n    req.on(\u0026amp;#8220;data\u0026amp;#8221;,function(chunk){\n  \n\n  \n  \n\n    }).on(\u0026amp;#8220;end\u0026amp;#8221;,function(){\n  \n\n  \n  \n\n    });\n  \n\n  \n  \n\n    res.writeHead(200,{\u0026amp;#8216;Content-Type\u0026amp;#8217;:\u0026amp;#8217;text/plain\u0026amp;#8217;,\u0026amp;#8221;Content-Length\u0026amp;#8221;:Buffer.byteLength(body)});\n  \n\n  \n  \n\n    res.end(\u0026amp;#8216;Hello Node!!!\u0026amp;#8217;);//每个HTTP请求的最后都会被调用，当客户端的请求完成后，开发者应该调用该方法结束HTTP请求\n  \n\n  \n  \n\n    });\n  \n\n  \n  \n\n    server.on(\u0026amp;#8220;connection\u0026amp;#8221;,function(req,res){\n  \n\n  \n  \n\n    });\n  \n\n  \n  \n\n    server.on(\u0026amp;#8220;request\u0026amp;#8221;,function(req,res){\n  \n\n  \n  \n\n    })\n  \n\n  \n  \n\n    server.listen(3000)\n  \n\n  \n  \n\n    //处理异常\n  \n\n  \n  \n\n    process.on(\u0026amp;#8220;uncaughtException\u0026amp;#8221;,function(){\n  \n\n  \n  \n\n    })\n  \n\n  \n  \n\n    // req.headesr 表示head信息\n  \n\n  \n  \n\n    POST上传文件\n  \n\n  \n  \n\n    表单类型设置为： enctype=\u0026amp;#8221;multipart/form-data\u0026amp;#8221;\n  \n\n  \n  \n\n    服务器处理上传文件通常基于stream来实现，这里比较流行的第三方库formidable\n  \n\n  \n  \n\n    function dealUpload(req,res){\n  \n\n  \n  \n\n    var form = new formidable.IncomingForm();\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;form.eekpExtension = true;\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    form.uploadDir =__dirname;\n  \n\n  \n  \n\n    from.parse(req,function(err,fields.files){\n  \n\n  \n  \n\n    if(err)throw err;\n  \n\n  \n  \n\n    console.log(fields);\n  \n\n  \n  \n\n    console.log(files);\n  \n\n  \n  \n\n    res.writeHead(200,{\u0026amp;#8220;Content-type\u0026amp;#8221;:\u0026amp;#8217;text/plain\u0026amp;#8217;});\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;res.end(\u0026amp;#8216;upload finished\u0026amp;#8217;);\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;})\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    }\n  \n\n  \n  \n\n    HTTP 客户端服务\n  \n\n  \n  \n\n    var http=require(\u0026amp;#8220;http\u0026amp;#8221;);\n  \n\n  \n  \n\n    http.get(\u0026amp;#8220;\u0026lt;span class=\u0026quot;md-link\u0026quot; spellcheck=\u0026quot;false\u0026quot;\u0026gt;[http://www.baidu.com](http://www.baidu.com)\u0026lt;/span\u0026gt;\u0026amp;#8220;,function(res){\n  \n\n  \n  \n\n    var statusCode = res.statusCode;\n  \n\n  \n  \n\n    if(statusCode==200){\n  \n\n  \n  \n\n    res.on(\u0026amp;#8220;data\u0026amp;#8221;,function(chunk){\n  \n\n  \n  \n\n    });\n  \n\n  \n  \n\n    res.on(\u0026amp;#8220;end\u0026amp;#8221;,function(){\n  \n\n  \n  \n\n    });\n  \n\n  \n  \n\n    res.on(\u0026amp;#8220;error\u0026amp;#8221;,function(e){\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;})\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    });\n  \n\n  \n  \n\n    //代理服务器\n  \n\n  \n  \n\n    var http =require(\u0026amp;#8220;http\u0026amp;#8221;);\n  \n\n  \n  \n\n    var url = require(\u0026amp;#8220;url\u0026amp;#8221;);\n  \n\n  \n  \n\n    http.createServer(function(req,res){\n  \n\n  \n  \n\n    var url = req.url.substring(1,req.url.length);//去掉最前面的/\n  \n\n  \n  \n\n    var proxyRequest = http.request(url,function(pres){\n  \n\n  \n  \n\n    res.writhHead(pres.statusCode,pres.headers);\n  \n\n  \n  \n\n    pres.on(\u0026amp;#8220;data\u0026amp;#8221;,function(data){\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;res.write(data);\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    });\n  \n\n  \n  \n\n    pres.on(\u0026amp;#8220;end\u0026amp;#8221;,function(){\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;res.end();\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;})\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    });\n  \n\n  \n  \n\n    req.on(\u0026amp;#8220;data\u0026amp;#8221;,function(data){\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;proxyRequest.write(data);\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    });\n  \n\n  \n  \n\n    req.on(\u0026amp;#8220;end\u0026amp;#8221;,function(){\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;proxyReques.end();\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;});\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;}).listen(8080);\u0026lt;/span\u0026gt;\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;WebSocekt (比较出名的WebSocket模块还有Socket.IO)\u0026lt;/span\u0026gt;\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    Node 实现WebSocket\n  \n\n  \n  \n\n    var WebSocketServer = require(\u0026amp;#8220;ws\u0026amp;#8221;).Server;\n  \n\n  \n  \n\n    var wss = new WebScoketServer({port:3304});\n  \n\n  \n  \n\n    wss.on(\u0026amp;#8220;connection\u0026amp;#8221;,function(ws){\n  \n\n  \n  \n\n    ws.on(\u0026amp;#8220;message\u0026amp;#8221;,function(message){\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;console.log(message);\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    });\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;ws.send(\u0026amp;#8220;Node Hello WebSocket\u0026amp;#8221;);\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;})\u0026lt;/span\u0026gt;\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  Events 在Node中只定义了一个类EventEmitter\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    var eventEmitter = require(\u0026amp;#8220;events\u0026amp;#8221;);\n  \n\n  \n  \n\n    var myEmitter = new eventEmitter();\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;myEmitter.on(\u0026amp;#8220;begin\u0026amp;#8221;,function(){//注册一个begin事件\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;console.log(\u0026amp;#8220;begin\u0026amp;#8221;);\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;});\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;myEmitter.emit(\u0026amp;#8220;begin\u0026amp;#8221;);//触发begin事件\u0026lt;/span\u0026gt;\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  多进程服务\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    child_process模块中包括很多创建子进程的方法，包括fork、spawn、exec、execFile\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;Cluster是Node 0.6之后新增模块（Cluster可以看做是做了封装的child_process模块）\u0026lt;/span\u0026gt;\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;Proces对象是一个全局的对象，每个Node进程都有独立的process对象，该对象中存储了当前的环境变量，也定义了一些事件\u0026lt;/span\u0026gt;\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    process.getuid();//用户id\n  \n\n  \n  \n\n    process.argv;//Node的命令行参数列表\n  \n\n  \n  \n\n    process.pid;//进程id\n  \n\n  \n  \n\n    process.cwd();//当前目录\n  \n\n  \n  \n\n    process.versoin;//Node版本\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;process.env;//\u0026lt;/span\u0026gt;\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  Timer setTimeout setInterval\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  nvm\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    nvm install version 安装某个版本的node\n  \n\n  \n  \n\n    nvm use veresion 切换到某个版本\n  \n\n  \n  \n\n    nvm ls 列出当前安装的所有的Node版本\n  \n\n  \n  \n\n    let关键字 会创建一个块级作用域\n  \n\n  \n  \n\n    const变量不可以再被修改\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  函数\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    参数可以设置默认值\n  \n\n  \n  \n\n    function gred(x=\u0026amp;#8221;a\u0026amp;#8221;,y=\u0026amp;#8221;b\u0026amp;#8221;){\n  \n\n  \n  \n\n    }\n  \n\n  \n  \n\n    Spread运算符（\u0026amp;#8230;）展开运算符\n  \n\n  \n  \n\n    var ab=[\u0026amp;#8220;ab\u0026amp;#8221;,\u0026amp;#8221;cd\u0026amp;#8221;]\n  \n\n  \n  \n\n    gred(..ab);\n  \n\n  \n  \n\n    箭头函数（ES6）\n  \n\n  \n  \n\n    var func= a=\u0026gt;a;等价于\n  \n\n  \n  \n\n    var func = function(a){\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;return a;\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    }\n  \n\n  \n  \n\n    多个参数\n  \n\n  \n  \n\n    var func=(a,b)=\u0026gt;{\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;console.log(a,b);\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  Promise 异步处理\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    var promis = new Promise(function(resolve.reject){\n  \n\n  \n  \n\n    //执行相关异步操作\n  \n\n  \n  \n\n    //resolve(data)\n  \n\n  \n  \n\n    // reject(err)\n  \n\n  \n  \n\n    }),then(res=\u0026gt;{}).catch(err=\u0026gt;{});\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;promise.all 多个promise需要执行封装为一个\u0026lt;/span\u0026gt;\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  回调的终点\u0026amp;#8211;async/await\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    node 7.6.0之后原生支持\n  \n\n  \n  \n\n    var asyncReadFile = async function(){\n  \n\n  \n  \n\n    var result1 = await readFile(\u0026amp;#8216;a.txt\u0026amp;#8217;);\n  \n\n  \n  \n\n    var result 2 = await readFile(\u0026amp;#8216;b.txt\u0026amp;#8217;);\n  \n\n  \n  \n\n    console.log(result1);\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;console.log(result2);\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  Koa2 构建web站点\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    koa-static 静态文件服务\n  \n\n  \n  \n\n    koa-router 路由服务\n  \n\n  \n  \n\n    koa-bodyparse\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  MongoDB (Mongoose)\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    npm install mongoose\n  \n\n  \n  \n\n    var mongoose = require(\u0026amp;#8220;mongoose\u0026amp;#8221;)\n  \n\n  \n  \n\n    mongoose.connect(\u0026amp;#8220;mongodb://xxx/test\u0026amp;#8221;);\n  \n\n  \n  \n\n    var db = mongose.connection;\n  \n\n  \n  \n\n    db.on(\u0026amp;#8220;error\u0026amp;#8221;,console.error.bind(console.\u0026amp;#8217;conection error:\u0026amp;#8217;))\n  \n\n  \n  \n\n    db.on(\u0026amp;#8216;open\u0026amp;#8217;.function(callback){\n  \n\n  \n  \n\n    })\n  \n\n  \n  \n\n    var loginSchema = new mongoose.Schema({\n  \n\n  \n  \n\n    username:String,\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;password:String\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    })\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;var login = db.model(\u0026amp;#8220;login\u0026amp;#8221;,loginSchema,\u0026amp;#8221;login\u0026amp;#8221;)//第一个名称是创建实例使用的名称，第二个是表结构参数，第三个是数据库显示的结合的名称不填的话默认是实例名称的复数s\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    var user1 = new login({username:\u0026amp;#8221;zhang\u0026amp;#8221;,password:\u0026amp;#8217;test\u0026amp;#8217;})\n  \n\n  \n  \n\n    user1.save(function(err){\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;if(err) return handleError(err)\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;})\u0026lt;/span\u0026gt;\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  Redis\n\n\n\n\u0026lt;blockquote\u0026gt;\n  \n\n    npm install redis\n  \n\n  \n  \n\n    var redis = require(\u0026amp;#8220;redis\u0026amp;#8221;)\n  \n\n  \n  \n\n    var client = redis.createClient(\u0026amp;#8216;6379\u0026amp;#8242;,\u0026amp;#8217;127.0.0.1\u0026amp;#8217;)\n  \n\n  \n  \n\n    client.on(\u0026amp;#8220;error\u0026amp;#8221;,function(error){\n  \n\n  \n  \n\n    })\n  \n\n  \n  \n\n    client.on(\u0026amp;#8220;ready\u0026amp;#8221;,funciont(){\n  \n\n  \n  \n\n    })\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;client.set(\u0026amp;#8220;name\u0026amp;#8221;,\u0026amp;#8221;zhang\u0026amp;#8221;,redis.print)\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    client.get(\u0026amp;#8220;name\u0026amp;#8221;,function(err,reply){\n  \n\n  \n  \n\n    })\n  \n\n  \n  \n\n    client.publish(\u0026amp;#8216;test\u0026amp;#8217;,\u0026amp;#8221;hello,Node\u0026amp;#8221;)\n  \n\n  \n  \n\n    client.subscribe(\u0026amp;#8216;test\u0026amp;#8217;)\n  \n\n  \n  \n\n    client.on(\u0026amp;#8220;message\u0026amp;#8221;,function(channel,message){\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;})\u0026lt;/span\u0026gt;\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  Localtunnel\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    localtunnel是一个有名的第三方模块\n  \n\n  \n  \n\n    localtunnel.me\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  爬虫\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    robot.txt是爬虫默认规则\n  \n\n  \n  \n\n    PHelper\n  \n\n  \n  \n\n    cheerio\n  \n\n  \n  \n\n    request.js //node第三方的HTTP请求 \u0026lt;span class=\u0026quot;md-link\u0026quot; spellcheck=\u0026quot;false\u0026quot;\u0026gt;[https://github.com/request/request](https://github.com/request/request)\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    cheerio 网页解析 \u0026lt;span class=\u0026quot;md-link\u0026quot; spellcheck=\u0026quot;false\u0026quot;\u0026gt;[https://github.com/cheeriojs/cheerio](https://github.com/cheeriojs/cheerio)\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;selenium\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    MongoDB存储数据\n  \n\n  \n  \n\n    Redis消息队列\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  测试与调试\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    使用Assert模块\n  \n\n  \n  \n\n    Jasmine\n  \n\n  \n  \n\n    Ava.js\n  \n\n  \n  \n\n    nyc代码覆盖率\n  \n\n  \n  \n\n    Travis\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;\u0026quot;\u0026gt;node-inspector v8-inspector\u0026lt;/span\u0026gt;\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e  package.json\n\n\n\n\u0026lt;blockquote contenteditable=\u0026quot;true\u0026quot;\u0026gt;\n  \n\n    package.json常用字段\n  \n\n  \n  \n\n    name项目名称\n  \n\n  \n  \n\n    verion项目版本号\n  \n\n  \n  \n\n    scripts项目不同阶段的命令\n  \n\n  \n  \n\n    version字段说明\n  \n\n  \n  \n\n    version：完全匹配\n  \n\n  \n  \n\n    \u0026lt;span spellcheck=\u0026quot;false\u0026quot;\u0026gt;`\u0026amp;gt;`\u0026lt;/span\u0026gt;version 大于这个版本\n  \n\n  \n  \n\n    \u0026lt;span spellcheck=\u0026quot;false\u0026quot;\u0026gt;`\u0026amp;gt;=`\u0026lt;/span\u0026gt;version 大于登录这个版本\n  \n\n  \n  \n\n    ~version 非常接近这个版本\n  \n\n  \n  \n\n    ^version与这个版本不兼容\n  \n\n  \n  \n\n    1.2.x 这个符号1.2.x的版本 x是任意数字\n  \n\n  \n  \n\n    *或者“” 任何版本都可以\n  \n\n  \n  \n\n    \u0026lt;span class=\u0026quot;md-expand\u0026quot;\u0026gt;version1-version2 版本在version1和version2之间（包括version1和version2）\u0026lt;/span\u0026gt;\n  \n\n\u0026lt;/blockquote\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e","title":"新时期的Node.js入门总结"},{"content":"最近在做一个项目的时候，出现了一个很奇怪的问题，我的java文件前面出现了一个奇怪的蓝色j，\n这使得我的代码其他地方无法对它进行调用，所以程序一运行，调用到它的地方就会报错，（因为我的这个代码是用protobuffer协议自动生成的java文件，比较大，大概有5M多）。\n后来上网查了一下，发现是IDEA对能关联的文件大小做了限制，主要是为了保护内存，默认值为2500kb或者5000kb，对于一般的java文件也够用了，只是这里我用protocbuf生成的java文件过大，所以要对它这个默认的值进行修改。\n找到Android studio 的安装目录下bin 下的idea.properties文件（默认安装路径：C:\\Program Files\\Android\\Android Studio\\bin）。\n打开这个文件，对里面的idea.max.intellisense.filesizej进行设置，保存( 单位是kb）\n然后重启Android studio即可。\n","permalink":"https://blog.zdltech.com/posts/android-studio%E9%A1%B9%E7%9B%AEjava%E6%96%87%E4%BB%B6%E8%BF%87%E5%A4%A7%E5%AF%BC%E8%87%B4%E7%9A%84%E9%97%AE%E9%A2%98%E8%AE%B0%E5%BD%95/","summary":"\u003cp\u003e最近在做一个项目的时候，出现了一个很奇怪的问题，我的java文件前面出现了一个奇怪的蓝色j，\u003c/p\u003e\n\u003cp\u003e这使得我的代码其他地方无法对它进行调用，所以程序一运行，调用到它的地方就会报错，（因为我的这个代码是用protobuffer协议自动生成的java文件，比较大，大概有5M多）。\u003c/p\u003e\n\u003cp\u003e后来上网查了一下，发现是IDEA对能关联的文件大小做了限制，主要是为了保护内存，默认值为2500kb或者5000kb，对于一般的java文件也够用了，只是这里我用protocbuf生成的java文件过大，所以要对它这个默认的值进行修改。\u003c/p\u003e\n\u003cp\u003e找到Android studio 的安装目录下bin 下的idea.properties文件（默认安装路径：C:\\Program Files\\Android\\Android Studio\\bin）。\u003c/p\u003e\n\u003cp\u003e打开这个文件，对里面的idea.max.intellisense.filesizej进行设置，保存( 单位是kb）\u003c/p\u003e\n\u003cp\u003e然后重启Android studio即可。\u003c/p\u003e","title":"Android studio项目java文件过大导致的问题记录"},{"content":"安装nodemon:\n修改package.json\n“scripts”: {\n“start”: “node ./bin/www”,\n“run”:”./node_modules/.bin/nodemon ./bin/www”\n},\n启动命令 npm run run\nnodemon最大的作用就是项目重启，触发重启的事件就是系统文件改变了。因为我们开发过程中经常要对系统文件进行修改，我们每次修改后的通常做法是先退出程序然后再开启程序，这样很劳神费力改一个字都要做这两个步骤，现在好了，我们文件随便改，一改他就重启，这两个步骤就被省略了会大大提高我们的编码效率和减少debug时间。\n转自：https://blog.csdn.net/lbPro0412/article/details/82454163\n","permalink":"https://blog.zdltech.com/posts/node-js%E4%B9%8B%E7%83%AD%E6%9B%B4%E6%96%B0%E9%87%8D%E5%90%AFnodemon/","summary":"\u003cp\u003e安装nodemon:\u003c/p\u003e\n\u003cp\u003e修改package.json\u003c/p\u003e\n\u003cp\u003e“scripts”: {\u003cbr\u003e\n“start”: “node ./bin/www”,\u003cbr\u003e\n“run”:”./node_modules/.bin/nodemon ./bin/www”\u003cbr\u003e\n},\u003cbr\u003e\n启动命令 npm run run\u003c/p\u003e\n\u003cp\u003enodemon最大的作用就是项目重启，触发重启的事件就是系统文件改变了。因为我们开发过程中经常要对系统文件进行修改，我们每次修改后的通常做法是先退出程序然后再开启程序，这样很劳神费力改一个字都要做这两个步骤，现在好了，我们文件随便改，一改他就重启，这两个步骤就被省略了会大大提高我们的编码效率和减少debug时间。\u003c/p\u003e\n\u003cp\u003e转自：https://blog.csdn.net/lbPro0412/article/details/82454163\u003c/p\u003e","title":"node.js之热更新重启nodemon"},{"content":" 在终端输入命令,进入用户目录 ``` $ cd ~ ``` 测试adb,开启终端,输入命令,显示出”Android Debug Bridge version 1.0.39″ 为配置成功 ``` $ adb version ``` 第二步工作是：创建、修改 adb_usb.ini 文件，这里也分为2小步\n打开终端,输入命令,查看设备信息 ``` $ system_profiler SPUSBDataType ``` 1.2 得到自己对应的设备信息,其中Vendor ID 中的信息,需要保留,等下使用\n``` SAMSUNG_Android: Product ID: 0x6753 Vendor ID: 0x05e4 (Samsung Electronics Co., Ltd.) Version: 6.00 Serial Number: 7d0076027c174055 Speed: Up to 420 Mb/sec Manufacturer: SAMSUNG Location ID: 0x13200000 / 10 Current Available (mA): 400 Current Required (mA): 86 Extra Operating Current (mA): 0 \u0026lt;/div\u0026gt; 2.创建、修改adb_usb.ini文件,可以在终端输入命令,也可以查找文件 2.1 查找adb_usb.ini文件 2.1.1输入命令 \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; vi ~/.android/adb_usb.ini\n\u0026lt;/div\u0026gt; 2.1.2 查找文件 ![](https://images2015.cnblogs.com/blog/487543/201704/487543-20170416184609352-349569903.png) 2.2 在adb_usb.ini中 输入设备的Vendor ID后,保存并退出 2.3 重新启动finder \u0026amp;nbsp; 第三步:在终端输入命令,关闭并重新启动adb \u0026amp;nbsp; \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; $ adbkill-server $ adbstart-server\n\u0026lt;/div\u0026gt; \u0026amp;nbsp; 第四步: 开启手机上开发者选项中的usb调试功能 \u0026amp;nbsp; 第五步:在android Studio中创建项目运行到手机上 \u0026amp;nbsp; 更多usb.ids查看下面地址 http://www.linux-usb.org/usb.ids http://www.linux-usb.org/usb.ids http://www.linux-usb.org/usb.ids 第一步 找到自己设备的 ID。 About This Mac(关于本机) -\u0026gt; System Report(系统报告) -\u0026gt; USB-\u0026gt; 选择你所连接的Android 设备 \u0026amp;#8211;\u0026gt; Vendor ID (供应商ID)。可见,我的 Nexus 5 的 Vendor ID 为 0x18d1 。 http://www.linux-usb.org/usb.ids 第二步 在终端执行如下命令,命令中的 YOUR\\_VENDOR\\_ID 用你的 Android 设备 Vendor ID 代替, 这里可以代入0x18d1 : http://www.linux-usb.org/usb.ids 第三步 在终端中执行如下命令,发现已经可以识别到设备了。 http://www.linux-usb.org/usb.ids 结果如下: http://www.linux-usb.org/usb.ids ","permalink":"https://blog.zdltech.com/posts/mac%E7%94%B5%E8%84%91%E4%BD%BF%E7%94%A8android-studio%E8%BF%9B%E8%A1%8C%E7%9C%9F%E6%9C%BA%E8%B0%83%E8%AF%95/","summary":"\u003col\u003e\n\u003cli\u003e在终端输入命令,进入用户目录\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  ```\n$ cd ~\n```\n\u003c/div\u003e\n\u003col\u003e\n\u003cli\u003e测试adb,开启终端,输入命令,显示出”\u003cspan class=\"s1\"\u003eAndroid Debug Bridge version 1.0.39″ 为配置成功\u003c/span\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  ```\n$ adb version\n```\n\u003c/div\u003e\n\u003cp\u003e第二步工作是：创建、修改 adb_usb.ini 文件，这里也分为2小步\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e打开终端,输入命令,查看设备信息\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  ```\n$ system_profiler SPUSBDataType\n```\n\u003c/div\u003e\n\u003cp\u003e1.2 得到自己对应的设备信息,其中Vendor ID 中的信息,需要保留,等下使用\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  ```\n        SAMSUNG_Android:\n\u003cpre\u003e\u003ccode\u003e      Product ID: 0x6753\n      Vendor ID: 0x05e4  (Samsung Electronics Co., Ltd.)\n      Version: 6.00\n      Serial Number: 7d0076027c174055\n      Speed: Up to 420 Mb/sec\n      Manufacturer: SAMSUNG\n      Location ID: 0x13200000 / 10\n      Current Available (mA): 400\n      Current Required (mA): 86\n      Extra Operating Current (mA): 0\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e2.创建、修改adb_usb.ini文件,可以在终端输入命令,也可以查找文件\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e2.1 查找adb_usb.ini文件\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e2.1.1输入命令\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003evi ~/.android/adb_usb.ini\u003c/p\u003e","title":"解决 Mac OSX 无法识别 Android 设备"},{"content":"摘要： Android App Bundles 在今年的Google I/O大会上，Google向 Android 引入了新 App 动态化框架（即Android App Bundle，缩写为AAB），与Instant App不同，AAB是借助Split Apk完成动态加载，使用AAB动态下发方式，可以大幅度减少应用体积。\n## Android App Bundles 在今年的Google I/O大会上，Google向 Android 引入了新 App 动态化框架（即Android App Bundle，缩写为AAB），与Instant App不同，AAB是借助Split Apk完成动态加载，使用AAB动态下发方式，可以大幅度减少应用体积。现在只须在 Android Studio 中构建一个应用束 (app bundle)，就可以将应用所需的全部内容 (适用于所有设备) 都涵盖在内：所有语言、所有设备屏幕大小、所有硬件架构。 下面是Dynamic Delivery示意效果图： 不过要想体验Dynamic Delivery，需要先下载 Android Studio 3.2 学习Android App Bundles可以将它和Split Apks来对比学习。 Split Apks split apks是Android 5.0开始提供多apk构建机制，借助split apks可以将一个apk基于ABI和屏幕密度两个维度拆分城多个apk，这样可以有效减少apk体积。当用户下载应用程序安装包时，只会包含对应平台的so和资源。因为需要google play支持，所以国内就没戏了。针对不同cpu架构问题，国内应用开发商大部分都会将so文件只放在armabi目录下，如此做虽然可以有效减少包体积，但可能带来性能问题。split apks详细的内容可以访问下面的链接：[https://link.zhihu.com/?target=https%3A//developer.android.com/studio/build/configure-apk-splits%3Fauthuser%3D2](https://link.zhihu.com/?target=https%3A//developer.android.com/studio/build/configure-apk-splits%3Fauthuser%3D2) Split Apks的运作原理有点类似于Android的组件化，安装应用程序时，首先安装base apk，然后安装split apks。为了说明splite apks运作原理，来看一下Android 5.0关于splite apks的源码。 打开[ApplicationInfo](http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/content/pm/ApplicationInfo.java)类中，可以看到如下信息： `/** * Full paths to zero \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;or\u0026amp;lt;/span\u0026gt; more \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;split\u0026amp;lt;/span\u0026gt; APKs that, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;when\u0026amp;lt;/span\u0026gt; combined with the base * APK \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;defined\u0026amp;lt;/span\u0026gt; in {@link \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;#sourceDir}, form a complete application.\u0026amp;lt;/span\u0026gt; *\u0026amp;lt;span class=\u0026#34;hljs-regexp\u0026#34;\u0026gt;/ public String[] splitSourceDirs; /\u0026amp;lt;/span\u0026gt;** * Full path to the publicly available parts of {@link \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;#splitSourceDirs},\u0026amp;lt;/span\u0026gt; * including resources \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;and\u0026amp;lt;/span\u0026gt; manifest. This may be different from * {@link \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;#splitSourceDirs} if an application is forward locked.\u0026amp;lt;/span\u0026gt; *\u0026amp;lt;span class=\u0026#34;hljs-regexp\u0026#34;\u0026gt;/ public String[] splitPublicSourceDirs;\u0026amp;lt;/span\u0026gt;` [LoadeApk](http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/app/LoadedApk.java)中有PathClassLoader和Resources创建过程。LoadedApk#mClassLoader是PathClassLoader实例引用，接着看PathClassLoader的创建过程。 zipPaths = new ArrayList\u0026lt;\u0026gt;(); final ArrayList\u0026lt;String\u0026gt; libPaths = new ArrayList\u0026lt;\u0026gt;(); ....... zipPaths.add(mAppDir); //将split apk路径追加到zipPaths中 if (mSplitAppDirs != null) { Collections.addAll(zipPaths, mSplitAppDirs); } libPaths.add(mLibDir); ...... final String zip = TextUtils.join(File.pathSeparator, zipPaths); final String lib = TextUtils.join(File.pathSeparator, libPaths); ...... //如果mSplitAppDirs不为空，则zip将包含split apps所有路径。 mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib, mBaseClassLoader); StrictMode.setThreadPolicy(oldPolicy); } else { if (mBaseClassLoader == null) { mClassLoader = ClassLoader.getSystemClassLoader(); } else { mClassLoader = mBaseClassLoader; } } return mClassLoader; } }\u0026#34; data-snippet-id=\u0026#34;ext.b0abcb7003a3d76aeb1ae260fba2afe7\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ClassLoader \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getClassLoader\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;synchronized\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mClassLoader != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mClassLoader; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mIncludeCode \u0026amp;\u0026amp; !mPackageName.equals(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;android\u0026#34;\u0026amp;lt;/span\u0026gt;)) { ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;String\u0026amp;gt; zipPaths = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;String\u0026amp;gt; libPaths = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); ....... zipPaths.add(mAppDir); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//将split apk路径追加到zipPaths中\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mSplitAppDirs != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { Collections.addAll(zipPaths, mSplitAppDirs); } libPaths.add(mLibDir); ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; String zip = TextUtils.join(File.pathSeparator, zipPaths); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; String lib = TextUtils.join(File.pathSeparator, libPaths); ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//如果mSplitAppDirs不为空，则zip将包含split apps所有路径。\u0026amp;lt;/span\u0026gt; mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib, mBaseClassLoader); StrictMode.setThreadPolicy(oldPolicy); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mBaseClassLoader == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { mClassLoader = ClassLoader.getSystemClassLoader(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { mClassLoader = mBaseClassLoader; } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mClassLoader; } }` 在创建PathClassLoader时，dex文件路径包含base app和split apps路径，LoadedApk#mResources是Resources实例引用，Resources的源码如下： `\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Resources \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getResources\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;ActivityThread mainThread\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mResources == \u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs, mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, \u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mResources; }` 可以发现：split apks资源路径（LoadedApk#mSplitResDirs）也会被增加至Resources中。 Android App Bundles 下面再来看Android App Bundles，Android App Bundle 支持模块化，通过Dynamic Delivery with split APKs，将一个apk拆分成多个apk，按需加载（包括加载C/C++ libraries），这样开发者可以随时按需交付功能，而不是仅限在安装过程中。 Android App Bundle 通常会包括以下几个文件： - Base Apk：首次安装的apk，公共代码和资源，所以其他的模块都基于Base Apk； - Configuration APKs：native libraries 和适配当前手机屏幕分辨率的资源； - Dynamic feature APKs：不需要在首次安装就加载的模块。 ![这里写图片描述](https://img-blog.csdn.net/20180516221843565) AAB并不是一个插件化框架，它利用的是Android Framework提供的split apks技术来完成的，而所有安装split apk工作均是通过IPC交由google play完成。 具体使用时，在Android Studio新增一项module——Dynamic Feature Module。 在创建dynamic_feature时，有两个选项是默认勾选的，当然我们也可以更改其状态。 - Enable on-demand: 是否支持按需下载模式。如果不支持，那么该feature则在安装app时被安装。 - Fusing: 如果app运行在Android 5.0（不包括5.0）以下，勾选Fusing则表示该feature会被一起打包至完整apk中。 下面看一个简单的实例程序。 在示例中，有四个feature，通过module名很清楚这些feature是举例介绍如何访问代码、资源、so等。 dynamic feature module编译所使用的插件com.android.dynamic-feature，那么该插件有何独特之处，通过编译产物分析，运行示例后，发现在所有dynamic feature模块build目录下均会生成apk文件。\n接着反编译主apk（com.android.application插件生成产物），会发现两个有趣的现象： - 所有dynamic feature module的代码、资源、so并未打包至主apk中。 - 主apk manifest信息包括所有dynamic feature module的manifest，即feature manifest会被合并至主apk manifest中。 Build Bundle(s) Android App Bundle提供一种全新编译产物格式文件aab，使用Android Studio提供的App Bundle即可。 如上图，当选择Build Bundle(s)时，在主工程build目录下回生成bundle.aab文件，该文件是压缩格式文件，解压该aab文件内容如下。 从aab文件内容，可知其包含base和feature的代码、资源、so等，同时还有BundleConfig.pb这一配置文件，该配置文件是google play用于拆分apk。如果我们需要在google play上支持动态发布，只需要上传aab文件即可，后续工作交给google play完成。 Play Core Library Play Core Library是AAB提供的核心库，用于下载、安装dynamic feature模块。另外，我们也可以用这些API下载on-demand模块用于instant app。关于Play Core Library具体如何使用，大家可以查看相关文档。 兼容性问题处理 6.0以下版本 当app运行设备版本不高于6.0时，需要使用SplitCompat库才能立即访问下载模块代码和资源。AAB提供SplitCompatApplication类用于开启SplitCompat。 `\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;SplitCompatApplication\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Application\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;SplitCompatApplication\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;attachBaseContext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context var1)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.attachBaseContext(var1); SplitCompat.install(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;); } }` 在Application#attachBaseContext(Context)中调用SplitCompat.install(Context)。在该方法中主要完成split apks代码（dex和so）和资源的安装。下面是一些兼容的条件分支语句： `\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; a \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;a\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (VERSION.SDK_INT == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;21\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//com.google.android.play.core.splitcompat.b.c\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; c(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (VERSION.SDK_INT == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;22\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//com.google.android.play.core.splitcompat.b.f\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; f(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (VERSION.SDK_INT == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;23\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//com.google.android.play.core.splitcompat.b.g\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; g(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; AssertionError(); } }` 高于8.0版本 在Android 8.0中，Instant Apps相关代码嵌入至Framework。因此如果on-demand模块用于Instant Apps中，需要在on-demand下载成功中，调用SplitInstallHelper.updateAppInfo(Context)。 25) { a.a(\u0026amp;quot;Calling dispatchPackageBroadcast!\u0026amp;quot;, new Object[0]); try { Class var1; Method var2; (var2 = (var1 = Class.forName(\u0026amp;quot;android.app.ActivityThread\u0026amp;quot;)).getMethod(\u0026amp;quot;currentActivityThread\u0026amp;quot;)).setAccessible(true); Object var3 = var2.invoke((Object)null); Field var4; (var4 = var1.getDeclaredField(\u0026amp;quot;mAppThread\u0026amp;quot;)).setAccessible(true); Object var5; (var5 = var4.get(var3)).getClass().getMethod(\u0026amp;quot;dispatchPackageBroadcast\u0026amp;quot;, Integer.TYPE, String[].class).invoke(var5, 3, new String[]{var0.getPackageName()}); a.a(\u0026amp;quot;Calling dispatchPackageBroadcast\u0026amp;quot;, new Object[0]); } catch (Exception var6) { a.a(var6, \u0026amp;quot;Update app info with dispatchPackageBroadcast failed!\u0026amp;quot;, new Object[0]); } } }\u0026#34; data-snippet-id=\u0026#34;ext.fc596701974d7885a5867ac0edb0ea3a\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`public \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; updateAppInfo(Context var0) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (VERSION.SDK_INT \u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;25\u0026amp;lt;/span\u0026gt;) { a.a(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Calling dispatchPackageBroadcast!\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;Object\u0026amp;lt;/span\u0026gt;[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;]); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { Class var1; Method var2; (var2 = (var1 = Class.forName(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;android.app.ActivityThread\u0026#34;\u0026amp;lt;/span\u0026gt;)).getMethod(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;currentActivityThread\u0026#34;\u0026amp;lt;/span\u0026gt;)).setAccessible(\u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;Object\u0026amp;lt;/span\u0026gt; var3 = var2.invoke((\u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;Object\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); Field var4; (var4 = var1.getDeclaredField(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;mAppThread\u0026#34;\u0026amp;lt;/span\u0026gt;)).setAccessible(\u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;Object\u0026amp;lt;/span\u0026gt; var5; (var5 = var4.get(var3)).getClass().getMethod(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;dispatchPackageBroadcast\u0026#34;\u0026amp;lt;/span\u0026gt;, Integer.TYPE, \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;[].class).invoke(var5, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;3\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;[]{var0.getPackageName()}); a.a(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Calling dispatchPackageBroadcast\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;Object\u0026amp;lt;/span\u0026gt;[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;]); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (Exception var6) { a.a(var6, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Update app info with dispatchPackageBroadcast failed!\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;Object\u0026amp;lt;/span\u0026gt;[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;]); } } }` 从上述代码得知其反射调用ActivityThread#dispatchPackageBroadcast方法。最终是调用至LoadedApk#updateApplicationInfo。该方法做了如下事情 - 重新创建mClassLoader - 重新创建mResources - 更新applicationInfo（调用LoadedApk#setApplicationInfo完成）。 官方bundletool https://developer.android.com/studio/command-line/bundletool 转自：https://yq.aliyun.com/articles/593597 ","permalink":"https://blog.zdltech.com/posts/android%E5%8A%A8%E6%80%81%E5%8C%96%E6%A1%86%E6%9E%B6app-bundles/","summary":"\u003cp\u003e\u003cem\u003e摘要：\u003c/em\u003e Android App Bundles 在今年的Google I/O大会上，Google向 Android 引入了新 App 动态化框架（即Android App Bundle，缩写为AAB），与Instant App不同，AAB是借助Split Apk完成动态加载，使用AAB动态下发方式，可以大幅度减少应用体积。\u003c/p\u003e\n\u003cdiv class=\"content-detail markdown-body\"\u003e\n  ## Android App Bundles\n\u003cpre\u003e\u003ccode\u003e在今年的Google I/O大会上，Google向 Android 引入了新 App 动态化框架（即Android App Bundle，缩写为AAB），与Instant App不同，AAB是借助Split Apk完成动态加载，使用AAB动态下发方式，可以大幅度减少应用体积。现在只须在 Android Studio 中构建一个应用束 (app bundle)，就可以将应用所需的全部内容 (适用于所有设备) 都涵盖在内：所有语言、所有设备屏幕大小、所有硬件架构。\n\n\n\n\n\n下面是Dynamic Delivery示意效果图：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"https://img-blog.csdn.net/20180516215026733\"\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e不过要想体验Dynamic Delivery，需要先下载\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"https://developer.android.com/studio/preview/\"\u003eAndroid Studio 3.2\u003c/a\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"https://img-blog.csdn.net/20180516215147494\"\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e学习Android App Bundles可以将它和Split Apks来对比学习。\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"split-apks\"\u003eSplit Apks\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003esplit apks是Android 5.0开始提供多apk构建机制，借助split apks可以将一个apk基于ABI和屏幕密度两个维度拆分城多个apk，这样可以有效减少apk体积。当用户下载应用程序安装包时，只会包含对应平台的so和资源。因为需要google play支持，所以国内就没戏了。针对不同cpu架构问题，国内应用开发商大部分都会将so文件只放在armabi目录下，如此做虽然可以有效减少包体积，但可能带来性能问题。split apks详细的内容可以访问下面的链接：[https://link.zhihu.com/?target=https%3A//developer.android.com/studio/build/configure-apk-splits%3Fauthuser%3D2](https://link.zhihu.com/?target=https%3A//developer.android.com/studio/build/configure-apk-splits%3Fauthuser%3D2)\n\n\n\n\n\nSplit Apks的运作原理有点类似于Android的组件化，安装应用程序时，首先安装base apk，然后安装split apks。为了说明splite apks运作原理，来看一下Android 5.0关于splite apks的源码。\n\n\n\n\n\n打开[ApplicationInfo](http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/content/pm/ApplicationInfo.java)类中，可以看到如下信息：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`/**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * Full paths to zero \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;or\u0026amp;lt;/span\u0026gt; more \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;split\u0026amp;lt;/span\u0026gt; APKs that, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;when\u0026amp;lt;/span\u0026gt; combined with the base\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * APK \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;defined\u0026amp;lt;/span\u0026gt; in {@link \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;#sourceDir}, form a complete application.\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   *\u0026amp;lt;span class=\u0026#34;hljs-regexp\u0026#34;\u0026gt;/\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  public String[] splitSourceDirs;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  /\u0026amp;lt;/span\u0026gt;**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * Full path to the publicly available parts of {@link \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;#splitSourceDirs},\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * including resources \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;and\u0026amp;lt;/span\u0026gt; manifest. This may be different from\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * {@link \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;#splitSourceDirs} if an application is forward locked.\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   *\u0026amp;lt;span class=\u0026#34;hljs-regexp\u0026#34;\u0026gt;/\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  public String[] splitPublicSourceDirs;\u0026amp;lt;/span\u0026gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e[LoadeApk](http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/app/LoadedApk.java)中有PathClassLoader和Resources创建过程。LoadedApk#mClassLoader是PathClassLoader实例引用，接着看PathClassLoader的创建过程。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ezipPaths = new ArrayList\u0026lt;\u0026gt;(); final ArrayList\u0026lt;String\u0026gt; libPaths = new ArrayList\u0026lt;\u0026gt;(); ....... zipPaths.add(mAppDir); //将split apk路径追加到zipPaths中 if (mSplitAppDirs != null) { Collections.addAll(zipPaths, mSplitAppDirs); } libPaths.add(mLibDir); ...... final String zip = TextUtils.join(File.pathSeparator, zipPaths); final String lib = TextUtils.join(File.pathSeparator, libPaths); ...... //如果mSplitAppDirs不为空，则zip将包含split apps所有路径。 mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib, mBaseClassLoader); StrictMode.setThreadPolicy(oldPolicy); } else { if (mBaseClassLoader == null) { mClassLoader = ClassLoader.getSystemClassLoader(); } else { mClassLoader = mBaseClassLoader; } } return mClassLoader; } }\u0026#34; data-snippet-id=\u0026#34;ext.b0abcb7003a3d76aeb1ae260fba2afe7\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ClassLoader \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getClassLoader\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;synchronized\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mClassLoader != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mClassLoader;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mIncludeCode \u0026amp;\u0026amp; !mPackageName.equals(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;android\u0026#34;\u0026amp;lt;/span\u0026gt;)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              ......\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;String\u0026amp;gt; zipPaths = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;String\u0026amp;gt; libPaths = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              .......\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              zipPaths.add(mAppDir);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//将split apk路径追加到zipPaths中\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mSplitAppDirs != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  Collections.addAll(zipPaths, mSplitAppDirs);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              libPaths.add(mLibDir);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              ......\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; String zip = TextUtils.join(File.pathSeparator, zipPaths);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; String lib = TextUtils.join(File.pathSeparator, libPaths);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              ......\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//如果mSplitAppDirs不为空，则zip将包含split apps所有路径。\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      mBaseClassLoader);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              StrictMode.setThreadPolicy(oldPolicy);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mBaseClassLoader == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  mClassLoader = ClassLoader.getSystemClassLoader();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  mClassLoader = mBaseClassLoader;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mClassLoader;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e在创建PathClassLoader时，dex文件路径包含base app和split apps路径，LoadedApk#mResources是Resources实例引用，Resources的源码如下：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Resources \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getResources\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;ActivityThread mainThread\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;/span\u0026gt;{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mResources == \u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, \u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mResources;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e可以发现：split apks资源路径（LoadedApk#mSplitResDirs）也会被增加至Resources中。\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"android-app-bundles\"\u003eAndroid App Bundles\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e下面再来看Android App Bundles，Android App Bundle 支持模块化，通过Dynamic Delivery with split APKs，将一个apk拆分成多个apk，按需加载（包括加载C/C++ libraries），这样开发者可以随时按需交付功能，而不是仅限在安装过程中。\n\n\n\n\n\nAndroid App Bundle 通常会包括以下几个文件：\n\n\n\n\n- Base Apk：首次安装的apk，公共代码和资源，所以其他的模块都基于Base Apk；\n\n- Configuration APKs：native libraries 和适配当前手机屏幕分辨率的资源；\n\n- Dynamic feature APKs：不需要在首次安装就加载的模块。\n\n\n\n\n\n![这里写图片描述](https://img-blog.csdn.net/20180516221843565)\n\n\n\n\n\nAAB并不是一个插件化框架，它利用的是Android Framework提供的split apks技术来完成的，而所有安装split apk工作均是通过IPC交由google play完成。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e具体使用时，在Android Studio新增一项module——Dynamic Feature Module。\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"https://img-blog.csdn.net/20180516222501205\"\u003e\n在创建dynamic_feature时，有两个选项是默认勾选的，当然我们也可以更改其状态。\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"https://img-blog.csdn.net/20180516222556906\"\u003e\u003c/p\u003e","title":"Android动态化框架App Bundles"},{"content":"一、前言：再优秀的开源库都有坑要填 手上的项目使用的图片加载框架是：Universal-Image-Loader+业务需要定制化的一些代码。Universal-Image-Loader 这个框架是一个非常经典好用的框架，唯一的问题是是作者很久之前就不再更新了。所以综合考虑下，确定使用Glide+封装代替当前的图片加载框架。\n二、困惑： 在没有真正使用 Glide 之前，我所看到的文章基本都是赞美这个库的功能强大，加载流畅。然而，当我用上了以后，才发现并不完美。遇到了不少的坑，需要自己填。\n2.1 Glide 配合 OKHttp 使用的坑： 需要在Gradle中引入：\ncompile “com.github.bumptech.glide:glide:3.7.0”\ncompile “com.github.bumptech.glide:okhttp3-integration:1.4.0@aar”\n这里就有一个坑，如果你用到自定义的 GlideModule，这里的可能会失效，被com.github.bumptech.glide:okhttp3-integration:1.4.0@aar默认的替换\n解决方法是升级版本号：\ncompile “com.github.bumptech.glide:okhttp3-integration:1.4.0@aar” -》 compile “com.github.bumptech.glide:okhttp3-integration:1.5.0” 注意，没有@arr\n2.2 OKHttpClient 超时设置导致图片无法加载坑： 因为Glide本身只负责图片加载，网络请求图片数据由网络框架决定。网络请求一般会有超时的问题，坑的是OKHttp默认的超时时间太短了，如果不修改，网络状态比较差\n就很容易请求超时，图片自然就加载不出来。我设置的参数是60,60,30这个可以自己根据实际情况确定。\n`//这个是源码里面的，默认超时时间，都是10s，10000ms connectTimeout = 10_000; readTimeout = 10_000; writeTimeout = 10_000; //手动设置超时时间 OkHttpClient client=new OkHttpClient.Builder() .connectTimeout(HTTP_CONNECT_TIMEOUT, TimeUnit.SECONDS) .readTimeout(HTTP_READ_TIMEOUT, TimeUnit.SECONDS) .writeTimeout(HTTP_WRITE_TIMEOUT, TimeUnit.SECONDS) .build;` 2.3 Glide 查看 log 的坑： 如果你使用 Glide 经常出现图片加载不出来或者加载有问题，你需要查看 Glide 本身的 log，不过这个必须通过 adb 命令开启，详情百度，需要注意如果是请求图片问题，关注请求的 log，图片加载||转换的问题，关注图片加载||转换的log。\n2.4 Glide 加载的图片内存占用巨多的坑： 在使用 Glide 的第一个版本，OOM 问题一下子爆炸了，查看内存占用，使用 Universal-Image-Loader 的旧版本，App 占用50m~80m内存，\n而使用 Glide 加载列表大图的时候，突然猛增到120M+，低端机器自然很容易就 OOM 了。\nGlide 有一个优点被很多人称赞，就是它会根据图片控件的大小对 Bitmap 进程缩放处理，适应控件的大小。\n但是，如果是一个控件，在高分屏下，它的控件大小往往比实际图片尺寸大很多，举例一个控件:\n长宽：1080_400，图片原始尺寸540_200，如果不做任何设置，Glide 会把 bitmap 放大到控件大小，那么占用的内存就变成了原始大小四倍。。。\n这个是 Glide 的特性，暂时没有找到的方法修改。\n临时方案：为了避免Glide自动把bitmap放大，使用在加载图片的时候，使用 .override(width, height) 限制图片的宽高\n2.5 Glide 使用过渡动画造成图片变形的 bug Glide 默认会加载图片的时候会有一个过渡效果，其原理是采用TransitionDrawable实现的。\n但是这个和 placeHolder,一起使用，尤其是你的playHolder的尺寸比你加载的图片要大，这个时候就会出现，你加载出来的图片变形的问题。\n很多人推荐使用 .dontAnimate() 解决问题，即去掉过渡动画。\n但是，如果产品一定需要加入过渡动画，官方其实没有提供完美的解决方案，Glide的作者之一在stackoverflow有回答并且给出了 github 的代码。\nhttp://stackoverflow.com/questions/32235413/glide-load-drawable-but-dont-scale-placeholder\nhttps://github.com/TWiStErRob/glide-support/tree/master/src/glide4/java/com/bumptech/glide/supportapp\n注意：我在使用的过程中发现，如果你的ImageView的type是center_crop 的话，那么必须确保你的place_holder默认图片，长宽小于你加载的图片，不然即使使用的了作者的代码，任然会有变形的问题。\n转自：https://www.cnblogs.com/bylijian/p/6908813.html\n","permalink":"https://blog.zdltech.com/posts/glide%E5%A1%AB%E5%9D%91%E6%8C%87%E5%8D%97/","summary":"\u003ch1 id=\"一前言再优秀的开源库都有坑要填\"\u003e一、前言：再优秀的开源库都有坑要填\u003c/h1\u003e\n\u003cp\u003e手上的项目使用的图片加载框架是：Universal-Image-Loader+业务需要定制化的一些代码。Universal-Image-Loader 这个框架是一个非常经典好用的框架，唯一的问题是是作者很久之前就不再更新了。所以综合考虑下，确定使用Glide+封装代替当前的图片加载框架。\u003c/p\u003e\n\u003ch1 id=\"二困惑\"\u003e二、困惑：\u003c/h1\u003e\n\u003cp\u003e在没有真正使用 Glide 之前，我所看到的文章基本都是赞美这个库的功能强大，加载流畅。然而，当我用上了以后，才发现并不完美。遇到了不少的坑，需要自己填。\u003c/p\u003e\n\u003ch2 id=\"glide-配合-okhttp-使用的坑\"\u003e2.1 Glide 配合 OKHttp 使用的坑：\u003c/h2\u003e\n\u003cp\u003e需要在Gradle中引入：\u003cbr\u003e\ncompile “com.github.bumptech.glide:glide:3.7.0”\u003cbr\u003e\ncompile “com.github.bumptech.glide:okhttp3-integration:1.4.0@aar”\u003cbr\u003e\n这里就有一个坑，如果你用到自定义的 GlideModule，这里的可能会失效，被com.github.bumptech.glide:okhttp3-integration:1.4.0@aar默认的替换\u003cbr\u003e\n解决方法是升级版本号：\u003cbr\u003e\ncompile “com.github.bumptech.glide:okhttp3-integration:1.4.0@aar” -》 compile “com.github.bumptech.glide:okhttp3-integration:1.5.0” 注意，没有@arr\u003c/p\u003e\n\u003ch2 id=\"okhttpclient-超时设置导致图片无法加载坑\"\u003e2.2 OKHttpClient 超时设置导致图片无法加载坑：\u003c/h2\u003e\n\u003cp\u003e因为Glide本身只负责图片加载，网络请求图片数据由网络框架决定。网络请求一般会有超时的问题，坑的是OKHttp默认的超时时间太短了，如果不修改，网络状态比较差\u003cbr\u003e\n就很容易请求超时，图片自然就加载不出来。我设置的参数是60,60,30这个可以自己根据实际情况确定。\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n  \u003cdiv class=\"alert-info\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`//这个是源码里面的，默认超时时间，都是10s，10000ms\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003econnectTimeout = 10_000;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ereadTimeout = 10_000;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewriteTimeout = 10_000;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e//手动设置超时时间\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e OkHttpClient client=new OkHttpClient.Builder()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                                .connectTimeout(HTTP_CONNECT_TIMEOUT, TimeUnit.SECONDS)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                                .readTimeout(HTTP_READ_TIMEOUT, TimeUnit.SECONDS)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                                .writeTimeout(HTTP_WRITE_TIMEOUT, TimeUnit.SECONDS)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                                .build;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"glide-查看-log-的坑\"\u003e2.3 Glide 查看 log 的坑：\u003c/h2\u003e\n\u003cp\u003e如果你使用 Glide 经常出现图片加载不出来或者加载有问题，你需要查看 Glide 本身的 log，不过这个必须通过 adb 命令开启，详情百度，需要注意如果是请求图片问题，关注请求的 log，图片加载||转换的问题，关注图片加载||转换的log。\u003c/p\u003e","title":"Glide填坑指南"},{"content":"","permalink":"https://blog.zdltech.com/posts/typora%E4%BD%BF%E7%94%A8/","summary":"","title":"typora使用"},{"content":" 轻量级的微服务 总结：整个微服务使用Spring boot + Docker 冰山上，ZooKeeper服务注册、Node.js服务网关、Jenkins等冰山下。\n总体上可以分为：开发框架（上）、容器技术（上）、注册中心（下）、调用中心、部署中心、日志中心、监控中心、追踪中心、消息中心、配置中心。\n注册中心：用于注册微服务相关配置信息的中心\n调用中心：用于提供给前端调用的统一入口（我们选用Node.js实现）\n部署中心：用于编译并打包微服务源码并将其部署到Docker引擎中（Jenkins）\n日志中心：用于收集并管理微服务应用程序中产生的日志\n监控中心：用于监控微服务的实时运行状况\n追踪中心：用于最终微服务的调用轨迹\n消息中心：用于解耦服务之间的调用关系\n配置中心：用于管理微服务应用程序所需的配置参数\n（我们认为，中心分为两类：一类是含有业务意义的中心，另一类是不含业务意义的中心-只是技术层面的中心）\n微服务日志 总结：docker中查看日志路径 /var/lib/docker/containers/\u0026lt;container_id目录看到一个container_id-json.log文件，Docker默认使用docker logs查看的就是这些json文件，Docker默认使用Json-file格式，还有其他格式\nnone：容器不输出任何日志\njson-file：容器默认输出的日志以json格式写入文件中（默认）\nsyslog：容器输出日志写入宿主机的Syslog中\njournald：容器输出日志写入宿主机的Journald中\ngelf：容器输出的日志以GELF（Graylog Extended log fromat）格式写入Graylog中\nfluentd: 容器输出的日志写入宿主机的Fluentd中\nawalogs：容器输出日志写入Ammazon CloudWatch Logs中\nsplunk：容器输出日志写入splunk中\netwlogs：容器输出日志写入ETW （event tracing for windows）中\ngcplogs：容器输出日志写入GCP（Google Cloud Platform）中\nnats：容器输出日志写入NATS服务器中\ndocker中 –log-driver参数配置日志驱动\n–log-opt max-size –log-opt max-file 分别设置日志文件大小和日志文件数量\n例如：docker run -p 80:80 –log-dirver json-file –log-opt max-size=10m –log-opt max-file=3 –name xxx 容器名称\ndocker日志驱动（https://docs.docker.com/engine/admin/logging/overview/）\n默认linux系统安装Syslog（名称Rsyslog），还有一个Syslog-ng（https://www.balabit.com/network-security/syslog-ng）更强大\n通过 rsyslogd -v 检查rsyslog是否安装\nRsyslog官网http://www.rsyslog.com\nELK 官网 https://www.elastic.co/\nKibana：用于数据可视化\nElasticsearch：用于数据搜索、分析与存储\nLogstash：用于数据收集、将数据存入Elasticsearch中\nBeats：用于数据传输，将数据从磁盘上传输到Logstash中\nX-Pack：提供一些扩展功能，包括安全、预警、监控、报表、图形化等\nElastic Cloud：提供Elastic栈的云服务，提供公有云和私有云解决方案\n微服务监控 总结：Spring boot自带监控actuator，有些需要在application.properties中配置才能够访问\nactuator包括info（应用基本信息）、health（应用是否健康）、metrics（相关运行指标、开可以扩展其他新指标）、env（可以访问的环境变量）、loggers（查看和修改日志级别配置）、dump（线程相关信息）、trace（请求调用轨迹信息）\nSpring boot Admin开源 https://github.com/codecentric/spring-boot-admin\ncAdvisor开源 https://github.com/google/cadvisor\nInfluxDB开源https://github.com/influxdata/influxdb\nGrafana官网https://grafana.com https://github.com/grafana/grafana\n集成InfluxDB+cAdvisor+Grafana 必须先启动InfluxDB 随后才能其他cAvisor和Grafana\nZipKin开源 http://zipkin.io https://github.com/openzipkin/zipkin（google Dapper https://research.google.com/pubs/pub36356.html）\nKafka 官网 http://kafka.apache.org\nScribe官网 https://github.com/facebookarchive/scribe\nZipkin java客户端 https://github.com/openzipkin/brave\n微服务通信 当服务间滴啊用较为频繁时，我们一般不会选择HTTP调用，而是选择基于TCP的RPC调用\nRPC是通过Socket通信的 常用RPC框架 Google gRPC、Facebook Thrift、Twitter Finagle、Alibaba Dubbo、新浪微博Motan等\ngRPC官网：http://www.grpc.io\nProtocol Buffers 官网：https://developers.google.com/protocol-buffers/\n搭建分布式RPC框架使用Netty + Zookeeper + protostuff\nProtostuff官网：http://www.protostuff.io\nNetty 官网：http://netty.io\n微服务解耦 总结：RabbitMQ性能高于ActiveMQ\n微服务测试 总结：通过配置@FixMethodOrder（MethodSorters.NAME_ASCENDING）使所有待测试方法安装字母升序的方式被JUnit框架调用\nAssertJ : https://joel-costigliola.github.io/assertj/index.html\nJayway JsonPath: https://github.com/json-path/JsonPath\nJayway JsonPath Evaluator http://jsonpath.herokuapp.com\nJSONassert http://jsonassert.skyscreamer.org\nNewman npm: https://www.npmjs.com/package/newman\nSwagger 官网：http://swagger.io\napiDoc http://apidocjs.com\n微服务配置 总结：Ansible是一款开源的自动化运维工具，它基于Python开发，可用于配置系统与部署软件\n通过SSH登录配置服务器\n生成密钥 ssh-keygen -t rsa copy密钥到服务器 ssh-copy-id root@serverip ","permalink":"https://blog.zdltech.com/posts/%E8%BD%BB%E9%87%8F%E7%BA%A7%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E4%B8%8B%E6%80%BB%E7%BB%93/","summary":"\u003ch1\u003e\u003c/h1\u003e\n\u003ch2 id=\"轻量级的微服务\"\u003e\u003ca class=\"md-header-anchor \" name=\"header-n7\"\u003e\u003c/a\u003e轻量级的微服务\u003c/h2\u003e\n\u003chr\u003e\n\u003cp\u003e\u003cimg alt=\"2018-08-25-2\" loading=\"lazy\" src=\"https://ws4.sinaimg.cn/large/006tNbRwly1fumcpw4i0bj31hq0rgtfi.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e总结：整个微服务使用Spring boot + Docker 冰山上，ZooKeeper服务注册、Node.js服务网关、Jenkins等冰山下。\u003c/p\u003e\n\u003cp\u003e总体上可以分为：开发框架（上）、容器技术（上）、注册中心（下）、调用中心、部署中心、日志中心、监控中心、追踪中心、消息中心、配置中心。\u003c/p\u003e\n\u003cp\u003e注册中心：用于注册微服务相关配置信息的中心\u003c/p\u003e\n\u003cp\u003e调用中心：用于提供给前端调用的统一入口（我们选用Node.js实现）\u003c/p\u003e\n\u003cp\u003e部署中心：用于编译并打包微服务源码并将其部署到Docker引擎中（Jenkins）\u003c/p\u003e\n\u003cp\u003e日志中心：用于收集并管理微服务应用程序中产生的日志\u003c/p\u003e\n\u003cp\u003e监控中心：用于监控微服务的实时运行状况\u003c/p\u003e\n\u003cp\u003e追踪中心：用于最终微服务的调用轨迹\u003c/p\u003e\n\u003cp\u003e消息中心：用于解耦服务之间的调用关系\u003c/p\u003e\n\u003cp\u003e配置中心：用于管理微服务应用程序所需的配置参数\u003c/p\u003e\n\u003cp\u003e（我们认为，中心分为两类：一类是含有业务意义的中心，另一类是不含业务意义的中心-只是技术层面的中心）\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"2018-08-25-3\" loading=\"lazy\" src=\"https://ws2.sinaimg.cn/large/006tNbRwly1fumd4djmgmj31kw23vqv5.jpg\"\u003e\u003c/p\u003e\n\u003ch2 id=\"微服务日志\"\u003e\u003ca class=\"md-header-anchor \" name=\"header-n14\"\u003e\u003c/a\u003e微服务日志\u003c/h2\u003e\n\u003chr\u003e\n\u003cp\u003e\u003cimg alt=\"2018-08-25-4\" loading=\"lazy\" src=\"https://ws1.sinaimg.cn/large/006tNbRwly1fumdb3gvloj31jg0r6th7.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e总结：docker中查看日志路径 /var/lib/docker/containers/\u0026lt;container_id目录看到一个container_id-json.log文件，Docker默认使用docker logs查看的就是这些json文件，Docker默认使用Json-file格式，还有其他格式\u003c/p\u003e\n\u003cp\u003enone：容器不输出任何日志\u003c/p\u003e\n\u003cp\u003ejson-file：容器默认输出的日志以json格式写入文件中（默认）\u003c/p\u003e\n\u003cp\u003esyslog：容器输出日志写入宿主机的Syslog中\u003c/p\u003e\n\u003cp\u003ejournald：容器输出日志写入宿主机的Journald中\u003c/p\u003e\n\u003cp\u003egelf：容器输出的日志以GELF（Graylog Extended log fromat）格式写入Graylog中\u003c/p\u003e\n\u003cp\u003efluentd: 容器输出的日志写入宿主机的Fluentd中\u003c/p\u003e\n\u003cp\u003eawalogs：容器输出日志写入Ammazon CloudWatch Logs中\u003c/p\u003e\n\u003cp\u003esplunk：容器输出日志写入splunk中\u003c/p\u003e\n\u003cp\u003eetwlogs：容器输出日志写入ETW （event tracing for windows）中\u003c/p\u003e\n\u003cp\u003egcplogs：容器输出日志写入GCP（Google Cloud Platform）中\u003c/p\u003e\n\u003cp\u003enats：容器输出日志写入NATS服务器中\u003c/p\u003e\n\u003cp\u003edocker中 –log-driver参数配置日志驱动\u003c/p\u003e\n\u003cp\u003e–log-opt max-size –log-opt max-file 分别设置日志文件大小和日志文件数量\u003c/p\u003e\n\u003cp\u003e例如：docker run -p 80:80 –log-dirver json-file –log-opt max-size=10m –log-opt max-file=3 –name xxx 容器名称\u003c/p\u003e\n\u003cp\u003edocker日志驱动（\u003ca href=\"https://docs.docker.com/engine/admin/logging/overview/\"\u003ehttps://docs.docker.com/engine/admin/logging/overview/\u003c/a\u003e）\u003c/p\u003e","title":"轻量级微服务架构下总结"},{"content":"1、了解几个概念\n（1）分辨率。分辨率就是手机屏幕的像素点数，一般描述成屏幕的“宽×高”，安卓手机屏幕常见的分辨率有480×800、720×1280、1080×1920等。720×1280表示此屏幕在宽度方向有720个像素，在高度方向有1280个像素。\n（2）屏幕大小。屏幕大小是手机对角线的物理尺寸，以英寸（inch）为单位。比如某某手机为“5寸大屏手机”，就是指对角线的尺寸，5寸×2.54厘米/寸=12.7厘米。\n（3）密度（dpi，dots per inch；或PPI，pixels per inch）。从英文顾名思义，就是每英寸的像素点数，数值越高当然显示越细腻。假如我们知道一部手机的分辨率是1080×1920，屏幕大小是5英寸，你 能否算出此屏幕的密度呢？哈哈，中学的勾股定理派上用场啦！通过宽1080和高1920，根据勾股定理，我们得出对角线的像素数大约是2203，那么用 2203除以5就是此屏幕的密度了，计算结果是440。440dpi的屏幕已经相当细腻了。\n2、实际密度与系统密度\n尚未发现他处使用“实际密度”和“系统密度”这两个词汇，暂时由我如此定义吧。\n“实际密度”就是我们自己算出来的密度，这个密度代表了屏幕真实的细腻程度，如上述例子中的440dpi就是实际密度，说明这块屏幕每寸有440个 像素。5英寸1080×1920的屏幕密度是440，而相同分辨率的4.5英寸屏幕密度是490。如此看来，屏幕密度将会出现很多数值，呈现严重的碎片 化。而密度又是安卓屏幕将界面进行缩放显示的依据，那么安卓是如何适配这么多屏幕的呢？\n其实，每部安卓手机屏幕都有一个初始的固定密度，这些数值是120、160、240、320、480，我们权且称为“系统密度”。大家发现规律没 有？相隔数值之间是2倍的关系。一般情况下，240×320的屏幕是低密度120dpi，即ldpi；320×480的屏幕是中密度160dpi，即 mdpi；480×800的屏幕是高密度240dpi，即hdpi；720×1280的屏幕是超高密度320dpi，即xhdpi；1080×1920的 屏幕是超超高密度480dpi，即xxhdpi。\n安卓对界面元素进行缩放的比例依据正是系统密度，而不是实际密度。\n3、一个重要的单位dp\ndp也可写为dip，即density-independent pixel。你可以想象dp更类似一个物理尺寸，比如一张宽和高均为100dp的图片在320×480和480×800的手机上“看起来”一样大。而实际 上，它们的像素值并不一样。dp正是这样一个尺寸，不管这个屏幕的密度是多少，屏幕上相同dp大小的元素看起来始终差不多大。\n另外，文字尺寸使用sp，即scale-independentpixel的缩写，这样，当你在系统设置里调节字号大小时，应用中的文字也会随之变大变小。\n4、dp与px的转换\n在安卓中，系统密度为160dpi的中密度手机屏幕为基准屏幕，即320×480的手机屏幕。在这个屏幕中，1dp=1px。\n100dp在320×480（mdpi，160dpi）中是100px。那么100dp在480×800（hdpi，240dpi）的手机上是多少 px呢？我们知道100dp在两个手机上看起来差不多大，根据160与240的比例关系，我们可以知道，在480×800中，100dp实际覆盖了 150px。因此，如果你为mdpi手机提供了一张100px的图片，这张图片在hdpi手机上就会拉伸至150px，但是他们都是100dp。\n中密度和高密度的缩放比例似乎可以不通过160dpi和240dpi计算，而通过320px和480px也可以算出。但是按照宽度计算缩放比例不适 用于超高密度xhdpi和超超高密度xxhdpi了。即720×1280中1dp是多少px呢？如果用720/320，你会得出1dp=2.25px，实 际这样算出来是不对的。dp与px的换算要以系统密度为准，720×1280的系统密度为320，320×480的系统密度为 160，320/160=2，那么在720×1280中，1dp=2px。同理，在1080×1920中，1dp=3px。\n大家可以记住下面这个比例，dp与px的换算就十分easy啦！\nldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12，我们发现，相隔数字之间还是2倍的关系。计算的时候，以mdpi 为基准。比如在720×1280（xhdpi）中，1dp等于多少px呢？mdpi是4，xhdpi是8，2倍的关系，即1dp=2px。反着计算更重 要，比如你用PhotoShop在720×1280的画布中制作了界面效果图，两个元素的间距是20px，那要标注多少dp呢？2倍的关系，那就是 10dp！\n当安卓系统字号设为“普通”时，sp与px的尺寸换算和dp与px是一样的。比如某个文字大小在720×1280的PS画布中是24px，那么告诉工程师，这个文字大小是12sp。\n5、建议在xdhpi中作图\n安卓手机有这么多屏幕，我到底依据哪种屏幕作图呢？没有必要为不同密度的手机都提供一套素材，大部分情况下，一套就够了。\n现在手机比较高的分辨率是1080×1920，你可以选择这个尺寸作图，但是图片素材将会增大应用安装包的大小。并且尺寸越大的图片占用的内存也就 越高。如果你不是设计ROM，而是做一款应用，我建议大家用PS在720×1280的画布中作图。这个尺寸兼顾了美观性、经济性和计算的简单。美观性是 指，以这个尺寸做出来的应用，在720×1280中显示完美，在1080×1920中看起来也比较清晰；经济性是指，这个分辨率下导出的图片尺寸适中，内 存消耗不会过高，并且图片文件大小适中，安装包也不会过大；计算的简单，就是1dp=2px啊，多好计算啊！\n做出来的图片，记着让界面工程师放进drawable-xhdpi的资源文件夹中。\n6、屏幕的宽高差异\n在720×1280中作图，要考虑向下兼容不同的屏幕。通过计算我们可以知道，320×480和480×800的屏幕宽度都是320dp，而 720×1280和1080×1920的屏幕宽度都是360dp。它们之间有40dp的差距，这40dp在设计中影响还是很大的。如下图蝴蝶图片距离屏幕 的左右边距在320dp宽的屏幕和360dp宽的屏幕中就不一样。\n不仅宽度上有差异，高度上的差异更加明显。对于天气等工具类应用，由于界面一般是独占式的，更要考虑屏幕之间的比例差异\n如果想消除这些比例差异，可以通过添加布局文件来实现。一般情况下，布局文件放在layout文件夹中，如果要单独对360dp的屏幕进行调整，你 可以单做做一个布局文件放在layout-w360dp中；如果你想对某个特殊的分辨率进行调整，那么你可以将布局文件放在标有分辨率的文件夹中，如 layout-854×480。\n7、几个资源的文件夹\n在720×1280中做了图片，要让开发人员放到drawable-xhdpi的资源文件夹中，这样才可以显示正确。个人认为仅提供一套素材就可以 了，可以测试一下应用在低端手机上运行是否流畅，如果比较卡顿，可以根据需要提供部分mdpi的图片素材，因为xhdpi中的图片运行在mdpi的手机上 会比较占内存。\n以应用图标为例，xhdpi中的图标大小是96px，如果要单独给mdpi提供图标，那么这个图标大小是48px，放到drawable-mdpi 的资源文件夹中。各个资源文件夹中的图片尺寸同样符合ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12的规律。\n如果你把一个高2px的分割线素材做成了9.png图片，你想让细线在不同密度中都是2px，而不被安卓根据密度进行缩放，怎么办？你可以把这个分 割线素材放到drawable-nodpi中，这个资源文件夹中的图片，将按照实际像素大小进行显示，而不会被安卓根据密度进行缩放。即在mdpi中细线 是2px（2dp），在xhdpi中细线是2px（1dp）。\n表 1. 可用于为 不同屏幕配置提供特殊资源的配置限定符。\n屏幕特性 \u0026lt;th\u0026gt; 限定符 \u0026lt;/th\u0026gt; \u0026lt;th\u0026gt; 说明 \u0026lt;/th\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td rowspan=\u0026quot;4\u0026quot;\u0026gt; 尺寸 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; `small` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于*小*尺寸屏幕的资源。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; `normal` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于*正常*尺寸屏幕的资源。（这是基线尺寸。） \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; `large` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于*大*尺寸屏幕的资源。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; `xlarge` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于*超大*尺寸屏幕的资源。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td rowspan=\u0026quot;8\u0026quot;\u0026gt; 密度 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; `ldpi` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于低密度 (*ldpi*) 屏幕 (~120dpi) 的资源。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; `mdpi` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于中密度 (*mdpi*) 屏幕 (~160dpi) 的资源。（这是基线 密度。） \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; `hdpi` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于高密度 (*hdpi*) 屏幕 (~240dpi) 的资源。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; `xhdpi` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于超高密度 (*xhdpi*) 屏幕 (~320dpi) 的资源。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; `xxhdpi` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于超超高密度 (*xxhdpi*) 屏幕 (~480dpi) 的资源。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; `xxxhdpi` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于超超超高密度 (*xxxhdpi*) 屏幕 (~640dpi) 的资源。此限定符仅适用于 启动器图标，请参阅上面的[注](https://developer.android.com/guide/practices/screens_support#xxxhdpi-note)。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; `nodpi` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于所有密度的资源。这些是密度独立的资源。不管当前屏幕的密度如何，系统都不会 缩放以此限定符标记的资源。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; `tvdpi` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于密度介于 mdpi 和 hdpi 之间屏幕（约为 213dpi）的资源。它并不是 “主要”密度组，主要用于电视，而大多数应用都不 需要它 — 对于大多数应用而言，提供 mdpi 和 hdpi 资源便已足够，系统将根据需要对其进行 缩放。如果发现必须提供 tvdpi 资源，应以 1.33*mdpi 的系数 调整其大小。例如，mdpi 屏幕的 100px x 100px 图像应该相当于 tvdpi 的 133px x 133px。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td rowspan=\u0026quot;2\u0026quot;\u0026gt; 方向 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; `land` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于横屏（长宽比）的资源。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; `port` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于竖屏（高宽比）的资源。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td rowspan=\u0026quot;2\u0026quot;\u0026gt; 纵横比 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; `long` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于纵横比明显高于或宽于（分别在竖屏 或横屏时）基线屏幕配置的屏幕的资源。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; `notlong` \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 适用于使用纵横比类似于基线屏幕 配置的屏幕的资源。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; https://developer.android.com/guide/practices/screens_support\nxhdpi：2.0 hdpi：1.5 mdpi：1.0（基准） ldpi：0.75 https://developer.android.com/training/multiscreen/screendensities ","permalink":"https://blog.zdltech.com/posts/android-hdpi-ldpi-mdpi-xhdpi-xxhdpi%E9%80%82%E9%85%8D%E8%AF%A6%E8%A7%A3/","summary":"\u003cp\u003e1、了解几个概念\u003cbr\u003e\n（1）分辨率。分辨率就是手机屏幕的像素点数，一般描述成屏幕的“宽×高”，安卓手机屏幕常见的分辨率有480×800、720×1280、1080×1920等。720×1280表示此屏幕在宽度方向有720个像素，在高度方向有1280个像素。\u003cbr\u003e\n（2）屏幕大小。屏幕大小是手机对角线的物理尺寸，以英寸（inch）为单位。比如某某手机为“5寸大屏手机”，就是指对角线的尺寸，5寸×2.54厘米/寸=12.7厘米。\u003c/p\u003e\n\u003cp\u003e（3）密度（dpi，dots per inch；或PPI，pixels per inch）。从英文顾名思义，就是每英寸的像素点数，数值越高当然显示越细腻。假如我们知道一部手机的分辨率是1080×1920，屏幕大小是5英寸，你 能否算出此屏幕的密度呢？哈哈，中学的勾股定理派上用场啦！通过宽1080和高1920，根据勾股定理，我们得出对角线的像素数大约是2203，那么用 2203除以5就是此屏幕的密度了，计算结果是440。440dpi的屏幕已经相当细腻了。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img-blog.csdn.net/20160120160618605?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e2、实际密度与系统密度\u003cbr\u003e\n尚未发现他处使用“实际密度”和“系统密度”这两个词汇，暂时由我如此定义吧。\u003cbr\u003e\n“实际密度”就是我们自己算出来的密度，这个密度代表了屏幕真实的细腻程度，如上述例子中的440dpi就是实际密度，说明这块屏幕每寸有440个 像素。5英寸1080×1920的屏幕密度是440，而相同分辨率的4.5英寸屏幕密度是490。如此看来，屏幕密度将会出现很多数值，呈现严重的碎片 化。而密度又是安卓屏幕将界面进行缩放显示的依据，那么安卓是如何适配这么多屏幕的呢？\u003cbr\u003e\n其实，每部安卓手机屏幕都有一个初始的固定密度，这些数值是120、160、240、320、480，我们权且称为“系统密度”。大家发现规律没 有？相隔数值之间是2倍的关系。一般情况下，240×320的屏幕是低密度120dpi，即ldpi；320×480的屏幕是中密度160dpi，即 mdpi；480×800的屏幕是高密度240dpi，即hdpi；720×1280的屏幕是超高密度320dpi，即xhdpi；1080×1920的 屏幕是超超高密度480dpi，即xxhdpi。\u003cbr\u003e\n安卓对界面元素进行缩放的比例依据正是系统密度，而不是实际密度。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img-blog.csdn.net/20160120160723274?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e3、一个重要的单位dp\u003cbr\u003e\ndp也可写为dip，即density-independent pixel。你可以想象dp更类似一个物理尺寸，比如一张宽和高均为100dp的图片在320×480和480×800的手机上“看起来”一样大。而实际 上，它们的像素值并不一样。dp正是这样一个尺寸，不管这个屏幕的密度是多少，屏幕上相同dp大小的元素看起来始终差不多大。\u003cbr\u003e\n另外，文字尺寸使用sp，即scale-independentpixel的缩写，这样，当你在系统设置里调节字号大小时，应用中的文字也会随之变大变小。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img-blog.csdn.net/20160120160830450\"\u003e\u003c/p\u003e\n\u003cp\u003e4、dp与px的转换\u003cbr\u003e\n在安卓中，系统密度为160dpi的中密度手机屏幕为基准屏幕，即320×480的手机屏幕。在这个屏幕中，1dp=1px。\u003cbr\u003e\n100dp在320×480（mdpi，160dpi）中是100px。那么100dp在480×800（hdpi，240dpi）的手机上是多少 px呢？我们知道100dp在两个手机上看起来差不多大，根据160与240的比例关系，我们可以知道，在480×800中，100dp实际覆盖了 150px。因此，如果你为mdpi手机提供了一张100px的图片，这张图片在hdpi手机上就会拉伸至150px，但是他们都是100dp。\u003cbr\u003e\n中密度和高密度的缩放比例似乎可以不通过160dpi和240dpi计算，而通过320px和480px也可以算出。但是按照宽度计算缩放比例不适 用于超高密度xhdpi和超超高密度xxhdpi了。即720×1280中1dp是多少px呢？如果用720/320，你会得出1dp=2.25px，实 际这样算出来是不对的。dp与px的换算要以系统密度为准，720×1280的系统密度为320，320×480的系统密度为 160，320/160=2，那么在720×1280中，1dp=2px。同理，在1080×1920中，1dp=3px。\u003cbr\u003e\n大家可以记住下面这个比例，dp与px的换算就十分easy啦！\u003cbr\u003e\nldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12，我们发现，相隔数字之间还是2倍的关系。计算的时候，以mdpi 为基准。比如在720×1280（xhdpi）中，1dp等于多少px呢？mdpi是4，xhdpi是8，2倍的关系，即1dp=2px。反着计算更重 要，比如你用PhotoShop在720×1280的画布中制作了界面效果图，两个元素的间距是20px，那要标注多少dp呢？2倍的关系，那就是 10dp！\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img-blog.csdn.net/20160120160913200\"\u003e\u003c/p\u003e\n\u003cp\u003e当安卓系统字号设为“普通”时，sp与px的尺寸换算和dp与px是一样的。比如某个文字大小在720×1280的PS画布中是24px，那么告诉工程师，这个文字大小是12sp。\u003c/p\u003e\n\u003cp\u003e5、建议在xdhpi中作图\u003cbr\u003e\n安卓手机有这么多屏幕，我到底依据哪种屏幕作图呢？没有必要为不同密度的手机都提供一套素材，大部分情况下，一套就够了。\u003cbr\u003e\n现在手机比较高的分辨率是1080×1920，你可以选择这个尺寸作图，但是图片素材将会增大应用安装包的大小。并且尺寸越大的图片占用的内存也就 越高。如果你不是设计ROM，而是做一款应用，我建议大家用PS在720×1280的画布中作图。这个尺寸兼顾了美观性、经济性和计算的简单。美观性是 指，以这个尺寸做出来的应用，在720×1280中显示完美，在1080×1920中看起来也比较清晰；经济性是指，这个分辨率下导出的图片尺寸适中，内 存消耗不会过高，并且图片文件大小适中，安装包也不会过大；计算的简单，就是1dp=2px啊，多好计算啊！\u003cbr\u003e\n做出来的图片，记着让界面工程师放进drawable-xhdpi的资源文件夹中。\u003c/p\u003e\n\u003cp\u003e6、屏幕的宽高差异\u003cbr\u003e\n在720×1280中作图，要考虑向下兼容不同的屏幕。通过计算我们可以知道，320×480和480×800的屏幕宽度都是320dp，而 720×1280和1080×1920的屏幕宽度都是360dp。它们之间有40dp的差距，这40dp在设计中影响还是很大的。如下图蝴蝶图片距离屏幕 的左右边距在320dp宽的屏幕和360dp宽的屏幕中就不一样。\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"https://img-blog.csdn.net/20160120160952684\"\u003e\u003c/p\u003e\n\u003cp\u003e不仅宽度上有差异，高度上的差异更加明显。对于天气等工具类应用，由于界面一般是独占式的，更要考虑屏幕之间的比例差异\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img-blog.csdn.net/20160120161027544\"\u003e\u003c/p\u003e\n\u003cp\u003e如果想消除这些比例差异，可以通过添加布局文件来实现。一般情况下，布局文件放在layout文件夹中，如果要单独对360dp的屏幕进行调整，你 可以单做做一个布局文件放在layout-w360dp中；如果你想对某个特殊的分辨率进行调整，那么你可以将布局文件放在标有分辨率的文件夹中，如 layout-854×480。\u003c/p\u003e\n\u003cp\u003e7、几个资源的文件夹\u003cbr\u003e\n在720×1280中做了图片，要让开发人员放到drawable-xhdpi的资源文件夹中，这样才可以显示正确。个人认为仅提供一套素材就可以 了，可以测试一下应用在低端手机上运行是否流畅，如果比较卡顿，可以根据需要提供部分mdpi的图片素材，因为xhdpi中的图片运行在mdpi的手机上 会比较占内存。\u003cbr\u003e\n以应用图标为例，xhdpi中的图标大小是96px，如果要单独给mdpi提供图标，那么这个图标大小是48px，放到drawable-mdpi 的资源文件夹中。各个资源文件夹中的图片尺寸同样符合ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12的规律。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img-blog.csdn.net/20160120161103029\"\u003e\u003c/p\u003e\n\u003cp\u003e如果你把一个高2px的分割线素材做成了9.png图片，你想让细线在不同密度中都是2px，而不被安卓根据密度进行缩放，怎么办？你可以把这个分 割线素材放到drawable-nodpi中，这个资源文件夹中的图片，将按照实际像素大小进行显示，而不会被安卓根据密度进行缩放。即在mdpi中细线 是2px（2dp），在xhdpi中细线是2px（1dp）。\u003c/p\u003e","title":"Android hdpi ldpi mdpi xhdpi xxhdpi适配详解"},{"content":" 最近一期做WiFi打印机打印小票功能，其中有一个功能点是把Logo打印在小票上面。 实现思路就是对网上的思路进行一下调整修改，方便Android端调用，很简单； 测试的打印机型号：Zebra GK888T Bitmap to ZPL \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 51 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 52 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 53 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 54 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 55 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 56 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 57 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 58 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 59 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 60 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 61 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 62 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 63 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 64 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 65 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 66 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 67 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 68 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 69 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 70 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 71 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 72 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 73 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 74 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 75 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 76 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 77 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 78 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 79 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 80 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 81 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 82 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 83 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 84 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 85 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 86 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 87 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 88 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 89 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 90 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 91 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 92 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 93 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 94 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 95 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 96 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 97 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 98 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 99 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 100 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 101 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 102 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 103 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 104 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 105 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 106 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 107 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 108 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 109 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 110 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 111 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 112 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 113 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 114 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 115 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 116 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 117 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 118 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 119 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 120 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 121 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 122 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 123 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 124 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 125 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 126 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 127 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 128 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 129 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 130 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 131 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 132 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 133 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 134 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 135 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 136 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 137 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 138 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 139 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 140 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 141 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 142 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 143 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 144 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 145 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 146 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 147 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 148 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 149 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 150 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 151 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 152 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 153 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 154 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 155 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 156 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 157 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 158 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 159 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 160 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 161 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 162 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 163 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 164 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 165 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 166 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 167 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 168 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 169 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 170 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 171 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 172 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 173 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 174 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 175 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 176 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 177 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 178 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 179 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 180 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 181 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 182 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 183 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 184 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 185 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 186 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 187 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 188 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 189 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 190 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 191 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 192 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 193 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 194 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 195 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 196 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 197 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 198 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; */ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;ZPLImageConverter\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context context; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;ZPLImageConverter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Context context)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.context = context; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; blackLimit = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;380\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; total; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthBytes; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; compressHex = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; Map\u0026lt;Integer, String\u0026gt; mapCode = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;Integer, String\u0026gt;(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;G\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;H\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;J\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;K\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;6\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;L\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;7\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;M\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;N\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;9\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;O\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;P\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;11\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Q\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;12\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;R\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;13\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;S\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;T\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;15\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;U\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;V\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;17\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;W\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;18\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;X\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;19\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Y\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;g\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;40\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;h\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;60\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;i\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;80\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;j\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;k\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;120\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;l\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;140\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;m\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;160\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;n\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;180\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;o\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;p\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;220\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;q\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;240\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;r\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;260\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;280\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;t\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;300\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;u\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;320\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;v\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;340\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;w\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;360\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;x\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;380\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;y\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;400\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;z\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;convertFromImg\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Bitmap image)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; IOException \u0026lt;/span\u0026gt;{ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; String cuerpo = createBody(image); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(compressHex) \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; cuerpo = encodeHexAscii(cuerpo); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; headDoc() + cuerpo + footDoc(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;createBody\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Bitmap originalImage)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; IOException \u0026lt;/span\u0026gt;{ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; StringBuffer sb = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringBuffer(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Graphics2D graphics = originalImage.createGraphics();\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// graphics.drawImage(originalImage, 0, 0, null);\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height = originalImage.getHeight(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width = originalImage.getWidth(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; rgb, red, green, blue, index=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; auxBinaryChar[] = {\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;}; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; widthBytes = width/\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(width%\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; widthBytes= (((\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)(width / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;)) + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; widthBytes= width/\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.total = widthBytes*height; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; h = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; h\u0026lt;height; h++) \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; w = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; w\u0026lt;width; w++) \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// rgb = originalImage.getRGB(w, h);\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; rgb = originalImage.getPixel(w, h); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; red = (rgb \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt; ) \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x000000FF\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; green = (rgb \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; ) \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x000000FF\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; blue = (rgb) \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x000000FF\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; auxChar = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;1\u0026amp;#8217;\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; totalColor = red + green + blue; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(totalColor\u0026gt;blackLimit){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; auxChar = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; auxBinaryChar[index] = auxChar; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; index++; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(index==\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; || w==(width-\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;)){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sb.append(fourByteBinary(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; String(auxBinaryChar))); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; auxBinaryChar = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;[]{\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;}; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; index=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sb.append(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\\n\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; sb.toString(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;fourByteBinary\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(String binaryStr)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;{ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; decimal = Integer.parseInt(binaryStr,\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (decimal\u0026gt;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;15\u0026lt;/span\u0026gt;){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; Integer.toString(decimal,\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;).toUpperCase(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;0\u0026amp;#8221;\u0026lt;/span\u0026gt; + Integer.toString(decimal,\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;).toUpperCase(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;encodeHexAscii\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(String code)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;{ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; maxlinea = widthBytes * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; StringBuffer sbCode = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringBuffer(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; StringBuffer sbLinea = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringBuffer(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; String previousLine = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; counter = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; aux = code.charAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; firstChar = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; i\u0026lt; code.length(); i++ ){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(firstChar){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; aux = code.charAt(i); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; firstChar = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;continue\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(code.charAt(i)==\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;\\n\u0026amp;#8217;\u0026lt;/span\u0026gt;){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(counter\u0026gt;=maxlinea \u0026amp;\u0026amp; aux==\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sbLinea.append(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;,\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(counter\u0026gt;=maxlinea \u0026amp;\u0026amp; aux==\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;F\u0026amp;#8217;\u0026lt;/span\u0026gt;){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sbLinea.append(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;!\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (counter\u0026gt;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; multi20 = (counter/\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;)*\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; resto20 = (counter%\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sbLinea.append(mapCode.get(multi20)); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(resto20!=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sbLinea.append(mapCode.get(resto20) + aux); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sbLinea.append(aux); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sbLinea.append(mapCode.get(counter) + aux); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mapCode.get(counter)==\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; counter = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; firstChar = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(sbLinea.toString().equals(previousLine)){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sbCode.append(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;:\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sbCode.append(sbLinea.toString()); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; previousLine = sbLinea.toString(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sbLinea.setLength(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;continue\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(aux == code.charAt(i)){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; counter++; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(counter\u0026gt;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; multi20 = (counter/\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;)*\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; resto20 = (counter%\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sbLinea.append(mapCode.get(multi20)); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(resto20!=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sbLinea.append(mapCode.get(resto20) + aux); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sbLinea.append(aux); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; sbLinea.append(mapCode.get(counter) + aux); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; counter = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; aux = code.charAt(i); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; sbCode.toString(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;headDoc\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; String str = \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026amp;#8221;^XA \u0026amp;#8221; +*/\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;^FO10,50^GFA,\u0026amp;#8221;\u0026lt;/span\u0026gt;+ total + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;,\u0026amp;#8221;\u0026lt;/span\u0026gt;+ total + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;,\u0026amp;#8221;\u0026lt;/span\u0026gt; + widthBytes +\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;, \u0026amp;#8220;\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; str; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;footDoc\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;{ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; String str = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;^FS\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*+ \u0026amp;#8220;^XZ\u0026amp;#8221;*/\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; str; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;setCompressHex\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; compressHex)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.compressHex = compressHex; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;setBlacknessLimitPercentage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; percentage)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;{ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; blackLimit = (percentage * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;768\u0026lt;/span\u0026gt; / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 调用方式 就是把Bitmap对象转化为ZPL编码格式，并把转化后的内容塞到ZPL命令中，和打印机通过Wifi 连接，把组装后的命令发给打印机就可以了。 1 \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; ZPLImageConverter zp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ZPLImageConverter(context); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; zp.setCompressHex(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; zp.setBlacknessLimitPercentage(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;50\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; String str = zp.convertFromImg(myBitmap); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; zplStr += str; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026amp;#8230;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 其它命令的时候可以参考zebra打印机官方文档。 refs - [http://labelary.com/viewer.html](http://labelary.com/viewer.html) （在线调整打印小票样式细节） - [http://www.jcgonzalez.com/java-image-to-zpl-example](http://www.jcgonzalez.com/java-image-to-zpl-example) - https://jinfengli.github.io/2017/11/17/zebra_printer_logo/ ","permalink":"https://blog.zdltech.com/posts/android%E5%AE%9E%E7%8E%B0%E6%96%91%E9%A9%ACwifi%E6%89%93%E5%8D%B0%E6%9C%BA%E6%89%93%E5%8D%B0%E5%B0%8F%E7%A5%A8%E5%9B%BE%E7%89%87/","summary":"\u003cdiv class=\"post-body\"\u003e\n\u003cpre\u003e\u003ccode\u003e最近一期做WiFi打印机打印小票功能，其中有一个功能点是把Logo打印在小票上面。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca id=\"more\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e实现思路就是对网上的思路进行一下调整修改，方便Android端调用，很简单；\n\n\n\n\n\n测试的打印机型号：Zebra GK888T\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4 id=\"bitmap-to-zpl\"\u003eBitmap to ZPL\u003cfigure class=\"highlight java\"\u003e\u003c/h4\u003e\n  \u003ctable\u003e\n    \u003ctr\u003e\n      \u003ctd class=\"gutter\"\u003e\n        \u003cdiv class=\"top-box hide\"\u003e\n          \u003cdiv class=\"alert-info\"\u003e\n          \u003c/div\u003e\n        \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      1\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      2\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      3\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      4\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      5\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      6\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      7\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      8\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      9\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      10\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      11\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      12\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      13\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      14\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      15\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      16\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      17\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      18\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      19\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      20\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      21\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      22\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      23\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      24\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      25\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      26\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      27\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      28\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      29\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      30\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      31\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      32\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      33\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      34\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      35\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      36\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      37\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      38\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      39\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      40\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      41\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      42\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      43\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      44\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      45\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      46\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      47\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      48\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      49\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      50\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      51\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      52\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      53\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      54\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      55\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      56\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      57\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      58\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      59\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      60\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      61\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      62\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      63\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      64\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      65\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      66\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      67\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      68\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      69\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      70\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      71\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      72\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      73\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      74\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      75\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      76\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      77\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      78\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      79\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      80\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      81\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      82\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      83\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      84\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      85\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      86\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      87\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      88\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      89\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      90\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      91\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      92\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      93\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      94\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      95\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      96\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      97\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      98\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      99\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      100\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      101\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      102\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      103\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      104\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      105\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      106\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      107\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      108\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      109\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      110\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      111\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      112\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      113\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      114\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      115\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      116\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      117\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      118\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      119\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      120\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      121\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      122\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      123\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      124\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      125\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      126\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      127\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      128\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      129\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      130\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      131\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      132\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      133\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      134\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      135\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      136\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      137\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      138\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      139\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      140\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      141\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      142\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      143\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      144\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      145\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      146\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      147\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      148\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      149\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      150\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      151\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      152\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      153\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      154\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      155\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      156\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      157\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      158\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      159\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      160\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      161\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      162\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      163\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      164\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      165\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      166\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      167\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      168\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      169\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      170\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      171\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      172\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      173\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      174\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      175\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      176\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      177\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      178\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      179\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      180\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      181\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      182\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      183\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      184\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      185\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      186\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      187\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      188\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      189\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      190\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      191\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      192\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      193\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      194\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      195\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      196\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      197\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      198\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/td\u0026gt;\n  \n  \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      */\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;ZPLImageConverter\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context context;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;ZPLImageConverter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Context context)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.context = context;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; blackLimit = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;380\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; total;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthBytes;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; compressHex = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; Map\u0026lt;Integer, String\u0026gt; mapCode = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;Integer, String\u0026gt;();\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      {\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;G\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;H\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;J\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;K\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;6\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;L\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;7\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;M\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;N\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;9\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;O\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;P\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;11\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Q\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;12\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;R\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;13\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;S\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;T\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;15\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;U\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;V\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;17\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;W\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;18\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;X\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;19\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Y\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;g\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;40\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;h\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;60\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;i\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;80\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;j\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;k\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;120\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;l\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;140\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;m\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;160\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;n\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;180\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;o\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;p\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;220\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;q\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;240\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;r\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;260\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;280\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;t\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;300\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;u\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;320\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;v\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;340\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;w\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;360\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;x\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;380\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;y\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      mapCode.put(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;400\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;z\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;convertFromImg\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Bitmap image)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; IOException \u0026lt;/span\u0026gt;{\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      String cuerpo = createBody(image);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(compressHex)\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      cuerpo = encodeHexAscii(cuerpo);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; headDoc() + cuerpo + footDoc();\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;createBody\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Bitmap originalImage)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; IOException \u0026lt;/span\u0026gt;{\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      StringBuffer sb = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringBuffer();\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Graphics2D graphics = originalImage.createGraphics();\u0026lt;/span\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// graphics.drawImage(originalImage, 0, 0, null);\u0026lt;/span\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height = originalImage.getHeight();\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width = originalImage.getWidth();\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; rgb, red, green, blue, index=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; auxBinaryChar[] = {\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;};\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      widthBytes = width/\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(width%\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      widthBytes= (((\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)(width / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;)) + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      widthBytes= width/\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.total = widthBytes*height;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; h = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; h\u0026lt;height; h++)\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      {\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; w = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; w\u0026lt;width; w++)\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      {\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// rgb = originalImage.getRGB(w, h);\u0026lt;/span\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      rgb = originalImage.getPixel(w, h);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      red = (rgb \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt; ) \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x000000FF\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      green = (rgb \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; ) \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x000000FF\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      blue = (rgb) \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x000000FF\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; auxChar = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;1\u0026amp;#8217;\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; totalColor = red + green + blue;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(totalColor\u0026gt;blackLimit){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      auxChar = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      auxBinaryChar[index] = auxChar;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      index++;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(index==\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; || w==(width-\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;)){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sb.append(fourByteBinary(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; String(auxBinaryChar)));\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      auxBinaryChar = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;[]{\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;};\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      index=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sb.append(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\\n\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; sb.toString();\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;fourByteBinary\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(String binaryStr)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;{\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; decimal = Integer.parseInt(binaryStr,\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (decimal\u0026gt;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;15\u0026lt;/span\u0026gt;){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; Integer.toString(decimal,\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;).toUpperCase();\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;0\u0026amp;#8221;\u0026lt;/span\u0026gt; + Integer.toString(decimal,\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;).toUpperCase();\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;encodeHexAscii\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(String code)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;{\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; maxlinea = widthBytes * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      StringBuffer sbCode = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringBuffer();\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      StringBuffer sbLinea = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringBuffer();\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      String previousLine = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; counter = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; aux = code.charAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; firstChar = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; i\u0026lt; code.length(); i++ ){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(firstChar){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      aux = code.charAt(i);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      firstChar = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;continue\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(code.charAt(i)==\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;\\n\u0026amp;#8217;\u0026lt;/span\u0026gt;){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(counter\u0026gt;=maxlinea \u0026amp;\u0026amp; aux==\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;0\u0026amp;#8217;\u0026lt;/span\u0026gt;){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sbLinea.append(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;,\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(counter\u0026gt;=maxlinea \u0026amp;\u0026amp; aux==\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;F\u0026amp;#8217;\u0026lt;/span\u0026gt;){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sbLinea.append(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;!\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (counter\u0026gt;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; multi20 = (counter/\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;)*\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; resto20 = (counter%\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sbLinea.append(mapCode.get(multi20));\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(resto20!=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sbLinea.append(mapCode.get(resto20) + aux);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sbLinea.append(aux);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sbLinea.append(mapCode.get(counter) + aux);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mapCode.get(counter)==\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      counter = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      firstChar = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(sbLinea.toString().equals(previousLine)){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sbCode.append(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;:\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sbCode.append(sbLinea.toString());\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      previousLine = sbLinea.toString();\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sbLinea.setLength(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;continue\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(aux == code.charAt(i)){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      counter++;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(counter\u0026gt;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; multi20 = (counter/\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;)*\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; resto20 = (counter%\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sbLinea.append(mapCode.get(multi20));\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(resto20!=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sbLinea.append(mapCode.get(resto20) + aux);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sbLinea.append(aux);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      sbLinea.append(mapCode.get(counter) + aux);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      counter = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      aux = code.charAt(i);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; sbCode.toString();\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;headDoc\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      String str = \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026amp;#8221;^XA \u0026amp;#8221; +*/\u0026lt;/span\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;^FO10,50^GFA,\u0026amp;#8221;\u0026lt;/span\u0026gt;+ total + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;,\u0026amp;#8221;\u0026lt;/span\u0026gt;+ total + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;,\u0026amp;#8221;\u0026lt;/span\u0026gt; + widthBytes +\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;, \u0026amp;#8220;\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; str;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;footDoc\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;{\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      String str = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;^FS\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*+ \u0026amp;#8220;^XZ\u0026amp;#8221;*/\u0026lt;/span\u0026gt;;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; str;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;setCompressHex\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; compressHex)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.compressHex = compressHex;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;setBlacknessLimitPercentage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; percentage)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;{\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      blackLimit = (percentage * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;768\u0026lt;/span\u0026gt; / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      }\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/td\u0026gt;\n\u0026lt;/tr\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/table\u003e\u003c/figure\u003e \n\u003ch4 id=\"调用方式\"\u003e调用方式\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e就是把Bitmap对象转化为ZPL编码格式，并把转化后的内容塞到ZPL命令中，和打印机通过Wifi 连接，把组装后的命令发给打印机就可以了。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cfigure class=\"highlight java\"\u003e \n  \u003ctable\u003e\n    \u003ctr\u003e\n      \u003ctd class=\"gutter\"\u003e\n        \u003cdiv class=\"line\"\u003e\n          1\n        \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      2\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      3\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      4\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      5\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      6\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      7\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/td\u0026gt;\n  \n  \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      ZPLImageConverter zp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ZPLImageConverter(context);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      zp.setCompressHex(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      zp.setBlacknessLimitPercentage(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;50\u0026lt;/span\u0026gt;);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      String str = zp.convertFromImg(myBitmap);\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      zplStr += str;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026amp;#8230;\u0026lt;/span\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/td\u0026gt;\n\u0026lt;/tr\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/table\u003e\u003c/figure\u003e \n\u003cpre\u003e\u003ccode\u003e其它命令的时候可以参考zebra打印机官方文档。\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4 id=\"refs\"\u003erefs\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- [http://labelary.com/viewer.html](http://labelary.com/viewer.html) （在线调整打印小票样式细节）\n\n- [http://www.jcgonzalez.com/java-image-to-zpl-example](http://www.jcgonzalez.com/java-image-to-zpl-example)\n\n- https://jinfengli.github.io/2017/11/17/zebra_printer_logo/\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Android实现斑马Wifi打印机打印小票图片"},{"content":" # Bootstrap **Adminlte** 项目：https://github.com/almasaeed2… 演示：https://adminlte.io/themes/Ad… **SB Admin** 项目：https://github.com/BlackrockD… 演示：https://blackrockdigital.gith… **Gentelella Admin** 项目：https://github.com/puikinsh/g… 演示：https://colorlib.com/polygon/… **Vali Admin** 项目：https://github.com/pratikbors… 演示：http://pratikborsadiya.in/val… **ModularAdmin** 项目：https://github.com/modularcod… 演示：https://gurayyarar.github.io/… **Metis** 项目：https://github.com/puikinsh/B… 演示：https://colorlib.com/polygon/… **Ace** 项目：https://github.com/bopoda/ace 演示：http://ace.jeka.by/ **Light Bootstrap Dashboard** 项目：https://github.com/creativeti… 演示：http://demos.creative-tim.com… **Material Dashboard** 项目：https://github.com/creativeti… 演示：http://demos.creative-tim.com… **Clearmin** 项目：https://github.com/paomedia/c… 演示：http://cm.paomedia.com/ Vue **Element Admin** 项目：https://github.com/PanJiaChen… 演示：https://panjiachen.github.io/… **Vue-Bulma** 项目：https://github.com/vue-bulma/… 演示：https://admin.vuebulma.com/ **Iview-Admin** 项目：https://github.com/iview/ivie… 演示：https://admin.iviewui.com **Vuestic-Admin** 项目：https://github.com/epicmaxco/… 演示：https://vuestic.epicmax.co/ **D2-Admin** 项目：https://github.com/d2-project… 演示：https://fairyever.gitee.io/d2… **Vue-Material-Admin** 项目：https://github.com/tookit/vue… 演示：http://vma.isocked.com/ Angularjs **Rdash-Angular** 项目：https://github.com/rdash/rdas… 演示：http://rdash.github.io/ **Ng-Admin** 项目：https://github.com/marmelab/n… 演示：https://marmelab.com/ng-admin… Angular **Ngx-Admin** 项目：https://github.com/akveo/ngx-… 演示：http://akveo.com/ngx-admin/ **Ng-Alain** 项目：https://github.com/cipchk/ng-… 演示：https://cipchk.github.io/ng-a… **SB-Admin-BS4-Angular6** 项目：https://github.com/start-angu…\n**Angular-Material** 项目：https://github.com/flatlogic/… 演示：http://flatlogic.github.io/an… React **React-Admin** 项目：https://github.com/marmelab/r… 演示：https://marmelab.com/react-ad… **Ant-Design-Pro** 项目：https://github.com/ant-design… 演示：https://preview.pro.ant.design/ **SB-Admin-React** 项目：https://github.com/start-reac…\n**React-Material-Admin** 项目：https://github.com/rafaelhz/r… 演示：https://rafaelhz.github.io/re… **React-Webpack-Skeleton** 项目：https://github.com/knledg/rea… 演示：http://knledg.github.io/ **Bear-Admin** 项目：https://github.com/huzzbuzz/b… 演示：http://huzzbuzz.coding.me/bea… **React-Director-Admin** 项目：https://github.com/MacKentoch… 演示：http://mackentoch.github.io/r… **Admin-On-Rest** 项目：https://github.com/marmelab/a… 演示：https://marmelab.com/admin-on… 原文链接： [https://forum.bestvist.com/to\u0026amp;#8230;](https://forum.bestvist.com/topic/150/%E5%90%8E%E7%AE%A1%E6%A8%A1%E7%89%88%E6%95%B4%E7%90%86) ","permalink":"https://blog.zdltech.com/posts/%E5%90%8E%E7%AE%A1%E6%A8%A1%E7%89%88%E6%95%B4%E7%90%86/","summary":"\u003cdiv class=\"article fmt article__content\" data-id=\"1190000015835976\" data-license=\"\"\u003e\n  # Bootstrap\n\u003cpre\u003e\u003ccode\u003e**Adminlte**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/almasaeed2010/AdminLTE\"\u003ehttps://github.com/almasaeed2…\u003c/a\u003e\n演示：\u003ca href=\"https://adminlte.io/themes/AdminLTE/index2.html\"\u003ehttps://adminlte.io/themes/Ad…\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1532963333268_admin-adminlte.png\" loading=\"lazy\" src=\"http://images.bestvist.com/FvRfOf51pG1_D-Q7I7W9fWmMY15V\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**SB Admin**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/BlackrockDigital/startbootstrap-sb-admin\"\u003ehttps://github.com/BlackrockD…\u003c/a\u003e\n演示：\u003ca href=\"https://blackrockdigital.github.io/startbootstrap-sb-admin/\"\u003ehttps://blackrockdigital.gith…\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1532963355592_admin-start-bootstrap.png\" loading=\"lazy\" src=\"http://images.bestvist.com/FpOcWa2r7-uQWQaQZKrmzm5WjpQB\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**Gentelella Admin**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/puikinsh/gentelella\"\u003ehttps://github.com/puikinsh/g…\u003c/a\u003e\n演示：\u003ca href=\"https://colorlib.com/polygon/gentelella/index.html\"\u003ehttps://colorlib.com/polygon/…\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1532963370697_admin-gentelella-alela.png\" loading=\"lazy\" src=\"http://images.bestvist.com/Fis-0b4B4jSG3VRSNebNhVXsrbLY\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**Vali Admin**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/pratikborsadiya/vali-admin\"\u003ehttps://github.com/pratikbors…\u003c/a\u003e\n演示：\u003ca href=\"http://pratikborsadiya.in/vali-admin/\"\u003ehttp://pratikborsadiya.in/val…\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1532963391407_admin-vali.png\" loading=\"lazy\" src=\"http://images.bestvist.com/FqMwKs3eqN4F45fBTDBJaOli96s6\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**ModularAdmin**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/modularcode/modular-admin-html\"\u003ehttps://github.com/modularcod…\u003c/a\u003e\n演示：\u003ca href=\"https://gurayyarar.github.io/AdminBSBMaterialDesign/index.html\"\u003ehttps://gurayyarar.github.io/…\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1532963413895_admin-modular-admin.png\" loading=\"lazy\" src=\"http://images.bestvist.com/FhbHxjXm-pHhWVDsVG1-OSAJuotb\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**Metis**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/puikinsh/Bootstrap-Admin-Template\"\u003ehttps://github.com/puikinsh/B…\u003c/a\u003e\n演示：\u003ca href=\"https://colorlib.com/polygon/metis/\"\u003ehttps://colorlib.com/polygon/…\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1532963434724_admin-metis.png\" loading=\"lazy\" src=\"http://images.bestvist.com/Fu7UbKcgdT2-X-98dOpv4KadOXNo\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**Ace**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/bopoda/ace\"\u003ehttps://github.com/bopoda/ace\u003c/a\u003e\n演示：\u003ca href=\"http://ace.jeka.by/\"\u003ehttp://ace.jeka.by/\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1532963453654_admin-ace-admin.png\" loading=\"lazy\" src=\"http://images.bestvist.com/FrRNyCcDbiuPi7SBPMwAHO4iN3eK\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**Light Bootstrap Dashboard**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/creativetimofficial/light-bootstrap-dashboard\"\u003ehttps://github.com/creativeti…\u003c/a\u003e\n演示：\u003ca href=\"http://demos.creative-tim.com/light-bootstrap-dashboard\"\u003ehttp://demos.creative-tim.com…\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1532963476875_admin-light-bootstrap.png\" loading=\"lazy\" src=\"http://images.bestvist.com/Fj7KS_6QmvBe6OqmXS6JY8_6lEhT\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**Material Dashboard**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/creativetimofficial/material-dashboard\"\u003ehttps://github.com/creativeti…\u003c/a\u003e\n演示：\u003ca href=\"http://demos.creative-tim.com/material-dashboard/examples/dashboard.html\"\u003ehttp://demos.creative-tim.com…\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1532963504324_admin-material-dashboard.png\" loading=\"lazy\" src=\"http://images.bestvist.com/FrJcNBOutgmeh_ITpbgWyXlFei4z\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**Clearmin**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/paomedia/clearmin\"\u003ehttps://github.com/paomedia/c…\u003c/a\u003e\n演示：\u003ca href=\"http://cm.paomedia.com/\"\u003ehttp://cm.paomedia.com/\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1532963519587_admin-clearmin.png\" loading=\"lazy\" src=\"http://images.bestvist.com/Fsa8JPZWLj0RKTO4pKEciE3Dpnjx\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003ch1 id=\"vue\"\u003eVue\u003c/h1\u003e\n\u003cpre\u003e\u003ccode\u003e**Element Admin**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/PanJiaChen/vue-element-admin\"\u003ehttps://github.com/PanJiaChen…\u003c/a\u003e\n演示：\u003ca href=\"https://panjiachen.github.io/vue-element-admin/\"\u003ehttps://panjiachen.github.io/…\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1532963547572_admin-vue-element.png\" loading=\"lazy\" src=\"http://images.bestvist.com/FsfMEJzXFnxMUTOn6nHWpLTyA-l3\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**Vue-Bulma**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/vue-bulma/vue-admin\"\u003ehttps://github.com/vue-bulma/…\u003c/a\u003e\n演示：\u003ca href=\"https://admin.vuebulma.com/\"\u003ehttps://admin.vuebulma.com/\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1532963569652_admin-vue-bulma.png\" loading=\"lazy\" src=\"http://images.bestvist.com/FiulRgcvQmvge_UdWgVQtpvBfCwm\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**Iview-Admin**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/iview/iview-admin\"\u003ehttps://github.com/iview/ivie…\u003c/a\u003e\n演示：\u003ca href=\"https://admin.iviewui.com/\"\u003ehttps://admin.iviewui.com\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1533140586135_admin-vue-iview.png\" loading=\"lazy\" src=\"http://images.bestvist.com/Fouz13thyKjMpyJkE049W-SErSZc\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**Vuestic-Admin**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目：\u003ca href=\"https://github.com/epicmaxco/vuestic-admin\"\u003ehttps://github.com/epicmaxco/…\u003c/a\u003e\n演示：\u003ca href=\"https://vuestic.epicmax.co/\"\u003ehttps://vuestic.epicmax.co/\u003c/a\u003e\n\u003cspan class=\"img-wrap\"\u003e\u003cimg alt=\"0_1532963626552_admin-vuestic.png\" loading=\"lazy\" src=\"http://images.bestvist.com/FiqbnfAILZZfVnZg5Z9nLScD3WDR\"\u003e\u003c/span\u003e\u003c/p\u003e","title":"后管模版整理"},{"content":"在写界面的时候 然后发现在界面最底下的几行文字 正好被虚拟导航栏遮挡住了，不滑动还看不到底下的文字，所以想隐去这些导航栏。\n采用下面的代码将DecorView中的属性设置为隐藏 navigation，我这里注销掉了全屏的属性 ，按需添加or删除属性吧\n11 \u0026amp;\u0026amp; Build.VERSION.SDK_INT \u0026lt; 19) { // lower api View v = this.getWindow().getDecorView(); if(v!=null){ v.setSystemUiVisibility(View.GONE); } } else if (Build.VERSION.SDK_INT \u0026gt;= 19) { //for new api versions. View decorView = getWindow().getDecorView(); int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY/* | View.SYSTEM_UI_FLAG_FULLSCREEN*/; if (decorView != null) { decorView.setSystemUiVisibility(uiOptions); } } }1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 \u0026#34; data-snippet-id=\u0026#34;ext.c635ae4a92490f41cf801e12d12759e7\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;hideBottomMenu\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//隐藏虚拟按键\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (Build.VERSION.SDK_INT \u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;11\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; Build.VERSION.SDK_INT \u0026amp;lt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;19\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// lower api\u0026amp;lt;/span\u0026gt; View v = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.getWindow().getDecorView(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(v!=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){ v.setSystemUiVisibility(View.GONE); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (Build.VERSION.SDK_INT \u0026amp;gt;= \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;19\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//for new api versions.\u0026amp;lt;/span\u0026gt; View decorView = getWindow().getDecorView(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* | View.SYSTEM_UI_FLAG_FULLSCREEN*/\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (decorView != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { decorView.setSystemUiVisibility(uiOptions); } } }` 我们业务逻辑只要window获取焦点就执行\n@Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); } }\n","permalink":"https://blog.zdltech.com/posts/%E8%99%9A%E6%8B%9F%E5%AF%BC%E8%88%AA%E6%A0%8F%E9%80%82%E9%85%8D/","summary":"\u003cp\u003e在写界面的时候 然后发现在界面最底下的几行文字 正好被虚拟导航栏遮挡住了，不滑动还看不到底下的文字，所以想隐去这些导航栏。\u003cbr\u003e\n采用下面的代码将DecorView中的属性设置为隐藏 navigation，我这里注销掉了全屏的属性 ，按需添加or删除属性吧\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n  \u003cdiv class=\"alert-info\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e 11 \u0026amp;\u0026amp; Build.VERSION.SDK_INT \u0026lt; 19) { // lower api\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            View v = this.getWindow().getDecorView();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            if(v!=null){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                v.setSystemUiVisibility(View.GONE);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } else if (Build.VERSION.SDK_INT \u0026gt;= 19) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            //for new api versions.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            View decorView = getWindow().getDecorView();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY/* | View.SYSTEM_UI_FLAG_FULLSCREEN*/;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            if (decorView != null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                decorView.setSystemUiVisibility(uiOptions);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e2\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e3\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e4\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e5\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e6\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e7\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e8\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e9\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e10\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e11\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e12\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e13\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e14\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e15\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e16\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e17\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e18\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026#34; data-snippet-id=\u0026#34;ext.c635ae4a92490f41cf801e12d12759e7\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`  \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;hideBottomMenu\u0026amp;lt;/span\u0026gt;() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//隐藏虚拟按键\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (Build.VERSION.SDK_INT \u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;11\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; Build.VERSION.SDK_INT \u0026amp;lt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;19\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// lower api\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            View v = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.getWindow().getDecorView();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(v!=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                v.setSystemUiVisibility(View.GONE);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (Build.VERSION.SDK_INT \u0026amp;gt;= \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;19\u0026amp;lt;/span\u0026gt;) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//for new api versions.\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            View decorView = getWindow().getDecorView();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* | View.SYSTEM_UI_FLAG_FULLSCREEN*/\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (decorView != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                decorView.setSystemUiVisibility(uiOptions);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e \u003c/p\u003e","title":"虚拟导航栏适配"},{"content":"1.yum -y install mariadb mariadb-server\n2. 安装完成MariaDB，首先启动MariaDB\nsystemctl start mariadb\n3.设置开机启动\nsystemctl enable mariadb\n4.接下来进行MariaDB的相关简单配置\nsystemctl enable mariadb\n首先是设置密码，会提示先输入密码\nEnter current password for root (enter for none):\u0026lt;–初次运行直接回车\n设置密码\nSet root password? [Y/n] \u0026lt;– 是否设置root用户密码，输入y并回车或直接回车\nNew password: \u0026lt;– 设置root用户的密码\nRe-enter new password: \u0026lt;– 再输入一次你设置的密码\n其他配置\nRemove anonymous users? [Y/n] \u0026lt;– 是否删除匿名用户，回车\nDisallow root login remotely? [Y/n] \u0026lt;–是否禁止root远程登录,回车,\nRemove test database and access to it? [Y/n] \u0026lt;– 是否删除test数据库，回车\nReload privilege tables now? [Y/n] \u0026lt;– 是否重新加载权限表，回车\n5.初始化MariaDB完成，接下来测试登录\nmysql -uroot -ppassword 登录成功\n6.配置MariaDB的字符集\n文件/etc/my.cnf\n``` vi /etc/my.cnf ``` 在[mysqld]标签下添加\ninit_connect=\u0026#39;SET collation_connection = utf8_unicode_ci\u0026#39; init_connect=\u0026#39;SET NAMES utf8\u0026#39; character-set-server=utf8 collation-server=utf8_unicode_ci skip-character-set-client-handshake 文件/etc/my.cnf.d/client.cnf\n``` vi /etc/my.cnf.d/client.cnf ``` 在[client]中添加\n``` default-character-set=utf8 ``` 文件/etc/my.cnf.d/mysql-clients.cnf\n``` vi /etc/my.cnf.d/mysql-clients.cnf ``` 在[mysql]中添加\n``` default-character-set=utf8 ``` 全部配置完成，重启mariadb\n``` systemctl restart mariadb ``` 之后进入MariaDB查看字符集\nshow variables like \u0026amp;quot;%character%\u0026amp;quot;;show variables like \u0026amp;quot;%collation%\u0026amp;quot;;\u0026#34; data-snippet-id=\u0026#34;ext.7007b5ae0e53f2c1b43b16674057128f\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;mysql\u0026amp;gt; show variables like \u0026#34;%character%\u0026#34;;show variables like \u0026#34;%collation%\u0026#34;; 显示为\n| Variable_name | Value |\n| character_set_client | utf8 |\n| character_set_connection | utf8 |\n| character_set_database | utf8 |\n| character_set_filesystem | binary |\n| character_set_results | utf8 |\n| character_set_server | utf8 |\n| character_set_system | utf8 |\n| character_sets_dir | /usr/share/mysql/charsets/ |\n8 rows in set (0.00 sec)\n| Variable_name | Value |\n| collation_connection | utf8_unicode_ci |\n| collation_database | utf8_unicode_ci |\n| collation_server | utf8_unicode_ci |\n3 rows in set (0.00 sec)\n字符集配置完成。\n3、添加用户，设置权限\n创建用户命令\ncreate user username@localhost identified by \u0026#39;password\u0026#39;; \u0026#34; data-snippet-id=\u0026#34;ext.b2c730cd0da2567d259938bf357bbaf9\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;mysql\u0026amp;gt;create user username@localhost identified by \u0026#39;password\u0026#39;; 直接创建用户并授权的命令\ngrant all on *.* to username@localhost indentified by \u0026#39;password\u0026#39;;\u0026#34; data-snippet-id=\u0026#34;ext.e752475ec64bd5b2ac790c749a8193b5\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;mysql\u0026amp;gt;grant all on *.* to username@localhost indentified by \u0026#39;password\u0026#39;; 授予外网登陆权限\ngrant all privileges on *.* to username@\u0026#39;%\u0026#39; identified by \u0026#39;password\u0026#39;;\u0026#34; data-snippet-id=\u0026#34;ext.9a0f65aeb097d1c3a89b2eb03db754f7\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;mysql\u0026amp;gt;grant all privileges on *.* to username@\u0026#39;%\u0026#39; identified by \u0026#39;password\u0026#39;; 授予权限并且可以授权\ngrant all privileges on *.* to username@\u0026#39;hostname\u0026#39; identified by \u0026#39;password\u0026#39; with grant option;\u0026#34; data-snippet-id=\u0026#34;ext.68429d9257f06dee6cad84424b244cc2\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;mysql\u0026amp;gt;grant all privileges on *.* to username@\u0026#39;hostname\u0026#39; identified by \u0026#39;password\u0026#39; with grant option; 简单的用户和权限配置基本就这样了。\n其中只授予部分权限把 其中 all privileges或者all改为select,insert,update,delete,create,drop,index,alter,grant,references,reload,shutdown,process,file其中一部分。\n设置最大连接错误\n通过 show global variables like ‘%max_connect_errors%’; 查看数据库连接。默认10个\n通过 set global max_connect_errors=2000; 设置最大连接数为2000\n在CentOS7上安装完成MariaDB之后，发现无论命令行还是程序中连接MariaDB的时候都很慢，\n我修改的配置文件是：/etc/my.cnf.d/server.cnf\n","permalink":"https://blog.zdltech.com/posts/centos7%E5%AE%89%E8%A3%85mariadb/","summary":"\u003cp\u003e1.yum -y install mariadb mariadb-server\u003c/p\u003e\n\u003cp\u003e2. 安装完成MariaDB，首先启动MariaDB\u003c/p\u003e\n\u003cp\u003esystemctl start mariadb\u003c/p\u003e\n\u003cp\u003e3.设置开机启动\u003c/p\u003e\n\u003cp\u003esystemctl enable mariadb\u003c/p\u003e\n\u003cp\u003e4.接下来进行MariaDB的相关简单配置\u003c/p\u003e\n\u003cp\u003esystemctl enable mariadb\u003c/p\u003e\n\u003cp\u003e首先是设置密码，会提示先输入密码\u003c/p\u003e\n\u003cp\u003eEnter current password for root (enter for none):\u0026lt;–初次运行直接回车\u003c/p\u003e\n\u003cp\u003e设置密码\u003c/p\u003e\n\u003cp\u003eSet root password? [Y/n] \u0026lt;– 是否设置root用户密码，输入y并回车或直接回车\u003cbr\u003e\nNew password: \u0026lt;– 设置root用户的密码\u003cbr\u003e\nRe-enter new password: \u0026lt;– 再输入一次你设置的密码\u003c/p\u003e\n\u003cp\u003e其他配置\u003c/p\u003e\n\u003cp\u003eRemove anonymous users? [Y/n] \u0026lt;– 是否删除匿名用户，回车\u003c/p\u003e\n\u003cp\u003eDisallow root login remotely? [Y/n] \u0026lt;–是否禁止root远程登录,回车,\u003c/p\u003e\n\u003cp\u003eRemove test database and access to it? [Y/n] \u0026lt;– 是否删除test数据库，回车\u003c/p\u003e\n\u003cp\u003eReload privilege tables now? [Y/n] \u0026lt;– 是否重新加载权限表，回车\u003c/p\u003e","title":"Centos7安装MariaDB"},{"content":" 很无语，CentOS居然php版本才5.1.6，很多开源的CMS无法安装。 查看php版本命令： #php -v 下面的命令是删除不干净的 #yum remove php 因为使用这个命令以后再用 #php -v 还是会看到有版本信息的。。。。。 \u0026amp;nbsp; 必须强制删除，使用下面命令查看全部php软件包 #rpm -qa|grep php 提示如下： #php-pdo-5.1.6-27.el5_5.3 #php-mysql-5.1.6-27.el5_5.3 #php-xml-5.1.6-27.el5_5.3 #php-cli-5.1.6-27.el5_5.3 #php-common-5.1.6-27.el5_5.3 #php-gd-5.1.6-27.el5_5.3\n注意卸载要先卸载没有依赖的 pdo是mysql的依赖项；common是gd的依赖项； 例如：# rpm -e php-pdo-5.1.6-27.el5_5.3 error: Failed dependencies: php-pdo is needed by (installed) php-mysql-5.1.6-27.el5_5.3.i386\n所以正确的卸载顺序是(卸载顺序很重要)： # rpm -e php-mysql-5.1.6-27.el5_5.3 rpm -e php-pdo-5.1.6-27.el5_5.3 rpm -e php-xml-5.1.6-27.el5_5.3 rpm -e php-cli-5.1.6-27.el5_5.3 rpm -e php-gd-5.1.6-27.el5_5.3 rpm -e php-common-5.1.6-27.el5_5.3 再用 # php -v 查看版本信息已经没有提示 ## 关于php-fpm nginx本身不能处理PHP，它只是个web服务器，当接收到请求后，如果是php请求，则发给php解释器处理，并把结果返回给客户端。 nginx一般是把请求发fastcgi管理进程处理，fascgi管理进程选择cgi子进程处理结果并返回被nginx。 PHP-FPM是一个PHP FastCGI管理器，是只用于PHP的。 PHP在 5.3.3 之后已经讲php-fpm写入php源码核心了。所以已经不需要另外下载了。 获取PHP下载地址 为什么选择5.6.30这个版本，因为学习，不是研究。诚然，7.0新增了很多PHP的新特性，性能上面也有些提升，如果是研究，倒是可以折腾一番，后面得空再讲7.0的版本以及如何在各个PHP版本之间切换。 打开php的官网：http://php.net/，查看php的版本列表 ![](https://images2015.cnblogs.com/blog/465728/201702/465728-20170222135638429-399501886.png) 右击，复制链接地址，在远程主机登录，下载该软件（我选的是Australia的主机mirror下载的） ``` wget http://au1.php.net/get/php-5.6.30.tar.gz/from/this/mirror \u0026lt;/div\u0026gt; 下载下来的是一个mirror文件，改成我们需要的文件名 \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` #mv mirror php-5.6.30.tar.gz #tar zxvf php-5.6.30.tar.gz #cd php-5.6.30 配置安装 进入到目录，我们需要在安装的时候将安装目录配置到/usr/local/php/里 ![复制代码](https://common.cnblogs.com/images/copycode.gif) \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` #./configure \u0026ndash;prefix=/usr/local/php \u0026ndash;with-curl \u0026ndash;with-freetype-dir \u0026ndash;with-gd \u0026ndash;with-gettext \u0026ndash;with-iconv-dir \u0026ndash;with-kerberos \u0026ndash;with-libdir=lib64 \u0026ndash;with-libxml-dir \u0026ndash;with-MySQL \u0026ndash;with-mysqli \u0026ndash;with-openssl \u0026ndash;with-pcre-regex \u0026ndash;with-pdo-mysql \u0026ndash;with-pdo-sqlite \u0026ndash;with-pear \u0026ndash;with-png-dir \u0026ndash;with-xmlrpc \u0026ndash;with-xsl \u0026ndash;with-zlib \u0026ndash;enable-fpm \u0026ndash;enable-bcmath \u0026ndash;enable-libxml \u0026ndash;enable-inline-optimization \u0026ndash;enable-gd-native-ttf \u0026ndash;enable-mbregex \u0026ndash;enable-mbstring \u0026ndash;enable-opcache \u0026ndash;enable-pcntl \u0026ndash;enable-shmop \u0026ndash;enable-soap \u0026ndash;enable-sockets \u0026ndash;enable-sysvsem \u0026ndash;enable-xml \u0026ndash;enable-zip\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](https://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 配置的过程中可能会报如下错误 错误1： \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` xml2-config not found. Please check your libxml2 installation. 解决办法 安装libxml2相关组件 ``` #yum install libxml2 #yum install libxml2-devel -y ``` 错误2： ``` /include/curl/\u0026quot; data-snippet-id=\u0026ldquo;ext.212df541b0fb06adb59198e5569a12d6\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Please reinstall the libcurl distribution - easy.h should be in \u0026lt;curl-dir\u0026gt;/include/curl/\n\u0026lt;/div\u0026gt; 安装curl相关组件 \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; ``` #yum install curl curl-devel 错误3： ``` configure: error: png.h not found. ``` 安装libpng相关组件 ``` #yum install libpng #yum install libpng-devel ``` 错误4： ``` freetype-config not found. ``` 安装freetype相关组件 ``` #yum install freetype-devel ``` 错误5： ``` = 1.1.0 distribution\u0026quot; data-snippet-id=\u0026ldquo;ext.c1578c4835ee681a52395d65c1c30f51\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;xslt-config not found. Please reinstall the libxslt \u0026gt;= 1.1.0 distribution\n\u0026lt;/div\u0026gt; 安装libxslt相关组件 \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; ``` #yum install libxslt-devel 好的，当我们看到下面这句话的时候，说明你的php已经配置完成啦！ ![](https://images2015.cnblogs.com/blog/465728/201702/465728-20170222212310929-2087784236.png) 接下来我们只需要编译安装即可完成php的安装 ``` #make \u0026\u0026 make install ``` 看到这句话，表明安装完成！ ![](https://images2015.cnblogs.com/blog/465728/201702/465728-20170222214326898-859959823.png) 为了保险起见，我们make test一把，看看是否真的成功了。 配置相关 php.ini配置 首先我们需要配置的是php.ini这个文件 安装目录有2个文件：php.ini-development和php.ini-production php.ini-production 线上版本使用 php.ini-development 开发版本使用 我们选择development进行配置 ``` cp php.ini-development /usr/local/php/lib/php.ini \u0026lt;/div\u0026gt; ### php-fpm配置 拷贝php-fpm配置文件 \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` #cp -R ./sapi/fpm/php-fpm.conf /usr/local/php/etc/php-fpm.conf 拷贝启用文件 ``` #cp -R ./sapi/fpm/php-fpm /etc/init.d/php-fpm（已弃用，详细的见注1）\n\u0026lt;/div\u0026gt; 启动 \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; ``` #/etc/init.d/php-fpm 查看php是否启动成功 ``` #ps aux | grep php ``` ![](https://images2015.cnblogs.com/blog/465728/201702/465728-20170222220434788-885246487.png) 看到这些，表明你的php已经启动成功啦！ 重启及关闭 ``` #kill -9 进程号 #/etc/init.d/php-fpm ``` 配置Nginx支持PHP 进入nginx主目录，/usr/local/nginx; ``` #cd /usr/local/nginx ``` 进入配置目录 ``` #cd conf ``` Nginx支持PHP需要修改nginx.conf ``` #vim nginx.conf ``` 代开下面代码，让Nginx支持PHP，在server代码段里。 ![](https://images2015.cnblogs.com/blog/465728/201702/465728-20170222221437929-431643452.png) 修改完，这段代码变为，红色部分为我们主机目录为/usr/www，需要修改fastcgi_param SCRIPT_FILENAME指向对应目录即可： ![](https://images2015.cnblogs.com/blog/465728/201702/465728-20170222222833320-1693195452.png) \u0026amp;nbsp; 设置主目录设置为/usr/www。 ![](https://images2015.cnblogs.com/blog/465728/201702/465728-20170222222355632-1795566322.png) 注释掉root那行，新增一行：root /usr/www; 保存退出。 根据Nginx章的解释，我们重启Nginx服务。 ``` #/etc/init.d/nginx restart ``` 如果你没有按照我们在Nginx的方法配置，可以按照以下的方式重启Nginx服务 ``` # /usr/local/nginx/sbin/nginx -s reload ``` 重启成功！下面我们在/usr/www目录下添加一个新文件。 ``` #vim /usr/www/phpinfo.php ``` 插入以下内容 ``` \u0026lt;?php phpinfo(); ?\u0026gt; ``` 在浏览器中打开http://远程ip/phpinfo.php![](https://images2015.cnblogs.com/blog/465728/201702/465728-20170222223026976-871816997.png) 看到这个页面，恭喜你，你的PHP已经安装配置完成。你可以在这个页面看到所有php依赖的组件，下一节我将和大家详细讲解一下这个页面，如果对本节有什么疑问的，欢迎在评论区和我交流讨论，有留言必回。^_^ 注 设置php开机自启动与开启php服务便捷方式 上面的方法中，我在拷贝php-fpm的服务时出了问题，不应该直接将php-fpm的可执行文件拷贝到/etc/init.d/目录下去，应该将php给我们准备好的init.d.php-fpm。 ``` #cp ./sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm ``` 将php-fpm服务添加到chkconfig列表 ``` #chkconfig --add php-fpm ``` 设置开机自启动 ``` #chkconfig php-fpm on ``` 以后重启和停止php的方式为 ``` #service php-fpm start #service php-fpm stop #service php-fpm restart #service php-fpm reload\n\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026#34;blog_post_info_block\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/linux-centos%E5%AE%8C%E5%85%A8%E5%8D%B8%E8%BD%BDphp%E5%8F%8A%E6%89%8B%E5%8A%A8%E5%AE%89%E8%A3%85php/","summary":"\u003cdiv id=\"cnblogs_post_body\" class=\"blogpost-body\"\u003e\n\u003cpre\u003e\u003ccode\u003e很无语，CentOS居然php版本才5.1.6，很多开源的CMS无法安装。\n\n\n\n\n\n查看php版本命令：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003e  #php -v\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/blockquote\u003e\n\u003cpre\u003e\u003ccode\u003e下面的命令是删除不干净的\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003e  #yum remove php\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/blockquote\u003e\n\u003cpre\u003e\u003ccode\u003e因为使用这个命令以后再用\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003e  #php -v\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/blockquote\u003e\n\u003cpre\u003e\u003ccode\u003e还是会看到有版本信息的。。。。。\n\n\n\n\n\n\u0026amp;nbsp;\n\n\n\n\n\n必须强制删除，使用下面命令查看全部php软件包\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003e  #rpm -qa|grep php\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/blockquote\u003e\n\u003cpre\u003e\u003ccode\u003e提示如下：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003e  #php-pdo-5.1.6-27.el5_5.3\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e#php-mysql-5.1.6-27.el5_5.3\n#php-xml-5.1.6-27.el5_5.3\n#php-cli-5.1.6-27.el5_5.3\n#php-common-5.1.6-27.el5_5.3\n#php-gd-5.1.6-27.el5_5.3\u003c/p\u003e\n  \u003c/blockquote\u003e\n\u003cpre\u003e\u003ccode\u003e注意卸载要先卸载没有依赖的\n\n\n\n\n\npdo是mysql的依赖项；common是gd的依赖项；\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e例如：# rpm -e php-pdo-5.1.6-27.el5_5.3\nerror: Failed dependencies:\nphp-pdo is needed by (installed) php-mysql-5.1.6-27.el5_5.3.i386\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e所以正确的卸载顺序是(卸载顺序很重要)：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003e  # rpm -e php-mysql-5.1.6-27.el5_5.3\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch1 id=\"rpm--e-php-pdo-516-27el5_53\"\u003erpm -e php-pdo-5.1.6-27.el5_5.3\u003c/h1\u003e\n\u003ch1 id=\"rpm--e-php-xml-516-27el5_53\"\u003erpm -e php-xml-5.1.6-27.el5_5.3\u003c/h1\u003e\n\u003ch1 id=\"rpm--e-php-cli-516-27el5_53\"\u003erpm -e php-cli-5.1.6-27.el5_5.3\u003c/h1\u003e\n\u003ch1 id=\"rpm--e-php-gd-516-27el5_53\"\u003erpm -e php-gd-5.1.6-27.el5_5.3\u003c/h1\u003e\n\u003ch1 id=\"rpm--e-php-common-516-27el5_53\"\u003erpm -e php-common-5.1.6-27.el5_5.3\u003c/h1\u003e\n  \u003c/blockquote\u003e\n\u003cpre\u003e\u003ccode\u003e再用\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003e  # php -v\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/blockquote\u003e\n\u003cpre\u003e\u003ccode\u003e查看版本信息已经没有提示\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv class=\"clear\"\u003e\n  ## 关于php-fpm\n\u003cpre\u003e\u003ccode\u003enginx本身不能处理PHP，它只是个web服务器，当接收到请求后，如果是php请求，则发给php解释器处理，并把结果返回给客户端。\n\n\n\n\n\nnginx一般是把请求发fastcgi管理进程处理，fascgi管理进程选择cgi子进程处理结果并返回被nginx。\n\n\n\n\n\nPHP-FPM是一个PHP FastCGI管理器，是只用于PHP的。\n\n\n\n\n\nPHP在 5.3.3 之后已经讲php-fpm写入php源码核心了。所以已经不需要另外下载了。\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"获取php下载地址\"\u003e获取PHP下载地址\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e为什么选择5.6.30这个版本，因为学习，不是研究。诚然，7.0新增了很多PHP的新特性，性能上面也有些提升，如果是研究，倒是可以折腾一番，后面得空再讲7.0的版本以及如何在各个PHP版本之间切换。\n\n\n\n\n\n打开php的官网：http://php.net/，查看php的版本列表\n\n\n\n\n\n![](https://images2015.cnblogs.com/blog/465728/201702/465728-20170222135638429-399501886.png)\n\n\n\n\n\n右击，复制链接地址，在远程主机登录，下载该软件（我选的是Australia的主机mirror下载的）\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"cnblogs_code\"\u003e\n    \u003cdiv class=\"top-box hide\"\u003e\n      \u003cdiv class=\"alert-info\"\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e```\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch1 id=\"wget\"\u003ewget  \u003ca href=\"http://au1.php.net/get/php-5.6.30.tar.gz/from/this/mirror\"\u003ehttp://au1.php.net/get/php-5.6.30.tar.gz/from/this/mirror\u003c/a\u003e\u003c/h1\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    下载下来的是一个mirror文件，改成我们需要的文件名\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#mv mirror php-5.6.30.tar.gz\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#tar zxvf php-5.6.30.tar.gz\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#cd php-5.6.30\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003c/div\u003e\n\u003ch2 id=\"配置安装\"\u003e配置安装\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e进入到目录，我们需要在安装的时候将安装目录配置到/usr/local/php/里\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"cnblogs_code\"\u003e\n    \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n      \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](https://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e#./configure \u0026ndash;prefix=/usr/local/php \u0026ndash;with-curl \u0026ndash;with-freetype-dir \u0026ndash;with-gd \u0026ndash;with-gettext \u0026ndash;with-iconv-dir \u0026ndash;with-kerberos \u0026ndash;with-libdir=lib64 \u0026ndash;with-libxml-dir \u0026ndash;with-MySQL \u0026ndash;with-mysqli \u0026ndash;with-openssl \u0026ndash;with-pcre-regex \u0026ndash;with-pdo-mysql \u0026ndash;with-pdo-sqlite \u0026ndash;with-pear \u0026ndash;with-png-dir \u0026ndash;with-xmlrpc \u0026ndash;with-xsl \u0026ndash;with-zlib \u0026ndash;enable-fpm \u0026ndash;enable-bcmath \u0026ndash;enable-libxml \u0026ndash;enable-inline-optimization \u0026ndash;enable-gd-native-ttf \u0026ndash;enable-mbregex \u0026ndash;enable-mbstring \u0026ndash;enable-opcache \u0026ndash;enable-pcntl \u0026ndash;enable-shmop \u0026ndash;enable-soap \u0026ndash;enable-sockets \u0026ndash;enable-sysvsem \u0026ndash;enable-xml \u0026ndash;enable-zip\u003c/p\u003e","title":"Linux CentOS完全卸载PHP及手动安装php"},{"content":" doxygen是一种从源代码生成文档的工具，支持多种语言。当然，源代码中需按一定的格式写注释，这些注释的格式也能帮助我们养成很好的注释习惯，可以尝试一下。 使用doxygen生成文档的方法很简单： ** $ doxygen -g –s $ doxygen \u0026lt;/blockquote\u0026gt; 只需两个简单命令就可以了。 下面简单说明一下： 1、在工程目录下输入doxygen –s –g doxyconfig，其中doxyconfig为生成配置的文件名称，可任意指定，如果不指定，默认生成的配置文件为Doxyfile。man手册中没有详细说明选项的意思，这里不妨猜测一下，-s为simple，-g为generate，如果不指定-s，则生成的配置文件大约为63KB，行数约1500左右；反之，则约成10KB，行数约250左右。——此处猜测便根据这些测试而来的。 2、生成配置文件后，会出现提示信息，大意是说那个配置文件已经生成了，现在编辑它，之后输入doxygen Doxyfile(经实践证明，可以只输入doxygen命令)就可以产生工程的文档了。如果再次使用doxygen生产配置文件，则原来的就配置文件就变成了备份文件，添加后缀名.bak。 3、根据doxygen要求的注释格式来编写代码的注释，这一步要求比较高，而且工作量比较大。我们在文章后面还要讲解的。 下面介绍一下如何编辑生成的配置文件，我们以我们的串口程序为例子。 \u0026amp;nbsp; doxygen的配置文件与大多数linux平台的配置文件类似，就是一些关键字与值，配置文件中的值以YES和NO居多。 \u0026lt;blockquote\u0026gt; DOXYFILE_ENCODING = UTF-8，默认编码为UTF-8，这样可以支持中文。 PROJECT_NAME = “SerialPort”，项目名称，多个单词需要使用引号(“”)。 PROJECT_NUMBER = “1.0 beta”，项目版本号。 OUTPUT_DIRECTORY = serialport-html，输出文档的目录，如果为空，表示在当前目录，建议写上表示本工程的有意义的目录名称，比如我们就指定目录名称为serialport-html。 OUTPUT_LANGUAGE = English，文档语言，可以指定为Chinese。 IMAGE_PATH = image_dir，指定图片存放的目录，我们将图片放到当前目录下的image_dir目录中，因为我们的文档会出现测试图片示例。 HTML_OUTPUT= . ，html输出目录名称，默认为html目录，如果为“.”则表明为上述OUTPUT_DIRECTORY目录。 GENERATE_LATEX = NO，是否生成LaTeX，默认生成的，但我们不想生成。 好了，我们需要修改的就这么多，使用上述第2步骤的命令就可以生成一个漂亮的文档了。此外还有一些常用的设置选项。 INPUT =xxx，代码文件或目录，多个文件(目录)需要以空格隔开，如果不指定，表示当前目录，但是，如果指定目录且当前目录有代码文件的话，需要使用点号(“.”)表示当前目录。 FILE_PATTERNS=xxx，指定各种文件，我们常用为*.cpp *.c *.h，等等。 \u0026lt;/blockquote\u0026gt; 上面基本就是我们常用的了，如果还想更深入了解，请移步到google网站。 下面就是真正需要花费一定时间的工作：为我们的程序作特定格式的注释。 doxygen支持多种注释风格，比如JavaDoc风格，它在C语言块注释开始处再添加一个星号(*)构成，如下： \u0026lt;div\u0026gt; 1. /** 2. * … text … 3. */ \u0026lt;/div\u0026gt; Qt风格： \u0026lt;div\u0026gt; ``` 1. /*! ``` 2. * ... text ... ``` 3. */ \u0026lt;/div\u0026gt; 上面两种方式中间的星号(*)是可选的，不过，个人认为添加会更美观一些。 C++风格的，——就是在C++注释后面再添加“/”： \u0026lt;div\u0026gt; ``` 1. /// ``` 2. /// ... text ... ``` 3. /// \u0026lt;/div\u0026gt; 或者是这样： \u0026lt;div\u0026gt; ``` 1. //! ``` 2. //!... text ... ``` 3. //! \u0026lt;/div\u0026gt; 经测试，实际使用中，如果是单行注释的话，可以使用如下的格式： \u0026lt;div\u0026gt; ``` 1. /** ... text ... */ ``` 2. /**\u0026amp;lt; ... text ... */ \u0026lt;/div\u0026gt; 这些格式会被doxygen文档化，如果不想让它文档化，可以“破坏”这些格式，比如可以使用“正宗”的C/C++注释： \u0026lt;div\u0026gt; ``` 1. /* ... text ... */ ``` 2. // ... text ... \u0026lt;/div\u0026gt; 上述风格来自doxygen的manual页面，具体地址为： [http://www.stack.nl/~dimitri/doxygen/docblocks.html](http://www.stack.nl/~dimitri/doxygen/docblocks.html) http://www.stack.nl/~dimitri/doxygen/index.html ``` # 自定义文档首页 # INPUT = README.md other_sources # USE_MDFILE_AS_MAINPAGE = README.md 下面介绍一下常用doxygen的命令，更多详细使用说明，请参考如下地址： [http://www.stack.nl/~dimitri/doxygen/commands.html#cmde](http://www.stack.nl/~dimitri/doxygen/commands.html#cmde) doxygen命令以@或开始，两种方式均可以。文中以@标记之。 \u0026lt;blockquote\u0026gt; @def 宏定义说明 @fn 函数 函数说明 @param 参数 参数说明 @return 返回值说明(出错返回什么值，等等) @file 文件名 @author 作者 @version 程序版本 @date 日期 @note 注解(注意事项，等) @warning 警告信息 @bug bug信息 @test 测试示例、信息 @todo 一些未完事宜 (@bug、@test以及@todo等会出现链接页面) 上面这样适合在函数、文件前面出现。 下面为生成特殊字体的命令： @a @e @em：其后的单个字(word)表现为斜体，以强调作用。如有多个word的话，使用*xxx xxx*代替。 @b：其后的word为粗体，多个则使用\u0026lt;b\u0026gt;xxx xxx**。 @c @p：字体表现为打印机字体，多个则使用\u0026lt;tt\u0026gt;xxx xxx\u0026lt;/tt\u0026gt;。 \u0026lt;/blockquote\u0026gt; ` ` `下面是一些具体的实例。 ` `在文件开始处的版权声明及其它信息：` ** /** * Copyleft (C) 2010 Late Lee * This program is tested on LINUX PLATFORM, WITH GCC 4.x. * The program is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY. Please feel free to * use the program, and I feel free to ignore the related * issues. Any questions or suggestions, or bugs, please * contact me at or e-mail to * if you want to do this. * @file serialport.c * @author Late Lee * @date Mon Jan 10 2011 * * @brief Some utils of the serial port, such as open the port, close * the port and setup the port. * @note This is a note. * @warning This is a warning. * @bug This is a bug. */ \u0026lt;/blockquote\u0026gt; \u0026amp;nbsp; 在函数前的注释： \u0026amp;nbsp; \u0026lt;blockquote\u0026gt; /** * open_port – Open a serial port * * @param port : The port number, eg, open_port(1) will open com1 * * @return Return fd if success, otherwise will return -1 with some msg. */ \u0026lt;/blockquote\u0026gt; 定义宏使用的注释： \u0026lt;blockquote\u0026gt; /** * @def error_exit * @brief A macro that prints the @a error msg and exit. */ #define error_exit(error) do{ fprintf(stderr, “%sn”, error); exit(0); } while(0) \u0026lt;/blockquote\u0026gt; \u0026amp;nbsp; \u0026amp;nbsp; 或者你会说，这样的注释风格太麻烦了！不怕！现在有了跟emacs结合的doxymacs，在emacs中配置了doxymacs，这些注释是十分方便的！比如需要在文件前插入注释，按C-c d i即可，在函数前插入注释，按C-c d f即可，等等。具体的请移步到这里的文章：[http://www.latelee.org/embedded-linux/learning-elinux-4-my-emacs-ii](http://www.latelee.org/embedded-linux/learning-elinux-4-my-emacs-ii.html)及[http://www.latelee.org/embedded-linux/learning-elinux-4-my-emacs](http://www.latelee.org/embedded-linux/learning-elinux-4-my-emacs.html)。如果你使用的不是emacs，那Sorry，我也不太会，如果你懂，不妨分享一下。 这个串口程序的文档已经放到网站上了，这里main.c文件参考页面地址：[http://www.latelee.org/yetanothertest/serialport-html-cn/main_8c.html](http://www.latelee.org/yetanothertest/serialport-html-cn/main_8c.html) 此外，我们还测试生成中文文档，因此doxygen使用UTF8，因此只要将代码文件保存为utf8编码即可(使用Ultra Edit或notepad++等等编辑器很容易做到)。但这又引出一个问题，gcc并不支持utf8！经过google，发现gcc 4.4.0版本以后已经支持utf8了，因此，为了做这个测试，花了一个小时左右编译、安装高版本的gcc(我们使用4.4.5版本)，结果，这个版本的gcc是支持utf8的。后来，又发现，如果使用“UTF-8 无BOM格式编码”格式保存源文件的话，在原来的gcc下也编译通过。因此如果想在程序中使用中文注释，建议以此格式保存，当然，在系统的locale不是中文的情况下看到的中文是乱码的。 1、尽信书则不如无书，我们建议各位到实践中试一试，这样学到的知识才是我们自己的，比如，在指定源代码目录中，我的测试文件main.c放在当前目录下，如果不指定“.”的话，doxygen便不会处理该文件，这是网上很多资料没有说明的，因此需要实践才能了解。 2、我们强烈建议各位到官方网站学习，因为其它地方绝大部分都出自官方网站，manual页面地址是： [http://www.stack.nl/~dimitri/doxygen/manual.html](http://www.stack.nl/~dimitri/doxygen/manual.html) Doxygen是一种开源跨平台的，以类似JavaDoc风格描述的文档系统，完全支持C、C++、Java、Objective-C和IDL语言，部分支持PHP、C#。注释的语法与Qt-Doc、KDoc和JavaDoc兼容。Doxgen可以从一套归档源文件开始，生成HTML格式的在线类浏览器，或离线的LATEX、RTF参考手册。\nDoxygen 是一个程序的文件产生工具，可将程序中的特定批注转换成为说明文件。通常我们在写程序时，或多或少都会写上批注，但是对于其它人而言，要直接探索程序里的批注，与打捞铁达尼号同样的辛苦。大部分有用的批注都是属于针对函式，类别等等的说明。所以，如果能依据程序本身的结构，将批注经过处理重新整理成为一个纯粹的参考手册，对于后面利用您的程序代码的人而言将会减少许多的负担。不过，反过来说，整理文件的工作对于您来说，就是沉重的负担。\nDoxygen 就是在您写批注时，稍微按照一些它所制订的规则。接着，他就可以帮您产生出漂亮的文档了。\n因此，Doxygen 的使用可分为两大部分。首先是特定格式的批注撰写，第二便是利用Doxygen的工具来产生文档。\n1） 输出表格\n` \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * DSTATUS | value| instruction * ------------| ---- | ----------------------- * STA_NOINIT | 0x01 | Drive not initialized * STA_NODISK | 0x02 | No medium in the drive * STA_PROTECT | 0x04 | Write protected */\u0026amp;lt;/span\u0026gt;` 效果为:\n（2） 参考其他函数注释：\n@see\n（3） module name:\n`\u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * \u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @defgroup\u0026amp;lt;/span\u0026gt; test_module_name * \u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @brief\u0026amp;lt;/span\u0026gt; module example. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * \u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @ingroup\u0026amp;lt;/span\u0026gt; test_module_name * \u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @brief\u0026amp;lt;/span\u0026gt; source file of module example. * \u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @file\u0026amp;lt;/span\u0026gt; test_module_name.c * \u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @author\u0026amp;lt;/span\u0026gt; test * \u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @version\u0026amp;lt;/span\u0026gt; 1.0 * \u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @date\u0026amp;lt;/span\u0026gt; 2018/2/27 * /\u0026amp;lt;/span\u0026gt;` （4） \u0026lt;b\u0026gt; ** 以黑体显示字符，用法格式如下：\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;b\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; multiple words \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;b\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 若要黑体显示像标题一样单独一行，可以在后面添加/n，如下图示例所示：\n生成样式为：\n**使用步骤** 1、第一次使用需要安装doxygen的程序 2、生成doxygen配置文件\n3、编码时，按照某种格式编写注释 4、生成对应文档\n1、安装doxygen及其相关程序 1.1Doxygen下载\nhttp://sourceforge.net/projects/doxygen/?source=dlp 进行下载\n本文使用的为Doxygen 1.8.3.1\n安装，我们将在配置的时候使用doxywizard，Doxygen的GUI版本。\n1.2HTML Help Workshop下载\n如果你希望你的Doxygen自动生成chm，那么请下载HTML Help Workshop，我们将要使用当中的hcc.exe文件以及相关dll\nhttp://www.microsoft.com/en-us/download/details.aspx?id=21138 进行下载\n下载其中的htmlhelp.exe并安装，记住安装目录，我们将在Doxygen配置时使用。\n1.3 Graphviz\ngraphviz 是一个由AT\u0026amp;T实验室启动的开源工具包，用于绘制DOT语言脚本描述的图形。Doxygen 使用 graphviz 自动生成类之间和文件之间的调用关系图，如不需要此功能可不安装该工具包。\n安装并记录安装目录，同样我们一会需要配置Doxygen\n2.配置Doxygen 2.1基本配置\n在基本配置中，会介绍一些关于Doxygen的基本配置，例如各种乱码，输出内容等。\n首先我们打开开始-》所有程序-》Doxygen-》doxywizard\n第一步，选择你的工作目录（配置文件位置 D:\\Doxygen），点击Select。\n第二步，进行配置\nWizard选项卡：\n首先修改Project name，选择扫描源代码的目录，Source code directory：，勾选Scan recursively （递归扫描），之后选择输出目录，作为测试选择桌面进行查看。\n在Wizard的Topics下的Mode，选择All Entities，可以输出相对完整的功能，是否包含源代码看你自身情况，在下面选择好你的语言。这里作者使用的是C# 所以选择Java or C#\n在Output中，如果你需要输出chm格式，请勾选。\n在Diagrams中选择使用GraphViz包，来输出UML\nExpert选项卡：\n说明：编码格式，UTF-8 是首选。如果需要显示中文则选择GB2312.\nTAB_SIZE 主要是帮助文件中代码的缩进尺寸，譬如@code和@endcode段中代码的排版，建议设置成4。\nBuild页面，这个页面是生成帮助信息中比较关键的配置页面：\nEXTRACT_ALL 表示：输出所有的函数，但是private和static函数不属于其管制。\nEXTRACT_PRIVATE 表示：输出private函数。\nEXTRACT_STATIC 表示：输出static函数。同时还有几个EXTRACT，相应查看文档即可。\nSHOW_INCLUDE_FILES 表示：是否显示包含文件，如果开启，帮助中会专门生成一个页面，里面包含所有包含文件的列\n表。\nINLINE_INFO ：如果开启，那么在帮助文档中，inline函数前面会有一个inline修饰词来标明。\nSORT_MEMBER_DOCS ：如果开启，那么在帮助文档列表显示的时候，函数名称会排序，否则按照解释的顺序显\n示。\n说明：INPUT_ENCODING (输入的源文件的编码)，要与源文件的编码格式相同。如果源文件不是UTF-8编码最好转一下。\n总结：我查看到我的代码文件是utf-8的（vs2013中打开文件 选另存为可看到编码格式）（（VS2012的话）：文件-\u0026gt;高级保存选项)。\n在Expert的HTML中，首先要看HHC_LOCATION选项，添加安装目录（注：作者目录为C:/Program Files (x86)/HTML Help Workshop/hhc.exe）\n勾选CHM_INDEX_ENCODING，在你源代码中的字符集是什么就填写什么，\n之后在Expert的Dot中勾选CLASS_DIAGRAMS,UML_LOOK\n为了减少chm体积，在DOT_IMAGE_FORMAT中选择gif或者jpg，均可。 最后选择好DOT_PATH所输出的位置。 ![](http://img.blog.csdn.net/20150426150054043?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmlncHVkZGluZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 点击 Run doxygen 按钮， Doxygen 就会从源代码中抓取符合规范的注释生成你定制的格式的文档。 几个错误：Error: When enabling GENERATE_HTMLHELP the search engine (SEARCHENGINE) should be disabled. I\u0026amp;#8217;ll do it for you. warning: The selected output language \u0026amp;#8220;chinese\u0026amp;#8221; has not been updated since release 1.8.2. As a result some sentences may appear in English. 解决：把HTML里面的SEARCHENGINE设置为NO 接下来的工作就是学习 doxygen 的注释规范了，参考 《doxygen 快速入门》第 2 节 “常用注释语法”。慢慢的就可以体会到 doxygen 的方便性。 3、doxygen 的注释规范 并非所有程序代码中的批注都会被Doxygen 所处理。您必需依照正确的格式撰写。原则上，Doxygen 仅处理与程序结构相关的批注，如\nFunction，Class ，档案的批注等。对于Function内部的批注则不做处理。Doxygen可处理下面几种类型的批注。\nJavaDoc类型：\n/**\n* … 批注 …\n*/\nQt类型：\n/*!\n* … 批注 …\n*/\n单行型式的批注：\n/// … 批注 …\n或\n//! … 批注 …\n要使用哪种型态完全看自己的喜好。以笔者自己来说，大范围的注解我会使用JavaDoc 型的。单行的批注则使用”///” 的类型。\n此外，由于Doxygen 对于批注是视为在解释后面的程序代码。也就是说，任何一个批注都是在说明其后的程序代码。如果要批注前面的程\n式码则需用下面格式的批注符号。\n/*!\u0026lt; … 批注 … */\n/**\u0026lt; … 批注 … */\n//!\u0026lt; … 批注 …\n///\u0026lt; … 批注 …\n上面这个方式并不适用于任何地方，只能用在class 的member或是function的参数上。\n举例来说，若我们有下面这样的class。\nclass MyClass {\npublic:\nint member1 ;\nint member2:\nvoid member_function();\n};\n加上批注后，就变成这样：\n/**\n* 我的自订类别说明 …\n*/\nclass MyClass {\npublic:\nint member1 ; ///\u0026lt; 第一个member说明 …\nint member2: ///\u0026lt; 第二个member说明 …\nint member_function(int a, int b);\n};\n/**\n* 自订类别的member_funtion说明 …\n*\n* @param a 参数a的说明\n* @param b 参数b的说明\n*\n* @return 传回a+b。\n*/\nint MyClass::member_function( int a, int b )\n{\nreturn a+b ;\n}\n当您使用Doxygen 产生说明文档时，Doxygen 会帮您parsing 您的程式码。并且依据程序结构建立对应的文件。然后再将您的批注，依据其位置套入于正确的地方。您可能已经注意到，除了一般文字说明外，还有一些其它特别的指令，像是@param及@return 等。这正是Doxygen 另外一个重要的部分，因为一个类别或是函式其实都有固定几个要说明的部分。为了让Doxygen 能够判断，所有我们就必需使用这些指令，来告诉Doxygen 后面的批注是在说明什么东西。Doxygen 在处理时，就会帮您把这些部分做特别的处理或是排版。甚至是制作参考连结。\n首先，我们先说明在Doxygen 中对于类别或是函数批注的一个特定格式。\n/**\n* class或function的简易说明…\n*\n* class或function的详细说明…\n* …\n*/\n上面这个例子要说的是，在Doxygen 处理一个class 或是function注解时，会先判断第一行为简易说明。这个简易说明将一直到空一行的出现。或是遇到第一个”.” 为止。之后的批注将会被视为详细说明。两者的差异在于Doxygen 在某些地方只会显示简易说明，而不显示详细说明。如：class 或function的列表。\n另一种比较清楚的方式是指定@brief的指令。这将会明确的告诉Doxygen，何者是简易说明。例如：\n/**\n* @brief class或function的简易说明…\n*\n* class或function的详细说明…\n* …\n*/\n除了这个class 及function外，Doxygen 也可针对档案做说明，条件是该批注需置于档案的前面。主要也是利用一些指令，通常这部分注解都会放在档案的开始地方。如：\n/*! \\file myfile.h\n\\brief 档案简易说明\n详细说明.\n\\author 作者信息\n*/\n如您所见，档案批注约略格式如上，请别被”\u0026amp;#8221; 所搞混。其实，”\u0026amp;#8221; 与”@” 都是一样的，都是告诉Doxygen 后面是一个指令。两种在Doxygen 都可使用。笔者自己比较偏好使用”@”。\n接着我们来针对一些常用的指令做说明：\n@file \u0026lt;td valign=\u0026quot;top\u0026quot;\u0026gt; 档案的批注说明。 \u0026lt;/td\u0026gt; @author \u0026lt;td valign=\u0026quot;top\u0026quot;\u0026gt; 作者的信息 \u0026lt;/td\u0026gt; @brief \u0026lt;td valign=\u0026quot;top\u0026quot;\u0026gt; 用于class 或function的批注中，后面为class 或function的简易说明。 \u0026lt;/td\u0026gt; @param \u0026lt;td valign=\u0026quot;top\u0026quot;\u0026gt; 格式为 @param arg_name 参数说明 主要用于函式说明中，后面接参数的名字，然后再接关于该参数的说明。\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td valign=\u0026quot;top\u0026quot;\u0026gt; @return \u0026lt;/td\u0026gt; \u0026lt;td valign=\u0026quot;top\u0026quot;\u0026gt; 后面接函数传回值的说明。用于function的批注中。说明该函数的传回值。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td valign=\u0026quot;top\u0026quot;\u0026gt; @retval \u0026lt;/td\u0026gt; \u0026lt;td valign=\u0026quot;top\u0026quot;\u0026gt; 格式为 @retval value 传回值说明 主要用于函式说明中，说明特定传回值的意义。所以后面要先接一个传回值。然后在放该传回值的说明。\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; Doxygen 所支持的指令很多，有些甚至是关于输出排版的控制。您可从Doxygen的使用说明中找到详尽的说明。 下面我们准备一组example.h 及example.cpp 来说明Doxygen 批注的使用方式： example.h: /** * @file 本范例的include档案。 * * 这个档案只定义example这个class。 * * @author garylee@localhost */\n#define EXAMPLE_OK 0 ///\u0026lt; 定义EXAMPLE_OK的宏为0。 /** * @brief Example class的简易说明 * * 本范例说明Example class。 * 这是一个极为简单的范例。 * */ class Example { private: int var1 ; ///\u0026lt; 这是一个private的变数 public: int var2 ; ///\u0026lt; 这是一个public的变数成员。 int var3 ; ///\u0026lt; 这是另一个public的变数成员。 void ExFunc1(void); int ExFunc2(int a, char b); char *ExFunc3(char *c) ; };\nexample.cpp: /** * @file 本范例的程序代码档案。 * * 这个档案用来定义example这个class的 * member function。 * * @author garylee@localhost */\n/** * @brief ExFunc1的简易说明 * * ExFunc1没有任何参数及传回值。 */ void Example::ExFunc1(void) { // empty funcion. }\n/** * @brief ExFunc2的简易说明 * * ExFunc3()传回两个参数相加的值。 * * @param a 用来相加的参数。 * @param b 用来相加的参数。 * @return 传回两个参数相加的结果。 */ int ExFunc2(int a, char b) { return (a+b); }\n/** * @brief ExFunc3的简易说明 * * ExFunc3()只传回参数输入的指标。 * * @param c 传进的字符指针。 * @retval NULL 空字符串。 * @retval !NULL 非空字符串。 */ char * ExFunc2(char * c) { return c; }\n# 附：我的配置文件 ","permalink":"https://blog.zdltech.com/posts/doxygen-%E7%A8%8B%E5%BA%8F%E6%96%87%E6%A1%A3%E7%94%9F%E6%88%90%E5%B7%A5%E5%85%B7/","summary":"\u003carticle\u003e \n\u003cdiv id=\"article_content\" class=\"article_content clearfix csdn-tracking-statistics\" data-pid=\"blog\" data-mod=\"popu_307\" data-dsm=\"post\"\u003e\n  \u003cdiv class=\"htmledit_views\"\u003e\n\u003cpre\u003e\u003ccode\u003e  doxygen是一种从源代码生成文档的工具，支持多种语言。当然，源代码中需按一定的格式写注释，这些注释的格式也能帮助我们养成很好的注释习惯，可以尝试一下。\n\n\n\n\n\n  使用doxygen生成文档的方法很简单：\n\n\n\n**\n  \n\n    $ doxygen -g –s\n  \n\n  \n  \n\n    $ doxygen\n  \n\n\u0026lt;/blockquote\u0026gt;\n\n\n\n  只需两个简单命令就可以了。\n\n\n\n\n\n  下面简单说明一下：\n\n\n\n\n\n  1、在工程目录下输入doxygen –s –g doxyconfig，其中doxyconfig为生成配置的文件名称，可任意指定，如果不指定，默认生成的配置文件为Doxyfile。man手册中没有详细说明选项的意思，这里不妨猜测一下，-s为simple，-g为generate，如果不指定-s，则生成的配置文件大约为63KB，行数约1500左右；反之，则约成10KB，行数约250左右。——此处猜测便根据这些测试而来的。\n\n\n\n\n\n  2、生成配置文件后，会出现提示信息，大意是说那个配置文件已经生成了，现在编辑它，之后输入doxygen Doxyfile(经实践证明，可以只输入doxygen命令)就可以产生工程的文档了。如果再次使用doxygen生产配置文件，则原来的就配置文件就变成了备份文件，添加后缀名.bak。\n\n\n\n\n\n  3、根据doxygen要求的注释格式来编写代码的注释，这一步要求比较高，而且工作量比较大。我们在文章后面还要讲解的。\n\n\n\n\n\n  下面介绍一下如何编辑生成的配置文件，我们以我们的串口程序为例子。\n\n\n\n\n\n  \u0026amp;nbsp;\n\n\n\n\n\n  doxygen的配置文件与大多数linux平台的配置文件类似，就是一些关键字与值，配置文件中的值以YES和NO居多。\n\n\n\n\u0026lt;blockquote\u0026gt;\n  \n\n    DOXYFILE_ENCODING = UTF-8，默认编码为UTF-8，这样可以支持中文。\n  \n\n  \n  \n\n    PROJECT_NAME = “SerialPort”，项目名称，多个单词需要使用引号(“”)。\n  \n\n  \n  \n\n    PROJECT_NUMBER = “1.0 beta”，项目版本号。\n  \n\n  \n  \n\n    OUTPUT_DIRECTORY = serialport-html，输出文档的目录，如果为空，表示在当前目录，建议写上表示本工程的有意义的目录名称，比如我们就指定目录名称为serialport-html。\n  \n\n  \n  \n\n    OUTPUT_LANGUAGE = English，文档语言，可以指定为Chinese。\n  \n\n  \n  \n\n    IMAGE_PATH = image_dir，指定图片存放的目录，我们将图片放到当前目录下的image_dir目录中，因为我们的文档会出现测试图片示例。\n  \n\n  \n  \n\n    HTML_OUTPUT= . ，html输出目录名称，默认为html目录，如果为“.”则表明为上述OUTPUT_DIRECTORY目录。\n  \n\n  \n  \n\n    GENERATE_LATEX = NO，是否生成LaTeX，默认生成的，但我们不想生成。\n  \n\n  \n  \n\n    好了，我们需要修改的就这么多，使用上述第2步骤的命令就可以生成一个漂亮的文档了。此外还有一些常用的设置选项。\n  \n\n  \n  \n\n    INPUT =xxx，代码文件或目录，多个文件(目录)需要以空格隔开，如果不指定，表示当前目录，但是，如果指定目录且当前目录有代码文件的话，需要使用点号(“.”)表示当前目录。\n  \n\n  \n  \n\n    FILE_PATTERNS=xxx，指定各种文件，我们常用为*.cpp *.c *.h，等等。\n  \n\n\u0026lt;/blockquote\u0026gt;\n\n\n\n  上面基本就是我们常用的了，如果还想更深入了解，请移步到google网站。\n\n\n\n\n\n  下面就是真正需要花费一定时间的工作：为我们的程序作特定格式的注释。\n\n\n\n\n\n  doxygen支持多种注释风格，比如JavaDoc风格，它在C语言块注释开始处再添加一个星号(*)构成，如下：\n\n\n\n\u0026lt;div\u0026gt;\n  \n\n    1.           /**\n  \n\n  \n  \n\n    2.            * … text …\n  \n\n  \n  \n\n    3.            */\n  \n\n\u0026lt;/div\u0026gt;\n\n\n\n  Qt风格：\n\n\n\n\u0026lt;div\u0026gt;\n  ```\n1.           /*!\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t2.            * ... text ...\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e  ```\n3.            */\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      上面两种方式中间的星号(*)是可选的，不过，个人认为添加会更美观一些。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      C++风格的，——就是在C++注释后面再添加“/”：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t1.           ///\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e  ```\n2.           /// ... text ...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t3.           ///\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e\u0026lt;/div\u0026gt;\n\n\n\n  或者是这样：\n\n\n\n\u0026lt;div\u0026gt;\n  ```\n1.           //!\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t2.           //!... text ...\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e  ```\n3.           //!\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      经测试，实际使用中，如果是单行注释的话，可以使用如下的格式：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t1.           /** ... text ... */\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e  ```\n2.           /**\u0026amp;lt; ... text ... */\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      这些格式会被doxygen文档化，如果不想让它文档化，可以“破坏”这些格式，比如可以使用“正宗”的C/C++注释：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t1.           /* ... text ... */\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e  ```\n2.           // ... text ...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      上述风格来自doxygen的manual页面，具体地址为：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      [http://www.stack.nl/~dimitri/doxygen/docblocks.html](http://www.stack.nl/~dimitri/doxygen/docblocks.html)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      http://www.stack.nl/~dimitri/doxygen/index.html\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# 自定义文档首页\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# INPUT                  = README.md other_sources\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# USE_MDFILE_AS_MAINPAGE = README.md\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e  下面介绍一下常用doxygen的命令，更多详细使用说明，请参考如下地址：\n\n\n\n\n\n  [http://www.stack.nl/~dimitri/doxygen/commands.html#cmde](http://www.stack.nl/~dimitri/doxygen/commands.html#cmde)\n\n\n\n\n\n  doxygen命令以@或开始，两种方式均可以。文中以@标记之。\n\n\n\n\u0026lt;blockquote\u0026gt;\n  \n\n    @def 宏定义说明\n  \n\n  \n  \n\n    @fn 函数 函数说明\n  \n\n  \n  \n\n    @param 参数 参数说明\n  \n\n  \n  \n\n    @return 返回值说明(出错返回什么值，等等)\n  \n\n  \n  \n\n    @file 文件名\n  \n\n  \n  \n\n    @author 作者\n  \n\n  \n  \n\n    @version 程序版本\n  \n\n  \n  \n\n    @date 日期\n  \n\n  \n  \n\n    @note 注解(注意事项，等)\n  \n\n  \n  \n\n    @warning 警告信息\n  \n\n  \n  \n\n    @bug bug信息\n  \n\n  \n  \n\n    @test 测试示例、信息\n  \n\n  \n  \n\n    @todo 一些未完事宜\n  \n\n  \n  \n\n    (@bug、@test以及@todo等会出现链接页面)\n  \n\n  \n  \n\n    上面这样适合在函数、文件前面出现。\n  \n\n  \n  \n\n    下面为生成特殊字体的命令：\n  \n\n  \n  \n\n    @a @e @em：其后的单个字(word)表现为斜体，以强调作用。如有多个word的话，使用*xxx xxx*代替。\n  \n\n  \n  \n\n    @b：其后的word为粗体，多个则使用\u0026lt;b\u0026gt;xxx xxx**。\n  \n\n  \n  \n\n    @c @p：字体表现为打印机字体，多个则使用\u0026lt;tt\u0026gt;xxx xxx\u0026lt;/tt\u0026gt;。\n  \n\n\u0026lt;/blockquote\u0026gt;\n\n\n\n  ` `\n\n\n\n\n\n  `下面是一些具体的实例。 `\n\n\n\n\n\n  `在文件开始处的版权声明及其它信息：`\n\n\n\n**\n  \n\n    /**\n  \n\n  \n  \n\n    *                      Copyleft (C) 2010  Late Lee\n  \n\n  \n  \n\n    *        This program is tested on LINUX PLATFORM, WITH GCC 4.x.\n  \n\n  \n  \n\n    *        The program is distributed in the hope that it will be\n  \n\n  \n  \n\n    *        useful, but WITHOUT ANY WARRANTY. Please feel free to\n  \n\n  \n  \n\n    *        use the program, and I feel free to ignore the related\n  \n\n  \n  \n\n    *        issues. Any questions or suggestions, or bugs, please\n  \n\n  \n  \n\n    *        contact me at  or e-mail to\n  \n\n  \n  \n\n    *         if you want to do this.\n  \n\n  \n  \n\n    * @file   serialport.c\n  \n\n  \n  \n\n    * @author Late Lee\n  \n\n  \n  \n\n    * @date   Mon Jan 10 2011\n  \n\n  \n  \n\n    *\n  \n\n  \n  \n\n    * @brief  Some utils of the serial port, such as open the port, close\n  \n\n  \n  \n\n    *         the port and setup the port.\n  \n\n  \n  \n\n    * @note   This is a note.\n  \n\n  \n  \n\n    * @warning This is a warning.\n  \n\n  \n  \n\n    * @bug    This is a bug.\n  \n\n  \n  \n\n    */\n  \n\n\u0026lt;/blockquote\u0026gt;\n\n\n\n  \u0026amp;nbsp;\n\n\n\n\n\n  在函数前的注释：\n\n\n\n\n\n  \u0026amp;nbsp;\n\n\n\n\u0026lt;blockquote\u0026gt;\n  \n\n    /**\n  \n\n  \n  \n\n    * open_port – Open a serial port\n  \n\n  \n  \n\n    *\n  \n\n  \n  \n\n    * @param port : The port number, eg, open_port(1) will open com1\n  \n\n  \n  \n\n    *\n  \n\n  \n  \n\n    * @return Return fd if success, otherwise will return -1 with some msg.\n  \n\n  \n  \n\n    */\n  \n\n\u0026lt;/blockquote\u0026gt;\n\n\n\n  定义宏使用的注释：\n\n\n\n\u0026lt;blockquote\u0026gt;\n  \n\n    /**\n  \n\n  \n  \n\n    * @def error_exit\n  \n\n  \n  \n\n    * @brief A macro that prints the @a error msg and exit.\n  \n\n  \n  \n\n    */\n  \n\n  \n  \n\n    #define error_exit(error)\n  \n\n  \n  \n\n    do{\n  \n\n  \n  \n\n    fprintf(stderr, “%sn”, error);\n  \n\n  \n  \n\n    exit(0);\n  \n\n  \n  \n\n    } while(0)\n  \n\n\u0026lt;/blockquote\u0026gt;\n\n\n\n  \u0026amp;nbsp;\n\n\n\n\n\n  \u0026amp;nbsp;\n\n\n\n\n\n  或者你会说，这样的注释风格太麻烦了！不怕！现在有了跟emacs结合的doxymacs，在emacs中配置了doxymacs，这些注释是十分方便的！比如需要在文件前插入注释，按C-c d i即可，在函数前插入注释，按C-c d f即可，等等。具体的请移步到这里的文章：[http://www.latelee.org/embedded-linux/learning-elinux-4-my-emacs-ii](http://www.latelee.org/embedded-linux/learning-elinux-4-my-emacs-ii.html)及[http://www.latelee.org/embedded-linux/learning-elinux-4-my-emacs](http://www.latelee.org/embedded-linux/learning-elinux-4-my-emacs.html)。如果你使用的不是emacs，那Sorry，我也不太会，如果你懂，不妨分享一下。\n\n\n\n\n\n  这个串口程序的文档已经放到网站上了，这里main.c文件参考页面地址：[http://www.latelee.org/yetanothertest/serialport-html-cn/main_8c.html](http://www.latelee.org/yetanothertest/serialport-html-cn/main_8c.html)\n\n\n\n\n\n  此外，我们还测试生成中文文档，因此doxygen使用UTF8，因此只要将代码文件保存为utf8编码即可(使用Ultra Edit或notepad++等等编辑器很容易做到)。但这又引出一个问题，gcc并不支持utf8！经过google，发现gcc 4.4.0版本以后已经支持utf8了，因此，为了做这个测试，花了一个小时左右编译、安装高版本的gcc(我们使用4.4.5版本)，结果，这个版本的gcc是支持utf8的。后来，又发现，如果使用“UTF-8 无BOM格式编码”格式保存源文件的话，在原来的gcc下也编译通过。因此如果想在程序中使用中文注释，建议以此格式保存，当然，在系统的locale不是中文的情况下看到的中文是乱码的。\n\n\n\n\n\n  1、尽信书则不如无书，我们建议各位到实践中试一试，这样学到的知识才是我们自己的，比如，在指定源代码目录中，我的测试文件main.c放在当前目录下，如果不指定“.”的话，doxygen便不会处理该文件，这是网上很多资料没有说明的，因此需要实践才能了解。\n\n\n\n\n\n  2、我们强烈建议各位到官方网站学习，因为其它地方绝大部分都出自官方网站，manual页面地址是：\n\n\n\n\n\n  [http://www.stack.nl/~dimitri/doxygen/manual.html](http://www.stack.nl/~dimitri/doxygen/manual.html)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\u003c/article\u003e \n\u003cdiv class=\"article-bar-bottom\"\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Doxygen—程序文档生成工具"},{"content":"无论是写文章、做 PPT 还是找壁纸、换头像，搜图片都是件费时却最出效果的事情。之前小美给大家分享了最好用无版权图片网站之一的 Pixabay，不过图片素材这种东西，尤其是可自由修改使用的图片素材，向来是嫌少不嫌多的。所以这次，小美就把私藏的 60 余家无版权图片网站分享给大家，这家找不到合适的图片？没关系，下一家就有了！从此再也不会被找图这件事情所束缚。\n本次推荐分为第一找图梯队、第二找图梯队、精准找图、分门别类找图、备选方案以及最后的终极找图梯队组成。\n第一找图梯队 根据二八定律，80% 的结果可能来自于 20% 的原因。这在找图片这件事上也适用。虽然这次推荐的无版权图片网站有数十家，但是真正好用的也是只有一部分，而这一部分就足够使用了。\nUnsplash** 最知名的无版权图片网站，这家以风景为主，数量足够多，但是很多滤镜感太强，颜色太过厚重，比较适合做壁纸，事实上很多壁纸软件也是直接从这上面下载的图\nPixabay** 小美最常用的一家，可以说是全球最大的免费图片网站了。图多而且种类足够丰富。这其实也是一家集合网站，可以看到 Unsplash 家的很多图也能在 Pixabay 里搜到\nPexels** 这家也有很多精美的图片，而且比较好的一点是会有「一周精选」，平常没事的时候来收收图也挺好的\nvisualhunt** 数量超级多的无版权图片网站，可以根据颜色进行搜索\n第二找图梯队 这里面是一些图片资源没有那么丰富，但是质量都还不错的，如果之前的网站没有找到合适的，可以在这里再次搜寻一下。\n别样网** 找图新欢，旅行日常为主，图片多为用户自己上传，所以在其他地方很少见到\nGratisography** 每周都会更新，图片角度和题材都比较另类，人物图片不少，另外他家的 logo 也比较另类……\nStreetWill 优点是图片都比较精致小众，缺点是更新慢\nIM FREE** 图片分类详细，可按分类进行筛选\nMagdeleine** 有编辑精选，图片也比较厚重\nFancyCrave** 每天两张手工筛选精品照片，每张都在诉说一个故事\n精准找图梯队 一般搜索图片都是用关键词进行搜索，搜索单一的关键词还好，一旦稍复杂些的就很容易搜索不出来，这时候你就需要一些精准找图方案。\nFlickr** 第一个是雅虎著名的图片社区——Flickr，由于汇集了大批的摄影师，所以 Flickr 家的图片质量都相当之高，不过你可能会说 Flickr 的图片不都是有版权的吗？别急，在「授权」那里选择「所有创用CC」或者「允许商业用途」即可找到那些可以使用的图片啦\nps.由于 Flickr 目前没有简体中文版，所以搜索时用英文或者繁体中文会得到比较好的结果\nGoogle** 第二个是我大谷歌，谷歌的图片搜索那是相当的强大，选择右侧的「工具」，可以自定义很多东西，包括大小、颜色及使用权限\n分类找图 Life of Pix** 景色建筑为主，色调比较统一\npngimg 这个厉害了，2 万多张不同种类的无背景素材图片！全都是抠好图的，直接免费用！\nMoveast** 全部都是旅行风景图片\n旅行日记** 从名字就能看出来，主要是旅行题材的图片\nFoodiesFeed** 全是好吃的！全是免费的（图片）！\nSozai-Page** 日本的高清食物无背景素材图片\nPEEKSPACE** 超清的太空图片，大多来自 NASA\nkaboompics** 以生活化场景为主，比方说手机、日历之类的，也有一些 mockup\n泼辣有图** 泼辣修图出的开源摄影网站，全部是无版权的摄影作品\nOliur Rahman** 各种 iPhone、MacBook 和其他物件的好照片\nPixite Source** 出品了图像编辑应用 Union、涂色应用 Pigment、矢量制作工具 Assembly 等知名应用的 Pixite，出的一个图库网站，可以搜索图片、材质、色调搜索，里面有很多比较精致的小众插图\nFree Nature Stock** 如网站名，全部是自然风光图片\nNew Old Stock** 公共领域的一些老照片，可以免费使用\nFreely Photos** 很多十字架，很多宗教祈祷的图片\n备选方案 接下来这些就是上述都找不到的情况下的备选方案啦，多达XX个网站，不信没有合适的，哼。\n这些网站有的是因为图片质量参差不齐，有的是因为上述的网站已经能够解决需求，所以没怎么刷，大家平时有时间的时候可以多逛逛这些网站，收集一些素材。\nMMT** 色调比较亮丽，有很多花，也有很多 iPhone……\nRealistic Shots** 生活化场景为主，每周 7 张图片\nDesignerPics** 多为局部特写，也可按种类进行筛选\nStokpic** 有很多人物图片，每两周更新 10 张\nJÉSHOOTS** 2014 年开始运营的无版权图片网站，图片质量还不错\nISO REPUBLIC** 多走简洁风格\njay mantri** 个人博客网站，每周更新 7 张图片\npicjumbo** 日常场景居多，有不少数码设备\nZEROSPACE** 台湾的无版权图片网站，质量还行\npublic domain archive** 很多黑白照片，也有很多可供个人使用的无版权图片\nRAUMROT** 里面有很多可供商用的图片选集，在主页的底部\nFFCU** 图片数量不多，不过有一些好图\nStockSnap** 生活类图片，角度和主题都不错\nMy Stock Photos** 这里面的图片都挺好看的\nskuawk** 摄影师拍摄的无版权图片网站，分类浏览\nBARN IMAGES** 有很多比较生活化和小清新的图片\nfreejpg** 有一些动物的图片，可直接搜索，也可按照颜色搜索\nstockvault** 大部分为摄影作品，也有少量的插图\ngoodfreephotos** 1 万 8 千多张无版权图片，质量嘛，参差不齐……\nSnapwire Snaps** Tumblr 图片博客，以自然风景和食物为主\ntookapic** 63000+ 的无版权真实照片\nFREEMAGEBANK** 多为日常生活图片，另外简笔画的图质量也蛮高的\nCupcake** 图片色调厚实，适合做背景图\nTrunklog** 瑞典的一位摄影师旅行所拍摄的照片，全部无偿使用\n接下来介绍一些日本的无版权图片网站。\nPAKUTASO** 一看就知道是霓虹国的网站，稀奇古怪的图片一大堆，不过网站 logo 好萌……\nPhotock** 日本的无版权图片网站，在里面能很容易地找到富士山、樱花、东京等元素\n無料写真素材** 日本无版权图片，全部都是日式元素图片，红叶啊、樱花啊、猫啊啥的\nphotosku** 还是日本的，基本没用过……\n東京デート** 日本东京专门的无版权图片网站\n沖縄写真素材** 恩…日本冲绳专门的无版权图片网站…\nFutta** 日本无版权图片网站，基本为风景图片\nImgstyle** 如其描述：无料、商业利用可、加工自由、登录不要（全部都是高清植物图片）\nソザイング** 这家网站有个分类叫做「365日365枚」，就像一本无版权图片的日记本一样，里面有很多很有意思的图片，比方说纯蓝色的水彩、并立的企鹅、一颗土豆等\n终极图片合集 对于像小美这样的懒人来说，挨个网站去搜还是略麻烦，如果有集合类的网站就好了……\n……等会，谁说没有的？！\nThe Stocks** The Stocks 就是家无版权图片集合网站，集合了 Unsplash、Stocksy、Pixabay、Free Range、Little Visuals、New Old Stock、Visual Hunt、Super Famous、Startup Stock、GRATISOGRAPHY、GETREFE、PEXELS、jay mantri、Magdeleine、travel coffee、MOVEAST、Barn Images 一共 17 家图片网站，全部 CC0 协议！全部无版权免费使用！\n除了无版权图片外，The Stocks 里还有多家配色、图标、视频、手机/电脑外壳、字体等网站集合……想给这家网站捐钱！\n（不过由于是集合网站，所以刷新速度上可能会慢点，但这网站我依然给满分）\nAllTheFreeStock** 这个跟 Stocks 差不多，但却更加强大！一个地址，找到所有无版权图片、模型、视频、声效、配色、网页模板、字体、图标、邮件模板……\n简直就是懒人福音！\nEVERYPIXEL** 智能搜图工具，可以搜索各大图片网站的图片，并对齐进行精准化的分类。颜色、类型、尺寸、版权，而且可以九宫格单独设置……除了赞美，我无能为力\nLibreStock** 一键搜索 47 家无版权图片网站的精品好图\nFinda Photo** 一件搜索 Barn Images、Life Of Pix 等十余家的无版权图片，网站本身做得很简洁\n好啦，本次的无版权网站大推荐就到这里啦，愿大家都能快速找到自己需要的图片！\n转自：https://zhuanlan.zhihu.com/p/25980505?utm_medium=social\u0026amp;utm_source=qq?utm_medium=social\u0026amp;utm_source=qq\n","permalink":"https://blog.zdltech.com/posts/%E7%BB%99%E4%BD%A0-60-%E5%AE%B6%E5%85%8D%E8%B4%B9%E7%89%88%E6%9D%83%E5%9B%BE%E7%89%87%E7%BD%91%E7%AB%99%E4%BB%A5%E5%90%8E%E5%88%AB%E5%86%8D%E8%B7%9F%E6%88%91%E8%AF%B4%E6%89%BE%E4%B8%8D/","summary":"\u003cp\u003e无论是写文章、做 PPT 还是找壁纸、换头像，搜图片都是件费时却最出效果的事情。之前小美给大家分享了最好用无版权图片网站之一的 Pixabay，不过图片素材这种东西，尤其是可自由修改使用的图片素材，向来是嫌少不嫌多的。所以这次，小美就把私藏的 60 余家无版权图片网站分享给大家，这家找不到合适的图片？没关系，下一家就有了！从此再也不会被找图这件事情所束缚。\u003c/p\u003e\n\u003cp\u003e本次推荐分为第一找图梯队、第二找图梯队、精准找图、分门别类找图、备选方案以及最后的终极找图梯队组成。\u003c/p\u003e\n\u003ch4 id=\"第一找图梯队\"\u003e\u003cstrong\u003e第一找图梯队\u003c/strong\u003e\u003c/h4\u003e\n\u003cp\u003e根据二八定律，80% 的结果可能来自于 20% 的原因。这在找图片这件事上也适用。虽然这次推荐的无版权图片网站有数十家，但是真正好用的也是只有一部分，而这一部分就足够使用了。\u003c/p\u003e\n\u003ch4 id=\"unsplash\"\u003e\u003ca href=\"https://unsplash.com/\"\u003eUnsplash**\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e最知名的无版权图片网站，这家以风景为主，数量足够多，但是很多滤镜感太强，颜色太过厚重，比较适合做壁纸，事实上很多壁纸软件也是直接从这上面下载的图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://image.uisdc.com/images/2017/03/uisdc-pic-20170327-1.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"pixabay\"\u003e\u003ca href=\"https://pixabay.com/\"\u003ePixabay**\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e小美最常用的一家，可以说是全球最大的免费图片网站了。图多而且种类足够丰富。这其实也是一家集合网站，可以看到 Unsplash 家的很多图也能在 Pixabay 里搜到\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://image.uisdc.com/images/2017/03/uisdc-pic-20170327-2.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"pexels\"\u003e\u003ca href=\"https://www.pexels.com/\"\u003ePexels**\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e这家也有很多精美的图片，而且比较好的一点是会有「一周精选」，平常没事的时候来收收图也挺好的\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://image.uisdc.com/images/2017/03/uisdc-pic-20170327-3.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"visualhunt\"\u003e\u003ca href=\"https://visualhunt.com/\"\u003evisualhunt**\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e数量超级多的无版权图片网站，可以根据颜色进行搜索\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://image.uisdc.com/images/2017/03/uisdc-pic-20170327-4.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"第二找图梯队\"\u003e\u003cstrong\u003e第二找图梯队\u003c/strong\u003e\u003c/h4\u003e\n\u003cp\u003e这里面是一些图片资源没有那么丰富，但是质量都还不错的，如果之前的网站没有找到合适的，可以在这里再次搜寻一下。\u003c/p\u003e\n\u003ch4 id=\"别样网\"\u003e\u003ca href=\"http://www.ssyer.com/\"\u003e别样网**\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e找图新欢，旅行日常为主，图片多为用户自己上传，所以在其他地方很少见到\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://image.uisdc.com/images/2017/03/uisdc-pic-20170327-5.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"gratisography\"\u003e\u003ca href=\"http://www.gratisography.com/\"\u003eGratisography**\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e每周都会更新，图片角度和题材都比较另类，人物图片不少，另外他家的 logo 也比较另类……\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://image.uisdc.com/images/2017/03/uisdc-pic-20170327-6.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"streetwill\"\u003e\u003ca href=\"http://streetwill.co/\"\u003eStreetWill\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e优点是图片都比较精致小众，缺点是更新慢\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://image.uisdc.com/images/2017/03/uisdc-pic-20170327-7.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"im-free\"\u003e\u003ca href=\"http://imcreator.com/free\"\u003eIM FREE**\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e图片分类详细，可按分类进行筛选\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://image.uisdc.com/images/2017/03/uisdc-pic-20170327-8.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"magdeleine\"\u003e\u003ca href=\"http://magdeleine.co/browse/\"\u003eMagdeleine**\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e有编辑精选，图片也比较厚重\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://image.uisdc.com/images/2017/03/uisdc-pic-20170327-9.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"fancycrave\"\u003e\u003ca href=\"http://fancycrave.com/\"\u003eFancyCrave**\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e每天两张手工筛选精品照片，每张都在诉说一个故事\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://image.uisdc.com/images/2017/03/uisdc-pic-20170327-10.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"精准找图梯队\"\u003e\u003cstrong\u003e精准找图梯队\u003c/strong\u003e\u003c/h4\u003e\n\u003cp\u003e一般搜索图片都是用关键词进行搜索，搜索单一的关键词还好，一旦稍复杂些的就很容易搜索不出来，这时候你就需要一些精准找图方案。\u003c/p\u003e\n\u003ch4 id=\"flickr\"\u003e\u003ca href=\"https://www.flickr.com/\"\u003eFlickr**\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e第一个是雅虎著名的图片社区——Flickr，由于汇集了大批的摄影师，所以 Flickr 家的图片质量都相当之高，不过你可能会说 Flickr 的图片不都是有版权的吗？别急，在「授权」那里选择「所有创用CC」或者「允许商业用途」即可找到那些可以使用的图片啦\u003c/p\u003e\n\u003cp\u003eps.由于 Flickr 目前没有简体中文版，所以搜索时用英文或者繁体中文会得到比较好的结果\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://image.uisdc.com/images/2017/03/uisdc-pic-20170327-11.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"google\"\u003e\u003ca href=\"http://www.google.com/\"\u003eGoogle**\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e第二个是我大谷歌，谷歌的图片搜索那是相当的强大，选择右侧的「工具」，可以自定义很多东西，包括大小、颜色及使用权限\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://image.uisdc.com/images/2017/03/uisdc-pic-20170327-12.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"分类找图\"\u003e\u003cstrong\u003e分类找图\u003c/strong\u003e\u003c/h4\u003e\n\u003ch4 id=\"life-of-pix\"\u003e\u003ca href=\"http://www.lifeofpix.com/\"\u003eLife of Pix**\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e景色建筑为主，色调比较统一\u003c/p\u003e","title":"给你 60 家免费版权图片网站，以后别再跟我说找不到图了"},{"content":" 1、firewalld的基本使用 启动： systemctl start firewalld 查看状态： systemctl status firewalld 停止： systemctl disable firewalld 禁用： systemctl stop firewalld 2.systemctl是CentOS7的服务管理工具中主要的工具，它融合之前service和chkconfig的功能于一体。 启动一个服务：systemctl start firewalld.service 关闭一个服务：systemctl stop firewalld.service 重启一个服务：systemctl restart firewalld.service 显示一个服务的状态：systemctl status firewalld.service 在开机时启用一个服务：systemctl enable firewalld.service 在开机时禁用一个服务：systemctl disable firewalld.service 查看服务是否开机启动：systemctl is-enabled firewalld.service 查看已启动的服务列表：systemctl list-unit-files|grep enabled\n3.配置firewalld-cmd \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 那怎么开启一个端口呢 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 添加 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 重新载入 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 查看 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 删除 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/centos7%E4%BD%BF%E7%94%A8firewalld%E6%89%93%E5%BC%80%E5%85%B3%E9%97%AD%E9%98%B2%E7%81%AB%E5%A2%99%E4%B8%8E%E7%AB%AF%E5%8F%A3/","summary":"\u003cdiv\u003e\n  1、firewalld的基本使用\n\u003c/div\u003e\n\u003cdiv\u003e\n  启动： systemctl start firewalld\n\u003c/div\u003e\n\u003cdiv\u003e\n  查看状态： systemctl status firewalld\n\u003c/div\u003e\n\u003cdiv\u003e\n  停止： systemctl disable firewalld\n\u003c/div\u003e\n\u003cdiv\u003e\n  禁用： systemctl stop firewalld\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  2.systemctl是CentOS7的服务管理工具中主要的工具，它融合之前service和chkconfig的功能于一体。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e启动一个服务：systemctl start firewalld.service\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e关闭一个服务：systemctl stop firewalld.service\n重启一个服务：systemctl restart firewalld.service\n显示一个服务的状态：systemctl status firewalld.service\n在开机时启用一个服务：systemctl enable firewalld.service\n在开机时禁用一个服务：systemctl disable firewalld.service\n查看服务是否开机启动：systemctl is-enabled firewalld.service\n查看已启动的服务列表：systemctl list-unit-files|grep enabled\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e3.配置firewalld-cmd\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    \u003cdiv\u003e\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n    那怎么开启一个端口呢\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n    添加\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n    重新载入\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n    查看\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n    删除\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e","title":"CentOS7使用firewalld打开关闭防火墙与端口"},{"content":" 不支持HTML、没有 Dom。网页用的 JS、CSS 基本要全部重写，WXML 的语法和 HTML 差异还挺大，基本是一个个照着手册的属性去改。CSS 选择器不支持级联。\n小程序源码打包后的大小限制为1M，超大传不上去。单次通过 wx.request传输的数据最大也是1M。\nMINA 框架实现的 tab bar，最多5个 tab；通过 wx. navigateTo 推入后台的页面最多5层，超过会无法打开新页面。\n小程序没有 webview 控件，自带的 view 和 text 又不支持图文混排，还不能动态 set WXML …… 所以小程序上的富文本也就只能做到固定焦点图+纯文本+emoji了 [二哈]\n不支持 A 标签，无法打开普通网页。\n未经腾讯公司授权的情况下，微信小程序的添加，必须是免费的，不得设置付费添加。\n强制用户分享或关注：分享或关注后才能继续下一步操作。包括但不限于：分享或关注后方可解锁功能或能力，分享或关注后方查阅、下载图片或视频等。\n不得滥用模板消息和客服消息，包括但不限于利用模板消息和客服消息骚扰用户、广告营销、向用户发送与客服咨询无关的任何文案、图片。\n完成注册后，如帐号长期未登录，微信小程序可能被终止使用，终止使用后注册所使用的邮箱、身份证、微信号等信息可能将被取消注册状态。\n除个体工商户类型可认证5个小程序外，其他类型一个主体可认证50个小程序\n标签数量不得少于2个，最多不得超过5个，为确保点击区域，建议标签数量不超过4项\n绑定开发者\n\u0026gt; 登录微信公众平台小程序，进入用户身份- 开发者，新增绑定开发者。 \u0026gt; 个人主体小程序最多可绑定5个开发者，10个体验者。 \u0026gt; 未认证的组织类型小程序最多可绑定10个开发者，20个体验者 \u0026gt; 已认证的小程序最多可绑定20个开发者，40个体验者 \u0026gt; 代码大小限制2M以内（包括图片等所有资源）\n\u0026gt; 请问现在小程序代码支持多大？ \u0026gt; 采用分包，可以到 4 M \u0026gt;\nwx.setStorage(OBJECT) 小程序存储的容量有多大限制?目前每个小程序限制5M\n绑定开发者\n` 个人主体小程序最多可绑定5个开发者，10个体验者。 未认证的组织类型小程序最多可绑定10个开发者，20个体验者 已认证的小程序最多可绑定20个开发者，40个体验者。 ` 请求必须是https\n账号体系参考 没有限制说必须微信登录\n运营规范\nhttps://developers.weixin.qq.com/blogdetail?action=get_post_info\u0026amp;docid=0008ec49d849681c05866d9a957008\u0026amp;highline=%E4%B8%8A%E7%BA%BF%E5%A4%A7%E5%B0%8F\n开发 微信小程序转发 (辨别到群与个人、多个转发按钮、转发带参数)总结 ","permalink":"https://blog.zdltech.com/posts/wei-xin-xiao-cheng-xu-kai-fa-zong-jie/","summary":"\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e不支持HTML、没有 Dom。网页用的 JS、CSS 基本要全部重写，WXML 的语法和 HTML 差异还挺大，基本是一个个照着手册的属性去改。CSS 选择器不支持级联。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e小程序源码打包后的大小限制为1M，超大传不上去。单次通过 wx.request传输的数据最大也是1M。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eMINA 框架实现的 tab bar，最多5个 tab；通过 wx. navigateTo 推入后台的页面最多5层，超过会无法打开新页面。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e小程序没有 webview 控件，自带的 view 和 text 又不支持图文混排，还不能动态 set WXML …… 所以小程序上的富文本也就只能做到固定焦点图+纯文本+emoji了 [二哈]\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e不支持 A 标签，无法打开普通网页。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e未经腾讯公司授权的情况下，微信小程序的添加，必须是免费的，不得设置付费添加。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e强制用户分享或关注：分享或关注后才能继续下一步操作。包括但不限于：分享或关注后方可解锁功能或能力，分享或关注后方查阅、下载图片或视频等。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e不得滥用模板消息和客服消息，包括但不限于利用模板消息和客服消息骚扰用户、广告营销、向用户发送与客服咨询无关的任何文案、图片。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e完成注册后，如帐号长期未登录，微信小程序可能被终止使用，终止使用后注册所使用的邮箱、身份证、微信号等信息可能将被取消注册状态。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e除个体工商户类型可认证5个小程序外，其他类型一个主体可认证50个小程序\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e标签数量不得少于2个，最多不得超过5个，为确保点击区域，建议标签数量不超过4项\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e绑定开发者\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026gt;     登录微信公众平台小程序，进入用户身份- 开发者，新增绑定开发者。\n\u0026gt;     个人主体小程序最多可绑定5个开发者，10个体验者。\n\u0026gt;     未认证的组织类型小程序最多可绑定10个开发者，20个体验者\n\u0026gt;     已认证的小程序最多可绑定20个开发者，40个体验者\n\u0026gt;     \n\u003c/code\u003e\u003c/pre\u003e\n\u003col start=\"13\"\u003e\n\u003cli\u003e\n\u003cp\u003e代码大小限制2M以内（包括图片等所有资源）\u003cbr\u003e\n\u0026gt;     请问现在小程序代码支持多大？\n\u0026gt;     采用分包，可以到 4 M\n\u0026gt;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ewx.setStorage(OBJECT) 小程序存储的容量有多大限制?目前每个小程序限制5M\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e绑定开发者\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e个人主体小程序最多可绑定5个开发者，10个体验者。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e未认证的组织类型小程序最多可绑定10个开发者，20个体验者\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e已认证的小程序最多可绑定20个开发者，40个体验者。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e请求必须是https\u003c/p\u003e","title":"微信小程序开发总结"},{"content":" Doxygen 是一个开源跨平台的，以类似 JavaDoc 风格编写软件参考文檔的工具\nGetting started 创建配置文件\n`doxygen -g \u0026amp;lt;config-\u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;\u0026amp;gt;` 运行 doxygen\n`doxygen \u0026amp;lt;config-\u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;\u0026amp;gt;` Configuration 项目名称\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;PROJECT_NAME\u0026amp;lt;/span\u0026gt; = My Project` 项目简介\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;PROJECT_BRIEF\u0026amp;lt;/span\u0026gt; = What a project` 项目 Logo\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;PROJECT_LOGO\u0026amp;lt;/span\u0026gt; = src/images/logo.png` 主页面\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;USE_MDFILE_AS_MAINPAGE\u0026amp;lt;/span\u0026gt; = README.md` 文档的语言\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;OUTPUT_LANGUAGE\u0026amp;lt;/span\u0026gt; = Chinese` 指定需要生成文档的文件，以空格分割\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;INPUT\u0026amp;lt;/span\u0026gt; = ./src` 排除的文件\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;EXCLUDE\u0026amp;lt;/span\u0026gt; = .\u0026amp;lt;span class=\u0026#34;hljs-regexp\u0026#34;\u0026gt;/src/\u0026amp;lt;/span\u0026gt;Demo` 写入文档的路径\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;OUTPUT_DIRECTORY\u0026amp;lt;/span\u0026gt; = ./docs` 是否搜索子目录\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;RECURSIVE\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;YES\u0026amp;lt;/span\u0026gt;` 标记指定一个或多个通配符模式\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;EXCLUDE_PATTERNS\u0026amp;lt;/span\u0026gt; = */node_modules/*` 即使各个类或函数没有文档，也要提取信息\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;EXTRACT_ALL\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;YES\u0026amp;lt;/span\u0026gt;` 是否记录私有成员\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;EXTRACT_PRIVATE\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;YES\u0026amp;lt;/span\u0026gt;` 是否包含静态成员\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;EXTRACT_STATIC\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;YES\u0026amp;lt;/span\u0026gt;` 生成一个搜索框\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;SEARCHENGINE\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;YES\u0026amp;lt;/span\u0026gt;` 点工具\n`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;HAVE_DOT\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;YES\u0026amp;lt;/span\u0026gt;` 指定 graphviz 的路径\n`DOT_PATH` Output Formats HTML\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;GE\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-symbol\u0026#34;\u0026gt;NERATE_HTML\u0026amp;lt;/span\u0026gt;` HTML 帮助编译器\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;GE\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-symbol\u0026#34;\u0026gt;NERATE_HTMLHELP\u0026amp;lt;/span\u0026gt;` Special Commands brief details param return note 参考：http://cedar-renjun.github.io/2014/03/21/learn-doxygen-in-10-minutes/\nhttps://blog.csdn.net/u012247418/article/details/79719467\nhttp://www.ctex.org/HomePage\n","permalink":"https://blog.zdltech.com/posts/%E4%BD%BF%E7%94%A8-doxygen-%E7%94%9F%E6%88%90%E6%BA%90%E7%A0%81%E6%96%87%E6%A1%A3/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003ccode\u003eDoxygen\u003c/code\u003e 是一个开源跨平台的，以类似 \u003ccode\u003eJavaDoc\u003c/code\u003e 风格编写软件参考文檔的工具\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"articleHeader0\"\u003eGetting started\u003c/h2\u003e\n\u003cp\u003e创建配置文件\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`doxygen -g \u0026amp;lt;config-\u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;\u0026amp;gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e运行 doxygen\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`doxygen \u0026amp;lt;config-\u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;\u0026amp;gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"articleHeader1\"\u003eConfiguration\u003c/h2\u003e\n\u003cp\u003e项目名称\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;PROJECT_NAME\u0026amp;lt;/span\u0026gt; = My Project`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e项目简介\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;PROJECT_BRIEF\u0026amp;lt;/span\u0026gt; = What a project`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e项目 Logo\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;PROJECT_LOGO\u0026amp;lt;/span\u0026gt; = src/images/logo.png`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e主页面\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;USE_MDFILE_AS_MAINPAGE\u0026amp;lt;/span\u0026gt; = README.md`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e文档的语言\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;OUTPUT_LANGUAGE\u0026amp;lt;/span\u0026gt; = Chinese`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e指定需要生成文档的文件，以空格分割\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;INPUT\u0026amp;lt;/span\u0026gt; = ./src`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e排除的文件\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;EXCLUDE\u0026amp;lt;/span\u0026gt; = .\u0026amp;lt;span class=\u0026#34;hljs-regexp\u0026#34;\u0026gt;/src/\u0026amp;lt;/span\u0026gt;Demo`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e写入文档的路径\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;OUTPUT_DIRECTORY\u0026amp;lt;/span\u0026gt; = ./docs`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e是否搜索子目录\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;RECURSIVE\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-literal\u0026#34;\u0026gt;YES\u0026amp;lt;/span\u0026gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e标记指定一个或多个通配符模式\u003c/p\u003e","title":"使用 Doxygen 生成源码文档"},{"content":"在开发Android的过程中，我们会遇到各种问题，有时候为了满足某一个需求（或者快速的上线完成一个版本）， 我们会使用各种框架，代码编写可能随意一些，造成一些冗余的代码，整个工程越跑越慢，APP越跑越慢， 当达到一定阶段的时候，就不得不需要我们进行工程的优化，今天就来说说优化过程中使用到的工具。\nAndroid的应用性能的指标主要有： 布局复杂度：布局复杂会导致布局需要更长的时间，从而导致进入应用慢、页面切换慢； 耗电量：耗电量大会导致机器发热、缩短机器的有效使用时长； 内存：内存消耗大会导致频繁GC，GC时会暂停其它工作，导致页面卡顿；内存泄露会导致剩余可用内存越来越小；内存不足会导致应用异常； 网络：频繁的网络访问会导致耗电和影响应用的性能；网络交互数据大小会影响网络传输的效率； 程序执行效率：糟糕的代码会严重影响程序的运行效率，UI线程过多的任务会阻塞应用的正常运行，长时间持有某个对象会导致潜在的内存泄露，频繁的IO操作、网络操作而不用缓存会严重影响程序的运行效率。 工具 Memory Monitor：查看整个app所占用的内存，以及发生GC的时刻\nAllocation Tracker：使用此工具来追踪内存的分配。\nHeap Tool：查看当前内存快照，便于对比分析哪些对象有可能是泄漏了的。\nBattery History Tool 电量审查工具（Android 5.0，不属于编译器的工具）\ntraceview 工具（计算每个方法占用CPU时间）\nNetworking Traffic Tool （android studio）网络请求发生的时间，每次请求的数据量等信息\nHierarchy viewer 层级显示工具（检测布局复杂度，各视图的布局耗时情况）\nLint 代码审查工具 给出代码优化建议\n耗电量：Android开发者模式中的电量统计\nleakcanary：square/leakcanary · GitHub，通过集成到程序中的方式，在程序运行时检测应用中存在的内存泄露，并在页面中显示，在应用中集成leancanry后，程序运行时会存在卡顿的情况，这个是正常的，因为leancanry就是通过gc操作来检测内存泄露的，gc会知道应用卡顿，说明文档：LeakCanary 中文使用说明、LeakCanary: 让内存泄露无所遁形。\nGT：GT Home，GT是腾讯开发的一款APP的随身调测平台，利用GT，可以对CPU、内存、流量、点亮、帧率/流畅度进行测试，还可以查看开发日志、crash日志、抓取网络数据包、APP内部参数调试、真机代码耗时统计等等，需要说明的是，应用需要集成GT的sdk后，GT这个apk才能在应用运行时对各个性能进行检测。\niTest：iTest，业内首创的Android自动化性能监控工具，它能够记录特定应用的性能消耗情况，包括cpu、内存、流量、电量等信息，支持浮窗实时查看应用的具体信息，iTest不需要集成sdk到应用中，在itest中选中需要测试的应用即可进行测试；\nEmmagee：Emmagee下载、NetEase/Emmagee · GitHub，网易开发的性能检测工具，Emmage和iTest一样，不需要在应用中集成sdk，能够对应用的常用性能指标进行检测，并以csv的格式保存方便查看应用的各项参数\nAPT：Tencent/apt | CODE，腾讯出的。\nFPSService：百度一位开发者写的帧率测试工具，需要集成到应用中才可查看\nAndroidGodEye:AndroidGodEye是一个可以在PC浏览器中实时监控Android数据指标（比如性能指标，但是不局限于性能）的工具，你可以通过wifi/usb连接手机和pc，通过pc浏览器实时监控手机性能。\n系统分为三部分：\nCore 核心部分，提供所有模块; Debug Monitor部分，提供Debug阶段开发者面板; Toolbox 快速接入工具集，给开发者提供各种便捷接入的工具。\nAndroidGodEye提供了多种监控模块，比如cpu、内存、卡顿、内存泄漏等等，并且提供了Debug阶段的Monitor看板实时展示这 些数据。而且提供了api供开发者在release阶段进行数据上报。 慢慢一个个工具使用吧\n参考引用 https://blog.csdn.net/u010255127/article/details/49135551\nhttps://segmentfault.com/a/1190000012413613\n","permalink":"https://blog.zdltech.com/posts/android-you-hua-gong-ju-shou-ji/","summary":"\u003cp\u003e在开发Android的过程中，我们会遇到各种问题，有时候为了满足某一个需求（或者快速的上线完成一个版本），\n我们会使用各种框架，代码编写可能随意一些，造成一些冗余的代码，整个工程越跑越慢，APP越跑越慢，\n当达到一定阶段的时候，就不得不需要我们进行工程的优化，今天就来说说优化过程中使用到的工具。\u003c/p\u003e\n\u003ch3 id=\"toc_0\"\u003eAndroid的应用性能的指标主要有：\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e布局复杂度：布局复杂会导致布局需要更长的时间，从而导致进入应用慢、页面切换慢；\u003c/li\u003e\n\u003cli\u003e耗电量：耗电量大会导致机器发热、缩短机器的有效使用时长；\u003c/li\u003e\n\u003cli\u003e内存：内存消耗大会导致频繁GC，GC时会暂停其它工作，导致页面卡顿；内存泄露会导致剩余可用内存越来越小；内存不足会导致应用异常；\u003c/li\u003e\n\u003cli\u003e网络：频繁的网络访问会导致耗电和影响应用的性能；网络交互数据大小会影响网络传输的效率；\u003c/li\u003e\n\u003cli\u003e程序执行效率：糟糕的代码会严重影响程序的运行效率，UI线程过多的任务会阻塞应用的正常运行，长时间持有某个对象会导致潜在的内存泄露，频繁的IO操作、网络操作而不用缓存会严重影响程序的运行效率。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"toc_1\"\u003e工具\u003c/h3\u003e\n\u003cp\u003eMemory Monitor：查看整个app所占用的内存，以及发生GC的时刻\u003cbr\u003e\nAllocation Tracker：使用此工具来追踪内存的分配。\u003cbr\u003e\nHeap Tool：查看当前内存快照，便于对比分析哪些对象有可能是泄漏了的。\u003cbr\u003e\nBattery History Tool 电量审查工具（Android 5.0，不属于编译器的工具）\u003cbr\u003e\ntraceview 工具（计算每个方法占用CPU时间）\u003cbr\u003e\nNetworking Traffic Tool （android studio）网络请求发生的时间，每次请求的数据量等信息\u003cbr\u003e\nHierarchy viewer 层级显示工具（检测布局复杂度，各视图的布局耗时情况）\u003cbr\u003e\nLint 代码审查工具 给出代码优化建议\u003cbr\u003e\n耗电量：Android开发者模式中的电量统计\u003c/p\u003e\n\u003cp\u003eleakcanary：\u003ca href=\"https://github.com/square/leakcanary\"\u003esquare/leakcanary · GitHub\u003c/a\u003e，通过集成到程序中的方式，在程序运行时检测应用中存在的内存泄露，并在页面中显示，在应用中集成leancanry后，程序运行时会存在卡顿的情况，这个是正常的，因为leancanry就是通过gc操作来检测内存泄露的，gc会知道应用卡顿，说明文档：LeakCanary 中文使用说明、LeakCanary: 让内存泄露无所遁形。\u003c/p\u003e\n\u003cp\u003eGT：\u003ca href=\"http://gt.tencent.com/\"\u003eGT Home\u003c/a\u003e，GT是腾讯开发的一款APP的随身调测平台，利用GT，可以对CPU、内存、流量、点亮、帧率/流畅度进行测试，还可以查看开发日志、crash日志、抓取网络数据包、APP内部参数调试、真机代码耗时统计等等，需要说明的是，应用需要集成GT的sdk后，GT这个apk才能在应用运行时对各个性能进行检测。\u003c/p\u003e\n\u003cp\u003eiTest：\u003ca href=\"https://itest.iflytesting.com/%3Fp%3D1\"\u003eiTest\u003c/a\u003e，业内首创的Android自动化性能监控工具，它能够记录特定应用的性能消耗情况，包括cpu、内存、流量、电量等信息，支持浮窗实时查看应用的具体信息，iTest不需要集成sdk到应用中，在itest中选中需要测试的应用即可进行测试；\u003c/p\u003e\n\u003cp\u003eEmmagee：\u003ca href=\"https://github.com/NetEase/Emmagee\"\u003eEmmagee下载、NetEase/Emmagee · GitHub\u003c/a\u003e，网易开发的性能检测工具，Emmage和iTest一样，不需要在应用中集成sdk，能够对应用的常用性能指标进行检测，并以csv的格式保存方便查看应用的各项参数\u003c/p\u003e\n\u003cp\u003eAPT：\u003ca href=\"https://code.csdn.net/Tencent/apt\"\u003eTencent/apt | CODE\u003c/a\u003e，腾讯出的。\u003c/p\u003e\n\u003cp\u003eFPSService：百度一位开发者写的帧率测试工具，需要集成到应用中才可查看\u003c/p\u003e\n\u003cp\u003eAndroidGodEye:\u003ca href=\"https://github.com/Kyson/AndroidGodEye\"\u003eAndroidGodEye\u003c/a\u003e是一个可以在PC浏览器中实时监控Android数据指标（比如性能指标，但是不局限于性能）的工具，你可以通过wifi/usb连接手机和pc，通过pc浏览器实时监控手机性能。\u003cbr\u003e\n系统分为三部分：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eCore 核心部分，提供所有模块;\u003c/li\u003e\n\u003cli\u003eDebug Monitor部分，提供Debug阶段开发者面板;\u003c/li\u003e\n\u003cli\u003eToolbox 快速接入工具集，给开发者提供各种便捷接入的工具。\u003cbr\u003e\nAndroidGodEye提供了多种监控模块，比如cpu、内存、卡顿、内存泄漏等等，并且提供了Debug阶段的Monitor看板实时展示这 些数据。而且提供了api供开发者在release阶段进行数据上报。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cblockquote\u003e\n\u003cp\u003e慢慢一个个工具使用吧\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch4 id=\"toc_2\"\u003e参考引用\u003c/h4\u003e\n\u003cp\u003e\u003ca href=\"https://blog.csdn.net/u010255127/article/details/49135551\"\u003ehttps://blog.csdn.net/u010255127/article/details/49135551\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"https://segmentfault.com/a/1190000012413613\"\u003ehttps://segmentfault.com/a/1190000012413613\u003c/a\u003e\u003c/p\u003e","title":"Android 优化工具收集"},{"content":"作者寄语 很久之前就想写一个专题，专写Android开发框架，专题的名字叫 XXX 从入门到放弃 ，沉淀了这么久，看过网络诸多大神的博客，静下心来开始写这个专题，为什么叫入门到放弃呢；相信大家学习新框架的时候，尤其是像Rxjava或者Dagger等等这种新的编程思想；需要一定的阅读理解能力和思维逻辑；那么本专题旨在帮助大家不要太过急功近利，不要被冗长的代码和文章，晦涩的思想所打败，相信大家只要坚持看完，一定会有所收获的；废话不多说，那么这个专题开篇就以RxJava来讲吧，预计后面还会有几篇大型框架的讲解，想想还有点小激动；\n友情提示：文章较长，请耐心看完；\n前言 RxJava等编程思想正在Android开发者中变的越来越流行。唯一的问题就是上手不容易，尤其是大部分人之前都是使用命令式编程语言。\n首先要先理清这么一个问题：Rxjava和我们平时写的程序有什么不同。相信稍微对Rxjava有点认知的朋友都会深深感受到用这种方式写的程序和我们一般写的程序有很明显的不同。我们一般写的程序 统称为命令式程序，是以流程为核心的，每一行代码实际上都是机器实际上要执行的指令。而Rxjava这样的编程风格，称为函数响应式编程。函数响应式编程是以数据流为核心，处理数据的输入，处理以及输出的。这种思路写出来的代码就会跟机器实际执行的指令大相径庭。所以对于已经习惯命令式编程的我们来说，刚开始接触Rxjava的时候必然会很不适应，而且也不太符合我们平时的思维习惯。但是久而久之你会发现这个框架的精髓，尤其是你运用到大项目中的时候，简直爱不释手，随着程序逻辑变得越来越复杂，它依然能够保持代码简洁。\nRxJava是什么 a library for composing asynchronous and event-based programs using observable sequences for the Java VM\n解释：一个对于构成使用的Java虚拟机观察序列异步和基于事件的程序库\nRxJava 是一个响应式编程框架，采用观察者设计模式。所以自然少不了 Observable 和 Subscriber 这两个东东了。\nRxJava 是一个开源项目，地址：https://github.com/ReactiveX/RxJava\nRxAndroid，用于 Android 开发，添加了 Android 用的接口。地址： https://github.com/ReactiveX/RxAndroid\n基本概念 网上关于RxJava的博文也有很多，我也看过许多，其中不乏有优秀的文章，但绝大部分文章都有一个共同点，就是侧重于讲RxJava中各种强大的操作符，而忽略了最基本的东西——概念，所以一开始我也看的一脸懵逼，看到后面又忘了前面的，脑子里全是问号，这个是什么，那个又是什么，这两个长得怎么那么像。举个不太恰当的例子，概念之于初学者，就像食物之于人，当你饿了，你会想吃面包、牛奶，那你为什么不去吃土呢，因为你知道面包牛奶是用来干嘛的，土是用来干嘛的。同理，前面已经说过，RxJava无非是发送数据与接收数据，那么什么是发射源，什么是接收源，这就是你应该明确的事，也是RxJava的入门条件之一，下面就依我个人理解，对发射源和接收源做个归类，以及RxJava中频繁出现的几个“单词”解释一通;\nObservable：发射源，英文释义“可观察的”，在观察者模式中称为“被观察者”或“可观察对象”； Observer：接收源，英文释义“观察者”，没错！就是观察者模式中的“观察者”，可接收Observable、Subject发射的数据； Subject：Subject是一个比较特殊的对象，既可充当发射源，也可充当接收源，为避免初学者被混淆，本章将不对Subject做过多的解释和使用，重点放在Observable和Observer上，先把最基本方法的使用学会，后面再学其他的都不是什么问题； Subscriber：“订阅者”，也是接收源，那它跟Observer有什么区别呢？Subscriber实现了Observer接口，比Observer多了一个最重要的方法unsubscribe( )，用来取消订阅，当你不再想接收数据了，可以调用unsubscribe( )方法停止接收，Observer 在 subscribe() 过程中,最终也会被转换成 Subscriber 对象，一般情况下，建议使用Subscriber作为接收源； Subscription ：Observable调用subscribe( )方法返回的对象，同样有unsubscribe( )方法，可以用来取消订阅事件； Action0：RxJava中的一个接口，它只有一个无参call（）方法，且无返回值，同样还有Action1，Action2…Action9等，Action1封装了含有 1 个参的call（）方法，即call（T t），Action2封装了含有 2 个参数的call方法，即call（T1 t1，T2 t2），以此类推； Func0：与Action0非常相似，也有call（）方法，但是它是有返回值的，同样也有Func0、Func1…Func9; RxJava最核心的两个东西是Observables（被观察者，事件源）和Subscribers（观察者）。Observables发出一系列事件，Subscribers处理这些事件。这里的事件可以是任何你感兴趣的东西（触摸事件，web接口调用返回的数据…）\n一个Observable可以发出零个或者多个事件，知道结束或者出错。每发出一个事件，就会调用它的Subscriber的onNext方法，最后调用Subscriber.onCompleted()或者Subscriber.onError()结束。\nRxjava的看起来很想设计模式中的观察者模式，但是有一点明显不同，那就是如果一个Observerble没有任何的的Subscriber，那么这个Observable是不会发出任何事件的。\n基本用法 Observable的创建 使用create( ),最基本的创建方式：\n``` 1 2 3 4 5 6 ``` \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` myObservable = Observable.create(new Observable.OnSubscribe() {\n@Override\npublic void call(Subscriber\u0026lt;? super String\u0026gt; subscriber) {\nsubscriber.onNext(\u0026amp;quot;Hello, world!\u0026amp;quot;); //发射一个\u0026amp;quot;Hello, world!\u0026amp;quot;的String subscriber.onCompleted();//发射完成,这种方法需要手动调用onCompleted，才会回调Observer的onCompleted方法 }});\n\u0026quot; data-snippet-id=\u0026ldquo;ext.6f0f68f15b946479de4712f099778d42\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Observable\u0026lt;String\u0026gt; myObservable = Observable.create(new Observable.OnSubscribe\u0026lt;String\u0026gt;() { @Override public void call(Subscriber\u0026lt;? super String\u0026gt; subscriber) { subscriber.onNext(\u0026ldquo;Hello, world!\u0026quot;); //发射一个\u0026quot;Hello, world!\u0026ldquo;的String subscriber.onCompleted();//发射完成,这种方法需要手动调用onCompleted，才会回调Observer的onCompleted方法 }});\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 可以看到，这里传入了一个 `OnSubscribe` 对象作为参数。`OnSubscribe` 会被存储在返回的 `Observable` 对象中，它的作用相当于一个计划表，当 `Observable` 被订阅的时候，`OnSubscribe` 的 `call()` 方法会自动被调用，事件序列就会依照设定依次触发（对于上面的代码，就是观察者`Subscriber`将会被调用一次 onNext() 和一次 onCompleted()）。这样，由被观察者调用了观察者的回调方法，就实现了由被观察者向观察者的事件传递，即`观察者模式`。 这个例子很简单：事件的内容是字符串，而不是一些复杂的对象；事件的内容是已经定好了的，而不像有的观察者模式一样是待确定的（例如网络请求的结果在请求返回之前是未知的）；所有事件在一瞬间被全部发送出去，而不是夹杂一些确定或不确定的时间间隔或者经过某种触发器来触发的。总之，这个例子看起来毫无实用价值。但这是为了便于说明，实质上只要你想，各种各样的事件发送规则你都可以自己来写。至于具体怎么做，后面都会讲到，但现在不行。只有把基础原理先说明白了，上层的运用才能更容易说清楚。 * * * ### Subscriber的创建 {#Subscriber的创建} 上面定义的`Observable`对象仅仅发出一个Hello World字符串，然后就结束了。接着我们创建一个`Subscriber`来处理`Observable`对象发出的字符串：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` mySubscriber = new Subscriber() {\n@Override public void onNext(String s) { System.out.println(s); //打印出\u0026amp;quot;Hello, world!\u0026amp;quot; } @Override public void onCompleted() { } @Override public void onError(Throwable e) { } };\n\u0026quot; data-snippet-id=\u0026ldquo;ext.392f4ad40c761715fa14ca49992ae111\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Subscriber\u0026lt;String\u0026gt; mySubscriber = new Subscriber\u0026lt;String\u0026gt;() { @Override public void onNext(String s) { System.out.println(s); //打印出\u0026quot;Hello, world!\u0026quot; } @Override public void onCompleted() { } @Override public void onError(Throwable e) { } };\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 除了 `Observer` 接口之外，RxJava 还内置了一个实现了 `Observer` 的抽象类：`Subscriber`。 `Subscriber` 对 `Observer` 接口进行了一些扩展，但他们的基本使用方式是完全一样的：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` myObserver = new Observer() {\n@Override public void onNext(String s) { System.out.println(s); //打印出\u0026amp;quot;Hello, world!\u0026amp;quot; } @Override public void onCompleted() { } @Override public void onError(Throwable e) { } };\n\u0026quot; data-snippet-id=\u0026ldquo;ext.3402ab10e4b9c2012a8eb06419869d62\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Observer\u0026lt;String\u0026gt; myObserver = new Observer\u0026lt;String\u0026gt;() { @Override public void onNext(String s) { System.out.println(s); //打印出\u0026quot;Hello, world!\u0026quot; } @Override public void onCompleted() { } @Override public void onError(Throwable e) { } };\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 不仅基本使用方式一样，实质上，在 `RxJava` 的 `subscribe` 过程中，`Observer` 也总是会先被转换成一个 `Subscriber` 再使用。所以如果你只想使用基本功能，选择 `Observer` 和 `Subscriber`是`完全一样`的。它们的区别对于使用者来说主要有两点： 1. `onStart()`: 这是 `Subscriber` 增加的方法。它会在 subscribe 刚开始，而事件还未发送之前被调用，可以用于做一些准备工作，例如数据的清零或重置。这是一个可选方法，默认情况下它的实现为空。需要注意的是，如果对准备工作的线程有要求（例如弹出一个显示进度的对话框，这必须在主线程执行），`onStart()` 就不适用了，因为它总是在 `subscribe` 所发生的线程被调用，而不能指定线程。要在指定的线程来做准备工作，可以使用 `doOnSubscribe()`方法，具体可以在后面的文中看到。 2. `unsubscribe()`: 这是 `Subscriber` 所实现的另一个接口 `Subscription` 的方法，用于取消订阅。在这个方法被调用后，`Subscriber` 将不再接收事件。一般在这个方法调用前，可以使用 `isUnsubscribed()` 先判断一下状态。 `unsubscribe()` 这个方法很重要，因为在 subscribe() 之后， `Observable` 会持有 `Subscriber` 的引用，这个引用如果不能及时被释放，将有内存泄露的风险。所以最好保持一个原则：要在不再使用的时候尽快在合适的地方（例如 onPause() onStop() 等方法中）调用 unsubscribe() 来解除引用关系，以避免内存泄露的发生。 * * * ### Observable与Subscriber的关联 {#Observable与Subscriber的关联} 这里`subscriber`仅仅就是打印`observable`发出的字符串。通过`subscribe`函数就可以将我们定义的`myObservable`对象和`mySubscriber`对象关联起来，这样就完成了`subscriber`对`observable`的订阅。 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; myObservable.subscribe(myObserver); // 或者： myObservable.subscribe(mySubscriber); 一旦`mySubscriber`订阅了`myObservable`，`myObservable`就是调用`mySubscriber`对象的`onNext`和`onComplete`方法，`mySubscriber` 就会打印出Hello World！ ### 订阅（Subscriptions） {#订阅（Subscriptions）} 当调用`Observable.subscribe()`，会返回一个`Subscription`对象。这个对象代表了被观察者和订阅者之间的联系。\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` System.out.println(s));\n\u0026quot; data-snippet-id=\u0026ldquo;ext.b71e95e3bd4be7ff504a72b04194a069\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Subscription subscription = Observable.just(\u0026ldquo;Hello, World!\u0026quot;) .subscribe(s -\u0026gt; System.out.println(s));\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 你可以在后面使用这个`Subscription`对象来操作被观察者和订阅者之间的联系.\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` subscription.unsubscribe();//接触订阅关系 System.out.println(\u0026ldquo;Unsubscribed=\u0026quot; + subscription.isUnsubscribed()); // Outputs \u0026ldquo;Unsubscribed=true\u0026rdquo;\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; RxJava的另外一个好处就是它处理`unsubscribing`的时候，会停止整个调用链。如果你使用了一串很复杂的操作符，调用`unsubscribe`将会在他当前执行的地方终止。不需要做任何额外的工作！ * * * ### 简化代码（Observable与Subscriber） {#简化代码（Observable与Subscriber）} #### 简化`Observable`： {#简化Observable：} 是不是觉得仅仅为了打印一个hello world要写这么多代码太啰嗦？我这里主要是为了展示RxJava背后的原理而采用了这种比较啰嗦的写法，RxJava其实提供了很多便捷的函数来帮助我们减少代码。 首先来看看如何简化`Observable`对象的创建过程。RxJava内置了很多简化创建`Observable`对象的函数，比如`Observable.just`就是用来创建只发出一个事件就结束的`Observable`对象，上面创建`Observable`对象的代码可以简化为一行： \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; myObservable = Observable.just(\u0026quot;Hello, world!\u0026quot;); //发送\u0026quot;Hello, world!\u0026quot; \u0026quot; data-snippet-id=\u0026ldquo;ext.88d9b532ef3eb7adf0d46d0dfacb1604\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Observable\u0026amp;lt;String\u0026amp;gt; myObservable = Observable.just(\u0026quot;Hello, world!\u0026quot;); //发送\u0026quot;Hello, world!\u0026quot; 其他方法： 1.使用just( )，将为你创建一个Observable并自动为你调用onNext( )发射数据： \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; justObservable = Observable.just(\u0026quot;just1\u0026quot;,\u0026quot;just2\u0026quot;);//依次发送\u0026quot;just1\u0026quot;和\u0026quot;just2\u0026quot; 2.使用from( )，遍历集合，发送每个item： \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; list = new ArrayList\u0026lt;\u0026gt;(); list.add(\u0026quot;from1\u0026quot;); list.add(\u0026quot;from2\u0026quot;); list.add(\u0026quot;from3\u0026quot;); fromObservable = Observable.from(list); //遍历list 每次发送一个 /** 注意，just()方法也可以传list，但是发送的是整个list对象，而from（）发送的是list的一个item** / \u0026quot; data-snippet-id=\u0026ldquo;ext.b967679a423f704078fbb21ee1719d92\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;List\u0026amp;lt;String\u0026amp;gt; list = new ArrayList\u0026amp;lt;\u0026amp;gt;(); list.add(\u0026quot;from1\u0026quot;); list.add(\u0026quot;from2\u0026quot;); list.add(\u0026quot;from3\u0026quot;); fromObservable = Observable.from(list); //遍历list 每次发送一个 /** 注意，just()方法也可以传list，但是发送的是整个list对象，而from（）发送的是list的一个item** / 3.使用defer( )，有观察者订阅时才创建Observable，并且为每个观察者创建一个新的Observable： \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; () { @Override //注意此处的call方法没有Subscriber参数 public Observable call() { return Observable.just(\u0026quot;deferObservable\u0026quot;); }}); \u0026quot; data-snippet-id=\u0026ldquo;ext.556ce830172ffb195b7b59f933829978\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;deferObservable = Observable.defer(new Func0\u0026amp;lt;Observable\u0026amp;lt;String\u0026amp;gt;\u0026amp;gt;() { @Override //注意此处的call方法没有Subscriber参数 public Observable\u0026amp;lt;String\u0026amp;gt; call() { return Observable.just(\u0026quot;deferObservable\u0026quot;); }}); 4.使用interval( ),创建一个按固定时间间隔发射整数序列的Observable，可用作定时器： \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; intervalObservable = Observable.interval(1, TimeUnit.SECONDS);//每隔一秒发送一次 5.使用range( ),创建一个发射特定整数序列的Observable，第一个参数为起始值，第二个为发送的个数，如果为0则不发送，负数则抛异常： \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; rangeObservable = Observable.range(10, 5);//将发送整数10，11，12，13，14 6.使用timer( ),创建一个Observable，它在一个给定的延迟后发射一个特殊的值，等同于Android中Handler的postDelay( )方法： \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; timeObservable = Observable.timer(3, TimeUnit.SECONDS); //3秒后发射一个值 7.使用repeat( ),创建一个重复发射特定数据的Observable: \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; repeatObservable = Observable.just(\u0026quot;repeatObservable\u0026quot;).repeat(3);//重复发射3次 #### 简化`Subscriber`： {#简化Subscriber：} 接下来看看如何简化Subscriber，上面的例子中，我们其实并不关心OnComplete和OnError，我们只需要在onNext的时候做一些处理，这时候就可以使用Action1类。\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` onNextAction = new Action1() {\n@Override public void call(String s) { System.out.println(s); } };\n\u0026quot; data-snippet-id=\u0026ldquo;ext.6b4432f3e6ccc551929d1094da1b4c22\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Action1\u0026lt;String\u0026gt; onNextAction = new Action1\u0026lt;String\u0026gt;() { @Override public void call(String s) { System.out.println(s); } };\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; `subscribe`方法有一个重载版本，接受三个Action1类型的参数，分别对应OnNext，OnComplete， OnError函数: \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; myObservable.subscribe(onNextAction, onErrorAction, onCompleteAction); 这里我们并不关心onError和onComplete，所以只需要第一个参数就可以 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; myObservable.subscribe(onNextAction); // Outputs \u0026quot;Hello, world!\u0026quot; 上面的代码最终可以写成这样:\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` () {\n@Override public void call(String s) { System.out.println(s); } }); \u0026quot; data-snippet-id=\u0026ldquo;ext.10dd2d796490253cb675df1d2b992575\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Observable.just(\u0026ldquo;Hello, world!\u0026quot;) .subscribe(new Action1\u0026lt;String\u0026gt;() { @Override public void call(String s) { System.out.println(s); } });\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 使用java8的[lambda][1]可以使代码更简洁: \u0026gt; 不熟悉Lambda的可以看我之前写的：[Java8之Lambda表达式(Android用法)][1]\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` System.out.println(s));\n\u0026quot; data-snippet-id=\u0026ldquo;ext.08610b1e5f26297dc4fb248624b40867\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Observable.just(\u0026ldquo;Hello, world!\u0026quot;) .subscribe(s -\u0026gt; System.out.println(s));\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 简单解释一下这段代码中出现的 `Action1` 和 `Action0`。 `Action0` 是 `RxJava` 的一个接口，它只有一个方法 `call()`，这个方法是无参无返回值的；由于 `onCompleted()` 方法也是无参无返回值的，因此 `Action0` 可以被当成一个包装对象，将 `onCompleted()` 的内容打包起来将自己作为一个参数传入 `subscribe()` 以实现不完整定义的回调。这样其实也可以看做将`onCompleted()` 方法作为参数传进了 subscribe()，相当于其他某些语言中的『闭包』。 `Action1` 也是一个接口，它同样只有一个方法 call(T param)，这个方法也无返回值，但有一个参数；与 `Action0` 同理，由于 `onNext(T obj)` 和 `onError(Throwable error)`也是单参数无返回值的，因此 Action1 可以将 onNext(obj) 和 `onError(error)` 打包起来传入 subscribe() 以实现不完整定义的回调。事实上，虽然 Action0 和 Action1 在 API 中使用最广泛，但 `RxJava` 是提供了多个 `ActionX` 形式的接口 (例如 Action2, Action3) 的，它们可以被用以包装不同的无返回值的方法。 注：正如前面所提到的，`Observer` 和 `Subscriber` 具有相同的角色，而且 `Observer` 在 `subscribe()` 过程中最终会被转换成 `Subscriber` 对象，因此，从这里开始，后面的描述我将用 `Subscriber` 来代替 `Observer` ，这样更加严谨。 ## 操作符(Operators) {#操作符-Operators} 操作符就是为了解决对Observable对象的 `变换`(关键词) 的问题，操作符用于在Observable和最终的Subscriber之间修改Observable发出的事件。RxJava提供了很多很有用的操作符。 比如map操作符，就是用来把把一个事件转换为另一个事件的。 ### map()操作符： {#map-操作符：}\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` () {\n@Override public Bitmap call(String filePath) { // 参数类型 String return getBitmapFromPath(filePath); // 返回类型 Bitmap } }) .subscribe(new Action1\u0026lt;Bitmap\u0026gt;() { @Override public void call(Bitmap bitmap) { // 参数类型 Bitmap showBitmap(bitmap); } }); \u0026quot; data-snippet-id=\u0026ldquo;ext.6d786ffa93ee4d871f5da8faa1ce249c\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Observable.just(\u0026ldquo;images/logo.png\u0026rdquo;) // 输入类型 String .map(new Func1\u0026lt;String, Bitmap\u0026gt;() { @Override public Bitmap call(String filePath) { // 参数类型 String return getBitmapFromPath(filePath); // 返回类型 Bitmap } }) .subscribe(new Action1\u0026lt;Bitmap\u0026gt;() { @Override public void call(Bitmap bitmap) { // 参数类型 Bitmap showBitmap(bitmap); } });\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 使用`lambda`可以简化为:\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` getBitmapFromPath(filePath); // 返回类型 Bitmap\n) .subscribe( bitmap -\u0026gt; showBitmap(bitmap); ); \u0026quot; data-snippet-id=\u0026ldquo;ext.5767f6f1dd8f73d57e01c05f7158ce56\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Observable.just(\u0026ldquo;images/logo.png\u0026rdquo;) // 输入类型 String .map( filePath -\u0026gt; getBitmapFromPath(filePath); // 返回类型 Bitmap ) .subscribe( bitmap -\u0026gt; showBitmap(bitmap); );\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 可以看到，`map()` 方法将参数中的 `String` 对象转换成一个 `Bitmap` 对象后返回，而在经过 `map()` 方法后，事件的参数类型也由 `String` 转为了 `Bitmap`。这种直接变换对象并返回的，是最常见的也最容易理解的变换。不过 `RxJava` 的变换远不止这样，它不仅可以针对事件对象，还可以针对整个事件队列，这使得 `RxJava` 变得非常灵活。 `map()`操作符进阶：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` s.hashCode())\n.map(i -\u0026gt; Integer.toString(i)) .subscribe(s -\u0026gt; System.out.println(s)); \u0026quot; data-snippet-id=\u0026ldquo;ext.f303a1db9e9f51832d1137c8e39612cd\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Observable.just(\u0026ldquo;Hello, world!\u0026quot;) .map(s -\u0026gt; s.hashCode()) .map(i -\u0026gt; Integer.toString(i)) .subscribe(s -\u0026gt; System.out.println(s));\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 是不是很酷？`map()`操作符就是用于变换`Observable`对象的，map操作符返回一个`Observable`对象，这样就可以实现`链式调用`，在一个Observable对象上`多次`使用map操作符，最终将最简洁的数据传递给`Subscriber`对象。 ### flatMap()操作符： {#flatMap-操作符：} 假设我有这样一个方法： 这个方法根据输入的字符串返回一个网站的url列表 Observable\u0026lt;List\u0026lt;String\u0026gt;\u0026gt; query(String text); Observable.flatMap()接收一个Observable的输出作为输入，同时输出另外一个Observable。直接看代码：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` , Observable\u0026gt;() {\n@Override public Observable\u0026lt;String\u0026gt; call(List\u0026lt;String\u0026gt; urls) { return Observable.from(urls); } }) .subscribe(url -\u0026gt; System.out.println(url)); \u0026quot; data-snippet-id=\u0026ldquo;ext.40593b18e38e05ac8183192461033277\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;query(\u0026ldquo;Hello, world!\u0026quot;) .flatMap(new Func1\u0026lt;List\u0026lt;String\u0026gt;, Observable\u0026lt;String\u0026gt;\u0026gt;() { @Override public Observable\u0026lt;String\u0026gt; call(List\u0026lt;String\u0026gt; urls) { return Observable.from(urls); } }) .subscribe(url -\u0026gt; System.out.println(url));\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 这里我贴出了整个的函数代码，以方便你了解发生了什么，使用lambda可以大大简化代码长度：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` Observable.from(urls))\n.subscribe(url -\u0026gt; System.out.println(url)); \u0026quot; data-snippet-id=\u0026ldquo;ext.c6573d7dbbe1b8aa574a0f69afe358a8\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;query(\u0026ldquo;Hello, world!\u0026quot;) .flatMap(urls -\u0026gt; Observable.from(urls)) .subscribe(url -\u0026gt; System.out.println(url));\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; `flatMap()`是不是看起来很奇怪？为什么它要返回另外一个`Observable`呢？理解`flatMap`的关键点在于，`flatMap`输出的新的`Observable`正是我们在`Subscriber`想要接收的。现在`Subscriber`不再收到`List\u0026lt;String\u0026gt;`，而是收到一些列`单个`的字符串，就像`Observable.from()`的输出一样。 `flatMap()` 和`map()`有一个相同点：它也是把传入的参数转化之后返回另一个对象。但需要注意，和 `map()` 不同的是， `flatMap()` 中返回的是个 `Observable` 对象，并且这个 `Observable` 对象并不是被直接发送到了 `Subscriber` 的回调方法中。`flatMap()` 的原理是这样的： 1. 使用传入的事件对象创建一个 `Observable` 对象； 2. 并不发送这个 `Observable`, 而是将它激活，于是它开始发送事件； 3. 每一个创建出来的 `Observable` 发送的事件，都被汇入同一个 `Observable` ，而这个 `Observable` 负责将这些事件统一交给 `Subscriber` 的回调方法。这三个步骤，把事件拆成了两级，通过一组新创建的 `Observable` 将初始的对象`『铺平』`之后通过统一路径分发了下去。而这个`『铺平』`就是 `flatMap()` 所谓的 `flat`。 值得注意的是`.from()`是Observable创建时候用的，`.flatMap()`才是操作符； ### 其他操作符： {#其他操作符：} 目前为止，我们已经接触了两个操作符，RxJava中还有更多的操作符，那么我们如何使用其他的操作符来改进我们的代码呢？ \u0026gt; 更多RxJava的操作符请查看：[RxJava操作符大全](http://blog.csdn.net/maplejaw_/article/details/52396175) `getTitle()`返回null如果url不存在。我们不想输出”null”，那么我们可以从返回的title列表中过滤掉null值！\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` Observable.from(urls))\n.flatMap(url -\u0026gt; getTitle(url)) .filter(title -\u0026gt; title != null) .subscribe(title -\u0026gt; System.out.println(title)); \u0026quot; data-snippet-id=\u0026ldquo;ext.bddbc8369a63a12d1041bd64632fafbc\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;query(\u0026ldquo;Hello, world!\u0026quot;) .flatMap(urls -\u0026gt; Observable.from(urls)) .flatMap(url -\u0026gt; getTitle(url)) .filter(title -\u0026gt; title != null) .subscribe(title -\u0026gt; System.out.println(title));\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; `filter()`输出和输入相同的元素，并且会过滤掉那些不满足检查条件的。 如果我们只想要最多5个结果：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` Observable.from(urls))\n.flatMap(url -\u0026gt; getTitle(url)) .filter(title -\u0026gt; title != null) .take(5) .subscribe(title -\u0026gt; System.out.println(title)); \u0026quot; data-snippet-id=\u0026ldquo;ext.bf2be14f52f7a938405ff62439a28892\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;query(\u0026ldquo;Hello, world!\u0026quot;) .flatMap(urls -\u0026gt; Observable.from(urls)) .flatMap(url -\u0026gt; getTitle(url)) .filter(title -\u0026gt; title != null) .take(5) .subscribe(title -\u0026gt; System.out.println(title));\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; `take()`输出最多指定数量的结果。 如果我们想在打印之前，把每个标题保存到磁盘：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` Observable.from(urls))\n.flatMap(url -\u0026gt; getTitle(url)) .filter(title -\u0026gt; title != null) .take(5) .doOnNext(title -\u0026gt; saveTitle(title)) .subscribe(title -\u0026gt; System.out.println(title)); \u0026quot; data-snippet-id=\u0026ldquo;ext.92a12e631702ebcbee18d622a29e4c29\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;query(\u0026ldquo;Hello, world!\u0026quot;) .flatMap(urls -\u0026gt; Observable.from(urls)) .flatMap(url -\u0026gt; getTitle(url)) .filter(title -\u0026gt; title != null) .take(5) .doOnNext(title -\u0026gt; saveTitle(title)) .subscribe(title -\u0026gt; System.out.println(title));\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; `doOnNext()`允许我们在每次输出一个元素之前做一些额外的事情，比如这里的保存标题。 看到这里操作数据流是多么简单了么。你可以添加任意多的操作，并且不会搞乱你的代码。 `RxJava`包含了大量的操作符。操作符的数量是有点吓人，但是很值得你去挨个看一下，这样你可以知道有哪些操作符可以使用。弄懂这些操作符可能会花一些时间，但是一旦弄懂了，你就完全掌握了`RxJava`的威力。 感觉如何？ 好吧，你是一个怀疑主义者，并且还很难被说服，那为什么你要关心这些操作符呢？ 因为操作符可以让你对数据流做任何操作。 将一系列的操作符链接起来就可以完成复杂的逻辑。代码被分解成一系列可以组合的片段。这就是`响应式函数编程`的魅力。用的越多，就会越多的改变你的编程思维。 ## 线程控制(Scheduler) {#线程控制-Scheduler} 假设你编写的`Android app`需要从网络请求数据。网络请求需要花费较长的时间，因此你打算在另外一个线程中加载数据。那么问题来了！ 编写多线程的`Android`应用程序是很难的，因为你必须确保代码在正确的线程中运行，否则的话可能会导致`app`崩溃。最常见的就是在非主线程更新UI。 在不指定线程的情况下， `RxJava` 遵循的是线程不变的原则，即：在哪个线程调用 `subscribe()`，就在哪个线程生产事件；在哪个线程生产事件，就在哪个线程消费事件。如果需要切换线程，就需要用到 `Scheduler` （调度器）。 使用RxJava，你可以使用`subscribeOn()`指定观察者代码运行的线程，使用`observerOn()`指定订阅者运行的线程 ### Scheduler 的 API {#Scheduler-的-API} 在RxJava 中，`Scheduler` ——调度器，相当于线程控制器，`RxJava` 通过它来指定每一段代码应该运行在什么样的线程。`RxJava` 已经内置了几个 `Scheduler` ，它们已经适合大多数的使用场景： * Schedulers.immediate(): 直接在当前线程运行，相当于不指定线程。这是默认的 Scheduler。 * Schedulers.newThread(): 总是启用新线程，并在新线程执行操作。 * Schedulers.io(): I/O 操作（读写文件、读写数据库、网络信息交互等）所使用的 Scheduler。行为模式和 newThread() 差不多，区别在于 io() 的内部实现是是用一个无数量上限的线程池，可以重用空闲的线程，因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中，可以避免创建不必要的线程。 * Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算，即不会被 I/O 等操作限制性能的操作，例如图形的计算。这个 Scheduler 使用的固定的线程池，大小为 CPU 核数。不要把 I/O 操作放在 computation() 中，否则 I/O 操作的等待时间会浪费 CPU。 * 另外， Android 还有一个专用的 AndroidSchedulers.mainThread()，它指定的操作将在 Android 主线程运行。 有了以上这几个 `Scheduler` ，就可以使用 `subscribeOn()` 和 `observeOn()` 两个方法来对线程进行控制了。 * subscribeOn(): 指定 `subscribe()` 所发生的线程，即 `Observable.OnSubscribe` 被激活时所处的线程。或者叫做事件产生的线程。 * observeOn(): 指定 `Subscriber` 所运行在的线程。或者叫做事件消费的线程。 注意：`observeOn()` 指定的是 `Subscriber` 的线程，而这个 `Subscriber` 并不一定是 `subscribe()` 参数中的 `Subscriber`（这块参考RxJava变换部分），而是 `observeOn()` 执行时的当前 `Observable` 所对应的 `Subscriber` ，即它的直接**下级** `Subscriber` 。 换句话说，`observeOn()` 指定的是它之后的操作所在的线程。因此如果有多次切换线程的需求，只要在每个想要切换线程的位置调用一次 `observeOn()` 即可。 代码示例：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` () {\n@Override public void call(Integer number) { Log.d(tag, \u0026amp;quot;number:\u0026amp;quot; + number); } }); \u0026quot; data-snippet-id=\u0026ldquo;ext.6cc8ec0224da030dbbe3e37d90b1f4a1\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Observable.just(1, 2, 3, 4) .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程 .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程 .subscribe(new Action1\u0026lt;Integer\u0026gt;() { @Override public void call(Integer number) { Log.d(tag, \u0026ldquo;number:\u0026quot; + number); } });\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 上面这段代码中，由于 `subscribeOn(Schedulers.io())` 的指定，被创建的事件的内容 1、2、3、4 将会在 `IO` 线程发出； 而由于 `observeOn(AndroidScheculers.mainThread())` 的指定，因此 `subscriber` 数字的打印将发生在`主线程` 。 事实上，这种在 `subscribe()` 之前写上两句`subscribeOn(Scheduler.io())` 和 `observeOn(AndroidSchedulers.mainThread())` 的使用方式非常常见，它适用于多数的 `『后台线程取数据，主线程显示』`的程序策略。 下面的实例，在`Observable.OnSubscribe`的`call()`中模拟了长时间获取数据过程，在`Subscriber`的`noNext()`中显示数据到UI。\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;18\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;19\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;20\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;21\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;22\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;23\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;24\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;25\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;26\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;27\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;28\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;29\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;32\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;33\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` () {\n@Override public void call(Subscriber\u0026lt;? super String\u0026gt; subscriber) { subscriber.onNext(\u0026amp;quot;info1\u0026amp;quot;); SystemClock.sleep(2000); subscriber.onNext(\u0026amp;quot;info2-sleep 2s\u0026amp;quot;); SystemClock.sleep(3000); subscriber.onNext(\u0026amp;quot;info2-sleep 3s\u0026amp;quot;); SystemClock.sleep(5000); subscriber.onCompleted(); } })\n.subscribeOn(Schedulers.io()) //指定 subscribe() 发生在 IO 线程\n.observeOn(AndroidSchedulers.mainThread()) //指定 Subscriber 的回调发生在主线程\n.subscribe(new Subscriber() {\n@Override public void onCompleted() { Log.v(TAG, \u0026amp;quot;onCompleted()\u0026amp;quot;); } @Override public void onError(Throwable e) { Log.v(TAG, \u0026amp;quot;onError() e=\u0026amp;quot; + e); } @Override public void onNext(String s) { showInfo(s); //UI view显示数据 } });\n\u0026quot; data-snippet-id=\u0026ldquo;ext.c714863b6ca770d6061f427c10ac9326\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Observable.create(new Observable.OnSubscribe\u0026lt;String\u0026gt;() { @Override public void call(Subscriber\u0026lt;? super String\u0026gt; subscriber) { subscriber.onNext(\u0026ldquo;info1\u0026rdquo;);\nSystemClock.sleep(2000); subscriber.onNext(\u0026ldquo;info2-sleep 2s\u0026rdquo;);\nSystemClock.sleep(3000); subscriber.onNext(\u0026ldquo;info2-sleep 3s\u0026rdquo;);\nSystemClock.sleep(5000); subscriber.onCompleted(); } }) .subscribeOn(Schedulers.io()) //指定 subscribe() 发生在 IO 线程 .observeOn(AndroidSchedulers.mainThread()) //指定 Subscriber 的回调发生在主线程 .subscribe(new Subscriber\u0026lt;String\u0026gt;() { @Override public void onCompleted() { Log.v(TAG, \u0026ldquo;onCompleted()\u0026quot;); }\n@Override public void onError(Throwable e) { Log.v(TAG, \u0026ldquo;onError() e=\u0026quot; + e); }\n@Override public void onNext(String s) { showInfo(s); //UI view显示数据 } });\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 至此，我们可以看到`call()`将会发生在 IO 线程，而`showInfo(s)`则被设定在了主线程。这就意味着，即使加载`call()`耗费了几十甚至几百毫秒的时间，也不会造成丝毫界面的卡顿。 值得注意：`subscribeOn ()` 与 `observeOn()`都会返回了一个**新**的`Observable`，因此若不是采用上面这种直接流方式，而是分步调用方式，需要将新返回的`Observable`赋给原来的`Observable`，否则线程调度将不会起作用。 [![](http://s9.rr.itc.cn/r/wapChange/20171_22_18/a29dkz1448365256619.jpeg)](http://s9.rr.itc.cn/r/wapChange/20171_22_18/a29dkz1448365256619.jpeg) 使用下面方式，最后发现“OnSubscribe”还是在默认线程中运行；原因是subscribeOn这类操作后，返回的是一个新的Observable。\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` observable.subscribeOn(Schedulers.io()); observable.observeOn(AndroidSchedulers.mainThread()); observable .subscribe(subscribe);\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 可以修改为下面两种方式：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` observable = observable.subscribeOn(Schedulers.io()); observable = observable.observeOn(AndroidSchedulers.mainThread()); observable .subscribe(subscribe); //OR observable.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subscribe);\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 前面讲到了，可以利用 `subscribeOn()` 结合 `observeOn()` 来实现线程控制，让事件的产生和消费发生在不同的线程。可是在了解了 `map()` `flatMap()` 等变换方法后，有些好事的（其实就是当初刚接触 RxJava 时的我）就问了：能不能多切换几次线程？ 答案是：能。 因为 `observeOn()` 指定的是 `Subscriber` 的线程，而这个 `Subscriber` 并不是（严格说应该为『不一定是』，但这里不妨理解为『不是』）`subscribe()` 参数中的 `Subscriber` ，而是 `observeOn()` 执行时的当前 `Observable` 所对应的 `Subscriber` ，即它的直接下级 `Subscriber` 。换句话说，`observeOn()` 指定的是它之后的操作所在的线程。因此如果有多次切换线程的需求，只要在每个想要切换线程的位置调用一次 `observeOn()` 即可。上代码：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` Observable.just(1, 2, 3, 4) // IO 线程，由 subscribeOn() 指定 .subscribeOn(Schedulers.io()) .observeOn(Schedulers.newThread()) .map(mapOperator) // 新线程，由 observeOn() 指定 .observeOn(Schedulers.io()) .map(mapOperator2) // IO 线程，由 observeOn() 指定 .observeOn(AndroidSchedulers.mainThread) .subscribe(subscriber); // Android 主线程，由 observeOn() 指定\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 如上，通过 observeOn() 的多次调用，程序实现了线程的多次切换。 不过，不同于 `observeOn()` ， `subscribeOn()` 的位置放在哪里都可以，但它是只能调用一次的。 又有好事的（其实还是当初的我）问了：如果我非要调用多次 `subscribeOn()` 呢？会有什么效果？ 这个问题先放着，我们还是从 `RxJava` 线程控制的原理说起吧。 ### Scheduler 的原理 {#Scheduler-的原理} 其实， `subscribeOn()` 和 `observeOn()` 的内部实现，也是用的 `lift()`。具体看图（不同颜色的箭头表示不同的线程）： `subscribeOn()`原理图： [![](http://ww4.sinaimg.cn/mw1024/52eb2279jw1f2rxcynbsuj20ha0d7wg2.jpg)](http://ww4.sinaimg.cn/mw1024/52eb2279jw1f2rxcynbsuj20ha0d7wg2.jpg) `observeOn()` 原理图： [![](http://ww4.sinaimg.cn/mw1024/52eb2279jw1f2rxd05lttj20hj0cyabl.jpg)](http://ww4.sinaimg.cn/mw1024/52eb2279jw1f2rxd05lttj20hj0cyabl.jpg) 从图中可以看出，`subscribeOn()` 和 `observeOn()` 都做了线程切换的工作（图中的 “schedule…” 部位）。不同的是， `subscribeOn()` 的线程切换发生在 `OnSubscribe` 中，即在它通知上一级 `OnSubscribe` 时，这时事件还没有开始发送，因此 `subscribeOn()` 的线程控制可以从事件发出的开端就造成影响；而 `observeOn()` 的线程切换则发生在它内建的 `Subscriber` 中，即发生在它即将给下一级 `Subscriber` 发送事件时，因此 `observeOn()` 控制的是它后面的线程。 最后，我用一张图来解释当多个 `subscribeOn()` 和 `observeOn()` 混合使用时，线程调度是怎么发生的（由于图中对象较多，相对于上面的图对结构做了一些简化调整）： [![](http://ww1.sinaimg.cn/mw1024/52eb2279jw1f2rxd1vl7xj20hd0hzq6e.jpg)](http://ww1.sinaimg.cn/mw1024/52eb2279jw1f2rxd1vl7xj20hd0hzq6e.jpg) 图中共有 5 处含有对事件的操作。由图中可以看出，①和②两处受第一个 `subscribeOn()` 影响，运行在红色线程；③和④处受第一个 `observeOn()` 的影响，运行在绿色线程；⑤处受第二个 `onserveOn()` 影响，运行在紫色线程；而第二个 `subscribeOn()` ，由于在通知过程中线程就被第一个 `subscribeOn()` 截断，因此对整个流程并没有任何影响。这里也就回答了前面的问题：当使用了**多个** `subscribeOn()` 的时候，只有**第一个** `subscribeOn()` 起作用。 ### 延伸：doOnSubscribe() {#延伸：doOnSubscribe} \u0026gt; `doOnSubscribe()`一般用于执行一些初始化操作. 然而，虽然超过一个的 `subscribeOn()` 对事件处理的流程没有影响，但在流程之前却是可以利用的。 在前面讲 `Subscriber` 的时候，提到过 `Subscriber` 的 `onStart()` 可以用作流程开始前的初始化。然而 `onStart()` 由于在 `subscribe()` 发生时就被调用了，因此不能指定线程，而是只能执行在 `subscribe()` 被调用时的线程。这就导致如果 `onStart()` 中含有对线程有要求的代码（例如在界面上显示一个 `ProgressBar`，这必须在主线程执行），将会有线程非法的风险，因为有时你无法预测 `subscribe()` 将会在什么线程执行。 而与 `Subscriber.onStart()` 相对应的，有一个方法 `Observable.doOnSubscribe()` 。它和 `Subscriber.onStart()` 同样是在 `subscribe()` 调用后而且在事件发送前执行，但区别在于它可以指定线程。默认情况下， `doOnSubscribe()` 执行在 `subscribe()` 发生的线程；而如果在 `doOnSubscribe()` 之后有 `subscribeOn()` 的话，它将执行在离它最近的 `subscribeOn()` 所指定的线程。 示例：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` Observable.create(onSubscribe) .subscribeOn(Schedulers.io()) .doOnSubscribe(new Action0() { @Override public void call() { progressBar.setVisibility(View.VISIBLE); // 需要在主线程执行 } }) .subscribeOn(AndroidSchedulers.mainThread()) // 指定主线程 .observeOn(AndroidSchedulers.mainThread()) .subscribe(subscriber);\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 如上，在 `doOnSubscribe()` 的后面跟一个 `subscribeOn()` ，就能指定准备工作的线程了。 ## RxJava 的适用场景和使用方式 {#RxJava-的适用场景和使用方式} ### RxJava + Retrofit {#RxJava-Retrofit} \u0026gt; Retrofit 是 Square 的一个著名的网络请求库。对于`Retrofit`不了解的同学 \u0026gt; 可以参考我之前写的文章：[全新的网络加载框架Retrofit2，上位的小三][2] `Retrofit` 除了提供了传统的 `Callback` 形式的 `API`，还有 `RxJava` 版本的 `Observable` 形式 `API`。下面我用对比的方式来介绍 `Retrofit` 的 `RxJava` 版 `API` 和传统版本的区别。 以获取一个 `MovieEntity` 对象的接口作为例子。使用`Retrofit` 的传统 API，你可以用这样的方式来定义请求：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` getTopMovie(@Query(\u0026quot;start\u0026quot;) int start, @Query(\u0026quot;count\u0026quot;) int count);//正常返回Call对象\n\u0026quot; data-snippet-id=\u0026ldquo;ext.bb25c5750a1be5a2a0bb3bbf0b4008e1\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;@GET(\u0026ldquo;top250\u0026rdquo;) Call\u0026lt;MovieEntity\u0026gt; getTopMovie(@Query(\u0026ldquo;start\u0026rdquo;) int start, @Query(\u0026ldquo;count\u0026rdquo;) int count);//正常返回Call对象\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 我们来写`getMovie`方法的代码:\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;18\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;19\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;20\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;21\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;22\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;23\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` call = movieService.getTopMovie(0, 10);\ncall.enqueue(new Callback\u0026lt;MovieEntity\u0026gt;() { @Override public void onResponse(Call\u0026lt;MovieEntity\u0026gt; call, Response\u0026lt;MovieEntity\u0026gt; response) { resultTV.setText(response.body().toString()); } @Override public void onFailure(Call\u0026lt;MovieEntity\u0026gt; call, Throwable t) { resultTV.setText(t.getMessage()); } }); }\n\u0026quot; data-snippet-id=\u0026ldquo;ext.8b67ad7559bbfbd0e78348e0944ba727\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;//进行网络请求 private void getMovie(){ String baseUrl = \u0026ldquo;https://api.douban.com/v2/movie/\u0026quot;;\nRetrofit retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .build();\nMovieService movieService = retrofit.create(MovieService.class); Call\u0026lt;MovieEntity\u0026gt; call = movieService.getTopMovie(, 10); call.enqueue(new Callback\u0026lt;MovieEntity\u0026gt;() { @Override public void onResponse(Call\u0026lt;MovieEntity\u0026gt; call, Response\u0026lt;MovieEntity\u0026gt; response) { resultTV.setText(response.body().toString()); }\n@Override public void onFailure(Call\u0026lt;MovieEntity\u0026gt; call, Throwable t) { resultTV.setText(t.getMessage()); } }); }\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 以上为没有经过封装的、原生态的`Retrofit`写网络请求的代码。 而使用 `RxJava` 形式的 `API`，定义同样的请求是这样的：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` getTopMovie(@Query(\u0026quot;start\u0026quot;) int start, @Query(\u0026quot;count\u0026quot;) int count);//RxJava返回Observable对象\n\u0026quot; data-snippet-id=\u0026ldquo;ext.f43f3ef3e57e2bf5909d8a6e6313d47b\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;@GET(\u0026ldquo;top250\u0026rdquo;) Observable\u0026lt;MovieEntity\u0026gt; getTopMovie(@Query(\u0026ldquo;start\u0026rdquo;) int start, @Query(\u0026ldquo;count\u0026rdquo;) int count);//RxJava返回Observable对象\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; `Retrofit`本身对`Rxjava`提供了支持，`getMovie`方法改为：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;18\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;19\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;20\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;21\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;22\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;23\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;24\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;25\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;26\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;27\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;28\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;29\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;32\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` () {\n@Override public void onCompleted() { Toast.makeText(MainActivity.this, \u0026amp;quot;Get Top Movie Completed\u0026amp;quot;, Toast.LENGTH_SHORT).show(); } @Override public void onError(Throwable e) { resultTV.setText(e.getMessage()); } @Override public void onNext(MovieEntity movieEntity) { resultTV.setText(movieEntity.toString()); } }); }\n\u0026quot; data-snippet-id=\u0026ldquo;ext.41512327707f0b44328dd730239e0432\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;//进行网络请求 private void getMovie(){ String baseUrl = \u0026ldquo;https://api.douban.com/v2/movie/\u0026quot;;\nRetrofit retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//提供RXjava支持 .build();\nMovieService movieService = retrofit.create(MovieService.class);\nmovieService.getTopMovie(, 10)//返回Observable对象 .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber\u0026lt;MovieEntity\u0026gt;() { @Override public void onCompleted() { Toast.makeText(MainActivity.this, \u0026ldquo;Get Top Movie Completed\u0026rdquo;, Toast.LENGTH_SHORT).show(); }\n@Override public void onError(Throwable e) { resultTV.setText(e.getMessage()); }\n@Override public void onNext(MovieEntity movieEntity) { resultTV.setText(movieEntity.toString()); } }); }\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 这样基本上就完成了`Retrofit`和`Rxjava`的结合，大家可以自己进行封装；那么用上了`RxJava`,我们就可以用它强大的`操作符`来对数据进行处理和操作，各位看官可以具体去实现，我在这里不做多做赘述。 参考文章：[RxJava 与 Retrofit 结合的最佳实践](http://gank.io/post/56e80c2c677659311bed9841) ### RxBinding {#RxBinding} [`RxBinding`](https://github.com/JakeWharton/RxBinding) 是 `Jake Wharton` 的一个开源库，它提供了一套在 `Android` 平台上的基于 `RxJava`的 `Binding API`。所谓 `Binding`，就是类似设置 `OnClickListener` 、设置 `TextWatcher` 这样的注册绑定对象的 `API`。 举个设置点击监听的例子。使用 `RxBinding` ，可以把事件监听用这样的方法来设置：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` () {\n@Override public void call(ViewClickEvent event) { // Click handling } }); \u0026quot; data-snippet-id=\u0026ldquo;ext.2e9ddebb88d234f9d279c7a2d49df1cf\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;Button button = \u0026hellip;; RxView.clickEvents(button) // 以 Observable 形式来反馈点击事件 .subscribe(new Action1\u0026lt;ViewClickEvent\u0026gt;() { @Override public void call(ViewClickEvent event) { // Click handling } });\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 看起来除了形式变了没什么区别，实质上也是这样。甚至如果你看一下它的源码，你会发现它连实现都没什么惊喜：它的内部是直接用一个包裹着的 `setOnClickListener()` 来实现的。然而，仅仅这一个形式的改变，却恰好就是 `RxBinding` 的目的：扩展性。通过 `RxBinding` 把点击监听转换成 `Observable` 之后，就有了对它进行扩展的可能。扩展的方式有很多，根据需求而定。一个例子是前面提到过的 `throttleFirst()` 操作符，用于去抖动，也就是消除手抖导致的快速连环点击：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` RxView.clickEvents(button) .throttleFirst(500, TimeUnit.MILLISECONDS) .subscribe(clickAction);\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 如果想对 `RxBinding` 有更多了解，可以去它的 [`GitHub`](https://github.com/JakeWharton/RxBinding) 项目 下面看看。 ### RxLifecyle {#RxLifecyle} [`RxLifecycle`](https://github.com/trello/RxLifecycle) 配合 `Activity/Fragment` 生命周期来管理订阅的。 由于 `RxJava` `Observable`订阅后（调用 `subscribe` 函数），一般会在后台线程执行一些操作（比如访问网络请求数据），当后台操作返回后，调用 `Observer` 的 `onNext` 等函数，然后在 更新 UI 状态。 但是后台线程请求是需要时间的，如果用户点击刷新按钮请求新的微博信息，在刷新还没有完成的时候，用户退出了当前界面返回前面的界面，这个时候刷新的 `Observable` 如果不取消订阅，则会导致之前的 `Activity`无法被 `JVM` 回收导致内存泄露。 这就是 `Android` 里面的生命周期管理需要注意的地方，`RxLifecycle` 就是用来干这事的。比如下面的示例：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` myObservable .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) .subscribe();\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 这样`Activity`在`destroy`的时候就会自动取消这个`observer` ### RxBus {#RxBus} `RxBus`并不是一个库，而是一种模式。相信大多数开发者都使用过`EventBus`或者`Otto`，作为事件总线通信库，如果你的项目已经加入`RxJava`和`EventBus`，不妨用`RxBus`代替`EventBus`，以减少库的依赖。`RxJava`也可以轻松实现事件总线，因为它们都依据于观察者模式。 拓展链接： [用RxJava实现事件总线(Event Bus)](http://www.jianshu.com/p/ca090f6e2fe2) [[深入RxBus]：支持Sticky事件](http://www.jianshu.com/p/71ab00a2677b) ### RxPermission {#RxPermission} [`RxPermission`](https://github.com/tbruyelle/RxPermissions)是基于`RxJava`开发的用于帮助在`Android 6.0`中处理运行时权限检测的框架。在`Android 6.0`中，系统新增了部分权限的运行时动态获取。而不再是在以前的版本中安装的时候授予权限。 拓展链接： [使用RxPermission框架对android6.0权限进行检测](http://blog.csdn.net/hzl9966/article/details/52062658?foxhandler=RssReadRenderProcessHandler) ## 总结 {#总结} 简而言之`Rxjava`是一个很牛逼的库，如果你的项目中还没有使用`RxJava`的话，建议可以尝试去集成使用；对大多数人而已`RxJava`是一个比较难上手的库了，不亚于`Dagger`的上手难度；不过当你认识学习使用过了，你就会发现`RxJava`的魅力所在；如果看一遍没有看懂的童鞋，建议多看几次；动手写写代码，我想信本文可以给到你们一些帮助；你们真正的体会到什么是 `从入门到放弃再到不离不弃`；这就是`RxJava`的魅力所在。 [![](https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1795638508,1691952572\u0026amp;fm=26\u0026amp;gp=0.jpg)](https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1795638508,1691952572\u0026amp;fm=26\u0026amp;gp=0.jpg) 拓展阅读： [我所理解的RxJava——上手其实很简单](http://www.jianshu.com/p/5e93c9101dc5) [深入浅出RxJava \u0026amp;#8211; 大头鬼](http://blog.csdn.net/lzyzsd/article/details/41833541/) [给 Android 开发者的 RxJava 详解 \u0026amp;#8211; 抛物线](http://gank.io/post/560e15be2dca930e00da1083) \u0026amp;nbsp; 转自：https://www.daidingkang.cc/2017/05/19/Rxjava/ [1]: http://www.daidingkang.cc/2017/05/11/java8-Lambda/ [2]: https://www.daidingkang.cc/2016/06/17/Retrofit2-network-framework-parsing/ ","permalink":"https://blog.zdltech.com/posts/rxjava-%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E6%94%BE%E5%BC%83%E5%86%8D%E5%88%B0%E4%B8%8D%E7%A6%BB%E4%B8%8D%E5%BC%83/","summary":"\u003ch2 id=\"作者寄语\"\u003e作者寄语\u003c/h2\u003e\n\u003cp\u003e很久之前就想写一个\u003ccode\u003e专题\u003c/code\u003e，专写\u003ccode\u003eAndroid开发框架\u003c/code\u003e，专题的名字叫 \u003ccode\u003eXXX 从入门到放弃\u003c/code\u003e ，沉淀了这么久，看过网络诸多大神的博客，静下心来开始写这个\u003ccode\u003e专题\u003c/code\u003e，为什么叫\u003ccode\u003e入门到放弃\u003c/code\u003e呢；相信大家学习新框架的时候，尤其是像\u003ccode\u003eRxjava\u003c/code\u003e或者\u003ccode\u003eDagger\u003c/code\u003e等等这种新的编程思想；需要一定的阅读理解能力和思维逻辑；那么本专题旨在帮助大家不要太过急功近利，不要被冗长的代码和文章，晦涩的思想所打败，相信大家只要坚持看完，一定会有所收获的；废话不多说，那么这个专题开篇就以\u003ccode\u003eRxJava\u003c/code\u003e来讲吧，预计后面还会有几篇大型框架的讲解，想想还有点小激动；\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e友情提示：文章较长，请耐心看完；\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image\u0026amp;quality=100\u0026amp;size=b4000_4000\u0026amp;sec=1495248245\u0026amp;di=c9ca01bb247425031e2cc7de2caf56c4\u0026amp;src=http://n1.itc.cn/img8/wb/recom/2016/05/12/146299468983076012.JPEG\"\u003e\u003cimg loading=\"lazy\" src=\"https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image\u0026quality=100\u0026size=b4000_4000\u0026sec=1495248245\u0026di=c9ca01bb247425031e2cc7de2caf56c4\u0026src=http://n1.itc.cn/img8/wb/recom/2016/05/12/146299468983076012.JPEG\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eRxJava\u003c/code\u003e等编程思想正在\u003ccode\u003eAndroid\u003c/code\u003e开发者中变的越来越流行。唯一的问题就是上手不容易，尤其是大部分人之前都是使用\u003ccode\u003e命令式编程语言\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e首先要先理清这么一个问题：Rxjava和我们平时写的程序有什么不同。相信稍微对Rxjava有点认知的朋友都会深深感受到用这种方式写的程序和我们一般写的程序有很明显的不同。我们一般写的程序 统称为\u003ccode\u003e命令式程序\u003c/code\u003e，是以\u003ccode\u003e流程\u003c/code\u003e为核心的，每一行代码实际上都是机器实际上要执行的指令。而Rxjava这样的编程风格，称为\u003ccode\u003e函数响应式编程\u003c/code\u003e。函数响应式编程是以数据流为核心，处理数据的输入，处理以及输出的。这种思路写出来的代码就会跟机器实际执行的指令大相径庭。所以对于已经习惯\u003ccode\u003e命令式编程\u003c/code\u003e的我们来说，刚开始接触\u003ccode\u003eRxjava\u003c/code\u003e的时候必然会很不适应，而且也不太符合我们平时的思维习惯。但是久而久之你会发现这个框架的精髓，尤其是你运用到大项目中的时候，简直爱不释手，随着程序逻辑变得越来越复杂，它依然能够保持代码简洁。\u003c/p\u003e\n\u003ch2 id=\"RxJava是什么\"\u003eRxJava是什么\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003ea library for composing asynchronous and event-based programs using observable sequences for the Java VM\u003cbr\u003e\n解释：一个对于构成使用的Java虚拟机观察序列\u003ccode\u003e异步\u003c/code\u003e和基于事件的程序库\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eRxJava 是一个响应式编程框架，采用观察者设计模式。所以自然少不了 Observable 和 Subscriber 这两个东东了。\u003cbr\u003e\nRxJava 是一个开源项目，地址：\u003ca href=\"https://github.com/ReactiveX/RxJava\"\u003ehttps://github.com/ReactiveX/RxJava\u003c/a\u003e\u003cbr\u003e\nRxAndroid，用于 Android 开发，添加了 Android 用的接口。地址： \u003ca href=\"https://github.com/ReactiveX/RxAndroid\"\u003ehttps://github.com/ReactiveX/RxAndroid\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"基本概念\"\u003e基本概念\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e网上关于\u003ccode\u003eRxJava\u003c/code\u003e的博文也有很多，我也看过许多，其中不乏有优秀的文章，但绝大部分文章都有一个共同点，就是侧重于讲RxJava中各种强大的操作符，而忽略了最基本的东西——概念，所以一开始我也看的一脸懵逼，看到后面又忘了前面的，脑子里全是问号，这个是什么，那个又是什么，这两个长得怎么那么像。举个不太恰当的例子，概念之于初学者，就像食物之于人，当你饿了，你会想吃面包、牛奶，那你为什么不去吃土呢，因为你知道面包牛奶是用来干嘛的，土是用来干嘛的。同理，前面已经说过，\u003ccode\u003eRxJava\u003c/code\u003e无非是发送数据与接收数据，那么什么是发射源，什么是接收源，这就是你应该明确的事，也是\u003ccode\u003eRxJava\u003c/code\u003e的入门条件之一，下面就依我个人理解，对发射源和接收源做个归类，以及\u003ccode\u003eRxJava\u003c/code\u003e中频繁出现的几个“单词”解释一通;\u003c/p\u003e\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eObservable\u003c/code\u003e：发射源，英文释义“可观察的”，在观察者模式中称为“被观察者”或“可观察对象”；\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eObserver\u003c/code\u003e：接收源，英文释义“观察者”，没错！就是观察者模式中的“观察者”，可接收\u003ccode\u003eObservable\u003c/code\u003e、\u003ccode\u003eSubject\u003c/code\u003e发射的数据；\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eSubject\u003c/code\u003e：\u003ccode\u003eSubject\u003c/code\u003e是一个比较特殊的对象，既可充当发射源，也可充当接收源，为避免初学者被混淆，本章将不对\u003ccode\u003eSubject\u003c/code\u003e做过多的解释和使用，重点放在\u003ccode\u003eObservable\u003c/code\u003e和\u003ccode\u003eObserver\u003c/code\u003e上，先把最基本方法的使用学会，后面再学其他的都不是什么问题；\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eSubscriber\u003c/code\u003e：“订阅者”，也是接收源，那它跟Observer有什么区别呢？\u003ccode\u003eSubscriber\u003c/code\u003e实现了\u003ccode\u003eObserver\u003c/code\u003e接口，比Observer多了一个最重要的方法unsubscribe( )，用来取消订阅，当你不再想接收数据了，可以调用\u003ccode\u003eunsubscribe( )\u003c/code\u003e方法停止接收，Observer 在 subscribe() 过程中,最终也会被转换成 Subscriber 对象，一般情况下，建议使用Subscriber作为接收源；\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eSubscription\u003c/code\u003e ：\u003ccode\u003eObservable\u003c/code\u003e调用\u003ccode\u003esubscribe( )\u003c/code\u003e方法返回的对象，同样有\u003ccode\u003eunsubscribe( )\u003c/code\u003e方法，可以用来取消订阅事件；\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eAction0\u003c/code\u003e：\u003ccode\u003eRxJava\u003c/code\u003e中的一个接口，它只有一个无参\u003ccode\u003ecall（）\u003c/code\u003e方法，且无返回值，同样还有Action1，Action2…Action9等，Action1封装了含有 1 个参的call（）方法，即call（T t），Action2封装了含有 2 个参数的call方法，即call（T1 t1，T2 t2），以此类推；\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eFunc0\u003c/code\u003e：与Action0非常相似，也有call（）方法，但是它是有返回值的，同样也有Func0、Func1…Func9;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eRxJava最核心的两个东西是\u003ccode\u003eObservables\u003c/code\u003e（被观察者，事件源）\u003ccode\u003e和Subscribers\u003c/code\u003e（观察者）。O\u003ccode\u003ebservables\u003c/code\u003e发出一系列事件，\u003ccode\u003eSubscribers\u003c/code\u003e处理这些事件。这里的事件可以是任何你感兴趣的东西（触摸事件，web接口调用返回的数据…）\u003c/p\u003e","title":"RxJava 从入门到放弃再到不离不弃"},{"content":"1. 安装 react 要使用 react，就必须装下面两个包的。\n`$ npm \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;install\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;--save react react-dom\u0026amp;lt;/span\u0026gt; ` 2. 建立 babel 可能你不懂 babel 是什么，你可以把它理解为编译器，它能把 react 代码转成一般浏览器可读可执行的代码，通常可以用它来转化 react 或 vue 这样的前端代码，或者把 es6 代码转成普通的 javascript 代码等等。\n如果还不理解的话，可以看我这篇文章 babel 入门指南。\n要让 babel 很好的转化 react 代码，首先要安装好 babel，再装 babel 转化 react 的包。\n运行下面的命令。\n`$ npm \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;install\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;--save-dev babel-core babel-preset-react babel-preset-env\u0026amp;lt;/span\u0026gt; ` 创建 .babelrc 文件。\n{ \u0026lt;span class=\u0026quot;hljs-attr\u0026quot;\u0026gt;\u0026quot;presets\u0026quot;\u0026lt;/span\u0026gt;: [\u0026lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;env\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;react\u0026quot;\u0026lt;/span\u0026gt;] } 为什么我知道要这么做呢？\n因为我是分别结合 babel 和 react 的官网给的最新官方指南。\n可以参考下面两个链接：\nReact preset React Installation 3. 在 webpack 使用 babel-loader 最后我们需要在 webpack 中使用一个 loader 来转化 react 的代码。\n首先，安装。\n`$ npm \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;install\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;--save-dev babel-loader\u0026amp;lt;/span\u0026gt; ` webpack.config.js\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;var\u0026amp;lt;/span\u0026gt; HtmlWebpackPlugin = \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;require\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;html-webpack-plugin\u0026#39;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;const\u0026amp;lt;/span\u0026gt; ExtractTextPlugin = \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;require\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;extract-text-webpack-plugin\u0026#39;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;module\u0026amp;lt;/span\u0026gt;.exports = { \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;entry\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;./src/app.js\u0026#39;\u0026amp;lt;/span\u0026gt;, ... module: { \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;rules\u0026amp;lt;/span\u0026gt;: [ { \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;test\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-regexp\u0026#34;\u0026gt;/\\.scss$/\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;use\u0026amp;lt;/span\u0026gt;: ExtractTextPlugin.extract({ \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;fallback\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;style-loader\u0026#39;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//resolve-url-loader may be chained before sass-loader if necessary\u0026amp;lt;/span\u0026gt; use: [\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;css-loader\u0026#39;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;sass-loader\u0026#39;\u0026amp;lt;/span\u0026gt;] }) }, \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 这两行是处理 react 相关的内容\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;test\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-regexp\u0026#34;\u0026gt;/\\.js$/\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;loader\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;babel-loader\u0026#39;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;exclude\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-regexp\u0026#34;\u0026gt;/node_modules/\u0026amp;lt;/span\u0026gt; }, { \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;test\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-regexp\u0026#34;\u0026gt;/\\.jsx$/\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;loader\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;babel-loader\u0026#39;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;exclude\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-regexp\u0026#34;\u0026gt;/node_modules/\u0026amp;lt;/span\u0026gt; } ] } }; ` 4. 写 react 组件 接着我们来准备一些 react 的代码，要来测试一下。\nsrc/index.html\n`\u0026amp;lt;span class=\u0026#34;hljs-meta\u0026#34;\u0026gt;\u0026amp;lt;!DOCTYPE html\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;html\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;lang\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;en\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;head\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;meta\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;charset\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;UTF-8\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;title\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;Hello World\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;title\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;head\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;body\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;div\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;root\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;div\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;body\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;html\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; ` src/app.js\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; css \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;./app.scss\u0026#39;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; React \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;react\u0026#39;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; ReactDOM \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;react-dom\u0026#39;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; Root \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;./Root\u0026#39;\u0026amp;lt;/span\u0026gt;; ReactDOM.render( \u0026amp;lt;span class=\u0026#34;xml\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;Root\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;Root\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;document\u0026amp;lt;/span\u0026gt;.getElementById(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;root\u0026#39;\u0026amp;lt;/span\u0026gt;) ); ` src/Root.js\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; React \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;react\u0026#39;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;export\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;default\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Root\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;React\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Component\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ render() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; ( \u0026amp;lt;span class=\u0026#34;xml\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;div\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;{{textAlign:\u0026amp;lt;/span\u0026gt; \u0026#39;\u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;center\u0026amp;lt;/span\u0026gt;\u0026#39;}}\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;h1\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;Hello World\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;h1\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;div\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;); } } ` 效果如下：\n参考链接：\nSetting up Webpack, Babel and React from scratch, revisited Setup a React Environment Using webpack and Babel Setting up React with Webpack 3.0, Yarn and Babel https://love2.io/@hfpp2012/doc/webpack-tutorial/chapters/8.md ","permalink":"https://blog.zdltech.com/posts/%E7%94%A8-webpack-%E5%92%8C-babel-%E9%85%8D%E7%BD%AE-react-%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83/","summary":"\u003ch2 id=\"1-react\"\u003e1. 安装 react\u003c/h2\u003e\n\u003cp\u003e要使用 react，就必须装下面两个包的。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`$ npm \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;install\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;--save react react-dom\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"2-babel\"\u003e2. 建立 babel\u003c/h2\u003e\n\u003cp\u003e可能你不懂 \u003ccode\u003ebabel\u003c/code\u003e 是什么，你可以把它理解为编译器，它能把 \u003ccode\u003ereact\u003c/code\u003e 代码转成一般浏览器可读可执行的代码，通常可以用它来转化 \u003ccode\u003ereact\u003c/code\u003e 或 \u003ccode\u003evue\u003c/code\u003e 这样的前端代码，或者把 \u003ccode\u003ees6\u003c/code\u003e 代码转成普通的 javascript 代码等等。\u003c/p\u003e\n\u003cp\u003e如果还不理解的话，可以看我这篇文章 \u003ca href=\"https://www.rails365.net/articles/babel-ru-men-zhi-nan\"\u003ebabel 入门指南\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e要让 \u003ccode\u003ebabel\u003c/code\u003e 很好的转化 \u003ccode\u003ereact\u003c/code\u003e 代码，首先要安装好 \u003ccode\u003ebabel\u003c/code\u003e，再装 \u003ccode\u003ebabel\u003c/code\u003e 转化 \u003ccode\u003ereact\u003c/code\u003e 的包。\u003c/p\u003e\n\u003cp\u003e运行下面的命令。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`$ npm \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;install\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;--save-dev babel-core babel-preset-react babel-preset-env\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e创建 \u003ccode\u003e.babelrc\u003c/code\u003e 文件。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e{\n  \u0026lt;span class=\u0026quot;hljs-attr\u0026quot;\u0026gt;\u0026quot;presets\u0026quot;\u0026lt;/span\u0026gt;: [\u0026lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;env\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;react\u0026quot;\u0026lt;/span\u0026gt;]\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e为什么我知道要这么做呢？\u003c/p\u003e\n\u003cp\u003e因为我是分别结合 \u003ccode\u003ebabel\u003c/code\u003e 和 \u003ccode\u003ereact\u003c/code\u003e 的官网给的最新官方指南。\u003c/p\u003e","title":"用 webpack 和 babel 配置 react 开发环境"},{"content":"一、前言 在开发中，我们常常需要ViewPager结合Fragment一起使用，来实现多页签的切换效果。在以前，我们有以下一系列第三方库来帮我们实现:\nPagerSlidingTabStrip SmartTabLayout FlycoTabLayout ViewPagerIndicator … 而现在，我们可以使用Design support library库的TabLayout来实现了。\n二、最终效果图 三、TabLayout的使用 1. 添加依赖 由于TabLayout在design包内，所以首先需要在app目录下的build.gradle中添加以下依赖：\n``` 1 2 3 4 ``` \u0026lt;td class=\u0026quot;code hljs bash\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` dependencies { \u0026hellip; compile \u0026lsquo;com.android.support:design:23.4.0\u0026rsquo; }\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; ## 2. 创建布局 {#2-创建布局} 布局相当简单，只要添加TabLayout和ViewPager的布局即可： ### layout/activity_main.xml {#layout-activity-main-xml}\u0026lt;figure class=\u0026#34;highlight xml\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;18\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;19\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;20\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;21\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code hljs xml\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;LinearLayout xmlns:android=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot; xmlns:tools=\u0026quot;http://schemas.android.com/tools\u0026quot;\nandroid:id=\u0026amp;quot;@+id/activity_main\u0026amp;quot; android:layout_width=\u0026amp;quot;match_parent\u0026amp;quot; android:layout_height=\u0026amp;quot;match_parent\u0026amp;quot; android:orientation=\u0026amp;quot;vertical\u0026amp;quot;\u0026gt; \u0026lt;android.support.design.widget.TabLayout android:id=\u0026amp;quot;@+id/tab_layout\u0026amp;quot; style=\u0026amp;quot;@style/TabLayoutStyle\u0026amp;quot; android:layout_width=\u0026amp;quot;match_parent\u0026amp;quot; android:layout_height=\u0026amp;quot;wrap_content\u0026amp;quot; /\u0026gt; \u0026lt;android.support.v4.view.ViewPager android:id=\u0026amp;quot;@+id/view_pager\u0026amp;quot; android:layout_width=\u0026amp;quot;match_parent\u0026amp;quot; android:layout_height=\u0026amp;quot;0dp\u0026amp;quot; android:layout_weight=\u0026amp;quot;1\u0026amp;quot; android:background=\u0026amp;quot;@android:color/white\u0026amp;quot;/\u0026gt; \u0026quot; data-snippet-id=\u0026ldquo;ext.7e95e4aafc1011c962a1047c143edc4e\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;utf-8\u0026rdquo;?\u0026gt; \u0026lt;LinearLayout xmlns:android=\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot; xmlns:tools=\u0026ldquo;http://schemas.android.com/tools\u0026quot; android:id=\u0026rdquo;@+id/activity_main\u0026rdquo; android:layout_width=\u0026ldquo;match_parent\u0026rdquo; android:layout_height=\u0026ldquo;match_parent\u0026rdquo; android:orientation=\u0026ldquo;vertical\u0026rdquo;\u0026gt;\n\u0026lt;android.support.design.widget.TabLayout android:id=\u0026quot;@+id/tab_layout\u0026quot; style=\u0026quot;@style/TabLayoutStyle\u0026quot; android:layout_width=\u0026ldquo;match_parent\u0026rdquo; android:layout_height=\u0026ldquo;wrap_content\u0026rdquo; /\u0026gt;\n\u0026lt;android.support.v4.view.ViewPager android:id=\u0026quot;@+id/view_pager\u0026quot; android:layout_width=\u0026ldquo;match_parent\u0026rdquo; android:layout_height=\u0026ldquo;0dp\u0026rdquo; android:layout_weight=\u0026ldquo;1\u0026rdquo; android:background=\u0026quot;@android:color/white\u0026quot;/\u0026gt; \u0026lt;/LinearLayout\u0026gt;\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 还有其他的属性我习惯在style文件中设置： ### values/styles.xml {#values-styles-xml}\u0026lt;figure class=\u0026#34;highlight xml\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code hljs xml\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026quot; data-snippet-id=\u0026ldquo;ext.3491be7a86f191eb534e54eaf54d5af9\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo; style=\u0026ldquo;box-sizing: border-box; margin: 0px; display: block;\u0026quot;\u0026gt;\u0026lt;!\u0026ndash; TabLayout样式 \u0026ndash;\u0026gt; \u0026lt;style name=\u0026ldquo;TabLayoutStyle\u0026rdquo; parent=\u0026ldquo;Widget.Design.TabLayout\u0026rdquo;\u0026gt; \u0026lt;item name=\u0026ldquo;tabIndicatorColor\u0026rdquo;\u0026gt;@color/colorPrimary\u0026lt;/item\u0026gt; \u0026lt;item name=\u0026ldquo;tabSelectedTextColor\u0026rdquo;\u0026gt;@color/colorPrimary\u0026lt;/item\u0026gt; \u0026lt;item name=\u0026ldquo;tabTextAppearance\u0026rdquo;\u0026gt;@style/TabTextAppearence\u0026lt;/item\u0026gt; \u0026lt;item name=\u0026ldquo;tabPaddingEnd\u0026rdquo;\u0026gt;0dp\u0026lt;/item\u0026gt; \u0026lt;/style\u0026gt; \u0026lt;style name=\u0026ldquo;TabTextAppearence\u0026rdquo; parent=\u0026ldquo;TextAppearance.Design.Tab\u0026rdquo;\u0026gt; \u0026lt;item name=\u0026ldquo;android:textSize\u0026rdquo;\u0026gt;16sp\u0026lt;/item\u0026gt; \u0026lt;item name=\u0026ldquo;textAllCaps\u0026rdquo;\u0026gt;false\u0026lt;/item\u0026gt; \u0026lt;/style\u0026gt;\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; ## 3. 创建Fragment {#3-创建Fragment}\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;18\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;19\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;20\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;21\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;22\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;23\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;24\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;25\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;26\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;27\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;28\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;29\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;32\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;33\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;34\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;35\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;36\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;38\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code hljs java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` package com.sherlockshi.badgedtablayoutpractise;\nimport android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView;\n/** * Author: SherlockShi * Date: 2016-11-01 16:31 * Description: */ public class PageFragment extends Fragment {\nprivate static final String PAGE_NAME_KEY = \u0026ldquo;PAGE_NAME_KEY\u0026rdquo;;\npublic static PageFragment getInstance(String pageName) { Bundle args = new Bundle(); args.putString(PAGE_NAME_KEY, pageName); PageFragment pageFragment = new PageFragment(); pageFragment.setArguments(args);\nreturn pageFragment; }\n@Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_page, container, false); TextView textView = (TextView) view.findViewById(R.id.tv_page_name); textView.setText(getArguments().getString(PAGE_NAME_KEY));\nreturn view; } }\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 其中Fragment的布局`layout/fragment_page.xml`:\u0026lt;figure class=\u0026#34;highlight xml\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code hljs xml\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;TextView xmlns:android=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot; xmlns:tools=\u0026quot;http://schemas.android.com/tools\u0026quot;\nandroid:id=\u0026amp;quot;@+id/tv_page_name\u0026amp;quot; android:layout_width=\u0026amp;quot;match_parent\u0026amp;quot; android:layout_height=\u0026amp;quot;match_parent\u0026amp;quot; android:gravity=\u0026amp;quot;center\u0026amp;quot;/\u0026gt; \u0026quot; data-snippet-id=\u0026ldquo;ext.370f013e7e86a8c7c5395e82126045d2\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;utf-8\u0026rdquo;?\u0026gt; \u0026lt;TextView xmlns:android=\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot; xmlns:tools=\u0026ldquo;http://schemas.android.com/tools\u0026quot; android:id=\u0026rdquo;@+id/tv_page_name\u0026rdquo; android:layout_width=\u0026ldquo;match_parent\u0026rdquo; android:layout_height=\u0026ldquo;match_parent\u0026rdquo; android:gravity=\u0026ldquo;center\u0026rdquo;/\u0026gt;\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; ## 4. ViewPager的适配器 {#4-ViewPager的适配器}\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;18\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;19\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;20\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;21\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;22\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;23\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;24\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;25\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;26\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;27\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;28\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;29\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;32\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;33\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;34\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;35\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;36\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;38\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;41\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;42\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;43\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;44\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;45\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;46\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;47\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code hljs java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` mFragmentList;\nprivate List\u0026lt;String\u0026gt; mPageTitleList; private List\u0026lt;Integer\u0026gt; mBadgeCountList; public SimpleFragmentPagerAdapter(Context context, FragmentManager fm, List\u0026lt;Fragment\u0026gt; fragmentList, List\u0026lt;String\u0026gt; pageTitleList, List\u0026lt;Integer\u0026gt; badgeCountList) {\nsuper(fm); this.mContext = context; this.mFragmentList = fragmentList; this.mPageTitleList = pageTitleList; this.mBadgeCountList = badgeCountList; } @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mFragmentList.size(); } @Override public CharSequence getPageTitle(int position) { return mPageTitleList.get(position); } }\n\u0026quot; data-snippet-id=\u0026ldquo;ext.f1ef424453dae480ac7d46b6bf9a7cfc\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;package com.sherlockshi.badgedtablayoutpractise;\nimport android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter;\nimport java.util.List;\n/** * Author: SherlockShi * Date: 2016-11-01 17:38 * Description: */ public class SimpleFragmentPagerAdapter extends FragmentPagerAdapter {\nprivate Context mContext; private List\u0026lt;Fragment\u0026gt; mFragmentList; private List\u0026lt;String\u0026gt; mPageTitleList; private List\u0026lt;Integer\u0026gt; mBadgeCountList;\npublic SimpleFragmentPagerAdapter(Context context, FragmentManager fm, List\u0026lt;Fragment\u0026gt; fragmentList, List\u0026lt;String\u0026gt; pageTitleList, List\u0026lt;Integer\u0026gt; badgeCountList) { super(fm); this.mContext = context; this.mFragmentList = fragmentList; this.mPageTitleList = pageTitleList; this.mBadgeCountList = badgeCountList; }\n@Override public Fragment getItem(int position) { return mFragmentList.get(position); }\n@Override public int getCount() { return mFragmentList.size(); }\n@Override public CharSequence getPageTitle(int position) { return mPageTitleList.get(position); } }\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; ## 5. 设置TabLayout {#5-设置TabLayout}\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;18\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;19\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;20\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;21\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;22\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;23\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;24\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;25\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;26\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;27\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;28\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;29\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;32\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;33\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;34\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;35\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;36\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;38\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;41\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;42\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;43\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;44\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;45\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;46\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;47\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;48\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;49\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;50\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;51\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;52\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;53\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;54\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;55\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;56\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;57\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code hljs java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` mPageTitleList = new ArrayList();\nprivate List\u0026lt;Fragment\u0026gt; mFragmentList = new ArrayList\u0026lt;Fragment\u0026gt;(); private List\u0026lt;Integer\u0026gt; mBadgeCountList = new ArrayList\u0026lt;Integer\u0026gt;(); private SimpleFragmentPagerAdapter mPagerAdapter; private TabLayout mTabLayout; private ViewPager mViewPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initFragments(); initView(); } private void initFragments() { mPageTitleList.add(\u0026amp;quot;Tab1\u0026amp;quot;); mPageTitleList.add(\u0026amp;quot;Tab2\u0026amp;quot;); mPageTitleList.add(\u0026amp;quot;Tab3\u0026amp;quot;); mBadgeCountList.add(6); mBadgeCountList.add(16); mBadgeCountList.add(166); for (int i = 0; i \u0026lt; mPageTitleList.size(); i++) { mFragmentList.add(PageFragment.getInstance(mPageTitleList.get(i))); } } private void initView() { mTabLayout = (TabLayout) findViewById(R.id.tab_layout); mViewPager = (ViewPager) findViewById(R.id.view_pager); mPagerAdapter = new SimpleFragmentPagerAdapter(getSupportFragmentManager(), mFragmentList, mPageTitleList); mViewPager.setAdapter(mPagerAdapter); mTabLayout.setupWithViewPager(mViewPager); initBadgeViews(); setUpTabBadge(); } }\n\u0026quot; data-snippet-id=\u0026ldquo;ext.70f381a93ec7f8d5b4c401b6ed6c0077\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;package com.sherlockshi.badgedtablayoutpractise;\nimport android.os.Bundle; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.view.ViewGroup;\nimport java.util.ArrayList; import java.util.List;\npublic class MainActivity extends AppCompatActivity {\nprivate List\u0026lt;String\u0026gt; mPageTitleList = new ArrayList\u0026lt;String\u0026gt;(); private List\u0026lt;Fragment\u0026gt; mFragmentList = new ArrayList\u0026lt;Fragment\u0026gt;(); private List\u0026lt;Integer\u0026gt; mBadgeCountList = new ArrayList\u0026lt;Integer\u0026gt;();\nprivate SimpleFragmentPagerAdapter mPagerAdapter; private TabLayout mTabLayout; private ViewPager mViewPager;\n@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);\ninitFragments(); initView(); }\nprivate void initFragments() { mPageTitleList.add(\u0026ldquo;Tab1\u0026rdquo;); mPageTitleList.add(\u0026ldquo;Tab2\u0026rdquo;); mPageTitleList.add(\u0026ldquo;Tab3\u0026rdquo;);\nmBadgeCountList.add(6); mBadgeCountList.add(16); mBadgeCountList.add(166);\nfor (int i = ; i \u0026lt; mPageTitleList.size(); i++) { mFragmentList.add(PageFragment.getInstance(mPageTitleList.get(i))); } }\nprivate void initView() { mTabLayout = (TabLayout) findViewById(R.id.tab_layout); mViewPager = (ViewPager) findViewById(R.id.view_pager);\nmPagerAdapter = new SimpleFragmentPagerAdapter(getSupportFragmentManager(), mFragmentList, mPageTitleList); mViewPager.setAdapter(mPagerAdapter); mTabLayout.setupWithViewPager(mViewPager);\ninitBadgeViews(); setUpTabBadge(); } }\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; # 四、设置角标 {#四、设置角标} ## 1. 添加角标Badge {#1-添加角标Badge} 添加角标的关键代码只需要一行：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code hljs css\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` mBadgeViews.get(i).setTargetView(((ViewGroup) mTabLayout.getChildAt()).getChildAt(i));\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 完整代码只需要在设置完TabLayout和ViewPager后，遍历每一个Tab，为Tab添加角标：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code hljs cs\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` private void setUpTabBadge() { for (int i = ; i \u0026lt; mFragmentList.size(); i++) { mBadgeViews.get(i).setTargetView(((ViewGroup) mTabLayout.getChildAt()).getChildAt(i)); mBadgeViews.get(i).setText(formatBadgeNumber(mBadgeCountList.get(i))); } }\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; ## 2. 更新角标 {#2-更新角标} 在需要更新角标的地方，只要调用以下方法就可实现：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code hljs bash\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` mBadgeCountList.set(1, count++); setUpTabBadge();\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 以上，就可以轻松地为TabLayout添加角标，并处理角标的更新了。 # 五、问题 {#五、问题} ## 1. 重复选中的状态 {#1-重复选中的状态} 但是如果需要更新角标，那么在`更新角标后`，再点击另一个Tab，会出现`上一个Tab`和`当前Tab`都是选中状态（如下图的Tab1和Tab2）： ![](http://7xlpfl.com1.z0.glb.clouddn.com/sherlockshi/2016-11-03-Snip20161103_6.png) ## 2. 角标位置不可控 {#2-角标位置不可控} 而且如上图所示，角标的位置不好控制，有的离文字很近，有的离得很远，无法精确控制。 # 六、最实用的TabLayout加角标方法 {#六、最实用的TabLayout加角标方法} ## 1. 添加getTabItemView()方法 {#1-添加getTabItemView-方法} 在重写的FragmentPagerAdapter中添加自定义Tab布局方法：\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code hljs cs\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` public View getTabItemView(int position) { View view = LayoutInflater.from(mContext).inflate(R.layout.tab_layout_item, null); TextView textView = (TextView) view.findViewById(R.id.textview); textView.setText(mPageTitleList.get(position));\nView target = view.findViewById(R.id.badgeview_target);\nBadgeView badgeView = new BadgeView(mContext); badgeView.setTargetView(target); badgeView.setBadgeMargin(, 6, 10, ); badgeView.setTextSize(10); badgeView.setText(formatBadgeNumber(mBadgeCountList.get(position)));\nreturn view; }\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 对应的自定义布局为：\u0026lt;figure class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;18\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;19\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;20\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;21\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;22\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;23\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;24\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;25\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;26\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;27\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;28\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;29\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code hljs xml\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;LinearLayout xmlns:android=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;\nxmlns:tools=\u0026amp;quot;http://schemas.android.com/tools\u0026amp;quot; android:layout_width=\u0026amp;quot;match_parent\u0026amp;quot; android:layout_height=\u0026amp;quot;wrap_content\u0026amp;quot; android:orientation=\u0026amp;quot;horizontal\u0026amp;quot;\u0026gt; \u0026lt;!-- LinearLayout的Height必须为wrap_content,如果为match_parent,那么在第二次加载Badge的时候,Tab布局会出现问题 --\u0026gt; \u0026lt;View android:layout_width=\u0026amp;quot;0dp\u0026amp;quot; android:layout_weight=\u0026amp;quot;1\u0026amp;quot; android:layout_height=\u0026amp;quot;wrap_content\u0026amp;quot;/\u0026gt; \u0026lt;TextView android:id=\u0026amp;quot;@+id/textview\u0026amp;quot; android:layout_width=\u0026amp;quot;wrap_content\u0026amp;quot; android:layout_height=\u0026amp;quot;wrap_content\u0026amp;quot; android:layout_gravity=\u0026amp;quot;center\u0026amp;quot; android:layout_marginLeft=\u0026amp;quot;-30dp\u0026amp;quot; android:textColor=\u0026amp;quot;@color/tab_text_color_selector\u0026amp;quot;/\u0026gt; \u0026lt;View android:id=\u0026amp;quot;@+id/badgeview_target\u0026amp;quot; android:layout_width=\u0026amp;quot;0dp\u0026amp;quot; android:layout_weight=\u0026amp;quot;1\u0026amp;quot; android:layout_height=\u0026amp;quot;40dp\u0026amp;quot; android:layout_marginLeft=\u0026amp;quot;4dp\u0026amp;quot; android:layout_gravity=\u0026amp;quot;center\u0026amp;quot;/\u0026gt; \u0026quot; data-snippet-id=\u0026ldquo;ext.89ae1cafa820c0153ee8e464b7820214\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;utf-8\u0026rdquo;?\u0026gt; \u0026lt;LinearLayout xmlns:android=\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot; xmlns:tools=\u0026ldquo;http://schemas.android.com/tools\u0026quot; android:layout_width=\u0026ldquo;match_parent\u0026rdquo; android:layout_height=\u0026ldquo;wrap_content\u0026rdquo; android:orientation=\u0026ldquo;horizontal\u0026rdquo;\u0026gt; \u0026lt;!\u0026ndash; LinearLayout的Height必须为wrap_content,如果为match_parent,那么在第二次加载Badge的时候,Tab布局会出现问题 \u0026ndash;\u0026gt;\n\u0026lt;View android:layout_width=\u0026ldquo;0dp\u0026rdquo; android:layout_weight=\u0026ldquo;1\u0026rdquo; android:layout_height=\u0026ldquo;wrap_content\u0026rdquo;/\u0026gt;\n\u0026lt;TextView android:id=\u0026rdquo;@+id/textview\u0026rdquo; android:layout_width=\u0026ldquo;wrap_content\u0026rdquo; android:layout_height=\u0026ldquo;wrap_content\u0026rdquo; android:layout_gravity=\u0026ldquo;center\u0026rdquo; android:layout_marginLeft=\u0026quot;-30dp\u0026rdquo; android:textColor=\u0026quot;@color/tab_text_color_selector\u0026quot;/\u0026gt;\n\u0026lt;View android:id=\u0026quot;@+id/badgeview_target\u0026quot; android:layout_width=\u0026ldquo;0dp\u0026rdquo; android:layout_weight=\u0026ldquo;1\u0026rdquo; android:layout_height=\u0026ldquo;40dp\u0026rdquo; android:layout_marginLeft=\u0026ldquo;4dp\u0026rdquo; android:layout_gravity=\u0026ldquo;center\u0026rdquo;/\u0026gt; \u0026lt;/LinearLayout\u0026gt;\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; ## 2. 设置自定义布局 {#2-设置自定义布局}\u0026lt;figure class=\u0026#34;highlight java\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;18\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;19\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;20\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code hljs coffeescript\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` private void setUpTabBadge() { for (int i = ; i \u0026lt; mFragmentList.size(); i++) { TabLayout.Tab tab = mTabLayout.getTabAt(i);\n// 更新Badge前,先remove原来的customView,否则Badge无法更新 View customView = tab.getCustomView(); if (customView != null) { ViewParent parent = customView.getParent(); if (parent != null) { ((ViewGroup) parent).removeView(customView); } }\n// 更新CustomView tab.setCustomView(mPagerAdapter.getTabItemView(i)); }\n// 需加上以下代码,不然会出现更新Tab角标后,选中的Tab字体颜色不是选中状态的颜色 mTabLayout.getTabAt(mTabLayout.getSelectedTabPosition()).getCustomView().setSelected(true); }\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 上面的示例会有两个坑： * 一个坑是每次为TabLayout添加Badge后，会出现Tab的字体颜色不是选中状态的颜色，需要手动设置Tab为选中状态，可以参考上面的第19行代码解决，这应该是TabLayout的一个Bug； * 另一个坑是如果每次更新Badge的时候，直接重新tab.setCustomView的话，会出现Badge不更新，解决办法是先移除之前的自定义布局，然后再重新设置布局，具体可参考第6-12行代码解决。 # 七、总结 {#七、总结} 以上是自己在使用TabLayout的过程中发现的一些问题及解决办法，如果大家有更好的解决方法，或者还有别的坑，欢迎留言。 当然，大家也可以直接使用第三方控件来实现以上功能，现在主流的几个控件也都做得很好，也很省心。 项目代码已共享到Github：[BadgedTabLayoutPractise](https://github.com/SherlockShi/BadgedTabLayoutPractise) # 八、参考资料 {#八、参考资料} [android design library提供的TabLayout的用法](http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0731/3247.html) [Google Play Style Tabs using TabLayout](https://guides.codepath.com/android/Google-Play-Style-Tabs-using-TabLayout#design-support-library) [Android Tablayout tabs with notification badge like whatsApp](http://stackoverflow.com/questions/31968162/android-tablayout-tabs-with-notification-badge-like-whatsapp) ","permalink":"https://blog.zdltech.com/posts/%E4%B8%BAtablayout%E6%B7%BB%E5%8A%A0%E8%A7%92%E6%A0%87%E7%9A%84%E6%9C%80%E7%AE%80%E5%8D%95%E6%96%B9%E6%B3%95/","summary":"\u003ch1 id=\"一、前言\"\u003e一、前言\u003c/h1\u003e\n\u003cp\u003e在开发中，我们常常需要ViewPager结合Fragment一起使用，来实现多页签的切换效果。在以前，我们有以下一系列第三方库来帮我们实现:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/astuetz/PagerSlidingTabStrip\"\u003ePagerSlidingTabStrip\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ogaclejapan/SmartTabLayout\"\u003eSmartTabLayout\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/H07000223/FlycoTabLayout\"\u003eFlycoTabLayout\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/JakeWharton/ViewPagerIndicator\"\u003eViewPagerIndicator\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e…\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e而现在，我们可以使用\u003ccode\u003eDesign support library\u003c/code\u003e库的\u003ccode\u003eTabLayout\u003c/code\u003e来实现了。\u003c/p\u003e\n\u003ch1 id=\"二、最终效果图\"\u003e二、最终效果图\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://7xlpfl.com1.z0.glb.clouddn.com/sherlockshi/2016-11-03-demo2.gif\"\u003e\u003c/p\u003e\n\u003ch1 id=\"三、TabLayout的使用\"\u003e三、TabLayout的使用\u003c/h1\u003e\n\u003ch2 id=\"1-添加依赖\"\u003e1. 添加依赖\u003c/h2\u003e\n\u003cp\u003e由于TabLayout在design包内，所以首先需要在app目录下的\u003ccode\u003ebuild.gradle\u003c/code\u003e中添加以下依赖：\u003cfigure class=\"highlight groovy\"\u003e\u003c/p\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd class=\"gutter\"\u003e\n      ```\n\u003cspan class=\"line\"\u003e1\u003c/span\u003e\n\u003cspan class=\"line\"\u003e2\u003c/span\u003e\n\u003cspan class=\"line\"\u003e3\u003c/span\u003e\n\u003cspan class=\"line\"\u003e4\u003c/span\u003e\n```\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td class=\u0026quot;code hljs bash\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cspan class=\"line\"\u003edependencies {\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\t\u0026hellip;\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\tcompile \u003cspan class=\"string\"\u003e\u003cspan class=\"hljs-string\"\u003e\u0026lsquo;com.android.support:design:23.4.0\u0026rsquo;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"line\"\u003e}\u003c/span\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;/tr\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e## 2. 创建布局 {#2-创建布局}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e布局相当简单，只要添加TabLayout和ViewPager的布局即可：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e### layout/activity_main.xml {#layout-activity-main-xml}\u0026lt;figure class=\u0026#34;highlight xml\u0026#34;\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;table\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;tr\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026lt;div class=\u0026#34;alert-info\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;18\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;19\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;20\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;21\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e\u0026lt;/td\u0026gt;\n\n\u0026lt;td class=\u0026quot;code hljs xml\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u0026lt;LinearLayout xmlns:android=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;\nxmlns:tools=\u0026quot;http://schemas.android.com/tools\u0026quot;\u003c/p\u003e","title":"为TabLayout添加角标的最简单方法"},{"content":" 由于系统崩溃，造成平时积累的软件工具及开发常用插件丢失，好记性不如记录下来，方便以后查阅。\nAndroid Studio插件 1. GsonFormat 2. ADB Idea 3. Android Develop Templates 4. Android Dialog 5. Android Drawable Importer 6. Android Drawable Viewer 7. Android Parcelable code generator 8. Android Selectors Generate 9. Android String.xml To CSV Converter 10. dash 11. Database Navigator 12. JSON TO Kotlin Class 13. Markdown Navigator 14. Parcelable Code Generator (for kotlin) 15. Generator Android Resource sublime Text3 数据恢复 复制 /Users/用户/Library/Application\\ Support/Sublime\\ Text\\ 3/Local/Session.sublime_session 这个就是之前没有保存的数据，通过复制/Users/用户/Library/Application\\ Support/Sublime\\ Text\\ 3/下面的所有内容，来恢复插件等等！！ ","permalink":"https://blog.zdltech.com/posts/kai-fa-ren-yuan-zhi-huan-jing-pei-zhi/","summary":"\u003cblockquote\u003e\n\u003cp\u003e由于系统崩溃，造成平时积累的软件工具及开发常用插件丢失，好记性不如记录下来，方便以后查阅。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"toc_0\"\u003eAndroid Studio插件\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e1. GsonFormat\n2. ADB Idea\n3. Android Develop Templates\n4. Android Dialog\n5. Android Drawable Importer\n6. Android Drawable Viewer\n7. Android Parcelable code generator\n8. Android Selectors Generate\n9. Android String.xml To  CSV Converter\n10. dash\n11. Database Navigator\n12. JSON TO Kotlin Class\n13. Markdown Navigator\n14. Parcelable Code Generator (for kotlin)\n15. Generator Android Resource\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"toc_1\"\u003esublime Text3 数据恢复\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e复制 /Users/用户/Library/Application\\ Support/Sublime\\ Text\\ 3/Local/Session.sublime_session 这个就是之前没有保存的数据，通过复制/Users/用户/Library/Application\\ Support/Sublime\\ Text\\ 3/下面的所有内容，来恢复插件等等！！\n\u003c/code\u003e\u003c/pre\u003e","title":"常用工具配置"},{"content":" nginx是通过alias设置虚拟目录，在nginx的配置中，alias目录和root目录是有区别的： 1）alias指定的目录是准确的，即location匹配访问的path目录下的文件直接是在alias目录下查找的； 2）root指定的目录是location匹配访问的path目录的上一级目录,这个path目录一定要是真实存在root指定目录下的； 3）使用alias标签的目录块中不能使用rewrite的break（具体原因不明）；另外，alias指定的目录后面必须要加上”/”符号！！ 4）alias虚拟目录配置中，location匹配的path目录如果后面不带”/”，那么访问的url地址中这个path目录后面加不加”/”不影响访问，访问时它会自动加上”/”； 但是如果location匹配的path目录后面加上”/”，那么访问的url地址中这个path目录必须要加上”/”，访问时它不会自动加上”/”。如果不加上”/”，访问就会失败！ 5）root目录配置中，location匹配的path目录后面带不带”/”，都不会影响访问。\n举例说明（比如nginx配置的域名是www.wangshibo.com）： （1） location /huan/ { alias /home/www/huan/; }\n在上面alias虚拟目录配置下，访问http://www.wangshibo.com/huan/a.html实际指定的是/home/www/huan/a.html。 注意：alias指定的目录后面必须要加上”/”，即/home/www/huan/不能改成/home/www/huan\n上面的配置也可以改成root目录配置，如下，这样nginx就会去/home/www/huan下寻找http://www.wangshibo.com/huan的访问资源，两者配置后的访问效果是一样的！ location /huan/ { root /home/www/; }\n（2） 上面的例子中alias设置的目录名和location匹配访问的path目录名一致，这样可以直接改成root目录配置；那要是不一致呢？ 再看一例： location /web/ { alias /home/www/html/; }\n访问http://www.wangshibo.com/web的时候就会去/home/www/html/下寻找访问资源。 这样的话，还不能直接改成root目录配置。 如果非要改成root目录配置，就只能在/home/www下将html-\u0026gt;web（做软连接，即快捷方式），如下： location /web/ { root /home/www/; }\n# ln -s /home/www/web /home/www/html //即保持/home/www/web和/home/www/html内容一直 所以，一般情况下，在nginx配置中的良好习惯是： 1）在location /中配置root目录； 2）在location /path中配置alias虚拟目录。\n如下一例： server { listen 80; server_name www.wangshibo.com; index index.html index.php index.htm; access_log /usr/local/nginx/logs/image.log;\nlocation / { root /var/www/html; }\nlocation /haha { //匹配的path目录haha不需要真实存在alias指定的目录中 alias /var/www/html/ops/; //后面的”/”符号一定要带上 rewrite ^/opp/hen.php(.*)/opp/hen.php?s=1 last;\nrewrite ^/opp/(.*)/opp/hen.php?s=1 last; }\nlocation /wang { //匹配的path目录wang一定要真实存在root指定的目录中（就/var/www/html下一定要有wang目录存在） root /var/www/html; }\n} ","permalink":"https://blog.zdltech.com/posts/nginx%E8%99%9A%E6%8B%9F%E7%9B%AE%E5%BD%95alias%E5%92%8Croot%E7%9B%AE%E5%BD%95/","summary":"\u003cdiv id=\"cnblogs_post_body\" class=\"blogpost-body\"\u003e\n\u003cpre\u003e\u003ccode\u003enginx是通过alias设置虚拟目录，在nginx的配置中，alias目录和root目录是有区别的：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e1）alias指定的目录是准确的，即location匹配访问的path目录下的文件直接是在alias目录下查找的；\n2）root指定的目录是location匹配访问的path目录的上一级目录,这个path目录一定要是真实存在root指定目录下的；\n3）使用alias标签的目录块中不能使用rewrite的break（具体原因不明）；另外，alias指定的目录后面必须要加上”/”符号！！\n4）alias虚拟目录配置中，location匹配的path目录如果后面不带”/”，那么访问的url地址中这个path目录后面加不加”/”不影响访问，访问时它会自动加上”/”；\n但是如果location匹配的path目录后面加上”/”，那么访问的url地址中这个path目录必须要加上”/”，访问时它不会自动加上”/”。如果不加上”/”，访问就会失败！\n5）root目录配置中，location匹配的path目录后面带不带”/”，都不会影响访问。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e举例说明（比如nginx配置的域名是www.wangshibo.com）：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e（1）\nlocation /huan/ {\nalias /home/www/huan/;\n}\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e在上面alias虚拟目录配置下，访问http://www.wangshibo.com/huan/a.html实际指定的是/home/www/huan/a.html。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e注意：alias指定的目录后面必须要加上”/”，即/home/www/huan/不能改成/home/www/huan\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e上面的配置也可以改成root目录配置，如下，这样nginx就会去/home/www/huan下寻找http://www.wangshibo.com/huan的访问资源，两者配置后的访问效果是一样的！\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003elocation /huan/ {\nroot /home/www/;\n}\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e（2）\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上面的例子中alias设置的目录名和location匹配访问的path目录名一致，这样可以直接改成root目录配置；那要是不一致呢？\n再看一例：\nlocation /web/ {\nalias /home/www/html/;\n}\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e访问http://www.wangshibo.com/web的时候就会去/home/www/html/下寻找访问资源。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这样的话，还不能直接改成root目录配置。\n如果非要改成root目录配置，就只能在/home/www下将html-\u0026gt;web（做软连接，即快捷方式），如下：\nlocation /web/ {\nroot /home/www/;\n}\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e# ln -s /home/www/web /home/www/html       //即保持/home/www/web和/home/www/html内容一直\n\n\n\n\n\n所以，一般情况下，在nginx配置中的良好习惯是：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e1）在location /中配置root目录；\n2）在location /path中配置alias虚拟目录。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e如下一例：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eserver {\nlisten 80;\nserver_name \u003ca href=\"https://www.wangshibo.com\"\u003ewww.wangshibo.com\u003c/a\u003e;\nindex index.html index.php index.htm;\naccess_log /usr/local/nginx/logs/image.log;\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003elocation / {\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eroot /var/www/html;\n}\u003c/p\u003e","title":"Nginx虚拟目录alias和root目录"},{"content":"Android 分包导致低于5.0版本报错ClassNotFoundException 项目在4.4系统运行就报错，在5.0以上没问题。原因就是 报错ClassNotFoundException\n方法数超64K（1K=1024,65536刚好是64K）;需要分包操作\n解决方案 1、在module下的build.gradle文件 ，添加multiDexEnabled true\n`defaultConfig {` ` ``applicationId ``\"com.haxi.mh\"` ` ``minSdkVersion ``15` ` ``targetSdkVersion ``26` ` ``versionCode ``1` ` ``versionName ``\"1.0.0\"` ` ``testInstrumentationRunner ``\"android.support.test.runner.AndroidJUnitRunner\"` ` ``// dex突破65535的限制` ` ``multiDexEnabled ``true` ` ``ndk {` ` ``// 设置支持的SO库架构` ` ``abiFilters ``'armeabi'` `//, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'` ` ``}` ` ``}` 2.兼容低版本（在build.gradle中 android代码库中，和defaultConfig同级） `//分包兼容低版本` `dexOptions {` ` ``javaMaxHeapSize ``\"4g\"` ` ``jumboMode = ``true` `}` 3.添加依赖包 `/* multidex兼容包，配合AndroidStudio实现了一个APK包含多个dex的功能 */` ` ``compile ``'com.android.support:multidex:1.0.1'` `4.让自己的Application继承MultiDexApplication类，或者在Application下重新attachBaseContext（Context base）方法，初始化 MultiDex.install(this); ` `@Override` `protected``void``attachBaseContext(Context base) {` ` ``super``.attachBaseContext(base);` ` ``MultiDex.install(base);` `}` 其他： 此外，有没有办法指定某些类被分包到主dex呢？有，在app目录下创建一个maindexlist.txt，我们在这个txt里将我们想要放在主dex中的类写进去即可，为了方便减少错误的出现，可以在在\\app\\build\\intermediates\\multi-dex\\debug目录下找到了一个maindexlist.txt，注意，这个你直接在改了没用，一运行又恢复了，你要的做的是将这个maindexlist.txt复制到app目录下，在进行添加添加指定类即可， 参考: [https://www.2cto.com/kf/201712/707967.html](https://www.2cto.com/kf/201712/707967.html) [https://stackoverflow.com/questions/35225939/android-multidex-classnotfoundexception](https://stackoverflow.com/questions/35225939/android-multidex-classnotfoundexception) [http://blog.csdn.net/daitu_liang/article/details/72987378](http://blog.csdn.net/daitu_liang/article/details/72987378) ","permalink":"https://blog.zdltech.com/posts/android-%E5%88%86%E5%8C%85%E5%A4%9Adex%E5%A4%84%E7%90%86/","summary":"\u003ch4 id=\"android-分包导致低于50版本报错classnotfoundexception\"\u003eAndroid 分包导致低于5.0版本报错ClassNotFoundException\u003c/h4\u003e\n\u003cblockquote\u003e\n\u003cp\u003e项目在4.4系统运行就报错，在5.0以上没问题。原因就是 报错ClassNotFoundException\u003c/p\u003e\n\u003cp\u003e方法数超64K（1K=1024,65536刚好是64K）;需要分包操作\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch4 id=\"解决方案\"\u003e解决方案\u003c/h4\u003e\n\u003cp\u003e1、在module下的build.gradle文件 ，添加multiDexEnabled true\u003c/p\u003e\n\u003cdiv class=\"line number1 index0 alt2\"\u003e\n  `defaultConfig {`\n\u003c/div\u003e\n\u003cdiv class=\"line number2 index1 alt1\"\u003e\n  `        ``applicationId ``\"com.haxi.mh\"`\n\u003c/div\u003e\n\u003cdiv class=\"line number3 index2 alt2\"\u003e\n  `        ``minSdkVersion ``15`\n\u003c/div\u003e\n\u003cdiv class=\"line number4 index3 alt1\"\u003e\n  `        ``targetSdkVersion ``26`\n\u003c/div\u003e\n\u003cdiv class=\"line number5 index4 alt2\"\u003e\n  `        ``versionCode ``1`\n\u003c/div\u003e\n\u003cdiv class=\"line number6 index5 alt1\"\u003e\n  `        ``versionName ``\"1.0.0\"`\n\u003c/div\u003e\n\u003cdiv class=\"line number7 index6 alt2\"\u003e\n  `        ``testInstrumentationRunner ``\"android.support.test.runner.AndroidJUnitRunner\"`\n\u003c/div\u003e\n\u003cdiv class=\"line number8 index7 alt1\"\u003e\n  `        ``// dex突破65535的限制`\n\u003c/div\u003e\n\u003cdiv class=\"line number9 index8 alt2\"\u003e\n  `        ``multiDexEnabled ``true`\n\u003c/div\u003e\n\u003cdiv class=\"line number10 index9 alt1\"\u003e\n  `        ``ndk {`\n\u003c/div\u003e\n\u003cdiv class=\"line number11 index10 alt2\"\u003e\n  `            ``// 设置支持的SO库架构`\n\u003c/div\u003e\n\u003cdiv class=\"line number12 index11 alt1\"\u003e\n  `            ``abiFilters ``'armeabi'` `//, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'`\n\u003c/div\u003e\n\u003cdiv class=\"line number13 index12 alt2\"\u003e\n  `        ``}`\n\u003c/div\u003e\n\u003cdiv class=\"line number14 index13 alt1\"\u003e\n  `    ``}`\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  2.兼容低版本（在build.gradle中 android代码库中，和defaultConfig同级）\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"line number1 index0 alt2\"\u003e\n    `//分包兼容低版本`\n  \u003c/div\u003e\n  \u003cdiv class=\"line number2 index1 alt1\"\u003e\n    `dexOptions {`\n  \u003c/div\u003e\n  \u003cdiv class=\"line number3 index2 alt2\"\u003e\n    `    ``javaMaxHeapSize ``\"4g\"`\n  \u003c/div\u003e\n  \u003cdiv class=\"line number4 index3 alt1\"\u003e\n    `    ``jumboMode = ``true`\n  \u003c/div\u003e\n  \u003cdiv class=\"line number5 index4 alt2\"\u003e\n    `}`\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  3.添加依赖包\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"line number1 index0 alt2\"\u003e\n    `/* multidex兼容包，配合AndroidStudio实现了一个APK包含多个dex的功能 */`\n  \u003c/div\u003e\n  \u003cdiv class=\"line number2 index1 alt1\"\u003e\n    ` ``compile ``'com.android.support:multidex:1.0.1'`\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  `4.让自己的Application继承MultiDexApplication类，或者在Application下重新attachBaseContext（Context base）方法，初始化 MultiDex.install(this); `\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"line number1 index0 alt2\"\u003e\n    `@Override`\n  \u003c/div\u003e\n  \u003cdiv class=\"line number2 index1 alt1\"\u003e\n    `protected``void``attachBaseContext(Context base) {`\n  \u003c/div\u003e\n  \u003cdiv class=\"line number3 index2 alt2\"\u003e\n    `    ``super``.attachBaseContext(base);`\n  \u003c/div\u003e\n  \u003cdiv class=\"line number4 index3 alt1\"\u003e\n    `    ``MultiDex.install(base);`\n  \u003c/div\u003e\n  \u003cdiv class=\"line number5 index4 alt2\"\u003e\n    `}`\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  其他：\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  此外，有没有办法指定某些类被分包到主dex呢？有，在app目录下创建一个maindexlist.txt，我们在这个txt里将我们想要放在主dex中的类写进去即可，为了方便减少错误的出现，可以在在\\app\\build\\intermediates\\multi-dex\\debug目录下找到了一个maindexlist.txt，注意，这个你直接在改了没用，一运行又恢复了，你要的做的是将这个maindexlist.txt复制到app目录下，在进行添加添加指定类即可，\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  参考:\n\u003c/div\u003e\n\u003cdiv\u003e\n  [https://www.2cto.com/kf/201712/707967.html](https://www.2cto.com/kf/201712/707967.html)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  [https://stackoverflow.com/questions/35225939/android-multidex-classnotfoundexception](https://stackoverflow.com/questions/35225939/android-multidex-classnotfoundexception)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  [http://blog.csdn.net/daitu_liang/article/details/72987378](http://blog.csdn.net/daitu_liang/article/details/72987378)\n\u003c/div\u003e","title":"Android 分包（多dex）处理"},{"content":"一、常用设置\n1､日志格式\nlog_format main \u0026#39;\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;time_iso8601|\u0026lt;/span\u0026gt;remote_addr|\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;remote_user|\u0026lt;/span\u0026gt;request_method|\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;uri|\u0026#39; \u0026#39;\u0026lt;/span\u0026gt;status|\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;request_time|\u0026lt;/span\u0026gt;request_length|\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;body_bytes_sent|\u0026lt;/span\u0026gt;bytes_sent|\u0026#39; \u0026#39;\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;connection|\u0026lt;/span\u0026gt;http_x_forwarded_for|\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;upstream_addr|\u0026lt;/span\u0026gt;upstream_status|\u0026#39; \u0026#39;\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;upstream_response_time|\u0026lt;/span\u0026gt;args|\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;http_referer|\u0026lt;/span\u0026gt;http_user_agent\u0026#39;; access_log logs/access.log main; 2､反向代理透传客户端IP设置\nproxy_set_header Host \u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;http_host; proxy_set_header X-Real-IP\u0026lt;/span\u0026gt;remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 3､全局变量\n$args #这个变量等于请求行中的参数。 $content_length #请求头中的Content-length字段。 $content_type #请求头中的Content-Type字段。 $document_root #当前请求在root指令中指定的值。 $host #请求主机头字段，否则为服务器名称。 $http_user_agent #客户端agent信息 $http_cookie #客户端cookie信息 $limit_rate #这个变量可以限制连接速率。 $request_body_file #客户端请求主体信息的临时文件名。 $request_method #客户端请求的动作，通常为GET或POST。 $remote_addr #客户端的IP地址。 $remote_port #客户端的端口。 $remote_user #已经经过Auth Basic Module验证的用户名。 $request_filename #当前请求的文件路径，由root或alias指令与URI请求生成。 $query_string #与$args相同。 $scheme #HTTP方法（如http，https）。 $server_protocol #请求使用的协议，通常是HTTP/1.0或HTTP/1.1。 $server_addr #服务器地址，在完成一次系统调用后可以确定这个值。 $server_name #服务器名称。 $server_port #请求到达服务器的端口号。 $request_uri #包含请求参数的原始URI，不包含主机名，如：”/foo/bar.php?arg=baz”。 $uri #不带请求参数的当前URI，$uri不包含主机名，如”/foo/bar.html”。 $document_uri #与$uri相同。 二、Rewrite规则\n**语法：**rewrite 正则 替换 标志位\nflag标记（rewrite指令的最后一项参数）：\n`1.last last是终止当前location的rewrite检测,但会继续重试location匹配并处理区块中的rewrite规则。`\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; `2.break break是终止当前location的rewrite检测,而且不再进行location匹配。`\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `3.redirect 返回302临时重定向，浏览器地址会显示跳转后的URL地址。` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `4.permanent 返回301永久重定向，浏览器地址会显示跳转后的URL地址。` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 例： \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;cnblogs_code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` 正则匹配 location ~ ^/(a|bb|ccc)/ { rewrite ^/([a-z]+)/(.*)http://106.185.48.229/2?1; }\n注：用括号括起来的参数为后面的1 $2 变量 \u0026lt;/div\u0026gt; **三、反向代理的路由策略** Location的配置： 语法： \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; ``` location [=|~|~*|^~] /uri/ {…} \u0026lt;/div\u0026gt; 语法说明： \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `= 开头表示精确匹配，不支持正则。` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `^~ 开头表示uri以某个常规字符串开头，不支持正则，理解为匹配url路径即可。` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `~和~* 开头表示区分大小写的和不区分大小写的正则匹配。` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `!~和!~* 开头表示区分大小写不匹配及不区分大小写不匹配的正则匹配。` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `/ 通用匹配，任何请求都会匹配，通常放着配置的最后。` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 匹配优先级： \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; **`= \u0026amp;gt; ^~ \u0026amp;gt; ~, ~* \u0026amp;gt; 空`** \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; **`全匹配 \u0026amp;gt; 路径匹配 \u0026amp;gt; 正则匹配 \u0026amp;gt; 字符串匹配`** \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ** ** \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 示例： \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;cnblogs_code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;alert-info\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ``` 字符串匹配 location /static { alias /home/www/static; access_log off; }\n路径匹配，此时proxy_pass的结束 / 决定是否带上匹配的路径 location ^~ /333/ { proxy_pass http://106.185.48.229/; }\n正则匹配，此时proxy_pass不能带结束 / location ~ ^/(xxx|yyy)/ { proxy_pass http://106.185.48.229; }\n字符串匹配，此时proxy_pass的结束 / 决定是否带上匹配得路径 location /zzz/ { proxy_pass http://106.185.48.229/; }\n默认匹配 location / { proxy_pass http://127.0.0.1:8080; }\n\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/nginx%E5%BA%94%E7%94%A8%E4%B9%8Blocation%E8%B7%AF%E7%94%B1%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%E5%8F%8A%E9%87%8D%E5%86%99%E7%AD%96%E7%95%A5/","summary":"\u003cp\u003e\u003cstrong\u003e一、常用设置\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e1､日志格式\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n    \u003cdiv class=\"alert-info\"\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elog_format main \u0026#39;\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;time_iso8601|\u0026lt;/span\u0026gt;remote_addr|\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;remote_user|\u0026lt;/span\u0026gt;request_method|\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;uri|\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026#39;\u0026lt;/span\u0026gt;status|\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;request_time|\u0026lt;/span\u0026gt;request_length|\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;body_bytes_sent|\u0026lt;/span\u0026gt;bytes_sent|\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026#39;\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;connection|\u0026lt;/span\u0026gt;http_x_forwarded_for|\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;upstream_addr|\u0026lt;/span\u0026gt;upstream_status|\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026#39;\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;upstream_response_time|\u0026lt;/span\u0026gt;args|\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;http_referer|\u0026lt;/span\u0026gt;http_user_agent\u0026#39;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eaccess_log  logs/access.log  main;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp\u003e2､反向代理透传客户端IP设置\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n    \u003cdiv class=\"alert-info\"\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eproxy_set_header Host \u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;http_host;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eproxy_set_header X-Real-IP\u0026lt;/span\u0026gt;remote_addr;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp\u003e3､全局变量\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n    \u003cdiv class=\"alert-info\"\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$args #这个变量等于请求行中的参数。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$content_length #请求头中的Content-length字段。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$content_type #请求头中的Content-Type字段。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$document_root #当前请求在root指令中指定的值。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$host #请求主机头字段，否则为服务器名称。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$http_user_agent #客户端agent信息\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$http_cookie #客户端cookie信息\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$limit_rate #这个变量可以限制连接速率。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$request_body_file #客户端请求主体信息的临时文件名。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$request_method #客户端请求的动作，通常为GET或POST。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$remote_addr #客户端的IP地址。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$remote_port #客户端的端口。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$remote_user #已经经过Auth Basic Module验证的用户名。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$request_filename #当前请求的文件路径，由root或alias指令与URI请求生成。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$query_string #与$args相同。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$scheme #HTTP方法（如http，https）。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$server_protocol #请求使用的协议，通常是HTTP/1.0或HTTP/1.1。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$server_addr #服务器地址，在完成一次系统调用后可以确定这个值。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$server_name #服务器名称。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$server_port #请求到达服务器的端口号。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$request_uri #包含请求参数的原始URI，不包含主机名，如：”/foo/bar.php?arg=baz”。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$uri #不带请求参数的当前URI，$uri不包含主机名，如”/foo/bar.html”。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$document_uri #与$uri相同。\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003e二、Rewrite规则\u003c/strong\u003e\u003c/p\u003e","title":"Nginx应用之Location路由反向代理及重写策略"},{"content":"一、升级本地cocopod到最新版本\n1、先切换gem源\ngem source -a https://gems.ruby-china.org\n查看是否切换成功\ngem source -l\n打印出*\\* CURRENT SOURCES **\nhttps://gems.ruby-china.org\n就说明切换成功，如果还是官方的源, 请手动重启电脑尝试\n2、接下来就可以开始升级了cocoapods了\n3、然后敲下\n4、剩下的就是设置pod仓库了\npod setup 重新设置下 pod仓库\n二、cocopod升级到指定的指定版本\n1、在终端输入：sudo gem uninstall cocoapods\n显示所有的版本，输入相应的数字，删除不想要的版本\n2、在终端输入：sudo gem install cocoapods -v指定版本号\n输出：Fetching: cocoapods-1.1.1.gem (100%)\nERROR: While executing gem … (Errno::EPERM)\n3、上面的方法不行，那咱们就换一种输入：sudo gem install -n /usr/local/bin cocoapods -v 指定版本\n","permalink":"https://blog.zdltech.com/posts/cocospod-%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E4%B8%8E%E6%9B%B4%E6%96%B0%E5%88%B0%E6%8C%87%E5%AE%9A%E7%89%88%E6%9C%AC/","summary":"\u003cp\u003e一、升级本地cocopod到最新版本\u003c/p\u003e\n\u003cp\u003e1、先切换gem源\u003c/p\u003e\n\u003cp\u003egem source -a \u003ca href=\"https://gems.ruby-china.org\"\u003ehttps://gems.ruby-china.org\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e查看是否切换成功\u003c/p\u003e\n\u003cp\u003egem source -l\u003c/p\u003e\n\u003cp\u003e打印出*\\\u003cem\u003e* CURRENT SOURCES **\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://gems.ruby-china.org\"\u003ehttps://gems.ruby-china.org\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e就说明切换成功，如果还是官方的源, 请手动重启电脑尝试\u003c/p\u003e\n\u003cp\u003e2、接下来就可以开始升级了cocoapods了\u003c/p\u003e\n\u003cp\u003e3、然后敲下\u003c/p\u003e\n\u003cp\u003e4、剩下的就是设置pod仓库了\u003c/p\u003e\n\u003cp\u003epod setup 重新设置下 pod仓库\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e二、cocopod升级到指定的指定版本\u003c/p\u003e\n\u003cp\u003e1、在终端输入：sudo gem uninstall cocoapods\u003c/p\u003e\n\u003cp\u003e显示所有的版本，输入相应的数字，删除不想要的版本\u003c/p\u003e\n\u003cp\u003e2、在终端输入：sudo gem install cocoapods -v指定版本号\u003c/p\u003e\n\u003cp\u003e输出：Fetching: cocoapods-1.1.1.gem (100%)\u003c/p\u003e\n\u003cp\u003eERROR:  While executing gem … (Errno::EPERM)\u003c/p\u003e\n\u003cp\u003e3、上面的方法不行，那咱们就换一种输入：sudo gem install -n /usr/local/bin cocoapods -v 指定版本\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e","title":"cocospod 版本更新与更新到指定版本"},{"content":"第一步：查找apk的包名\nadb shell pm list package\n查找所有安装的包名\nadb shell pm list package -3\n查找所有安装的第三方的包名\nadb shell ps\n查找正在执行的进程\nadb shell dumpsys activity activities ，它会列出当前手机中所有正在运行的应用的详细信息，按打开顺序排列，最后打开的APK信息会放在输出的最前面。\n第二步根据包名或者到安装的路径\nadb shell path 包名 （例如adb shell pm path phxDroid.phxDroid）\n第三步导出\nadb pull apk的路径 apk导出路径 （例如 adb pull /data/app/phxDroid.phxDroid-1.apk ~/Desktop/ 导出apk到桌面）\n","permalink":"https://blog.zdltech.com/posts/android-%E4%BD%BF%E7%94%A8%E5%91%BD%E4%BB%A4%E6%9F%A5%E6%89%BEapk/","summary":"\u003cp\u003e第一步：查找apk的包名\u003cbr\u003e\nadb shell pm list package\u003cbr\u003e\n查找所有安装的包名\u003cbr\u003e\nadb shell pm list package -3\u003cbr\u003e\n查找所有安装的第三方的包名\u003cbr\u003e\nadb shell ps\u003cbr\u003e\n查找正在执行的进程\u003cbr\u003e\nadb shell dumpsys activity activities ，它会列出当前手机中所有正在运行的应用的详细信息，按打开顺序排列，最后打开的APK信息会放在输出的最前面。\u003c/p\u003e\n\u003cp\u003e第二步根据包名或者到安装的路径\u003cbr\u003e\nadb shell path 包名 （例如adb shell pm path phxDroid.phxDroid）\u003c/p\u003e\n\u003cp\u003e第三步导出\u003cbr\u003e\nadb pull apk的路径 apk导出路径 （例如 adb pull /data/app/phxDroid.phxDroid-1.apk ~/Desktop/ 导出apk到桌面）\u003c/p\u003e","title":"android 使用命令查找apk"},{"content":"先上张图片\n制作mac下面确定Jenkis的应用\non run {input, parameters}\ndisplay dialog “输入执行动作：（1是启动，2是关闭）.” default answer “1” buttons {“确定”, “取消”} with title “启动Jenkins” default button 1\nif the button returned of the result is “确定” then\nset executeType to text returned of the result\nend if\nend run\necho +———————————————————-+\necho + 1是启动，2是停止 +\necho +———————————————————-+\nprintf ‘Input your want execute Parameter:’\nread executeType\nprintf ‘you Input 类型 is executeType’ printf “\\n”\ncd /Users/jason/Documents/developer_tools/Tomcat/bin pwd\nif [[executeType == 1 ]];then ./startup.sh printf 启动成功 printf “\\n” else ./shutdown.sh printf “关闭成功” printf “\\n” fi\nmac制作截图工具 on run {input, parameters}\ndisplay dialog “输入文件的名称（例如1、2）.” default answer “1” buttons {“确定”, “取消”} with title “Android 截图” default button 1 if the button returned of the result is “确定” then set executeType to text returned of the result end if end run\n#!/bin/sh\necho +———————————————————-+ echo + 输入名称 + echo +———————————————————-+ printf “Input your want execute Parameter:” read executeType printf “you Input 名称 is executeType” printf “\\n” cd ~/Desktop/ /Users/jason/Documents/developer_tools/adt-bundle-mac-x86_64-20140702/sdk/platform-tools/adb shell screencap -p | perl -pe ‘s/\\x0D\\x0A/\\x0A/g’\u0026gt;executeType.png\nadb shell screencap -p 手机上路径\n电脑上路径 adb shell screencap -p | perl -pe ‘s/\\x0D\\x0A/\\x0A/g’ \u0026gt; $executeType.png\n其他\non run {input, parameters}\ndisplay alert “《” \u0026amp; (input as text) \u0026amp; “》” \u0026amp; “输入参数” //弹出提醒对话框 end run\non run {input, parameters} tell application “Terminal” //打开指定的应用，需要添加双引号 activate end tell return input end run\n欢迎交流指正：411437734@qq.com\n","permalink":"https://blog.zdltech.com/posts/mac%E4%B8%8B%E5%88%B6%E4%BD%9C%E7%AE%80%E5%8D%95%E7%9A%84ox%E5%BA%94%E7%94%A8/","summary":"\u003cp\u003e先上张图片\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.zdltech.com/blogphp/images/2017/12/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7-2017-12-06-15.43.23.png\"\u003e\u003cimg loading=\"lazy\" src=\"http://www.zdltech.com/blogphp/images/2017/12/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7-2017-12-06-15.43.23-300x205.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e制作mac下面确定Jenkis的应用\u003cbr\u003e\non run {input, parameters}\u003c/p\u003e\n\u003cp\u003edisplay dialog “输入执行动作：（1是启动，2是关闭）.” default answer “1” buttons {“确定”, “取消”} with title “启动Jenkins” default button 1\u003cbr\u003e\nif the button returned of the result is “确定” then\u003cbr\u003e\nset executeType to text returned of the result\u003cbr\u003e\nend if\u003cbr\u003e\nend run\u003c/p\u003e\n\u003cp\u003eecho +———————————————————-+\u003cbr\u003e\necho + 1是启动，2是停止 +\u003cbr\u003e\necho +———————————————————-+\u003cbr\u003e\nprintf ‘Input your want execute Parameter:’\u003cbr\u003e\nread executeType\u003cbr\u003e\nprintf ‘you Input 类型 is \u003cspan class=\"katex math inline\"\u003eexecuteType’\nprintf “\\n”\u003c/p\u003e\n\u003cp\u003ecd /Users/jason/Documents/developer_tools/Tomcat/bin\npwd\u003c/p\u003e","title":"Mac下制作简单的ox应用"},{"content":"java执行jar文件命令\njava -jar 文件.jar\n到此就成功执行jar了，\n我的jar中有多个入口，我想执行其他的入口，怎么搞？\n不着急慢慢看下去\njava运行jar包中指定Class的main方法，这时可以通过：\njava -cp xxx.jar xxx.com.xxxx [args]\n其中-cp命令是将xxx.jar加入到classpath，这样java class loader就会在这里面查找匹配的类。\nmac中执行apple script运行jar的命令\non run {input, parameters}\nset p to POSIX path of (path to me)\ndo shell script “java -jar ” \u0026amp; p \u0026amp; “Contents/Jar/JavaSwingTest.jar”\nend run\n","permalink":"https://blog.zdltech.com/posts/java-%E6%89%A7%E8%A1%8C%E8%BF%90%E8%A1%8Cjar%E6%96%87%E4%BB%B6/","summary":"\u003cp\u003ejava执行jar文件命令\u003c/p\u003e\n\u003cp\u003ejava -jar  文件.jar\u003c/p\u003e\n\u003cp\u003e到此就成功执行jar了，\u003c/p\u003e\n\u003cp\u003e我的jar中有多个入口，我想执行其他的入口，怎么搞？\u003c/p\u003e\n\u003cp\u003e不着急慢慢看下去\u003c/p\u003e\n\u003cp\u003ejava运行jar包中指定Class的main方法，这时可以通过：\u003c/p\u003e\n\u003cp\u003ejava -cp  xxx.jar   xxx.com.xxxx [args]\u003c/p\u003e\n\u003cp\u003e其中-cp命令是将xxx.jar加入到classpath，这样java class loader就会在这里面查找匹配的类。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003emac中执行apple script运行jar的命令\u003c/p\u003e\n\u003cp\u003eon run {input, parameters}\u003cbr\u003e\nset p to POSIX path of (path to me)\u003cbr\u003e\ndo shell script “java -jar ” \u0026amp; p \u0026amp; “Contents/Jar/JavaSwingTest.jar”\u003cbr\u003e\nend run\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Java 执行运行Jar文件"},{"content":"使用mac中自带的工具iconutil\niconutil -c icns iconset文件夹\n生成icns文件\n例如：iconutil -c icns abc.iconset\niconutil -c iconset icns文件\n生成iconset文件夹，里面包含多种png图片\n制作iconset文件时文件中文件名称必须是下面的命名，否则可能转换不成功\nFilename Image Size (in pixels)\nicon_512x512@2x.png 1024 x 1024\nicon_512x512.png 512 x 512\nicon_256x256@2x.png 512 x 512\nicon_256x256.png 256 x 256\nicon_128x128@2x.png 256 x 256\nicon_128x128.png 128 x 128\nicon_32x32@2x.png 64 x 64\nicon_32x32.png 32 x 32\nicon_16x16@2x.png 32 x 32\nicon_16x16.png 16 x 16\n这样就可以生成icns文件，我们就可以替换mac下的app的图标了\n步骤为；\n1.选择应用\n2.右键-点击显示简介\n3.拖动生成的icns文件到简介的左上角的图标处\n4.看看应用的图标是否已经替换了，~~\n记录下，防止大家走弯路~~\n","permalink":"https://blog.zdltech.com/posts/mac-%E4%B8%8B%E5%88%B6%E4%BD%9Cicns-%E5%9B%BE%E6%A0%87/","summary":"\u003cp\u003e使用mac中自带的工具iconutil\u003c/p\u003e\n\u003cp\u003eiconutil  -c  icns  iconset文件夹\u003c/p\u003e\n\u003cp\u003e生成icns文件\u003c/p\u003e\n\u003cp\u003e例如：iconutil -c icns abc.iconset\u003c/p\u003e\n\u003cp\u003eiconutil  -c  iconset  icns文件\u003c/p\u003e\n\u003cp\u003e生成iconset文件夹，里面包含多种png图片\u003c/p\u003e\n\u003cp\u003e制作iconset文件时文件中文件名称必须是下面的命名，否则可能转换不成功\u003c/p\u003e\n\u003cp\u003eFilename                                       Image Size (in pixels)\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"mailto:icon_512x512@2x.png\"\u003eicon_512x512@2x.png\u003c/a\u003e                 1024 x 1024\u003c/p\u003e\n\u003cp\u003eicon_512x512.png                         512 x 512\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"mailto:icon_256x256@2x.png\"\u003eicon_256x256@2x.png\u003c/a\u003e                 512 x 512\u003c/p\u003e\n\u003cp\u003eicon_256x256.png                         256 x 256\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"mailto:icon_128x128@2x.png\"\u003eicon_128x128@2x.png\u003c/a\u003e                 256 x 256\u003c/p\u003e\n\u003cp\u003eicon_128x128.png                         128 x 128\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"mailto:icon_32x32@2x.png\"\u003eicon_32x32@2x.png\u003c/a\u003e                          64 x 64\u003c/p\u003e\n\u003cp\u003eicon_32x32.png                                32 x 32\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"mailto:icon_16x16@2x.png\"\u003eicon_16x16@2x.png\u003c/a\u003e                        32 x 32\u003c/p\u003e\n\u003cp\u003eicon_16x16.png                                16 x 16\u003c/p\u003e\n\u003cp\u003e这样就可以生成icns文件，我们就可以替换mac下的app的图标了\u003c/p\u003e\n\u003cp\u003e步骤为；\u003c/p\u003e\n\u003cp\u003e1.选择应用\u003c/p\u003e\n\u003cp\u003e2.右键-点击显示简介\u003c/p\u003e\n\u003cp\u003e3.拖动生成的icns文件到简介的左上角的图标处\u003c/p\u003e\n\u003cp\u003e4.看看应用的图标是否已经替换了，~~\u003c/p\u003e\n\u003cp\u003e记录下，防止大家走弯路~~\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Mac 下制作icns 图标"},{"content":"搞了一上午终于搞定了腾讯云企业邮箱的发送，话说腾讯云的东西就是繁琐，但是好用，还是得认真看文档啊，不然真的摸不着北。\n腾讯企业邮箱官网：http://exmail.qq.com\n点击开通\n你跟着步骤走就行了，没啥难的，如果你没有域名，你就去买一个呗，也花不了多少钱的。\n注册成功后，是这个页面，并且会有一个弹窗告诉你一些信息\n现在你点击添加成员，因为你不添加成员的话你是无法发送邮件的。\n完成后是这样\n然后你打开腾讯企业邮箱登录界面，输入你刚才增加的成员邮箱的：登录名 + 密码，进去后是一个类似于普通QQ邮箱的界面\n第一次进去会要求重新设置密码，设置一下就好了。默认的已经开通了SSL协议；\n如何设置IMAP、POP3/SMTP及其SSL加密方式？ 如果您的电子邮件客户端支持SSL，可以在设置中选择使用SSL。 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; **通用配置参数：** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **（我们已经默认都支持这些协议，用户无需自己手动开启这些服务器与端口）** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **POP3/SMTP协议** \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; 接收邮件服务器：pop.exmail.qq.com ，使用SSL，端口号995 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 发送邮件服务器：smtp.exmail.qq.com ，使用SSL，端口号465 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 海外用户可使用以下服务器 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; 接收邮件服务器：hwpop.exmail.qq.com ，使用SSL，端口号995 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 发送邮件服务器：hwsmtp.exmail.qq.com ，使用SSL，端口号465 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; **IMAP协议** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; 接收邮件服务器：imap.exmail.qq.com ，使用SSL，端口号993 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; 发送邮件服务器：smtp.exmail.qq.com ，使用SSL，端口号465 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 海外用户可使用以下服务器 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; 接收邮件服务器：hwimap.exmail.qq.com ，使用SSL，端口号993 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; 发送邮件服务器：hwsmtp.exmail.qq.com ，使用SSL，端口号465 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; **账户名：**您的企业邮箱账户名，账户名需要填写完整的邮件地址 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **密码：**您的企业邮箱密码 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **电子邮件地址：**您的企业邮箱的完整邮件地址 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 使用SSL协议之前，请您先参考[常用客户端的一般配置方式](http://service.exmail.qq.com/cgi-bin/help?subtype=1\u0026amp;\u0026amp;id=28\u0026amp;\u0026amp;no=1000585)： \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 使用java代码发送邮箱\n","permalink":"https://blog.zdltech.com/posts/java-%E8%85%BE%E8%AE%AF%E4%BC%81%E4%B8%9A%E9%82%AE%E7%AE%B1-javamail%E5%8F%91%E9%80%81%E9%82%AE%E4%BB%B6/","summary":"\u003cp\u003e搞了一上午终于搞定了腾讯云企业邮箱的发送，话说腾讯云的东西就是繁琐，但是好用，还是得认真看文档啊，不然真的摸不着北。\u003c/p\u003e\n\u003cp\u003e腾讯企业邮箱官网：http://exmail.qq.com\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20171011143839038?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhb2RlaG9uZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e点击开通\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20171011143956303?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhb2RlaG9uZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e你跟着步骤走就行了，没啥难的，如果你没有域名，你就去买一个呗，也花不了多少钱的。\u003c/p\u003e\n\u003cp\u003e注册成功后，是这个页面，并且会有一个弹窗告诉你一些信息\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20171011145245058?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhb2RlaG9uZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e现在你点击添加成员，因为你不添加成员的话你是无法发送邮件的。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20171011145428805?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhb2RlaG9uZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e完成后是这样\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20171011145549564?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhb2RlaG9uZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e然后你打开腾讯企业邮箱登录界面，输入你刚才增加的成员邮箱的：登录名 + 密码，进去后是一个类似于普通QQ邮箱的界面\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20171011145620389?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhb2RlaG9uZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e第一次进去会要求重新设置密码，设置一下就好了。默认的已经开通了SSL协议；\u003c/p\u003e\n\u003ch2 id=\"如何设置imappop3smtp及其ssl加密方式\"\u003e如何设置IMAP、POP3/SMTP及其SSL加密方式？\u003c/h2\u003e\n\u003cdiv class=\"answer\"\u003e\n  \u003cdiv\u003e\n    \u003cdiv\u003e\n      如果您的电子邮件客户端支持SSL，可以在设置中选择使用SSL。\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  \u0026lt;div\u0026gt;\n    \u0026lt;div\u0026gt;\n      \u0026lt;div\u0026gt;\n        **通用配置参数：**\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div\u0026gt;\n        **（我们已经默认都支持这些协议，用户无需自己手动开启这些服务器与端口）**\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div\u0026gt;\n        **POP3/SMTP协议**\n\n        \n        \u0026lt;div\u0026gt;\n          \u0026lt;div\u0026gt;\n            接收邮件服务器：pop.exmail.qq.com ，使用SSL，端口号995\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div\u0026gt;\n            发送邮件服务器：smtp.exmail.qq.com ，使用SSL，端口号465\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div\u0026gt;\n            海外用户可使用以下服务器\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div\u0026gt;\n            \u0026lt;div\u0026gt;\n              接收邮件服务器：hwpop.exmail.qq.com ，使用SSL，端口号995\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div\u0026gt;\n              发送邮件服务器：hwsmtp.exmail.qq.com ，使用SSL，端口号465\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div\u0026gt;\n            \u0026lt;div\u0026gt;\n              **IMAP协议**\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div\u0026gt;\n              \u0026lt;div\u0026gt;\n                接收邮件服务器：imap.exmail.qq.com  ，使用SSL，端口号993\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div\u0026gt;\n                \u0026lt;div\u0026gt;\n                  发送邮件服务器：smtp.exmail.qq.com ，使用SSL，端口号465\n                \u0026lt;/div\u0026gt;\n                \n                \u0026lt;div\u0026gt;\n                  海外用户可使用以下服务器\n                \u0026lt;/div\u0026gt;\n                \n                \u0026lt;div\u0026gt;\n                  \u0026lt;div\u0026gt;\n                    接收邮件服务器：hwimap.exmail.qq.com ，使用SSL，端口号993\n                  \u0026lt;/div\u0026gt;\n                  \n                  \u0026lt;div\u0026gt;\n                    \u0026lt;div\u0026gt;\n                      发送邮件服务器：hwsmtp.exmail.qq.com ，使用SSL，端口号465\n                    \u0026lt;/div\u0026gt;\n                    \n                    \u0026lt;div\u0026gt;\n                    \u0026lt;/div\u0026gt;\n                  \u0026lt;/div\u0026gt;\n                \u0026lt;/div\u0026gt;\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      \u0026lt;div\u0026gt;\n        \u0026lt;div\u0026gt;\n          \u0026lt;div\u0026gt;\n            **账户名：**您的企业邮箱账户名，账户名需要填写完整的邮件地址\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div\u0026gt;\n            **密码：**您的企业邮箱密码\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div\u0026gt;\n            **电子邮件地址：**您的企业邮箱的完整邮件地址\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div\u0026gt;\n            使用SSL协议之前，请您先参考[常用客户端的一般配置方式](http://service.exmail.qq.com/cgi-bin/help?subtype=1\u0026amp;\u0026amp;id=28\u0026amp;\u0026amp;no=1000585)：\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e使用java代码发送邮箱\u003c/p\u003e","title":"Java + 腾讯企业邮箱 + javamail发送邮件"},{"content":"这一周过的是够有意思的，先停两天电，然后感冒了，然后项目出Bug了，然后发烧了，呵呵哒，赶紧只能过来写点东西压压惊。鉴于最近正好在研究Android投屏及反像控制和Android双开的技术原理，本周就先写写Android投影以及反向控制的原理了。\n1 目标 Android投影屏幕到电脑 电脑端反向控制Android手机（如QQ，微信，淘宝…) 2 背景 最近在项目小组中遇到一件事，小组有时候需要演示demo供大家参考，当演示Android手机投屏时，就需要借助第三方软件进行投屏，比如说360手机管家的演示功能还有一个神器Vysor(通过Google浏览器投屏并控制手机)，但是随之也会带来问题，通过反编译Vysor的Apk可以看到它是使用adb命令截屏然后通过Async网络库传输屏幕投影给后台，既然有网络操作，如果是公司比较重要的东西，万一第三方在后面偷偷保留了演示录屏（我相信这些应用应该都不会，有职业操守），然后可能就会有自己去做投屏的需求。\n3 预览图 今天写的原理都是经过本人实现过的，目前PC端已经正常工作，并且可以投屏多台Android。Web端通过node.js websocket webrtc HTML实现的目前还在开发中，鉴于之前没怎么用过前端，所以写的比较慢。\n目前测试实时投影在真实机上还可以。\nPC端的动态截图如下。\n![](http://upload-images.jianshu.io/upload_images/2778947-8a87e728b4a3a098.gif?imageMogr2/auto-orient/strip) 时间.gif ![](http://upload-images.jianshu.io/upload_images/2778947-7599f0e5882c029e.gif?imageMogr2/auto-orient/strip) p2 ![](http://upload-images.jianshu.io/upload_images/2778947-81c7dde223025610.gif?imageMogr2/auto-orient/strip) 地图.gif 4 原理图 ![](http://upload-images.jianshu.io/upload_images/2778947-b9c17077a52e9b6a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 原理.png 5 投屏 投影屏幕，可以去传输图像也可以去传输视频，具体使用哪一种就去看你的需求。而投影图像又分为通过ADB命令去截取图像以及通过Android的ImageReader获取图像然后通过网络传输两种方式，所以投屏的实现是有很多种的，你想使用哪一种都是可以的。\n图像流 现在的产品看到他们都是借助手机连线到电脑端的，通过adb直接去截取图片，这样的话就会很快，如果你只是在公司内部用，使用公司的局域网进行通信我觉得也已经够用了，因此也可以实现通过网络Socket直接去传输图像的字节码。但是现在手机分辨率可高了，因此如果你不对图像进行处理直接通过Socket传输的话那么会让PC端投屏变得很卡，因此AndroidClient可以先对图像进行压缩裁剪之后再去传输。\nAndroid端这块我是开启了一个Service，然后通过ImageReader获取屏幕的图像，之后对图片进行裁剪压缩之后再利用Socket传输图像数据信息。其中的基本代码流程如下：\n`virtualDisplay = mediaProjection.createVirtualDisplay(\u0026#34;MainScreen\u0026#34;,width,height,dpi ,DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,imageReader.getSurface() ,null,screenHandler); imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader imageReader) { Log.i(TAG, \u0026#34;call onImageAvailable\u0026#34;); try { //如果有图片那么就获取 img = imageReader.acquireLatestImage(); if (img != null) { //图像处理 //send 数据 } } }` 视频流 起初我采用的就是图片传输，后来想想其实还是有其他方案的，其实可以通过获取Android手机的屏幕视频流通过H264进行编码进行传输给后台Server，这样可以让画面显示的更加流畅。Android Client里面有一个MediaCodec的类以及VirtualDisplay类可以去读取Android的屏幕流，然后转化为H264视频流。\nAndroid端依然是开启一个Service去获取屏幕流，但是编码H264时会有一个坑，就是需要你去手动加入SPS和PPS，之后才是视频帧。此处的处理代码如下\n`//1,get SPS and PPS MediaFormat outputFormat = codec.getOutputFormat(); ByteBuffer sps = outputFormat.getByteBuffer(\u0026#34;csd-0\u0026#34;); // SPS ByteBuffer pps outputFormat.getByteBuffer(\u0026#34;csd-1\u0026#34;); // PPS //2, change ByteBuffer to byte[] ... //3, send byte[] to server by socket ...` 6 反向控制 PC端去控制手机有如下两大块技术：\nAndroid通过USB数据线或者Wifi连接打开ADB，通过本地执行ADB command Android手机root掉，通过Android客户端执行ADB command Adb连接方式有如下两种：\nUsb数据线 Wifi: adb tcpip 5555, adb connect android_ip_address PC应用程序：\nServer端的代码主题逻辑不复杂：通过Socket接收Android 客户端传过来的图像数据信息解压缩显示到Ui上面，当用户点击UI时获取鼠标点击的坐标，通过比例换算转化成实际Android真机的坐标，之后通过ADB执行对应的Command命令，然后Android图像的变化再通过Socket实时传输给Server端记住坐标系变化不要忘记了，一开始我忘记了转化坐标结果显示就不对。\n当然PC端也可以读取Android Client端的H264编码视频流，然后PC端使用FFMPEG这个库去解码，关于FFMPEG库的相关使用，我推荐大家去看看雷霄骅的技术博客，此人在音视频方面给予大家很大的帮助。\nWeb应用程序：\n首先通过在node.js上通过socket获取Android Client端的H264视频流，然后通过WebSocket实时将字节数组传输给WebRtc，通过WebRtc的video标签去显示，题外话：WebRtc也是个好东西，你可以基于它去做很多有意思的东西比如网络视屏以及现在挺热的Android直播，程序员去多折腾折腾还是很有意思的。之后通过js获取鼠标点击的坐标事件，之后的操作和PC很相似了，都是得到命令然后执行，然后AndroidClient再投屏图像，如此循环。\n这大概就是屏幕投影的原理了。并不复杂。关键你要有一颗折腾的心。最近准备把Web端的这块实现完了就来写一篇双开的原理实现。欢迎其他程序员一起入坑一起交流，不管你是学习Android的还是后端的还是前端开发的，都欢迎大家一起交流原理思想，一起学习，一起进步。\n还有本人写博客并不多，所以语法表述之类的还尚待提高，而且今天写的时候烧还没退头一直很懵，还请见谅，欢迎大家提出其他的实现想法以及意见。\n也喜欢你可以加入QQ群大家一起交流交流：94839608\n转载：http://www.bijishequ.com/detail/222725\nandroid屏幕共享及远程控制原理 http://blog.csdn.net/qingchunweiliang/article/details/69210431\n","permalink":"https://blog.zdltech.com/posts/android%E5%B1%8F%E5%B9%95%E6%8A%95%E5%BD%B1%E5%8F%8A%E5%8F%8D%E5%90%91%E6%8E%A7%E5%88%B6%E5%8E%9F%E7%90%86/","summary":"\u003cp\u003e这一周过的是够有意思的，先停两天电，然后感冒了，然后项目出Bug了，然后发烧了，呵呵哒，赶紧只能过来写点东西压压惊。鉴于最近正好在研究Android投屏及反像控制和Android双开的技术原理，本周就先写写Android投影以及反向控制的原理了。\u003c/p\u003e\n\u003ch1 id=\"1-目标\"\u003e1 目标\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003eAndroid投影屏幕到电脑\u003c/li\u003e\n\u003cli\u003e电脑端反向控制Android手机（如QQ，微信，淘宝…)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"2-背景\"\u003e2 背景\u003c/h1\u003e\n\u003cp\u003e最近在项目小组中遇到一件事，小组有时候需要演示demo供大家参考，当演示Android手机投屏时，就需要借助第三方软件进行投屏，比如说360手机管家的演示功能还有一个神器Vysor(通过Google浏览器投屏并控制手机)，但是随之也会带来问题，通过反编译Vysor的Apk可以看到它是使用adb命令截屏然后通过Async网络库传输屏幕投影给后台，既然有网络操作，如果是公司比较重要的东西，万一第三方在后面偷偷保留了演示录屏（我相信这些应用应该都不会，有职业操守），然后可能就会有自己去做投屏的需求。\u003c/p\u003e\n\u003ch1 id=\"3-预览图\"\u003e3 预览图\u003c/h1\u003e\n\u003cp\u003e今天写的原理都是经过本人实现过的，目前PC端已经正常工作，并且可以投屏多台Android。Web端通过node.js websocket webrtc HTML实现的目前还在开发中，鉴于之前没怎么用过前端，所以写的比较慢。\u003c/p\u003e\n\u003cp\u003e目前测试实时投影在真实机上还可以。\u003cbr\u003e\nPC端的动态截图如下。\u003c/p\u003e\n\u003cdiv class=\"image-package\"\u003e\n\u003cpre\u003e\u003ccode\u003e![](http://upload-images.jianshu.io/upload_images/2778947-8a87e728b4a3a098.gif?imageMogr2/auto-orient/strip)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-caption\"\u003e\n    时间.gif\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"image-package\"\u003e\n\u003cpre\u003e\u003ccode\u003e![](http://upload-images.jianshu.io/upload_images/2778947-7599f0e5882c029e.gif?imageMogr2/auto-orient/strip)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-caption\"\u003e\n    p2\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"image-package\"\u003e\n\u003cpre\u003e\u003ccode\u003e![](http://upload-images.jianshu.io/upload_images/2778947-81c7dde223025610.gif?imageMogr2/auto-orient/strip)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-caption\"\u003e\n    地图.gif\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003ch1 id=\"4-原理图\"\u003e4 原理图\u003c/h1\u003e\n\u003cdiv class=\"image-package\"\u003e\n\u003cpre\u003e\u003ccode\u003e![](http://upload-images.jianshu.io/upload_images/2778947-b9c17077a52e9b6a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-caption\"\u003e\n    原理.png\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003ch1 id=\"5-投屏\"\u003e5 投屏\u003c/h1\u003e\n\u003cp\u003e投影屏幕，可以去传输图像也可以去传输视频，具体使用哪一种就去看你的需求。而投影图像又分为通过ADB命令去截取图像以及通过Android的ImageReader获取图像然后通过网络传输两种方式，所以投屏的实现是有很多种的，你想使用哪一种都是可以的。\u003c/p\u003e\n\u003ch2 id=\"图像流\"\u003e图像流\u003c/h2\u003e\n\u003cp\u003e现在的产品看到他们都是借助手机连线到电脑端的，通过adb直接去截取图片，这样的话就会很快，如果你只是在公司内部用，使用公司的局域网进行通信我觉得也已经够用了，因此也可以实现通过网络Socket直接去传输图像的字节码。但是现在手机分辨率可高了，因此如果你不对图像进行处理直接通过Socket传输的话那么会让PC端投屏变得很卡，因此AndroidClient可以先对图像进行压缩裁剪之后再去传输。\u003c/p\u003e\n\u003cp\u003eAndroid端这块我是开启了一个Service，然后通过ImageReader获取屏幕的图像，之后对图片进行裁剪压缩之后再利用Socket传输图像数据信息。其中的基本代码流程如下：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`virtualDisplay = mediaProjection.createVirtualDisplay(\u0026#34;MainScreen\u0026#34;,width,height,dpi\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                ,DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,imageReader.getSurface()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                ,null,screenHandler);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            public void onImageAvailable(ImageReader imageReader) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                Log.i(TAG, \u0026#34;call onImageAvailable\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                try {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    //如果有图片那么就获取\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    img = imageReader.acquireLatestImage();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    if (img != null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                     //图像处理\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                     //send 数据\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"视频流\"\u003e视频流\u003c/h2\u003e\n\u003cp\u003e起初我采用的就是图片传输，后来想想其实还是有其他方案的，其实可以通过获取Android手机的屏幕视频流通过H264进行编码进行传输给后台Server，这样可以让画面显示的更加流畅。Android Client里面有一个MediaCodec的类以及VirtualDisplay类可以去读取Android的屏幕流，然后转化为H264视频流。\u003c/p\u003e","title":"Android屏幕投影及反向控制原理"},{"content":"在nginx配置文件 mime.types中配置\napplication/vnd.android.package-archive apk;\napplication/iphone pxl ipa;\n这样apk在界面中就可以下载并提示安装\n服务器iis支持.apk文件下载的设置\nIIS服务器不能下载.apk文件的原因：iis的默认MIME类型中没有.apk文件，所以无法下载。\nIIS服务器不能下载.apk文件的解决办法：既然.apk无法下载是因为没有MIME，那么添加一个MIME类型就可以了。\nIIS服务器不能下载.apk文件的解决步骤：\n打开IIS服务管理器，找到服务器，右键-属性，打开IIS服务属性；\n单击MIME类型下的“MIME类型”按钮，打开MIME类型设置窗口；\n单击“新建”，建立新的MIME类型；\n扩展名中填写“.apk”,\nMIME类型中填写apk的MIME类型“ application/vnd.android.package-archive ”\n单击“确定”保存设置。\n重启IIS，使设置生效。\n服务器apache支持.apk文件下载的设置\n在Apache安装目录下的conf/mime.types文件的对应位置，加上以下一行语句，指定APK文件的MIME类型为 application/vnd.android.package-archive 即可：\napplication/vnd.android.package-archive apk;\n重启apache即可\n服务器nginx支持.apk文件下载的设置\napk 和 .ipa分别是android应用和ios应用的扩展名。\n如果在浏览器下载这些文件为后缀的文件时，会自动重命名为zip文件。\n当然可以下载后手动修改后缀，依然可以安装。\n如果想下载后缀直接就是apk ipa的，可以修改 /usr/local/nginx/conf目录下的mime.types\n增加如下配置，重启nginx生效\napplication/vnd.android.package-archive apk;\napplication/iphone pxl ipa;\n少人做了Android的APP应用且放在了外网上，但是手机用户通过url找到了apk文件却无法实现下载，也或者下载后无法自动安装。针对这样一些问题今天进行了一个技术性的汇总，希望可以帮到那些为此问题烦恼的Android开发者。\n写了一些 android 的应用放在网站上让人下载，在某些机型上，三星的 android 的 4.0 以上多款机型最普遍, 用安卓自带浏览器下载程序，会提示 “无法打开文件”，导致下载后不能直安装.\n一般性只能采用下面方法解决:\n1、用 UC 来下载安装,但这样就要求客户要用 UC 才可下载及安装我们的系统\n2、叫用户自己在 android 在桌面上，打开文件夹, 则该 apk 点击时即可安装\n问题：某些 android 自带浏览器 , 可能 对下载的 apk 安装进行了限制。 我想通过自己办法，例如修改 apk 或者加某些编译参数，能否解决这种安装的兼容问题 ?\n最终人性化的解决方法：\n(1)、在IIS服务器上，MIME类型中添加一个：\n文件扩展名： .apk\nMIME类型： application/vnd.android.package-archive\n(2)、服务端部署在tomcat下，已经在tomcat的web.xml里面配置了mini type\nview sourceprint?\napk\napplication/vnd.android.package-archive\n按照以上方法，解决了三星手机的下载后，apk无法打开直接安装的问题，同时却发现华为的一款手机使用默认的浏览器下载后仍然无法打开安装，经过多番测试，发现在android的AndroidManifest.xml中，如果缺少targetSdkVersion，华为手机通过默认浏览器下载后无法安装，加上之后一切正常(可见对于不同的android系统是多么的让人纠结啊)\nview sourceprint?\nnginx安装及配置为简单的文件服务器\ncentos 6.5\n直接yum安装即可\nyum install nginx -y\n配置文件位于：/etc/nginx/nginx.conf，里面可以修改处理器数量、日志路径、pid文件路径等，默认的日志：\n错误日志 /var/log/nginx/error.log\n访问日志 /var/log/nginx/access.log\n在nginx.conf末尾有一句：include /etc/nginx/conf.d/*.conf;　推荐把用户自己的配置放到conf.d/\n下面把默认的server修改为一个简单的文件服务器，vi /etc/nginx/conf.d/default.conf，修改监听端口listen和文件目录root\n复制代码\nautoindex on;# 显示目录\nautoindex_exact_size on;# 显示文件大小\nautoindex_localtime on;# 显示文件时间\nserver {\nlisten 8080 default_server;\nlisten [::]:8080 default_server;\nserver_name _;\n#root /usr/share/nginx/html;\nroot /data/file;\n…省略…\n}\n复制代码\n启动nginx\n/etc/init.d/nginx start\n浏览器访问，http://[nginx-ip]:8080，可以看到/data/file目录下的文件，点击可下载：\n另，修改了nginx配置后可以在不影响使用的情况下重载\n/etc/init.d/nginx reload\nnginx作为下载文件服务器\nhttp://blog.csdn.net/zhang_ruiqiang/article/details/48141783\nNginx打开目录浏览功能(autoindex)\nNginx默认是不允许列出整个目录的。如需此功能，打开nginx.conf文件，在location server 或 http段中加入\nautoindex on;\nautoindex_exact_size off;\n默认为on，显示出文件的确切大小，单位是bytes。\n改为off后，显示出文件的大概大小，单位是kB或者MB或者GB\nautoindex_localtime on;\n默认为off，显示的文件时间为GMT时间。\n改为on后，显示的文件时间为文件的服务器时间\n更多请参考：\nhttp://blog.csdn.net/u013410747/article/details/63262561\nhttp://www.jianshu.com/p/248d8e7cb3c4\n自己搭建服务器提供IOS IPA包下载\nhttp://blog.csdn.net/pzlsun/article/details/52080491\n发布测试版本，通过网页在线安装ipa和apk\nhttp://blog.csdn.net/langresser_king/article/details/51351467\nhttp://kailian.github.io/2016/11/04/ipa-install\nhttp://h.farll.com/archives/ota-ios-app-ipk-install-online-https.html\nhttp://www.jianshu.com/p/75f01a638a07\n","permalink":"https://blog.zdltech.com/posts/nginx-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8B%E8%BD%BDapk%E5%92%8Cipa/","summary":"\u003cp\u003e在nginx配置文件 mime.types中配置\u003cbr\u003e\napplication/vnd.android.package-archive apk;\u003cbr\u003e\napplication/iphone pxl ipa;\u003cbr\u003e\n这样apk在界面中就可以下载并提示安装\u003cbr\u003e\n服务器iis支持.apk文件下载的设置\u003cbr\u003e\nIIS服务器不能下载.apk文件的原因：iis的默认MIME类型中没有.apk文件，所以无法下载。\u003cbr\u003e\nIIS服务器不能下载.apk文件的解决办法：既然.apk无法下载是因为没有MIME，那么添加一个MIME类型就可以了。\u003cbr\u003e\nIIS服务器不能下载.apk文件的解决步骤：\u003cbr\u003e\n打开IIS服务管理器，找到服务器，右键-属性，打开IIS服务属性；\u003cbr\u003e\n单击MIME类型下的“MIME类型”按钮，打开MIME类型设置窗口；\u003cbr\u003e\n单击“新建”，建立新的MIME类型；\u003cbr\u003e\n扩展名中填写“.apk”,\u003cbr\u003e\nMIME类型中填写apk的MIME类型“ application/vnd.android.package-archive ”\u003cbr\u003e\n单击“确定”保存设置。\u003cbr\u003e\n重启IIS，使设置生效。\u003cbr\u003e\n服务器apache支持.apk文件下载的设置\u003c/p\u003e\n\u003cp\u003e在Apache安装目录下的conf/mime.types文件的对应位置，加上以下一行语句，指定APK文件的MIME类型为 application/vnd.android.package-archive 即可：\u003cbr\u003e\napplication/vnd.android.package-archive apk;\u003c/p\u003e\n\u003cp\u003e重启apache即可\u003c/p\u003e\n\u003cp\u003e服务器nginx支持.apk文件下载的设置\u003cbr\u003e\napk 和 .ipa分别是android应用和ios应用的扩展名。\u003c/p\u003e\n\u003cp\u003e如果在浏览器下载这些文件为后缀的文件时，会自动重命名为zip文件。\u003c/p\u003e\n\u003cp\u003e当然可以下载后手动修改后缀，依然可以安装。\u003c/p\u003e\n\u003cp\u003e如果想下载后缀直接就是apk ipa的，可以修改 /usr/local/nginx/conf目录下的mime.types\u003c/p\u003e\n\u003cp\u003e增加如下配置，重启nginx生效\u003c/p\u003e\n\u003cp\u003eapplication/vnd.android.package-archive apk;\u003cbr\u003e\napplication/iphone pxl ipa;\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e少人做了Android的APP应用且放在了外网上，但是手机用户通过url找到了apk文件却无法实现下载，也或者下载后无法自动安装。针对这样一些问题今天进行了一个技术性的汇总，希望可以帮到那些为此问题烦恼的Android开发者。\u003cbr\u003e\n写了一些 android 的应用放在网站上让人下载，在某些机型上，三星的 android 的 4.0 以上多款机型最普遍, 用安卓自带浏览器下载程序，会提示 “无法打开文件”，导致下载后不能直安装.\u003cbr\u003e\n一般性只能采用下面方法解决:\u003cbr\u003e\n1、用 UC 来下载安装,但这样就要求客户要用 UC 才可下载及安装我们的系统\u003cbr\u003e\n2、叫用户自己在 android 在桌面上，打开文件夹, 则该 apk 点击时即可安装\u003cbr\u003e\n问题：某些 android 自带浏览器 , 可能 对下载的 apk 安装进行了限制。 我想通过自己办法，例如修改 apk 或者加某些编译参数，能否解决这种安装的兼容问题 ?\u003cbr\u003e\n最终人性化的解决方法：\u003cbr\u003e\n(1)、在IIS服务器上，MIME类型中添加一个：\u003cbr\u003e\n文件扩展名： .apk\u003cbr\u003e\nMIME类型： application/vnd.android.package-archive\u003cbr\u003e\n(2)、服务端部署在tomcat下，已经在tomcat的web.xml里面配置了mini type\u003c/p\u003e","title":"Nginx 配置文件服务器下载apk和ipa"},{"content":" # ToolBar基本使用 关于ToolBar的使用，网上已经非常多了， **\n思路决定出路 so, 思路是这样的： - 隐藏ActionBar，\u0026lt;strong\u0026gt;这里有两种设定方法** - 布局文件中声明， 没什么说的 - 代码中设定一下，没什么说的 可以参考这里学习： Android 5.x Theme 与 ToolBar 实战 Android Toolbar样式定制详解\nToolBar菜单 ToolBar使用菜单，思路长这样： **\n首先在menu/menu_main.xml去声明布局，然后重写onCreateOptionsMenu(inflate该布局)和onOptionsItemSelected(设定其点击事件)即可，当然也可以通过toolbar.setOnMenuItemClickListener实现点击menu的回调。 这里遇到个坑，我只需要有一个菜单，默认设定后颜色为黑色，和橙色的colorPrimary不搭调，然后想着设定为白色，没想到掉坑里去了，其实我不是一个人：[Android中菜单的字体太小了：设置actionbar中menu的text的size](http://www.crifan.com/android_menu_text_size_too_small/)，这位大神很给力，尝试了各种方法，最后搞掂，思路清晰，粗暴但是不简单呐。 我直接从他的解决方法入手，开始搞，然而不是很靠谱，只能修改字体大小，颜色还是黑的，丑爆。 因此来到了这里:Android Toolbar样式定制详解，\n方法就是\u0026lt;strong\u0026gt;`添加 ToolBar 主题`** 这个demo运行，完美解决，但是在我自己的项目里，一直出不来效果，一定是哪里出现了问题。。 没错，确实是我的问题，凡事还是多反思自己，我画蛇添足咯，多写了点东西，是什么呢，你们应该猜到了，我们来看： 首先敲定ToolBar布局，加一个theme： \u0026lt;/android.support.v7.widget.Toolbar\u0026gt;\u0026#34; data-snippet-id=\u0026#34;ext.563df2e6a04501bd3623452810697ad7\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;` \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;android.support.v7.widget.Toolbar\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@+id/toolbar\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;?/attr/actionBarSize\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;?attr/colorPrimary\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;app:theme\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@style/ToolbarTheme\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;android.support.v7.widget.Toolbar\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 然后定义ToolBarTheme样式 注意，此处的坑较多，首先，要有个parent，然后actionMenuTextColor前面**不能有android前缀**，谁加谁怀孕，当然在values-v21/styles.xml里是需要添加android前缀的。 \u0026#34; data-snippet-id=\u0026#34;ext.124cfa678dc23e56377d3d6a603f2c55\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026amp;gt;` \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;\u0026amp;lt;!-- ToolBar菜单样式 --\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;ToolbarTheme\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;parent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@style/ThemeOverlay.AppCompat.ActionBar\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;xml\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;actionMenuTextColor\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;@color/white\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;\u0026amp;lt;!-- 敲定颜色--\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;android:textSize\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;18sp\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;\u0026amp;lt;!-- 搞掂字体大小--\u0026amp;gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;` \u0026amp;lt;item name=\u0026#34;android:textAllCaps\u0026#34;\u0026amp;gt;false\u0026amp;lt;/item\u0026amp;gt; ` \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 好了，这样就可以了，ToolBar 修改菜单字体和颜色完成。 \u0026amp;lt;item name=\u0026#34;android:textAllCaps\u0026#34;\u0026amp;gt;false\u0026amp;lt;/item\u0026amp;gt; 设置防止都是大写 ","permalink":"https://blog.zdltech.com/posts/toolbar-%E4%BF%AE%E6%94%B9%E8%8F%9C%E5%8D%95%E5%AD%97%E4%BD%93%E5%92%8C%E9%A2%9C%E8%89%B2/","summary":"\u003cdiv\u003e\n  # ToolBar基本使用\n  \u003chr /\u003e\n\u003cpre\u003e\u003ccode\u003e关于ToolBar的使用，网上已经非常多了，\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e**\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  思路决定出路\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/blockquote\u003e\n\u003cpre\u003e\u003ccode\u003eso, 思路是这样的：\n\n\n\n\n- 隐藏ActionBar，\u0026lt;strong\u0026gt;这里有两种设定方法**\n\n- 布局文件中声明， 没什么说的\n\n- 代码中设定一下，没什么说的\n\n\n\n\n\n可以参考这里学习：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/45303349\"\u003eAndroid 5.x Theme 与 ToolBar 实战\u003c/a\u003e\n\u003ca href=\"http://www.cnblogs.com/oyjt/p/4762640.html\"\u003eAndroid Toolbar样式定制详解\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"toolbar菜单\"\u003eToolBar菜单\u003c/h1\u003e\n  \u003chr /\u003e\n\u003cpre\u003e\u003ccode\u003eToolBar使用菜单，思路长这样：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e**\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  首先在menu/menu_main.xml去声明布局，然后重写onCreateOptionsMenu(inflate该布局)和onOptionsItemSelected(设定其点击事件)即可，当然也可以通过toolbar.setOnMenuItemClickListener实现点击menu的回调。\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/blockquote\u003e\n\u003cpre\u003e\u003ccode\u003e这里遇到个坑，我只需要有一个菜单，默认设定后颜色为黑色，和橙色的colorPrimary不搭调，然后想着设定为白色，没想到掉坑里去了，其实我不是一个人：[Android中菜单的字体太小了：设置actionbar中menu的text的size](http://www.crifan.com/android_menu_text_size_too_small/)，这位大神很给力，尝试了各种方法，最后搞掂，思路清晰，粗暴但是不简单呐。\n\n\n\n\n\n我直接从他的解决方法入手，开始搞，然而不是很靠谱，只能修改字体大小，颜色还是黑的，丑爆。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e因此来到了这里:\u003ca href=\"http://www.cnblogs.com/oyjt/p/4762640.html\"\u003eAndroid Toolbar样式定制详解\u003c/a\u003e，\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e方法就是\u0026lt;strong\u0026gt;`添加 ToolBar 主题`**\n\n\n\n\n\n这个demo运行，完美解决，但是在我自己的项目里，一直出不来效果，一定是哪里出现了问题。。\n\n\n\n\n\n没错，确实是我的问题，凡事还是多反思自己，我画蛇添足咯，多写了点东西，是什么呢，你们应该猜到了，我们来看：\n\n\n\n\n\n首先敲定ToolBar布局，加一个theme：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003eandroid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eToolbar\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-snippet-id=\u0026#34;\u003c/span\u003eext\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e563\u003c/span\u003edf2e6a04501bd3623452810697ad7\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-snippet-saved=\u0026#34;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-codota-status=\u0026#34;\u003c/span\u003edone\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;`    \u0026amp;lt;span class=\u0026#34;\u003c/span\u003ehljs\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003etag\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ehljs\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ename\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;android.support.v7.widget.Toolbar\u0026amp;lt;/span\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attr\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:id\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;@+id/toolbar\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attr\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_width\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;match_parent\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attr\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_height\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;?/attr/actionBarSize\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attr\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:background\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;?attr/colorPrimary\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attr\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eapp:theme\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;@style/ToolbarTheme\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-tag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-name\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eToolbar\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e然后定义ToolBarTheme样式\n\n\n\n\n\n注意，此处的坑较多，首先，要有个parent，然后actionMenuTextColor前面**不能有android前缀**，谁加谁怀孕，当然在values-v21/styles.xml里是需要添加android前缀的。\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026#34; data-snippet-id=\u0026#34;ext.124cfa678dc23e56377d3d6a603f2c55\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026amp;gt;`    \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;\u0026amp;lt;!-- ToolBar菜单样式 --\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;ToolbarTheme\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;parent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@style/ThemeOverlay.AppCompat.ActionBar\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;xml\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;actionMenuTextColor\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;@color/white\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;\u0026amp;lt;!--  敲定颜色--\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;android:textSize\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;18sp\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;\u0026amp;lt;!--  搞掂字体大小--\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;item name=\u0026#34;android:textAllCaps\u0026#34;\u0026amp;gt;false\u0026amp;lt;/item\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e` \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e好了，这样就可以了，ToolBar 修改菜单字体和颜色完成。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;item name=\u0026#34;android:textAllCaps\u0026#34;\u0026amp;gt;false\u0026amp;lt;/item\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e设置防止都是大写\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"ToolBar 修改菜单字体和颜色"},{"content":" 我们经常会有这样的需求，在切换Fragment或者点击某个按钮后动态更新Toolbar上Menu项.但是onCreateOptionsMenu方法只在创建Activity的时候调用一次，以后就不再调用了，所以就不能在onCreateOptionsMenu中做处理了。 不过系统提供了另外的一个方法onPrepareOptionsMenu,我们可以在这个方法中做一些逻辑处理，然后在需要更新Menu的地方调用invalidateOptionsMenu方法。 效果图如下： 点击`管理专辑`按钮更换Menu, ![](http://images2015.cnblogs.com/blog/902237/201607/902237-20160720181845747-1609503965.png) ``` \u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-meta\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kw\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;dt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onCreateOptionsMenu\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(Menu menu)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;getMenuInflater\u0026amp;lt;/span\u0026gt;().\u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;inflate\u0026amp;lt;/span\u0026gt;(R.\u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;menu\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;menu\u0026amp;lt;/span\u0026gt;, menu); \u0026amp;lt;span class=\u0026quot;kw\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kw\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;onCreateOptionsMenu\u0026amp;lt;/span\u0026gt;(menu); }\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;sourceCode\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-meta\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;dt\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onPrepareOptionsMenu\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Menu menu)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; (mIsEditStatus) { menu.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;findItem\u0026amp;lt;/span\u0026gt;(R.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;id\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;action_share\u0026amp;lt;/span\u0026gt;).\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;setVisible\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;); menu.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;findItem\u0026amp;lt;/span\u0026gt;(R.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;id\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;action_edit\u0026amp;lt;/span\u0026gt;).\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;setVisible\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; { menu.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;findItem\u0026amp;lt;/span\u0026gt;(R.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;id\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;action_share\u0026amp;lt;/span\u0026gt;).\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;setVisible\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;); menu.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;findItem\u0026amp;lt;/span\u0026gt;(R.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;id\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;action_edit\u0026amp;lt;/span\u0026gt;).\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;setVisible\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;onPrepareOptionsMenu\u0026amp;lt;/span\u0026gt;(menu); }` ``` `\u0026lt;span class=\"fu\"\u003einvalidateOptionsMenu\u0026lt;/span\u003e(); \u0026lt;span class=\"co\"\u003e\u0026lt;span class=\"hljs-comment\"\u003e//重新绘制menu\u0026lt;/span\u003e\u0026lt;/span\u003e` ``` 另外的一个需求是在Menu中要显示图标和文字，虽然在`menu.xml`文件中配置了图标和文字，但是在有图标的情况下文字是不会显示的，即使设置 `app:showAsAction=\u0026quot;always|withText\u0026quot;` 但是我在运行的时候发现并没有显示文字，处理方法是通过另外一个属性实现`app:actionLayout`. 首先menu.xml定义如下：\n``` \u0026lt;item android:id=\u0026amp;quot;@+id/action_share\u0026amp;quot; android:title=\u0026amp;quot;分享\u0026amp;quot; android:orderInCategory=\u0026amp;quot;80\u0026amp;quot; android:icon=\u0026amp;quot;@drawable/icon_share_white\u0026amp;quot; app:showAsAction=\u0026amp;quot;always|withText\u0026amp;quot; /\u0026gt; \u0026lt;item android:id=\u0026amp;quot;@+id/action_edit\u0026amp;quot; android:title=\u0026amp;quot;\u0026amp;quot; android:orderInCategory=\u0026amp;quot;60\u0026amp;quot; app:showAsAction=\u0026amp;quot;always\u0026amp;quot; app:actionLayout=\u0026amp;quot;@layout/menu_action_album_edit\u0026amp;quot; /\u0026gt; \" data-snippet-id=\"ext.be441354fd8820bfea71da7e5777101d\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003e`\u0026lt;span class=\"kw\"\u003e\u0026lt;span class=\"hljs-tag\"\u003e\u0026lt;\u0026lt;span class=\"hljs-name\"\u003emenu\u0026lt;/span\u003e\u0026lt;/span\u003e\u0026lt;/span\u003e\u0026lt;span class=\"ot\"\u003e\u0026lt;span class=\"hljs-tag\"\u003e \u0026lt;span class=\"hljs-attr\"\u003exmlns:android\u0026lt;/span\u003e=\u0026lt;/span\u003e\u0026lt;/span\u003e\u0026lt;span class=\"st\"\u003e\u0026lt;span class=\"hljs-tag\"\u003e\u0026lt;span class=\"hljs-string\"\u003e\"http://schemas.android.com/apk/res/android\"\u0026lt;/span\u003e\u0026lt;/span\u003e\u0026lt;/span\u003e \u0026lt;span class=\"ot\"\u003e\u0026lt;span class=\"hljs-tag\"\u003e \u0026lt;span class=\"hljs-attr\"\u003exmlns:app\u0026lt;/span\u003e=\u0026lt;/span\u003e\u0026lt;/span\u003e\u0026lt;span class=\"st\"\u003e\u0026lt;span class=\"hljs-tag\"\u003e\u0026lt;span class=\"hljs-string\"\u003e\"http://schemas.android.com/apk/res-auto\"\u0026lt;/span\u003e\u0026lt;/span\u003e\u0026lt;/span\u003e \u0026lt;span class=\"ot\"\u003e\u0026lt;span class=\"hljs-tag\"\u003e \u0026lt;span class=\"hljs-attr\"\u003exmlns:tools\u0026lt;/span\u003e=\u0026lt;/span\u003e\u0026lt;/span\u003e\u0026lt;span class=\"st\"\u003e\u0026lt;span class=\"hljs-tag\"\u003e\u0026lt;span class=\"hljs-string\"\u003e\"http://schemas.android.com/tools\"\u0026lt;/span\u003e\u0026lt;/span\u003e\u0026lt;/span\u003e \u0026lt;span class=\"ot\"\u003e\u0026lt;span class=\"hljs-tag\"\u003e \u0026lt;span class=\"hljs-attr\"\u003etools:context\u0026lt;/span\u003e=\u0026lt;/span\u003e\u0026lt;/span\u003e\u0026lt;span class=\"st\"\u003e\u0026lt;span class=\"hljs-tag\"\u003e\u0026lt;span class=\"hljs-string\"\u003e\".album.AlbumDetailActivity\"\u0026lt;/span\u003e\u0026lt;/span\u003e\u0026lt;/span\u003e\u0026lt;span class=\"kw\"\u003e\u0026lt;span class=\"hljs-tag\"\u003e\u0026gt;\u0026lt;/span\u003e\u0026lt;/span\u003e \u0026amp;lt;span class=\u0026quot;kw\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-name\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;ot\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attr\u0026quot;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;st\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;@+id/action_share\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;ot\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attr\u0026rdquo;\u0026gt;android:title\u0026lt;/span\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;st\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;分享\u0026rdquo;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;ot\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attr\u0026rdquo;\u0026gt;android:orderInCategory\u0026lt;/span\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;st\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;80\u0026rdquo;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;ot\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attr\u0026rdquo;\u0026gt;android:icon\u0026lt;/span\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;st\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026quot;@drawable/icon_share_white\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;ot\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attr\u0026rdquo;\u0026gt;app:showAsAction\u0026lt;/span\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;st\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;always|withText\u0026rdquo;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kw\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;kw\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-name\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;ot\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attr\u0026quot;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;st\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;@+id/action_edit\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;ot\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attr\u0026rdquo;\u0026gt;android:title\u0026lt;/span\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;st\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026quot;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;ot\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attr\u0026rdquo;\u0026gt;android:orderInCategory\u0026lt;/span\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;st\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;60\u0026rdquo;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;ot\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attr\u0026rdquo;\u0026gt;app:showAsAction\u0026lt;/span\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;st\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;always\u0026rdquo;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;ot\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attr\u0026rdquo;\u0026gt;app:actionLayout\u0026lt;/span\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;st\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026quot;@layout/menu_action_album_edit\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kw\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;kw\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026ldquo;hljs-name\u0026rdquo;\u0026gt;menu\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;`\n\u0026lt;/div\u0026gt; `app:actionLayout`指向了一个布局，可以在这个布局中定义你想要的控件。我的定义是这样的。 `menu_action_album_edit.xml` \u0026lt;div class=\u0026#34;sourceCode\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;TextView xmlns:android=\u0026amp;quot;http://schemas.android.com/apk/res/android\u0026amp;quot; android:layout_width=\u0026amp;quot;wrap_content\u0026amp;quot; android:layout_height=\u0026amp;quot;wrap_content\u0026amp;quot; android:paddingLeft=\u0026amp;quot;10dip\u0026amp;quot; android:paddingRight=\u0026amp;quot;10dip\u0026amp;quot; android:gravity=\u0026amp;quot;center\u0026amp;quot; android:text=\u0026amp;quot;@string/app_edit\u0026amp;quot; android:drawableLeft=\u0026amp;quot;@drawable/album_edit_white\u0026amp;quot; android:textColor=\u0026amp;quot;@color/white\u0026amp;quot; android:clickable=\u0026amp;quot;true\u0026amp;quot; /\u0026gt;\u0026#34; data-snippet-id=\u0026#34;ext.67853aa79917befa6351c9258124c9c9\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-meta\u0026#34;\u0026gt;\u0026amp;lt;?xml\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-meta\u0026#34;\u0026gt; version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-meta\u0026#34;\u0026gt;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-name\u0026#34;\u0026gt;TextView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;ot\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;st\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;ot\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;st\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;ot\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;st\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;ot\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;android:paddingLeft\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;st\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;10dip\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;ot\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;android:paddingRight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;st\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;10dip\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;ot\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;android:gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;st\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;center\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;ot\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;android:text\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;st\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@string/app_edit\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;ot\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;android:drawableLeft\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;st\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@drawable/album_edit_white\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;ot\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;android:textColor\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;st\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@color/white\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;ot\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attr\u0026#34;\u0026gt;android:clickable\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;st\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;true\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;` `android:drawableLeft`中指定你的图标。 然后还要在onCreateOptionsMenu中重写一下Menu的点击事件,现在onCreateOptionsMenu方法是这样的：\n``` `\u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-meta\u0026rdquo;\u0026gt;@Override\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kw\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;dt\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;boolean\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;onCreateOptionsMenu\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;(Menu menu)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;getMenuInflater\u0026lt;/span\u0026gt;().\u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;inflate\u0026lt;/span\u0026gt;(R.\u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;menu\u0026lt;/span\u0026gt;.\u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;menu\u0026lt;/span\u0026gt;, menu); \u0026lt;span class=\u0026ldquo;dt\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; MenuItem item = menu.\u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;findItem\u0026lt;/span\u0026gt;(R.\u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;id\u0026lt;/span\u0026gt;.\u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;action_edit\u0026lt;/span\u0026gt;); item.\u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;getActionView\u0026lt;/span\u0026gt;().\u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;setOnClickListener\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026ldquo;kw\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; View.\u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;OnClickListener\u0026lt;/span\u0026gt;() { \u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-meta\u0026rdquo;\u0026gt;@Override\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kw\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;dt\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;void\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;onClick\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;(View v)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026ldquo;fu\u0026rdquo;\u0026gt;onOptionsItemSelected\u0026lt;/span\u0026gt;(item); } });\n\u0026amp;lt;span class=\u0026quot;kw\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kw\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;onCreateOptionsMenu\u0026amp;lt;/span\u0026gt;(menu); }` \u0026lt;/div\u0026gt; 然后像普通的Menu item一样在onOptionsItemSelected中处理点击事件就可以了。 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;clear\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026#34;blog_post_info_block\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/%E5%8A%A8%E6%80%81%E6%9B%B4%E6%96%B0toolbar-menu%E4%BB%A5%E5%8F%8Amenu%E4%B8%AD%E5%90%8C%E6%97%B6%E6%98%BE%E7%A4%BA%E6%96%87%E5%AD%97%E5%92%8C%E5%9B%BE%E6%A0%87/","summary":"\u003cdiv id=\"cnblogs_post_body\" class=\"cnblogs-markdown\"\u003e\n\u003cpre\u003e\u003ccode\u003e我们经常会有这样的需求，在切换Fragment或者点击某个按钮后动态更新Toolbar上Menu项.但是onCreateOptionsMenu方法只在创建Activity的时候调用一次，以后就不再调用了，所以就不能在onCreateOptionsMenu中做处理了。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e不过系统提供了另外的一个方法onPrepareOptionsMenu,我们可以在这个方法中做一些逻辑处理，然后在需要更新Menu的地方调用invalidateOptionsMenu方法。\n效果图如下：\n\u003cimg loading=\"lazy\" src=\"http://images2015.cnblogs.com/blog/902237/201607/902237-20160720181829857-1144529244.png\"\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e点击`管理专辑`按钮更换Menu,\n\n\n\n\n\n![](http://images2015.cnblogs.com/blog/902237/201607/902237-20160720181845747-1609503965.png)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"sourceCode\"\u003e\n    \u003cdiv class=\"top-box hide\"\u003e\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003e    \u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-meta\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kw\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;dt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onCreateOptionsMenu\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(Menu menu)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;getMenuInflater\u0026amp;lt;/span\u0026gt;().\u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;inflate\u0026amp;lt;/span\u0026gt;(R.\u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;menu\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;menu\u0026amp;lt;/span\u0026gt;, menu); \u0026amp;lt;span class=\u0026quot;kw\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kw\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026quot;fu\u0026quot;\u0026gt;onCreateOptionsMenu\u0026amp;lt;/span\u0026gt;(menu); }\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;div class=\u0026#34;sourceCode\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-meta\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;dt\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onPrepareOptionsMenu\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Menu menu)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; (mIsEditStatus) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            menu.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;findItem\u0026amp;lt;/span\u0026gt;(R.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;id\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;action_share\u0026amp;lt;/span\u0026gt;).\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;setVisible\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            menu.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;findItem\u0026amp;lt;/span\u0026gt;(R.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;id\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;action_edit\u0026amp;lt;/span\u0026gt;).\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;setVisible\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } \u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            menu.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;findItem\u0026amp;lt;/span\u0026gt;(R.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;id\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;action_share\u0026amp;lt;/span\u0026gt;).\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;setVisible\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            menu.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;findItem\u0026amp;lt;/span\u0026gt;(R.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;id\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;action_edit\u0026amp;lt;/span\u0026gt;).\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;setVisible\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kw\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;fu\u0026#34;\u0026gt;onPrepareOptionsMenu\u0026amp;lt;/span\u0026gt;(menu);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003c/div\u003e\n  \u003cdiv class=\"sourceCode\"\u003e\n    ```\n`\u0026lt;span class=\"fu\"\u003einvalidateOptionsMenu\u0026lt;/span\u003e(); \u0026lt;span class=\"co\"\u003e\u0026lt;span class=\"hljs-comment\"\u003e//重新绘制menu\u0026lt;/span\u003e\u0026lt;/span\u003e`\n```\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e另外的一个需求是在Menu中要显示图标和文字，虽然在`menu.xml`文件中配置了图标和文字，但是在有图标的情况下文字是不会显示的，即使设置 `app:showAsAction=\u0026quot;always|withText\u0026quot;` 但是我在运行的时候发现并没有显示文字，处理方法是通过另外一个属性实现`app:actionLayout`.\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e首先\u003ccode\u003emenu.xml\u003c/code\u003e定义如下：\u003c/p\u003e","title":"动态更新Toolbar Menu以及Menu中同时显示文字和图标"},{"content":" 在android studio3 下面，使用multiDexEnabled true造成导出的包缺少内容（support-v4） 如图：图一添加使用multiDexEnabled true，图二没有添加multiDexEnabled\n有没有其他理想的解决方法，希望大家评论给我，谢谢\n2.在build.gradle中忽略重复的引用，使用exclude（如果想在一个包忽略多个添加多行）\n格式：implementation(‘引用的库’){\nexclude group:’包名’,module:’模块名称（通常是包名后面和版本直接的内容）’\n}\n如果是 implementation project需要写成这种格式(把project扩在小括号中)\nimplementation(project(‘……’)){\n…同上\n}\n注意：可以单独使用group和module（推荐都写上）\n例如：\nimplementation(‘com.google.android:flexbox:0.2.3’) {\nexclude group: ‘com.android.support’, module: ‘appcompat-v7’\n}\n3. implementation 和compile 区别 （compile是被废弃了）\n在AS3.0默认推荐使用implementation，如果依赖有问题使用api代替implementation，\n更多参考：（自备梯子）https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html\n或者：（不用梯子）https://developer.android.google.cn/studio/build/gradle-plugin-3-0-0-migration.html\n4.所有项目使用指定库配置(更多请参考：http://www.jianshu.com/p/429733dbbc34)\n例如：\nallprojects {\nrepositories {\njcenter()\ngoogle()\n}\nconfigurations.all((Closure) {\nresolutionStrategy {\nforce ‘com.android.support:support-v4:26.0.2’ // your version of support library\n}\n})\n}\n希望大家评论交流！！！\n转自：http://www.zdltech.com/blogphp/archives/1335.html\naapt2的作用说明\n开启了aapt2后，资源的增量编译会加速编译速度，但是有些场景aapt2并不是很合适，因此必要的情况下，建议关闭aapt2，比如jenkins上构建时，我们并不需要增量编译，因此可以关闭，可以通过gradle参数达到关闭的效果，命令如下\n1\ngradle assembleRelease -Pandroid.enableAapt2=false\n简单总结了几种不适合使用aapt2的场景\n插件化和热修复中，需要使用public.xml的场景\n构建过程，需要动态增删改资源的场景，如删除一部分线上不应该出现的资源\n","permalink":"https://blog.zdltech.com/posts/%E5%9C%A8android-studio3-%E9%97%AE%E9%A2%98%E6%B1%87%E6%80%BB/","summary":"\u003col\u003e\n\u003cli\u003e在android studio3 下面，使用multiDexEnabled true造成导出的包缺少内容（support-v4）\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e如图：图一添加使用multiDexEnabled true，图二没有添加multiDexEnabled\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.zdltech.com/blogphp/images/2017/11/1.png\"\u003e\u003cimg loading=\"lazy\" src=\"http://www.zdltech.com/blogphp/images/2017/11/1-300x192.png\"\u003e\u003c/a\u003e \u003ca href=\"http://www.zdltech.com/blogphp/images/2017/11/2.png\"\u003e\u003cimg loading=\"lazy\" src=\"http://www.zdltech.com/blogphp/images/2017/11/2-300x201.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e有没有其他理想的解决方法，希望大家评论给我，谢谢\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e2.在build.gradle中忽略重复的引用，使用exclude（如果想在一个包忽略多个添加多行）\u003c/p\u003e\n\u003cp\u003e格式：implementation(‘引用的库’){\u003c/p\u003e\n\u003cp\u003eexclude group:’包名’,module:’模块名称（通常是包名后面和版本直接的内容）’\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e如果是 implementation  project需要写成这种格式(把project扩在小括号中)\u003c/p\u003e\n\u003cp\u003eimplementation(project(‘……’)){\u003c/p\u003e\n\u003cp\u003e…同上\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e注意：可以单独使用group和module（推荐都写上）\u003c/p\u003e\n\u003cp\u003e例如：\u003c/p\u003e\n\u003cp\u003eimplementation(‘com.google.android:flexbox:0.2.3’) {\u003cbr\u003e\nexclude group: ‘com.android.support’, module: ‘appcompat-v7’\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e3. implementation 和compile  区别 （compile是被废弃了）\u003c/p\u003e\n\u003cp\u003e在AS3.0默认推荐使用implementation，如果依赖有问题使用api代替implementation，\u003c/p\u003e\n\u003cp\u003e更多参考：（自备梯子）\u003ca href=\"https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html\"\u003ehttps://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e或者：（不用梯子）\u003ca href=\"https://developer.android.google.cn/studio/build/gradle-plugin-3-0-0-migration.html\"\u003ehttps://developer.android.google.cn/studio/build/gradle-plugin-3-0-0-migration.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e4.所有项目使用指定库配置(更多请参考：\u003ca href=\"http://www.jianshu.com/p/429733dbbc34\"\u003ehttp://www.jianshu.com/p/429733dbbc34\u003c/a\u003e)\u003c/p\u003e\n\u003cp\u003e例如：\u003c/p\u003e\n\u003cp\u003eallprojects {\u003cbr\u003e\nrepositories {\u003cbr\u003e\njcenter()\u003cbr\u003e\ngoogle()\u003cbr\u003e\n}\u003cbr\u003e\nconfigurations.all((Closure) {\u003cbr\u003e\nresolutionStrategy {\u003cbr\u003e\nforce ‘com.android.support:support-v4:26.0.2’ // your version of support library\u003cbr\u003e\n}\u003cbr\u003e\n})\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e希望大家评论交流！！！\u003c/p\u003e\n\u003cp\u003e转自：\u003ca href=\"http://www.zdltech.com/blogphp/archives/1335.html\"\u003ehttp://www.zdltech.com/blogphp/archives/1335.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eaapt2的作用说明\u003c/p\u003e\n\u003cp\u003e开启了aapt2后，资源的增量编译会加速编译速度，但是有些场景aapt2并不是很合适，因此必要的情况下，建议关闭aapt2，比如jenkins上构建时，我们并不需要增量编译，因此可以关闭，可以通过gradle参数达到关闭的效果，命令如下\u003c/p\u003e\n\u003cp\u003e1\u003cbr\u003e\ngradle assembleRelease -Pandroid.enableAapt2=false\u003cbr\u003e\n简单总结了几种不适合使用aapt2的场景\u003c/p\u003e\n\u003cp\u003e插件化和热修复中，需要使用public.xml的场景\u003cbr\u003e\n构建过程，需要动态增删改资源的场景，如删除一部分线上不应该出现的资源\u003c/p\u003e","title":"在android studio3 问题汇总"},{"content":"序言：作为这个世界上走在最前沿的生物“猿”，怎么能对新事物一无所知呢，10月26日，随着Android 8.1 Oreo的预览版发布，Android Studio3.0正式版也发布了，作为Android开发的猿们我们应该早就知道谷歌在今年5月的开发者大会上就说了要支持Kotlin语言，所以这次更新一个比较大的点就在于支持Kotlin语言了，下面就跟着LZ的脚步来探索一下AS3.0吧 相信很多人很早就体验过谷歌爸爸放出来的体验版本了，虽然说正式版已经出了，但是很多人也不敢轻易贸然的更新，因为怕会掉进坑里出不来（真是一只胆小的猿，鉴定完毕）\n安装 如果你从Android Studio内部点击更新的话，会跳转到Android的官网，没有梯子的同学可以去这个网站下载更新：\n![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-251c2b749c023786.jpg?imageMogr2/auto-orient/strip) Android Studio3.0正式版 安装过程中遇到的问题 1、Gradle Sync failed： `\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Gradle\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; sync failed\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Cause\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; com\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;build\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;gradle\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;api\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;BaseVariant\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getOutputs\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Ljava\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;/\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;util\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;/\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;List\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Consult\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; IDE log \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; more details \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Help\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;|\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Show\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;8s\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;123ms\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; ` 其实一开始不是这个错，最开始是一个redownload的一个错，后来LZ把2.3版本的给删了，缓存给清除了，然后就变成这个错了。既然有错，那就解决呗，顺手百度了一个，下面看看stackoverflow的解决方案\n![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-b0c5d70ced723ce7.jpg?imageMogr2/auto-orient/strip) 这个方法确实也适用于我，把ButterKnife降级之后就OK了。如果有其他更好的解决方法，欢迎私信我，有偿给发红包。“一个问题的解决是为了更好的迎接下一个问题的出现”——鲁迅\n解决方案：把项目中依赖的ButterKnife降级到8.4.0\n2、Unable to resolve dependency for: ![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-99c78ce71d52f017.jpg?imageMogr2/auto-orient/strip) 第一眼看这个错的时候我以为我setting.gradle中没有依赖appCommon，看完之后明明确实依赖了，而且这是一个老项目，在AS2.3版本的时候很正常，然后我就知道这又是一个坑，无奈的又去上了一把Internet，然后试过网上说的在buildTypes中加入preview节点，然而并没有什么卵用，查了半天还是没有找到解决的方法，后来看着这段报错信息的时候，我看到了signingConfigs，我想到gradle中好像有这么个节点，抱着试一试的态度我删了那个节点，然后，卧槽卧槽卧槽，可以成功编译了，这是不是有一种躺着过坑的赶脚。如果有其他更好的解决方法，欢迎私信我，有偿给发红包\n解决方案：把项目中的signingConfigs节点删除掉就好了，如果你担心多渠道打包的事情，那么就用打包工具吧。\n以下是群里的朋友遇到的一些问题：\n3、app:transformDexArchiveWithExterLibsDexMergeForDebug ![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-f555bbfcb58d36bf.jpg?imageMogr2/auto-orient/strip) 解决方案：将电脑中的.gradle目录删除掉（清除掉gradle缓存）重新build。\n参考stackoverflow\n解决方案详解在这里\n4、gradle打包，自定义apk名称代码报错（Cannot set the value of read-only property ‘outputFile’ ） Open File\u0026lt;/a\u0026gt; \u0026#34; data-snippet-id=\u0026#34;ext.5f35c05816ba13a2bcef2a84fccc9aad\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Error\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;56\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Cannot\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; the value of read\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;-\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;only property \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#39;outputFile\u0026#39;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;ApkVariantOutputImpl_Decorated\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;apkData\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Main\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;type\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;MAIN\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; fullName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;debug\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; filters\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=[]}}\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; of type com\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;build\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;gradle\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;internal\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;api\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;ApkVariantOutputImpl\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;a href\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;openFile:D:/eclipseCode/ipay-android/xinlebao/build.gradle\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Open\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;a\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; ` 解决方案：修改文件名代码请这样写\nvariant.outputs.all { outputFileName = \u0026amp;quot;xinlebao_${defaultConfig.versionName}_${releaseTime()}.apk\u0026amp;quot; } } \u0026#34; data-snippet-id=\u0026#34;ext.4cdcb6d6fc814947273a83f1d4c2ec5e\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;applicationVariants\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;all \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; variant \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;-\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; variant\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;outputs\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;all \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; outputFileName \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;xinlebao_\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{defaultConfig.versionName}_\u0026amp;lt;/span\u0026gt;{releaseTime()}.apk\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; ` 5、AAPT2 编译报错 AAPT2 error `\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Error\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;java\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;util\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;concurrent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;ExecutionException\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; com\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tools\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;aapt2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Aapt2Exception\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; AAPT2 error\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; check logs \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; details \u0026amp;lt;/span\u0026gt;` 解决方案：在gradle.properties中关闭APPT2 编译\n`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;enableAapt2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt; ` 注：如果是eclipse转到as上的项目，可能没有gradle.properties文件，请在项目根目录中手动创建 6、apt插件问题（Error:Cannot choose between the following configurations of project :mylibrary:） `\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Error\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Cannot\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; choose between the following configurations of project \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;mylibrary\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;-\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; debugApiElements \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;-\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; debugRuntimeElements \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;-\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; releaseApiElements \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;-\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; releaseRuntimeElements \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;All\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; of them match the consumer attributes\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt; ` 解决方案：如下\n`\u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;//1.在project的build.gradle中删除 classpath \u0026#39;com.neenbedankt.gradle.plugins:android-apt:1.8\u0026#39; //2.在module的build.gradle中删除 apply plugin: \u0026#39;android-apt\u0026#39; //3.将module的build.gradle文件中的dependency apt \u0026#39;com.jakewharton:butterknife-compiler:8.1.0\u0026#39; //改为 annotationProcessor \u0026#39;com.jakewharton:butterknife-compiler:8.1.0\u0026#39; \u0026amp;lt;/span\u0026gt;` 好了，以上就是最近更新3.0所遇到的一些问题，如果你还遇到其他的问题，欢迎私信我。\nAndroid Studio 3.0 1、.gradle文件 哇塞，问题解决之后就想着赶紧创建一个新的项目来看看有啥变化，首先一个变化比较大的是.gradle文件：\n![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-4071985194a308d1.jpg?imageMogr2/auto-orient/strip) 我们可以看到，谷歌爸爸把buildToolsVersion构建工具的版本给“干掉了”，在以前的版本中，buildToolsVersion也会给项目的构建带来很多错，现在谷歌爸爸把它给“干掉了”；还有就是下面的依赖换成了implementation，那么它和compile有什么区别呢？别着急，喝杯茶听我细细道来：\ncompile和api api完全等同于compile，二者没有区别。我们大家都知道，随着Android版本的更新，有很多过时的类和方法，compile亦是如此，我们可以把compile理解成api的过去式。\napi和implementation 这两个是AS3.0版本中新增的指令，下面用一张图来说明一啊两者的区别：\n![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-14d24f476fdcfd8d.jpg?imageMogr2/auto-orient/strip) 图片参考 有想详细了解的同学，请参考官方的\n2、支持Kotlin 还在初学Kotlin语言的同学有福了，AS3.0支持将Java代码直接转成Kotlin代码，下面我们通过一段VCR来认识一下这个功能：\n![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-4e5910926ba01047.jpg?imageMogr2/auto-orient/strip) 在java文件中，选中你要转换的代码，然后在顶部选择Code——\u0026gt;Convert Java File to Kotlin File进行转换就好了，转换之后，这就是一个Kotlin文件了。\n3、logcat栏 在AS上几个版本中，在Logcat还是Android Monitor的时候，里面有很多东西，网络啊，内存啊，CPU啊什么的，AS3.0中，谷歌将其分开了，Logcat就单独放出来了，之前那个看网络，内存，CPU的单独拎出来了，一个叫Android Profiler的东西：\n![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-48477336a2259941.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 是不是很帅，据说这玩意儿还自带抓包功能哦（这是LZ最喜欢的一个功能）。只不过默认是关闭的，我们要手动把它开起来。进入Run——\u0026gt;Edit Configurations，然后把下面这个钩上就好了：\n![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-f59e476b3d2be15f.jpg?imageMogr2/auto-orient/strip) 需要注意的是，你项目中的API版本得是API26以下，而且你的手机版本得是Android5.0以上才能使用抓包功能。开启之后，我们来抓个包试试吧：\n![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-8b3788f8eda84567.jpg?imageMogr2/auto-orient/strip) 在手机上发起一次网络请求，NETWORK那一栏会发生明显的变化，我们选择那个区域进行抓包，可以看到请求了一个接口MainServlet（如果该区域下会请求多个接口，则会一一列出来），然后我们点击MainServlet，就会出现后台传过来的Json，Header之类的信息，怎么样，是不是很屌，以后再也不用再麻烦测试帮你抓包了，也不用再装什么其他软件了。CPU和MEMORY也一样，都具有记录当前页面的数据，你也可以根据它所记录的数据进行相应的分析。这两个就不展示了，有兴趣的同学可以更新之后自己玩玩。最后需要注意的是开启这个之后会降低应用程序的构建速度，因此只有在你要开始对应用程序进行概要分析时，再启用它。\n4、文件管理器 AS3.0中，文件管理器工具允许和你的AS连接的手机无缝交互，你可以在AS3.0上查看，复制并删除设备上的文件。当检查由应用程序创建的文件或是要讲文件传输到设备时，非常有用：\n`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;data\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;/\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;data\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;/\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;app_name\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;/\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;包含存储在内部存储上的应用程序的数据文件\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; sdcard\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;/\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;包含存储在外部用户存储上的用户文件\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;（图片等）\u0026amp;lt;/span\u0026gt; ` ![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-bff4c6af104d7e76.jpg?imageMogr2/auto-orient/strip) 5、支持Java8 同样，喜欢写lambda的同学也有福利了，这次AS的改版支持了Java8，可以直接将Java代码格式成lambda格式的，但是你得给你的项目设置成支持Java8，右键你的module，选择open Module Settings，进去之后按照如下设置就可以了：\n![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-d24c7cfadf257fc7.jpg?imageMogr2/auto-orient/strip) 这样你就能使用lambda表达式了，系统会自动提醒你哪里可以转换成lambda表达式，是不是好智能：\n![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-2d21141e4e240243.jpg?imageMogr2/auto-orient/strip) 参考 http://blog.csdn.net/soslinken/article/details/73114637\nhttp://blog.csdn.net/niubitianping/article/details/72600923\nhttp://www.jianshu.com/p/9af06314e036\nhttps://stackoverflow.com/questions/45679847/android-studio-3-0-compile-issue-cannot-choose-between-configurations\nhttps://stackoverflow.com/questions/44114044/flavordimensions-gradle-error-android-studio-3-0-canary-1\n转自：http://www.shellsec.com/news/49488.html\n","permalink":"https://blog.zdltech.com/posts/android-studio3-0%E6%9B%B4%E6%96%B0%E4%B9%8B%E8%B7%AF%E9%81%87%E5%9D%91%E5%BF%85%E5%85%A5/","summary":"\u003ch3 id=\"序言作为这个世界上走在最前沿的生物猿怎么能对新事物一无所知呢10月26日随着android-81-oreo的预览版发布android-studio30正式版也发布了作为android开发的猿们我们应该早就知道谷歌在今年5月的开发者大会上就说了要支持kotlin语言所以这次更新一个比较大的点就在于支持kotlin语言了下面就跟着lz的脚步来探索一下as30吧\"\u003e序言：作为这个世界上走在最前沿的生物“猿”，怎么能对新事物一无所知呢，10月26日，随着Android 8.1 Oreo的预览版发布，Android Studio3.0正式版也发布了，作为Android开发的猿们我们应该早就知道谷歌在今年5月的开发者大会上就说了要支持Kotlin语言，所以这次更新一个比较大的点就在于支持Kotlin语言了，下面就跟着LZ的脚步来探索一下AS3.0吧\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e相信很多人很早就体验过谷歌爸爸放出来的体验版本了，虽然说正式版已经出了，但是很多人也不敢轻易贸然的更新，因为怕会掉进坑里出不来（真是一只胆小的猿，鉴定完毕）\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"安装\"\u003e安装\u003c/h2\u003e\n\u003cp\u003e如果你从Android Studio内部点击更新的话，会跳转到Android的官网，没有梯子的同学可以去\u003ca href=\"http://www.androiddevtools.cn/\"\u003e这个网站下载\u003c/a\u003e更新：\u003c/p\u003e\n\u003cdiv class=\"image-package\"\u003e\n\u003cpre\u003e\u003ccode\u003e![Android Studio3.0更新之路（遇坑必入）](http://upload-images.jianshu.io/upload_images/490111-251c2b749c023786.jpg?imageMogr2/auto-orient/strip)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-caption\"\u003e\n    Android Studio3.0正式版\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003ch2 id=\"安装过程中遇到的问题\"\u003e安装过程中遇到的问题\u003c/h2\u003e\n\u003ch5 id=\"1gradle-sync-failed\"\u003e1、Gradle Sync failed：\u003c/h5\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Gradle\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; sync failed\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Cause\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; com\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;build\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;gradle\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;api\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;BaseVariant\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getOutputs\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Ljava\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;/\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;util\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;/\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;List\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Consult\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; IDE log \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; more details \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Help\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;|\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Show\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;8s\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;123ms\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; `\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其实一开始不是这个错，最开始是一个\u003ccode\u003eredownload\u003c/code\u003e的一个错，后来LZ把2.3版本的给删了，缓存给清除了，然后就变成这个错了。既然有错，那就解决呗，顺手百度了一个，下面看看\u003ca href=\"https://stackoverflow.com/questions/44042754/android-studio-3-0-unable-to-find-method-com-android-build-gradle-internal-va\"\u003estackoverflow的解决方案\u003c/a\u003e\u003c/p\u003e","title":"Android Studio3.0更新之路（遇坑必入）"},{"content":"好久没有写文章了，年前公司新开了一个项目，是和usb转串口通信相关的，需求是用安卓平板通过usb转接后与好几个外设进行通信，一直忙到最近，才慢慢闲下来，趁着这个周末不忙，记录下usb转串口通信开发的基本流程。\n我们开发使用的是usb主机模式，即：安卓平板作为主机，usb外设作为从机进行数据通信。整个开发流程可以总结为以下几点：\n1.发现设备\nusbList = usbManager.getDeviceList();1 2 1 2 \u0026#34; data-snippet-id=\u0026#34;ext.1d1481e9c3517ce217b699b6673dd389\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbManager\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbManager \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbManager\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getSystemService\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;USB_SERVICE\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Map\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbDevice\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbList \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbManager\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getDeviceList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt;` 通过UsbManager这个系统提供的类，我们可以枚举出当前连接的所有usb设备，我们主要需要的是UsbDevice对象，关于UsbDevice这个类，官方是这样注释的：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;This\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; represents a USB device attached to the android device \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;with\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; the android device acting \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;as\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; the USB host\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;` 是的，这个类就代表了android所连接的usb设备。\n2.打开设备\n接下来，我们需要打开刚刚搜索到的usb设备，我们可以将平板与usb外设之间的连接想象成一个通道，只有把通道的门打开后，两边才能进行通信。\n一般来说，在没有定制的android设备上首次访问usb设备的时候，默认我们是没有访问权限的，因此我们首先要判断对当前要打开的usbDevice是否有访问权限：\n`\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(!\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;usbManager\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;hasPermission\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;usbDevice\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;))\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbPermissionReceiver \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbPermissionReceiver\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;//申请权限\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; intent \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;ACTION_DEVICE_PERMISSION\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;PendingIntent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; mPermissionIntent \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;PendingIntent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getBroadcast\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;IntentFilter\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; permissionFilter \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;IntentFilter\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;ACTION_DEVICE_PERMISSION\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;registerReceiver\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;usbPermissionReceiver\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; permissionFilter\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbManager\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;requestPermission\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;usbDevice\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; mPermissionIntent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt;` 这里我们声明一个广播UsbPermissionReceiver，当接受到授权成功的广播后做一些其他处理：\n` \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbPermissionReceiver\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;BroadcastReceiver\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onReceive\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; action \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getAction\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;ACTION_DEVICE_PERMISSION\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;equals\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;action\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;))\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;synchronized\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbDevice\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; device \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getParcelableExtra\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbManager\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;EXTRA_DEVICE\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;device\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getDeviceName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;().\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;equals\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;usbDevice\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getDeviceName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getBooleanExtra\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbManager\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;EXTRA_PERMISSION_GRANTED\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;))\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;//授权成功,在这里进行打开设备操作\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;//授权失败\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt;` 接下来，我们要找到具有数据传输功能的接口UsbInterface，从它里边儿找到数据输入和输出端口UsbEndpoint，一般情况下，一个usbDevice有多个UsbInterface，我们需要的一般是第一个，所以：\n`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;usbInterface\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;usbDevice\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getInterface\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 同样的，一个usbInterface有多个UsbEndpoint，有控制端口和数据端口等，因此我们需要根据类型和数据流向来找到我们需要的数据输入和输出两个端口：\n`\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; index \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; index \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbInterface\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getEndpointCount\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; index\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;++)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbEndpoint\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; point \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbInterface\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getEndpoint\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;index\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;point\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getType\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;==\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbConstants\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;USB_ENDPOINT_XFER_BULK\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;point\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getDirection\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;==\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbConstants\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;USB_DIR_IN\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbEndpointIn \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; point\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;point\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getDirection\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;==\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbConstants\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;USB_DIR_OUT\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbEndpointOut \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; point\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt;` 最后，才是真正的打开usb设备，我们需要和usb外设建立一个UsbDeviceConnection，它的注释很简介的说明了它的用途：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;This\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;is\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; used \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; sending \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;and\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; receiving data \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;and\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; control messages to a USB device\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;` 它的获取也很简单，就一句代码：\n`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;usbDeviceConnection \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbManager\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;openDevice\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;usbDevice\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 到这里，理论上平板和usb外设之间的连接已经建立了，也可以首发数据了，但是，我们大部分情况下还需要对usb串口进行一些配置，比如波特率,停止位,数据控制等，不然两边配置不同，收到的数据会乱码。具体怎么配置，就看你使用的串口芯片是什么了，目前流行的有pl2303,ch340等，由于篇幅问题，需要具体配置串口代码的朋友请自行查阅。\n3.数据传输\n到这里，我们已经可以与usb外设进行数据传输了，首先来看怎么向usb设备发送数据。\n` \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;1.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;向\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;usb\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;外设发送数据\u0026amp;lt;/span\u0026gt;` 在第二步中，我们已经获取了数据的输出端口usbEndpointIn，我们向外设发送数据就是通过这个端口来实现的。来看怎么用：\n`\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; ret \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbDeviceConnection\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;bulkTransfer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;usbEndpointOut\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; data\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; data\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;length\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; DEFAULT_TIMEOUT\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` bulkTransfer这个函数用于在给定的端口进行数据传输，第一个参数就是此次传输的端口，这里我们用的输出端口，第二个参数是要发送的数据，类型为字节数组，第三个参数代表要发送的数据长度，最后一个参数是超时，返回值代表发送成功的字节数，如果返回-1，那就是发送失败了。\n`\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;2.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;接受\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;usb\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;外设发送来的数据\u0026amp;lt;/span\u0026gt;` 同理，我们已经找到了数据输入端口usbEndpointIn，因为数据的输入是不定时的，因此我们可以另开一个线程，来专门接受数据，接受数据的代码如下：\n`\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; inMax \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; inEndpoint\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getMaxPacketSize\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;ByteBuffer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; byteBuffer \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;ByteBuffer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;allocate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;inMax\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbRequest\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbRequest \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbRequest\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbRequest\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;initialize\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;connection\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; inEndpoint\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbRequest\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;queue\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;byteBuffer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; inMax\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;connection\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;requestWait\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;==\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbRequest\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;){\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;byte\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;[]\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; retData \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; byteBuffer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;array\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Byte\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; byte1 \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; retData\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;){\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;System\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;err\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;println\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;byte1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt;` 以上，就是usb转串口通信的基本流程，有些地方写的不是很全面，比如接收usb外设数据的方法应该还有别的，不足之处欢迎指正。\n转载：http://blog.csdn.net/weixin_38251977/article/details/69944095\n其他参考：http://www.genshuixue.com/i-cxy/p/15606086\n","permalink":"https://blog.zdltech.com/posts/android-usb%E8%BD%AC%E4%B8%B2%E5%8F%A3%E9%80%9A%E4%BF%A1%E5%BC%80%E5%8F%91%E5%9F%BA%E6%9C%AC%E6%B5%81%E7%A8%8B/","summary":"\u003cp\u003e好久没有写文章了，年前公司新开了一个项目，是和usb转串口通信相关的，需求是用安卓平板通过usb转接后与好几个外设进行通信，一直忙到最近，才慢慢闲下来，趁着这个周末不忙，记录下usb转串口通信开发的基本流程。\u003c/p\u003e\n\u003cp\u003e我们开发使用的是usb主机模式，即：安卓平板作为主机，usb外设作为从机进行数据通信。整个开发流程可以总结为以下几点：\u003c/p\u003e\n\u003cp\u003e1.发现设备\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e usbList = usbManager.getDeviceList();1 2 1 2 \u0026#34; data-snippet-id=\u0026#34;ext.1d1481e9c3517ce217b699b6673dd389\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbManager\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbManager \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbManager\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getSystemService\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;USB_SERVICE\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Map\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;UsbDevice\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbList \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; usbManager\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getDeviceList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e通过UsbManager这个系统提供的类，我们可以枚举出当前连接的所有usb设备，我们主要需要的是UsbDevice对象，关于UsbDevice这个类，官方是这样注释的：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;This\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; represents a USB device attached to the android device \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;with\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; the android device\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e acting \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;as\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; the USB host\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e是的，这个类就代表了android所连接的usb设备。\u003c/p\u003e","title":"Android USB转串口通信开发基本流程"},{"content":"在Android布局中进行使用到空格，以便实现文字的对齐。那么在android中如何表示一个空格呢？ 注：下面的#160，#8201等等皆需要加上\u0026amp;方可实现效果\n空格：#160;\n窄空格：#8201;\n一个汉字宽度的空格：#160;#160;#8201;，用两个空格（#160;#160;）占一个汉字的宽度时，两个空格比一个汉字略窄，三个空格（#160;#160;#160;）比一个汉字略宽\n在实际使用中需要灵活使用#160;和#8201;的组合。\nandroid:text=”真实姓名:”\nandroid:text=”身 份 证:”\nandroid:text=”姓 ‒名:”\nandroid:text=”身份证:”\n#8194;半个中文字更准确点，\n#8195;一个中文字但用起来会比中文字宽一点点。\n所以中文对齐还是建议使用#8194;，\n而#160; #8201;在不同机型有不同表现。\nTextView实现首行缩进的方法： 在string资源文件中，在文字的前面加入”\\u3000\\u3000”即可实现首行缩进\n在Java代码中，使用setText(“\\u3000\\u3000”+xxxxx);\n\\u3000是全角空格的16进制Unicode编码。\n\\xa0代表 转自：http://blog.csdn.net/u014651216/article/details/52411113\n","permalink":"https://blog.zdltech.com/posts/android%E5%B8%83%E5%B1%80%E4%B8%AD%E7%9A%84%E7%A9%BA%E6%A0%BC%E5%92%8C%E5%8D%A0%E4%B8%80%E4%B8%AA%E6%B1%89%E5%AD%97%E5%AE%BD%E5%BA%A6%E7%9A%84%E7%A9%BA%E6%A0%BC%E7%9A%84%E5%AE%9E%E7%8E%B0/","summary":"\u003ch4 id=\"在android布局中进行使用到空格以便实现文字的对齐那么在android中如何表示一个空格呢\"\u003e在Android布局中进行使用到空格，以便实现文字的对齐。那么在android中如何表示一个空格呢？\u003c/h4\u003e\n\u003cp\u003e\u003cstrong\u003e注：下面的#160，#8201等等皆需要加上\u0026amp;方可实现效果\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e空格：#160;\u003cbr\u003e\n窄空格：#8201;\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e一个汉字宽度的空格：#160;#160;#8201;，用两个空格（#160;#160;）占一个汉字的宽度时，两个空格比一个汉字略窄，三个空格（#160;#160;#160;）比一个汉字略宽\u003cbr\u003e\n在实际使用中需要灵活使用#160;和#8201;的组合。\u003c/p\u003e\n\u003cp\u003eandroid:text=”真实姓名:”\u003cbr\u003e\nandroid:text=”身  份  证:”\u003c/p\u003e\n\u003cp\u003eandroid:text=”姓  ‒名:”\u003cbr\u003e\nandroid:text=”身份证:”\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e#8194;半个中文字更准确点，\u003cbr\u003e\n#8195;一个中文字但用起来会比中文字宽一点点。\u003cbr\u003e\n所以中文对齐还是建议使用#8194;，\u003cbr\u003e\n而#160; #8201;在不同机型有不同表现。\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch4 id=\"textview实现首行缩进的方法\"\u003eTextView实现首行缩进的方法：\u003c/h4\u003e\n\u003cp\u003e在string资源文件中，在文字的前面加入”\\u3000\\u3000”即可实现首行缩进\u003cbr\u003e\n在Java代码中，使用setText(“\\u3000\\u3000”+xxxxx);\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\\u3000是全角空格的16进制Unicode编码。\u003c/p\u003e\n\u003cp\u003e\\xa0代表 \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e转自：http://blog.csdn.net/u014651216/article/details/52411113\u003c/p\u003e","title":"Android布局中的空格和占一个汉字宽度的空格的实现"},{"content":"一、问题在哪里？\ntextview显示长文字时会进行自动折行，如果遇到一些特殊情况，自动折行会杯具成这个样子：\n上述特殊情况包括：\n1)全角/半角符号混排（一般是数字、字母、汉字混排）\n2)全角/半角标点符号出现在行首时，该标点符号会连同其前一个字符跳到下一行\n3)英文单词不能被折成两行\n4)……\n二、怎么搞？\n通常有两类解决方案：\n1)修改文本内容，将所有符号全角化、在标点符号前面加空格等等……\n2)保持文本内容不变，在合适的位置将文本手动分成多行\n本文采用第二种方案，更加通用，也最大限度的保留了原文本。\n三、开始干活\n3.1　“在合适的位置将文本手动分成多行”需要知道textview的实际宽度、字体大小等信息，框架如下：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) 1 public class TestCActivity extends Activity { 2 private TextView mText; 3 4 @Override 5 protected void onCreate(Bundle savedInstanceState) { 6 super.onCreate(savedInstanceState); 7 8 setContentView(R.layout.testc); 9 10 mText = (TextView)findViewById(R.id.txt); 11 mText.setText(\u0026#34;本文地址http://www.cnblogs.com/goagent/p/5159125.html本文地址啊本文。地址。啊http://www.cnblogs.com/goagent/p/5159125.html\u0026#34;); 12 mText.getViewTreeObserver().addOnGlobalLayoutListener(new OnTvGlobalLayoutListener()); 13 } 14 15 private class OnTvGlobalLayoutListener implements OnGlobalLayoutListener { 16 @Override 17 public void onGlobalLayout() { 18 mText.getViewTreeObserver().removeOnGlobalLayoutListener(this); 19 final String newText = autoSplitText(mText); 20 if (!TextUtils.isEmpty(newText)) { 21 mText.setText(newText); 22 } 23 } 24 } 25 26 private String autoSplitText(final TextView tv) { 27 final String rawText = tv.getText().toString(); 28 final Paint tvPaint = tv.getPaint(); 29 final int tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); 30 31 //autoSplitText begin.... 32 String newText = rawText; 33 //autoSplitText end.... 34 35 return newText; 36 } 37 } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 3.2　实现自动分割文本，简单来说就是用textview的paint逐字符测量，如果发现当前行绘制不下了，就手动加入一个换行符：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) 1 private String autoSplitText(final TextView tv) { 2 final String rawText = tv.getText().toString(); //原始文本 3 final Paint tvPaint = tv.getPaint(); //paint，包含字体等信息 4 final float tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); //控件可用宽度 5 6 //将原始文本按行拆分 7 String [] rawTextLines = rawText.replaceAll(\u0026#34;\\r\u0026#34;, \u0026#34;\u0026#34;).split(\u0026#34;\\n\u0026#34;); 8 StringBuilder sbNewText = new StringBuilder(); 9 for (String rawTextLine : rawTextLines) { 10 if (tvPaint.measureText(rawTextLine) \u0026amp;lt;= tvWidth) { 11 //如果整行宽度在控件可用宽度之内，就不处理了 12 sbNewText.append(rawTextLine); 13 } else { 14 //如果整行宽度超过控件可用宽度，则按字符测量，在超过可用宽度的前一个字符处手动换行 15 float lineWidth = 0; 16 for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) { 17 char ch = rawTextLine.charAt(cnt); 18 lineWidth += tvPaint.measureText(String.valueOf(ch)); 19 if (lineWidth \u0026amp;lt;= tvWidth) { 20 sbNewText.append(ch); 21 } else { 22 sbNewText.append(\u0026#34;\\n\u0026#34;); 23 lineWidth = 0; 24 --cnt; 25 } 26 } 27 } 28 sbNewText.append(\u0026#34;\\n\u0026#34;); 29 } 30 31 //把结尾多余的\\n去掉 32 if (!rawText.endsWith(\u0026#34;\\n\u0026#34;)) { 33 sbNewText.deleteCharAt(sbNewText.length() - 1); 34 } 35 36 return sbNewText.toString(); 37 } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 3.3　话不多说，效果如下：\n四、更多玩法\n4.1　可以封装一个自定义的textview，直接包含自动排版换行的功能：\n![](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif) ![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` 1 package cc.snser.test; 2 3 import android.content.Context; 4 import android.graphics.Paint; 5 import android.text.TextUtils; 6 import android.util.AttributeSet; 7 import android.widget.TextView; 8 9 public class AutoSplitTextView extends TextView { 10 private boolean mEnabled = true; 11 12 public AutoSplitTextView(Context context) { 13 super(context); 14 } 15 16 public AutoSplitTextView(Context context, AttributeSet attrs) { 17 super(context, attrs); 18 } 19 20 public AutoSplitTextView(Context context, AttributeSet attrs, int defStyle) { 21 super(context, attrs, defStyle); 22 } 23 24 public void setAutoSplitEnabled(boolean enabled) { 25 mEnabled = enabled; 26 } 27 28 @Override 29 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 30 if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 31 \u0026amp;\u0026amp; MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY 32 \u0026amp;\u0026amp; getWidth() \u0026gt; 0 33 \u0026amp;\u0026amp; getHeight() \u0026gt; 0 34 \u0026amp;\u0026amp; mEnabled) { 35 String newText = autoSplitText(this); 36 if (!TextUtils.isEmpty(newText)) { 37 setText(newText); 38 } 39 } 40 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 41 } 42 43 private String autoSplitText(final TextView tv) { 44 final String rawText = tv.getText().toString(); //原始文本 45 final Paint tvPaint = tv.getPaint(); //paint，包含字体等信息 46 final float tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); //控件可用宽度 47 48 //将原始文本按行拆分 49 String [] rawTextLines = rawText.replaceAll(\u0026quot;\\r\u0026quot;, \u0026ldquo;\u0026rdquo;).split(\u0026quot;\\n\u0026quot;); 50 StringBuilder sbNewText = new StringBuilder(); 51 for (String rawTextLine : rawTextLines) { 52 if (tvPaint.measureText(rawTextLine) \u0026lt;= tvWidth) { 53 //如果整行宽度在控件可用宽度之内，就不处理了 54 sbNewText.append(rawTextLine); 55 } else { 56 //如果整行宽度超过控件可用宽度，则按字符测量，在超过可用宽度的前一个字符处手动换行 57 float lineWidth = 0; 58 for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) { 59 char ch = rawTextLine.charAt(cnt); 60 lineWidth += tvPaint.measureText(String.valueOf(ch)); 61 if (lineWidth \u0026lt;= tvWidth) { 62 sbNewText.append(ch); 63 } else { 64 sbNewText.append(\u0026quot;\\n\u0026quot;); 65 lineWidth = 0; 66 \u0026ndash;cnt; 67 } 68 } 69 } 70 sbNewText.append(\u0026quot;\\n\u0026quot;); 71 } 72 73 //把结尾多余的\\n去掉 74 if (!rawText.endsWith(\u0026quot;\\n\u0026quot;)) { 75 sbNewText.deleteCharAt(sbNewText.length() - 1); 76 } 77 78 return sbNewText.toString(); 79 } 80 }\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; ![](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif) \u0026lt;div id=\u0026#34;cnblogs_code_open_8e2944ef-bf7a-4b98-bd80-4ca691a8c9cf\u0026#34; class=\u0026#34;cnblogs_code_hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ``` 1 package cc.snser.test; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 6 public class TestCActivity extends Activity { 7 private AutoSplitTextView mText; 8 9 @Override 10 protected void onCreate(Bundle savedInstanceState) { 11 super.onCreate(savedInstanceState); 12 13 setContentView(R.layout.testc); 14 15 mText = (AutoSplitTextView)findViewById(R.id.txt); 16 mText.setText(\u0026#34;本文地址http://www.cnblogs.com/goagent/p/5159125.html本文地址啊本文。地址。啊http://www.cnblogs.com/goagent/p/5159125.html\u0026#34;); 17 } 18 } \u0026lt;div class=\u0026quot;cnblogs_code_toolbar\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_copy\u0026quot;\u0026gt;\u0026lt;a title=\u0026quot;复制代码\u0026quot;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif) View testc.xml 4.2　实现悬挂缩进\n![](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif) ![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` 1 private String autoSplitText(final TextView tv, final String indent) { 2 final String rawText = tv.getText().toString(); //原始文本 3 final Paint tvPaint = tv.getPaint(); //paint，包含字体等信息 4 final float tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); //控件可用宽度 5 6 //将缩进处理成空格 7 String indentSpace = \u0026ldquo;\u0026rdquo;; 8 float indentWidth = 0; 9 if (!TextUtils.isEmpty(indent)) { 10 float rawIndentWidth = tvPaint.measureText(indent); 11 if (rawIndentWidth \u0026lt; tvWidth) { 12 while ((indentWidth = tvPaint.measureText(indentSpace)) \u0026lt; rawIndentWidth) { 13 indentSpace += \u0026quot; \u0026ldquo;; 14 } 15 } 16 } 17 18 //将原始文本按行拆分 19 String [] rawTextLines = rawText.replaceAll(\u0026quot;\\r\u0026rdquo;, \u0026ldquo;\u0026rdquo;).split(\u0026quot;\\n\u0026quot;); 20 StringBuilder sbNewText = new StringBuilder(); 21 for (String rawTextLine : rawTextLines) { 22 if (tvPaint.measureText(rawTextLine) \u0026lt;= tvWidth) { 23 //如果整行宽度在控件可用宽度之内，就不处理了 24 sbNewText.append(rawTextLine); 25 } else { 26 //如果整行宽度超过控件可用宽度，则按字符测量，在超过可用宽度的前一个字符处手动换行 27 float lineWidth = 0; 28 for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) { 29 char ch = rawTextLine.charAt(cnt); 30 //从手动换行的第二行开始，加上悬挂缩进 31 if (lineWidth \u0026lt; 0.1f \u0026amp;\u0026amp; cnt != 0) { 32 sbNewText.append(indentSpace); 33 lineWidth += indentWidth; 34 } 35 lineWidth += tvPaint.measureText(String.valueOf(ch)); 36 if (lineWidth \u0026lt;= tvWidth) { 37 sbNewText.append(ch); 38 } else { 39 sbNewText.append(\u0026quot;\\n\u0026quot;); 40 lineWidth = 0; 41 \u0026ndash;cnt; 42 } 43 } 44 } 45 sbNewText.append(\u0026quot;\\n\u0026quot;); 46 } 47 48 //把结尾多余的\\n去掉 49 if (!rawText.endsWith(\u0026quot;\\n\u0026quot;)) { 50 sbNewText.deleteCharAt(sbNewText.length() - 1); 51 } 52 53 return sbNewText.toString(); 54 }\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 调用方式： \u0026lt;span class=\u0026#34;cnblogs_code\u0026#34;\u0026gt;autoSplitText(tv, \u0026amp;#8220;1、\u0026amp;#8221;);\u0026lt;/span\u0026gt; 悬挂缩进效果： ![](http://images2015.cnblogs.com/blog/423151/201602/423151-20160224161817286-620248371.png) 转自：_http://www.cnblogs.com/snser/p/5159125.html]_ \u0026amp;nbsp; \u0026amp;nbsp; \u0026lt;div class=\u0026#34;title\u0026#34;\u0026gt; ## Android中 TextView 加载 混合字符 自动换行解决方案 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;content\u0026#34;\u0026gt; 昨天测试提看一个bug,如下： 【3.1.0】当实勘员点评由中文和数字组成时，第一个中文后会自动换行 最终解决办法为加入这个方法： \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; ![技术分享](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif) \u0026lt;div id=\u0026#34;cnblogs_code_open_b676ddb2-cf37-4729-81b1-6fbaa6f0745c\u0026#34; class=\u0026#34;cnblogs_code_hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ``` private String autoSplitText(final TextView tv) { final String rawText = tv.getText().toString(); //原始文本 final Paint tvPaint = tv.getPaint(); //paint，包含字体等信息 final float tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); //控件可用宽度 //将原始文本按行拆分 String[] rawTextLines = rawText.replaceAll(\u0026#34;\\r\u0026#34;, \u0026#34;\u0026#34;).split(\u0026#34;\\n\u0026#34;); StringBuilder sbNewText = new StringBuilder(); for (String rawTextLine : rawTextLines) { if (tvPaint.measureText(rawTextLine) \u0026amp;lt;= tvWidth) { //如果整行宽度在控件可用宽度之内，就不处理了 sbNewText.append(rawTextLine); } else { //如果整行宽度超过控件可用宽度，则按字符测量，在超过可用宽度的前一个字符处手动换行 float lineWidth = 0; for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) { char ch = rawTextLine.charAt(cnt); lineWidth += tvPaint.measureText(String.valueOf(ch)); if (lineWidth \u0026amp;lt;= tvWidth) { sbNewText.append(ch); } else { sbNewText.append(\u0026#34;\\n\u0026#34;); lineWidth = 0; --cnt; } } } sbNewText.append(\u0026#34;\\n\u0026#34;); } //把结尾多余的\\n去掉 if (!rawText.endsWith(\u0026#34;\\n\u0026#34;)) { sbNewText.deleteCharAt(sbNewText.length() - 1); } return sbNewText.toString(); } \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_collapse\u0026quot;\u0026gt;View Code\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026amp;nbsp; 加载完调用： \u0026lt;div class=\u0026quot;cnblogs_code\u0026quot;\u0026gt; ![技术分享](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif) \u0026lt;div id=\u0026quot;cnblogs_code_open_f0bb6e5e-2c9c-43fb-97bd-a567fd48c148\u0026quot; class=\u0026quot;cnblogs_code_hide\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; ``` tvDes.setText(desc.getSurvey_conclusion()); tvDes.setText(autoSplitText(tvDes));\n\u0026lt;/div\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_collapse\u0026#34;\u0026gt;View Code\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026amp;nbsp; 如果出现不正常的问题，再换种方式调用，： \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; ![技术分享](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif) \u0026lt;div id=\u0026#34;cnblogs_code_open_f9e0301e-16f5-43d7-b89a-7fc4725cbb4a\u0026#34; class=\u0026#34;cnblogs_code_hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ``` ViewTreeObserver observer = tvDes.getViewTreeObserver(); observer.addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { tvDes.setText(autoSplitText(tvDes)); } }); \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_collapse\u0026quot;\u0026gt;View Code\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; 就可以了。 ","permalink":"https://blog.zdltech.com/posts/android-textview-%E8%87%AA%E5%8A%A8%E6%8D%A2%E8%A1%8C-%E6%95%B4%E9%BD%90%E6%8E%92%E7%89%88/","summary":"\u003cp\u003e\u003cstrong\u003e一、问题在哪里？\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003etextview显示长文字时会进行自动折行，如果遇到一些特殊情况，自动折行会杯具成这个样子：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images2015.cnblogs.com/blog/423151/201602/423151-20160223182710036-1140598862.png\"\u003e\u003c/p\u003e\n\u003cp\u003e上述特殊情况包括：\u003c/p\u003e\n\u003cp\u003e1)全角/半角符号混排（一般是数字、字母、汉字混排）\u003c/p\u003e\n\u003cp\u003e2)全角/半角标点符号出现在行首时，该标点符号会连同其前一个字符跳到下一行\u003c/p\u003e\n\u003cp\u003e3)英文单词不能被折成两行\u003c/p\u003e\n\u003cp\u003e4)……\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e二、怎么搞？\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e通常有两类解决方案：\u003c/p\u003e\n\u003cp\u003e1)修改文本内容，将所有符号全角化、在标点符号前面加空格等等……\u003c/p\u003e\n\u003cp\u003e2)保持文本内容不变，在合适的位置将文本手动分成多行\u003c/p\u003e\n\u003cp\u003e本文采用第二种方案，更加通用，也最大限度的保留了原文本。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e三、开始干活\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e3.1　　“在合适的位置将文本手动分成多行”需要知道textview的实际宽度、字体大小等信息，框架如下：\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e public \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e TestCActivity \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e Activity {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e     private TextView mText;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e     \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e4\u003c/span\u003e     @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e5\u003c/span\u003e     protected void onCreate(Bundle savedInstanceState) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e6\u003c/span\u003e         super\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonCreate(savedInstanceState);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e7\u003c/span\u003e         \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e8\u003c/span\u003e         setContentView(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elayout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etestc);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e9\u003c/span\u003e         \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e10\u003c/span\u003e         mText \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (TextView)findViewById(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etxt);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e11\u003c/span\u003e         mText\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetText(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;本文地址http://www.cnblogs.com/goagent/p/5159125.html本文地址啊本文。地址。啊http://www.cnblogs.com/goagent/p/5159125.html\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e12\u003c/span\u003e         mText\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetViewTreeObserver()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddOnGlobalLayoutListener(new OnTvGlobalLayoutListener());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e13\u003c/span\u003e     }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e14\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e15\u003c/span\u003e     private \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e OnTvGlobalLayoutListener implements OnGlobalLayoutListener {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e16\u003c/span\u003e         @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e17\u003c/span\u003e         public void onGlobalLayout() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e18\u003c/span\u003e             mText\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetViewTreeObserver()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eremoveOnGlobalLayoutListener(this);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e19\u003c/span\u003e             final String newText \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e autoSplitText(mText);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e             \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003eTextUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eisEmpty(newText)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e21\u003c/span\u003e                 mText\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetText(newText);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e22\u003c/span\u003e             }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e23\u003c/span\u003e         }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e24\u003c/span\u003e     }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e25\u003c/span\u003e     \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e26\u003c/span\u003e     private String autoSplitText(final TextView tv) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e27\u003c/span\u003e         final String rawText \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e tv\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetText()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etoString();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e28\u003c/span\u003e         final Paint tvPaint \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e tv\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetPaint();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e29\u003c/span\u003e         final int tvWidth \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e tv\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetWidth() \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e tv\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetPaddingLeft() \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e tv\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetPaddingRight();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e30\u003c/span\u003e         \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e31\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003eautoSplitText begin\u003cspan style=\"color:#ff79c6\"\u003e....\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e32\u003c/span\u003e         String newText \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rawText;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e33\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003eautoSplitText end\u003cspan style=\"color:#ff79c6\"\u003e....\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e34\u003c/span\u003e         \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e35\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e newText;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e36\u003c/span\u003e     }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e37\u003c/span\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e3.2　　实现自动分割文本，简单来说就是用textview的paint逐字符测量，如果发现当前行绘制不下了，就手动加入一个换行符：\u003c/p\u003e","title":"android textview 自动换行 整齐排版"},{"content":"前几天在网上找了找Android动态获取权限的文章和视频，自己整理了一下。几天看一位大神说真正的程序员是有着分享精神的，我这个刚刚入行的小菜鸟，也想把自己整理的东西分享给大家。\n本文参考了A_si的Permission——郭霖认为最优的运行时权限方案和郭霖大神的CSDN视屏\n在这之前，我们需要知道什么是权限? 权限是一种安全机制。Android权限主要用于限制应用程序内部某些具有限制性特性的功能使用以及应用程序之间的组件访问。\n比如网络权限\n\u0026quot; data-snippet-id=\u0026quot;ext.1ecd4ff36f58d5c42638b9d887b68988\u0026quot; data-snippet-saved=\u0026quot;false\u0026quot; data-codota-status=\u0026quot;done\u0026quot;\u0026gt;\u0026amp;lt;user-permission android:name=\u0026quot;android.permission.INTERNET\u0026quot;/\u0026amp;gt;当我们的程序需要访问网络的时候，必须添加这个权限，不添加则无法访问网络。\n这里还需要注意的是：在Android6.0之前，我们只需要在AndroidManifest.xml文件中直接添加权限即可，但是在Android6.0之后，我们只在AndroidManifest.xml文件中配置是不够的，还需要在Java代码中进行动态获取权限。当然这里不是所有的权限都需要动态获取，只需要获取危险权限就可以了。（毕竟Android权限100多种，要是每个都需要获取，那不累死开发人员啦）\nAndroid中的危险权限分为9组24种 ![](http://upload-images.jianshu.io/upload_images/3780051-92dda32c577e32cb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 1454742-2c2196fd438a4ed3.png 我们只需要在用这些权限的时候，才需要去动态申请，除这些之外的权限，我们只需要在AndroidManifest.xml文件种写上即可，动态申请的权限同样需要在AndroidManifest.xml文件中写。而且每一组种的权限只要有一个授权了，其他的也会自动授权\n下面这张图是我们的build.gradle文件中的版本信息\n![](http://upload-images.jianshu.io/upload_images/3780051-e00a73adfc0a922a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) Image.png 1、targetSdkVersion版本号如果\u0026lt;= 21时，不需要动态处理权限 。但是有时候我们的应用程序会打不开。\n2、如果是之前的老版本升级上来的，系统会默认开启之前所有的权限，比如之前的targetSdkVersion是21，后来升级之后变成了25，这个时候系统会自动授权。一定要记住是升级变成的25，否则还是需要授权。\nTips： 为什么SD卡读写权限是危险权限,能不能不申请权限但又能使用SD卡呢？\n（1）把SD权限设置为危险权限，是为了防止应用随便在用户的手机上些东西，如果不加防范，用户的SD卡就会有很多乱七八糟的东西。\n（2）用户可以不申请权限而使用SD卡，但是只能使用系统提供的默认的路径。\n我们可以使用Android系统提供的SDK目录。路径是Android\\data\\程序包名。这个目录是程序可以不需要经过\n用户授权就可以直接使用，甚至不需要添加WRITE_EXTERNAL_STORAGE这个权限。 这个目录会在程序删除时也会直接删除。\n如何访问这个目录呢？\nFile file = getExternalCacheDir();\nString s = file.getPath; 这个方法得到的是cache的路径，但是一般的垃圾清理软件都可以把这里面的数据清理掉\nFile[] files = getExternalCacheDirs(); 这个得到的是一个文件数组，要求Api最小19\n如果我们不想垃圾清理软件把我们缓存的数据清理掉，则可以放在file文件下\ngetExternalFilesDir(“”); 这个表示所有的操作都是放在file目录下进行的\ngetExternalFilesDir(“mm”); 这个表示会在file目录下在见一个mm目录，然后所有的操作都会放在这个目录下。\n下面我们来看如何动态获取权限！！！ 先看最简单的，动态获取一个权限 比如现在要动态获取一个打电话的权限。。\n首先需要在AndroidManifest.xml文件中写上这个权限\n\u0026quot; data-snippet-id=\u0026quot;ext.f281d8d8d9cfe2d283d570842a2b4c1e\u0026quot; data-snippet-saved=\u0026quot;false\u0026quot; data-codota-status=\u0026quot;done\u0026quot;\u0026gt;\u0026amp;lt;user-permission android:name=\u0026quot;android.premission.CALL_PHONE\u0026quot;/\u0026amp;gt;\n然后在Java代码进行动态获取\n请求授权的代码\n` \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 请求授权 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;requestPermission\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (ContextCompat.checkSelfPermission(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//表示未授权时\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//进行授权\u0026amp;lt;/span\u0026gt; ActivityCompat.requestPermissions(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; String[]{Manifest.permission.CALL_PHONE},\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;); }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//调用打电话的方法\u0026amp;lt;/span\u0026gt; makeCall(); } }` 请求之后，我们需要重写onRequestPermissionsResult这个方法\n0 \u0026amp;\u0026amp; grantResults[0] == PackageManager.PERMISSION_GRANTED){ //同意权限申请 makeCall(); }else { //拒绝权限申请 Toast.makeText(this,\u0026amp;quot;权限被拒绝了\u0026amp;quot;,Toast.LENGTH_SHORT).show(); } break; default: break; } }\u0026#34; data-snippet-id=\u0026#34;ext.c814d2943169cc7a8eb396089025e8d0\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 权限申请返回结果 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; requestCode 请求码 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; permissions 权限数组 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; grantResults 申请结果数组，里面都是int类型的数 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onRequestPermissionsResult\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; requestCode, @NonNull String[] permissions, @NonNull \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] grantResults)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onRequestPermissionsResult(requestCode, permissions, grantResults); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (requestCode) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (grantResults.length \u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; grantResults[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] == PackageManager.PERMISSION_GRANTED){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//同意权限申请\u0026amp;lt;/span\u0026gt; makeCall(); }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//拒绝权限申请\u0026amp;lt;/span\u0026gt; Toast.makeText(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;权限被拒绝了\u0026#34;\u0026amp;lt;/span\u0026gt;,Toast.LENGTH_SHORT).show(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;default\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } }` `\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 打电话方法 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;makeCall\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { Intent intent = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Intent(Intent.ACTION_CALL); intent.setData(Uri.parse(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;tel://123456789\u0026#34;\u0026amp;lt;/span\u0026gt;)); startActivity(intent); }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (SecurityException e){ e.printStackTrace(); } }` 上面只是对一个权限进行授权，如果我们需要对多个权限进行授权呢？难道还是这样一个一个写吗？答案是否定的，我们看一下授权申请的方法\n`ActivityCompat.requestPermissions(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; String[]{Manifest.permission.CALL_PHONE},\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;);` 我们注意到权限的参数是一个String类型的数组，这就说明我们可以直接把所有要授权的权限放在一个数组中，这样就可以对多个权限进行授权了\n以打电话和SD卡权限为例\npermissionList = new ArrayList\u0026lt;\u0026gt;(); if (ContextCompat.checkSelfPermission(this,Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){ permissionList.add(Manifest.permission.CALL_PHONE); } if (ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } if (!permissionList.isEmpty()){ //申请的集合不为空时，表示有需要申请的权限 ActivityCompat.requestPermissio8ns(this,permissionList.toArray(new String[permissionList.size()]),1); }else { //所有的权限都已经授权过了 } }\u0026#34; data-snippet-id=\u0026#34;ext.ff0bb02df4416bb454d3b2bed0141ea2\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 当有多个权限需要申请的时候 * 这里以打电话和SD卡读写权限为例 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;requestPermissions\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ List\u0026amp;lt;String\u0026amp;gt; permissionList = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (ContextCompat.checkSelfPermission(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){ permissionList.add(Manifest.permission.CALL_PHONE); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (ContextCompat.checkSelfPermission(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!permissionList.isEmpty()){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//申请的集合不为空时，表示有需要申请的权限\u0026amp;lt;/span\u0026gt; ActivityCompat.requestPermissio8ns(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,permissionList.toArray(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; String[permissionList.size()]),\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;); }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//所有的权限都已经授权过了\u0026amp;lt;/span\u0026gt; } }` 同样需要写onRequestPermissionsResult（）方法，这里和单个权限申请的写法有一点区别\n0){ //安全写法，如果小于0，肯定会出错了 for (int i = 0; i \u0026lt; grantResults.length; i++) { int grantResult = grantResults[i]; if (grantResult == PackageManager.PERMISSION_DENIED){ //这个是权限拒绝 String s = permissions[i]; Toast.makeText(this,s+\u0026amp;quot;权限被拒绝了\u0026amp;quot;,Toast.LENGTH_SHORT).show(); }else{ //授权成功了 //do Something } } } break; default: break; } }\u0026#34; data-snippet-id=\u0026#34;ext.789f8b8f8033b536ba78732541441089\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 权限申请返回结果 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; requestCode 请求码 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; permissions 权限数组 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; grantResults 申请结果数组，里面都是int类型的数 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onRequestPermissionsResult\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; requestCode, @NonNull String[] permissions, @NonNull \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] grantResults)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onRequestPermissionsResult(requestCode, permissions, grantResults); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (requestCode) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (grantResults.length \u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//安全写法，如果小于0，肯定会出错了\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; grantResults.length; i++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; grantResult = grantResults[i]; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (grantResult == PackageManager.PERMISSION_DENIED){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//这个是权限拒绝\u0026amp;lt;/span\u0026gt; String s = permissions[i]; Toast.makeText(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,s+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;权限被拒绝了\u0026#34;\u0026amp;lt;/span\u0026gt;,Toast.LENGTH_SHORT).show(); }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//授权成功了\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//do Something\u0026amp;lt;/span\u0026gt; } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;default\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } }` 上面两种是单个和多个的权限申请，可是这还有一个问题，就是我们只能在当前类中使用。这个时候，我们需要想到一个封装，然后让所有的类都可以使用。\n如何去封装呢？ 我们在开发一个项目的时候，都会打一个框架，这里面可定会有各种各样的基类，这个时候我们就可以把权限的申请放在BaseActivity中，然后各个子Activity去继承BaseActivity。\n然后通过接口回调的方式把授权结果传给子Activity。\n下面来看代码：\n首先是定义的接口\ngrantedPermission); //拒绝授权 void onDenied(List\u0026lt;String\u0026gt; deniedPermission); }\u0026#34; data-snippet-id=\u0026#34;ext.0f4c8fae6e47e05470987aca7add4a35\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * Created by 11213 on 2017/1/4. * 权限回调接口 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;interface\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;PermissionListener\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//授权成功\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onGranted\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//授权部分\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onGranted\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;List\u0026amp;lt;String\u0026amp;gt; grantedPermission\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//拒绝授权\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDenied\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;List\u0026amp;lt;String\u0026amp;gt; deniedPermission\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;/span\u0026gt;; }` BaseActivity的代码\npermissionList = new ArrayList\u0026lt;\u0026gt;(); //遍历传递过来的权限集合 for (String permission : permissions) { //判断是否已经授权 if (ContextCompat.checkSelfPermission(this,permission) != PackageManager.PERMISSION_GRANTED){ //未授权，则加入待授权的权限集合中 permissionList.add(permission); } } //判断集合 if (!permissionList.isEmpty()){ //如果集合不为空，则需要去授权 ActivityCompat.requestPermissions(this,permissionList.toArray(new String[permissionList.size()]),1); }else{ //为空，则已经全部授权 listener.onGranted(); } } /** * 权限申请结果 * @param requestCode 请求码 * @param permissions 所有的权限集合 * @param grantResults 授权结果集合 */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case 1: if (grantResults.length \u0026gt; 0){ //被用户拒绝的权限集合 List\u0026lt;String\u0026gt; deniedPermissions = new ArrayList\u0026lt;\u0026gt;(); //用户通过的权限集合 List\u0026lt;String\u0026gt; grantedPermissions = new ArrayList\u0026lt;\u0026gt;(); for (int i = 0; i \u0026lt; grantResults.length; i++) { //获取授权结果，这是一个int类型的值 int grantResult = grantResults[i]; if (grantResult != PackageManager.PERMISSION_GRANTED){ //用户拒绝授权的权限 String permission = permissions[i]; deniedPermissions.add(permission); }else{ //用户同意的权限 String permission = permissions[i]; grantedPermissions.add(permission); } } if (deniedPermissions.isEmpty()){ //用户拒绝权限为空 mlistener.onGranted(); }else { //不为空 //回调授权成功的接口 mlistener.onDenied(deniedPermissions); //回调授权失败的接口 mlistener.onGranted(grantedPermissions); } } break; default: break; } } }\u0026#34; data-snippet-id=\u0026#34;ext.c943cef309b422e3f8f37937b199c748\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;BaseActivity1\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AppCompatActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; PermissionListener mlistener; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 权限申请 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; permissions 待申请的权限集合 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; listener 申请结果监听事件 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;requestRunTimePermission\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(String[] permissions,PermissionListener listener)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.mlistener = listener; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//用于存放为授权的权限\u0026amp;lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; permissionList = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//遍历传递过来的权限集合\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (String permission : permissions) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//判断是否已经授权\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (ContextCompat.checkSelfPermission(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,permission) != PackageManager.PERMISSION_GRANTED){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//未授权，则加入待授权的权限集合中\u0026amp;lt;/span\u0026gt; permissionList.add(permission); } } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//判断集合\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!permissionList.isEmpty()){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//如果集合不为空，则需要去授权\u0026amp;lt;/span\u0026gt; ActivityCompat.requestPermissions(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,permissionList.toArray(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; String[permissionList.size()]),\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;); }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//为空，则已经全部授权\u0026amp;lt;/span\u0026gt; listener.onGranted(); } } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 权限申请结果 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; requestCode 请求码 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; permissions 所有的权限集合 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; grantResults 授权结果集合 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onRequestPermissionsResult\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; requestCode, @NonNull String[] permissions, @NonNull \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] grantResults)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onRequestPermissionsResult(requestCode, permissions, grantResults); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (requestCode) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (grantResults.length \u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//被用户拒绝的权限集合\u0026amp;lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; deniedPermissions = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//用户通过的权限集合\u0026amp;lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; grantedPermissions = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; grantResults.length; i++) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获取授权结果，这是一个int类型的值\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; grantResult = grantResults[i]; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (grantResult != PackageManager.PERMISSION_GRANTED){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//用户拒绝授权的权限\u0026amp;lt;/span\u0026gt; String permission = permissions[i]; deniedPermissions.add(permission); }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//用户同意的权限\u0026amp;lt;/span\u0026gt; String permission = permissions[i]; grantedPermissions.add(permission); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (deniedPermissions.isEmpty()){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//用户拒绝权限为空\u0026amp;lt;/span\u0026gt; mlistener.onGranted(); }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//不为空\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//回调授权成功的接口\u0026amp;lt;/span\u0026gt; mlistener.onDenied(deniedPermissions); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//回调授权失败的接口\u0026amp;lt;/span\u0026gt; mlistener.onGranted(grantedPermissions); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;default\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } } }` 子Activity中进行调用\ngrantedPermission) { //授权失败权限集合 } @Override public void onDenied(List\u0026lt;String\u0026gt; deniedPermission) { //授权成功权限集合 } }); }\u0026#34; data-snippet-id=\u0026#34;ext.03eae7d246bb567fcbd94c1bf544e33f\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;requestPermission\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ requestRunTimePermission(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; String[]{Manifest.permission.CALL_PHONE, Manifest.permission.WRITE_EXTERNAL_STORAGE} , \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; PermissionListener() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onGranted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//所有权限授权成功\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onGranted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(List\u0026amp;lt;String\u0026amp;gt; grantedPermission)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//授权失败权限集合\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDenied\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(List\u0026amp;lt;String\u0026amp;gt; deniedPermission)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//授权成功权限集合\u0026amp;lt;/span\u0026gt; } }); }` 上面的代码注释很详细，就不再解释了\n上面的封装，只能用在Activity中，如果要用在非Activity中（在v4包下的Fragment也可以进行授权），比如工具类中使用时，上面的就不适用了，因为我们看到，申请权限的方法必须传递一个Activity对象，为Activity又不可以new。这个时候，我们要想到，Activity管理栈。\n代码如下：\n接口还是上面的接口。。。\nActivity管理栈\nactivityList = new ArrayList\u0026lt;\u0026gt;(); /** 添加一个Activity到集合中*/ public static void addActivity(Activity activity){ activityList.add(activity); } /** 从集合中删除一个Activity*/ public static void removeActivity(Activity activity){ activityList.remove(activity); } /**获取Activity栈中的栈顶的Activity * 需要注意的是，栈是先进后出，所以最上面的Activity是集合中的最后一个*/ public static Activity getTopActivity(){ if (activityList.isEmpty()){ //Activity栈为空 return null; }else { //不为空时 return activityList.get(activityList.size() - 1); } } }\u0026#34; data-snippet-id=\u0026#34;ext.8d1bd8fb905fe33c054dc5d0c20e7d01\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * Created by 11213 on 2017/1/5. * Activity管理类 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ActivityCollector\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; List\u0026amp;lt;Activity\u0026amp;gt; activityList = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** 添加一个Activity到集合中*/\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;addActivity\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;Activity activity\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;/span\u0026gt;{ activityList.add(activity); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** 从集合中删除一个Activity*/\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;removeActivity\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;Activity activity\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;/span\u0026gt;{ activityList.remove(activity); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/**获取Activity栈中的栈顶的Activity * 需要注意的是，栈是先进后出，所以最上面的Activity是集合中的最后一个*/\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; Activity \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getTopActivity\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (activityList.isEmpty()){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//Activity栈为空\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//不为空时\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; activityList.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;get\u0026amp;lt;/span\u0026gt;(activityList.size() - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;); } } }` BaseActivity的代码\npermissionList = new ArrayList\u0026lt;\u0026gt;(); //遍历传递过来的权限集合 for (String permission : permissions) { //判断是否已经授权 if (ContextCompat.checkSelfPermission(topActivity,permission) != PackageManager.PERMISSION_GRANTED){ //未授权，则加入待授权的权限集合中 permissionList.add(permission); } } //判断集合 if (!permissionList.isEmpty()){ //如果集合不为空，则需要去授权 ActivityCompat.requestPermissions(topActivity,permissionList.toArray(new String[permissionList.size()]),1); }else{ //为空，则已经全部授权 listener.onGranted(); } } /** * 权限申请结果 * @param requestCode 请求码 * @param permissions 所有的权限集合 * @param grantResults 授权结果集合 */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case 1: if (grantResults.length \u0026gt; 0){ //被用户拒绝的权限集合 List\u0026lt;String\u0026gt; deniedPermissions = new ArrayList\u0026lt;\u0026gt;(); //用户通过的权限集合 List\u0026lt;String\u0026gt; grantedPermissions = new ArrayList\u0026lt;\u0026gt;(); for (int i = 0; i \u0026lt; grantResults.length; i++) { //获取授权结果，这是一个int类型的值 int grantResult = grantResults[i]; if (grantResult != PackageManager.PERMISSION_GRANTED){ //用户拒绝授权的权限 String permission = permissions[i]; deniedPermissions.add(permission); }else{ //用户同意的权限 String permission = permissions[i]; grantedPermissions.add(permission); } } if (deniedPermissions.isEmpty()){ //用户拒绝权限为空 mlistener.onGranted(); }else { //不为空 //回调授权成功的接口 mlistener.onDenied(deniedPermissions); //回调授权失败的接口 mlistener.onGranted(grantedPermissions); } } break; default: break; } } }\u0026#34; data-snippet-id=\u0026#34;ext.60b0918cb02dbae2cbe55fba8666bfcc\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;BaseActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AppCompatActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; PermissionListener mlistener; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 创建Activity时加到管理栈中 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; savedInstanceState */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(@Nullable Bundle savedInstanceState)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreate(savedInstanceState); ActivityCollector.addActivity(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 销毁时从Activity管理栈中移除 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDestroy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onDestroy(); ActivityCollector.removeActivity(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 权限申请 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; permissions 待申请的权限集合 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; listener 申请结果监听事件 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;requestRunTimePermission\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(String[] permissions,PermissionListener listener)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ mlistener = listener; Activity topActivity = ActivityCollector.getTopActivity(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (topActivity == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//用于存放为授权的权限\u0026amp;lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; permissionList = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//遍历传递过来的权限集合\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (String permission : permissions) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//判断是否已经授权\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (ContextCompat.checkSelfPermission(topActivity,permission) != PackageManager.PERMISSION_GRANTED){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//未授权，则加入待授权的权限集合中\u0026amp;lt;/span\u0026gt; permissionList.add(permission); } } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//判断集合\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!permissionList.isEmpty()){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//如果集合不为空，则需要去授权\u0026amp;lt;/span\u0026gt; ActivityCompat.requestPermissions(topActivity,permissionList.toArray(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; String[permissionList.size()]),\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;); }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//为空，则已经全部授权\u0026amp;lt;/span\u0026gt; listener.onGranted(); } } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 权限申请结果 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; requestCode 请求码 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; permissions 所有的权限集合 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; grantResults 授权结果集合 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onRequestPermissionsResult\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; requestCode, @NonNull String[] permissions, @NonNull \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] grantResults)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onRequestPermissionsResult(requestCode, permissions, grantResults); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (requestCode) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (grantResults.length \u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//被用户拒绝的权限集合\u0026amp;lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; deniedPermissions = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//用户通过的权限集合\u0026amp;lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; grantedPermissions = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; grantResults.length; i++) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获取授权结果，这是一个int类型的值\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; grantResult = grantResults[i]; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (grantResult != PackageManager.PERMISSION_GRANTED){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//用户拒绝授权的权限\u0026amp;lt;/span\u0026gt; String permission = permissions[i]; deniedPermissions.add(permission); }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//用户同意的权限\u0026amp;lt;/span\u0026gt; String permission = permissions[i]; grantedPermissions.add(permission); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (deniedPermissions.isEmpty()){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//用户拒绝权限为空\u0026amp;lt;/span\u0026gt; mlistener.onGranted(); }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//不为空\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//回调授权成功的接口\u0026amp;lt;/span\u0026gt; mlistener.onDenied(deniedPermissions); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//回调授权失败的接口\u0026amp;lt;/span\u0026gt; mlistener.onGranted(grantedPermissions); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;default\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } } }` 调用方法\ngrantedPermission) { } @Override public void onDenied(List\u0026lt;String\u0026gt; deniedPermission) { } }); } }\u0026#34; data-snippet-id=\u0026#34;ext.a6e743e188017c0c176d406510f98143\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Util\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;requestPermission\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ BaseActivity.requestRunTimePermission(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; String[]{Manifest.permission.CALL_PHONE, Manifest.permission.WRITE_EXTERNAL_STORAGE} , \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; PermissionListener() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onGranted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onGranted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(List\u0026amp;lt;String\u0026amp;gt; grantedPermission)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDenied\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(List\u0026amp;lt;String\u0026amp;gt; deniedPermission)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ } }); } }` 后边的这些代码的注释写的很详细，大家都可以看明白。这些可以直接封装到自己的项目中，另外还有一些其他的封装思路，比如郭神说的使用一个透明的Activity。当然我们也可以使用第三方库。\n官方文档：https://developer.android.com/guide/topics/permissions/requesting.html\n","permalink":"https://blog.zdltech.com/posts/android%E5%8A%A8%E6%80%81%E8%8E%B7%E5%8F%96%E6%9D%83%E9%99%90/","summary":"\u003cp\u003e前几天在网上找了找Android动态获取权限的文章和视频，自己整理了一下。几天看一位大神说真正的程序员是有着分享精神的，我这个刚刚入行的小菜鸟，也想把自己整理的东西分享给大家。\u003c/p\u003e\n\u003cp\u003e本文参考了\u003ca href=\"http://www.jianshu.com/u/75729e43614d\"\u003eA_si\u003c/a\u003e的\u003ca href=\"http://www.jianshu.com/p/c6cb758cbb43\"\u003ePermission——郭霖认为最优的运行时权限方案\u003c/a\u003e和\u003ca href=\"http://edu.csdn.net/course/detail/3539\"\u003e郭霖大神的CSDN视屏\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"-\"\u003e\u003ca target=\"_blank\" name=\"t0\"\u003e\u003c/a\u003e在这之前，我们需要知道什么是权限?\u003c/h2\u003e\n\u003cp\u003e权限是一种安全机制。Android权限主要用于限制应用程序内部某些具有限制性特性的功能使用以及应用程序之间的组件访问。\u003cbr\u003e\n比如网络权限\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003ccode\u003e\u0026quot; data-snippet-id=\u0026quot;ext.1ecd4ff36f58d5c42638b9d887b68988\u0026quot; data-snippet-saved=\u0026quot;false\u0026quot; data-codota-status=\u0026quot;done\u0026quot;\u0026gt;\u0026amp;lt;user-permission android:name=\u0026quot;android.permission.INTERNET\u0026quot;/\u0026amp;gt;\u003c/code\u003e当我们的程序需要访问网络的时候，必须添加这个权限，不添加则无法访问网络。\u003c/p\u003e\n\u003cp\u003e这里还需要注意的是：在Android6.0之前，我们只需要在AndroidManifest.xml文件中直接添加权限即可，但是在Android6.0之后，我们只在AndroidManifest.xml文件中配置是不够的，还需要在Java代码中进行动态获取权限。当然这里不是所有的权限都需要动态获取，只需要获取危险权限就可以了。（毕竟Android权限100多种，要是每个都需要获取，那不累死开发人员啦）\u003c/p\u003e\n\u003ch2 id=\"android-9-24-\"\u003e\u003ca target=\"_blank\" name=\"t1\"\u003e\u003c/a\u003eAndroid中的危险权限分为9组24种\u003c/h2\u003e\n\u003cdiv class=\"image-package\"\u003e\n\u003cpre\u003e\u003ccode\u003e![](http://upload-images.jianshu.io/upload_images/3780051-92dda32c577e32cb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-caption\"\u003e\n    1454742-2c2196fd438a4ed3.png\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e我们只需要在用这些权限的时候，才需要去动态申请，除这些之外的权限，我们只需要在AndroidManifest.xml文件种写上即可，动态申请的权限同样需要在AndroidManifest.xml文件中写。而且每一组种的权限只要有一个授权了，其他的也会自动授权\u003c/p\u003e\n\u003cp\u003e下面这张图是我们的build.gradle文件中的版本信息\u003c/p\u003e\n\u003cdiv class=\"image-package\"\u003e\n\u003cpre\u003e\u003ccode\u003e![](http://upload-images.jianshu.io/upload_images/3780051-e00a73adfc0a922a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-caption\"\u003e\n    Image.png\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e1、targetSdkVersion版本号如果\u0026lt;= 21时，不需要动态处理权限 。但是有时候我们的应用程序会打不开。\u003cbr\u003e\n2、如果是之前的老版本升级上来的，系统会默认开启之前所有的权限，比如之前的targetSdkVersion是21，后来升级之后变成了25，这个时候系统会自动授权。一定要记住是升级变成的25，否则还是需要授权。\u003c/p\u003e\n\u003cp\u003eTips： 为什么SD卡读写权限是危险权限,能不能不申请权限但又能使用SD卡呢？\u003cbr\u003e\n（1）把SD权限设置为危险权限，是为了防止应用随便在用户的手机上些东西，如果不加防范，用户的SD卡就会有很多乱七八糟的东西。\u003cbr\u003e\n（2）用户可以不申请权限而使用SD卡，但是只能使用系统提供的默认的路径。\u003cbr\u003e\n我们可以使用Android系统提供的SDK目录。路径是Android\\data\\程序包名。这个目录是程序可以不需要经过\u003cbr\u003e\n用户授权就可以直接使用，甚至不需要添加WRITE_EXTERNAL_STORAGE这个权限。 这个目录会在程序删除时也会直接删除。\u003c/p\u003e\n\u003cp\u003e如何访问这个目录呢？\u003cbr\u003e\nFile file = getExternalCacheDir();\u003cbr\u003e\nString s = file.getPath; 这个方法得到的是cache的路径，但是一般的垃圾清理软件都可以把这里面的数据清理掉\u003cbr\u003e\nFile[] files = getExternalCacheDirs(); 这个得到的是一个文件数组，要求Api最小19\u003c/p\u003e\n\u003cp\u003e如果我们不想垃圾清理软件把我们缓存的数据清理掉，则可以放在file文件下\u003cbr\u003e\ngetExternalFilesDir(“”); 这个表示所有的操作都是放在file目录下进行的\u003cbr\u003e\ngetExternalFilesDir(“mm”); 这个表示会在file目录下在见一个mm目录，然后所有的操作都会放在这个目录下。\u003c/p\u003e\n\u003ch2 id=\"-\"\u003e\u003ca target=\"_blank\" name=\"t2\"\u003e\u003c/a\u003e下面我们来看如何动态获取权限！！！\u003c/h2\u003e\n\u003ch3 id=\"-\"\u003e\u003ca target=\"_blank\" name=\"t3\"\u003e\u003c/a\u003e先看最简单的，动态获取一个权限\u003c/h3\u003e\n\u003cp\u003e比如现在要动态获取一个打电话的权限。。\u003cbr\u003e\n首先需要在AndroidManifest.xml文件中写上这个权限\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003ccode\u003e\u0026quot; data-snippet-id=\u0026quot;ext.f281d8d8d9cfe2d283d570842a2b4c1e\u0026quot; data-snippet-saved=\u0026quot;false\u0026quot; data-codota-status=\u0026quot;done\u0026quot;\u0026gt;\u0026amp;lt;user-permission android:name=\u0026quot;android.premission.CALL_PHONE\u0026quot;/\u0026amp;gt;\u003c/code\u003e\u003cbr\u003e\n然后在Java代码进行动态获取\u003cbr\u003e\n请求授权的代码\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e` \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * 请求授权\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;requestPermission\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (ContextCompat.checkSelfPermission(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//表示未授权时\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//进行授权\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            ActivityCompat.requestPermissions(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; String[]{Manifest.permission.CALL_PHONE},\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//调用打电话的方法\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            makeCall();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e请求之后，我们需要重写onRequestPermissionsResult这个方法\u003c/p\u003e","title":"Android动态获取权限"},{"content":" ### 一、反编译代码 **1、**反编译java代码首先需要下载**dex2jar**这个工具，下载地址：[https://sourceforge.net/projects/dex2jar/files/](https://sourceforge.net/projects/dex2jar/files/) 目前最新版是2.0， 下载完后并解压缩。 2、将要反编译的apk文件重命名为zip格式并解压缩，注意其中的classes.dex文件，它存放了全部的java代码，将classes.dex文件拷贝到dex2jar解压后的根目录下。 **3、**打开cmd，进入dex2jar解压后的根目录，执行命令：\n**\nd2j-dex2jar classes.dex 如下图： ![](http://upload-images.jianshu.io/upload_images/1633070-6fc5febd3f11a9ef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; dex2jar \u0026lt;/div\u0026gt; 命令执行完后在对应目录下会生成\u0026lt;strong\u0026gt;classes-dex2jar.jar**文件 ![](http://upload-images.jianshu.io/upload_images/1633070-ba7fc87bb47cc64e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; jar文件 \u0026lt;/div\u0026gt; **4、**要查看java代码，还需要下载**jd-gui**这个工具，下载地址：[http://jd.benow.ca/](http://jd.benow.ca/)，目前最新版是1.4.0，下载完后解压缩，并用**jd-gui.exe**打开上边反编译出来的jar文件： ![](http://upload-images.jianshu.io/upload_images/1633070-3bb77b39750f7562.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; java code \u0026lt;/div\u0026gt; 到此，已经顺利的反编译出了java代码 那资源文件呢，再回头看一下刚才apk文件对应的解压缩文件，所有的xml文件都是乱码，例如AndroidManifest.xml：\n![](http://upload-images.jianshu.io/upload_images/1633070-2e019b033641d4d3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; AndroidManifest.xml \u0026lt;/div\u0026gt; 当然要还原原始的资源文件还是有办法的，继续往下看。 二、反编译资源 **1、**要反编译apk中的资源文件，就需要**apktool**这个工具了，下载地址：[http://ibotpeaches.github.io/Apktool/install/](http://ibotpeaches.github.io/Apktool/install/)，进入下载页面： ![](http://upload-images.jianshu.io/upload_images/1633070-6715ef0d87edee56.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; apktool download \u0026lt;/div\u0026gt; 按照图中1、2两条的提示，下载**apktool.bat和apktool.jar**这两个文件，目前最新的apktool是2.1.1，并放到同一文件夹： ![](http://upload-images.jianshu.io/upload_images/1633070-e6e8d64f3519b021.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; apktool \u0026lt;/div\u0026gt; ， **2、**将要反编译的apk文件放到apktool文件夹，打开cmd，进入apktool文件夹目录，执行命令：\n**\napktool d test.apk 如下图： ![](http://upload-images.jianshu.io/upload_images/1633070-151c11d5e4441a32.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; apktool d test.apk \u0026lt;/div\u0026gt; 执行成功后，在当前目录下会生成一个\u0026lt;strong\u0026gt;test**文件夹： ![](http://upload-images.jianshu.io/upload_images/1633070-fa211d2ec1ef87f7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; test文件夹目录 \u0026lt;/div\u0026gt; 其中，res文件夹下存放的是反编译出来的所有资源，smali文件夹下存放的是反编译出来的所有代码，AndroidManifest.xml则是经过反编译还原后的manifest文件。smali文件夹下的文件smali文件使用的是Android虚拟机所使用的寄存器语言，如果看的懂smail文件的话，就可以修改源代码的逻辑了，好可怕的事\u0026amp;#8230;当然这不是我们重点讨论的。 此时查看AndroidManifest.xml文件，发现已经成功反编译出来了：\n![](http://upload-images.jianshu.io/upload_images/1633070-d2b11ce97476bbe7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; AndroidManifest.xml \u0026lt;/div\u0026gt; 三、重新打包 **1、**既然资源文件已经顺利的反编译出来了，那我们就可以适当的修改点东西了，例如换个图标啥的、改下布局文件等，这里我们将AndroidManifest.xml中的**channel**值改为**10001**，然后开始重新打包，同样在cmd中切换到apktool文件夹目录，执行命令： **\napktool b test -o new_test.apk 如下图： ![](http://upload-images.jianshu.io/upload_images/1633070-bf129e00ce2c95a3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; 重新打包 \u0026lt;/div\u0026gt; 执行成功后，在当前目录会生成一个新的\u0026lt;strong\u0026gt;new_test.apk**文件： ![](http://upload-images.jianshu.io/upload_images/1633070-698147e9613e33d2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; new_test.apk \u0026lt;/div\u0026gt; **2、**但是呢，这个apk文件目前并不能安装，因为需要重新签名。没有签名文件的话，通过Android Studio可以很简单的生成一个哦，将准备好的签名文件放到apktool文件夹根目录，继续在cmd执行命令： **\njarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore 签名文件名 -storepass 签名密码 待签名的APK文件名 签名的别名 如下图： ![](http://upload-images.jianshu.io/upload_images/1633070-33d04894402b27a6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; jarsigner start \u0026lt;/div\u0026gt; ![](http://upload-images.jianshu.io/upload_images/1633070-023bbb0c13037123.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; jarsigner success \u0026lt;/div\u0026gt; 注意，其中jarsigner命令文件是存放在jdk的bin目录下的，需要将bin目录配置在系统的环境变量中才可以在任何位置执行此命令。 3、签名完成后，建议对APK文件进行一次对齐操作，这样可以使得程序在Android系统中运行得更快，对齐操作使用的是zipalign工具，该工具在/build-tools/**目录下，需要将这个目录配置到系统环境变量当中才可以在任何位置执行此命令。继续在cmd中执行命令：\n**\nzipalign 4 new_test.apk new_test_aligned.apk 执行成功后，会生成一个对齐后的\u0026lt;strong\u0026gt;new_test_aligned.apk**文件： ![](http://upload-images.jianshu.io/upload_images/1633070-4f618b2fa16e0096.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; new_test_aligned.apk \u0026lt;/div\u0026gt; **4、**最后可以通过如下命令验证apk签名是否成功： **\njarsigner -verify -verbose -certs new_test_aligned.apk 如下图： ![](http://upload-images.jianshu.io/upload_images/1633070-ea4fcacc116d84aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; verify start \u0026lt;/div\u0026gt; ![](http://upload-images.jianshu.io/upload_images/1633070-0df1b887a22faf23.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt; verify success \u0026lt;/div\u0026gt; 到这里apk反编译及重新打包流程就介绍完毕了。 \u0026lt;strong\u0026gt;以上用到的工具也可以在此下载哦：[反编译及二次打包工具](http://download.csdn.net/detail/shehuan320_/9551427)** 转载：http://www.jianshu.com/p/792a08d5452c\n安卓apk反编译、修改、重新打包、签名全过程 首先明确，反编译别人apk是一件不厚道的事情。代码是程序员辛苦工作的成果，想通过这种手段不劳而获，是不对的。这也说明，代码混淆是非常重要的。本文抱着学习的态度，研究在一些特殊的情况下如果有需要，该怎么反编译apk。\n工具简介 apktool，编译和反编译apk，从apk中提取图片和布局资源\ndex2jar，将可运行文件classes.dex反编译为jar源码文件\njd-gui，查看jar源码文件\n反编译 apktool安装 Windows系统：\n首先确保系统安装有Java 下载apktool.bat脚本 下载最新版本的apktool.jar，并且重命名为apktool.jar 将apktool.bat和apktool.jar放在同一目录下，就可以在命令行窗口使用了。 其他系统请参考链接 用法 可以直接在命令行执行apktool.bat查看帮助。这里介绍两个最常用的：\n反编译 `apktool\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.bat\u0026amp;lt;/span\u0026gt; d -o \u0026amp;lt;output_dir\u0026amp;gt; test\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.apk\u0026amp;lt;/span\u0026gt;` 其中\u0026lt;output_dir\u0026gt;指定输出目录，默认为apk.out。\n编译 `apktool.bat b -o \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;output.apk\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;input_dir\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 其中\u0026lt;input_dir\u0026gt;就是上面反编译输出的目录，\u0026lt;ouput.apk\u0026gt;是编译的输出结果，默认为dist/.apk。\n示例 一个典型的apktool反编译的结果如下：\n此时，可以查看AndroidManifest.xml，res及smali文件了。甚至可以修改这个目录下的资源文件或者smali文件，然后重新编译。\n值得注意的是，apktool反编译出来只能得到apk的smali文件，即汇编语言版本，并不能得到源代码。\n查看源码 一. 这里需要用到另外两个工具，下载dex2jar并解压。下载jd-gui，这是一个带UI的应用程序。\n二. 将需要反编译的apk的后缀名改为.zip或者.rar，然后解压到一个文件夹，得到其中的classes.dex文件。\n三. 将classes.dex复制到解压后的dex2jar-2.0文件夹下。从命令行进入到该目录，执行\n`d2j-dex2jar\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.bat\u0026amp;lt;/span\u0026gt; classes\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.dex\u0026amp;lt;/span\u0026gt;` 会生成由classes.dex反编译得到的jar文件，classes-dex2jar.jar。\n四. 然后使用jd-gui打开classes-dex2jar.jar，就可以查看源码了。\n如果apk在发布的时候加过混淆处理，那么我们也只能得到混淆后的版本。想通过阅读源码来破解别人的apk，还是有一些难度的。\n修改代码 如果只是修改apk相应的资源，例如图片，比较好办，在res文件夹下找到相应的文件替换就可以。\n修改代码比较麻烦，因为反编译出来的结果中只有smali文件，即Java虚拟机支持的汇编语言。\n如果确实需要修改代码，就得对照smali文件和从classes.dex反编译出来的源码了，按照smali的规范来改动即可。相当于写汇编，这个难度比较大。\n重新打包 使用apktool编译前面反编译生成的目录即可。\n签名 签名是对要发布的apk文件作标记，确保你的apk文件有唯一的身份归属认证，只有相同签名和相同包名的文件才可以覆盖安装并保留用户信息。\n对于反编译的apk，我们可以通过jarsigner来对它进行签名。\n生成keystore文件 首先，签名需要keystore文件，可以使用keytool工具生成，一般Java环境都带有keytool命令，可以在命令行测试。\n`keytool \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;-genkey\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;-alias\u0026amp;lt;/span\u0026gt; demo\u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;keystore \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;-keyalg\u0026amp;lt;/span\u0026gt; RSA \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;-validity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;40000\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;-keystore\u0026amp;lt;/span\u0026gt; demo\u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;keystore` 各个参数解释如下：\n-genkey 产生证书文件\n-alias 产生别名\n-keystore 指定密钥库的.keystore文件中\n-keyalg 指定密钥的算法,这里指定为RSA(非对称密钥算法)\n-validity 为证书有效天数，这里我们写的是40000天\n输入上述命令后，会有如下的提示：\n的主密码 （如果和 keystore 密码相同，按回车）：1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \u0026#34; data-snippet-id=\u0026#34;ext.ce951cbdba2d3ebc4e65523849d95030\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`输入keystore密码： 再次输入新密码: 您的名字与姓氏是什么？ [Unknown]： test 您的组织单位名称是什么？ [Unknown]： test 您的组织名称是什么？ [Unknown]： 您所在的城市或区域名称是什么？ [Unknown]： 您所在的州或省份名称是什么？ [Unknown]： 该单位的两字母国家代码是什么 [Unknown]： CN=test, OU=test, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;O\u0026amp;lt;/span\u0026gt;=Unknown, L=Unknown, ST=Unknown, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;C\u0026amp;lt;/span\u0026gt;=Unknown 正确吗？ [否]： y 输入\u0026amp;lt;demo.keystore\u0026amp;gt;的主密码 （如果和 keystore 密码相同，按回车）：` 签名apk jarsigner也存在于Java JDK的安装包当中，所以安装好了Java环境的话，可以直接在命令行使用。\n`jarsigner -verbose -keystore demo\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.keystore\u0026amp;lt;/span\u0026gt; demo\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.apk\u0026amp;lt;/span\u0026gt; demo\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.keystore\u0026amp;lt;/span\u0026gt;` -verbose 指定生成详细输出\n-keystore 指定数字证书存储路径\n这样，就完成了对一个apk的签名过程，然后就可以安装使用了。注意如果你的手机上原来就有这个apk，需要卸载掉。因为新apk的签名已经改变了。\n参考 apktool\ndex2jar\njd-gui\nAndroid开发学习总结（六）—— APK反编译\nandroid apk反编译、修改源码、重新打包全过程\n","permalink":"https://blog.zdltech.com/posts/android-apk%E5%8F%8D%E7%BC%96%E8%AF%91%E5%8F%8A%E9%87%8D%E6%96%B0%E6%89%93%E5%8C%85%E6%B5%81%E7%A8%8B/","summary":"\u003cdiv\u003e\n  ### 一、反编译代码\n\u003cpre\u003e\u003ccode\u003e**1、**反编译java代码首先需要下载**dex2jar**这个工具，下载地址：[https://sourceforge.net/projects/dex2jar/files/](https://sourceforge.net/projects/dex2jar/files/)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e目前最新版是2.0， 下载完后并解压缩。\n\u003cstrong\u003e2、\u003cstrong\u003e将要反编译的apk文件重命名为zip格式并解压缩，注意其中的\u003c/strong\u003eclasses.dex\u003c/strong\u003e文件，它存放了全部的java代码，将classes.dex文件拷贝到dex2jar解压后的根目录下。\n**3、**打开cmd，进入dex2jar解压后的根目录，执行命令：\u003c/p\u003e\n\u003cp\u003e**\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  d2j-dex2jar classes.dex\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/blockquote\u003e\n\u003cpre\u003e\u003ccode\u003e如下图：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-package\"\u003e\n\u003cpre\u003e\u003ccode\u003e  ![](http://upload-images.jianshu.io/upload_images/1633070-6fc5febd3f11a9ef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n\n\n\u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt;\n  dex2jar\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e命令执行完后在对应目录下会生成\u0026lt;strong\u0026gt;classes-dex2jar.jar**文件\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-package\"\u003e\n\u003cpre\u003e\u003ccode\u003e  ![](http://upload-images.jianshu.io/upload_images/1633070-ba7fc87bb47cc64e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n\n\n\u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt;\n  jar文件\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e**4、**要查看java代码，还需要下载**jd-gui**这个工具，下载地址：[http://jd.benow.ca/](http://jd.benow.ca/)，目前最新版是1.4.0，下载完后解压缩，并用**jd-gui.exe**打开上边反编译出来的jar文件：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-package\"\u003e\n\u003cpre\u003e\u003ccode\u003e  ![](http://upload-images.jianshu.io/upload_images/1633070-3bb77b39750f7562.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n\n\n\u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt;\n  java code\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e到此，已经顺利的反编译出了java代码\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e那资源文件呢，再回头看一下刚才apk文件对应的解压缩文件，所有的xml文件都是乱码，例如\u003cstrong\u003eAndroidManifest.xml\u003c/strong\u003e：\u003c/p\u003e\n  \u003cdiv class=\"image-package\"\u003e\n\u003cpre\u003e\u003ccode\u003e  ![](http://upload-images.jianshu.io/upload_images/1633070-2e019b033641d4d3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n\n\n\u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt;\n  AndroidManifest.xml\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e当然要还原原始的资源文件还是有办法的，继续往下看。\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3 id=\"二反编译资源\"\u003e二、反编译资源\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003e**1、**要反编译apk中的资源文件，就需要**apktool**这个工具了，下载地址：[http://ibotpeaches.github.io/Apktool/install/](http://ibotpeaches.github.io/Apktool/install/)，进入下载页面：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-package\"\u003e\n\u003cpre\u003e\u003ccode\u003e  ![](http://upload-images.jianshu.io/upload_images/1633070-6715ef0d87edee56.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n\n\n\u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt;\n  apktool download\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e按照图中1、2两条的提示，下载**apktool.bat和apktool.jar**这两个文件，目前最新的apktool是2.1.1，并放到同一文件夹：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-package\"\u003e\n\u003cpre\u003e\u003ccode\u003e  ![](http://upload-images.jianshu.io/upload_images/1633070-e6e8d64f3519b021.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n\n\n\u0026lt;div class=\u0026quot;image-caption\u0026quot;\u0026gt;\n  apktool\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e，\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e**2、**将要反编译的apk文件放到apktool文件夹，打开cmd，进入apktool文件夹目录，执行命令：\u003c/p\u003e","title":"Android apk反编译及重新打包流程"},{"content":"Spring Boot加载配置文件 https://my.oschina.net/wangyuefive/blog/704615#h3_4 问题3：如何根据线上环境和线下环境加载不同的配置？如何加载多个配置文件？ 1、Profiles： Spring Profiles提供了一种隔离应用程序配置的方式，并让这些配置只能在特定的环境下生效。在配置文件中，用spring.profiles.active属性来指定特定环境的配置文件。在Spring Boot中多环境配置文件名需要满足application-{profile}.properties的格式，其中{profile}对应你的环境标识，比如：\napplication-dev.properties：开发环境 application-test.properties：测试环境 application-prod.properties：生产环境 至于哪个具体的配置文件会被加载，需要在application.properties文件中通过spring.profiles.active属性来设置，其值对应{profile}值。例如：\napplication.properties配置：spring.profiles.active = dev即指定application-dev.properties会被加载。\n2、通过启动参数指定运行环境。 通过命令行启动：\n` java -jar xxxxx.jar \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;--spring.profiles.active=prod。\u0026amp;lt;/span\u0026gt;` 上述指定为prod环境，则spring application会自动根据application-{profile}.properties的格式找到application-prod.properties文件加载。\n3、加载多个自定义文件。 例如：\n` spring.profiles.active = dev,database` 等于告诉Spring Boot加载application-dev.properties和application-database.properties文件，从而实现多个配置文件的加载。\n四种读取properties文件的方式 http://www.imooc.com/article/18252\n集成Mybatis http://www.imooc.com/article/15406\n开启定时任务 http://www.imooc.com/article/15612\nspring-boot上传文件MultiPartFile获取不到文件问题解决\nhttp://blog.csdn.net/happy_cheng/article/details/54178392\nSpring boot上传文件时MultipartFile为空问题 http://blog.csdn.net/tanga842428/article/details/72773773\nspring boot默认日志配置，以及改用log4j日志配置学习使用排出多余的依赖\nhttp://blog.csdn.net/yanweihpu/article/details/54139382\nhttp://blog.csdn.net/loongshawn/article/details/50951329\n","permalink":"https://blog.zdltech.com/posts/springboot-%E5%AD%A6%E4%B9%A0%E7%BD%91%E7%AB%99%E6%94%B6%E8%97%8F/","summary":"\u003ch1 class=\"detail-title\" id=\"spring-boot加载配置文件\"\u003eSpring Boot加载配置文件\u003c/h1\u003e\n\u003ch1 class=\"detail-title\"\u003e\u003ca href=\"https://my.oschina.net/wangyuefive/blog/704615#h3_4\"\u003ehttps://my.oschina.net/wangyuefive/blog/704615#h3_4\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch2 id=\"h2_6\"\u003e\u003cstrong\u003e问题3：如何根据线上环境和线下环境加载不同的配置？如何加载多个配置文件？\u003c/strong\u003e\u003c/h2\u003e\n\u003ch3 id=\"h3_7\"\u003e\u003cstrong\u003e1、Profiles：\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003eSpring Profiles提供了一种隔离应用程序配置的方式，并让这些配置只能在特定的环境下生效。在配置文件中，用spring.profiles.active属性来指定特定环境的配置文件。在Spring Boot中多环境配置文件名需要满足\u003ccode\u003eapplication-{profile}.properties\u003c/code\u003e的格式，其中\u003ccode\u003e{profile}\u003c/code\u003e对应你的环境标识，比如：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eapplication-dev.properties\u003c/code\u003e：开发环境\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eapplication-test.properties\u003c/code\u003e：测试环境\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eapplication-prod.properties\u003c/code\u003e：生产环境\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e至于哪个具体的配置文件会被加载，需要在\u003ccode\u003eapplication.properties\u003c/code\u003e文件中通过\u003ccode\u003espring.profiles.active\u003c/code\u003e属性来设置，其值对应\u003ccode\u003e{profile}\u003c/code\u003e值。例如：\u003c/p\u003e\n\u003cp\u003eapplication.properties配置：spring.profiles.active = dev即指定application-dev.properties会被加载。\u003c/p\u003e\n\u003ch3 id=\"h3_8\"\u003e\u003cstrong\u003e2、通过启动参数指定运行环境。\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e通过命令行启动：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`  java -jar xxxxx.jar   \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;--spring.profiles.active=prod。\u0026amp;lt;/span\u0026gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e上述指定为prod环境，则spring application会自动根据application-{profile}.properties的格式找到application-prod.properties文件加载。\u003c/p\u003e\n\u003ch3 id=\"h3_9\"\u003e\u003cstrong\u003e3、加载多个自定义文件。\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e例如：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e` spring.profiles.active = dev,database`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e等于告诉Spring Boot加载application-dev.properties和application-database.properties文件，从而实现多个配置文件的加载。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 class=\"detail-title\" id=\"四种读取properties文件的方式\"\u003e\u003cspan class=\"d-t\"\u003e四种读取properties文件的方式\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"http://www.imooc.com/article/18252\"\u003ehttp://www.imooc.com/article/18252\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 class=\"detail-title\" id=\"集成mybatis\"\u003e\u003cspan class=\"d-t\"\u003e集成Mybatis\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"http://www.imooc.com/article/15406\"\u003ehttp://www.imooc.com/article/15406\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 class=\"detail-title\" id=\"开启定时任务\"\u003e\u003cspan class=\"d-t\"\u003e开启定时任务\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"http://www.imooc.com/article/15612\"\u003ehttp://www.imooc.com/article/15612\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/happy_cheng/article/details/54178392\"\u003espring-boot上传文件MultiPartFile获取不到文件问题解决\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/happy_cheng/article/details/54178392\"\u003ehttp://blog.csdn.net/happy_cheng/article/details/54178392\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 id=\"spring-boot上传文件时multipartfile为空问题\"\u003e\u003cspan class=\"link_title\"\u003e\u003ca href=\"http://blog.csdn.net/tanga842428/article/details/72773773\"\u003eSpring boot上传文件时MultipartFile为空问题\u003c/a\u003e\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/tanga842428/article/details/72773773\"\u003ehttp://blog.csdn.net/tanga842428/article/details/72773773\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/yanweihpu/article/details/54139382\"\u003espring boot默认日志配置，以及改用log4j日志配置\u003c/a\u003e学习使用排出多余的依赖\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/yanweihpu/article/details/54139382\"\u003ehttp://blog.csdn.net/yanweihpu/article/details/54139382\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/loongshawn/article/details/50951329\"\u003ehttp://blog.csdn.net/loongshawn/article/details/50951329\u003c/a\u003e\u003c/p\u003e","title":"SpringBoot 学习网站收藏"},{"content":"参考：http://blog.csdn.net/u014695188/article/details/52347318\n参考：http://blog.csdn.net/u012706811/article/details/52185345\n整体步骤：\n（1） 在pom.xml中引入thymeleaf;\n（2） 如何关闭thymeleaf缓存\n（3） 编写模板文件.html\nSpring Boot默认就是使用thymeleaf模板引擎的，所以只需要在pom.xml加入依赖即可：\n\u0026laquo;/span\u0026gt;dependency\u0026gt;\n\u0026laquo;/span\u0026gt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt;\n\u0026laquo;/span\u0026gt;artifactId\u0026gt;spring-boot-starter-thymeleaf\u0026lt;/artifactId\u0026gt;\n\u0026lt;/dependency\u0026gt;\nThymeleaf缓存在开发过程中，肯定是不行的，那么就要在开发的时候把缓存关闭，只需要在application.properties进行配置即可：\n[html] view plain copy\n########################################################\n###THYMELEAF (ThymeleafAutoConfiguration)\n########################################################\n#spring.thymeleaf.prefix=classpath:/templates/\n#spring.thymeleaf.suffix=.html\n#spring.thymeleaf.mode=HTML5\n#spring.thymeleaf.encoding=UTF-8\n# ;charset= is added\n#spring.thymeleaf.content-type=text/html\n# set to false for hot refresh\nspring.thymeleaf.cache=false\n编写模板文件src/main/resouces/templates/helloHtml.html\n[html] view plain copy\n编写访问路径(com.kfit.test.web.TemplateController):\n[html] view plain copy\npackage com.kfit.test.web;\nimport java.util.Map;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\n/**\n模板测试.\n@author Administrator\n*/\n@Controller\npublicclass TemplateController {\n/**\n返回html模板. */\n@RequestMapping(“/helloHtml”)\npublic String helloHtml(Map\u0026lt;String,Object\u0026gt; map){\nmap.put(“hello”,”from TemplateController.helloHtml”);\nreturn”/helloHtml”;\n}\n}\n启动应用，输入地址：http://127.0.0.1:8080/helloHtml 会输出：\nHello.v.2\nfrom TemplateController.helloHtml\n使用freemarker\n使用freemarker也很简单，\n在pom.xml加入freemarker的依赖：\n[html] view plain copy\norg.springframework.boot\nspring-boot-starter-freemarker\n剩下的编码部分都是一样的，说下application.properties文件：\n[html] view plain copy\n########################################################\n###FREEMARKER (FreeMarkerAutoConfiguration)\n########################################################\nspring.freemarker.allow-request-override=false\nspring.freemarker.cache=true\nspring.freemarker.check-template-location=true\nspring.freemarker.charset=UTF-8\nspring.freemarker.content-type=text/html\nspring.freemarker.expose-request-attributes=false\nspring.freemarker.expose-session-attributes=false\nspring.freemarker.expose-spring-macro-helpers=false\n#spring.freemarker.prefix=\n#spring.freemarker.request-context-attribute=\n#spring.freemarker.settings.*=\n#spring.freemarker.suffix=.ftl\n#spring.freemarker.template-loader-path=classpath:/templates/#comma-separatedlist\n#spring.freemarker.view-names= #whitelistofviewnamesthatcanberesolved\ncom.kfit.test.web.TemplateController：\n[html] view plain copy\n/**\n返回html模板.\n*/ @RequestMapping(“/helloFtl”)\npublic String helloFtl(Map\u0026lt;String,Object\u0026gt; map){\nmap.put(“hello”,”from TemplateController.helloFtl”);\nreturn”/helloFtl”;\n}\n访问地址：http://127.0.0.1:8080/helloFtl\nHello.v.2\nfrom TemplateController.helloFtl\nthymeleaf和freemarker是可以共存的。\n————————————————————————————————————————————————\n本文记录一下几点：\n一、资源文件的约定目录结构\n二、Maven配置\n三、开发时修改thymeleaf模板自动重新加载配置\n四、thymeleaf常用基础知识点\n一、资源文件的约定目录结构\nMaven的资源文件目录：/src/java/resources\nspring-boot项目静态文件目录：/src/java/resources/static\nspring-boot项目模板文件目录：/src/java/resources/templates\nspring-boot静态首页的支持，即index.html放在以下目录结构会直接映射到应用的根目录下：\n[html] view plain copy\nclasspath:/META-INF/resources/index.html\nclasspath:/resources/index.html\nclasspath:/static/index.html\ncalsspath:/public/index.html\n由于使用thymeleaf的html5模板，所以我将index.html模板文件直接放到了/src/java/resources/templates目录下。然而这个目录并不是首页文件的默认目录，所以我们需要手动将应用根路径映射到/src/java/resources/templates/index.html下。这个在spring-mvc的Controller下映射一下就可以了。\n[html] view plain copy\n@RequestMapping(“/”)\npublic String index(){\nreturn “index”;\n}\n在spring-boot下，默认约定了Controller试图跳转中thymeleaf模板文件的的前缀prefix是”classpath:/templates/”,后缀suffix是”.html”\n这个在application.properties配置文件中是可以修改的。\n如下配置可以修改试图跳转的前缀和后缀\n[html] view plain copy\nspring.thymeleaf.prefix: /templates/\nspring.thymeleaf.suffix: .html\n更过有关thymeleaf中的默认这是可以查看org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties这个类的属性\n二、Maven配置\n在pom.xml中加入如下依赖\n[html] view plain copy\norg.springframework.boot\nspring-boot-starter-thymeleaf\n原来关于spring-boot-starter-web等的依赖就可以去掉了，因为spring-boot-starter-thymeleaf是包含这些依赖的。而关于jsp的依赖也可以去掉了，因为我们已经完全抛弃jsp了。\n三、开发时修改thymeleaf模板自动重新加载配置\nSpring-boot使用thymeleaf时默认是有缓存的，即你把一个页面代码改了不会刷新页面的效果，你必须重新运行spring-boot的main()方法才能看到页面更改的效果。我们可以把thymeleaf的缓存关掉，用于支持页面修改后重新发布到spring-boot内嵌的tomcat中去。在application.properties配置文件中加入以下配置。\n[html] view plain copy\n# Allow Thymeleaf templates to be reloaded at dev time\nspring.thymeleaf.cache: false\nserver.tomcat.access_log_enabled: true\nserver.tomcat.basedir: target/tomcat\n四、thymeleaf常用基础知识点\n1、在html页面中引入thymeleaf命名空间，即，此时在html模板文件中动态的属性使用th:命名空间修饰\n2、引用静态资源文件，比如CSS和JS文件，语法格式为“@{}”，如@{/js/blog/blog.js}会引入/static目录下的/js/blog/blog.js文件\n3、访问spring-mvc中model的属性，语法格式为“{}”，如{user.id}可以获取model里的user对象的id属性\n4、循环，在html的标签中，加入th:each=“value:{list}”形式的属性，如可以迭代users的数据\n5、判断，在html标签中，加入th:if=”表达式”可以根据条件显示html元素\n以上代码表示若blog.publishTime时间不为空，则显示时间\n6、时间的格式化，{#dates.format(blog.publishTime,’yyyy-MM-dd HH:mm:ss’)} 表示将时间格式化为”yyyy-MM-dd HH:mm:ss”格式化写法与Java格式化Date的写法是一致的。\n7、字符串拼接，有两种形式 比如拼接这样一个URL:/blog/delete/{blogId} 第一种：th:href=”‘/blog/delete/’ + {blog.id }” 第二种：th:href=”{‘/blog/delete/’ + blog.id }”\n","permalink":"https://blog.zdltech.com/posts/spring-boot-%E4%BD%BF%E7%94%A8thymeleaf%E6%A8%A1%E6%9D%BF/","summary":"\u003cp\u003e参考：http://blog.csdn.net/u014695188/article/details/52347318\u003c/p\u003e\n\u003cp\u003e参考：http://blog.csdn.net/u012706811/article/details/52185345\u003c/p\u003e\n\u003ch1\u003e\u003c/h1\u003e\n\u003cp\u003e整体步骤：\u003cbr\u003e\n（1） 在pom.xml中引入thymeleaf;\u003cbr\u003e\n（2） 如何关闭thymeleaf缓存\u003cbr\u003e\n（3） 编写模板文件.html\u003cbr\u003e\nSpring Boot默认就是使用thymeleaf模板引擎的，所以只需要在pom.xml加入依赖即可：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"tag\"\u003e\u0026laquo;/span\u0026gt;\u003cspan class=\"tag-name\"\u003edependency\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"tag\"\u003e\u0026laquo;/span\u0026gt;\u003cspan class=\"tag-name\"\u003egroupId\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026gt;\u003c/span\u003eorg.springframework.boot\u003cspan class=\"tag\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"tag-name\"\u003egroupId\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"tag\"\u003e\u0026laquo;/span\u0026gt;\u003cspan class=\"tag-name\"\u003eartifactId\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026gt;\u003c/span\u003espring-boot-starter-thymeleaf\u003cspan class=\"tag\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"tag-name\"\u003eartifactId\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"tag-name\"\u003edependency\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003c/h1\u003e\n\u003cp\u003eThymeleaf缓存在开发过程中，肯定是不行的，那么就要在开发的时候把缓存关闭，只需要在application.properties进行配置即可：\u003cbr\u003e\n[html] view plain copy\u003cbr\u003e\n########################################################\u003cbr\u003e\n###THYMELEAF (ThymeleafAutoConfiguration)\u003cbr\u003e\n########################################################\u003cbr\u003e\n#spring.thymeleaf.prefix=classpath:/templates/\u003cbr\u003e\n#spring.thymeleaf.suffix=.html\u003cbr\u003e\n#spring.thymeleaf.mode=HTML5\u003cbr\u003e\n#spring.thymeleaf.encoding=UTF-8\u003cbr\u003e\n# ;charset= is added\u003cbr\u003e\n#spring.thymeleaf.content-type=text/html\u003cbr\u003e\n# set to false for hot refresh\u003c/p\u003e\n\u003cp\u003espring.thymeleaf.cache=false\u003c/p\u003e\n\u003cp\u003e编写模板文件src/main/resouces/templates/helloHtml.html\u003cbr\u003e\n[html] view plain copy\u003c/p\u003e\n\u003cp\u003e编写访问路径(com.kfit.test.web.TemplateController):\u003cbr\u003e\n[html] view plain copy\u003cbr\u003e\npackage com.kfit.test.web;\u003c/p\u003e\n\u003cp\u003eimport java.util.Map;\u003cbr\u003e\nimport org.springframework.stereotype.Controller;\u003cbr\u003e\nimport org.springframework.web.bind.annotation.RequestMapping;\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e模板测试.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e@author Administrator\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e*/\u003c/p\u003e\n\u003cp\u003e@Controller\u003c/p\u003e\n\u003cp\u003epublicclass TemplateController {\u003cbr\u003e\n/**\u003c/p\u003e","title":"spring-boot–使用thymeleaf模板"},{"content":" 由于项目的优化改进，用到AES+RSA加密传输数据。于是，在网上摘录了网友们的AES算法，如下： **public static byte**[] encrypt(**byte**[] raw, **byte**[] clear) **throws **Exception { SecretKeySpec skeySpec = **new **SecretKeySpec(raw, **\u0026#34;AES\u0026#34;**); Cipher cipher = Cipher.getInstance(**\u0026#34;AES\u0026#34;**); cipher.init(Cipher.***ENCRYPT_MODE***, skeySpec); **byte**[] encrypted = cipher.doFinal(clear); **return **encrypted; } **public static byte**[] decrypt(**byte**[] raw, **byte**[] encrypted) **throws **Exception { SecretKeySpec skeySpec = **new **SecretKeySpec(raw, **\u0026#34;AES\u0026#34;**); Cipher cipher = Cipher.getInstance(**\u0026#34;AES\u0026#34;**); cipher.init(Cipher.***DECRYPT_MODE***, skeySpec); **byte**[] decrypted = cipher.doFinal(encrypted); **return **decrypted; } **public static byte**[] getRawKey(**byte**[] seed) **throws **Exception { KeyGenerator kgen = KeyGenerator.getInstance(**\u0026#34;AES\u0026#34;**); SecureRandom sr = SecureRandom.getInstance(**\u0026#34;SHA1PRNG\u0026#34;**, **\u0026#34;Crypto\u0026#34;**); sr.setSeed(seed); kgen.init(128, sr); SecretKey skey = kgen.generateKey(); **byte**[] raw = skey.getEncoded(); **return **raw; } 一切正常的在Android 4.3-6.1的手机上加解密，但是我用 *LGE Nexus 5X (7.1.1 API 25)*上发现在Android N上 google去掉了**Crypto **provider，意味着我们将不能继续像上面那样对数据加密填充。当然，在studio里的Logcat里会提示前往关于Android N对Crypto的解决方案： http://Android-developers.blogspot.com/2016/06/security-crypto-provider-deprecated-in.html\n解决方案：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;SecureRandom\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; sr \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;SecureRandom\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getInstance\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;SHA1PRNG\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;CryptoProvider\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;());\u0026amp;lt;/span\u0026gt;` 代替\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;SecureRandom\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; sr \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;SecureRandom\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getInstance\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;SHA1PRNG\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Crypto\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` **[java]** [view plain](http://blog.csdn.net/mazhidong/article/details/71189396#) [copy](http://blog.csdn.net/mazhidong/article/details/71189396#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.security.Provider; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Implementation of Provider for SecureRandom. The implementation supports the\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026amp;#8220;SHA1PRNG\u0026amp;#8221; algorithm described in JavaTM Cryptography Architecture, API\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Specification \u0026amp; Reference\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; CryptoProvider \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Provider { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Creates a Provider and puts parameters\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; CryptoProvider() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Crypto\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1.0\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;HARMONY (SHA1 digest; SecureRandom; SHA1withDSA signature)\u0026amp;#8221;\u0026lt;/span\u0026gt;); - put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;SecureRandom.SHA1PRNG\u0026amp;#8221;\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl\u0026amp;#8221;\u0026lt;/span\u0026gt;); - put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;SecureRandom.SHA1PRNG ImplementedIn\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Software\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - } ","permalink":"https://blog.zdltech.com/posts/android-java-security-nosuchproviderexception-no-such-provider-crypto/","summary":"\u003cdiv\u003e\n  由于项目的优化改进，用到AES+RSA加密传输数据。于是，在网上摘录了网友们的AES算法，如下：\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e**public static byte**[] encrypt(**byte**[] raw, **byte**[] clear) **throws **Exception {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      SecretKeySpec skeySpec = **new **SecretKeySpec(raw, **\u0026#34;AES\u0026#34;**);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      Cipher cipher = Cipher.getInstance(**\u0026#34;AES\u0026#34;**);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      cipher.init(Cipher.***ENCRYPT_MODE***, skeySpec);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      **byte**[] encrypted = cipher.doFinal(clear);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      **return **encrypted;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  **public static byte**[] decrypt(**byte**[] raw, **byte**[] encrypted) **throws **Exception {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      SecretKeySpec skeySpec = **new **SecretKeySpec(raw, **\u0026#34;AES\u0026#34;**);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      Cipher cipher = Cipher.getInstance(**\u0026#34;AES\u0026#34;**);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      cipher.init(Cipher.***DECRYPT_MODE***, skeySpec);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      **byte**[] decrypted = cipher.doFinal(encrypted);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      **return **decrypted;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  **public static byte**[] getRawKey(**byte**[] seed) **throws **Exception {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      KeyGenerator kgen = KeyGenerator.getInstance(**\u0026#34;AES\u0026#34;**);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      SecureRandom sr = SecureRandom.getInstance(**\u0026#34;SHA1PRNG\u0026#34;**, **\u0026#34;Crypto\u0026#34;**);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      sr.setSeed(seed);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      kgen.init(128, sr);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      SecretKey skey = kgen.generateKey();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      **byte**[] raw = skey.getEncoded();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      **return **raw;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"top-box hide\"\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e一切正常的在Android 4.3-6.1的手机上加解密，但是我用 *LGE Nexus 5X (7.1.1 API 25)*上发现在Android N上 google去掉了**Crypto **provider，意味着我们将不能继续像上面那样对数据加密填充。当然，在studio里的Logcat里会提示前往关于Android N对Crypto的解决方案：\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp\u003ehttp://\u003ca href=\"http://lib.csdn.net/base/android\"\u003eAndroid\u003c/a\u003e-developers.blogspot.com/2016/06/security-crypto-provider-deprecated-in.html\u003c/p\u003e","title":"Android java.security.NoSuchProviderException: no such provider: Crypto"},{"content":" 虚拟机设置桥接模式，其他模式不可以（也许未配置正确，需要高手指点） 目录/etc/sysconfig/network-scripts TYPE=Ethernet BOOTPROTO=static DEFROUTE=yes PEERDNS=yes PEERROUTES=yes IPV4_FAILURE_FATAL=yes IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_PEERDNS=yes IPV6_PEERROUTES=yes IPV6_FAILURE_FATAL=no NAME=eno16777736 UUID=44fe454e-8b9a-4976-9417-71f6dfe80500 DEVICE=eno16777736 ONBOOT=yes BROADCAST=192.168.0.255 DNS1=192.168.0.254 IPADDR=192.168.0.251 NETMASK=255.255.255.0 GATEWAY=192.168.0.254 参考文章： [http://www.linuxidc.com/Linux/2017-06/144401.htm](http://www.linuxidc.com/Linux/2017-06/144401.htm) [http://www.cnblogs.com/testlurunxiu/p/5831242.html](http://www.cnblogs.com/testlurunxiu/p/5831242.html) 备注：主要修改添加地方 BOOTPROTO=static IPV4_FAILURE_FATAL=yes ONBOOT=yes BROADCAST=192.168.0.255 DNS1=192.168.0.254 IPADDR=192.168.0.251 NETMASK=255.255.255.0 GATEWAY=192.168.0.254 先判断centos有没有联网 需要配置上面 ONBOOT=yes表示可以联网 yum search ifconfig 查询到的安装就可 如果新机子没有ifconfig 安装教程 ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA/4AAANqCAYAAAA0a5CYAAAME2lDQ1BJQ0MgUHJvZmlsZQAASImVVwdUk8kWnr+kEBJaIBQpoXekSJfeBQHpYCMkAUKJkBBU7MiigmtBxYIVXQGxrQWQRUXEjgj2/kBERVkXC1hQeZMCur523j1n/vly5947353cmTMDgKItKycnC1UCIJufJ4gK8mUmJCYxSd0AAzpAHbgCNRZbmOMTGRkGoIz2f5eh2wAR9zesxbH+dfy/ijKHK2QDgERCnMIRsrMhPgYArsHOEeQBQGiDesPZeTliPACxqgASBICIi3GaFGuIcYoUW0lsYqL8IPYGgExlsQRpACiIeTPz2WkwjoKYoy2fw+NDvBViT3Y6iwPxQ4itsrNnQaxIhtgs5Yc4aX+LmTIWk8VKG8PSXCRC9ucJc7JYc//P5fjfkp0lGp3DADZquiA4SpwzXLfqzFmhYkyFuImfEh4BsQrEF3kcib0Y308XBcfK7PvZQj+4ZoABAAo4LP9QiLUhZogyY31k2J4lkPhCezSclxcSI8MpgllRsvhoPj8rPEwWZ3k6N2QUb+cKA6JHbVJ5gSEQw0pDjxWkx8RLeaKt+by4cIgVIO4QZkaHynwfF6T7hY/aCERRYs5GEL9PFQRGSW0wjWzhaF6YDZslmQvWAuadlx4TLPXFErjChLBRDhyuf4CUA8bh8mNl3DBYXb5RMt/inKxImT22nZsVFCVdZ+ywMD961Pd6Hiww6TpgTzJYkyJlcw3l5EXGSLnhKAgDfsAfMIEIthQwC2QAXnt/fT/8JR0JBCwgAGmAC6xlmlGPeMkIH36jQQH4EyIuEI75+UpGuSAf6r+OaaVfa5AqGc2XeGSCZxBn41q4J+6Oh8GvN2z2uAvuOurHVBydlRhA9CcGEwOJ5mM82JB1FmwCwPs3ulDYc2F2Yi780Ry+xyM8I3QSnhBuEboI90AceCqJIrOaySsU/MScCSaDLhgtUJZdyo/Z4SaQtSPui3tA/pA7zsC1gDU+AWbig3vB3Byh9keGojFu39fy5/nErH/MR6ZXsFBwlLFIGftn/Masfo7i98MacWAf+rMlthw7il3AzmCXsCasHjCx01gD1oadFOOxSngqqYTR2aIk3DJhHN6ojW2tbZ/tl5/mZsnmF6+XMI87J0+8Gfxm5cwV8NLS85g+8DTmMkP4bBsrpr2tnTMA4rNdenS8Y0jObIRx+bsutxkA1xKoTPuuYxkCcOIZAPSh7zrDt7Dc1wBwsoMtEuRLdeLjGBAABSjCXaEJdIEhMIP52AMn4A68QQCYBCJADEgEM+CKp4NsyHk2mA+WgGJQCtaADWAL2AF2g2pwABwB9aAJnAHnwRXQAW6BB7AuesErMACGwDCCICSEhtARTUQPMUYsEXvEBfFEApAwJApJRJKRNISPiJD5yFKkFClDtiC7kBrkd+QEcga5hHQi95BupA95i3xGMZSKqqI6qAk6HnVBfdBQNAadjqahuWgBWoSuQjehleh+tA49g15Bb6Fd6Ct0EAOYPMbA9DFrzAXzwyKwJCwVE2ALsRKsHKvEDmKN8H++gXVh/dgnnIjTcSZuDWszGI/F2XguvhBfiW/Bq/E6vBW/gXfjA/g3Ao2gTbAkuBFCCAmENMJsQjGhnLCXcJxwDu6bXsIQkUhkEE2JznBfJhIziPOIK4nbiIeIzcROYg9xkEQiaZIsSR6kCBKLlEcqJm0m7SedJl0n9ZI+kuXJemR7ciA5icwnF5LLyfvIp8jXyc/Jw3JKcsZybnIRchy5uXKr5fbINcpdk+uVG6YoU0wpHpQYSgZlCWUT5SDlHOUh5Z28vLyBvKv8FHme/GL5TfKH5S/Kd8t/oqpQLah+1GlUEXUVtYraTL1HfUej0Uxo3rQkWh5tFa2Gdpb2mPZRga5goxCiwFFYpFChUKdwXeG1opyisaKP4gzFAsVyxaOK1xT7leSUTJT8lFhKC5UqlE4o3VEaVKYr2ylHKGcrr1Tep3xJ+YUKScVEJUCFo1KkslvlrEoPHaMb0v3obPpS+h76OXqvKlHVVDVENUO1VPWAarvqgJqK2gS1OLU5ahVqJ9W6GBjDhBHCyGKsZhxh3GZ8VtdR91Hnqq9QP6h+Xf2DxjgNbw2uRonGIY1bGp81mZoBmpmaazXrNR9p4VoWWlO0Zmtt1zqn1T9OdZz7OPa4knFHxt3XRrUttKO052nv1m7THtTR1QnSydHZrHNWp1+Xoeutm6G7XveUbp8eXc9Tj6e3Xu+03kumGtOHmcXcxGxlDuhr6wfri/R36bfrDxuYGsQaFBocMnhkSDF0MUw1XG/YYjhgpGc02Wi+Ua3RfWM5YxfjdOONxheMP5iYmsSbLDOpN3lhqmEaYlpgWmv60Ixm5mWWa1ZpdtOcaO5inmm+zbzDArVwtEi3qLC4ZolaOlnyLLdZdloRrFyt+FaVVnesqdY+1vnWtdbdNgybMJtCm3qb1+ONxieNXzv+wvhvto62WbZ7bB/YqdhNsiu0a7R7a29hz7avsL/pQHMIdFjk0ODwZoLlBO6E7RPuOtIdJzsuc2xx/Ork7CRwOujU52zknOy81fmOi6pLpMtKl4uuBFdf10WuTa6f3Jzc8tyOuP3lbu2e6b7P/cVE04nciXsm9ngYeLA8dnl0eTI9kz13enZ56XuxvCq9nngbenO893o/9zH3yfDZ7/Pa19ZX4Hvc94Ofm98Cv2Z/zD/Iv8S/PUAlIDZgS8DjQIPAtMDawIEgx6B5Qc3BhODQ4LXBd0J0QtghNSEDk5wnLZjUGkoNjQ7dEvokzCJMENY4GZ08afK6yQ/DjcP54fURICIkYl3Eo0jTyNzIP6YQp0ROqZjyLMouan7UhWh69MzofdFDMb4xq2MexJrFimJb4hTjpsXVxH2I948vi+9KGJ+wIOFKolYiL7EhiZQUl7Q3aXBqwNQNU3unOU4rnnZ7uun0OdMvzdCakTXj5EzFmayZR5MJyfHJ+5K/sCJYlazBlJCUrSkDbD/2RvYrjjdnPaeP68Et4z5P9UgtS32R5pG2Lq0v3Su9PL2f58fbwnuTEZyxI+NDZkRmVeZIVnzWoWxydnL2Cb4KP5PfOkt31pxZnTmWOcU5XbluuRtyBwShgr1CRDhd2JCnCq85bSIz0S+i7nzP/Ir8j7PjZh+dozyHP6dtrsXcFXOfFwQW/DYPn8ee1zJff/6S+d0LfBbsWogsTFnYsshwUdGi3sVBi6uXUJZkLrlaaFtYVvh+afzSxiKdosVFPb8E/VJbrFAsKL6zzH3ZjuX4ct7y9hUOKzav+FbCKblcaltaXvplJXvl5V/tft3068iq1FXtq51Wb19DXMNfc3ut19rqMuWygrKedZPX1a1nri9Z/37DzA2XyieU79hI2Sja2LUpbFPDZqPNazZ/2ZK+5VaFb8WhrdpbV2z9sI2z7fp27+0Hd+jsKN3xeSdv591dQbvqKk0qy3cTd+fvfrYnbs+F31x+q9mrtbd079cqflVXdVR1a41zTc0+7X2ra9FaUW3f/mn7Ow74H2g4aH1w1yHGodLD4LDo8Mvfk3+/fST0SMtRl6MHjxkf23qcfrykDqmbWzdQn17f1ZDY0Hli0omWRvfG43/Y/FHVpN9UcVLt5OpTlFNFp0ZOF5webM5p7j+TdqanZWbLg7MJZ2+2TmltPxd67uL5wPNnL/hcOH3R42LTJbdLJy67XK6/4nSlrs2x7fhVx6vH253a6645X2vocO1o7JzYeeq61/UzN/xvnL8ZcvPKrfBbnbdjb9+9M+1O113O3Rf3su69uZ9/f/jB4oeEhyWPlB6VP9Z+XPkP838c6nLqOtnt3932JPrJgx52z6unwqdfeoue0Z6VP9d7XvPC/kVTX2Bfx8upL3tf5bwa7i/+U/nPra/NXh/7y/uvtoGEgd43gjcjb1e+03xX9X7C+5bByMHHQ9lDwx9KPmp+rP7k8unC5/jPz4dnfyF92fTV/Gvjt9BvD0eyR0ZyWAKW5CqAwYampgLwtgoAWiK8O3QAQFGQvr0kgkjfixIE/hOWvs8k4gRAlTcAsYsBCIN3lO2wGUNMhb346h3jDVAHh7EmE2Gqg700FhW+YAgfR0be6QBAagTgq2BkZHjbyMjXPZDsPQCac6VvPrEQ4f1+p+Sec9VwGfhZ/gnMx2wN6C944gAAQABJREFUeAHsvc+KJce5r720z8Hugg2tbvgQsuBo8225N8KGb37gXICRQRPfgAcCzzYYjXwBGgmBZwYPdAOaCGR8AQbPNxwhZMvGFkiiMVS7wVC9G0R/+WT5tyoqKjMjc/2rVVVPwOqIjD9vvPFErOr1RkRGvLRarV50n7X7H//7f6we/e6H6+f//uLZ6s//8fn62cB+CTz84P9ZvfzWwxvJ/M1v/7/VX372p9XZr/+xX0gbSv9/P/+P1XffuLcu/Yf/839X3/7+2/WzAQlIQAISkIAEJCABCUhAAreRwP+sG4Uh9Nn/+K862uc9E/jeJ/9rdf9HD/pa5L8f2E5g7YerUiUgAQlIQAISkIAEJCCB4ybwUqeeK/4jfZTdD3MNcVeUR0BeU3Tdf/bPNXWE1UpAAhKQgAQkIAEJSEAC10rgyop/tJlr7Cb/ofzaeDsmPbOiHIPzUEysZx6B9A+5eS1hzLH74snHp6vnn56tXv/wjRv52sVY24yXgAQkIAEJSEACEpCABO4egX85tiZjkJ2886+DapH299+c9q8iYPA//uXXK4w0nQR2SeDe90/6cwq+84OTfrztUrayJCABCUhAAhKQgAQkIAEJHJrAIsM/Rjmr7oT5sLpdujKN9NqNpWPAJ/+//erf1/IzCcChdxj6pz//24oweV/5z++txZMP2ZGT51rHsfojqEy//5OHiV77qRu50XeduEWAepFdO+JIw1FfePBMWiY+0t5W+yk35iK/ZFD371T7Ux4/n7p8KZs8pSNvysWvy5f5h8Kl/KH+GypTxpX1PXj74erss7My2bAEJCABCUhAAhKQgAQkIIEbSYB3/NefzvB50Rld6+cyjXg+5CG+M7LW4Tx3huG6LOFSFvmn0pFB/s6IXctI/amLugkTT7gzdPswZVI29SY9dbbqR1ZkI5/nUv/IjU48l/kTT72Uw09cy4/+db60ifgyzDP1L2l/Lbt+Rn6pN20r29Bqf8pHbs2zxb9uX+TM9ev66v4r5ZTtTHz0r33anTz6F38rZCELx4BjwDHgGHAMOAYcA44Bx8DNGAOLVvy7Tu2va8sVaLwznXBnIPZXpT396JRsvWN1HsdqdCu9zzjxD9ewUReruGz3x9Urulw9mKvknv72yVo38s6pn1P1v3n/K7L37vF7F2EiuGaPXQdxtLW8Hi7xm/jojf6dkbkuTrhs0zphJFDmrds/UuRKNNfxpU/L/iXjnPZTPg5+8IH9HP7o/+q7r6X4Yr/Vfy2BvD6CDlzzRztgSFzGcau86RKQgAQkIAEJSEACEpCABI6RwOjhfkuV5X1oXIzGunwrvc7fesaQvPfovM5WXtJb9SMPx4FuYw4jltcLylcMyEvZsXaPyRqKZ9KB1xxiaGJolxMRQ2UOGbdN+1v8aQcTDbDsVtz7ZmF4f/3jL2c1cU7/TQnqdgesr1N89LsfrrPe+/zEw/3WNAxIQAISkIAEJCABCUhAAjeRwM4M/xjMY0ZwK70FDyOQnQMYxRiGGMV//ekXK4y0+98+6Fdop2RsWz+yWQ1mt0EM86n6NknrV/3fPV/1z7vl2cEwJG/JxMdQ+aVxS9tfGvvPV+cTKmPjI7owgZKbGujnZx+c7Y136sRnguHJO6erkzdP+vq61xI0+EtAhiUgAQlIQAISkIAEJCCBG0tg8Vb/sZZisGEYltvvs20d47WVHrnIwPiqHdvGWQ3HcMQwzDZ0wjEU6zLlc6v+pL/yi4ut5uXKL7Iw+lntz+pyKX9XYVb4qYMt7/Vqf8kGtmxtX+owprOivrTsnPZzIF4cbWDCBhe+Y+MDpkNcMwESmWP6R/5U/0XGmJ/D/Ib0GCtjvAQkIAEJSEACEpCABCQggWMnsLMVfxqKMc5KabkVvjTKW+nIyHb3yMhJ/hh2vHtdGuNLtoLP1Q/Dkh0EuLq+rPSXOiQf+u3CZdUfWfVqf8kGLnwOueo/t/2ZWGCiotyq3+r/mivtqxlMMUb+VP9NlSWNa/zYGcJOhZwj0SpjugQkIAEJSEACEpCABCQggWMn8FKnICeWrx2rnRhgpcG+TjRwEAIYrxwut8ToPYhijUpukt7oysTOriZsGmhMloAEJCABCUhAAhKQgAQkcG0ERlf8MYxwrNqykqo7DIGlJ/kfRqvbUQu7UXZ1C8PtIGIrJCABCUhAAhKQgAQkIIG7QOCK4c8KqKv9h+/68lR5+e+HvxNY++GqVAlIQAISkIAEJCABCUjguAmMbvWP2nd5xX/paw/1irJbyTOKrsev+8/+uZ5+sFYJSEACEpCABCQgAQlI4HoJXFnxjzrHuupcG2/HpGdWlGNwhqX+cRBI/6BNXmUZ0ozdF08+Pu0P+nv9wzd81WUIknESkIAEJCABCUhAAhKQwI0hsLPr/HbVYgyyk3f+dVAcaZy2jrHPh1PfMdJ0EtglAU7352BFT/ffJVVlSUACEpCABCQgAQlIQALXRWCR4R+jnFV3wnxY3S5dmUZ67cbSMeCT/99+9e9r+ZkE4NA7DH2ulCNM3lz5Rx3kQ3bk5LnWcaz+6Fmml3fOJz11Izf6Jm0bn3qRXTviSMNRX3jwTFomPtLeVvspN+Yiv2RQ9+9U+1MeP5+6fCmbPKUjb8rFr8uX+YfCpfyh/hsqU8aV9T14++Hq7LOzMtmwBCQgAQlIQAISkIAEJCCBG0mA6/zWn87wedEZXevnMo14PuQhvjOy1uE8d4bhuizhUhb5p9KRQf7OiF3LSP2pi7oJE0+4M3T7MGVSNvUmPXW26kdWZCOf51L/yI1OPJf5E0+9lMNPXMuP/nW+tIn4Mswz9S9pfy27fkZ+qTdtK9vQan/KR27Ns8W/bl/kzPXr+ur+K+WU7Ux89K992p08+hd/K2QhC8eAY8Ax4BhwDDgGHAOOAcfAzRgDi1b8u07t75fP3ee8M51wZyD2V6U9/eiUbL1jdR7HanQrvc848Q/XsFEXq7hs98fVK7ocRMgWbdzT3z5Z68bznPrv/+jB6pv3vyJ77x6/dxEm4uW3Hva7Ds5Tuzq6tu7qejj0Rv/OyIz4Ply2aZ0wEijz1u0fKXIl+i8/+9OaW9m/ZJzTfsrHwQ8+sJ/DH/1fffe1FF/st/qvJZDXR9CBQxlpBwyJyzhulTddAhKQgAQkIAEJSEACEpDAMRIYPdxvqbK8D43LREBdvpVe5289Y0jee3ReZysv6a36kYd7/un41m6MWF4vKF8xoAxlx9pN+lzHpAOvOcTQxNAuJyLmytlXvm3a3+KPzkw0wLJbce+bgOH99Y+/nNWcOf03JajbHbBi4gD36Hc/XGe99/mJh/utaRiQgAQkIAEJSEACEpCABG4igZ0Z/jGYx4zgVnoLHkYgOwcwijEMMYr/+tMveiPt/rcP+hXaKRnb1o9sVoPZbRDDfKq+TdL6Vf93z1f98255djAMyVsy8TFUfmnc0vaXxv7z1fmEytj4iC5MoLDKjqOfn31wtjfeqROfCYYn75yuTt486evrXkvQ4C8BGZaABCQgAQlIQAISkIAEbiyBxVv9x1qKwYZhWG6/z7Z1jNdWeuQiA+OrdmwbZzUcwxHDMNvQCcdQrMuUz636k/7KLy62mpcrv8jC6Ge1P6vLpfxdhVnhpw62vNer/SUb2GaFekndGNNZUV9Sjrxz2s+BeHG0gQkbXPiOjQ+YDnHNBEhkjukf+VP9Fxljfg7zG9JjrIzxEpCABCQgAQlIQAISkIAEjp3Azlb8aSjGOCul5Vb40ihvpSMj290jIyf5Y9jx7nVpjC/ZCj5XPwxLdhDg6vqy0l/qkHzotwuXVX9k1av9JRu48Dnkqv/c9mdigYmKcqt+q/9rrrSvZjDFGPlT/TdVljSu8WNnCDsVco5Eq4zpEpCABCQgAQlIQAISkIAEjp3AS52CnFi+dqx2YoCVBvs60cBBCGC8crjcEqP3IIo1KrlJeqMrEzu7mrBpoDFZAhKQgAQkIAEJSEACEpDAtREYXfHHMMKxastKqu4wBNjCD/ObZvQfhs52tbAbZVe3MGyniaUlIAEJSEACEpCABCQgAQkcjsAVw58VUFf7D9cBqak8VV7+obJb3wms3fJUmgQkIAEJSEACEpCABCRwMwiMbvWP+nd5xX/paw/1irJbyTOKrsev+8/+uZ5+SK27ehWE2z046HPo+5U+T52H/vs1p/4p/aO3vgQkIAEJSEACEpCABHZJ4MqKf4Qf66pzbbwdk55ZUa5//Iep/vUSSP+gRV5lGdKI3RdPPj7tD/p7/cM3fNVlCNKRxtFfORD0OlS87vqvo83WKQEJSEACEpCABCRw/AR2dp3frpqKQcaK2JAjjdPWMfb58AMfI00ngV0S4HR/zljwdP9dUt2dLPqG7//QwYyc4VBfAbm7mtuS5tQ/pX+7BnNIQAISkIAEJCABCUhgOYFFhn+MclbdCfNhdbt0ZRrptRtLx4BPfrbxRn4mATj0Lit5hEnPlX/UQT5kR06eyVfqOFZ/9CzTyzvnk566o1/it/WpF9m1I440HHWGB8+kZeIj7W21n3JjLvJLBiU7yk21P+XDBr8uX8omvXTkLcsOlS/zD4VL+UP9N1SmjCv1ffD2w9lGJPVed//N4TfVf4yhmn/JhrSMs+QreZG3lg+X2mWMIiPjt84z9Fz2LWVLlzTiyr8ftfyWfpGT9pV1EEf7h/RPuan6k2dIduop86SepOlLQAISkIAEJCABCUhgGwJc57f+dD/kX3Q/TNfPZRrxfMhDfPcjdR3Oc/fDel2WcCmL/FPpyCB/9+N6LSP1py7qJkw84e7HcR+mTMqm3qSnzlb9yIps5PNc6h+50YnnMn/iqZdy+Ilr+dG/zpc2EV+Geab+Je2vZdfPyC/1pm1lG1rtT/nIrXm2+Nfti5y5fl1f3X+lnLKdiY/+tU+7k2fMP5b+G/ruROdW/5V9TZm6v8Il+cbGR9JTb/yUL3UkrnxO3il/jDVlpuSl/WP61e1N/ugyR/+p+iNnTP8l4zey9C/+75KFLBwDjgHHgGPAMeAYcAyMj4FFK/4dyP5++Wyx5Z3phLsf0/1VaU8/OiVb705//rfe737o9iu/bIMdS/9nkVGPstTFKi7b/XH1im55Dd7T3z5Z60beln69vB89WH3z/lcEe/f4vYswES+/9bDfdXCeuurbgl67cGz/Rf/O2FiLI1y2aZ0wEijz1u0fKXIl+i8/+9OaW9m/ZJzTfsrHwQ8+sJ/DH/1fffe1FF/s32/0X0sg28fRgUPjaAcMics4nip/DP3X4tfqv3yX085nfzxb3Xt0ksfenzM+ajmlAMrDKg6dD+XS/iH95oxP9Nyn/tuO30NxtB4JSEACEpCABCQggZtHYPRwv6VN4X1o3NCPauJb6eRZ4vihXhslU+Vb9SMP9/zTs1ExGLG8XlC+YkBmyo61e1TYQAKTDmxTjqGJoVJORAwUOWjUNu1v8achTDTAsls17duF4f31j7+c1cY5/TclqFttXWF44R797ofrrPc+P5l9uN9191+L35z+61a9+8maAKAP5jrkX+f79S09p/SbMz5b8rdJ33b8blO3ZSUgAQlIQAISkIAEbj+BnRn+MZjHjOBWegs1Bgg7BzCKMQwxiv/60y96I+3+tw/6lbgpGdvWj2xWJ9ltEMN8qr5N0vpV43fPV/1jQJWro7XMJRMfddlNnpe2vzSmnq/OJ1TGxkf0YQKFVXYc/fzsg7O98U6d+EwwPHnndHXy5klfHwYwhvQSdwz9N8Wv1X+0mVX+tJvJkCUO+fA7W12s6C8pv++8U/rt4u/DvvVXvgQkIAEJSEACEpCABDYlsHir/1hFGBz8sC6332fbOgZRKz1y8+M8z/HZNs5qOIYjhiHGSYycGIrJO+S36k/6K7+42GpervwiE6Of1f6szg3Vs20cq8bUwZb3erW/ZAPbrFAvqRNjOivqS8qRd077ORAvjjZkxTh8x8YHTIe4ZgIkMsf0j/yp/ouMMT+H+Q3pMVamjt93/9X15XkOv1b/sSL+7A8XO1643WCJi3wm6I7RTemX8TM2PvfdntS/zfjdt47Kl4AEJCABCUhAAhK4uQR2tuIPAoxxVg3LrfClUd5KR0a2S0dGTvLnhzHvXpfG+JKt4HP1w7BkBwGuri8r/aUOyYd+u3BZNUZWvdpfsoELn0Ou+s9tfyYWmKgot+q3+r/mSvtqBlOMkT/Vf1NlScPQZeWXnQoYiZu46+y/Fr9W//H+OpNr+e7lefXJ+Y6IFo/IR8bqVxe5y78BF7GHD7X0a43PfWu87fjdt37Kl4AEJCABCUhAAhK4uQRe6lTnxPK1Y+UQA+JYfqyvFbtDAYzX+hCxm9D8m6Q3ujKxs6sJm7J/bhKHUm/Dx0WAnRPsmmFCQCcBCUhAAhKQgAQkIIFtCIyu+GO84Fi19YfnNoiXlV16kv8y6Xc7d31w3T5o2H/7oHo3ZWL0c+aCTgISkIAEJCABCUhAAtsSuGL4swLqav+2WJeXL0+Vl/9yfnNK7HMCy/6b0wPmmSLApFFesyDf0leZpmSbJgEJSEACEpCABCRwtwlc2eq/CxxsUeVd6W22UfPKQV1+KG5I37n5hsomjh/heSc4ccjl/e8l752n7FyfOsp3te/ijgvGD++J72sr/ty+MJ8EJCABCUhAAhKQgAQkIIHbQODKin+5cjnVwJZBuu05ARjYr354+f3W1z98oz/8j9PXn3x8OmqAk4/D2WrDnfbkFQbCU23gukA+9Spxb5B+up93w9EJ3XOgIc86CUhAAhKQgAQkIAEJSEACEpDANgSuGP6cwv716stJmazIcl/3lMs1blN56rR6tZv0GOoYwzhW2/kwQZE71/uE6p8Y/Vk9TvKc7bOU4d3anEhfHtbGZEG9EyGyd+FzpVp9hd0u5EZG2ZbE7dLfhXz697Nf/9cu1VKWBCQgAQlIQAISkIAEJCCBO0tgo63+MfxjXIdejPQ8lz7btrmjur57fswQH6qDw9nKFfgyD+H+GrGi0npFn4kFdIhBT1YmEMpn4sp6yjrqtKGy5NnEjR08V/IZamN5HsDQxEm2y4/t5KhvD6jfM96VfHTPYWWMAerlmYmO6FgzKOuGaSYVUo64lJ2TTp6pOlryKa+TgAQkIAEJSEACEpCABCRwEwlwnd/60xmPLzoD6AV+GV+GOyPuRWcgzkpHTmd09nnxS7nIQBayUy918yEv6XnG74y2S8/JU8pEFvmGZJayEqb+snzqTPtSR/KXfotDyWxuGPlhUpcp9SSNdkZPnqfKRtZUnrQ9eXkOy23l06bUnXpoT/imTvzkLeNSPzLCAd0SnpNe84oeqQfZU/KTT//i74UsZOEYcAw4BhwDjgHHgGPAMeAYOP4xcGWrf9dpvSsPmEtc6WfrfRm3Tbi8TaAz/PrV4MfvfdW/p98ZY/1NA52h1m+DZys4eVjhr1fro0NnEPbvy7NqTJj2oPO9RyfrMsgrDyEkH45V9qcfnfblcpZAdjd0xuOlXQdnq3+kyr379SsGvI5Ae+LY4cBq+J9/vdm935xpUPYrDMpTxreVT/m+7z446RnX7Uk7pnx2CqRcufsjZcbS6Vt2F9CmOPqU9jGW0As3Vj5l9CUgAQlIQAISkIAEJCABCdw0AoOGf7m9fJMG8e79Ju+pY+DjMBC/ef+r9en2GO+9cfbZWf9eP8Y2Bi7bvGuHMY+BxyF5GIYY6rhMANzrtvp3q8zrVw7KiYCUIR035wR/DMoYopTJpMWQUUr6to720L44+iqOOtEnHJf2I3IxhEtjH9lp47byo+d1+PQlruyr69DDOiUgAQlIQAISkIAEJCABCRyawKDhv60SGNPlyuqzP5zNEolxjtHNSj8G2n+/+6w33onLyv6rn7/Wy+LU/tKIyw4AVqyZOCgN7zJMYWRxgGHqIo7ydT7iY0QTjivjqOuvP/1irUvOGegnKv65ipxy2/oY/azyR89MUJRyYQJHHHo+++Bs8HaDskzCtGXsNoTk2UZ+ZFyHz84OXCYxrkMH65SABCQgAQlIQAISkIAEJHAdBP5lm0oxbofcve+frA3hrLQO5avjMMrYWs/KO0YrK9D4xLGSj8v29my9j4z+JPjO4K3jSUcGn/s/edhnR1b/3B0yF5et3nnGj0wM6XwwjhPGxwgvJyCSNiSvlL1JGB7lJAqc42DHp3b1zgv0H7uRAaOf1f4hObuQX+t2yGf6iLZnDFB3xtQ++uqQbbMuCUhAAhKQgAQkIAEJSEACUwS2WvHHgHz+v88uGb4YU2zTj1uy7R/j7Oz3/1i/o45xjmMVHYMa4xNjFwM4Vw7OWVmnLK4v3231Z3KAz9CKeZ9xi3/Q58HbD9c7FLYQdaUo75/DIlvx87z6ZNXvkqjPZWD3Q23U0jelDPJksiR+LSevVNTxS+VfadCBI5ikYddE+FF9xsaBVbE6CUhAAhKQgAQkIAEJSEACByNw5To/jOPawGtpE+OJsqyossqMcRnDNFeuYWjX1/mRJ8Zpnc4Kbba1Y1D3B9f98z12dKReJhpisEZPjLuUK8PoV17nR315rSBl8cfiKZ9zAMr8ZTiTFWlzmWZYAhKQgAQkIAEJSEACEpCABCRwaAJXVvzLd7iXKFMbxZ/9+r/61dVMCkRWaRBjtMfoJz3v3hOOPAx+JhE4qC7GfHSMkR3DHyOf3QC1Sz4mEljxzjP5MPx36er27lK2siQgAQlIQAISkIAEJCABCUhAAksJXFnxXyrA/BKQgAQkIAEJSEACEpCABCQgAQkcL4GtDvfbtlms6per75HHKj/xpB+jO3b9jpHZkE5j/T+Ud25cZDJ++LAL5K442svY3JULy7nydl3/3HrLfNF5qv/Hvr+MlZTDR5ZOAhKQgAQkIAEJSEACt4HAla3+t6FRtuHuEuAMhvLAwrtL4m62fJv+z6tEGPxLzzm5m7RttQQkIAEJSEACEpDATSFwacX/GFbsAMd7/7wrz7v8x+iOXb9jZHYonTjjob7C8FB1W8/+CbT+Rs3pf7+/++8na5CABCQgAQlIQAISOC4Ci1f86wP0ysPs2ELLQXylK9OJL8uzMlu6Mo34uiw/+rkFgOvycjsAh/5xKGBcKYM08tVykrf00Z1bA5798awvQz08Y0jkQMJSNmVrudEv5ciTsoRb6eSZqmNOeWSMuaGVzCH9yj4s05HLgYxT1+G10sv21f3f0m+sXcSXcnv9f3Weuxwfc/iVcpCQPp4zPs5rnP635lPfXFGyL+uP1KnyyVPejlG2n/S6fNqXsmX76/5JnpY/VX8pHzll/VP9X8os+ze3gpRyy/Sy/WWeuu5Wm5Le4pd8+hKQgAQkIAEJSEACEjg2Ai86hfpPZxi96Ayc9XPi43c/nF90P3zX6YQpk/Tuh/s6TFydv/vx3sclP89l+cSjw1A8cXxKHcvnufJTT+mnTvy0i/Ygs2wzZZK3LE84+oUD7U94TnrNK3qknpb85BvzS1ZDeSI/aTXPWh+e0Tn5W+m1PJ6pM+Vb+iXflD8lI+1Ln9T9M8U/fT5nfIzpFz6pv85Xx4/pU+eLnLQPHcu4PKf+pNX91+qflBvzW/WPtSfypvpubp45MtKXkVn78EVOzbnFr5bj8/n/K3KQg2PAMeAYcAw4BhwDjoHrHwOXtvp3HTLquh/B/er3049O13lyjV73Q7qPq7fms3p+79HJOj+r71ynF7fJVXpZ4YsMVkzjtpWPrFwvyEph3Z7UM+WjX8rxznDCKTOWPocvMsbKR/6UT/vYjTDlkB9H/7DjAd1wL7/1sH9/PumMBdLjWumt/pmjX+ra1B/jN4f/tuMjfOoxkbbU8fX3p1UeObQvY5hndI5L+TzX/dfqn5Sb8sfqn8u3NT6n6t53WovfvutXvgQkIAEJSEACEpCABDYlMHur/3d+cG7A18ZJXXG3qnfJGMSAxsV4fP7pWV1kJ8/7lr8TJSeEzOU7IaKZxEQEnLrVzD5vuQ26WbjLgJHPNv9yqz/lkMm4mEqP/Kn+31a/1LGJfwj+8GmdPzD2/aFNc8pPtX3b/pmS3Uqbw/c6+7+lP+lT/Fp/F+fIN48EJCABCUhAAhKQgAT2RWC24R+DLUbekEIYLaxS8gMe120dHspm3ACBOXwHii2OwkDJe9VMADz74GyVnRu1sNpYY/X47785Hc0/lZ6JmbqO+nmJfnXZbZ4PwR8+J2+erM5W/xhUtfX9aZUfFFpE7qJ/CnGLgnP5Xlf/z2nMFL855c0jAQlIQAISkIAEJCCB6yIwe6s/P8j54Xv/Jw/XunbvvPbhbC1mRezZHy5W9O99/2Kbf8q/8ouLrea7vDJr3/LXjd5TIPpP8d2magzvIeO7XoHm4MQ4tl1nxwZxGP2s9g/JaaWnfWP9P1e/6LZrP/rti3/JJ6/G1G2Y+v7MKV/Lq5+n+i/tH+ufWtbS58gf4zu3/zP5sbT+XeSf4rcL+cqQgAQkIAEJSEACEpDAvghcWfEvT8Sm0nI7OCv5rEqWW72zekxe3u+lfNLzvPpk1Z+8T3lWme9/+4Ds/Yn3uzT+9y2/V3qP/7T4blt1zZpT2zNpU8rOqwAYWeWNCdkZUMvJyf+t9Fb/1HLH9Ct13WV43/zDp/6O5TuU78vY96dVvsUi5WvO6b9W/7Tkt9JbfGu9hvqfM0LKvzHkSbta9W+bnnpqPcNvW/mWl4AEJCABCUhAAhKQwL4IvNQJ5gTwW+lYWWXVGoND1yaAwV8fztYuZQ4JSEACEpCABCQgAQlIQAISOGYCs7f6H3MjxnTD6OfMAZ0EJCABCUhAAhKQgAQkIAEJSOCuEriy1f8mg+DMgWyTph3lawo3uV3qLgEJSEACEpCABCQgAQlIQAIS2JTAQbf635Wt5LxiwHvId+3d3/oqurH231U+m35JLScBCUhAAhKQgAQkIAEJSGAbAhtt9eeavpzov03llr1dBDhLgYPqMPh1EpCABCQgAQlIQAISkIAEJHAcBBYZ/hj8XLvFlX1cA8fKrRMAVzuSk/IxgLnCTHeVgHyuMjFGAhKQgAQkIAEJSEACEpDAvggsMvyffHy64iqrpx+d9vr097z/M7xEQbaEs+2fT3knPBMJiY9fyiVv4uOX5cnLRETS8Idc6h9KG4tDN8ox+YHcPBOODpGb+mtZdbmyLHlb6eSZqqNVfg4/6hhzrf4ZK5f4Kd1JG5pEIo40XNoXeaTRH3FJTx/xXKYn35Rfj5/UnTJjbch4SN15RoeMj8jQl4AEJCABCUhAAhKQgAQkcGgCXOc3+9MZRi864+ZFZwC96Aya2eWoozOC+k/KRU7qT3yeqYP68kz5zqBaPyc+PnnJUz4jI8/xiSvzJX7Kp97Un3rQlzaUOiIjeWt5lOeTdtYMW+k1j+iRelrlSZ/iFzljfvROeq1P4slXtjPx8Yf4DMWRv9S5DJNG++EfuaTXeern5B3yw7NuZ/LW7U1+0qM/fuKRMzQ+Ik9//t8dWcnKMeAYcAw4BhwDjgHHgGPAMbD5GFi04t8ZMv2p+V//+MvVN+9/tXr9wzc69ssc98RnC/zj975affeNe+sV0cRHIlfx3Xt0ksfVf3/xbMUugzH38lsPV49/+fU6mZ0JyK9d3kWv41vP1M82dRw3BtT6tsqTXrYfPWoZY+mwpy3ZbYGs05//Da/ffdAHun/GypPe4hcZY36ta90/Y+XmxMMV/TqjeZ2dcMl8nTARoP3pI7JRfq7L+KnbSfk5/EtdNx0fc3U1nwQkIAEJSEACEpCABCQggbkEFl3nh0HEu+s4jKs///rzufXMztetql4y1jGg4jCUMcC6Vdw+qr6uD8OY6/zKK/3ISJkhYy5yb4L/nR+cT4Bs044WvzkcpvpnTvmpPEwmcRtCJjQwxIk7lGP8cHbFkNsF/yG5xklAAhKQgAQkIAEJSEACEtg3gUWG/66VqY0pjEpWkTFQcd026StVlpMPTAA8++BsbSiy4vr335yun68UvsERzz89N0i3ncSY4tfCM6d/WjKm0vtV/3fPV/1jgJer93XZcjdInbbJM+Pn5M2T1dnqfFdHKWNX/EuZhiUgAQlIQAISkIAEJCABCRyCwKKt/rtQ6MHbD9di+sMBixV9Vly5MSDu3vcvtvlj8PKpXQxE4jH6We0fyleWw4DNroEy/pjDGOwYpvd/csEv2+KnjOO0aQ4/8sJljM1U/6SebX1W+OlDxka92h/DnDpo+/0fPVhc3VT7Mn669/SvyN2W/xWBRkhAAhKQgAQkIAEJSEACEjgQgYOv+GPYx7DEkOO8gDjez2ard7bq53n1yWrFeQDcKFA63ucvjd5sEa/zca88httNd+yEYNIifGhPXr2Y07aaS82vJSP9kfrzTP+U/diSM5WeVX/ylH3Lc14FoH5057PLVf+MH8bg6lfUeO7CeFv+kacvAQlIQAISkIAEJCABCUjgkARe6irjVHSdBI6GABNDTCrUhv/RKKgiEpCABCQgAQlIQAISkIAEbhCBg2/1v0FsVPUaCGxykv81qGmVEpCABCQgAQlIQAISkIAEbgyBg2/1vzFkVPSgBDjIMe/sZ2v9QRWwMglIQAISkIAEJCABCUhAAreUgCv+R9ixHC7HdvfWIYVHqPrGKnFGAGc+4HIA31j77yKfjcFaUAISkIAEJCABCUhAAhK48wQ2MvxZnc2J8neeoAB2RoDD81jt5zBGnQQkIAEJSEACEpCABCQgAQnshsAiwx+Dn1VYTubnGj1WXg89AcBq8NB1a7vBcRxSONQOA/g23ESwD6Ly2QdVZUpAAhKQgAQkIAEJSEACt5XAIsP/ycen/ZV6Tz867Xlw13rCcwExUZCt3PhxTCjwXE4kJC95mHRIfq5bi4xyEoA4nrnyLunldnHSEh8/9eNHh6Thl+WTN/LzPMePXmlHnss6Ijf113KJL8uVZcnbSifPVB2t8nP5UM+Qa/EfKlPGTelOWjl2Uo440nBpX5lGf8QlPX3Ec5mefFN+xixl+aTulBlrQ/o1decZGUNjMPL0JSABCUhAAhKQgAQkIAEJzCHAdX6zP51h86IzTl50BsyLziCZXY46KNsZMusyPCMn9SOP9M7o6WUTrutIesqUPmllmVrHWhbp6BAZU7KTB59y5C3jWmHaFPnhgD6wLHVATvLWMinPJ+2o29dKr9sbPVJPqzzp6Jb8S/3onXK1PoknX9nOxMcf4jMUR/5S5zJMGu2Hf+SSXuepn5N3yA/Pup3JW7c3+UmP/viJR87Q+Ig8/fl/t2QlK8eAY8Ax4BhwDDgGHAOOgbs8Bhat+HeGyOqV//zeioPYvnn/q9XrH77RsZvvXn7r4erxL79eF2C3wHffuLd+Zms76azoI5vw0u3u3P+eMrwznjCVlGGen/3xbHXv0QnB3nG4HLsYWi7vorfy1enIz930T3/75Io+df6h56n2kX8snb6DdblD4/Tnf+ur6IzNdVVj5ckwl89aWBVo8a+yL3qEK/p1RvO6HOGS+TphIkD700dko/xcl/Fdt5Pyc/iXum46Pubqaj4JSEACEpCABCQgAQlI4O4QWHSdHwZNrlrDOPrzrz9fRArDk4kDPqXDKIqxhDGKAYWLYVrm3TbcrbpemmzAwIrDoEeXbpW3jyKNSY7b4L7zg/MJjnDepE274DPFfxOdyjJMRjFplHHDOCLuUI7xzdkXQ24X/IfkGicBCUhAAhKQgAQkIAEJSKBFYJHh3xLWSmdF8++/OV0bZkP5WaVlJZ473bttzjs1vDE6kY0Bi0N+7crJDSYAnn1wNqlvXf5Yn59/em6QlpMsm+i6DZ85/DfRKWX6Vf93z1f9Y4CXq/fJF7/c7ZG4bXzG98mbJ6uz1T+uiNkV/yuCjZCABCQgAQlIQAISkIAEJNAgsGirf0NWMxmjn9V+jM8hx5bzvErAlW4Y/+U2dMrEuBoq34pjRZYbCeLuff9imz86DekVAzJl8DFgsyugjD/mMAY77O7/5Hw3BbpmW/yUcZw2zeUDlzE2U/xTz7Y+K/yMIV7ZqFf7y7FD2xlfS91U+zK+6zFLHdvyX6qn+SUgAQlIQAISkIAEJCABCYTAQVf8swX70e9+mPp7P/e2s02bd6xxGEp53/8vq4v3rrOdO68LkCdy+4IT/yCbOlI2z6tPVqvH733V31hQFkf2HKO4LHPMYXY6MGmR9qNrXt2Yo3fdb0v5hHfqzzP8d/VKRVb9aU/dd+XYQXc+u1z1zzhkjK1+dUE0jLflfyHRkAQkIAEJSEACEpCABCQggfkEXuqycqq5TgK3hgCr8kwq1Ib/rWmgDZGABCQgAQlIQAISkIAEJLCAwEG3+i/Qy6wS2IjAJif5b1SRhSQgAQlIQAISkIAEJCABCdwQAgfd6n9DmKjmDSTAQY15Zz9b629gM1RZAhKQgAQkIAEJSEACEpDAzgnc6BV/DpwbO0hu56SOSCCHx9HuocMIj0jNnauSQxVzwF7Zfs4IwODnc1f57By4AiUgAQlIQAISkIAEJCCBW0FgI8Of1dWcCH8rKNiIG0GAw/Ew7HMY5I1QWiUlIAEJSEACEpCABCQgAQlcM4FFhj8GP6usXInHNXesrN60CQBWi4euW7vmflhUPYfWYQBz84HuKgH5XGVijAQkIAEJSEACEpCABCRwdwksMvyffHzaX3n39KPTnhh3pSc8B2FtdDNpwGRCXNKzlRu/3M5NvnK7d3knPWnZ4l2WJx5HPcTjuG4teepJAHRKWvL3hbp/0KVMI1zrR97omHJzfPSgXPTMc1lH5EaHWi7xZbmyLHlb6eSZqqNVfi4f6hly6E4d5Wco31jclO6kDU1SEUcaLu2L/LHxmT4ifzl+U27Kr8dX6k6ZsTakX1N3ntFhaAxGnr4EJCABCUhAAhKQgAQkIAEIcJ3f7E9nuLzojI8XnYHyojM4Zpejjs5IedEZLOsykZX6SeeT59Qz9Vzmr/VBR+pIefxahzKNvKU8npGRPFNlkwefMqWcMm0sDJfIjx60BwZ1G5K3lkV5PuFQ91ErveYVPVJPqzzpZf+m3Fw/eid/rU/iyVe2M/Hxh/gMxZG/1LkMk0b74R+5pNd56ufkHfLDs25n8tbtTX7Soz9+4pEzND4iT3/+3zVZycox4BhwDDgGHAOOAceAY+A2j4FFK/6dobF65T+/t+IgtW/e/2r1+odvdGx267h/Pe7xe1+tvvvGvfWKJqe2U28c6aWrt74/++PZ6t6jkzLLZPjltx6uHv/y63UedjNQf9x/f/FsxS6Hlsu76K18dTryc/f8098+2WgrP/zCAT0STl1j6fQtbS13cJz+/G99sc7YTPHVWHkyzOWzFlYFal2X9l8l7tIjXNGvM5rX8YRL5uuEiQDtTx+RjfJzXcZX3U7Kz+Ff6rrp+Jirq/kkIAEJSEACEpCABCQggdtDYNF1fhgsvFuOw/j5868/PxgJDCPc80/PJuvsVk0vGesYSHMdhi8TG3xKR920HUOacLfK2ycjm0mQ2+C+84PzCZIho3Ru+3bBZ5v+a+nJpBGveWRCA0O8nEhqld82nfHF2RhDbhf8h+QaJwEJSEACEpCABCQgAQlIYJHhv2tcrdX40hiK4T+lA0Yjq8QYoLhuG/RU9itprKj+/Tena8PwSoYuopz8YALg2Qdnk/mHZBxjXCZUMsmxqY7b8Nm2/1o696v+756v+scAL1fv6/Kt8Vnnbz0zvk7ePFmdrf5xJeuu+F8RbIQEJCABCUhAAhKQgAQkcOcJLNrqvy2tGD7IYZs1W/dr9+Dth+uo/vDAf67YY1BS/pVfXGy1f/S7H67zEmBFlRsH4u59/+o2/1KH5IuP0c9q/9AkA3FD8TEgIwMfAza7Asr4Yw6Hb3lgYrbFTxnHadNcPnAZYzOn/1Lfpj4r/PQxY6te7S/Hxtj4bNU71b6Mr/LVicjbln/k6EtAAhKQgAQkIAEJSEACEqgJHHTFP1utMbx4l57P0KpqDEMMsXIrPSv5pN3/9nzCgPvcS+Of96/Zyp2t+nlefbJayyl1AAY6ZOt3/FImeXJvfB1P2TlGMTJugoMvkxbhh855tWOO/tvySX+l/jyX/TdHj6k8WfUnT9135diYGp9T8qfSMr4Yo6tfXeQM4235X0g0JAEJSEACEpCABCQgAQlI4ILAS12QU8uPwmHUY+zVBtlRKKcSt4aA4+zWdKUNkYAEJCABCUhAAhKQgARmEDjoVv8Z+phFAnslsMlJ/ntVSOESkIAEJCABCUhAAhKQgAT2TOCgW/333BbFS2CUAAc95kyJbK0fzWyCBCQgAQlIQAISkIAEJCCBW0TgqLb63yKuNkUCEpCABCSwcwIcDso5IZw9w6GgpeOQ1fKsFc7JyS03Zb59hefUP6X/vvRSrgQkIAEJSEACq5Ur/o4CCUhAAhK49QRqo3ROg7M7KMbqWJmn3e0z2VFU5jn0mTWvf/jGpQNrS10OEb7u+g/RRuuQgAQkIAEJ3GQCHO7nRwaOAceAY8AxcGvHQGf4v+he+Vm3rzPmLz13N5qs0/J/ImUSjt+dE/KiLstz0uMPyUvavvzu4NJet33Jb8m97vpb+pnubz3HgGPAMeAYuMtjwBX/rvd1EpCABCQggZpAuZWeg0Fz1Wjy5WrZ7AxI/D58rlr97hv31qLLOsu08rpQdiKUV+LWbahfBSjlUFFZR25DefD2w/Xuhsgvy43VX+apZadRZZ7soih1SD59CUhAAhKQgASWE9DwX87MEhKQgAQkcAsIPPvD2exWnH121m+jp8DTj05Xr/zitd6oxlg9hMu7+kOvHSQtxvnQlbgx+ofOBkB/2vH335yuTn/+t7455EdeaXhj1PP6QiYTSH/yzun6HIGp+qPjkP5UyAGsuNSX5z7SfyQgAQlIQAIS2JrA2vDPj4IhiY9/+XUfXa92JK/p8mEsOD6+l6/EJd/vh98Pvx/7/fsQY/XSF6/xcPLmyQpjfqm79+hkdVodqocMjN7aca5AuWugTj/k88tvPewnLob0QU92EzChEQdT/qZjqGcioT6zgB0Du3KckYD8uMfvfbXeWZC4Md/fL/v9fsHd/9/9/33o++fvG3/f+Pdhu7+Pm/x+GfouLom78m5iV9g4GTgGHAOOAcfArRkD9Tv+vO9fvsPfrXhfamv93j7PnYHZf/g/kvyUT7n4U/9/ImNOvpaMbpLhkq7JT3yt95w0ygzJLOWV4cikLWV9Q3mSN/5QXXCkbNkfiUs5fX+XOQYcA44Bx4BjYLsx4Ip/N4KcsXTGshsGrmh0q3tDzu+H349j/35sOmM+tPqd70C/I2D1jzz2Pque2YrO1vXO8L2U3nro33/vMnXG73oVvVVmV+mszg+1CfnPPz3f+dAZ20ezQ2FJu13x9/8vdyT4//fQ3wx/v/j7hXFxzH8fNv39MjTe58YNrhx0hY2XgWPAMeAYcAzcijHACnJO9Y9f/j9X7wBgBbpMz0o18eUnK/jxyzL7CEePIdnoRfpQGrsVptLRnzwpm/x5HipLmbK+oTwpH39Mf2SV/YIsPimn728yx4BjwDHgGHAMbDcG1iv+HUidBCQgAQlI4FYT6AzP1ZOPL95lT2M5sK4zPtcn57OyT968304+Vo/q2XnKjLm6PM+cip/D8cbK7SM+epen7lNPvYOhXBlJ2j70qWWyg6Iz9Fe5KYFDCB/97od1Np8lIAEJSEACEtiQwEtdOWbUdRKQgAQkIIFbS4Bt7JzEj9FfGvNjDa63vWO0Z6t+WSZX4mG01oYykwI5zZ4y5MGNnazfJ/pPTwDer7772iV+opGABCQgAQlIYHMCrvhvzs6SEpCABCRwQwh85wcn61Pihwz4uhkY9M/+eLZenef9+KkVf4z5GPaRxV305QRCPTGQfPpXCWD0w18nAQlIQAISkMBuCLjivxuOSpGABCQgAQlIYEMC9QF9TJpcxysRG6pvMQlIQAISkMDRE7hThn/5/iY943bLox+fGymYLbn272V8rEbW93BfznH+dFv5+f0f6m3jJCABCUhAAhKQgATuAoE7tdU/71qy9fK6Dg3qTi1ebzdlgA0Zp+V20bw/umQwtsqn/XOMwCX1mlcCx0zgGL7/x8xH3SQgAQlIQAISkIAEbi+Bf9l10zA6WTHc1G1bftN6D1GOrYz3vn/SHwDFu568L8phU3EY5LQfg5x0PjFWkmfKn1v+9Q/fmBKztzTaVn/2URkHd8Fu6o7ufdQ7R+ZNGN/Xye8m8JnTz+aRgAQkIAEJSEACEpDAMRG4ZPjnRzer0jHQCJcO4zVp+HEpwzMHJyXP3EmAueXZrhvZZf3Ro5WefEN+DOdSPnFzXMrCJy6s8ow/dVgRkwC81zjnxOlSZsJzyqPT339zumInwaYujDcpX05qoEPJi7FSsq/7N4zLPGX/RK+kD+mXPkkeysx1lEHHjFWed/X9QI+h7wrtK3WcamP0K/OUfOp2ph3JU5ZDVu0iP+WG2l/KSL5aztBzmXfq70cpf0jHVvpQ3YmDAzLLT9gkj74EJCABCUhAAhKQgARuKgGu8+s/3Q/eF3w6A+RSXJ47o6lPT36eux/a67zE1+WTd64/VZ66qDOyan1a6SnX/Zjv9cRPHP5U3WW+sXDkwivhoTpST82OZ8qSnk9dfqxu4lvlkZU6k3dK3lgaZdFvLH0sPu1Oev1ct5V6yv6u80dO7YdhHZ/xUtdT5xt7pv5ah/I58lOe5/BOXJk/cfid4btuK+GUoy08k6fmUdcX/dI+8idM+bLusr5SD8Jj/CKf9JSpZUZv0qmD9OSd45fy6vyt9rfSIw8m1FOyIW2q7pTVP/+/Qg5ycAw4BhwDjgHHgGPAMXCzxsClFf+u864c/lWuDL/81sN+ezr5cE8/Ol1994175w97/rf7kd7XRZ1xpz//Wx/sDJH+yiR0GUtPmSmftnKF0KaOreVs32fFku30hOvt5uE5dJ0U+hOfbf6UX3IWQas8Ov31p19s2rx1OV4/QMdNXLmai4xyd0PNit0R9x6drKvZtn8yfut61hXMCNTnIqQ/KRr5EbPk+/HsDxdt5XWQOK4QI601/pMf/dI++inhpON3BnJ/l3m+P2VaKzzV/vs/erD65v2v1iIev3cRXkduGGi1v5U+p9ptx9ecOswjAQlIQAISkIAEJCCB6yBwxfCfUgLD8pX//N56K2yMUn50z3HdCuC6bLe61oeJm+O4gxk3ZMgQ30onT8thKGEYL9WtlIsxFWOwNqxoK9vsY9hTDiOsdBj7cSk/ly/lxsp3q8N93WP8Uue+/XKrP5zr/odH+GNIlm7b/mH8nn22v3uht/l+oBcGP5NYjBEmPQgz8cEEwi7GNywz4VROuJSMNw1njD7/dD98W+1vpc9p17bja04d5pGABCQgAQlIQAISkMB1EFh0qj8GLUZJDNKlCnMn79erL5cW6/PHoMDAGDJeW+lzK0V2VrMxQJ99cLaovRjYGG0YrRi15T3ExD35+GLHApMMTJ6kTZkwmKtrnW+qPKvRMUxTDiPw8ZtfL2pfyu7CZxIAHTImMPphhwGGqycFiNumf+DDCvrZ6h+I2rnb5vvB+KV/ev26SQAmAggzGUCbn3da4zJWNlUe5g/efthPOIXzprIOWa71/W6lz9V1m/E1tw7zSUACEpCABCQgAQlI4NAEFq34Y/Sz4p/VvSFlY1wNpc2JGyvPD3LS7v/k4VoMRjaO1ctW+rrQSIA2DbWrXiHOavSQGFZo4YOxzzV9GPrExaE/Rldc2oLuOLZJl3xpH2WSnnJj/lR5jLzsNMBHLkbgJpM4WZUf02NuPIZt6TB82dYeV255n9s/KTvkZ/yWfTKUb9O4yB8aR5EJ97rdpKWP6X/GM4YskzVx247vyMFnfDLBUu82KfMsDUe/8paK7AhaImuKD2n5ziDzOr7/S9piXglIQAISkIAEJCABCRwLgUUr/jES6x/05V30GJ+s4mLA4Nh6nnJzGj1VHuMVYyWykZfVecKtdPJMubpd6D53SzTGHu3GmMZhCFG+j1v9qZeDfkwc3P/2Ygt7qT91sQJf6lGmT+lO2rblW/J3kQ6P1a8uJDF24rIDIP2b59Un3Tjq3hcvuVBmSf+QP+Ow1mEJY+SMuciv9Zz7/eBGh7hMBGCgx207viMHH+M/EzilfmWepeF6fCO3ZtGSeVO//612mS4BCUhAAhKQgAQkIIHrJPBSVzmnbuuOnAATBlNuV8brVB2mSWAJAXZWcFgmEwI6CUhAAhKQgAQkIAEJSOD6CGj4Xx97a5bArSbAjgJ2LJTnXNzqBts4CUhAAhKQgAQkIAEJHCmBRVv9j7QNqiUBCRwBAd65z2saqMOrCxr9R9AxqiABCUhAAhKQgAQkcOcJXFnx51318r1cDtS6q1t1w2LuNnpWODmgLm5X705Hnv4yAnX/2T/L+JlbAhKQgAQkIAEJSEACErgdBEZX/Ocau4fGUBtvx6RnJkhicB6ajfVNE0j/kGvqzASuEeTaRU7Wf/3DN+7sxNc0TVMlIAEJSEACEpCABCQggZtCYNF1fodoFAbZ2HVrpHFlGsY+H051H7rr/RB6WsftJcA1gtyQ8J0fnPTj7fa21JZJQAISkIAEJCABCUhAAneBwCLDP0Y5q+6E+bC6XboyjfTajaVjwCc/161FfiYBeH8YQ58r0wiTXr5PTD5kR06eyVfqOFZ/9CzTyzvDk566o1/it/WpF9m1I440HHWGB8+kZeIj7W21n3JjLvJLBiU7yk21P+XDBr8uX8omvXTkLcsOlS/zD4VL+UP9N1SmjCv1ffD2w9XZZxfX6ZX5DEtAAhKQgAQkIAEJSEACErhJBLjOb/3pDJ8XncG1fi7TiOdDHuI7I2sdznNnGK7LEi5lkX8qHRnk74zYtYzUn7qomzDxhDtDtw9TJmVTb9JTZ6t+ZEU28nku9Y/c6MRzmT/x1Es5/MS1/Ohf50ubiC/DPFP/kvbXsutn5Jd607ayDa32p3zk1jxb/Ov2Rc5cv66v7r9STtnOxEf/2qfdyaN/8bdCFrJwDDgGHAOOAceAY8Ax4BhwDNyMMbBoxb/r1NVffvan1be//5Zg/+5zwp2B2B9s9/Sj0z6Nf1idx7Ea3UrvM078w6F51MUqLtv9cfWKLgcRskUbx4ni0Y3nOfXf/9GD1Tfvf0X23j1+7yJMxMtvPex3HZyndnV0bS0P80v8Jj56o39nZK6LEy7btE4YCZR56/aPFLkSPda/ZJzTfsrHwQ8+sJ/DH/25931T1+q/llxeH0EHDmWkHTAkLuO4Vd50CUhAAhKQgAQkIAEJSEACx0hg9HC/pcryPjSuNLZLGa30Mu+cMIbkvUfndc7J36ofeTgOdBtzGLG8XlC+YkBeyo61e0zWUDyTDrzmEEMTQ7uciBgqc8i4bdrf4k87OHwPlt2Ke9+sJdfBzem/KVbd7oAVEwe48laLe5+feLjfFDjTJCABCUhAAhKQgAQkIIGjJ7Azwz8G85gR3EpvkcIIZOcARjGGIUbxX3/6RW+k3f/2Qb9COyVj2/qRzWowuw1imE/Vt0lav+r/7vmqf94tzw6GIXlLJj6Gyi+NW9r+0th/vjqfUBkbH9GFCRRW2XH087MPzvbGO3Xic9/8k3dOVydvnvT1da8laPCXgAxLQAISkIAEJCABCUhAAjeWwOKt/mMtxWDDMCy332fbOsZrKz1ykYHxVTu2jbMajuGIYcjqcIzEGIp1mfK5VX/SX/nFxVbzcuUXWRj9rPZndbmUv6swK/zUwZb3erW/ZAPbrFAvqRtjOivqS8qRd077ORAvjjYwYYML37HxAdMhrpkAicwx/SN/qv8iY8zPYX5DeoyVMV4CEpCABCQgAQlIQAISkMCxE9jZij8NxRhnpbTcCl8a5a10ZGS7e2TkJH8MO969Lo3xJVvB5+qHYckOAlxdX1b6Sx2SD/124bLqj6x6tb9kAxc+h4vVYIoAAEAASURBVFz1n9v+TCwwUcFKelyr/2uutK9mEFlDPvKn+m+oTBnHNX7sDGGnQs6RKNMNS0ACEpCABCQgAQlIQAISuIkEXuqU5sTytWO1EwOsNNjXiQYOQgDjlcPllhi9B1GsUclN0htdmdjZ1YRNA43JEpCABCQgAQlIQAISkIAEro3A6Io/hhGOVVtWUnWHIbD0JP/DaHU7amE3yq5uYbgdRGyFBCQgAQlIQAISkIAEJHAXCFwx/FkBdbX/8F1fniov//3wdwJrP1yVKgEJSEACEpCABCQgAQkcN4HRrf5R+y6v+C997aFeUXYreUbR9fh1/9k/19MP1ioBCUhAAhKQgAQkIAEJXC+BKyv+UedYV51r4+2Y9MyKcgzOsNQ/DgLpH7TJqyxDmrH74snHp/1Bf69/+IavugxBMk4CEpCABCQgAQlIQAISuDEEdnad365ajEF28s6/DoojjdPWMfb5cOo7RppOArskwOn+HKzo6f67pKosCUhAAhKQgAQkIAEJSOC6CCwy/GOUs+pOmA+r26Ur00iv3Vg6Bnzy/9uv/n0tP5MAHHqHoc+VcoTJmyv/qIN8yI6cPNc6jtUfPcv08s75pKdu5EbfpG3jUy+ya0ccaTjqCw+eScvER9rbaj/lxlzklwzq/p1qf8rj51OXL2WTp3TkTbn4dfky/1C4lD/Uf0NlyriyvgdvP1ydfXZWJhuWgAQkIAEJSEACEpCABCRwIwlwnd/60xk+Lzqja/1cphHPhzzEd0bWOpznzjBclyVcyiL/VDoyyN8ZsWsZqT91UTdh4gl3hm4fpkzKpt6kp85W/ciKbOTzXOofudGJ5zJ/4qmXcviJa/nRv86XNhFfhnmm/iXtr2XXz8gv9aZtZRta7U/5yK15tvjX7YucuX5dX91/pZyynYmP/rVPu5NH/+JvhSxk4RhwDDgGHAOOAceAY8Ax4Bi4GWNg0Yp/16n9/fK5+5x3phPuDMT+qrSnH52SrXeszuNYjW6l9xkn/uEaNupiFZft/rh6RZeDCNmijXv62ydr3XieU//9Hz1YffP+V2Tv3eP3LsJEvPzWw37XwXlqV0fX1l1dD4fe6N8ZmRHfh8s2rRNGAmXeuv0jRa5E/+Vnf1pzK/uXjHPaT/k4+MEH9nP4o/+r776W4ov9Vv+1BPL6CDpwKCPtgCFxGcet8qZLQAISkIAEJCABCUhAAhI4RgKjh/stVZb3oXGZCKjLt9Lr/K1nDMl7j87rbOUlvVU/8nDPPx3f2o0Ry+sF5SsGlKHsWLtJn+uYdOA1hxiaGNrlRMRcOfvKt037W/zRmYkGWHYr7n0TMLy//vGXs5ozp/+mBHW7A1ZMHOAe/e6H66z3Pj/xcL81DQMSkIAEJCABCUhAAhKQwE0ksDPDPwbzmBHcSm/Bwwhk5wBGMYYhRvFff/pFb6Td//ZBv0I7JWPb+pHNajC7DWKYT9W3SVq/6v/u+ap/3i3PDoYheUsmPobKL41b2v7S2H++Op9QGRsf0YUJFFbZcfTzsw/O9sY7deIzwfDkndPVyZsnfX3dawka/CUgwxKQgAQkIAEJSEACEpDAjSWweKv/WEsx2DAMy+332baO8dpKj1xkYHzVjm3jrIZjOGIYZhs64RiKdZnyuVV/0l/5xcVW83LlF1kY/az2Z3W5lL+rMCv81MGW93q1v2QD26xQL6kbYzor6kvKkXdO+zkQL442MGGDC9+x8QHTIa6ZAInMMf0jf6r/ImPMz2F+Q3qMlTFeAhKQgAQkIAEJSEACEpDAsRPY2Yo/DcUYZ6W03ApfGuWtdGRku3tk5CR/DDvevS6N8SVbwefqh2HJDgJcXV9W+ksdkg/9duGy6o+serW/ZAMXPodc9Z/b/kwsMFFRbtVv9X/NlfbVDKYYI3+q/6bKksY1fuwMYadCzpFolTFdAhKQgAQkIAEJSEACEpDAsRN4qVOQE8vXjtVODLDSYF8nGjgIAYxXDpdbYvQeRLFGJTdJb3RlYmdXEzYNNCZLQAISkIAEJCABCUhAAhK4NgKjK/4YRjhWbVlJ1R2GAFv4YX7TjP7D0NmuFnaj7OoWhu00sbQEJCABCUhAAhKQgAQkIIHDEbhi+LMC6mr/4TogNZWnyss/VHbrO4G1W55Kk4AEJCABCUhAAhKQgARuBoHRrf5R/y6v+C997aFeUXYreUbR9fh1/9k/19MP1ioBCUhAAhKQgAQkIAEJXC+BKyv+UedYV51r4+2Y9MyKcgzOsNQ/DgLpH7TJqyxDmrH74snHp/1Bf69/+IavugxBMk4CEpCABCQgAQlIQAISuDEEdnad365ajEF28s6/DoojjdPWMfb5cOo7RppOArskwOn+nLHg6f67pKosCUhAAhKQgAQkIAEJSOC6CCwy/GOUs+pOmA+r26Ur00iv3Vg6Bnzy/9uv/n0tP5MAHHqHoc+VcoTJmyv/qIN8yI6cPNc6jtUfPcv08s75pKdu5EbfpG3jUy+ya0ccaTjqCw+eScvER9rbaj/lxlzklwzq/p1qf8rj51OXL2WTp3TkTbn4dfky/1C4lD/Uf0NlyriyvgdvP1ydfXZWJhuWgAQkIAEJSEACEpCABCRwIwlwnd/60xk+Lzqja/1cphHPhzzEd0bWOpznzjBclyVcyiL/VDoyyN8ZsWsZqT91UTdh4gl3hm4fpkzKpt6kp85W/ciKbOTzXOofudGJ5zJ/4qmXcviJa/nRv86XNhFfhnmm/iXtr2XXz8gv9aZtZRta7U/5yK15tvjX7YucuX5dX91/pZyynYmP/rVPu5NH/+JvhSxk4RhwDDgGHAOOAceAY8Ax4Bi4GWNg0Yp/16n9/fK5+5x3phPuDMT+qrSnH52SrXeszuNYjW6l9xkn/uEaNupiFZft/rh6Rbe8Bu/pb5+sdSPvnPrv/+jB6pv3vyJ77x6/dxEm4uW3Hva7Ds5TVyvauqvr4dhajv6dkRnxfbhs0zphJFDmrds/UuRK9F9+9qc1t7J/yTin/ZSPgx98YD+HP/q/+u5rKb7Yb/VfSyCvj6ADhzLSDhgSl3HcKm+6BCQgAQlIQAISkIAEJCCBYyQwerjfUmV5HxqXiYC6fCu9zt96xpC89+i8zlZe0lv1Iw/3/NPxrd0YsbxeUL5iQBnKjrWb9LmOSQdec4ihiaFdTkTMlbOvfNu0v8UfnZlogGW34t43AcP76x9/Oas5c/pvSlC3O2DFxAHu0e9+uM567/MTD/db0zAgAQlIQAISkIAEJCABCdxEAjsz/GMwjxnBrfQWPIxAdg5gFGMYYhT/9adf9Eba/W8f9Cu0UzK2rR/ZrAaz2yCG+VR9m6T1q/7vnq/6591y4sbckomPMRlL4pe2vzT2n6/OJ1TGxkf0YAKFVXYc/fzsg7O98U6d+EwwPHnndHXy5klfX/daggZ/CciwBCQgAQlIQAISkIAEJHBjCSze6j/WUgw2DMNy+322rWO8ttIjFxkYX7Vj2zir4RiOGIbZhk44hmJdpnxu1Z/0V35xsdW8XPlFFkY/q/1ZXS7l7yrMCj91sOW9Xu0v2cA2K9RL6saYzor6knLkndN+DsSLow1M2ODCd2x8wHSIayZAInNM/8if6r/IGPNzmN+QHmNljJeABCQgAQlIQAISkIAEJHDsBHa24k9DMcZZKS23wpdGeSsdGdnuHhk5yR/DjnevS2N8yVbwufphWLKDAFfXl5X+UofkQ79duKz6I6te7S/ZwIXPIVf957Y/EwtMVJRb9Vv9X3OlfTWDKcbIn+q/qbKkcY0fO0PYqZBzJFplTJeABCQgAQlIQAISkIAEJHDsBF7qFOTE8rVjtRMDrDTY14kGDkIA45XD5ZYYvQdRrFHJTdIbXZnY2dWETQONyRKQgAQkIAEJSEACEpCABK6NwOiKP4YRjlVbVlJ1hyHAFn6Y3zSj/zB0tquF3Si7uoVhO00sLQEJSEACEpCABCQgAQlI4HAErhj+rIC62n+4DkhN5any8g+V3fpOYO2Wp9IkIAEJSEACEpCABCQggZtBYHSrf9S/yyv+S197qFeU3UqeUXQ9ft1/9s/19IO1SkACEpCABCQgAQlIQALXS+DKin/UOdZV59p4OyY9s6IcgzMs9Y+DQPoHbfIqy5Bm7L548vFpf9Df6x++4asuQ5CMk4AEJCABCUhAAhKQgARuDIGdXee3qxZjkJ2886+D4kjjtHWMfT6c+o6RppPALglwuj9nLHi6/y6pKksCEpCABCQgAQlIQAISuC4Ciwz/GOWsuhPmw+p26co00ms3lo4Bn/z/9qt/X8vPJACH3mHoc6UcYfLmyj/qIB+yIyfPtY5j9UfPMr28cz7pqRu50Tdp2/jUi+zaEUcajvrCg2fSMvGR9rbaT7kxF/klg7p/p9qf8vj51OVL2eQpHXlTLn5dvsw/FC7lD/XfUJkyrqzvwdsPV2efnZXJhiUgAQlIQAISkIAEJCABCdxIAlznt/50hs+LzuhaP5dpxPMhD/GdkbUO57kzDNdlCZeyyD+Vjgzyd0bsWkbqT13UTZh4wp2h24cpk7KpN+mps1U/siIb+TyX+kdudOK5zJ946qUcfuJafvSv86VNxJdhnql/Sftr2fUz8ku9aVvZhlb7Uz5ya54t/nX7ImeuX9dX918pp2xn4qN/7dPu5NG/+FshC1k4BhwDjgHHgGPAMeAYcAw4Bm7GGFi04t91an+/fO4+553phDsDsb8q7elHp2TrHavzOFajW+l9xol/uIaNuljFZbs/rl7RLa/Be/rbJ2vdyDun/vs/erD65v2vyN67x+9dhIl4+a2H/a6D89TVirbu6no4tpajf2dkRnwfLtu0ThgJlHnr9o8UuRL9l5/9ac2t7F8yzmk/5ePgBx/Yz+GP/q+++1qKL/Zb/dcSyOsj6MChjLQDhsRlHLfKmy4BCUhAAhKQgAQkIAEJSOAYCYwe7rdUWd6HxmUioC7fSq/zt54xJO89Oq+zlZf0Vv3Iwz3/dHxrN0YsrxeUrxhQhrJj7SZ9rmPSgdccYmhiaJcTEXPl7CvfNu1v8UdnJhpg2a24903A8P76x1/Oas6c/psS1O0OWDFxgHv0ux+us977/MTD/dY0DEhAAhKQgAQkIAEJSEACN5HAzgz/GMxjRnArvQUPI5CdAxjFGIYYxX/96Re9kXb/2wf9Cu2UjG3rRzarwew2iGE+Vd8maf2q/7vnq/55t5y4Mbdk4mNMxpL4pe0vjf3nq/MJlbHxET2YQGGVHUc/P/vgbG+8Uyc+EwxP3jldnbx50tfXvZagwV8CMiwBCUhAAhKQgAQkIAEJ3FgCi7f6j7UUgw3DsNx+n23rGK+t9MhFBsZX7dg2zmo4hiOGYbahE46hWJcpn1v1J/2VX1xsNS9XfpGF0c9qf1aXS/m7CrPCTx1sea9X+0s2sM0K9ZK6Maazor6kHHnntJ8D8eJoAxM2uPAdGx8wHeKaCZDIHNM/8qf6LzLG/BzmN6THWBnjJSABCUhAAhKQgAQkIAEJHDuBna3401CMcVZKy63wpVHeSkdGtrtHRk7yx7Dj3evSGF+yFXyufhiW7CDA1fVlpb/UIfnQbxcuq/7Iqlf7SzZw4XPIVf+57c/EAhMV5Vb9Vv/XXGlfzWCKMfKn+m+qLGlc48fOEHYq5ByJVhnTJSABCUhAAhKQgAQkIAEJHDuBlzoFObF87VjtxAArDfZ1ooGDEMB45XC5JUbvQRRrVHKT9EZXJnZ2NWHTQGOyBCQgAQlIQAISkIAEJCCBayMwuuKPYYRj1ZaVVN1hCLCFH+Y3zeg/DJ3tamE3yq5uYdhOE0tLQAISkIAEJCABCUhAAhI4HIErhj8roK72H64DUlN5qrz8Q2W3vhNYu+WpNAlIQAISkIAEJCABCUjgZhAY3eof9e/yiv/S1x7qFWW3kmcUXY9f999d6R9uv+AgzGMbfy3+rfTrGUXHU6t8jqcv1EQCEpCABCQgAQncNAJXVvzTgGNdda5//B6TnllRjsEZlvrHQSD9gzZ5lWVIM3ZfPPn4tD/o7/UP3/BVlyFIG8SF/9j3o5W+QZW3qsgx8Cl3JgF3aHKp/G5tMnHcKp/xcxPPQblVA9LGSEACEpCABCRwowjs7Dq/XbWaH32sWA450jhtHWOfD6e+80NUJ4FdEuB0f85YuKmn+6M73499HFw49f3cZR9cl6xt27dt+etq95x6OX+E70b597e8PhODnPZjkCdPJivmyJ9bnsk4nQQkIAEJSEACEpDAMgKLDP/8qGXVnTAffqyVrkwjvXZj6Rjwyc825cjPJAA/OjH0uVKOMOm58o86yIfsyMkz+Uodx+qPnmV6eed80lN39Ev8tj71Irt2xJGGo87w4Jm0THykva32U27MRX7JoGRHuan2p3zY4NflS9mkl468Zdmh8mX+oXApf6j/hsqUcaW+D95+uDr77KxMHg1T73X3X9n2mi2KE8c4yRjhOeOH9Cn+KUO+oe8n8chGZvkh/lCu1T70GBu/c9o31Y655Vt91Eqf0mGq/6bKkZay5RgOq7Lssz+Ofx+YBOCK1U0PJp1THp2Y/GUngU4CEpCABCQgAQlIYBkBrvNbf7ofgC+6H9Dr5zKNeD7kIb77kboO57n7YbYuS7iURf6pdGSQvzMg1jJSf+qibsLEE+5+cPdhyqRs6k166mzVj6zIRj7Ppf6RG514LvMnnnoph5+4lh/963xpE/FlmGfqX9L+Wnb9jPxSb9pWtqHV/pSP3Jpni3/dvsiZ69f11f1XyinbmfjoX/u0O3nG/GPov+g2pUvNuHwuw5FV+1N5yrFCubq/I6v1/WilR07to1utX/ncGr/IK/PX8uc8T5WvedT6tNJT/xifqbpTdsqPXMZPwvhlGepIPehbpvGcsZd8dfkyfx1ulUdW6kzeWobPF/+Xy0IWjgHHgGPAMeAYcAyUY2DRin9XsN/GmS3EbONMuPtR1l+V9vSjU7L1jtV5XPdjsF9R4iq1sfQ+48Q/lKUuVnFZ8cHVK7rlNXisPEU38rb06+X96MHqm/e/Iti7x+9dhIl4+a2H/a6D89RV35ZdXQ/HKhn6d8ZAxPfhsk3rhJFAmbdu/0iRK9Fs0w23sn/JOKf9lI+DH3xgP4c/+r/67mspvti/3+i/lkC2J6MD7y3TDhgSl3E8Vf5Y+m9KR9JoV7kiS3vjtuWfcRN5rA7fe3SSx4P4U+2bM373pWRr/LfS5+i1i/5jVxU7OthOT7ju04wX8tSO7zrx2eZP+Ue/+2GdbfS5VR6d/vrTL0bLmyABCUhAAhKQgAQkME5g9HC/8SLDKbwPjat/KCZ3Kz355vr8UF5iVLTqRx7u+afjW1n5YcrrBeUrBpSh7Fi7SZ/rmHTgh3MMTQyVciJirpx95dum/S3+6MxEAyy71cK+CRjeX//4y1nNmdN/U4K63QErJg5wpbFy7/OT2Yf7HXv/TbWftG34R3a3EttP9uSZPjwWt834pQ3lGEmb5o7R1vhvpae+KX8X/cffHv7u4PJ3KHXSfiZdE09f86HeOIz9OPLxt3LJ38ex8pnw3cXf2einLwEJSEACEpCABO4SgZ0Z/jGYx37ktdJb0PmBzc4BfkxiGPLjlNUfjLT73z7oVzKnZGxbP7JZ7Sp/+E7Vt0lav2r87vmqf94tL1dna5lLJj7qsps8L21/acw8X51PqIyNj+jDD3tWDHH087MPztaGRvLsw2eC4ck7p6uTN0/6+mqDZk6dx95/c9qwDX+YscofQxBD8Zjc0vFb684Y+Xo1byKqLtv6+9NKr+WNPW/Tf8hkxxF9yCQY/VdOvBHHbRdx+fub73R2AyR9qT9Vnr/3mbiJXCZJH795fu5L4vQlIAEJSEACEpCABIYJLN7qPyzmfKWfH27l9vtsW8cg4gfpVHrkkgfjq3ZsG+eHHj8yMQwxLvIjN4ZiXaZ8btWf9PKU6nLlF1kY/VnBKmXvMsyqMXWw5b1e7S/ZwDYr1Evqx5jOivqScuSd034OxIujDVnxDd+x8UG/8qldJkASP6Z/5E/1X2SM+TnMb0iPsTJ1/L77r65vV89z+ZdjsK4bw+zZHy52zHAC/DG5OeN3qn1z2jJWPuNzbPy30lt1z+2/se8P8plY5W8Pxj6vu/D3hbg42lZ+v9MWdMdl7Of7w98oyiQ9csb8qfL8vc8rBPjI5bWO7D4Yk2m8BCQgAQlIQAISkMA5gZ2t+COOH2es+vHjMa40ylvplOHHHwZ+ZLD1kx93/Hjkx2hpjM/dZhtdWvWTzg9jdhDg6vryI7PUIfnm/rjtBU/8k1VjstSr/SUbuPA55Kr/3PZnYoEf5+WKYYt/zZX21Qwm0PXjb6r/psqShqHKyis7FTASN3HH3H+t9szhX45B5OX7SRhDrPzu5nn1yerSOCDvdbg543eqfXN0nirfGv+t9Fb9c/pvTAbGOn1Hn+H4e0bf9nGr83Mh6r+P5Cv/vjP2WYEv9SjTyT/lti0/Jds0CUhAAhKQgAQkcNcJvNQB4GTmteMHID/clvxgWxc2sBMCGK/8AF9i9O6k4i2F3CS90ZWJnV1N2JTobhKHUm/DEtgXAb4TU87/b6bomCYBCUhAAhKQgAS2JzC64p8faqzastKjOwyBbI+9aUb/YehsVwu7UdiOvk9n/+2TrrJvKgEN+5vac+otAQlIQAISkMBtIXDF8GcF1B9ph+/e8sRw+e+H/z4nsOy//fSZUiUgAQlIQAISkIAEJCCB7Qlc2eq/vcjzQ6J4V3qbbdS8clCXH4ob0nduvqGyiWPlNu8EJw65vP+9z9V46ijfkb2LOy44UIx3i/e1FT/9qS8BCUhAAhKQgAQkIAEJSOAuELiy4l+uXE4BaBmk254TgIH96oevXXrN4PUP3+gP/+Nkaa6VGjPAycfhbLXhTnvyCgPhqTZwfRSfepW4N0g/3c+74eiE7uWBacTpJCABCUhAAhKQgAQkIAEJSEACmxK4YvjPuauaFdmhK/dKJXKNWxnXCter3eSPoY4xjMPY58MERe5c7xOqf2L0Z/U4yXNuAqAMd1nnRHp0yGF7TBbUOxEiexc+76DXV9jtQm5klG1J3C79Xcinfz/79X/tUi1lSUACEpCABCQgAQlIQAISuLMENtrqH8M/xnXoxUjPc+mzbZs71uu758cM8aE6OJytXIEv8xBmNb509Yo+EwvoEIOevEwglM/ElfWUddRpQ2XJs4kbO3iu5DPUxvI8gKGJk2yXH9vJkQmN6MwrDrlKkbhdyUf3V999rZ9QYQxQL89MdETHmkFZN7pkUiHliEvZOenkmaqjJZ/yOglIQAISkIAEJCABCUhAAjeRANf5rT+d8fiiM4Be4JfxZbgz4l50BuKsdOR0RmefF7+UiwxkITv1Ujcf8pKeZ/zOaLv0nDylTGSRb0hmKSth6i/Lp860L3Ukf+m3OJTM5oaRHyZ1mVJP0mhn9OR5qmxkTeVJ25OX57DcVj5tSt2ph/aEb+rET94yLvUjIxzQLeE56TWv6JF6kD0lP/n0L/5eyEIWjgHHgGPAMeAYcAw4BhwDjoHjHwNXtvp3nda78oC5xJV+tt6XcduEy9sEOsOvXw1+/N5X/Xv6nTHWrzx3hlq/DZ6t4ORhhb9erY8OnUHYvy/PqjFh2oPO9x6drMsgrzyEkHw4VtmffnTal8tZAtnd0BmPl3YdnK3+kSr37tevGPA6Au2JY4cDq+F//vVm1y9ypkHZrzAoV/+3lU/5vu8+OOkZ1+1JO6Z8dgqkXLn7I2XG0ulbdhfQpjj6lPYxltALN1Y+ZfQlIAEJSEACEpCABCQgAQncNAKDhn+5vXyTBvHu/SbvqWPg4zAQv3n/q/Xp9hjvvXH22Vn/Xj/GNgYu27xrhzGPgccheRiGGOq4TADc67b6d6vM61cOyomAlCEdN+cEfwzKGKKUyaTFkFFK+raO9tC+OPoqjjrRJxyX9iNyMYRLYx/ZaeO28qPndfj0Ja7sq+vQwzolIAEJSEACEpCABCQgAQkcmsCg4b+tEhjT5crqsz+czRKJcY7RzUo/Btp/v/usN96Jy8r+q5+/1svi1P7SiMsOAFasmTgoDe8yTGFkfb36cl0XcZSv8xEfI5pwXBlHXX/96RdrXXLOQD9R8c9V5JTb1sfoZ5U/emaCopQLEzji0PPZB2eDtxuUZRKmLWO3ISTPNvIj4zp8dnbgMolxHTpYpwQkIAEJSEACEpCABCQggesg8C/bVIpxO+Tuff9kbQhnpXUoXx2HUcbWelbeMVpZgcYnjpV8XLa3Z+t9ZPQnwXcGbx1POjL43P/Jwz47svrn7pC5uGz1zjN+ZGJI54NxnDA+Rng5AZG0IXml7E3C8CgnUeAcBzs+tat3XqD/2I0MGP2s9g/J2YX8WrdDPtNHtD1jgLozpvbRV4dsm3VJQAISkIAEJCABCUhAAhKYIrDVij8G5PP/fXbJ8MWYYpt+3JJt/xhnZ7//x/oddYxzHKvoGNQYnxi7GMCs2OPmrKxTFteX77b6MznAZ2jFvM+4xT/o8+Dth+sdCluIulKU989hka34eV59sup3SdTnMrD7oTZq6ZtSBnkyWRK/lpNXKur4pfKvNOjAEUzSsGsi/Kg+Y+PAqlidBCQgAQlIQAISkIAEJCCBgxG4cp0fxnFt4LW0ifFEWVZUWWXGuIxhmivXMLTr6/zIE+O0TmeFNtvaMaj7g+v++R47OlIvEw0xWKMnxl3KlWH0K6/zo768VpCy+GPxlM85AGX+MpzJirS5TDMsAQlIQAISkIAEJCABCUhAAhI4NIErK/7lO9xLlKmN4s9+/V/96momBSKrNIgx2mP0k5537wlHHgY/kwgcVBdjPjrGyI7hj5HPboDaJR8TCax455l8GP67dHV7dylbWRKQgAQkIAEJSEACEpCABCQggaUErqz4LxVgfglIQAISkIAEJCABCUhAAhKQgASOl8Clw/1YCWeFXScBCUhAAhKQgAQkIAEJSOBYCLBTmM9Nc9pXN63Hbq++lwz/29tMWyYBCUhAAhKQgAQkIAEJ3DUCLGpifOfDWV6buJTH5/Xim+Roc/Qfan8rvdXWVvlW+nXLb9V/W9I1/G9LT9oOCUhAAhKQgAQkIAEJSOASAc4T4wyufDhofMnOAc4dw2jmQPLIyLljlyra8CEGeelvKGqwGG3lVrToTrhsfyt9UGgR2SrfSi9EDQZb5Vvpg0LvaOSg4c8sVgYfgz2unjEjT+nyxUhZ/LI8eemcMr0sb1gCEpCABCQgAQlIQAISkMC+CHDY9xLHjWAcMl4eSL6kfJ03q9+ljVROKqAf9tKuHNdYl1etEy6vtm6lR4/Yh3mO3yrfSo+cfctPPXfZv3KqPyfo5+R9BmZ5fd3zT8/62aIAo4MYmDlVnyv2yuv5ki8+eel8ZpxwPCNjl7NmqUtfAhKQgAQkIAEJSEACEpBACGBscwNYbJfET/mskNe3gsVWmio3lIZt9ewPZ/1NZkPpxKEfV6PvwmVyoZy0wJ7DJY3wWDo3qU25yBgrn7Jj6dctP/rdFf/Kij+GezqBq+4YfOnUxAfOsz+ere49OsnjihmqV999bf1cB15+6+Hq8S+/Xkc//eh08Pq9dQYDEpCABCQgAQlIQAISkIAEtiCQVXYWKTHalzhsIRZGs1UeWwY5Sx2LnU8+Ph2cdEB+dkRTT2koL62nzP+dH1zYaYmPPUdaKz1l8FmozeJt4lvlW+mRcwj5ZV13NXxlxb8FgkHLFyCOrS9xDAgmCRi4ONK+/vGXSe7LseLPp3SUySAs4w1LQAISkIAEJCABCUhAAhLYhgD2yNerc5sEOwXjfcmqf7lwSTlsmSX2C4Y9C6RjBn25Yxr9ahtq07Zndb8snwXdoTTytdJLWUMyWuVb6YeUX9Z1F8JXVvzLRmeWJkY5Rj+r/JnxKo3+lCNv0uvDMxjwfHGSHj/yI0NfAhKQgAQkIAEJSEACEpDArglgi5Q7llvysV+2dRj22FDYUi1HXmyoXbjYWOV17aV910pv6dAq30q/bvmt+m9b+hXD/8HbD9dtZNt+adyz0s97KXG88xLH7E1mcBKHX76j8vffnK5nyMo8hiUgAQlIQAISkIAEJCABCeybAKv1pT1DfdlmP1R3DsOLncMZZUwGxKgdKjMUx66DOcb/yZsX9tWQnKVxTHSUr2ITLncwtNJTH5MW2dWdOPxW+VZ6ZO1bfuq5y/6Vrf58EdKpDOpyqz4zUGxVyVb9PK8+6Tq9Ow+gft+Fji63tGRLTZ1v0wMy7nLH2XYJSEACEpCABCQgAQlIYJpADhdPLhY1Y5MkbsrHlnn85uX3+tm1vInDroqBW9o/2FerX11IXHoOwUXJqyHayg6H2Hd1+1vpVyVejmmVb6Vflnb1qVW+lX5V4t2Nealr+ou723xbLgEJSEACEpCABCQgAQkcOwEMeByGnk4CElhO4MpW/+UiLCEBCUhAAhKQgAQkIAEJSEACEpDAsRJwxf9Ye0a9JCABCUhAAhKQgAQkIAEJSEACOyDgiv8OICpCAhKQgAQkIAEJSEACEtgfAbb6Z7v//mrZvWTerS9P1d99DUqUwDwCGv7zOJlLAhKQgAQkIAEJSEACErhhBDC6Mb7z+d4n/2ujFnCq/0014mnzVPtb6S1grfKt9OuW36r/tqTv3PC/qV+I29KhtkMCEpCABCQgAQlIQAISOCfAqfycwp/P/R892GjnwOsfvrEXpDHIS3+XFbFLgivY037C5c6JVnpLl1b5Vvp1y2/Vf5vSrxj+dM7QwMssF+lxyctzZnIIcyVFZJRbW4jjOddY8Jw7MSlXz8iRXrroENl1+TKvYQlIQAISkIAEJCABCUhAAiUBritf6rB5/v6b09UmZeu6YjOVNhBXpMcwp47S3qrLL33mGvZv3v9qXYxwrmYnspWegrHf8hy/Vb6VHjn7lp967rL/P8vGM8joHAYejmc64c//8fnq299/u+JOyUe/++Hq7LOz1fNPz/q8uWeSeym/Xn3ZG/wMXmbXhhyTArm3EtmlQ2bqJp50dMi1HdQ9JbuUZVgCEpCABCQgAQlIQAISkEAIYGx/9417a9si8VM+ZV5+62FvD+Fv4zD6n/3hbIXdNObQD1trFy6TC6Vdhr2FSxrhsXTsvykXGWPlU3Ys/brlR7+74l8y/BnMj3/59brtTz86vTQjROeQjvHObBThVoethf0zgOGeMkwolC7xiXv2x7PVvUcneezrfPXd11Z//vXlcusMBiQgAQlIQAISkIAEJCABCRQEMLjZ4o/LomWRPBlki/9ff/rFZJ45iSxostpeGsEph221+tX5U7kImvRN/e/84MKOiozYW0Np5CnTz35/sZBb223kHZJRlidP7cr0Q8qv9biLz5cMf2aYWPHnUzpmc9JJrL5ntisr8WXebcN8KdAj7ulvnyTYz7ShS14BIG1qxmxd0IAEJCABCUhAAhKQgAQkcCcJZGcyjceOYPFyjh3DzmO2+McO2hReFk2HjH5kljua0W9XNk5W90u9s0o/lEa+Vnopa0hGq3wr/ZDyy7ruQvjSO/5Zxc87JvHLwc4XgJV4jHNmz3bpMPqRnXpLoz/1oEvSNz2cI7L0JSABCUhAAhKQgAQkIIG7QwCjv9xRPNVyFjtZEMUY54P9gxGPPbTEYdhj42DrtBx5szuhlbeVHhuuPHMtq/SktdJvu/xW+25b+iXDnxktBndmYurGMmhIZ9aMbTIMynIgkZ/Jg5M3r24rqWUNPfNl4r2XOE6djEOnIb129Q5M6tGXgAQkIAEJSEACEpCABG4nAWyZ0t6glTHs6xazvT0LjvjYORjmc3YL1LKwn+YY/5vaUXV9eWaig1el4wgTF9dKTz4mLeBUu1b5Vnrk7Vt+6rnL/qWt/hnEHKJXurwLwwwXgx3HDBEd2cetLg7z490V4vhS4cgTuX3ExD/ILsvmefVJJ+e9r/qDBcviyB7bMlPmMywBCUhAAhKQgAQkIAEJ3D0CrM7HLqH17Ciea5vsmhbGfwzcHHZOHdg/ecef59hehLd1tJUdDjHa6/a30lv1t8q30q9bfqv+25T+UteYF7epQbZFAhKQgAQkIAEJSEACErhdBLK9HkNSJwEJLCdwaav/8uKWkIAEJCABCUhAAhKQgAQkIAEJSOCYCbjif8y9o24SkIAEJCABCUhAAhKQgAQkIIEtCex1xZ/D+PI+yZZ6WlwCEpCABCQgAQlIQAISuKME2Oqf7f43CQG2UH0Y+k3SX11vD4G9Gv63B5MtkYAEJCABCUhAAhKQgARuGgGMbozvfDa9jjwLmjfRiKfNU+1vpbf6vFW+lX7d8lv135b0ozP8nRW7LUPLdkhAAhKQgAQkIAEJSOB6CXADWHklH9eRb7Jz4PUP39hLQ2KQl/4uK6KtXJEeBoTL9rfSW7q0yrfSr1t+q/7blH7J8K+NbjqKGZq4pJcDk9mv0uWKCvLc/8nDMqnf5lKWJRyXmSCeudIi+epZNXRKWlmecpmJK9Nr/cink4AEJCABCUhAAhKQgATuHoH//uLZ4kZjf/z9N6erTcrWlcXmKW0UrjCPYU4d1Lcrx1WGXLceR7i83rCVnnKx8fIcv1W+lR45+5afeu6y/z+XNh6jnIGJY+Ay+/Xn//h8/UygTO8T/vnP80/P1mlE0cEMbK7l4F7Lr1df9kY9g5/ZudqRl8ET+TwjI/U/+t0PV2Nla1k+S0ACEpCABCQgAQlIQAJ3hwDG9nffuNfbHnNbTZmX33rY2xv42zhsp2d/OOvtnjE56Hf22dlY8qL4TC6UdhX2GC5phMfSv/39tySPusgYK5+CY+nXLT/63RX/0or/nEZjWMc9fu+r/suTTmfrTDmjRHrp6s599sez1b1HJ2WWyTBftse//Hqd5+lHp339iWCG7NV3X8ujvgQkIAEJSEACEpCABCRwxwlklZ1Fwj/8n/+7iAaLnH/96ReLygxlZrHyyceng5MO5W5nFjhLQ3lI1ty47/zgqp0Ve4y0VnpZDwutWXxNfKt8Kz1y8Pctv6zrroYXr/iPgYrxn1mksXwMemay4p7+9kmCTZ9yrPjzKR11M4gZMITzCgCy2Umgk4AEJCABCUhAAhKQgATuJoHsLKb12AksJLLjuOXYXcwW/xjLrfxj6Rj2LFCOGfTljmX025UNM2SXtWy2VnrZxpsuv2zLXQhPrvi3VuMzizP3y4DRzyo/s0V8lhj9dAZfGL6oKR+/rJ9w4jc9vOMudLxtlIAEJCABCUhAAhKQwF0jgC3RsnHChN3GLDjm/DAWITHimRBY4jDssYGwhVqOvNgwu3Cxkcoz00r7rZXe0qFVvpV+3fJb9d+29EuGP4b1yZvnW0IY0EOD7sHbF++2sK0+xjsdS/lXfnGx1Z7tNKXjy8J7LXGcKlm7Uoc6jRk3vnyZiSrTiRuK39U7MmVdhiUgAQlIQAISkIAEJCCBm0cAW6K0R2hBDPu6Ndl+nkVF7BQM8zm7BWpZ7DqYY/zHFqvLb/rMREf5KjRh4uJa6cnHpAWcatcq30qPvH3LTz132b+01Z/385nF4gtBJ/EZmhFLpzP4y630fDlIu//t+SwV79CUxj9flMgHep5Xn6zWckodyIMO+XLFL2WSJ+/q1PGUHdtSQzmdBCQgAQlIQAISkIAEJHB7CbCYiW0Tx6JlbIrEHcrHboqBi/2SFXHso9WvLrSIbXMRs3mItmLPxX6r299Kb9XcKt9Kv275rfpvU/pLXWNezG0QAwZjXWN6LjHzSUACEpCABCQgAQlIQALbEsj2egxJnQQksJzApa3+y4tbQgISkIAEJCABCUhAAhKQgAQkIIFjJnBpq/8xK6puEpCABCQgAQlIQAISkMDdJOBK/93sd1u9OwKLVvw52GKX2/w5jC/vm5RN4uRJ4ocO6yvzXVf42PW7Li5L6x3r/6VyyvyRyfjhM+f01LL8TQ7T3vLU1m3bEpZz5ey6/rn1lvmi81T/j31/885dyiJLJwEJSEACEpCABCQggdtAwBX/29CLtmFN4PUP37h0IOQ6wcCdILBN/3M4KQ6Dvz4o9E7As5ESkIAEJCABCUhAAreWwKUV/2NYsYM0uwrYXZCTLo+N/rHrd2y8DqkPV0Z6heMhiR+2rtbfqDn97/f3sH1mbRKQgAQkIAEJSEAC109g8Yo/22H5cR2HgR7HFtr+OopEdH6ZTnRZnuv2SlemEV+X5Uc/two8ePvh6v6Pzq8M5EqK8krBUgZp5KvllHUmjO7ca8n9mpShHp5pa67bKGVP6Zdy5ElZwtF/LJ08U3XMKY+MMTe0kjmkX9mHZTpy6ytRarat9LJ9df+39BtrF/Gl3PJKlHJ8zOFXykFu2jdnfJC/5Wo+XImZleY535+p8qn7e5/8r9HvR10+7UvZsv11/yRPy5+qv5SPnLL+qf4vZZb9m1tGSrlletn/ZZ667labkt7il3z6EpCABCQgAQlIQAISODYCXOfXfzrD6EVnfKyfEx+/++H8ovvhu04nTJmkdz/c12Hi6vzdj/c+Lvl5LssnHh2G4onjU+pYPs+Vn3pKP3Xip120B5llmymTvGV5wtEvHGh/wnPSa17RI/W05CffmF+yGsoT+Umredb68IzOyd9Kr+XxTJ0p39Iv+ab8KRlpX/qk7p8p/unzOeNjTL/wSf11vjp+TJ86X+SkfehYxuU59Set7r9W/6TcmN+qf6w9kTfVd3PzzJGRvozM2ocvcmrOLX61HJ/P/1+RgxwcA44Bx4BjwDHgGHAMXP8YuLTVv+uQUdf9CO5Xv59+dLrOk9M1ux/SfVy9NZ/V83uPTtb5WUn/5v2v1s+P37sIryMbgazwJRsrpnHbykdWDi9kpbBuT+qZ8tEv5VjJTThlxtLn8EXGWPnIn/JpH7sNphzy4+gfdjygG+7ltx72788nnbFQ7v5opbf6Z45+qXtTf4zfHP7bjo/wqcdE2lLH19+fVnnk0L6MYZ7ROS7l81z3X6t/Um7KH6t/Lt/W+Jyqe99pLX77rl/5EpCABCQgAQlIQAIS2JTA7K3+3/nBuQFfGyd1xd2q3iVjEAMaF+Px+adndZGdPO9b/k6UnBAyl++EiGYSExFw6lYz+7zlNuhm4S4DRv4r//m9/lPmRybjYio9+af6f1v9Uscm/iH4w6d1/sDY94c2zSk/1fZt+2dKdittDt/r7P+W/qRP8Wv9XZwj3zwSkIAEJCABCUhAAhLYF4HZhn8Mthh5QwphtLBKyQ94XLd1eCibcQME5vAdKLY4CgMl71UzAfDsg7NVdm7UwmpjjdXjv//mdDT/VHomZuo66ucl+tVlt3k+BH/4nLx5sjpb/WNQ1db3p1V+UGgRuYv+KcQtCs7le139P6cxU/zmlDePBCQgAQlIQAISkIAErovA7K3+/CDnh+/9nzxc69q989qHs7WYFbFnf7hY0b/3/Ytt/in/yi8utprv8sqsfctfN3pPgeg/xXebqjG8h4zvegWagxPj2HadHRvEYfSz4j8kp5We9o31/1z9otuu/ei3L/4ln7waU7dh6vszp3wtr36e6r+0f6x/allLnyN/jO/c/s/kx9L6d5F/it8u5CtDAhKQgAQkIAEJSEAC+yJwZcW/PBGbSsvt4KzksyqJ8ReX1WOeeb+X8knP8+qTVX/yPuVZZb7/7fmJ/JwYv0vjf9/y0+Z9+S2+29Zbs+bU9kzalLLzKgBGVnljQnYG1HJy8n8rvdU/tdwx/UpddxneN//wqb9j+Q7l+zL2/WmVb7FI+Zpz+q/VPy35rfQW31qvof7njJDybwx50q5W/dump55az/DbVr7lJSABCUhAAhKQgAQksC8CL3WCOQH8VjpWVlm1xuDQtQlg8NeHs7VLmUMCEpCABCQgAQlIQAISkIAEjpnA7K3+x9yIMd0w+jlzQCcBCUhAAhKQgAQkIAEJSEACErirBK5s9b/JIDhzINukaUf5msJNbpe6S0ACEpCABCQgAQlIQAISkIAENiVw0K3+d2UrOa8Y8B7yXXv3t76Kbqz9d5XPpl9Sy0lAAhKQgAQkIAEJSEACEtiGwEZb/bmmLyf6b1O5ZW8XAc5S4KA6DH6dBCQgAQlIQAISkIAEJCABCRwHgUWGPwY/125xZR/XwLFy6wTA1Y7kpHwMYK4w010lIJ+rTIyRgAQkIAEJSEACEpCABCSwLwKLDP8nH5/21+89/ei016e/5/2f4SUKsiWcbf98yjvhmUhIfPxSLnkTH78sT14mIpKGP+RS/1DaWBy6UY7JD+TmmXB0iNzUX8uqy5VlydtKJ89UHa3yc/hRx5hr9c9YucRP6U7a0CQScaTh0r7II43+iEt6+ojnMj35pvx6/KTulBlrQ8ZD6s4zOmR8RIa+BCQgAQlIQAISkIAEJCCBQxPgOr/Zn84wetEZNy86A+hFZ9DMLkcdnRHUf1IuclJ/4vNMHdSXZ8p3BtX6OfHxyUue8hkZeY5PXJkv8VM+9ab+1IO+tKHUERnJW8ujPJ+0s2bYSq95RI/U0ypP+hS/yBnzo3fSa30ST76ynYmPP8RnKI78pc5lmDTaD//I/f/ZO78WW4pzDy9jiHvgwNYNQVQ4hhM1iMK5D+QDBAO5yRfwInDuAuKVH8CrIORO8MIv4I2g5AMI3gci4p9IFNxhExgVhNkRNvv009vf2u+q6e7V68/MnlnzFMx0d9Vbb731dHWvfquqq0lvZdrjyA5tw7OtZ2Tb+kae9NjPNvHoGWof0ed2/n1HVrKyDdgGbAO2AduAbcA2YBuwDWzfBjYa8e8cmX7V/Ju/+2rxrz9/vXj67Wc69psFvhOfKfC3Xv968cgz15YjoomPRj7Fd+25oxwu/vP57QWzDMbCoy/dWNz6y81lMjMT0N+GvIvexq87pnymqRP4YkBr77r8pNf6Y0erYywd9tQlsy3QdfzKv9n0sw/6ne7fWH7S1/GLjrFta2t7fsbyzYmHK/Z1TvNSnP3KfJkwsUP9c44QI//ckPbT1pP8c/hXW7dtH3NtVU4CEpCABCQgAQlIQAISkMBcAht9zg+HiHfXCThXX7z1ydxyZst1o6orzjoOVAKOMg5YN4rbR7Wf68Mx5nN+9ZN+CJJnyJmL3suw/dkL9zpAdqnHOn5zOEydnzn5p2ToTOJrCOnQwBEn7rwC7Ye1K4bCPvgP6TVOAhKQgAQkIAEJSEACEpDAWRPYyPHftzGtM4VTySgyDiqhmyZ9qsja+UAHwO03TpaOIiOu375/vDw+lfkSR/zw0T2HdNdOjCl+6/DMOT/rdEyl96P+r94b9Y8DXkfv27x1Nkibts0x7efo+aPFyeLerI6qY1/8q073JSABCUhAAhKQgAQkIAEJnAeBjab678Ogx35/Y6mmXxywjOgz4soXAxKuPXt/mj8OL39tiINIPE4/o/1DcjUfDmxmDdT4i7yPw45jev0P9/llWvyUc5w6zeGHLFzG2Eydn5Sz65YRfs4hbaMd7Y9jThnU/fpvH9u4uKn6pf107+mf0rsr/1MKjZCABCQgAQlIQAISkIAEJHBOBM59xB/HPo4ljhzrBSTwfjZTvTNVP8eL9xYL1gN47oMXI9pveZ+/Or2ZIt7K8V15HLfLHpgJQadF+FCfvHoxp24tl5bfOh05Hyk/x5yfeh7X6ZlKz6g/MvXccpxXASgf2/nb56h/2g9tcPEmJd4LYbwr/+hzKwEJSEACEpCABCQgAQlI4DwJPNQVxqroBglcGAJ0DNGp0Dr+F8ZADZGABCQgAQlIQAISkIAEJHCJCJz7VP9LxEZTHwCBbVbyfwBmWqQEJCABCUhAAhKQgAQkIIFLQ+Dcp/pfGjIaeq4EWMgx7+xnav25GmBhEpCABCQgAQlIQAISkIAEDpSAI/4X8MSyuBzT3dctUngBTd/aJNYIYM0HQhbgG6v/VeSzNVgzSkACEpCABCQgAQlIQAJXnsBWjj+js1lR/soTFMDeCLB4HqP9LMZokIAEJCABCUhAAhKQgAQkIIH9ENjI8cfhZxSWlfn5jB4jr+fdAcBo8NDn1vaD42JoYVE7HOBD+BLBWRCVz1lQVacEJCABCUhAAhKQgAQkcKgENnL8v3n3uP+k3nfvHPc8+NZ69ucCoqMgU7nZJtChwHHtSIgsMnQ6RJ7PrUVH7QQgjmM+eZf0Ol2ctMRnm/LZxoaksa35Ixv9OZ6zjV2pR45rGdGb8lu9xNd8NS+y69KRmSpjXf65fChnKKzjP5Snxk3ZTlptO8lHHGmE1K+mcT4Skp5zxHFNj9zUNm2WvPyl7OQZq0POa8rOMTqG2mD0uZWABCQgAQlIQAISkIAEJDCHAJ/zm/3XOTZ3O+fkbufA3O0cktn5KIO8nSOzzMMxelI++kjvnJ5eN/ttGUlPnrolreZpbWx1kY4N0TGlOzJsyYdsjVu3T52iPxywB5bVBvREttVJfv5Sj7Z+69Lb+saOlLMuP+nYFvlNt7E7+Vp7Eo9crWfisx3iMxSHfLW57pNG/eEfvaS3Mu1xZIe24dnWM7JtfSNPeuxnm3j0DLWP6HM7/74lK1nZBmwDtgHbgG3ANmAbsA1c5Taw0Yh/54gsHv/TkwsWYvvXn79ePP32Mx27+eHRl24sbv3l5jIDswUeeeba8pip7aQzoo9u9jed7s7335OHd8azTyF1n+Pbn50srj13xG4fWFyOWQzrQt5FXyfXpqM/36b/7q/fnLKnlR86nqof8mPpnDtY1xkax6/8uy+iczaXRY3lR2Aun6WyZmcd/0Z8o0O4Yl/nNC/zsV+ZLxMmdqh/zhFi5J8b0r7bepJ/Dv9q67btY66tyklAAhKQgAQkIAEJSEACV4fARp/zw6HJp9Zwjr5465ONSOF40nHAXw04RXGWcEZxoAhxTKvsrvvdqOtKZwMOVgIOPbZ0o7x9FGl0chxC+NkL9zo4wnmbOu2DzxT/bWyqeeiMotMo7YZ2RNx5Bdo3a18MhX3wH9JrnAQkIAEJSEACEpCABCQggXUENnL81ylbl86I5rfvHy8dsyF5RmkZieeb7t0057063jid6MaBJaC/DbVzgw6A22+cTNrb5r+oxz98dM8hrZ0s29i6C585/LexKXn6Uf9X7436xwGvo/eRy7bO9kjcLlva99HzR4uTxfen1OyL/ynFRkhAAhKQgAQkIAEJSEACElhDYKOp/mt0rU3G6We0H+dzKDDlPK8S8Ek3nP86DZ08ca6G8q+LY0SWLxIkXHv2/jR/bBqyKw5k8rDFgc2sgBp/kfdx2GF3/Q/3ZlNga6bFTznHqdNcPnAZYzPFP+XsumWEnzbEKxvtaH9tO9Sd9rVpmKpf2nfbZiljV/6b2qm8BCQgAQlIQAISkIAEJCCBEDjXEf9MwX7ugxdTfr/Nd9uZps071gQcpbzv/8/F/feuM507rwsgE719xol/6KaM5M3x4r3F4tbrX/dfLKjZ0T3HKa55LvI+Mx3otEj9sTWvbsyxuz1vm/IJ75SfY/jv65WKjPpTn/bc1baD7fztc9Q/7ZA2tnjzPtEw3pX/fY3uSUACEpCABCQgAQlIQAISmE/goU6UVc0NEjgYAozK06nQOv4HU0ErIgEJSEACEpCABCQgAQlIYAMC5zrVfwO7FJXAVgS2Wcl/q4LMJAEJSEACEpCABCQgAQlI4JIQONep/peEiWZeQgIs1Jh39jO1/hJWQ5MlIAEJSEACEpCABCQgAQnsncClHvFnwbmxheT2TuoCKWTxOOo9tBjhBTJz76ZkUcUssFfrzxoBOPz8XVU+eweuQglIQAISkIAEJCABCUjgIAhs5fgzupoV4Q+CgpW4FARYHA/HPotBXgqjNVICEpCABCQgAQlIQAISkMADJrCR44/Dzygrn8TjM3eMrF62DgBGi4c+t/aAz8NGxbNoHQ4wXz4wnCYgn9NMjJGABCQgAQlIQAISkIAEri7dRZA/AABAAElEQVSBjRz/b9497j959907xz0xvpWe/TkIW6ebTgM6ExKSnqncbOt0buTqdO/6TXrSMsW75ieeQDnEE/jcWmTaTgBsSlrk+0zdP2ypaey39iEbG5NvzhY7yBc7c1zLiN7Y0OolvuareZFdl47MVBnr8s/lQzlDAdspo/4NyY3FTdlO2lAnFXGkEVK/6B9rnzlHyNf2m3xT27Z9pezkGatDzmvKzjE2DLXB6HMrAQlIQAISkIAEJCABCUgAAnzOb/Zf57jc7ZyPu52DcrdzOGbno4zOSbnbOSzLPNGV8knnL8cpZ+q4yrf2YCNlJD/b1oaahmzVxzE6IjOVNzJsyVP11LSxfbhEf+ygPjBo6xDZVhf5+QuH9hytS295xY6Usy4/6fX8Jt/cbeyOfGtP4pGr9Ux8tkN8huKQrzbXfdKoP/yjl/RWpj2O7NA2PNt6Rratb+RJj/1sE4+eofYRfW7n39dkJSvbgG3ANmAbsA3YBmwDtoFDbgMbjfh3jsbi8T89uWAhtX/9+evF028/07HZb+D76wm3Xv968cgz15YjmqzaTrkJpNfQTn2//dnJ4tpzR1Vkcv/Rl24sbv3l5lKG2QyUn/Cfz28vmOWwLuRd9HVybTr68+357/76zVZT+eEXDtiR/ZQ1ls65pa51BsfxK//us3XOZrIvxvIjMJfPUlmz09q66flr1K0cwhX7Oqd5Gc9+Zb5MmNih/jlHiJF/bkj7autJ/jn8q63bto+5tionAQlIQAISkIAEJCABCRwOgY0+54fDwrvlBJyfL9765NxI4BgRfvjoZLLMbtR0xVnHQZobcHzp2OCvBsqm7jjS7HejvH0yuukEOYTwsxfudZAMOaVz67cPPrucv3V20mnEax7p0MARrx1J6/Lvmk77Ym2MobAP/kN6jZOABCQgAQlIQAISkIAEJLCR479vXOtG46szFMd/ygacRkaJcUAJ3TToKfFTaYyofvv+8dIxPCXQRdTODzoAbr9xMik/pOMixqVDJZ0c29q4C59dz986m/tR/1fvjfrHAa+j923+de2zlV93TPs6ev5ocbL4/pTovvifUmyEBCQgAQlIQAISkIAEJHDlCWw01X9XWnF80MM0a6but+Gx399YRvWLB/44Yo9DSf7HX7s/1f65D15cyrLDiCpfHEi49uzpaf7Vhshli9PPaP9QJwNxQ/FxIKODLQ5sZgXU+Iu8H751wcRMi59yjlOnuXzgMsZmzvlLedtuGeHnHNO22tH+2jbG2ue6cqfql/ZVX52Ivl35R49bCUhAAhKQgAQkIAEJSEACLYFzHfHPVGscL96l529oVDWOIY5YnUrPSD5p1+/c6zDge+7V+ef9a6ZyZ6p+jhfvLZZ6qg3AwIZM/c626kQm341v48k7xylGx2UI8KXTIvywOa92zLF/Vz45Xyk/x/X8zbFjSiaj/si05662jan2OaV/Ki3tiza6ePO+ZBjvyv++RvckIAEJSEACEpCABCQgAQncJ/BQt8uq5Rci4NTj7LUO2YUwTiMOhoDt7GBOpRWRgAQkIAEJSEACEpCABGYQONep/jPsUUQCZ0pgm5X8z9QglUtAAhKQgAQkIAEJSEACEjhjAuc61f+M66J6CYwSYKHHrCmRqfWjwiZIQAISkIAEJCABCUhAAhI4IAJnPtWfRd9YnX+T6fvkYbGzfYaz0Dll31h5Y/FTumrarvmjC0e4rp+QeLcSkIAEJCABCUhAAhKQgAQkcFgEtp7qz8rkvCudld/HsLBKPIuZ4bDODazczyJzNWSlfMqsf/WTfZQxtGI6euh8aHVW/XU/das2U0/KnRuefvuZU7aglwXwxmysulNelcUe8tc61zztPvKVVd3/5t3jteeu1eexBCQgAQlIQAISkIAEJCABCVw+AqdG/OuU6KnqfNd9Zo8RYxzTqdF8nG1WK28D+egQYMX8Orof5zbyrOyf/KThUOcYW2+9/vVK/tjPdO5qG/t8Qz0rq0f/0HZIL3JtPHX78uXP+/Jbu1u92BPbalpb/5oWnZma3pZfZbMfrhyHHQ6/iyaGkFsJSEACEpCABCQgAQlIQAJXi8Apx3+s+mMOfJUfcmz5LFo+z1Zl03HAyHZ1xms56KvT0VvHtz2O/uhky+cC82530rMdcoZxtplxQLlDI/w403xvnoDTzoyGan9013oQhy0nH58sO0nauiXf2Ba76isT6INrOgWG8qUToMqkM2Go7kM6jJOABCQgAQlIQAISkIAEJCCBy01g1PGP85zqtY5s4se2OJh1dB65dTpwhq89e7R0rHFOmRVA5wEOPNPTmV2AHM58Og+GbMDp/eGjk+VsgHbEf8yW2MA33etMBuS/ff940MlP+XGqc5wt9Xjs9zcGOyAyKo/sWH7SkLv92clSB0zocKBe1U5k0ynAfhtS3lC+VtZjCUhAAhKQgAQkIAEJSEACEjgMAne7apz660a773bO4TK+c3yX+8h3DvLdzlFdiYse8rXypA3FJQ+6ar7Idk5sX1bSOE5a8g5tkavx5K9xQzqQSTk1b+pKWuqMLhhVOdKQJS76OU5ctklDBzqrjqF98s2RG8obW3bJP6bX+NPXjUxkYhuwDdgGbAO2AduAbcA2YBuwDVy0NjC6uB8jw3UkmentTH3PH6PvTIkfCozSM2LeObZLefK1OojrnOVeBe/5U15ksmU6O+/xE9oR986BXubvBX781zm5/bT6lbju/X6m2tdA2diYwKh8rTPxpDO7INPsmdrfOeJ9ljqFPjqGtrG/ptVya/wm+9Q/trT5qFvOFesQpF41fh82tOV6LAEJSEACEpCABCQgAQlIQAIXi8BP55qTKeJVPs5k4nC4cfqZgk9gKnp9/x1HNQvzJU+7TTmRjXOKU37705PemSUPTi3v2PcO+YffL9VgwxOvPtUvuodMDeh+5M377+fzKgKdCel8qOsJkC9l106Q+spB1c0+nRd0iKRctkzzJz5lJA9coj9xyZfjdgvbGlJ/dNcFEmFHxwkBGeqZY+pChwV5+EJAPT9Vt/sSkIAEJCABCUhAAhKQgAQkcBgEZjv+66qLw41zjlM5Ngq9TgfpGelnP44wI/VZvR9HNZ0COK84+V+8de+rAcQTeBceR7iOyCcPtsXBn+qEQD4zDB596Uavl3849kMzAyLAugK8f08eZj3grH/81t+SPLmt9kYQe+nw6B309xZL25N+Ujo9Epd6kRcOHFMfRv7pKCG0fJLXrQQkIAEJSEACEpCABCQgAQkcFoHRqf6bVpPR/zjUm+aNPI48swVwgDMyjRPNZ/gYtaYjgL90DhCHM0unAwEHF2e7DTjAyBFw3NuR9laeY3QNjYZjCwGdQwGbkg8mjPhTHo42fNinQ4GAXDtroupEdun0dwnkp/5wWhdiX7bIYwOdFuG4TofpEpCABCQgAQlIQAISkIAEJHD5CayM+DMqnCnhVA0HsYb2mDQc9IwwV9k5+3VUHXlGo4feh//undXV9MlXy6yj3jjmfBkgAccXZx+nl4CjffTGUe+4b9JRETYZlecYHjlGd2tXyjtZ3HsVgQ4KXhWgjmGZ1fmRrQG7q9OfNMqjHGY1jNmPbjochjoVyHNz8VXfeTAll/LcSkACEpCABCQgAQlIQAISkMDlJrDi+FdnetdqMbI89E56HF708/45i+UR8qrAzbe+6o+xJc42jv/cwCg68ilnyAFGhtH0yFTnvS2H0XU6Q7A1nQfIYB864uxjf2YVVB048CwOSKifH0yZ5MdedMceZIfsJp5A2ZQX+dgWXtGN7bzHT6CDpgbKowxeTTBIQAISkIAEJCABCUhAAhKQwOESeKirGp+TM0hAAhKQgAQkIAEJSEACEpCABCRwgAT29o7/RWXDqDej45sERvKHwlj8kGyN2zZfdGybf9t8KdetBCQgAQlIQAISkIAEJCABCVx+ApfW8c9U93XOLa8S8MrBnAXxcjpZkb/VS/7H//TkqfjkmdryVQKm4bdhkw6JofzETdULe+vifpRPvTYpt7XZYwlIQAISkIAEJCABCUhAAhK4XARW3vG/CKbXd+Kn7Mnq/+ucWJz4vPNe9ZGPDoG8H1/T2G/XFXj8taf6d+JZPJC8Qwvn4VTjbA8F7M07+Uknrv8cYffOPmGq7kP5sR27hhb5QxcLB9LpMFTukP2xy60EJCABCUhAAhKQgAQkIAEJHA6Bvb3jnxHyfMpu34gY3V63+OCQ44zzO+SM40jjMGM3NqcjoLU7zjMOf+pGOUMr7rd5GY3n8358YpD8OOFVTyuf46kOhMhMfU2hdobUjgUYYotOfyi6lYAEJCABCUhAAhKQgAQkcDUIsLjfXv46h/VuN7p8l+2uOlsdndO6kc7O6b7b5mmPx2ykDuQnHTs6R/9U2akrsp2jPZie8khPfZIv+odsQKbq5Dj5ka/62vykVXspBxtrndo8Hu+n/ctRjrYB24BtwDZgG7AN2AZsA7YB28BFbAN7nerPiDh/jIh3jmY/1Tyj5F3lNwqM0jNCPjY6TRm3Xv965RN7KaBzflem0Cd+zpa8BD6Dx6wARvb5HN/1O/c+yVd1DL1C0DnafV5mCmSGAp/MSz3Cg5kAfCaQMPS6Qf8pxDdraYuVmQtDZSPNZxTr1H/WOEg9KDM2rWr2SAISkIAEJCABCUhAAhKQgAQOlcDKVH+c6XxzPhXOlHiO16UnT7aRxwmOw5u0ddtutHzFSaUjoQa+Qd86uUlHlnSm1Q9N848c29bpxuZrzx4tvnz5836afnWU6RSIA4/cN+8eL4/j8GcKPvbHsScu+ym7LTfx0ZPjqe2Y80+esOf8cU6RHdK9zbmZssk0CUhAAhKQgAQkIAEJSEACErh4BE5NU+9M3Cmuczp3nvKfafKxpT1OfN0yzZ0p7ZTPfk1jf52OzjHu8yHHPnnYZh+90YnMUBk1Pfvttupv04aOx6b6t/EcU3/+Yhtb7E4d0F/rQZ6aNlS+cbtdD/KTn23ANmAbsA3YBmwDtgHbgG3ANvAg28Bep/p3TmQ/ws4ocp1u3lXwzEPn4PYzABjZ7hzbrcpbrpD/6v3sdz680+ujPozwo5tXDG5/dn/6/n3p1T1mHswNnfPdvyIwJd/OXoAzgbwJmQWAnf3rAl0Co/711QJkv/njvdkKm87ESDluJSABCUhAAhKQgAQkIAEJSOByENib44/TT4jjed7VZwp+puFvUzbOMw79WKBjgXf1v1kcL3hvfko2OsZYdCP+EVlu6WBAnnLisC8TB3Zw5lun/fjDfy8l6ai4ufhqQVm1E4Z60gmwC6tlIe5IQAISkIAEJCABCUhAAhKQwIUnsDfHv3VCt6k5Tmp9F74dMW+PKSPv1G9b3rfvH/cONI73WKiO88mH3y+O3jgaXFSw5qceQ/Yig81j5eGQf/zW36qq/pODRGzKmPLbzoefvXDUz1ZYKcADCUhAAhKQgAQkIAEJSEACEjhYAntz/PdBqC6kt6s+Fv5rR85ZUK864xwzej8WmC7fLnYY2TrtPgv15VWHyIxta6dAXTyxla8dISxWuC60swWq09/We50u0yUgAQlIQAISkIAEJCABCUjgMAisrOp/GFWyFhKQgAQkIAEJSEACEpCABCQgAQmEwE+yc5m2vKdeF7TbxvasSVDzopNR87lhVxvmlnMocsxgYOZB/uR3KGfWelwlAtwjuYbP+/p9kPcP6jqnvut+P4Z+d3ZtO9vonFufXW0zvwQkIAEJSEACF4fApXT8eU/9uQ9ePPUgxgNQndI+hfnRl270C9+1MrweMOcBj7KGbGj1eXyfAK9y8PoBr0Y8qMDrG+l4GHNeajrOxqZhXX7aFzLrnIShcqv97G8Sal7K38ZhqDo2LR9bd80fp3OIXeWe/U1srLaN8akyQ7qn7EvalG2RGarfHH7r7EPHLu2P/A8qrLt/hGvdDp2jOfajo/4O8MUX7vfrAgvAknfs/PGKWNW7Tt/c9Dn3qdamtj5pe3PLVE4CEpCABCQggctHYPlt+s70S7HfPcyd+k49tncPP7Ps7x5wVr5l3z2oLfXN1UGeMV7dg93dqfSxfPuIr3XZRt+u+eeUGT5s58jvS6ZzdFfaCMe0peiPXbSPxG2ynZufNrYN59Z+9BA318Zar7m2Vt27lr9LfvLCjPM1lx18ap1rXYb2q+wQnyn7t7GPepAPW+bknyo/Our9a6x9ED+X4RCnqbiz0lvLzLlhW+Pb/U3Pf81fOdIuqNfQ3zob0Fllql7ia1otf2q/ttPIDempZUWOOhCPfL33kY7etEeOSR/SG11uL8fzkufJ82QbsA3YBmwDaQPntrhf90DRlbn5yvR9ph//dQ8t/R6r4mfxPhbH++bd436EpS6al3xDq/4/8epTiywk2D3sLG795ebg5+26B5+VT+FFZ/fg1I9ax57EZ0uZ/HUPTaOr90e2btHHIn7ULYsKtov/wbEuLJgF/LA1efpFDd+8pxl9cz7dNzc/da9fXkj5qce69MgNbeHVjkJl4cQh+RqXvJzLfP0grKqNtz87qdlW9hnVg/ccXisZfzyYkx+b+JIEM042DZz3usjjv/78db+AZeq7Tl+tF1+VoI0ePX+0OFl8vy5rn75r+bvkp46p5/U7j621l+sazrXO6zJV2SE+U/Zvah+2wD9hTv6p8tGzLh2Zde2vXr9cC9xTcv3UNHQlnv259w9kp0Ku2cjUMhI3Z7vN+ad+XFO1HXBf4fei3ldyr2lta/lwfvmdae9p9XcjMnPqhMySz4/39+RDT70vE4/NyOe6IS42UwdCazNxtCMC9xoWv62fie0T/CcBCUhAAhKQwKUlMDlq0tVqb+ndQ0g/asJ2W70ZlUBH97C51BOdpEd34nLMlrjuwWs5soGOxBFf/1JWmx/57sFpWQ7pyKZs0roHqpX0qmNsP2VHD3LE5Th2Jj/HbTlVPnKbbKfyUxZlRl9rz7r05IMP5bQMp8pO3qlt9MIr+0NlpJyWHcfkJT1/bf6p8tflR1fKjOyUvpqW+gzFbWJjzR8ONW5sf9fyd81f7ZpjNzI1zzb7tZxN7K/5xsod0hfZofxD8oljm/3oYJs4tjmean/cC5OOPMdDHHON1LKyP2R70tZt2/vJ0P0NHW29hvQO2T0k18aRD/1wyBYZWHBM3SujNj/HNR/HVT77uUcN5Z+KI19Nxy7+atzUfs4d9WzzkVbv71N6TNvfc5EsZWkbsA3YBmwD59UGzvUdf0YeGHG49txR/x5k95DR1XOzwOhLRjAY6Seg57t3jvsRdka7uweY/i9yKaF7IOt3GcmKPDpiF7YxcsKWP0Z+qo7Ye/LxST+K0z08Ld8Xp1xG6hOmRpYjM7RtR+ixJ4FRYkZxEqhDO8qTtH1vYUdZlJkQNvBel548U1vqyvndNjBKCx/OxdNvP9PvE1dDePazImpCt0/9iM/5R1c7WtdkWTlclx+bvnz585U8cw9Y16INqdtQWivbHncOSM+njm62MvV4qIxNyt81f7Vl3T7XaZ0ZsU5+KL3lsy/7O2erv2fQrjZZ62Jd+evSqeO69sfoPiPeCbdev7+fuLPc7uv+tsv559pPu6aumRl283df9fy4x8OI8zgWmPnDdU4bym9GKzv3uluXj3OGbUMBG/ObRzq/V9hPHdP2SM/vGPc+RvtzzLbmHyrDOAlIQAISkIAELg+Blan+PChkuniqUKea75oenTyo3Fx8tVzoCwcrTmRkhrY4mAQeSJahm/JIfh7W6kPK0IMVD748yOWhjYflIbml7m4HnVU3dmJHazMPeHQInGXAseTBLFMxU1ZszPHYdt35G8tHfByL+lBc5delV9mxfc4Ndcn5rW1vLE8bz/nJNPq2TVF/pn8nngdz/vJwjy7OawJysJ7Ldyo/U2Ype4xfyhzbsmhYG7CLMJTWytZj6lw51LSx/aEy2vKn2tec/GNlbxKPTZz/41c+2STbiuwQn33Zn3sfBdLO2/vIiiHlYJvy6/nh/jTV/qpsKfZcd3e9v2HsPs5/WOS+n86/vHbE/b93uLvfsDbAmTQ6lHH+0RFnGll05P5GJ2S997S62mPaJYxqoP1EX41nn84vOiHSMYDD3wbs4z57+9OT5X2xlfFYAhKQgAQkIIHDILDi+NeH0qHq7ZoenXEQeGjJQ0nSprY46V+8de+BPo52ddxxPnmIGXpvmYe1oYesoYemGsfDWR7g6ruOQw54RhnjBE/VZZs0bNnUYavlrDt/Vbbdj+PBQ/GQ87ouvdU3dozuPKByHm6/sdkDKe2C2RY8fNPOavvKA3nK5rzyUJ86ZTZA0jfdTuXHGY1jE72MsN16fl6nV5jTjtPm086SFr1TW5yH9j3mKfmkpYyp8qfa15z8KWuXLY5OHbXeVNcYn7Own/sfs5/mhLnlj52fR9/erf3NsXFXmV3vb5S/6/mHX2Yd5Xcq9UoHQI7zO5EOAe49BOrBtc1vEbMm0oFJOueR+xt5h36Ponto28rTVumcTEcm97F0bid/7hUcD3UcZL0M7o1thzJ5qEtbLvEGCUhAAhKQgAQuJ4HZ7wd21dtJtnvw6d8ZZburru4hZvkeNvvo6x7U+ncw2U7pJ717SBqUia6p/N3D4eC7kOjtHuhW6ojslK6aRt5WHnsSF35jtqML+V34TuVv02JP6rAuPXLYT11rPdivx8gO8Qjf6KpbOJFOXMoIO+Kwr7aN1v7kjx2kk6eWMbW/SX70Vtuid6p+rT0tb3RM5afu6+ozlX9O+anH0HZO/qnyoxOZIXact13qt47PHPtzDobsi/3ZUg905jjbsfqtK39devSzHWp/xNXrY+xcpJ1XfdlHx1Cdkj6mk3TykZ7rL3naba7tVm7O+W911eNaf/aThl31fLJfOSFH2al38iKDbOLZRq7qSzmbbNHd1p9y27gpndgTW2Nb6sJ5iN1TOkzb7ZlIfvKzDdgGbAO2gfNsAysj/l3BZxa6h4hed0Zztymoe0hZTnVkFKWOXHYPPItrz96bus/oM+VlJGSbsrbJkxFPbGFkh+0+Q+rTjjxlxImyYJJ3NTmeO5UYWcJUfkZ+OAd1ZKiez3Xp90oY/9/WC9vriNV4zntTfKl3Zl3An/x93OLelw2wr3ugXWSUC33VfspiBL7aUdOnyidt1/zr9HP+sz4GslwDaRPr8pLOqB4BBgmbtI9dy98lP9dzbXec10X3mk8dkeR1im3X1oDHOj5T9s+xr5Wp569NG6rfVPnYvy4dmanQXh/cV+q1MJU3aVP3j8iMbbGf0JZZ729jeYnf5fx3jvjK70ktB7u4Zj796O+Ds52Q5X5TZ4QRx+9B56D3o/4co4f7J7O25t7XyDcU0F1/DyODHesCv0thDFtCbOP64Xd0k/veuvJMl4AEJCABCUjg4hBYjmx0Jl2a/e5BeWUUhhGKaj8jIsjUuOwPjZaQ1j0QLUdAIju0raM4Q+mJQ46ycuz28rSv9lzRvqb+WnmPL++59tzdO3fcvzrn8krev6bqve6+nrz8ntT7P/GJG/tt2rTtoa/+9tV7FGlVH2WSHvvq72D2SUOmzVv1uO+9zTZgG7AN2AZsA5ezDZzbiH/XQPYeeJf/F3e6kb8utCMUGRFhlJBR4F1HWKrx6HrsvRsrI6c1ve4zItk9RI2OFFVZ9y8ugbZ9XVxLtUwC+yHAu+67zKDYjxUPRku7iB5WdE7xcsYZM2WmQtc5sFwroHOke9HMXOC3qXPCl78fiZ/SRxp56qwX4vh9qfemuk+50c1vEKGmM8Mls1z4jWS2ALM+CLWu0dEn+E8CEpCABCQggUtL4KHOckYFDBKQgAQkcIUJtI5lFqW7wkisugQkIAEJSEACEjgYAhfS8T+LEfKz0DnVCsbKG4uf0lXTds0fXd3UzpUV7xPfbimPMOfd0TavxxKQgAQkIAEJSEACEpCABCTw4An85MGbcNoCPsnEVMMaOGbqYvuHA5uAk8oUy6HAp89anUNyxKGDcuL0ElenZnK8LvBZpdYWjllUqY0f0pXyqiz2kL/WeShv4pBveeWY70xTxrqAw09d5pY5pg/26IhNtV5jeYyXgAQkIAEJSEACEpCABCQggf0QWFkAqFP5QI87x3BlEbXOYVzaQ1o97hzJU4sQEdc5t32ezrlc5mW/c3SXx1P1HNKLfBuPLdhEWms3NtS/5K9x7Cf/kD3RmbS2/MTXLfVMGWHFcWVR5dv9MUZDdqJ/rl5sjyy6YltbvscP9vqTv/xtA7YB24BtwDZgG7AN2AZsA4fXBvY21T+jx/kkU9dYtgqdQ7hcYKhzFlemo3N86/Wvl9PO2+MUiC3YwZbPn2UBo6RnO7ToX+eULphxwAJMncMc0eWWxZSy8BOLHvEJqaE613qQGVtOPj5ZLjLY1m1ZwMgOdjFrIYsUoo+FnupiTW3WztHuP2dXZdDDrIGhupN/qM7E13pzTOg/t1fqRFzsYn9OQG8WlJojr4wEJCABCUhAAhKQgAQkIAEJbEZgb44/xcbp2+Tb4NVcnGG+IRzHGueU71mjDwee6ek4vsjhzE8tPoXT+8NHJ8tOAo75CkCc9NYxjx2xge9Rx8kmDXm+v5z8ka/bONU1jn3q8djvbwx2QFTHdyw/OpBjhe10YoQx9ap2IpvzwH4bUt5QvqG4Nv86DpRNaDm1/Fu9HktAAhKQgAQkIAEJSEACEpDA2RGYNf29K362XOc899PNOydwdp7O6e2ngneOZZ8nW3Sgr3Mc++nhHCdtyqa2bPLXuCEdyKScqpvyYx9b0tDFFPoqRxqyxEU/x4nLNmnooLyqY2iffHPkhvLGlk3yUx51G/oLh7GyqFPlHLnKhjjKCIfIuJ1/jclKVrYB24BtwDZgG7AN2AZsA7YB28DcNvDTTnAZOmdsOaKcyDqqvi49eZgmf3PxVT8yz9TxjE4nfWjLInInH36/eOTNa8vp5uQlMKWeae4ZcX/0pRt9fOc4Lr58+fPlqH4f2f3rnNx+Wn2O2TLaz1T7GjpndGWqPqPy2L549b5U58T2TDLbgONrrx0tbn96MjnN/r6Gbkp893pCG9Cza6D+zALobW6UUTem9BPqd5hr/Nh5yflrVC4POU+0BWZnDE3T5xWE+r3ptCFmK9Aueu7dfn0FYancHQlIQAISkIAEJCABCUhAAhLYK4EVx3+dw7cuPZalgwDHcsgpjdzQNlPRcWpxKuMg45TjbKczgG06BHBEE3D6n3j1qb5DILJJQzcdCwTyslo9nQk4ooTW1pRNvkynr68c9JnKPzov6CBIuWyZ5k98yog4U+GjP3HJl+N2y2sPNaT+6KaMBNjldYnUM8fUBYebPHQM1Cn5sGvLiM52S714laItGznSwou2kI4POgAog3NJ2zBIQAISkIAEJCABCUhAAhKQwPkQWDvVvDNjlkznyG48xb/V3Tm/p6aYd87iyur3nWPb29M5nSvTxYnnr3M2T9mbPENprQ3RQ31IS172sWVKBzaRjzzIUh/yEZ980YccMm359Zg8sSP5a/rUfpWnTGxYV17VR37yELeu3slX8xBXj9EFj2pX8rmdd43JSU62AduAbcA2YBuwDdgGbAO2AdvApm3gJ12GvYTOOe31MJpcR5E3Ud45hv2CfejIyDQjw0zTZ3SeEXH+GL1mSxxT/TuntC+GGQIsyteGztHs5Yif+/16dA3VA1sI6BwK2JR8jHoz+g0bRuSZUcA+swwIyGVkfEgXssxyiD7yU284rQuxL1vksYHR9nBcp4Op/HUmwZB82CetzVOPeV2DQFxC2k2O3UpAAhKQgAQkIAEJSEACEpDAfgmsTPXfRXWc01104BhmWnjV8907q6vpd6PXK++Wr0z17xzz6lji+OLsx4HF0T5646h33Nup/bXMdp8y6XDIe+kc40DnGPnWLuIo72Rx71UEnGReFaCO5CWMvWeP3dXp74W7f5RHOWPv9iOH7jrdPnnZUue8Zz8lRxl0qkwFOiD6tRN+rB/H6dQgP7wypR8Hn7pjPxxSNnEGCUhAAhKQgAQkIAEJSEACEjhbApNTzbuizyW9cwZPTQHvnMd+anjnUK7YQPyUXch3jmX/h94h2c4RXcq06VV/dLU2kAcdkaWcKpP4zoFflsP+UFnJF5vZjtmd/KRHPvkpk7jIEB+Z2JM0ttXmKkue6Kzy0R+d2SKD/FAZ4cy26mI/bNp4j8/nmpOznG0DtgHbgG3ANmAbsA3YBmwDV6MNPPTjie42BglIQAISkIAEJCABCUhAAhKQgAQOjcDe3vE/NDDWRwISkIAEJCABCUhAAhKQgAQkcAgEdPwP4SxaBwlIQAISkIAEJCABCUhAAhKQwAgBHf8RMEZLQAISkIAEJCABCUhAAhKQgAQOgYCO/yGcResgAQlIQAISkIAEJCABCUhAAhIYIaDjPwLGaAlIQAISkIAEJCABCUhAAhKQwCEQ0PE/hLNoHSQgAQlIQAISkIAEJCABCUhAAiMEdPxHwBgtAQlIQAISkIAEJCABCUhAAhI4BAI6/odwFq2DBCQgAQlIQAISkIAEJCABCUhghICO/wgYoyUgAQlIQAISkIAEJCABCUhAAodAQMf/EM6idZCABCQgAQlIQAISkIAEJCABCYwQ0PEfAWO0BCQgAQlIQAISkIAEJCABCUjgEAjo+B/CWbQOEpCABCQgAQlIQAISkIAEJCCBEQI6/iNgjJaABCQgAQlIQAISkIAEJCABCRwCgTNz/B/+9cODfMbiB4UHInfNH5VPvvff2T213VcZVfFZ6Kz63ZeABCQgAQlIQAISkIAEJCABCQwRGHT8j/74X4vn7/zvojqrN974eR83pGQo7um3n1mgpwaOn/vgxVPxVSb7Ka/qwB7yTzntyc8Weeox9PfNu8cLyhgKj7/21OJ/PvnVShLHQ3qqLZRX7a0KfvbC0SmdNd19CUhAAhKQgAQkIAEJSEACEpDAWRG42yle+euc2budE7sSh0wb3znDSznkO8d49C/5W5mhcmJPdOa4LT/xdds53ksbsI80yiS+yo3tp8zYGR3Ik1aPh+whjrzI1zLZ7zoaZtkwZpvxq+1UHvKwDdgGbAO2AduAbcA2YBuwDdgGbAOz2sCqEM4tzivw4vzWLY5vjpEdc2arg4wu5KojnDLmniTKqvnRFwd7TAfyrQx6iKu6av5qd2sjx+SPfHuc+DBhi0x4tdsxG6LH7WrblIc8bAO2AduAbcA2YBuwDdgGbAO2AdvA5m3goR+hdZt7oXNUF9eePVr8689fL07e+j7R/TT1b98/Xhy/8u9lXLvTOcX9VPw2/p//94/FY7+/sbj+28fapMV/Pr+9+OJXn/TxY/lJRO72ZydLHbf+crO3pXOeV+xEtnO4F4//6Ul2T4WUN5QvdX/kmWt9Puz+xZu/XFDWteeOFrweABPkqMt3f/1mcfN3X50qgwj0//DRyeLOh3f6dI6Pnj9a8us6GJb1HlRgpAQkIAEJSEACEpCABCQgAQlIYE8EliPYnXPaj4TXUe+ujOUUf9Iz4j004k4aI9zkiQ6OE5dt0tCBTuSn/sg3R25MB+Wty4/tyMS2bDNqnzSOkzZWHvHI1XTy17g5Omp+96fbiHzkYxuwDdgGbAO2AduAbcA2YBuwDdgGhtvAyuJ+jMrXUf4OWj96zug2i9ORdv0PN5aL63388N8QWRtuvf71KZnOCT4Vt2lE5zwvbWnzMnugm1rf/3358ufLetX4agMj89SP0X7yZcvMgdjfznigfPS1oXPyFycfn6xEM9rfxpG32rCSwQMJSEACEpCABCQgAQlIQAISkMAeCPw0OnBC22nrcUqZHp8OgTrlPXmzxXlmOjyOM4Et0+WJbx1kXhmI/uRPvhy3W6bd1/Dpb/7ed0igO1PqScchz3R9ZPjCQI6pCx0W5OELAe2rC3kVAB28ghAb6RS5/enJSt1S/smH91+JwOl/4tWnFnQ2tPVB9yNv3nuNIHbRmdDaX+vovgQkIAEJSEACEpCABCQgAQlIYFcCK1PSO2X9VPbO8V1OTWefeP6Ysp4p+4mr286J7fORB9nO+e3zEZ980dc51Wun4JMHOcpI/lre1H6Vp0xswKapPNjb/pGHvMkX+4nLPmns81fLbfMMpUXG7fC0FLnIxTZgG7AN2AZsA7YB24BtwDZgG7ANbN8GVqb6dyCXgdHudjScRKasEzoHtt+2/xhdTz5mCTDiz6g5I/LMKGCfUW4CcplJ0OrhGFlG2aOP/Iyidw73kPhKXOzLlkRsYOQeHfy1Ab0s2MeMgMwMYGE/6ky9ki+vARDHyH7XMdCrghmLIrYBG5AjMCOCehkkIAEJSEACEpCABCQgAQlIQALnRWA5kt0V2O/XUWziMpLdOb5LWeLqceTGdBDPyHnnBPej5+Tlr3OClzqTly1yY2ljo+rJj952ZL+tE6P1rVwd2Y88NiAb3WyTVuOyj3xNpx6tLcgQnzxut++5kp3sbAO2AduAbcA2YBuwDdgGbAO2AdvA2jZwWqA6rnGQW+cXsNXJrU4zadGBgxsnf8jZRS66I9c65EMnkfIin/zoIi7ysZ242JM0ttVm9lv7oi/6k3dIV9LY1nLRW9OyD7vYnzi3p9uiTGRiG7AN2AZsA7YB24BtwDZgG7AN2AZ2awMP/Qiw2xgkIAEJSEACEpCABCQgAQlIQAISODQCo+/4H1pFrY8EJCABCUhAAhKQgAQkIAEJSOAqEtDxv4pn3TpLQAISkIAEJCABCUhAAhKQwJUhoON/ZU61FZWABCQgAQlIQAISkIAEJCCBq0hAx/8qnnXrLAEJSEACEpCABCQgAQlIQAJXhoCO/5U51VZUAhKQgAQkIAEJSEACEpCABK4iAR3/q3jWrbMEJCABCUhAAhKQgAQkIAEJXBkCOv5X5lRbUQlIQAISkIAEJCABCUhAAhK4igR0/K/iWbfOEpCABCQgAQlIQAISkIAEJHBlCOj4X5lTbUUlIAEJSEACEpCABCQgAQlI4CoS0PG/imfdOktAAhKQgAQkIAEJSEACEpDAlSGg439lTrUVlYAEJCABCUhAAhKQgAQkIIGrSEDH/yqedessAQlIQAISkIAEJCABCUhAAleGgI7/lTnVVlQCEpCABCQgAQlIQAISkIAEriIBHf+reNatswQkIAEJSEACEpCABCQgAQlcGQI6/lfmVFtRCUhAAhKQgAQkIAEJSEACEriKBHT8r+JZt84SkIAEJCABCUhAAhKQgAQkcGUI6PhfmVNtRSUgAQlIQAISkIAEJCABCUjgKhLQ8b+KZ906S0ACEpCABCQgAQlIQAISkMCVIfDT1PTGGz9fPP6nJ3O4sr31l5v9senyWWkYPx7YPrw+aAreH7w/eH84TcD7o/dH74/+Pvj76O/j6V+HxcLfB38fjl/591DTOLO4hzrNd89Mu4olIAEJSEACEpCABCQgAQlIQAISeKAEHPHv8NvjZo8bV6E98vbID92NvT94f/D+4P3R3wd/H/x9OE3A30d/H/193O330RH/0/cVYyQgAQlIQAISkIAEJCABCUhAAhLYkoCL+20JzmwSkIAEJCABCUhAAhKQgAQkIIHLQEDH/zKcJW2UgAQkIAEJSEACEpCABCQgAQlsSUDHf0twZpOABCQgAQlIQAISkIAEJCABCVwGAjr+l+EsaaMEJCABCUhAAhKQgAQkIAEJSGBLAhfK8X/+zv8ujv74X1tWxWwSOAwCD//64QV/24Ybb/z8VFb0eW2dwmLEBSWwS/tvqzR0PbQyHktAAhKQgAQkcLUIXMXn4gvl+F+t5mZtJTBO4LkPXjzl/LfOUHscbdeeO1o8+d5/57DfXv/DjcUv3vylzv8KFQ8uEgHac5z0x197arSt0rbpJOZvbthEdq5O5SQgAQkcEoH/+eRXy2cH7se5z05tD6n+1uXqEXjs9zeWbX6b2tNxwPUx9jy+jc6zzvPTTQoYenj69Dd/X9z58M4mapSVgAQGCODQXP/tY8sUnH/Cfz6/vfjiV58scN4f/2D1W8ofP/y3pXx2bn96sjj5+CSH/fbRl24s2muVG5XX7gomDx4wAb6Vnm/anrz1fW8NnQH1G+r//L9/LG7+7qs+bW4bzremH3D1LF4CEpDAhSXAcwbOP4Hnje/++s3yXksczyi3Xv965blh7j2Y/AYJXEQC37x7vJNZXCeX6Vl6I8cfMjx01Qeyp99+pndKSKPng1HFGlrHpH2Ii1NT82Q/jlAcljn6uWk98sy1XgUnA0eq2tCWX9NSrlsJPAgCODM3F1/1PYeMeHJMe61OfK4/fmyRqeFUx9ybi/6Hm5vat+8fL7hWc20k39T1Fxm3EjgvAtyzh0LafZtWf2zze9HK5Lh2HiSufbBNvFsJSEACV5EAzj/P2t+9c7y49uMzBs/VX778+YJnidxzed7Is/lV5GSdD5sAzxO09/i7h1TbjR3/Wnkcksf/dM/JJv6Hj05WnGxuFjguGcGJ0z3nZgF0Ri4zsjNHP3kIceZz3Ed2/1J+0jnGRm50BglcFAL0tG/TA5l2TZv+15+/7m9YdBCgj2sw12HqmRtbjt1K4EEToKP2+p17s16yZbS+71DuOrLaUH9L0nFWZXLPz4h/ew1UWfclIAEJXEUCGVRLB+vR80f983xlwcDB7c9OloN7DBqkE6DKuS+Bi0iA5+J24Ct29jNtm+cLrgVeA8Cvbdt5nit4/qiBZ+p2RkxNvyj7Ozn+T7z6VD+imMq0cLhJ8L5xAtONeQBr5ZKebXVcEse2zdfq5+RxshI4Af0J/TEi5SedHs2hUaCku5XAgyBAOz1+5V5nFNcP7ZTAft9ef7xBDY2O4uhzc8NR+ufiHwt+wMlPPK8OVEfpQdTNMiUwRWBoBJ4fWe7rtOU47jyocjwVaPP1nk9HNfkOsQd/ioNpEpCABKYIcE/89KO/97MCv/zo85VZhsnHc8WY4xQZtxK4qATGBnjxN5kRm2eLav/QswLPFTyHZ6Bt8cL9HAw+oA/ftA5a35e4GHsbO/515GXoIa3tVanOCTeNOm15CAH66UkcAo78mH5OBoHembFA+Zyw1tknb9upMKbDeAmcJQGmz3FDoecwHVmM2J+8cO9GwqsAUyHv5TFjgN5KZs3QttGn0z9FzrSLRqA66dzXq6NP217Xs84IFdNTuSYI/KZwHQz14F+0umuPBCQggfMkwHMCzhH3SJyWPFPHhqWj82MEz+IGCVxmArWNz/UDecW2HemvDLiGLvps8o0d/0wFqhXNfno60rPCDaQGHHoe3k4W9xZtqmnZz/QKdEVP0tbpj9zYlvLHenbG8hgvgfMiQPvOj2udtnz0xtGC2TVfvLX6SgrX19A7SDj7hPQ4ckNDLh0A1WGa6ig7r3pbjgRCgM6uTPEnjlEoZrocdw+l3y2O+x/UzICZ6qzlWsLp72X+EO33rgnfTb3Pwz0JSEACQwR+9sJRP3CQtFNrCCXBrQQuKQEGBeITpsNrqio49HmWnpJj9gCzDefonNJzVml7/ZwfI+pxOjD42rOrUzEBzGg7IzlTAYeFqRI8vNUwpZ8HPBz7uuBZVkWPjpRfe3mS5lYCD5oAHV38uLZ/XDO03TY+o/qxm5tMO12Ja42RT2bSkB/HauhTgdHhVgIPigAPmrwKRucXf9zPq3PPPp0AtF86r8bCitM/IETnMjq4HgwSkIAErjoBnhPyfMFzBYFZVelkZc0g7sncn+s9+qpzs/6XmwDP1nlm5pmCZ+ixEL91bDZ6m49rpvrDbfqDPN54xH/KWB6ocDAylT7Hi/fujbQEcH1dAH0Z5ay6cf55gONmlCnK0TemP45TRozIV53/lF/jKDP6a/nuS+BBEKjXQhyYfqp/934y7Z8f44zkY1+9CeUHu9pNOu/sVQcqU5rajrmaz30JnDeBfjZY8xlK2mr98Zxqs8hyb+d+PvQFi/xu8PoZ1xm99/X35bzra3kSkIAELgIBnhM+futv/TM3swAzOMZzAw4Pz+ysGZSQQbl2Vm7S3UrgohOgDfOskEBb5xl6bJSe55P4kMkzteWamprdPpX3PNLudoUc5F93w7rbndyDrNuhnjPrtbjb/eje7RySfguPzkG5S1tmny1pNb1l1t24lvJtWj1GRz12/zDvg5flvNJuq63cu2tcbfNtGtfM2L2e64e/qtt927ptwDZgG1htA3kmyP2S5416D673Up+vV9nZli4Pj/os0Z63PGPnGmjT2+P2GmnTL+LxXkf8uwpeqMB70bwyYJDARSeQ0UrsZIpzHfmvtqdnnrju5tXLbtLrTp6EuvBm4txK4EEQoP3XkX1s4PUWFoNNm63XBG2++2FeGbHf5Dp4EHW0TAlIQAIXmQDPBNxvmV3I/ZVXq5hhWJ9PSCPwLNKuO3SR66ZtV5tAniOgUJ8lWip5xu4GEvrZ62OypPP6OaHOHGj1XcTjhzqjGAk5iMCNKtM5qRA3sTot+iAqaSUkIAEJSEACEpCABCQgAQlIQAIbEDgox3+DeisqAQlIQAISkIAEJCABCUhAAhK4EgT2uqr/lSBmJSUgAQlIQAISkIAEJCABCUhAApeIgI7/JTpZmioBCUhAAhKQgAQkIAEJSEACEtiUgI7/psSUl4AEJCABCUhAAhKQgAQkIAEJXCICOv6X6GRpqgQkIAEJSEACEpCABCQgAQlIYFMCy8/5tSviV0W3/nKzP6wr5pt+n4B8bB+0Bq+PJ+9fFGXP68Prw+vD+4P3R++P5Wdhuevvg78P/j74+3CVfx+OX/n38n54Hjuu6n8elC1DAhKQgAQkIAEJSEACEpCABCTwgAg44t+Bt8fZHmeuv6vc42j9Pf+2f0dkuQ+0wd9Hfx9pE94fvD+09waOvT94f6AdeH/Y/v7giD8tyCABCUhAAhKQgAQkIAEJSEACEpDAXgi4uN9eMKpEAhKQgAQkIAEJSEACEpCABCRwMQno+F/M86JVEpCABCQgAQlIQAISkIAEJCCBvRDQ8d8LRpVIQAISkIAEJCABCUhAAhKQgAQuJgEd/4t5XrRKAhKQgAQkIAEJSEACEpCABCSwFwJn7vg//OuHF0d//K+djL3xxs83zk+5/BkkIAEJSEACEpCABCQgAQlIQAJXmcDWjj/O/PN3/nexzim//ocbi1+8+cudnfD/+eRXa89T28Hw3AcvruSJzSuRHkhAAhKQgAQkIAEJSEACEpCABA6YwE/buj353n8vrv/2sTb61PF3f/1m8fHDf1s7mv/oSzd6uVYBTjgdAp/+5u+LOx/eWUkm7eSt75dxfOPwu3eOl8fZoTPgi199ksM+D50R//n89uLLlz9fYGMb8s1R4qnrrde/PlV+m8djCUhAAhKQgAQkIAEJSEACEpDAZSXwUGf43TnGt072UJ6hTgMc7cf/9OQpcZzym7/7qp8xgGOfwAyCIXmc+UeeuRaxfhsnvuaPANP8H3/tqcW1Z49O5YvMP//vH4uj548WbX7qSll0bBgkIAEJSEACEpCABCQgAQlIQAKXmcCpEf9UBge8dYiTNrbFkb+5+KpPxvF++u1neh3RM9R5kLToPPn4ZMXhpjOBgO45ITMJkKVzoc4IIK119E8W92cWzNGvjAQkIAEJSEACEpCABCQgAQlI4DIRGH3Hn1F3HOWxgEM+tnge+XD6q9M9pqeNr1P8SeO1gzGnv7WBaf6P/f7eqwW8QkDARuL549UC6pVjtkN1wG5H+3t8/pOABCQgAQlIQAISkIAEJCCBS05gdKp/OzqPk1wD0+RxsoeccmQzjX5o2n7VU9/xzxT7mj72qgAyUzbg0DPVH/voILj96cnGMxiqHe5LQAISkIAEJCABCUhAAhKQgAQuI4HZjn/bETBU2UyzZ4r9N+8eryzQh/wcHVVvK48zPzWTYKjjoOob2mftgG1mJgzpMk4CEpCABCQgAQlIQAISkIAEJHDRCIxO9d/UUJz+TLPfNO+QPKP0rMxfA05/G1fTM0Wfafr8MVsAxz77zC5gP68BkD7k9NOB0M5wqOW4LwEJSEACEpCABCQgAQlIQAISuCwERhf327QCvJvfvp+/qY4qzxT9oRH89tN/NU/2mRnw3Acv9odx8llEEH23PzvpV/qnA8AgAQlIQAISkIAEJCABCUhAAhI4dAIrjn/raLej3u0xcHaZKk95375/PPruPaPxceLjqFcb6voA2JJPAWaUn1kDCZlBwKwBPtWH3rFOhKFZANHjVgISkIAEJCABCUhAAhKQgAQkcJkIjL7jv0sl4nCzIn8NOOoZiSee4+t/uLF0/OO41zxTHQt0AsT5x5GvutBROwlYCLDOSKidHNFRy3VfAhKQgAQkIAEJSEACEpCABCRwCATOxPE/BDDWQQISkIAEJCABCUhAAhKQgAQkcAgE9ra43yHAYBYAswTyxywCgwQkIAEJSEACl4MACw3zG37ev98+P1yO9qGVwwS4Zrh2DBKQwOYELtP1o+Nfzm++CsDUf4MELiIBXqNJx9TYw21N52F007AuPw/UyPiQsClZ5acItG2bV782DVVHXjnbRMeu+eN0Dl0b9brK/iY2VtvIP8SnygzpnrIvaVO2RWaofnBeV/66dHRc1vvLuueHcK3boXMEA4MEJCABCcwnkN+m3F+H7q2H/Pszn9Q9ybvd5tz+upNytztBW5e3a/45de0ePO5SDts58sqcX/u5yqy7B/27nSO/bJMcdzey5XHa7bbX19z82HAe1+FVPtdXse613c5ti5VTe33QTomrMlP7u+QnL9cE1+PcawP7ap2nbCOtyg7xmbJ/G/uoB/koe07+qfKjo96/xs4P8XMZrmPWpp+V3lpOzg3bGt/ub3r+2/we+9yxzzZwHtfGPu1Vl+1/qg3U3y/k1v0+Rde2vz+X6frZaMS/q1g/yjfVa9LBXRmR7GD2IXk4+MWbv1zKdA8z9wTW/J+bvztpS93Y24Z16a18Pe5+yFd0o584gwR2JZC2xfWTkGspx2z5HOVYePy1pxbf/fWblUUsx2SH4ufkxya+xMGimwYJ7JNAXXyVL67Qxo6eP5pdxON/enLxrz9/vZRnn7i5YZf8fC6WL8/wGdo5gd89rqNa53X5quwQnyn7N7UPW+o1Pif/VPnoW5eOzLr7S/39rs8E5K1p7W9/ld3m+QP9hNyT0d+WcU9i3v9tzv88zUpJYDcC9Tqqz7e02bT7bGtJeYZJGtuaH9l9XT+1XPclMESg/n6Rvo/fn6FyxuLym9NeA2Py5x0/2SvdGbNM7y7kUz3xxHU3hJVRgeTpLvKVEUriq3zkNtlO5e9uWMsRCnRSPvLRvy49ct2J6vOxTRzbqbKrnPv324ws5rNIu+N6yv5QG0w7pD1XvhyTl/T8tfmrfLu/Lj+6UmZkWx0ezz/fsppmlXY+h1OulyqbuDnXQGS3zV/zzbEbmZpnm/1azib213xj5Q7pi+xQ/iH5xLHNfnSwTRzbHE/dX7oHqeX9B3mOhzjmHljLyv6Q7Ulbt22fJ4aeb9DR1mtI75DdQ3LGTd8j5LM/PrRJ/nI9ttdb4sOca5VrIMfrrq2510/0ud3fub1qLHMPTr3bY+ITl3bNdur3J7rGtrX9c+3Ua2Msz4OK32jEvzNy0X4Wr/aqPPrSjcWtv9xErA/fvXO8eOSZazk802130vqyKDOBUQpC9yDQ9zxiy1h68kxtqesTrz41JWKaBLYmwCge1w8jUk+//Uy/T1wNud6QaQPtm3hGHvlDV/18ZivfHq/Lj01fvvx5m81jCeydQPcD3LffOso9VcjPXjg9MyDXzlBaq2tIZpP8rb6p4+6BoP8dnZJZl9by2Zf93QNLP6rHfWOTtW7Wlb8unfquu7/weeA6o+PW6/dnd6zjtY/0fT3f7OP876M+6pBAS4Dn+9z3uL54JuDZmpD45GH24bXn7t931z0f7+v6SfluJdASGPv9np9T/AAAQABJREFU2sfvT1vW2DG/zd+8e7z8TP2Y3IOM/+k+C+cmwXQK/mrgxtHeNGp69jlp/LjXwNTlOdMnc2LHylmXXssc22fxHurS9ez0InNtG9NnvARaAnRW8QNJSMdVZLg+mB6ceG4w/NEuE2rHG3Jci3OvP3SM5b/+hxt92WPXV8p3K4FdCdCmazufo++Hj06/ApMH1qRN/b5EppbV5q9p2+6jk+v7+JX71+ymuob47Mt+fmtvLu69rsDvHPeD3G+m7Nym/MoXZ5hzPnZ/qbJTdpxl2q7PN9i2j/N/lnVUtwSmCHDv4TpI4Bk4Yd3z8T6un5TlVgJDBMZ+v9b9Pq37/RkqayiOgTc6wOYOWAzpOI+4vTr+VHjTB7ZayXrSavyc/ZxYfliHHh7Wpc8pAxl0M5pK4MHo9hsnsx6M+gz+k8AaAtyA6EmnAwxHpXZ6EUdPYgKj74zMpc1nNkDSN91O5cdZyQ939HKTu/X8PMcgedxKYIoAD5aM6m76w5l7PrO7krft7J36fZmTf8ruuWmso1FHrefmi9wYn7OwH6e/jujFhqHt3PLHzs+jb1/8+8uuzzdw2/X8D7E3TgJnQaC9f3Lv4dkkAw08n7SB+8DY8/E+rp+2PI8lMEag/n6t+33a1+8PM2Ye+/2NUwNyYzY+qPiNp/pPGYrTnxHGMTku/k0WbGr1jOXnxJLGyGQCThSBB8F16ckztsW54q8NJx+fHmlqZTyWwBwCPBRz/eCgMM0WR5+4BNo3N5WEtPXc1LKYWdop7Z88SU++se1Ufn7s8woBW/Ryk5szGjhWnvESqATyIBnHvaZln87WzLhKXLb80NdXsdgnbm6Yk3+q/HXlcF1ee/Zo2TExJD+lfx2fOfYPlTkWx73o9qfzf9/WlT+Vvu7+kt9vHOeETV5jSh7uW1PPH1P85zzfpJyh7ZzzP5TPOAmcF4H6fMH9s47o0/Ff7wfcyxJo23nuSBzb+ny86/VT9bovgXUE2t+vXX5/1pVV03l+p4OMjrKLGvY64h8noP1BxomJ84FzwUghJ4XAyUi+OZCm8vPwAOzoRl96H9lfl47MVGjrhe1TD6lTukyTQCXAjybXBc40geuF9tXHLf7RtzPaLw+m1+/cfx2mtm/aIiPwtZ3W9Fre0P6u+Yd0GieBuQTymhdtPGGT3wd+RxihTn4eWjf5bdklP51s9XeH63bx5r2V8bluCXTU8UCwbVjHZ8r+Ofa1MpVfmzZUv6nyqfO69HVc2vsfzxX1XrcuP+lTzw/r8mM/oS2zPt9M6dj1/E/pNk0C+yCAY5/7J51kdcYhzyZc97nP5XjxXvcc360H0F4X7fPxrtfPPuqnjsMl0P5G1d8var3r788m5Lhu8EW5lub+Pmyif1fZhzoFrMppkIAEDphAfszHqrhJB8GYDuMlIAEJnBcBZkMxKpmOlfMq13IkIAEJSEACl5WAjv9lPXPaLQEJSEACEriiBPLOcR2VvKIorLYEJCABCUhgFoG9TvWfVaJCEpCABCQgAQlIYAMCQ1M5dfo3AKioBCQgAQlceQKO+F/5JiAACUhAAhKQgAQkIAEJSEACEjhkAntd1f+QQVk3CUhAAhKQgAQkIAEJSEACEpDAZSSg438Zz5o2S0ACEpCABCQgAQlIQAISkIAEZhLQ8Z8JSjEJSEACEpCABCQgAQlIQAISkMBlJKDjfxnPmjZLQAISkIAEJCABCUhAAhKQgARmEtDxnwlKMQlIQAISkIAEJCABCUhAAhKQwGUkoON/Gc+aNktAAhKQgAQkIAEJSEACEpCABGYS0PGfCUoxCUhAAhKQgAQkIAEJSEACEpDAZSSg438Zz5o2S0ACEpCABCQgAQlIQAISkIAEZhLQ8Z8JSjEJSEACEpCABCQgAQlIQAISkMBlJKDjfxnPmjZLQAISkIAEJCABCUhAAhKQgARmEtDxnwlKMQlIQAISkIAEJCABCUhAAhKQwGUkoON/Gc+aNktAAhKQgAQkIAEJSEACEpCABGYSmOX433jj5zPVrYqdd77V0j2SgAQkIAEJSEACEpCABCQgAQlI4KdzEfzPJ79afPGrT1bEifvy5c8Xdz68sxKfg8f/9OTi2nNHi5u/+ypRCzoDTj4+WZy89f0yrt159KUbi+/eOe71Pvnef/f5h/IRV/VzTJmbhO/++s2KfZvkVVYCEpCABCQgAQlIQAISkIAEJHDRCTzUGXg3RuJkX//tYzlc2eIgt2mf/ubvi8dfe2rQcUbX7U87B79z8n/x5i9P6aqdASuJ3UGcfeKfv/O/y+R//t8/Fk+8+tTikWeu9XG3/nJzshPh4V8/vGLfUOfFUrk7EpCABCQgAQlIQAISkIAEJCCBAySw4vinfnNGzv/z+e1TMwCS/+iP/5Xd3lHPTAEc73/9+evR0f7q5KMAx57Rf/JjE7MA6Gi49frXi6fffmawfJz95z54cVn+1A4dCVMzD6bymiYBCUhAAhKQgAQkIAEJSEACErgMBEan+lenGKebcPzKv/stjv3R80f9fvuPtMd+f2M5C+DLjz5fjtozQ2DstQD0fPzw3xY47nHq+xH7bup+OgRw/AnouP3ZSb8/9C/T96dG/OmE0OkfomecBCQgAQlIQAISkIAEJCABCRwSgVHHv5+e/+ZqVev78zjpQ6E6/aRf/0P3vn73mgDT/uPQD+VLHPJM5cfZp/MhMwvofPjZC/c6G3DoCWyRT4fEUkf3usL1O/dfWaj76USIrFsJSEACEpCABCQgAQlIQAISkMAhEzg11R9neu5U+THnH2BZLyBrA2Q0v9XNdP7quDMSz2g+awCwn/f50UlHAIFOCToECN++f7xcCLCPaP6lA8HR/QaMhxKQgAQkIAEJSEACEpCABCRwJQiccvyHar1uqn8cd+QyKyCvCmTqP+/lZ5p/XbyPPFnBP2sD1FkDWRfgh49OVvKz0GDteNikw6KtY9XTpnksAQlIQAISkIAEJCABCUhAAhK4zASWU/3nOM5x6lNhRusJ5E2IE41zn9X8GfVnmn8dvf/mj8f9O/bpNCA/6wZwjONfA6P1dABkdJ+0jPhHjk6FlE1cOhzq1wOG4pLfrQQkIAEJSEACEpCABCQgAQlI4BAJnBrxxzmOwz5V4SygNyVDGg57VvXnmE6CoXf903mAA19nBOSdfBYG5H3+rPIfvdg7NI2/zj6gXGYg8CnAagvxBglIQAISkIAEJCABCUhAAhKQwCETWI74p5I40R+/tbpwXzvVP7LrtjjtdRQeeRboG1qRP68BtDrzygDxj759Y/Hly5+viDBL4GTx/UocB8wcyGwC7GAWAXnTkTC34+KUYiMkIAEJSEACEpCABCQgAQlIQAKXiMApx7/azqh6pudnYb2a3u63swWq0x+HmzyM3k8F3t+/ufhqKZK89XOAdB4kPmsE5HiZ8cedakf2sTWzBlp5jyUgAQlIQAISkIAEJCABCUhAAodC4NRU/0OpmPWQgAQkIAEJSEACEpCABCQgAQlIYLH4iRAkIAEJSEACEpCABCQgAQlIQAISOFwCOv6He26tmQQkIAEJSEACEpCABCQgAQlIwBF/24AEJCABCUhAAhKQgAQkIAEJSOCQCTjif8hn17pJQAISkIAEJCABCUhAAhKQwJUnoON/5ZuAACQgAQlIQAISkIAEJCABCUjgkAksP+d3442fLx7/05ODdb31l5t9vOnyGWogtg+vD9qF9wfvD94fThPw/uj90fujvw/+Pvr7ePrXYbHw98Hfh+NX/j3UNM4szs/5nRlaFUtAAhKQgAQkIAEJSEACEpCABB48AUf8u3Ngj5s9blyK9sjbIz90S/b+4P3B+4P3R38f/H3w9+E0AX8f/X3093G330dH/E/fV4yRgAQkIAEJSEACEpCABCQgAQlIYEsCLu63JTizSUACEpCABCQgAQlIQAISkIAELgMBHf/LcJa0UQISkIAEJCABCUhAAhKQgAQksCUBHf8twZlNAhKQgAQkIAEJSEACEpCABCRwGQjo+F+Gs6SNEpCABCQgAQlIQAISkIAEJCCBLQnMcvxvvPHzjdU//OuHF/xdxrAP24eYoffoj/81G8ll5Te7ggpKQAISkIAEJCABCUhAAhKQwJkTmOX4Y8X/fPKrtca0Tu1zH7y4kof05+/870rcvg9SRmvLJuX87IWjBba3jjfO/Fz7H33pxiCzX7z5y1N6h2yjrCEbhmSNk4AEJCABCUhAAhKQgAQkIAEJjBEYdPxbp5lvDH758uendLSdASdvfd87xon/7q/fnMqTb36S8OR7/z3LCT6lZCAiTvljv78xkLpZFDr++X//WNz58E4/Qo+dBJz5jx/+21pl8Lv92cnii1990svSWUAc+v7z+e1+u04J3wymLPK0gQ6JuR0QbV6PJSABCUhAAhKQgAQkIAEJSOBqEXioq+7dWmUcaJzONuCwPvLMtZXoOPF0DLQB5/Tx155aXHv26FS+yOJcHz1/tBjKH5lttjjF6KYjYpMQZ5q64rhf/+1jCzovvnn3uFfDaH0bkI2DnzQ6PhKHw1/rWNPoULj5u6+SbblFho6WdsZEBCiTgMxQx0Dk3EpAAhKQgAQkIAEJSEACEpCABH7aIjj5+GRlVDuj3UMOapuXYxzdOMg4zXGAk1adYOJOFps55+Q5q8AIexz1lJF60yGS9HQoENd2WhBHB0nSmD1w+9OTlRH6dDDQORG5lMfxt+/f62ioswuwi0DZdKo8/fYzOv2B5lYCEpCABCQgAQlIQAISkIAERgmcdvybUXJGvasDWjXRKXDr9a+XDigOLc4+8hnxZ9uOXNcZBZ/+5u/L/FX3g9p/4tWn+s4KHPCM9LP/3TvHfZ3o1Pjn4h+9ea3TT10JMIg8OnDWI1tH/JGtHR+U08d1nS8tM+LRm04HZiQYJCABCUhAAhKQgAQkIAEJSEAC6wisOP44pUPT+TNC3SpjxJrp/BkVH+ogYCo6Diuj3nF+Wz0X5Tij6iv1fXOx4JUG6hHHHnvjgFfbGYVnhkNmSbBI4JBczYPOqhtG2EGZlRedAszGMEhAAhKQgAQkIAEJSEACEpCABDYhsOL412n5KKEjAOczDihOapzbFFId26GOg+t3HutFmTlQR/qTf+gd+aSd95a6fPHWvQX54mjX+uHI04nB6wp1pB47cdZbfsSvdCIQ0YUaR/3zrv7xh/fXSoBVy4uOFgJ2GCQgAQlIQAISkIAEJCABCUhAAnMJsLjfqb9u1Ppu5+ivxHeO/am4obyJ65znu+ThmP3oY9s5v31cZPe5RXfniK/Yvql+7EYPf6kDTNDLdkrfELvIR1eOh7aUAa82Db2xKem71rMtw+PT14JMZGIbsA3YBmwDtgHbgG3ANmAbsA1c5jawMuLfVWQZmL7fOamnpv7PWUWemQF5R513+AnMGkAf76az0v/QawHLwrfY6RzhlRHyfoHBbpr+JjMKan0Z2f/Xn79eTtWnTtjNDIAfPjo5tSjfFiZvnIVzcnPxVf/KQX09YGNFZpCABCQgAQlIQAISkIAEJCCBK0Ng1PGHAFPX48THUe9GnJdw2oX54nzjbCPfjVAvZdlnSjuvCrCOAHrndCIsFazZqa8krBEdTa5T9alLDXRkhAF2X3vtaGPnnzrvI4QbU/75akB9HWEf+tUhAQlIQAISkIAEJCABCUhAAodDYMXxj+NeqxcnPnFxfjmmEyDOf5zams57/fwReD8dhzXOdR1dj45e8AL9413+X9z5ZW9RrRcRmRHBe/jUbZ/ON7oee+/GyloAY1g4P/vuRBkry3gJSEACEpCABCQgAQlIQAISuHwEHupM5l1ygwQkIAEJSEACEpCABCQgAQlIQAIHSOAnB1gnqyQBCUhAAhKQgAQkIAEJSEACEpDAjwR0/G0KEpCABCQgAQlIQAISkIAEJCCBAyag43/AJ9eqSUACEpCABCQgAQlIQAISkIAEdPxtAxKQgAQkIAEJSEACEpCABCQggQMmoON/wCfXqklAAhKQgAQkIAEJSEACEpCABHT8bQMSkIAEJCABCUhAAhKQgAQkIIEDJqDjf8An16pJQAISkIAEJCABCUhAAhKQgAR0/G0DEpCABCQgAQlIQAISkIAEJCCBAyag43/AJ9eqSUACEpCABCQgAQlIQAISkIAEdPxtAxKQgAQkIAEJSEACEpCABCQggQMmoON/wCfXqklAAhKQgAQkIAEJSEACEpCABHT8bQMSkIAEJCABCUhAAhKQgAQkIIEDJqDjf8An16pJQAISkIAEJCABCUhAAhKQgAQ2dvwf/vXD50JtqJyhuHMx5pIU8vyd/10c/fG/Lom1mikBCUhAAhKQgAQkIAEJSEAC50Fg0vFvHUmcyuc+eHFvzmWrv1b4Zy8cLf7nk1/VqMXTbz/Tl/3ke/89aQN2onvq78YbP1/RvY+DtlzsbANxsWsoHXk6OKbYtDo9loAEJCABCUhAAhKQgAQkIAEJjBH46VgC8Z/+5u+9s/3FW5/0Yo/9/sbi44f/NpoFR/b6bx8bTW8T0IUDfrL4vk/C4aVjoQYcYMKtv9zstydvfb/gj7KOnj9aHL/y7z6+/Yf8WBp5v3vnuM2y8zF2ffzWfT7YfvuNk6Ud1PXas0dLhnRsENfaSQeHQQISkIAEJCABCUhAAhKQgAQksA8Cg44/I9e/ePOXS/1xvom4fueeY//dX79Z3PzdV0sZdji+uViNIx4H98uXP1/c+fAOhyuhOr2kp2MBG1rH/tGXbizzUhYyQ44zQo//6cn+b5mh2bn1+tdNzP4P//P57RWl2PTP//vHMu5ff/6651wZUJ9v3z9e1LouM2y4k44YOnCG2G+oTnEJSEACEpCABCQgAQlIQAISuIQEBh1/6jHk2Kd+OKcnH5/kcC/bdrSf8m9/etJPeU8BONK1EyIy5K2ObTvynvztlo6DJ159avHFr+7NaGjTdznGpkeeubYczeeYgG0JP3x0j2HsZ4vDjz27Ov44/fBrO2dStlsJSEACEpCABCQgAQlIQAISuBoERh3/fVe/TuEfGoFuR/txyBmVZzQcZ3/5WkDX4YDznFkJcWxxmmsZc+yn44CZCHG85+RZJ5NRduSoZwJrFrQhnRWknXz4ff9aBfbsGphhwWyC2smwq07zS0ACEpCABCQgAQlIQAISkMDlJHBujn919nHkGb1vR9ozmk8ajmsceZx+HH1mGTD9nzUB6BiojnXtOMiMhDi+647rqdt1FkB93YH6ZK2BjO7XsuhwIJCWKf7pDKhym+zzigb8UvdN8iorAQlIQAISkIAEJCABCUhAAodHYNLxjyPeVpuR8vpeepu+7hhHnpHxNiSekX4c4P+8eq9zANmM7D/xyVN9Nt6Dn3KS+zUK3mxKKMf1XfsqlbUN+o6GMi2/yszdx+m/9ty9kf7YWvVmFgBpj759o381gHUAErDl1vPjixRGrm6pF4swMurfdqxUOfclIAEJSEACEpCABCQgAQlI4OoQuNtVdfnXjULf5a9zUO92jn8fX/eR5bgboV7mqfmH9jsntNc5lFbjUi7ylJ2/Wl7XCXCXv5qv3cc28iR+3XHk9r3F/sqJfeqWctiv6YlnS1qtQ00b26e85IFRLWssj/H3274sZGEbsA3YBmwDtgHbgG3ANmAbsA0cYhv4SVeplcCn5DI6zcg+gWnjjMa3oXM0+yn4bfy2x5RLWYxU1/IY+WaGAVPj+Rxe/WRg5+ieKg5ZRr2xjz9G0dGRYzLwysBQQB8zDLYJnRO/LIOy2pkR2HX7s3sLFpLO/i4zJ6ZszAwJyoGbQQISkIAEJCABCUhAAhKQgASuJoGVqf7dCHHvjE6hwInMZ/b2vbI/Dnd16us6ADjkWYEfG3Bo6RzIO/+xOTqY8h7nF4ccW/PeO8cEtq3jnan+t35973WD6J2zRVerr81X1wBo0+rxNtP0a2cJurbRUW1wXwISkIAEJCABCUhAAhKQgAQuP4GHuiow9Xww0BHAJ+mGQutkDskkDj2sVp+ZBImf2uLcM/sg37pn9DyOfPLh/BNiS46TPneb/HPllZOABCQgAQlIQAISkIAEJCABCVwWApOO/2WphHZKQAISkIAEJCABCUhAAhKQgAQkMEzg1Dv+Q2KZGj+UNhbHiD1/+whD7/HvQ++h6WDGg6wO7axaHwlIQAISkIAEJCABCUhAArsRmOX4UwTT9deF1ul87oMXV7KQvs10fBbq23bBPQxIufvqiFipVHOAndSRvyFmsaVlhZrkq9td6t2Y5qEEJCABCUhAAhKQgAQkIAEJXEECg45/65SyYB3v6LehdWxZPK86vPkqQM3Ht+0TcGrnOuPfvHucbFttsWWTNQa2KSQzI1gzIOsGxHEnDTZ0YoyF5MuWxQ13rfdYWcZLQAISkIAEJCABCUhAAhKQwNUgsLKqP1XGQeXzd4s3VwHghLYL/eHEI19Xso/DG4eezoE2X6+/U8/K+9f/cGNx/OG/VwubeYRTjWOc1fpnZjszsUdfutEvRpgCsjDhzcVXPaNwun7nsYiMbul8+fb93eoGH76S8Olv/n7mnR6jFTFBAhKQgAQkIAEJSEACEpCABB4ogVOOP5+9i/OOZRmxblfUH7MahzWfxGOUvX5SjrR8CjD5TxbfZ7efGt92EiSx/8xf0xlBxwEj6D98dHLKsU0HBk5vDdTn1uubf6qv6hjbb23HLgKdIJvONoBhPQ9jZY7FU8/bn56c+hLCmLzxEpCABCQgAQlIQAISkIAEJHCYBE47/t10/RpwuMcc0NaJZio7zj7yOLuPv/ZUv23f9c+IP+XU0ejaSVBtYNYAo98ZMa9pQ6P9fdndrIWl3S/cz0EHBvpuf7Z/p5i6P/HqU4sv3vqkL5D6E372wtHi5MNVrn3CyD86LejU2DZQP2YbDLHZVqf5JCABCUhAAhKQgAQkIAEJSOByElhx/Iem5TOdH4d+KOCc4txmNsDS0S7CjHTjEDP6POS4F9HB3bwyQOLckXNsakf6q3I6GHCuqW/b2cCshN5572Q2DelUCC/Y0XGSkf85+qgjrwwcv7J5+ehnpgCvZej0z6GtjAQkIAEJSEACEpCABCQggcMn8FBXxbtj1WwdY5zSp99+5pSznPxDHQdJG9vipLbOd5XFQSfQacAMg3QyVJm6jzyvK1THF2eeVwLavNjbjvzHaadTo+qoZczdz2sPbYcIZYzpp47brlsQvdT12rNHk1zn1kE5CUhAAhKQgAQkIAEJSEACErjcBFZG/GtVcEDblfxx+tu4mqd14HHCGb3OCPt37xz377rTgcD0f0bE180C4LWAOM68mz/l/ONoE+Y67EyHZ82BGlJWjdt2n9H3TabswwWHfa79Y3bRwQGntuNmTN54CUhAAhKQgAQkIAEJSEACEjhcAqOOf6attwvWzVmkLo492DLlHgc/I+w4t3McbOSTH12UzWj4mPPfLhxInqmAg10XF0R2bHbAlJ6k0dFR1y+oo/ptWr8AYrdYYZ3xwBcOmIGwj5DzxyyAuo7CPnSrQwISkIAEJCABCUhAAhKQgAQuFwGm+o/+dU783c55XKaznz/Sat7Oue3TOoe9j+8c9LuRyT5p5E98zV/3p2Q657zXQXk1z9g+8pQ/ll7jx+pWZdwfby+ykY1twDZgG7AN2AZsA7YB24BtwDZgG7hYbWDlHf92VLo7WSsj0hzX0DnJy9HkzpFfMGJdp+6TnlBHv4ljND+zCTIiXeXnzghAx5jsUBmxx60EJCABCUhAAhKQgAQkIAEJSOAqEFhx/K9Cha2jBCQgAQlIQAISkIAEJCABCUjgKhH4yUWqLCP+WaBvyi5kkGWWwXmGufZN2YTN6MkfsxJ2Cax3MMYsZU3pn8rf5sPW2M32vPm39ngsAQlIQAISkIAEJCABCUhAAusJjC7utz6rErsQGHs9YROdcby3/QrApvnrVxtw/A0SkIAEJCABCUhAAhKQgAQkcPEJrIz419Hc7DMivM+A3rER6rnl4OjiOM/5wsBcnZdR7vHXnlrwicNtQ5ufc8M6DzUQZ5CABCQgAQlIQAISkIAEJCCBy0tgxfHHmebvu79+s7j1l5v9Pp+FS8jU8XQKsM2ocWTGtnQgxInkU3bRMdQJEFlkasdDO9W8LWsX+6JrXRmRYxs75zKoedt9ym2dbmSII60NKbPt/Kj2s9jiWBjLz+cIkzaWd118bFgnV9M3rX/N674EJCABCUhAAhKQgAQkIAEJTBM49Zm7zqG92zmcp+I7R/xu56ifiu/Uz46b0kFam94eUxY2EN+WOyTbykwdd87nSr1hUMup+scYTeknrXOqV3RGftM6UT66kp8tcdQhcRxX+xMf2TY/suQnX2TH8hPf5k8edIzli0y73bT+bX6P51+DspKVbcA2YBuwDdgGbAO2AduAbeBqtYGVEf/u5E+G/3x+e/HEq09Nyuya2H72jzLnhl3s65zY/vOC371zvCwunybsnNJlHDudY7v45t3jlU8XrghsccDrC9hfR/3ZJ659hx9bCe1o//XfPrb415/vT/0few1gLD86v3z58wV62jqTNjewFsCmaxhsUv+5dignAQlIQAISkIAEJCABCUhAAovFRo4/Dh2OYTea2/91I8MXiuEu9v3shaO+Lq0z3VaQ1xQIrTPeym1zjNPOVPuER1+6seLIJ759N5/4OPM/fHQSsdHtUP4IU39e80g9E38e27n1Pw9bLEMCEpCABCQgAQlIQAISkMChENjI8afSOIZZC4CR4TpCfRGgbGtfHOY40GN1YUbC7c9OBt+7H8szN76OemfEve1giH3rOijGypyTn5kOzDQ4746dOfUfq5fxEpCABCQgAQlIQAISkIAEJDBMYLbjj8MYp7GqOvl4/QhzlcehPHr+3uh6jd91f1f7cKSxrS6Il06N1vlmwcOzcv4z6s0rFXXafviMjdbHftITnvvgxewut2P5lwI/7mTKfxs/55hXIZgVsk1YV/9tdJpHAhKQgAQkIAEJSEACEpDAVSbw01r56qwxms+0c1b4z8r+rSPJlPDWKa76hvZx7JhGnint6Mi79EPym8Ttah+vCuC0xjbKHntXHSZxcD/9zd9PvW+/id1Vth/1fvXeugYt23S8jI32Yz/n8Pqdx3qV2FWZrMtf7aAMzk1lUdPPan+q/mdVpnolIAEJSEACEpCABCQgAQkcMoGHusqxgrvhnAjgfOOMj3UoYAbOe7vIIfFMvWfBvjHHH5mpsGv+qhsb99nh0eoeqn+VcV8CEpCABCQgAQlIQAISkIAE5hFYGfGfl0WpfRDI7ApeL2CkPmFsJf+887+t079rfuxjhsMjz1yLqWeyHav/mRSmUglIQAISkIAEJCABCUhAAleAgCP+F+QkMxrP6xWEqdkAF8TcvZtx1eu/d6AqlIAEJCABCUhAAhKQgAQk8COBC+X4tyPKZzWVPGd/bNo9o+OsQ3DW5ceO89qOvUJwXuVbjgQkIAEJSEACEpCABCQgAQmcP4ELNdU/U97jkJ8/DkuUgAQkIAEJSEACEpCABCQgAQkcFoEVxz/vndcqXsVp56ws//Fbf6sY3JeABCQgAQlIQAISkIAEJCABCVxKAiuOPzWoq6nz3jWdAdX5b6fjJ414PtU39Am6p99+pl/ALlPNH/v9jeX77PVzgXMIjpVP3kzRr3piX+Jqfj5XV0NNI77NO8f+qoO68d5+q6eWWfejn9cMEurrBnPqx+J49RN87eKB0cs279WnjDn619WvLb/WfWgmR8qudqWMmremuy8BCUhAAhKQgAQkIAEJSEACmxHgc379X+d43u2cv+Ux8Z0Tdrdz5vq4uk8a8eRhv3Mil3LsI0s8+jhmH9m2jPYYuc5B7OXYcpy/qfKTL7JsW/lqF+kcx/6aD5uH4olr7a3Hc/XXsup+9Ceu1TeXRysXfa2tOa9Jb/Ntyq+2B3RynHbAcS0/ZQ5tyYPsUJpx968HWcjCNmAbsA3YBmwDtgHbgG3ANmAbmNMGftIJTYbbn50srj13tOicwv5Tbt+9c7yUP37l3/0+I8W3P70nR8S1Z4+WMkfPH/VpiagzCohjRHpOWFc+OtpP3cX26Gf0nVkJCbdev7+fuHXbKfv3pT82YB+fz6PuhHX1e/SlGwtmMbRy0Zdt51gvvnn3eJHzl/g236b8Un700Vbq5/8410+8+lSSR7es9eBo/ygeEyQgAQlIQAISkIAEJCABCWxE4NRU/7HcP3vhnjPfOoeRP/n4ZIHjRyfAt+8f950F7NNpsI2DHb3Zris/cji11dlkuj0hzvMPH51EdK/bs9YfY8fqRzr15jxMBV4jwAFvX8lInjH9c+pH+bxmUF81QC95aTc49Ox3o/l9cZu+5hEb3UpAAhKQgAQkIAEJSEACEpDAfAJrHX9G73Hk4zDHiWuLIB3HjxF+nE/+2Cf/WGdBq2PqeF355MVpZZQ6XwfopspPqbzwaW1nx7r64dD3/Bffj9aNGQussYCucIrwOv2RG9tSPm2lnUlQ5WkLGc2nA+D2GyeT8jWv+xKQgAQkIAEJSEACEpCABCSwOYHJqf44zjjzOHI4bDh21/9wY1lK9w53v8/ocZx7Rns5xlFnBsC+wrryKQdbeeUgob5ykPyPv3Z/qvlzH7wY0Z23+9KPU57AtPjMWCBuqn6k43TDn5kWU+Hm777qO0hw9GuY0j+nfik/swOqbuKG4odmKGBXZgVUHe5LQAISkIAEJCABCUhAAhKQwOYETo349yvKv3lPEY5+RmeJYYQYp6xO5a7p1UnFUSQwAr+vsK58RrOxP/blePHeYoGzS34cyut3HutNYkX5fTr/+9Ifpxf+2J2Q+ozVLyPt9RySt56j6EJvHOysrL9O/7r6pfyWKfoJbTzrEYy9chA73UpAAhKQgAQkIAEJSEACEpDAbgQe6rKzerrhDAgw8s6oPQ7znIDDj/N9WZzhTes3h4EyEpCABCQgAQlIQAISkIAEJLBfApNT/fdb1NXThtO/zxkPF43godfvovHWHglIQAISkIAEJCABCUhAAtsQODXVfxsl5rlHgDUPMg2fmENbtf7Q62c7loAEJCABCUhAAhKQgAQkcKgEmOq/8tdN4V4edwuyLfeRq2ltvrHjbfKM6do0vlugcCubNy1nTP48y+9eFdh7Xc/T/iGGD7r8IZv2Gbdr/Wr+szj/u9a12rerrnX5L2L919l8nnzW2XLW6d2aInc5R/lrf1vOunz1r/7Oy2OYB88rtNHzbp9eH8Pn4yq00/NuaxeF6VX6/ZvL/EHdf+bad9nkNvU/r8K1ODrVv7sgu/O7WDz99jP9auwcd0D6xfPYrgssHJdV//nEHMfnHWLng3pn/kGXvyvvB23/NuXTTruHtuVfdFQWNX2bdrkuP2Ui091warGn9mNb2mfVm/1ch6cydxFt/iGZBxl30e17kGwo+6rxYa0TFhrNYp/75t9e+/n92aScqmPq2hvTuWt+7hlj947cE+p2ExurbegY4lNlhnRP2Ze02LdpfpiuK39dOjq4rrBh3f0X2YsU1l0f4Vq3Q4x3qVPlSzm5R1WdtfwH+ftZbbpM+7TLtm3ynL3ruZxz/V0kTmlbef45a9vatj10/6ttm/11Mtu0/7Oup/pXCfCltE2uLRYhb+XbtpN20sqtlnyxj5Yj+l1l+p7urjL9yDHH3cV5t2vc/TbxHEeWbVe9lb/uBnS3u2CWcezX4za9zb+vY+zF/n3p21TPeZfPuYDtpnaOyZ+3/a0dm5ZPG6NtRg/H6MgxbWEXRnPz5/pYdy7W1Q89Uzra/LvULYz2uW3t26fuIV0Xrf5DNta4s+CzK4Nd89f6je3nOtr3vbleKymjxo3Zk/j2/sH1V3+3Ije23SU/eWFPm5h7DtbdH1o7K4shPlP2b2Mf9SAfdszJP1V+dFDn1Gvs/BA/l2F0zd2eld5afs7Nuutj0/Nfyxjab/lzTHuMbOyq7Shpc7Zz85/l+Ztj53nI5DoPX+o8db6Ri2y1rz1HNa1efzV+bB/5+odNrWxNz35rN/mG8ra6qE+bNzrrNjLE1bZHPHGt3rHyh/LWOPQM6Yv+lNfmSfqcba1X9lO/OfnPWgabdqnfWdu3Tn+Y1i314a/G1f2qE7lcZ5yXtOOhtkrcJqxqmdlPWdWG89hfGfFnNIZPyH3z7vGCXhJGZuiJJDz+2lN9PKP3X778ef/+OvJDn4rLt+i7yvU977z3zl+Ok96B7XWfxb/ozmcFuxvk4KyDDvyyV687iUsbY2u1jThkusawlEs5VY79xKf8pGNHdLNFV8K68pGbyh891CllsF9Dm7+m1f3WfuwkbxuISx3CJzKkpfxwi205Jk/KSj62iQs/jpGtNrBPXA1TiynShll3Ydse5jn5senb94/766ja1e639WvT4YOeMVun8o+1z3XtK4xhmr+UE/vCPOmJb7fJl/NHOnlaGyJHepuGfBva8tP2WjmO09ZSxhz9lV3yV91t+TWNcsIl25Rd5dhP/BCflIsO9msYKz95kOVznimfOs8Jc/NXPpTRhnXprXw93oRfzZf9eq3Ald8yfq/mBn6j/vXnr5fi7Nc1W5YJ/8/e26xYcpz73kubjXb3qKWeCNuwfeDIehE6V2B4L8Bogya6AQ8M72yD0UgXoJExnJnAA92AJgaZfQEHPN9gISzbB1sgmcbQcoOh2gLRb/6y9F/1rKfiK1euVbVq1T+gKr6er/hHZK54IiIzK4k1/HwKld/S+PnWipq5mH5t3R9KvD18WvYvtQ/94K8wwt/Sj5xePTRcH637bxyfcczDG+vy2I60+1xfyCfUrt/L2vH/S/tf1xb6FWSL8sR35fcz2qw0fQYusR91n4VG9cT6U7341M/KQyca6ZF85feJuc653p9/Pva5a+bkj35y+RnqqO+Vtx9vnnxwdc+KdfH6i+WtNF+V0rz+315/sDPfot18gln1iuNvGLgxhuDNuEW9qou8I/KjjFK6pb93/yvJi2Uj879In9O99mlcaWxmfvKRRmNVdPDRfpWTJ61AnWQrVp14yNfub5IvHu4fUb7qo43q58gj3cSHDNhSGp+0h75nvHJNQBPHebQB35RrEtvwffF1we0QQdcLPojsHP29P4T+LGO7YjZ12M7O/tT4uU7lE+Ncr3Ly+a9UNw2Q7cp/pj9WfhoExdXEqRN3bI72ToN0p452Y7tshJY/0UVcRKO4pB9ZkV+0iiVX+ay/xy/7YhspU178kk8eHcrHONuPDGRFGtJRfkxTh3zkkBY/seygvdSTz3Kzfuqhlw6lM2bUiya3jbzsEF3mz3bEfI8fWdIp2sgf06X2xXrsi/mcLvHnNkEje+DPbaUuYi/csi7l1W8xH+WrnLhln+iW2if9uR2SF+1HdmwbNJkvtz/bQz72g/RLH/nY/qhfNLUY2dke+LOMmO/pR1ekr+lulbf4M17Znl699NJu9JTaz/UpurVxqy1ZtmyK5SrLdkYapUWrPLHKRvgj34jd0ESefdJRj2yNclSW7Y98kT6mxRvLlC7xl+hVRqy0ZBCrjFh5XY/EeSz1rm/J1m+E8jEu2R7rW+l8veT7h3hzu1QeY+yI+ZG05NI+pYWd+JGrNgpL1QlT0RBnftGW4h4/sqRTtCU5tTLZJZuQoTQ8qhd/HA/qc2L1E7zQkBcPMXKRFctG08iDFz2RJ9sa65SGJtqCDMpUH2NsX2pjtgvZ2Cu5Wb/KYww9dhFH3khDmrrYN5T15Gf7Sm0c1Y++LE9llJfqsI+2qZ44twEZtb9e+8QnHcorpm3IiHlsUF52wR/LlM+2luxBhuglQ3GuYyzGPpZ+6UG+0sjQdSV55GN7VL42lv3IJq1rBvuwh7xooq5ISzltEy9ptS/GJTlRZikd5Zbqb6JsZ8df35tnxYOVD1YopobNK3iszJFmFYTyqfHz39SIyc7LMIE61ynfipGFjAnYFtleddhBiKuJ5Fll0WkD8uimTCHTs3L54I3dHSNWikQHXkpLBnFN/7w6O+kr8cCXy7P+Hj8ysC+ubMZVX/FDR3j28dN5ZfYyd/W/ZD8ykRX7izRlUd+VlOupSMuqV26vOEr6qYOe/mIFj3FIOstQe6HJgVVoyrXyBj/P84yGHr9WCHvyau0TH7jSj7XQ4o/jk52AuPKescrjC+z4RGMtrBk/khnbtdQ+6c/tkGzF0w1/Pp3ELmMMmS+3nx2VuOObd1KkXzLz9dPDT3y9/ovXk8YzvD39kn+MGJsZS7RZQfhyL+/Vi6cVj+LXkqE6xgDXd8RSdaX45bd27/PQaLyU6rKMEs0S/iyvle/dH1q8qsv4HMp+5gP8rnNfXfIuh57+Xj3t6t1/e9e3sDlWfKjrd9/+Zzyew+9nq3/i719pftb6/eH+o/tFa36idzG07KjVaaefeQj3zRh0v4hlMc1JFsaQAnNZymLY9/qLMkhjG/f7+BuoE1Bc39w/cuA34MGPHs4Ywlc6oQBP7fevJx9ecJPvkeduo/qRk+9/lBE0N2Sc5D7qzf8uJdT/j7Svzr2Z8WzNT+DFbo1h8nH+kMdXnv9Avza0rr9D3f9aNjJuo48HFvhwjBn6lt8R5i3QUKaxiEydDtT44pTNxWdXJ3L4PdP4IOYecVfDtc/5MTie/vZywszFweAAAMCgoVocoOGABpDE8HEUpnSx82NDQIYCsiRDZcR0HM6H9MS60TR2xBuW+Ji0vjZNSL7afDEXMRA5yhEDbeYCV9inc2v6kRsHknTEuKV/hD/Kymn4OS7JXwzqP5XV7Oemw81QE37wizci8a+Na/qRi279+MkO6eNHjx9ClYMlf3EsaSxKFljk9kteKa7xP3r38kc431xLMlrtwxba9/Tnvy+xzmUt/irTdxWt8QVO6Nd1ytiPR5HWjp+ebdS37BsZ/4zPOIHLOmvyaTfhm0+vbvSZt9f+Hn6St2//9fRLfi3m+sj359zHNV45XrXx3auvyY3lPfxG7aeP430g6qilS/2ex0RL/wh/TfeS8pH7Q09eCZ9D2c/9Qr+v3Ee4X+p+3LJrH/2xf3CG6fPa+Iy0LTuOWbf2+sW2tf1/Dr+fx+yjm5LN3DcGxkYO3G/i7y99x3yFOTLXC/fyWA//vtefdPP7ufnwMpdtxIn67FeXdmMD1ze/tZpfaQ4EN9chdVyX+fqv/f715CM3OrZcC9H5H9Vfuv8hOwZsefbO17ODSFqhNv+r3XfERzzSvkgf04e6f9XmP1HXsdKHuP/1bMOhj9cEY5QxozKc+29+fDHnn//yYvt7Ab74h/QjCwWz0z/1u3Dv6b1r9TuOfx4UrHAwoQNMbgK62NVILmx+bHVh6KaTL8jsaMLPyiAhXzDzjWcqR5fkzoSD/9RRWS7slDHR5WaEA86iRqSj/ZTpRsaNd2lo6QcvBt7F5upGEuX39Pf4o6xSWv2Vb8SRtmU//fHP9y5v5lrAaPVRPi0R9dTSLf3w0Hf0ET96+YeRMi5YBRZ1+GFAJv1M+9eEFj/Oum5s0sFYfvLm7sS31z5+FFuLKT1+6SbOzlhvfMEDTvrB56bJzVHjZe34QX4MS+1Df+v6QTY3ee5XtFXXsXSOtF+0pXik/S38kLmk/7INI/ozT8zr/hzLRtNyzHQtZb5efaav5Vv4jdhPH3P9tO5LJd3oJcTfnTw+W/pH+Et6l5b17g89eTV8jmE/k+TR34BR/bX+eeWjsftvD59j1q+9frFtbf/f9d/PQ/bPzvX91iEll2Vx7ZUcfKgZG/zexsBvGTzxd4z5K79vz9+86O44Lrn+pBed3MuZN5WcdtFxf/3809/tzK9Kc6DLTYyrk3ejv38l+dJdi0f01+5/NZmxnD46VNinfWt10/a1/k20YfTeLp5D3P8kqxTz24AP8Ojby3dh4L/yu4KfIL+Sa4IFIja3Na9FFnTx+kQOC2DYzHwCfzUuMkl/9DdUdhfia0f9mfTrj6Nz3GS0468FAB154IYUwYsN5gYlOTmmrubciHbpxE26a6uJqqct3CBoSz4VwE05vmxFixPiHYlb+lkk0YptSVZPf4+/JDOWiV8331indMt+aOg32sCpjNyHXCQ6LsOPxnzxSPBg3NLPhY1uJuCMQeRTpoB++lWBC5ygSaVsV/uxER7Vi68Wt/i5FjR2iZHLj2i+Plrtwy4dlavZ0OKHJ7afPuJaU2iNL3QLF9ETa4GH9CHGz772Rf2xzynPgfHBDxw38hha7WcM0Gfgq5Bv9K32j+CH3F7/SXcpbukXPW3QNaiyJXGNX/jomkIm1w+Be3WvfiZs/BvFryFi+6Kh1m8Hk+s8wZZMJgXxURfSlI2GEf6W/p4eMOrdH1rytZBdw2fE/p6NsZ57dfw9jXWldE9/q753/9X4bF3fJZtyWe36EF0L/5HrV3JK8dr+P4ffzxa+JcxyWev3J9PW8vyuYMfSkMeo5gv8RvPbpLxirlN4YmD+yryHayvPXyMd6aXXn/i5VphfwR9/a3X/EF1cOIGO31zZrph2RRmt37+WfOmsxSP6Jb92/4uyudbAOTp2rflf5K2lpV/1ET+V1eJD3L9a8x/pbd3fYt0+8/vR+98+1xf9xbXNuGPeTQxmCvx2UMZ8nJ196HPQ9cn1KBmUaVNDY1pxnFtnWaee39nxl7FcRKyQcPEzOAUo5dzwGADspkZgxbs2Rgf6mLwvDerMll3zRf/e5YmDTEdn025ueATlN59cHqHq2dPTLydwXn367jgVMhlIBOmr6e/xz0Ia/8SfHRr6GSx69iMa/Nj1V3pOfPePG6Pw40Ljb8mqYEs/dcgGIwL2In8u21w+18RFyvjUih90wpY0trMDH9sf66FphbX8rfahF6eKH89a6PHDpzeSkuY6jddRa3wxiYi4wA++8/VCZgqHGD/I0aRpiX20Q/pr1w+yFaDXD4jGd6v90OfxA1/ERPpjGfqgI+TyjN9I/82CKv9a+nUvi9cgYrBBfBWxO8UtfvABU92fYIzXT69+R1Eh08OvwLJTpIVGjS8ql7QfnLhfiZ8f9iXYreFnIhVx1RjnGgFXQu/+MBM1/vXwadk/Yl+mifjlulL7WvppVq++0fS5qnd99/ipb10fPX7sJ+RxrvtTj39N/5/D72cPn9F6Xd/592eU/5B0XBcE7qPRLl3zWVecf+meL5p8jcXrTzSjMbL1e6lTi9w/4twKWbr/lzaCqMcG5vPY3fv9a8lHViuM6O/d/7AvXpv593vt/G9N+2j72vuX+lO/M8pH/6Z1f4t1YMPfkvn92vtfq/8Zr5rrzmNhc3Xqjzlx3MBCDv2ssVuTy/Wk9uVHwms8rXJd39AwFugHrg/Z3eI9Rt32DZCT8Dk9NXh+6+E0yZvfbDg54/MbDacVq7mectGW4ukC2nnbY6ZBDjJzOfkJnPkPGaX6Vhly9+FryVxSd9v6l9haoh21nz6q9V9J7mjZqP5ReUvoNO5q8RJZNdq17VvLX7PrUOU9+441bg5lf5bDGO/d6zJPK9/Dp8Xruvrbko2NsdlnDBz6+t7HhnPhqf1uqvwU2nlqvz/8tjDXztgwhz0l3LJ9++b9+3fY+/S53r/WtivP2eTPatyO+Kdcf+IrXaPIYjxjq+Tepbi44z81YN5JJeZ4iFbKtGLFSmkviLZGF4/QRJreKkykjempA+ZsXgWNNMdM37b+tW0btX+6COad5LgTvFY3/KP6D6GrJGPfcVeSVSpb2761/CWbDll26vbt01ZWjlsnMJbIPEd8lrTftEbg1BA45PV9am27aXuO/ft50+05pr7JqZjF1056MIcFz8mxaD5nf0wbDy3bv3+HRnQzP5Z2qPnJ4a3bX2Lt9MaIxMmpn8l0jZHhZAKnTuZTZt8JYae9Fjj9yi481x87/nFHHvnxVEisq8k7xfKXJqNYsXAwAk0EuAi0AOQf+SZUrqwgwM2Y42WHXjSqqFtczKKWjsHBfJvHsBYbbwYjYASaCPj6bsJz9pW3/fsjZ8Tzp7MfakdpoO9fR4H1Xgo9uOOfV0TiM4qnjvBt/zCcOj62zwgYASNgBIyAETACRsAIGAEjYATuHgLVo/77NoUvAXC0Qi9yKMnR4sA+u39x5xnZ+bhUrD/Gjp1WbdWuXltF59gIGAEjYASMgBEwAkbACBgBI2AEjMBtILDzOT+c2vy31CjeCZDfoJhlsDiwT+CoC58z4qgUfzjd8fM8uR5ayg4dpJ+4tcCxVC/YZ3vjQgPPScX+KdHqWSp0swgS+SOv0pKRaWU75dPLMpR1bASMgBEwAkbACBgBI2AEjIARMAJ3DIFrO/5xF17OIA5uL+Ac4vQT9Kke0nnXHUeT7zm+8vbV99ahI+C0xhcwUJZ1t15mwfO52K+gz09E5xz98TneLB/e2JZ8okCyW7H4S7JbfNTNn3iYvjOZX1IobKI9cupj+ySfdmqRRGXEsX9jOS+pePD7h/NigV5YgU5k1D4tE/mdNgJGwAgYASNgBIyAETACRsAIGIHTRGBnxz+biAPIM/raFc71MY9zKEcX55I0f3IioeWIPw5/yVGl/ptPL7Z88Gbd8PGCORxenFJkST6yCfHFYcgjqE5Ov2zjxEDezWbhgW82QsOiRel0gnbLseHQgTbHUwySz5susScuCIBzXMQQLe0Em6UOO+0GX7VLWEiuYyNgBIyAETACRsAIGAEjYASMgBG4ewg0HX+aww47nzQ4RMCJxrmshejUQlPSjWNMyCcDXn7ruo2SpzqcYZx9hWfTzrpOKagMZ1p8fNaBei0cQKNFA+iwQU6y+InjIkgsH0ln51s82JE/gZgXNqDlsxUsBix1+uGl3eBDuzjtQVpYUO9gBIyAETACRsAIGAEjYASMgBEwAncPga7jf6gmsQvNEf+eI8kOvHbU9fk42YAzigw535Rrx15OsGiJ5bCrDucZp1jy9T1G0UXeXpqTBezA42gfMkTnex+5HM0n1E5p4NSr/cIu6uFUBe1CTu1kRqR32ggYASNgBIyAETACRsAIGAEjYAROG4Frz/hnc3EAcbbXBnbb5XhLFk7okzevvgCAI8ouv3arcfRjYCEg7nqzO47zjuOuBQV24HXcXzv9quO0AG0ZdWgzf7TlmGnsA6/YfmxnkUFtQ3/JPt5rwEIHuPCSxUgPDycVchnlObTepZBpnTcCRsAIGAEjYASMgBEwAkbACBiB00WgueOP44mzPuoot5qp4+/arceRxQmNstH1/PPL5/KRpd1ryZXzq/yjdy932+XYczSdZ+EVSMej/Tj97Pi3dvjjDr6eq5e8GCMjL0SoXqcWlN8n1pF/8eLQoy/aPi+chEcXRAsevASQ+tKjCKJzbASMgBEwAkbACBgBI2AEjIARMALnj8C1HX+cxc2Hlw3H0cZRv6mg5+b1wjrlN59s5pf4sXjAMfVH3766NSnaxyIC7yOAhsCR9biwoLSO+EtIfFM+Cw/ip/16eSC0ON2Rl0WFkd1z6VkS47wjX1ig58+bP13TrzZl2XL+sffZO19v2xH7Fx7aqBMWWYbzRsAIGAEjYASMgBEwAkbACBgBI3D3EXhpasKLu98Mt8AIGAEjYASMgBEwAkbACBgBI2AEjIARKCHQPOpfYnCZETACRsAIGAEjYASMgBEwAkbACBgBI3B3ELDjf3f6ypYaASNgBIyAETACRsAIGAEjYASMgBFYjMC9cvz10j19zi6+KG8xcmYwAkdCgBcyMkZvenz6+jhSh96C2EO/1HPJWFxCOwIN8ta0Zw0v9tU+jdqyHZsPjUNLn+uMgBEwAkbACBgBI9BD4F45/vqyAC/zO0bgKwhaVCDeZ8IYZcTP+Y3au5ZfTmdpshzbpvQSG6NtNXwiTUl2yz7VtWwTTal9YNzT36tHBhN+bKjpgOYUQ+/6EK4xLvXRmrZFfNFTcp6ifhYrloYe/13tv4hD6YseGvslTCOv0sKBmMLfek8AAEAASURBVJeFgttI4IWieVzkflUfZDrkl+6btCfaDU3Mt+x6+ObDzT7jJMoc4c/Xe3wRLLKEf5TrtBEwAkbACBgBI2AEbhIBXu53sL9pQvdimuDsLW8t/0hbpgnjC/QQj9CP0sR2S0cs68mZJrMvpgnm1ibSlPX4VL+GH14wmSbiczxiN/aN0Mm+SFvCp2X/PvbRHvjQP8Lf0i8ZI/0DzbHG8bHkqo+I1Te962Np/0cdpXTGnzzjUbSyK44j1Y3Eo/zH7L8RO9fSgE+p72hXqbymD+wj1vRHjx969Rm06EQ+ZZk3y5cdyIjXbpQDDXnqpUd8tRi7+VN9HlcqVxzbrLJsO+Vqm2iIsUs4Z/uQG+0oYRJlOX24eYmxNJYeAx4DHgMeAx4Dmxc7n/ObJi0bPqHHt+z5ZjyBT+LFT9pNE5ftJ+ao1+f0pknMlid+Mg55I5+8G+WfJlWbf3v9AarnIP3K9+pFV4qnyd3O5/KgiZ/6K/HEsthOdsj4VB67TRebf0SyappP94GXwl9/8eUGLGuf7BOd4jX86JCe+LlEyc7xNInd/P03T4f6Vrw9fFr2L7UPneCvMMLf0o+cXj00XB/g8srbj8leC3F8cm1xnWkMxzoYVU569PqAthVq12+Lp1S3tP91bfGJSo0z2RLb+fwPFyV1c9lr7/9gvh/FcVQlLlSM8Pf6ryB2W6T75/fe+8H2HhXvH6qf74/fcakePOGj/YwJ7gOSI5qtokYCHYyrB+893Nqgewqyf/jR69tyxOT7u0RjDyFiTb8xRluf/+S3Q59E5fr7y0//uPjkCzo///R3871YY0V2EdOPcczEOo2zWKY01y+BMfj1r5/OJwa4T8egMalP2qqOtsTfHcqRA320UXZhByFf05TJDvrl0buPN09/+zeKHYyAETACRsAIGAEjcHQEtjsh06Tx2k4lZdMkcKaZJjlz/WTRNj9NbLb8lEd60S2JW/zowgbJy/b06sU3TcpmO4lVRtzSHelG00vkyaYoW2XZzkijtGiVJ1bZCH/kG7EbmsizTzrqka1Rjsqy/ZEv0se0eGOZ0iX+Er3KiJWWDGKVESuv64FY14142OFTPWXkSzjCVyqHp2S75PfifL2Qj/aIP7dL5TGu2RdpclpyaZ/Swk60yFUbs23CVDTEmV9ySnGPH1nSKdqSnFqZ7JJNyFAaHtWLP44H9Tmx+gleaMiLpxfLftEpjxyVKc72qTzioDLFrTrZLtpoO2m1P8bwiJ6YtkbMKIs6kaN60pk/ylIamaMYZnno4E+yejH8al/mo27Ujp4e13vnymPAY8BjwGPAY8BjYOkYuPaMP7sQcZcn7pqyi8kuh8Kzj59e2wVR3aHjabI360KngnZapgnVvHvDjkytXjytmLayy3aIME2qZ6wili25L7/18Fq1dqNKdZm4RLOEP8tr5afJ687JhBZtrS7jcyj7p8n2/Cwyz9eyUzoaevp79ehhN5UdzlpgJ5dTHApPPrhKq+yY8aGu3337n/HI/YMdb7AirTGqdut+E3fFVcf1TTm7qvzBn5+jFm0p7vH3+q8kM5dx/1Sb2BlXWnTafSdP/2MT9zYCbdf9gp34zDsT7fGPa4Jd+NEADnFXn/7mj4BNjOHJud3aLbmcbiJQxx+76hefXenlelTfEdPGUqBPJYNY/SKZ5ElzPUlnSU6rjN8MZBDHIPxVho544k3lxOCqviOPPE480Dbde6innD/GLrv9yhNHfmQ4GAEjYASMgBEwAkbgWAjsHPXvKWGSysRFRxVFz+RlZJLKRImJVAy1o6aRhrQcr5qeXn2WV8oz2dVEjfps26j9OLUc99bCRElXLvvm06sJsuo0KVRdS79oxEuc+WPdvmlk4kA+/fnv9xUxH3/N+BzKfibpX22+mG1jYo1zONIP++iP+OIY0aba+Iy0ewO3knHt9Yv6tf1PX+gxiNwvjO84LriO+ItOKP2pAD/3Imyq4S5axTV+jly3+k/8dzFmgQF8uB7ywm5sDzjidOO4KlAGxnHBAudYR/FZrNB9k0VX9Dx44+Gl0z/Rwb80yEbZw7jVAg/Os+oZL3Ght3R/jLrj7xb3dtoZHX/GGrpiYLyAWylgB48daGEg4iZ68EAXCy95vIvGsREwAkbACBgBI2AEbgKBRY4/k7w4MV9qYHTKlvLKMWMyWJrk9+pH9SFbEzgmfM9/eTVhG7GfySM7YnnnqKdfbWIiKt68mNHSP8Lfs2Gknolu3LUe4Yk0NXyOYT+TdpyQkTCqv9Y/r3z0eHYaonOBk/LkzbGFhxEb19KsvX7Rv7b/WSDRc+w4anKakM2iILvECpyewOHTNY/9a0KLn8UILYxIx7H7b+f6fkta18W0ITqqtFljm13oeTf/V1eLdqpDK4sfuvfJCujhi3TUkY+05KPjPC/wfnh5ioH7xYMfPdw675JNHPs7liudF1/RofujaBTn+yPXqt45IBotTigfZcUFJurRhbMuh51xOOM3LRArRP7YftXrfSngEe8Nqqd/sl7VOTYCRsAIGAEjYASMwCERuHbUvyUcp5/JCxOgWmAis+/xS2TW+JlYUsfkVEHHT5l89erFU4tpU6ld8ahqjVflODKEOBlUnWIm5XFirnJiHNX4qAHpuEMZaUvpEf6W/pLMWAY+TOD3bV8PnxH7oz29NGN1yRHnnv5WPZN3HCH9MVbZEZTToPGJ46ygXUzlR+La9SHeVv+OXL+SU4rX9j+OGH2Cg4YziTNEmQJtw1FT0LUOdgQcyHj/4fqHR/Xiq8Ut/l7/SWYLX9G04tg+rm8c20MG8NAYjI45OsCp5WRqrMoerlcWX4QveJfukaIXhrSJsY9+yrQoG+0ifei2yw5iOf1xYYn24bjHMRd5Ylptj2Xwth7lUfvVTu4X6g/SjHnqiAmUtfoj6nbaCBgBI2AEjIARMAJrEVi046+JYXZY4o4Qk2s9y4hxTG7EN2Jsi59JErsqTP4VmEgp9OpFV4tzu7C95eRmOfMu11QYHfsl7QcndqjFz8R4CXZr+JnUR1zpQ95szcRVk1McsdZb1zMeOd/Dp2X/iH2ZJuKX60rta+mnLb363N6cB0f6VruAXDd5zGWenG9dH5k257GfkHXG6zfzxPya/sdhBHMcQgLOJNfGXLa5fK9Ixge6eH1zLXKCItof66FvhbX8LdlL6nR9c21Fx3SJjEPQ5mPtUSbXC7vxcvqpY/xw/x099YUMnbhpOcxRb05zz9D1Qh2Y9YIWGEvYMsaoZ9y1xg68pR38iEfNDsa6xqicfGHH/ZPF05bumlyXGwEjYASMgBEwAkZgLQLDbyyeFJnWGHgMHGgMTDuP27fI+9pad2+ZnOnt29RL6VPAF7vo82Pakts+Oa9FfZNzWh178ExOe5EP2yfHuVuPHcigvTVZyMl4iAc92NjCCv5IQ7qEMTKzDegVVi0dkika8RBH3dSjg3JhHu1TmroSr+Q7XncfMH7Gz2PAY8BjwGPAY6A+Bhbt+E9AOhgBI3AgBDjqveYExYHMOAsx3kG97MZ4QoeSyeHc6d/J6dzmdfpiWzAlJmd2m42028IpwUmNyxd8lr8/z8sE2TFHNzv+cecd+doNR2asizpIl3bXJ+d6ezKJtkYajuKPjgNOf3z2q6vTYuiLsskT0BFlxjT46LSMcIv182mF6cQCAayxVaenpgWA7YsEJWMm9D8jYASMgBEwAkbACBwJgZcmueyqOBgBI3BkBLJjwaMILcfnyOZY/A0jgKOIA7jk8aEbNtHqjIARMAJGwAgYASNgBM4UgXvl+MddFvrTOy1nOqrveLOmY8jzM8g3PT59fdzxgWPzjYARMAJGwAicMQJsoBD0zqK70lQv/N+Vnjp/Oxe91f+uw8ExS45i4lAdI3C0lYtbf7pBLdEVZeRjuiNy1vLjdGI/cQ5qV4yX2BhtQ0YJn0hTkt2yT3Wybyk/7e3p79Ujg2O/2FDCkPpTDb3rQ7jGuITxmvZFfNGjI9RRZtTPYsXS0OO/q/23FAfTGwEjYASMgBG4DwiMzA/j/KM2t7nL84Ne+3r1vXHS4+/Vr5WvPr5rc+9eu49R33yB0qRwUf00qb72wqYlMtbyj+iaLtyjvGBpGmxbrKQjlvVsmxzh7YuhoJ2cmmsvpWrJWMMPL9hPF+Ycj9iNfSN0sjnSlvBp2b+PfbQHPvSP8Lf0SwZtVntq/UP5scbxseSqTcTqG+JYntNL+z/z53zGnzzjUXSyK44j1Y3Eo/zH7L8RO02z7DfHeBkvjwGPAY+B+zEGmBfwt7a/4/wQWXn+cej5XW/uRn3+W9vGyN9rX68+yiqle/y9+pLMWNbipw7slvgvUfY9TF/dLDQwBZ6AjKAIYA1Q1UUe1UmeaFrxKL8m5dKRZfbqoZcDkB0blUs2cabJ+lr52o2jxpPxwsGhrEafy9fyS16Wo/IYYxtjIZYtTWd8st5a+zNdTW+WL7oafy7P+nv1yAcT/tANv3Qqphw5/GnMl+qoVzmxaMWruKQj8uV07fqNdLoOWmMfvUv6XzIjj2yRbvK0s5anLtaLbjQe4ccG/mr919JFn4BL7OOIoerVd8SqFx82ik5yRNPS7bqr3zFjYSw8BjwGPAbOcwzoN3pt//L7iizJ0e+u8vwmU6Y8sXSvmR9Inn7r9fue9Wf7xLdvnOXn9vXqpVfzEuUV9/h79ZKzr3zxZz0qd3x1P7h21J/vG/P9Zo7E88ebiacBMmF29dZj1fF256mT5jpeUkY5gRdYiWb0RVYj/OjiG9KSjf6pk2ed/OvVbwkrCd42HW1HT3xrdIWtWsx3si8+u6jWx4rp4p+zEa9vPr3kVV2kz2nR7Muf5fXyjJO1z1hFfA5tP/KQP2pjT3+vHrygab3tfLrRz7Bq/GaMddSeMZjDyPWReXJ++tGa34gu/fH6zbS9/NL+5zriEZvX/vP78/0ErEjHx27oK+43XNPcc8AyvvyQ759zb6Jef+qXnr3U9/h7/TeiA1z4Zj0Yl745T73w5+WOvIlegfFK++gXyYHm0buPReLYCBgBI2AEjIARWIEAv/Vxfqh5RGv+fIj5gUxmLvj884t5LlDzMeL8WHz7xr329ep7env8vfq18nv8rt9F4Jrjn986HSevTMSZlCo8+/jp9pNEKjtWzMDhQkCngpw6nIRevXhaMW3lE2uHCCxCgFW8kbTkvvzWw2vVuiGU6jJxiWYJf5bXyuNAlpzTFk+uy/gcyn5uqDiFLOJEpzLrz/me/l498nDicPpqAaf2r7/4clvNZ89uMhzq+t23/xmPcmrBirTGqHDQ/QbHNweu/+g4wx8/DZfpc77H3+u/LK+U57pQm1jIUVq08bqh/7FJP4q0XfcLHP7MKxmOjYARMAJGwAgYgWUI1OaHh5jfjVrC3JcFfvkvkY/5jTY12CDQfCDS7JPuta9XH3VqgyqW9fh79VHWPvIjv9N9BP61T3JFwSSVXTr+YmDiOjJJ5aLD+Ylh9JNmGjg1Pb36qLOWZsDRFi48QrZt1H6dPChd2DXd2t2P9XIIVNfSL5oWf6zbN41Nl7vav99XxPZkRsTnUPazQ/zV5ovZNvoR5zDqqRm9j/7YPzjDnEapjc9IW7Ph2OVrr1/sW9v/9AXjh5D7hfENhirnOuKP61KB/lSAjnsRNtVwF63iGj+76q3+E79jI2AEjIARMAJG4O4hUJsf9uZ/vfndKBI49nGBP/PFjVfmr9kHyfSj+V77SnKWzFlPUX6pTS67RGCR48+AjRPzpSDGi24prwZWbZLfqx/VhwPBShuBC+/5Ly+2jsiI/Tgq7OouXamT48LpBfHmxYyW/hH+UQxadK+9/4OdXesWbamuhs8x7MfJe/DG9ZMUJbtG9df655WPHs+7t3FRjJv8kzfHFh5KNh26bO31iz1r+58f0Od/uJgXAHH0GdMKLAqyEq7A6Ql29HXNY/+a0OJnMUILI9Jx7P7bub7fklbHRsAIGAEjYASMwDERiPPD3vzvUPM7HPtX33l8bUOj1E5omYNoI6tEM1rWa5/k1Oa3qq/FpyK/Zp/LdxG4dtR/t3o3h9OvHbbdmqsck+uHb445W1dcV6kaPwOLuvi8K04EAUe5V3+loZzCudAKV6QYfUYfHhwZghz3OZP+sZjAXylwI4qPGpCOO5Qlnlg2wt/SH2WV0uDDc9L7tq+Hz4j9JbtqZYxVnqMaDT39rXodT9Lz24xVbtzavdb4xHFWWHJMXTy160P1rf4duX4lpxSv7X9+VOgTnH0ew8DRp0yBtvGjqKBrXT8qLKjF+w/XPzyqF18tbvH3+k8yW/iKphXH9nF9s6LvYASMgBEwAkbACNwcAnl+uGZ+t8Rq5j9sfrAJ1gpr/KiS3Fb7oO/VSyZ2l3yYHn+vfq188TvuI7Box19OTHZYmMRr8s3kmlUqLioCnS2+vjmbeTe5xs/knEEn2cjT7jzpXj00rZDbhe0tJzfL0mMM8aJY0n5wYoda/DgFS7Bbw48TFXGlDzYfbmbHClwJOGLcsPYNPXxa9o/Yl2kifrmu1L6Wftrcq+/hAo707aNvLx934brJY64nY831hf2ErDNevy39a/qfRQMwZzGEwP2Ca2Mu2/xpvs4yPtDF65trkRMU0f5YD30rrOVvyV5Sp+ubRYt44mGJDNMaASNgBIyAETACYwjkOWCcHyJh7fxuzIpLKn735UDH+ZfmpZJF3aFCr329+p4dPf5e/Rr5uW+FI3Ms+S89+fep/qWpsXyuwsEIGIEbRoDdbnZ9fWNaD7yc6ZqkJQsENRlry7GRhY8li4lrdZrfCBgBI2AEjMC5IICTR8CRdDACRmA5Aot2/JeLN4cRMAI1BHD615ygqMm9j+Wn4NjfR9zdZiNgBIyAETACRsAIGIG7gYAd/7vRT7byDBDIx5E4auaj3mfQsW6CETACRsAIGAEjcHQEvNN/dIit4MwRWPRyv9LL75bgw1HX+DKvJby3RcsL6Vo29+pLdiMPLNbiWZJ9ymV6pom2t9p/rvjwg8XOtP5GnP59xtcpj4Fs27m3L7aXfvcx/4jI3UzrqGm2vlae6XIevtZvTKbP+aW89+13J+PlvBEwAkbACBiB+4pA1fFnMoKjFgMv98Jhuy9BE6TaZL1Xf19wGm0nz7Lj/BzyhSWjuu8i3bmPr3Nv310cc+dssxYcY8zC09LApx+zk89Y5uWouXxUNo/9xLDEmedLEUvawcsxMz35iIvSmS7a6LQRMAJGwAgYASNwtxBoHvXnDeI5cDz5mIEJR+sFWL36Q9rGp9eefHAdA+no1YsuxywkfPar/87Fzn+HgPG5BGLf8bVmIN3m9YXuGPIbWXM9tHojLnUl+qWPU+BwzW+EDYZEHaF4TqpO5S1+0dTijD1OF1/CYLGMUGq/vhqSaaWDcj7BOfoCyaxD8iVvbZzbGOVl7Eq6s33w5z6IMmNaOKqMhe2vf/1U2UXxs493+bhW+d3iE0y0o7ZYrH7KyhinsW3kSy/+jDSSoS9llOqgie3GNl0TLFb88KPXt2Mj44it++Ij2xwbASNgBIyAETACp4UAb/W/9jf96L+YJgk75dNuxgvKS/QjZdPEZJaJDNL8SV4sU53okd2rh0b0kX+a3Fyzd5rwzbQtm+GTbSW6XA9WyJWdymOLbJBe2Zflyv5IJ97Yvlo9NLEOeVFHTz66ZJviqD/KKqVps/gUl+ikJ8tu2U4d4y/Lo4w6ytEZx2wer6pXH5Fv9XHWRR6ZahuxdIu21gaNB+lWHhkZB2RRVrKtpz/Xyy5idKFXNpCXjlhGuf4insiotU82i09xqW2ilW7y/MET9ZGnPbV66oR/1id8sw7JKsXCINusfLYv6kdej7+kM5ZF+Vk2dLE+8ikNFrG9wkD1rZg2Ij/yQ6+2ixe7oNOfyolln3CI8mKZeEUPL7aSj/rIo086aF/Mq3yfGH1LZMm+aLvsy7Joa002tNleaEv0EQt4anKxQzKFUUlPlAEPtOiAFtklfTU50uf4+tzJmBgTjwGPAY8Bj4ETHgPlzqlNBCjftzGaNMXJBGWtfNaV6WO95KsMW5ncKK+YMmiVL8Wl9ke6XE8bZBuTONJMpKDLkzrRRnmkZb8mYJqYia5XD33UJTtG+WW/6JfGslt82R6VQyd8VBbjEj6lMniizTFNHe0Hf8mmPtPkvGhLsfDM7RRtbq/oqZf9xCpHTml8QJ/HF2WRTzpjrHqVkccm5Ufa38Kj1T50tHhlg+JS+zI/+nL/gZ9kCFPppr38kYeP+sgvvlKsMRnlZ7psX9Q/wp/l5bzk534TneqVz3G2AXrKMl0pD049rLALmeLPdlKXbezlJSv3NeURX/J5/Il3nzi2Yyk/vMIVDEq4CavYfrWHsvwX6WNdSbbGKHiQhpc2wIdd5EUT2xZpKUe2eElHvUqX5ESZTpfnT8bFuHgMeAx4DHgMnOIYqD7jz/HQb3/77WTzVaDs+ecXVwV7pPIxfo7nHjLo2CMyOab/b68/uPYSPT1rXtM7TZ7mqtx+0dfqaYuOeHKcssYvOaUY+8WHnUqLtlaPTbQ1HkHV20+nyZvY5+OokpnlY39+1nTLOJCQXJHyqboHbzxUdlUMrtg3TVS3ckhHzLcVjcSa8cezvRw/zu1E3Qj+0dbW+KiNr5Z+bFA9aQJjgTERw77tH23fyPiptS/ayZjF9tajNugCRwXay3PWyOde9c2n4/cq3l9C0PUrma046t+HvySb57Vpw+jR/CiDccn45FGFyZGrjtXIozSPFPTu7cccX/R1Plau/tN44dEzsJmc0mvvn1E7RmLuG1wH+wTdS+Nz8mCHTfEPOzliz5/GFP3CcXqV01fYQZ6xS55AXnT5BaDoZ4woIJt7LLrhe/mth/P3raGhTNhBz2MIBNkJ3hefXV0j0in74rU1M/qfETACRsAIGAEjcKcRKD7jr8kCE4T43J8cSyYfmszc6dZXjO89W92rr4g9ajETPkLJKR1VjLNB39PvBCZ+eeLZkzXtQu04m4ecPDLxZ/KsBQ0ckdJ7KHo27lvP+I8T5SjnEPhLXm18tfTDSz0OB38x0KdrxgWyRto3On5q7UPP/Hz9h6R2n02+LNmtz+OTNrK4wnPLf//N7jPY8OMM46TFkGWoDudQOMbFkmhfjRcZJf4R/SxYiF/jfC747l/UT1vzAgE8OILIydfuiP6oK6ePOb6yrlKe3xy9G4XfIO5TEYOR9nEtcN94+vPfl1R0y3Co0fmXn/5xHmdgrH6Kv4vYEvMIxqEmUD7345yb/n033nH8RVO7XtEf+xUMGJ8qw7n/5scXc/75Ly+21z3tZnEBuYyP2emf8KTcwQgYASNgBIyAEbgfCBQdf3avcKiYaOHIybliosvE4dX3H98Jx3/EWcndrIlQbeLVq8/ybiofd8dqto/YAq8mn0wqmTxqYtvjZ6ywyy9nhMnvIQPj8Z/vXe76ywFvLUAd6rSB2sCEn4n1xeYfKtrGh8K/Nb5a+jGEehze0f7aGj+QGG1fb/y02ocZODHoYkcV5zm3JTrhJbPj4pB0iQ7n6KvNF8ruxPG0AG1AL39aBBNxTf8If0u/5GO/2s8Yz+O7pl/8irkOc2jp595+6RD/LbNt88ccX8jGqY3tbd2/ofv809/N44R+ps9a7VMjWHTS75nKRmP04DDrVIsWuuBHf7RfCzgl2diuBQzGV1xc13iLZZLBggELV4++vVy8Eg33WS0ksHjA7/fT316OX/FiX1yUnRfApgUHcAcP7OWayyGfwsj1zhsBI2AEjIARMAJ3B4HiUX8mgJqAMSnA2WGyo2O3HAllEnKMwERERxJL8nv1TL4U4lFclREzAdIEK5aTbu1GjtRneTeVZ2IHNjpyjF4cJ4L6cs5U/jGpzY7SzBuOgpIHtxp27AjG48KtyW/FjG4x45GdWPo2T+Dj2KDteXe3K7zTPpxqdJfG/lr8ZVtr/LX0w6/6Uj9Kfi+OGEbaXvtGx0+rfdKHLpyaGtaiK8WzU/XdzmqpvlaGTpzfkvNT44nla/mzLNqPM1caa5H2UGk9FsW9sRaOOb64lrle49il/Tr+jk15IbG1MFBqA7K5J43cD0v8jN3MS79TTsBJxkb0sPCSaSWTe1O8jzLmlGdhh4VXyiIWpPlto0406FbQaQEWq1iEiryiYaECfsa5ZFCmRT3q4h90DkbACBgBI2AEjMD5IHBtx59JSXSo5snLz2jw5THBOTVNLpgg/uXTP847HYeEA91M+HTMlglN3PXr1WOLHFOcGHaBRoMmS3FCFXl79ZH2NtJM4ugXYYcNTORGQ3Z6wL42eS3JZDIZ+075zSebRf1Qkq0y7GHXn5Bti2MD2/k75K6/xiFt1PFc7BDGa/Hvja+eftXnftTOILb2QsQQ2nj99dqX9ebx02tftI1rUOPnyZu794BId8g094qvf/Z0e/9YKnstf9RH++k3MH32ztUjN3nscY+jX9YG9DGO5YBKHs6f7qHHHF9cy3/e/Gln4SWOPeyJu92yT9ee8q2YRdHSSYgWj+oYu1r4VlmMWaDBgf56+p1ET4sWPuxGJrjDi1MvnFUf5UOn+nnRc3N5Ig8aFlt1Ako8jJseNvzW6/7IowsORsAIGAEjYASMwPkjsH1L8zQR2b7ld2r2XD5NSopvLYZ2miRu324s+tuMsQd797Vh2q1ptqdXv69e8y178+fafj5VvM99fJ17+051XNmuZfeXHl7T4mrzd2JyqJu/Qfrt1H1Mv7GxvPXbiv5oI/ri7x5yuNYiTUxTh3zx1eyFLsqNMpw+7JgynsbTY8BjwGPAY+AmxsB2x3+aLMwvK9Lu0TQZmHeO447PZNA2sAPBjhw7C0t2FLcCTiwxTXBmi2hXKfTqSzwuOzwCjEt2OfNu/+E13azEcx9f596+mx0t1nYKCEyOcfVxonjqSr+PnMbicSjuX9qNlwxON/Dbo3LaNznnO3nK+J0mUKcALycG5tMg3xW2julzGoHTA+hmx18nCWBFfjy5E+ukz7ERMAJGwAgYASNwNxF4aTKbnYGzCEyGWIw4N6fwLDpnZSM0QUZMnByvFGt2I2AEjIARMAJGwAgYASNgBIzA2SNwVo7/sXvLCwvHRtjyjYARMAJGwAgYASNgBIyAETACRuDQCGyP+kfBOuYfy3I6v3gp13O0V0cPvUOb0dk/H3e+a49h7C/9klPHPfc5PRHtQ5qOucqmWH8M++MRWHT2xqnscmwEjIARMAJGwAgYASNgBIyAEThXBIqOP41tOX08q8gng1qB4/bxW8WHcv7jgoL0y7nMTh/1qhNti180pxqzIMPnqIQl/UCZ3rbds7uET+mt4D/86PWmKPQS9D4IEWf75gWk6VNXek4012f7S/ZFx71ULyxkA3GpLNY7bQSMgBEwAkbACBgBI2AEjIARuE8I/EutsezW42iV/nhBEUEv7KrJUDk7uzh9awO7xdiFM49zp78olwULleM0Rid2hD/K6qWRBz564RL0tDNiJhlycpVXDL0caZXVYl4YxefWFEjrJVLYgN6Is2wRPXHEB5xKzjvf62ZBoBTocz6JxRiI7RZt63NZLfvFn+3LixqxHhtjeyWjF4M3WDkYASNgBIyAETACRsAIGAEjYATuAwJ77fgLmFfffzz0Ij2+v7w24GQiB8cvv3k/56WLbxu/9p+XixT78EtOKcbp5/vJ2s2GBicU5xaHWnmcTJxrfR89O7LQ06ZekJMdX1zId6MJ1IEBCyK8kZl2U4dsykYDcl55+/FsL3Ep8Pbor399edrjtbCbDy1tw6F+9O1lP0kWdSP2Q7cksPiQv18Nv5x6cI14LZFtWiNgBIyAETACRsAIGAEjYASMwLkgUHT8cabm5/M/7DfzyY+/vOaIRy6cYXbekUk6O76RtpV+9O6lI7rEkfveez/Y6LNG+/DX7MGZx5HPtuDo0lYFHofA+SZA+8/3LneohQF4sGud5Yg/xi+/9TBm57QWPKi7+O0/5n5AP32HXNKiucZcKOB0xF9++sdCzWURzjuPGmAvCwssMny1+WKHHr045LJBlSP2i7YVx3GpBZZIrzI90vHnzXXnP59yiPxOGwEjYASMgBEwAkbACBgBI2AEzg2B4lF/HDscqNIfAMSj9j3HEscXRxeZtV3kfUDFaWZnl7/4yAGOoco5dh535KOeGn+kKaVnx3OqKDnrOLy0V/r1PWTtdsej+cgGD8pGgnb3I63kxjqwxvkmaIEh8kR8sFMywIMj/q3+ZPEEGgJ06IFPgVMQ1GvcUK7HGKKNopfuWBftE6/oieNRf+xHZynQPyz6cELBwQgYASNgBIyAETACRsAIGAEjcJ8RKDr+LUDkVOJs43hFxy/z4ZTFY+w4uSVnLvOV8nqZoJxFnFrt7kb66BhGp3+UP8oqpZHPgkKpHWDDLrscX8VypnFG5SxrsaK0gFDSKxnig0a76KqjjP7QM/glpzjig33iZREiLlpo1z72b4kmLubwKEY8es/pAeTQZ9LTsz/a19uZh/YQj5GAm4MRMAJGwAgYASNgBIyAETACRuBcEdhx/HFmtVtdi3HkOBLOTiqOY3T0IkizAzo9Ax8dW9I4pSWHNPKW0jiO7OBqF71E0ypbyx9ls6BQcv7Z7cZ51uJE5FFau/48hjC62y9eFhXgUyBNmQJONfqxj1MZOMXR0RZdKcbJ1kIFMQsUONY6NYAc2hxpSDMepAOeuMOuxyvk9PfsL9nVKnv45vXHH0RPH9B+vY9A5cQa57HMaSNgBIyAETACRsAIGAEjYASMwLkisPOMf95hxUHCOY3OO2WRLtYJJO0Sy2lUOTFOKY4/Cws4jksCvF//7OnMu4RPtGv5JYcYWXIgcbJxbtXevDihevjAi2f9lZ4Tg/+Q/+CNh9v2sxAinTi6HJPHWSdgD472XFZ4zn1Q5ZastlCh4/S0i3FBv/JyP4XYxy37RY+9m/BuCRYT4njL9WCrAAYRe9pfGp+id2wEjIARMAJGwAgYASNgBIyAEbgPCLw0NfJFraHs5GbHKTv+mZd6dr7lkOZ65XH+dUw7OsaqP+cY5xgHPWN7zm1224yAETACRsAIGAEjYASMgBEwAkbgdhBoOv4yCWeeI90EdlFLTj2LBOzG3jcnXhiNxpyG4Ln4uIs9yms6I2AEjIARMAJGwAgYASNgBIyAETACSxEYcvyXCjX9dQTiCYd4/P06pUuMgBEwAkbACBgBI2AEjIARMAJGwAgcDoGdl/sdTuwySXonwDKuu0XNOwFw+I/p9HPqgscIeNadP9J68d7dQsvWgoDeIWE0DoeArguuDf7AOIZePbTxOou8o+l9+TUeZDu2HiPsa9+oLceWP2rHoenol31eXHtoO25b3rn2723jetv6Y7/qPkmZgxEwAkbACNwdBHZe7jdiNjf8+AK1Fk9+MVuLlkmTHxNoIdSv++bTi5lIb9Eno7I+992nYAzlwMsHWXS5S0HXGLbfp0dCbqL/+CJJ7XElxkiv/jbHkcaCxsdt2mLd1xFgUXffF9del+aSEgLxsUPqj7mQXtJ/n8s0l7iv84v73PduuxEwAueFAC/3G/6bJp0vpsnNDv206vti2rXvlkkPMjK96hSjA7nKE0+OwbW/aEupPvKfexpcp4nRFjPwoCy2O2PU64fIO5JGfu438VEe9Zd0x3qlcxskrxeDRc2WEm+2nbFFWYn2mGXYXcIGncJEcY1uX/syBlHOqfffqH2tMdFqf8TiNtNcD9i5z3WhcRPjfeTcZvv31Z379ljXN9dkvA/va+858uU+WNJGeOP9jnT8/V8ia1/aNfbvq/NU+LhPxHENFvfl3nEqfWA7xn0VY2WsPAaqY6BaUXR4uNHnH1sm0vEHGbBLZeoEZPCj0fvLesRPedZHXf5Rho4y8d2VmB/XQ9stzDOm+YcbXGO/RMyEr3AlL3mxLPLLySKmPOojH/ux5fBGO0bSrfFX48ce2YtdcZIjnho+NdtrciQvx8Ipl7v/2vcp4VYbX7qm4tgkrfHbq6c/Mk3uI/J5fMAjuh6/2hBtFG+MNRZiW2N9LY1+7GvV93THNuialzx4aYPKI77QRF7qxKe4x59lSI/4e7HkQ1e7LnP/SWYNu5qcqEsy9omRzx+86ndk6y+PgZr90p3raZfqss3Q6vqARvWxH6P+WA6t5BKrr2S3YsYL9T18sYU/aGMbon25Dh2xfaV6yvQHfW389uyXjBYGI/0nObW4JV/2R5rYP8iMdWoT5RHfmm6XX40VY2EsPAY8Bu7wGFjWeaUfL/2I51g/1BkcZPADlMtjnh8lTQpiOWnqSrL1wxfp0VOijTSnltaP8yHtAjP+WjLBCQxFQz72k/o39kvGPOclCzlZP3KivkP2VZQrG3qxbM/tFl8Ln9wW8Uim8r241k+18iivZR902JLt6eUl/9T7b8Q+YRDHr9qnOOOh8hjX+lr458l25CVd4898tetB9+BMn/XkfE1epqvZxxhEhujJg5fypDN+OQ9tTX6Pv6dfdtRi2XIT1/fI9Vqzk3KNJWLRyX7lcyweled2qr42brJ86GmH5Kl/xM9YUFo0xLX+pS7rEF+NR/TShT6NQdLRvl77VC+d5CVLtkmfaHp50REjC5kqy/qyLNGNxiPy0aE+gV5pdPSuH9kb2zBqm+mWzaONl/HyGPAYuK0xsNfL/Xj2WC+qI+ab9Dw3m8umRt16eP6Hi82DNx7euh1LDOBZ3kM/u/joJ69unn9++Q6Ami18ZpB+VHj28dPtZxxVRl9f/Oofym54j8NI4HOQX//66Q6pnhmcJidz+V9/8eXmtf/8fvGlazuMncw0cZnHZIesWP3qO49nG/Q8dSRq4QMmYIFuBdKURbxU14pL/eT+ayG2mcdpb3y1Jayv1fiIz8AukZr5Dn3vWnt9MQaRofDkg6u0yva9P4zwj+iXnFp8U9d36Rqu2RTLuWdMztv8m8VvQPx0LveS7733g0i+k9b4U2G+f6s+jzPRj8T0r/i5Ryo9wtui6d0/+f1A16N3H2/+/pvL3xHSMfTap3rxZHwo33f88huGjchUUN9NixpzUa//xFeKR+TD1+qf3vWDvYw55kuMwfhbVrLJZUbACBgBI3D3EFj8cr+X3zqME82PJD8urZAn8i1a161HgD7B8eYvBiYdh5rgRbk5zeTvs1/991zMZInxwWRJTvi0Y7Fh8hJDfnkftjLBe/rz30ey4fSDH12ObyY9mriJuYcPTtH/+PB/bvmwIzpKknOsuGffsfRKbq//RNeK1/ZfS/ax68D/4rP24lrPhmmXbmexjfF9qLCmf+gXghbrDmXTqJxD6T/V65v7DfddLaqXcOE+CA763cz3vt71f4jxWbLrUGVL7p/gkBf0e+3r4bOmHZoXtX4ne/3X0j8iv8W/5PrhZbhfbb7Yvqiy9TLUlk7XGQEjYASMwOkhsNjxpwk4X4++3XXAKM8OY9w9pl6BH7E8aVHdoWMmetohOLTsuyQPvC8d4r9VzcbJBqvs8FYZFlQgm902nA+F1mQGus8//d38BQkmLUyoNCERfyl+7f0frHK2mXzi3PDlCpy4aG8PH2j/+d7lrr8cwMhfsrdUlie00JxD/5Xamsv27b+l4yvrPUQeGx6++XBzsbka40vk4vSzyx8XupbwL6EtXV9L+O8q7U1d36VruIUZ91z+tONf+33kPqjTYCwAPP/lxfZ+3bs/LR2fS9vQat9IXev+CR4sBoMR7ea37C8//eN8n2YuAia99vXwGbGxRqMFMf1W1eha/VfjoXxUfkvGaJ0W2Jm/3bUv4oy20XRGwAgYgfuKwOKj/kxsOU7GD63+yPMjoTwxZbWAA3gTu/n8gLHKfwxHtta2Q5TjAGhX5xDykMGxXLBAdi3g9LN4o92BGl2rXJOvTMOEmwWjKJvd8bg4RH/F0FoYiHRKI5uFnn2cbckgZnLGpyWxT8c0KR/Bh3aCIUdySS8NXBf5VAMy3H9tJEfGV1vC+lqNjzhmlkjl+oxHxLU7vURGi3bN9cU1wbXNwozC6GddRb8mPqT+m7i+uYb3+Y3jt4rfT8YBvwE6bs29Ld47haUWGMlr/JXoYn1tfMZ7N3pL9yHp3TeOOkoyavdP7n/cj2kb+LA4Rj9qzjHSvh4+JXtyWc1+jc/4+IH6jt+jkf5DF31e+u3vyc925rz4W9evFp0Ye+B61+ZNuc3OGwEjYASMwHUEFu/4rzlGjXp+APd1zuIPIpMSHY2Mq9JMDjYfXjaUH2l+wBwunVmwyBOLuLOkH/o8occJZuIwEpi40Qc6/YFjj1wmP3/e/GneoZEc1SlPn+aTJEv6j0kXO6aHCLSXdoPFs3e+nnc+RvDRrhU27LMAIX4mYdKHLOxx/4FEOYyMrzLn4UrVX/EehPTRMcxiabx2lN98sjnIztva6wtni/uHrlFdH4dDsC3pkPqPeX1z7fLbs8/1LwQYS/whiz+eHc/3Ze6fUYfGX6bT/Vv1tfEZ793I5u/Qu/5RB23NvwG6/1EX2xb7izpC/O0i32uf6mv4IKMXWvYzPllY128fsuK1n/Xm/uvp7skf4a9dv4wxQrS3J8/1RsAIGAEjcDcR2L6FdjK/mZ6c9p231op+2kG4Vl4qg376YWzqkEzH7b4wPqeLzzS5qn6RYrTfkDHt0Ppa6dyTRvE03eGvF+7xt3k/vy39reuba5Z6j7f9x1sLX+O6P64Zu9u6frIdzh+uT42lsfQY8BjojYHho/7s1P/wo9e3q+qT4GLgOOn0wz3vXMVjiPBTznN5DkbgXBE4xG4f2LDzwskYrhkHI3CKCPA4y6FO2OzTvtvQ37q+da1613Sf3rzkaeG7v1RzlhC4jeunZIfLjIARMAJG4OYQeGlSxe6EgxEwAisQYMFLz8R64r8CSLOeLAI4ZfEYcz5qfWzDb1O/r+/j9q7xPS6+SL/N6+f4rbMGI2AEjIARGEFgL8d/OiK28/zdiCLTGIEeAuyY8VxzfLazx3PK9Zxy4blOLwScci9d2dYbf736K0lO3RYCuuakn2fteTb6HILH3zn0ottgBIyAETACRuD2EFj8cj+ZyktsNKFiJZmX/ikPDSv4vImXl/LkoMlZdvKY2Nz0LlK27Rzy4KgQJ74s2MwvdvqusoZ1rX9gk4zcd9J3zDjuCqEnvxgqtlt21Nqo+hxnGVGH2i6etbKRs1RGxkAv7pJNrTi3raR/jfyWbupG9LdkZNti37T4VLdWv+S0Yo2Rfa6P0fa1rs+WbaqLOMT7g+rXxLkNhx6fPdt4HK03Ltbgt6Z92B75l177vbZTH/uWfA8LaByMgBEwAkbACBiB+4PA4hcRTZPbnZf5TY7/9mVmpKfJx5wnPcF47W+a/FwrE11+WdQ0SavSisfxJcZgJexHMIG21Ef0QZajfqXvct2IrhGanlzGneSMtJV2RB7xtmJsaNXHOmhL+IlGNiqf46X2oSteH+Rb11LWl/NZ/6HlZ305n/Xn+pyPfSlsY1mm7+Wz/t74a9WDHfVrro/Yllb7sLtlS63dLZk1niXlhx4/uX9GbBnBZV/81rYv82MHZSPtgmakbdCMyjPd9bmJMTEmHgMeAx4DHgPnPAYW7fhPk4oJi6ug5z3ZVdAngkjraPM3P76YP98Xd/2nic72+8bTRHf+3jnfr1ZghyjqYUeKFwJGGaI913iaEG7ARDiOtpNv9LKLNHpUHmxzoH/43jEnOGLgU0j6HJI+5xXrR9L0dzxxAE+pjWo/9XHHMLaL8YD9D998uLnY/APSnYAu2hF5dggOkCnhF23nWqiFfe1rvUxtFF9squlvya+1ReWH0M/4030FuWCsk0SxL3v9L5tqca390Mc+jONPskr1h7g+RtpXuz5lWwu/pfcHyVQ80r+t8TPCH3UtuX5jn+i3CFl5V72F34h9rfbJ9lrMuOYkiII+Daf7KuW5/5bcHyXXsREwAkbACBgBI2AEaggs3iGYJkg7OxXTZKW4s1qig3Yy5IV2n4jJQ0usumkit82r/L7EtH2fnRv4wBFe/QnfjJ3wj+WUCXfJivVKIzv2l8p7cbYFHRoP8Gab2T2VPSXZLTuoK/H0ymRDSzYySvhle7X7W9K51j7wz9j08I121PSr/SX5kb+UXqufsYD+LKekizJo9xmH4s1y1Xbpz/3Zq5e8NXZJhmyM7cMu9TlxrIO+h5941A5itTXqraUzLfLi9Sub1X7ZKnkj/KJFhtJLYuku8fTwG7EP+dKR21fSqTJk5zapTHrVf+IhH3VIt+jz+IRPNLJRshx7B8tjwGPAY8BjwGPAY2D4c37TYLkWponn/MwiOxZ8GmaabOz8sfMSP+mnXWToeBaT3Qzt5LNzq/DyWw/n3Vrl71vMDmdpp6eHA6cEwBxe/thx5uVyMUyTxbmPKGc3Mwb65JifW1RfSye7Zw/euOp3ytkREx3viKBN00RXLNt4mhDP7Yu7pKqcJsw7O2sqH4mFHXaAJWM8hhZ+vNWfXTwF7C+FNfbplMG8q5mECzcVl/ClrqW/JV9ya/Fa/dwfGLNZTklfq/9L9LGs1f7e+OvVRz1r0qX29a7PHn4j94eWzblfSuOrNX5G+NHf6p+Wfb26Hn4j9rXa19LPb1oO0qc69Z/onn38dL7/KU/cG3+9+1eU5bQRMAJGwAgYASNwvxDYy/HHyefY4qvvPN589R9fzBM1OauaeMjxjI4ZNCwSMHnS8d0Itxw85Mfjj5HG6TYC8Xi5MBSucNJf6iOcfybZBGKO1moyOhce4R8OjRaI9Pm7pWqQga1qX+SnrUyg47iL9aNp+DkmzBiPoYafMP7m04tIfi29xj4WHWi3+g/hYBFDD9+W/hH5UVcpvUY/jmlcKCzJp6zV/zUelbfaL5rbjkvtG7k+R/Dr3R96bW/178j4afGj+1j9M4If+lv2jbQPGaVQui/QVoLq6D9+V3V/1KKt6Epya2W1+1eN3uVGwAgYASNgBIzA+SOw1zP+mjzK8WKyzmSlFERDHRMYJjM4LgQmY+z44kxBx8Tq618/3ax5jnIWfE//aTdqtPn0o3bccZY18RQ/u8pP3vyq6GCLZknMpJq+1aIP/d0K2gmLixHIYFe95tjzHHPcdW/JX1sX8RuVtcY+Fkq4PhQ4ncH1xHUFRiP4tvT35EtvLV6rn/Fbe2eDdPb6X3S1uNX+zFMaf5GmVx9pR9O19o1cnz38lt4fss29/u2Nnx4/+pb0T7avlR/Br2dfr30t/bqHcYJI9648fuif2oJmSXbmL9G4zAgYASNgBIyAETACQmDRjr92Gku7cjhBqifmGDk7pjFw1JLJjXY0qMPpV3j++cV8vDqWqe4+xUxAawspLRxweNkx0g4RCyvgrUln5oUWzAn5xAZ8HCuNCzeZf2mehQXpg/fBj64ff4077Jz8iGNICwWaOGf9tBuZtfpM38ojK0/0M33ED4zBDMdFQTt2yq+1D/kRn0fvXp5GUP/28O3p78lXO2rxWv04PWCaH6+Qvl7/i64W99oPX8Q3j7+R+prukfJW+0auzx5+S+8P2eZe//bGT49/pH+yTaP5Efx69vXa17OF30jGlAJpyhTUf+BQC73xKT5k9O5fonVsBIyAETACRsAI3A8EFu34tyBhws5fDNFpo1w7vaLBwYWHhQImKqThwWE9pMMpfece4/CyQx8dTrBVANfYR2A9inPmnZ8x/3D3revSU4tZSIBPNii/+eRqAYiFAS16MNGOi0BMZAmqJ83EWW3AEV5zWoQxGLFDdlxEyBhk/Bjf2KavHrD4FeWttS/Lp/2xf4VnDd+e/p589LXCWv3qR40t6VIbe/0v+lrcaz98rfHXqs9jQ21gDOf7XtW+zviu8am8h1/v/iA5tbjXv73x0+Mf6Z+abYco79nXa1/PBvqHE1a6f+X7h/ov3jOQGb8s0RqfvftXzz7XGwEjYASMgBEwAueNwEtT83h78qLAjhxHcjVRyXmEzY78tPsZHTdNeKRMExp2utip1QRZk2jVi96xETACRsAIGAEjYASMgBEwAkbACBgBI7AMgUWOvxxyVLA7ot1QHP95hyvpZkcjOv6qzjsTUZZoiLVQ4AWAiIrTRsAIGAEjYASMgBEwAkbACBgBI2AExhFY5PiPizWlETACRsAIGAEjYASMgBEwAkbACBgBI3AKCCx6uV/NYE4CrAm1l3mtkXkfeTkhcdew5DGPls29+lI/Iw8sOFlyn4JeCknbW+2/r/iUxsI+46sk51TLzr19p4q77TICRsAIGAEjYASMwKkhcLCX++F06Bn9JY3ECeExgT9vrh4dWMJv2ruLgBxzPTKSW9Krz/T3Pa/rLz9Kc99xqbX/3MfXubev1q8uvx0EWGzMofa4X6Zz3ggYASNgBIyAETg+AgfZ8cdMPkUUAztNLAaUgiak1PGSQN7aHZ0/6uF3ODwCTM5aO+y9+kNaxKfvnnzwZVVkr77GyFhiTOkzdzW6+1pufC57ft/xtWbc3Ob1he74l+/PsU5p3avJl+iX3qd12kTyiaOOWB7rhHmLXzS1GHnx3oftlClk3eR1mi3TiofyjIvqSnHWIfkl2n3KkB/bGGVk7Eq6s33k1T9RVinNPTf+8UWLr3+9Oy8o8bnMCBgBI2AEjIARuBkEFu/4MxGoBX1GjHpe2PfNpxfzpCE7YEy49WkuPplWk/nkx1/eS+eNiSTflGYStU9gMip8teMSy/SpMfUTjmCvHlr6SZ+8kl2lFy+O2K/JZB4bkpvrmbTy3Ws+10fbsIM8OMkG6ZWMjJ/sFx904iXdq4empaPHT5tan+pCfiuAQX6JZm5ji79lO3Us3ulLHZKDc/DK24/n0zxqnxbpqOPzZHqBp+r51ngef5LXi5EZ7yP5c3i1NoyMj6g7jy/V9fTn+oh/q/0j1xc21NpH3ZLxU2tffJEq9tKe2OexnroffvT69iQX1xpyuWbBm75ZEoRBvObULslp6R/hl5xeTNv4kkzsP3ii/iiDMf7g9w/n+6TGOxjEr9FE+pxW3+l+rHr1k/LHGl+6d0Ts6X+C+p+xFz+PKpv2idHH/UT3in1kmMcIGAEjYASMgBE4PAJ8zm/x3zQJe8EfvNNkZf4jPU1kXkwTim2+JBu+aWJQ1UmdZJf4z71smoDNGC5tJ7jzF7Ht5bOOTB/rJV9l9BG2Kq94xH54GSviyXGup02yjfFGGn7oyEd+0cYy0rJferFT6ZF66KMu2SE9I/Jj34hvNI62wpPtkRzohI/KYlzCp1QGD3Jkc0xTR/vBX7LVftFnftHVYuGZ2yn63F7RUy/7iVWOnNL4gD6PL8oin3TGWPUqI49Nyo+0P2MoXuJW+6hv8UY5pEvty/zoy/0X+06YSjft5U/yqY/82YaY15iM8mM96Wxf1D/Cn+XlvOTnfhOd6pXPcbYBesoyXSkPTj2ssAuZ4s92Updt7OUlK/c15RFf8nn8iXefOLZjH37zLJ+TGTNj5jHgMeAx4DHQGwN7H/XXrsekYCewm88uCrsI08SiekyQnctpclD8y7uaOwruQYZntfNO1Giz847V0l25nh7kK3BMX7uAKiPu2T9Nlmfy0d1+yaYt2kFi56zGL/pSjP3iw06lRVurx2ba+uzjq6Or2iljnCvU+KnHfk4b7BuyrZx+YMf9EAFcsW9yNrbiSEfMtxWNBO1XH0EG/2jgZAE7jrmd8I/gH21tjY/a+GvpxwbVkyYwFhgTMezb/tH2jYyfWvuinYxZbG89aoMucFSgvZzGQD473ZzoGg2P3n08k8ax0eON+vfhL8nnNApt0PswSjS1MsYl45Pfp8mJr47VEj8nYJ5/3sbrmOOLvs7H7tV/Gi9//cWXMzb8Lk+LAKVmDJVx3+A6cDACRsAIGAEjYAROC4Hho/5MDvIxZX7cmSQoMKGKZUwaH7z3cPOXn/7x2mQ+T5Alg5hJKRM0h/NEoPdsda/+NlAZfwQuAABAAElEQVR5+a1LB7vklI7ag7PBdaRrhuujtoBWk8mEPDqb0TGr8YyWM/HHqdGCBo4IZTcVaNfFZ2Xn6BD4qx218dXSDy/13OP4i4E+XTMukDXSvtHxU2sfeuZF1Q9JbYqLi7E+j0/ayOIKx//zO12QhzOsRzzIE7KMy9LNvMAkHONvQUu/eIlxLjP/iH4WLMSvcT4XfPcv6qeteYEAHhbbkJOv3RH9UVdOH3N8ZV2lPIsyn/3q8vEyfoO5T0UMRtrHtcB94+nPf19S4TIjYASMgBEwAkbgFhEYdvyZ9BV3oadJJJM7djOYEMXJwy22y6pvAIERZyWbwcSQUHOUevVZ3k3l4+5YzfYRW+J1xMT6+S8vto52jx+nn11+OSNMxA8ZuHb/+d7lrr8c8NYO7aFOG6gNOBm87PNi8w8VbeND4d8aXy39GEJ96T0IWyNXJEbb1xs/rfZhHk42uljExXnOzm90wkvNiYtD0iU6HOGvNl8ouxPH0wK0Ab38aRFMxDX9I/wt/ZKP/Wo/YzyP75p+8SvmOsyhpZ/fyEuH+G+ZbZs/5vhCNovpsb2t+zd0n3/6u3mc0M/0Wat9agSLTje5WCi9jo2AETACRsAIGIE+Ansf9Uc0jggvC9IRRiYGeSJXM4GdFWhLf/OuS43xHpSD6yiOS+GQc1Pj69XHkxjxKG6U17K/tRuJjF591HOTaSa+YKMjx+jGcSLEyfRcUPjH5Dk7SjNv2uHW9VAQMe8461qjXruXJdp9y5i0s5NK3+YJfBwbtD3v7o7obLUPpxrd8dEJyVyLv+S0xldLP/yqL/Wj5PfiiGGk7bVvdPy02id96OK+XcNadKWYsV5cAC4RhzJ04vzmU2OBpJlcyx+Fq/38zpTGWqQ9VFqPRXFvrIVjji+uZa7XOHZpP48uKOSFxNbCgHhijGzuSSP3w8jntBEwAkbACBgBI3AzCAzv+GdzmMBsj/C/e1XLpJDJfe/twK2dFR/1v8Lz0CkmgEz4dEw291OvHnu0KIETw2LPaNCkk4l3KfTqSzw3WcZOO+Ne2KF7iROUnR6wXzJJ5pqJfaf85pPNon5oYYY97PoTsm1xbGA7f4fc9dfuM23cfHccHTuE8Vr8e+Orp1/1uR/jm9KxtxUihtDF66/Xvqw3j59e+6JdXIMaP0/e/Orazn+kPVSae8XXP3u6vX8slbuWP+qT8w+mz965euQmjz3ucTphE/mXptGn30bdP5ERH4U45vjiWv7z5k87Cy9x7GELCwOPvn2V5Dbo2tsWNBIsipZOQjRYXGUEjIARMAJGwAjcMALbtwhPervpaXI5v1mYWPTT7t/2bc8qm3YPZrppkrN9K3ism5z7Lb/KFVMHv/KO+/1yExiV+nKJXvo0jpvM26vP9M4fZ1ys7edT7ZdzH1/n3r5THVe26zj3IeNqXD0GPAY8BjwGPAYOOwYW7fizU8EOyMguALsztec9p07ceckU+RzYCXE4HwR0pLa229+rPx8kTrslHOHnGs+7/adtdd+6cx9f596+fg+bwggYASNgBIyAETACRqCFwEtTJTvrDkagiwALP61HNLoCTHCyCEy7xdtn9kcW9k62ITbMCBgBI2AEjIARMAJGwAgYgWsI3DnHn+dYa7vG11qXCtgVO/ZOJvbFZ3HXPiOKQ8b3l0fs5vlzPgmlsOTZY/E4NgJGwAgYASNgBIyAETACRsAIGIHzQqB61D/uAJaaXNoVxLGeX45UYqiU5RcMQYZuAo8LSKb08abhV99/3HyZGQ4wb0jWy5JmYd/9o+4QL2uKMktp2VuqGy1jEYEw4vRDF9vF7ryDETACRsAIGAEjYASMgBEwAkbACBiBquPPZ8NKO8044vGTbhFCHNTPfvXfsWj+fBA74LXdZzm3YlIep1+BxQGePZYjj12EkhOPfbw5W85y3oGHLzrF2UEv0ddsR9YxQ/40F3bnhRLKchuOaZNlGwEjYASMgBEwAkbACBgBI2AEjMDdQuBfWuaye49jGf+W7OjjhP/wo9fn58KJ2cmXYy+9+dg+zq6cfugfvvlQpLOjrwwLAezqZ3nQy+nHbgKOMX88n47jrHzJYZ6d7UADffx2u/QvjVmkwOYcKKMuB7XrGj7Td85Vl3mOmV9q/zFtsWwjYASMgBEwAkbACBgBI2AEjIARGEeg6fjjKEcnWc7ziHicdk4G6Pg5TjoOPQsAWkjIDiwLBdrNJx0Du/2SpXLKomOMzmcfX54GIM1OfdSnkwrSrzjagY06WYAevtkumdK7T8wphPj9d8mgjLoc8m6/6nlnAHU3HZbaf9P2WZ8RMAJGwAgYASNgBIyAETACRsAIlBGoHvV/8MbDDX+lHf7STrnE47DDU3v7e3Te2UWOz+J/770fXL6c7sPN/EkxaJGHw67de+khxmmOR98f/Ojh7OjzgjvKWRSQDGzCqUcO9svZjwsHUTZp0ebyffKcQvjne893Hllgt7/06bSWbX/56R/nlwd+/bOxF/7tY2uJZ4n9JX6XGQEjYASMgBEwAkbACBgBI2AEjMDtILDj+OOIx7fC10yKTnh8az277IS8MDAfv//s4pq4uAhApfLI0XF/ynnfgPLojosKcpLFT54dce3aI+vJB19ubcJeQsvhpx6nHD2HDOyaswAh2155+/Gi3X5swW4WNZCT36cwYisLKSywCOsRHtGM2i96x0bACBgBI2AEjIARMAJGwAgYASNw+wjsOP7RGWQR4PkfLh1unEWcdzmsNbPlnFMfFwe29NNOfgx5gYA69LKrXQo443J6N5Os/NI9nH6O9tMO0rxUEB3IxGnVs/8l2bnsYlqoWEKf+Uv5uGuOfELWoYWM1sIE/cCigRZaSrpqZSwYEOjTrLvGo/IR+0Xr2AgYASNgBIyAETACRsAIGAEjYAROA4Edx18myfmMjjzH6vMz6s/+6+vtTrx4Y1xy7KnXQkKkJY1jT8B518kDHH0CPAQcZu3456P47PTz6ADl7OxDpwWI2eH9buFBZbPA6V9eQKCchY5vfnzRPRkgGaOxds2xj3QOtWf7M52O/OfyXr7WJz0+1ffsF51jI2AEjIARMAJGwAgYASNgBIyAETgNBIqOP84nDl48co8D3tvxX9sk5GcdOPw848/7BliI0AIAurITq4WKKCMeh2dhYWQnn4UPFjnYVY+nINa2D37tmisdZWrBpbXbL3od+c+LMaqvxcJTWNXoauUt+2s8LjcCRsAIGAEjYASMgBEwAkbACBiB20PgmuOPc8yb9XUMXLvj2nk/pqk4vhzPjwG9POMvZ56deMLF5h+RbHu0f6dwymhxgHblFxbq5EDmwakWX647RJ7TDKX3B/R2+7NNpYWSnn066v/kx1/ufZqhZn9Pt+uNgBEwAkbACBgBI2AEjIARMAJG4OYR2HH8cfJxtOX0E2vHHMdZiwDZzOyQqr5GTz2PCeSA45tl6YWDeWc75nVUP/JqEUE20C7tcn+1+WJWPT/7v1n27H+2uZaX3vjyQ2jBkTJhLH6dZBjZ7RdPjoVVLo/5iFEsH03X7B/lN50RMAJGwAgYASNgBIyAETACRsAI3CwCL03qXtysyvupjccmHv3k1bnxa53v20Dwrtt/G5hZpxEwAkbACBgBI2AEjIARMAJG4BQQ+JdTMCLbwO43O+Z65j3X38U8pw1w+O+C01/C/xTsZ0zoZMQxxsCx5R/DZss0AkbACBgBI2AEjIARMAJGwAj0EDhJx79ntOuNgBEwAkbACBgBI2AEjIARMAJGwAgYgTEEdhx/djzjH8+M30aY3y0w7Y6ved59X7vPfdd3pH23if++/WY+I2AEjIARMAJGwAgYASNgBIyAESgjsOP4Q8Lb5nUknbe38zI3hew0Usez3wqqp4w0f0vqWWgQH3EOlHHUuyYf+ihDdFlOKR9pefO97IhHy6U/6oiPI+iIvHiJYxC/dJEnrYCsyEt6iXzk0CdRhhZvpBOaWvtiu5BRCi0aeHr9U5IZy2r2Rxq1BX0RP2gyf+Qr1QufTEdeemIflOhcZgSMgBEwAkbACBgBI2AEjIAROHUEeLnf/Dc5Ui8mx22bn5yiF5Pzs83n+snJulafaWKedMyjN+cpwwbKZZfiHj+2YrPoyZfkqL4Ul+wRnfRPjuCsA11KQxPT5KkHo8wfMY76Ylo8Me7JRxcyMl2U0dMBbQ3/3B7pk3xkZ/k5L9pSLHk1+3vyxS/Z5ON4UH1LvvqGsQO9ZDm+vEcYB+PgMeAx4DHgMeAx4DHgMeAx4DFw98bAtR3/qRPnMDlAG3b8n3zwpYqGYk4MxE/V8em6GHr1kbaUbvHz1vy//uLK3qW2l/TlMvTrEYT/+//8fpuGTuXief6Hi82DNx4qO8ct+8Hqe+/9YIc+ZnryX3n78fw5xkwXZeybnpzleTw8+/jpVsTTn/9tTjNWFFrtE00tHrG/JV/8ko+tjGEF1ffwmRYLNl//+ulG7RO/YyNgBIyAETACRsAIGAEjYASMwF1E4F+z0RwD33x4WXoX3kAv+3FMCd98eqGiW4lxGqOz+ey/vh62g4UE2jHtbM888PI2/Rha8tF78dlx2v/yW5cLGD2nOdq6NL3Wfvhf+8/vz39RN5hi94h8xj8LMHHxKspy2ggYASNgBIyAETACRsAIGAEjcNcQuLbjz47q5//v7+Z2TEedm+3Ju9lN4ntQiVPOLr/ekbDE6Rc8OKji5wRD7IOefBzWh2/unjCQ3LWxFlS0wLJWXol/rf3wP/nfX23xE45arBiRz/inD8HawQgYASNgBIyAETACRsAIGAEjcA4IXHP8aRSOEs4/u6fxGHd0nHBIcUxPJWAz9r32/tVR+Tf+z/9abF5s41JmdpSff3614/7gR+NOOA51yamOO/g9+X//zdNrfZbbsG/7hO+jdx9vRWpR4lC74yP2b5UXEuIv4Qi56uOYLoiZT1nY+S8h4zIjYASMgBEwAkbACBgBI2AE7iIC1476qxE4eux+cvT5yZtfzc878/w8eRYE2Fnl75R2/TkqzzH5R99eLkiweLHU+Y9tBAvaOPqst/ACH4Lym082147szwTpX7YV3dGplryafNkZH9dARXxkY037wJedcOnPslNzFmdH7G8JFX/GkXHAeFZ9Cx/J5xEL2sp4Er/qHBsBI2AEjIARMAJGwAgYASNgBO4SAi9NxvLm8rMM7OzysjwcVgcjYASMgBEwAkbACBgBI2AEjIARMAL3EYHiUf9zAQKnnyPbDkbACBgBI2AEjIARMAJGwAgYASNgBO4rAtWj/ncREJ45j8fQS2/Fv4vtss1GwAgYASNgBIyAETACRsAIGAEjYAT2ReAkj/pzRJ/nsP1s9b7duo7P+K/Dz9xGwAgYASNgBIyAETACRsAIGIFTQuCsj/qfEtC2xQgYASNgBIyAETACRsAIGAEjYASMwG0gsLPjzxvMY+DTb/ftxXhgwNvz49v0IyZ3PX3q7Tu2fceWf9fHh+03AkbACBgBI2AEjIARMAJG4PwQuOb4R6cXJyl+zi47TTxTz+f8+PQZQfWvvvN48+gnl5/Ui8/Z9+r5fBrfqleIn6EbkQ9NlIFu7MhyJD/G3//k37c2x/KMB3leGig74+MIOiIf+aPuXvv5/nztU3TI7MmHJr/nQIs3I+2L2CEr2k6e0KLpte9SQvn/iH1w5vZFG1v4jcovW+dSI2AEjIARMAJGwAgYASNgBIzA3UaAz/nNf5Pj9mJyLrf5ycl7MTlM23yun5ywa/WZJuZJxzx6c54ybKBcdinu8WMrNouefEmO6ktxyR7RSf/kYM460KU0NDFNnnowyvwR46gvpsUT4558dCEj00UZPR3Q1vDP7ZE+yUd2lp/zoq3FLfqsj3zs7xav9I3QiNbx5X3BOBgHjwGPAY8BjwGPAY8BjwGPAY+Buz0Gqs/4T87fvKv95IMvpz4eD3GHHC52nGPo1UfaUrrFz+7+X39xZe9S20v6chn6v/3tt3Mxj0EoTUFMk+dTgpyIiKFlP1hxmqAWevJfefvxfEIj09XkLSmfFhPm8fDs46dbtqc//9ucZqwotNonmn1jtU/82KKTF5T18BOfYyNgBIyAETACRsAIGAEjYASMwH1C4Nrn/Hib/ubDSwjiMepTBwXHlPDNpxe3auq0A73jjPK4wWhgIYF2TLvSM0t8TEIyWvJxgi8+O077X37rcgHjGIsKalsvpn18rjF+shEeMMOuEfx6OlxvBIyAETACRsAIGAEjYASMgBE4NwSuOf7s2OI886z5dJR6o13dUsPzbnaJ5j6V4ZSzy68XIvJc+dKAA6sFFxYAnv/yYtsHPfnseD988+HmYvOPpWq79FpQkZPdZTgCAe37+2+ebvEoqWjhV6J3mREwAkbACBgBI2AEjIARMAJG4NwRKB71x3nipXXsrMZj3HIsAYVFAb3A7xRAwmbse+39q6Py+UV5I3bGNo7QRxp2pJ9/frXj/uBHu8f8I21O41Dzl0Pcwe/JxynOfZbl7ds+4fvo3cdbkYwBwiG/gNCyT+0r4TSCH7a25FPvYASMgBEwAkbACBgBI2AEjIARODcEru34q4E4euz+c/T/yZtfzbusPD9PHueSt/3zd0q7/uy0s0v+6NvLLwqweLHU+Y9tBIv4VQNhU4uFl46iK7/5ZLP98kGNl/JsK7qjUy15Nfk6nREf10CuThCQXtM+8OXUgfRn2eTXhpZ9al/GiX4m5PKMHzQt+dQ7GAEjYASMgBEwAkbACBgBI2AEzg2Bnc/5nVvjOK3Ay/J09P7c2uf2GAEjYASMgBEwAkbACBgBI2AEjIAR6CFQPOrfY7or9Tj9PHPvYASMgBEwAkbACBgBI2AEjIARMAJG4L4iUD3qfxcB4ZnzeAy99Fb8u9gu22wEjIARMAJGwAgYASNgBIyAETACRmBfBM76qP++oPCIAM/J8+w47zpwOE8EeCEg7wWI70BY0tK1/Et0mdYIGAEjYASMgBEwAkbACBgBI7AvAmd91H9fUMxnBIyAETACRsAIGAEjYASMgBEwAkbgXBDYOv68rZ034pf+qDuXQPviJwpL7eJN+uwC38Zu/4h9JZtHy44tf9QO0xkBI2AEjIARMAJGwAgYASNgBIzAzSBQPOr//U/+fdb+1X98sWMFTiOflOOleXxTnhCPw+uIfGSKx6jF/+o7jzePfnL5yb34HL6OTkf+JfLhy8/589123upPm6Qzyqc9+mQeCxxqFzTRdvG0aHrtk4xSPGIffLl90cYWfqPyS7aprCUfGrVfeGIrn3uM4yjbr/6RjqX1sf3IyPy5PvYfn/vjnRCRZi2/2uHYCBgBI2AEjIARMAJGwAgYASNwSgi8mIzZ+ZucxBf85fLJsXvB3+QAznWTE7VNQ6ty8VE/OVJbOeKfFgh2ypSnXmnJiHFPPrqifZFX6Z4O6LABOvEozu2RPtXDk+XnvGhrcYs+6yOPTZLV4l1CI9oc9+TneuyL40j2536UntH6SB/bL/5aPbZEevLYHOlzPtPnfKSXHMe79xPjYTw8BjwGPAY8BjwGPAY8BjwGPAZudwxsj/pPHTEU2CHXEXh20pWGOabJ8yk9dnxjiDvslLPjq0Ca0wS10JP/ytuPN+ziZrqavCXlk7M6nwZ49vHTLdvTn/9tTk8LBduyVvu2RHsm1D6xY0s8odDDT3z7xmvly/5a/4zWy/7cfvHX6jnx8ddffKnqzZMPrtIUruXfCnbCCBgBI2AEjIARMAJGwAgYASNwQggc/HN+047ojjPKUf7RwEICDva0izqzxMcAJKMlHyf44rMLkR40fvmtywWMmtN6UGUVYbSPo+nxk4WQghl2jeBXET1UvFZ+r39G6lvtb+GjBn7zaX18rOWXDsdGwAgYASNgBIyAETACRsAIGIFTQuCgjj9OObv8OIiE6Sj14rbiwOqZaxYAnv/yYqOd9Z58dqQfvvlwc7H5x2K9PQY5jHKye/THqKd9f//N0y0eJR0t/Er0S8uWyM+nPXr9M1Lfan8LH/qtF9by9+S73ggYASNgBIyAETACRsAIGAEjcBsILD7q3zKSHdPnn1/tqD740e4x/xYvjlnJOYs7+D35OIXsCMej91mnnMtc3svj8ML76N3HW9LpmfI5rZfZbStWJFr2qX0lnEbww6yW/JbZI/KjbLDJL1OU/bX+Ga0vtR/bxV+qV/+99v7VoyRv/J//tdPktfw7wpwxAkbACBgBI2AEjIARMAJGwAicCAIH3fHn+fb/8eH/3B5FV37zyWbnze61tmdHjOf1o1MteTrqrrzk62QANmw+vNKiEwSU8Ix3tBEd4rviKKc4ycCpA+mHKsoucy0rbdknOzNOfPmAkMszftC05FPfCj35UTa6+Yu7/rK/1j+j9dkOfflB/LV6+o9TJI++vfyiBHyRdi1/CzvXGQEjYASMgBEwAkbACBgBI2AEbguB4uf8bssY6zUCRsAIGAEjYASMgBEwAkbACBgBI2AEDovAQY/6H9Y0SzMCRsAIGAEjYASMgBEwAkbACBgBI2AE1iJgx38tguY3AkbACBgBI2AEjIARMAJGwAgYASNwwgicpOPPy994Frv0krYTxvJsTDP+Z9OVbogRMAJGwAgYASNgBIyAETACRmBzko6/+8UIGAEjYASMgBEwAkbACBgBI2AEjIAROAwCOy/3Y5c9Bj7PxpvQ71MAA74WEL8mcE7tP/f2nVNfuS1GwAgYASNgBIyAETACRsAIGIFDIHDN8Y9OL05i/Nxddhr5Vjufa/vqP76YbVH9q+883n7D/dl/fT1cz6fy/u31B9t25U/l9eTDGGWgm2/JZzlbBSHx/U/+fWtzKN5ZBJD+7733g62d+pQcPByRnz9VFwRE3eKv4cOjDfHzcohZIh96+iR+blCLNyPti9ghK9pOntCi6bXvUoL/GwEjYASMgBEwAkbACBgBI2AEjMBNI/BiUjj/TY7bi8l53eYnJ+/F5DBu87l+cjKv1WeamCcd8+jNecqwgXLZpbjHj63YLHryJTmqL8Ule0Qn/ZODPutAl9LQxDR56sEo80eMo76YFk+Me/LRhYxMF2X0dEBbwz+3R/okH9lZfs6L1vHlNWccjIPHgMeAx4DHgMeAx4DHgMeAx4DHwLHHQPUZ/8n5m3e1n3zw5WTDeIgnBuBixzmGXn2kLaVb/Ozu//UXV/Yutb2kL5eh/9vffjsX8xiE0hTENPnnf7iYT0SQVmjZD1acJqiFnvxX3n48n9DIdDV5S8qnxYR5PDz7+OmW7enP/zanGSsKrfaJxrERMAJGwAgYASNgBIyAETACRsAI3BwC/5pVzUfVP7wsLR31zvSnkscxJXzz6cWtmjTtim8fA8AQHjcYDSwk0I5pl3xmiY9JSEZLPo9JXHx2nPa//NbD2YRjLCqobY6NgBEwAkbACBgBI2AEjIARMAJG4PAIXNvxZ8eW58oJ01Hupkae73e4QgCnnF1+Fkz4W+L0SwqOtfg5wRD7oCefEwMP3zxOn2hBRQssstexETACRsAIGAEjYASMgBEwAkbACJw2Atccf8zF+cT55yVx8Rh3dCxxSHFMTyVgM/a99v7VUfn8orwRW2MbR+gjDTvuzz+/2nF/8KNxJxyHuuRUxx38nvy//+bptT6L9pHet33C99G7j7citShxrl9A2DbUCSNgBIyAETACRsAIGAEjYASMwB1GoOj40x4cPXb/OfovB4/n51kM0FF03vh/SoGj8ixGYB9/OrmwxMbYRmSo7SMywEv4wIss7OGN+iOBhQrZTgy+0anuyeeZe3josygn6l7TPvDlPQKSTVvv0uMgEQenjYARMAJGwAgYASNgBIyAETAC9wWBnc/5nVujOa3Ay/JwWB2MgBEwAkbACBgBI2AEjIARMAJGwAjcRwSqO/7nAAZOP8/cOxgBI2AEjIARMAJGwAgYASNgBIyAEbivCFx7q/9dBoJj+Rw/Vyi9FV91jo2AETACRsAIGAEjYASMgBEwAkbACNwHBE7+qD8vvONTcvFZ96Udw4KAvjk/yqsX7fGuA4fzQCB/CpF3QLh/z6Nvz6kVPKLEezpuenz6+jinUeS2GAEjYASMgBEwAsdCgPe3ff3rp6v802PZ1pJ7a0f9mdzykrjey/N4izyTYDnirca06pjU9kL8ggG0+asAsrknx/WniQDveuBlhPu89HGkRdwE9OLDkbFdkhlljL4UMspZy68xnq8FdMS2Kb3ExmhbDZ9IU5Ldsk91LdtEU2ofbezp79Ujg3sVNtR0QHOKoXd9CNcYl/poTdsivugp3fej/pH7eranx39X+y+303kjYASMgBEwAkZgDIHe/DBK0dwkbkov4Y+ybiP9YlJ6sL9p4vZimlh1/6BD7wRUU/c0sSvWw4eeCfxr9SWZJbqSbGRSDr1sFD7InRYqtvqoL8kV/X2Mwa+E/ygWa/lH9NBntbEzwl+jie2WjlhW41M5YyuOSdJxvImuFq/hhxdMdP2O2I19I3SyN9KW8GnZv499tAc+9I/wt/RLxkj/QHOscXwsueojYvUNcSzP6aX9n/lzPuNPPt6DZVccR1lGKz/Kf8z+a9nnusPNQ4ylsfQY8BjwGPAYGBkDI/PDLCf6f/vwZ3k3nL+ZgREnzLUGyulgcqs/Aaq8Yk0IqY/yavSazImfGNrML1lMEtFR4pMMJqA1fsm5jVg2L9VNu2hT7AfhLFkZX5VHHuEjeaJpxaP8apt0ZJm9eujlABBHfpVLNnGmifS9NLYsGR8ZL/qCsp4e1a/lr8lReYwPMfYzPqP2Z7poV0xn+aqr8efyjH+vHvn0N3/ohl86FVOOHP405kt11KucWLTiVVzSEflyunb9RjpdB62xv7T/JTNeD7JFusnTzlqeulgvutF4hB8b+Kv136gu093MvMI4G2ePAY8BjwGPgUONAeZWvXkV85naXGSE/1C2rpBznAHD5CkaxUQq5ntpgM08OV+SkTtsZLIX5cCvSXXu2KWT3Sj3JtPgRBuW6lS7I4ZxENOnUa4myFFPpI/lo+kWP+2K4yrb06uXDXJCiFVG3NId6UbTS+TJpihbZdnOSKO0aJUnVtkIf+QbsRuayLNPOuqRrVGOyrL9kS/Sx7R4Y5nSJf4SvcqIlZYMYpURK697FHG8jqjnfqJ65Us46h4ETf4r2Z5pavl8vZSuX3hzu0rySnaX6GKZ5NI+pYWd6JCrNkasqBemoiHO/JJTinv8yJJO0ZbkuOz6uDQmxsRjwGPAY8Bj4K6PAc0/Wu1gLlebe4zwt2TfRN3RnvHn7frTBG9qQzlMwBWf34Qavh9+9PqGZ06Xhvi8BbyPfvLq5qv/+KIoJtswddjm1Xce7zwHPnXu9tlm3jVAu6DTH/WnFvSs7j52/fn/+9POiyr++cfnWzGvvP148+R/f7XNP/v46ebfXn+wzR8zAc7oQqeCXtjIeOnVi6cV01Y+AXmIMDkOM1Z5PNZk8wLLHPTiwVJdpi3RLOHP8lr5yWHcME7WhIzPoeznmuba5P0cS97l0NPfqwcL7ll/+ekfq7BwL/rrL77c1j/54Cq9LTxi4lDX7779z3jk/sF9FKxIa4yq2brfQJMD1z/lvKeDP/jze1gyT8z3+Hv9F2U5bQSMgBEwAkbACNwvBOTz5bnLXULhaJ/zYwIXnR4mXUzIFXAcXnv/B0WnnMkd9Uww4+f54I0yyMc3X+NMoCcGJoeZR/XZBiaTOdC5fBbw+ecXi78MkGXd9TzY0h+5T7gQRi4CnDKcnxhGP7kox6ump1cfddbSLJjQFo2XbNuo/YzDv//m6aLx8s2nF9fM0g1GdS39oolCMn+s2zeNTBzIpz9fvignnSV8DmU/i3xfbS4X+uhHrn8tEEl/Kd5Hf8SXexV9Xhufkbak/ybK1l6/2Li2/+kLxg8h9wvjO143jBP+4gIw/akAP/cibKrhLlrFNX5eItvqP/E7NgJGwAgYASNgBO4nAvitN71pc2ikj+b4Z0NZCIgTOOrjwgB5dm5x+nG4CEzs4uQwTwJnovAvy4c+ymCCmE8SRBugzwsHj769dFRxWLPDi+pSu4JJZ5WkrXFivrRx0SlbyivHrDbJ79WP6sOB0AIQjuPzX14t+IzYzxhiVzeOqxHdcly4BsSbFzNa+kf4R+zo0XDTi7vWPfpcX8PnGPbj5D144/pJimwT+VH9tf555aPH870j3iO4lz15c2zhoWTTocvWXr/Ys7b/WSB5/oeLeQEQR58xrcA9lk/jKHB6gh19XfPYvya0+FmM0MKIdJxa/8kux0bACBgBI2AEjMDNIsBc5P9v72xWLDmuBHw1MlYXGFrdMDSWYCRGLZnGAu8NfgAhgTZ+AS0E3hmMVnoArYxAuwYv9ALaCMboAQSzH7BoJLcGS6A2zUC1GwaqLWh68suac+tUVGRmZN2fqnvrC6jOyIg4J058EXk7T0RkJiHuF7db+/pq29hW/7kmckMd2+znytbKc1NZbrud2srJxEFsI42tpNwsRpzdBcRjCzGORTnZULNl22k4V7Fqvc66cfpjhW1IL7wO7rQ5WzUdQ/JcaOSxMhcBJ4KAozyVHzJDRy7ouKhzmaN7Z1fic36OM+YI4bjnvIjTL0N9w3jKjxoQzyuUoWPo2CI/Vv+Q3kiHz7XXD87dvik+LfaHLS1Hxio7dVrDVP1j+eVvB2OVHUUxcRnjE8c5wpxt6iEzdH1E/lj/tly/oad2XLX/+Y2nT3D2+Q3F0SctAm3j/4AIca3Hf7JMOOXfH65/ZCI/5IaOY/JT/Tek03QJSEACEpCABPafwD6s9tNLW1vxnxoSOEtjDtOUfJnPzWVtBb/lJpEb3LgpDyefG3j0sVqF88MEwFUL4cQEm2g/jIIrN9eslHGDTsBZCrkoP3Yck+fmnD4I3ejJ/TCVP1YveWW7sH3OmIzHGLJjP6f9cGKFOuTZ+TKH3SryOFGZK324uHt6RwuOGOP/vGGKz5j9LfaVZTK/Mq/WvrH6afNU/hQXxid9G7uIuG7KMTelY+z6mJLFfkJZZ75+x3Ss0v/8psKcyRACvxdcG33a4vi9IiUfyuXrm2uRHRTZ/pxP+bGwqvyYbvMkIAEJSEACEtg9Ai33h9zDEMLXya1skc/lLzr+XGcAb45eS6g52lOKWbHhhi8HVgbZ8lk6XejPZTmf2noeTnzcIIZTRX3lDW90XtiEHTzLQUdHnF0DbAktZbP9xiUgAQlMEWC1m10d+TdtSsb8OoH8u14rEb//tTzTJCABCUhAAhKQwBCB8AFrjv+QzGVNX+uK/zpvYNny2a/KJXI42/kGj/PYDkqxcNyTSL8VNN/05Ti6woGP2ZyczwplrFKyUkWHRxvzJEfoyPUal4AEJDBGAKd/lR0UY7qvWl7+3b5qbbe9EpCABCQgAQlshkA8krgPTj+E1rrivxnkapWABCSw+wTKicnyqxG730JbIAEJSEACEpCABCRwWQls3fFnZX3bsybccMfzrZe1I7Rr8wTyLg1qc6fG5plbw3wCzC6z22nb49PrY35fKSEBCUhAAhKQwNUjMPRY+mUnsda3+rN1vvyLLfSA4IaWFzPltBIQIFsDN6qxBWNMhhemzdE7psu83SXAYxpsCcah2kRgjOXxz4TT3JB1nGfMrirP9UQbatdVblvE59iYbUO+xieXqekesy/yxmyLMrX20VdT9U/lo4PfN2wYqoMylzFMXR/BNR9rfbRK2zJf6qn9X5Hr5/+AuWFKflf7by4Hy0tAAhKQgAQkcExg6v4wc4p7k/wuujnyWddFxHm539r+Ohi9Lo7dTdwpvd1NWn/e3fCfSs/1I9fdmD3j2EHs45zX/igzpiv0Yge64tzj+vq7ZEk/rcJ6VfnSntp5HmO1/POm5XZHHTltSi9jOa4RyhJvGd+hdxV5ZGHPtdLaB9g3p325bI3PmP3nsY92IAefFvmx+kNHS/9QppVh9F3rcVN6c/3RNxxzehmf2/+lfHle8uc8/x8SduVxVOoYO2+V32T/jdln3ub+X5KtbB0DjgHHgGOgNgZa7g9LOe5N4h7pPPKlvi2fr3cgxM0gN2fAiMZkSGVelJk6AjnfCNbKx00bN8gtf9FxNV27mhYM5tofTgWMg13JOwZ45EcdWSbyQl+UGTu2ykfboo5S51Q+5cMBKPs+0kM3x7JMWd/YObbka2CsLHklL64T0qbkIn9V+SE9kZ6P572Gs46ST6v9ZbmsM8dL/ZE3JF+ml/yn8tFPf/NH3chHnXEkHT38xZiv5ZEf6RyjbMjGsVZHlivjQ9dvLhfXwdjYn9v/oTNfD2FL1M057Rw6Jy/nR7nWY4s8NvA31H+tdVluvfcV8pSnY8Ax4BhwDGx6DHBvNXVfxf3M0L1Ii/ym29Cgf70DiRsmKuXmKeDleBhEGoDifOiYbz7HYId81B/nHOmgsCXSW3RF2V07hnMx1+6aM5EHcdlnnJe8c/m59VN+TJ66qDP0lvZM5YccfU89eWxN1R2yc45jbSn1hE05PdJKO3OZiEfZOOcYaS3yWa7FbspkmfPEcz1ha9YTaaX9WS6Xz/GQzWkRr8nXykcax4iHDo6RxjHO43rgWP7m8DsU+ZTnvMYRuVo6MjXbSW/5K6+X2vWLnrJdNd1D9tXKRlropX0RD3ZRBr3RxsyK/GAaZTiW8qGndpySR1fUGWVrekxrG29ykpNjwDHgGHAM7NIYiPuPMZu5dxu692iRH9O9jby1PuPfgTj1eaofvzrqn+PlGXteVtUBWf7d+v1Li4efPOjPkeMv53MegfRayGVq+Vc1LZ7VPU/7+Wxhfmbln/efLNW8+PbNvs8i4fFnh4sXbl+L040e6Wvqos4I8cLGzpHox89YfsiMHWkrn1hbR+gch55VZjmm96e/PDiTHS/BrOWVhWtl5siX+sbOO4dxwThZJZR81mV/94Pc/47wLpE573KYqn8qHxavfHp78d179wex8GnQv//xh2X+w49O4svEDUbWdf2et/8Zj/zm838BrIjHGI1mx+9N+SlX8rm+Sec9HfwhTz+3hin5qf5rrcdyEpCABCQgAQnsH4HwO8t7l11q6U/WaeytD1/uv3t//emNXi3OPTdyOKIPFt/3L7vKjhAOW/7+MnGgoidD5bNXEbh5Dv3o/sefD31jf8DZ8JEbZ/qUvxzos9xfOS/HccrovxxaP2kWjtdQPVP5uc6hOOOUtsREU2lbq/04tXPHJZNkZYgfmMgbqz/KZB2lfM47bxydOJCHf/j6vCoWNT7rsv/BO9/3vzUYRz/iHMYE0ZjB56k/88UZps+HxmcuO2bHJvNWvX6xbdX+py8YP4SyXxjf+bphnPDHdRmB/oyAPL9F2DTEPcrGcUj++m9vjvZfyHuUgAQkIAEJSOBqEsA/3faizbpJr9XxzzfdGMrN8NG941V/btIO7nSrmu8v+hVlnH5Wb7756i/NN23oLJ0x0soQjltO7x3OuznlWNfpFM/GCKw60VKOj7G6yrxwzIZu8qfyS31D5zgQMRnFOHry8dHSQWmxH0eFVd08wTVUV04Px4XrImTLyYyx+lvkc33njfOjl1et5+oZ4rMJ+3Hy2G3UElrrH+qfFz+92a9I50kxft8e3mmbeGixcdUyq16/1L9q//N/wpO/HvUTgDj6jOkI/EY/+vxkRw+7J+IrMPQP9q8SxuSZjIiJkajjsvVf2OVRAhKQgAQkIIHtEogFnLhf3G7t66ttrVv9w6xYqeGmG4eM7dnc5OH8czNFuPHuzcnvVAfk0NtyjG3uOG/xx2QBW5PjPI75prNF966UgX9t8mNV+1mNixW2IV3cXPcTPEMFJtKH5OPGn5W5CDgRBBzlqfyQGToy1mrjjYmr1sAYJ4TjXpOjX4b6Bkc1P2pAPK9Q1vTltBb5sfqzrlocPtdePzh3+6b4tNhfs2sojbH65Jv2/puqfyy//N1hHPObE6vaMT5xnCPM2aYeMkPXR+SP9W/L9Rt6asdV+59JE/qE310ew8DRJy0CbeP/hQhxrcd/skw45d8frn9kIj/kho5j8lP9N6TTdAlIQAISkIAE9p/APqz200trW/HnBi6cem7quBnDAY2bMm7y2O7PjVqEyIvzfAwnYde3VOQ27Xo8nJjSYYn+pn3cXDMOuEEn4CyFXJ8w8c+YPDfnjKnQjSomcSJM5Ue5oWPZLmwfc+JLPf2uki4xO/Zz2g8nJstCngmrOexWkceJylz7a7nbIcP1ClcCjhirtecNU3zG7G+xryyT+ZV5tfaN1U+bp/KnuMCRvo1HlbhuyjE3pWPs+piSxX5CWWe+fsd0rNL/TBrAPN4NwW8/10aftjh+r0jJB1vy9c21yA6KbH/OH7OdvFXlp/SbLwEJSEACEpDAbhFouT+MhcGa39oif5mIPNcZwxuh1x6AxMuSwmnIFTBJwE6AGkDkuLHjBpEbNc6ZZWGVKMdDH2k1PZHPkUkEtpDOceKyvHEJSEAC6ybA7yC7Omq/keuua9/1xWTZUDvnTBAM6TBdAhKQgAQkIIGrRwA/koXoKX9zF8isbcU/GsuKLM9KErjZKmdColw+5hUnoCLHTTE3c6w4sspVxkOefJ4F3YfOiDZ5lIAE9p8ATv8qOyj2n1B7C3Xs21lZUgISkIAEJCCBNgL4o4R98TM3tuLfhtNSEpCABK4GgXIStOVFpVeDjK2UgAQkIAEJSEACEtg0AR3/TRNWvwQkIAEJSEACEpCABCQgAQlI4AIJbOSt/hfYHquWgAQkIAEJSEACEpCABCQgAQlIIBHQ8U8wjEpAAhKQgAQkIAEJSEACEpCABPaNgI7/vvWo7ZGABCQgAQlIQAISkIAEJCABCSQCOv4JhlEJSEACEpCABCQgAQlIQAISkMC+EdDx37cetT0SkIAEJCABCUhAAhKQgAQkIIFEQMc/wTAqAQlIQAISkIAEJCABCUhAAhLYNwI6/vvWo7ZHAhKQgAQkIAEJSEACEpCABCSQCOj4JxhGJSABCUhAAhKQgAQkIAEJSEAC+0ZAx3/fetT2SEACEpCABCQgAQlIQAISkIAEEgEd/wTDqAQkIAEJSEACEpCABCQgAQlIYN8I6PjvW4/aHglIQAISkIAEJCABCUhAAhKQQCKg459gGJWABCQgAQlIQAISkIAEJCABCewbga04/jc//tfZ3J7/9fML/gwSkIAEJCABCUhAAhKQgAQkIAEJnJ/AT0rRl/7j3xbX37pRJp85/+f9J4v//sXXZ9KHEv79619Mlj94/2eLoz/971LFG1++ubj3/H8tz8l/9e5rp9KWmUYkIAEJSEACEpCABCQgAQlIQAISOEPgjOP/4J3vFw8W358pmBNwwA/uHOSkU/HSgT/8w/8sHn92eKoMJ+VkAE7/nae/WjCp8N179xePv3h0RubhJw+WaUxSPPzoh8XT/3y6TDMiAQlIQAISkIAEJCABCUhAAhKQwAmB57ros5PTtlg4/jj0ZWBb/63fv1Qm9878C7evnUoPJ76mh23+tz58eXHt9YNFKRdK/va7b/sJiFKeCQVk8m6BkPEoAQlIQAISkIAEJCABCUhAAhK4SgTOrPjjcLPF/pvf/OVcK+lH945OOdysyhPYSdASYjs/ZVnxz48T1CYcjhYnjwa06LeMBCQgAQlIQAISkIAEJCABCUjgKhE4s+Ifjv8UBFbry5X2mgxb94dW3sut+pTF2WeSIFb82crPRMRQOO8ExZA+0yUgAQlIQAISkIAEJCABCUhAAvtE4MyKP40L53tuQ2OLfZZjggCHvhbYqs92/tgNUJsg4Pl97HnyzVHTREOtHtMkIAEJSEACEpCABCQgAQlIQAJXlUB1xT8746uAKV/exyr+K5/ePrV9P+uvTRzk/Fp87tcFajpMk4AEJCABCUhAAhKQgAQkIAEJ7CuBf1mlYTxzPxTYxs+b+XPA6S/Tcj7P87PqH3/sFsCx55w42/qJcySQlt8BELqYQBjaZRBlPEpAAhKQgAQkIAEJSEACEpCABK4CgepW/9aG80m/H399VH0JINv3ayv4LZ/ey+8ZCCef9wmg78lfj/o3/TMBYJCABCQgAQlIQAISkIAEJCABCUhgnEDV8b/+1o3F9ac3xiX/P5dP9w054azGhxMfZfJKfPlivvgUYKzyxxcBqCp2ELBrgE/1oXdoEqG2C6CpMRaSgAQkIAEJSEACEpCABCQgAQnsGYEzz/iv0r5w3LOOsWfwmQQI5x9H/vpvb556gV+eJOBFgEd/Ovl0X95NEDpyvcYlIAEJSEACEpCABCQgAQlIQAISWCzW6vgLVAISkIAEJCABCUhAAhKQgAQkIIHLRWCll/tdrqZs3pp4aSA7Efhjl4JBAhLYLQK8lPQirl9/P3ZrnGitBCQgAQlIQAIS2CcCOv4zejO+OhAvHJwhuraivOsgJh6GnJecj7MxN0zJM+FBmbGvOgzVme3P73AYKp/Tsyz182jJ3JB1zK2fulaVD6ezxi5zj/gcG7NtQ3xymZruMfsib8y2KFNrXwu/KfvQscr4Q/6iwtTvR3DNx1ofXZT91isBCUhAAhKQgAQksNsEnnXmX5q/7qb3Wec0nNueVeVbWHSOxzPq4dhSfl1lOkf3WefIL+vkvHMMludh13n5tcpjw3k4l/ajh7RWPrldrbZm3avWv4o8sjCjv1rZwSe3ObelFs9la3zG7D+PfbQDOWxpkR+rP3Tk8T00PkhvZVjjNJa2Kb25zugbjjm9jM/t/1Le88vz/5p9YV84BhwDjgHHgGPAMXDRY2CtK/7dTXO/Cjy2atfd/J9ase4A9CFkOHn17mvLMp0zc1xg4t9W+e5meqkbe8swlV+Wz+fdjfwp3egnrSWELHwiBKs458jnDIfCrQ9fXjz+4tGplyAOla2lt8hj0z/+fLjgpY1zA1+A+Psff1iKESetDNEHZXp+uSNfdMAGPinZGlrrH9K3ijyfo+TLFnzmsiUw7uGc2zwll8vW+IzZP9c+bMljoEV+rH70TeVTZmr8xdjh2su/CcjmvPLaz2XP8/uDfkJcs+gv6zgu0fbvefq/TbOlJCABCUhAAhKQgASuKoHRVacOSnN+d6N7ZiWOtFiJ7G6K+/zQyXl3M35Kfy4f5eYcx+SpizpDX2nPVH7IsVJHPRwjjeNY3bncUDz0wivitTqinpId58iSH3+l/FDdpE/JoyvqjLJj+nJetKeWVtqIbuzPZWvx4FDLK9Pm1F/Kcr6qfNbZYndL+7POWjzXM8f+LFfTS1pNX5StydfKRxrHiIeOXAd5cT42/jrnfTk+Kc95jWNcI7muiNdsj7ypY/l7Uvt9Q0e0NdpV01uzu1bOtPb/n2QlK8eAY8Ax4BhwDDgGrvIYWOuKfwdyUX52L68Kvvj2zcXDTx5QrA+PPztcvHD7Wpxu9NjdZPd1UWcEVikJnSPQr8xjy1B+yIwdaevPP3h5rMhoHqu08GHF8ZVPb/dx0nIInpQpA/aTzsoyf+h648s3y2KD51Py2PTde/cH5ccyfvrLsyvz0bYyL56FHtPXOYB9+/Iq91j5sg7KDtVf07OqfE3nUFrnMPbX0VB+S3rJZ132x8o442rOuy6m6p/Kp81T4+/6WzdO7Sh5+NHJ7pIWZquWWdfv2zr6f9W2KC8BCUhAAhKQgAQksF8E1u74j+HBsWQ7b7ea1f+FU4pT3hLC6Qh5jqS1hHAswtkrZabyy/K1cxxWHOOwr9W2rIvJiHDuY2Ii8tHH9u9w7EnHwcshT6yEfCtf9AzJ44xQ9xC/bEMt/uNXZx9RCLtqeTUdkUabsSXaF+ljx1odZf1j46tFfqz+1jxswoFsndCo6a3xWZf9PKoQ44/rl3HREqbqn8qfGn9lX7bYtO4yq/6+Yc86+n/d7VKfBCQgAQlIQAISkMDuE/jJNpuAQzvXYcv24XQ8WLQ9I53liIdjwY11zXmdyi/1DZ2jG8eIwATAk4+PZjmoODg8x8/qJY5ofiactEefn+xYYJIB5yvaFBMGQ7ZNpY/J44yGYxN62F3w8M6DpvYFc3ZXhFN7nskWnFreDRA6wpapY0v9Y+OrRX7KhpZ83rOQ34PQIpPLDPHZhP1MEl174+xOjmxPxFvrHxofL3662vgLOzZ5XPX3DdtW7f9Ntk/dEpCABCQgAQlIQAK7S2CrK/44/az4x+pcDRs3z3Ne2FbqGJLH8SDv+m9vLkVitRIncip/KTQQoU21dh3dO73SHbsBampweuCDA8o2ahx90iJg/413T+yPtoRTFS/LCztoHzKRH3qGjmPysf0+VnvRy2Mdc1bdcRTzoxDE8w6DsAvnFU5liB0UY07/GN/W+st647xFfqz+0DN0pN+uvX4wOqkxpn+KT4v9Q7bV0hmrT745Pb5r5SJtqv6x/KnxF9cvjnOE2FEU5y1HxvXY788Y/5bftzEbWvp/TN48CUhAAhKQgAQkIAEJDBHY6op/OInlDTlObjinOJ+sJONUEHAGQm6oETl9TB7nAacydCMXq/PEp/IpMxbKdmH7mJOadXHTT7txpgnwQL5PW3zb68E+HI/rT28sRbP91MUKfLYj5y+FBiKryg+oXSbTj6wQ0wYCXyCY07dMhBBCnvic8bFq/avIMwmTxx39urh7/GZ8+pXARM7YVxv6QiP/TPEZs7/FvrJM7r8yr9a+sfpp1lT+SNP7rPL64HclXwtT8uSP/X5MyWM/oawz/76N6Vi1/8d0mycBCUhAAhKQgAQkcLUJPNc1nzdmG/acQHaWa02dM0FQkzdNApeNALtl2FUSEyuXzT7tkYAEJCABCUhAAhKQwLYI6Phvi7T1SEACWyXA7h52UOT3ZGzVACuTgAQkIAEJSEACEpDAJSGw1a3+l6TNmiEBCewhgfJxAx5F0Onfw462SRKQgAQkIAEJSEACswm44j8bmQISkIAEJCABCUhAAhKQgAQkIIHdIbDVt/rvDhYtlYAEJCABCUhAAhKQgAQkIAEJ7AcBHf/96EdbIQEJSEACEpCABCQgAQlIQAISqBLQ8a9iMVECEpCABCQgAQlIQAISkIAEJLAfBHT896MfbYUEJCABCUhAAhKQgAQkIAEJSKBKQMe/isVECUhAAhKQgAQkIAEJSEACEpDAfhDQ8d+PfrQVEpCABCQgAQlIQAISkIAEJCCBKgEd/yoWEyUgAQlIQAISkIAEJCABCUhAAvtBQMd/P/rRVkhAAhKQgAQkIAEJSEACEpCABKoEdPyrWEyUgAQkIAEJSEACEpCABCQgAQnsBwEd//3oR1shAQlIQAISkIAEJCABCUhAAhKoEtDxr2IxUQISkIAEJCABCUhAAhKQgAQksB8EdPz3ox9thQQkIAEJSEACEpCABCQgAQlIoEpg0vF//tfPL/hrDUPl5+horctyEpCABCQgAQlIQAISkIAEJCABCYwTmHT8n/7n08Urn95evPQf/zauKeW+8eWbZyYLbn348hkdTgYkaEYlIAEJSEACEpCABCQgAQlIQAIbIHDG8b/58b+eqea/f/H14uFHP5xJ//evf7E4eP9nZ9L/ef/JggmDMjz6/LBPYhLhztNf9RMKZZk4J3/OZEPIeZSABCQgAQlIQAISkIAEJCABCUjghMBPTqLHsVu/f2nBXxlw5l+4fe1U8sNPHpw6jxPK4bhHQPbJX48Wr959bbG4u1j87XffLh68831kV4/IGCQgAQlIQAISkIAEJCABCUhAAhJYjcApx5/V+3vP/9eoRlb5//Hnw8XhH/5nsBxOO7sEcmD1Hof/6E//u0ymvny+zPj/yJNvjsokzyUgAQlIQAISkIAEJCABCUhAAhKYQeCU4x9OOE769bduVNV885u/LH76y4NqXpmIY88qPw5/Ldx49+bix6+Oqo8FsEPAIAEJSEACEpCABCQgAQlIQAISkMBqBJ7rxJ+dRwWTA9dePzizss8L+3i5H+HxF49Obelna9syagAADKlJREFUt0B+XCAeFajtHuBdA0f3jkZ3BJzHbmUkIAEJSEACEpCABCQgAQlIQAJXicApxz9W6FsAsIrPaj2h9iK/rAMn/sW3b56ZJMhlyji2DO0GKMt6LgEJSEACEpCABCQgAQlIQAISkECdwCnHvyzCqj5v88exxxFna/7YS/nKFf1S39D51HsFhuRMl4AEJCABCUhAAhKQgAQkIAEJSGCcwKln/MuibOWfWs1nQiDeDVC+0C/0xScCa1v6o0w+5scFnBTIZIxLQAISkIAEJCABCUhAAhKQgATmERh0/Fm9/+69+6PacNAP7hwsjhYnb+ofFWjMZLJBh78RlsUkIAEJSEACEpCABCQgAQlIQAIjBJaOf15lpzxv78+r/azq//yDlxd3nv7qjLrWlfwzgiZIQAISkIAEJCABCUhAAhKQgAQksFECo8/4b7RmlUtAAhKQgAQkIAEJSEACEpCABCSwcQL/UtbAyj+r+vHHlv+rGoJFa/thFdw4Im+4OAJl/9k/F9cX1iwBCUhAAhKQgAQkIAEJXByB5Vb/0oTL+ow9ztsLt68tzb1MdsbLDXE43/jyzaWNRi4HgegfrGFiZijwNYtHnx/2n5N85dPbsz5DOaTTdAlIQAISkIAEJCABCUhAAhdF4MyK/0UZEvXikPGlgFog7x9/Puxf/IfD//CTBwucNIME1kmAr1nwTouf/vKgH2/r1K0uCUhAAhKQgAQkIAEJSEAC2yYwy/EPpzxvmS63s+e82qrqUD4OfJR/9e5ryy3zMQnAJwFx9HmRIHHK3vr9S0telEN36IlzymUbh+oPRTn/+m9vRvLyGHWjN+xdZq4Qod747GFWQxp5BOoLHpyTFxMf0d6p9iM3FEJ/ZpDZITfW/pDnGH+lfNZNmRwoG3JxLOVz+Vo866/1X00mp+X6brx7c3F07yhnG5eABCQgAQlIQAISkIAEJLCTBJ51Vi//OsfnWed0Lc9zHun8UYb0zslaxuO8cwyXssSzLsqP5aOD8p0Tu9QR9Udd1E2cdOKdo9vHkQnZqDfyo86p+tEVutHPebY/9IZNnOfykU69yHGMtKlj2F+WizaRnuOcU/+c9pe6y3P0Z7tpW27DVPtDPvSWPKf4l+0LPa3Hsr6y/7Ke3M5ID/vLI+2OMh5PfitkIQvHgGPAMeAYcAw4BhwDjgHHwG6MgVkr/l2nLv72u2+Xn/njmen45F/nIPbP3j/+7JBifYjP/LEaPZUfMkNHnuunLlZx2e5PKFd0/3n/Sb9Fm7zHXzxa2sZ5S/3X37qx+Psff6B4Hx5+dBIn4cW3b/a7Do5zuzq6tub3DUT6eY5sLcf+zslcihPPbVpmDERy2bL9AyJnkof6l4It7Uc+AvzgA/sW/tjPJyPPG6b6b0ovj49gA5+ypB0wJC3G8ZS8+RKQgAQkIAEJSEACEpCABC4jgcGX+801luehCTERUMpP5Zflp85xJK+9cVznVFnyp+pHH+HHr4a3duPE8nhBfsQAGWSH2k1+a2DSgcccwtHE0c4TEa16NlVulfZP8cdmJpJg2a24903A8X7wzvdNzWnpvzFF3e6ABRMHhPxixmtfH/hyvzFw5klAAhKQgAQkIAEJSEACl57A2hz/cJiHnOCp/ClSOIHsHMApxjHEKf7uvfu9k3b96Y1+hXZMx6r1o5vVYHYbhGM+Vt958vpV/w+OV/3j2XLShsKciY8hHXPS57Y/O/s/Lo4nVIbGR9jBBEp8qYF+fvLx0cZ4R50cmWB49P7h4uDOQV9f91iCDn8GZFwCEpCABCQgAQlIQAIS2FkCs7f6D7UUhw3HMG+/j23rOK9T+aEXHThfZWDbOKvhOI44hvGYAfFwFEuZfD5Vf+Tf+vBkq3le+UUXTj+r/bG6nPWvK84KP3Ww5b1c7c9sYBsr1HPqxpmOFfU5cpRtaT8vxItAG5iwIQTfofEB0xrXmAAJnUP2h/6x/gsdQ8d4mV/NjiEZ0yUgAQlIQAISkIAEJCABCVx2Amtb8aehOOOslOat8Nkpn8pHR2x3Dx3xJn8cO569zs74nK3grfbhWLKDgFDWFyv92YYoh33rCLHqj65ytT+zgQt/21z1b21/TCwwUZG36k/1f8mV9pUMxhijf6z/xmTJ4zN+7Axhp0K8R2JKxnwJSEACEpCABCQgAQlIQAKXncBznYG8sXwZWO3EAcsO+zLTyFYI4Lzycrk5Tu9WDJuoZJfsxlYmdtY1YTOBxmwJSEACEpCABCQgAQlIQAIXRmBwxR/HiMCqLSuphu0QmPsm/+1YtR+1sBtlXV9h2A8itkICEpCABCQgAQlIQAISuAoEzjj+rIC62r/9rs9vlZf/Zvg7gbUZrmqVgAQkIAEJSEACEpCABC43gcGt/mH2VV7xn/vYQ7mi7FbyGEUXcyz7z/65mH6wVglIQAISkIAEJCABCUjgYgmcWfEPcy7rqnPpvF0mO2NFORzOYOnxchCI/sGaeJSlZhm7Lx59fti/6O+VT2/7qEsNkmkSkIAEJCABCUhAAhKQwM4QWNvn/NbVYhyyg/d/VlVHHm9bx9nnj7e+46QZJLBOArzdnxcr+nb/dVJVlwQkIAEJSEACEpCABCRwUQRmOf7hlLPqTpw/VrdzyHnkl2EoHwc+yr9697Wl/pgE4KV3OPp8Uo44ZeOTf9RBOXSHnjgvbRyqP+zM+fmb85EfdaM37I28VY7Ui+4ykEYegfqCB+fkxcRHtHeq/cgNhdCfGZT9O9b+kOcYf6V81k2ZHCgbcnEs5XP5Wjzrr/VfTSan5fpuvHtzcXTvKGcbl4AEJCABCUhAAhKQgAQksJME+Jzf8q9zfJ51TtfyPOeRzh9lSO+crGU8zjvHcClLPOui/Fg+OijfObFLHVF/1EXdxEkn3jm6fRyZkI16Iz/qnKofXaEb/Zxn+0Nv2MR5Lh/p1Iscx0ibOob9ZbloE+k5zjn1z2l/qbs8R3+2m7blNky1P+RDb8lzin/ZvtDTeizrK/sv68ntjPSwvzzS7ijj8eS3QhaycAw4BhwDjgHHgGPAMeAYcAzsxhiYteLfdWr/ffn49jnPTEe8cxD7T6U9/uyQYn1gdZ7AavRUfl9w5B8+w0ZdrOKy3Z9QrujyIkK2aBMef/FoaRvnLfVff+vG4u9//IHifXj40UmchBffvtnvOjjO7ero2rquz8NhN/Z3Tmao7+O5TcuMgUguW7Z/QORM8t9+9+2SW+5fCra0H/kI8IMP7Fv4Y//PP3g5xGcfp/pvSiGPj2ADL2WkHTAkLcbxlLz5EpCABCQgAQlIQAISkIAELiOBwZf7zTWW56EJMRFQyk/ll+WnznEkr71xXOdUWfKn6kcf4cevhrd248TyeEF+xAAZZIfaTX5rYNKBxxzC0cTRzhMRrXo2VW6V9k/xx2YmGmDZrbj3TcDxfvDO903Naem/MUXd7oAFEweEN758c1n02tcHvtxvScOIBCQgAQlIQAISkIAEJLCLBNbm+IfDPOQET+VPwcMJZOcATjGOIU7xd+/d7520609v9Cu0YzpWrR/drAaz2yAc87H6zpPXr/p/cLzqH8+Wxw6Gmr45Ex81+blpc9ufnf0fF8cTKkPjI2xhAoVVdgL9/OTjo43xjjo5MsHw6P3DxcGdg76+7rEEHf4MyLgEJCABCUhAAhKQgAQksLMEZm/1H2opDhuOYd5+H9vWcV6n8kMvOnC+ysC2cVbDcRxxDGMbOvFwFEuZfD5Vf+Tf+vBkq3le+UUXTj+r/bG6nPWvK84KP3Ww5b1c7c9sYBsr1HPqxpmOFfU5cpRtaT8vxItAG5iwIQTfofEB0xrXmAAJnUP2h/6x/gsdQ8d4mV/NjiEZ0yUgAQlIQAISkIAEJCABCVx2Amtb8aehOOOslOat8Nkpn8pHR2x3Dx3xJn8cO569zs74nK3grfbhWLKDgFDWFyv92YYoh33rCLHqj65ytT+zgQt/21z1b21/TCwwUZG36k/1f8mV9pUMxhijf6z/xmTJ4zN+7Axhp0K8R2JKxnwJSEACEpCABCQgAQlIQAKXncBznYG8sXwZWO3EAcsO+zLTyFYI4Lzycrk5Tu9WDJuoZJfsxlYmdtY1YTOBxmwJSEACEpCABCQgAQlIQAIXRmBwxR/HiMCqLSuphu0QYAs/zHfN6d8OndVqYTfKur7CsJolSktAAhKQgAQkIAEJSEACEtgegTOOPyugrvZvrwOipvxWefkHlfUencBaL0+1SUACEpCABCQgAQlIQAK7QWBwq3+Yf5VX/Oc+9lCuKLuVPEbRxRzL/ttk/8QOmaGWOpkzRMZ0CUhAAhKQgAQkIAEJSGDTBP4PB7kFVB7gXQwAAAAASUVORK5CYII=) ","permalink":"https://blog.zdltech.com/posts/vm%E8%99%9A%E6%8B%9F%E6%9C%BA-%E9%85%8D%E7%BD%AE%E9%9D%99%E6%80%81ip%E5%9C%B0%E5%9D%80centos/","summary":"\u003cdiv\u003e\n  虚拟机设置桥接模式，其他模式不可以（也许未配置正确，需要高手指点）\n\u003c/div\u003e\n\u003cdiv\u003e\n  目录/etc/sysconfig/network-scripts\n\u003c/div\u003e\n\u003cdiv\u003e\n  TYPE=Ethernet\n\u003c/div\u003e\n\u003cdiv\u003e\n  BOOTPROTO=static\n\u003c/div\u003e\n\u003cdiv\u003e\n  DEFROUTE=yes\n\u003c/div\u003e\n\u003cdiv\u003e\n  PEERDNS=yes\n\u003c/div\u003e\n\u003cdiv\u003e\n  PEERROUTES=yes\n\u003c/div\u003e\n\u003cdiv\u003e\n  IPV4_FAILURE_FATAL=yes\n\u003c/div\u003e\n\u003cdiv\u003e\n  IPV6INIT=yes\n\u003c/div\u003e\n\u003cdiv\u003e\n  IPV6_AUTOCONF=yes\n\u003c/div\u003e\n\u003cdiv\u003e\n  IPV6_DEFROUTE=yes\n\u003c/div\u003e\n\u003cdiv\u003e\n  IPV6_PEERDNS=yes\n\u003c/div\u003e\n\u003cdiv\u003e\n  IPV6_PEERROUTES=yes\n\u003c/div\u003e\n\u003cdiv\u003e\n  IPV6_FAILURE_FATAL=no\n\u003c/div\u003e\n\u003cdiv\u003e\n  NAME=eno16777736\n\u003c/div\u003e\n\u003cdiv\u003e\n  UUID=44fe454e-8b9a-4976-9417-71f6dfe80500\n\u003c/div\u003e\n\u003cdiv\u003e\n  DEVICE=eno16777736\n\u003c/div\u003e\n\u003cdiv\u003e\n  ONBOOT=yes\n\u003c/div\u003e\n\u003cdiv\u003e\n  BROADCAST=192.168.0.255\n\u003c/div\u003e\n\u003cdiv\u003e\n  DNS1=192.168.0.254\n\u003c/div\u003e\n\u003cdiv\u003e\n  IPADDR=192.168.0.251\n\u003c/div\u003e\n\u003cdiv\u003e\n  NETMASK=255.255.255.0\n\u003c/div\u003e\n\u003cdiv\u003e\n  GATEWAY=192.168.0.254\n\u003c/div\u003e\n\u003cdiv\u003e\n  参考文章：\n\u003c/div\u003e\n\u003cdiv\u003e\n  [http://www.linuxidc.com/Linux/2017-06/144401.htm](http://www.linuxidc.com/Linux/2017-06/144401.htm)\n\u003c/div\u003e\n\u003cdiv\u003e\n  [http://www.cnblogs.com/testlurunxiu/p/5831242.html](http://www.cnblogs.com/testlurunxiu/p/5831242.html)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  备注：主要修改添加地方\n\u003c/div\u003e\n\u003cdiv\u003e\n  BOOTPROTO=static\n\u003c/div\u003e\n\u003cdiv\u003e\n  IPV4_FAILURE_FATAL=yes\n\u003c/div\u003e\n\u003cdiv\u003e\n  ONBOOT=yes\n\u003c/div\u003e\n\u003cdiv\u003e\n  BROADCAST=192.168.0.255\n\u003c/div\u003e\n\u003cdiv\u003e\n  DNS1=192.168.0.254\n\u003c/div\u003e\n\u003cdiv\u003e\n  IPADDR=192.168.0.251\n\u003c/div\u003e\n\u003cdiv\u003e\n  NETMASK=255.255.255.0\n\u003c/div\u003e\n\u003cdiv\u003e\n  GATEWAY=192.168.0.254\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  先判断centos有没有联网 需要配置上面 ONBOOT=yes表示可以联网\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  yum search ifconfig\n\u003c/div\u003e\n\u003cdiv\u003e\n  查询到的安装就可\n\u003c/div\u003e\n\u003cdiv\u003e\n  如果新机子没有ifconfig 安装教程\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA/4AAANqCAYAAAA0a5CYAAAME2lDQ1BJQ0MgUHJvZmlsZQAASImVVwdUk8kWnr+kEBJaIBQpoXekSJfeBQHpYCMkAUKJkBBU7MiigmtBxYIVXQGxrQWQRUXEjgj2/kBERVkXC1hQeZMCur523j1n/vly5947353cmTMDgKItKycnC1UCIJufJ4gK8mUmJCYxSd0AAzpAHbgCNRZbmOMTGRkGoIz2f5eh2wAR9zesxbH+dfy/ijKHK2QDgERCnMIRsrMhPgYArsHOEeQBQGiDesPZeTliPACxqgASBICIi3GaFGuIcYoUW0lsYqL8IPYGgExlsQRpACiIeTPz2WkwjoKYoy2fw+NDvBViT3Y6iwPxQ4itsrNnQaxIhtgs5Yc4aX+LmTIWk8VKG8PSXCRC9ucJc7JYc//P5fjfkp0lGp3DADZquiA4SpwzXLfqzFmhYkyFuImfEh4BsQrEF3kcib0Y308XBcfK7PvZQj+4ZoABAAo4LP9QiLUhZogyY31k2J4lkPhCezSclxcSI8MpgllRsvhoPj8rPEwWZ3k6N2QUb+cKA6JHbVJ5gSEQw0pDjxWkx8RLeaKt+by4cIgVIO4QZkaHynwfF6T7hY/aCERRYs5GEL9PFQRGSW0wjWzhaF6YDZslmQvWAuadlx4TLPXFErjChLBRDhyuf4CUA8bh8mNl3DBYXb5RMt/inKxImT22nZsVFCVdZ+ywMD961Pd6Hiww6TpgTzJYkyJlcw3l5EXGSLnhKAgDfsAfMIEIthQwC2QAXnt/fT/8JR0JBCwgAGmAC6xlmlGPeMkIH36jQQH4EyIuEI75+UpGuSAf6r+OaaVfa5AqGc2XeGSCZxBn41q4J+6Oh8GvN2z2uAvuOurHVBydlRhA9CcGEwOJ5mM82JB1FmwCwPs3ulDYc2F2Yi780Ry+xyM8I3QSnhBuEboI90AceCqJIrOaySsU/MScCSaDLhgtUJZdyo/Z4SaQtSPui3tA/pA7zsC1gDU+AWbig3vB3Byh9keGojFu39fy5/nErH/MR6ZXsFBwlLFIGftn/Masfo7i98MacWAf+rMlthw7il3AzmCXsCasHjCx01gD1oadFOOxSngqqYTR2aIk3DJhHN6ojW2tbZ/tl5/mZsnmF6+XMI87J0+8Gfxm5cwV8NLS85g+8DTmMkP4bBsrpr2tnTMA4rNdenS8Y0jObIRx+bsutxkA1xKoTPuuYxkCcOIZAPSh7zrDt7Dc1wBwsoMtEuRLdeLjGBAABSjCXaEJdIEhMIP52AMn4A68QQCYBCJADEgEM+CKp4NsyHk2mA+WgGJQCtaADWAL2AF2g2pwABwB9aAJnAHnwRXQAW6BB7AuesErMACGwDCCICSEhtARTUQPMUYsEXvEBfFEApAwJApJRJKRNISPiJD5yFKkFClDtiC7kBrkd+QEcga5hHQi95BupA95i3xGMZSKqqI6qAk6HnVBfdBQNAadjqahuWgBWoSuQjehleh+tA49g15Bb6Fd6Ct0EAOYPMbA9DFrzAXzwyKwJCwVE2ALsRKsHKvEDmKN8H++gXVh/dgnnIjTcSZuDWszGI/F2XguvhBfiW/Bq/E6vBW/gXfjA/g3Ao2gTbAkuBFCCAmENMJsQjGhnLCXcJxwDu6bXsIQkUhkEE2JznBfJhIziPOIK4nbiIeIzcROYg9xkEQiaZIsSR6kCBKLlEcqJm0m7SedJl0n9ZI+kuXJemR7ciA5icwnF5LLyfvIp8jXyc/Jw3JKcsZybnIRchy5uXKr5fbINcpdk+uVG6YoU0wpHpQYSgZlCWUT5SDlHOUh5Z28vLyBvKv8FHme/GL5TfKH5S/Kd8t/oqpQLah+1GlUEXUVtYraTL1HfUej0Uxo3rQkWh5tFa2Gdpb2mPZRga5goxCiwFFYpFChUKdwXeG1opyisaKP4gzFAsVyxaOK1xT7leSUTJT8lFhKC5UqlE4o3VEaVKYr2ylHKGcrr1Tep3xJ+YUKScVEJUCFo1KkslvlrEoPHaMb0v3obPpS+h76OXqvKlHVVDVENUO1VPWAarvqgJqK2gS1OLU5ahVqJ9W6GBjDhBHCyGKsZhxh3GZ8VtdR91Hnqq9QP6h+Xf2DxjgNbw2uRonGIY1bGp81mZoBmpmaazXrNR9p4VoWWlO0Zmtt1zqn1T9OdZz7OPa4knFHxt3XRrUttKO052nv1m7THtTR1QnSydHZrHNWp1+Xoeutm6G7XveUbp8eXc9Tj6e3Xu+03kumGtOHmcXcxGxlDuhr6wfri/R36bfrDxuYGsQaFBocMnhkSDF0MUw1XG/YYjhgpGc02Wi+Ua3RfWM5YxfjdOONxheMP5iYmsSbLDOpN3lhqmEaYlpgWmv60Ixm5mWWa1ZpdtOcaO5inmm+zbzDArVwtEi3qLC4ZolaOlnyLLdZdloRrFyt+FaVVnesqdY+1vnWtdbdNgybMJtCm3qb1+ONxieNXzv+wvhvto62WbZ7bB/YqdhNsiu0a7R7a29hz7avsL/pQHMIdFjk0ODwZoLlBO6E7RPuOtIdJzsuc2xx/Ork7CRwOujU52zknOy81fmOi6pLpMtKl4uuBFdf10WuTa6f3Jzc8tyOuP3lbu2e6b7P/cVE04nciXsm9ngYeLA8dnl0eTI9kz13enZ56XuxvCq9nngbenO893o/9zH3yfDZ7/Pa19ZX4Hvc94Ofm98Cv2Z/zD/Iv8S/PUAlIDZgS8DjQIPAtMDawIEgx6B5Qc3BhODQ4LXBd0J0QtghNSEDk5wnLZjUGkoNjQ7dEvokzCJMENY4GZ08afK6yQ/DjcP54fURICIkYl3Eo0jTyNzIP6YQp0ROqZjyLMouan7UhWh69MzofdFDMb4xq2MexJrFimJb4hTjpsXVxH2I948vi+9KGJ+wIOFKolYiL7EhiZQUl7Q3aXBqwNQNU3unOU4rnnZ7uun0OdMvzdCakTXj5EzFmayZR5MJyfHJ+5K/sCJYlazBlJCUrSkDbD/2RvYrjjdnPaeP68Et4z5P9UgtS32R5pG2Lq0v3Su9PL2f58fbwnuTEZyxI+NDZkRmVeZIVnzWoWxydnL2Cb4KP5PfOkt31pxZnTmWOcU5XbluuRtyBwShgr1CRDhd2JCnCq85bSIz0S+i7nzP/Ir8j7PjZh+dozyHP6dtrsXcFXOfFwQW/DYPn8ee1zJff/6S+d0LfBbsWogsTFnYsshwUdGi3sVBi6uXUJZkLrlaaFtYVvh+afzSxiKdosVFPb8E/VJbrFAsKL6zzH3ZjuX4ct7y9hUOKzav+FbCKblcaltaXvplJXvl5V/tft3068iq1FXtq51Wb19DXMNfc3ut19rqMuWygrKedZPX1a1nri9Z/37DzA2XyieU79hI2Sja2LUpbFPDZqPNazZ/2ZK+5VaFb8WhrdpbV2z9sI2z7fp27+0Hd+jsKN3xeSdv591dQbvqKk0qy3cTd+fvfrYnbs+F31x+q9mrtbd079cqflVXdVR1a41zTc0+7X2ra9FaUW3f/mn7Ow74H2g4aH1w1yHGodLD4LDo8Mvfk3+/fST0SMtRl6MHjxkf23qcfrykDqmbWzdQn17f1ZDY0Hli0omWRvfG43/Y/FHVpN9UcVLt5OpTlFNFp0ZOF5webM5p7j+TdqanZWbLg7MJZ2+2TmltPxd67uL5wPNnL/hcOH3R42LTJbdLJy67XK6/4nSlrs2x7fhVx6vH253a6645X2vocO1o7JzYeeq61/UzN/xvnL8ZcvPKrfBbnbdjb9+9M+1O113O3Rf3su69uZ9/f/jB4oeEhyWPlB6VP9Z+XPkP838c6nLqOtnt3932JPrJgx52z6unwqdfeoue0Z6VP9d7XvPC/kVTX2Bfx8upL3tf5bwa7i/+U/nPra/NXh/7y/uvtoGEgd43gjcjb1e+03xX9X7C+5bByMHHQ9lDwx9KPmp+rP7k8unC5/jPz4dnfyF92fTV/Gvjt9BvD0eyR0ZyWAKW5CqAwYampgLwtgoAWiK8O3QAQFGQvr0kgkjfixIE/hOWvs8k4gRAlTcAsYsBCIN3lO2wGUNMhb346h3jDVAHh7EmE2Gqg700FhW+YAgfR0be6QBAagTgq2BkZHjbyMjXPZDsPQCac6VvPrEQ4f1+p+Sec9VwGfhZ/gnMx2wN6C944gAAQABJREFUeAHsvc+KJce5r720z8Hugg2tbvgQsuBo8225N8KGb37gXICRQRPfgAcCzzYYjXwBGgmBZwYPdAOaCGR8AQbPNxwhZMvGFkiiMVS7wVC9G0R/+WT5tyoqKjMjc/2rVVVPwOqIjD9vvPFErOr1RkRGvLRarV50n7X7H//7f6we/e6H6+f//uLZ6s//8fn62cB+CTz84P9ZvfzWwxvJ/M1v/7/VX372p9XZr/+xX0gbSv9/P/+P1XffuLcu/Yf/839X3/7+2/WzAQlIQAISkIAEJCABCUhAAreRwP+sG4Uh9Nn/+K862uc9E/jeJ/9rdf9HD/pa5L8f2E5g7YerUiUgAQlIQAISkIAEJCCB4ybwUqeeK/4jfZTdD3MNcVeUR0BeU3Tdf/bPNXWE1UpAAhKQgAQkIAEJSEAC10rgyop/tJlr7Cb/ofzaeDsmPbOiHIPzUEysZx6B9A+5eS1hzLH74snHp6vnn56tXv/wjRv52sVY24yXgAQkIAEJSEACEpCABO4egX85tiZjkJ2886+DapH299+c9q8iYPA//uXXK4w0nQR2SeDe90/6cwq+84OTfrztUrayJCABCUhAAhKQgAQkIAEJHJrAIsM/Rjmr7oT5sLpdujKN9NqNpWPAJ/+//erf1/IzCcChdxj6pz//24oweV/5z++txZMP2ZGT51rHsfojqEy//5OHiV77qRu50XeduEWAepFdO+JIw1FfePBMWiY+0t5W+yk35iK/ZFD371T7Ux4/n7p8KZs8pSNvysWvy5f5h8Kl/KH+GypTxpX1PXj74erss7My2bAEJCABCUhAAhKQgAQkIIEbSYB3/NefzvB50Rld6+cyjXg+5CG+M7LW4Tx3huG6LOFSFvmn0pFB/s6IXctI/amLugkTT7gzdPswZVI29SY9dbbqR1ZkI5/nUv/IjU48l/kTT72Uw09cy4/+db60ifgyzDP1L2l/Lbt+Rn6pN20r29Bqf8pHbs2zxb9uX+TM9ev66v4r5ZTtTHz0r33anTz6F38rZCELx4BjwDHgGHAMOAYcA44Bx8DNGAOLVvy7Tu2va8sVaLwznXBnIPZXpT396JRsvWN1HsdqdCu9zzjxD9ewUReruGz3x9Urulw9mKvknv72yVo38s6pn1P1v3n/K7L37vF7F2EiuGaPXQdxtLW8Hi7xm/jojf6dkbkuTrhs0zphJFDmrds/UuRKNNfxpU/L/iXjnPZTPg5+8IH9HP7o/+q7r6X4Yr/Vfy2BvD6CDlzzRztgSFzGcau86RKQgAQkIAEJSEACEpCABI6RwOjhfkuV5X1oXIzGunwrvc7fesaQvPfovM5WXtJb9SMPx4FuYw4jltcLylcMyEvZsXaPyRqKZ9KB1xxiaGJolxMRQ2UOGbdN+1v8aQcTDbDsVtz7ZmF4f/3jL2c1cU7/TQnqdgesr1N89LsfrrPe+/zEw/3WNAxIQAISkIAEJCABCUhAAjeRwM4M/xjMY0ZwK70FDyOQnQMYxRiGGMV//ekXK4y0+98+6Fdop2RsWz+yWQ1mt0EM86n6NknrV/3fPV/1z7vl2cEwJG/JxMdQ+aVxS9tfGvvPV+cTKmPjI7owgZKbGujnZx+c7Y136sRnguHJO6erkzdP+vq61xI0+EtAhiUgAQlIQAISkIAEJCCBG0tg8Vb/sZZisGEYltvvs20d47WVHrnIwPiqHdvGWQ3HcMQwzDZ0wjEU6zLlc6v+pL/yi4ut5uXKL7Iw+lntz+pyKX9XYVb4qYMt7/Vqf8kGtmxtX+owprOivrTsnPZzIF4cbWDCBhe+Y+MDpkNcMwESmWP6R/5U/0XGmJ/D/Ib0GCtjvAQkIAEJSEACEpCABCQggWMnsLMVfxqKMc5KabkVvjTKW+nIyHb3yMhJ/hh2vHtdGuNLtoLP1Q/Dkh0EuLq+rPSXOiQf+u3CZdUfWfVqf8kGLnwOueo/t/2ZWGCiotyq3+r/mivtqxlMMUb+VP9NlSWNa/zYGcJOhZwj0SpjugQkIAEJSEACEpCABCQggWMn8FKnICeWrx2rnRhgpcG+TjRwEAIYrxwut8ToPYhijUpukt7oysTOriZsGmhMloAEJCABCUhAAhKQgAQkcG0ERlf8MYxwrNqykqo7DIGlJ/kfRqvbUQu7UXZ1C8PtIGIrJCABCUhAAhKQgAQkIIG7QOCK4c8KqKv9h+/68lR5+e+HvxNY++GqVAlIQAISkIAEJCABCUjguAmMbvWP2nd5xX/paw/1irJbyTOKrsev+8/+uZ5+sFYJSEACEpCABCQgAQlI4HoJXFnxjzrHuupcG2/HpGdWlGNwhqX+cRBI/6BNXmUZ0ozdF08+Pu0P+nv9wzd81WUIknESkIAEJCABCUhAAhKQwI0hsLPr/HbVYgyyk3f+dVAcaZy2jrHPh1PfMdJ0EtglAU7352BFT/ffJVVlSUACEpCABCQgAQlIQALXRWCR4R+jnFV3wnxY3S5dmUZ67cbSMeCT/99+9e9r+ZkE4NA7DH2ulCNM3lz5Rx3kQ3bk5LnWcaz+6Fmml3fOJz11Izf6Jm0bn3qRXTviSMNRX3jwTFomPtLeVvspN+Yiv2RQ9+9U+1MeP5+6fCmbPKUjb8rFr8uX+YfCpfyh/hsqU8aV9T14++Hq7LOzMtmwBCQgAQlIQAISkIAEJCCBG0mA6/zWn87wedEZXevnMo14PuQhvjOy1uE8d4bhuizhUhb5p9KRQf7OiF3LSP2pi7oJE0+4M3T7MGVSNvUmPXW26kdWZCOf51L/yI1OPJf5E0+9lMNPXMuP/nW+tIn4Mswz9S9pfy27fkZ+qTdtK9vQan/KR27Ns8W/bl/kzPXr+ur+K+WU7Ux89K992p08+hd/K2QhC8eAY8Ax4BhwDDgGHAOOAcfAzRgDi1b8u07t75fP3ee8M51wZyD2V6U9/eiUbL1jdR7HanQrvc848Q/XsFEXq7hs98fVK7ocRMgWbdzT3z5Z68bznPrv/+jB6pv3vyJ77x6/dxEm4uW3Hva7Ds5Tuzq6tu7qejj0Rv/OyIz4Ply2aZ0wEijz1u0fKXIl+i8/+9OaW9m/ZJzTfsrHwQ8+sJ/DH/1fffe1FF/st/qvJZDXR9CBQxlpBwyJyzhulTddAhKQgAQkIAEJSEACEpDAMRIYPdxvqbK8D43LREBdvpVe5289Y0jee3ReZysv6a36kYd7/un41m6MWF4vKF8xoAxlx9pN+lzHpAOvOcTQxNAuJyLmytlXvm3a3+KPzkw0wLJbce+bgOH99Y+/nNWcOf03JajbHbBi4gD36Hc/XGe99/mJh/utaRiQgAQkIAEJSEACEpCABG4igZ0Z/jGYx4zgVnoLHkYgOwcwijEMMYr/+tMveiPt/rcP+hXaKRnb1o9sVoPZbRDDfKq+TdL6Vf93z1f98255djAMyVsy8TFUfmnc0vaXxv7z1fmEytj4iC5MoLDKjqOfn31wtjfeqROfCYYn75yuTt486evrXkvQ4C8BGZaABCQgAQlIQAISkIAEbiyBxVv9x1qKwYZhWG6/z7Z1jNdWeuQiA+OrdmwbZzUcwxHDMNvQCcdQrMuUz636k/7KLy62mpcrv8jC6Ge1P6vLpfxdhVnhpw62vNer/SUb2GaFekndGNNZUV9Sjrxz2s+BeHG0gQkbXPiOjQ+YDnHNBEhkjukf+VP9Fxljfg7zG9JjrIzxEpCABCQgAQlIQAISkIAEjp3Azlb8aSjGOCul5Vb40ihvpSMj290jIyf5Y9jx7nVpjC/ZCj5XPwxLdhDg6vqy0l/qkHzotwuXVX9k1av9JRu48Dnkqv/c9mdigYmKcqt+q/9rrrSvZjDFGPlT/TdVljSu8WNnCDsVco5Eq4zpEpCABCQgAQlIQAISkIAEjp3AS52CnFi+dqx2YoCVBvs60cBBCGC8crjcEqP3IIo1KrlJeqMrEzu7mrBpoDFZAhKQgAQkIAEJSEACEpDAtREYXfHHMMKxastKqu4wBNjCD/ObZvQfhs52tbAbZVe3MGyniaUlIAEJSEACEpCABCQgAQkcjsAVw58VUFf7D9cBqak8VV7+obJb3wms3fJUmgQkIAEJSEACEpCABCRwMwiMbvWP+nd5xX/paw/1irJbyTOKrsev+8/+uZ5+SK27ehWE2z046HPo+5U+T52H/vs1p/4p/aO3vgQkIAEJSEACEpCABHZJ4MqKf4Qf66pzbbwdk55ZUa5//Iep/vUSSP+gRV5lGdKI3RdPPj7tD/p7/cM3fNVlCNKRxtFfORD0OlS87vqvo83WKQEJSEACEpCABCRw/AR2dp3frpqKQcaK2JAjjdPWMfb58AMfI00ngV0S4HR/zljwdP9dUt2dLPqG7//QwYyc4VBfAbm7mtuS5tQ/pX+7BnNIQAISkIAEJCABCUhgOYFFhn+MclbdCfNhdbt0ZRrptRtLx4BPfrbxRn4mATj0Lit5hEnPlX/UQT5kR06eyVfqOFZ/9CzTyzvnk566o1/it/WpF9m1I440HHWGB8+kZeIj7W21n3JjLvJLBiU7yk21P+XDBr8uX8omvXTkLcsOlS/zD4VL+UP9N1SmjCv1ffD2w9lGJPVed//N4TfVf4yhmn/JhrSMs+QreZG3lg+X2mWMIiPjt84z9Fz2LWVLlzTiyr8ftfyWfpGT9pV1EEf7h/RPuan6k2dIduop86SepOlLQAISkIAEJCABCUhgGwJc57f+dD/kX3Q/TNfPZRrxfMhDfPcjdR3Oc/fDel2WcCmL/FPpyCB/9+N6LSP1py7qJkw84e7HcR+mTMqm3qSnzlb9yIps5PNc6h+50YnnMn/iqZdy+Ilr+dG/zpc2EV+Geab+Je2vZdfPyC/1pm1lG1rtT/nIrXm2+Nfti5y5fl1f3X+lnLKdiY/+tU+7k2fMP5b+G/ruROdW/5V9TZm6v8Il+cbGR9JTb/yUL3UkrnxO3il/jDVlpuSl/WP61e1N/ugyR/+p+iNnTP8l4zey9C/+75KFLBwDjgHHgGPAMeAYcAyMj4FFK/4dyP5++Wyx5Z3phLsf0/1VaU8/OiVb705//rfe737o9iu/bIMdS/9nkVGPstTFKi7b/XH1im55Dd7T3z5Z60beln69vB89WH3z/lcEe/f4vYswES+/9bDfdXCeuurbgl67cGz/Rf/O2FiLI1y2aZ0wEijz1u0fKXIl+i8/+9OaW9m/ZJzTfsrHwQ8+sJ/DH/1fffe1FF/s32/0X0sg28fRgUPjaAcMics4nip/DP3X4tfqv3yX085nfzxb3Xt0ksfenzM+ajmlAMrDKg6dD+XS/iH95oxP9Nyn/tuO30NxtB4JSEACEpCABCQggZtHYPRwv6VN4X1o3NCPauJb6eRZ4vihXhslU+Vb9SMP9/zTs1ExGLG8XlC+YkBmyo61e1TYQAKTDmxTjqGJoVJORAwUOWjUNu1v8achTDTAsls17duF4f31j7+c1cY5/TclqFttXWF44R797ofrrPc+P5l9uN9191+L35z+61a9+8maAKAP5jrkX+f79S09p/SbMz5b8rdJ33b8blO3ZSUgAQlIQAISkIAEbj+BnRn+MZjHjOBWegs1Bgg7BzCKMQwxiv/60y96I+3+tw/6lbgpGdvWj2xWJ9ltEMN8qr5N0vpV43fPV/1jQJWro7XMJRMfddlNnpe2vzSmnq/OJ1TGxkf0YQKFVXYc/fzsg7O98U6d+EwwPHnndHXy5klfHwYwhvQSdwz9N8Wv1X+0mVX+tJvJkCUO+fA7W12s6C8pv++8U/rt4u/DvvVXvgQkIAEJSEACEpCABDYlsHir/1hFGBz8sC6332fbOgZRKz1y8+M8z/HZNs5qOIYjhiHGSYycGIrJO+S36k/6K7+42GpervwiE6Of1f6szg3Vs20cq8bUwZb3erW/ZAPbrFAvqRNjOivqS8qRd077ORAvjjZkxTh8x8YHTIe4ZgIkMsf0j/yp/ouMMT+H+Q3pMVamjt93/9X15XkOv1b/sSL+7A8XO1643WCJi3wm6I7RTemX8TM2PvfdntS/zfjdt47Kl4AEJCABCUhAAhK4uQR2tuIPAoxxVg3LrfClUd5KR0a2S0dGTvLnhzHvXpfG+JKt4HP1w7BkBwGuri8r/aUOyYd+u3BZNUZWvdpfsoELn0Ou+s9tfyYWmKgot+q3+r/mSvtqBlOMkT/Vf1NlScPQZeWXnQoYiZu46+y/Fr9W//H+OpNr+e7lefXJ+Y6IFo/IR8bqVxe5y78BF7GHD7X0a43PfWu87fjdt37Kl4AEJCABCUhAAhK4uQRe6lTnxPK1Y+UQA+JYfqyvFbtDAYzX+hCxm9D8m6Q3ujKxs6sJm7J/bhKHUm/Dx0WAnRPsmmFCQCcBCUhAAhKQgAQkIIFtCIyu+GO84Fi19YfnNoiXlV16kv8y6Xc7d31w3T5o2H/7oHo3ZWL0c+aCTgISkIAEJCABCUhAAtsSuGL4swLqav+2WJeXL0+Vl/9yfnNK7HMCy/6b0wPmmSLApFFesyDf0leZpmSbJgEJSEACEpCABCRwtwlc2eq/CxxsUeVd6W22UfPKQV1+KG5I37n5hsomjh/heSc4ccjl/e8l752n7FyfOsp3te/ijgvGD++J72sr/ty+MJ8EJCABCUhAAhKQgAQkIIHbQODKin+5cjnVwJZBuu05ARjYr354+f3W1z98oz/8j9PXn3x8OmqAk4/D2WrDnfbkFQbCU23gukA+9Spxb5B+up93w9EJ3XOgIc86CUhAAhKQgAQkIAEJSEACEpDANgSuGP6cwv716stJmazIcl/3lMs1blN56rR6tZv0GOoYwzhW2/kwQZE71/uE6p8Y/Vk9TvKc7bOU4d3anEhfHtbGZEG9EyGyd+FzpVp9hd0u5EZG2ZbE7dLfhXz697Nf/9cu1VKWBCQgAQlIQAISkIAEJCCBO0tgo63+MfxjXIdejPQ8lz7btrmjur57fswQH6qDw9nKFfgyD+H+GrGi0npFn4kFdIhBT1YmEMpn4sp6yjrqtKGy5NnEjR08V/IZamN5HsDQxEm2y4/t5KhvD6jfM96VfHTPYWWMAerlmYmO6FgzKOuGaSYVUo64lJ2TTp6pOlryKa+TgAQkIAEJSEACEpCABCRwEwlwnd/60xmPLzoD6AV+GV+GOyPuRWcgzkpHTmd09nnxS7nIQBayUy918yEv6XnG74y2S8/JU8pEFvmGZJayEqb+snzqTPtSR/KXfotDyWxuGPlhUpcp9SSNdkZPnqfKRtZUnrQ9eXkOy23l06bUnXpoT/imTvzkLeNSPzLCAd0SnpNe84oeqQfZU/KTT//i74UsZOEYcAw4BhwDjgHHgGPAMeAYOP4xcGWrf9dpvSsPmEtc6WfrfRm3Tbi8TaAz/PrV4MfvfdW/p98ZY/1NA52h1m+DZys4eVjhr1fro0NnEPbvy7NqTJj2oPO9RyfrMsgrDyEkH45V9qcfnfblcpZAdjd0xuOlXQdnq3+kyr379SsGvI5Ae+LY4cBq+J9/vdm935xpUPYrDMpTxreVT/m+7z446RnX7Uk7pnx2CqRcufsjZcbS6Vt2F9CmOPqU9jGW0As3Vj5l9CUgAQlIQAISkIAEJCABCdw0AoOGf7m9fJMG8e79Ju+pY+DjMBC/ef+r9en2GO+9cfbZWf9eP8Y2Bi7bvGuHMY+BxyF5GIYY6rhMANzrtvp3q8zrVw7KiYCUIR035wR/DMoYopTJpMWQUUr6to720L44+iqOOtEnHJf2I3IxhEtjH9lp47byo+d1+PQlruyr69DDOiUgAQlIQAISkIAEJCABCRyawKDhv60SGNPlyuqzP5zNEolxjtHNSj8G2n+/+6w33onLyv6rn7/Wy+LU/tKIyw4AVqyZOCgN7zJMYWRxgGHqIo7ydT7iY0QTjivjqOuvP/1irUvOGegnKv65ipxy2/oY/azyR89MUJRyYQJHHHo+++Bs8HaDskzCtGXsNoTk2UZ+ZFyHz84OXCYxrkMH65SABCQgAQlIQAISkIAEJHAdBP5lm0oxbofcve+frA3hrLQO5avjMMrYWs/KO0YrK9D4xLGSj8v29my9j4z+JPjO4K3jSUcGn/s/edhnR1b/3B0yF5et3nnGj0wM6XwwjhPGxwgvJyCSNiSvlL1JGB7lJAqc42DHp3b1zgv0H7uRAaOf1f4hObuQX+t2yGf6iLZnDFB3xtQ++uqQbbMuCUhAAhKQgAQkIAEJSEACUwS2WvHHgHz+v88uGb4YU2zTj1uy7R/j7Oz3/1i/o45xjmMVHYMa4xNjFwM4Vw7OWVmnLK4v3231Z3KAz9CKeZ9xi3/Q58HbD9c7FLYQdaUo75/DIlvx87z6ZNXvkqjPZWD3Q23U0jelDPJksiR+LSevVNTxS+VfadCBI5ikYddE+FF9xsaBVbE6CUhAAhKQgAQkIAEJSEACByNw5To/jOPawGtpE+OJsqyossqMcRnDNFeuYWjX1/mRJ8Zpnc4Kbba1Y1D3B9f98z12dKReJhpisEZPjLuUK8PoV17nR315rSBl8cfiKZ9zAMr8ZTiTFWlzmWZYAhKQgAQkIAEJSEACEpCABCRwaAJXVvzLd7iXKFMbxZ/9+r/61dVMCkRWaRBjtMfoJz3v3hOOPAx+JhE4qC7GfHSMkR3DHyOf3QC1Sz4mEljxzjP5MPx36er27lK2siQgAQlIQAISkIAEJCABCUhAAksJXFnxXyrA/BKQgAQkIAEJSEACEpCABCQgAQkcL4GtDvfbtlms6per75HHKj/xpB+jO3b9jpHZkE5j/T+Ud25cZDJ++LAL5K442svY3JULy7nydl3/3HrLfNF5qv/Hvr+MlZTDR5ZOAhKQgAQkIAEJSEACt4HAla3+t6FRtuHuEuAMhvLAwrtL4m62fJv+z6tEGPxLzzm5m7RttQQkIAEJSEACEpDATSFwacX/GFbsAMd7/7wrz7v8x+iOXb9jZHYonTjjob7C8FB1W8/+CbT+Rs3pf7+/++8na5CABCQgAQlIQAISOC4Ci1f86wP0ysPs2ELLQXylK9OJL8uzMlu6Mo34uiw/+rkFgOvycjsAh/5xKGBcKYM08tVykrf00Z1bA5798awvQz08Y0jkQMJSNmVrudEv5ciTsoRb6eSZqmNOeWSMuaGVzCH9yj4s05HLgYxT1+G10sv21f3f0m+sXcSXcnv9f3Weuxwfc/iVcpCQPp4zPs5rnP635lPfXFGyL+uP1KnyyVPejlG2n/S6fNqXsmX76/5JnpY/VX8pHzll/VP9X8os+ze3gpRyy/Sy/WWeuu5Wm5Le4pd8+hKQgAQkIAEJSEACEjg2Ai86hfpPZxi96Ayc9XPi43c/nF90P3zX6YQpk/Tuh/s6TFydv/vx3sclP89l+cSjw1A8cXxKHcvnufJTT+mnTvy0i/Ygs2wzZZK3LE84+oUD7U94TnrNK3qknpb85BvzS1ZDeSI/aTXPWh+e0Tn5W+m1PJ6pM+Vb+iXflD8lI+1Ln9T9M8U/fT5nfIzpFz6pv85Xx4/pU+eLnLQPHcu4PKf+pNX91+qflBvzW/WPtSfypvpubp45MtKXkVn78EVOzbnFr5bj8/n/K3KQg2PAMeAYcAw4BhwDjoHrHwOXtvp3HTLquh/B/er3049O13lyjV73Q7qPq7fms3p+79HJOj+r71ynF7fJVXpZ4YsMVkzjtpWPrFwvyEph3Z7UM+WjX8rxznDCKTOWPocvMsbKR/6UT/vYjTDlkB9H/7DjAd1wL7/1sH9/PumMBdLjWumt/pmjX+ra1B/jN4f/tuMjfOoxkbbU8fX3p1UeObQvY5hndI5L+TzX/dfqn5Sb8sfqn8u3NT6n6t53WovfvutXvgQkIAEJSEACEpCABDYlMHur/3d+cG7A18ZJXXG3qnfJGMSAxsV4fP7pWV1kJ8/7lr8TJSeEzOU7IaKZxEQEnLrVzD5vuQ26WbjLgJHPNv9yqz/lkMm4mEqP/Kn+31a/1LGJfwj+8GmdPzD2/aFNc8pPtX3b/pmS3Uqbw/c6+7+lP+lT/Fp/F+fIN48EJCABCUhAAhKQgAT2RWC24R+DLUbekEIYLaxS8gMe120dHspm3ACBOXwHii2OwkDJe9VMADz74GyVnRu1sNpYY/X47785Hc0/lZ6JmbqO+nmJfnXZbZ4PwR8+J2+erM5W/xhUtfX9aZUfFFpE7qJ/CnGLgnP5Xlf/z2nMFL855c0jAQlIQAISkIAEJCCB6yIwe6s/P8j54Xv/Jw/XunbvvPbhbC1mRezZHy5W9O99/2Kbf8q/8ouLrea7vDJr3/LXjd5TIPpP8d2magzvIeO7XoHm4MQ4tl1nxwZxGP2s9g/JaaWnfWP9P1e/6LZrP/rti3/JJ6/G1G2Y+v7MKV/Lq5+n+i/tH+ufWtbS58gf4zu3/zP5sbT+XeSf4rcL+cqQgAQkIAEJSEACEpDAvghcWfEvT8Sm0nI7OCv5rEqWW72zekxe3u+lfNLzvPpk1Z+8T3lWme9/+4Ds/Yn3uzT+9y2/V3qP/7T4blt1zZpT2zNpU8rOqwAYWeWNCdkZUMvJyf+t9Fb/1HLH9Ct13WV43/zDp/6O5TuU78vY96dVvsUi5WvO6b9W/7Tkt9JbfGu9hvqfM0LKvzHkSbta9W+bnnpqPcNvW/mWl4AEJCABCUhAAhKQwL4IvNQJ5gTwW+lYWWXVGoND1yaAwV8fztYuZQ4JSEACEpCABCQgAQlIQAISOGYCs7f6H3MjxnTD6OfMAZ0EJCABCUhAAhKQgAQkIAEJSOCuEriy1f8mg+DMgWyTph3lawo3uV3qLgEJSEACEpCABCQgAQlIQAIS2JTAQbf635Wt5LxiwHvId+3d3/oqurH231U+m35JLScBCUhAAhKQgAQkIAEJSGAbAhtt9eeavpzov03llr1dBDhLgYPqMPh1EpCABCQgAQlIQAISkIAEJHAcBBYZ/hj8XLvFlX1cA8fKrRMAVzuSk/IxgLnCTHeVgHyuMjFGAhKQgAQkIAEJSEACEpDAvggsMvyffHy64iqrpx+d9vr097z/M7xEQbaEs+2fT3knPBMJiY9fyiVv4uOX5cnLRETS8Idc6h9KG4tDN8ox+YHcPBOODpGb+mtZdbmyLHlb6eSZqqNVfg4/6hhzrf4ZK5f4Kd1JG5pEIo40XNoXeaTRH3FJTx/xXKYn35Rfj5/UnTJjbch4SN15RoeMj8jQl4AEJCABCUhAAhKQgAQkcGgCXOc3+9MZRi864+ZFZwC96Aya2eWoozOC+k/KRU7qT3yeqYP68kz5zqBaPyc+PnnJUz4jI8/xiSvzJX7Kp97Un3rQlzaUOiIjeWt5lOeTdtYMW+k1j+iRelrlSZ/iFzljfvROeq1P4slXtjPx8Yf4DMWRv9S5DJNG++EfuaTXeern5B3yw7NuZ/LW7U1+0qM/fuKRMzQ+Ik9//t8dWcnKMeAYcAw4BhwDjgHHgGPAMbD5GFi04t8ZMv2p+V//+MvVN+9/tXr9wzc69ssc98RnC/zj975affeNe+sV0cRHIlfx3Xt0ksfVf3/xbMUugzH38lsPV49/+fU6mZ0JyK9d3kWv41vP1M82dRw3BtT6tsqTXrYfPWoZY+mwpy3ZbYGs05//Da/ffdAHun/GypPe4hcZY36ta90/Y+XmxMMV/TqjeZ2dcMl8nTARoP3pI7JRfq7L+KnbSfk5/EtdNx0fc3U1nwQkIAEJSEACEpCABCQggbkEFl3nh0HEu+s4jKs///rzufXMztetql4y1jGg4jCUMcC6Vdw+qr6uD8OY6/zKK/3ISJkhYy5yb4L/nR+cT4Bs044WvzkcpvpnTvmpPEwmcRtCJjQwxIk7lGP8cHbFkNsF/yG5xklAAhKQgAQkIAEJSEACEtg3gUWG/66VqY0pjEpWkTFQcd026StVlpMPTAA8++BsbSiy4vr335yun68UvsERzz89N0i3ncSY4tfCM6d/WjKm0vtV/3fPV/1jgJer93XZcjdInbbJM+Pn5M2T1dnqfFdHKWNX/EuZhiUgAQlIQAISkIAEJCABCRyCwKKt/rtQ6MHbD9di+sMBixV9Vly5MSDu3vcvtvlj8PKpXQxE4jH6We0fyleWw4DNroEy/pjDGOwYpvd/csEv2+KnjOO0aQ4/8sJljM1U/6SebX1W+OlDxka92h/DnDpo+/0fPVhc3VT7Mn669/SvyN2W/xWBRkhAAhKQgAQkIAEJSEACEjgQgYOv+GPYx7DEkOO8gDjez2ard7bq53n1yWrFeQDcKFA63ucvjd5sEa/zca88httNd+yEYNIifGhPXr2Y07aaS82vJSP9kfrzTP+U/diSM5WeVX/ylH3Lc14FoH5057PLVf+MH8bg6lfUeO7CeFv+kacvAQlIQAISkIAEJCABCUjgkARe6irjVHSdBI6GABNDTCrUhv/RKKgiEpCABCQgAQlIQAISkIAEbhCBg2/1v0FsVPUaCGxykv81qGmVEpCABCQgAQlIQAISkIAEbgyBg2/1vzFkVPSgBDjIMe/sZ2v9QRWwMglIQAISkIAEJCABCUhAAreUgCv+R9ixHC7HdvfWIYVHqPrGKnFGAGc+4HIA31j77yKfjcFaUAISkIAEJCABCUhAAhK48wQ2MvxZnc2J8neeoAB2RoDD81jt5zBGnQQkIAEJSEACEpCABCQgAQnshsAiwx+Dn1VYTubnGj1WXg89AcBq8NB1a7vBcRxSONQOA/g23ESwD6Ly2QdVZUpAAhKQgAQkIAEJSEACt5XAIsP/ycen/ZV6Tz867Xlw13rCcwExUZCt3PhxTCjwXE4kJC95mHRIfq5bi4xyEoA4nrnyLunldnHSEh8/9eNHh6Thl+WTN/LzPMePXmlHnss6Ijf113KJL8uVZcnbSifPVB2t8nP5UM+Qa/EfKlPGTelOWjl2Uo440nBpX5lGf8QlPX3Ec5mefFN+xixl+aTulBlrQ/o1decZGUNjMPL0JSABCUhAAhKQgAQkIAEJzCHAdX6zP51h86IzTl50BsyLziCZXY46KNsZMusyPCMn9SOP9M7o6WUTrutIesqUPmllmVrHWhbp6BAZU7KTB59y5C3jWmHaFPnhgD6wLHVATvLWMinPJ+2o29dKr9sbPVJPqzzp6Jb8S/3onXK1PoknX9nOxMcf4jMUR/5S5zJMGu2Hf+SSXuepn5N3yA/Pup3JW7c3+UmP/viJR87Q+Ig8/fl/t2QlK8eAY8Ax4BhwDDgGHAOOgbs8Bhat+HeGyOqV//zeioPYvnn/q9XrH77RsZvvXn7r4erxL79eF2C3wHffuLd+Zms76azoI5vw0u3u3P+eMrwznjCVlGGen/3xbHXv0QnB3nG4HLsYWi7vorfy1enIz930T3/75Io+df6h56n2kX8snb6DdblD4/Tnf+ur6IzNdVVj5ckwl89aWBVo8a+yL3qEK/p1RvO6HOGS+TphIkD700dko/xcl/Fdt5Pyc/iXum46Pubqaj4JSEACEpCABCQgAQlI4O4QWHSdHwZNrlrDOPrzrz9fRArDk4kDPqXDKIqxhDGKAYWLYVrm3TbcrbpemmzAwIrDoEeXbpW3jyKNSY7b4L7zg/MJjnDepE274DPFfxOdyjJMRjFplHHDOCLuUI7xzdkXQ24X/IfkGicBCUhAAhKQgAQkIAEJSKBFYJHh3xLWSmdF8++/OV0bZkP5WaVlJZ473bttzjs1vDE6kY0Bi0N+7crJDSYAnn1wNqlvXf5Yn59/em6QlpMsm+i6DZ85/DfRKWX6Vf93z1f9Y4CXq/fJF7/c7ZG4bXzG98mbJ6uz1T+uiNkV/yuCjZCABCQgAQlIQAISkIAEJNAgsGirf0NWMxmjn9V+jM8hx5bzvErAlW4Y/+U2dMrEuBoq34pjRZYbCeLuff9imz86DekVAzJl8DFgsyugjD/mMAY77O7/5Hw3BbpmW/yUcZw2zeUDlzE2U/xTz7Y+K/yMIV7ZqFf7y7FD2xlfS91U+zK+6zFLHdvyX6qn+SUgAQlIQAISkIAEJCABCYTAQVf8swX70e9+mPp7P/e2s02bd6xxGEp53/8vq4v3rrOdO68LkCdy+4IT/yCbOlI2z6tPVqvH733V31hQFkf2HKO4LHPMYXY6MGmR9qNrXt2Yo3fdb0v5hHfqzzP8d/VKRVb9aU/dd+XYQXc+u1z1zzhkjK1+dUE0jLflfyHRkAQkIAEJSEACEpCABCQggfkEXuqycqq5TgK3hgCr8kwq1Ib/rWmgDZGABCQgAQlIQAISkIAEJLCAwEG3+i/Qy6wS2IjAJif5b1SRhSQgAQlIQAISkIAEJCABCdwQAgfd6n9DmKjmDSTAQY15Zz9b629gM1RZAhKQgAQkIAEJSEACEpDAzgnc6BV/DpwbO0hu56SOSCCHx9HuocMIj0jNnauSQxVzwF7Zfs4IwODnc1f57By4AiUgAQlIQAISkIAEJCCBW0FgI8Of1dWcCH8rKNiIG0GAw/Ew7HMY5I1QWiUlIAEJSEACEpCABCQgAQlcM4FFhj8GP6usXInHNXesrN60CQBWi4euW7vmflhUPYfWYQBz84HuKgH5XGVijAQkIAEJSEACEpCABCRwdwksMvyffHzaX3n39KPTnhh3pSc8B2FtdDNpwGRCXNKzlRu/3M5NvnK7d3knPWnZ4l2WJx5HPcTjuG4teepJAHRKWvL3hbp/0KVMI1zrR97omHJzfPSgXPTMc1lH5EaHWi7xZbmyLHlb6eSZqqNVfi4f6hly6E4d5Wco31jclO6kDU1SEUcaLu2L/LHxmT4ifzl+U27Kr8dX6k6ZsTakX1N3ntFhaAxGnr4EJCABCUhAAhKQgAQkIAEIcJ3f7E9nuLzojI8XnYHyojM4Zpejjs5IedEZLOsykZX6SeeT59Qz9Vzmr/VBR+pIefxahzKNvKU8npGRPFNlkwefMqWcMm0sDJfIjx60BwZ1G5K3lkV5PuFQ91ErveYVPVJPqzzpZf+m3Fw/eid/rU/iyVe2M/Hxh/gMxZG/1LkMk0b74R+5pNd56ufkHfLDs25n8tbtTX7Soz9+4pEzND4iT3/+3zVZycox4BhwDDgGHAOOAceAY+A2j4FFK/6dobF65T+/t+IgtW/e/2r1+odvdGx267h/Pe7xe1+tvvvGvfWKJqe2U28c6aWrt74/++PZ6t6jkzLLZPjltx6uHv/y63UedjNQf9x/f/FsxS6Hlsu76K18dTryc/f8098+2WgrP/zCAT0STl1j6fQtbS13cJz+/G99sc7YTPHVWHkyzOWzFlYFal2X9l8l7tIjXNGvM5rX8YRL5uuEiQDtTx+RjfJzXcZX3U7Kz+Ff6rrp+Jirq/kkIAEJSEACEpCABCQggdtDYNF1fhgsvFuOw/j5868/PxgJDCPc80/PJuvsVk0vGesYSHMdhi8TG3xKR920HUOacLfK2ycjm0mQ2+C+84PzCZIho3Ru+3bBZ5v+a+nJpBGveWRCA0O8nEhqld82nfHF2RhDbhf8h+QaJwEJSEACEpCABCQgAQlIYJHhv2tcrdX40hiK4T+lA0Yjq8QYoLhuG/RU9itprKj+/Tena8PwSoYuopz8YALg2Qdnk/mHZBxjXCZUMsmxqY7b8Nm2/1o696v+756v+scAL1fv6/Kt8Vnnbz0zvk7ePFmdrf5xJeuu+F8RbIQEJCABCUhAAhKQgAQkcOcJLNrqvy2tGD7IYZs1W/dr9+Dth+uo/vDAf67YY1BS/pVfXGy1f/S7H67zEmBFlRsH4u59/+o2/1KH5IuP0c9q/9AkA3FD8TEgIwMfAza7Asr4Yw6Hb3lgYrbFTxnHadNcPnAZYzOn/1Lfpj4r/PQxY6te7S/Hxtj4bNU71b6Mr/LVicjbln/k6EtAAhKQgAQkIAEJSEACEqgJHHTFP1utMbx4l57P0KpqDEMMsXIrPSv5pN3/9nzCgPvcS+Of96/Zyp2t+nlefbJayyl1AAY6ZOt3/FImeXJvfB1P2TlGMTJugoMvkxbhh855tWOO/tvySX+l/jyX/TdHj6k8WfUnT9135diYGp9T8qfSMr4Yo6tfXeQM4235X0g0JAEJSEACEpCABCQgAQlI4ILAS12QU8uPwmHUY+zVBtlRKKcSt4aA4+zWdKUNkYAEJCABCUhAAhKQgARmEDjoVv8Z+phFAnslsMlJ/ntVSOESkIAEJCABCUhAAhKQgAT2TOCgW/333BbFS2CUAAc95kyJbK0fzWyCBCQgAQlIQAISkIAEJCCBW0TgqLb63yKuNkUCEpCABCSwcwIcDso5IZw9w6GgpeOQ1fKsFc7JyS03Zb59hefUP6X/vvRSrgQkIAEJSEACq5Ur/o4CCUhAAhK49QRqo3ROg7M7KMbqWJmn3e0z2VFU5jn0mTWvf/jGpQNrS10OEb7u+g/RRuuQgAQkIAEJ3GQCHO7nRwaOAceAY8AxcGvHQGf4v+he+Vm3rzPmLz13N5qs0/J/ImUSjt+dE/KiLstz0uMPyUvavvzu4NJet33Jb8m97vpb+pnubz3HgGPAMeAYuMtjwBX/rvd1EpCABCQggZpAuZWeg0Fz1Wjy5WrZ7AxI/D58rlr97hv31qLLOsu08rpQdiKUV+LWbahfBSjlUFFZR25DefD2w/Xuhsgvy43VX+apZadRZZ7soih1SD59CUhAAhKQgASWE9DwX87MEhKQgAQkcAsIPPvD2exWnH121m+jp8DTj05Xr/zitd6oxlg9hMu7+kOvHSQtxvnQlbgx+ofOBkB/2vH335yuTn/+t7455EdeaXhj1PP6QiYTSH/yzun6HIGp+qPjkP5UyAGsuNSX5z7SfyQgAQlIQAIS2JrA2vDPj4IhiY9/+XUfXa92JK/p8mEsOD6+l6/EJd/vh98Pvx/7/fsQY/XSF6/xcPLmyQpjfqm79+hkdVodqocMjN7aca5AuWugTj/k88tvPewnLob0QU92EzChEQdT/qZjqGcioT6zgB0Du3KckYD8uMfvfbXeWZC4Md/fL/v9fsHd/9/9/33o++fvG3/f+Pdhu7+Pm/x+GfouLom78m5iV9g4GTgGHAOOAcfArRkD9Tv+vO9fvsPfrXhfamv93j7PnYHZf/g/kvyUT7n4U/9/ImNOvpaMbpLhkq7JT3yt95w0ygzJLOWV4cikLWV9Q3mSN/5QXXCkbNkfiUs5fX+XOQYcA44Bx4BjYLsx4Ip/N4KcsXTGshsGrmh0q3tDzu+H349j/35sOmM+tPqd70C/I2D1jzz2Pque2YrO1vXO8L2U3nro33/vMnXG73oVvVVmV+mszg+1CfnPPz3f+dAZ20ezQ2FJu13x9/8vdyT4//fQ3wx/v/j7hXFxzH8fNv39MjTe58YNrhx0hY2XgWPAMeAYcAzcijHACnJO9Y9f/j9X7wBgBbpMz0o18eUnK/jxyzL7CEePIdnoRfpQGrsVptLRnzwpm/x5HipLmbK+oTwpH39Mf2SV/YIsPimn728yx4BjwDHgGHAMbDcG1iv+HUidBCQgAQlI4FYT6AzP1ZOPL95lT2M5sK4zPtcn57OyT968304+Vo/q2XnKjLm6PM+cip/D8cbK7SM+epen7lNPvYOhXBlJ2j70qWWyg6Iz9Fe5KYFDCB/97od1Np8lIAEJSEACEtiQwEtdOWbUdRKQgAQkIIFbS4Bt7JzEj9FfGvNjDa63vWO0Z6t+WSZX4mG01oYykwI5zZ4y5MGNnazfJ/pPTwDer7772iV+opGABCQgAQlIYHMCrvhvzs6SEpCABCRwQwh85wcn61Pihwz4uhkY9M/+eLZenef9+KkVf4z5GPaRxV305QRCPTGQfPpXCWD0w18nAQlIQAISkMBuCLjivxuOSpGABCQgAQlIYEMC9QF9TJpcxysRG6pvMQlIQAISkMDRE7hThn/5/iY943bLox+fGymYLbn272V8rEbW93BfznH+dFv5+f0f6m3jJCABCUhAAhKQgATuAoE7tdU/71qy9fK6Dg3qTi1ebzdlgA0Zp+V20bw/umQwtsqn/XOMwCX1mlcCx0zgGL7/x8xH3SQgAQlIQAISkIAEbi+Bf9l10zA6WTHc1G1bftN6D1GOrYz3vn/SHwDFu568L8phU3EY5LQfg5x0PjFWkmfKn1v+9Q/fmBKztzTaVn/2URkHd8Fu6o7ufdQ7R+ZNGN/Xye8m8JnTz+aRgAQkIAEJSEACEpDAMRG4ZPjnRzer0jHQCJcO4zVp+HEpwzMHJyXP3EmAueXZrhvZZf3Ro5WefEN+DOdSPnFzXMrCJy6s8ow/dVgRkwC81zjnxOlSZsJzyqPT339zumInwaYujDcpX05qoEPJi7FSsq/7N4zLPGX/RK+kD+mXPkkeysx1lEHHjFWed/X9QI+h7wrtK3WcamP0K/OUfOp2ph3JU5ZDVu0iP+WG2l/KSL5aztBzmXfq70cpf0jHVvpQ3YmDAzLLT9gkj74EJCABCUhAAhKQgARuKgGu8+s/3Q/eF3w6A+RSXJ47o6lPT36eux/a67zE1+WTd64/VZ66qDOyan1a6SnX/Zjv9cRPHP5U3WW+sXDkwivhoTpST82OZ8qSnk9dfqxu4lvlkZU6k3dK3lgaZdFvLH0sPu1Oev1ct5V6yv6u80dO7YdhHZ/xUtdT5xt7pv5ah/I58lOe5/BOXJk/cfid4btuK+GUoy08k6fmUdcX/dI+8idM+bLusr5SD8Jj/CKf9JSpZUZv0qmD9OSd45fy6vyt9rfSIw8m1FOyIW2q7pTVP/+/Qg5ycAw4BhwDjgHHgGPAMXCzxsClFf+u864c/lWuDL/81sN+ezr5cE8/Ol1994175w97/rf7kd7XRZ1xpz//Wx/sDJH+yiR0GUtPmSmftnKF0KaOreVs32fFku30hOvt5uE5dJ0U+hOfbf6UX3IWQas8Ov31p19s2rx1OV4/QMdNXLmai4xyd0PNit0R9x6drKvZtn8yfut61hXMCNTnIqQ/KRr5EbPk+/HsDxdt5XWQOK4QI601/pMf/dI++inhpON3BnJ/l3m+P2VaKzzV/vs/erD65v2v1iIev3cRXkduGGi1v5U+p9ptx9ecOswjAQlIQAISkIAEJCCB6yBwxfCfUgLD8pX//N56K2yMUn50z3HdCuC6bLe61oeJm+O4gxk3ZMgQ30onT8thKGEYL9WtlIsxFWOwNqxoK9vsY9hTDiOsdBj7cSk/ly/lxsp3q8N93WP8Uue+/XKrP5zr/odH+GNIlm7b/mH8nn22v3uht/l+oBcGP5NYjBEmPQgz8cEEwi7GNywz4VROuJSMNw1njD7/dD98W+1vpc9p17bja04d5pGABCQgAQlIQAISkMB1EFh0qj8GLUZJDNKlCnMn79erL5cW6/PHoMDAGDJeW+lzK0V2VrMxQJ99cLaovRjYGG0YrRi15T3ExD35+GLHApMMTJ6kTZkwmKtrnW+qPKvRMUxTDiPw8ZtfL2pfyu7CZxIAHTImMPphhwGGqycFiNumf+DDCvrZ6h+I2rnb5vvB+KV/ev26SQAmAggzGUCbn3da4zJWNlUe5g/efthPOIXzprIOWa71/W6lz9V1m/E1tw7zSUACEpCABCQgAQlI4NAEFq34Y/Sz4p/VvSFlY1wNpc2JGyvPD3LS7v/k4VoMRjaO1ctW+rrQSIA2DbWrXiHOavSQGFZo4YOxzzV9GPrExaE/Rldc2oLuOLZJl3xpH2WSnnJj/lR5jLzsNMBHLkbgJpM4WZUf02NuPIZt6TB82dYeV255n9s/KTvkZ/yWfTKUb9O4yB8aR5EJ97rdpKWP6X/GM4YskzVx247vyMFnfDLBUu82KfMsDUe/8paK7AhaImuKD2n5ziDzOr7/S9piXglIQAISkIAEJCABCRwLgUUr/jES6x/05V30GJ+s4mLA4Nh6nnJzGj1VHuMVYyWykZfVecKtdPJMubpd6D53SzTGHu3GmMZhCFG+j1v9qZeDfkwc3P/2Ygt7qT91sQJf6lGmT+lO2rblW/J3kQ6P1a8uJDF24rIDIP2b59Un3Tjq3hcvuVBmSf+QP+Ow1mEJY+SMuciv9Zz7/eBGh7hMBGCgx207viMHH+M/EzilfmWepeF6fCO3ZtGSeVO//612mS4BCUhAAhKQgAQkIIHrJPBSVzmnbuuOnAATBlNuV8brVB2mSWAJAXZWcFgmEwI6CUhAAhKQgAQkIAEJSOD6CGj4Xx97a5bArSbAjgJ2LJTnXNzqBts4CUhAAhKQgAQkIAEJHCmBRVv9j7QNqiUBCRwBAd65z2saqMOrCxr9R9AxqiABCUhAAhKQgAQkcOcJXFnx51318r1cDtS6q1t1w2LuNnpWODmgLm5X705Hnv4yAnX/2T/L+JlbAhKQgAQkIAEJSEACErgdBEZX/Ocau4fGUBtvx6RnJkhicB6ajfVNE0j/kGvqzASuEeTaRU7Wf/3DN+7sxNc0TVMlIAEJSEACEpCABCQggZtCYNF1fodoFAbZ2HVrpHFlGsY+H051H7rr/RB6WsftJcA1gtyQ8J0fnPTj7fa21JZJQAISkIAEJCABCUhAAneBwCLDP0Y5q+6E+bC6XboyjfTajaVjwCc/161FfiYBeH8YQ58r0wiTXr5PTD5kR06eyVfqOFZ/9CzTyzvDk566o1/it/WpF9m1I440HHWGB8+kZeIj7W21n3JjLvJLBiU7yk21P+XDBr8uX8omvXTkLcsOlS/zD4VL+UP9N1SmjCv1ffD2w9XZZxfX6ZX5DEtAAhKQgAQkIAEJSEACErhJBLjOb/3pDJ8XncG1fi7TiOdDHuI7I2sdznNnGK7LEi5lkX8qHRnk74zYtYzUn7qomzDxhDtDtw9TJmVTb9JTZ6t+ZEU28nku9Y/c6MRzmT/x1Es5/MS1/Ohf50ubiC/DPFP/kvbXsutn5Jd607ayDa32p3zk1jxb/Ov2Rc5cv66v7r9STtnOxEf/2qfdyaN/8bdCFrJwDDgGHAOOAceAY8Ax4BhwDNyMMbBoxb/r1NVffvan1be//5Zg/+5zwp2B2B9s9/Sj0z6Nf1idx7Ea3UrvM078w6F51MUqLtv9cfWKLgcRskUbx4ni0Y3nOfXf/9GD1Tfvf0X23j1+7yJMxMtvPex3HZyndnV0bS0P80v8Jj56o39nZK6LEy7btE4YCZR56/aPFLkSPda/ZJzTfsrHwQ8+sJ/DH/25931T1+q/llxeH0EHDmWkHTAkLuO4Vd50CUhAAhKQgAQkIAEJSEACx0hg9HC/pcryPjSuNLZLGa30Mu+cMIbkvUfndc7J36ofeTgOdBtzGLG8XlC+YkBeyo61e0zWUDyTDrzmEEMTQ7uciBgqc8i4bdrf4k87OHwPlt2Ke9+sJdfBzem/KVbd7oAVEwe48laLe5+feLjfFDjTJCABCUhAAhKQgAQkIIGjJ7Azwz8G85gR3EpvkcIIZOcARjGGIUbxX3/6RW+k3f/2Qb9COyVj2/qRzWowuw1imE/Vt0lav+r/7vmqf94tzw6GIXlLJj6Gyi+NW9r+0th/vjqfUBkbH9GFCRRW2XH087MPzvbGO3Xic9/8k3dOVydvnvT1da8laPCXgAxLQAISkIAEJCABCUhAAjeWwOKt/mMtxWDDMCy332fbOsZrKz1ykYHxVTu2jbMajuGIYcjqcIzEGIp1mfK5VX/SX/nFxVbzcuUXWRj9rPZndbmUv6swK/zUwZb3erW/ZAPbrFAvqRtjOivqS8qRd077ORAvjjYwYYML37HxAdMhrpkAicwx/SN/qv8iY8zPYX5DeoyVMV4CEpCABCQgAQlIQAISkMCxE9jZij8NxRhnpbTcCl8a5a10ZGS7e2TkJH8MO969Lo3xJVvB5+qHYckOAlxdX1b6Sx2SD/124bLqj6x6tb9kAxc+h4vVYIoAAEAASURBVFz1n9v+TCwwUcFKelyr/2uutK9mEFlDPvKn+m+oTBnHNX7sDGGnQs6RKNMNS0ACEpCABCQgAQlIQAISuIkEXuqU5sTytWO1EwOsNNjXiQYOQgDjlcPllhi9B1GsUclN0htdmdjZ1YRNA43JEpCABCQgAQlIQAISkIAEro3A6Io/hhGOVVtWUnWHIbD0JP/DaHU7amE3yq5uYbgdRGyFBCQgAQlIQAISkIAEJHAXCFwx/FkBdbX/8F1fniov//3wdwJrP1yVKgEJSEACEpCABCQgAQkcN4HRrf5R+y6v+C997aFeUXYreUbR9fh1/9k/19MP1ioBCUhAAhKQgAQkIAEJXC+BKyv+UedYV51r4+2Y9MyKcgzOsNQ/DgLpH7TJqyxDmrH74snHp/1Bf69/+IavugxBMk4CEpCABCQgAQlIQAISuDEEdnad365ajEF28s6/DoojjdPWMfb5cOo7RppOArskwOn+HKzo6f67pKosCUhAAhKQgAQkIAEJSOC6CCwy/GOUs+pOmA+r26Ur00iv3Vg6Bnzy/9uv/n0tP5MAHHqHoc+VcoTJmyv/qIN8yI6cPNc6jtUfPcv08s75pKdu5EbfpG3jUy+ya0ccaTjqCw+eScvER9rbaj/lxlzklwzq/p1qf8rj51OXL2WTp3TkTbn4dfky/1C4lD/Uf0NlyriyvgdvP1ydfXZWJhuWgAQkIAEJSEACEpCABCRwIwlwnd/60xk+Lzqja/1cphHPhzzEd0bWOpznzjBclyVcyiL/VDoyyN8ZsWsZqT91UTdh4gl3hm4fpkzKpt6kp85W/ciKbOTzXOofudGJ5zJ/4qmXcviJa/nRv86XNhFfhnmm/iXtr2XXz8gv9aZtZRta7U/5yK15tvjX7YucuX5dX91/pZyynYmP/rVPu5NH/+JvhSxk4RhwDDgGHAOOAceAY8Ax4Bi4GWNg0Yp/16n9/fK5+5x3phPuDMT+qrSnH52SrXeszuNYjW6l9xkn/uEaNupiFZft/rh6RZeDCNmijXv62ydr3XieU//9Hz1YffP+V2Tv3eP3LsJEvPzWw37XwXlqV0fX1l1dD4fe6N8ZmRHfh8s2rRNGAmXeuv0jRa5E/+Vnf1pzK/uXjHPaT/k4+MEH9nP4o/+r776W4ov9Vv+1BPL6CDpwKCPtgCFxGcet8qZLQAISkIAEJCABCUhAAhI4RgKjh/stVZb3oXGZCKjLt9Lr/K1nDMl7j87rbOUlvVU/8nDPPx3f2o0Ry+sF5SsGlKHsWLtJn+uYdOA1hxiaGNrlRMRcOfvKt037W/zRmYkGWHYr7n0TMLy//vGXs5ozp/+mBHW7A1ZMHOAe/e6H66z3Pj/xcL81DQMSkIAEJCABCUhAAhKQwE0ksDPDPwbzmBHcSm/Bwwhk5wBGMYYhRvFff/pFb6Td//ZBv0I7JWPb+pHNajC7DWKYT9W3SVq/6v/u+ap/3i3PDoYheUsmPobKL41b2v7S2H++Op9QGRsf0YUJFFbZcfTzsw/O9sY7deIzwfDkndPVyZsnfX3dawka/CUgwxKQgAQkIAEJSEACEpDAjSWweKv/WEsx2DAMy+332baO8dpKj1xkYHzVjm3jrIZjOGIYZhs64RiKdZnyuVV/0l/5xcVW83LlF1kY/az2Z3W5lL+rMCv81MGW93q1v2QD26xQL6kbYzor6kvKkXdO+zkQL442MGGDC9+x8QHTIa6ZAInMMf0jf6r/ImPMz2F+Q3qMlTFeAhKQgAQkIAEJSEACEpDAsRPY2Yo/DcUYZ6W03ApfGuWtdGRku3tk5CR/DDvevS6N8SVbwefqh2HJDgJcXV9W+ksdkg/9duGy6o+serW/ZAMXPodc9Z/b/kwsMFFRbtVv9X/NlfbVDKYYI3+q/6bKksY1fuwMYadCzpFolTFdAhKQgAQkIAEJSEACEpDAsRN4qVOQE8vXjtVODLDSYF8nGjgIAYxXDpdbYvQeRLFGJTdJb3RlYmdXEzYNNCZLQAISkIAEJCABCUhAAhK4NgKjK/4YRjhWbVlJ1R2GAFv4YX7TjP7D0NmuFnaj7OoWhu00sbQEJCABCUhAAhKQgAQkIIHDEbhi+LMC6mr/4TogNZWnyss/VHbrO4G1W55Kk4AEJCABCUhAAhKQgARuBoHRrf5R/y6v+C997aFeUXYreUbR9fh1/9k/19MP1ioBCUhAAhKQgAQkIAEJXC+BKyv+UedYV51r4+2Y9MyKcgzOsNQ/DgLpH7TJqyxDmrH74snHp/1Bf69/+IavugxBMk4CEpCABCQgAQlIQAISuDEEdnad365ajEF28s6/DoojjdPWMfb5cOo7RppOArskwOn+nLHg6f67pKosCUhAAhKQgAQkIAEJSOC6CCwy/GOUs+pOmA+r26Ur00iv3Vg6Bnzy/9uv/n0tP5MAHHqHoc+VcoTJmyv/qIN8yI6cPNc6jtUfPcv08s75pKdu5EbfpG3jUy+ya0ccaTjqCw+eScvER9rbaj/lxlzklwzq/p1qf8rj51OXL2WTp3TkTbn4dfky/1C4lD/Uf0NlyriyvgdvP1ydfXZWJhuWgAQkIAEJSEACEpCABCRwIwlwnd/60xk+Lzqja/1cphHPhzzEd0bWOpznzjBclyVcyiL/VDoyyN8ZsWsZqT91UTdh4gl3hm4fpkzKpt6kp85W/ciKbOTzXOofudGJ5zJ/4qmXcviJa/nRv86XNhFfhnmm/iXtr2XXz8gv9aZtZRta7U/5yK15tvjX7YucuX5dX91/pZyynYmP/rVPu5NH/+JvhSxk4RhwDDgGHAOOAceAY8Ax4Bi4GWNg0Yp/16n9/fK5+5x3phPuDMT+qrSnH52SrXeszuNYjW6l9xkn/uEaNupiFZft/rh6Rbe8Bu/pb5+sdSPvnPrv/+jB6pv3vyJ77x6/dxEm4uW3Hva7Ds5TVyvauqvr4dhajv6dkRnxfbhs0zphJFDmrds/UuRK9F9+9qc1t7J/yTin/ZSPgx98YD+HP/q/+u5rKb7Yb/VfSyCvj6ADhzLSDhgSl3HcKm+6BCQgAQlIQAISkIAEJCCBYyQwerjfUmV5HxqXiYC6fCu9zt96xpC89+i8zlZe0lv1Iw/3/NPxrd0YsbxeUL5iQBnKjrWb9LmOSQdec4ihiaFdTkTMlbOvfNu0v8UfnZlogGW34t43AcP76x9/Oas5c/pvSlC3O2DFxAHu0e9+uM567/MTD/db0zAgAQlIQAISkIAEJCABCdxEAjsz/GMwjxnBrfQWPIxAdg5gFGMYYhT/9adf9Eba/W8f9Cu0UzK2rR/ZrAaz2yCG+VR9m6T1q/7vnq/6591y4sbckomPMRlL4pe2vzT2n6/OJ1TGxkf0YAKFVXYc/fzsg7O98U6d+EwwPHnndHXy5klfX/daggZ/CciwBCQgAQlIQAISkIAEJHBjCSze6j/WUgw2DMNy+322rWO8ttIjFxkYX7Vj2zir4RiOGIbZhk44hmJdpnxu1Z/0V35xsdW8XPlFFkY/q/1ZXS7l7yrMCj91sOW9Xu0v2cA2K9RL6saYzor6knLkndN+DsSLow1M2ODCd2x8wHSIayZAInNM/8if6r/IGPNzmN+QHmNljJeABCQgAQlIQAISkIAEJHDsBHa24k9DMcZZKS23wpdGeSsdGdnuHhk5yR/DjnevS2N8yVbwufphWLKDAFfXl5X+UofkQ79duKz6I6te7S/ZwIXPIVf957Y/EwtMVJRb9Vv9X3OlfTWDKcbIn+q/qbKkcY0fO0PYqZBzJFplTJeABCQgAQlIQAISkIAEJHDsBF7qFOTE8rVjtRMDrDTY14kGDkIA45XD5ZYYvQdRrFHJTdIbXZnY2dWETQONyRKQgAQkIAEJSEACEpCABK6NwOiKP4YRjlVbVlJ1hyHAFn6Y3zSj/zB0tquF3Si7uoVhO00sLQEJSEACEpCABCQgAQlI4HAErhj+rIC62n+4DkhN5any8g+V3fpOYO2Wp9IkIAEJSEACEpCABCQggZtBYHSrf9S/yyv+S197qFeU3UqeUXQ9ft1/9s/19IO1SkACEpCABCQgAQlIQALXS+DKin/UOdZV59p4OyY9s6IcgzMs9Y+DQPoHbfIqy5Bm7L548vFpf9Df6x++4asuQ5CMk4AEJCABCUhAAhKQgARuDIGdXee3qxZjkJ2886+D4kjjtHWMfT6c+o6RppPALglwuj9nLHi6/y6pKksCEpCABCQgAQlIQAISuC4Ciwz/GOWsuhPmw+p26co00ms3lo4Bn/z/9qt/X8vPJACH3mHoc6UcYfLmyj/qIB+yIyfPtY5j9UfPMr28cz7pqRu50Tdp2/jUi+zaEUcajvrCg2fSMvGR9rbaT7kxF/klg7p/p9qf8vj51OVL2eQpHXlTLn5dvsw/FC7lD/XfUJkyrqzvwdsPV2efnZXJhiUgAQlIQAISkIAEJCABCdxIAlznt/50hs+LzuhaP5dpxPMhD/GdkbUO57kzDNdlCZeyyD+Vjgzyd0bsWkbqT13UTZh4wp2h24cpk7KpN+mps1U/siIb+TyX+kdudOK5zJ946qUcfuJafvSv86VNxJdhnql/Sftr2fUz8ku9aVvZhlb7Uz5ya54t/nX7ImeuX9dX918pp2xn4qN/7dPu5NG/+FshC1k4BhwDjgHHgGPAMeAYcAw4Bm7GGFi04t91an+/fO4+553phDsDsb8q7elHp2TrHavzOFajW+l9xol/uIaNuljFZbs/rl7RLa/Be/rbJ2vdyDun/vs/erD65v2vyN67x+9dhIl4+a2H/a6D89TVirbu6no4tpajf2dkRnwfLtu0ThgJlHnr9o8UuRL9l5/9ac2t7F8yzmk/5ePgBx/Yz+GP/q+++1qKL/Zb/dcSyOsj6MChjLQDhsRlHLfKmy4BCUhAAhKQgAQkIAEJSOAYCYwe7rdUWd6HxmUioC7fSq/zt54xJO89Oq+zlZf0Vv3Iwz3/dHxrN0YsrxeUrxhQhrJj7SZ9rmPSgdccYmhiaJcTEXPl7CvfNu1v8UdnJhpg2a24903A8P76x1/Oas6c/psS1O0OWDFxgHv0ux+us977/MTD/dY0DEhAAhKQgAQkIAEJSEACN5HAzgz/GMxjRnArvQUPI5CdAxjFGIYYxX/96Re9kXb/2wf9Cu2UjG3rRzarwew2iGE+Vd8maf2q/7vnq/55t5y4Mbdk4mNMxpL4pe0vjf3nq/MJlbHxET2YQGGVHUc/P/vgbG+8Uyc+EwxP3jldnbx50tfXvZagwV8CMiwBCUhAAhKQgAQkIAEJ3FgCi7f6j7UUgw3DsNx+n23rGK+t9MhFBsZX7dg2zmo4hiOGYbahE46hWJcpn1v1J/2VX1xsNS9XfpGF0c9qf1aXS/m7CrPCTx1sea9X+0s2sM0K9ZK6Maazor6kHHnntJ8D8eJoAxM2uPAdGx8wHeKaCZDIHNM/8qf6LzLG/BzmN6THWBnjJSABCUhAAhKQgAQkIAEJHDuBna3401CMcVZKy63wpVHeSkdGtrtHRk7yx7Dj3evSGF+yFXyufhiW7CDA1fVlpb/UIfnQbxcuq/7Iqlf7SzZw4XPIVf+57c/EAhMV5Vb9Vv/XXGlfzWCKMfKn+m+qLGlc48fOEHYq5ByJVhnTJSABCUhAAhKQgAQkIAEJHDuBlzoFObF87VjtxAArDfZ1ooGDEMB45XC5JUbvQRRrVHKT9EZXJnZ2NWHTQGOyBCQgAQlIQAISkIAEJCCBayMwuuKPYYRj1ZaVVN1hCLCFH+Y3zeg/DJ3tamE3yq5uYdhOE0tLQAISkIAEJCABCUhAAhI4HIErhj8roK72H64DUlN5qrz8Q2W3vhNYu+WpNAlIQAISkIAEJCABCUjgZhAY3eof9e/yiv/S1x7qFWW3kmcUXY9f999d6R9uv+AgzGMbfy3+rfTrGUXHU6t8jqcv1EQCEpCABCQgAQncNAJXVvzTgGNdda5//B6TnllRjsEZlvrHQSD9gzZ5lWVIM3ZfPPn4tD/o7/UP3/BVlyFIG8SF/9j3o5W+QZW3qsgx8Cl3JgF3aHKp/G5tMnHcKp/xcxPPQblVA9LGSEACEpCABCRwowjs7Dq/XbWaH32sWA450jhtHWOfD6e+80NUJ4FdEuB0f85YuKmn+6M73499HFw49f3cZR9cl6xt27dt+etq95x6OX+E70b597e8PhODnPZjkCdPJivmyJ9bnsk4nQQkIAEJSEACEpDAMgKLDP/8qGXVnTAffqyVrkwjvXZj6Rjwyc825cjPJAA/OjH0uVKOMOm58o86yIfsyMkz+Uodx+qPnmV6eed80lN39Ev8tj71Irt2xJGGo87w4Jm0THykva32U27MRX7JoGRHuan2p3zY4NflS9mkl468Zdmh8mX+oXApf6j/hsqUcaW+D95+uDr77KxMHg1T73X3X9n2mi2KE8c4yRjhOeOH9Cn+KUO+oe8n8chGZvkh/lCu1T70GBu/c9o31Y655Vt91Eqf0mGq/6bKkZay5RgOq7Lssz+Ofx+YBOCK1U0PJp1THp2Y/GUngU4CEpCABCQgAQlIYBkBrvNbf7ofgC+6H9Dr5zKNeD7kIb77kboO57n7YbYuS7iURf6pdGSQvzMg1jJSf+qibsLEE+5+cPdhyqRs6k166mzVj6zIRj7Ppf6RG514LvMnnnoph5+4lh/963xpE/FlmGfqX9L+Wnb9jPxSb9pWtqHV/pSP3Jpni3/dvsiZ69f11f1XyinbmfjoX/u0O3nG/GPov+g2pUvNuHwuw5FV+1N5yrFCubq/I6v1/WilR07to1utX/ncGr/IK/PX8uc8T5WvedT6tNJT/xifqbpTdsqPXMZPwvhlGepIPehbpvGcsZd8dfkyfx1ulUdW6kzeWobPF/+Xy0IWjgHHgGPAMeAYcAyUY2DRin9XsN/GmS3EbONMuPtR1l+V9vSjU7L1jtV5XPdjsF9R4iq1sfQ+48Q/lKUuVnFZ8cHVK7rlNXisPEU38rb06+X96MHqm/e/Iti7x+9dhIl4+a2H/a6D89RV35ZdXQ/HKhn6d8ZAxPfhsk3rhJFAmbdu/0iRK9Fs0w23sn/JOKf9lI+DH3xgP4c/+r/67mspvti/3+i/lkC2J6MD7y3TDhgSl3E8Vf5Y+m9KR9JoV7kiS3vjtuWfcRN5rA7fe3SSx4P4U+2bM373pWRr/LfS5+i1i/5jVxU7OthOT7ju04wX8tSO7zrx2eZP+Ue/+2GdbfS5VR6d/vrTL0bLmyABCUhAAhKQgAQkME5g9HC/8SLDKbwPjat/KCZ3Kz355vr8UF5iVLTqRx7u+afjW1n5YcrrBeUrBpSh7Fi7SZ/rmHTgh3MMTQyVciJirpx95dum/S3+6MxEAyy71cK+CRjeX//4y1nNmdN/U4K63QErJg5wpbFy7/OT2Yf7HXv/TbWftG34R3a3EttP9uSZPjwWt834pQ3lGEmb5o7R1vhvpae+KX8X/cffHv7u4PJ3KHXSfiZdE09f86HeOIz9OPLxt3LJ38ex8pnw3cXf2einLwEJSEACEpCABO4SgZ0Z/jGYx37ktdJb0PmBzc4BfkxiGPLjlNUfjLT73z7oVzKnZGxbP7JZ7Sp/+E7Vt0lav2r87vmqf94tL1dna5lLJj7qsps8L21/acw8X51PqIyNj+jDD3tWDHH087MPztaGRvLsw2eC4ck7p6uTN0/6+mqDZk6dx95/c9qwDX+YscofQxBD8Zjc0vFb684Y+Xo1byKqLtv6+9NKr+WNPW/Tf8hkxxF9yCQY/VdOvBHHbRdx+fub73R2AyR9qT9Vnr/3mbiJXCZJH795fu5L4vQlIAEJSEACEpCABIYJLN7qPyzmfKWfH27l9vtsW8cg4gfpVHrkkgfjq3ZsG+eHHj8yMQwxLvIjN4ZiXaZ8btWf9PKU6nLlF1kY/VnBKmXvMsyqMXWw5b1e7S/ZwDYr1Evqx5jOivqScuSd034OxIujDVnxDd+x8UG/8qldJkASP6Z/5E/1X2SM+TnMb0iPsTJ1/L77r65vV89z+ZdjsK4bw+zZHy52zHAC/DG5OeN3qn1z2jJWPuNzbPy30lt1z+2/se8P8plY5W8Pxj6vu/D3hbg42lZ+v9MWdMdl7Of7w98oyiQ9csb8qfL8vc8rBPjI5bWO7D4Yk2m8BCQgAQlIQAISkMA5gZ2t+COOH2es+vHjMa40ylvplOHHHwZ+ZLD1kx93/Hjkx2hpjM/dZhtdWvWTzg9jdhDg6vryI7PUIfnm/rjtBU/8k1VjstSr/SUbuPA55Kr/3PZnYoEf5+WKYYt/zZX21Qwm0PXjb6r/psqShqHKyis7FTASN3HH3H+t9szhX45B5OX7SRhDrPzu5nn1yerSOCDvdbg543eqfXN0nirfGv+t9Fb9c/pvTAbGOn1Hn+H4e0bf9nGr83Mh6r+P5Cv/vjP2WYEv9SjTyT/lti0/Jds0CUhAAhKQgAQkcNcJvNQB4GTmteMHID/clvxgWxc2sBMCGK/8AF9i9O6k4i2F3CS90ZWJnV1N2JTobhKHUm/DEtgXAb4TU87/b6bomCYBCUhAAhKQgAS2JzC64p8faqzastKjOwyBbI+9aUb/YehsVwu7UdiOvk9n/+2TrrJvKgEN+5vac+otAQlIQAISkMBtIXDF8GcF1B9ph+/e8sRw+e+H/z4nsOy//fSZUiUgAQlIQAISkIAEJCCB7Qlc2eq/vcjzQ6J4V3qbbdS8clCXH4ob0nduvqGyiWPlNu8EJw65vP+9z9V46ijfkb2LOy44UIx3i/e1FT/9qS8BCUhAAhKQgAQkIAEJSOAuELiy4l+uXE4BaBmk254TgIH96oevXXrN4PUP3+gP/+Nkaa6VGjPAycfhbLXhTnvyCgPhqTZwfRSfepW4N0g/3c+74eiE7uWBacTpJCABCUhAAhKQgAQkIAEJSEACmxK4YvjPuauaFdmhK/dKJXKNWxnXCter3eSPoY4xjMPY58MERe5c7xOqf2L0Z/U4yXNuAqAMd1nnRHp0yGF7TBbUOxEiexc+76DXV9jtQm5klG1J3C79Xcinfz/79X/tUi1lSUACEpCABCQgAQlIQAISuLMENtrqH8M/xnXoxUjPc+mzbZs71uu758cM8aE6OJytXIEv8xBmNb509Yo+EwvoEIOevEwglM/ElfWUddRpQ2XJs4kbO3iu5DPUxvI8gKGJk2yXH9vJkQmN6MwrDrlKkbhdyUf3V999rZ9QYQxQL89MdETHmkFZN7pkUiHliEvZOenkmaqjJZ/yOglIQAISkIAEJCABCUhAAjeRANf5rT+d8fiiM4Be4JfxZbgz4l50BuKsdOR0RmefF7+UiwxkITv1Ujcf8pKeZ/zOaLv0nDylTGSRb0hmKSth6i/Lp860L3Ukf+m3OJTM5oaRHyZ1mVJP0mhn9OR5qmxkTeVJ25OX57DcVj5tSt2ph/aEb+rET94yLvUjIxzQLeE56TWv6JF6kD0lP/n0L/5eyEIWjgHHgGPAMeAYcAw4BhwDjoHjHwNXtvp3nda78oC5xJV+tt6XcduEy9sEOsOvXw1+/N5X/Xv6nTHWrzx3hlq/DZ6t4ORhhb9erY8OnUHYvy/PqjFh2oPO9x6drMsgrzyEkHw4VtmffnTal8tZAtnd0BmPl3YdnK3+kSr37tevGPA6Au2JY4cDq+F//vVm1y9ypkHZrzAoV/+3lU/5vu8+OOkZ1+1JO6Z8dgqkXLn7I2XG0ulbdhfQpjj6lPYxltALN1Y+ZfQlIAEJSEACEpCABCQgAQncNAKDhn+5vXyTBvHu/SbvqWPg4zAQv3n/q/Xp9hjvvXH22Vn/Xj/GNgYu27xrhzGPgccheRiGGOq4TADc67b6d6vM61cOyomAlCEdN+cEfwzKGKKUyaTFkFFK+raO9tC+OPoqjjrRJxyX9iNyMYRLYx/ZaeO28qPndfj0Ja7sq+vQwzolIAEJSEACEpCABCQgAQkcmsCg4b+tEhjT5crqsz+czRKJcY7RzUo/Btp/v/usN96Jy8r+q5+/1svi1P7SiMsOAFasmTgoDe8yTGFkfb36cl0XcZSv8xEfI5pwXBlHXX/96RdrXXLOQD9R8c9V5JTb1sfoZ5U/emaCopQLEzji0PPZB2eDtxuUZRKmLWO3ISTPNvIj4zp8dnbgMolxHTpYpwQkIAEJSEACEpCABCQggesg8C/bVIpxO+Tuff9kbQhnpXUoXx2HUcbWelbeMVpZgcYnjpV8XLa3Z+t9ZPQnwXcGbx1POjL43P/Jwz47svrn7pC5uGz1zjN+ZGJI54NxnDA+Rng5AZG0IXml7E3C8CgnUeAcBzs+tat3XqD/2I0MGP2s9g/J2YX8WrdDPtNHtD1jgLozpvbRV4dsm3VJQAISkIAEJCABCUhAAhKYIrDVij8G5PP/fXbJ8MWYYpt+3JJt/xhnZ7//x/oddYxzHKvoGNQYnxi7GMCs2OPmrKxTFteX77b6MznAZ2jFvM+4xT/o8+Dth+sdCluIulKU989hka34eV59sup3SdTnMrD7oTZq6ZtSBnkyWRK/lpNXKur4pfKvNOjAEUzSsGsi/Kg+Y+PAqlidBCQgAQlIQAISkIAEJCCBgxG4cp0fxnFt4LW0ifFEWVZUWWXGuIxhmivXMLTr6/zIE+O0TmeFNtvaMaj7g+v++R47OlIvEw0xWKMnxl3KlWH0K6/zo768VpCy+GPxlM85AGX+MpzJirS5TDMsAQlIQAISkIAEJCABCUhAAhI4NIErK/7lO9xLlKmN4s9+/V/96momBSKrNIgx2mP0k5537wlHHgY/kwgcVBdjPjrGyI7hj5HPboDaJR8TCax455l8GP67dHV7dylbWRKQgAQkIAEJSEACEpCABCQggaUErqz4LxVgfglIQAISkIAEJCABCUhAAhKQgASOl8Clw/1YCWeFXScBCUhAAhKQgAQkIAEJSOBYCLBTmM9Nc9pXN63Hbq++lwz/29tMWyYBCUhAAhKQgAQkIAEJ3DUCLGpifOfDWV6buJTH5/Xim+Roc/Qfan8rvdXWVvlW+nXLb9V/W9I1/G9LT9oOCUhAAhKQgAQkIAEJSOASAc4T4wyufDhofMnOAc4dw2jmQPLIyLljlyra8CEGeelvKGqwGG3lVrToTrhsfyt9UGgR2SrfSi9EDQZb5Vvpg0LvaOSg4c8sVgYfgz2unjEjT+nyxUhZ/LI8eemcMr0sb1gCEpCABCQgAQlIQAISkMC+CHDY9xLHjWAcMl4eSL6kfJ03q9+ljVROKqAf9tKuHNdYl1etEy6vtm6lR4/Yh3mO3yrfSo+cfctPPXfZv3KqPyfo5+R9BmZ5fd3zT8/62aIAo4MYmDlVnyv2yuv5ki8+eel8ZpxwPCNjl7NmqUtfAhKQgAQkIAEJSEACEpBACGBscwNYbJfET/mskNe3gsVWmio3lIZt9ewPZ/1NZkPpxKEfV6PvwmVyoZy0wJ7DJY3wWDo3qU25yBgrn7Jj6dctP/rdFf/Kij+GezqBq+4YfOnUxAfOsz+ere49OsnjihmqV999bf1cB15+6+Hq8S+/Xkc//eh08Pq9dQYDEpCABCQgAQlIQAISkIAEtiCQVXYWKTHalzhsIRZGs1UeWwY5Sx2LnU8+Ph2cdEB+dkRTT2koL62nzP+dH1zYaYmPPUdaKz1l8FmozeJt4lvlW+mRcwj5ZV13NXxlxb8FgkHLFyCOrS9xDAgmCRi4ONK+/vGXSe7LseLPp3SUySAs4w1LQAISkIAEJCABCUhAAhLYhgD2yNerc5sEOwXjfcmqf7lwSTlsmSX2C4Y9C6RjBn25Yxr9ahtq07Zndb8snwXdoTTytdJLWUMyWuVb6YeUX9Z1F8JXVvzLRmeWJkY5Rj+r/JnxKo3+lCNv0uvDMxjwfHGSHj/yI0NfAhKQgAQkIAEJSEACEpDArglgi5Q7llvysV+2dRj22FDYUi1HXmyoXbjYWOV17aV910pv6dAq30q/bvmt+m9b+hXD/8HbD9dtZNt+adyz0s97KXG88xLH7E1mcBKHX76j8vffnK5nyMo8hiUgAQlIQAISkIAEJCABCeybAKv1pT1DfdlmP1R3DsOLncMZZUwGxKgdKjMUx66DOcb/yZsX9tWQnKVxTHSUr2ITLncwtNJTH5MW2dWdOPxW+VZ6ZO1bfuq5y/6Vrf58EdKpDOpyqz4zUGxVyVb9PK8+6Tq9Ow+gft+Fji63tGRLTZ1v0wMy7nLH2XYJSEACEpCABCQgAQlIYJpADhdPLhY1Y5MkbsrHlnn85uX3+tm1vInDroqBW9o/2FerX11IXHoOwUXJqyHayg6H2Hd1+1vpVyVejmmVb6Vflnb1qVW+lX5V4t2Nealr+ou723xbLgEJSEACEpCABCQgAQkcOwEMeByGnk4CElhO4MpW/+UiLCEBCUhAAhKQgAQkIAEJSEACEpDAsRJwxf9Ye0a9JCABCUhAAhKQgAQkIAEJSEACOyDgiv8OICpCAhKQgAQkIAEJSEACEtgfAbb6Z7v//mrZvWTerS9P1d99DUqUwDwCGv7zOJlLAhKQgAQkIAEJSEACErhhBDC6Mb7z+d4n/2ujFnCq/0014mnzVPtb6S1grfKt9OuW36r/tqTv3PC/qV+I29KhtkMCEpCABCQgAQlIQAISOCfAqfycwp/P/R892GjnwOsfvrEXpDHIS3+XFbFLgivY037C5c6JVnpLl1b5Vvp1y2/Vf5vSrxj+dM7QwMssF+lxyctzZnIIcyVFZJRbW4jjOddY8Jw7MSlXz8iRXrroENl1+TKvYQlIQAISkIAEJCABCUhAAiUBritf6rB5/v6b09UmZeu6YjOVNhBXpMcwp47S3qrLL33mGvZv3v9qXYxwrmYnspWegrHf8hy/Vb6VHjn7lp967rL/P8vGM8joHAYejmc64c//8fnq299/u+JOyUe/++Hq7LOz1fNPz/q8uWeSeym/Xn3ZG/wMXmbXhhyTArm3EtmlQ2bqJp50dMi1HdQ9JbuUZVgCEpCABCQgAQlIQAISkEAIYGx/9417a9si8VM+ZV5+62FvD+Fv4zD6n/3hbIXdNObQD1trFy6TC6Vdhr2FSxrhsXTsvykXGWPlU3Ys/brlR7+74l8y/BnMj3/59brtTz86vTQjROeQjvHObBThVoethf0zgOGeMkwolC7xiXv2x7PVvUcneezrfPXd11Z//vXlcusMBiQgAQlIQAISkIAEJCABCRQEMLjZ4o/LomWRPBlki/9ff/rFZJ45iSxostpeGsEph221+tX5U7kImvRN/e/84MKOiozYW0Np5CnTz35/sZBb223kHZJRlidP7cr0Q8qv9biLz5cMf2aYWPHnUzpmc9JJrL5ntisr8WXebcN8KdAj7ulvnyTYz7ShS14BIG1qxmxd0IAEJCABCUhAAhKQgAQkcCcJZGcyjceOYPFyjh3DzmO2+McO2hReFk2HjH5kljua0W9XNk5W90u9s0o/lEa+Vnopa0hGq3wr/ZDyy7ruQvjSO/5Zxc87JvHLwc4XgJV4jHNmz3bpMPqRnXpLoz/1oEvSNz2cI7L0JSABCUhAAhKQgAQkIIG7QwCjv9xRPNVyFjtZEMUY54P9gxGPPbTEYdhj42DrtBx5szuhlbeVHhuuPHMtq/SktdJvu/xW+25b+iXDnxktBndmYurGMmhIZ9aMbTIMynIgkZ/Jg5M3r24rqWUNPfNl4r2XOE6djEOnIb129Q5M6tGXgAQkIAEJSEACEpCABG4nAWyZ0t6glTHs6xazvT0LjvjYORjmc3YL1LKwn+YY/5vaUXV9eWaig1el4wgTF9dKTz4mLeBUu1b5Vnrk7Vt+6rnL/qWt/hnEHKJXurwLwwwXgx3HDBEd2cetLg7z490V4vhS4cgTuX3ExD/ILsvmefVJJ+e9r/qDBcviyB7bMlPmMywBCUhAAhKQgAQkIAEJ3D0CrM7HLqH17Ciea5vsmhbGfwzcHHZOHdg/ecef59hehLd1tJUdDjHa6/a30lv1t8q30q9bfqv+25T+UteYF7epQbZFAhKQgAQkIAEJSEACErhdBLK9HkNSJwEJLCdwaav/8uKWkIAEJCABCUhAAhKQgAQkIAEJSOCYCbjif8y9o24SkIAEJCABCUhAAhKQgAQkIIEtCex1xZ/D+PI+yZZ6WlwCEpCABCQgAQlIQAISuKME2Oqf7f43CQG2UH0Y+k3SX11vD4G9Gv63B5MtkYAEJCABCUhAAhKQgARuGgGMbozvfDa9jjwLmjfRiKfNU+1vpbf6vFW+lX7d8lv135b0ozP8nRW7LUPLdkhAAhKQgAQkIAEJSOB6CXADWHklH9eRb7Jz4PUP39hLQ2KQl/4uK6KtXJEeBoTL9rfSW7q0yrfSr1t+q/7blH7J8K+NbjqKGZq4pJcDk9mv0uWKCvLc/8nDMqnf5lKWJRyXmSCeudIi+epZNXRKWlmecpmJK9Nr/cink4AEJCABCUhAAhKQgATuHoH//uLZ4kZjf/z9N6erTcrWlcXmKW0UrjCPYU4d1Lcrx1WGXLceR7i83rCVnnKx8fIcv1W+lR45+5afeu6y/z+XNh6jnIGJY+Ay+/Xn//h8/UygTO8T/vnP80/P1mlE0cEMbK7l4F7Lr1df9kY9g5/ZudqRl8ET+TwjI/U/+t0PV2Nla1k+S0ACEpCABCQgAQlIQAJ3hwDG9nffuNfbHnNbTZmX33rY2xv42zhsp2d/OOvtnjE56Hf22dlY8qL4TC6UdhX2GC5phMfSv/39tySPusgYK5+CY+nXLT/63RX/0or/nEZjWMc9fu+r/suTTmfrTDmjRHrp6s599sez1b1HJ2WWyTBftse//Hqd5+lHp339iWCG7NV3X8ujvgQkIAEJSEACEpCABCRwxwlklZ1Fwj/8n/+7iAaLnH/96ReLygxlZrHyyceng5MO5W5nFjhLQ3lI1ty47/zgqp0Ve4y0VnpZDwutWXxNfKt8Kz1y8Pctv6zrroYXr/iPgYrxn1mksXwMemay4p7+9kmCTZ9yrPjzKR11M4gZMITzCgCy2Umgk4AEJCABCUhAAhKQgATuJoHsLKb12AksJLLjuOXYXcwW/xjLrfxj6Rj2LFCOGfTljmX025UNM2SXtWy2VnrZxpsuv2zLXQhPrvi3VuMzizP3y4DRzyo/s0V8lhj9dAZfGL6oKR+/rJ9w4jc9vOMudLxtlIAEJCABCUhAAhKQwF0jgC3RsnHChN3GLDjm/DAWITHimRBY4jDssYGwhVqOvNgwu3Cxkcoz00r7rZXe0qFVvpV+3fJb9d+29EuGP4b1yZvnW0IY0EOD7sHbF++2sK0+xjsdS/lXfnGx1Z7tNKXjy8J7LXGcKlm7Uoc6jRk3vnyZiSrTiRuK39U7MmVdhiUgAQlIQAISkIAEJCCBm0cAW6K0R2hBDPu6Ndl+nkVF7BQM8zm7BWpZ7DqYY/zHFqvLb/rMREf5KjRh4uJa6cnHpAWcatcq30qPvH3LTz132b+01Z/385nF4gtBJ/EZmhFLpzP4y630fDlIu//t+SwV79CUxj9flMgHep5Xn6zWckodyIMO+XLFL2WSJ+/q1PGUHdtSQzmdBCQgAQlIQAISkIAEJHB7CbCYiW0Tx6JlbIrEHcrHboqBi/2SFXHso9WvLrSIbXMRs3mItmLPxX6r299Kb9XcKt9Kv275rfpvU/pLXWNezG0QAwZjXWN6LjHzSUACEpCABCQgAQlIQALbEsj2egxJnQQksJzApa3+y4tbQgISkIAEJCABCUhAAhKQgAQkIIFjJnBpq/8xK6puEpCABCQgAQlIQAISkMDdJOBK/93sd1u9OwKLVvw52GKX2/w5jC/vm5RN4uRJ4ocO6yvzXVf42PW7Li5L6x3r/6VyyvyRyfjhM+f01LL8TQ7T3vLU1m3bEpZz5ey6/rn1lvmi81T/j31/885dyiJLJwEJSEACEpCABCQggdtAwBX/29CLtmFN4PUP37h0IOQ6wcCdILBN/3M4KQ6Dvz4o9E7As5ESkIAEJCABCUhAAreWwKUV/2NYsYM0uwrYXZCTLo+N/rHrd2y8DqkPV0Z6heMhiR+2rtbfqDn97/f3sH1mbRKQgAQkIAEJSEAC109g8Yo/22H5cR2HgR7HFtr+OopEdH6ZTnRZnuv2SlemEV+X5Uc/two8ePvh6v6Pzq8M5EqK8krBUgZp5KvllHUmjO7ca8n9mpShHp5pa67bKGVP6Zdy5ElZwtF/LJ08U3XMKY+MMTe0kjmkX9mHZTpy6ytRarat9LJ9df+39BtrF/Gl3PJKlHJ8zOFXykFu2jdnfJC/5Wo+XImZleY535+p8qn7e5/8r9HvR10+7UvZsv11/yRPy5+qv5SPnLL+qf4vZZb9m1tGSrlletn/ZZ667labkt7il3z6EpCABCQgAQlIQAISODYCXOfXfzrD6EVnfKyfEx+/++H8ovvhu04nTJmkdz/c12Hi6vzdj/c+Lvl5LssnHh2G4onjU+pYPs+Vn3pKP3Xip120B5llmymTvGV5wtEvHGh/wnPSa17RI/W05CffmF+yGsoT+Umredb68IzOyd9Kr+XxTJ0p39Iv+ab8KRlpX/qk7p8p/unzOeNjTL/wSf11vjp+TJ86X+SkfehYxuU59Set7r9W/6TcmN+qf6w9kTfVd3PzzJGRvozM2ocvcmrOLX61HJ/P/1+RgxwcA44Bx4BjwDHgGHAMXP8YuLTVv+uQUdf9CO5Xv59+dLrOk9M1ux/SfVy9NZ/V83uPTtb5WUn/5v2v1s+P37sIryMbgazwJRsrpnHbykdWDi9kpbBuT+qZ8tEv5VjJTThlxtLn8EXGWPnIn/JpH7sNphzy4+gfdjygG+7ltx72788nnbFQ7v5opbf6Z45+qXtTf4zfHP7bjo/wqcdE2lLH19+fVnnk0L6MYZ7ROS7l81z3X6t/Um7KH6t/Lt/W+Jyqe99pLX77rl/5EpCABCQgAQlIQAIS2JTA7K3+3/nBuQFfGyd1xd2q3iVjEAMaF+Px+adndZGdPO9b/k6UnBAyl++EiGYSExFw6lYz+7zlNuhm4S4DRv4r//m9/lPmRybjYio9+af6f1v9Uscm/iH4w6d1/sDY94c2zSk/1fZt+2dKdittDt/r7P+W/qRP8Wv9XZwj3zwSkIAEJCABCUhAAhLYF4HZhn8Mthh5QwphtLBKyQ94XLd1eCibcQME5vAdKLY4CgMl71UzAfDsg7NVdm7UwmpjjdXjv//mdDT/VHomZuo66ucl+tVlt3k+BH/4nLx5sjpb/WNQ1db3p1V+UGgRuYv+KcQtCs7le139P6cxU/zmlDePBCQgAQlIQAISkIAErovA7K3+/CDnh+/9nzxc69q989qHs7WYFbFnf7hY0b/3/Ytt/in/yi8utprv8sqsfctfN3pPgeg/xXebqjG8h4zvegWagxPj2HadHRvEYfSz4j8kp5We9o31/1z9otuu/ei3L/4ln7waU7dh6vszp3wtr36e6r+0f6x/allLnyN/jO/c/s/kx9L6d5F/it8u5CtDAhKQgAQkIAEJSEAC+yJwZcW/PBGbSsvt4KzksyqJ8ReX1WOeeb+X8knP8+qTVX/yPuVZZb7/7fmJ/JwYv0vjf9/y0+Z9+S2+29Zbs+bU9kzalLLzKgBGVnljQnYG1HJy8n8rvdU/tdwx/UpddxneN//wqb9j+Q7l+zL2/WmVb7FI+Zpz+q/VPy35rfQW31qvof7njJDybwx50q5W/dump55az/DbVr7lJSABCUhAAhKQgAQksC8CL3WCOQH8VjpWVlm1xuDQtQlg8NeHs7VLmUMCEpCABCQgAQlIQAISkIAEjpnA7K3+x9yIMd0w+jlzQCcBCUhAAhKQgAQkIAEJSEACErirBK5s9b/JIDhzINukaUf5msJNbpe6S0ACEpCABCQgAQlIQAISkIAENiVw0K3+d2UrOa8Y8B7yXXv3t76Kbqz9d5XPpl9Sy0lAAhKQgAQkIAEJSEACEtiGwEZb/bmmLyf6b1O5ZW8XAc5S4KA6DH6dBCQgAQlIQAISkIAEJCABCRwHgUWGPwY/125xZR/XwLFy6wTA1Y7kpHwMYK4w010lIJ+rTIyRgAQkIAEJSEACEpCABCSwLwKLDP8nH5/21+89/ei016e/5/2f4SUKsiWcbf98yjvhmUhIfPxSLnkTH78sT14mIpKGP+RS/1DaWBy6UY7JD+TmmXB0iNzUX8uqy5VlydtKJ89UHa3yc/hRx5hr9c9YucRP6U7a0CQScaTh0r7II43+iEt6+ojnMj35pvx6/KTulBlrQ8ZD6s4zOmR8RIa+BCQgAQlIQAISkIAEJCCBQxPgOr/Zn84wetEZNy86A+hFZ9DMLkcdnRHUf1IuclJ/4vNMHdSXZ8p3BtX6OfHxyUue8hkZeY5PXJkv8VM+9ab+1IO+tKHUERnJW8ujPJ+0s2bYSq95RI/U0ypP+hS/yBnzo3fSa30ST76ynYmPP8RnKI78pc5lmDTaD//I/f/ZO78WW4pzDy9jiHvgwNYNQVQ4hhM1iMK5D+QDBAO5yRfwInDuAuKVH8CrIORO8MIv4I2g5AMI3gci4p9IFNxhExgVhNkRNvv009vf2u+q6e7V68/MnlnzFMx0d9Vbb731dHWvfquqq0lvZdrjyA5tw7OtZ2Tb+kae9NjPNvHoGWof0ed2/n1HVrKyDdgGbAO2AduAbcA2YBuwDWzfBjYa8e8cmX7V/Ju/+2rxrz9/vXj67Wc69psFvhOfKfC3Xv968cgz15YjoomPRj7Fd+25oxwu/vP57QWzDMbCoy/dWNz6y81lMjMT0N+GvIvexq87pnymqRP4YkBr77r8pNf6Y0erYywd9tQlsy3QdfzKv9n0sw/6ne7fWH7S1/GLjrFta2t7fsbyzYmHK/Z1TvNSnP3KfJkwsUP9c44QI//ckPbT1pP8c/hXW7dtH3NtVU4CEpCABCQgAQlIQAISkMBcAht9zg+HiHfXCThXX7z1ydxyZst1o6orzjoOVAKOMg5YN4rbR7Wf68Mx5nN+9ZN+CJJnyJmL3suw/dkL9zpAdqnHOn5zOEydnzn5p2ToTOJrCOnQwBEn7rwC7Ye1K4bCPvgP6TVOAhKQgAQkIAEJSEACEpDAWRPYyPHftzGtM4VTySgyDiqhmyZ9qsja+UAHwO03TpaOIiOu375/vDw+lfkSR/zw0T2HdNdOjCl+6/DMOT/rdEyl96P+r94b9Y8DXkfv27x1Nkibts0x7efo+aPFyeLerI6qY1/8q073JSABCUhAAhKQgAQkIAEJnAeBjab678Ogx35/Y6mmXxywjOgz4soXAxKuPXt/mj8OL39tiINIPE4/o/1DcjUfDmxmDdT4i7yPw45jev0P9/llWvyUc5w6zeGHLFzG2Eydn5Sz65YRfs4hbaMd7Y9jThnU/fpvH9u4uKn6pf107+mf0rsr/1MKjZCABCQgAQlIQAISkIAEJHBOBM59xB/HPo4ljhzrBSTwfjZTvTNVP8eL9xYL1gN47oMXI9pveZ+/Or2ZIt7K8V15HLfLHpgJQadF+FCfvHoxp24tl5bfOh05Hyk/x5yfeh7X6ZlKz6g/MvXccpxXASgf2/nb56h/2g9tcPEmJd4LYbwr/+hzKwEJSEACEpCABCQgAQlI4DwJPNQVxqroBglcGAJ0DNGp0Dr+F8ZADZGABCQgAQlIQAISkIAEJHCJCJz7VP9LxEZTHwCBbVbyfwBmWqQEJCABCUhAAhKQgAQkIIFLQ+Dcp/pfGjIaeq4EWMgx7+xnav25GmBhEpCABCQgAQlIQAISkIAEDpSAI/4X8MSyuBzT3dctUngBTd/aJNYIYM0HQhbgG6v/VeSzNVgzSkACEpCABCQgAQlIQAJXnsBWjj+js1lR/soTFMDeCLB4HqP9LMZokIAEJCABCUhAAhKQgAQkIIH9ENjI8cfhZxSWlfn5jB4jr+fdAcBo8NDn1vaD42JoYVE7HOBD+BLBWRCVz1lQVacEJCABCUhAAhKQgAQkcKgENnL8v3n3uP+k3nfvHPc8+NZ69ucCoqMgU7nZJtChwHHtSIgsMnQ6RJ7PrUVH7QQgjmM+eZf0Ol2ctMRnm/LZxoaksa35Ixv9OZ6zjV2pR45rGdGb8lu9xNd8NS+y69KRmSpjXf65fChnKKzjP5Snxk3ZTlptO8lHHGmE1K+mcT4Skp5zxHFNj9zUNm2WvPyl7OQZq0POa8rOMTqG2mD0uZWABCQgAQlIQAISkIAEJDCHAJ/zm/3XOTZ3O+fkbufA3O0cktn5KIO8nSOzzMMxelI++kjvnJ5eN/ttGUlPnrolreZpbWx1kY4N0TGlOzJsyYdsjVu3T52iPxywB5bVBvREttVJfv5Sj7Z+69Lb+saOlLMuP+nYFvlNt7E7+Vp7Eo9crWfisx3iMxSHfLW57pNG/eEfvaS3Mu1xZIe24dnWM7JtfSNPeuxnm3j0DLWP6HM7/74lK1nZBmwDtgHbgG3ANmAbsA1c5Taw0Yh/54gsHv/TkwsWYvvXn79ePP32Mx27+eHRl24sbv3l5jIDswUeeeba8pip7aQzoo9u9jed7s7335OHd8azTyF1n+Pbn50srj13xG4fWFyOWQzrQt5FXyfXpqM/36b/7q/fnLKnlR86nqof8mPpnDtY1xkax6/8uy+iczaXRY3lR2Aun6WyZmcd/0Z8o0O4Yl/nNC/zsV+ZLxMmdqh/zhFi5J8b0r7bepJ/Dv9q67btY66tyklAAhKQgAQkIAEJSEACV4fARp/zw6HJp9Zwjr5465ONSOF40nHAXw04RXGWcEZxoAhxTKvsrvvdqOtKZwMOVgIOPbZ0o7x9FGl0chxC+NkL9zo4wnmbOu2DzxT/bWyqeeiMotMo7YZ2RNx5Bdo3a18MhX3wH9JrnAQkIAEJSEACEpCABCQggXUENnL81ylbl86I5rfvHy8dsyF5RmkZieeb7t0057063jid6MaBJaC/DbVzgw6A22+cTNrb5r+oxz98dM8hrZ0s29i6C585/LexKXn6Uf9X7436xwGvo/eRy7bO9kjcLlva99HzR4uTxfen1OyL/ynFRkhAAhKQgAQkIAEJSEACElhDYKOp/mt0rU3G6We0H+dzKDDlPK8S8Ek3nP86DZ08ca6G8q+LY0SWLxIkXHv2/jR/bBqyKw5k8rDFgc2sgBp/kfdx2GF3/Q/3ZlNga6bFTznHqdNcPnAZYzPFP+XsumWEnzbEKxvtaH9tO9Sd9rVpmKpf2nfbZiljV/6b2qm8BCQgAQlIQAISkIAEJCCBEDjXEf9MwX7ugxdTfr/Nd9uZps071gQcpbzv/8/F/feuM507rwsgE719xol/6KaM5M3x4r3F4tbrX/dfLKjZ0T3HKa55LvI+Mx3otEj9sTWvbsyxuz1vm/IJ75SfY/jv65WKjPpTn/bc1baD7fztc9Q/7ZA2tnjzPtEw3pX/fY3uSUACEpCABCQgAQlIQAISmE/goU6UVc0NEjgYAozK06nQOv4HU0ErIgEJSEACEpCABCQgAQlIYAMC5zrVfwO7FJXAVgS2Wcl/q4LMJAEJSEACEpCABCQgAQlI4JIQONep/peEiWZeQgIs1Jh39jO1/hJWQ5MlIAEJSEACEpCABCQgAQnsncClHvFnwbmxheT2TuoCKWTxOOo9tBjhBTJz76ZkUcUssFfrzxoBOPz8XVU+eweuQglIQAISkIAEJCABCUjgIAhs5fgzupoV4Q+CgpW4FARYHA/HPotBXgqjNVICEpCABCQgAQlIQAISkMADJrCR44/Dzygrn8TjM3eMrF62DgBGi4c+t/aAz8NGxbNoHQ4wXz4wnCYgn9NMjJGABCQgAQlIQAISkIAEri7dRZA/AABAAElEQVSBjRz/b9497j959907xz0xvpWe/TkIW6ebTgM6ExKSnqncbOt0buTqdO/6TXrSMsW75ieeQDnEE/jcWmTaTgBsSlrk+0zdP2ypaey39iEbG5NvzhY7yBc7c1zLiN7Y0OolvuareZFdl47MVBnr8s/lQzlDAdspo/4NyY3FTdlO2lAnFXGkEVK/6B9rnzlHyNf2m3xT27Z9pezkGatDzmvKzjE2DLXB6HMrAQlIQAISkIAEJCABCUgAAnzOb/Zf57jc7ZyPu52DcrdzOGbno4zOSbnbOSzLPNGV8knnL8cpZ+q4yrf2YCNlJD/b1oaahmzVxzE6IjOVNzJsyVP11LSxfbhEf+ygPjBo6xDZVhf5+QuH9hytS295xY6Usy4/6fX8Jt/cbeyOfGtP4pGr9Ux8tkN8huKQrzbXfdKoP/yjl/RWpj2O7NA2PNt6Rratb+RJj/1sE4+eofYRfW7n39dkJSvbgG3ANmAbsA3YBmwDtoFDbgMbjfh3jsbi8T89uWAhtX/9+evF028/07HZb+D76wm3Xv968cgz15YjmqzaTrkJpNfQTn2//dnJ4tpzR1Vkcv/Rl24sbv3l5lKG2QyUn/Cfz28vmOWwLuRd9HVybTr68+357/76zVZT+eEXDtiR/ZQ1ls65pa51BsfxK//us3XOZrIvxvIjMJfPUlmz09q66flr1K0cwhX7Oqd5Gc9+Zb5MmNih/jlHiJF/bkj7autJ/jn8q63bto+5tionAQlIQAISkIAEJCABCRwOgY0+54fDwrvlBJyfL9765NxI4BgRfvjoZLLMbtR0xVnHQZobcHzp2OCvBsqm7jjS7HejvH0yuukEOYTwsxfudZAMOaVz67cPPrucv3V20mnEax7p0MARrx1J6/Lvmk77Ym2MobAP/kN6jZOABCQgAQlIQAISkIAEJLCR479vXOtG46szFMd/ygacRkaJcUAJ3TToKfFTaYyofvv+8dIxPCXQRdTODzoAbr9xMik/pOMixqVDJZ0c29q4C59dz986m/tR/1fvjfrHAa+j923+de2zlV93TPs6ev5ocbL4/pTovvifUmyEBCQgAQlIQAISkIAEJHDlCWw01X9XWnF80MM0a6but+Gx399YRvWLB/44Yo9DSf7HX7s/1f65D15cyrLDiCpfHEi49uzpaf7Vhshli9PPaP9QJwNxQ/FxIKODLQ5sZgXU+Iu8H751wcRMi59yjlOnuXzgMsZmzvlLedtuGeHnHNO22tH+2jbG2ue6cqfql/ZVX52Ivl35R49bCUhAAhKQgAQkIAEJSEACLYFzHfHPVGscL96l529oVDWOIY5YnUrPSD5p1+/c6zDge+7V+ef9a6ZyZ6p+jhfvLZZ6qg3AwIZM/c626kQm341v48k7xylGx2UI8KXTIvywOa92zLF/Vz45Xyk/x/X8zbFjSiaj/si05662jan2OaV/Ki3tiza6ePO+ZBjvyv++RvckIAEJSEACEpCABCQgAQncJ/BQt8uq5Rci4NTj7LUO2YUwTiMOhoDt7GBOpRWRgAQkIAEJSEACEpCABGYQONep/jPsUUQCZ0pgm5X8z9QglUtAAhKQgAQkIAEJSEACEjhjAuc61f+M66J6CYwSYKHHrCmRqfWjwiZIQAISkIAEJCABCUhAAhI4IAJnPtWfRd9YnX+T6fvkYbGzfYaz0Dll31h5Y/FTumrarvmjC0e4rp+QeLcSkIAEJCABCUhAAhKQgAQkcFgEtp7qz8rkvCudld/HsLBKPIuZ4bDODazczyJzNWSlfMqsf/WTfZQxtGI6euh8aHVW/XU/das2U0/KnRuefvuZU7aglwXwxmysulNelcUe8tc61zztPvKVVd3/5t3jteeu1eexBCQgAQlIQAISkIAEJCABCVw+AqdG/OuU6KnqfNd9Zo8RYxzTqdF8nG1WK28D+egQYMX8Orof5zbyrOyf/KThUOcYW2+9/vVK/tjPdO5qG/t8Qz0rq0f/0HZIL3JtPHX78uXP+/Jbu1u92BPbalpb/5oWnZma3pZfZbMfrhyHHQ6/iyaGkFsJSEACEpCABCQgAQlIQAJXi8Apx3+s+mMOfJUfcmz5LFo+z1Zl03HAyHZ1xms56KvT0VvHtz2O/uhky+cC82530rMdcoZxtplxQLlDI/w403xvnoDTzoyGan9013oQhy0nH58sO0nauiXf2Ba76isT6INrOgWG8qUToMqkM2Go7kM6jJOABCQgAQlIQAISkIAEJCCBy01g1PGP85zqtY5s4se2OJh1dB65dTpwhq89e7R0rHFOmRVA5wEOPNPTmV2AHM58Og+GbMDp/eGjk+VsgHbEf8yW2MA33etMBuS/ff940MlP+XGqc5wt9Xjs9zcGOyAyKo/sWH7SkLv92clSB0zocKBe1U5k0ynAfhtS3lC+VtZjCUhAAhKQgAQkIAEJSEACEjgMAne7apz660a773bO4TK+c3yX+8h3DvLdzlFdiYse8rXypA3FJQ+6ar7Idk5sX1bSOE5a8g5tkavx5K9xQzqQSTk1b+pKWuqMLhhVOdKQJS76OU5ctklDBzqrjqF98s2RG8obW3bJP6bX+NPXjUxkYhuwDdgGbAO2AduAbcA2YBuwDVy0NjC6uB8jw3UkmentTH3PH6PvTIkfCozSM2LeObZLefK1OojrnOVeBe/5U15ksmU6O+/xE9oR986BXubvBX781zm5/bT6lbju/X6m2tdA2diYwKh8rTPxpDO7INPsmdrfOeJ9ljqFPjqGtrG/ptVya/wm+9Q/trT5qFvOFesQpF41fh82tOV6LAEJSEACEpCABCQgAQlIQAIXi8BP55qTKeJVPs5k4nC4cfqZgk9gKnp9/x1HNQvzJU+7TTmRjXOKU37705PemSUPTi3v2PcO+YffL9VgwxOvPtUvuodMDeh+5M377+fzKgKdCel8qOsJkC9l106Q+spB1c0+nRd0iKRctkzzJz5lJA9coj9xyZfjdgvbGlJ/dNcFEmFHxwkBGeqZY+pChwV5+EJAPT9Vt/sSkIAEJCABCUhAAhKQgAQkcBgEZjv+66qLw41zjlM5Ngq9TgfpGelnP44wI/VZvR9HNZ0COK84+V+8de+rAcQTeBceR7iOyCcPtsXBn+qEQD4zDB596Uavl3849kMzAyLAugK8f08eZj3grH/81t+SPLmt9kYQe+nw6B309xZL25N+Ujo9Epd6kRcOHFMfRv7pKCG0fJLXrQQkIAEJSEACEpCABCQgAQkcFoHRqf6bVpPR/zjUm+aNPI48swVwgDMyjRPNZ/gYtaYjgL90DhCHM0unAwEHF2e7DTjAyBFw3NuR9laeY3QNjYZjCwGdQwGbkg8mjPhTHo42fNinQ4GAXDtroupEdun0dwnkp/5wWhdiX7bIYwOdFuG4TofpEpCABCQgAQlIQAISkIAEJHD5CayM+DMqnCnhVA0HsYb2mDQc9IwwV9k5+3VUHXlGo4feh//undXV9MlXy6yj3jjmfBkgAccXZx+nl4CjffTGUe+4b9JRETYZlecYHjlGd2tXyjtZ3HsVgQ4KXhWgjmGZ1fmRrQG7q9OfNMqjHGY1jNmPbjochjoVyHNz8VXfeTAll/LcSkACEpCABCQgAQlIQAISkMDlJrDi+FdnetdqMbI89E56HF708/45i+UR8qrAzbe+6o+xJc42jv/cwCg68ilnyAFGhtH0yFTnvS2H0XU6Q7A1nQfIYB864uxjf2YVVB048CwOSKifH0yZ5MdedMceZIfsJp5A2ZQX+dgWXtGN7bzHT6CDpgbKowxeTTBIQAISkIAEJCABCUhAAhKQwOESeKirGp+TM0hAAhKQgAQkIAEJSEACEpCABCRwgAT29o7/RWXDqDej45sERvKHwlj8kGyN2zZfdGybf9t8KdetBCQgAQlIQAISkIAEJCABCVx+ApfW8c9U93XOLa8S8MrBnAXxcjpZkb/VS/7H//TkqfjkmdryVQKm4bdhkw6JofzETdULe+vifpRPvTYpt7XZYwlIQAISkIAEJCABCUhAAhK4XARW3vG/CKbXd+Kn7Mnq/+ucWJz4vPNe9ZGPDoG8H1/T2G/XFXj8taf6d+JZPJC8Qwvn4VTjbA8F7M07+Uknrv8cYffOPmGq7kP5sR27hhb5QxcLB9LpMFTukP2xy60EJCABCUhAAhKQgAQkIAEJHA6Bvb3jnxHyfMpu34gY3V63+OCQ44zzO+SM40jjMGM3NqcjoLU7zjMOf+pGOUMr7rd5GY3n8358YpD8OOFVTyuf46kOhMhMfU2hdobUjgUYYotOfyi6lYAEJCABCUhAAhKQgAQkcDUIsLjfXv46h/VuN7p8l+2uOlsdndO6kc7O6b7b5mmPx2ykDuQnHTs6R/9U2akrsp2jPZie8khPfZIv+odsQKbq5Dj5ka/62vykVXspBxtrndo8Hu+n/ctRjrYB24BtwDZgG7AN2AZsA7YB28BFbAN7nerPiDh/jIh3jmY/1Tyj5F3lNwqM0jNCPjY6TRm3Xv965RN7KaBzflem0Cd+zpa8BD6Dx6wARvb5HN/1O/c+yVd1DL1C0DnafV5mCmSGAp/MSz3Cg5kAfCaQMPS6Qf8pxDdraYuVmQtDZSPNZxTr1H/WOEg9KDM2rWr2SAISkIAEJCABCUhAAhKQgAQOlcDKVH+c6XxzPhXOlHiO16UnT7aRxwmOw5u0ddtutHzFSaUjoQa+Qd86uUlHlnSm1Q9N848c29bpxuZrzx4tvnz5836afnWU6RSIA4/cN+8eL4/j8GcKPvbHsScu+ym7LTfx0ZPjqe2Y80+esOf8cU6RHdK9zbmZssk0CUhAAhKQgAQkIAEJSEACErh4BE5NU+9M3Cmuczp3nvKfafKxpT1OfN0yzZ0p7ZTPfk1jf52OzjHu8yHHPnnYZh+90YnMUBk1Pfvttupv04aOx6b6t/EcU3/+Yhtb7E4d0F/rQZ6aNlS+cbtdD/KTn23ANmAbsA3YBmwDtgHbgG3ANvAg28Bep/p3TmQ/ws4ocp1u3lXwzEPn4PYzABjZ7hzbrcpbrpD/6v3sdz680+ujPozwo5tXDG5/dn/6/n3p1T1mHswNnfPdvyIwJd/OXoAzgbwJmQWAnf3rAl0Co/711QJkv/njvdkKm87ESDluJSABCUhAAhKQgAQkIAEJSOByENib44/TT4jjed7VZwp+puFvUzbOMw79WKBjgXf1v1kcL3hvfko2OsZYdCP+EVlu6WBAnnLisC8TB3Zw5lun/fjDfy8l6ai4ufhqQVm1E4Z60gmwC6tlIe5IQAISkIAEJCABCUhAAhKQwIUnsDfHv3VCt6k5Tmp9F74dMW+PKSPv1G9b3rfvH/cONI73WKiO88mH3y+O3jgaXFSw5qceQ/Yig81j5eGQf/zW36qq/pODRGzKmPLbzoefvXDUz1ZYKcADCUhAAhKQgAQkIAEJSEACEjhYAntz/PdBqC6kt6s+Fv5rR85ZUK864xwzej8WmC7fLnYY2TrtPgv15VWHyIxta6dAXTyxla8dISxWuC60swWq09/We50u0yUgAQlIQAISkIAEJCABCUjgMAisrOp/GFWyFhKQgAQkIAEJSEACEpCABCQgAQmEwE+yc5m2vKdeF7TbxvasSVDzopNR87lhVxvmlnMocsxgYOZB/uR3KGfWelwlAtwjuYbP+/p9kPcP6jqnvut+P4Z+d3ZtO9vonFufXW0zvwQkIAEJSEACF4fApXT8eU/9uQ9ePPUgxgNQndI+hfnRl270C9+1MrweMOcBj7KGbGj1eXyfAK9y8PoBr0Y8qMDrG+l4GHNeajrOxqZhXX7aFzLrnIShcqv97G8Sal7K38ZhqDo2LR9bd80fp3OIXeWe/U1srLaN8akyQ7qn7EvalG2RGarfHH7r7EPHLu2P/A8qrLt/hGvdDp2jOfajo/4O8MUX7vfrAgvAknfs/PGKWNW7Tt/c9Dn3qdamtj5pe3PLVE4CEpCABCQggctHYPlt+s70S7HfPcyd+k49tncPP7Ps7x5wVr5l3z2oLfXN1UGeMV7dg93dqfSxfPuIr3XZRt+u+eeUGT5s58jvS6ZzdFfaCMe0peiPXbSPxG2ynZufNrYN59Z+9BA318Zar7m2Vt27lr9LfvLCjPM1lx18ap1rXYb2q+wQnyn7t7GPepAPW+bknyo/Our9a6x9ED+X4RCnqbiz0lvLzLlhW+Pb/U3Pf81fOdIuqNfQ3zob0Fllql7ia1otf2q/ttPIDempZUWOOhCPfL33kY7etEeOSR/SG11uL8fzkufJ82QbsA3YBmwDaQPntrhf90DRlbn5yvR9ph//dQ8t/R6r4mfxPhbH++bd436EpS6al3xDq/4/8epTiywk2D3sLG795ebg5+26B5+VT+FFZ/fg1I9ax57EZ0uZ/HUPTaOr90e2btHHIn7ULYsKtov/wbEuLJgF/LA1efpFDd+8pxl9cz7dNzc/da9fXkj5qce69MgNbeHVjkJl4cQh+RqXvJzLfP0grKqNtz87qdlW9hnVg/ccXisZfzyYkx+b+JIEM042DZz3usjjv/78db+AZeq7Tl+tF1+VoI0ePX+0OFl8vy5rn75r+bvkp46p5/U7j621l+sazrXO6zJV2SE+U/Zvah+2wD9hTv6p8tGzLh2Zde2vXr9cC9xTcv3UNHQlnv259w9kp0Ku2cjUMhI3Z7vN+ad+XFO1HXBf4fei3ldyr2lta/lwfvmdae9p9XcjMnPqhMySz4/39+RDT70vE4/NyOe6IS42UwdCazNxtCMC9xoWv62fie0T/CcBCUhAAhKQwKUlMDlq0tVqb+ndQ0g/asJ2W70ZlUBH97C51BOdpEd34nLMlrjuwWs5soGOxBFf/1JWmx/57sFpWQ7pyKZs0roHqpX0qmNsP2VHD3LE5Th2Jj/HbTlVPnKbbKfyUxZlRl9rz7r05IMP5bQMp8pO3qlt9MIr+0NlpJyWHcfkJT1/bf6p8tflR1fKjOyUvpqW+gzFbWJjzR8ONW5sf9fyd81f7ZpjNzI1zzb7tZxN7K/5xsod0hfZofxD8oljm/3oYJs4tjmean/cC5OOPMdDHHON1LKyP2R70tZt2/vJ0P0NHW29hvQO2T0k18aRD/1wyBYZWHBM3SujNj/HNR/HVT77uUcN5Z+KI19Nxy7+atzUfs4d9WzzkVbv71N6TNvfc5EsZWkbsA3YBmwD59UGzvUdf0YeGHG49txR/x5k95DR1XOzwOhLRjAY6Seg57t3jvsRdka7uweY/i9yKaF7IOt3GcmKPDpiF7YxcsKWP0Z+qo7Ye/LxST+K0z08Ld8Xp1xG6hOmRpYjM7RtR+ixJ4FRYkZxEqhDO8qTtH1vYUdZlJkQNvBel548U1vqyvndNjBKCx/OxdNvP9PvE1dDePazImpCt0/9iM/5R1c7WtdkWTlclx+bvnz585U8cw9Y16INqdtQWivbHncOSM+njm62MvV4qIxNyt81f7Vl3T7XaZ0ZsU5+KL3lsy/7O2erv2fQrjZZ62Jd+evSqeO69sfoPiPeCbdev7+fuLPc7uv+tsv559pPu6aumRl283df9fy4x8OI8zgWmPnDdU4bym9GKzv3uluXj3OGbUMBG/ObRzq/V9hPHdP2SM/vGPc+RvtzzLbmHyrDOAlIQAISkIAELg+Blan+PChkuniqUKea75oenTyo3Fx8tVzoCwcrTmRkhrY4mAQeSJahm/JIfh7W6kPK0IMVD748yOWhjYflIbml7m4HnVU3dmJHazMPeHQInGXAseTBLFMxU1ZszPHYdt35G8tHfByL+lBc5delV9mxfc4Ndcn5rW1vLE8bz/nJNPq2TVF/pn8nngdz/vJwjy7OawJysJ7Ldyo/U2Ype4xfyhzbsmhYG7CLMJTWytZj6lw51LSx/aEy2vKn2tec/GNlbxKPTZz/41c+2STbiuwQn33Zn3sfBdLO2/vIiiHlYJvy6/nh/jTV/qpsKfZcd3e9v2HsPs5/WOS+n86/vHbE/b93uLvfsDbAmTQ6lHH+0RFnGll05P5GJ2S997S62mPaJYxqoP1EX41nn84vOiHSMYDD3wbs4z57+9OT5X2xlfFYAhKQgAQkIIHDILDi+NeH0qHq7ZoenXEQeGjJQ0nSprY46V+8de+BPo52ddxxPnmIGXpvmYe1oYesoYemGsfDWR7g6ruOQw54RhnjBE/VZZs0bNnUYavlrDt/Vbbdj+PBQ/GQ87ouvdU3dozuPKByHm6/sdkDKe2C2RY8fNPOavvKA3nK5rzyUJ86ZTZA0jfdTuXHGY1jE72MsN16fl6nV5jTjtPm086SFr1TW5yH9j3mKfmkpYyp8qfa15z8KWuXLY5OHbXeVNcYn7Own/sfs5/mhLnlj52fR9/erf3NsXFXmV3vb5S/6/mHX2Yd5Xcq9UoHQI7zO5EOAe49BOrBtc1vEbMm0oFJOueR+xt5h36Ponto28rTVumcTEcm97F0bid/7hUcD3UcZL0M7o1thzJ5qEtbLvEGCUhAAhKQgAQuJ4HZ7wd21dtJtnvw6d8ZZburru4hZvkeNvvo6x7U+ncw2U7pJ717SBqUia6p/N3D4eC7kOjtHuhW6ojslK6aRt5WHnsSF35jtqML+V34TuVv02JP6rAuPXLYT11rPdivx8gO8Qjf6KpbOJFOXMoIO+Kwr7aN1v7kjx2kk6eWMbW/SX70Vtuid6p+rT0tb3RM5afu6+ozlX9O+anH0HZO/qnyoxOZIXact13qt47PHPtzDobsi/3ZUg905jjbsfqtK39devSzHWp/xNXrY+xcpJ1XfdlHx1Cdkj6mk3TykZ7rL3naba7tVm7O+W911eNaf/aThl31fLJfOSFH2al38iKDbOLZRq7qSzmbbNHd1p9y27gpndgTW2Nb6sJ5iN1TOkzb7ZlIfvKzDdgGbAO2gfNsAysj/l3BZxa6h4hed0Zztymoe0hZTnVkFKWOXHYPPItrz96bus/oM+VlJGSbsrbJkxFPbGFkh+0+Q+rTjjxlxImyYJJ3NTmeO5UYWcJUfkZ+OAd1ZKiez3Xp90oY/9/WC9vriNV4zntTfKl3Zl3An/x93OLelw2wr3ugXWSUC33VfspiBL7aUdOnyidt1/zr9HP+sz4GslwDaRPr8pLOqB4BBgmbtI9dy98lP9dzbXec10X3mk8dkeR1im3X1oDHOj5T9s+xr5Wp569NG6rfVPnYvy4dmanQXh/cV+q1MJU3aVP3j8iMbbGf0JZZ729jeYnf5fx3jvjK70ktB7u4Zj796O+Ds52Q5X5TZ4QRx+9B56D3o/4co4f7J7O25t7XyDcU0F1/DyODHesCv0thDFtCbOP64Xd0k/veuvJMl4AEJCABCUjg4hBYjmx0Jl2a/e5BeWUUhhGKaj8jIsjUuOwPjZaQ1j0QLUdAIju0raM4Q+mJQ46ycuz28rSv9lzRvqb+WnmPL++59tzdO3fcvzrn8krev6bqve6+nrz8ntT7P/GJG/tt2rTtoa/+9tV7FGlVH2WSHvvq72D2SUOmzVv1uO+9zTZgG7AN2AZsA5ezDZzbiH/XQPYeeJf/F3e6kb8utCMUGRFhlJBR4F1HWKrx6HrsvRsrI6c1ve4zItk9RI2OFFVZ9y8ugbZ9XVxLtUwC+yHAu+67zKDYjxUPRku7iB5WdE7xcsYZM2WmQtc5sFwroHOke9HMXOC3qXPCl78fiZ/SRxp56qwX4vh9qfemuk+50c1vEKGmM8Mls1z4jWS2ALM+CLWu0dEn+E8CEpCABCQggUtL4KHOckYFDBKQgAQkcIUJtI5lFqW7wkisugQkIAEJSEACEjgYAhfS8T+LEfKz0DnVCsbKG4uf0lXTds0fXd3UzpUV7xPfbimPMOfd0TavxxKQgAQkIAEJSEACEpCABCTw4An85MGbcNoCPsnEVMMaOGbqYvuHA5uAk8oUy6HAp89anUNyxKGDcuL0ElenZnK8LvBZpdYWjllUqY0f0pXyqiz2kL/WeShv4pBveeWY70xTxrqAw09d5pY5pg/26IhNtV5jeYyXgAQkIAEJSEACEpCABCQggf0QWFkAqFP5QI87x3BlEbXOYVzaQ1o97hzJU4sQEdc5t32ezrlc5mW/c3SXx1P1HNKLfBuPLdhEWms3NtS/5K9x7Cf/kD3RmbS2/MTXLfVMGWHFcWVR5dv9MUZDdqJ/rl5sjyy6YltbvscP9vqTv/xtA7YB24BtwDZgG7AN2AZsA4fXBvY21T+jx/kkU9dYtgqdQ7hcYKhzFlemo3N86/Wvl9PO2+MUiC3YwZbPn2UBo6RnO7ToX+eULphxwAJMncMc0eWWxZSy8BOLHvEJqaE613qQGVtOPj5ZLjLY1m1ZwMgOdjFrIYsUoo+FnupiTW3WztHuP2dXZdDDrIGhupN/qM7E13pzTOg/t1fqRFzsYn9OQG8WlJojr4wEJCABCUhAAhKQgAQkIAEJbEZgb44/xcbp2+Tb4NVcnGG+IRzHGueU71mjDwee6ek4vsjhzE8tPoXT+8NHJ8tOAo75CkCc9NYxjx2xge9Rx8kmDXm+v5z8ka/bONU1jn3q8djvbwx2QFTHdyw/OpBjhe10YoQx9ap2IpvzwH4bUt5QvqG4Nv86DpRNaDm1/Fu9HktAAhKQgAQkIAEJSEACEpDA2RGYNf29K362XOc899PNOydwdp7O6e2ngneOZZ8nW3Sgr3Mc++nhHCdtyqa2bPLXuCEdyKScqpvyYx9b0tDFFPoqRxqyxEU/x4nLNmnooLyqY2iffHPkhvLGlk3yUx51G/oLh7GyqFPlHLnKhjjKCIfIuJ1/jclKVrYB24BtwDZgG7AN2AZsA7YB28DcNvDTTnAZOmdsOaKcyDqqvi49eZgmf3PxVT8yz9TxjE4nfWjLInInH36/eOTNa8vp5uQlMKWeae4ZcX/0pRt9fOc4Lr58+fPlqH4f2f3rnNx+Wn2O2TLaz1T7GjpndGWqPqPy2L549b5U58T2TDLbgONrrx0tbn96MjnN/r6Gbkp893pCG9Cza6D+zALobW6UUTem9BPqd5hr/Nh5yflrVC4POU+0BWZnDE3T5xWE+r3ptCFmK9Aueu7dfn0FYancHQlIQAISkIAEJCABCUhAAhLYK4EVx3+dw7cuPZalgwDHcsgpjdzQNlPRcWpxKuMg45TjbKczgG06BHBEE3D6n3j1qb5DILJJQzcdCwTyslo9nQk4ooTW1pRNvkynr68c9JnKPzov6CBIuWyZ5k98yog4U+GjP3HJl+N2y2sPNaT+6KaMBNjldYnUM8fUBYebPHQM1Cn5sGvLiM52S714laItGznSwou2kI4POgAog3NJ2zBIQAISkIAEJCABCUhAAhKQwPkQWDvVvDNjlkznyG48xb/V3Tm/p6aYd87iyur3nWPb29M5nSvTxYnnr3M2T9mbPENprQ3RQ31IS172sWVKBzaRjzzIUh/yEZ980YccMm359Zg8sSP5a/rUfpWnTGxYV17VR37yELeu3slX8xBXj9EFj2pX8rmdd43JSU62AduAbcA2YBuwDdgGbAO2AdvApm3gJ12GvYTOOe31MJpcR5E3Ud45hv2CfejIyDQjw0zTZ3SeEXH+GL1mSxxT/TuntC+GGQIsyteGztHs5Yif+/16dA3VA1sI6BwK2JR8jHoz+g0bRuSZUcA+swwIyGVkfEgXssxyiD7yU284rQuxL1vksYHR9nBcp4Op/HUmwZB82CetzVOPeV2DQFxC2k2O3UpAAhKQgAQkIAEJSEACEpDAfgmsTPXfRXWc01104BhmWnjV8907q6vpd6PXK++Wr0z17xzz6lji+OLsx4HF0T5646h33Nup/bXMdp8y6XDIe+kc40DnGPnWLuIo72Rx71UEnGReFaCO5CWMvWeP3dXp74W7f5RHOWPv9iOH7jrdPnnZUue8Zz8lRxl0qkwFOiD6tRN+rB/H6dQgP7wypR8Hn7pjPxxSNnEGCUhAAhKQgAQkIAEJSEACEjhbApNTzbuizyW9cwZPTQHvnMd+anjnUK7YQPyUXch3jmX/h94h2c4RXcq06VV/dLU2kAcdkaWcKpP4zoFflsP+UFnJF5vZjtmd/KRHPvkpk7jIEB+Z2JM0ttXmKkue6Kzy0R+d2SKD/FAZ4cy26mI/bNp4j8/nmpOznG0DtgHbgG3ANmAbsA3YBmwDV6MNPPTjie42BglIQAISkIAEJCABCUhAAhKQgAQOjcDe3vE/NDDWRwISkIAEJCABCUhAAhKQgAQkcAgEdPwP4SxaBwlIQAISkIAEJCABCUhAAhKQwAgBHf8RMEZLQAISkIAEJCABCUhAAhKQgAQOgYCO/yGcResgAQlIQAISkIAEJCABCUhAAhIYIaDjPwLGaAlIQAISkIAEJCABCUhAAhKQwCEQ0PE/hLNoHSQgAQlIQAISkIAEJCABCUhAAiMEdPxHwBgtAQlIQAISkIAEJCABCUhAAhI4BAI6/odwFq2DBCQgAQlIQAISkIAEJCABCUhghICO/wgYoyUgAQlIQAISkIAEJCABCUhAAodAQMf/EM6idZCABCQgAQlIQAISkIAEJCABCYwQ0PEfAWO0BCQgAQlIQAISkIAEJCABCUjgEAjo+B/CWbQOEpCABCQgAQlIQAISkIAEJCCBEQI6/iNgjJaABCQgAQlIQAISkIAEJCABCRwCgTNz/B/+9cODfMbiB4UHInfNH5VPvvff2T213VcZVfFZ6Kz63ZeABCQgAQlIQAISkIAEJCABCQwRGHT8j/74X4vn7/zvojqrN974eR83pGQo7um3n1mgpwaOn/vgxVPxVSb7Ka/qwB7yTzntyc8Weeox9PfNu8cLyhgKj7/21OJ/PvnVShLHQ3qqLZRX7a0KfvbC0SmdNd19CUhAAhKQgAQkIAEJSEACEpDAWRG42yle+euc2budE7sSh0wb3znDSznkO8d49C/5W5mhcmJPdOa4LT/xdds53ksbsI80yiS+yo3tp8zYGR3Ik1aPh+whjrzI1zLZ7zoaZtkwZpvxq+1UHvKwDdgGbAO2AduAbcA2YBuwDdgGbAOz2sCqEM4tzivw4vzWLY5vjpEdc2arg4wu5KojnDLmniTKqvnRFwd7TAfyrQx6iKu6av5qd2sjx+SPfHuc+DBhi0x4tdsxG6LH7WrblIc8bAO2AduAbcA2YBuwDdgGbAO2AdvA5m3goR+hdZt7oXNUF9eePVr8689fL07e+j7R/TT1b98/Xhy/8u9lXLvTOcX9VPw2/p//94/FY7+/sbj+28fapMV/Pr+9+OJXn/TxY/lJRO72ZydLHbf+crO3pXOeV+xEtnO4F4//6Ul2T4WUN5QvdX/kmWt9Puz+xZu/XFDWteeOFrweABPkqMt3f/1mcfN3X50qgwj0//DRyeLOh3f6dI6Pnj9a8us6GJb1HlRgpAQkIAEJSEACEpCABCQgAQlIYE8EliPYnXPaj4TXUe+ujOUUf9Iz4j004k4aI9zkiQ6OE5dt0tCBTuSn/sg3R25MB+Wty4/tyMS2bDNqnzSOkzZWHvHI1XTy17g5Omp+96fbiHzkYxuwDdgGbAO2AduAbcA2YBuwDdgGhtvAyuJ+jMrXUf4OWj96zug2i9ORdv0PN5aL63388N8QWRtuvf71KZnOCT4Vt2lE5zwvbWnzMnugm1rf/3358ufLetX4agMj89SP0X7yZcvMgdjfznigfPS1oXPyFycfn6xEM9rfxpG32rCSwQMJSEACEpCABCQgAQlIQAISkMAeCPw0OnBC22nrcUqZHp8OgTrlPXmzxXlmOjyOM4Et0+WJbx1kXhmI/uRPvhy3W6bd1/Dpb/7ed0igO1PqScchz3R9ZPjCQI6pCx0W5OELAe2rC3kVAB28ghAb6RS5/enJSt1S/smH91+JwOl/4tWnFnQ2tPVB9yNv3nuNIHbRmdDaX+vovgQkIAEJSEACEpCABCQgAQlIYFcCK1PSO2X9VPbO8V1OTWefeP6Ysp4p+4mr286J7fORB9nO+e3zEZ980dc51Wun4JMHOcpI/lre1H6Vp0xswKapPNjb/pGHvMkX+4nLPmns81fLbfMMpUXG7fC0FLnIxTZgG7AN2AZsA7YB24BtwDZgG7ANbN8GVqb6dyCXgdHudjScRKasEzoHtt+2/xhdTz5mCTDiz6g5I/LMKGCfUW4CcplJ0OrhGFlG2aOP/Iyidw73kPhKXOzLlkRsYOQeHfy1Ab0s2MeMgMwMYGE/6ky9ki+vARDHyH7XMdCrghmLIrYBG5AjMCOCehkkIAEJSEACEpCABCQgAQlIQALnRWA5kt0V2O/XUWziMpLdOb5LWeLqceTGdBDPyHnnBPej5+Tlr3OClzqTly1yY2ljo+rJj952ZL+tE6P1rVwd2Y88NiAb3WyTVuOyj3xNpx6tLcgQnzxut++5kp3sbAO2AduAbcA2YBuwDdgGbAO2AdvA2jZwWqA6rnGQW+cXsNXJrU4zadGBgxsnf8jZRS66I9c65EMnkfIin/zoIi7ysZ242JM0ttVm9lv7oi/6k3dIV9LY1nLRW9OyD7vYnzi3p9uiTGRiG7AN2AZsA7YB24BtwDZgG7AN2AZ2awMP/Qiw2xgkIAEJSEACEpCABCQgAQlIQAISODQCo+/4H1pFrY8EJCABCUhAAhKQgAQkIAEJSOAqEtDxv4pn3TpLQAISkIAEJCABCUhAAhKQwJUhoON/ZU61FZWABCQgAQlIQAISkIAEJCCBq0hAx/8qnnXrLAEJSEACEpCABCQgAQlIQAJXhoCO/5U51VZUAhKQgAQkIAEJSEACEpCABK4iAR3/q3jWrbMEJCABCUhAAhKQgAQkIAEJXBkCOv5X5lRbUQlIQAISkIAEJCABCUhAAhK4igR0/K/iWbfOEpCABCQgAQlIQAISkIAEJHBlCOj4X5lTbUUlIAEJSEACEpCABCQgAQlI4CoS0PG/imfdOktAAhKQgAQkIAEJSEACEpDAlSGg439lTrUVlYAEJCABCUhAAhKQgAQkIIGrSEDH/yqedessAQlIQAISkIAEJCABCUhAAleGgI7/lTnVVlQCEpCABCQgAQlIQAISkIAEriIBHf+reNatswQkIAEJSEACEpCABCQgAQlcGQI6/lfmVFtRCUhAAhKQgAQkIAEJSEACEriKBHT8r+JZt84SkIAEJCABCUhAAhKQgAQkcGUI6PhfmVNtRSUgAQlIQAISkIAEJCABCUjgKhLQ8b+KZ906S0ACEpCABCQgAQlIQAISkMCVIfDT1PTGGz9fPP6nJ3O4sr31l5v9senyWWkYPx7YPrw+aAreH7w/eH84TcD7o/dH74/+Pvj76O/j6V+HxcLfB38fjl/591DTOLO4hzrNd89Mu4olIAEJSEACEpCABCQgAQlIQAISeKAEHPHv8NvjZo8bV6E98vbID92NvT94f/D+4P3R3wd/H/x9OE3A30d/H/193O330RH/0/cVYyQgAQlIQAISkIAEJCABCUhAAhLYkoCL+20JzmwSkIAEJCABCUhAAhKQgAQkIIHLQEDH/zKcJW2UgAQkIAEJSEACEpCABCQgAQlsSUDHf0twZpOABCQgAQlIQAISkIAEJCABCVwGAjr+l+EsaaMEJCABCUhAAhKQgAQkIAEJSGBLAhfK8X/+zv8ujv74X1tWxWwSOAwCD//64QV/24Ybb/z8VFb0eW2dwmLEBSWwS/tvqzR0PbQyHktAAhKQgAQkcLUIXMXn4gvl+F+t5mZtJTBO4LkPXjzl/LfOUHscbdeeO1o8+d5/57DfXv/DjcUv3vylzv8KFQ8uEgHac5z0x197arSt0rbpJOZvbthEdq5O5SQgAQkcEoH/+eRXy2cH7se5z05tD6n+1uXqEXjs9zeWbX6b2tNxwPUx9jy+jc6zzvPTTQoYenj69Dd/X9z58M4mapSVgAQGCODQXP/tY8sUnH/Cfz6/vfjiV58scN4f/2D1W8ofP/y3pXx2bn96sjj5+CSH/fbRl24s2muVG5XX7gomDx4wAb6Vnm/anrz1fW8NnQH1G+r//L9/LG7+7qs+bW4bzremH3D1LF4CEpDAhSXAcwbOP4Hnje/++s3yXksczyi3Xv965blh7j2Y/AYJXEQC37x7vJNZXCeX6Vl6I8cfMjx01Qeyp99+pndKSKPng1HFGlrHpH2Ii1NT82Q/jlAcljn6uWk98sy1XgUnA0eq2tCWX9NSrlsJPAgCODM3F1/1PYeMeHJMe61OfK4/fmyRqeFUx9ybi/6Hm5vat+8fL7hWc20k39T1Fxm3EjgvAtyzh0LafZtWf2zze9HK5Lh2HiSufbBNvFsJSEACV5EAzj/P2t+9c7y49uMzBs/VX778+YJnidxzed7Is/lV5GSdD5sAzxO09/i7h1TbjR3/Wnkcksf/dM/JJv6Hj05WnGxuFjguGcGJ0z3nZgF0Ri4zsjNHP3kIceZz3Ed2/1J+0jnGRm50BglcFAL0tG/TA5l2TZv+15+/7m9YdBCgj2sw12HqmRtbjt1K4EEToKP2+p17s16yZbS+71DuOrLaUH9L0nFWZXLPz4h/ew1UWfclIAEJXEUCGVRLB+vR80f983xlwcDB7c9OloN7DBqkE6DKuS+Bi0iA5+J24Ct29jNtm+cLrgVeA8Cvbdt5nit4/qiBZ+p2RkxNvyj7Ozn+T7z6VD+imMq0cLhJ8L5xAtONeQBr5ZKebXVcEse2zdfq5+RxshI4Af0J/TEi5SedHs2hUaCku5XAgyBAOz1+5V5nFNcP7ZTAft9ef7xBDY2O4uhzc8NR+ufiHwt+wMlPPK8OVEfpQdTNMiUwRWBoBJ4fWe7rtOU47jyocjwVaPP1nk9HNfkOsQd/ioNpEpCABKYIcE/89KO/97MCv/zo85VZhsnHc8WY4xQZtxK4qATGBnjxN5kRm2eLav/QswLPFTyHZ6Bt8cL9HAw+oA/ftA5a35e4GHsbO/515GXoIa3tVanOCTeNOm15CAH66UkcAo78mH5OBoHembFA+Zyw1tknb9upMKbDeAmcJQGmz3FDoecwHVmM2J+8cO9GwqsAUyHv5TFjgN5KZs3QttGn0z9FzrSLRqA66dzXq6NP217Xs84IFdNTuSYI/KZwHQz14F+0umuPBCQggfMkwHMCzhH3SJyWPFPHhqWj82MEz+IGCVxmArWNz/UDecW2HemvDLiGLvps8o0d/0wFqhXNfno60rPCDaQGHHoe3k4W9xZtqmnZz/QKdEVP0tbpj9zYlvLHenbG8hgvgfMiQPvOj2udtnz0xtGC2TVfvLX6SgrX19A7SDj7hPQ4ckNDLh0A1WGa6ig7r3pbjgRCgM6uTPEnjlEoZrocdw+l3y2O+x/UzICZ6qzlWsLp72X+EO33rgnfTb3Pwz0JSEACQwR+9sJRP3CQtFNrCCXBrQQuKQEGBeITpsNrqio49HmWnpJj9gCzDefonNJzVml7/ZwfI+pxOjD42rOrUzEBzGg7IzlTAYeFqRI8vNUwpZ8HPBz7uuBZVkWPjpRfe3mS5lYCD5oAHV38uLZ/XDO03TY+o/qxm5tMO12Ja42RT2bSkB/HauhTgdHhVgIPigAPmrwKRucXf9zPq3PPPp0AtF86r8bCitM/IETnMjq4HgwSkIAErjoBnhPyfMFzBYFZVelkZc0g7sncn+s9+qpzs/6XmwDP1nlm5pmCZ+ixEL91bDZ6m49rpvrDbfqDPN54xH/KWB6ocDAylT7Hi/fujbQEcH1dAH0Z5ay6cf55gONmlCnK0TemP45TRozIV53/lF/jKDP6a/nuS+BBEKjXQhyYfqp/934y7Z8f44zkY1+9CeUHu9pNOu/sVQcqU5rajrmaz30JnDeBfjZY8xlK2mr98Zxqs8hyb+d+PvQFi/xu8PoZ1xm99/X35bzra3kSkIAELgIBnhM+futv/TM3swAzOMZzAw4Pz+ysGZSQQbl2Vm7S3UrgohOgDfOskEBb5xl6bJSe55P4kMkzteWamprdPpX3PNLudoUc5F93w7rbndyDrNuhnjPrtbjb/eje7RySfguPzkG5S1tmny1pNb1l1t24lvJtWj1GRz12/zDvg5flvNJuq63cu2tcbfNtGtfM2L2e64e/qtt927ptwDZgG1htA3kmyP2S5416D673Up+vV9nZli4Pj/os0Z63PGPnGmjT2+P2GmnTL+LxXkf8uwpeqMB70bwyYJDARSeQ0UrsZIpzHfmvtqdnnrju5tXLbtLrTp6EuvBm4txK4EEQoP3XkX1s4PUWFoNNm63XBG2++2FeGbHf5Dp4EHW0TAlIQAIXmQDPBNxvmV3I/ZVXq5hhWJ9PSCPwLNKuO3SR66ZtV5tAniOgUJ8lWip5xu4GEvrZ62OypPP6OaHOHGj1XcTjhzqjGAk5iMCNKtM5qRA3sTot+iAqaSUkIAEJSEACEpCABCQgAQlIQAIbEDgox3+DeisqAQlIQAISkIAEJCABCUhAAhK4EgT2uqr/lSBmJSUgAQlIQAISkIAEJCABCUhAApeIgI7/JTpZmioBCUhAAhKQgAQkIAEJSEACEtiUgI7/psSUl4AEJCABCUhAAhKQgAQkIAEJXCICOv6X6GRpqgQkIAEJSEACEpCABCQgAQlIYFMCy8/5tSviV0W3/nKzP6wr5pt+n4B8bB+0Bq+PJ+9fFGXP68Prw+vD+4P3R++P5Wdhuevvg78P/j74+3CVfx+OX/n38n54Hjuu6n8elC1DAhKQgAQkIAEJSEACEpCABCTwgAg44t+Bt8fZHmeuv6vc42j9Pf+2f0dkuQ+0wd9Hfx9pE94fvD+09waOvT94f6AdeH/Y/v7giD8tyCABCUhAAhKQgAQkIAEJSEACEpDAXgi4uN9eMKpEAhKQgAQkIAEJSEACEpCABCRwMQno+F/M86JVEpCABCQgAQlIQAISkIAEJCCBvRDQ8d8LRpVIQAISkIAEJCABCUhAAhKQgAQuJgEd/4t5XrRKAhKQgAQkIAEJSEACEpCABCSwFwJn7vg//OuHF0d//K+djL3xxs83zk+5/BkkIAEJSEACEpCABCQgAQlIQAJXmcDWjj/O/PN3/nexzim//ocbi1+8+cudnfD/+eRXa89T28Hw3AcvruSJzSuRHkhAAhKQgAQkIAEJSEACEpCABA6YwE/buj353n8vrv/2sTb61PF3f/1m8fHDf1s7mv/oSzd6uVYBTjgdAp/+5u+LOx/eWUkm7eSt75dxfOPwu3eOl8fZoTPgi199ksM+D50R//n89uLLlz9fYGMb8s1R4qnrrde/PlV+m8djCUhAAhKQgAQkIAEJSEACEpDAZSXwUGf43TnGt072UJ6hTgMc7cf/9OQpcZzym7/7qp8xgGOfwAyCIXmc+UeeuRaxfhsnvuaPANP8H3/tqcW1Z49O5YvMP//vH4uj548WbX7qSll0bBgkIAEJSEACEpCABCQgAQlIQAKXmcCpEf9UBge8dYiTNrbFkb+5+KpPxvF++u1neh3RM9R5kLToPPn4ZMXhpjOBgO45ITMJkKVzoc4IIK119E8W92cWzNGvjAQkIAEJSEACEpCABCQgAQlI4DIRGH3Hn1F3HOWxgEM+tnge+XD6q9M9pqeNr1P8SeO1gzGnv7WBaf6P/f7eqwW8QkDARuL549UC6pVjtkN1wG5H+3t8/pOABCQgAQlIQAISkIAEJCCBS05gdKp/OzqPk1wD0+RxsoeccmQzjX5o2n7VU9/xzxT7mj72qgAyUzbg0DPVH/voILj96cnGMxiqHe5LQAISkIAEJCABCUhAAhKQgAQuI4HZjn/bETBU2UyzZ4r9N+8eryzQh/wcHVVvK48zPzWTYKjjoOob2mftgG1mJgzpMk4CEpCABCQgAQlIQAISkIAEJHDRCIxO9d/UUJz+TLPfNO+QPKP0rMxfA05/G1fTM0Wfafr8MVsAxz77zC5gP68BkD7k9NOB0M5wqOW4LwEJSEACEpCABCQgAQlIQAISuCwERhf327QCvJvfvp+/qY4qzxT9oRH89tN/NU/2mRnw3Acv9odx8llEEH23PzvpV/qnA8AgAQlIQAISkIAEJCABCUhAAhI4dAIrjn/raLej3u0xcHaZKk95375/PPruPaPxceLjqFcb6voA2JJPAWaUn1kDCZlBwKwBPtWH3rFOhKFZANHjVgISkIAEJCABCUhAAhKQgAQkcJkIjL7jv0sl4nCzIn8NOOoZiSee4+t/uLF0/OO41zxTHQt0AsT5x5GvutBROwlYCLDOSKidHNFRy3VfAhKQgAQkIAEJSEACEpCABCRwCATOxPE/BDDWQQISkIAEJCABCUhAAhKQgAQkcAgE9ra43yHAYBYAswTyxywCgwQkIAEJSEACl4MACw3zG37ev98+P1yO9qGVwwS4Zrh2DBKQwOYELtP1o+Nfzm++CsDUf4MELiIBXqNJx9TYw21N52F007AuPw/UyPiQsClZ5acItG2bV782DVVHXjnbRMeu+eN0Dl0b9brK/iY2VtvIP8SnygzpnrIvaVO2RWaofnBeV/66dHRc1vvLuueHcK3boXMEA4MEJCABCcwnkN+m3F+H7q2H/Pszn9Q9ybvd5tz+upNytztBW5e3a/45de0ePO5SDts58sqcX/u5yqy7B/27nSO/bJMcdzey5XHa7bbX19z82HAe1+FVPtdXse613c5ti5VTe33QTomrMlP7u+QnL9cE1+PcawP7ap2nbCOtyg7xmbJ/G/uoB/koe07+qfKjo96/xs4P8XMZrmPWpp+V3lpOzg3bGt/ub3r+2/we+9yxzzZwHtfGPu1Vl+1/qg3U3y/k1v0+Rde2vz+X6frZaMS/q1g/yjfVa9LBXRmR7GD2IXk4+MWbv1zKdA8z9wTW/J+bvztpS93Y24Z16a18Pe5+yFd0o584gwR2JZC2xfWTkGspx2z5HOVYePy1pxbf/fWblUUsx2SH4ufkxya+xMGimwYJ7JNAXXyVL67Qxo6eP5pdxON/enLxrz9/vZRnn7i5YZf8fC6WL8/wGdo5gd89rqNa53X5quwQnyn7N7UPW+o1Pif/VPnoW5eOzLr7S/39rs8E5K1p7W9/ld3m+QP9hNyT0d+WcU9i3v9tzv88zUpJYDcC9Tqqz7e02bT7bGtJeYZJGtuaH9l9XT+1XPclMESg/n6Rvo/fn6FyxuLym9NeA2Py5x0/2SvdGbNM7y7kUz3xxHU3hJVRgeTpLvKVEUriq3zkNtlO5e9uWMsRCnRSPvLRvy49ct2J6vOxTRzbqbKrnPv324ws5rNIu+N6yv5QG0w7pD1XvhyTl/T8tfmrfLu/Lj+6UmZkWx0ezz/fsppmlXY+h1OulyqbuDnXQGS3zV/zzbEbmZpnm/1azib213xj5Q7pi+xQ/iH5xLHNfnSwTRzbHE/dX7oHqeX9B3mOhzjmHljLyv6Q7Ulbt22fJ4aeb9DR1mtI75DdQ3LGTd8j5LM/PrRJ/nI9ttdb4sOca5VrIMfrrq2510/0ud3fub1qLHMPTr3bY+ITl3bNdur3J7rGtrX9c+3Ua2Msz4OK32jEvzNy0X4Wr/aqPPrSjcWtv9xErA/fvXO8eOSZazk802130vqyKDOBUQpC9yDQ9zxiy1h68kxtqesTrz41JWKaBLYmwCge1w8jUk+//Uy/T1wNud6QaQPtm3hGHvlDV/18ZivfHq/Lj01fvvx5m81jCeydQPcD3LffOso9VcjPXjg9MyDXzlBaq2tIZpP8rb6p4+6BoP8dnZJZl9by2Zf93QNLP6rHfWOTtW7Wlb8unfquu7/weeA6o+PW6/dnd6zjtY/0fT3f7OP876M+6pBAS4Dn+9z3uL54JuDZmpD45GH24bXn7t931z0f7+v6SfluJdASGPv9np9T/AAAQABJREFU2sfvT1vW2DG/zd+8e7z8TP2Y3IOM/+k+C+cmwXQK/mrgxtHeNGp69jlp/LjXwNTlOdMnc2LHylmXXssc22fxHurS9ez0InNtG9NnvARaAnRW8QNJSMdVZLg+mB6ceG4w/NEuE2rHG3Jci3OvP3SM5b/+hxt92WPXV8p3K4FdCdCmazufo++Hj06/ApMH1qRN/b5EppbV5q9p2+6jk+v7+JX71+ymuob47Mt+fmtvLu69rsDvHPeD3G+m7Nym/MoXZ5hzPnZ/qbJTdpxl2q7PN9i2j/N/lnVUtwSmCHDv4TpI4Bk4Yd3z8T6un5TlVgJDBMZ+v9b9Pq37/RkqayiOgTc6wOYOWAzpOI+4vTr+VHjTB7ZayXrSavyc/ZxYfliHHh7Wpc8pAxl0M5pK4MHo9hsnsx6M+gz+k8AaAtyA6EmnAwxHpXZ6EUdPYgKj74zMpc1nNkDSN91O5cdZyQ939HKTu/X8PMcgedxKYIoAD5aM6m76w5l7PrO7krft7J36fZmTf8ruuWmso1FHrefmi9wYn7OwH6e/jujFhqHt3PLHzs+jb1/8+8uuzzdw2/X8D7E3TgJnQaC9f3Lv4dkkAw08n7SB+8DY8/E+rp+2PI8lMEag/n6t+33a1+8PM2Ye+/2NUwNyYzY+qPiNp/pPGYrTnxHGMTku/k0WbGr1jOXnxJLGyGQCThSBB8F16ckztsW54q8NJx+fHmlqZTyWwBwCPBRz/eCgMM0WR5+4BNo3N5WEtPXc1LKYWdop7Z88SU++se1Ufn7s8woBW/Ryk5szGjhWnvESqATyIBnHvaZln87WzLhKXLb80NdXsdgnbm6Yk3+q/HXlcF1ee/Zo2TExJD+lfx2fOfYPlTkWx73o9qfzf9/WlT+Vvu7+kt9vHOeETV5jSh7uW1PPH1P85zzfpJyh7ZzzP5TPOAmcF4H6fMH9s47o0/Ff7wfcyxJo23nuSBzb+ny86/VT9bovgXUE2t+vXX5/1pVV03l+p4OMjrKLGvY64h8noP1BxomJ84FzwUghJ4XAyUi+OZCm8vPwAOzoRl96H9lfl47MVGjrhe1TD6lTukyTQCXAjybXBc40geuF9tXHLf7RtzPaLw+m1+/cfx2mtm/aIiPwtZ3W9Fre0P6u+Yd0GieBuQTymhdtPGGT3wd+RxihTn4eWjf5bdklP51s9XeH63bx5r2V8bluCXTU8UCwbVjHZ8r+Ofa1MpVfmzZUv6nyqfO69HVc2vsfzxX1XrcuP+lTzw/r8mM/oS2zPt9M6dj1/E/pNk0C+yCAY5/7J51kdcYhzyZc97nP5XjxXvcc360H0F4X7fPxrtfPPuqnjsMl0P5G1d8var3r788m5Lhu8EW5lub+Pmyif1fZhzoFrMppkIAEDphAfszHqrhJB8GYDuMlIAEJnBcBZkMxKpmOlfMq13IkIAEJSEACl5WAjv9lPXPaLQEJSEACEriiBPLOcR2VvKIorLYEJCABCUhgFoG9TvWfVaJCEpCABCQgAQlIYAMCQ1M5dfo3AKioBCQgAQlceQKO+F/5JiAACUhAAhKQgAQkIAEJSEACEjhkAntd1f+QQVk3CUhAAhKQgAQkIAEJSEACEpDAZSSg438Zz5o2S0ACEpCABCQgAQlIQAISkIAEZhLQ8Z8JSjEJSEACEpCABCQgAQlIQAISkMBlJKDjfxnPmjZLQAISkIAEJCABCUhAAhKQgARmEtDxnwlKMQlIQAISkIAEJCABCUhAAhKQwGUkoON/Gc+aNktAAhKQgAQkIAEJSEACEpCABGYS0PGfCUoxCUhAAhKQgAQkIAEJSEACEpDAZSSg438Zz5o2S0ACEpCABCQgAQlIQAISkIAEZhLQ8Z8JSjEJSEACEpCABCQgAQlIQAISkMBlJKDjfxnPmjZLQAISkIAEJCABCUhAAhKQgARmEtDxnwlKMQlIQAISkIAEJCABCUhAAhKQwGUkoON/Gc+aNktAAhKQgAQkIAEJSEACEpCABGYSmOX433jj5zPVrYqdd77V0j2SgAQkIAEJSEACEpCABCQgAQlI4KdzEfzPJ79afPGrT1bEifvy5c8Xdz68sxKfg8f/9OTi2nNHi5u/+ypRCzoDTj4+WZy89f0yrt159KUbi+/eOe71Pvnef/f5h/IRV/VzTJmbhO/++s2KfZvkVVYCEpCABCQgAQlIQAISkIAEJHDRCTzUGXg3RuJkX//tYzlc2eIgt2mf/ubvi8dfe2rQcUbX7U87B79z8n/x5i9P6aqdASuJ3UGcfeKfv/O/y+R//t8/Fk+8+tTikWeu9XG3/nJzshPh4V8/vGLfUOfFUrk7EpCABCQgAQlIQAISkIAEJCCBAySw4vinfnNGzv/z+e1TMwCS/+iP/5Xd3lHPTAEc73/9+evR0f7q5KMAx57Rf/JjE7MA6Gi49frXi6fffmawfJz95z54cVn+1A4dCVMzD6bymiYBCUhAAhKQgAQkIAEJSEACErgMBEan+lenGKebcPzKv/stjv3R80f9fvuPtMd+f2M5C+DLjz5fjtozQ2DstQD0fPzw3xY47nHq+xH7bup+OgRw/AnouP3ZSb8/9C/T96dG/OmE0OkfomecBCQgAQlIQAISkIAEJCABCRwSgVHHv5+e/+ZqVev78zjpQ6E6/aRf/0P3vn73mgDT/uPQD+VLHPJM5cfZp/MhMwvofPjZC/c6G3DoCWyRT4fEUkf3usL1O/dfWaj76USIrFsJSEACEpCABCQgAQlIQAISkMAhEzg11R9neu5U+THnH2BZLyBrA2Q0v9XNdP7quDMSz2g+awCwn/f50UlHAIFOCToECN++f7xcCLCPaP6lA8HR/QaMhxKQgAQkIAEJSEACEpCABCRwJQiccvyHar1uqn8cd+QyKyCvCmTqP+/lZ5p/XbyPPFnBP2sD1FkDWRfgh49OVvKz0GDteNikw6KtY9XTpnksAQlIQAISkIAEJCABCUhAAhK4zASWU/3nOM5x6lNhRusJ5E2IE41zn9X8GfVnmn8dvf/mj8f9O/bpNCA/6wZwjONfA6P1dABkdJ+0jPhHjk6FlE1cOhzq1wOG4pLfrQQkIAEJSEACEpCABCQgAQlI4BAJnBrxxzmOwz5V4SygNyVDGg57VvXnmE6CoXf903mAA19nBOSdfBYG5H3+rPIfvdg7NI2/zj6gXGYg8CnAagvxBglIQAISkIAEJCABCUhAAhKQwCETWI74p5I40R+/tbpwXzvVP7LrtjjtdRQeeRboG1qRP68BtDrzygDxj759Y/Hly5+viDBL4GTx/UocB8wcyGwC7GAWAXnTkTC34+KUYiMkIAEJSEACEpCABCQgAQlIQAKXiMApx7/azqh6pudnYb2a3u63swWq0x+HmzyM3k8F3t+/ufhqKZK89XOAdB4kPmsE5HiZ8cedakf2sTWzBlp5jyUgAQlIQAISkIAEJCABCUhAAodC4NRU/0OpmPWQgAQkIAEJSEACEpCABCQgAQlIYLH4iRAkIAEJSEACEpCABCQgAQlIQAISOFwCOv6He26tmQQkIAEJSEACEpCABCQgAQlIwBF/24AEJCABCUhAAhKQgAQkIAEJSOCQCTjif8hn17pJQAISkIAEJCABCUhAAhKQwJUnoON/5ZuAACQgAQlIQAISkIAEJCABCUjgkAksP+d3442fLx7/05ODdb31l5t9vOnyGWogtg+vD9qF9wfvD94fThPw/uj90fujvw/+Pvr7ePrXYbHw98Hfh+NX/j3UNM4szs/5nRlaFUtAAhKQgAQkIAEJSEACEpCABB48AUf8u3Ngj5s9blyK9sjbIz90S/b+4P3B+4P3R38f/H3w9+E0AX8f/X3093G330dH/E/fV4yRgAQkIAEJSEACEpCABCQgAQlIYEsCLu63JTizSUACEpCABCQgAQlIQAISkIAELgMBHf/LcJa0UQISkIAEJCABCUhAAhKQgAQksCUBHf8twZlNAhKQgAQkIAEJSEACEpCABCRwGQjo+F+Gs6SNEpCABCQgAQlIQAISkIAEJCCBLQnMcvxvvPHzjdU//OuHF/xdxrAP24eYoffoj/81G8ll5Te7ggpKQAISkIAEJCABCUhAAhKQwJkTmOX4Y8X/fPKrtca0Tu1zH7y4kof05+/870rcvg9SRmvLJuX87IWjBba3jjfO/Fz7H33pxiCzX7z5y1N6h2yjrCEbhmSNk4AEJCABCUhAAhKQgAQkIAEJjBEYdPxbp5lvDH758uendLSdASdvfd87xon/7q/fnMqTb36S8OR7/z3LCT6lZCAiTvljv78xkLpZFDr++X//WNz58E4/Qo+dBJz5jx/+21pl8Lv92cnii1990svSWUAc+v7z+e1+u04J3wymLPK0gQ6JuR0QbV6PJSABCUhAAhKQgAQkIAEJSOBqEXioq+7dWmUcaJzONuCwPvLMtZXoOPF0DLQB5/Tx155aXHv26FS+yOJcHz1/tBjKH5lttjjF6KYjYpMQZ5q64rhf/+1jCzovvnn3uFfDaH0bkI2DnzQ6PhKHw1/rWNPoULj5u6+SbblFho6WdsZEBCiTgMxQx0Dk3EpAAhKQgAQkIAEJSEACEpCABH7aIjj5+GRlVDuj3UMOapuXYxzdOMg4zXGAk1adYOJOFps55+Q5q8AIexz1lJF60yGS9HQoENd2WhBHB0nSmD1w+9OTlRH6dDDQORG5lMfxt+/f62ioswuwi0DZdKo8/fYzOv2B5lYCEpCABCQgAQlIQAISkIAERgmcdvybUXJGvasDWjXRKXDr9a+XDigOLc4+8hnxZ9uOXNcZBZ/+5u/L/FX3g9p/4tWn+s4KHPCM9LP/3TvHfZ3o1Pjn4h+9ea3TT10JMIg8OnDWI1tH/JGtHR+U08d1nS8tM+LRm04HZiQYJCABCUhAAhKQgAQkIAEJSEAC6wisOP44pUPT+TNC3SpjxJrp/BkVH+ogYCo6Diuj3nF+Wz0X5Tij6iv1fXOx4JUG6hHHHnvjgFfbGYVnhkNmSbBI4JBczYPOqhtG2EGZlRedAszGMEhAAhKQgAQkIAEJSEACEpCABDYhsOL412n5KKEjAOczDihOapzbFFId26GOg+t3HutFmTlQR/qTf+gd+aSd95a6fPHWvQX54mjX+uHI04nB6wp1pB47cdZbfsSvdCIQ0YUaR/3zrv7xh/fXSoBVy4uOFgJ2GCQgAQlIQAISkIAEJCABCUhAAnMJsLjfqb9u1Ppu5+ivxHeO/am4obyJ65znu+ThmP3oY9s5v31cZPe5RXfniK/Yvql+7EYPf6kDTNDLdkrfELvIR1eOh7aUAa82Db2xKem71rMtw+PT14JMZGIbsA3YBmwDtgHbgG3ANmAbsA1c5jawMuLfVWQZmL7fOamnpv7PWUWemQF5R513+AnMGkAf76az0v/QawHLwrfY6RzhlRHyfoHBbpr+JjMKan0Z2f/Xn79eTtWnTtjNDIAfPjo5tSjfFiZvnIVzcnPxVf/KQX09YGNFZpCABCQgAQlIQAISkIAEJCCBK0Ng1PGHAFPX48THUe9GnJdw2oX54nzjbCPfjVAvZdlnSjuvCrCOAHrndCIsFazZqa8krBEdTa5T9alLDXRkhAF2X3vtaGPnnzrvI4QbU/75akB9HWEf+tUhAQlIQAISkIAEJCABCUhAAodDYMXxj+NeqxcnPnFxfjmmEyDOf5zams57/fwReD8dhzXOdR1dj45e8AL9413+X9z5ZW9RrRcRmRHBe/jUbZ/ON7oee+/GyloAY1g4P/vuRBkry3gJSEACEpCABCQgAQlIQAISuHwEHupM5l1ygwQkIAEJSEACEpCABCQgAQlIQAIHSOAnB1gnqyQBCUhAAhKQgAQkIAEJSEACEpDAjwR0/G0KEpCABCQgAQlIQAISkIAEJCCBAyag43/AJ9eqSUACEpCABCQgAQlIQAISkIAEdPxtAxKQgAQkIAEJSEACEpCABCQggQMmoON/wCfXqklAAhKQgAQkIAEJSEACEpCABHT8bQMSkIAEJCABCUhAAhKQgAQkIIEDJqDjf8An16pJQAISkIAEJCABCUhAAhKQgAR0/G0DEpCABCQgAQlIQAISkIAEJCCBAyag43/AJ9eqSUACEpCABCQgAQlIQAISkIAEdPxtAxKQgAQkIAEJSEACEpCABCQggQMmoON/wCfXqklAAhKQgAQkIAEJSEACEpCABHT8bQMSkIAEJCABCUhAAhKQgAQkIIEDJqDjf8An16pJQAISkIAEJCABCUhAAhKQgAQ2dvwf/vXD50JtqJyhuHMx5pIU8vyd/10c/fG/Lom1mikBCUhAAhKQgAQkIAEJSEAC50Fg0vFvHUmcyuc+eHFvzmWrv1b4Zy8cLf7nk1/VqMXTbz/Tl/3ke/89aQN2onvq78YbP1/RvY+DtlzsbANxsWsoHXk6OKbYtDo9loAEJCABCUhAAhKQgAQkIAEJjBH46VgC8Z/+5u+9s/3FW5/0Yo/9/sbi44f/NpoFR/b6bx8bTW8T0IUDfrL4vk/C4aVjoQYcYMKtv9zstydvfb/gj7KOnj9aHL/y7z6+/Yf8WBp5v3vnuM2y8zF2ffzWfT7YfvuNk6Ud1PXas0dLhnRsENfaSQeHQQISkIAEJCABCUhAAhKQgAQksA8Cg44/I9e/ePOXS/1xvom4fueeY//dX79Z3PzdV0sZdji+uViNIx4H98uXP1/c+fAOhyuhOr2kp2MBG1rH/tGXbizzUhYyQ44zQo//6cn+b5mh2bn1+tdNzP4P//P57RWl2PTP//vHMu5ff/6651wZUJ9v3z9e1LouM2y4k44YOnCG2G+oTnEJSEACEpCABCQgAQlIQAISuIQEBh1/6jHk2Kd+OKcnH5/kcC/bdrSf8m9/etJPeU8BONK1EyIy5K2ObTvynvztlo6DJ159avHFr+7NaGjTdznGpkeeubYczeeYgG0JP3x0j2HsZ4vDjz27Ov44/fBrO2dStlsJSEACEpCABCQgAQlIQAISuBoERh3/fVe/TuEfGoFuR/txyBmVZzQcZ3/5WkDX4YDznFkJcWxxmmsZc+yn44CZCHG85+RZJ5NRduSoZwJrFrQhnRWknXz4ff9aBfbsGphhwWyC2smwq07zS0ACEpCABCQgAQlIQAISkMDlJHBujn919nHkGb1vR9ozmk8ajmsceZx+HH1mGTD9nzUB6BiojnXtOMiMhDi+647rqdt1FkB93YH6ZK2BjO7XsuhwIJCWKf7pDKhym+zzigb8UvdN8iorAQlIQAISkIAEJCABCUhAAodHYNLxjyPeVpuR8vpeepu+7hhHnpHxNiSekX4c4P+8eq9zANmM7D/xyVN9Nt6Dn3KS+zUK3mxKKMf1XfsqlbUN+o6GMi2/yszdx+m/9ty9kf7YWvVmFgBpj759o381gHUAErDl1vPjixRGrm6pF4swMurfdqxUOfclIAEJSEACEpCABCQgAQlI4OoQuNtVdfnXjULf5a9zUO92jn8fX/eR5bgboV7mqfmH9jsntNc5lFbjUi7ylJ2/Wl7XCXCXv5qv3cc28iR+3XHk9r3F/sqJfeqWctiv6YlnS1qtQ00b26e85IFRLWssj/H3274sZGEbsA3YBmwDtgHbgG3ANmAbsA0cYhv4SVeplcCn5DI6zcg+gWnjjMa3oXM0+yn4bfy2x5RLWYxU1/IY+WaGAVPj+Rxe/WRg5+ieKg5ZRr2xjz9G0dGRYzLwysBQQB8zDLYJnRO/LIOy2pkR2HX7s3sLFpLO/i4zJ6ZszAwJyoGbQQISkIAEJCABCUhAAhKQgASuJoGVqf7dCHHvjE6hwInMZ/b2vbI/Dnd16us6ADjkWYEfG3Bo6RzIO/+xOTqY8h7nF4ccW/PeO8cEtq3jnan+t35973WD6J2zRVerr81X1wBo0+rxNtP0a2cJurbRUW1wXwISkIAEJCABCUhAAhKQgAQuP4GHuiow9Xww0BHAJ+mGQutkDskkDj2sVp+ZBImf2uLcM/sg37pn9DyOfPLh/BNiS46TPneb/HPllZOABCQgAQlIQAISkIAEJCABCVwWApOO/2WphHZKQAISkIAEJCABCUhAAhKQgAQkMEzg1Dv+Q2KZGj+UNhbHiD1/+whD7/HvQ++h6WDGg6wO7axaHwlIQAISkIAEJCABCUhAArsRmOX4UwTT9deF1ul87oMXV7KQvs10fBbq23bBPQxIufvqiFipVHOAndSRvyFmsaVlhZrkq9td6t2Y5qEEJCABCUhAAhKQgAQkIAEJXEECg45/65SyYB3v6LehdWxZPK86vPkqQM3Ht+0TcGrnOuPfvHucbFttsWWTNQa2KSQzI1gzIOsGxHEnDTZ0YoyF5MuWxQ13rfdYWcZLQAISkIAEJCABCUhAAhKQwNUgsLKqP1XGQeXzd4s3VwHghLYL/eHEI19Xso/DG4eezoE2X6+/U8/K+9f/cGNx/OG/VwubeYRTjWOc1fpnZjszsUdfutEvRpgCsjDhzcVXPaNwun7nsYiMbul8+fb93eoGH76S8Olv/n7mnR6jFTFBAhKQgAQkIAEJSEACEpCABB4ogVOOP5+9i/OOZRmxblfUH7MahzWfxGOUvX5SjrR8CjD5TxbfZ7efGt92EiSx/8xf0xlBxwEj6D98dHLKsU0HBk5vDdTn1uubf6qv6hjbb23HLgKdIJvONoBhPQ9jZY7FU8/bn56c+hLCmLzxEpCABCQgAQlIQAISkIAEJHCYBE47/t10/RpwuMcc0NaJZio7zj7yOLuPv/ZUv23f9c+IP+XU0ejaSVBtYNYAo98ZMa9pQ6P9fdndrIWl3S/cz0EHBvpuf7Z/p5i6P/HqU4sv3vqkL5D6E372wtHi5MNVrn3CyD86LejU2DZQP2YbDLHZVqf5JCABCUhAAhKQgAQkIAEJSOByElhx/Iem5TOdH4d+KOCc4txmNsDS0S7CjHTjEDP6POS4F9HB3bwyQOLckXNsakf6q3I6GHCuqW/b2cCshN5572Q2DelUCC/Y0XGSkf85+qgjrwwcv7J5+ehnpgCvZej0z6GtjAQkIAEJSEACEpCABCQggcMn8FBXxbtj1WwdY5zSp99+5pSznPxDHQdJG9vipLbOd5XFQSfQacAMg3QyVJm6jzyvK1THF2eeVwLavNjbjvzHaadTo+qoZczdz2sPbYcIZYzpp47brlsQvdT12rNHk1zn1kE5CUhAAhKQgAQkIAEJSEACErjcBFZG/GtVcEDblfxx+tu4mqd14HHCGb3OCPt37xz377rTgcD0f0bE180C4LWAOM68mz/l/ONoE+Y67EyHZ82BGlJWjdt2n9H3TabswwWHfa79Y3bRwQGntuNmTN54CUhAAhKQgAQkIAEJSEACEjhcAqOOf6attwvWzVmkLo492DLlHgc/I+w4t3McbOSTH12UzWj4mPPfLhxInqmAg10XF0R2bHbAlJ6k0dFR1y+oo/ptWr8AYrdYYZ3xwBcOmIGwj5DzxyyAuo7CPnSrQwISkIAEJCABCUhAAhKQgAQuFwGm+o/+dU783c55XKaznz/Sat7Oue3TOoe9j+8c9LuRyT5p5E98zV/3p2Q657zXQXk1z9g+8pQ/ll7jx+pWZdwfby+ykY1twDZgG7AN2AZsA7YB24BtwDZgG7hYbWDlHf92VLo7WSsj0hzX0DnJy9HkzpFfMGJdp+6TnlBHv4ljND+zCTIiXeXnzghAx5jsUBmxx60EJCABCUhAAhKQgAQkIAEJSOAqEFhx/K9Cha2jBCQgAQlIQAISkIAEJCABCUjgKhH4yUWqLCP+WaBvyi5kkGWWwXmGufZN2YTN6MkfsxJ2Cax3MMYsZU3pn8rf5sPW2M32vPm39ngsAQlIQAISkIAEJCABCUhAAusJjC7utz6rErsQGHs9YROdcby3/QrApvnrVxtw/A0SkIAEJCABCUhAAhKQgAQkcPEJrIz419Hc7DMivM+A3rER6rnl4OjiOM/5wsBcnZdR7vHXnlrwicNtQ5ufc8M6DzUQZ5CABCQgAQlIQAISkIAEJCCBy0tgxfHHmebvu79+s7j1l5v9Pp+FS8jU8XQKsM2ocWTGtnQgxInkU3bRMdQJEFlkasdDO9W8LWsX+6JrXRmRYxs75zKoedt9ym2dbmSII60NKbPt/Kj2s9jiWBjLz+cIkzaWd118bFgnV9M3rX/N674EJCABCUhAAhKQgAQkIAEJTBM49Zm7zqG92zmcp+I7R/xu56ifiu/Uz46b0kFam94eUxY2EN+WOyTbykwdd87nSr1hUMup+scYTeknrXOqV3RGftM6UT66kp8tcdQhcRxX+xMf2TY/suQnX2TH8hPf5k8edIzli0y73bT+bX6P51+DspKVbcA2YBuwDdgGbAO2AduAbeBqtYGVEf/u5E+G/3x+e/HEq09Nyuya2H72jzLnhl3s65zY/vOC371zvCwunybsnNJlHDudY7v45t3jlU8XrghsccDrC9hfR/3ZJ659hx9bCe1o//XfPrb415/vT/0few1gLD86v3z58wV62jqTNjewFsCmaxhsUv+5dignAQlIQAISkIAEJCABCUhAAovFRo4/Dh2OYTea2/91I8MXiuEu9v3shaO+Lq0z3VaQ1xQIrTPeym1zjNPOVPuER1+6seLIJ759N5/4OPM/fHQSsdHtUP4IU39e80g9E38e27n1Pw9bLEMCEpCABCQgAQlIQAISkMChENjI8afSOIZZC4CR4TpCfRGgbGtfHOY40GN1YUbC7c9OBt+7H8szN76OemfEve1giH3rOijGypyTn5kOzDQ4746dOfUfq5fxEpCABCQgAQlIQAISkIAEJDBMYLbjj8MYp7GqOvl4/QhzlcehPHr+3uh6jd91f1f7cKSxrS6Il06N1vlmwcOzcv4z6s0rFXXafviMjdbHftITnvvgxewut2P5lwI/7mTKfxs/55hXIZgVsk1YV/9tdJpHAhKQgAQkIAEJSEACEpDAVSbw01r56qwxms+0c1b4z8r+rSPJlPDWKa76hvZx7JhGnint6Mi79EPym8Ttah+vCuC0xjbKHntXHSZxcD/9zd9PvW+/id1Vth/1fvXeugYt23S8jI32Yz/n8Pqdx3qV2FWZrMtf7aAMzk1lUdPPan+q/mdVpnolIAEJSEACEpCABCQgAQkcMoGHusqxgrvhnAjgfOOMj3UoYAbOe7vIIfFMvWfBvjHHH5mpsGv+qhsb99nh0eoeqn+VcV8CEpCABCQgAQlIQAISkIAE5hFYGfGfl0WpfRDI7ApeL2CkPmFsJf+887+t079rfuxjhsMjz1yLqWeyHav/mRSmUglIQAISkIAEJCABCUhAAleAgCP+F+QkMxrP6xWEqdkAF8TcvZtx1eu/d6AqlIAEJCABCUhAAhKQgAQk8COBC+X4tyPKZzWVPGd/bNo9o+OsQ3DW5ceO89qOvUJwXuVbjgQkIAEJSEACEpCABCQgAQmcP4ELNdU/U97jkJ8/DkuUgAQkIAEJSEACEpCABCQgAQkcFoEVxz/vndcqXsVp56ws//Fbf6sY3JeABCQgAQlIQAISkIAEJCABCVxKAiuOPzWoq6nz3jWdAdX5b6fjJ414PtU39Am6p99+pl/ALlPNH/v9jeX77PVzgXMIjpVP3kzRr3piX+Jqfj5XV0NNI77NO8f+qoO68d5+q6eWWfejn9cMEurrBnPqx+J49RN87eKB0cs279WnjDn619WvLb/WfWgmR8qudqWMmremuy8BCUhAAhKQgAQkIAEJSEACmxHgc379X+d43u2cv+Ux8Z0Tdrdz5vq4uk8a8eRhv3Mil3LsI0s8+jhmH9m2jPYYuc5B7OXYcpy/qfKTL7JsW/lqF+kcx/6aD5uH4olr7a3Hc/XXsup+9Ceu1TeXRysXfa2tOa9Jb/Ntyq+2B3RynHbAcS0/ZQ5tyYPsUJpx968HWcjCNmAbsA3YBmwDtgHbgG3ANmAbmNMGftIJTYbbn50srj13tOicwv5Tbt+9c7yUP37l3/0+I8W3P70nR8S1Z4+WMkfPH/VpiagzCohjRHpOWFc+OtpP3cX26Gf0nVkJCbdev7+fuHXbKfv3pT82YB+fz6PuhHX1e/SlGwtmMbRy0Zdt51gvvnn3eJHzl/g236b8Un700Vbq5/8410+8+lSSR7es9eBo/ygeEyQgAQlIQAISkIAEJCABCWxE4NRU/7HcP3vhnjPfOoeRP/n4ZIHjRyfAt+8f950F7NNpsI2DHb3Zris/cji11dlkuj0hzvMPH51EdK/bs9YfY8fqRzr15jxMBV4jwAFvX8lInjH9c+pH+bxmUF81QC95aTc49Ox3o/l9cZu+5hEb3UpAAhKQgAQkIAEJSEACEpDAfAJrHX9G73Hk4zDHiWuLIB3HjxF+nE/+2Cf/WGdBq2PqeF355MVpZZQ6XwfopspPqbzwaW1nx7r64dD3/Bffj9aNGQussYCucIrwOv2RG9tSPm2lnUlQ5WkLGc2nA+D2GyeT8jWv+xKQgAQkIAEJSEACEpCABCSwOYHJqf44zjjzOHI4bDh21/9wY1lK9w53v8/ocZx7Rns5xlFnBsC+wrryKQdbeeUgob5ykPyPv3Z/qvlzH7wY0Z23+9KPU57AtPjMWCBuqn6k43TDn5kWU+Hm777qO0hw9GuY0j+nfik/swOqbuKG4odmKGBXZgVUHe5LQAISkIAEJCABCUhAAhKQwOYETo349yvKv3lPEY5+RmeJYYQYp6xO5a7p1UnFUSQwAr+vsK58RrOxP/blePHeYoGzS34cyut3HutNYkX5fTr/+9Ifpxf+2J2Q+ozVLyPt9RySt56j6EJvHOysrL9O/7r6pfyWKfoJbTzrEYy9chA73UpAAhKQgAQkIAEJSEACEpDAbgQe6rKzerrhDAgw8s6oPQ7znIDDj/N9WZzhTes3h4EyEpCABCQgAQlIQAISkIAEJLBfApNT/fdb1NXThtO/zxkPF43godfvovHWHglIQAISkIAEJCABCUhAAtsQODXVfxsl5rlHgDUPMg2fmENbtf7Q62c7loAEJCABCUhAAhKQgAQkcKgEmOq/8tdN4V4edwuyLfeRq2ltvrHjbfKM6do0vlugcCubNy1nTP48y+9eFdh7Xc/T/iGGD7r8IZv2Gbdr/Wr+szj/u9a12rerrnX5L2L919l8nnzW2XLW6d2aInc5R/lrf1vOunz1r/7Oy2OYB88rtNHzbp9eH8Pn4yq00/NuaxeF6VX6/ZvL/EHdf+bad9nkNvU/r8K1ODrVv7sgu/O7WDz99jP9auwcd0D6xfPYrgssHJdV//nEHMfnHWLng3pn/kGXvyvvB23/NuXTTruHtuVfdFQWNX2bdrkuP2Ui091warGn9mNb2mfVm/1ch6cydxFt/iGZBxl30e17kGwo+6rxYa0TFhrNYp/75t9e+/n92aScqmPq2hvTuWt+7hlj947cE+p2ExurbegY4lNlhnRP2Ze02LdpfpiuK39dOjq4rrBh3f0X2YsU1l0f4Vq3Q4x3qVPlSzm5R1WdtfwH+ftZbbpM+7TLtm3ynL3ruZxz/V0kTmlbef45a9vatj10/6ttm/11Mtu0/7Oup/pXCfCltE2uLRYhb+XbtpN20sqtlnyxj5Yj+l1l+p7urjL9yDHH3cV5t2vc/TbxHEeWbVe9lb/uBnS3u2CWcezX4za9zb+vY+zF/n3p21TPeZfPuYDtpnaOyZ+3/a0dm5ZPG6NtRg/H6MgxbWEXRnPz5/pYdy7W1Q89Uzra/LvULYz2uW3t26fuIV0Xrf5DNta4s+CzK4Nd89f6je3nOtr3vbleKymjxo3Zk/j2/sH1V3+3Ije23SU/eWFPm5h7DtbdH1o7K4shPlP2b2Mf9SAfdszJP1V+dFDn1Gvs/BA/l2F0zd2eld5afs7Nuutj0/Nfyxjab/lzTHuMbOyq7Shpc7Zz85/l+Ztj53nI5DoPX+o8db6Ri2y1rz1HNa1efzV+bB/5+odNrWxNz35rN/mG8ra6qE+bNzrrNjLE1bZHPHGt3rHyh/LWOPQM6Yv+lNfmSfqcba1X9lO/OfnPWgabdqnfWdu3Tn+Y1i314a/G1f2qE7lcZ5yXtOOhtkrcJqxqmdlPWdWG89hfGfFnNIZPyH3z7vGCXhJGZuiJJDz+2lN9PKP3X778ef/+OvJDn4rLt+i7yvU977z3zl+Ok96B7XWfxb/ozmcFuxvk4KyDDvyyV687iUsbY2u1jThkusawlEs5VY79xKf8pGNHdLNFV8K68pGbyh891CllsF9Dm7+m1f3WfuwkbxuISx3CJzKkpfxwi205Jk/KSj62iQs/jpGtNrBPXA1TiynShll3Ydse5jn5senb94/766ja1e639WvT4YOeMVun8o+1z3XtK4xhmr+UE/vCPOmJb7fJl/NHOnlaGyJHepuGfBva8tP2WjmO09ZSxhz9lV3yV91t+TWNcsIl25Rd5dhP/BCflIsO9msYKz95kOVznimfOs8Jc/NXPpTRhnXprXw93oRfzZf9eq3Ald8yfq/mBn6j/vXnr5fi7Nc1W5YJ/8/e26xYcpz73kubjXb3qKWeCNuwfeDIehE6V2B4L8Bogya6AQ8M72yD0UgXoJExnJnAA92AJgaZfQEHPN9gISzbB1sgmcbQcoOh2gLRb/6y9F/1rKfiK1euVbVq1T+gKr6er/hHZK54IiIzK4k1/HwKld/S+PnWipq5mH5t3R9KvD18WvYvtQ/94K8wwt/Sj5xePTRcH637bxyfcczDG+vy2I60+1xfyCfUrt/L2vH/S/tf1xb6FWSL8sR35fcz2qw0fQYusR91n4VG9cT6U7341M/KQyca6ZF85feJuc653p9/Pva5a+bkj35y+RnqqO+Vtx9vnnxwdc+KdfH6i+WtNF+V0rz+315/sDPfot18gln1iuNvGLgxhuDNuEW9qou8I/KjjFK6pb93/yvJi2Uj879In9O99mlcaWxmfvKRRmNVdPDRfpWTJ61AnWQrVp14yNfub5IvHu4fUb7qo43q58gj3cSHDNhSGp+0h75nvHJNQBPHebQB35RrEtvwffF1we0QQdcLPojsHP29P4T+LGO7YjZ12M7O/tT4uU7lE+Ncr3Ly+a9UNw2Q7cp/pj9WfhoExdXEqRN3bI72ToN0p452Y7tshJY/0UVcRKO4pB9ZkV+0iiVX+ay/xy/7YhspU178kk8eHcrHONuPDGRFGtJRfkxTh3zkkBY/seygvdSTz3Kzfuqhlw6lM2bUiya3jbzsEF3mz3bEfI8fWdIp2sgf06X2xXrsi/mcLvHnNkEje+DPbaUuYi/csi7l1W8xH+WrnLhln+iW2if9uR2SF+1HdmwbNJkvtz/bQz72g/RLH/nY/qhfNLUY2dke+LOMmO/pR1ekr+lulbf4M17Znl699NJu9JTaz/UpurVxqy1ZtmyK5SrLdkYapUWrPLHKRvgj34jd0ESefdJRj2yNclSW7Y98kT6mxRvLlC7xl+hVRqy0ZBCrjFh5XY/EeSz1rm/J1m+E8jEu2R7rW+l8veT7h3hzu1QeY+yI+ZG05NI+pYWd+JGrNgpL1QlT0RBnftGW4h4/sqRTtCU5tTLZJZuQoTQ8qhd/HA/qc2L1E7zQkBcPMXKRFctG08iDFz2RJ9sa65SGJtqCDMpUH2NsX2pjtgvZ2Cu5Wb/KYww9dhFH3khDmrrYN5T15Gf7Sm0c1Y++LE9llJfqsI+2qZ44twEZtb9e+8QnHcorpm3IiHlsUF52wR/LlM+2luxBhuglQ3GuYyzGPpZ+6UG+0sjQdSV55GN7VL42lv3IJq1rBvuwh7xooq5ISzltEy9ptS/GJTlRZikd5Zbqb6JsZ8df35tnxYOVD1YopobNK3iszJFmFYTyqfHz39SIyc7LMIE61ynfipGFjAnYFtleddhBiKuJ5Fll0WkD8uimTCHTs3L54I3dHSNWikQHXkpLBnFN/7w6O+kr8cCXy7P+Hj8ysC+ubMZVX/FDR3j28dN5ZfYyd/W/ZD8ykRX7izRlUd+VlOupSMuqV26vOEr6qYOe/mIFj3FIOstQe6HJgVVoyrXyBj/P84yGHr9WCHvyau0TH7jSj7XQ4o/jk52AuPKescrjC+z4RGMtrBk/khnbtdQ+6c/tkGzF0w1/Pp3ELmMMmS+3nx2VuOObd1KkXzLz9dPDT3y9/ovXk8YzvD39kn+MGJsZS7RZQfhyL+/Vi6cVj+LXkqE6xgDXd8RSdaX45bd27/PQaLyU6rKMEs0S/iyvle/dH1q8qsv4HMp+5gP8rnNfXfIuh57+Xj3t6t1/e9e3sDlWfKjrd9/+Zzyew+9nq3/i719pftb6/eH+o/tFa36idzG07KjVaaefeQj3zRh0v4hlMc1JFsaQAnNZymLY9/qLMkhjG/f7+BuoE1Bc39w/cuA34MGPHs4Ywlc6oQBP7fevJx9ecJPvkeduo/qRk+9/lBE0N2Sc5D7qzf8uJdT/j7Svzr2Z8WzNT+DFbo1h8nH+kMdXnv9Avza0rr9D3f9aNjJuo48HFvhwjBn6lt8R5i3QUKaxiEydDtT44pTNxWdXJ3L4PdP4IOYecVfDtc/5MTie/vZywszFweAAAMCgoVocoOGABpDE8HEUpnSx82NDQIYCsiRDZcR0HM6H9MS60TR2xBuW+Ji0vjZNSL7afDEXMRA5yhEDbeYCV9inc2v6kRsHknTEuKV/hD/Kymn4OS7JXwzqP5XV7Oemw81QE37wizci8a+Na/qRi279+MkO6eNHjx9ClYMlf3EsaSxKFljk9kteKa7xP3r38kc431xLMlrtwxba9/Tnvy+xzmUt/irTdxWt8QVO6Nd1ytiPR5HWjp+ebdS37BsZ/4zPOIHLOmvyaTfhm0+vbvSZt9f+Hn6St2//9fRLfi3m+sj359zHNV45XrXx3auvyY3lPfxG7aeP430g6qilS/2ex0RL/wh/TfeS8pH7Q09eCZ9D2c/9Qr+v3Ee4X+p+3LJrH/2xf3CG6fPa+Iy0LTuOWbf2+sW2tf1/Dr+fx+yjm5LN3DcGxkYO3G/i7y99x3yFOTLXC/fyWA//vtefdPP7ufnwMpdtxIn67FeXdmMD1ze/tZpfaQ4EN9chdVyX+fqv/f715CM3OrZcC9H5H9Vfuv8hOwZsefbO17ODSFqhNv+r3XfERzzSvkgf04e6f9XmP1HXsdKHuP/1bMOhj9cEY5QxozKc+29+fDHnn//yYvt7Ab74h/QjCwWz0z/1u3Dv6b1r9TuOfx4UrHAwoQNMbgK62NVILmx+bHVh6KaTL8jsaMLPyiAhXzDzjWcqR5fkzoSD/9RRWS7slDHR5WaEA86iRqSj/ZTpRsaNd2lo6QcvBt7F5upGEuX39Pf4o6xSWv2Vb8SRtmU//fHP9y5v5lrAaPVRPi0R9dTSLf3w0Hf0ET96+YeRMi5YBRZ1+GFAJv1M+9eEFj/Oum5s0sFYfvLm7sS31z5+FFuLKT1+6SbOzlhvfMEDTvrB56bJzVHjZe34QX4MS+1Df+v6QTY3ee5XtFXXsXSOtF+0pXik/S38kLmk/7INI/ozT8zr/hzLRtNyzHQtZb5efaav5Vv4jdhPH3P9tO5LJd3oJcTfnTw+W/pH+Et6l5b17g89eTV8jmE/k+TR34BR/bX+eeWjsftvD59j1q+9frFtbf/f9d/PQ/bPzvX91iEll2Vx7ZUcfKgZG/zexsBvGTzxd4z5K79vz9+86O44Lrn+pBed3MuZN5WcdtFxf/3809/tzK9Kc6DLTYyrk3ejv38l+dJdi0f01+5/NZmxnD46VNinfWt10/a1/k20YfTeLp5D3P8kqxTz24AP8Ojby3dh4L/yu4KfIL+Sa4IFIja3Na9FFnTx+kQOC2DYzHwCfzUuMkl/9DdUdhfia0f9mfTrj6Nz3GS0468FAB154IYUwYsN5gYlOTmmrubciHbpxE26a6uJqqct3CBoSz4VwE05vmxFixPiHYlb+lkk0YptSVZPf4+/JDOWiV8331indMt+aOg32sCpjNyHXCQ6LsOPxnzxSPBg3NLPhY1uJuCMQeRTpoB++lWBC5ygSaVsV/uxER7Vi68Wt/i5FjR2iZHLj2i+Plrtwy4dlavZ0OKHJ7afPuJaU2iNL3QLF9ETa4GH9CHGz772Rf2xzynPgfHBDxw38hha7WcM0Gfgq5Bv9K32j+CH3F7/SXcpbukXPW3QNaiyJXGNX/jomkIm1w+Be3WvfiZs/BvFryFi+6Kh1m8Hk+s8wZZMJgXxURfSlI2GEf6W/p4eMOrdH1rytZBdw2fE/p6NsZ57dfw9jXWldE9/q753/9X4bF3fJZtyWe36EF0L/5HrV3JK8dr+P4ffzxa+JcxyWev3J9PW8vyuYMfSkMeo5gv8RvPbpLxirlN4YmD+yryHayvPXyMd6aXXn/i5VphfwR9/a3X/EF1cOIGO31zZrph2RRmt37+WfOmsxSP6Jb92/4uyudbAOTp2rflf5K2lpV/1ET+V1eJD3L9a8x/pbd3fYt0+8/vR+98+1xf9xbXNuGPeTQxmCvx2UMZ8nJ196HPQ9cn1KBmUaVNDY1pxnFtnWaee39nxl7FcRKyQcPEzOAUo5dzwGADspkZgxbs2Rgf6mLwvDerMll3zRf/e5YmDTEdn025ueATlN59cHqHq2dPTLydwXn367jgVMhlIBOmr6e/xz0Ia/8SfHRr6GSx69iMa/Nj1V3pOfPePG6Pw40Ljb8mqYEs/dcgGIwL2In8u21w+18RFyvjUih90wpY0trMDH9sf66FphbX8rfahF6eKH89a6PHDpzeSkuY6jddRa3wxiYi4wA++8/VCZgqHGD/I0aRpiX20Q/pr1w+yFaDXD4jGd6v90OfxA1/ERPpjGfqgI+TyjN9I/82CKv9a+nUvi9cgYrBBfBWxO8UtfvABU92fYIzXT69+R1Eh08OvwLJTpIVGjS8ql7QfnLhfiZ8f9iXYreFnIhVx1RjnGgFXQu/+MBM1/vXwadk/Yl+mifjlulL7WvppVq++0fS5qnd99/ipb10fPX7sJ+RxrvtTj39N/5/D72cPn9F6Xd/592eU/5B0XBcE7qPRLl3zWVecf+meL5p8jcXrTzSjMbL1e6lTi9w/4twKWbr/lzaCqMcG5vPY3fv9a8lHViuM6O/d/7AvXpv593vt/G9N+2j72vuX+lO/M8pH/6Z1f4t1YMPfkvn92vtfq/8Zr5rrzmNhc3Xqjzlx3MBCDv2ssVuTy/Wk9uVHwms8rXJd39AwFugHrg/Z3eI9Rt32DZCT8Dk9NXh+6+E0yZvfbDg54/MbDacVq7mectGW4ukC2nnbY6ZBDjJzOfkJnPkPGaX6Vhly9+FryVxSd9v6l9haoh21nz6q9V9J7mjZqP5ReUvoNO5q8RJZNdq17VvLX7PrUOU9+441bg5lf5bDGO/d6zJPK9/Dp8Xruvrbko2NsdlnDBz6+t7HhnPhqf1uqvwU2nlqvz/8tjDXztgwhz0l3LJ9++b9+3fY+/S53r/WtivP2eTPatyO+Kdcf+IrXaPIYjxjq+Tepbi44z81YN5JJeZ4iFbKtGLFSmkviLZGF4/QRJreKkykjempA+ZsXgWNNMdM37b+tW0btX+6COad5LgTvFY3/KP6D6GrJGPfcVeSVSpb2761/CWbDll26vbt01ZWjlsnMJbIPEd8lrTftEbg1BA45PV9am27aXuO/ft50+05pr7JqZjF1056MIcFz8mxaD5nf0wbDy3bv3+HRnQzP5Z2qPnJ4a3bX2Lt9MaIxMmpn8l0jZHhZAKnTuZTZt8JYae9Fjj9yi481x87/nFHHvnxVEisq8k7xfKXJqNYsXAwAk0EuAi0AOQf+SZUrqwgwM2Y42WHXjSqqFtczKKWjsHBfJvHsBYbbwYjYASaCPj6bsJz9pW3/fsjZ8Tzp7MfakdpoO9fR4H1Xgo9uOOfV0TiM4qnjvBt/zCcOj62zwgYASNgBIyAETACRsAIGAEjYATuHgLVo/77NoUvAXC0Qi9yKMnR4sA+u39x5xnZ+bhUrD/Gjp1WbdWuXltF59gIGAEjYASMgBEwAkbACBgBI2AEjMBtILDzOT+c2vy31CjeCZDfoJhlsDiwT+CoC58z4qgUfzjd8fM8uR5ayg4dpJ+4tcCxVC/YZ3vjQgPPScX+KdHqWSp0swgS+SOv0pKRaWU75dPLMpR1bASMgBEwAkbACBgBI2AEjIARMAJ3DIFrO/5xF17OIA5uL+Ac4vQT9Kke0nnXHUeT7zm+8vbV99ahI+C0xhcwUJZ1t15mwfO52K+gz09E5xz98TneLB/e2JZ8okCyW7H4S7JbfNTNn3iYvjOZX1IobKI9cupj+ySfdmqRRGXEsX9jOS+pePD7h/NigV5YgU5k1D4tE/mdNgJGwAgYASNgBIyAETACRsAIGIHTRGBnxz+biAPIM/raFc71MY9zKEcX55I0f3IioeWIPw5/yVGl/ptPL7Z88Gbd8PGCORxenFJkST6yCfHFYcgjqE5Ov2zjxEDezWbhgW82QsOiRel0gnbLseHQgTbHUwySz5susScuCIBzXMQQLe0Em6UOO+0GX7VLWEiuYyNgBIyAETACRsAIGAEjYASMgBG4ewg0HX+aww47nzQ4RMCJxrmshejUQlPSjWNMyCcDXn7ruo2SpzqcYZx9hWfTzrpOKagMZ1p8fNaBei0cQKNFA+iwQU6y+InjIkgsH0ln51s82JE/gZgXNqDlsxUsBix1+uGl3eBDuzjtQVpYUO9gBIyAETACRsAIGAEjYASMgBEwAncPga7jf6gmsQvNEf+eI8kOvHbU9fk42YAzigw535Rrx15OsGiJ5bCrDucZp1jy9T1G0UXeXpqTBezA42gfMkTnex+5HM0n1E5p4NSr/cIu6uFUBe1CTu1kRqR32ggYASNgBIyAETACRsAIGAEjYAROG4Frz/hnc3EAcbbXBnbb5XhLFk7okzevvgCAI8ouv3arcfRjYCEg7nqzO47zjuOuBQV24HXcXzv9quO0AG0ZdWgzf7TlmGnsA6/YfmxnkUFtQ3/JPt5rwEIHuPCSxUgPDycVchnlObTepZBpnTcCRsAIGAEjYASMgBEwAkbACBiB00WgueOP44mzPuoot5qp4+/arceRxQmNstH1/PPL5/KRpd1ryZXzq/yjdy932+XYczSdZ+EVSMej/Tj97Pi3dvjjDr6eq5e8GCMjL0SoXqcWlN8n1pF/8eLQoy/aPi+chEcXRAsevASQ+tKjCKJzbASMgBEwAkbACBgBI2AEjIARMALnj8C1HX+cxc2Hlw3H0cZRv6mg5+b1wjrlN59s5pf4sXjAMfVH3766NSnaxyIC7yOAhsCR9biwoLSO+EtIfFM+Cw/ip/16eSC0ON2Rl0WFkd1z6VkS47wjX1ig58+bP13TrzZl2XL+sffZO19v2xH7Fx7aqBMWWYbzRsAIGAEjYASMgBEwAkbACBgBI3D3EXhpasKLu98Mt8AIGAEjYASMgBEwAkbACBgBI2AEjIARKCHQPOpfYnCZETACRsAIGAEjYASMgBEwAkbACBgBI3B3ELDjf3f6ypYaASNgBIyAETACRsAIGAEjYASMgBFYjMC9cvz10j19zi6+KG8xcmYwAkdCgBcyMkZvenz6+jhSh96C2EO/1HPJWFxCOwIN8ta0Zw0v9tU+jdqyHZsPjUNLn+uMgBEwAkbACBgBI9BD4F45/vqyAC/zO0bgKwhaVCDeZ8IYZcTP+Y3au5ZfTmdpshzbpvQSG6NtNXwiTUl2yz7VtWwTTal9YNzT36tHBhN+bKjpgOYUQ+/6EK4xLvXRmrZFfNFTcp6ifhYrloYe/13tv4hD6YseGvslTCOv0sKBmMLfek8AAEAASURBVJeFgttI4IWieVzkflUfZDrkl+6btCfaDU3Mt+x6+ObDzT7jJMoc4c/Xe3wRLLKEf5TrtBEwAkbACBgBI2AEbhIBXu53sL9pQvdimuDsLW8t/0hbpgnjC/QQj9CP0sR2S0cs68mZJrMvpgnm1ibSlPX4VL+GH14wmSbiczxiN/aN0Mm+SFvCp2X/PvbRHvjQP8Lf0i8ZI/0DzbHG8bHkqo+I1Te962Np/0cdpXTGnzzjUbSyK44j1Y3Eo/zH7L8RO9fSgE+p72hXqbymD+wj1vRHjx969Rm06EQ+ZZk3y5cdyIjXbpQDDXnqpUd8tRi7+VN9HlcqVxzbrLJsO+Vqm2iIsUs4Z/uQG+0oYRJlOX24eYmxNJYeAx4DHgMeAx4Dmxc7n/ObJi0bPqHHt+z5ZjyBT+LFT9pNE5ftJ+ao1+f0pknMlid+Mg55I5+8G+WfJlWbf3v9AarnIP3K9+pFV4qnyd3O5/KgiZ/6K/HEsthOdsj4VB67TRebf0SyappP94GXwl9/8eUGLGuf7BOd4jX86JCe+LlEyc7xNInd/P03T4f6Vrw9fFr2L7UPneCvMMLf0o+cXj00XB/g8srbj8leC3F8cm1xnWkMxzoYVU569PqAthVq12+Lp1S3tP91bfGJSo0z2RLb+fwPFyV1c9lr7/9gvh/FcVQlLlSM8Pf6ryB2W6T75/fe+8H2HhXvH6qf74/fcakePOGj/YwJ7gOSI5qtokYCHYyrB+893Nqgewqyf/jR69tyxOT7u0RjDyFiTb8xRluf/+S3Q59E5fr7y0//uPjkCzo///R3871YY0V2EdOPcczEOo2zWKY01y+BMfj1r5/OJwa4T8egMalP2qqOtsTfHcqRA320UXZhByFf05TJDvrl0buPN09/+zeKHYyAETACRsAIGAEjcHQEtjsh06Tx2k4lZdMkcKaZJjlz/WTRNj9NbLb8lEd60S2JW/zowgbJy/b06sU3TcpmO4lVRtzSHelG00vkyaYoW2XZzkijtGiVJ1bZCH/kG7EbmsizTzrqka1Rjsqy/ZEv0se0eGOZ0iX+Er3KiJWWDGKVESuv64FY14142OFTPWXkSzjCVyqHp2S75PfifL2Qj/aIP7dL5TGu2RdpclpyaZ/Swk60yFUbs23CVDTEmV9ySnGPH1nSKdqSnFqZ7JJNyFAaHtWLP44H9Tmx+gleaMiLpxfLftEpjxyVKc72qTzioDLFrTrZLtpoO2m1P8bwiJ6YtkbMKIs6kaN60pk/ylIamaMYZnno4E+yejH8al/mo27Ujp4e13vnymPAY8BjwGPAY8BjYOkYuPaMP7sQcZcn7pqyi8kuh8Kzj59e2wVR3aHjabI360KngnZapgnVvHvDjkytXjytmLayy3aIME2qZ6wili25L7/18Fq1dqNKdZm4RLOEP8tr5afJ687JhBZtrS7jcyj7p8n2/Cwyz9eyUzoaevp79ehhN5UdzlpgJ5dTHApPPrhKq+yY8aGu3337n/HI/YMdb7AirTGqdut+E3fFVcf1TTm7qvzBn5+jFm0p7vH3+q8kM5dx/1Sb2BlXWnTafSdP/2MT9zYCbdf9gp34zDsT7fGPa4Jd+NEADnFXn/7mj4BNjOHJud3aLbmcbiJQxx+76hefXenlelTfEdPGUqBPJYNY/SKZ5ElzPUlnSU6rjN8MZBDHIPxVho544k3lxOCqviOPPE480Dbde6innD/GLrv9yhNHfmQ4GAEjYASMgBEwAkbgWAjsHPXvKWGSysRFRxVFz+RlZJLKRImJVAy1o6aRhrQcr5qeXn2WV8oz2dVEjfps26j9OLUc99bCRElXLvvm06sJsuo0KVRdS79oxEuc+WPdvmlk4kA+/fnv9xUxH3/N+BzKfibpX22+mG1jYo1zONIP++iP+OIY0aba+Iy0ewO3knHt9Yv6tf1PX+gxiNwvjO84LriO+ItOKP2pAD/3Imyq4S5axTV+jly3+k/8dzFmgQF8uB7ywm5sDzjidOO4KlAGxnHBAudYR/FZrNB9k0VX9Dx44+Gl0z/Rwb80yEbZw7jVAg/Os+oZL3Ght3R/jLrj7xb3dtoZHX/GGrpiYLyAWylgB48daGEg4iZ68EAXCy95vIvGsREwAkbACBgBI2AEbgKBRY4/k7w4MV9qYHTKlvLKMWMyWJrk9+pH9SFbEzgmfM9/eTVhG7GfySM7YnnnqKdfbWIiKt68mNHSP8Lfs2Gknolu3LUe4Yk0NXyOYT+TdpyQkTCqv9Y/r3z0eHYaonOBk/LkzbGFhxEb19KsvX7Rv7b/WSDRc+w4anKakM2iILvECpyewOHTNY/9a0KLn8UILYxIx7H7b+f6fkta18W0ITqqtFljm13oeTf/V1eLdqpDK4sfuvfJCujhi3TUkY+05KPjPC/wfnh5ioH7xYMfPdw675JNHPs7liudF1/RofujaBTn+yPXqt45IBotTigfZcUFJurRhbMuh51xOOM3LRArRP7YftXrfSngEe8Nqqd/sl7VOTYCRsAIGAEjYASMwCERuHbUvyUcp5/JCxOgWmAis+/xS2TW+JlYUsfkVEHHT5l89erFU4tpU6ld8ahqjVflODKEOBlUnWIm5XFirnJiHNX4qAHpuEMZaUvpEf6W/pLMWAY+TOD3bV8PnxH7oz29NGN1yRHnnv5WPZN3HCH9MVbZEZTToPGJ46ygXUzlR+La9SHeVv+OXL+SU4rX9j+OGH2Cg4YziTNEmQJtw1FT0LUOdgQcyHj/4fqHR/Xiq8Ut/l7/SWYLX9G04tg+rm8c20MG8NAYjI45OsCp5WRqrMoerlcWX4QveJfukaIXhrSJsY9+yrQoG+0ifei2yw5iOf1xYYn24bjHMRd5Ylptj2Xwth7lUfvVTu4X6g/SjHnqiAmUtfoj6nbaCBgBI2AEjIARMAJrEVi046+JYXZY4o4Qk2s9y4hxTG7EN2Jsi59JErsqTP4VmEgp9OpFV4tzu7C95eRmOfMu11QYHfsl7QcndqjFz8R4CXZr+JnUR1zpQ95szcRVk1McsdZb1zMeOd/Dp2X/iH2ZJuKX60rta+mnLb363N6cB0f6VruAXDd5zGWenG9dH5k257GfkHXG6zfzxPya/sdhBHMcQgLOJNfGXLa5fK9Ixge6eH1zLXKCItof66FvhbX8LdlL6nR9c21Fx3SJjEPQ5mPtUSbXC7vxcvqpY/xw/x099YUMnbhpOcxRb05zz9D1Qh2Y9YIWGEvYMsaoZ9y1xg68pR38iEfNDsa6xqicfGHH/ZPF05bumlyXGwEjYASMgBEwAkZgLQLDbyyeFJnWGHgMHGgMTDuP27fI+9pad2+ZnOnt29RL6VPAF7vo82Pakts+Oa9FfZNzWh178ExOe5EP2yfHuVuPHcigvTVZyMl4iAc92NjCCv5IQ7qEMTKzDegVVi0dkika8RBH3dSjg3JhHu1TmroSr+Q7XncfMH7Gz2PAY8BjwGPAY6A+Bhbt+E9AOhgBI3AgBDjqveYExYHMOAsx3kG97MZ4QoeSyeHc6d/J6dzmdfpiWzAlJmd2m42028IpwUmNyxd8lr8/z8sE2TFHNzv+cecd+doNR2asizpIl3bXJ+d6ezKJtkYajuKPjgNOf3z2q6vTYuiLsskT0BFlxjT46LSMcIv182mF6cQCAayxVaenpgWA7YsEJWMm9D8jYASMgBEwAkbACBwJgZcmueyqOBgBI3BkBLJjwaMILcfnyOZY/A0jgKOIA7jk8aEbNtHqjIARMAJGwAgYASNgBM4UgXvl+MddFvrTOy1nOqrveLOmY8jzM8g3PT59fdzxgWPzjYARMAJGwAicMQJsoBD0zqK70lQv/N+Vnjp/Oxe91f+uw8ExS45i4lAdI3C0lYtbf7pBLdEVZeRjuiNy1vLjdGI/cQ5qV4yX2BhtQ0YJn0hTkt2yT3Wybyk/7e3p79Ujg2O/2FDCkPpTDb3rQ7jGuITxmvZFfNGjI9RRZtTPYsXS0OO/q/23FAfTGwEjYASMgBG4DwiMzA/j/KM2t7nL84Ne+3r1vXHS4+/Vr5WvPr5rc+9eu49R33yB0qRwUf00qb72wqYlMtbyj+iaLtyjvGBpGmxbrKQjlvVsmxzh7YuhoJ2cmmsvpWrJWMMPL9hPF+Ycj9iNfSN0sjnSlvBp2b+PfbQHPvSP8Lf0SwZtVntq/UP5scbxseSqTcTqG+JYntNL+z/z53zGnzzjUXSyK44j1Y3Eo/zH7L8RO02z7DfHeBkvjwGPAY+B+zEGmBfwt7a/4/wQWXn+cej5XW/uRn3+W9vGyN9rX68+yiqle/y9+pLMWNbipw7slvgvUfY9TF/dLDQwBZ6AjKAIYA1Q1UUe1UmeaFrxKL8m5dKRZfbqoZcDkB0blUs2cabJ+lr52o2jxpPxwsGhrEafy9fyS16Wo/IYYxtjIZYtTWd8st5a+zNdTW+WL7oafy7P+nv1yAcT/tANv3Qqphw5/GnMl+qoVzmxaMWruKQj8uV07fqNdLoOWmMfvUv6XzIjj2yRbvK0s5anLtaLbjQe4ccG/mr919JFn4BL7OOIoerVd8SqFx82ik5yRNPS7bqr3zFjYSw8BjwGPAbOcwzoN3pt//L7iizJ0e+u8vwmU6Y8sXSvmR9Inn7r9fue9Wf7xLdvnOXn9vXqpVfzEuUV9/h79ZKzr3zxZz0qd3x1P7h21J/vG/P9Zo7E88ebiacBMmF29dZj1fF256mT5jpeUkY5gRdYiWb0RVYj/OjiG9KSjf6pk2ed/OvVbwkrCd42HW1HT3xrdIWtWsx3si8+u6jWx4rp4p+zEa9vPr3kVV2kz2nR7Muf5fXyjJO1z1hFfA5tP/KQP2pjT3+vHrygab3tfLrRz7Bq/GaMddSeMZjDyPWReXJ++tGa34gu/fH6zbS9/NL+5zriEZvX/vP78/0ErEjHx27oK+43XNPcc8AyvvyQ759zb6Jef+qXnr3U9/h7/TeiA1z4Zj0Yl745T73w5+WOvIlegfFK++gXyYHm0buPReLYCBgBI2AEjIARWIEAv/Vxfqh5RGv+fIj5gUxmLvj884t5LlDzMeL8WHz7xr329ep7env8vfq18nv8rt9F4Jrjn986HSevTMSZlCo8+/jp9pNEKjtWzMDhQkCngpw6nIRevXhaMW3lE2uHCCxCgFW8kbTkvvzWw2vVuiGU6jJxiWYJf5bXyuNAlpzTFk+uy/gcyn5uqDiFLOJEpzLrz/me/l498nDicPpqAaf2r7/4clvNZ89uMhzq+t23/xmPcmrBirTGqHDQ/QbHNweu/+g4wx8/DZfpc77H3+u/LK+U57pQm1jIUVq08bqh/7FJP4q0XfcLHP7MKxmOjYARMAJGwAgYgWUI1OaHh5jfjVrC3JcFfvkvkY/5jTY12CDQfCDS7JPuta9XH3VqgyqW9fh79VHWPvIjv9N9BP61T3JFwSSVXTr+YmDiOjJJ5aLD+Ylh9JNmGjg1Pb36qLOWZsDRFi48QrZt1H6dPChd2DXd2t2P9XIIVNfSL5oWf6zbN41Nl7vav99XxPZkRsTnUPazQ/zV5ovZNvoR5zDqqRm9j/7YPzjDnEapjc9IW7Ph2OVrr1/sW9v/9AXjh5D7hfENhirnOuKP61KB/lSAjnsRNtVwF63iGj+76q3+E79jI2AEjIARMAJG4O4hUJsf9uZ/vfndKBI49nGBP/PFjVfmr9kHyfSj+V77SnKWzFlPUX6pTS67RGCR48+AjRPzpSDGi24prwZWbZLfqx/VhwPBShuBC+/5Ly+2jsiI/Tgq7OouXamT48LpBfHmxYyW/hH+UQxadK+9/4OdXesWbamuhs8x7MfJe/DG9ZMUJbtG9df655WPHs+7t3FRjJv8kzfHFh5KNh26bO31iz1r+58f0Od/uJgXAHH0GdMKLAqyEq7A6Ql29HXNY/+a0OJnMUILI9Jx7P7bub7fklbHRsAIGAEjYASMwDERiPPD3vzvUPM7HPtX33l8bUOj1E5omYNoI6tEM1rWa5/k1Oa3qq/FpyK/Zp/LdxG4dtR/t3o3h9OvHbbdmqsck+uHb445W1dcV6kaPwOLuvi8K04EAUe5V3+loZzCudAKV6QYfUYfHhwZghz3OZP+sZjAXylwI4qPGpCOO5Qlnlg2wt/SH2WV0uDDc9L7tq+Hz4j9JbtqZYxVnqMaDT39rXodT9Lz24xVbtzavdb4xHFWWHJMXTy160P1rf4duX4lpxSv7X9+VOgTnH0ew8DRp0yBtvGjqKBrXT8qLKjF+w/XPzyqF18tbvH3+k8yW/iKphXH9nF9s6LvYASMgBEwAkbACNwcAnl+uGZ+t8Rq5j9sfrAJ1gpr/KiS3Fb7oO/VSyZ2l3yYHn+vfq188TvuI7Box19OTHZYmMRr8s3kmlUqLioCnS2+vjmbeTe5xs/knEEn2cjT7jzpXj00rZDbhe0tJzfL0mMM8aJY0n5wYoda/DgFS7Bbw48TFXGlDzYfbmbHClwJOGLcsPYNPXxa9o/Yl2kifrmu1L6Wftrcq+/hAo707aNvLx934brJY64nY831hf2ErDNevy39a/qfRQMwZzGEwP2Ca2Mu2/xpvs4yPtDF65trkRMU0f5YD30rrOVvyV5Sp+ubRYt44mGJDNMaASNgBIyAETACYwjkOWCcHyJh7fxuzIpLKn735UDH+ZfmpZJF3aFCr329+p4dPf5e/Rr5uW+FI3Ms+S89+fep/qWpsXyuwsEIGIEbRoDdbnZ9fWNaD7yc6ZqkJQsENRlry7GRhY8li4lrdZrfCBgBI2AEjMC5IICTR8CRdDACRmA5Aot2/JeLN4cRMAI1BHD615ygqMm9j+Wn4NjfR9zdZiNgBIyAETACRsAIGIG7gYAd/7vRT7byDBDIx5E4auaj3mfQsW6CETACRsAIGAEjcHQEvNN/dIit4MwRWPRyv9LL75bgw1HX+DKvJby3RcsL6Vo29+pLdiMPLNbiWZJ9ymV6pom2t9p/rvjwg8XOtP5GnP59xtcpj4Fs27m3L7aXfvcx/4jI3UzrqGm2vlae6XIevtZvTKbP+aW89+13J+PlvBEwAkbACBiB+4pA1fFnMoKjFgMv98Jhuy9BE6TaZL1Xf19wGm0nz7Lj/BzyhSWjuu8i3bmPr3Nv310cc+dssxYcY8zC09LApx+zk89Y5uWouXxUNo/9xLDEmedLEUvawcsxMz35iIvSmS7a6LQRMAJGwAgYASNwtxBoHvXnDeI5cDz5mIEJR+sFWL36Q9rGp9eefHAdA+no1YsuxywkfPar/87Fzn+HgPG5BGLf8bVmIN3m9YXuGPIbWXM9tHojLnUl+qWPU+BwzW+EDYZEHaF4TqpO5S1+0dTijD1OF1/CYLGMUGq/vhqSaaWDcj7BOfoCyaxD8iVvbZzbGOVl7Eq6s33w5z6IMmNaOKqMhe2vf/1U2UXxs493+bhW+d3iE0y0o7ZYrH7KyhinsW3kSy/+jDSSoS9llOqgie3GNl0TLFb88KPXt2Mj44it++Ij2xwbASNgBIyAETACp4UAb/W/9jf96L+YJgk75dNuxgvKS/QjZdPEZJaJDNL8SV4sU53okd2rh0b0kX+a3Fyzd5rwzbQtm+GTbSW6XA9WyJWdymOLbJBe2Zflyv5IJ97Yvlo9NLEOeVFHTz66ZJviqD/KKqVps/gUl+ikJ8tu2U4d4y/Lo4w6ytEZx2wer6pXH5Fv9XHWRR6ZahuxdIu21gaNB+lWHhkZB2RRVrKtpz/Xyy5idKFXNpCXjlhGuf4insiotU82i09xqW2ilW7y/MET9ZGnPbV66oR/1id8sw7JKsXCINusfLYv6kdej7+kM5ZF+Vk2dLE+8ikNFrG9wkD1rZg2Ij/yQ6+2ixe7oNOfyolln3CI8mKZeEUPL7aSj/rIo086aF/Mq3yfGH1LZMm+aLvsy7Joa002tNleaEv0EQt4anKxQzKFUUlPlAEPtOiAFtklfTU50uf4+tzJmBgTjwGPAY8Bj4ETHgPlzqlNBCjftzGaNMXJBGWtfNaV6WO95KsMW5ncKK+YMmiVL8Wl9ke6XE8bZBuTONJMpKDLkzrRRnmkZb8mYJqYia5XD33UJTtG+WW/6JfGslt82R6VQyd8VBbjEj6lMniizTFNHe0Hf8mmPtPkvGhLsfDM7RRtbq/oqZf9xCpHTml8QJ/HF2WRTzpjrHqVkccm5Ufa38Kj1T50tHhlg+JS+zI/+nL/gZ9kCFPppr38kYeP+sgvvlKsMRnlZ7psX9Q/wp/l5bzk534TneqVz3G2AXrKMl0pD049rLALmeLPdlKXbezlJSv3NeURX/J5/Il3nzi2Yyk/vMIVDEq4CavYfrWHsvwX6WNdSbbGKHiQhpc2wIdd5EUT2xZpKUe2eElHvUqX5ESZTpfnT8bFuHgMeAx4DHgMnOIYqD7jz/HQb3/77WTzVaDs+ecXVwV7pPIxfo7nHjLo2CMyOab/b68/uPYSPT1rXtM7TZ7mqtx+0dfqaYuOeHKcssYvOaUY+8WHnUqLtlaPTbQ1HkHV20+nyZvY5+OokpnlY39+1nTLOJCQXJHyqboHbzxUdlUMrtg3TVS3ckhHzLcVjcSa8cezvRw/zu1E3Qj+0dbW+KiNr5Z+bFA9aQJjgTERw77tH23fyPiptS/ayZjF9tajNugCRwXay3PWyOde9c2n4/cq3l9C0PUrma046t+HvySb57Vpw+jR/CiDccn45FGFyZGrjtXIozSPFPTu7cccX/R1Plau/tN44dEzsJmc0mvvn1E7RmLuG1wH+wTdS+Nz8mCHTfEPOzliz5/GFP3CcXqV01fYQZ6xS55AXnT5BaDoZ4woIJt7LLrhe/mth/P3raGhTNhBz2MIBNkJ3hefXV0j0in74rU1M/qfETACRsAIGAEjcKcRKD7jr8kCE4T43J8cSyYfmszc6dZXjO89W92rr4g9ajETPkLJKR1VjLNB39PvBCZ+eeLZkzXtQu04m4ecPDLxZ/KsBQ0ckdJ7KHo27lvP+I8T5SjnEPhLXm18tfTDSz0OB38x0KdrxgWyRto3On5q7UPP/Hz9h6R2n02+LNmtz+OTNrK4wnPLf//N7jPY8OMM46TFkGWoDudQOMbFkmhfjRcZJf4R/SxYiF/jfC747l/UT1vzAgE8OILIydfuiP6oK6ePOb6yrlKe3xy9G4XfIO5TEYOR9nEtcN94+vPfl1R0y3Co0fmXn/5xHmdgrH6Kv4vYEvMIxqEmUD7345yb/n033nH8RVO7XtEf+xUMGJ8qw7n/5scXc/75Ly+21z3tZnEBuYyP2emf8KTcwQgYASNgBIyAEbgfCBQdf3avcKiYaOHIybliosvE4dX3H98Jx3/EWcndrIlQbeLVq8/ybiofd8dqto/YAq8mn0wqmTxqYtvjZ6ywyy9nhMnvIQPj8Z/vXe76ywFvLUAd6rSB2sCEn4n1xeYfKtrGh8K/Nb5a+jGEehze0f7aGj+QGG1fb/y02ocZODHoYkcV5zm3JTrhJbPj4pB0iQ7n6KvNF8ruxPG0AG1AL39aBBNxTf8If0u/5GO/2s8Yz+O7pl/8irkOc2jp595+6RD/LbNt88ccX8jGqY3tbd2/ofv809/N44R+ps9a7VMjWHTS75nKRmP04DDrVIsWuuBHf7RfCzgl2diuBQzGV1xc13iLZZLBggELV4++vVy8Eg33WS0ksHjA7/fT316OX/FiX1yUnRfApgUHcAcP7OWayyGfwsj1zhsBI2AEjIARMAJ3B4HiUX8mgJqAMSnA2WGyo2O3HAllEnKMwERERxJL8nv1TL4U4lFclREzAdIEK5aTbu1GjtRneTeVZ2IHNjpyjF4cJ4L6cs5U/jGpzY7SzBuOgpIHtxp27AjG48KtyW/FjG4x45GdWPo2T+Dj2KDteXe3K7zTPpxqdJfG/lr8ZVtr/LX0w6/6Uj9Kfi+OGEbaXvtGx0+rfdKHLpyaGtaiK8WzU/XdzmqpvlaGTpzfkvNT44nla/mzLNqPM1caa5H2UGk9FsW9sRaOOb64lrle49il/Tr+jk15IbG1MFBqA7K5J43cD0v8jN3MS79TTsBJxkb0sPCSaSWTe1O8jzLmlGdhh4VXyiIWpPlto0406FbQaQEWq1iEiryiYaECfsa5ZFCmRT3q4h90DkbACBgBI2AEjMD5IHBtx59JSXSo5snLz2jw5THBOTVNLpgg/uXTP847HYeEA91M+HTMlglN3PXr1WOLHFOcGHaBRoMmS3FCFXl79ZH2NtJM4ugXYYcNTORGQ3Z6wL42eS3JZDIZ+075zSebRf1Qkq0y7GHXn5Bti2MD2/k75K6/xiFt1PFc7BDGa/Hvja+eftXnftTOILb2QsQQ2nj99dqX9ebx02tftI1rUOPnyZu794BId8g094qvf/Z0e/9YKnstf9RH++k3MH32ztUjN3nscY+jX9YG9DGO5YBKHs6f7qHHHF9cy3/e/Gln4SWOPeyJu92yT9ee8q2YRdHSSYgWj+oYu1r4VlmMWaDBgf56+p1ET4sWPuxGJrjDi1MvnFUf5UOn+nnRc3N5Ig8aFlt1Ako8jJseNvzW6/7IowsORsAIGAEjYASMwPkjsH1L8zQR2b7ld2r2XD5NSopvLYZ2miRu324s+tuMsQd797Vh2q1ptqdXv69e8y178+fafj5VvM99fJ17+051XNmuZfeXHl7T4mrzd2JyqJu/Qfrt1H1Mv7GxvPXbiv5oI/ri7x5yuNYiTUxTh3zx1eyFLsqNMpw+7JgynsbTY8BjwGPAY+AmxsB2x3+aLMwvK9Lu0TQZmHeO447PZNA2sAPBjhw7C0t2FLcCTiwxTXBmi2hXKfTqSzwuOzwCjEt2OfNu/+E13azEcx9f596+mx0t1nYKCEyOcfVxonjqSr+PnMbicSjuX9qNlwxON/Dbo3LaNznnO3nK+J0mUKcALycG5tMg3xW2julzGoHTA+hmx18nCWBFfjy5E+ukz7ERMAJGwAgYASNwNxF4aTKbnYGzCEyGWIw4N6fwLDpnZSM0QUZMnByvFGt2I2AEjIARMAJGwAgYASNgBIzA2SNwVo7/sXvLCwvHRtjyjYARMAJGwAgYASNgBIyAETACRuDQCGyP+kfBOuYfy3I6v3gp13O0V0cPvUOb0dk/H3e+a49h7C/9klPHPfc5PRHtQ5qOucqmWH8M++MRWHT2xqnscmwEjIARMAJGwAgYASNgBIyAEThXBIqOP41tOX08q8gng1qB4/bxW8WHcv7jgoL0y7nMTh/1qhNti180pxqzIMPnqIQl/UCZ3rbds7uET+mt4D/86PWmKPQS9D4IEWf75gWk6VNXek4012f7S/ZFx71ULyxkA3GpLNY7bQSMgBEwAkbACBgBI2AEjIARuE8I/EutsezW42iV/nhBEUEv7KrJUDk7uzh9awO7xdiFM49zp78olwULleM0Rid2hD/K6qWRBz564RL0tDNiJhlycpVXDL0caZXVYl4YxefWFEjrJVLYgN6Is2wRPXHEB5xKzjvf62ZBoBTocz6JxRiI7RZt63NZLfvFn+3LixqxHhtjeyWjF4M3WDkYASNgBIyAETACRsAIGAEjYATuAwJ77fgLmFfffzz0Ij2+v7w24GQiB8cvv3k/56WLbxu/9p+XixT78EtOKcbp5/vJ2s2GBicU5xaHWnmcTJxrfR89O7LQ06ZekJMdX1zId6MJ1IEBCyK8kZl2U4dsykYDcl55+/FsL3Ep8Pbor399edrjtbCbDy1tw6F+9O1lP0kWdSP2Q7cksPiQv18Nv5x6cI14LZFtWiNgBIyAETACRsAIGAEjYASMwLkgUHT8cabm5/M/7DfzyY+/vOaIRy6cYXbekUk6O76RtpV+9O6lI7rEkfveez/Y6LNG+/DX7MGZx5HPtuDo0lYFHofA+SZA+8/3LneohQF4sGud5Yg/xi+/9TBm57QWPKi7+O0/5n5AP32HXNKiucZcKOB0xF9++sdCzWURzjuPGmAvCwssMny1+WKHHr045LJBlSP2i7YVx3GpBZZIrzI90vHnzXXnP59yiPxOGwEjYASMgBEwAkbACBgBI2AEzg2B4lF/HDscqNIfAMSj9j3HEscXRxeZtV3kfUDFaWZnl7/4yAGOoco5dh535KOeGn+kKaVnx3OqKDnrOLy0V/r1PWTtdsej+cgGD8pGgnb3I63kxjqwxvkmaIEh8kR8sFMywIMj/q3+ZPEEGgJ06IFPgVMQ1GvcUK7HGKKNopfuWBftE6/oieNRf+xHZynQPyz6cELBwQgYASNgBIyAETACRsAIGAEjcJ8RKDr+LUDkVOJs43hFxy/z4ZTFY+w4uSVnLvOV8nqZoJxFnFrt7kb66BhGp3+UP8oqpZHPgkKpHWDDLrscX8VypnFG5SxrsaK0gFDSKxnig0a76KqjjP7QM/glpzjig33iZREiLlpo1z72b4kmLubwKEY8es/pAeTQZ9LTsz/a19uZh/YQj5GAm4MRMAJGwAgYASNgBIyAETACRuBcEdhx/HFmtVtdi3HkOBLOTiqOY3T0IkizAzo9Ax8dW9I4pSWHNPKW0jiO7OBqF71E0ypbyx9ls6BQcv7Z7cZ51uJE5FFau/48hjC62y9eFhXgUyBNmQJONfqxj1MZOMXR0RZdKcbJ1kIFMQsUONY6NYAc2hxpSDMepAOeuMOuxyvk9PfsL9nVKnv45vXHH0RPH9B+vY9A5cQa57HMaSNgBIyAETACRsAIGAEjYASMwLkisPOMf95hxUHCOY3OO2WRLtYJJO0Sy2lUOTFOKY4/Cws4jksCvF//7OnMu4RPtGv5JYcYWXIgcbJxbtXevDihevjAi2f9lZ4Tg/+Q/+CNh9v2sxAinTi6HJPHWSdgD472XFZ4zn1Q5ZastlCh4/S0i3FBv/JyP4XYxy37RY+9m/BuCRYT4njL9WCrAAYRe9pfGp+id2wEjIARMAJGwAgYASNgBIyAEbgPCLw0NfJFraHs5GbHKTv+mZd6dr7lkOZ65XH+dUw7OsaqP+cY5xgHPWN7zm1224yAETACRsAIGAEjYASMgBEwAkbgdhBoOv4yCWeeI90EdlFLTj2LBOzG3jcnXhiNxpyG4Ln4uIs9yms6I2AEjIARMAJGwAgYASNgBIyAETACSxEYcvyXCjX9dQTiCYd4/P06pUuMgBEwAkbACBgBI2AEjIARMAJGwAgcDoGdl/sdTuwySXonwDKuu0XNOwFw+I/p9HPqgscIeNadP9J68d7dQsvWgoDeIWE0DoeArguuDf7AOIZePbTxOou8o+l9+TUeZDu2HiPsa9+oLceWP2rHoenol31eXHtoO25b3rn2723jetv6Y7/qPkmZgxEwAkbACNwdBHZe7jdiNjf8+AK1Fk9+MVuLlkmTHxNoIdSv++bTi5lIb9Eno7I+992nYAzlwMsHWXS5S0HXGLbfp0dCbqL/+CJJ7XElxkiv/jbHkcaCxsdt2mLd1xFgUXffF9del+aSEgLxsUPqj7mQXtJ/n8s0l7iv84v73PduuxEwAueFAC/3G/6bJp0vpsnNDv206vti2rXvlkkPMjK96hSjA7nKE0+OwbW/aEupPvKfexpcp4nRFjPwoCy2O2PU64fIO5JGfu438VEe9Zd0x3qlcxskrxeDRc2WEm+2nbFFWYn2mGXYXcIGncJEcY1uX/syBlHOqfffqH2tMdFqf8TiNtNcD9i5z3WhcRPjfeTcZvv31Z379ljXN9dkvA/va+858uU+WNJGeOP9jnT8/V8ia1/aNfbvq/NU+LhPxHENFvfl3nEqfWA7xn0VY2WsPAaqY6BaUXR4uNHnH1sm0vEHGbBLZeoEZPCj0fvLesRPedZHXf5Rho4y8d2VmB/XQ9stzDOm+YcbXGO/RMyEr3AlL3mxLPLLySKmPOojH/ux5fBGO0bSrfFX48ce2YtdcZIjnho+NdtrciQvx8Ipl7v/2vcp4VYbX7qm4tgkrfHbq6c/Mk3uI/J5fMAjuh6/2hBtFG+MNRZiW2N9LY1+7GvV93THNuialzx4aYPKI77QRF7qxKe4x59lSI/4e7HkQ1e7LnP/SWYNu5qcqEsy9omRzx+86ndk6y+PgZr90p3raZfqss3Q6vqARvWxH6P+WA6t5BKrr2S3YsYL9T18sYU/aGMbon25Dh2xfaV6yvQHfW389uyXjBYGI/0nObW4JV/2R5rYP8iMdWoT5RHfmm6XX40VY2EsPAY8Bu7wGFjWeaUfL/2I51g/1BkcZPADlMtjnh8lTQpiOWnqSrL1wxfp0VOijTSnltaP8yHtAjP+WjLBCQxFQz72k/o39kvGPOclCzlZP3KivkP2VZQrG3qxbM/tFl8Ln9wW8Uim8r241k+18iivZR902JLt6eUl/9T7b8Q+YRDHr9qnOOOh8hjX+lr458l25CVd4898tetB9+BMn/XkfE1epqvZxxhEhujJg5fypDN+OQ9tTX6Pv6dfdtRi2XIT1/fI9Vqzk3KNJWLRyX7lcyweled2qr42brJ86GmH5Kl/xM9YUFo0xLX+pS7rEF+NR/TShT6NQdLRvl77VC+d5CVLtkmfaHp50REjC5kqy/qyLNGNxiPy0aE+gV5pdPSuH9kb2zBqm+mWzaONl/HyGPAYuK0xsNfL/Xj2WC+qI+ab9Dw3m8umRt16eP6Hi82DNx7euh1LDOBZ3kM/u/joJ69unn9++Q6Ami18ZpB+VHj28dPtZxxVRl9f/Oofym54j8NI4HOQX//66Q6pnhmcJidz+V9/8eXmtf/8fvGlazuMncw0cZnHZIesWP3qO49nG/Q8dSRq4QMmYIFuBdKURbxU14pL/eT+ayG2mcdpb3y1Jayv1fiIz8AukZr5Dn3vWnt9MQaRofDkg6u0yva9P4zwj+iXnFp8U9d36Rqu2RTLuWdMztv8m8VvQPx0LveS7733g0i+k9b4U2G+f6s+jzPRj8T0r/i5Ryo9wtui6d0/+f1A16N3H2/+/pvL3xHSMfTap3rxZHwo33f88huGjchUUN9NixpzUa//xFeKR+TD1+qf3vWDvYw55kuMwfhbVrLJZUbACBgBI3D3EFj8cr+X3zqME82PJD8urZAn8i1a161HgD7B8eYvBiYdh5rgRbk5zeTvs1/991zMZInxwWRJTvi0Y7Fh8hJDfnkftjLBe/rz30ey4fSDH12ObyY9mriJuYcPTtH/+PB/bvmwIzpKknOsuGffsfRKbq//RNeK1/ZfS/ax68D/4rP24lrPhmmXbmexjfF9qLCmf+gXghbrDmXTqJxD6T/V65v7DfddLaqXcOE+CA763cz3vt71f4jxWbLrUGVL7p/gkBf0e+3r4bOmHZoXtX4ne/3X0j8iv8W/5PrhZbhfbb7Yvqiy9TLUlk7XGQEjYASMwOkhsNjxpwk4X4++3XXAKM8OY9w9pl6BH7E8aVHdoWMmetohOLTsuyQPvC8d4r9VzcbJBqvs8FYZFlQgm902nA+F1mQGus8//d38BQkmLUyoNCERfyl+7f0frHK2mXzi3PDlCpy4aG8PH2j/+d7lrr8cwMhfsrdUlie00JxD/5Xamsv27b+l4yvrPUQeGx6++XBzsbka40vk4vSzyx8XupbwL6EtXV9L+O8q7U1d36VruIUZ91z+tONf+33kPqjTYCwAPP/lxfZ+3bs/LR2fS9vQat9IXev+CR4sBoMR7ea37C8//eN8n2YuAia99vXwGbGxRqMFMf1W1eha/VfjoXxUfkvGaJ0W2Jm/3bUv4oy20XRGwAgYgfuKwOKj/kxsOU7GD63+yPMjoTwxZbWAA3gTu/n8gLHKfwxHtta2Q5TjAGhX5xDykMGxXLBAdi3g9LN4o92BGl2rXJOvTMOEmwWjKJvd8bg4RH/F0FoYiHRKI5uFnn2cbckgZnLGpyWxT8c0KR/Bh3aCIUdySS8NXBf5VAMy3H9tJEfGV1vC+lqNjzhmlkjl+oxHxLU7vURGi3bN9cU1wbXNwozC6GddRb8mPqT+m7i+uYb3+Y3jt4rfT8YBvwE6bs29Ld47haUWGMlr/JXoYn1tfMZ7N3pL9yHp3TeOOkoyavdP7n/cj2kb+LA4Rj9qzjHSvh4+JXtyWc1+jc/4+IH6jt+jkf5DF31e+u3vyc925rz4W9evFp0Ye+B61+ZNuc3OGwEjYASMwHUEFu/4rzlGjXp+APd1zuIPIpMSHY2Mq9JMDjYfXjaUH2l+wBwunVmwyBOLuLOkH/o8occJZuIwEpi40Qc6/YFjj1wmP3/e/GneoZEc1SlPn+aTJEv6j0kXO6aHCLSXdoPFs3e+nnc+RvDRrhU27LMAIX4mYdKHLOxx/4FEOYyMrzLn4UrVX/EehPTRMcxiabx2lN98sjnIztva6wtni/uHrlFdH4dDsC3pkPqPeX1z7fLbs8/1LwQYS/whiz+eHc/3Ze6fUYfGX6bT/Vv1tfEZ793I5u/Qu/5RB23NvwG6/1EX2xb7izpC/O0i32uf6mv4IKMXWvYzPllY128fsuK1n/Xm/uvp7skf4a9dv4wxQrS3J8/1RsAIGAEjcDcR2L6FdjK/mZ6c9p231op+2kG4Vl4qg376YWzqkEzH7b4wPqeLzzS5qn6RYrTfkDHt0Ppa6dyTRvE03eGvF+7xt3k/vy39reuba5Z6j7f9x1sLX+O6P64Zu9u6frIdzh+uT42lsfQY8BjojYHho/7s1P/wo9e3q+qT4GLgOOn0wz3vXMVjiPBTznN5DkbgXBE4xG4f2LDzwskYrhkHI3CKCPA4y6FO2OzTvtvQ37q+da1613Sf3rzkaeG7v1RzlhC4jeunZIfLjIARMAJG4OYQeGlSxe6EgxEwAisQYMFLz8R64r8CSLOeLAI4ZfEYcz5qfWzDb1O/r+/j9q7xPS6+SL/N6+f4rbMGI2AEjIARGEFgL8d/OiK28/zdiCLTGIEeAuyY8VxzfLazx3PK9Zxy4blOLwScci9d2dYbf736K0lO3RYCuuakn2fteTb6HILH3zn0ottgBIyAETACRuD2EFj8cj+ZyktsNKFiJZmX/ikPDSv4vImXl/LkoMlZdvKY2Nz0LlK27Rzy4KgQJ74s2MwvdvqusoZ1rX9gk4zcd9J3zDjuCqEnvxgqtlt21Nqo+hxnGVGH2i6etbKRs1RGxkAv7pJNrTi3raR/jfyWbupG9LdkZNti37T4VLdWv+S0Yo2Rfa6P0fa1rs+WbaqLOMT7g+rXxLkNhx6fPdt4HK03Ltbgt6Z92B75l177vbZTH/uWfA8LaByMgBEwAkbACBiB+4PA4hcRTZPbnZf5TY7/9mVmpKfJx5wnPcF47W+a/FwrE11+WdQ0SavSisfxJcZgJexHMIG21Ef0QZajfqXvct2IrhGanlzGneSMtJV2RB7xtmJsaNXHOmhL+IlGNiqf46X2oSteH+Rb11LWl/NZ/6HlZ305n/Xn+pyPfSlsY1mm7+Wz/t74a9WDHfVrro/Yllb7sLtlS63dLZk1niXlhx4/uX9GbBnBZV/81rYv82MHZSPtgmakbdCMyjPd9bmJMTEmHgMeAx4DHgPnPAYW7fhPk4oJi6ug5z3ZVdAngkjraPM3P76YP98Xd/2nic72+8bTRHf+3jnfr1ZghyjqYUeKFwJGGaI913iaEG7ARDiOtpNv9LKLNHpUHmxzoH/43jEnOGLgU0j6HJI+5xXrR9L0dzxxAE+pjWo/9XHHMLaL8YD9D998uLnY/APSnYAu2hF5dggOkCnhF23nWqiFfe1rvUxtFF9squlvya+1ReWH0M/4030FuWCsk0SxL3v9L5tqca390Mc+jONPskr1h7g+RtpXuz5lWwu/pfcHyVQ80r+t8TPCH3UtuX5jn+i3CFl5V72F34h9rfbJ9lrMuOYkiII+Daf7KuW5/5bcHyXXsREwAkbACBgBI2AEaggs3iGYJkg7OxXTZKW4s1qig3Yy5IV2n4jJQ0usumkit82r/L7EtH2fnRv4wBFe/QnfjJ3wj+WUCXfJivVKIzv2l8p7cbYFHRoP8Gab2T2VPSXZLTuoK/H0ymRDSzYySvhle7X7W9K51j7wz9j08I121PSr/SX5kb+UXqufsYD+LKekizJo9xmH4s1y1Xbpz/3Zq5e8NXZJhmyM7cMu9TlxrIO+h5941A5itTXqraUzLfLi9Sub1X7ZKnkj/KJFhtJLYuku8fTwG7EP+dKR21fSqTJk5zapTHrVf+IhH3VIt+jz+IRPNLJRshx7B8tjwGPAY8BjwGPAY2D4c37TYLkWponn/MwiOxZ8GmaabOz8sfMSP+mnXWToeBaT3Qzt5LNzq/DyWw/n3Vrl71vMDmdpp6eHA6cEwBxe/thx5uVyMUyTxbmPKGc3Mwb65JifW1RfSye7Zw/euOp3ytkREx3viKBN00RXLNt4mhDP7Yu7pKqcJsw7O2sqH4mFHXaAJWM8hhZ+vNWfXTwF7C+FNfbplMG8q5mECzcVl/ClrqW/JV9ya/Fa/dwfGLNZTklfq/9L9LGs1f7e+OvVRz1r0qX29a7PHn4j94eWzblfSuOrNX5G+NHf6p+Wfb26Hn4j9rXa19LPb1oO0qc69Z/onn38dL7/KU/cG3+9+1eU5bQRMAJGwAgYASNwvxDYy/HHyefY4qvvPN589R9fzBM1OauaeMjxjI4ZNCwSMHnS8d0Itxw85Mfjj5HG6TYC8Xi5MBSucNJf6iOcfybZBGKO1moyOhce4R8OjRaI9Pm7pWqQga1qX+SnrUyg47iL9aNp+DkmzBiPoYafMP7m04tIfi29xj4WHWi3+g/hYBFDD9+W/hH5UVcpvUY/jmlcKCzJp6zV/zUelbfaL5rbjkvtG7k+R/Dr3R96bW/178j4afGj+1j9M4If+lv2jbQPGaVQui/QVoLq6D9+V3V/1KKt6Epya2W1+1eN3uVGwAgYASNgBIzA+SOw1zP+mjzK8WKyzmSlFERDHRMYJjM4LgQmY+z44kxBx8Tq618/3ax5jnIWfE//aTdqtPn0o3bccZY18RQ/u8pP3vyq6GCLZknMpJq+1aIP/d0K2gmLixHIYFe95tjzHHPcdW/JX1sX8RuVtcY+Fkq4PhQ4ncH1xHUFRiP4tvT35EtvLV6rn/Fbe2eDdPb6X3S1uNX+zFMaf5GmVx9pR9O19o1cnz38lt4fss29/u2Nnx4/+pb0T7avlR/Br2dfr30t/bqHcYJI9648fuif2oJmSXbmL9G4zAgYASNgBIyAETACQmDRjr92Gku7cjhBqifmGDk7pjFw1JLJjXY0qMPpV3j++cV8vDqWqe4+xUxAawspLRxweNkx0g4RCyvgrUln5oUWzAn5xAZ8HCuNCzeZf2mehQXpg/fBj64ff4077Jz8iGNICwWaOGf9tBuZtfpM38ojK0/0M33ED4zBDMdFQTt2yq+1D/kRn0fvXp5GUP/28O3p78lXO2rxWv04PWCaH6+Qvl7/i64W99oPX8Q3j7+R+prukfJW+0auzx5+S+8P2eZe//bGT49/pH+yTaP5Efx69vXa17OF30jGlAJpyhTUf+BQC73xKT5k9O5fonVsBIyAETACRsAI3A8EFu34tyBhws5fDNFpo1w7vaLBwYWHhQImKqThwWE9pMMpfece4/CyQx8dTrBVANfYR2A9inPmnZ8x/3D3revSU4tZSIBPNii/+eRqAYiFAS16MNGOi0BMZAmqJ83EWW3AEV5zWoQxGLFDdlxEyBhk/Bjf2KavHrD4FeWttS/Lp/2xf4VnDd+e/p589LXCWv3qR40t6VIbe/0v+lrcaz98rfHXqs9jQ21gDOf7XtW+zviu8am8h1/v/iA5tbjXv73x0+Mf6Z+abYco79nXa1/PBvqHE1a6f+X7h/ov3jOQGb8s0RqfvftXzz7XGwEjYASMgBEwAueNwEtT83h78qLAjhxHcjVRyXmEzY78tPsZHTdNeKRMExp2utip1QRZk2jVi96xETACRsAIGAEjYASMgBEwAkbACBgBI7AMgUWOvxxyVLA7ot1QHP95hyvpZkcjOv6qzjsTUZZoiLVQ4AWAiIrTRsAIGAEjYASMgBEwAkbACBgBI2AExhFY5PiPizWlETACRsAIGAEjYASMgBEwAkbACBgBI3AKCCx6uV/NYE4CrAm1l3mtkXkfeTkhcdew5DGPls29+lI/Iw8sOFlyn4JeCknbW+2/r/iUxsI+46sk51TLzr19p4q77TICRsAIGAEjYASMwKkhcLCX++F06Bn9JY3ECeExgT9vrh4dWMJv2ruLgBxzPTKSW9Krz/T3Pa/rLz9Kc99xqbX/3MfXubev1q8uvx0EWGzMofa4X6Zz3ggYASNgBIyAETg+AgfZ8cdMPkUUAztNLAaUgiak1PGSQN7aHZ0/6uF3ODwCTM5aO+y9+kNaxKfvnnzwZVVkr77GyFhiTOkzdzW6+1pufC57ft/xtWbc3Ob1he74l+/PsU5p3avJl+iX3qd12kTyiaOOWB7rhHmLXzS1GHnx3oftlClk3eR1mi3TiofyjIvqSnHWIfkl2n3KkB/bGGVk7Eq6s33k1T9RVinNPTf+8UWLr3+9Oy8o8bnMCBgBI2AEjIARuBkEFu/4MxGoBX1GjHpe2PfNpxfzpCE7YEy49WkuPplWk/nkx1/eS+eNiSTflGYStU9gMip8teMSy/SpMfUTjmCvHlr6SZ+8kl2lFy+O2K/JZB4bkpvrmbTy3Ws+10fbsIM8OMkG6ZWMjJ/sFx904iXdq4empaPHT5tan+pCfiuAQX6JZm5ji79lO3Us3ulLHZKDc/DK24/n0zxqnxbpqOPzZHqBp+r51ngef5LXi5EZ7yP5c3i1NoyMj6g7jy/V9fTn+oh/q/0j1xc21NpH3ZLxU2tffJEq9tKe2OexnroffvT69iQX1xpyuWbBm75ZEoRBvObULslp6R/hl5xeTNv4kkzsP3ii/iiDMf7g9w/n+6TGOxjEr9FE+pxW3+l+rHr1k/LHGl+6d0Ts6X+C+p+xFz+PKpv2idHH/UT3in1kmMcIGAEjYASMgBE4PAJ8zm/x3zQJe8EfvNNkZf4jPU1kXkwTim2+JBu+aWJQ1UmdZJf4z71smoDNGC5tJ7jzF7Ht5bOOTB/rJV9l9BG2Kq94xH54GSviyXGup02yjfFGGn7oyEd+0cYy0rJferFT6ZF66KMu2SE9I/Jj34hvNI62wpPtkRzohI/KYlzCp1QGD3Jkc0xTR/vBX7LVftFnftHVYuGZ2yn63F7RUy/7iVWOnNL4gD6PL8oin3TGWPUqI49Nyo+0P2MoXuJW+6hv8UY5pEvty/zoy/0X+06YSjft5U/yqY/82YaY15iM8mM96Wxf1D/Cn+XlvOTnfhOd6pXPcbYBesoyXSkPTj2ssAuZ4s92Updt7OUlK/c15RFf8nn8iXefOLZjH37zLJ+TGTNj5jHgMeAx4DHQGwN7H/XXrsekYCewm88uCrsI08SiekyQnctpclD8y7uaOwruQYZntfNO1Giz847V0l25nh7kK3BMX7uAKiPu2T9Nlmfy0d1+yaYt2kFi56zGL/pSjP3iw06lRVurx2ba+uzjq6Or2iljnCvU+KnHfk4b7BuyrZx+YMf9EAFcsW9yNrbiSEfMtxWNBO1XH0EG/2jgZAE7jrmd8I/gH21tjY/a+GvpxwbVkyYwFhgTMezb/tH2jYyfWvuinYxZbG89aoMucFSgvZzGQD473ZzoGg2P3n08k8ax0eON+vfhL8nnNApt0PswSjS1MsYl45Pfp8mJr47VEj8nYJ5/3sbrmOOLvs7H7tV/Gi9//cWXMzb8Lk+LAKVmDJVx3+A6cDACRsAIGAEjYAROC4Hho/5MDvIxZX7cmSQoMKGKZUwaH7z3cPOXn/7x2mQ+T5Alg5hJKRM0h/NEoPdsda/+NlAZfwQuAABAAElEQVR5+a1LB7vklI7ag7PBdaRrhuujtoBWk8mEPDqb0TGr8YyWM/HHqdGCBo4IZTcVaNfFZ2Xn6BD4qx218dXSDy/13OP4i4E+XTMukDXSvtHxU2sfeuZF1Q9JbYqLi7E+j0/ayOIKx//zO12QhzOsRzzIE7KMy9LNvMAkHONvQUu/eIlxLjP/iH4WLMSvcT4XfPcv6qeteYEAHhbbkJOv3RH9UVdOH3N8ZV2lPIsyn/3q8vEyfoO5T0UMRtrHtcB94+nPf19S4TIjYASMgBEwAkbgFhEYdvyZ9BV3oadJJJM7djOYEMXJwy22y6pvAIERZyWbwcSQUHOUevVZ3k3l4+5YzfYRW+J1xMT6+S8vto52jx+nn11+OSNMxA8ZuHb/+d7lrr8c8NYO7aFOG6gNOBm87PNi8w8VbeND4d8aXy39GEJ96T0IWyNXJEbb1xs/rfZhHk42uljExXnOzm90wkvNiYtD0iU6HOGvNl8ouxPH0wK0Ab38aRFMxDX9I/wt/ZKP/Wo/YzyP75p+8SvmOsyhpZ/fyEuH+G+ZbZs/5vhCNovpsb2t+zd0n3/6u3mc0M/0Wat9agSLTje5WCi9jo2AETACRsAIGIE+Ansf9Uc0jggvC9IRRiYGeSJXM4GdFWhLf/OuS43xHpSD6yiOS+GQc1Pj69XHkxjxKG6U17K/tRuJjF591HOTaSa+YKMjx+jGcSLEyfRcUPjH5Dk7SjNv2uHW9VAQMe8461qjXruXJdp9y5i0s5NK3+YJfBwbtD3v7o7obLUPpxrd8dEJyVyLv+S0xldLP/yqL/Wj5PfiiGGk7bVvdPy02id96OK+XcNadKWYsV5cAC4RhzJ04vzmU2OBpJlcyx+Fq/38zpTGWqQ9VFqPRXFvrIVjji+uZa7XOHZpP48uKOSFxNbCgHhijGzuSSP3w8jntBEwAkbACBgBI3AzCAzv+GdzmMBsj/C/e1XLpJDJfe/twK2dFR/1v8Lz0CkmgEz4dEw291OvHnu0KIETw2LPaNCkk4l3KfTqSzw3WcZOO+Ne2KF7iROUnR6wXzJJ5pqJfaf85pPNon5oYYY97PoTsm1xbGA7f4fc9dfuM23cfHccHTuE8Vr8e+Orp1/1uR/jm9KxtxUihtDF66/Xvqw3j59e+6JdXIMaP0/e/Orazn+kPVSae8XXP3u6vX8slbuWP+qT8w+mz965euQmjz3ucTphE/mXptGn30bdP5ERH4U45vjiWv7z5k87Cy9x7GELCwOPvn2V5Dbo2tsWNBIsipZOQjRYXGUEjIARMAJGwAjcMALbtwhPervpaXI5v1mYWPTT7t/2bc8qm3YPZrppkrN9K3ism5z7Lb/KFVMHv/KO+/1yExiV+nKJXvo0jpvM26vP9M4fZ1ys7edT7ZdzH1/n3r5THVe26zj3IeNqXD0GPAY8BjwGPAYOOwYW7fizU8EOyMguALsztec9p07ceckU+RzYCXE4HwR0pLa229+rPx8kTrslHOHnGs+7/adtdd+6cx9f596+fg+bwggYASNgBIyAETACRqCFwEtTJTvrDkagiwALP61HNLoCTHCyCEy7xdtn9kcW9k62ITbMCBgBI2AEjIARMAJGwAgYgWsI3DnHn+dYa7vG11qXCtgVO/ZOJvbFZ3HXPiOKQ8b3l0fs5vlzPgmlsOTZY/E4NgJGwAgYASNgBIyAETACRsAIGIHzQqB61D/uAJaaXNoVxLGeX45UYqiU5RcMQYZuAo8LSKb08abhV99/3HyZGQ4wb0jWy5JmYd/9o+4QL2uKMktp2VuqGy1jEYEw4vRDF9vF7ryDETACRsAIGAEjYASMgBEwAkbACBiBquPPZ8NKO8044vGTbhFCHNTPfvXfsWj+fBA74LXdZzm3YlIep1+BxQGePZYjj12EkhOPfbw5W85y3oGHLzrF2UEv0ddsR9YxQ/40F3bnhRLKchuOaZNlGwEjYASMgBEwAkbACBgBI2AEjMDdQuBfWuaye49jGf+W7OjjhP/wo9fn58KJ2cmXYy+9+dg+zq6cfugfvvlQpLOjrwwLAezqZ3nQy+nHbgKOMX88n47jrHzJYZ6d7UADffx2u/QvjVmkwOYcKKMuB7XrGj7Td85Vl3mOmV9q/zFtsWwjYASMgBEwAkbACBgBI2AEjIARGEeg6fjjKEcnWc7ziHicdk4G6Pg5TjoOPQsAWkjIDiwLBdrNJx0Du/2SpXLKomOMzmcfX54GIM1OfdSnkwrSrzjagY06WYAevtkumdK7T8wphPj9d8mgjLoc8m6/6nlnAHU3HZbaf9P2WZ8RMAJGwAgYASNgBIyAETACRsAIlBGoHvV/8MbDDX+lHf7STrnE47DDU3v7e3Te2UWOz+J/770fXL6c7sPN/EkxaJGHw67de+khxmmOR98f/Ojh7OjzgjvKWRSQDGzCqUcO9svZjwsHUTZp0ebyffKcQvjne893Hllgt7/06bSWbX/56R/nlwd+/bOxF/7tY2uJZ4n9JX6XGQEjYASMgBEwAkbACBgBI2AEjMDtILDj+OOIx7fC10yKTnh8az277IS8MDAfv//s4pq4uAhApfLI0XF/ynnfgPLojosKcpLFT54dce3aI+vJB19ubcJeQsvhpx6nHD2HDOyaswAh2155+/Gi3X5swW4WNZCT36cwYisLKSywCOsRHtGM2i96x0bACBgBI2AEjIARMAJGwAgYASNw+wjsOP7RGWQR4PkfLh1unEWcdzmsNbPlnFMfFwe29NNOfgx5gYA69LKrXQo443J6N5Os/NI9nH6O9tMO0rxUEB3IxGnVs/8l2bnsYlqoWEKf+Uv5uGuOfELWoYWM1sIE/cCigRZaSrpqZSwYEOjTrLvGo/IR+0Xr2AgYASNgBIyAETACRsAIGAEjYAROA4Edx18myfmMjjzH6vMz6s/+6+vtTrx4Y1xy7KnXQkKkJY1jT8B518kDHH0CPAQcZu3456P47PTz6ADl7OxDpwWI2eH9buFBZbPA6V9eQKCchY5vfnzRPRkgGaOxds2xj3QOtWf7M52O/OfyXr7WJz0+1ffsF51jI2AEjIARMAJGwAgYASNgBIyAETgNBIqOP84nDl48co8D3tvxX9sk5GcdOPw848/7BliI0AIAurITq4WKKCMeh2dhYWQnn4UPFjnYVY+nINa2D37tmisdZWrBpbXbL3od+c+LMaqvxcJTWNXoauUt+2s8LjcCRsAIGAEjYASMgBEwAkbACBiB20PgmuOPc8yb9XUMXLvj2nk/pqk4vhzPjwG9POMvZ56deMLF5h+RbHu0f6dwymhxgHblFxbq5EDmwakWX647RJ7TDKX3B/R2+7NNpYWSnn066v/kx1/ufZqhZn9Pt+uNgBEwAkbACBgBI2AEjIARMAJG4OYR2HH8cfJxtOX0E2vHHMdZiwDZzOyQqr5GTz2PCeSA45tl6YWDeWc75nVUP/JqEUE20C7tcn+1+WJWPT/7v1n27H+2uZaX3vjyQ2jBkTJhLH6dZBjZ7RdPjoVVLo/5iFEsH03X7B/lN50RMAJGwAgYASNgBIyAETACRsAI3CwCL03qXtysyvupjccmHv3k1bnxa53v20Dwrtt/G5hZpxEwAkbACBgBI2AEjIARMAJG4BQQ+JdTMCLbwO43O+Z65j3X38U8pw1w+O+C01/C/xTsZ0zoZMQxxsCx5R/DZss0AkbACBgBI2AEjIARMAJGwAj0EDhJx79ntOuNgBEwAkbACBgBI2AEjIARMAJGwAgYgTEEdhx/djzjH8+M30aY3y0w7Y6ved59X7vPfdd3pH23if++/WY+I2AEjIARMAJGwAgYASNgBIyAESgjsOP4Q8Lb5nUknbe38zI3hew0Usez3wqqp4w0f0vqWWgQH3EOlHHUuyYf+ihDdFlOKR9pefO97IhHy6U/6oiPI+iIvHiJYxC/dJEnrYCsyEt6iXzk0CdRhhZvpBOaWvtiu5BRCi0aeHr9U5IZy2r2Rxq1BX0RP2gyf+Qr1QufTEdeemIflOhcZgSMgBEwAkbACBgBI2AEjIAROHUEeLnf/Dc5Ui8mx22bn5yiF5Pzs83n+snJulafaWKedMyjN+cpwwbKZZfiHj+2YrPoyZfkqL4Ul+wRnfRPjuCsA11KQxPT5KkHo8wfMY76Ylo8Me7JRxcyMl2U0dMBbQ3/3B7pk3xkZ/k5L9pSLHk1+3vyxS/Z5ON4UH1LvvqGsQO9ZDm+vEcYB+PgMeAx4DHgMeAx4DHgMeAx4DFw98bAtR3/qRPnMDlAG3b8n3zwpYqGYk4MxE/V8em6GHr1kbaUbvHz1vy//uLK3qW2l/TlMvTrEYT/+//8fpuGTuXief6Hi82DNx4qO8ct+8Hqe+/9YIc+ZnryX3n78fw5xkwXZeybnpzleTw8+/jpVsTTn/9tTjNWFFrtE00tHrG/JV/8ko+tjGEF1ffwmRYLNl//+ulG7RO/YyNgBIyAETACRsAIGAEjYASMwF1E4F+z0RwD33x4WXoX3kAv+3FMCd98eqGiW4lxGqOz+ey/vh62g4UE2jHtbM888PI2/Rha8tF78dlx2v/yW5cLGD2nOdq6NL3Wfvhf+8/vz39RN5hi94h8xj8LMHHxKspy2ggYASNgBIyAETACRsAIGAEjcNcQuLbjz47q5//v7+Z2TEedm+3Ju9lN4ntQiVPOLr/ekbDE6Rc8OKji5wRD7IOefBzWh2/unjCQ3LWxFlS0wLJWXol/rf3wP/nfX23xE45arBiRz/inD8HawQgYASNgBIyAETACRsAIGAEjcA4IXHP8aRSOEs4/u6fxGHd0nHBIcUxPJWAz9r32/tVR+Tf+z/9abF5s41JmdpSff3614/7gR+NOOA51yamOO/g9+X//zdNrfZbbsG/7hO+jdx9vRWpR4lC74yP2b5UXEuIv4Qi56uOYLoiZT1nY+S8h4zIjYASMgBEwAkbACBgBI2AE7iIC1476qxE4eux+cvT5yZtfzc878/w8eRYE2Fnl75R2/TkqzzH5R99eLkiweLHU+Y9tBAvaOPqst/ACH4Lym082147szwTpX7YV3dGplryafNkZH9dARXxkY037wJedcOnPslNzFmdH7G8JFX/GkXHAeFZ9Cx/J5xEL2sp4Er/qHBsBI2AEjIARMAJGwAgYASNgBO4SAi9NxvLm8rMM7OzysjwcVgcjYASMgBEwAkbACBgBI2AEjIARMAL3EYHiUf9zAQKnnyPbDkbACBgBI2AEjIARMAJGwAgYASNgBO4rAtWj/ncREJ45j8fQS2/Fv4vtss1GwAgYASNgBIyAETACRsAIGAEjYAT2ReAkj/pzRJ/nsP1s9b7duo7P+K/Dz9xGwAgYASNgBIyAETACRsAIGIFTQuCsj/qfEtC2xQgYASNgBIyAETACRsAIGAEjYASMwG0gsLPjzxvMY+DTb/ftxXhgwNvz49v0IyZ3PX3q7Tu2fceWf9fHh+03AkbACBgBI2AEjIARMAJG4PwQuOb4R6cXJyl+zi47TTxTz+f8+PQZQfWvvvN48+gnl5/Ui8/Z9+r5fBrfqleIn6EbkQ9NlIFu7MhyJD/G3//k37c2x/KMB3leGig74+MIOiIf+aPuXvv5/nztU3TI7MmHJr/nQIs3I+2L2CEr2k6e0KLpte9SQvn/iH1w5vZFG1v4jcovW+dSI2AEjIARMAJGwAgYASNgBIzA3UaAz/nNf5Pj9mJyLrf5ycl7MTlM23yun5ywa/WZJuZJxzx6c54ybKBcdinu8WMrNouefEmO6ktxyR7RSf/kYM460KU0NDFNnnowyvwR46gvpsUT4558dCEj00UZPR3Q1vDP7ZE+yUd2lp/zoq3FLfqsj3zs7xav9I3QiNbx5X3BOBgHjwGPAY8BjwGPAY8BjwGPAY+Buz0Gqs/4T87fvKv95IMvpz4eD3GHHC52nGPo1UfaUrrFz+7+X39xZe9S20v6chn6v/3tt3Mxj0EoTUFMk+dTgpyIiKFlP1hxmqAWevJfefvxfEIj09XkLSmfFhPm8fDs46dbtqc//9ucZqwotNonmn1jtU/82KKTF5T18BOfYyNgBIyAETACRsAIGAEjYASMwH1C4Nrn/Hib/ubDSwjiMepTBwXHlPDNpxe3auq0A73jjPK4wWhgIYF2TLvSM0t8TEIyWvJxgi8+O077X37rcgHjGIsKalsvpn18rjF+shEeMMOuEfx6OlxvBIyAETACRsAIGAEjYASMgBE4NwSuOf7s2OI886z5dJR6o13dUsPzbnaJ5j6V4ZSzy68XIvJc+dKAA6sFFxYAnv/yYtsHPfnseD988+HmYvOPpWq79FpQkZPdZTgCAe37+2+ebvEoqWjhV6J3mREwAkbACBgBI2AEjIARMAJG4NwRKB71x3nipXXsrMZj3HIsAYVFAb3A7xRAwmbse+39q6Py+UV5I3bGNo7QRxp2pJ9/frXj/uBHu8f8I21O41Dzl0Pcwe/JxynOfZbl7ds+4fvo3cdbkYwBwiG/gNCyT+0r4TSCH7a25FPvYASMgBEwAkbACBgBI2AEjIARODcEru34q4E4euz+c/T/yZtfzbusPD9PHueSt/3zd0q7/uy0s0v+6NvLLwqweLHU+Y9tBIv4VQNhU4uFl46iK7/5ZLP98kGNl/JsK7qjUy15Nfk6nREf10CuThCQXtM+8OXUgfRn2eTXhpZ9al/GiX4m5PKMHzQt+dQ7GAEjYASMgBEwAkbACBgBI2AEzg2Bnc/5nVvjOK3Ay/J09P7c2uf2GAEjYASMgBEwAkbACBgBI2AEjIAR6CFQPOrfY7or9Tj9PHPvYASMgBEwAkbACBgBI2AEjIARMAJG4L4iUD3qfxcB4ZnzeAy99Fb8u9gu22wEjIARMAJGwAgYASNgBIyAETACRmBfBM76qP++oPCIAM/J8+w47zpwOE8EeCEg7wWI70BY0tK1/Et0mdYIGAEjYASMgBEwAkbACBgBI7AvAmd91H9fUMxnBIyAETACRsAIGAEjYASMgBEwAkbgXBDYOv68rZ034pf+qDuXQPviJwpL7eJN+uwC38Zu/4h9JZtHy44tf9QO0xkBI2AEjIARMAJGwAgYASNgBIzAzSBQPOr//U/+fdb+1X98sWMFTiOflOOleXxTnhCPw+uIfGSKx6jF/+o7jzePfnL5yb34HL6OTkf+JfLhy8/589123upPm6Qzyqc9+mQeCxxqFzTRdvG0aHrtk4xSPGIffLl90cYWfqPyS7aprCUfGrVfeGIrn3uM4yjbr/6RjqX1sf3IyPy5PvYfn/vjnRCRZi2/2uHYCBgBI2AEjIARMAJGwAgYASNwSgi8mIzZ+ZucxBf85fLJsXvB3+QAznWTE7VNQ6ty8VE/OVJbOeKfFgh2ypSnXmnJiHFPPrqifZFX6Z4O6LABOvEozu2RPtXDk+XnvGhrcYs+6yOPTZLV4l1CI9oc9+TneuyL40j2536UntH6SB/bL/5aPbZEevLYHOlzPtPnfKSXHMe79xPjYTw8BjwGPAY8BjwGPAY8BjwGPAZudwxsj/pPHTEU2CHXEXh20pWGOabJ8yk9dnxjiDvslLPjq0Ca0wS10JP/ytuPN+ziZrqavCXlk7M6nwZ49vHTLdvTn/9tTk8LBduyVvu2RHsm1D6xY0s8odDDT3z7xmvly/5a/4zWy/7cfvHX6jnx8ddffKnqzZMPrtIUruXfCnbCCBgBI2AEjIARMAJGwAgYASNwQggc/HN+047ojjPKUf7RwEICDva0izqzxMcAJKMlHyf44rMLkR40fvmtywWMmtN6UGUVYbSPo+nxk4WQghl2jeBXET1UvFZ+r39G6lvtb+GjBn7zaX18rOWXDsdGwAgYASNgBIyAETACRsAIGIFTQuCgjj9OObv8OIiE6Sj14rbiwOqZaxYAnv/yYqOd9Z58dqQfvvlwc7H5x2K9PQY5jHKye/THqKd9f//N0y0eJR0t/Er0S8uWyM+nPXr9M1Lfan8LH/qtF9by9+S73ggYASNgBIyAETACRsAIGAEjcBsILD7q3zKSHdPnn1/tqD740e4x/xYvjlnJOYs7+D35OIXsCMej91mnnMtc3svj8ML76N3HW9LpmfI5rZfZbStWJFr2qX0lnEbww6yW/JbZI/KjbLDJL1OU/bX+Ga0vtR/bxV+qV/+99v7VoyRv/J//tdPktfw7wpwxAkbACBgBI2AEjIARMAJGwAicCAIH3fHn+fb/8eH/3B5FV37zyWbnze61tmdHjOf1o1MteTrqrrzk62QANmw+vNKiEwSU8Ix3tBEd4rviKKc4ycCpA+mHKsoucy0rbdknOzNOfPmAkMszftC05FPfCj35UTa6+Yu7/rK/1j+j9dkOfflB/LV6+o9TJI++vfyiBHyRdi1/CzvXGQEjYASMgBEwAkbACBgBI2AEbguB4uf8bssY6zUCRsAIGAEjYASMgBEwAkbACBgBI2AEDovAQY/6H9Y0SzMCRsAIGAEjYASMgBEwAkbACBgBI2AE1iJgx38tguY3AkbACBgBI2AEjIARMAJGwAgYASNwwgicpOPPy994Frv0krYTxvJsTDP+Z9OVbogRMAJGwAgYASNgBIyAETACRmBzko6/+8UIGAEjYASMgBEwAkbACBgBI2AEjIAROAwCOy/3Y5c9Bj7PxpvQ71MAA74WEL8mcE7tP/f2nVNfuS1GwAgYASNgBIyAETACRsAIGIFDIHDN8Y9OL05i/Nxddhr5Vjufa/vqP76YbVH9q+883n7D/dl/fT1cz6fy/u31B9t25U/l9eTDGGWgm2/JZzlbBSHx/U/+fWtzKN5ZBJD+7733g62d+pQcPByRnz9VFwRE3eKv4cOjDfHzcohZIh96+iR+blCLNyPti9ghK9pOntCi6bXvUoL/GwEjYASMgBEwAkbACBgBI2AEjMBNI/BiUjj/TY7bi8l53eYnJ+/F5DBu87l+cjKv1WeamCcd8+jNecqwgXLZpbjHj63YLHryJTmqL8Ule0Qn/ZODPutAl9LQxDR56sEo80eMo76YFk+Me/LRhYxMF2X0dEBbwz+3R/okH9lZfs6L1vHlNWccjIPHgMeAx4DHgMeAx4DHgMeAx4DHwLHHQPUZ/8n5m3e1n3zw5WTDeIgnBuBixzmGXn2kLaVb/Ozu//UXV/Yutb2kL5eh/9vffjsX8xiE0hTENPnnf7iYT0SQVmjZD1acJqiFnvxX3n48n9DIdDV5S8qnxYR5PDz7+OmW7enP/zanGSsKrfaJxrERMAJGwAgYASNgBIyAETACRsAI3BwC/5pVzUfVP7wsLR31zvSnkscxJXzz6cWtmjTtim8fA8AQHjcYDSwk0I5pl3xmiY9JSEZLPo9JXHx2nPa//NbD2YRjLCqobY6NgBEwAkbACBgBI2AEjIARMAJG4PAIXNvxZ8eW58oJ01Hupkae73e4QgCnnF1+Fkz4W+L0SwqOtfg5wRD7oCefEwMP3zxOn2hBRQssstexETACRsAIGAEjYASMgBEwAkbACJw2Atccf8zF+cT55yVx8Rh3dCxxSHFMTyVgM/a99v7VUfn8orwRW2MbR+gjDTvuzz+/2nF/8KNxJxyHuuRUxx38nvy//+bptT6L9pHet33C99G7j7citShxrl9A2DbUCSNgBIyAETACRsAIGAEjYASMwB1GoOj40x4cPXb/OfovB4/n51kM0FF03vh/SoGj8ixGYB9/OrmwxMbYRmSo7SMywEv4wIss7OGN+iOBhQrZTgy+0anuyeeZe3josygn6l7TPvDlPQKSTVvv0uMgEQenjYARMAJGwAgYASNgBIyAETAC9wWBnc/5nVujOa3Ay/JwWB2MgBEwAkbACBgBI2AEjIARMAJGwAjcRwSqO/7nAAZOP8/cOxgBI2AEjIARMAJGwAgYASNgBIyAEbivCFx7q/9dBoJj+Rw/Vyi9FV91jo2AETACRsAIGAEjYASMgBEwAkbACNwHBE7+qD8vvONTcvFZ96Udw4KAvjk/yqsX7fGuA4fzQCB/CpF3QLh/z6Nvz6kVPKLEezpuenz6+jinUeS2GAEjYASMgBEwAsdCgPe3ff3rp6v802PZ1pJ7a0f9mdzykrjey/N4izyTYDnirca06pjU9kL8ggG0+asAsrknx/WniQDveuBlhPu89HGkRdwE9OLDkbFdkhlljL4UMspZy68xnq8FdMS2Kb3ExmhbDZ9IU5Ldsk91LdtEU2ofbezp79Ujg3sVNtR0QHOKoXd9CNcYl/poTdsivugp3fej/pH7eranx39X+y+303kjYASMgBEwAkZgDIHe/DBK0dwkbkov4Y+ybiP9YlJ6sL9p4vZimlh1/6BD7wRUU/c0sSvWw4eeCfxr9SWZJbqSbGRSDr1sFD7InRYqtvqoL8kV/X2Mwa+E/ygWa/lH9NBntbEzwl+jie2WjlhW41M5YyuOSdJxvImuFq/hhxdMdP2O2I19I3SyN9KW8GnZv499tAc+9I/wt/RLxkj/QHOscXwsueojYvUNcSzP6aX9n/lzPuNPPt6DZVccR1lGKz/Kf8z+a9nnusPNQ4ylsfQY8BjwGPAYGBkDI/PDLCf6f/vwZ3k3nL+ZgREnzLUGyulgcqs/Aaq8Yk0IqY/yavSazImfGNrML1lMEtFR4pMMJqA1fsm5jVg2L9VNu2hT7AfhLFkZX5VHHuEjeaJpxaP8apt0ZJm9eujlABBHfpVLNnGmifS9NLYsGR8ZL/qCsp4e1a/lr8lReYwPMfYzPqP2Z7poV0xn+aqr8efyjH+vHvn0N3/ohl86FVOOHP405kt11KucWLTiVVzSEflyunb9RjpdB62xv7T/JTNeD7JFusnTzlqeulgvutF4hB8b+Kv136gu093MvMI4G2ePAY8BjwGPgUONAeZWvXkV85naXGSE/1C2rpBznAHD5CkaxUQq5ntpgM08OV+SkTtsZLIX5cCvSXXu2KWT3Sj3JtPgRBuW6lS7I4ZxENOnUa4myFFPpI/lo+kWP+2K4yrb06uXDXJCiFVG3NId6UbTS+TJpihbZdnOSKO0aJUnVtkIf+QbsRuayLNPOuqRrVGOyrL9kS/Sx7R4Y5nSJf4SvcqIlZYMYpURK697FHG8jqjnfqJ65Us46h4ETf4r2Z5pavl8vZSuX3hzu0rySnaX6GKZ5NI+pYWd6JCrNkasqBemoiHO/JJTinv8yJJO0ZbkuOz6uDQmxsRjwGPAY8Bj4K6PAc0/Wu1gLlebe4zwt2TfRN3RnvHn7frTBG9qQzlMwBWf34Qavh9+9PqGZ06Xhvi8BbyPfvLq5qv/+KIoJtswddjm1Xce7zwHPnXu9tlm3jVAu6DTH/WnFvSs7j52/fn/+9POiyr++cfnWzGvvP148+R/f7XNP/v46ebfXn+wzR8zAc7oQqeCXtjIeOnVi6cV01Y+AXmIMDkOM1Z5PNZk8wLLHPTiwVJdpi3RLOHP8lr5yWHcME7WhIzPoeznmuba5P0cS97l0NPfqwcL7ll/+ekfq7BwL/rrL77c1j/54Cq9LTxi4lDX7779z3jk/sF9FKxIa4yq2brfQJMD1z/lvKeDP/jze1gyT8z3+Hv9F2U5bQSMgBEwAkbACNwvBOTz5bnLXULhaJ/zYwIXnR4mXUzIFXAcXnv/B0WnnMkd9Uww4+f54I0yyMc3X+NMoCcGJoeZR/XZBiaTOdC5fBbw+ecXi78MkGXd9TzY0h+5T7gQRi4CnDKcnxhGP7kox6ump1cfddbSLJjQFo2XbNuo/YzDv//m6aLx8s2nF9fM0g1GdS39oolCMn+s2zeNTBzIpz9fvignnSV8DmU/i3xfbS4X+uhHrn8tEEl/Kd5Hf8SXexV9Xhufkbak/ybK1l6/2Li2/+kLxg8h9wvjO143jBP+4gIw/akAP/cibKrhLlrFNX5eItvqP/E7NgJGwAgYASNgBO4nAvitN71pc2ikj+b4Z0NZCIgTOOrjwgB5dm5x+nG4CEzs4uQwTwJnovAvy4c+ymCCmE8SRBugzwsHj769dFRxWLPDi+pSu4JJZ5WkrXFivrRx0SlbyivHrDbJ79WP6sOB0AIQjuPzX14t+IzYzxhiVzeOqxHdcly4BsSbFzNa+kf4R+zo0XDTi7vWPfpcX8PnGPbj5D144/pJimwT+VH9tf555aPH870j3iO4lz15c2zhoWTTocvWXr/Ys7b/WSB5/oeLeQEQR58xrcA9lk/jKHB6gh19XfPYvya0+FmM0MKIdJxa/8kux0bACBgBI2AEjMDNIsBc5P9v72xWLDmuBHw1MlYXGFrdMDSWYCRGLZnGAu8NfgAhgTZ+AS0E3hmMVnoArYxAuwYv9ALaCMboAQSzH7BoJLcGS6A2zUC1GwaqLWh68suac+tUVGRmZN2fqnvrC6jOyIg4J058EXk7T0RkJiHuF7db+/pq29hW/7kmckMd2+znytbKc1NZbrud2srJxEFsI42tpNwsRpzdBcRjCzGORTnZULNl22k4V7Fqvc66cfpjhW1IL7wO7rQ5WzUdQ/JcaOSxMhcBJ4KAozyVHzJDRy7ouKhzmaN7Z1fic36OM+YI4bjnvIjTL0N9w3jKjxoQzyuUoWPo2CI/Vv+Q3kiHz7XXD87dvik+LfaHLS1Hxio7dVrDVP1j+eVvB2OVHUUxcRnjE8c5wpxt6iEzdH1E/lj/tly/oad2XLX/+Y2nT3D2+Q3F0SctAm3j/4AIca3Hf7JMOOXfH65/ZCI/5IaOY/JT/Tek03QJSEACEpCABPafwD6s9tNLW1vxnxoSOEtjDtOUfJnPzWVtBb/lJpEb3LgpDyefG3j0sVqF88MEwFUL4cQEm2g/jIIrN9eslHGDTsBZCrkoP3Yck+fmnD4I3ejJ/TCVP1YveWW7sH3OmIzHGLJjP6f9cGKFOuTZ+TKH3SryOFGZK324uHt6RwuOGOP/vGGKz5j9LfaVZTK/Mq/WvrH6afNU/hQXxid9G7uIuG7KMTelY+z6mJLFfkJZZ75+x3Ss0v/8psKcyRACvxdcG33a4vi9IiUfyuXrm2uRHRTZ/pxP+bGwqvyYbvMkIAEJSEACEtg9Ai33h9zDEMLXya1skc/lLzr+XGcAb45eS6g52lOKWbHhhi8HVgbZ8lk6XejPZTmf2noeTnzcIIZTRX3lDW90XtiEHTzLQUdHnF0DbAktZbP9xiUgAQlMEWC1m10d+TdtSsb8OoH8u14rEb//tTzTJCABCUhAAhKQwBCB8AFrjv+QzGVNX+uK/zpvYNny2a/KJXI42/kGj/PYDkqxcNyTSL8VNN/05Ti6woGP2ZyczwplrFKyUkWHRxvzJEfoyPUal4AEJDBGAKd/lR0UY7qvWl7+3b5qbbe9EpCABCQgAQlshkA8krgPTj+E1rrivxnkapWABCSw+wTKicnyqxG730JbIAEJSEACEpCABCRwWQls3fFnZX3bsybccMfzrZe1I7Rr8wTyLg1qc6fG5plbw3wCzC6z22nb49PrY35fKSEBCUhAAhKQwNUjMPRY+mUnsda3+rN1vvyLLfSA4IaWFzPltBIQIFsDN6qxBWNMhhemzdE7psu83SXAYxpsCcah2kRgjOXxz4TT3JB1nGfMrirP9UQbatdVblvE59iYbUO+xieXqekesy/yxmyLMrX20VdT9U/lo4PfN2wYqoMylzFMXR/BNR9rfbRK2zJf6qn9X5Hr5/+AuWFKflf7by4Hy0tAAhKQgAQkcExg6v4wc4p7k/wuujnyWddFxHm539r+Ohi9Lo7dTdwpvd1NWn/e3fCfSs/1I9fdmD3j2EHs45zX/igzpiv0Yge64tzj+vq7ZEk/rcJ6VfnSntp5HmO1/POm5XZHHTltSi9jOa4RyhJvGd+hdxV5ZGHPtdLaB9g3p325bI3PmP3nsY92IAefFvmx+kNHS/9QppVh9F3rcVN6c/3RNxxzehmf2/+lfHle8uc8/x8SduVxVOoYO2+V32T/jdln3ub+X5KtbB0DjgHHgGOgNgZa7g9LOe5N4h7pPPKlvi2fr3cgxM0gN2fAiMZkSGVelJk6AjnfCNbKx00bN8gtf9FxNV27mhYM5tofTgWMg13JOwZ45EcdWSbyQl+UGTu2ykfboo5S51Q+5cMBKPs+0kM3x7JMWd/YObbka2CsLHklL64T0qbkIn9V+SE9kZ6P572Gs46ST6v9ZbmsM8dL/ZE3JF+ml/yn8tFPf/NH3chHnXEkHT38xZiv5ZEf6RyjbMjGsVZHlivjQ9dvLhfXwdjYn9v/oTNfD2FL1M057Rw6Jy/nR7nWY4s8NvA31H+tdVluvfcV8pSnY8Ax4BhwDGx6DHBvNXVfxf3M0L1Ii/ym29Cgf70DiRsmKuXmKeDleBhEGoDifOiYbz7HYId81B/nHOmgsCXSW3RF2V07hnMx1+6aM5EHcdlnnJe8c/m59VN+TJ66qDP0lvZM5YccfU89eWxN1R2yc45jbSn1hE05PdJKO3OZiEfZOOcYaS3yWa7FbspkmfPEcz1ha9YTaaX9WS6Xz/GQzWkRr8nXykcax4iHDo6RxjHO43rgWP7m8DsU+ZTnvMYRuVo6MjXbSW/5K6+X2vWLnrJdNd1D9tXKRlropX0RD3ZRBr3RxsyK/GAaZTiW8qGndpySR1fUGWVrekxrG29ykpNjwDHgGHAM7NIYiPuPMZu5dxu692iRH9O9jby1PuPfgTj1eaofvzrqn+PlGXteVtUBWf7d+v1Li4efPOjPkeMv53MegfRayGVq+Vc1LZ7VPU/7+Wxhfmbln/efLNW8+PbNvs8i4fFnh4sXbl+L040e6Wvqos4I8cLGzpHox89YfsiMHWkrn1hbR+gch55VZjmm96e/PDiTHS/BrOWVhWtl5siX+sbOO4dxwThZJZR81mV/94Pc/47wLpE573KYqn8qHxavfHp78d179wex8GnQv//xh2X+w49O4svEDUbWdf2et/8Zj/zm838BrIjHGI1mx+9N+SlX8rm+Sec9HfwhTz+3hin5qf5rrcdyEpCABCQgAQnsH4HwO8t7l11q6U/WaeytD1/uv3t//emNXi3OPTdyOKIPFt/3L7vKjhAOW/7+MnGgoidD5bNXEbh5Dv3o/sefD31jf8DZ8JEbZ/qUvxzos9xfOS/HccrovxxaP2kWjtdQPVP5uc6hOOOUtsREU2lbq/04tXPHJZNkZYgfmMgbqz/KZB2lfM47bxydOJCHf/j6vCoWNT7rsv/BO9/3vzUYRz/iHMYE0ZjB56k/88UZps+HxmcuO2bHJvNWvX6xbdX+py8YP4SyXxjf+bphnPDHdRmB/oyAPL9F2DTEPcrGcUj++m9vjvZfyHuUgAQkIAEJSOBqEsA/3faizbpJr9XxzzfdGMrN8NG941V/btIO7nSrmu8v+hVlnH5Wb7756i/NN23oLJ0x0soQjltO7x3OuznlWNfpFM/GCKw60VKOj7G6yrxwzIZu8qfyS31D5zgQMRnFOHry8dHSQWmxH0eFVd08wTVUV04Px4XrImTLyYyx+lvkc33njfOjl1et5+oZ4rMJ+3Hy2G3UElrrH+qfFz+92a9I50kxft8e3mmbeGixcdUyq16/1L9q//N/wpO/HvUTgDj6jOkI/EY/+vxkRw+7J+IrMPQP9q8SxuSZjIiJkajjsvVf2OVRAhKQgAQkIIHtEogFnLhf3G7t66ttrVv9w6xYqeGmG4eM7dnc5OH8czNFuPHuzcnvVAfk0NtyjG3uOG/xx2QBW5PjPI75prNF966UgX9t8mNV+1mNixW2IV3cXPcTPEMFJtKH5OPGn5W5CDgRBBzlqfyQGToy1mrjjYmr1sAYJ4TjXpOjX4b6Bkc1P2pAPK9Q1vTltBb5sfqzrlocPtdePzh3+6b4tNhfs2sojbH65Jv2/puqfyy//N1hHPObE6vaMT5xnCPM2aYeMkPXR+SP9W/L9Rt6asdV+59JE/qE310ew8DRJy0CbeP/hQhxrcd/skw45d8frn9kIj/kho5j8lP9N6TTdAlIQAISkIAE9p/APqz200trW/HnBi6cem7quBnDAY2bMm7y2O7PjVqEyIvzfAwnYde3VOQ27Xo8nJjSYYn+pn3cXDMOuEEn4CyFXJ8w8c+YPDfnjKnQjSomcSJM5Ue5oWPZLmwfc+JLPf2uki4xO/Zz2g8nJstCngmrOexWkceJylz7a7nbIcP1ClcCjhirtecNU3zG7G+xryyT+ZV5tfaN1U+bp/KnuMCRvo1HlbhuyjE3pWPs+piSxX5CWWe+fsd0rNL/TBrAPN4NwW8/10aftjh+r0jJB1vy9c21yA6KbH/OH7OdvFXlp/SbLwEJSEACEpDAbhFouT+MhcGa39oif5mIPNcZwxuh1x6AxMuSwmnIFTBJwE6AGkDkuLHjBpEbNc6ZZWGVKMdDH2k1PZHPkUkEtpDOceKyvHEJSEAC6ybA7yC7Omq/keuua9/1xWTZUDvnTBAM6TBdAhKQgAQkIIGrRwA/koXoKX9zF8isbcU/GsuKLM9KErjZKmdColw+5hUnoCLHTTE3c6w4sspVxkOefJ4F3YfOiDZ5lIAE9p8ATv8qOyj2n1B7C3Xs21lZUgISkIAEJCCBNgL4o4R98TM3tuLfhtNSEpCABK4GgXIStOVFpVeDjK2UgAQkIAEJSEACEtg0AR3/TRNWvwQkIAEJSEACEpCABCQgAQlI4AIJbOSt/hfYHquWgAQkIAEJSEACEpCABCQgAQlIIBHQ8U8wjEpAAhKQgAQkIAEJSEACEpCABPaNgI7/vvWo7ZGABCQgAQlIQAISkIAEJCABCSQCOv4JhlEJSEACEpCABCQgAQlIQAISkMC+EdDx37cetT0SkIAEJCABCUhAAhKQgAQkIIFEQMc/wTAqAQlIQAISkIAEJCABCUhAAhLYNwI6/vvWo7ZHAhKQgAQkIAEJSEACEpCABCSQCOj4JxhGJSABCUhAAhKQgAQkIAEJSEAC+0ZAx3/fetT2SEACEpCABCQgAQlIQAISkIAEEgEd/wTDqAQkIAEJSEACEpCABCQgAQlIYN8I6PjvW4/aHglIQAISkIAEJCABCUhAAhKQQCKg459gGJWABCQgAQlIQAISkIAEJCABCewbga04/jc//tfZ3J7/9fML/gwSkIAEJCABCUhAAhKQgAQkIAEJnJ/AT0rRl/7j3xbX37pRJp85/+f9J4v//sXXZ9KHEv79619Mlj94/2eLoz/971LFG1++ubj3/H8tz8l/9e5rp9KWmUYkIAEJSEACEpCABCQgAQlIQAISOEPgjOP/4J3vFw8W358pmBNwwA/uHOSkU/HSgT/8w/8sHn92eKoMJ+VkAE7/nae/WjCp8N179xePv3h0RubhJw+WaUxSPPzoh8XT/3y6TDMiAQlIQAISkIAEJCABCUhAAhKQwAmB57ros5PTtlg4/jj0ZWBb/63fv1Qm9878C7evnUoPJ76mh23+tz58eXHt9YNFKRdK/va7b/sJiFKeCQVk8m6BkPEoAQlIQAISkIAEJCABCUhAAhK4SgTOrPjjcLPF/pvf/OVcK+lH945OOdysyhPYSdASYjs/ZVnxz48T1CYcjhYnjwa06LeMBCQgAQlIQAISkIAEJCABCUjgKhE4s+Ifjv8UBFbry5X2mgxb94dW3sut+pTF2WeSIFb82crPRMRQOO8ExZA+0yUgAQlIQAISkIAEJCABCUhAAvtE4MyKP40L53tuQ2OLfZZjggCHvhbYqs92/tgNUJsg4Pl97HnyzVHTREOtHtMkIAEJSEACEpCABCQgAQlIQAJXlUB1xT8746uAKV/exyr+K5/ePrV9P+uvTRzk/Fp87tcFajpMk4AEJCABCUhAAhKQgAQkIAEJ7CuBf1mlYTxzPxTYxs+b+XPA6S/Tcj7P87PqH3/sFsCx55w42/qJcySQlt8BELqYQBjaZRBlPEpAAhKQgAQkIAEJSEACEpCABK4CgepW/9aG80m/H399VH0JINv3ayv4LZ/ey+8ZCCef9wmg78lfj/o3/TMBYJCABCQgAQlIQAISkIAEJCABCUhgnEDV8b/+1o3F9ac3xiX/P5dP9w054azGhxMfZfJKfPlivvgUYKzyxxcBqCp2ELBrgE/1oXdoEqG2C6CpMRaSgAQkIAEJSEACEpCABCQgAQnsGYEzz/iv0r5w3LOOsWfwmQQI5x9H/vpvb556gV+eJOBFgEd/Ovl0X95NEDpyvcYlIAEJSEACEpCABCQgAQlIQAISWCzW6vgLVAISkIAEJCABCUhAAhKQgAQkIIHLRWCll/tdrqZs3pp4aSA7Efhjl4JBAhLYLQK8lPQirl9/P3ZrnGitBCQgAQlIQAIS2CcCOv4zejO+OhAvHJwhuraivOsgJh6GnJecj7MxN0zJM+FBmbGvOgzVme3P73AYKp/Tsyz182jJ3JB1zK2fulaVD6ezxi5zj/gcG7NtQ3xymZruMfsib8y2KFNrXwu/KfvQscr4Q/6iwtTvR3DNx1ofXZT91isBCUhAAhKQgAQksNsEnnXmX5q/7qb3Wec0nNueVeVbWHSOxzPq4dhSfl1lOkf3WefIL+vkvHMMludh13n5tcpjw3k4l/ajh7RWPrldrbZm3avWv4o8sjCjv1rZwSe3ObelFs9la3zG7D+PfbQDOWxpkR+rP3Tk8T00PkhvZVjjNJa2Kb25zugbjjm9jM/t/1Le88vz/5p9YV84BhwDjgHHgGPAMXDRY2CtK/7dTXO/Cjy2atfd/J9ase4A9CFkOHn17mvLMp0zc1xg4t9W+e5meqkbe8swlV+Wz+fdjfwp3egnrSWELHwiBKs458jnDIfCrQ9fXjz+4tGplyAOla2lt8hj0z/+fLjgpY1zA1+A+Psff1iKESetDNEHZXp+uSNfdMAGPinZGlrrH9K3ijyfo+TLFnzmsiUw7uGc2zwll8vW+IzZP9c+bMljoEV+rH70TeVTZmr8xdjh2su/CcjmvPLaz2XP8/uDfkJcs+gv6zgu0fbvefq/TbOlJCABCUhAAhKQgASuKoHRVacOSnN+d6N7ZiWOtFiJ7G6K+/zQyXl3M35Kfy4f5eYcx+SpizpDX2nPVH7IsVJHPRwjjeNY3bncUDz0wivitTqinpId58iSH3+l/FDdpE/JoyvqjLJj+nJetKeWVtqIbuzPZWvx4FDLK9Pm1F/Kcr6qfNbZYndL+7POWjzXM8f+LFfTS1pNX5StydfKRxrHiIeOXAd5cT42/jrnfTk+Kc95jWNcI7muiNdsj7ypY/l7Uvt9Q0e0NdpV01uzu1bOtPb/n2QlK8eAY8Ax4BhwDDgGrvIYWOuKfwdyUX52L68Kvvj2zcXDTx5QrA+PPztcvHD7Wpxu9NjdZPd1UWcEVikJnSPQr8xjy1B+yIwdaevPP3h5rMhoHqu08GHF8ZVPb/dx0nIInpQpA/aTzsoyf+h648s3y2KD51Py2PTde/cH5ccyfvrLsyvz0bYyL56FHtPXOYB9+/Iq91j5sg7KDtVf07OqfE3nUFrnMPbX0VB+S3rJZ132x8o442rOuy6m6p/Kp81T4+/6WzdO7Sh5+NHJ7pIWZquWWdfv2zr6f9W2KC8BCUhAAhKQgAQksF8E1u74j+HBsWQ7b7ea1f+FU4pT3hLC6Qh5jqS1hHAswtkrZabyy/K1cxxWHOOwr9W2rIvJiHDuY2Ii8tHH9u9w7EnHwcshT6yEfCtf9AzJ44xQ9xC/bEMt/uNXZx9RCLtqeTUdkUabsSXaF+ljx1odZf1j46tFfqz+1jxswoFsndCo6a3xWZf9PKoQ44/rl3HREqbqn8qfGn9lX7bYtO4yq/6+Yc86+n/d7VKfBCQgAQlIQAISkMDuE/jJNpuAQzvXYcv24XQ8WLQ9I53liIdjwY11zXmdyi/1DZ2jG8eIwATAk4+PZjmoODg8x8/qJY5ofiactEefn+xYYJIB5yvaFBMGQ7ZNpY/J44yGYxN62F3w8M6DpvYFc3ZXhFN7nskWnFreDRA6wpapY0v9Y+OrRX7KhpZ83rOQ34PQIpPLDPHZhP1MEl174+xOjmxPxFvrHxofL3662vgLOzZ5XPX3DdtW7f9Ntk/dEpCABCQgAQlIQAK7S2CrK/44/az4x+pcDRs3z3Ne2FbqGJLH8SDv+m9vLkVitRIncip/KTQQoU21dh3dO73SHbsBampweuCDA8o2ahx90iJg/413T+yPtoRTFS/LCztoHzKRH3qGjmPysf0+VnvRy2Mdc1bdcRTzoxDE8w6DsAvnFU5liB0UY07/GN/W+st647xFfqz+0DN0pN+uvX4wOqkxpn+KT4v9Q7bV0hmrT745Pb5r5SJtqv6x/KnxF9cvjnOE2FEU5y1HxvXY788Y/5bftzEbWvp/TN48CUhAAhKQgAQkIAEJDBHY6op/OInlDTlObjinOJ+sJONUEHAGQm6oETl9TB7nAacydCMXq/PEp/IpMxbKdmH7mJOadXHTT7txpgnwQL5PW3zb68E+HI/rT28sRbP91MUKfLYj5y+FBiKryg+oXSbTj6wQ0wYCXyCY07dMhBBCnvic8bFq/avIMwmTxx39urh7/GZ8+pXARM7YVxv6QiP/TPEZs7/FvrJM7r8yr9a+sfpp1lT+SNP7rPL64HclXwtT8uSP/X5MyWM/oawz/76N6Vi1/8d0mycBCUhAAhKQgAQkcLUJPNc1nzdmG/acQHaWa02dM0FQkzdNApeNALtl2FUSEyuXzT7tkYAEJCABCUhAAhKQwLYI6Phvi7T1SEACWyXA7h52UOT3ZGzVACuTgAQkIAEJSEACEpDAJSGw1a3+l6TNmiEBCewhgfJxAx5F0Onfw462SRKQgAQkIAEJSEACswm44j8bmQISkIAEJCABCUhAAhKQgAQkIIHdIbDVt/rvDhYtlYAEJCABCUhAAhKQgAQkIAEJ7AcBHf/96EdbIQEJSEACEpCABCQgAQlIQAISqBLQ8a9iMVECEpCABCQgAQlIQAISkIAEJLAfBHT896MfbYUEJCABCUhAAhKQgAQkIAEJSKBKQMe/isVECUhAAhKQgAQkIAEJSEACEpDAfhDQ8d+PfrQVEpCABCQgAQlIQAISkIAEJCCBKgEd/yoWEyUgAQlIQAISkIAEJCABCUhAAvtBQMd/P/rRVkhAAhKQgAQkIAEJSEACEpCABKoEdPyrWEyUgAQkIAEJSEACEpCABCQgAQnsBwEd//3oR1shAQlIQAISkIAEJCABCUhAAhKoEtDxr2IxUQISkIAEJCABCUhAAhKQgAQksB8EdPz3ox9thQQkIAEJSEACEpCABCQgAQlIoEpg0vF//tfPL/hrDUPl5+horctyEpCABCQgAQlIQAISkIAEJCABCYwTmHT8n/7n08Urn95evPQf/zauKeW+8eWbZyYLbn348hkdTgYkaEYlIAEJSEACEpCABCQgAQlIQAIbIHDG8b/58b+eqea/f/H14uFHP5xJ//evf7E4eP9nZ9L/ef/JggmDMjz6/LBPYhLhztNf9RMKZZk4J3/OZEPIeZSABCQgAQlIQAISkIAEJCABCUjghMBPTqLHsVu/f2nBXxlw5l+4fe1U8sNPHpw6jxPK4bhHQPbJX48Wr959bbG4u1j87XffLh68831kV4/IGCQgAQlIQAISkIAEJCABCUhAAhJYjcApx5/V+3vP/9eoRlb5//Hnw8XhH/5nsBxOO7sEcmD1Hof/6E//u0ymvny+zPj/yJNvjsokzyUgAQlIQAISkIAEJCABCUhAAhKYQeCU4x9OOE769bduVNV885u/LH76y4NqXpmIY88qPw5/Ldx49+bix6+Oqo8FsEPAIAEJSEACEpCABCQgAQlIQAISkMBqBJ7rxJ+dRwWTA9dePzizss8L+3i5H+HxF49Obelna9syagAADKlJREFUt0B+XCAeFajtHuBdA0f3jkZ3BJzHbmUkIAEJSEACEpCABCQgAQlIQAJXicApxz9W6FsAsIrPaj2h9iK/rAMn/sW3b56ZJMhlyji2DO0GKMt6LgEJSEACEpCABCQgAQlIQAISkECdwCnHvyzCqj5v88exxxFna/7YS/nKFf1S39D51HsFhuRMl4AEJCABCUhAAhKQgAQkIAEJSGCcwKln/MuibOWfWs1nQiDeDVC+0C/0xScCa1v6o0w+5scFnBTIZIxLQAISkIAEJCABCUhAAhKQgATmERh0/Fm9/+69+6PacNAP7hwsjhYnb+ofFWjMZLJBh78RlsUkIAEJSEACEpCABCQgAQlIQAIjBJaOf15lpzxv78+r/azq//yDlxd3nv7qjLrWlfwzgiZIQAISkIAEJCABCUhAAhKQgAQksFECo8/4b7RmlUtAAhKQgAQkIAEJSEACEpCABCSwcQL/UtbAyj+r+vHHlv+rGoJFa/thFdw4Im+4OAJl/9k/F9cX1iwBCUhAAhKQgAQkIAEJXByB5Vb/0oTL+ow9ztsLt68tzb1MdsbLDXE43/jyzaWNRi4HgegfrGFiZijwNYtHnx/2n5N85dPbsz5DOaTTdAlIQAISkIAEJCABCUhAAhdF4MyK/0UZEvXikPGlgFog7x9/Puxf/IfD//CTBwucNIME1kmAr1nwTouf/vKgH2/r1K0uCUhAAhKQgAQkIAEJSEAC2yYwy/EPpzxvmS63s+e82qrqUD4OfJR/9e5ryy3zMQnAJwFx9HmRIHHK3vr9S0telEN36IlzymUbh+oPRTn/+m9vRvLyGHWjN+xdZq4Qod747GFWQxp5BOoLHpyTFxMf0d6p9iM3FEJ/ZpDZITfW/pDnGH+lfNZNmRwoG3JxLOVz+Vo866/1X00mp+X6brx7c3F07yhnG5eABCQgAQlIQAISkIAEJLCTBJ51Vi//OsfnWed0Lc9zHun8UYb0zslaxuO8cwyXssSzLsqP5aOD8p0Tu9QR9Udd1E2cdOKdo9vHkQnZqDfyo86p+tEVutHPebY/9IZNnOfykU69yHGMtKlj2F+WizaRnuOcU/+c9pe6y3P0Z7tpW27DVPtDPvSWPKf4l+0LPa3Hsr6y/7Ke3M5ID/vLI+2OMh5PfitkIQvHgGPAMeAYcAw4BhwDjgHHwG6MgVkr/l2nLv72u2+Xn/njmen45F/nIPbP3j/+7JBifYjP/LEaPZUfMkNHnuunLlZx2e5PKFd0/3n/Sb9Fm7zHXzxa2sZ5S/3X37qx+Psff6B4Hx5+dBIn4cW3b/a7Do5zuzq6tub3DUT6eY5sLcf+zslcihPPbVpmDERy2bL9AyJnkof6l4It7Uc+AvzgA/sW/tjPJyPPG6b6b0ovj49gA5+ypB0wJC3G8ZS8+RKQgAQkIAEJSEACEpCABC4jgcGX+801luehCTERUMpP5Zflp85xJK+9cVznVFnyp+pHH+HHr4a3duPE8nhBfsQAGWSH2k1+a2DSgcccwtHE0c4TEa16NlVulfZP8cdmJpJg2a24903A8X7wzvdNzWnpvzFF3e6ABRMHhPxixmtfH/hyvzFw5klAAhKQgAQkIAEJSEACl57A2hz/cJiHnOCp/ClSOIHsHMApxjHEKf7uvfu9k3b96Y1+hXZMx6r1o5vVYHYbhGM+Vt958vpV/w+OV/3j2XLShsKciY8hHXPS57Y/O/s/Lo4nVIbGR9jBBEp8qYF+fvLx0cZ4R50cmWB49P7h4uDOQV9f91iCDn8GZFwCEpCABCQgAQlIQAIS2FkCs7f6D7UUhw3HMG+/j23rOK9T+aEXHThfZWDbOKvhOI44hvGYAfFwFEuZfD5Vf+Tf+vBkq3le+UUXTj+r/bG6nPWvK84KP3Ww5b1c7c9sYBsr1HPqxpmOFfU5cpRtaT8vxItAG5iwIQTfofEB0xrXmAAJnUP2h/6x/gsdQ8d4mV/NjiEZ0yUgAQlIQAISkIAEJCABCVx2Amtb8aehOOOslOat8Nkpn8pHR2x3Dx3xJn8cO569zs74nK3grfbhWLKDgFDWFyv92YYoh33rCLHqj65ytT+zgQt/21z1b21/TCwwUZG36k/1f8mV9pUMxhijf6z/xmTJ4zN+7Axhp0K8R2JKxnwJSEACEpCABCQgAQlIQAKXncBznYG8sXwZWO3EAcsO+zLTyFYI4Lzycrk5Tu9WDJuoZJfsxlYmdtY1YTOBxmwJSEACEpCABCQgAQlIQAIXRmBwxR/HiMCqLSuphu0QmPsm/+1YtR+1sBtlXV9h2A8itkICEpCABCQgAQlIQAISuAoEzjj+rIC62r/9rs9vlZf/Zvg7gbUZrmqVgAQkIAEJSEACEpCABC43gcGt/mH2VV7xn/vYQ7mi7FbyGEUXcyz7z/65mH6wVglIQAISkIAEJCABCUjgYgmcWfEPcy7rqnPpvF0mO2NFORzOYOnxchCI/sGaeJSlZhm7Lx59fti/6O+VT2/7qEsNkmkSkIAEJCABCUhAAhKQwM4QWNvn/NbVYhyyg/d/VlVHHm9bx9nnj7e+46QZJLBOArzdnxcr+nb/dVJVlwQkIAEJSEACEpCABCRwUQRmOf7hlLPqTpw/VrdzyHnkl2EoHwc+yr9697Wl/pgE4KV3OPp8Uo44ZeOTf9RBOXSHnjgvbRyqP+zM+fmb85EfdaM37I28VY7Ui+4ykEYegfqCB+fkxcRHtHeq/cgNhdCfGZT9O9b+kOcYf6V81k2ZHCgbcnEs5XP5Wjzrr/VfTSan5fpuvHtzcXTvKGcbl4AEJCABCUhAAhKQgAQksJME+Jzf8q9zfJ51TtfyPOeRzh9lSO+crGU8zjvHcClLPOui/Fg+OijfObFLHVF/1EXdxEkn3jm6fRyZkI16Iz/qnKofXaEb/Zxn+0Nv2MR5Lh/p1Iscx0ibOob9ZbloE+k5zjn1z2l/qbs8R3+2m7blNky1P+RDb8lzin/ZvtDTeizrK/sv68ntjPSwvzzS7ijj8eS3QhaycAw4BhwDjgHHgGPAMeAYcAzsxhiYteLfdWr/ffn49jnPTEe8cxD7T6U9/uyQYn1gdZ7AavRUfl9w5B8+w0ZdrOKy3Z9QrujyIkK2aBMef/FoaRvnLfVff+vG4u9//IHifXj40UmchBffvtnvOjjO7ero2rquz8NhN/Z3Tmao7+O5TcuMgUguW7Z/QORM8t9+9+2SW+5fCra0H/kI8IMP7Fv4Y//PP3g5xGcfp/pvSiGPj2ADL2WkHTAkLcbxlLz5EpCABCQgAQlIQAISkIAELiOBwZf7zTWW56EJMRFQyk/ll+WnznEkr71xXOdUWfKn6kcf4cevhrd248TyeEF+xAAZZIfaTX5rYNKBxxzC0cTRzhMRrXo2VW6V9k/xx2YmGmDZrbj3TcDxfvDO903Naem/MUXd7oAFEweEN758c1n02tcHvtxvScOIBCQgAQlIQAISkIAEJLCLBNbm+IfDPOQET+VPwcMJZOcATjGOIU7xd+/d7520609v9Cu0YzpWrR/drAaz2yAc87H6zpPXr/p/cLzqH8+Wxw6Gmr45Ex81+blpc9ufnf0fF8cTKkPjI2xhAoVVdgL9/OTjo43xjjo5MsHw6P3DxcGdg76+7rEEHf4MyLgEJCABCUhAAhKQgAQksLMEZm/1H2opDhuOYd5+H9vWcV6n8kMvOnC+ysC2cVbDcRxxDGMbOvFwFEuZfD5Vf+Tf+vBkq3le+UUXTj+r/bG6nPWvK84KP3Ww5b1c7c9sYBsr1HPqxpmOFfU5cpRtaT8vxItAG5iwIQTfofEB0xrXmAAJnUP2h/6x/gsdQ8d4mV/NjiEZ0yUgAQlIQAISkIAEJCABCVx2Amtb8aehOOOslOat8Nkpn8pHR2x3Dx3xJn8cO569zs74nK3grfbhWLKDgFDWFyv92YYoh33rCLHqj65ytT+zgQt/21z1b21/TCwwUZG36k/1f8mV9pUMxhijf6z/xmTJ4zN+7Axhp0K8R2JKxnwJSEACEpCABCQgAQlIQAKXncBznYG8sXwZWO3EAcsO+zLTyFYI4Lzycrk5Tu9WDJuoZJfsxlYmdtY1YTOBxmwJSEACEpCABCQgAQlIQAIXRmBwxR/HiMCqLSuphu0QYAs/zHfN6d8OndVqYTfKur7CsJolSktAAhKQgAQkIAEJSEACEtgegTOOPyugrvZvrwOipvxWefkHlfUencBaL0+1SUACEpCABCQgAQlIQAK7QWBwq3+Yf5VX/Oc+9lCuKLuVPEbRxRzL/ttk/8QOmaGWOpkzRMZ0CUhAAhKQgAQkIAEJSGDTBP4PB7kFVB7gXQwAAAAASUVORK5CYII=)\n\u003c/div\u003e","title":"vm虚拟机 配置静态ip地址（centos）"},{"content":"这个画廊的效果利用到了View的clipChildren属性，我们在这里要把ViewPager以及它的父窗体都设置为false，如下:\nAndroid:clipChildren=”false”\n因为如果clipChildren属性设置为true,就表明我们要将children给clip掉，就是说对于子元素来说，超出当前view的部分都会被切掉，那我们在这里把它设置成false，就表明超出view的部分，不要切掉，依然显示。\nxml代码部分：\n\u0026lt;LinearLayout\nandroid:id=”@+id/container”\nandroid:layout_width=”match_parent”\nandroid:layout_height=”100dp”\nandroid:clipChildren=”false”\nandroid:gravity=”center_horizontal”\nandroid:layerType=”software”\nandroid:orientation=”horizontal” \u0026gt;\n\u0026lt;android.support.v4.view.ViewPager\nandroid:id=”@+id/viewpager”\nandroid:layout_width=”match_parent”\nandroid:layout_height=”match_parent”\nandroid:layout_marginLeft=”110dp”\nandroid:layout_marginRight=”110dp”\nandroid:clipChildren=”false” \u0026gt;\n\u0026lt;/android.support.v4.view.ViewPager\u0026gt;\nJava代码部分：\n// 1.设置幕后item的缓存数目\nmViewPager.setOffscreenPageLimit(3);\n// 2.设置页与页之间的间距\nmViewPager.setPageMargin(10);\n// 3.将父类的touch事件分发至viewPgaer，否则只能滑动中间的一个view对象\ncontainer.setOnTouchListener(new View.OnTouchListener() {\n@Override\npublic boolean onTouch(View v, MotionEvent event) {\nreturn mViewPager.dispatchTouchEvent(event);\n}\n});\n参考效果图（上面代码并不能实现效果图，仅供参考）：\n正常情况下, ViewPager 一页只能显示一项数据, 但是如果需求是, 除了小显示本页数据, 还有包 左右两半的数据 也都露出一点来呢? 这该怎么处理? 后面在网上了搜了一下, 发现有不少这样得到文章, 这里自己也写一篇总结一下. 其实 主要就是用到 View 的 android:clipChildren 属性. 简单来说这个属性, 就是 父View 是否 束缚 子View 的显示范围. 如果 父View 有 padding , 那么 子View 则在 padding区域是不能显示内容的, 但是如果 设置 android:clipChildren 为 false 时, 则子View 就可以在 父View 的padding屈戌显示内容了. ok 基本了解了 android:clipChildren 那么来处理一下 ViewPager吧 先看一下我做的demo:\n基本就是上面那样, 除了可以显示 当先项的内容, 还可以显示 左右两边的内容. 下面贴一下主要代码: 布局文件: **[html]** [view plain](http://blog.csdn.net/chen930724/article/details/50464069#)\u0026lt;span data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/chen930724/article/details/50464069#)\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/view_pager_box\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;360dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;30dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:clipChildren\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;android.support.v4.view.ViewPager\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/view_pager\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:clipChildren\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 可以在看到 外层的 RelativeLayout 设置了android:clipChildren 为false ViewPager 同样页设置了 android:clipChildren 为false 需要两个都设置, 不然会出问题 activity 相关代码 **[java]** [view plain](http://blog.csdn.net/chen930724/article/details/50464069#)\u0026lt;span data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/chen930724/article/details/50464069#)\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; AppCompatActivity { - - ViewPager mViewPager; - RelativeLayout mViewPagerBox; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ViewPagerAdapter1 mViewPagerAdapter1; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - mViewPager = (ViewPager) findViewById(R.id.view_pager); - mViewPagerBox = (RelativeLayout) findViewById(R.id.view_pager_box); - - mViewPager.setOffscreenPageLimit(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;); - - mViewPagerAdapter1 = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewPagerAdapter1(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - mViewPager.setAdapter(mViewPagerAdapter1); - - mViewPagerBox.setOnTouchListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; View.OnTouchListener() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mViewPager.dispatchTouchEvent(event); - } - }); - - } - } 可以看到 和使用普通的 Viewpager 没有任何的区别, 需要注意的是, 为了能够滑动 左右漏出的两边时, 也能滑动 ViewPager 需要吧 Viewpager 的 父View收到的事件 传递给 viewpager 我们在使用Viewpager 的时候, 经常 会加入一些好看的滑动效果这个是怎么实现的呢? 其实很简单, google 以及为我提供了相应的方法. 通过 setPageTransformer 就可以设置 Viewpager的滑动效果. Android 官方文档 已经提供了两种 滑动效果: [http://developer.android.com/intl/zh-cn/training/animation/screen-slide.html](http://developer.android.com/intl/zh-cn/training/animation/screen-slide.html) ZoomOutPageTransformer: ![](http://img.blog.csdn.net/20160106001346888) ","permalink":"https://blog.zdltech.com/posts/android-%E4%BD%BF%E7%94%A8viewpager%E5%AE%9E%E7%8E%B0%E7%B1%BB%E4%BC%BCgallery%E7%94%BB%E5%BB%8A%E7%9A%84%E6%95%88%E6%9E%9C%E7%94%BB%E5%BB%8A%E6%95%88%E6%9E%9C%E4%B9%8Bviewpager%E6%98%BE%E7%A4%BA/","summary":"\u003cp\u003e这个画廊的效果利用到了View的clipChildren属性，我们在这里要把ViewPager以及它的父窗体都设置为false，如下:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://lib.csdn.net/base/android\"\u003eAndroid\u003c/a\u003e:clipChildren=”false”\u003c/p\u003e\n\u003cp\u003e因为如果clipChildren属性设置为true,就表明我们要将children给clip掉，就是说对于子元素来说，超出当前view的部分都会被切掉，那我们在这里把它设置成false，就表明超出view的部分，不要切掉，依然显示。\u003c/p\u003e\n\u003cp\u003exml代码部分：\u003c/p\u003e\n\u003cp\u003e\u0026lt;LinearLayout\u003cbr\u003e\n\u003ca href=\"http://lib.csdn.net/base/android\"\u003eandroid\u003c/a\u003e:id=”@+id/container”\u003cbr\u003e\nandroid:layout_width=”match_parent”\u003cbr\u003e\nandroid:layout_height=”100dp”\u003cbr\u003e\nandroid:clipChildren=”false”\u003cbr\u003e\nandroid:gravity=”center_horizontal”\u003cbr\u003e\nandroid:layerType=”software”\u003cbr\u003e\nandroid:orientation=”horizontal” \u0026gt;\u003c/p\u003e\n\u003cp\u003e\u0026lt;android.support.v4.view.ViewPager\u003cbr\u003e\nandroid:id=”@+id/viewpager”\u003cbr\u003e\nandroid:layout_width=”match_parent”\u003cbr\u003e\nandroid:layout_height=”match_parent”\u003cbr\u003e\nandroid:layout_marginLeft=”110dp”\u003cbr\u003e\nandroid:layout_marginRight=”110dp”\u003cbr\u003e\nandroid:clipChildren=”false” \u0026gt;\u003cbr\u003e\n\u0026lt;/android.support.v4.view.ViewPager\u0026gt;\u003cbr\u003e\n\u003c/LinearLayout\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://lib.csdn.net/base/java\"\u003eJava\u003c/a\u003e代码部分：\u003c/p\u003e\n\u003cp\u003e// 1.设置幕后item的缓存数目\u003cbr\u003e\nmViewPager.setOffscreenPageLimit(3);\u003cbr\u003e\n// 2.设置页与页之间的间距\u003cbr\u003e\nmViewPager.setPageMargin(10);\u003cbr\u003e\n// 3.将父类的touch事件分发至viewPgaer，否则只能滑动中间的一个view对象\u003cbr\u003e\ncontainer.setOnTouchListener(new View.OnTouchListener() {\u003cbr\u003e\n@Override\u003cbr\u003e\npublic boolean onTouch(View v, MotionEvent event) {\u003cbr\u003e\nreturn mViewPager.dispatchTouchEvent(event);\u003cbr\u003e\n}\u003cbr\u003e\n});\u003c/p\u003e\n\u003cp\u003e参考效果图（上面代码并不能实现效果图，仅供参考）：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://a1.eoeandroid.com/attachment/forum/201403/19/104709u3r9hyirjrzywm33.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv\u003e\n  正常情况下, ViewPager  一页只能显示一项数据,\n\u003c/div\u003e\n\u003cdiv\u003e\n  但是如果需求是,  除了小显示本页数据, 还有包 左右两半的数据 也都露出一点来呢?\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  这该怎么处理?\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  后面在网上了搜了一下, 发现有不少这样得到文章, 这里自己也写一篇总结一下.\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  其实 主要就是用到 View 的 android:clipChildren 属性.\n\u003c/div\u003e\n\u003cdiv\u003e\n  简单来说这个属性,  就是 父View 是否 束缚 子View 的显示范围.\n\u003c/div\u003e\n\u003cdiv\u003e\n  如果 父View  有 padding , 那么 子View 则在 padding区域是不能显示内容的,\n\u003c/div\u003e\n\u003cdiv\u003e\n  但是如果 设置 android:clipChildren 为 false 时, 则子View 就可以在 父View 的padding屈戌显示内容了.\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  ok 基本了解了 android:clipChildren  那么来处理一下  ViewPager吧\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cp\u003e先看一下我做的demo:\u003c/p\u003e","title":"Android 使用ViewPager实现类似gallery画廊的效果(画廊效果之ViewPager显示多个图片)"},{"content":"在pox.xml文件中添加\norg.apache apache-ant-zip 2.3 system ${basedir}/lib/apache-ant-zip-2.3.jar jsp中获取当前的url\n\u0026lt;%\nString path = request.getContextPath();\nString bastPath = request.getScheme()+”://”+request.getServerName()+”:”+request.getServerPort()+path+”/”;\n%\u0026gt;\n\u0026#8221; id=\u0026#8221;base_url\u0026#8221;\u003e The username you provided is not allowed to use the text-based Tomcat Manager (error 403)\nTomcat管理\nhttp://blog.csdn.net/jay_1989/article/details/52861620\n","permalink":"https://blog.zdltech.com/posts/maven%E6%B7%BB%E5%8A%A0%E6%9C%AC%E5%9C%B0jar%E7%9A%84%E6%96%B9%E6%B3%95/","summary":"\u003cp\u003e在pox.xml文件中添加\u003c/p\u003e\n\u003cdependency\u003e  \n\u003cgroupId\u003eorg.apache\u003c/groupId\u003e  \n\u003cartifactId\u003eapache-ant-zip\u003c/artifactId\u003e  \n\u003cversion\u003e2.3\u003c/version\u003e  \n\u003cscope\u003esystem\u003c/scope\u003e  \n\u003csystemPath\u003e${basedir}/lib/apache-ant-zip-2.3.jar\u003c/systemPath\u003e  \n\u003c/dependency\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003ejsp中获取当前的url\u003c/p\u003e\n\u003cp\u003e\u0026lt;%\u003cbr\u003e\nString path = request.getContextPath();\u003c/p\u003e\n\u003cp\u003eString bastPath = request.getScheme()+”://”+request.getServerName()+”:”+request.getServerPort()+path+”/”;\u003cbr\u003e\n%\u0026gt;\u003c/p\u003e\n\u003cbase href=\u0026#8221;\u003c%=bastPath%\u003e\u0026#8221; id=\u0026#8221;base_url\u0026#8221;\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/jay_1989/article/details/52861620\"\u003eThe username you provided is not allowed to use the text-based Tomcat Manager (error 403)\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eTomcat管理\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/jay_1989/article/details/52861620\"\u003ehttp://blog.csdn.net/jay_1989/article/details/52861620\u003c/a\u003e\u003c/p\u003e","title":"Maven添加本地jar的方法"},{"content":"MyBatis的返回参数类型分两种\n1. 对应的分类为：\n1.1.resultMap:\n1.2.resultType:\n2 .对应返回值类型：\n2.1.resultMap:结果集\n2.2.resultType:int,string ,long ,class\n3. 注意点：\n在MyBatis进行查询映射时，其实查询出来的每一个属性都是放在一个对应的Map里面的，其中键是属性名，值则是其对应的值。\n3.1 当提供的返回类型属性是resultType时，MyBatis会将Map里面的键值对取出赋给resultType所指定的对象对应的属性。所以其实MyBatis的每一个查询映射的返回类型都是ResultMap，只是当提供的返回类型属性是resultType的时\n候，MyBatis对自动的给把对应的值赋给resultType所指定对象的属性。\n3.2 当提供的返回类型是resultMap时，因为Map不能很好表示领域模型，就需要自己再进一步的把它转化为对应的对象，这常常在复杂查询中很有作用。\n4.案例\n4.1：resultMap案例\n**[html]** [view plain](http://blog.csdn.net/u010235716/article/details/51698787#) [copy](http://blog.csdn.net/u010235716/article/details/51698787#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;select\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;selectByPrimaryKey\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;resultMap\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;BaseResultMap\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;parameterType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;java.lang.Long\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - select - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;include\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;refid\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;Base_Column_List\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - from common_car_make - where \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt; = #{id,\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;jdbcType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;BIGINT\u0026lt;/span\u0026gt;} - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;select\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 4.2 resultType–long案例\n**[html]** [view plain](http://blog.csdn.net/u010235716/article/details/51698787#) [copy](http://blog.csdn.net/u010235716/article/details/51698787#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;select\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;queryCarTypeByModelIdCount\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;resultType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;java.lang.Long\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;parameterType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;java.util.Map\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - select count(*) from common_car_type cm - where \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;test\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;carModelId != null\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - and \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;cm.car_model_id\u0026lt;/span\u0026gt; = #{carModelId,\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;jdbcType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;DECIMAL\u0026lt;/span\u0026gt;} - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;select\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 4.3 resultType–int案例\n**[html]** [view plain](http://blog.csdn.net/u010235716/article/details/51698787#) [copy](http://blog.csdn.net/u010235716/article/details/51698787#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;select\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;queryCategoryBrandCount\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;resultType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;java.lang.Integer\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;parameterType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;java.util.HashMap\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - select count(1) - from common_category_brand - where \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;test\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;categoryId != null\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - and \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;category_id\u0026lt;/span\u0026gt; = #{categoryId,\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;jdbcType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;BIGINT\u0026lt;/span\u0026gt;} - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;test\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;brandId != null\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - and \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;brand_id\u0026lt;/span\u0026gt; = #{brandId,\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;jdbcType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;BIGINT\u0026lt;/span\u0026gt;} - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;select\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 4.4 resultType–class案例:查询结果对应类中的属性值\n**[html]** [view plain](http://blog.csdn.net/u010235716/article/details/51698787#) [copy](http://blog.csdn.net/u010235716/article/details/51698787#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;select\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;selectCommonBrand\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;resultType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;com.epeit.api.model.CommonBrandPo\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;parameterType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;java.lang.Long\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - select - id, brand_name brandName, brand_type brandType, icon, delete_flag deleteFlag - from common_brand - where \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt; = #{id,\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;jdbcType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;BIGINT\u0026lt;/span\u0026gt;} - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;select\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; ","permalink":"https://blog.zdltech.com/posts/mybatis%E7%9A%84%E8%BF%94%E5%9B%9E%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B/","summary":"\u003cp\u003eMyBatis的返回参数类型分两种\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. 对应的分类为：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e1.1.resultMap:\u003c/p\u003e\n\u003cp\u003e1.2.resultType:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2 .对应返回值类型：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e2.1.resultMap:结果集\u003c/p\u003e\n\u003cp\u003e2.2.resultType:int,string ,long ,class\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. 注意点：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在MyBatis进行查询映射时，其实查询出来的每一个属性都是放在一个对应的Map里面的，其中键是属性名，值则是其对应的值。\u003c/p\u003e\n\u003cp\u003e3.1 当提供的返回类型属性是resultType时，MyBatis会将Map里面的键值对取出赋给resultType所指定的对象对应的属性。所以其实MyBatis的每一个查询映射的返回类型都是ResultMap，只是当提供的返回类型属性是resultType的时\u003cbr\u003e\n候，MyBatis对自动的给把对应的值赋给resultType所指定对象的属性。\u003c/p\u003e\n\u003cp\u003e3.2 当提供的返回类型是resultMap时，因为Map不能很好表示领域模型，就需要自己再进一步的把它转化为对应的对象，这常常在复杂查询中很有作用。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4.案例\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4.1：resultMap案例\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"dp-highlighter bg_html\" style=\"font-family: Consolas, 'Courier New', Courier, mono, serif; font-size: 12px; background-color: #e7e5dc; width: 870.156px; overflow: hidden; padding-top: 1px; text-align: left; margin: 18px 0px !important; position: relative; border-color: #cccccc; color: #555555; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;\" data-original-code=\"[html] view plain copy print?\u003cselect id=\u0026quot;selectByPrimaryKey\u0026quot; resultMap=\u0026quot;BaseResultMap\u0026quot; parameterType=\u0026quot;java.lang.Long\u0026quot; \u003e  \n    select   \n    \u003cinclude refid=\u0026quot;Base_Column_List\u0026quot; /\u003e  \n    from common_car_make  \n    where id = #{id,jdbcType=BIGINT}  \n  \u003c/select\u003e  \n\" data-snippet-id=\"ext.c84abb6eaa10792e9b6bf48e863b6d1e\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/u010235716/article/details/51698787#)\u003cspan data-mod=\"popu_168\"\u003e [copy](http://blog.csdn.net/u010235716/article/details/51698787#)\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;select\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;selectByPrimaryKey\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;resultMap\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;BaseResultMap\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;parameterType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;java.lang.Long\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- select\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;include\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;refid\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;Base_Column_List\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- from common_car_make\n\n- where \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt; = #{id,\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;jdbcType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;BIGINT\u0026lt;/span\u0026gt;}\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;select\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003e4.2 resultType–long案例\u003c/strong\u003e\u003c/p\u003e","title":"MyBatis的返回参数类型"},{"content":"ToolBar简介 ToolBar是Android 5.0推出的一个新的导航控件用于取代之前的ActionBar，由于其高度的可定制性、灵活性、具有Material Design风格等优点，越来越多的应用也用上了ToolBar，比如常用的知乎软件其顶部导航栏正是使用ToolBar。官方考虑到仍有一部分用户的手机版本号低于5.0，所以，ToolBar也放进了support v7包内，使得低版本的系统也能使用上ToolBar。本文将使用support v7支持包的ToolBar来进行讲解，包括其基本用法、样式定制等知识点。\nToolBar的基本使用 引入support v7支持包 在你项目的build.gradle内输入如下代码，即能引入支持包，该支持包内有能向下兼容的ToolBar:\n`dependencies { compile fileTree(dir: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;libs\u0026#39;\u0026amp;lt;/span\u0026gt;, include: [\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;*.jar\u0026#39;\u0026amp;lt;/span\u0026gt;]) compile \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;com.android.support:appcompat-v7:23.1.1\u0026#39;\u0026amp;lt;/span\u0026gt; }`\u0026lt;a target=\u0026#34;_blank\u0026#34; name=\u0026#34;t3\u0026#34;\u0026gt;\u0026lt;/a\u0026gt; 更改主题 为了能够正常使用ToolBar，我们需要隐藏原来的ActionBar，这个可以在主题中修改，在values/styles.xml中做出如下修改：\n\u0026#34; width=\u0026#34;20\u0026#34; data-original-code=\u0026#34;![]( data-wp-preserve=)1 2 1 2 \u0026#34; data-snippet-id=\u0026#34;ext.2bc0da59d9ff7d2cc4639972565d3679\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34; style=\u0026#34;white-space: nowrap; word-wrap: break-word; box-sizing: border-box; position: relative; overflow-y: hidden; overflow-x: auto; margin: 0px 0px 1.1em; font-family: \u0026#34;Source Code Pro\u0026#34;, monospace; display: block; padding: 5px 5px 5px 60px; font-size: 14px; line-height: 1.45; word-break: break-all; color: rgb(51, 51, 51); background-color: rgba(128, 128, 128, 0.05); border: 0px solid rgb(136, 136, 136); border-radius: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;\u0026#34;\u0026amp;gt;`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;AppTheme\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;parent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;Theme.AppCompat.Light.NoActionBar\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 继承了Theme.Appcompat.Light.NoActionBar主题，这里提一下，这个Theme.AppCompat是支持包内的主题，对应着5.0版本的Theme.Material主题。然后在manifest文件中引用这个主题。\n在布局文件中创建这个控件，activity_main.xml文件中，代码如下所示： \u0026lt;android.support.v7.widget.Toolbar android:id=\u0026amp;quot;@+id/toolbar\u0026amp;quot; android:layout_width=\u0026amp;quot;wrap_content\u0026amp;quot; android:layout_height=\u0026amp;quot;wrap_content\u0026amp;quot;\u0026gt; \u0026lt;TextView android:layout_width=\u0026amp;quot;match_parent\u0026amp;quot; android:layout_height=\u0026amp;quot;wrap_content\u0026amp;quot; android:text=\u0026amp;quot;标题\u0026amp;quot; android:textSize=\u0026amp;quot;20sp\u0026amp;quot;/\u0026gt; \u0026lt;/android.support.v7.widget.Toolbar\u0026gt; \u0026lt;/FrameLayout\u0026gt;1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 2 3 4 5 6 7 8 9 10 11 12 13 14 \u0026#34; data-snippet-id=\u0026#34;ext.1a86e4dfe907e8befece5a749bd9ae61\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;FrameLayout xmlns:android=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; android:layout_width=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; android:layout_height=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt; \u0026amp;lt;android.support.v7.widget.Toolbar android:id=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@+id/toolbar\u0026#34;\u0026amp;lt;/span\u0026gt; android:layout_width=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; android:layout_height=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt; \u0026amp;lt;TextView android:layout_width=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; android:layout_height=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; android:text=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;标题\u0026#34;\u0026amp;lt;/span\u0026gt; android:textSize=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;20sp\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt; \u0026amp;lt;/android.support.v7.widget.Toolbar\u0026amp;gt; \u0026amp;lt;/FrameLayout\u0026amp;gt;` 在上面，创建了android.support.v7.widget.Toolbar，同时我们在内部放了一个TextView，这是与ActionBar最大的不同，因为ToolBar实际上是一个ViewGroup，支持在其内部放入子View。ok，我们运行程序，得到如下结果：\n可以看出ToolBar正常显示，当然了，这只是最简单的用法，接下来我们逐步添加内容、样式，使它看起开更加美，功能更加完善。\nToolBar的完善 一、首先我们考虑，改变ToolBar的颜色 要想改变toolbar的颜色很简单，直接在布局文件中添加一个backgroud属性指定颜色就可以了，但是为了全局考虑，我们可以这样：在values/styles.xml文件中做出如下修改：\n” data-snippet-id=”ext.fc1e69a167a083bb969f36abdf127335″ data-snippet-saved=”false” data-codota-status=”done” style=”white-space: nowrap; word-wrap: break-word; box-sizing: border-box; position: relative; overflow-y: hidden; overflow-x: auto; margin: 0px 0px 1.1em; font-family: “Source Code Pro”, monospace; display: block; padding: 5px 5px 5px 60px; font-size: 14px; line-height: 1.45; word-break: break-all; color: rgb(51, 51, 51); background-color: rgba(128, 128, 128, 0.05); border: 0px solid rgb(136, 136, 136); border-radius: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;”\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;style\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;AppTheme\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;parent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;Theme.AppCompat.Light.NoActionBar\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;css\u0026quot;\u0026gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;!\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;--\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;Customize\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;your\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;theme\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;here\u0026amp;lt;/span\u0026gt;. \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;--\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026quot;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;colorPrimary\u0026amp;lt;/span\u0026gt;\u0026quot;\u0026amp;gt;\u0026amp;lt;span class=\u0026quot;hljs-id\u0026quot;\u0026gt;#2e8abb\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt; \u0026amp;lt;!\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;--\u0026amp;lt;/span\u0026gt;浅蓝色\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;--\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026quot;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;colorPrimaryDark\u0026amp;lt;/span\u0026gt;\u0026quot;\u0026amp;gt;\u0026amp;lt;span class=\u0026quot;hljs-id\u0026quot;\u0026gt;#3A5FCD\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt; \u0026amp;lt;!\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;--\u0026amp;lt;/span\u0026gt;深蓝色\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;--\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;style\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n然后在布局文件中，添加如下属性：\n`android:background=\u0026#34;?attr/colorPrimary\u0026#34;` 这样，就能方便对每一个toolbar引用同样的颜色了，我们先看看现在的效果是怎样的：\n可以看到，颜色已经改变，同时我们注意到，顶部状态栏的颜色也变成了深蓝色，这是因为添加了”colorPrimaryDark”的属性，使得顶部状态栏随之改变，利用这一特性，我们可以轻松实现“状态栏沉浸”的效果了。当然，这只适用于Android 5.0以上，如果在低版本则这个属性无效。这里再附上一张图（图片来自http://blog.csdn.net/bbld_/article/details/41439715）：\n根据图中的说明，我们可以轻松地在styles.xml文件中定制我们的样式，如果想要改变toolbar的title、subtitle以及menu中文字的颜色，可以利用“textColorPrimary”属性等。\n二、添加title、subtitle、logo、导航栏图标 在MainActivity文件先获取控件的实例，接着通过一系列的set方法即可设置，代码如下：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;MainActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AppCompatActivity\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; Toolbar toolbar; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;(Bundle savedInstanceState) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(R.layout.activity_main); toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar.setTitle(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Title\u0026#34;\u0026amp;lt;/span\u0026gt;); toolbar.setSubtitle(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;SubTitle\u0026#34;\u0026amp;lt;/span\u0026gt;); toolbar.setLogo(R.mipmap.ic_launcher); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置导航图标要在setSupportActionBar方法之后\u0026amp;lt;/span\u0026gt; setSupportActionBar(toolbar); toolbar.setNavigationIcon(R.mipmap.ic_drawer_home); } }` 结果如下：\n如果你想修改标题和子标题的字体大小、颜色等，可以调用 setTitleTextColor 、 setTitleTextAppearance 、 setSubtitleTextColor、 setSubtitleTextAppearance 这些API。当然，这些设置都是支持在xml布局中直接添加的，但是用的不是android:命名空间，而是自定义命名空间，如下所示：\n\u0026lt;android.support.v7.widget.Toolbar ... toolbar:logo=\u0026amp;quot;@mipmap/ic_launcher\u0026amp;quot; toolbar:title=\u0026amp;quot;Title\u0026amp;quot; toolbar:subtitle=\u0026amp;quot;Sub Title\u0026amp;quot; toolbar:titleTextColor=\u0026amp;quot;#ffffff\u0026amp;quot;\u0026gt; \u0026lt;/android.support.v7.widget.Toolbar\u0026gt; \u0026lt;/FrameLayout\u0026gt;1 2 3 4 5 6 7 8 9 10 11 1 2 3 4 5 6 7 8 9 10 11 \u0026#34; data-snippet-id=\u0026#34;ext.6bb55765ee941b8f3369ecd83e1e7df6\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;FrameLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:toolbar\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res-auto\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;android.support.v7.widget.Toolbar \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;toolbar:logo\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@mipmap/ic_launcher\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;toolbar:title\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;Title\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;toolbar:subtitle\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;Sub Title\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;toolbar:titleTextColor\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#ffffff\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;android.support.v7.widget.Toolbar\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;FrameLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 三、添加菜单选项图标及点击事件 1.添加菜单选项图标 一般导航条，在其右侧都会有菜单选项，当然ToolBar也是支持自定义菜单的，首先我们在菜单文件中，修改如下：res/menu/menu_main.xml:\n\u0026lt;item android:id=\u0026amp;quot;@+id/action_search\u0026amp;quot; android:title=\u0026amp;quot;Search\u0026amp;quot; android:icon=\u0026amp;quot;@mipmap/ic_search\u0026amp;quot; app:showAsAction=\u0026amp;quot;ifRoom\u0026amp;quot;/\u0026gt; \u0026lt;item android:id=\u0026amp;quot;@+id/action_notifications\u0026amp;quot; android:title=\u0026amp;quot;notifications\u0026amp;quot; android:icon=\u0026amp;quot;@mipmap/ic_notifications\u0026amp;quot; app:showAsAction=\u0026amp;quot;ifRoom\u0026amp;quot;/\u0026gt; \u0026lt;item android:id=\u0026amp;quot;@+id/action_settings\u0026amp;quot; android:title=\u0026amp;quot;@string/action_settings\u0026amp;quot; android:orderInCategory=\u0026amp;quot;100\u0026amp;quot; android:icon=\u0026amp;quot;@mipmap/ic_launcher\u0026amp;quot; app:showAsAction=\u0026amp;quot;never\u0026amp;quot;/\u0026gt; \u0026lt;/menu\u0026gt;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 \u0026#34; data-snippet-id=\u0026#34;ext.f0444147847f1fba32c0d4481fdce644\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;menu\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:app\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res-auto\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:tools\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/tools\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;tools:context\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;.MainActivity\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/action_search\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:title\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;Search\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:icon\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@mipmap/ic_search\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:showAsAction\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;ifRoom\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/action_notifications\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:title\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;notifications\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:icon\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@mipmap/ic_notifications\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:showAsAction\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;ifRoom\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/action_settings\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:title\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@string/action_settings\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:orderInCategory\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;100\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:icon\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@mipmap/ic_launcher\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:showAsAction\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;never\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;menu\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 这里用了这样一个熟悉：app:showAsAction=”ifRoom”/”never”，app是自定义的命名空间，因为我们的activity继承的是AppCompatActivity，是support v7包的，并不是原生sdk内部的，因此不能使用android:showAsAction，否则会报错。然后ifRoom表示有空间则显示，never表示从不显示，而是会通过overflowwindow显示。\n接着我们在Activity中，要重写onCreateOptionsMenu()方法，把这个菜单加载进去：\n`\u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Overridepublic\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; }` 2.添加点击事件 菜单有了，我们要为菜单添加点击事件，这样菜单才会有实际用途,添加点击事件也很方便，可以这样操作：\n`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置导航图标、添加菜单点击事件要在setSupportActionBar方法之后\u0026amp;lt;/span\u0026gt; setSupportActionBar(toolbar); toolbar.setNavigationIcon(R.mipmap.ic_drawer_home); toolbar.setOnMenuItemClickListener(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Toolbar.OnMenuItemClickListener() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onMenuItemClick\u0026amp;lt;/span\u0026gt;(MenuItem item) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (item.getItemId()) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; R.id.action_search: Toast.makeText(MainActivity.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Search !\u0026#34;\u0026amp;lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; R.id.action_notifications: Toast.makeText(MainActivity.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Notificationa !\u0026#34;\u0026amp;lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; R.id.action_settings: Toast.makeText(MainActivity.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Settings !\u0026#34;\u0026amp;lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } });` 结果如下：\n可以看到，菜单选项图标正常显示，以及点击事件都正常触发，但是还有一点瑕疵的地方，那就是右上角的三个圆点，是黑色的，与图标格格不入，有没有什么办法改变它呢？答案是有的，可以通过添加样式改变，如下所示：\n” data-snippet-id=”ext.c030061741a5d10caa1f136c5155b512″ data-snippet-saved=”false” data-codota-status=”done” style=”white-space: nowrap; word-wrap: break-word; box-sizing: border-box; position: relative; overflow-y: hidden; overflow-x: auto; margin: 0px 0px 1.1em; font-family: “Source Code Pro”, monospace; display: block; padding: 5px 5px 5px 60px; font-size: 14px; line-height: 1.45; word-break: break-all; color: rgb(51, 51, 51); background-color: rgba(128, 128, 128, 0.05); border: 0px solid rgb(136, 136, 136); border-radius: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;”\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;style\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;AppTheme\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;parent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;Theme.AppCompat.Light.NoActionBar\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;css\u0026quot;\u0026gt;\u0026amp;lt;br /\u0026gt; ...\u0026amp;lt;br /\u0026gt; \u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026quot;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-pseudo\u0026quot;\u0026gt;:textColorSecondary\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;span class=\u0026quot;hljs-id\u0026quot;\u0026gt;#ffffff\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;style\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n“android:textColorSecondary”属性对应的就是右上角三个圆点的颜色了。改变之后将会变成你要的颜色。\n四、其他样式修改 修改Toolbar popup menu样式 我们先点击右上角的三个点，会弹出一个popup menu，如下所示：\n可以看到右上角的popup menu是白底黑字，那么有没有什么办法改变它的背景颜色，使菜单显示为黑底白字呢呢？答案是有的，我们可以这样设置：\n首先在styles.xml文件中，新建一个主题：\n” data-snippet-id=”ext.088e2c015987971a783a656bc24179ff” data-snippet-saved=”false” data-codota-status=”done” style=”white-space: nowrap; word-wrap: break-word; box-sizing: border-box; position: relative; overflow-y: hidden; overflow-x: auto; margin: 0px 0px 1.1em; font-family: “Source Code Pro”, monospace; display: block; padding: 5px 5px 5px 60px; font-size: 14px; line-height: 1.45; word-break: break-all; color: rgb(51, 51, 51); background-color: rgba(128, 128, 128, 0.05); border: 0px solid rgb(136, 136, 136); border-radius: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;”\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;\u0026amp;lt;!-- toolbar弹出菜单样式 --\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;style\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;ToolbarPopupTheme\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;parent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;@style/ThemeOverlay.AppCompat.Dark\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;css\u0026quot;\u0026gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026quot;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-pseudo\u0026quot;\u0026gt;:colorBackground\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;span class=\u0026quot;hljs-id\u0026quot;\u0026gt;#000000\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;style\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n可以看到这个主题的parent是直接继承自ThemeOverlay.AppCompat.Dark，是支持包的一个主题，并且我们在内部声明了“android:colorBackground”这个属性，我们只要更改这个属性就能变更菜单的背景颜色了。接下来我们在布局文件中引入这个主题，这也很简单，为toolbar添加额外的属性如下：\n`toolbar:popupTheme=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@style/ToolbarPopupTheme\u0026#34;\u0026amp;lt;/span\u0026gt;` 这样，改几行代码即可修改popup menu的背景颜色了，如下面所示：\n修改Toolbar popup menu 弹出位置 我们可以看到，popup menu的位置是过于偏上的，我们还可以修改它的位置，使它处于Toolbar之下，这样看起来可能更美观：\n修改styles.xml文件如下：\n\u0026#34; width=\u0026#34;20\u0026#34; data-original-code=\u0026#34;![]( data-wp-preserve=) ” data-snippet-id=”ext.472b4d5c30d245269fb75e12299470d7″ data-snippet-saved=”false” data-codota-status=”done” style=”white-space: nowrap; word-wrap: break-word; box-sizing: border-box; position: relative; overflow-y: hidden; overflow-x: auto; margin: 0px 0px 1.1em; font-family: “Source Code Pro”, monospace; display: block; padding: 5px 5px 5px 60px; font-size: 14px; line-height: 1.45; word-break: break-all; color: rgb(51, 51, 51); background-color: rgba(128, 128, 128, 0.05); border: 0px solid rgb(136, 136, 136); border-radius: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;”\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;style\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;ToolbarPopupTheme\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;parent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;@style/ThemeOverlay.AppCompat.Dark\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;css\u0026quot;\u0026gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026quot;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-pseudo\u0026quot;\u0026gt;:colorBackground\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;span class=\u0026quot;hljs-id\u0026quot;\u0026gt;#000000\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026quot;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;actionOverflowMenuStyle\u0026amp;lt;/span\u0026gt;\u0026quot;\u0026amp;gt;\u0026amp;lt;span class=\u0026quot;hljs-at_rule\u0026quot;\u0026gt;@\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;style/OverflowMenuStyle\u0026amp;lt;/item\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;!--新增一个item，用于控制menu--\u0026amp;gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;style\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;style\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;OverflowMenuStyle\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;parent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;Widget.AppCompat.Light.PopupMenu.Overflow\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;css\u0026quot;\u0026gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026quot;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;overlapAnchor\u0026amp;lt;/span\u0026gt;\u0026quot;\u0026amp;gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt; \u0026amp;lt;!\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;--\u0026amp;lt;/span\u0026gt;把该属性改为\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;即可使\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;menu\u0026amp;lt;/span\u0026gt;位置位于\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;toolbar\u0026amp;lt;/span\u0026gt;之下\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;--\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;br /\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;style\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n效果如下图：\n转载：http://blog.csdn.net/a553181867/article/details/51336899\n参考：http://www.jianshu.com/p/79604c3ddcae\nConstraintLayout 终极秘籍（下） http://blog.chengyunfeng.com/?p=1031\n新布局节点ConstraintLayout基本使用\nhttp://blog.csdn.net/android_zhengyongbo/article/details/65630103\n","permalink":"https://blog.zdltech.com/posts/android-toolbar-%E4%BD%BF%E7%94%A8%E5%AE%8C%E5%85%A8%E8%A7%A3%E6%9E%90/","summary":"\u003ch1 id=\"toolbar简介\"\u003eToolBar简介\u003c/h1\u003e\n\u003cp\u003eToolBar是\u003ca href=\"http://lib.csdn.net/base/android\"\u003eAndroid\u003c/a\u003e 5.0推出的一个新的导航控件用于取代之前的ActionBar，由于其高度的可定制性、灵活性、具有Material Design风格等优点，越来越多的应用也用上了ToolBar，比如常用的知乎软件其顶部导航栏正是使用ToolBar。官方考虑到仍有一部分用户的手机版本号低于5.0，所以，ToolBar也放进了support v7包内，使得低版本的系统也能使用上ToolBar。本文将使用support v7支持包的ToolBar来进行讲解，包括其基本用法、样式定制等知识点。\u003c/p\u003e\n\u003ch1 id=\"toolbar的基本使用\"\u003e\u003ca target=\"_blank\" name=\"t1\"\u003e\u003c/a\u003eToolBar的基本使用\u003c/h1\u003e\n\u003ch2 id=\"引入support-v7支持包\"\u003e\u003ca target=\"_blank\" name=\"t2\"\u003e\u003c/a\u003e引入support v7支持包\u003c/h2\u003e\n\u003cp\u003e在你项目的build.gradle内输入如下代码，即能引入支持包，该支持包内有能向下兼容的ToolBar:\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`dependencies {    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      compile fileTree(dir: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;libs\u0026#39;\u0026amp;lt;/span\u0026gt;, include: [\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;*.jar\u0026#39;\u0026amp;lt;/span\u0026gt;])    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      compile \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;com.android.support:appcompat-v7:23.1.1\u0026#39;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}`\u0026lt;a target=\u0026#34;_blank\u0026#34; name=\u0026#34;t3\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"更改主题\"\u003e更改主题\u003c/h2\u003e\n\u003cp\u003e为了能够正常使用ToolBar，我们需要隐藏原来的ActionBar，这个可以在主题中修改，在values/styles.xml中做出如下修改：\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; width=\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-original-code=\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003e[]( data\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ewp\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003epreserve\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e)\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-snippet-id=\u0026#34;\u003c/span\u003eext\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003ebc0da59d9ff7d2cc4639972565d3679\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-snippet-saved=\u0026#34;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-codota-status=\u0026#34;\u003c/span\u003edone\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; style=\u0026#34;\u003c/span\u003ewhite\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003espace: nowrap; word\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ewrap: \u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eword; box\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003esizing: border\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ebox; position: relative; overflow\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ey: hidden; overflow\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ex: auto; margin: \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003epx \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003epx \u003cspan style=\"color:#bd93f9\"\u003e1.1\u003c/span\u003eem; font\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003efamily: \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Source Code Pro\u0026#34;\u003c/span\u003e, monospace; display: block; padding: \u003cspan style=\"color:#bd93f9\"\u003e5\u003c/span\u003epx \u003cspan style=\"color:#bd93f9\"\u003e5\u003c/span\u003epx \u003cspan style=\"color:#bd93f9\"\u003e5\u003c/span\u003epx \u003cspan style=\"color:#bd93f9\"\u003e60\u003c/span\u003epx; font\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003esize: \u003cspan style=\"color:#bd93f9\"\u003e14\u003c/span\u003epx; line\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eheight: \u003cspan style=\"color:#bd93f9\"\u003e1.45\u003c/span\u003e; word\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e: \u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eall; color: rgb(\u003cspan style=\"color:#bd93f9\"\u003e51\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e51\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e51\u003c/span\u003e); background\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ecolor: rgba(\u003cspan style=\"color:#bd93f9\"\u003e128\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e128\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e128\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e0.05\u003c/span\u003e); border: \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003epx solid rgb(\u003cspan style=\"color:#bd93f9\"\u003e136\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e136\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e136\u003c/span\u003e); border\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eradius: \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003epx; font\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003estyle: normal; font\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003evariant\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eligatures: normal; font\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003evariant\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ecaps: normal; font\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eweight: normal; letter\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003espacing: normal; orphans: \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e; text\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ealign: start; text\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eindent: \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003epx; text\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003etransform: none; widows: \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e; word\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003espacing: \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003epx; \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ewebkit\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003etext\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003estroke\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ewidth: \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003epx; text\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003edecoration\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003estyle: initial; text\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003edecoration\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ecolor: initial;\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;gt;`\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ehljs\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003etag\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ehljs\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003etitle\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;\u003c/span\u003ehljs\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eattribute\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ehljs\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003evalue\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026#34;\u003c/span\u003eAppTheme\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;\u003c/span\u003ehljs\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eattribute\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;parent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ehljs\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003evalue\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026#34;\u003c/span\u003eTheme\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAppCompat\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLight\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eNoActionBar\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;    \u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-tag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003estyle\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e继承了Theme.Appcompat.Light.NoActionBar主题，这里提一下，这个Theme.AppCompat是支持包内的主题，对应着5.0版本的Theme.Material主题。然后在manifest文件中引用这个主题。\u003c/p\u003e","title":"Android ToolBar 使用完全解析"},{"content":"Android ConstraintLayout详解 AndroidStudio2.2开始，就推出了一个牛逼的布局，ConstraintLayout,此布局像是一个升级版的RelativeLayout，但是功能比RelativeLayout强大许多，号称一层布局就可以搞定复杂页面。在AS2.2下还可以用拖拽控件的方式就行布局（设计师的福音），不过本篇不讲解拖拽控件的相关用法，主要讲解一些相关属性含义。\n想学习拖拽控件设计ConstraintLayout的请点这里。\nAndroid官方教程在此。\n本文讲解参考这里，需自备梯子。\n开始！\n相对位置这个相对位置的设置有点类似RelativeLayout的layout_toLeftOf、alignParentLeft等这些属性。\nConstraintLayout一共支持相对位置的属性在此：\nlayout_constraintLeft_toLeftOf\nlayout_constraintLeft_toRightOf\nlayout_constraintRight_toLeftOf\nlayout_constraintRight_toRightOf\nlayout_constraintTop_toTopOf\nlayout_constraintTop_toBottomOf\nlayout_constraintBottom_toTopOf\nlayout_constraintBottom_toBottomOf\nlayout_constraintBaseline_toBaselineOf\nlayout_constraintStart_toEndOf\nlayout_constraintStart_toStartOf\nlayout_constraintEnd_toStartOf\nlayout_constraintEnd_toEndOf拿第一个属性来说，layout_constraintLeft_toLeftOf=”@+id/id_first”,表示当前View的左边界与id_first的View的做边界对齐。其实这个属性翻译成中文就是：当前view的左边对齐与引用view的左边。\n例子： \u0026lt;Button android:id=\u0026amp;quot;@+id/buttonB\u0026amp;quot; ... app:layout_constraintLeft_toRightOf=\u0026amp;quot;@+id/buttonA\u0026amp;quot; /\u0026gt;1 2 3 1 2 3 1 2 3 1 2 3 \u0026#34; data-snippet-id=\u0026#34;ext.3190b6ad748f0e96e5cbd62a084f67f5\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;Button android:id=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@+id/buttonA\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; /\u0026amp;gt; \u0026amp;lt;Button android:id=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@+id/buttonB\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; app:layout_constraintLeft_toRightOf=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@+id/buttonA\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;` 效果如下：\n当然，这些属性也支持设置为对齐父布局的左右前后。\n1 2 1 2 1 2 1 2 \u0026#34; data-snippet-id=\u0026#34;ext.66574d68fbfbe560220fafc526a7805f\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;Button android:id=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@+id/buttonB\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; app:layout_constraintLeft_toLeftOf=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;parent\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;` 这样，buttonB就依附在父布局的左边。类似Realitelayout的alignParentLeft。\nmargin属性这个属性没啥好说的，跟其他布局的margin属性差不多。支持的属性如下：\nAndroid:layout_marginStart\nandroid:layout_marginEnd\nandroid:layout_marginLeft\nandroid:layout_marginTop\nandroid:layout_marginRight\nandroid:layout_marginBottom\n注意：如上图，假如A紧贴父布局的左侧，B距离A 100dp，A设置为gone后，则B距离父布局的左侧100dp。 goneMargin属性这个布局比较有意思，还是拿上面的那副图做示例，假设我们现在有这样一个需求：假设A设置为gone，后，B需要距离父布局的左侧200dp，怎么办？这时候，goneMargin属性就派上用场啦，只要设置B的layout_goneMarginLeft=200dp即可。这样，A不为gone的时候，B距离A 100dp，A为gone时，B距离父布局左侧200dp。\n一共支持的属性如下：\nlayout_goneMarginStart\nlayout_goneMarginEnd\nlayout_goneMarginLeft\nlayout_goneMarginTop\nlayout_goneMarginRight\nlayout_goneMarginBottom Centering positioning and bias ，设置居中或者按比例偏移。\n假设我们要设置一个控件居中怎么办？很简单，利用上面介绍过的属性就可以办到。 \u0026lt;Button android:id=\u0026amp;quot;@+id/button\u0026amp;quot; ... app:layout_constraintHorizontal_bias=\u0026amp;quot;0.3\u0026amp;quot; app:layout_constraintLeft_toLeftOf=\u0026amp;quot;parent\u0026amp;quot; app:layout_constraintRight_toRightOf=\u0026amp;quot;parent/\u0026gt; \u0026lt;/\u0026gt;1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 \u0026#34; data-snippet-id=\u0026#34;ext.fa91acc62f5d2da7b193dcfae6657c0a\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;` \u0026amp;lt;android.support.constraint.ConstraintLayout \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt;\u0026amp;gt; \u0026amp;lt;Button android:id=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;@+id/button\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; app:layout_constraintHorizontal_bias=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;0.3\u0026#34;\u0026amp;lt;/span\u0026gt; app:layout_constraintLeft_toLeftOf=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;parent\u0026#34;\u0026amp;lt;/span\u0026gt; app:layout_constraintRight_toRightOf=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;parent/\u0026amp;gt; \u0026amp;lt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` bias支持的属性如下：\nlayout_constraintHorizontal_bias\nlayout_constraintVertical_bias\nConstraintLayout本身支持minHeight、minWidht属性，没啥好说的。 注意ConstraintLayout不支持match_parent属性，要用0dp代替，在加上设置特性的约束属性，即可实现match_parent的效果。 Ratio 设置宽高比。属性如下：app:layout_constraintDimensionRatio=””\n当前控件宽或高其一确定的话，可以使用ration属性，根据确定的宽或高确定另外高或宽的大小。 1 2 3 1 2 3 1 2 3 1 2 3 \u0026#34; data-snippet-id=\u0026#34;ext.61bb115f4c457e5f98465a4b7d6d7cca\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Button\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:layout_constraintDimensionRatio\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;1:2\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 当前Button的width已经确定，height根据设置的比例=2×width\nlayout_constraintDimensionRatio接受的值是两个float类型的比例，代表的含义是width：height。\nration属性还支持这样设置：\n1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 \u0026#34; data-snippet-id=\u0026#34;ext.a36ae08c59e13d415c4b81a470c4cb1d\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Button\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:layout_constraintDimensionRatio\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;H,16:9\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:layout_constraintBottom_toBottomOf\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:layout_constraintTop_toTopOf\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;parent\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 其中前面的字符H代表Height、W代表Width，谷歌官方的解释是：\nIn that case, you need to indicate which side should be constrained, by adding the letter W (for constraining the width) or H (for constraining the height) in front of the ratio\n翻译过来就是说，W、H代表哪条边应该被约束。什么鬼?完全不理解。\n还要经过我代码测试，勉强知晓了前面H、W的意思。上面示例代码的Button高已经确定，宽是高的十六分之九：9/16，如果前面设置位W的话，那么宽的大小是高的九分之十六：16/9倍。\n_总结：假设比例设置为a：b ，如果前面是H，不论哪一边确定，另外一边的大小都是确定边的b/a倍；如果前面是W，不论哪一边确定，另外一边的大小都是确定边的a/b倍。_不知道谷歌是出于什么哲学思想，感觉像是个bug。\nChains 链状结构。看图如下：\nChain Style\n要想chain style生效，必须设置当前链方向的边为wrap_content,比如上面的水平链，宽设为wrap_content。还有就是控件要相互引用，比如A的右边依赖B的左边，B的左边依赖A的右边，都是设置。\nchain style设置在第一个控件上\n即设置在head上。\n属性有两个：\nlayout_constraintHorizontal_chainStyle\nlayout_constraintVertical_chainStyle\n支持的值有三个：\nCHAIN_SPREAD：均与分布控件。\nCHAIN_SPREAD_INSIDE，同上，但是边上的控件不均匀分布。\nCHAIN_SPREAD_INSIDE：控件紧挨在一起。还可以通过bias属性设置偏移量。\n根据字面意思这三个属性好理解，效果如下：\nWeighted chains：\napp:layout_constraintHorizontal_weight\napp:layout_constraintVertical_weight\n跟线性布局的weight差不多，layout_constraintHorizontal_weight需要设置width=0dp，控件的大小根据设置的weight比例进行设置。\nGuideline\nGuideline是一条隐形的线，这条线可作为准线，根据此准线设置其他控件的位置。 \u0026lt;android.support.constraint.Guideline android:layout_width=\u0026quot;wrap_content\u0026quot; android:layout_height=\u0026quot;wrap_content\u0026quot; android:id=\u0026quot;@+id/guideline\u0026quot; app:layout_constraintGuide_begin=\u0026quot;100dp\u0026quot; android:orientation=\u0026quot;vertical\u0026quot;/\u0026gt; \u0026lt;/android.support.constraint.ConstraintLayout\u0026gt;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 \u0026quot; data-snippet-id=\u0026ldquo;ext.4098cef20a1ac7690dfc51f4d9b3d147\u0026rdquo; data-snippet-saved=\u0026ldquo;false\u0026rdquo; data-codota-status=\u0026ldquo;done\u0026rdquo;\u0026gt;` \u0026lt;android\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.support\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.constraint\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.ConstraintLayout\u0026lt;/span\u0026gt; xmlns:android=\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot;\u0026amp;lt;/span\u0026gt; xmlns:app=\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;http://schemas.android.com/apk/res-auto\u0026quot;\u0026amp;lt;/span\u0026gt; xmlns:tools=\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;http://schemas.android.com/tools\u0026quot;\u0026amp;lt;/span\u0026gt; android:layout_width=\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt; android:layout_height=\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt;\u0026gt;\n\u0026amp;lt;android\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.support\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.constraint\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.Guideline\u0026amp;lt;/span\u0026gt; android:layout_width=\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;wrap_content\u0026quot;\u0026amp;lt;/span\u0026gt; android:layout_height=\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;wrap_content\u0026quot;\u0026amp;lt;/span\u0026gt; android:id=\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;@+id/guideline\u0026quot;\u0026amp;lt;/span\u0026gt; app:layout_constraintGuide_begin=\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;100dp\u0026quot;\u0026amp;lt;/span\u0026gt; android:orientation=\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;vertical\u0026quot;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt; \u0026amp;lt;Button android:text=\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;Button\u0026quot;\u0026amp;lt;/span\u0026gt; android:layout_width=\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;wrap_content\u0026quot;\u0026amp;lt;/span\u0026gt; android:layout_height=\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;wrap_content\u0026quot;\u0026amp;lt;/span\u0026gt; android:id=\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;@+id/button\u0026quot;\u0026amp;lt;/span\u0026gt; app:layout_constraintLeft_toLeftOf=\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;@+id/guideline\u0026quot;\u0026amp;lt;/span\u0026gt; android:layout_marginTop=\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;16dp\u0026quot;\u0026amp;lt;/span\u0026gt; app:layout_constraintTop_toTopOf=\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;parent\u0026quot;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt; \u0026lt;/android\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.support\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.constraint\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.ConstraintLayout\u0026lt;/span\u0026gt;\u0026gt;`\n上面代码：guideline控件是一条隐形垂直的线，距离左边距100dp，Button由于设置了left_toLeft，所以也距离左边距100dp。 GuideLine支持的属性： layout\\_constraintGuide\\_begin：距离left或top的大小 layout\\_constraintGuide\\_end：距离right或bottom的大小 layout\\_constraintGuide\\_percent：float类型。距离left或top的大小的比例。 layout\\_constraintGuide\\_percent=”0.5” android:orientation=”vertical” ,那么guideline距离左侧的距离为父布局宽度的一半。 \u0026amp;nbsp; 转自：http://blog.csdn.net/android_zhengyongbo/article/details/65630103 \u0026amp;nbsp; 继续学习 http://blog.chengyunfeng.com/?p=1031 ","permalink":"https://blog.zdltech.com/posts/%E6%96%B0%E5%B8%83%E5%B1%80%E8%8A%82%E7%82%B9constraintlayout%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/","summary":"\u003ch3 id=\"android-constraintlayout详解\"\u003eAndroid ConstraintLayout详解\u003c/h3\u003e\n\u003cp\u003eAndroidStudio2.2开始，就推出了一个牛逼的布局，ConstraintLayout,此布局像是一个升级版的RelativeLayout，但是功能比RelativeLayout强大许多，号称一层布局就可以搞定复杂页面。在AS2.2下还可以用拖拽控件的方式就行布局（设计师的福音），不过本篇不讲解拖拽控件的相关用法，主要讲解一些相关属性含义。\u003cbr\u003e\n想学习拖拽控件设计ConstraintLayout的请点\u003ca href=\"http://www.jianshu.com/p/a8b49ff64cd3\"\u003e这里\u003c/a\u003e。\u003cbr\u003e\n\u003ca href=\"http://lib.csdn.net/base/android\"\u003eAndroid\u003c/a\u003e官方教程\u003ca href=\"https://codelabs.developers.google.com/codelabs/constraint-layout/\"\u003e在此\u003c/a\u003e。\u003cbr\u003e\n本文讲解参考\u003ca href=\"https://developer.android.com/reference/android/support/constraint/ConstraintLayout.html\"\u003e这里\u003c/a\u003e，需自备梯子。\u003c/p\u003e\n\u003cp\u003e开始！\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e相对位置这个相对位置的设置有点类似RelativeLayout的layout_toLeftOf、alignParentLeft等这些属性。\u003cbr\u003e\nConstraintLayout一共支持相对位置的属性在此：\u003cbr\u003e\nlayout_constraintLeft_toLeftOf\u003cbr\u003e\nlayout_constraintLeft_toRightOf\u003cbr\u003e\nlayout_constraintRight_toLeftOf\u003cbr\u003e\nlayout_constraintRight_toRightOf\u003cbr\u003e\nlayout_constraintTop_toTopOf\u003cbr\u003e\nlayout_constraintTop_toBottomOf\u003cbr\u003e\nlayout_constraintBottom_toTopOf\u003cbr\u003e\nlayout_constraintBottom_toBottomOf\u003cbr\u003e\nlayout_constraintBaseline_toBaselineOf\u003cbr\u003e\nlayout_constraintStart_toEndOf\u003cbr\u003e\nlayout_constraintStart_toStartOf\u003cbr\u003e\nlayout_constraintEnd_toStartOf\u003cbr\u003e\nlayout_constraintEnd_toEndOf拿第一个属性来说，layout_constraintLeft_toLeftOf=”@+id/id_first”,表示当前View的左边界与id_first的View的做边界对齐。其实这个属性翻译成中文就是：当前view的左边对齐与引用view的左边。\u003cbr\u003e\n例子：\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003eButton android:id\u003cspan style=\"color:#ff79c6\"\u003e=\u0026amp;\u003c/span\u003equot;@\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ebuttonB\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; \u003cspan style=\"color:#ff79c6\"\u003e...\u003c/span\u003e app:layout_constraintLeft_toRightOf\u003cspan style=\"color:#ff79c6\"\u003e=\u0026amp;\u003c/span\u003equot;@\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ebuttonA\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; \u003cspan style=\"color:#ff79c6\"\u003e/\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-snippet-id=\u0026#34;\u003c/span\u003eext\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e3190\u003c/span\u003eb6ad748f0e96e5cbd62a084f67f5\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-snippet-saved=\u0026#34;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-codota-status=\u0026#34;\u003c/span\u003edone\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;`\u0026amp;lt;Button android:id=\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ehljs\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003estring\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026#34;\u003c/span\u003e@\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ebuttonA\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;\u003c/span\u003ehljs\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ekeyword\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;Button android:id\u003cspan style=\"color:#ff79c6\"\u003e=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;@+id/buttonB\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;...\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                 app:layout_constraintLeft_toRightOf\u003cspan style=\"color:#ff79c6\"\u003e=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;@+id/buttonA\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e效果如下：\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20161028165955714\"\u003e\u003c/p\u003e\n\u003cp\u003e当然，这些属性也支持设置为对齐父布局的左右前后。\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-snippet-id=\u0026#34;\u003c/span\u003eext\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e66574\u003c/span\u003ed68fbfbe560220fafc526a7805f\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-snippet-saved=\u0026#34;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-codota-status=\u0026#34;\u003c/span\u003edone\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;`\u0026amp;lt;Button android:id=\u0026amp;lt;span class=\u0026#34;\u003c/span\u003ehljs\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003estring\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;\u0026#34;\u003c/span\u003e@\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ebuttonB\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;\u003c/span\u003ehljs\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ekeyword\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                 app:layout_constraintLeft_toLeftOf\u003cspan style=\"color:#ff79c6\"\u003e=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;parent\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这样，buttonB就依附在父布局的左边。类似Realitelayout的alignParentLeft。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003emargin属性这个属性没啥好说的，跟其他布局的margin属性差不多。支持的属性如下：\u003cbr\u003e\n\u003ca href=\"http://lib.csdn.net/base/android\"\u003eAndroid\u003c/a\u003e:layout_marginStart\u003cbr\u003e\n\u003ca href=\"http://lib.csdn.net/base/android\"\u003eandroid\u003c/a\u003e:layout_marginEnd\u003cbr\u003e\nandroid:layout_marginLeft\u003cbr\u003e\nandroid:layout_marginTop\u003cbr\u003e\nandroid:layout_marginRight\u003cbr\u003e\nandroid:layout_marginBottom\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20161028170043897\"\u003e 注意：如上图，假如A紧贴父布局的左侧，B距离A 100dp，A设置为gone后，则B距离父布局的左侧100dp。\u003c/li\u003e\n\u003cli\u003egoneMargin属性这个布局比较有意思，还是拿上面的那副图做示例，假设我们现在有这样一个需求：假设A设置为gone，后，B需要距离父布局的左侧200dp，怎么办？这时候，goneMargin属性就派上用场啦，只要设置B的layout_goneMarginLeft=200dp即可。这样，A不为gone的时候，B距离A 100dp，A为gone时，B距离父布局左侧200dp。\u003cbr\u003e\n一共支持的属性如下：\u003cbr\u003e\nlayout_goneMarginStart\u003cbr\u003e\nlayout_goneMarginEnd\u003cbr\u003e\nlayout_goneMarginLeft\u003cbr\u003e\nlayout_goneMarginTop\u003cbr\u003e\nlayout_goneMarginRight\u003cbr\u003e\nlayout_goneMarginBottom\u003c/li\u003e\n\u003cli\u003eCentering positioning and bias ，设置居中或者按比例偏移。\u003cbr\u003e\n假设我们要设置一个控件居中怎么办？很简单，利用上面介绍过的属性就可以办到。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003eButton android:id\u003cspan style=\"color:#ff79c6\"\u003e=\u0026amp;\u003c/span\u003equot;@\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ebutton\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; \u003cspan style=\"color:#ff79c6\"\u003e...\u003c/span\u003e app:layout_constraintHorizontal_bias\u003cspan style=\"color:#ff79c6\"\u003e=\u0026amp;\u003c/span\u003equot;\u003cspan style=\"color:#bd93f9\"\u003e0.3\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; app:layout_constraintLeft_toLeftOf\u003cspan style=\"color:#ff79c6\"\u003e=\u0026amp;\u003c/span\u003equot;parent\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003equot; app:layout_constraintRight_toRightOf\u003cspan style=\"color:#ff79c6\"\u003e=\u0026amp;\u003c/span\u003equot;parent\u003cspan style=\"color:#ff79c6\"\u003e/\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e4\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e5\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e4\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e5\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e4\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e5\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e4\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e5\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-snippet-id=\u0026#34;\u003c/span\u003eext\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003efa91acc62f5d2da7b193dcfae6657c0a\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-snippet-saved=\u0026#34;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34; data-codota-status=\u0026#34;\u003c/span\u003edone\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;` \u0026amp;lt;android.support.constraint.ConstraintLayout \u0026amp;lt;span class=\u0026#34;\u003c/span\u003ehljs\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003ekeyword\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e             \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;Button android:id\u003cspan style=\"color:#ff79c6\"\u003e=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;@+id/button\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;...\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                 app:layout_constraintHorizontal_bias\u003cspan style=\"color:#ff79c6\"\u003e=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;0.3\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                 app:layout_constraintLeft_toLeftOf\u003cspan style=\"color:#ff79c6\"\u003e=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;parent\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                 app:layout_constraintRight_toRightOf\u003cspan style=\"color:#ff79c6\"\u003e=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;parent/\u0026amp;gt; \u0026amp;lt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt;`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003ebias支持的属性如下：\u003cbr\u003e\nlayout_constraintHorizontal_bias\u003cbr\u003e\nlayout_constraintVertical_bias\u003c/p\u003e","title":"新布局节点ConstraintLayout基本使用"},{"content":"Protocol Buffers Protocol buffers 是一个用来序列化结构化数据的技术，支持多种语言诸如 C++、Java 以及 Python 语言，可以使用该技术来持久化数据或者序列化成网络传输的数据。相比较一些其他的 XML 技术而言，该技术的一个明显特点就是更加节省空间（以二进制流存储）、速度更快以及更加灵活。\n具体参见 Google 开发文档：https://developers.google.com/protocol-buffers/docs/overview\nProtoBuf.js 上面抄的内容不是本文重点，重点是 Google 没有推出官方的 JavaScript 库，在神奇的同性交友社区 Github 上，我找到了一个纯绿色无公害的 ProtoBuf.js 库。它是一个由纯 JavaScript 实现构建在 ByteBuffer.js 之上的 .proto 文件解析库，包含 Message 构建、数据序列化和反序列化等功能。\nGoogle Protocol Buffers 传输的数据是二进制格式，JavaScript 天生不具备处理二进制数据的能力，所以要依赖 ByteBuffer.js ，ByteBuffer 和 ProtoBuf 都是由同一个团队 dcode.io 出品，ByteBuffer 可以单独使用，兼容 IE8+。\n.proto 文件 .proto 文件是 Protocol Buffers 的结构化数据定义，结构化数据被称为 Message，具体的就不解释了，可以看最末的两篇参考文章。\nProtoBuf.js 可以解析 .proto，构建 Message 对象，实现数据的序列化和反序列化，对于 .proto 不了解可以看官方文档：https://developers.google.com/protocol-buffers/docs/proto3\n下面举几个例子简单说明：\n.proto文件初始化和构建 Message，例子参见：https://github.com/dcodeIO/ProtoBuf.js/blob/master/examples/websocket/www/index.html\n``` 1 2 ``` \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; ``` var builder = ProtoBuf.loadProtoFile(\u0026quot;./example.proto\u0026quot;); var Message = builder.build(\u0026ldquo;Message\u0026rdquo;);\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 对于声明了 package 的`.proto`，只需在构建时把包名带上就行。\u0026lt;figure class=\u0026#34;highlight javascript\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; ``` var builder = ProtoBuf.loadProtoFile(\u0026quot;./example.proto\u0026quot;); var Message = builder.build(\u0026ldquo;com.xxx.Message\u0026rdquo;);\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 使用`loadProtoFile()`会让`.proto`文件明文暴露，所以可以使用 ProtoBuf.js 提供的工具将`.proto`转义成 `json` 或 `js`，参见：[https://github.com/dcodeIO/ProtoBuf.js/wiki/pbjs](https://github.com/dcodeIO/ProtoBuf.js/wiki/pbjs) 安装 node 模块：\u0026lt;figure class=\u0026#34;highlight bash\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; ``` npm install -g protobufjs\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 以 [example.proto](https://github.com/dcodeIO/ProtoBuf.js/blob/master/examples/websocket/www/example.proto) 为例，在终端执行：\u0026lt;figure class=\u0026#34;highlight bash\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; ``` pbjs src/address_book.proto -t js\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 会输出：\u0026lt;figure class=\u0026#34;highlight javascript\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; ``` var _root = dcodeIO.ProtoBuf.newBuilder({})[\u0026lsquo;import\u0026rsquo;]({ \u0026ldquo;package\u0026rdquo;: null, \u0026ldquo;messages\u0026rdquo;: [ { \u0026ldquo;name\u0026rdquo;: \u0026ldquo;Message\u0026rdquo;, \u0026ldquo;fields\u0026rdquo;: [ { \u0026ldquo;rule\u0026rdquo;: \u0026ldquo;required\u0026rdquo;, \u0026ldquo;type\u0026rdquo;: \u0026ldquo;string\u0026rdquo;, \u0026ldquo;name\u0026rdquo;: \u0026ldquo;text\u0026rdquo;, \u0026ldquo;id\u0026rdquo;: 1 } ] } ] }).build();\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 在实际应用时，通常一个 `.proto` 文件里面会有很多个 Message 类型，所以会将输出结果保存为一个 builder，\u0026lt;figure class=\u0026#34;highlight javascript\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; ``` var builder = dcodeIO.ProtoBuf.newBuilder({})[\u0026lsquo;import\u0026rsquo;]({ \u0026ldquo;package\u0026rdquo;: null, \u0026ldquo;messages\u0026rdquo;: [ { \u0026ldquo;name\u0026rdquo;: \u0026ldquo;Message\u0026rdquo;, \u0026ldquo;fields\u0026rdquo;: [ { \u0026ldquo;rule\u0026rdquo;: \u0026ldquo;required\u0026rdquo;, \u0026ldquo;type\u0026rdquo;: \u0026ldquo;string\u0026rdquo;, \u0026ldquo;name\u0026rdquo;: \u0026ldquo;text\u0026rdquo;, \u0026ldquo;id\u0026rdquo;: 1 } ] } ] });\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 存成 builder 就可以根据需求构建 Message 类型对象，\u0026lt;figure class=\u0026#34;highlight javascript\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; ``` var Message = builder.build(\u0026ldquo;Message\u0026rdquo;); var msg = new Message({ text: \u0026lsquo;message from maxzhang.\u0026rsquo; });\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; ## 序列化和反序列化 {#序列化和反序列化} 在 Web 端使用 Protocol Buffers 时，无论发送还是接收的数据都应当是二进制格式，二进制数据可以直接使用 Message 类型对象解析，\u0026lt;figure class=\u0026#34;highlight javascript\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;7\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;9\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; ``` // 序列化 function encode(jsonData) { var Message = builder.build(\u0026ldquo;Message\u0026rdquo;); var msg = new Message(jsonData); return msg.toArrayBuffer(); }\n// 反序列化 function decodeMessage(data) { var msg = builder.build(\u0026ldquo;Message\u0026rdquo;).decode(data); return msg; }\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; `decode()` 返回一个 Message 实例对象（可以等同于 JSON Object），实例中的属性便是 `.proto` 文件中声明的变量与类型， 在 `.proto` 文件中声明数据类型需要遵循 [Protocol Buffers 数据类型](https://developers.google.com/protocol-buffers/docs/proto3#scalar) 规则，如下表： ![Protocol Buffers 数据类型](http://www.maxzhang.com/2015/09/ProtoBuf-js%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7/protobuf-types.jpg) 由于上图不包括 JavaScript 对应的数据类型，所以我自己补充了一个数据类型对应关系（每种数据类型我并没有一一验证使用过，可能有误，欢迎指正）： | .proto Type | JavaScript Type | | ----------- | --------------- | | double | Long | | float | float | | int32 | int | | int64 | Long | | uint32 | int | | uint64 | Long | | sint32 | int | | sint64 | Long | | fixed32 | int | | fixed64 | Long | | sfixed32 | int | | sfixed64 | Long | | bool | boolean | | string | string | | bytes | ByteBuffer | ### ByteBuffer.js {#ByteBuffer-js} bytes 类型是二进制格式数据，需要使用 [ByteBuffer.js](https://github.com/dcodeIO/ByteBuffer.js) 处理，ByteBuffer 可以直接操作二进制数据，例子：\u0026lt;figure class=\u0026#34;highlight javascript\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; ``` var ByteBuffer = require(\u0026ldquo;bytebuffer\u0026rdquo;);\nvar bb = new ByteBuffer() .writeIString(\u0026ldquo;Hello world!\u0026quot;) .flip(); console.log(bb.readIString() + \u0026rdquo; from ByteBuffer.js\u0026quot;);\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; ByteBuffer 可以直接写入或读取任意一种类型的值，值得长度为 8bits \u0026amp;#8211; 64bits，特殊的按位写入需要使用 JavaScript 位移操作符，比如：\u0026lt;figure class=\u0026#34;highlight javascript\u0026#34;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026#34;gutter\u0026#34;\u0026gt; ``` \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;4\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;line\u0026#34;\u0026gt;6\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; ``` // 写入数据格式 len of id(4bits) + id(12bits) var bb = new ByteBuffer(16); var id = 1; bb.writeInt8(String(id).length \u0026lt;\u0026lt; 4); bb.writeInt8(id); bb.flip();\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt;\u0026lt;/figure\u0026gt; 更多 ByteBuffer 接口参见API：[https://github.com/dcodeIO/ByteBuffer.js/wiki/API](https://github.com/dcodeIO/ByteBuffer.js/wiki/API) 在 [Message API](https://htmlpreview.github.io/?https://raw.githubusercontent.com/dcodeIO/ProtoBuf.js/master/docs/ProtoBuf.Builder.Message.html) 中的 `toArrayBuffer()` `toBuffer()` 等方法底层实际调用的是 ByteBuffer 的接口，与 ByteBuffer 不同的是“Message 对象是按照 JSON 的方式修改值，调用 `toArrayBuffer()` 接口序列化数据，调用 `decode()` 接口反序列数据”。 ### Long.js {#Long-js} 由于 JavaScript 精度问题，所以 `int64` 和 `uint64` 等类型数据会被转换成 [Long.js](https://github.com/dcodeIO/Long.js) 对象实例，Long 并不太复杂，与 [bignumber.js](https://github.com/MikeMcl/bignumber.js) 类似，具体参考 [Long.js API](https://github.com/dcodeIO/Long.js#api). ## WebSocket {#WebSocket} 关于 WebSocket 提供一个简单的[例子](https://github.com/dcodeIO/ProtoBuf.js/blob/master/examples/websocket/www/index.html)， 实际应用与例子差不多，就是做两件基础的事： * 连接 WebSocket，从 socket 通道拿到二进制数据，反序列化解析成 Message 对象。 * 实例化 Message 对象，然后序列化成二进制数据，发送给服务端。 ## 参考文章 {#参考文章} * [http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/](http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/) * [http://www.cnblogs.com/royenhome/archive/2010/10/29/1864860.html](http://www.cnblogs.com/royenhome/archive/2010/10/29/1864860.html) \u0026amp;nbsp; 转自：[http://www.maxzhang.com/2015/09/ProtoBuf-js使用技巧/](http://www.maxzhang.com/2015/09/ProtoBuf-js%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7/) ","permalink":"https://blog.zdltech.com/posts/protobuf-js-%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7/","summary":"\u003ch2 id=\"Protocol_Buffers\"\u003eProtocol Buffers\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003eProtocol buffers 是一个用来序列化结构化数据的技术，支持多种语言诸如 C++、Java 以及 Python 语言，可以使用该技术来持久化数据或者序列化成网络传输的数据。相比较一些其他的 XML 技术而言，该技术的一个明显特点就是更加节省空间（以二进制流存储）、速度更快以及更加灵活。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e具体参见 Google 开发文档：\u003ca href=\"https://developers.google.com/protocol-buffers/docs/overview\"\u003ehttps://developers.google.com/protocol-buffers/docs/overview\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"ProtoBuf-js\"\u003eProtoBuf.js\u003c/h2\u003e\n\u003cp\u003e上面抄的内容不是本文重点，重点是 Google 没有推出官方的 JavaScript 库，在神奇的同性交友社区 \u003ca href=\"http://github.com/\"\u003eGithub\u003c/a\u003e 上，我找到了一个纯绿色无公害的 \u003ca href=\"https://github.com/dcodeIO/ProtoBuf.js\"\u003eProtoBuf.js\u003c/a\u003e 库。它是一个由纯 JavaScript 实现构建在 \u003ca href=\"https://github.com/dcodeIO/ByteBuffer.js\"\u003eByteBuffer.js\u003c/a\u003e 之上的 \u003ccode\u003e.proto\u003c/code\u003e 文件解析库，包含 Message 构建、数据序列化和反序列化等功能。\u003c/p\u003e\n\u003cp\u003eGoogle Protocol Buffers 传输的数据是二进制格式，JavaScript 天生不具备处理二进制数据的能力，所以要依赖 \u003ca href=\"https://github.com/dcodeIO/ByteBuffer.js\"\u003eByteBuffer.js\u003c/a\u003e ，ByteBuffer 和 ProtoBuf 都是由同一个团队 \u003ca href=\"http://dcode.io/\"\u003edcode.io\u003c/a\u003e 出品，ByteBuffer 可以单独使用，兼容 IE8+。\u003c/p\u003e\n\u003ch2 id=\"-proto_文件\"\u003e\u003ccode\u003e.proto\u003c/code\u003e 文件\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003e.proto\u003c/code\u003e 文件是 Protocol Buffers 的结构化数据定义，结构化数据被称为 Message，具体的就不解释了，可以看最末的两篇参考文章。\u003c/p\u003e\n\u003cp\u003eProtoBuf.js 可以解析 \u003ccode\u003e.proto\u003c/code\u003e，构建 Message 对象，实现数据的序列化和反序列化，对于 \u003ccode\u003e.proto\u003c/code\u003e 不了解可以看官方文档：\u003ca href=\"https://developers.google.com/protocol-buffers/docs/proto3\"\u003ehttps://developers.google.com/protocol-buffers/docs/proto3\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e下面举几个例子简单说明：\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e.proto\u003c/code\u003e文件初始化和构建 Message，例子参见：\u003ca href=\"https://github.com/dcodeIO/ProtoBuf.js/blob/master/examples/websocket/www/index.html\"\u003ehttps://github.com/dcodeIO/ProtoBuf.js/blob/master/examples/websocket/www/index.html\u003c/a\u003e\u003cfigure class=\"highlight javascript\"\u003e\u003c/p\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd class=\"gutter\"\u003e\n      ```\n\u003cspan class=\"line\"\u003e1\u003c/span\u003e\n\u003cspan class=\"line\"\u003e2\u003c/span\u003e\n```\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003evar\u003c/span\u003e builder = ProtoBuf.loadProtoFile(\u003cspan class=\"string\"\u003e\u0026quot;./example.proto\u0026quot;\u003c/span\u003e);\u003c/span\u003e\n\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003evar\u003c/span\u003e Message = builder.build(\u003cspan class=\"string\"\u003e\u0026ldquo;Message\u0026rdquo;\u003c/span\u003e);\u003c/span\u003e\u003c/p\u003e","title":"ProtoBuf.js 使用技巧"},{"content":"\n概述 RecyclerView出现已经有一段时间了，相信大家肯定不陌生了，大家可以通过导入support-v7对其进行使用。\n据官方的介绍，该控件用于在有限的窗口中展示大量数据集，其实这样功能的控件我们并不陌生，例如：ListView、GridView。\n那么有了ListView、GridView为什么还需要RecyclerView这样的控件呢？整体上看RecyclerView架构，提供了一种插拔式的体验，高度的解耦，异常的灵活，通过设置它提供的不同LayoutManager，ItemDecoration , ItemAnimator实现令人瞠目的效果。\n你想要控制其显示的方式，请通过布局管理器LayoutManager 你想要控制Item间的间隔（可绘制），请通过ItemDecoration 你想要控制Item增删的动画，请通过ItemAnimator 你想要控制点击、长按事件，请自己写（擦，这点尼玛。） 基本使用 鉴于我们对于ListView的使用特别的熟悉，对比下RecyclerView的使用代码：\n`mRecyclerView = findView(R.id.id_recyclerview); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置布局管理器\u0026amp;lt;/span\u0026gt; mRecyclerView.setLayoutManager(layout); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置adapter\u0026amp;lt;/span\u0026gt; mRecyclerView.setAdapter(adapter) \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置Item增加、移除动画\u0026amp;lt;/span\u0026gt; mRecyclerView.setItemAnimator(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DefaultItemAnimator()); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//添加分割线\u0026amp;lt;/span\u0026gt; mRecyclerView.addItemDecoration(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DividerItemDecoration( getActivity(), DividerItemDecoration.HORIZONTAL_LIST));` ok，相比较于ListView的代码，ListView可能只需要去设置一个adapter就能正常使用了。而RecyclerView基本需要上面一系列的步骤，那么为什么会添加这么多的步骤呢？\n那么就必须解释下RecyclerView的这个名字了，从它类名上看，RecyclerView代表的意义是，我只管Recycler View，也就是说RecyclerView只管回收与复用View，其他的你可以自己去设置。可以看出其高度的解耦，给予你充分的定制自由（所以你才可以轻松的通过这个控件实现ListView,GirdView，瀑布流等效果）。\nJust like ListView Activity `\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;package\u0026amp;lt;/span\u0026gt; com.zhy.sample.demo_recyclerview; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.util.ArrayList; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.util.List; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.os.Bundle; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.app.ActionBarActivity; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.LinearLayoutManager; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView.ViewHolder; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.LayoutInflater; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.View; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.ViewGroup; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.widget.TextView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;HomeActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ActionBarActivity\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; RecyclerView mRecyclerView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; mDatas; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; HomeAdapter mAdapter; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;(Bundle savedInstanceState) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(R.layout.activity_single_recyclerview); initData(); mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview); mRecyclerView.setLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; LinearLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;)); mRecyclerView.setAdapter(mAdapter = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; HomeAdapter()); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initData\u0026amp;lt;/span\u0026gt;() { mDatas = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;String\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;A\u0026#39;\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;z\u0026#39;\u0026amp;lt;/span\u0026gt;; i++) { mDatas.add(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt; + (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;char\u0026amp;lt;/span\u0026gt;) i); } } class HomeAdapter extends RecyclerView.Adapter\u0026amp;lt;HomeAdapter.MyViewHolder\u0026amp;gt; { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; MyViewHolder \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreateViewHolder\u0026amp;lt;/span\u0026gt;(ViewGroup parent, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; viewType) { MyViewHolder holder = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; MyViewHolder(LayoutInflater.from( HomeActivity.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;).inflate(R.layout.item_home, parent, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;)); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; holder; } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onBindViewHolder\u0026amp;lt;/span\u0026gt;(MyViewHolder holder, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position) { holder.tv.setText(mDatas.get(position)); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getItemCount\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mDatas.size(); } class MyViewHolder extends ViewHolder { TextView tv; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;MyViewHolder\u0026amp;lt;/span\u0026gt;(View view) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;(view); tv = (TextView) view.findViewById(R.id.id_num); } } } }` Activity的布局文件 `\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;RelativeLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:tools\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/tools\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;android.support.v7.widget.RecyclerView \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/id_recyclerview\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:divider\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#ffff0000\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:dividerHeight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;10dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;RelativeLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` Item的布局文件 `\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;FrameLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#44ff0000\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;TextView \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/id_num\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;50dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;center\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:text\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;1\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;FrameLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 这么看起来用法与ListView的代码基本一致哈~~\n看下效果图：\n看起来好丑，Item间应该有个分割线，当你去找时，你会发现RecyclerView并没有支持divider这样的属性。那么怎么办，你可以给Item的布局去设置margin，当然了这种方式不够优雅，我们文章开始说了，我们可以自由的去定制它，当然我们的分割线也是可以定制的。\nItemDecoration 我们可以通过该方法添加分割线：\nmRecyclerView.addItemDecoration()\n该方法的参数为RecyclerView.ItemDecoration，该类为抽象类，官方目前并没有提供默认的实现类（我觉得最好能提供几个）。\n该类的源码：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;abstract\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ItemDecoration\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDraw\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent, State state) { onDraw(c, parent); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDrawOver\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent, State state) { onDrawOver(c, parent); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getItemOffsets\u0026amp;lt;/span\u0026gt;(Rect outRect, View view, RecyclerView parent, State state) { getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(), parent); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Deprecated\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getItemOffsets\u0026amp;lt;/span\u0026gt;(Rect outRect, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; itemPosition, RecyclerView parent) { outRect.set(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); }` 当我们调用mRecyclerView.addItemDecoration()方法添加decoration的时候，RecyclerView在绘制的时候，去会绘制decorator，即调用该类的onDraw和onDrawOver方法，\nonDraw方法先于drawChildren onDrawOver在drawChildren之后，一般我们选择复写其中一个即可。 getItemOffsets 可以通过outRect.set()为每个Item设置一定的偏移量，主要用于绘制Decorator。 接下来我们看一个RecyclerView.ItemDecoration的实现类，该类很好的实现了RecyclerView添加分割线（当使用LayoutManager为LinearLayoutManager时）。\n该类参考自：DividerItemDecoration\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;package\u0026amp;lt;/span\u0026gt; com.zhy.sample.demo_recyclerview; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the \u0026#34;License\u0026#34;); * limitations under the License. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.content.Context; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.content.res.TypedArray; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Canvas; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Rect; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.drawable.Drawable; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.LinearLayoutManager; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView.State; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.util.Log; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.View; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * This class is from the v7 samples of the Android SDK. It\u0026#39;s not by me! * \u0026amp;lt;p/\u0026amp;gt; * See the license above for details. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DividerItemDecoration\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;RecyclerView\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ItemDecoration\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] ATTRS = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[]{ android.R.attr.listDivider }; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; VERTICAL_LIST = LinearLayoutManager.VERTICAL; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; Drawable mDivider; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mOrientation; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DividerItemDecoration\u0026amp;lt;/span\u0026gt;(Context context, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; orientation) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); a.recycle(); setOrientation(orientation); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setOrientation\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; orientation) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (orientation != HORIZONTAL_LIST \u0026amp;\u0026amp; orientation != VERTICAL_LIST) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; IllegalArgumentException(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;invalid orientation\u0026#34;\u0026amp;lt;/span\u0026gt;); } mOrientation = orientation; } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDraw\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent) { Log.v(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;recyclerview - itemdecoration\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;onDraw()\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { drawHorizontal(c, parent); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawVertical\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left = parent.getPaddingLeft(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right = parent.getWidth() - parent.getPaddingRight(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount = parent.getChildCount(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; childCount; i++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; View child = parent.getChildAt(i); android.support.v7.widget.RecyclerView v = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView(parent.getContext()); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top = child.getBottom() + params.bottomMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawHorizontal\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top = parent.getPaddingTop(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom = parent.getHeight() - parent.getPaddingBottom(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount = parent.getChildCount(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; childCount; i++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; View child = parent.getChildAt(i); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left = child.getRight() + params.rightMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right = left + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getItemOffsets\u0026amp;lt;/span\u0026gt;(Rect outRect, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; itemPosition, RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mOrientation == VERTICAL_LIST) { outRect.set(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mDivider.getIntrinsicHeight()); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { outRect.set(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mDivider.getIntrinsicWidth(), \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); } } }` 该实现类可以看到通过读取系统主题中的 [Android](http://lib.csdn.net/base/android).R.attr.listDivider作为Item间的分割线，并且支持横向和纵向。如果你不清楚它是怎么做到的读取系统的属性用于自身，请参考我的另一篇博文：Android 深入理解Android中的自定义属性\n获取到listDivider以后，该属性的值是个Drawable，在getItemOffsets中，outRect去设置了绘制的范围。onDraw中实现了真正的绘制。\n我们在原来的代码中添加一句：\n`mRecyclerView.addItemDecoration(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DividerItemDecoration(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, DividerItemDecoration.VERTICAL_LIST));` ok，现在再运行，就可以看到分割线的效果了。 该分割线是系统默认的，你可以在theme.xml中找到该属性的使用情况。那么，使用系统的listDivider有什么好处呢？就是方便我们去随意的改变，该属性我们可以直接声明在：\n` \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;\u0026amp;lt;!-- Application theme. --\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;AppTheme\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;parent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;AppBaseTheme\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;css\u0026#34;\u0026gt; \u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026#34;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-pseudo\u0026#34;\u0026gt;:listDivider\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;span class=\u0026#34;hljs-at_rule\u0026#34;\u0026gt;@\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;drawable/divider_bg\u0026amp;lt;/item\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 然后自己写个drawable即可，下面我们换一种分隔符：\n`\u0026amp;lt;?xml version=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;1.0\u0026#34;\u0026amp;lt;/span\u0026gt; encoding=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;utf-8\u0026#34;\u0026amp;lt;/span\u0026gt;?\u0026amp;gt; \u0026amp;lt;shape xmlns:android=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; android:shape=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;rectangle\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;gt; \u0026amp;lt;gradient android:centerColor=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#ff00ff00\u0026#34;\u0026amp;lt;/span\u0026gt; android:endColor=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#ff0000ff\u0026#34;\u0026amp;lt;/span\u0026gt; android:startColor=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#ffff0000\u0026#34;\u0026amp;lt;/span\u0026gt; android:type=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;linear\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt; \u0026amp;lt;size android:height=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;4dp\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt; \u0026amp;lt;/shape\u0026amp;gt;` 现在的样子是：\n当然了，你可以根据自己的需求，去随意的绘制，反正是画出来的，随便玩~~\nok，看到这，你可能觉得，这玩意真尼玛麻烦，完全不能比拟的心爱的ListView。那么继续看。\nLayoutManager 好了，上面实现了类似ListView样子的Demo，通过使用其默认的LinearLayoutManager。\nRecyclerView.LayoutManager吧，这是一个抽象类，好在系统提供了3个实现类：\nLinearLayoutManager 现行管理器，支持横向、纵向。 GridLayoutManager 网格布局管理器 StaggeredGridLayoutManager 瀑布就式布局管理器 上面我们已经初步体验了下LinearLayoutManager，接下来看GridLayoutManager。\nGridLayoutManager 我们尝试去实现类似GridView，秒秒钟的事情：\n`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//mRecyclerView.setLayoutManager(new LinearLayoutManager(this));\u0026amp;lt;/span\u0026gt; mRecyclerView.setLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; GridLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;));` 只需要修改LayoutManager即可，还是很nice的。\n当然了，改为GridLayoutManager以后，对于分割线，前面的DividerItemDecoration就不适用了，主要是因为它在绘制的时候，比如水平线，针对每个child的取值为：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left = parent.getPaddingLeft(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right = parent.getWidth() - parent.getPaddingRight();` 因为每个Item一行，这样是没问题的。而GridLayoutManager时，一行有多个childItem，这样就多次绘制了，并且GridLayoutManager时，Item如果为最后一列（则右边无间隔线）或者为最后一行（底部无分割线）。\n针对上述，我们编写了DividerGridItemDecoration。\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;package\u0026amp;lt;/span\u0026gt; com.zhy.sample.demo_recyclerview; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.content.Context; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.content.res.TypedArray; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Canvas; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Rect; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.drawable.Drawable; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.GridLayoutManager; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView.LayoutManager; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView.State; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.StaggeredGridLayoutManager; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.View; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @author\u0026amp;lt;/span\u0026gt; zhy * */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DividerGridItemDecoration\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;RecyclerView\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ItemDecoration\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] ATTRS = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] { android.R.attr.listDivider }; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; Drawable mDivider; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DividerGridItemDecoration\u0026amp;lt;/span\u0026gt;(Context context) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); a.recycle(); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDraw\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent, State state) { drawHorizontal(c, parent); drawVertical(c, parent); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getSpanCount\u0026amp;lt;/span\u0026gt;(RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 列数\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; spanCount = -\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;; LayoutManager layoutManager = parent.getLayoutManager(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; GridLayoutManager) { spanCount = ((GridLayoutManager) layoutManager).getSpanCount(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; StaggeredGridLayoutManager) { spanCount = ((StaggeredGridLayoutManager) layoutManager) .getSpanCount(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; spanCount; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawHorizontal\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount = parent.getChildCount(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; childCount; i++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; View child = parent.getChildAt(i); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left = child.getLeft() - params.leftMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right = child.getRight() + params.rightMargin + mDivider.getIntrinsicWidth(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top = child.getBottom() + params.bottomMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawVertical\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount = parent.getChildCount(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; childCount; i++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; View child = parent.getChildAt(i); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top = child.getTop() - params.topMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom = child.getBottom() + params.bottomMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left = child.getRight() + params.rightMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right = left + mDivider.getIntrinsicWidth(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;isLastColum\u0026amp;lt;/span\u0026gt;(RecyclerView parent, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; pos, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; spanCount, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount) { LayoutManager layoutManager = parent.getLayoutManager(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; GridLayoutManager) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; ((pos + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) % spanCount == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一列，则不需要绘制右边\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; StaggeredGridLayoutManager) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; orientation = ((StaggeredGridLayoutManager) layoutManager) .getOrientation(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (orientation == StaggeredGridLayoutManager.VERTICAL) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; ((pos + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) % spanCount == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一列，则不需要绘制右边\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { childCount = childCount - childCount % spanCount; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (pos \u0026amp;gt;= childCount)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一列，则不需要绘制右边\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;isLastRaw\u0026amp;lt;/span\u0026gt;(RecyclerView parent, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; pos, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; spanCount, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount) { LayoutManager layoutManager = parent.getLayoutManager(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; GridLayoutManager) { childCount = childCount - childCount % spanCount; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (pos \u0026amp;gt;= childCount)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一行，则不需要绘制底部\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; StaggeredGridLayoutManager) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; orientation = ((StaggeredGridLayoutManager) layoutManager) .getOrientation(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// StaggeredGridLayoutManager 且纵向滚动\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (orientation == StaggeredGridLayoutManager.VERTICAL) { childCount = childCount - childCount % spanCount; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一行，则不需要绘制底部\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (pos \u0026amp;gt;= childCount) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// StaggeredGridLayoutManager 且横向滚动\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一行，则不需要绘制底部\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; ((pos + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) % spanCount == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getItemOffsets\u0026amp;lt;/span\u0026gt;(Rect outRect, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; itemPosition, RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; spanCount = getSpanCount(parent); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount = parent.getAdapter().getItemCount(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (isLastRaw(parent, itemPosition, spanCount, childCount))\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一行，则不需要绘制底部\u0026amp;lt;/span\u0026gt; { outRect.set(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mDivider.getIntrinsicWidth(), \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (isLastColum(parent, itemPosition, spanCount, childCount))\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一列，则不需要绘制右边\u0026amp;lt;/span\u0026gt; { outRect.set(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mDivider.getIntrinsicHeight()); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { outRect.set(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight()); } } } `主要在`getItemOffsets`方法中，去判断如果是最后一行，则不需要绘制底部；如果是最后一列，则不需要绘制右边，整个判断也考虑到了`StaggeredGridLayoutManager`的横向和纵向，所以稍稍有些复杂。最重要还是去理解，如何绘制什么的不重要。一般如果仅仅是希望有空隙，还是去设置item的margin方便。 最后的效果是：\nok，看到这，你可能还觉得RecyclerView不够强大？\n但是如果我们有这么个需求，纵屏的时候显示为ListView，横屏的时候显示两列的GridView，我们RecyclerView可以轻松搞定，而如果使用ListView去实现还是需要点功夫的~~~\n当然了，这只是皮毛，下面让你心服口服。\nStaggeredGridLayoutManager 瀑布流式的布局，其实他可以实现GridLayoutManager一样的功能，仅仅按照下列代码：\n`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// mRecyclerView.setLayoutManager(new GridLayoutManager(this,4));\u0026amp;lt;/span\u0026gt; mRecyclerView.setLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; StaggeredGridLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;, StaggeredGridLayoutManager.VERTICAL));` 这两种写法显示的效果是一致的，但是注意StaggeredGridLayoutManager构造的第二个参数传一个orientation，如果传入的是StaggeredGridLayoutManager.VERTICAL代表有多少列；那么传入的如果是StaggeredGridLayoutManager.HORIZONTAL就代表有多少行，比如本例如果改为：\n`mRecyclerView.setLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; StaggeredGridLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;, StaggeredGridLayoutManager.HORIZONTAL));` 那么效果为： 可以看到，固定为4行，变成了左右滑动。有一点需要注意，如果是横向的时候，item的宽度需要注意去设置，毕竟横向的宽度没有约束了，应为控件可以横向滚动了。\n如果你需要一样横向滚动的GridView，那么恭喜你。\nok，接下来准备看大招，如果让你去实现个瀑布流，最起码不是那么随意就可以实现的吧？但是，如果使用RecyclerView，分分钟的事。\n那么如何实现？其实你什么都不用做，只要使用StaggeredGridLayoutManager我们就已经实现了，只是上面的item布局我们使用了固定的高度，下面我们仅仅在适配器的onBindViewHolder方法中为我们的item设置个随机的高度（代码就不贴了，最后会给出源码下载地址），看看效果图：\n是不是棒棒哒，通过RecyclerView去实现ListView、GridView、瀑布流的效果基本上没有什么区别，而且可以仅仅通过设置不同的LayoutManager即可实现。\n还有更nice的地方，就在于item增加、删除的动画也是可配置的。接下来看一下ItemAnimator。\nItemAnimator ItemAnimator也是一个抽象类，好在系统为我们提供了一种默认的实现类，期待系统多\n添加些默认的实现。\n借助默认的实现，当Item添加和移除的时候，添加动画效果很简单:\n`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 设置item动画\u0026amp;lt;/span\u0026gt; mRecyclerView.setItemAnimator(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DefaultItemAnimator()); `系统为我们提供了一个默认的实现，我们为我们的瀑布流添加以上一行代码，效果为： 如果是GridLayoutManager呢？动画效果为：\n注意，这里更新数据集不是用adapter.notifyDataSetChanged()而是\nnotifyItemInserted(position)与notifyItemRemoved(position)\n否则没有动画效果。\n上述为adapter中添加了两个方法：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;addData\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position) { mDatas.add(position, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Insert One\u0026#34;\u0026amp;lt;/span\u0026gt;); notifyItemInserted(position); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;removeData\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position) { mDatas.remove(position); notifyItemRemoved(position); }` Activity中点击MenuItem触发：\n` \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreateOptionsMenu\u0026amp;lt;/span\u0026gt;(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreateOptionsMenu(menu); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onOptionsItemSelected\u0026amp;lt;/span\u0026gt;(MenuItem item) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (item.getItemId()) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; R.id.id_action_add: mAdapter.addData(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; R.id.id_action_delete: mAdapter.removeData(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; }` 好了，到这我对这个控件已经不是一般的喜欢了~~~\n当然了只提供了一种动画，那么我们肯定可以去自定义各种nice的动画效果。\n高兴的是，github上已经有很多类似的项目了，这里我们直接引用下：RecyclerViewItemAnimators，大家自己下载查看。\n提供了SlideInOutLeftItemAnimator,SlideInOutRightItemAnimator,\nSlideInOutTopItemAnimator,SlideInOutBottomItemAnimator等动画效果。\nClick and LongClick 不过一个挺郁闷的地方就是，系统没有提供ClickListener和LongClickListener。\n不过我们也可以自己去添加，只是会多了些代码而已。\n实现的方式比较多，你可以通过mRecyclerView.addOnItemTouchListener去监听然后去判断手势，\n当然你也可以通过adapter中自己去提供回调，这里我们选择后者，前者的方式，大家有兴趣自己去实现。\n那么代码也比较简单：\n`class HomeAdapter extends RecyclerView.Adapter\u0026amp;lt;HomeAdapter.MyViewHolder\u0026amp;gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;interface\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;OnItemClickLitener\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; onItemClick(View view, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; onItemLongClick(View view , \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; OnItemClickLitener mOnItemClickLitener; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setOnItemClickLitener\u0026amp;lt;/span\u0026gt;(OnItemClickLitener mOnItemClickLitener) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.mOnItemClickLitener = mOnItemClickLitener; } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onBindViewHolder\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; MyViewHolder holder, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position) { holder.tv.setText(mDatas.get(position)); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果设置了回调，则设置点击事件\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mOnItemClickLitener != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { holder.itemView.setOnClickListener(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; OnClickListener() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onClick\u0026amp;lt;/span\u0026gt;(View v) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; pos = holder.getLayoutPosition(); mOnItemClickLitener.onItemClick(holder.itemView, pos); } }); holder.itemView.setOnLongClickListener(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; OnLongClickListener() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onLongClick\u0026amp;lt;/span\u0026gt;(View v) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; pos = holder.getLayoutPosition(); mOnItemClickLitener.onItemLongClick(holder.itemView, pos); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; } }); } } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//...\u0026amp;lt;/span\u0026gt; } `adapter中自己定义了个接口，然后在onBindViewHolder中去为holder.itemView去设置相应 的监听最后回调我们设置的监听。\n最后别忘了给item添加一个drawable:\n`\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;selector\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:state_pressed\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;true\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:drawable\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@color/color_item_press\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:drawable\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@color/color_item_normal\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;selector\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` Activity中去设置监听：\n` mAdapter.setOnItemClickLitener(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; OnItemClickLitener() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onItemClick\u0026amp;lt;/span\u0026gt;(View view, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position) { Toast.makeText(HomeActivity.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, position + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; click\u0026#34;\u0026amp;lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onItemLongClick\u0026amp;lt;/span\u0026gt;(View view, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position) { Toast.makeText(HomeActivity.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, position + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; long click\u0026#34;\u0026amp;lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); mAdapter.removeData(position); } });` 测试效果：\nok，到此我们基本介绍了RecylerView常见用法，包含了：\n系统提供了几种LayoutManager的使用； 如何通过自定义ItemDecoration去设置分割线，或者一些你想作为分隔的drawable，注意这里\n巧妙的使用了系统的listDivider属性，你可以尝试添加使用divider和dividerHeight属性。 如何使用ItemAnimator为RecylerView去添加Item移除、添加的动画效果。 介绍了如何添加ItemClickListener与ItemLongClickListener。 可以看到RecyclerView可以实现：\nListView的功能 GridView的功能 横向ListView的功能，参考Android 自定义RecyclerView 实现真正的Gallery效果 横向ScrollView的功能 瀑布流效果 便于添加Item增加和移除动画 整个体验下来，感觉这种插拔式的设计太棒了，如果系统再能提供一些常用的分隔符，多添加些动画效果就更好了。\n通过简单改变下LayoutManager，就可以产生不同的效果，那么我们可以根据手机屏幕的宽度去动态设置LayoutManager，屏幕宽度一般的，显示为ListView；宽度稍大的显示两列的GridView或者瀑布流（或者横纵屏幕切换时变化，有点意思~）；显示的列数和宽度成正比。甚至某些特殊屏幕，让其横向滑动~~再选择一个nice的动画效果，相信这种插件式的编码体验一定会让你迅速爱上RecyclerView。\n参考资料 Android 自定义RecyclerView 实现真正的Gallery效果\nA First Glance at Android’s RecyclerView\nhttps://github.com/gabrielemariotti/RecyclerViewItemAnimators\nDividerItemDecoration\n转自：http://blog.csdn.net/lmj623565791/article/details/45059587；\n参考补充：http://www.jianshu.com/p/df4430c2a4a8\n修正的ItemDecoration\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.content.Context; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Canvas; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Paint; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Rect; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.annotation.ColorRes; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.GridLayoutManager; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView.ItemDecoration; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.StaggeredGridLayoutManager; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.View; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * Created by Mark on 2017/6/2. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;GridItemDecoration\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ItemDecoration\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ Paint mVerPaint, mHorPaint; Builder mBuilder; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;GridItemDecoration\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Builder builder)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ init(builder); } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;init\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Builder builder)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.mBuilder = builder; mVerPaint = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Paint(Paint.ANTI_ALIAS_FLAG); mVerPaint.setStyle(Paint.Style.FILL); mVerPaint.setColor(builder.verColor); mHorPaint = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Paint(Paint.ANTI_ALIAS_FLAG); mHorPaint.setStyle(Paint.Style.FILL); mHorPaint.setColor(builder.horColor); } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawHorizontal\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Canvas c, RecyclerView parent)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount = parent.getChildCount(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; childCount; i++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mBuilder.isExistHeadView \u0026amp;\u0026amp; i == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;continue\u0026amp;lt;/span\u0026gt;; View child = parent.getChildAt(i); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left = child.getLeft() - params.leftMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right = child.getRight() + params.rightMargin + mBuilder.dividerVerSize; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top = child.getBottom() + params.bottomMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom = top + mBuilder.dividerHorSize; c.drawRect(left, top, right, bottom, mHorPaint); } } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawVertical\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Canvas c, RecyclerView parent)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount = parent.getChildCount(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; childCount; i++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mBuilder.isExistHeadView \u0026amp;\u0026amp; i == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;continue\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; View child = parent.getChildAt(i); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top = child.getTop() - params.topMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom = child.getBottom() + params.bottomMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left = child.getRight() + params.rightMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right = left + mBuilder.dividerVerSize; c.drawRect(left, top, right, bottom, mVerPaint); } } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getSpanCount\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(RecyclerView parent)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 列数\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; spanCount = -\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;; RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; GridLayoutManager) { spanCount = ((GridLayoutManager) layoutManager).getSpanCount(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; StaggeredGridLayoutManager) { spanCount = ((StaggeredGridLayoutManager) layoutManager) .getSpanCount(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; spanCount; } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;isLastRaw\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(RecyclerView parent, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; pos, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; spanCount, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; GridLayoutManager) { childCount = childCount - childCount % spanCount; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (pos \u0026amp;gt;= childCount) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; StaggeredGridLayoutManager) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; orientation = ((StaggeredGridLayoutManager) layoutManager) .getOrientation(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// StaggeredGridLayoutManager 且纵向滚动\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (orientation == StaggeredGridLayoutManager.VERTICAL) { childCount = childCount - childCount % spanCount; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (pos \u0026amp;gt;= childCount) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// StaggeredGridLayoutManager 且横向滚动\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; ((pos + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) % spanCount == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-meta\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDraw\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Canvas c, RecyclerView parent, RecyclerView.State state)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onDraw(c, parent, state); drawHorizontal(c, parent); drawVertical(c, parent); } \u0026amp;lt;span class=\u0026#34;hljs-meta\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getItemOffsets\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.getItemOffsets(outRect, view, parent, state); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; spanCount = getSpanCount(parent); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount = parent.getAdapter().getItemCount(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mBuilder.isExistHeadView) itemPosition -= \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (itemPosition \u0026amp;lt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; column = itemPosition % spanCount; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left = column * mBuilder.dividerVerSize / spanCount; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right = mBuilder.dividerVerSize - (column + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) * mBuilder.dividerVerSize / spanCount; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!(isLastRaw(parent, itemPosition, spanCount, childCount) \u0026amp;\u0026amp; !mBuilder.isShowLastDivider)) bottom = mBuilder.dividerHorSize; outRect.set(left, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, right, bottom); marginOffsets(outRect, spanCount, itemPosition); } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;marginOffsets\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Rect outRect, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; spanCount, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; itemPosition)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mBuilder.marginRight == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; mBuilder.marginLeft == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; itemShrink = (mBuilder.marginLeft + mBuilder.marginRight) / spanCount; outRect.left += (mBuilder.marginLeft - (itemPosition % spanCount) * itemShrink); outRect.right += ((itemPosition % spanCount) + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) * itemShrink - mBuilder.marginLeft; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Builder\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; Context c; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; horColor; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; verColor; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; dividerHorSize; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; dividerVerSize; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; marginLeft, marginRight; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; isShowLastDivider = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; isExistHeadView = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Builder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context c)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.c = c; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 设置divider的颜色 * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; color * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Builder \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;color\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(@ColorRes \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; color)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.horColor = c.getResources().getColor(color); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.verColor = c.getResources().getColor(color); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 单独设置横向divider的颜色 * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; horColor * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Builder \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;horColor\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(@ColorRes \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; horColor)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.horColor = c.getResources().getColor(horColor); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 单独设置纵向divider的颜色 * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; verColor * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Builder \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;verColor\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(@ColorRes \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; verColor)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.verColor = c.getResources().getColor(verColor); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 设置divider的宽度 * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; size * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Builder \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;size\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; size)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.dividerHorSize = size; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.dividerVerSize = size; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 设置横向divider的宽度 * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; horSize * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Builder \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;horSize\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; horSize)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.dividerHorSize = horSize; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 设置纵向divider的宽度 * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; verSize * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Builder \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;verSize\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; verSize)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.dividerVerSize = verSize; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 设置剔除HeadView的RecyclerView左右两边的外间距 * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; marginLeft * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; marginRight * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Builder \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;margin\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; marginLeft, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; marginRight)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.marginLeft = marginLeft; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.marginRight = marginRight; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 最后一行divider是否需要显示 * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; isShow * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Builder \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;showLastDivider\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; isShow)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.isShowLastDivider = isShow; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 是否包含HeadView * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; isExistHead * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Builder \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;isExistHead\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; isExistHead)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.isExistHeadView = isExistHead; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; GridItemDecoration \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;build\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; GridItemDecoration(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;); } } }` ","permalink":"https://blog.zdltech.com/posts/android-recyclerview-%E4%BD%BF%E7%94%A8%E5%AE%8C%E5%85%A8%E8%A7%A3%E6%9E%90-%E4%BD%93%E9%AA%8C%E8%89%BA%E6%9C%AF%E8%88%AC%E7%9A%84%E6%8E%A7%E4%BB%B6-2/","summary":"\u003cp\u003e\u003ca target=\"_blank\" name=\"t0\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"概述\"\u003e概述\u003c/h3\u003e\n\u003cp\u003eRecyclerView出现已经有一段时间了，相信大家肯定不陌生了，大家可以通过导入support-v7对其进行使用。\u003cbr\u003e\n据官方的介绍，该控件用于在有限的窗口中展示大量数据集，其实这样功能的控件我们并不陌生，例如：ListView、GridView。\u003c/p\u003e\n\u003cp\u003e那么有了ListView、GridView为什么还需要RecyclerView这样的控件呢？整体上看RecyclerView\u003ca href=\"http://lib.csdn.net/base/architecture\"\u003e架构\u003c/a\u003e，提供了一种插拔式的体验，高度的解耦，异常的灵活，通过设置它提供的不同LayoutManager，ItemDecoration , ItemAnimator实现令人瞠目的效果。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e你想要控制其显示的方式，请通过布局管理器LayoutManager\u003c/li\u003e\n\u003cli\u003e你想要控制Item间的间隔（可绘制），请通过ItemDecoration\u003c/li\u003e\n\u003cli\u003e你想要控制Item增删的动画，请通过ItemAnimator\u003c/li\u003e\n\u003cli\u003e你想要控制点击、长按事件，请自己写（擦，这点尼玛。）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"基本使用\"\u003e\u003ca target=\"_blank\" name=\"t1\"\u003e\u003c/a\u003e基本使用\u003c/h3\u003e\n\u003cp\u003e鉴于我们对于ListView的使用特别的熟悉，对比下RecyclerView的使用代码：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`mRecyclerView = findView(R.id.id_recyclerview);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置布局管理器\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emRecyclerView.setLayoutManager(layout);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置adapter\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emRecyclerView.setAdapter(adapter)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置Item增加、移除动画\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emRecyclerView.setItemAnimator(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DefaultItemAnimator());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//添加分割线\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emRecyclerView.addItemDecoration(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DividerItemDecoration(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                getActivity(), DividerItemDecoration.HORIZONTAL_LIST));`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eok，相比较于ListView的代码，ListView可能只需要去设置一个adapter就能正常使用了。而RecyclerView基本需要上面一系列的步骤，那么为什么会添加这么多的步骤呢？\u003c/p\u003e\n\u003cp\u003e那么就必须解释下RecyclerView的这个名字了，从它类名上看，RecyclerView代表的意义是，我只管Recycler View，也就是说RecyclerView只管回收与复用View，其他的你可以自己去设置。可以看出其高度的解耦，给予你充分的定制自由（所以你才可以轻松的通过这个控件实现ListView,GirdView，瀑布流等效果）。\u003c/p\u003e\n\u003ch3 id=\"just-like-listview\"\u003e\u003ca target=\"_blank\" name=\"t2\"\u003e\u003c/a\u003eJust like ListView\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eActivity\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epackage\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ezhy\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esample\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edemo_recyclerview;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e java\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eutil\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eArrayList;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e java\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eutil\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eList;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eos\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBundle;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eActionBarActivity;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLinearLayoutManager;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eRecyclerView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eRecyclerView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eViewHolder;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLayoutInflater;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eViewGroup;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eTextView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-class\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eHomeActivity\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eActionBarActivity\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eprivate\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e RecyclerView mRecyclerView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eprivate\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e List\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;String\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt; mDatas;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eprivate\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e HomeAdapter mAdapter;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-annotation\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@Override\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eprotected\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eonCreate\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(Bundle savedInstanceState)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003esuper\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;.\u003c/span\u003eonCreate(savedInstanceState);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        setContentView(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elayout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eactivity_single_recyclerview);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        initData();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mRecyclerView \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (RecyclerView) findViewById(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid_recyclerview);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mRecyclerView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetLayoutManager(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e LinearLayoutManager(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ethis\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mRecyclerView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetAdapter(mAdapter \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e HomeAdapter());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eprotected\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003einitData\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mDatas \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e ArrayList\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;String\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eint\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e i \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;A\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e; i \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt; \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;z\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e; i\u003cspan style=\"color:#ff79c6\"\u003e++\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mDatas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eadd(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e (\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003echar\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e) i);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e HomeAdapter \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e RecyclerView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAdapter\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;HomeAdapter\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMyViewHolder\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-annotation\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@Override\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e MyViewHolder \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eonCreateViewHolder\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(ViewGroup parent, \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eint\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e viewType)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            MyViewHolder holder \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e MyViewHolder(LayoutInflater\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003efrom(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    HomeActivity\u003cspan style=\"color:#ff79c6\"\u003e.\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ethis\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003einflate(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elayout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eitem_home, parent,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e holder;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-annotation\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@Override\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eonBindViewHolder\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(MyViewHolder holder, \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eint\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e position)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            holder\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etv\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetText(mDatas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(position));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-annotation\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@Override\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eint\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003egetItemCount\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e mDatas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esize();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e MyViewHolder \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e ViewHolder\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            TextView tv;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eMyViewHolder\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(View view)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003esuper\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(view);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                tv \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (TextView) view\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003efindViewById(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid_num);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003eActivity的布局文件\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-tag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eRelativeLayout\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003exmlns:android\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003exmlns:tools\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://schemas.android.com/tools\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_width\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;match_parent\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_height\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;match_parent\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-tag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eRecyclerView\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:id\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;@+id/id_recyclerview\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:divider\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;#ffff0000\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:dividerHeight\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;10dp\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_width\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;match_parent\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_height\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;match_parent\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-tag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eRelativeLayout\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003eItem的布局文件\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;FrameLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#44ff0000\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;TextView\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/span\u0026gt;        \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/id_num\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;50dp\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;center\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:text\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;1\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;FrameLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这么看起来用法与ListView的代码基本一致哈~~\u003cbr\u003e\n看下效果图：\u003c/p\u003e","title":"Android RecyclerView 使用完全解析 体验艺术般的控件"},{"content":"Android开发中Gradle配置使用 前言 每次创建私有项目都需要配置gradle文件，没什么技术含量，还要多劳动（程序员就是懒），为了能方便使用，才有了本仓库的诞生。 欢迎各位小伙伴们来砸场，喜欢请star下…\n私有仓库使用 在下载config.properties文件放到工厂根目录（和gradle.properties同级） 如果使用Artifactory仓库配置工程build.gradle文件请看详细文件 在项目build.gradle文件中使用 apply from:\u0026amp;#39;https://coding.net/u/zdl_411437734/p/gradle/git/raw/master/nexusBintry.gradle\u0026amp;#39; 或者 apply from:\u0026amp;#39;https://coding.net/u/zdl_411437734/p/gradle/git/raw/master/artifactBintry.gradle\u0026amp;#39; 执行相关命令即可 gradle uploadArchives （nexus仓库） 或者 gradle assembleRelease artifactoryPublish (artifactory仓库) 详细使用文档\nSonarqube使用 详细使用文档\npack（打包）使用 经常打包apk，有一个困扰，怎么修改打包后的名称，怎么区分打包的是release版本还是debug版本，想了解请继续看\n在项目的buil.gradle文件配置打包的版本和输出的名称 //打包APK根据不同的环境打包不同的名称 ext{ productName = project.name versionName = \u0026quot;1.0.1\u0026quot; } //productName 打包出来的名称 //versionName 打包显示版本号 2 . 引入packe.gradle文件下载packe.gradle\napply from:\u0026quot;./pack.gradle\u0026quot; 或者 apply from:\u0026quot;https://coding.net/u/zdl_411437734/p/gradle/git/raw/master/pack.gradle\u0026quot; 3 . 打包即可（~~）\nsign（签名）使用 有时候，在集成第三方时候，需要我们输入签名，在开发中和发布中一般默认都是2个keystroe，在这种情况下，开发很不方便，不断要打包成正式包才能测试，为了解决这个问题，我们配置gradle在开发时就使用正式签名开发，想了解请继续看\n在项目的buil.gradle文件配置打包的版本和输出的名称 //打包APK根据不同的环境打包不同的名称 ext{ productName = \u0026quot;CommonProject\u0026quot; versionName = \u0026quot;2.0.1\u0026quot; keyPassword = \u0026quot;android\u0026quot; keyFilePath = \u0026quot;/Users/jason/Documents/keystore/android.keystore\u0026quot; storePassword = \u0026quot;android\u0026quot; keyAlias = \u0026quot;android\u0026quot; } //productName 打包出来的名称 //versionName 打包显示版本号 //keyPassword 密码 //keyFilePath 正式全路径 //storePassword 密码 //keyAlias 别名 2 . 引入sign.gradle文件下载sign.gradle\napply from:\u0026quot;./sign.gradle\u0026quot; 或者 apply from:\u0026quot;https://coding.net/u/zdl_411437734/p/gradle/git/raw/master/sign.gradle\u0026quot; 3 . 配置项目中build.gradle文件\nbuildTypes { release { signingConfig signingConfigs.releaseConfig } debug { signingConfig signingConfigs.debugConfig } } //在 android{}中配置buildTypes 配置文件 不想使用提供的在线的文件配置，请自行copy下面的内容放入自己的工程中 artifactory仓库使用配置文件artifactBintry.gradle 下载\nNexus参考配置文件nexusBintry.gradle 下载\nConfig.properties配置文件config.properties 下载\nNexus仓库配置文件(简易版)bintray.gradle 下载\nSonarqube配置文件sonarqube.gradle 下载\npack配置文件pack.gradle 下载\n联系我们 Email:411437734@qq.com\n个人博客：http://www.etongwl.com\n","permalink":"https://blog.zdltech.com/posts/androidgradle/","summary":"\u003ch1 id=\"toc_0\"\u003eAndroid开发中Gradle配置使用\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://img.shields.io/badge/AnroidGradleTools-V1.0.0-green.svg\"\u003e\u003c/p\u003e\n\u003ch5 id=\"toc_1\"\u003e前言\u003c/h5\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cfont size=\"2\"\u003e每次创建私有项目都需要配置gradle文件，没什么技术含量，还要多劳动（程序员就是懒），为了能方便使用，才有了本仓库的诞生。\n欢迎各位小伙伴们来砸场，喜欢请star下…\u003c/font\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"toc_2\"\u003e私有仓库使用\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e在下载config.properties文件放到工厂根目录（和gradle.properties同级）\u003c/li\u003e\n\u003cli\u003e如果使用Artifactory仓库配置工程build.gradle文件请看详细文件\u003c/li\u003e\n\u003cli\u003e在项目build.gradle文件中使用\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003eapply from:\u0026amp;#39;https://coding.net/u/zdl_411437734/p/gradle/git/raw/master/nexusBintry.gradle\u0026amp;#39;\n    或者\napply from:\u0026amp;#39;https://coding.net/u/zdl_411437734/p/gradle/git/raw/master/artifactBintry.gradle\u0026amp;#39;\n\u003c/code\u003e\u003c/pre\u003e\n\u003col\u003e\n\u003cli\u003e执行相关命令即可\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003egradle uploadArchives （nexus仓库）\n或者\ngradle assembleRelease artifactoryPublish (artifactory仓库)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"https://coding.net/u/zdl_411437734/p/gradle/git/blob/master/Maven.md\"\u003e详细使用文档\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"toc_3\"\u003eSonarqube使用\u003c/h3\u003e\n\u003cp\u003e\u003ca href=\"https://coding.net/u/zdl_411437734/p/gradle/git/blob/master/SONARQUBE.md\"\u003e详细使用文档\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"toc_4\"\u003epack（打包）使用\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cfont size=\"2\"\u003e经常打包apk，有一个困扰，怎么修改打包后的名称，怎么区分打包的是release版本还是debug版本，想了解请继续看\u003c/font\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003col\u003e\n\u003cli\u003e在项目的buil.gradle文件配置打包的版本和输出的名称\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e//打包APK根据不同的环境打包不同的名称\next{\n    productName = project.name\n    versionName = \u0026quot;1.0.1\u0026quot;\n}\n//productName 打包出来的名称\n//versionName 打包显示版本号\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e2 . 引入packe.gradle文件\u003ca href=\"http://zdl_411437734.coding.me/gradle/pack.gradle\"\u003e下载packe.gradle\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eapply from:\u0026quot;./pack.gradle\u0026quot;\n或者\napply from:\u0026quot;https://coding.net/u/zdl_411437734/p/gradle/git/raw/master/pack.gradle\u0026quot;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e3 . 打包即可（~~）\u003c/p\u003e\n\u003ch3 id=\"toc_5\"\u003esign（签名）使用\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cfont size=\"2\"\u003e有时候，在集成第三方时候，需要我们输入签名，在开发中和发布中一般默认都是2个keystroe，在这种情况下，开发很不方便，不断要打包成正式包才能测试，为了解决这个问题，我们配置gradle在开发时就使用正式签名开发，想了解请继续看\u003c/font\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003col\u003e\n\u003cli\u003e在项目的buil.gradle文件配置打包的版本和输出的名称\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e//打包APK根据不同的环境打包不同的名称\next{\n    productName = \u0026quot;CommonProject\u0026quot;\n    versionName = \u0026quot;2.0.1\u0026quot;\n    keyPassword = \u0026quot;android\u0026quot;\n    keyFilePath = \u0026quot;/Users/jason/Documents/keystore/android.keystore\u0026quot;\n    storePassword = \u0026quot;android\u0026quot;\n    keyAlias = \u0026quot;android\u0026quot;\n}\n\n//productName 打包出来的名称\n//versionName 打包显示版本号\n//keyPassword 密码\n//keyFilePath 正式全路径\n//storePassword 密码\n//keyAlias 别名\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e2 . 引入sign.gradle文件\u003ca href=\"http://zdl_411437734.coding.me/gradle/sign.gradle\"\u003e下载sign.gradle\u003c/a\u003e\u003c/p\u003e","title":"Android开发中Gradle配置使用"},{"content":"`sudo brew uninstall node brew update brew upgrade brew cleanup brew install node sudo chown -R 用户组（一般当前用户名） /usr/local brew link --overwrite node` ","permalink":"https://blog.zdltech.com/posts/brew-%E4%B8%ADnode-7-6-0-already-installed-its-just-not-linked-%E9%94%99%E8%AF%AF%E4%BF%AE%E6%94%B9/","summary":"\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`sudo brew uninstall node\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ebrew update\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ebrew upgrade\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ebrew cleanup\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ebrew install node\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo chown -R 用户组（一般当前用户名） /usr/local\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ebrew link --overwrite node`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"brew 中node-7.6.0 already installed, it’s just not linked.错误修改"},{"content":"实现方法很简单，根据图片文件的宽度与ImageView的宽度比例关系算出ImageView的高度。\npackage com.etongwl.commonlibs.view; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.NinePatchDrawable; import android.util.AttributeSet; import android.view.ViewGroup; import android.widget.ImageView; /* * @Override public void setImageDrawable(final Drawable drawable) { super.setImageDrawable(drawable); if (drawable != null) { post(new Runnable() { @Override public void run() { float mWidth = getWidth(); float pWidth = drawable.getBounds().width(); float pHeight = drawable.getBounds().height(); int mHeight = (int) ((mWidth / pWidth) * pHeight); LayoutParams params = getLayoutParams(); params.height = mHeight; params.width = (int) mWidth; setLayoutParams(params); } }); } } 首先, 如果drawable不为空, 则通过drawable.getBounds()去获取drawable边界的宽和高. 在根据ImageView的宽与drawable的宽的比例去计算高度, 最后通过LayoutParams设置ImageView的高度 * */ /* \u0026amp;lt;com.etongwl.commonlibs.view.AdaptiveImageView android:id=\u0026#34;@+id/detail_image\u0026#34; android:layout_width=\u0026#34;wrap_content\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:layout_gravity=\u0026#34;center\u0026#34; android:layout_marginTop=\u0026#34;15dp\u0026#34; android:scaleType=\u0026#34;centerCrop\u0026#34; android:background=\u0026#34;@drawable/diandianxinwen\u0026#34; android:visibility=\u0026#34;visible\u0026#34; /\u0026amp;gt; */ /** * 按比例缩放 */ @SuppressLint(\u0026#34;AppCompatCustomView\u0026#34;) public class AdaptiveImageView extends ImageView { // 控件默认长、宽 private int defaultWidth = 0; private int defaultHeight = 0; // 比例 private float scale = 0; public AdaptiveImageView(Context context) { super(context); } public AdaptiveImageView(Context context, AttributeSet attrs) { super(context, attrs); } public AdaptiveImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (drawable == null) { return; } if (getWidth() == 0 || getHeight() == 0) { return; } this.measure(0, 0); if (drawable.getClass() == NinePatchDrawable.class) return; Bitmap b = ((BitmapDrawable) drawable).getBitmap(); Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true); if (bitmap.getWidth() == 0 || bitmap.getHeight() == 0) { return; } if (defaultWidth == 0) { defaultWidth = getWidth(); } if (defaultHeight == 0) { defaultHeight = getHeight(); } scale = (float) defaultWidth / (float) bitmap.getWidth(); defaultHeight = Math.round(bitmap.getHeight() * scale); ViewGroup.LayoutParams params = this.getLayoutParams(); params.width = defaultWidth; params.height = defaultHeight; this.setLayoutParams(params); super.onDraw(canvas); } } 简单实现ImageView宽度填满屏幕，高度自适应的两种方式 两种方式 1.重写View的onMeasure方法参考这里easion_zms的专栏 核心代码\n2.设置ImageView的属性： //宽度填满屏幕 android:layout_width=”match_parent” android:scaleType=”fitXY” android:layout_height=”wrap_content” //保持比例，一定要设置 android:adjustViewBounds=”true”\nAndroid ImageView图片自适应\n\u0026lt;ImageView\nandroid:id=”@+id/dynamic_item_image”\nandroid:layout_width=”wrap_content”\nandroid:layout_height=”wrap_content”\nandroid:layout_gravity=”top”\nandroid:layout_marginTop=”5dip”\nandroid:adjustViewBounds=”true”\nandroid:background=”@drawable/imageview_background” /\u0026gt;\n另外，android:background=”@drawable/imageview_background”是给图片加了一个边框，其中\nimageview_background.xml:\n\u003c?xml version=\u0026#8221;1.0\u0026#8243; encoding=\u0026#8221;utf-8\u0026#8243;?\u003e \u0026lt;shape xmlns:android=”http://schemas.android.com/apk/res/android”\u0026gt; ImageView属性说明：\n1、类概述\n显示任意图像，例如图标。ImageView类可以加载各种来源的图片（如资源或图片库），需要计算图像的尺寸，比便它可以在其他布局中使用，并提供例如缩放和着色（渲染）各种显示选项。\n2、XML属性\n属性名称 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 描述 \u0026lt;/td\u0026gt; android:adjustViewBounds \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 是否保持宽高比。需要与maxWidth、MaxHeight一起使用，否则单独使用没有效果。 \u0026lt;/td\u0026gt; android:cropToPadding \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 是否截取指定区域用空白代替。单独设置无效果，需要与scrollY一起使用，效果如下，实现代码见代码部分： [\u0026lt;img loading=\u0026quot;lazy\u0026quot; decoding=\u0026quot;async\u0026quot; style=\u0026quot;border: 0px; max-width: 100%; vertical-align: middle;\u0026quot; title=\u0026quot;Android \u0026lt;wbr\u0026gt;ImageView图片自适应\u0026quot; src=\u0026quot;http://static.open-open.com/lib/uploadImg/20140506/20140506225808_136.jpg\u0026quot; alt=\u0026quot;Android ImageView图片自适应\u0026quot; width=\u0026quot;153\u0026quot; height=\u0026quot;80\u0026quot; /\u0026gt;](http://static.oschina.net/uploads/img/201405/06143901_RjRg.jpg) \u0026amp;nbsp; \u0026lt;/td\u0026gt; android:maxHeight \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 设置View的最大高度，单独使用无效，需要与setAdjustViewBounds一起使用。如果想设置图片固定大小，又想保持图片宽高比，需要如下设置： 1） 设置setAdjustViewBounds为true； 2） 设置maxWidth、MaxHeight； 3） 设置设置layout_width和layout_height为wrap_content。 \u0026lt;/td\u0026gt; android:maxWidth \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 设置View的最大宽度。同上。 \u0026lt;/td\u0026gt; android:scaleType \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 设置图片的填充方式。 \u0026lt;table class=\u0026quot;ke-zeroborder \u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; matrix \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 用矩阵来绘图 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; fitXY \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 1 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 拉伸图片（不按比例）以填充View的宽高 [\u0026lt;img loading=\u0026quot;lazy\u0026quot; decoding=\u0026quot;async\u0026quot; style=\u0026quot;border: 0px; max-width: 100%; vertical-align: middle;\u0026quot; title=\u0026quot;Android \u0026lt;wbr\u0026gt;ImageView图片自适应\u0026quot; src=\u0026quot;http://static.open-open.com/lib/uploadImg/20140506/20140506225808_94.png\u0026quot; alt=\u0026quot;Android ImageView图片自适应\u0026quot; width=\u0026quot;120\u0026quot; height=\u0026quot;30\u0026quot; /\u0026gt;](http://static.oschina.net/uploads/img/201405/06143901_f9F7.png) \u0026amp;nbsp; \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; layout_ height :30px layout_ width :120px \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; fitStart \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 2 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 按比例拉伸图片，拉伸后图片的高度为View的高度，且显示在View的左边 [\u0026lt;img loading=\u0026quot;lazy\u0026quot; decoding=\u0026quot;async\u0026quot; style=\u0026quot;border: 0px; max-width: 100%; vertical-align: middle;\u0026quot; title=\u0026quot;Android \u0026lt;wbr\u0026gt;ImageView图片自适应\u0026quot; src=\u0026quot;http://static.open-open.com/lib/uploadImg/20140506/20140506225808_131.png\u0026quot; alt=\u0026quot;Android ImageView图片自适应\u0026quot; width=\u0026quot;120\u0026quot; height=\u0026quot;30\u0026quot; /\u0026gt;](http://static.oschina.net/uploads/img/201405/06143901_FjUd.png) \u0026amp;nbsp; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; fitCenter \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 3 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 按比例拉伸图片，拉伸后图片的高度为View的高度，且显示在View的中间 [\u0026lt;img loading=\u0026quot;lazy\u0026quot; decoding=\u0026quot;async\u0026quot; style=\u0026quot;border: 0px; max-width: 100%; vertical-align: middle;\u0026quot; title=\u0026quot;Android \u0026lt;wbr\u0026gt;ImageView图片自适应\u0026quot; src=\u0026quot;http://static.open-open.com/lib/uploadImg/20140506/20140506225808_201.png\u0026quot; alt=\u0026quot;Android ImageView图片自适应\u0026quot; width=\u0026quot;120\u0026quot; height=\u0026quot;30\u0026quot; /\u0026gt;](http://static.oschina.net/uploads/img/201405/06143901_c4jh.png) \u0026amp;nbsp; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; fitEnd \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 4 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 按比例拉伸图片，拉伸后图片的高度为View的高度，且显示在View的右边 [\u0026lt;img loading=\u0026quot;lazy\u0026quot; decoding=\u0026quot;async\u0026quot; style=\u0026quot;border: 0px; max-width: 100%; vertical-align: middle;\u0026quot; title=\u0026quot;Android \u0026lt;wbr\u0026gt;ImageView图片自适应\u0026quot; src=\u0026quot;http://static.open-open.com/lib/uploadImg/20140506/20140506225808_509.png\u0026quot; alt=\u0026quot;Android ImageView图片自适应\u0026quot; width=\u0026quot;120\u0026quot; height=\u0026quot;30\u0026quot; /\u0026gt;](http://static.oschina.net/uploads/img/201405/06143901_aCWp.png) \u0026amp;nbsp; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; center \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 5 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 按原图大小显示图片，但图片宽高大于View的宽高时，截图图片中间部分显示[\u0026lt;img loading=\u0026quot;lazy\u0026quot; decoding=\u0026quot;async\u0026quot; style=\u0026quot;border: 0px; max-width: 100%; vertical-align: middle;\u0026quot; title=\u0026quot;Android \u0026lt;wbr\u0026gt;ImageView图片自适应\u0026quot; src=\u0026quot;http://static.open-open.com/lib/uploadImg/20140506/20140506225808_219.png\u0026quot; alt=\u0026quot;Android ImageView图片自适应\u0026quot; width=\u0026quot;80\u0026quot; height=\u0026quot;60\u0026quot; /\u0026gt;](http://static.oschina.net/uploads/img/201405/06143901_Rzoa.png) \u0026amp;nbsp; \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; \u0026amp;nbsp; layout_ height :60px layout_ width :80px padding :10px \u0026amp;nbsp; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; centerCrop \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 6 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 按比例放大原图直至等于某边View的宽高显示。[\u0026lt;img loading=\u0026quot;lazy\u0026quot; decoding=\u0026quot;async\u0026quot; style=\u0026quot;border: 0px; max-width: 100%; vertical-align: middle;\u0026quot; title=\u0026quot;Android \u0026lt;wbr\u0026gt;ImageView图片自适应\u0026quot; src=\u0026quot;http://static.open-open.com/lib/uploadImg/20140506/20140506225808_405.png\u0026quot; alt=\u0026quot;Android ImageView图片自适应\u0026quot; width=\u0026quot;80\u0026quot; height=\u0026quot;60\u0026quot; /\u0026gt;](http://static.oschina.net/uploads/img/201405/06143901_JPev.png) \u0026amp;nbsp; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; centerInside \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 7 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 当原图宽高或等于View的宽高时，按原图大小居中显示；反之将原图缩放至View的宽高居中显示。[\u0026lt;img loading=\u0026quot;lazy\u0026quot; decoding=\u0026quot;async\u0026quot; style=\u0026quot;border: 0px; max-width: 100%; vertical-align: middle;\u0026quot; title=\u0026quot;Android \u0026lt;wbr\u0026gt;ImageView图片自适应\u0026quot; src=\u0026quot;http://static.open-open.com/lib/uploadImg/20140506/20140506225809_159.png\u0026quot; alt=\u0026quot;Android ImageView图片自适应\u0026quot; width=\u0026quot;80\u0026quot; height=\u0026quot;60\u0026quot; /\u0026gt;](http://static.oschina.net/uploads/img/201405/06143902_UCBx.png) \u0026amp;nbsp; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/td\u0026gt; android:src \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 设置View的drawable(如图片，也可以是颜色，但是需要指定View的大小) \u0026lt;/td\u0026gt; android:tint \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 将图片渲染成指定的颜色。见下图： [\u0026lt;img loading=\u0026quot;lazy\u0026quot; decoding=\u0026quot;async\u0026quot; style=\u0026quot;border: 0px; max-width: 100%; vertical-align: middle;\u0026quot; title=\u0026quot;Android \u0026lt;wbr\u0026gt;ImageView图片自适应\u0026quot; src=\u0026quot;http://static.open-open.com/lib/uploadImg/20140506/20140506225809_434.jpg\u0026quot; alt=\u0026quot;Android ImageView图片自适应\u0026quot; width=\u0026quot;81\u0026quot; height=\u0026quot;69\u0026quot; /\u0026gt;](http://static.oschina.net/uploads/img/201405/06143902_dMaT.jpg) 左边为原图，右边为设置后的效果，见后面代码。 \u0026lt;/td\u0026gt; 原文地址：http://blog.sina.com.cn/s/blog_618199e60100y537.html\nandroid ImageView 宽度设定，高度自适应\n首先，需要给你的ImageView布局加上Android:adjustViewBounds=”true”\n\u0026lt;ImageView android:id=”@+id/test_image”\nandroid:layout_width=”wrap_content”\nandroid:layout_height=”wrap_content”\nandroid:scaleType=”fitXY”\nandroid:adjustViewBounds=”true”\nandroid:layout_gravity=”center”\nandroid:contentDescription=”@string/app_name”\nandroid:src=”@drawable/ic_launcher” /\u0026gt;\n然后，在代码里设置ImageView.最大宽度和最大高度，因为adjustViewBounds属性只有在设置了最大高度和最大宽度后才会起作用\nint screenWidth = getScreenWidth(this);\nViewGroup.LayoutParams lp = testImage.getLayoutParams();\nlp.width = screenWidth;\nlp.height = LayoutParams.WRAP_CONTENT;\ntestImage.setLayoutParams(lp);\ntestImage.setMaxWidth(screenWidth);\ntestImage.setMaxHeight(screenWidth * 5); 这里其实可以根据需求而定，我这里测试为最大宽度的5倍\n","permalink":"https://blog.zdltech.com/posts/%E8%87%AA%E5%AE%9A%E4%B9%89imageview-%E5%AE%BD%E5%BA%A6%E8%87%AA%E9%80%82%E5%BA%94%E5%B1%8F%E5%B9%95%E9%AB%98%E5%BA%A6%E7%AD%89%E6%AF%94%E7%BC%A9%E6%94%BE/","summary":"\u003cp\u003e实现方法很简单，根据图片文件的宽度与ImageView的宽度比例关系算出ImageView的高度。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epackage com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eetongwl\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecommonlibs\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eannotation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eSuppressLint;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003econtent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eContext;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBitmap;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eCanvas;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawable\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBitmapDrawable;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawable\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eDrawable;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawable\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eNinePatchDrawable;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eutil\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAttributeSet;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eViewGroup;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eImageView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e/*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public void setImageDrawable(final Drawable drawable) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetImageDrawable(drawable);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (drawable \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            post(new Runnable() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                @Override public void run() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    float mWidth \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e getWidth();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    float pWidth \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e drawable\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetBounds()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidth();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    float pHeight \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e drawable\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetBounds()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eheight();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    int mHeight \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (int) ((mWidth \u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e pWidth) \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e pHeight);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    LayoutParams params \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e getLayoutParams();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    params\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eheight \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e mHeight;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    params\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidth \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (int) mWidth;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    setLayoutParams(params);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            });\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    首先, 如果drawable不为空, 则通过drawable\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetBounds()去获取drawable边界的宽和高\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e 在根据ImageView的宽与drawable的宽的比例去计算高度, 最后通过LayoutParams设置ImageView的高度\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e/*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eetongwl\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecommonlibs\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAdaptiveImageView\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          android:id\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;@+id/detail_image\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          android:layout_width\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;wrap_content\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          android:layout_height\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;wrap_content\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          android:layout_gravity\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;center\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          android:layout_marginTop\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;15dp\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          android:scaleType\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;centerCrop\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          android:background\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;@drawable/diandianxinwen\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          android:visibility\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;visible\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 按比例缩放\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@SuppressLint(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;AppCompatCustomView\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e AdaptiveImageView \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e ImageView {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 控件默认长、宽\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private int defaultWidth \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private int defaultHeight \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 比例\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private float scale \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public AdaptiveImageView(Context context) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super(context);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public AdaptiveImageView(Context context, AttributeSet attrs) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super(context, attrs);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public AdaptiveImageView(Context context, AttributeSet attrs, int defStyle) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super(context, attrs, defStyle);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    protected void onDraw(Canvas canvas) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Drawable drawable \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e getDrawable();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (drawable \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (getWidth() \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e getHeight() \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        this\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emeasure(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (drawable\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetClass() \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e NinePatchDrawable\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Bitmap b \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e ((BitmapDrawable) drawable)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetBitmap();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Bitmap bitmap \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e b\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecopy(Bitmap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eConfig\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eARGB_8888, \u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (bitmap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetWidth() \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e bitmap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetHeight() \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (defaultWidth \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            defaultWidth \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e getWidth();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (defaultHeight \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            defaultHeight \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e getHeight();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        scale \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (float) defaultWidth \u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e (float) bitmap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetWidth();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        defaultHeight \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Math\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eround(bitmap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetHeight() \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e scale);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ViewGroup\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLayoutParams params \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e this\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetLayoutParams();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        params\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidth \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e defaultWidth;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        params\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eheight \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e defaultHeight;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        this\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetLayoutParams(params);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonDraw(canvas);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch1 class=\"title\" id=\"简单实现imageview宽度填满屏幕高度自适应的两种方式\"\u003e简单实现ImageView宽度填满屏幕，高度自适应的两种方式\u003c/h1\u003e\n\u003cp\u003e两种方式 1.重写View的onMeasure方法参考这里\u003ca href=\"http://blog.csdn.net/easion_zms/article/details/50263409\"\u003eeasion_zms的专栏\u003c/a\u003e 核心代码\u003c/p\u003e","title":"自定义ImageView 宽度自适应屏幕，高度等比缩放"},{"content":" /**\n* Return a new Context object for the given application name. This\n* Context is the same as what the named application gets when it is\n* launched, containing the same resources and class loader. Each call to\n* this method returns a new instance of a Context object; Context objects\n* are not shared, however they share common state (Resources, ClassLoader,\n* etc) so the Context instance itself is fairly lightweight.\n*\n* Throws {@link PackageManager.NameNotFoundException} if there is no\n* application with the given package name.\n*\n* Throws {@link java.lang.SecurityException} if the Context requested\n* can not be loaded into the caller’s process for security reasons (see\n* {@link #CONTEXT_INCLUDE_CODE} for more information}.\n*\n* @param packageName Name of the application’s package.\n* @param flags Option flags, one of {@link #CONTEXT_INCLUDE_CODE}\n* or {@link #CONTEXT_IGNORE_SECURITY}.\n*\n* @return A Context for the application.\n*\n* @throws java.lang.SecurityException\n* @throws PackageManager.NameNotFoundException if there is no application with\n* the given package name\n*/\nOverride\npublic Context createPackageContext(String packageName, int flags)\nthrows PackageManager.NameNotFoundException {\nif (packageName.equals(“system”) || packageName.equals(“android”)) {\nfinal ContextImpl context = new ContextImpl(mMainThread.getSystemContext());\ncontext.mBasePackageName = mBasePackageName;\nreturn context;\n}\nLoadedApk pi =\nmMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), flags);\nif (pi != null) {\nContextImpl c = new ContextImpl();\nc.mRestricted = (flags \u0026amp; CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;\nc.init(pi, null, mMainThread, mResources, mBasePackageName);\nif (c.mResources != null) {\nreturn c;\n}\n}\n// Should be a better exception.\nthrow new PackageManager.NameNotFoundException(\n“Application package “ + packageName + ” not found”);\n}\n主要作用是:创建其它程序的Context,通过创建的这个Context，就可以访问该软件包的资源，甚至可以执行其它软件包的代码。\n使用：\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - Context c = createPackageContext(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.dolphin.demo\u0026amp;#8221;\u0026lt;/span\u0026gt;, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SecurityException e) { - e.printStackTrace(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) { - e.printStackTrace(); - } 通常一个软件是不能创建其它程序的Context的，除非它们拥有相同的用户ID与签名。用户ID是一个字符串标识，在程序的AndroidManifest.xml文件的manifest标签中指定，格式为android:shareUserId=”**”。安装在设备中的每一个apk程序，Android系统会给其分配一个单独的用户空间,其中android:shareUserId就是对应一个Linux用户ID，并且为它创建一个沙箱，以防止与其它应用程序产生影响。用户ID 在应用程序被安装到设备中时分配。通过SharedUserid,拥有同一个Userid的多个APK可以配置成运行在同一个进程中，所以默认就是可以互相访问任意数据，也可以配置成运行在不同的进程中, 同时可以访问其APK的数据目录下的资源(图片，数据库和文件），就像访问本程序的数据一样。\n经常的用途：\n如经常一些应用提供的换皮肤功能，实现方法大致有两种：\n1）把需要替换的资源图片打包好之后，放在客户端指定的目录下面，切换皮肤，查找相应的资源时，直接切换资源查找的路径到该打包文件中对应的资源路径即可。\n2）把需要替换的资源，放在一个空的android 应用程序的drawable-**目录下面即可，编译，运行该apk，查找资源时，就需要用到createPackageContext获取对应包名的Context实例，然后通过context来查找对应的资源。查找时，也有两种方式：\n2.1）通过ID来查找资源图片；\n**[java]** [view plain](http://blog.csdn.net/wangbole/article/details/22876179#)\u0026lt;span data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/wangbole/article/details/22876179#)\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;28\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span data-mod=\u0026quot;popu_169\u0026quot;\u0026gt; [print](http://blog.csdn.net/wangbole/article/details/22876179#)\u0026lt;/span\u0026gt;[?](http://blog.csdn.net/wangbole/article/details/22876179#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/272565)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/272565/fork)\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; - Context context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - context = createPackageContext(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.dolphin.demo\u0026amp;#8221;\u0026lt;/span\u0026gt;, Context.CONTEXT_INCLUDE_CODE - | Context.CONTEXT_IGNORE_SECURITY); - txvA.setText(context.getResources().getText(R.string.message)); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (NameNotFoundException e) { - e.printStackTrace(); - } 2.2）通过资源Name，反推出资源ID，然后查找对应的资源图片；\n**[java]** [view plain](http://blog.csdn.net/wangbole/article/details/22876179#)\u0026lt;span data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/wangbole/article/details/22876179#)\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;28\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span data-mod=\u0026quot;popu_169\u0026quot;\u0026gt; [print](http://blog.csdn.net/wangbole/article/details/22876179#)\u0026lt;/span\u0026gt;[?](http://blog.csdn.net/wangbole/article/details/22876179#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/272565)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/272565/fork)\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*** \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param clazz 目标资源的R.java \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param className R.java的内部类，如layout,string,drawable\u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param name 资源名称 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getResourseIdByName(Class clazz, String className, String name) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - - Class[] classes = clazz.getClasses(); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获取R.java里的所有静态内部类 \u0026lt;/span\u0026gt; - Class desireClass = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; classes.length; i++) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (classes[i].getName().split(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\\\\$\u0026amp;#8221;\u0026lt;/span\u0026gt;)[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;].equals(className)) { - desireClass = classes[i]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (desireClass != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - id = desireClass.getField(name).getInt(desireClass); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IllegalArgumentException e) { - e.printStackTrace(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SecurityException e) { - e.printStackTrace(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IllegalAccessException e) { - e.printStackTrace(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (NoSuchFieldException e) { - e.printStackTrace(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; id; - } - - - Context context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - context = createPackageContext(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.dolphin.demo\u0026amp;#8221;\u0026lt;/span\u0026gt;, Context.CONTEXT_INCLUDE_CODE - | Context.CONTEXT_IGNORE_SECURITY); - Class cls = context.getClassLoader().loadClass(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.dolphin.demo.R\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获得目标apk的R类 \u0026lt;/span\u0026gt; - txvA.setText(context.getResources().getText(getResourseIdByName(cls, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;string\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;message\u0026amp;#8221;\u0026lt;/span\u0026gt;))); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (NameNotFoundException e) { - e.printStackTrace(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (ClassNotFoundException e) { - e.printStackTrace(); - } - ","permalink":"https://blog.zdltech.com/posts/android-%E4%B8%AD%E7%9A%84createpackagecontext/","summary":"\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"comment\"\u003e/**\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"comment\"\u003e     * Return a new Context object for the given application name.  This\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"comment\"\u003e     * Context is the same as what the named application gets when it is\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"comment\"\u003e     * launched, containing the same resources and class loader.  Each call to\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"comment\"\u003e     * this method returns a new instance of a Context object; Context objects\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"comment\"\u003e     * are not shared, however they share common state (Resources, ClassLoader,\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"comment\"\u003e     * etc) so the Context instance itself is fairly lightweight.\u003c/span\u003e\u003c/p\u003e","title":"Android 中的CreatePackageContext()"},{"content":"类加载器ClassLoader\n早期使用过Eclipse等Java编写的软件的同学可能比较熟悉，Eclipse可以加载许多第三方的插件（或者叫扩展），这就是动态加载。这些插件大多是一些Jar包，而使用插件其实就是动态加载Jar包里的Class进行工作。这其实非常好理解，Java代码都是写在Class里面的，程序运行在虚拟机上时，虚拟机需要把需要的Class加载进来才能创建实例对象并工作，而完成这一个加载工作的角色就是ClassLoader。\n对于Java程序来说，编写程序就是编写类，运行程序也就是运行类（编译得到的class文件），其中起到关键作用的就是类加载器ClassLoader。\nAndroid的Dalvik/ART虚拟机如同标准JAVA的JVM虚拟机一样，在运行程序时首先需要将对应的类加载到内存中。因此，我们可以利用这一点，在程序运行时手动加载Class，从而达到代码动态加载可执行文件的目的。Android的Dalvik/ART虚拟机虽然与标准Java的JVM虚拟机不一样，ClassLoader具体的加载细节不一样，但是工作机制是类似的，也就是说在Android中同样可以采用类似的动态加载插件的功能，只是在Android应用中动态加载一个插件的工作要比Eclipse加载一个插件复杂许多（这点后面在解释说明）。\n有几个ClassLoader实例？ 动态加载的基础是ClassLoader，从名字也可以看出，ClassLoader就是专门用来处理类加载工作的，所以这货也叫类加载器，而且一个运行中的APP 不仅只有一个类加载器。 其实，在Android系统启动的时候会创建一个Boot类型的ClassLoader实例，用于加载一些系统Framework层级需要的类，我们的Android应用里也需要用到一些系统的类，所以APP启动的时候也会把这个Boot类型的ClassLoader传进来。\n此外，APP也有自己的类，这些类保存在APK的dex文件里面，所以APP启动的时候，也会创建一个自己的ClassLoader实例，用于加载自己dex文件中的类。下面我们在项目里验证看看\n` \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Bundle savedInstanceState)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreate(savedInstanceState); ClassLoader classLoader = getClassLoader(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (classLoader != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){ Log.i(TAG, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;[onCreate] classLoader \u0026#34;\u0026amp;lt;/span\u0026gt; + i + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; : \u0026#34;\u0026amp;lt;/span\u0026gt; + classLoader.toString()); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;while\u0026amp;lt;/span\u0026gt; (classLoader.getParent()!=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){ classLoader = classLoader.getParent(); Log.i(TAG,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;[onCreate] classLoader \u0026#34;\u0026amp;lt;/span\u0026gt; + i + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; : \u0026#34;\u0026amp;lt;/span\u0026gt; + classLoader.toString()); } } }` 输出结果为\n`[onCreate] classLoader \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-symbol\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt; dalvik.system.\u0026amp;lt;span class=\u0026#34;hljs-constant\u0026#34;\u0026gt;PathClassLoader\u0026amp;lt;/span\u0026gt;[\u0026amp;lt;span class=\u0026#34;hljs-constant\u0026#34;\u0026gt;DexPathList\u0026amp;lt;/span\u0026gt;[[zip file \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;/data/app/me.kaede.anroidclassloadersample-1/base.apk\u0026#34;\u0026amp;lt;/span\u0026gt;],nativeLibraryDirectories=[\u0026amp;lt;span class=\u0026#34;hljs-regexp\u0026#34;\u0026gt;/vendor/lib\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-regexp\u0026#34;\u0026gt;/system/lib\u0026amp;lt;/span\u0026gt;]]] [onCreate] classLoader \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-symbol\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt; java.lang.\u0026amp;lt;span class=\u0026#34;hljs-constant\u0026#34;\u0026gt;BootClassLoader@14af4e32\u0026amp;lt;/span\u0026gt;` 可以看见有2个Classloader实例，一个是BootClassLoader（系统启动的时候创建的），另一个是PathClassLoader（应用启动时创建的，用于加载“/data/app/me.kaede.anroidclassloadersample-1/base.apk”里面的类）。由此也可以看出，一个运行的Android应用至少有2个ClassLoader。\n创建自己ClassLoader实例 动态加载外部的dex文件的时候，我们也可以使用自己创建的ClassLoader实例来加载dex里面的Class，不过ClassLoader的创建方式有点特殊，我们先看看它的构造方法\n` \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* * constructor for the BootClassLoader which needs parent to be null. */\u0026amp;lt;/span\u0026gt; ClassLoader(ClassLoader parentLoader, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; nullAllowed) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (parentLoader == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; !nullAllowed) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; NullPointerException(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;parentLoader == null \u0026amp;\u0026amp; !nullAllowed\u0026#34;\u0026amp;lt;/span\u0026gt;); } parent = parentLoader; }` 创建一个ClassLoader实例的时候，需要使用一个现有的ClassLoader实例作为新创建的实例的Parent。这样一来，一个Android应用，甚至整个Android系统里所有的ClassLoader实例都会被一棵树关联起来，这也是ClassLoader的 双亲代理模型（Parent-Delegation Model）的特点。\nClassLoader双亲代理模型加载类的特点和作用 JVM中ClassLoader通过defineClass方法加载jar里面的Class，而Android中这个方法被弃用了。\ndefineClass(byte[] classRep, int offset, int length) throws ClassFormatError { throw new UnsupportedOperationException(\u0026amp;quot;can\u0026#39;t load this type of class file\u0026amp;quot;); }\u0026#34; data-snippet-id=\u0026#34;ext.1a4965f41d758e8241b3b7862cb48fec\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;` \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Deprecated\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; Class\u0026amp;lt;?\u0026amp;gt; defineClass(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;byte\u0026amp;lt;/span\u0026gt;[] classRep, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; offset, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; length) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; ClassFormatError { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; UnsupportedOperationException(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;can\u0026#39;t load this type of class file\u0026#34;\u0026amp;lt;/span\u0026gt;); }` 取而代之的是loadClass方法\nloadClass(String className) throws ClassNotFoundException { return loadClass(className, false); } protected Class\u0026lt;?\u0026gt; loadClass(String className, boolean resolve) throws ClassNotFoundException { Class\u0026lt;?\u0026gt; clazz = findLoadedClass(className); if (clazz == null) { ClassNotFoundException suppressed = null; try { clazz = parent.loadClass(className, false); } catch (ClassNotFoundException e) { suppressed = e; } if (clazz == null) { try { clazz = findClass(className); } catch (ClassNotFoundException e) { e.addSuppressed(suppressed); throw e; } } } return clazz; }\u0026#34; data-snippet-id=\u0026#34;ext.962571328c8310ab58fcc1eef543bc9c\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Class\u0026amp;lt;?\u0026amp;gt; loadClass(String className) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; ClassNotFoundException { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; loadClass(className, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; Class\u0026amp;lt;?\u0026amp;gt; loadClass(String className, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; resolve) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; ClassNotFoundException { Class\u0026amp;lt;?\u0026amp;gt; clazz = findLoadedClass(className); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (clazz == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { ClassNotFoundException suppressed = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { clazz = parent.loadClass(className, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (ClassNotFoundException e) { suppressed = e; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (clazz == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { clazz = findClass(className); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (ClassNotFoundException e) { e.addSuppressed(suppressed); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; e; } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; clazz; }` 特点 从源码中我们也可以看出，loadClass方法在加载一个类的实例的时候，\n会先查询当前ClassLoader实例是否加载过此类，有就返回；\n如果没有。查询Parent是否已经加载过此类，如果已经加载过，就直接返回Parent加载的类；\n如果继承路线上的ClassLoader都没有加载，才由Child执行类的加载工作；\n这样做有个明显的特点，如果一个类被位于树根的ClassLoader加载过，那么在以后整个系统的生命周期内，这个类永远不会被重新加载。\n作用 首先是共享功能，一些Framework层级的类一旦被顶层的ClassLoader加载过就缓存在内存里面，以后任何地方用到都不需要重新加载。\n除此之外还有隔离功能，不同继承路线上的ClassLoader加载的类肯定不是同一个类，这样的限制避免了用户自己的代码冒充核心类库的类访问核心类库包可见成员的情况。这也好理解，一些系统层级的类会在系统初始化的时候被加载，比如java.lang.String，如果在一个应用里面能够简单地用自定义的String类把这个系统的String类给替换掉，那将会有严重的安全问题。\n使用ClassLoader一些需要注意的问题 我们都知道，我们可以通过动态加载获得新的类，从而升级一些代码逻辑，这里有几个问题要注意一下。\n如果你希望通过动态加载的方式，加载一个新版本的dex文件，使用里面的新类替换原有的旧类，从而修复原有类的BUG，那么你必须保证在加载新类的时候，旧类还没有被加载，因为如果已经加载过旧类，那么ClassLoader会一直优先使用旧类。\n如果旧类总是优先于新类被加载，我们也可以使用一个与加载旧类的ClassLoader没有树的继承关系的另一个ClassLoader来加载新类，因为ClassLoader只会检查其Parent有没有加载过当前要加载的类，如果两个ClassLoader没有继承关系，那么旧类和新类都能被加载。\n不过这样一来又有另一个问题了，在Java中，只有当两个实例的类名、包名以及加载其的ClassLoader都相同，才会被认为是同一种类型。上面分别加载的新类和旧类，虽然包名和类名都完全一样，但是由于加载的ClassLoader不同，所以并不是同一种类型，在实际使用中可能会出现类型不符异常。\n同一个Class = 相同的 ClassName + PackageName + ClassLoader\n以上问题在采用动态加载功能的开发中容易出现，请注意。\nDexClassLoader 和 PathClassLoader 在Android中，ClassLoader是一个抽象类，实际开发过程中，我们一般是使用其具体的子类DexClassLoader、PathClassLoader这些类加载器来加载类的，它们的不同之处是：\nDexClassLoader可以加载jar/apk/dex，可以从SD卡中加载未安装的apk；\nPathClassLoader只能加载系统中已经安装过的apk；\n类加载器的初始化 平时开发的时候，使用DexClassLoader就够用了，但是我们不妨挖一下这两者具体细节上的区别。\n`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// DexClassLoader.java\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DexClassLoader\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;BaseDexClassLoader\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DexClassLoader\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;(dexPath, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File(optimizedDirectory), libraryPath, parent); } }\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// PathClassLoader.java\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;PathClassLoader\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;BaseDexClassLoader\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;PathClassLoader\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(String dexPath, ClassLoader parent)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;(dexPath, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;, parent); } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;PathClassLoader\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(String dexPath, String libraryPath, ClassLoader parent)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;(dexPath, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;, libraryPath, parent); } }` 这两者只是简单的对BaseDexClassLoader做了一下封装，具体的实现还是在父类里。不过这里也可以看出，PathClassLoader的optimizedDirectory只能是null，进去BaseDexClassLoader看看这个参数是干什么的\n`\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;BaseDexClassLoader\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;(parent); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.originalPath = dexPath; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.pathList = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DexPathList(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, dexPath, libraryPath, optimizedDirectory); }` 这里创建了一个DexPathList实例，进去看看\nfiles, File optimizedDirectory) { ArrayList\u0026lt;Element\u0026gt; elements = new ArrayList\u0026lt;Element\u0026gt;(); for (File file : files) { ZipFile zip = null; DexFile dex = null; String name = file.getName(); if (name.endsWith(DEX_SUFFIX)) { dex = loadDexFile(file, optimizedDirectory); } else if (name.endsWith(APK_SUFFIX) || name.endsWith(JAR_SUFFIX) || name.endsWith(ZIP_SUFFIX)) { zip = new ZipFile(file); } …… if ((zip != null) || (dex != null)) { elements.add(new Element(file, zip, dex)); } } return elements.toArray(new Element[elements.size()]); } private static DexFile loadDexFile(File file, File optimizedDirectory) throws IOException { if (optimizedDirectory == null) { return new DexFile(file); } else { String optimizedPath = optimizedPathFor(file, optimizedDirectory); return DexFile.loadDex(file.getPath(), optimizedPath, 0); } } /** * Converts a dex/jar file path and an output directory to an * output file path for an associated optimized dex file. */ private static String optimizedPathFor(File path, File optimizedDirectory) { String fileName = path.getName(); if (!fileName.endsWith(DEX_SUFFIX)) { int lastDot = fileName.lastIndexOf(\u0026amp;quot;.\u0026amp;quot;); if (lastDot \u0026lt; 0) { fileName += DEX_SUFFIX; } else { StringBuilder sb = new StringBuilder(lastDot + 4); sb.append(fileName, 0, lastDot); sb.append(DEX_SUFFIX); fileName = sb.toString(); } } File result = new File(optimizedDirectory, fileName); return result.getPath(); }\u0026#34; data-snippet-id=\u0026#34;ext.008e5968a5d40ee78533ade96b47b4e5\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;` \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DexPathList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(ClassLoader definingContext, String dexPath, String libraryPath, File optimizedDirectory)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ …… \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; Element[] makeDexElements(ArrayList\u0026amp;lt;File\u0026amp;gt; files, File optimizedDirectory) { ArrayList\u0026amp;lt;Element\u0026amp;gt; elements = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;Element\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (File file : files) { ZipFile zip = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; DexFile dex = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; String name = file.getName(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (name.endsWith(DEX_SUFFIX)) { dex = loadDexFile(file, optimizedDirectory); } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(name.endsWith(APK_SUFFIX)\u0026amp;lt;/span\u0026gt; || name.\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;endsWith\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(JAR_SUFFIX)\u0026amp;lt;/span\u0026gt; || name.\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;endsWith\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(ZIP_SUFFIX)\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;/span\u0026gt;{ zip = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ZipFile(file); } …… \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; ((zip != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) || (dex != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;)) { elements.add(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Element(file, zip, dex)); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; elements.toArray(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Element[elements.size()]); } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; DexFile \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;loadDexFile\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(File file, File optimizedDirectory)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; IOException \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (optimizedDirectory == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DexFile(file); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { String optimizedPath = optimizedPathFor(file, optimizedDirectory); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; DexFile.loadDex(file.getPath(), optimizedPath, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); } } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * Converts a dex/jar file path and an output directory to an * output file path for an associated optimized dex file. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; String \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;optimizedPathFor\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(File path, File optimizedDirectory)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ String fileName = path.getName(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!fileName.endsWith(DEX_SUFFIX)) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; lastDot = fileName.lastIndexOf(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;.\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (lastDot \u0026amp;lt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { fileName += DEX_SUFFIX; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { StringBuilder sb = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; StringBuilder(lastDot + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;); sb.append(fileName, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, lastDot); sb.append(DEX_SUFFIX); fileName = sb.toString(); } } File result = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File(optimizedDirectory, fileName); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; result.getPath(); }` 看到这里我们明白了，optimizedDirectory是用来缓存我们需要加载的dex文件的，并创建一个DexFile对象，如果它为null，那么会直接使用dex文件原有的路径来创建DexFile\n对象。\noptimizedDirectory必须是一个内部存储路径，还记得我们之前说过的，无论哪种动态加载，加载的可执行文件一定要存放在内部存储。DexClassLoader可以指定自己的optimizedDirectory，所以它可以加载外部的dex，因为这个dex会被复制到内部路径的optimizedDirectory；而PathClassLoader没有optimizedDirectory，所以它只能加载内部的dex，这些大都是存在系统中已经安装过的apk里面的。\n加载类的过程 上面还只是创建了类加载器的实例，其中创建了一个DexFile实例，用来保存dex文件，我们猜想这个实例就是用来加载类的。\nAndroid中，ClassLoader用loadClass方法来加载我们需要的类\nloadClass(String className) throws ClassNotFoundException { return loadClass(className, false); } protected Class\u0026lt;?\u0026gt; loadClass(String className, boolean resolve) throws ClassNotFoundException { Class\u0026lt;?\u0026gt; clazz = findLoadedClass(className); if (clazz == null) { ClassNotFoundException suppressed = null; try { clazz = parent.loadClass(className, false); } catch (ClassNotFoundException e) { suppressed = e; } if (clazz == null) { try { clazz = findClass(className); } catch (ClassNotFoundException e) { e.addSuppressed(suppressed); throw e; } } } return clazz; }\u0026#34; data-snippet-id=\u0026#34;ext.d0d332530ed2c335bf42e279b0539b56\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Class\u0026amp;lt;?\u0026amp;gt; loadClass(String className) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; ClassNotFoundException { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; loadClass(className, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; Class\u0026amp;lt;?\u0026amp;gt; loadClass(String className, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; resolve) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; ClassNotFoundException { Class\u0026amp;lt;?\u0026amp;gt; clazz = findLoadedClass(className); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (clazz == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { ClassNotFoundException suppressed = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { clazz = parent.loadClass(className, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (ClassNotFoundException e) { suppressed = e; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (clazz == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { clazz = findClass(className); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (ClassNotFoundException e) { e.addSuppressed(suppressed); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; e; } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; clazz; }` loadClass方法调用了findClass方法，而BaseDexClassLoader重载了这个方法，得到BaseDexClassLoader看看\nfindClass(String name) throws ClassNotFoundException { Class clazz = pathList.findClass(name); if (clazz == null) { throw new ClassNotFoundException(name); } return clazz; }\u0026#34; data-snippet-id=\u0026#34;ext.3e3651dfd43235ddb34ead6e1bf20580\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; Class\u0026amp;lt;?\u0026amp;gt; findClass(String name) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; ClassNotFoundException { Class clazz = pathList.findClass(name); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (clazz == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ClassNotFoundException(name); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; clazz; }` 结果还是调用了DexPathList的findClass\n` \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Class \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;findClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(String name)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (Element element : dexElements) { DexFile dex = element.dexFile; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (dex != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { Class clazz = dex.loadClassBinaryName(name, definingContext); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (clazz != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; clazz; } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; }` 这里遍历了之前所有的DexFile实例，其实也就是遍历了所有加载过的dex文件，再调用loadClassBinaryName方法一个个尝试能不能加载想要的类，真是简单粗暴\n` \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Class \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;loadClassBinaryName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(String name, ClassLoader loader)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; defineClass(name, loader, mCookie); } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;native\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; Class \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;defineClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(String name, ClassLoader loader, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; cookie)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;;` 看到这里想必大家都明白了，loadClassBinaryName中调用了Native方法defineClass加载类。\n至此，ClassLoader的创建和加载类的过程的完成了。有趣的是，标准JVM中，ClassLoader是用defineClass加载类的，而Android中defineClass被弃用了，改用了loadClass方法，而且加载类的过程也挪到了DexFile中，在DexFile中加载类的具体方法也叫defineClass，不知道是Google故意写成这样的还是巧合。\n自定义ClassLoader 平时进行动态加载开发的时候，使用DexClassLoader就够了。但我们也可以创建自己的类去继承ClassLoader，需要注意的是loadClass方法并不是final类型的，所以我们可以重载loadClass方法并改写类的加载逻辑。\n通过前面我们分析知道，ClassLoader双亲代理的实现很大一部分就是在loadClass方法里，我们可以通过重写loadClass方法避开双亲代理的框架，这样一来就可以在重新加载已经加载过的类，也可以在加载类的时候注入一些代码。这是一种Hack的开发方式，采用这种开发方式的程序稳定性可能比较差，但是却可以实现一些“黑科技”的功能。\nAndroid程序比起一般Java程序在使用动态加载时麻烦在哪里 通过上面的分析，我们知道使用ClassLoader动态加载一个外部的类是非常容易的事情，所以很容易就能实现动态加载新的可执行代码的功能，但是比起一般的Java程序，在Android程序中使用动态加载主要有两个麻烦的问题：\nAndroid中许多组件类（如Activity、Service等）是需要在Manifest文件里面注册后才能工作的（系统会检查该组件有没有注册），所以即使动态加载了一个新的组件类进来，没有注册的话还是无法工作；\nRes资源是Android开发中经常用到的，而Android是把这些资源用对应的R.id注册好，运行时通过这些ID从Resource实例中获取对应的资源。如果是运行时动态加载进来的新类，那类里面用到R.id的地方将会抛出找不到资源或者用错资源的异常，因为新类的资源ID根本和现有的Resource实例中保存的资源ID对不上；\n说到底，抛开虚拟机的差别不说，一个Android程序和标准的Java程序最大的区别就在于他们的上下文环境（Context）不同。Android中，这个环境可以给程序提供组件需要用到的功能，也可以提供一些主题、Res等资源，其实上面说到的两个问题都可以统一说是这个环境的问题，而现在的各种Android动态加载框架中，核心要解决的东西也正是“如何给外部的新类提供上下文环境”的问题。\n推荐：http://www.jianshu.com/p/a620e368389a\n","permalink":"https://blog.zdltech.com/posts/android%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%9F%BA%E7%A1%80-classloader%E5%B7%A5%E4%BD%9C%E6%9C%BA%E5%88%B6/","summary":"\u003cp\u003e\u003cstrong\u003e类加载器ClassLoader\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e早期使用过Eclipse等Java编写的软件的同学可能比较熟悉，Eclipse可以加载许多第三方的插件（或者叫扩展），这就是动态加载。这些插件大多是一些Jar包，而使用插件其实就是动态加载Jar包里的Class进行工作。这其实非常好理解，Java代码都是写在Class里面的，程序运行在虚拟机上时，虚拟机需要把需要的Class加载进来才能创建实例对象并工作，而完成这一个加载工作的角色就是ClassLoader。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003e对于Java程序来说，编写程序就是编写类，运行程序也就是运行类（编译得到的\u003ccode\u003eclass文件\u003c/code\u003e），其中起到关键作用的就是类加载器ClassLoader。\u003c/em\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eAndroid的Dalvik/ART虚拟机如同标准JAVA的JVM虚拟机一样，在运行程序时首先需要将对应的类加载到内存中。因此，我们可以利用这一点，在程序运行时手动加载Class，从而达到代码动态加载可执行文件的目的。Android的Dalvik/ART虚拟机虽然与标准Java的JVM虚拟机不一样，ClassLoader具体的加载细节不一样，但是工作机制是类似的，也就是说在Android中同样可以采用类似的动态加载插件的功能，只是在Android应用中动态加载一个插件的工作要比Eclipse加载一个插件复杂许多（这点后面在解释说明）。\u003c/p\u003e\n\u003ch2 id=\"有几个classloader实例\"\u003e有几个ClassLoader实例？\u003c/h2\u003e\n\u003ch2 id=\"动态加载的基础是classloader从名字也可以看出classloader就是专门用来处理类加载工作的所以这货也叫类加载器而且一个运行中的app不仅只有一个类加载器\"\u003e动态加载的基础是ClassLoader，从名字也可以看出，ClassLoader就是专门用来处理类加载工作的，所以这货也叫类加载器，而且一个运行中的APP 不仅只有一个类加载器。\u003c/h2\u003e\n\u003cp\u003e其实，在Android系统启动的时候会创建一个Boot类型的ClassLoader实例，用于加载一些系统Framework层级需要的类，我们的Android应用里也需要用到一些系统的类，所以APP启动的时候也会把这个Boot类型的ClassLoader传进来。\u003c/p\u003e\n\u003cp\u003e此外，APP也有自己的类，这些类保存在APK的dex文件里面，所以APP启动的时候，也会创建一个自己的ClassLoader实例，用于加载自己dex文件中的类。下面我们在项目里验证看看\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`    \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Bundle savedInstanceState)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreate(savedInstanceState);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ClassLoader classLoader = getClassLoader();        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (classLoader != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            Log.i(TAG, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;[onCreate] classLoader \u0026#34;\u0026amp;lt;/span\u0026gt; + i + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; : \u0026#34;\u0026amp;lt;/span\u0026gt; + classLoader.toString());            \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;while\u0026amp;lt;/span\u0026gt; (classLoader.getParent()!=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                classLoader = classLoader.getParent();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                Log.i(TAG,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;[onCreate] classLoader \u0026#34;\u0026amp;lt;/span\u0026gt; + i + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; : \u0026#34;\u0026amp;lt;/span\u0026gt; + classLoader.toString());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输出结果为\u003c/p\u003e","title":"Android动态加载基础 ClassLoader工作机制"},{"content":"你真的了解ClassLoader吗？ 这篇文章翻译自zeroturnaround.com的 Do You Really Get Classloaders? ，融入和补充了笔者的一些实践、经验和样例。本文的例子比原文更加具有实际意义，文字内容也更充沛一些，非常感谢作者 Jevgeni Kabanov 能够共享如此优秀的文档。\n1. 为什么你需要了解和敬畏ClassLoader ClassLoader在Java语言中占据了核心地位，Java应用服务器，OSGi，以及大量的网络框架，它们大多数都用到了ClassLoader。如果在使用过程中出现了类加载错误，你能解决它吗？\n我们将从JVM和开发者两个角度讲述ClassLoader，将会选择一些典型的案例，然后演示如何解决它们。NoClassDefFoundError，LinkageError等很多错误都会有特定的表征，我们分析每个例子，然后进行解决。\n2. 进入ClassLoader 每个ClassLoader对象都是一个java.lang.ClassLoader的实例。每个Class对象都被这些ClassLoader对象所加载，通过继承java.lang.ClassLoader可以扩展出自定义ClassLoader，并使用这些自定义的ClassLoader对类进行加载。\n先大体了解一下ClassLoader的API：\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `package` `java.lang;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `public` `abstract` `class` `ClassLoader {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``public` `Class loadClass(String name);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``protected` `Class defineClass(``byte``[] b);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``public` `URL getResource(String name);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``public` `Enumeration getResources(String name);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``public` `ClassLoader getParent();` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 最重要的是ClassLoader的\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;loadClass\u0026lt;/span\u0026gt;方法，它接受一个全类名，然后返回一个Class类型的实例。\n\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;defineClass\u0026lt;/span\u0026gt;方法接受一组字节，然后将其具体化为一个Class类型实例，它一般从磁盘上加载一个文件，然后将文件的字节传递给JVM，通过JVM（native 方法）对于Class的定义，将其具体化，实例化为一个Class类型实例。\n\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;getParent\u0026lt;/span\u0026gt;方法返回其parent ClassLoader。\n\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;getResource\u0026lt;/span\u0026gt;和\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;getResources\u0026lt;/span\u0026gt;方法，从给定的repository中查找URLs，同时它们也具备类似\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;loadClass\u0026lt;/span\u0026gt;一样的代理机制，我们可以将\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;loadClass\u0026lt;/span\u0026gt;视为：\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;defineClass(getResource(name).getBytes())\u0026lt;/span\u0026gt;。\nJava由于其晚绑定和“解释型”的特性，类型的加载是到最晚才进行，一个类型直到被调用构造函数、静态方法或者在字段上使用时才会被加载。\n考虑如下代码：\n`1` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `public` `class` `A {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `2` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``public` `void` `doSomething() {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `3` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``B b = ``new` `B();` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `4` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``b.doSomethingElse();` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `5` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `6` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 代码：B b = new B();等同于B b = Class.forName(“B”, false, A.class.getClassLoader()).newInstance();\n这代表着，在类型A中使用到的类型，将由加载了类型A的类加载器来进行加载。\n3. ClassLoader继承体系 当启动一个JVM时，bootstrap 类加载器就会加载java的核心类，例如：rt.jar中的类。bootstrap 类加载器是其他类加载器的parent，它使唯一一个没有parent的类加载器。\n接下来是extension 类加载器，它以bootstrap 类加载器作为parent，它用来从Java系统变量java.ext.dir中的jar包中加载类的。\n第三个，也是最重要的一个就是开发者使用的system classpath 类加载器 。它是extension 类加载器 的child，它用来从Java系统变量java.class.path下面加载类，可以通过 -classpath 来指定这个位置。\n注意类加载器的体系并不是“继承”体系，而是一个“委派”体系。大多数类加载器首先会到自己的parent中查找类或者资源，如果找不到，才会在自己的本地进行查找。事实上，类加载器被定义加载哪些在parent中无法加载到的类，这样在较高层级的类加载器上的类型能够被“赋值”为较低类加载器加载的类型。\n类加载器的委托行为动机是为了避免相同的类被加载多次。回到1995年，Java的主要方向被放在Applet上，那时候网络带宽优先，所以程序中的类直到用时才会被加载。但是事实上，Java在服务器端展示了强劲的能力，但是服务器端要求类加载器能够反转委派原则，也就是先加载本地的类，如果加载不到，再到parent中加载。\nJavaEE的 委派模型\n每个方块都是一个类加载器，JavaEE规范推荐每个模块的类加载器先加载本类加载的内容，如果加载不到才回到parent类加载器中尝试加载。\n反转委派原则的原因是应用服务器中所携带的类库并不是应用所期待的，也许不适合应用开发者，一个常见的例子就是log4j的依赖在容器和不同的应用中都存在，但是它们的版本大都不同。\nTomcat的 类加载顺序（开启了delegate模式）\n在Tomcat中，默认的行为是先尝试在Bootstrap和Extension中进行类型加载，如果加载不到则在WebappClassLoader中进行加载，如果还是找不到则在Common中进行查找。在Alibaba使用的Tomcat开启了delegate模式，因此加载类型时会以parent类加载器优先。\n4. NoClassDefFoundError NoClassDefFoundError是在开发JavaEE程序中常见的一种问题。该问题会随着你所使用的JavaEE中间件环境的复杂度以及应用本身的体量变得更加复杂，尤其是现在的JavaEE服务器具有大量的类加载器。\n在JavaDoc中对NoClassDefFoundError的产生是由于JVM或者类加载器实例尝试加载类型的定义，但是该定义却没有找到，影响了执行路径。换句话说，在编译时这个类是能够被找到的，但是在执行时却没有找到。\n这一刻IDE是没有出错提醒的，但是在运行时却出现了错误。\n看看如下示例：\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `/**` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``* @author weipeng2k 2015年3月27日 下午5:15:15` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``*/` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `@WebServlet``(name = ``\u0026quot;NoClassDefFoundErrorServlet\u0026quot;``, urlPatterns = ``\u0026quot;/noClassDefFoundError.do\u0026quot;``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `public` `class` `NoClassDefFoundErrorServlet ``extends` `HttpServlet {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``private` `static` `final` `long` `serialVersionUID = 61585757018374721L;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``protected` `void` `doGet(HttpServletRequest req, HttpServletResponse resp) ``throws` `ServletException, IOException {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``resp.getWriter().println(TestCase.``class``.toString());` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 在看pom.xml中对于依赖的定义：\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `\u0026amp;lt;dependencies\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;dependency\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;groupId\u0026amp;gt;junit\u0026amp;lt;/groupId\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;artifactId\u0026amp;gt;junit\u0026amp;lt;/artifactId\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;version\u0026amp;gt;``3.8``.``1``\u0026amp;lt;/version\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;scope\u0026amp;gt;provided\u0026amp;lt;/scope\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;/dependency\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;dependency\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;groupId\u0026amp;gt;javax.servlet\u0026amp;lt;/groupId\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;artifactId\u0026amp;gt;servlet-api\u0026amp;lt;/artifactId\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;version\u0026amp;gt;``3.0``\u0026amp;lt;/version\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;scope\u0026amp;gt;provided\u0026amp;lt;/scope\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;/dependency\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `14` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;dependency\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `15` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;groupId\u0026amp;gt;org.springframework\u0026amp;lt;/groupId\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `16` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;artifactId\u0026amp;gt;spring\u0026amp;lt;/artifactId\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `17` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;version\u0026amp;gt;``2.5``.``6``\u0026amp;lt;/version\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `18` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;/dependency\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `19` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `\u0026amp;lt;/dependencies\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 其中对于junit的依赖是provided级别的，这里是为了能简化错误出现的条件。可以看到，在NoClassDefFoundErrorServlet中，使用了junit.jar中的TestCase，但是junit.jar在WEB-INF/lib中却没有，从而导致WebappClassLoader在进行加载TestCase时无法找到，从而抛出NoClassDefFoundError。我们需要从最终的war包中确定是否存在这个类，而不是在IDE中进行搜索。\n5. NoSuchMethodError 在另一个场景中，我们可能遇到了另一个错误，也就是NoSuchMethodError。\nNoSuchMethodError代表这个类型确实存在，但是一个不正确的版本被加载了。为了解决这个问题我们可以使用 ‘-verbose:class’ 来判断该JVM加载的到底是哪个版本。\n看如下示例：\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `import` `org.springframework.beans.factory.BeanFactoryUtils;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `/**` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``* @author weipeng2k 2015年3月31日 上午9:09:58` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``*/` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `@WebServlet``(name = ``\u0026quot;NoSuchMethodErrorServlet\u0026quot;``, urlPatterns = { ``\u0026quot;/noSuchMethodError.do\u0026quot;` `})` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `public` `class` `NoSuchMethodErrorServlet ``extends` `HttpServlet {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``private` `static` `final` `long` `serialVersionUID = 1699609060417354821L;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``protected` `void` `doGet(HttpServletRequest req, HttpServletResponse resp) ``throws` `ServletException, IOException {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``BeanFactoryUtils.isGeneratedBeanName(``\u0026quot;xxx\u0026quot;``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `14` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `15` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``resp.getWriter().println(``\u0026quot;done.\u0026quot;``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `16` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `17` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 在doGet方法中调用了BeanFactoryUtils.isGeneratedBeanName(”xxx“);，看一下项目的pom依赖。\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `\u0026amp;lt;``dependencies``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``dependency``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``groupId``\u0026amp;gt;junit\u0026amp;lt;/``groupId``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``artifactId``\u0026amp;gt;junit\u0026amp;lt;/``artifactId``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``version``\u0026amp;gt;4.11\u0026amp;lt;/``version``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``scope``\u0026amp;gt;provided\u0026amp;lt;/``scope``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``dependency``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``dependency``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``groupId``\u0026amp;gt;javax.servlet\u0026amp;lt;/``groupId``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``artifactId``\u0026amp;gt;servlet-api\u0026amp;lt;/``artifactId``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``version``\u0026amp;gt;3.0\u0026amp;lt;/``version``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``scope``\u0026amp;gt;provided\u0026amp;lt;/``scope``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``dependency``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `14` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``dependency``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `15` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``groupId``\u0026amp;gt;org.springframework\u0026amp;lt;/``groupId``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `16` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``artifactId``\u0026amp;gt;org.springframework.context\u0026amp;lt;/``artifactId``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `17` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``version``\u0026amp;gt;3.0.5.RELEASE\u0026amp;lt;/``version``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `18` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``scope``\u0026amp;gt;provided\u0026amp;lt;/``scope``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `19` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``dependency``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `20` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``dependency``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `21` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``groupId``\u0026amp;gt;org.apache.mina\u0026amp;lt;/``groupId``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `22` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``artifactId``\u0026amp;gt;mina-core\u0026amp;lt;/``artifactId``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `23` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``version``\u0026amp;gt;2.0.7\u0026amp;lt;/``version``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `24` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``dependency``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `25` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``dependency``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `26` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``groupId``\u0026amp;gt;com.alibaba.external\u0026amp;lt;/``groupId``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `27` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``artifactId``\u0026amp;gt;sourceforge.spring\u0026amp;lt;/``artifactId``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `28` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;``version``\u0026amp;gt;2.0.7\u0026amp;lt;/``version``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `29` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``dependency``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `30` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `\u0026amp;lt;/``dependencies``\u0026amp;gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 这里为了方便观察到结果，将org.springframework.context的 scope 改为了 provided ，目的是不将其打包入war包，而只是使用了sourceforge.spring中定义的2.0.7版本，这个版本肯定没有isGeneratedBeanName(String name)方法，但是在IDE中，由于应用依赖到了高版本的spring从而能够编译通过，但是在运行时却没有那么好运了。这种错误，常见于 Maven****坐标 的变动，使得应用依赖了多个 相同内容，不同版本 的jar包，以致在运行时选择了非期望的版本。\n6. ClassCastException NoClassDefFoundError和NoSuchMethodError是两个在 JavaEE 环境中经常出现的问题，这些问题需要 开发人员了解问题的本质，才能够被 从容 的处理。\n下面我们看一下ClassCastException，在一个类加载器的情况下，一般出现这种错误都会是在转型操作时，比如：A a = (A) method();，很容易判断出来method()方法返回的类型不是类型A，但是在 JavaEE 多个类加载器的环境下就会出现一些难以定位的情况。\n看如下示例：\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `package` `com.murdock.classloader.servlet;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `import` `java.io.File;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `import` `java.io.IOException;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `import` `java.net.URL;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `import` `javax.servlet.ServletException;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `import` `javax.servlet.annotation.WebServlet;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `import` `javax.servlet.http.HttpServlet;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `import` `javax.servlet.http.HttpServletRequest;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `import` `javax.servlet.http.HttpServletResponse;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `import` `org.apache.mina.proxy.utils.MD4;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `14` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `15` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `import` `com.murdock.classloader.CachedClassLoader;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `16` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `17` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `/**` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `18` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``* @author weipeng2k 2015年4月4日 下午6:00:54` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `19` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``*/` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `20` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `@WebServlet``(name = ``\u0026quot;ClassCastExceptionServlet\u0026quot;``, urlPatterns = ``\u0026quot;/classCastException.do\u0026quot;``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `21` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `public` `class` `ClassCastExceptionServlet ``extends` `HttpServlet {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `22` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``private` `static` `final` `long` `serialVersionUID = -8959000121057369987L;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `23` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `24` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `25` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``protected` `void` `doGet(HttpServletRequest req, HttpServletResponse resp) ``throws` `ServletException, IOException {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `26` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``String localFirst = req.getParameter(``\u0026quot;localFirst\u0026quot;``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `27` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``CachedClassLoader cl = ``null``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `28` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``cl = ``new` `CachedClassLoader(` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `29` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``new` `URL[] { ``new` `File(` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `30` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``\u0026quot;/Users/weipeng2k/.m2/repository/org/apache/mina/mina-core/2.0.7/mina-core-2.0.7.jar\u0026quot;``).toURI()` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `31` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``.toURL() }, ``this``.getClass().getClassLoader());` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `32` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``if` `(``\u0026quot;false\u0026quot;``.equals(localFirst)) {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `33` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``cl.setLocalFirst(``false``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `34` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `35` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``try` `{` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `36` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``Class\u0026amp;lt;?\u0026amp;gt; klass = cl.loadClass(``\u0026quot;org.apache.mina.proxy.utils.MD4\u0026quot;``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `37` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``MD4 md4 = (MD4) klass.newInstance();` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `38` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `39` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``resp.getWriter().println(md4);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `40` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `41` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``} ``catch` `(Exception ex) {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `42` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``throw` `new` `RuntimeException(ex);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `43` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``} ``finally` `{` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `44` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``cl.close();` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `45` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `46` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `47` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `48` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 在ClassCastExceptionServlet中，构建了一个CachedClassLoader，利用这个ClassLoader加载org.apache.mina.proxy.utils.MD4，然后反射调用构造该类的实例，将其赋给MD4，最后将其打印到浏览器。\n请求URL：http://localhost:8080/classCastException.do\n响应页面，出现错误：\n`1` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `java.lang.RuntimeException: java.lang.ClassCastException: org.apache.mina.proxy.utils.MD4 cannot be cast to org.apache.mina.proxy.utils.MD4` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `2` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``com.murdock.classloader.servlet.ClassCastExceptionServlet.doGet(ClassCastExceptionServlet.java:``42``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `3` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``javax.servlet.http.HttpServlet.service(HttpServlet.java:``622``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `4` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``javax.servlet.http.HttpServlet.service(HttpServlet.java:``729``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `5` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:``52``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 请求URL ：http://localhost:8080/classCastException.do?localFirst=false\n响应页面，输出正常：\n`1` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `org.apache.mina.proxy.utils.MD4``@401c8af5` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 请求的URL加上了\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;localFirst=false\u0026lt;/span\u0026gt;就可以正常的输出，而它也就是在CachedClassLoder上设置了一下，为什么有这么大的差别。\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;org.apache.mina.proxy.utils.MD4\u0026lt;/span\u0026gt;全类名一致，为什么会出现ClassCastException呢？\n在JVM中，如何确定一个类型实例？答：全类名吗？不是，是类加载器加上全类名。在JVM中，类型被定义在一个叫**SystemDictionary** 的数据结构中，该数据结构接受类加载器和全类名作为参数，返回类型实例。\nSystemDictionary 如图所示：\n类型加载时，需要传入类加载器和需要加载的全类名，如果在 SystemDictionary 中能够命中一条记录，则返回_class_ 列上对应的类型实例引用，如果无法命中记录，则会调用\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;loader.loadClass(name);\u0026lt;/span\u0026gt;进行类型加载。\n这里不会更加深入的介绍 SystemDictionary 如何进行类型加载的过程，而是需要指出 JVM**中确定一个类型的坐标是通过类加载器和全类名做到的 。回想一下\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;MD4 md4 = (MD4) klass.newInstance();\u0026lt;/span\u0026gt;，是不是代表着等式两边的MD4是不同的类加载器加载的呢？那问题一定出在 CachedClassLoader** 上。这里贴一下\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;loadClass(String name)\u0026lt;/span\u0026gt;方法的部分逻辑。\nCachedClassLoader 的loadClass逻辑：\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `if` `(localFirst) {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``try` `{` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``clazz = findClass(name);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``if` `(clazz != ``null``) {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``return` `clazz;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``} ``catch` `(ClassNotFoundException ex) {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``return` `super``.loadClass(name);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `} ``else` `{` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``return` `super``.loadClass(name);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 可以看到在 localFirst 为true时，该类加载器会首先加载自身 repository 中的类型，如果加载不到，则会尝试默认的加载机制进行加载，也就是parent优先加载。这样就可以解释MD4 md4 = (MD4) klass.newInstance();，等式左边MD4 md4，这个类型是WebappClassLoader.org.apache.mina.proxy.utils.MD4，等式右边klass.newInstance()返回的类型是CachedClassLoader.org.apache.mina.proxy.utils.MD4，二者并不是同一个类型，所以无法完成类型转换，最终抛出 ClassCastException 。而当 localFirst 为false时，该类加载器遵循parent优先，从而会先委派给WebappClassLoader进行加载，当然转型也就不会有问题了。\n在传统的双亲委派模型下，这种 ClassCastException 是不会发生的，因为它的加载顺序杜绝了出现这种问题的可能，而在 JavaEE 环境下，每个资源模块（比如一个war包）都优先使用自身的资源，正因为突破了双亲委派模型， 奇怪的问题 就发生了。\n7. LinkageError 有时候事情会变得更糟，和 ClassCastException 本质一样，加载自不同位置的*相同类*在同一段逻辑（比如：方法）中交互时，会出现 LinkageError 。\n我们先看一下出错的异常信息，然后分析一下它产生的条件和原因：\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `java.lang.LinkageError: loader constraint violation: when resolving overridden method ``\u0026quot;com.murdock.classloader.linkageerror.Param2.generate()Lcom/murdock/classloader/linkageerror/Param2;\u0026quot;``the ``class` `loader (instance of com/murdock/classloader/linkageerror/LinkageErrorTest$``1``) of the current ``class``, com/murdock/classloader/linkageerror/Param2, and its superclass loader (instance of sun/misc/Launcher$AppClassLoader), have different Class objects ``for` `the type com/murdock/classloader/linkageerror/Param2 used in the signature` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``at java.lang.Class.getDeclaredConstructors0(Native Method)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``at java.lang.Class.privateGetDeclaredConstructors(Class.java:``2671``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``at java.lang.Class.getConstructor0(Class.java:``3075``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``at java.lang.Class.newInstance(Class.java:``412``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``at com.murdock.classloader.linkageerror.LinkageErrorTest.test(LinkageErrorTest.java:``34``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:``62``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:``43``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``at java.lang.reflect.Method.invoke(Method.java:``497``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``at org.junit.runners.model.FrameworkMethod$``1``.runReflectiveCall(FrameworkMethod.java:``47``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:``12``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:``44``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `14` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:``17``)` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 看到一堆出错信息，但是不要紧张，慢慢的读一下出错信息，这种错误一般会让你直觉感觉不会出现。\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;loader constraint violation\u0026lt;/span\u0026gt;表示类加载器冲突了，这句话暗示： 相同的类，由不同的ClassLoader加载，但是在这里遇到了。\n\u0026amp;lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;when resolving overridden method \u0026quot;com.murdock.classloader.linkageerror.Param2.generate()Lcom/murdock/classloader/linkageerror/Param2;\u0026quot;\u0026amp;lt;/span\u0026gt;表示在解析那条语句出现了问题，这里表示在\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;Param2.generate()\u0026lt;/span\u0026gt;方法的解析过程中出现了问题。\n\u0026amp;lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;the class loader (instance of com/murdock/classloader/linkageerror/LinkageErrorTest$1) of the current class, com/murdock/classloader/linkageerror/Param2,\u0026amp;lt;/span\u0026gt;表示解析的语句所在的类型\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;Param2\u0026lt;/span\u0026gt;是\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;LinkageErrorTest$1\u0026lt;/span\u0026gt;类加载器加载的。\n\u0026amp;lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;and its superclass loader (instance of sun/misc/Launcher$AppClassLoader), have different Class objects for the type com/murdock/classloader/linkageerror/Param2 used in the signature\u0026amp;lt;/span\u0026gt;表示\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;Param2\u0026lt;/span\u0026gt;的超类\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;Param\u0026lt;/span\u0026gt;中被覆盖的方法返回的类型\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;Param2\u0026lt;/span\u0026gt;为\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;Launcher$AppClassLoader\u0026lt;/span\u0026gt;加载。\nLinkage在常规情况下非常难以制造，只有在多个类加载器交互时才有可能出现，下面看一下问题代码。出现问题的类和参数：\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `package` `com.murdock.classloader.linkageerror;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `/**` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``* @author weipeng2k 2015年4月28日 上午10:04:26` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``*/` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `public` `class` `HandleUtils {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``public` `void` `m(Param param) {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``param.generate();` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `package` `com.murdock.classloader.linkageerror;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `14` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `15` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `public` `class` `Param {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `16` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``public` `Param2 generate() {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `17` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``return` `new` `Param2();` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `18` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `19` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `20` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `21` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `package` `com.murdock.classloader.linkageerror;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `22` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `23` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `public` `class` `Param2 ``extends` `Param {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `24` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``public` `Param2 generate() {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `25` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``return` `new` `Param2();` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `26` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `27` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 测试用例如下：\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `@Test` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `public` `void` `test() ``throws` `Exception {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``// cl1在加载HandleUtils和Param时将会使用AppClassLoader` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``URLClassLoader cl1 = ``new` `URLClassLoader(``new` `URL[] {``new` `File(``\u0026quot;target/test-classes\u0026quot;``).toURI().toURL()}, ``null``) {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``public` `Class\u0026amp;lt;?\u0026amp;gt; loadClass(String name) ``throws` `ClassNotFoundException {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``if``(``\u0026quot;com.murdock.classloader.linkageerror.HandleUtils\u0026quot;``.equals(name)) {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``return` `ClassLoader.getSystemClassLoader().loadClass(name);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``if` `(``\u0026quot;com.murdock.classloader.linkageerror.Param\u0026quot;``.equals(name)) {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `14` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``return` `ClassLoader.getSystemClassLoader().loadClass(name);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `15` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `16` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `17` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``return` `super``.loadClass(name);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `18` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `19` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `20` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``};` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `21` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `22` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``ClassLoader.getSystemClassLoader().loadClass(``\u0026quot;com.murdock.classloader.linkageerror.Param2\u0026quot;``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `23` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``HandleUtils hu = (HandleUtils) cl1.loadClass(``\u0026quot;com.murdock.classloader.linkageerror.HandleUtils\u0026quot;``).newInstance();` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `24` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``hu.m((Param) cl1.loadClass(``\u0026quot;com.murdock.classloader.linkageerror.Param2\u0026quot;``).newInstance());` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `25` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; LinkageError 需要观察哪个类被不同的类加载器加载了，在哪个方法或者调用处发生（交汇）的，然后才能想解决方法，解决方法无外乎两种。第一，还是不同的类加载器加载，但是相互不再交汇影响，这里需要针对发生问题的地方做一些改动，比如更换实现方式，避免出现上述问题；第二，冲突的类需要由一个Parent类加载器进行加载。**LinkageError** 和**ClassCastException** 本质是一样的，加载自不同类加载器的类型，在同一个类的方法或者调用中出现，如果有转型操作那么就会抛 ClassCastException ，如果是直接的方法调用处的参数或者返回值解析，那么就会产生 LinkageError 。\n8. 类加载器问题对照表 遇到类加载器问题时，可以尝试使用下面的表格进行问题排查。\n**类找不到** \u0026lt;td\u0026gt; **加****载****了不正确的类** \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; **多于一个类被加****载** \u0026lt;/td\u0026gt; ClassNotFoundException NoClassDefFoundError \u0026lt;td\u0026gt; IncompatibleClassChangeError NoSuchMethodError NoSuchFieldError IllegalAccessError \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; ClassCastException LinkageError \u0026lt;/td\u0026gt; IDE class lookup (Ctrl+Shift+T in Eclipse)find . -name “*.jar” -exec jar -tf {} \\; | grep DateUtils使用middleware-detector \u0026lt;td\u0026gt; 通过在启动参数中加 -verbose:class，观察加载的类来自哪个jar包使用middelware-detector \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 通过`-verbose:class`观察 \u0026lt;/td\u0026gt; 9. 使用Middleware-Detector进行类查找 出现了 ClassNotFoundException 或者 NoClassDefFoundError ，需要检查一下程序的classpath下面是否存在你所预想的类。这时可以使用Middleware-Detector工具进行类查找，该工具是Alibaba中间件团队开发的一款中间件问题诊断工具，当然也包括了许多支持性质的工具。\n下面我们使用Middleware-Detector进行类查找，比如我们要查找apache的Utils，我们怀疑这个类在classpath下找不到。\n启动middleware-detector，查看 Pandora 提供的自定义检查器，目前编号为1的Pandora自定义检查器就是进行classpath下的指定类或者接口的查找工作。\n配置classpath目录以及需要查找的类名，这里类名支持 * 号进行模糊匹配。可以看到设定当前的classpath目录到了_WEB-INF/lib_ 下面，然后找寻\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;*apache*comm*A*Utils\u0026lt;/span\u0026gt;是否存在，如果能够找到则会输出到终端，这里就找到了ArchiveUtils和ArrayUtils两个符合要求的类。如果无法找到，那么就可能是\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;pom.xml\u0026lt;/span\u0026gt;的依赖配置不正确了，需要检查一下。\n10. 使用Middleware-Detector进行检查类冲突 出现了 NoSuchMethodError 或者 NoSuchFieldError ，这时一般是应用的classpath下包含了多个包含了想同类的jar包，而很不幸的加载到了 不正确 的jar包。\n我们可以通过使用Middleware-Detector的类查找进行定位，但是不能发现一个修复一个，这里Middleware-Detector提供了一个检查classpath下有冲突jar包的功能。只需要设置classpath的目录，然后运行cc –check tomcat#1即可。有冲突的jar就需要自己在pom.xml里面进行仲裁或者排除了。\n**原创文章，转载请注明：** 转载自[并发编程网 – ifeve.com](http://ifeve.com/)**本文链接地址:**[深入浅出ClassLoader](http://ifeve.com/classloader/) 一看你就懂，超详细java中的ClassLoader详解\nClassLoader翻译过来就是类加载器，普通的Java开发者其实用到的不多，但对于某些框架开发者来说却非常常见。理解ClassLoader的加载机制，也有利于我们编写出更高效的代码。ClassLoader的具体作用就是将class文件加载到jvm虚拟机中去，程序就可以正确运行了。但是，jvm启动的时候，并不会一次性加载所有的class文件，而是根据需要去动态加载。想想也是的，一次性加载那么多jar包那么多class，那内存不崩溃。本文的目的也是学习ClassLoader这种加载机制。\n备注：本文篇幅比较长，但内容简单，大家不要恐慌，安静地耐心翻阅就是\nClass文件的认识 我们都知道在Java中程序是运行在虚拟机中，我们平常用文本编辑器或者是IDE编写的程序都是.java格式的文件，这是最基础的源码，但这类文件是不能直接运行的。如我们编写一个简单的程序HelloWorld.java\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;HelloWorld\u0026amp;lt;/span\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;main\u0026amp;lt;/span\u0026gt;(String[] args){ System.out.println(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Hello world!\u0026#34;\u0026amp;lt;/span\u0026gt;); } }` 如图：\n然后，我们需要在命令行中进行java文件的编译\n`javac HelloWorld\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.java\u0026amp;lt;/span\u0026gt;` 可以看到目录下生成了.class文件\n我们再从命令行中执行命令：\n`java HelloWorld` 上面是基本代码示例，是所有入门JAVA语言时都学过的东西，这里重新拿出来是想让大家将焦点回到class文件上，class文件是字节码格式文件，java虚拟机并不能直接识别我们平常编写的.java源文件，所以需要javac这个命令转换成.class文件。另外，如果用C或者Python编写的程序正确转换成.class文件后，java虚拟机也是可以识别运行的。更多信息大家可以参考这篇。\n了解了.class文件后，我们再来思考下，我们平常在Eclipse中编写的java程序是如何运行的，也就是我们自己编写的各种类是如何被加载到jvm(java虚拟机)中去的。\n你还记得java环境变量吗？ 初学java的时候，最害怕的就是下载JDK后要配置环境变量了，关键是当时不理解，所以战战兢兢地照着书籍上或者是网络上的介绍进行操作。然后下次再弄的时候，又忘记了而且是必忘。当时，心里的想法很气愤的，想着是–这东西一点也不人性化，为什么非要自己配置环境变量呢？太不照顾菜鸟和新手了，很多菜鸟就是因为卡在环境变量的配置上，遭受了太多的挫败感。\n因为我是在Windows下编程的，所以只讲Window平台上的环境变量，主要有3个：JAVA_HOME、PATH、CLASSPATH。\nJAVA_HOME 指的是你JDK安装的位置，一般默认安装在C盘，如\n`C:\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\Program\u0026amp;lt;/span\u0026gt; Files\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\Java\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\jdk\u0026amp;lt;/span\u0026gt;1.8.0_91` PATH 将程序路径包含在PATH当中后，在命令行窗口就可以直接键入它的名字了，而不再需要键入它的全路径,比如上面代码中我用的到javac和java两个命令。\n一般的\n`PATH=\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;%JAVA_HOME\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;%\\\u0026amp;lt;/span\u0026gt;bin;\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;%JAVA_HOME\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;%\\\u0026amp;lt;/span\u0026gt;jre\\bin;\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;%PATH\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;%;\u0026amp;lt;/span\u0026gt;` 也就是在原来的PATH路径上添加JDK目录下的bin目录和jre目录的bin.\nCLASSPATH `CLASSPATH=.;\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;%JAVA_HOME\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;%\\\u0026amp;lt;/span\u0026gt;lib;\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;%JAVA_HOME\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;%\\\u0026amp;lt;/span\u0026gt;lib\\tools.jar` 一看就是指向jar包路径。\n需要注意的是前面的.;，.代表当前目录。\n环境变量的设置与查看 设置可以右击我的电脑，然后点击属性，再点击高级，然后点击环境变量，具体不明白的自行查阅文档。\n查看的话可以打开命令行窗口\n`\u0026lt;code class=\"language-cmd hljs dos has-numbering\"\u003e\u0026lt;br /\u003e \u0026lt;span class=\"hljs-keyword\"\u003eecho\u0026lt;/span\u003e \u0026lt;span class=\"hljs-envvar\"\u003e%JAVA_HOME%\u0026lt;/span\u003e`echo %PATH% `\u0026amp;lt;code class=\u0026quot;language-cmd hljs dos has-numbering\u0026quot;\u0026gt;`\u0026lt;/code\u0026gt;\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;echo\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-envvar\u0026quot;\u0026gt;%CLASSPATH%\u0026lt;/span\u0026gt; 好了，扯远了，知道了环境变量，特别是CLASSPATH时，我们进入今天的主题Classloader.\nJAVA类加载流程 Java语言系统自带有三个类加载器:\n我们上面简单介绍了3个ClassLoader。说明了它们加载的路径。并且还提到了-Xbootclasspath和-D java.ext.dirs这两个虚拟机参数选项。\n加载顺序？ 我们看到了系统的3个类加载器，但我们可能不知道具体哪个先行呢？\n我可以先告诉你答案\nBootstrap CLassloder Extention ClassLoader AppClassLoader 为了更好的理解，我们可以查看源码。\n看sun.misc.Launcher,它是一个java虚拟机的入口应用。\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Launcher\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; Launcher launcher = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Launcher(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; String bootClassPath = System.getProperty(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;sun.boot.class.path\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; Launcher \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getLauncher\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; launcher; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ClassLoader loader; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Launcher\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Create the extension class loader\u0026amp;lt;/span\u0026gt; ClassLoader extcl; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { extcl = ExtClassLoader.getExtClassLoader(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (IOException e) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; InternalError( \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Could not create extension class loader\u0026#34;\u0026amp;lt;/span\u0026gt;, e); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Now create the class loader to use to launch the application\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { loader = AppClassLoader.getAppClassLoader(extcl); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (IOException e) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; InternalError( \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Could not create application class loader\u0026#34;\u0026amp;lt;/span\u0026gt;, e); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置AppClassLoader为线程上下文类加载器，这个文章后面部分讲解\u0026amp;lt;/span\u0026gt; Thread.currentThread().setContextClassLoader(loader); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* * Returns the class loader used to launch the main application. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ClassLoader \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getClassLoader\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; loader; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* * The class loader used for loading installed extensions. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; class ExtClassLoader extends URLClassLoader {} \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * The class loader used for loading from java.class.path. * runs in a restricted security context. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; class AppClassLoader extends URLClassLoader {}` Launcher初始化了ExtClassLoader和AppClassLoader。 Launcher中并没有看见BootstrapClassLoader，但通过System.getProperty(\u0026quot;sun.boot.class.path\u0026quot;)得到了字符串bootClassPath,这个应该就是BootstrapClassLoader加载的jar包路径。 我们可以先代码测试一下sun.boot.class.path是什么内容。\n`System.out.println(System.getProperty(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;sun.boot.class.path\u0026#34;\u0026amp;lt;/span\u0026gt;));` 得到的结果是：\n`C:\u0026lt;span class=\"hljs-command\"\u003e\\Program\u0026lt;/span\u003e Files\u0026lt;span class=\"hljs-command\"\u003e\\Java\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\jre\u0026lt;/span\u003e1.8.0_91\u0026lt;span class=\"hljs-command\"\u003e\\lib\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\resources\u0026lt;/span\u003e.jar;\u0026lt;br /\u003e C:\u0026lt;span class=\"hljs-command\"\u003e\\Program\u0026lt;/span\u003e Files\u0026lt;span class=\"hljs-command\"\u003e\\Java\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\jre\u0026lt;/span\u003e1.8.0_91\u0026lt;span class=\"hljs-command\"\u003e\\lib\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\rt\u0026lt;/span\u003e.jar;\u0026lt;br /\u003e C:\u0026lt;span class=\"hljs-command\"\u003e\\Program\u0026lt;/span\u003e Files\u0026lt;span class=\"hljs-command\"\u003e\\Java\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\jre\u0026lt;/span\u003e1.8.0_91\u0026lt;span class=\"hljs-command\"\u003e\\lib\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\sunrsasign\u0026lt;/span\u003e.jar;\u0026lt;br /\u003e C:\u0026lt;span class=\"hljs-command\"\u003e\\Program\u0026lt;/span\u003e Files\u0026lt;span class=\"hljs-command\"\u003e\\Java\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\jre\u0026lt;/span\u003e1.8.0_91\u0026lt;span class=\"hljs-command\"\u003e\\lib\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\jsse\u0026lt;/span\u003e.jar;\u0026lt;br /\u003e C:\u0026lt;span class=\"hljs-command\"\u003e\\Program\u0026lt;/span\u003e Files\u0026lt;span class=\"hljs-command\"\u003e\\Java\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\jre\u0026lt;/span\u003e1.8.0_91\u0026lt;span class=\"hljs-command\"\u003e\\lib\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\jce\u0026lt;/span\u003e.jar;\u0026lt;br /\u003e C:\u0026lt;span class=\"hljs-command\"\u003e\\Program\u0026lt;/span\u003e Files\u0026lt;span class=\"hljs-command\"\u003e\\Java\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\jre\u0026lt;/span\u003e1.8.0_91\u0026lt;span class=\"hljs-command\"\u003e\\lib\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\charsets\u0026lt;/span\u003e.jar;\u0026lt;br /\u003e C:\u0026lt;span class=\"hljs-command\"\u003e\\Program\u0026lt;/span\u003e Files\u0026lt;span class=\"hljs-command\"\u003e\\Java\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\jre\u0026lt;/span\u003e1.8.0_91\u0026lt;span class=\"hljs-command\"\u003e\\lib\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\jfr\u0026lt;/span\u003e.jar;\u0026lt;br /\u003e C:\u0026lt;span class=\"hljs-command\"\u003e\\Program\u0026lt;/span\u003e Files\u0026lt;span class=\"hljs-command\"\u003e\\Java\u0026lt;/span\u003e\u0026lt;span class=\"hljs-command\"\u003e\\jre\u0026lt;/span\u003e1.8.0_91\u0026lt;span class=\"hljs-command\"\u003e\\classes\u0026lt;/span\u003e` 可以看到，这些全是JRE目录下的jar包或者是class文件。\nExtClassLoader源码 如果你有足够的好奇心，你应该会对它的源码感兴趣\n() { public ExtClassLoader run() throws IOException { int len = dirs.length; for (int i = 0; i \u0026lt; len; i++) { MetaIndex.registerDirectory(dirs[i]); } return new ExtClassLoader(dirs); } }); } catch (java.security.PrivilegedActionException e) { throw (IOException) e.getException(); } } private static File[] getExtDirs() { String s = System.getProperty(\u0026amp;quot;java.ext.dirs\u0026amp;quot;); File[] dirs; if (s != null) { StringTokenizer st = new StringTokenizer(s, File.pathSeparator); int count = st.countTokens(); dirs = new File[count]; for (int i = 0; i \u0026lt; count; i++) { dirs[i] = new File(st.nextToken()); } } else { dirs = new File[0]; } return dirs; } ...... }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 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 \u0026#34; data-snippet-id=\u0026#34;ext.8b40bc39f28146d6e25bee49c06f18d9\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* * The class loader used for loading installed extensions. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; class ExtClassLoader extends URLClassLoader { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; { ClassLoader.registerAsParallelCapable(); } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * create an ExtClassLoader. The ExtClassLoader is created * within a context that limits which files it can read */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; ExtClassLoader \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getExtClassLoader\u0026amp;lt;/span\u0026gt;() \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; IOException { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; File[] dirs = getExtDirs(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Prior implementations of this doPrivileged() block supplied\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// aa synthesized ACC via a call to the private method\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// ExtClassLoader.getContext().\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; AccessController.doPrivileged( \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; PrivilegedExceptionAction\u0026amp;lt;ExtClassLoader\u0026amp;gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ExtClassLoader \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;run\u0026amp;lt;/span\u0026gt;() \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; IOException { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; len = dirs.length; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; len; i++) { MetaIndex.registerDirectory(dirs[i]); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ExtClassLoader(dirs); } }); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (java.security.PrivilegedActionException e) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; (IOException) e.getException(); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; File[] \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getExtDirs\u0026amp;lt;/span\u0026gt;() { String s = System.getProperty(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;java.ext.dirs\u0026#34;\u0026amp;lt;/span\u0026gt;); File[] dirs; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (s != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { StringTokenizer st = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; StringTokenizer(s, File.pathSeparator); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; count = st.countTokens(); dirs = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File[count]; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; count; i++) { dirs[i] = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File(st.nextToken()); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { dirs = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;]; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; dirs; } ...... }` 我们先前的内容有说过，可以指定-D java.ext.dirs参数来添加和改变ExtClassLoader的加载路径。这里我们通过可以编写测试代码。\n`System.out.println(System.getProperty(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;java.ext.dirs\u0026#34;\u0026amp;lt;/span\u0026gt;)); `结果如下： `C:\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\Program\u0026amp;lt;/span\u0026gt; Files\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\Java\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\jre\u0026amp;lt;/span\u0026gt;1.8.0_91\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\lib\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\ext\u0026amp;lt;/span\u0026gt;;C:\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\Windows\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\Sun\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\Java\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\lib\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\ext\u0026amp;lt;/span\u0026gt;`\u0026lt;a name=\u0026#34;t9\u0026#34;\u0026gt;\u0026lt;/a\u0026gt; AppClassLoader源码 () { public AppClassLoader run() { URL[] urls = (s == null) ? new URL[0] : pathToURLs(path); return new AppClassLoader(urls, extcl); } }); } ...... }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 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 \u0026#34; data-snippet-id=\u0026#34;ext.4662359bb6e43c93004593fae6f19f13\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * The class loader used for loading from java.class.path. * runs in a restricted security context. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; class AppClassLoader extends URLClassLoader { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt; public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; ClassLoader \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getAppClassLoader\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; ClassLoader extcl) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; IOException { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt; final\u0026amp;lt;/span\u0026gt; String s = System.getProperty(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;java.class.path\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt; final\u0026amp;lt;/span\u0026gt; File[] path = (s == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) ? \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] : getClassPath(s); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt; return\u0026amp;lt;/span\u0026gt; AccessController.doPrivileged( \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; PrivilegedAction\u0026amp;lt;AppClassLoader\u0026amp;gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt; public\u0026amp;lt;/span\u0026gt; AppClassLoader \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;run\u0026amp;lt;/span\u0026gt;() { URL[] urls = (s == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) ? \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; URL[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] : pathToURLs(path); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt; return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; AppClassLoader(urls, extcl); } }); } ...... }` 可以看到AppClassLoader加载的就是java.class.path下的路径。我们同样打印它的值。\n`System.out.println(System.getProperty(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;java.class.path\u0026#34;\u0026amp;lt;/span\u0026gt;));` 结果：\n`D:\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\workspace\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\ClassLoaderDemo\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-command\u0026#34;\u0026gt;\\bin\u0026amp;lt;/span\u0026gt;` 这个路径其实就是当前java工程目录bin，里面存放的是编译生成的class文件。\n好了，自此我们已经知道了BootstrapClassLoader、ExtClassLoader、AppClassLoader实际是查阅相应的环境属性sun.boot.class.path、java.ext.dirs和java.class.path来加载资源文件的。\n接下来我们探讨它们的加载顺序，我们先用Eclipse建立一个java工程。\n然后创建一个Test.java文件。\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Test\u0026amp;lt;/span\u0026gt;{\u0026amp;lt;/span\u0026gt;}` 然后，编写一个ClassLoaderTest.java文件。\n`\u0026lt;code class=\"language-java hljs has-numbering\"\u003e\u0026lt;br /\u003e \u0026lt;span class=\"hljs-keyword\"\u003epublic\u0026lt;/span\u003e \u0026lt;span class=\"hljs-class\"\u003e\u0026lt;span class=\"hljs-keyword\"\u003eclass\u0026lt;/span\u003e \u0026lt;span class=\"hljs-title\"\u003eClassLoaderTest\u0026lt;/span\u003e {\u0026lt;/span\u003e`public static void main(String[] args) { // TODO Auto-generated method stub `\u0026amp;lt;code class=\u0026quot;language-java hljs has-numbering\u0026quot;\u0026gt;`\u0026lt;/code\u0026gt;ClassLoader cl = Test.class.getClassLoader(); `\u0026amp;lt;code class=\u0026quot;language-java hljs has-numbering\u0026quot;\u0026gt;`\u0026lt;/code\u0026gt;System.out.println(\u0026lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026amp;#8220;ClassLoader is:\u0026amp;#8221;\u0026lt;/span\u0026gt;+cl.toString()); `\u0026amp;lt;code class=\u0026quot;language-java hljs has-numbering\u0026quot;\u0026gt;`\u0026lt;/code\u0026gt;} `\u0026amp;lt;code class=\u0026quot;language-java hljs has-numbering\u0026quot;\u0026gt;`\u0026lt;/code\u0026gt;} 我们获取到了Test.class文件的类加载器，然后打印出来。结果是：\n`ClassLoader is:sun\u0026lt;span class=\"hljs-preprocessor\"\u003e.misc\u0026lt;/span\u003e\u0026lt;span class=\"hljs-preprocessor\"\u003e.Launcher\u0026lt;/span\u003e$AppClassLoader\u0026lt;span class=\"hljs-localvars\"\u003e@73\u0026lt;/span\u003ed16e93 ` 也就是说明Test.class文件是由AppClassLoader加载的。\n这个Test类是我们自己编写的，那么int.class或者是String.class的加载是由谁完成的呢？\n我们可以在代码中尝试\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ClassLoaderTest\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;main\u0026amp;lt;/span\u0026gt;(String[] args) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated method stub\u0026amp;lt;/span\u0026gt; ClassLoader cl = Test.class.getClassLoader(); System.out.println(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;ClassLoader is:\u0026#34;\u0026amp;lt;/span\u0026gt;+cl.toString()); cl = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;.class.getClassLoader(); System.out.println(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;ClassLoader is:\u0026#34;\u0026amp;lt;/span\u0026gt;+cl.toString()); } }` 运行一下，却报错了\n`ClassLoader is:sun\u0026lt;span class=\"hljs-preprocessor\"\u003e.misc\u0026lt;/span\u003e\u0026lt;span class=\"hljs-preprocessor\"\u003e.Launcher\u0026lt;/span\u003e$AppClassLoader\u0026lt;span class=\"hljs-localvars\"\u003e@73\u0026lt;/span\u003ed16e93\u0026lt;br /\u003e Exception \u0026lt;span class=\"hljs-keyword\"\u003ein\u0026lt;/span\u003e thread \u0026lt;span class=\"hljs-string\"\u003e\"main\"\u0026lt;/span\u003e java\u0026lt;span class=\"hljs-preprocessor\"\u003e.lang\u0026lt;/span\u003e\u0026lt;span class=\"hljs-preprocessor\"\u003e.NullPointerException\u0026lt;/span\u003e\u0026lt;br /\u003e at ClassLoaderTest\u0026lt;span class=\"hljs-preprocessor\"\u003e.main\u0026lt;/span\u003e(ClassLoaderTest\u0026lt;span class=\"hljs-preprocessor\"\u003e.java\u0026lt;/span\u003e:\u0026lt;span class=\"hljs-number\"\u003e15\u0026lt;/span\u003e)` 提示的是空指针，意思是int.class这类基础类没有类加载器加载？\n当然不是！\nint.class是由Bootstrap ClassLoader加载的。要想弄明白这些，我们首先得知道一个前提。\n每个类加载器都有一个父加载器 每个类加载器都有一个父加载器，比如加载Test.class是由AppClassLoader完成，那么AppClassLoader也有一个父加载器，怎么样获取呢？很简单，通过getParent方法。比如代码可以这样编写：\n`ClassLoader cl = Test.class.getClassLoader(); System.out.println(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;ClassLoader is:\u0026#34;\u0026amp;lt;/span\u0026gt;+cl.toString()); System.out.println(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;ClassLoader\\\u0026#39;s parent is:\u0026#34;\u0026amp;lt;/span\u0026gt;+cl.getParent().toString()); `运行结果如下： `ClassLoader \u0026lt;span class=\"hljs-keyword\"\u003eis\u0026lt;/span\u003e:sun.misc.Launcher$AppClassLoader@\u0026lt;span class=\"hljs-number\"\u003e73\u0026lt;/span\u003ed16e93\u0026lt;br /\u003e ClassLoader\u0026lt;span class=\"hljs-attribute\"\u003e's\u0026lt;/span\u003e parent \u0026lt;span class=\"hljs-keyword\"\u003eis\u0026lt;/span\u003e:sun.misc.Launcher$ExtClassLoader@\u0026lt;span class=\"hljs-number\"\u003e15\u0026lt;/span\u003edb9742` 这个说明，AppClassLoader的父加载器是ExtClassLoader。那么ExtClassLoader的父加载器又是谁呢？ System.out.println(\u0026#8220;ClassLoader is:\u0026#8221;+cl.toString()); `System.out.println(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;ClassLoader\\\u0026#39;s parent is:\u0026#34;\u0026amp;lt;/span\u0026gt;+cl.getParent().toString()); System.out.println(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;ClassLoader\\\u0026#39;s grand father is:\u0026#34;\u0026amp;lt;/span\u0026gt;+cl.getParent().getParent().toString());` 运行如果：\n`ClassLoader \u0026lt;span class=\"hljs-keyword\"\u003eis\u0026lt;/span\u003e:sun.misc.Launcher$AppClassLoader@\u0026lt;span class=\"hljs-number\"\u003e73\u0026lt;/span\u003ed16e93\u0026lt;br /\u003e Exception \u0026lt;span class=\"hljs-keyword\"\u003ein\u0026lt;/span\u003e thread \u0026lt;span class=\"hljs-string\"\u003e\"main\"\u0026lt;/span\u003e ClassLoader\u0026lt;span class=\"hljs-attribute\"\u003e's\u0026lt;/span\u003e parent \u0026lt;span class=\"hljs-keyword\"\u003eis\u0026lt;/span\u003e:sun.misc.Launcher$ExtClassLoader@\u0026lt;span class=\"hljs-number\"\u003e15\u0026lt;/span\u003edb9742\u0026lt;br /\u003e java.lang.NullPointerException\u0026lt;br /\u003e at ClassLoaderTest.main(ClassLoaderTest.java:\u0026lt;span class=\"hljs-number\"\u003e13\u0026lt;/span\u003e)` 又是一个空指针异常，这表明ExtClassLoader也没有父加载器。那么，为什么标题又是每一个加载器都有一个父加载器呢？这不矛盾吗？为了解释这一点，我们还需要看下面的一个基础前提。\n父加载器不是父类 我们先前已经粘贴了ExtClassLoader和AppClassLoader的代码。\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; class ExtClassLoader extends URLClassLoader {} \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; class AppClassLoader extends URLClassLoader {}` 可以看见ExtClassLoader和AppClassLoader同样继承自URLClassLoader，但上面一小节代码中，为什么调用AppClassLoader的getParent()代码会得到ExtClassLoader的实例呢？先从URLClassLoader说起，这个类又是什么？\n先上一张类的继承关系图\nURLClassLoader的源码中并没有找到getParent()方法。这个方法在ClassLoader.java中。\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;abstract\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ClassLoader\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// The parent class loader for delegation\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Note: VM hardcoded the offset of this field, thus all new fields\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// must be added *after* it.\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; ClassLoader parent; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// The class loader for the system\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// @GuardedBy(\u0026#34;ClassLoader.class\u0026#34;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; ClassLoader scl; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ClassLoader\u0026amp;lt;/span\u0026gt;(Void unused, ClassLoader parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.parent = parent; ... } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ClassLoader\u0026amp;lt;/span\u0026gt;(ClassLoader parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;(checkCreateClassLoader(), parent); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ClassLoader\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;(checkCreateClassLoader(), getSystemClassLoader()); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; ClassLoader \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getParent\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (parent == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; parent; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; ClassLoader \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getSystemClassLoader\u0026amp;lt;/span\u0026gt;() { initSystemClassLoader(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (scl == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; scl; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;synchronized\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initSystemClassLoader\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!sclSet) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (scl != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; IllegalStateException(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;recursive invocation\u0026#34;\u0026amp;lt;/span\u0026gt;); sun.misc.Launcher l = sun.misc.Launcher.getLauncher(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (l != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { Throwable oops = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//通过Launcher获取ClassLoader\u0026amp;lt;/span\u0026gt; scl = l.getClassLoader(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { scl = AccessController.doPrivileged( \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; SystemClassLoaderAction(scl)); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (PrivilegedActionException pae) { oops = pae.getCause(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (oops \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; InvocationTargetException) { oops = oops.getCause(); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (oops != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (oops \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; Error) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; (Error) oops; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// wrap the exception\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Error(oops); } } } sclSet = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } } }` 我们可以看到getParent()实际上返回的就是一个ClassLoader对象parent，parent的赋值是在ClassLoader对象的构造方法中，它有两个情况：\n由外部类创建ClassLoader时直接指定一个ClassLoader为parent。 由getSystemClassLoader()方法生成，也就是在sun.misc.Laucher通过getClassLoader()获取，也就是AppClassLoader。直白的说，一个ClassLoader创建时如果没有指定parent，那么它的parent默认就是AppClassLoader。 我们主要研究的是ExtClassLoader与AppClassLoader的parent的来源，正好它们与Launcher类有关，我们上面已经粘贴过Launcher的部分代码。\n() { public ExtClassLoader run() throws IOException { //ExtClassLoader在这里创建 return new ExtClassLoader(dirs); } }); } catch (java.security.PrivilegedActionException e) { throw (IOException) e.getException(); } } /* * Creates a new ExtClassLoader for the specified directories. */ public ExtClassLoader(File[] dirs) throws IOException { super(getExtURLs(dirs), null, factory); } } }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 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 \u0026#34; data-snippet-id=\u0026#34;ext.a48bc3c9f667193c6d8a3b3c2611b995\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Launcher\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; URLStreamHandlerFactory factory = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Factory(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; Launcher launcher = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Launcher(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; String bootClassPath = System.getProperty(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;sun.boot.class.path\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; Launcher \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getLauncher\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; launcher; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ClassLoader loader; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Launcher\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Create the extension class loader\u0026amp;lt;/span\u0026gt; ClassLoader extcl; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { extcl = ExtClassLoader.getExtClassLoader(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (IOException e) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; InternalError( \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Could not create extension class loader\u0026#34;\u0026amp;lt;/span\u0026gt;, e); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Now create the class loader to use to launch the application\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//将ExtClassLoader对象实例传递进去\u0026amp;lt;/span\u0026gt; loader = AppClassLoader.getAppClassLoader(extcl); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (IOException e) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; InternalError( \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Could not create application class loader\u0026#34;\u0026amp;lt;/span\u0026gt;, e); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ClassLoader \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getClassLoader\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; loader; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; class ExtClassLoader extends URLClassLoader { \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * create an ExtClassLoader. The ExtClassLoader is created * within a context that limits which files it can read */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; ExtClassLoader \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getExtClassLoader\u0026amp;lt;/span\u0026gt;() \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; IOException { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; File[] dirs = getExtDirs(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Prior implementations of this doPrivileged() block supplied\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// aa synthesized ACC via a call to the private method\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// ExtClassLoader.getContext(). \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; AccessController.doPrivileged( \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; PrivilegedExceptionAction\u0026amp;lt;ExtClassLoader\u0026amp;gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ExtClassLoader \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;run\u0026amp;lt;/span\u0026gt;() \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; IOException { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//ExtClassLoader在这里创建\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ExtClassLoader(dirs); } }); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (java.security.PrivilegedActionException e) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; (IOException) e.getException(); } } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* * Creates a new ExtClassLoader for the specified directories. */ \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ExtClassLoader\u0026amp;lt;/span\u0026gt;(File[] dirs) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; IOException { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;(getExtURLs(dirs), \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;, factory); } } }` 我们需要注意的是\n`ClassLoader extcl;` extcl = ExtClassLoader.getExtClassLoader(); loader = AppClassLoader.getAppClassLoader(extcl); 代码已经说明了问题AppClassLoader的parent是一个ExtClassLoader实例。\nExtClassLoader并没有直接找到对parent的赋值。它调用了它的父类也就是URLClassLoder的构造方法并传递了3个参数。\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ExtClassLoader\u0026amp;lt;/span\u0026gt;(File[] dirs) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; IOException { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;(getExtURLs(dirs), \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;, factory); }` 对应的代码\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;URLClassLoader\u0026amp;lt;/span\u0026gt;(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;(parent); }` 答案已经很明了了，ExtClassLoader的parent为null。\n上面张贴这么多代码也是为了说明AppClassLoader的parent是ExtClassLoader，ExtClassLoader的parent是null。这符合我们之前编写的测试代码。\n不过，细心的同学发现，还是有疑问的我们只看到ExtClassLoader和AppClassLoader的创建，那么BootstrapClassLoader呢？\n还有，ExtClassLoader的父加载器为null,但是Bootstrap CLassLoader却可以当成它的父加载器这又是为何呢？\n我们继续往下进行。\nBootstrap ClassLoader是由C++编写的。 Bootstrap ClassLoader是由C/C++编写的，它本身是虚拟机的一部分，所以它并不是一个JAVA类，也就是无法在java代码中获取它的引用，JVM启动时通过Bootstrap类加载器加载rt.jar等核心jar包中的class文件，之前的int.class,String.class都是由它加载。然后呢，我们前面已经分析了，JVM初始化sun.misc.Launcher并创建Extension ClassLoader和AppClassLoader实例。并将ExtClassLoader设置为AppClassLoader的父加载器。Bootstrap没有父加载器，但是它却可以作用一个ClassLoader的父加载器。比如ExtClassLoader。这也可以解释之前通过ExtClassLoader的getParent方法获取为Null的现象。具体是什么原因，很快就知道答案了。\n双亲委托 双亲委托。\n我们终于来到了这一步了。\n一个类加载器查找class和resource时，是通过“委托模式”进行的，它首先判断这个class是不是已经加载成功，如果没有的话它并不是自己进行查找，而是先通过父加载器，然后递归下去，直到Bootstrap ClassLoader，如果Bootstrap classloader找到了，直接返回，如果没有找到，则一级一级返回，最后到达自身去查找这些对象。这种机制就叫做双亲委托。\n整个流程可以如下图所示：\n这张图是用时序图画出来的，不过画出来的结果我却自己都觉得不理想。\n大家可以看到2根箭头，蓝色的代表类加载器向上委托的方向，如果当前的类加载器没有查询到这个class对象已经加载就请求父加载器（不一定是父类）进行操作，然后以此类推。直到Bootstrap ClassLoader。如果Bootstrap ClassLoader也没有加载过此class实例，那么它就会从它指定的路径中去查找，如果查找成功则返回，如果没有查找成功则交给子类加载器，也就是ExtClassLoader,这样类似操作直到终点，也就是我上图中的红色箭头示例。\n用序列描述一下：\n一个AppClassLoader查找资源时，先看看缓存是否有，缓存有从缓存中获取，否则委托给父加载器。 递归，重复第1部的操作。 如果ExtClassLoader也没有加载过，则由Bootstrap ClassLoader出面，它首先查找缓存，如果没有找到的话，就去找自己的规定的路径下，也就是sun.mic.boot.class下面的路径。找到就返回，没有找到，让子加载器自己去找。 Bootstrap ClassLoader如果没有查找成功，则ExtClassLoader自己在java.ext.dirs路径中去查找，查找成功就返回，查找不成功，再向下让子加载器找。 ExtClassLoader查找不成功，AppClassLoader就自己查找，在java.class.path路径下查找。找到就返回。如果没有找到就让子类找，如果没有子类会怎么样？抛出各种异常。 上面的序列，详细说明了双亲委托的加载流程。我们可以发现委托是从下向上，然后具体查找过程却是自上至下。\n我说过上面用时序图画的让自己不满意，现在用框图，最原始的方法再画一次。\n上面已经详细介绍了加载过程，但具体为什么是这样加载，我们还需要了解几个个重要的方法loadClass()、findLoadedClass()、findClass()、defineClass()。\n重要方法 loadClass() JDK文档中是这样写的，通过指定的全限定类名加载class，它通过同名的loadClass(String,boolean)方法。\nloadClass(String name, boolean resolve) throws ClassNotFoundException1 2 3 1 2 3 \u0026#34; data-snippet-id=\u0026#34;ext.48538537cbf6744758895c66d4af71de\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; Class\u0026amp;lt;?\u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;loadClass\u0026amp;lt;/span\u0026gt;(String name, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; resolve) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; ClassNotFoundException` 上面是方法原型，一般实现这个方法的步骤是\n执行findLoadedClass(String)去检测这个class是不是已经加载过了。 执行父加载器的loadClass方法。如果父加载器为null，则jvm内置的加载器去替代，也就是Bootstrap ClassLoader。这也解释了ExtClassLoader的parent为null,但仍然说Bootstrap ClassLoader是它的父加载器。 如果向上委托父加载器没有加载成功，则通过findClass(String)查找。 如果class在上面的步骤中找到了，参数resolve又是true的话，那么loadClass()又会调用resolveClass(Class)这个方法来生成最终的Class对象。 我们可以从源代码看出这个步骤。\nloadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 首先，检测是否已经加载 Class\u0026lt;?\u0026gt; c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { //父加载器不为空则调用父加载器的loadClass c = parent.loadClass(name, false); } else { //父加载器为空则调用Bootstrap Classloader c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); //父加载器没有找到，则调用findclass c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { //调用resolveClass() resolveClass(c); } return c; } }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 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 \u0026#34; data-snippet-id=\u0026#34;ext.448d162044bbbfd90c24221855b9ef7c\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; Class\u0026amp;lt;?\u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;loadClass\u0026amp;lt;/span\u0026gt;(String name, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; resolve) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; ClassNotFoundException { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;synchronized\u0026amp;lt;/span\u0026gt; (getClassLoadingLock(name)) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 首先，检测是否已经加载\u0026amp;lt;/span\u0026gt; Class\u0026amp;lt;?\u0026amp;gt; c = findLoadedClass(name); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (c == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;long\u0026amp;lt;/span\u0026gt; t0 = System.nanoTime(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (parent != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//父加载器不为空则调用父加载器的loadClass\u0026amp;lt;/span\u0026gt; c = parent.loadClass(name, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//父加载器为空则调用Bootstrap Classloader\u0026amp;lt;/span\u0026gt; c = findBootstrapClassOrNull(name); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (ClassNotFoundException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// ClassNotFoundException thrown if class not found\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// from the non-null parent class loader\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (c == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// If still not found, then invoke findClass in order\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// to find the class.\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;long\u0026amp;lt;/span\u0026gt; t1 = System.nanoTime(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//父加载器没有找到，则调用findclass\u0026amp;lt;/span\u0026gt; c = findClass(name); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// this is the defining class loader; record the stats\u0026amp;lt;/span\u0026gt; sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (resolve) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//调用resolveClass()\u0026amp;lt;/span\u0026gt; resolveClass(c); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; c; } }` 代码解释了双亲委托。\n另外，要注意的是如果要编写一个classLoader的子类，也就是自定义一个classloader，建议覆盖findClass()方法，而不要直接改写loadClass()方法。\n另外\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (parent != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//父加载器不为空则调用父加载器的loadClass\u0026amp;lt;/span\u0026gt; c = parent.loadClass(name, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//父加载器为空则调用Bootstrap Classloader\u0026amp;lt;/span\u0026gt; c = findBootstrapClassOrNull(name); }` 前面说过ExtClassLoader的parent为null，所以它向上委托时，系统会为它指定Bootstrap ClassLoader。\n自定义ClassLoader 不知道大家有没有发现，不管是Bootstrap ClassLoader还是ExtClassLoader等，这些类加载器都只是加载指定的目录下的jar包或者资源。如果在某种情况下，我们需要动态加载一些东西呢？比如从D盘某个文件夹加载一个class文件，或者从网络上下载class主内容然后再进行加载，这样可以吗？\n如果要这样做的话，需要我们自定义一个classloader。\n自定义步骤 编写一个类继承自ClassLoader抽象类。 复写它的findClass()方法。 在findClass()方法中调用defineClass()。 defineClass() 这个方法在编写自定义classloader的时候非常重要，它能将class二进制内容转换成Class对象，如果不符合要求的会抛出各种异常。\n注意点： 一个ClassLoader创建时如果没有指定parent，那么它的parent默认就是AppClassLoader。\n上面说的是，如果自定义一个ClassLoader，默认的parent父加载器是AppClassLoader，因为这样就能够保证它能访问系统内置加载器加载成功的class文件。\n自定义ClassLoader示例之DiskClassLoader。 假设我们需要一个自定义的classloader,默认加载路径为D:\\lib下的jar包和资源。\n我们写编写一个测试用的类文件，Test.java\nTest.java `\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;package\u0026amp;lt;/span\u0026gt; com.frank.test; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Test\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;say\u0026amp;lt;/span\u0026gt;(){ System.out.println(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Say Hello\u0026#34;\u0026amp;lt;/span\u0026gt;); } }` 然后将它编译过年class文件Test.class放到D:\\lib这个路径下。\nDiskClassLoader 我们编写DiskClassLoader的代码。\nfindClass(String name) throws ClassNotFoundException { // TODO Auto-generated method stub String fileName = getFileName(name); File file = new File(mLibPath,fileName); try { FileInputStream is = new FileInputStream(file); ByteArrayOutputStream bos = new ByteArrayOutputStream(); int len = 0; try { while ((len = is.read()) != -1) { bos.write(len); } } catch (IOException e) { e.printStackTrace(); } byte[] data = bos.toByteArray(); is.close(); bos.close(); return defineClass(name,data,0,data.length); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return super.findClass(name); } //获取要加载 的class文件名 private String getFileName(String name) { // TODO Auto-generated method stub int index = name.lastIndexOf(\u0026#39;.\u0026#39;); if(index == -1){ return name+\u0026amp;quot;.class\u0026amp;quot;; }else{ return name.substring(index)+\u0026amp;quot;.class\u0026amp;quot;; } } }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 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 \u0026#34; data-snippet-id=\u0026#34;ext.067b59aff348b158b874150ad02dfe05\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.ByteArrayOutputStream; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.File; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.FileInputStream; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.FileNotFoundException; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.IOException; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DiskClassLoader\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ClassLoader\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; String mLibPath; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DiskClassLoader\u0026amp;lt;/span\u0026gt;(String path) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated constructor stub\u0026amp;lt;/span\u0026gt; mLibPath = path; } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; Class\u0026amp;lt;?\u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;findClass\u0026amp;lt;/span\u0026gt;(String name) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throws\u0026amp;lt;/span\u0026gt; ClassNotFoundException { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated method stub\u0026amp;lt;/span\u0026gt; String fileName = getFileName(name); File file = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File(mLibPath,fileName); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { FileInputStream is = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; FileInputStream(file); ByteArrayOutputStream bos = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ByteArrayOutputStream(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; len = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;while\u0026amp;lt;/span\u0026gt; ((len = is.read()) != -\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) { bos.write(len); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (IOException e) { e.printStackTrace(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;byte\u0026amp;lt;/span\u0026gt;[] data = bos.toByteArray(); is.close(); bos.close(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; defineClass(name,data,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;,data.length); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (IOException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.findClass(name); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获取要加载 的class文件名\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; String \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getFileName\u0026amp;lt;/span\u0026gt;(String name) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated method stub\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; index = name.lastIndexOf(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;.\u0026#39;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(index == -\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;){ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; name+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;.class\u0026#34;\u0026amp;lt;/span\u0026gt;; }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; name.substring(index)+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;.class\u0026#34;\u0026amp;lt;/span\u0026gt;; } } }` 我们在findClass()方法中定义了查找class的方法，然后数据通过defineClass()生成了Class对象。\n测试 现在我们要编写测试代码。我们知道如果调用一个Test对象的say方法，它会输出”Say Hello”这条字符串。但现在是我们把Test.class放置在应用工程所有的目录之外，我们需要加载它，然后执行它的方法。具体效果如何呢？我们编写的DiskClassLoader能不能顺利完成任务呢？我们拭目以待。\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.lang.reflect.InvocationTargetException; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.lang.reflect.Method; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ClassLoaderTest\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;main\u0026amp;lt;/span\u0026gt;(String[] args) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated method stub\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//创建自定义classloader对象。\u0026amp;lt;/span\u0026gt; DiskClassLoader diskLoader = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DiskClassLoader(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;D:\\\\lib\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//加载class文件\u0026amp;lt;/span\u0026gt; Class c = diskLoader.loadClass(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;com.frank.test.Test\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(c != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { Object obj = c.newInstance(); Method method = c.getDeclaredMethod(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;say\u0026#34;\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//通过反射调用Test类的say方法\u0026amp;lt;/span\u0026gt; method.invoke(obj, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (ClassNotFoundException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } } }` 我们点击运行按钮，结果显示。\n可以看到，Test类的say方法正确执行，也就是我们写的DiskClassLoader编写成功。\n回首 讲了这么大的篇幅，自定义ClassLoader才姗姗来迟。 很多同学可能觉得前面有些啰嗦，但我按照自己的思路，我觉得还是有必要的。因为我是围绕一个关键字进行讲解的。\n关键字是什么？\n关键字 路径 从开篇的环境变量 到3个主要的JDK自带的类加载器 到自定义的ClassLoader 它们的关联部分就是路径，也就是要加载的class或者是资源的路径。\nBootStrap ClassLoader、ExtClassLoader、AppClassLoader都是加载指定路径下的jar包。如果我们要突破这种限制，实现自己某些特殊的需求，我们就得自定义ClassLoader，自已指定加载的路径，可以是磁盘、内存、网络或者其它。\n所以，你说路径能不能成为它们的关键字？\n当然上面的只是我个人的看法，可能不正确，但现阶段，这样有利于自己的学习理解。\n自定义ClassLoader还能做什么？ 突破了JDK系统内置加载路径的限制之后，我们就可以编写自定义ClassLoader，然后剩下的就叫给开发者你自己了。你可以按照自己的意愿进行业务的定制，将ClassLoader玩出花样来。\n玩出花之Class解密类加载器 常见的用法是将Class文件按照某种加密手段进行加密，然后按照规则编写自定义的ClassLoader进行解密，这样我们就可以在程序中加载特定了类，并且这个类只能被我们自定义的加载器进行加载，提高了程序的安全性。\n下面，我们编写代码。\n1.定义加密解密协议 加密和解密的协议有很多种，具体怎么定看业务需要。在这里，为了便于演示，我简单地将加密解密定义为异或运算。当一个文件进行异或运算后，产生了加密文件，再进行一次异或后，就进行了解密。\n2.编写加密工具类 `\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.File; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.FileInputStream; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.FileNotFoundException; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.FileOutputStream; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.IOException; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;FileUtils\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;test\u0026amp;lt;/span\u0026gt;(String path){ File file = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File(path); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { FileInputStream fis = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; FileInputStream(file); FileOutputStream fos = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; FileOutputStream(path+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;en\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; b = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; b1 = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;while\u0026amp;lt;/span\u0026gt;((b = fis.read()) != -\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//每一个byte异或一个数字2\u0026amp;lt;/span\u0026gt; fos.write(b ^ \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;); } fos.close(); fis.close(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (IOException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (FileNotFoundException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } } }`\u0026lt;a name=\u0026#34;t31\u0026#34;\u0026gt;\u0026lt;/a\u0026gt; 测试 我们可以在ClassLoaderTest.java中的main方法中如下编码：\n`DeClassLoader diskLoader = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DeClassLoader(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;D:\\\\lib\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//加载class文件\u0026amp;lt;/span\u0026gt; Class c = diskLoader.loadClass(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;com.frank.test.Test\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(c != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { Object obj = c.newInstance(); Method method = c.getDeclaredMethod(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;say\u0026#34;\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//通过反射调用Test类的say方法\u0026amp;lt;/span\u0026gt; method.invoke(obj, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (ClassNotFoundException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } `查看运行结果是： 可以看到了，同样成功了。现在，我们有两个自定义的ClassLoader:DiskClassLoader和DeClassLoader，我们可以尝试一下，看看DiskClassLoader能不能加载Test.classen文件也就是Test.class加密后的文件。\n我们首先移除D:\\\\lib\\\\Test.class文件，只剩下一下Test.classen文件，然后进行代码的测试。\n`DeClassLoader diskLoader1 = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DeClassLoader(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;D:\\\\lib\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//加载class文件\u0026amp;lt;/span\u0026gt; Class c = diskLoader1.loadClass(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;com.frank.test.Test\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(c != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { Object obj = c.newInstance(); Method method = c.getDeclaredMethod(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;say\u0026#34;\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//通过反射调用Test类的say方法\u0026amp;lt;/span\u0026gt; method.invoke(obj, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (ClassNotFoundException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } DiskClassLoader diskLoader = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DiskClassLoader(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;D:\\\\lib\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//加载class文件\u0026amp;lt;/span\u0026gt; Class c = diskLoader.loadClass(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;com.frank.test.Test\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(c != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { Object obj = c.newInstance(); Method method = c.getDeclaredMethod(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;say\u0026#34;\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//通过反射调用Test类的say方法\u0026amp;lt;/span\u0026gt; method.invoke(obj, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (ClassNotFoundException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } } `运行结果： 我们可以看到。DeClassLoader运行正常，而DiskClassLoader却找不到Test.class的类,并且它也无法加载Test.classen文件。\nContext ClassLoader 线程上下文类加载器 前面讲到过Bootstrap ClassLoader、ExtClassLoader、AppClassLoader，现在又出来这么一个类加载器，这是为什么？\n前面三个之所以放在前面讲，是因为它们是真实存在的类，而且遵从”双亲委托“的机制。而ContextClassLoader其实只是一个概念。\n查看Thread.java源码可以发现\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Thread\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;implements\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Runnable\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* The context ClassLoader for this thread */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ClassLoader contextClassLoader; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setContextClassLoader\u0026amp;lt;/span\u0026gt;(ClassLoader cl) { SecurityManager sm = System.getSecurityManager(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (sm != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { sm.checkPermission(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; RuntimePermission(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;setContextClassLoader\u0026#34;\u0026amp;lt;/span\u0026gt;)); } contextClassLoader = cl; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ClassLoader \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getContextClassLoader\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (contextClassLoader == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; SecurityManager sm = System.getSecurityManager(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (sm != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { ClassLoader.checkClassLoaderPermission(contextClassLoader, Reflection.getCallerClass()); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; contextClassLoader; } }` contextClassLoader只是一个成员变量，通过setContextClassLoader()方法设置，通过getContextClassLoader()设置。\n每个Thread都有一个相关联的ClassLoader，默认是AppClassLoader。并且子线程默认使用父线程的ClassLoader除非子线程特别设置。\n我们同样可以编写代码来加深理解。\n现在有2个SpeakTest.class文件，一个源码是\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;package\u0026amp;lt;/span\u0026gt; com.frank.test; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;SpeakTest\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;implements\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ISpeak\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;speak\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated method stub\u0026amp;lt;/span\u0026gt; System.out.println(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Test\u0026#34;\u0026amp;lt;/span\u0026gt;); } }` 它生成的SpeakTest.class文件放置在D:\\\\lib\\\\test目录下。\n另外ISpeak.java代码\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;package\u0026amp;lt;/span\u0026gt; com.frank.test; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;interface\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ISpeak\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;speak\u0026amp;lt;/span\u0026gt;(); } `然后，我们在这里还实现了一个SpeakTest.java `\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;package\u0026amp;lt;/span\u0026gt; com.frank.test; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;SpeakTest\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;implements\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ISpeak\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;speak\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated method stub\u0026amp;lt;/span\u0026gt; System.out.println(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;I\\\u0026#39; frank\u0026#34;\u0026amp;lt;/span\u0026gt;); } }` 它生成的SpeakTest.class文件放置在D:\\\\lib目录下。\n然后我们还要编写另外一个ClassLoader，DiskClassLoader1.java这个ClassLoader的代码和DiskClassLoader.java代码一致，我们要在DiskClassLoader1中加载位置于D:\\\\lib\\\\test中的SpeakTest.class文件。\n测试代码：\n`DiskClassLoader1 diskLoader1 = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DiskClassLoader1(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;D:\\\\lib\\\\test\u0026#34;\u0026amp;lt;/span\u0026gt;); Class cls1 = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//加载class文件\u0026amp;lt;/span\u0026gt; cls1 = diskLoader1.loadClass(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;com.frank.test.SpeakTest\u0026#34;\u0026amp;lt;/span\u0026gt;); System.out.println(cls1.getClassLoader().toString()); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(cls1 != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { Object obj = cls1.newInstance(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//SpeakTest1 speak = (SpeakTest1) obj;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//speak.speak();\u0026amp;lt;/span\u0026gt; Method method = cls1.getDeclaredMethod(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;speak\u0026#34;\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//通过反射调用Test类的speak方法\u0026amp;lt;/span\u0026gt; method.invoke(obj, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (ClassNotFoundException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } DiskClassLoader diskLoader = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DiskClassLoader(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;D:\\\\lib\u0026#34;\u0026amp;lt;/span\u0026gt;); System.out.println(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Thread \u0026#34;\u0026amp;lt;/span\u0026gt;+Thread.currentThread().getName()+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; classloader: \u0026#34;\u0026amp;lt;/span\u0026gt;+Thread.currentThread().getContextClassLoader().toString()); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Thread(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Runnable() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;run\u0026amp;lt;/span\u0026gt;() { System.out.println(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Thread \u0026#34;\u0026amp;lt;/span\u0026gt;+Thread.currentThread().getName()+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; classloader: \u0026#34;\u0026amp;lt;/span\u0026gt;+Thread.currentThread().getContextClassLoader().toString()); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated method stub\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//加载class文件\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Thread.currentThread().setContextClassLoader(diskLoader);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//Class c = diskLoader.loadClass(\u0026#34;com.frank.test.SpeakTest\u0026#34;);\u0026amp;lt;/span\u0026gt; ClassLoader cl = Thread.currentThread().getContextClassLoader(); Class c = cl.loadClass(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;com.frank.test.SpeakTest\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Class c = Class.forName(\u0026#34;com.frank.test.SpeakTest\u0026#34;);\u0026amp;lt;/span\u0026gt; System.out.println(c.getClassLoader().toString()); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(c != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { Object obj = c.newInstance(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//SpeakTest1 speak = (SpeakTest1) obj;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//speak.speak();\u0026amp;lt;/span\u0026gt; Method method = c.getDeclaredMethod(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;speak\u0026#34;\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//通过反射调用Test类的say方法\u0026amp;lt;/span\u0026gt; method.invoke(obj, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (ClassNotFoundException e) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO Auto-generated catch block\u0026amp;lt;/span\u0026gt; e.printStackTrace(); } } }).start();` 结果如下：\n我们可以得到如下的信息：\nDiskClassLoader1加载成功了SpeakTest.class文件并执行成功。 子线程的ContextClassLoader是AppClassLoader。 AppClassLoader加载不了父线程当中已经加载的SpeakTest.class内容。 我们修改一下代码，在子线程开头处加上这么一句内容。\n`Thread.currentThread().setContextClassLoader(diskLoader1)` 结果如下：\n可以看到子线程的ContextClassLoader变成了DiskClassLoader。\n继续改动代码：\n`Thread.currentThread().setContextClassLoader(diskLoader);\u0026lt;br /\u003e ` 结果： 可以看到DiskClassLoader1和DiskClassLoader分别加载了自己路径下的SpeakTest.class文件，并且它们的类名是一样的com.frank.test.SpeakTest，但是执行结果不一样，因为它们的实际内容不一样。\nContext ClassLoader的运用时机 其实这个我也不是很清楚，我的主业是Android，研究ClassLoader也是为了更好的研究Android。网上的答案说是适应那些Web服务框架软件如Tomcat等。主要为了加载不同的APP，因为加载器不一样，同一份class文件加载后生成的类是不相等的。如果有同学想多了解更多的细节，请自行查阅相关资料。\n总结 ClassLoader用来加载class文件的。 系统内置的ClassLoader通过双亲委托来加载指定路径下的class和资源。 可以自定义ClassLoader一般覆盖findClass()方法。 ContextClassLoader与线程相关，可以获取和设置，可以绕过双亲委托的机制。 下一步 你可以研究ClassLoader在Web容器内的应用了，如Tomcat。 可以尝试以这个为基础，继续学习Android中的ClassLoader机制。 引用 我这篇文章写了好几天，修修改改，然后加上自己的理解。参考了下面的这些网站。\ngrepcode ClassLoader源码 http://blog.csdn.net/xyang81/article/details/7292380 http://blog.csdn.net/irelandken/article/details/7048817 https://docs.oracle.com/javase/7/docs/api/java/net/URLClassLoader.html ","permalink":"https://blog.zdltech.com/posts/%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BAclassloader/","summary":"\u003ch1 id=\"你真的了解classloader吗\"\u003e你真的了解ClassLoader吗？\u003c/h1\u003e\n\u003cp\u003e这篇文章翻译自zeroturnaround.com的 \u003ca href=\"http://zeroturnaround.com/rebellabs/rebel-labs-tutorial-do-you-really-get-classloaders/4/\"\u003e\u003cstrong\u003eDo You Really Get Classloaders?\u003c/strong\u003e\u003c/a\u003e ，融入和补充了笔者的一些实践、经验和样例。本文的例子比原文更加具有实际意义，文字内容也更充沛一些，非常感谢作者 \u003cstrong\u003eJevgeni Kabanov\u003c/strong\u003e 能够共享如此优秀的文档。\u003c/p\u003e\n\u003ch2 id=\"1-为什么你需要了解和敬畏classloader\"\u003e1. 为什么你需要了解和敬畏ClassLoader\u003c/h2\u003e\n\u003cp\u003eClassLoader在Java语言中占据了核心地位，Java应用服务器，OSGi，以及大量的网络框架，它们大多数都用到了ClassLoader。如果在使用过程中出现了类加载错误，你能解决它吗？\u003c/p\u003e\n\u003cp\u003e我们将从JVM和开发者两个角度讲述ClassLoader，将会选择一些典型的案例，然后演示如何解决它们。NoClassDefFoundError，LinkageError等很多错误都会有特定的表征，我们分析每个例子，然后进行解决。\u003c/p\u003e\n\u003ch2 id=\"2-进入classloader\"\u003e2. 进入ClassLoader\u003c/h2\u003e\n\u003cp\u003e每个ClassLoader对象都是一个java.lang.ClassLoader的实例。每个Class对象都被这些ClassLoader对象所加载，通过继承java.lang.ClassLoader可以扩展出自定义ClassLoader，并使用这些自定义的ClassLoader对类进行加载。\u003c/p\u003e\n\u003cp\u003e先大体了解一下ClassLoader的API：\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv id=\"highlighter_282394\" class=\"syntaxhighlighter \" data-original-code=\"package java.lang; public abstract class ClassLoader { public Class loadClass(String name); protected Class defineClass(byte[] b); public URL getResource(String name); public Enumeration getResources(String name); public ClassLoader getParent(); } \" data-snippet-id=\"ext.e745d43d7d3801450a8a51b9bdea7769\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003e\n  \u003cdiv class=\"lines\"\u003e\n    \u003cdiv class=\"line alt1\"\u003e\n      \u003ctable\u003e\n        \u003ctr\u003e\n          \u003ctd class=\"number\"\u003e\n            `01`\n          \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `package` `java.lang;`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `02`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `03`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `public` `abstract` `class` `ClassLoader {`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `04`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        ` ``public` `Class loadClass(String name);`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `05`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `06`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        ` ``protected` `Class defineClass(``byte``[] b);`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `07`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `08`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        ` ``public` `URL getResource(String name);`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `09`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `10`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        ` ``public` `Enumeration getResources(String name);`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `11`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `12`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        ` ``public` `ClassLoader getParent();`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `13`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `}`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cspan lang=\"EN-US\"\u003e    \u003c/span\u003e最重要的是\u003cspan lang=\"EN-US\"\u003eClassLoader\u003c/span\u003e的\u003ccode\u003e\u0026lt;span lang=\u0026quot;EN-US\u0026quot;\u0026gt;loadClass\u0026lt;/span\u0026gt;\u003c/code\u003e方法，它接受一个全类名，然后返回一个\u003cspan lang=\"EN-US\"\u003eClass\u003c/span\u003e类型的实例。\u003c/p\u003e","title":"深入浅出ClassLoader ，超详细java中的ClassLoader详解"},{"content":"Android实现图片相似度\nhttp://zzimoo.com/similar/\nOpenCV笔记大集锦\nhttp://blog.csdn.net/langb2014/article/details/51379326\nThinkPHP5.0完全开发手册\nhttp://www.kancloud.cn/manual/thinkphp5\nGitHub秘籍（中文版）\nhttp://www.kancloud.cn/thinkphp/github-tips\nREST API 安全设计指南\nhttp://www.kancloud.cn/kancloud/rest-api-design-safety\nAtom IDE极速入门\nhttp://www.kancloud.cn/kinghs/atom\nOHSCE官方教程免费版\nhttp://www.kancloud.cn/ohsce/ohscebook\n深入浅出ES6\nhttp://www.kancloud.cn/kancloud/es6-in-depth\nECMAScript 6入门\nhttp://www.kancloud.cn/kancloud/ecmascript6-guide\nSublime Text 全程指南\nhttp://www.kancloud.cn/digest/sublime-text-complete-guide\n深入浅出React\nhttp://www.kancloud.cn/kancloud/react-in-depth\n图像处理算法\nhttp://www.kancloud.cn/digest/imageproebow\niOS 高级\nhttp://www.kancloud.cn/digest/data\nFlex 布局教程：语法篇\nhttp://www.kancloud.cn/digest/flex-grammar\nAndroid性能优化\nhttp://www.kancloud.cn/digest/android-performance\n设计模式C++实现\nhttp://www.kancloud.cn/digest/walker1\n系统架构师技能学习\nhttp://www.kancloud.cn/digest/archi\nJava工具类专栏\nhttp://www.kancloud.cn/digest/java-utility-classes\nC++开发人脸性别识别教程\nhttp://www.kancloud.cn/digest/genderrecogtion\nUiAutomator从入门到原理\nhttp://www.kancloud.cn/digest/uiautomatorpriciple\nAndroid NDK开发学习\nhttp://www.kancloud.cn/digest/zlndk\nReact Native学习指南\nhttp://www.kancloud.cn/digest/rnative\nRabbitMQ Java入门教程\nhttp://www.kancloud.cn/digest/rabbitmq-for-java\nFFmpeg入门实践与分析\nhttp://www.kancloud.cn/digest/ffmpegtutorial\n开源物联网系统设计\nhttp://www.kancloud.cn/digest/bare-minimum-iot-system\nIOS 网络编程\nhttp://www.kancloud.cn/digest/ios-data\nAndroid流媒体播放\nhttp://www.kancloud.cn/digest/rtmp-android\nCocos2d游戏开发\nhttp://www.kancloud.cn/digest/cocos2d\nAndroid核心分析\nhttp://www.kancloud.cn/digest/androidcore\nOpenCV 应用笔记\nhttp://www.kancloud.cn/digest/usingopencv\n游戏引擎开发\nhttp://www.kancloud.cn/digest/game-engine-dev\n电商系统\nhttp://www.kancloud.cn/digest/b2c-it\n无线局域网开发\nhttp://www.kancloud.cn/digest/wlan\nandroid SDK开发\nhttp://www.kancloud.cn/digest/phoebe\n大数据开源框架\nhttp://www.kancloud.cn/digest/bigdata-open\nandroid源码解析\nhttp://www.kancloud.cn/digest/androidframeworks\nAndroid Studio详细教程\nhttp://www.kancloud.cn/stormzhang/android_studio\niOS开发进阶\nhttp://www.kancloud.cn/digest/iosdevelopment001\nAndroid特效专辑\nhttp://www.kancloud.cn/digest/liuguilin\nAndroid开发高手进阶\nhttp://www.kancloud.cn/digest/androidadvanced\nvue\nhttp://www.kancloud.cn/dingyiming/vue\nJNI/NDK开发指南\nhttp://www.kancloud.cn/xyang0917/blogjnindk\n《架构师成长之路》漫画连载\nhttp://www.kancloud.cn/qiniu/architect-growth\nAndroid（OpenCV）开发\nhttp://www.kancloud.cn/yanzi1225627/android-opencv\nAndroid JNI入门\nhttp://www.kancloud.cn/digest/android-jni\n设计模式与系统架构\nhttp://www.kancloud.cn/longxuan/my-designpattern\n轻松搞定RabbitMQ\nhttp://www.kancloud.cn/longxuan/rabbitmq-arron\nandroid应用安全\nhttp://www.kancloud.cn/digest/android-safe\nJava线程\nhttp://www.kancloud.cn/digest/java-thread\n微信硬件平台解决方案\nhttp://www.kancloud.cn/yueqian_scut/iot-wechat\nAppium之android平台的源码分析\nhttp://www.kancloud.cn/digest/itfootball-appium\nGradle学习系列\nhttp://www.kancloud.cn/digest/itfootball-gradle\nreact-native试玩\nhttp://www.kancloud.cn/digest/doctorqrn\n《机器学习实战》笔记\nhttp://www.kancloud.cn/digest/machinglearninginact\n打造android ORM框架\nhttp://www.kancloud.cn/qibin0506/opendroid\nGoogle 开源项目风格指南 (中文版)\nhttp://www.kancloud.cn/kancloud/google-style-guide\nReact-Native入门指南\nhttp://www.kancloud.cn/kancloud/react-native-lession\niOS及Mac开源项目和学习资料【超级全面】\nhttp://www.kancloud.cn/digest/ios-mac-study\n手淘 H5 性能最佳实践\nhttp://www.kancloud.cn/kancloud/posts\n持续集成（第二版）\nhttp://www.kancloud.cn/kancloud/continuousintegration\nReact 编程风格指南\nhttp://www.kancloud.cn/kancloud/react-style\nReact Navtive框架教程\nhttp://www.kancloud.cn/digest/reactvavtive\nSketch 3中文手册\nhttp://www.kancloud.cn/manual/sketch3\nAndroid6.0 新特性详解\nhttp://www.kancloud.cn/digest/android6_new_features\n前端开发者学习手册（英）\nhttp://www.kancloud.cn/english/front-end-handbook\nReact 入门实例教程\nhttp://www.kancloud.cn/kancloud/react\nThinkCMF开发手册(最新版本：x1.6.0)\nhttp://www.kancloud.cn/goldenwind/thinkcmf_manual\niOS安全系列\nhttp://www.kancloud.cn/digest/ios-security\n解析 Android 架构设计原则\nhttp://www.kancloud.cn/digest/architecting-android-the-evolution\n亿级Web系统搭建——单机到分布式集群\nhttp://www.kancloud.cn/kancloud/web-million-build\n大数据管理系统LAXCUS\nhttp://www.kancloud.cn/infoq/laxcus\niOS应用架构谈（更新中）\nhttp://www.kancloud.cn/kancloud/ios-app-arch\n使用React、Node.js、MongoDB、Socket.IO开发一个角色投票应用\nhttp://www.kancloud.cn/kancloud/create-voting-app\n[译] Android 开发规范与应用\nhttp://www.kancloud.cn/kancloud/android-standard-app\n一站式学习Wireshark\nhttp://www.kancloud.cn/digest/wireshark\n从P1到P7——我在淘宝这7年\nhttp://www.kancloud.cn/digest/taobao-seven-years\n一步步搭建物联网系统\nhttp://www.kancloud.cn/ituring/designiot\n微服务架构探讨\nhttp://www.kancloud.cn/infoq/micro-service-architecture\nAndroid性能优化篇 [ 谷歌官方 ]\nhttp://www.kancloud.cn/kancloud/android-performance\nGradle 2 用户指南\nhttp://www.kancloud.cn/kancloud/gradle2-user-guide\nGradle Android Plugin 中文手册\nhttp://www.kancloud.cn/kancloud/gradle-for-android\nFresco 中文版\nhttp://www.kancloud.cn/kancloud/fresco\n高斯模糊的算法\nhttp://www.kancloud.cn/kancloud/gaussian_blur\nStack Overflow 揭秘程式开发者15 个不为人知的秘密\nhttp://www.kancloud.cn/thinkphp/stack-overflow\nLinkedIn架构这十年\nhttp://www.kancloud.cn/kancloud/brief-history-scaling-linkedin\nAndroid Training官方培训课程中文版\nhttp://www.kancloud.cn/kancloud/android-training-course\n架构之重构的12条军规\nhttp://www.kancloud.cn/kancloud/architect-12-rules\nMake 命令教程\nhttp://www.kancloud.cn/kancloud/make-command\nAndroid Gradle 用户指南\nhttp://www.kancloud.cn/kancloud/android-gradle-guide\nAPI Design And Documentation\nhttp://www.kancloud.cn/thinkphp/api-design-and-documentation\nExpress框架\nhttp://www.kancloud.cn/kanbox/express\n","permalink":"https://blog.zdltech.com/posts/%E8%B5%84%E6%BA%90%E6%94%B6%E8%97%8F/","summary":"\u003cp\u003eAndroid实现图片相似度\u003cbr\u003e\n\u003ca href=\"http://zzimoo.com/similar/\"\u003ehttp://zzimoo.com/similar/\u003c/a\u003e\u003cbr\u003e\nOpenCV笔记大集锦\u003cbr\u003e\n\u003ca href=\"http://blog.csdn.net/langb2014/article/details/51379326\"\u003ehttp://blog.csdn.net/langb2014/article/details/51379326\u003c/a\u003e\u003cbr\u003e\nThinkPHP5.0完全开发手册\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/manual/thinkphp5\"\u003ehttp://www.kancloud.cn/manual/thinkphp5\u003c/a\u003e\u003cbr\u003e\nGitHub秘籍（中文版）\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/thinkphp/github-tips\"\u003ehttp://www.kancloud.cn/thinkphp/github-tips\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eREST API 安全设计指南\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/kancloud/rest-api-design-safety\"\u003ehttp://www.kancloud.cn/kancloud/rest-api-design-safety\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAtom IDE极速入门\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/kinghs/atom\"\u003ehttp://www.kancloud.cn/kinghs/atom\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eOHSCE官方教程免费版\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/ohsce/ohscebook\"\u003ehttp://www.kancloud.cn/ohsce/ohscebook\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e深入浅出ES6\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/kancloud/es6-in-depth\"\u003ehttp://www.kancloud.cn/kancloud/es6-in-depth\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eECMAScript 6入门\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/kancloud/ecmascript6-guide\"\u003ehttp://www.kancloud.cn/kancloud/ecmascript6-guide\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eSublime Text 全程指南\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/sublime-text-complete-guide\"\u003ehttp://www.kancloud.cn/digest/sublime-text-complete-guide\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e深入浅出React\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/kancloud/react-in-depth\"\u003ehttp://www.kancloud.cn/kancloud/react-in-depth\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e图像处理算法\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/imageproebow\"\u003ehttp://www.kancloud.cn/digest/imageproebow\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eiOS 高级\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/data\"\u003ehttp://www.kancloud.cn/digest/data\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eFlex 布局教程：语法篇\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/flex-grammar\"\u003ehttp://www.kancloud.cn/digest/flex-grammar\u003c/a\u003e\u003cbr\u003e\nAndroid性能优化\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/android-performance\"\u003ehttp://www.kancloud.cn/digest/android-performance\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e设计模式C++实现\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/walker1\"\u003ehttp://www.kancloud.cn/digest/walker1\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e系统架构师技能学习\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/archi\"\u003ehttp://www.kancloud.cn/digest/archi\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eJava工具类专栏\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/java-utility-classes\"\u003ehttp://www.kancloud.cn/digest/java-utility-classes\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eC++开发人脸性别识别教程\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/genderrecogtion\"\u003ehttp://www.kancloud.cn/digest/genderrecogtion\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eUiAutomator从入门到原理\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/uiautomatorpriciple\"\u003ehttp://www.kancloud.cn/digest/uiautomatorpriciple\u003c/a\u003e\u003cbr\u003e\nAndroid NDK开发学习\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/zlndk\"\u003ehttp://www.kancloud.cn/digest/zlndk\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eReact Native学习指南\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/rnative\"\u003ehttp://www.kancloud.cn/digest/rnative\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eRabbitMQ Java入门教程\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/rabbitmq-for-java\"\u003ehttp://www.kancloud.cn/digest/rabbitmq-for-java\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eFFmpeg入门实践与分析\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/ffmpegtutorial\"\u003ehttp://www.kancloud.cn/digest/ffmpegtutorial\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e开源物联网系统设计\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/bare-minimum-iot-system\"\u003ehttp://www.kancloud.cn/digest/bare-minimum-iot-system\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eIOS 网络编程\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/ios-data\"\u003ehttp://www.kancloud.cn/digest/ios-data\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAndroid流媒体播放\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/rtmp-android\"\u003ehttp://www.kancloud.cn/digest/rtmp-android\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eCocos2d游戏开发\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/cocos2d\"\u003ehttp://www.kancloud.cn/digest/cocos2d\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAndroid核心分析\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/androidcore\"\u003ehttp://www.kancloud.cn/digest/androidcore\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eOpenCV 应用笔记\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/usingopencv\"\u003ehttp://www.kancloud.cn/digest/usingopencv\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e游戏引擎开发\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/game-engine-dev\"\u003ehttp://www.kancloud.cn/digest/game-engine-dev\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e电商系统\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/b2c-it\"\u003ehttp://www.kancloud.cn/digest/b2c-it\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e无线局域网开发\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/wlan\"\u003ehttp://www.kancloud.cn/digest/wlan\u003c/a\u003e\u003cbr\u003e\nandroid SDK开发\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/phoebe\"\u003ehttp://www.kancloud.cn/digest/phoebe\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e大数据开源框架\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/bigdata-open\"\u003ehttp://www.kancloud.cn/digest/bigdata-open\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eandroid源码解析\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/androidframeworks\"\u003ehttp://www.kancloud.cn/digest/androidframeworks\u003c/a\u003e\u003cbr\u003e\nAndroid Studio详细教程\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/stormzhang/android_studio\"\u003ehttp://www.kancloud.cn/stormzhang/android_studio\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eiOS开发进阶\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/iosdevelopment001\"\u003ehttp://www.kancloud.cn/digest/iosdevelopment001\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAndroid特效专辑\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/liuguilin\"\u003ehttp://www.kancloud.cn/digest/liuguilin\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAndroid开发高手进阶\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/androidadvanced\"\u003ehttp://www.kancloud.cn/digest/androidadvanced\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003evue\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/dingyiming/vue\"\u003ehttp://www.kancloud.cn/dingyiming/vue\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eJNI/NDK开发指南\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/xyang0917/blogjnindk\"\u003ehttp://www.kancloud.cn/xyang0917/blogjnindk\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e《架构师成长之路》漫画连载\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/qiniu/architect-growth\"\u003ehttp://www.kancloud.cn/qiniu/architect-growth\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAndroid（OpenCV）开发\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/yanzi1225627/android-opencv\"\u003ehttp://www.kancloud.cn/yanzi1225627/android-opencv\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAndroid JNI入门\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/android-jni\"\u003ehttp://www.kancloud.cn/digest/android-jni\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e设计模式与系统架构\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/longxuan/my-designpattern\"\u003ehttp://www.kancloud.cn/longxuan/my-designpattern\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e轻松搞定RabbitMQ\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/longxuan/rabbitmq-arron\"\u003ehttp://www.kancloud.cn/longxuan/rabbitmq-arron\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eandroid应用安全\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/android-safe\"\u003ehttp://www.kancloud.cn/digest/android-safe\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eJava线程\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/java-thread\"\u003ehttp://www.kancloud.cn/digest/java-thread\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e微信硬件平台解决方案\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/yueqian_scut/iot-wechat\"\u003ehttp://www.kancloud.cn/yueqian_scut/iot-wechat\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAppium之android平台的源码分析\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/itfootball-appium\"\u003ehttp://www.kancloud.cn/digest/itfootball-appium\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eGradle学习系列\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/itfootball-gradle\"\u003ehttp://www.kancloud.cn/digest/itfootball-gradle\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003ereact-native试玩\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/doctorqrn\"\u003ehttp://www.kancloud.cn/digest/doctorqrn\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e《机器学习实战》笔记\u003cbr\u003e\n\u003ca href=\"http://www.kancloud.cn/digest/machinglearninginact\"\u003ehttp://www.kancloud.cn/digest/machinglearninginact\u003c/a\u003e\u003c/p\u003e","title":"资源收藏"},{"content":"引言\n前段日子，公司为了提高产品出产效率，想把公司每个产品各个小功能抽取出来，这样再做一个新产品的时候，重复的功能就可以直接使用之前写好的模块就行了。想法是不错的，但一开始实践起来很麻烦，同事A就将自己的模块做成module，为了图方便，将整个module项目直接发送给同事B和同事C，代码第一次写成以后一般都会有一些小bug的，这样，同事A在自己电脑上修改代码，然后再次修改代码分别传给B和C。B和C需要替换之前的module，重新运行。这相当的麻烦，如果还有同事D,E,F..做起来真是噩梦，可能有有人想问，为什么不用svn或者git，用版本控制工具当然会好非常多，但每次pull其实也比较麻烦。还有另一种方法，使用本地maven仓库，使用过android studio的开发者都应该体会过其中的好处，当需要依赖一个新的模块(或者叫library)时，只需要这样\n填写需要的模块及对应的版本号，同步一下就行了，很方便。本篇文章就教各位如何使用Artifactory来搭建本地仓库，来完成上图的效果\n什么是Artifactory?\n一句话，开源的Maven仓库管理者\n搭建Artifactory\n1.检测你的jdk版本是否为1.8及以上\n打开cmd，输入java -version，如果输出结果如下所示即可，如果是1.6或者1.7，去官网下载最新版本替换\n`java -version java version \u0026quot;1.8.0_31\u0026quot; Java(TM) SE Runtime Environment (build 1.8.0_31-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)\" data-snippet-id=\"ext.437a4825669d574acb250e72155a8b81\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003eC:\\Users\\Administrator\u0026gt;java -version\u0026lt;br /\u003e java version \"1.8.0_31\"\u0026lt;br /\u003e Java(TM) SE Runtime Environment (build 1.8.0_31-b13)\u0026lt;br /\u003e Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)` 2.下载Artifactory，解压下载好的安装包，打开解压后文件夹下的bin文件夹，运行artifactory.bat，大概等待1分钟左右就安装完成了\n3.打开http://localhost:8081/artifactory将会看到管理界面，如果看到此界面，就表示artifactory已经安装成功了.如果不是该界面，则需要等待安装完成\n上传library到maven\n创建自己的library project(注意你的 module是apply plugin: ‘com.android.library’)，写好自己模块的代码后,准备上传\n1.添加相关插件引用\n在你library 项目中顶级的build.gradle文件中，添加一条新的classpath引用\n**[plain]** [view plain](http://blog.csdn.net/level_26/article/details/53483444#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/level_26/article/details/53483444#)\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;16\u0026quot; height=\u0026quot;16\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026amp;#8221;font-family:Microsoft YaHei;font-size:14px;\u0026amp;#8221;\u0026gt;buildscript { - dependencies { - classpath \u0026amp;#8220;org.jfrog.buildinfo:build-info-extractor-gradle:4.4.0\u0026amp;#8221; - } - }\u0026lt;/span\u0026gt; 然后在你的library module的build.gradle中，添加两条语句\napply plugin: ‘com.jfrog.artifactory’\napply plugin: ‘maven-publish’\n一个是用来配置maven的，一个是用来配置artifactory的\n2.配置参数\n每个maven的artifact(你可以理解为library)都有三个必要的属性需要添加，分别是\nartifactId:你library的名字，建议使用当前module的名字，在后面配置的时候方便使用\ngroupId:一般情况下是你library的包名\nversion:版本\n举个例子 groupId:com.example.utils\nartifactId:utils\nversion:1.0.0\n上述就是将自己常用的工具封装成一个module的例子，如果上传好以后，在build.gradle里面添加相应连接引用就行了\n然后在library的build.gradle中添加\ndef packageName = ‘com.example.common’\ndef libraryVersion = ‘1.0.0’\n上述语句定义了两个属性，分别是包名和版本号\n**[plain]** [view plain](http://blog.csdn.net/level_26/article/details/53483444#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/level_26/article/details/53483444#)\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;16\u0026quot; height=\u0026quot;16\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - publishing { - publications { - aar(MavenPublication) { - groupId packageName - version = libraryVersion - artifactId project.getName() - // Tell maven to prepare the generated \u0026amp;#8220;*.aar\u0026amp;#8221; file for publishing - artifact(\u0026amp;#8220;\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;buildDir/outputs/aar/\u0026lt;/span\u0026gt;{project.getName()}-release.aar\u0026amp;#8221;) - } - } - } 上面是配置maven的参数，aar表示要生成的文件为aar，groupId等三个属性就是之前提到的maven的三要素，最后一行是告诉maven去哪里找到你要发布的aar文件\n其中project.getName()用于得到当前的module名字，一般情况下，你生成的aar就是对应的module名+后缀名+.aar\n**[plain]** [view plain](http://blog.csdn.net/level_26/article/details/53483444#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/level_26/article/details/53483444#)\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;16\u0026quot; height=\u0026quot;16\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026amp;#8221;font-family:Microsoft YaHei;font-size:14px;\u0026amp;#8221;\u0026gt;artifactory { - contextUrl = \u0026amp;#8216;http://localhost:8081/artifactory\u0026amp;#8217; - publish { - repository { - repoKey = \u0026amp;#8216;libs-release-local\u0026amp;#8217; - username = \u0026amp;#8220;admin\u0026amp;#8221; - password = \u0026amp;#8220;password\u0026amp;#8221; - } - defaults { - publications(\u0026amp;#8216;aar\u0026amp;#8217;) - publishArtifacts = true - properties = [\u0026amp;#8216;qa.level\u0026amp;#8217;: \u0026amp;#8216;basic\u0026amp;#8217;, \u0026amp;#8216;dev.team\u0026amp;#8217;: \u0026amp;#8216;core\u0026amp;#8217;] - publishPom = true - } - } - }\u0026lt;/span\u0026gt; 上述则是artifactory需要的配置\ncontextUrl:表示要发布到哪里去，上下文连接\nrepository的repoKey表示要发布到哪个artifactory哪个分支下\nusername和password则是用于访问artifactory的权限认证，默认账号密码为admin和password\npubilcations:表示要发布的文件类型\npublishPom:是否将自动生成的pom.xml文件发布到Artifactory\n其实前期并不需要把所有的属性都弄明白，等需要用到的时候，再单个去查就可以了\n3.打包并发布到Artifactory\n在library主项目下，执行gradle命令\ngradle assembleRelease artifactoryPublish\n这行命令有两个功能，assembleRelease在前表示先打包，artifactoryPublish在后表示打包完以后发布到artifactory当中\n打开http://locahost:8081/artifactory，看是否能找到刚才发布的module，如下图所示表示上传成功，否则失败，检验上述步骤是否有遗漏，再重试\n引用本地仓库的library\n在项目顶级build.gradle中引入新的maven地址\n**[plain]** [view plain](http://blog.csdn.net/level_26/article/details/53483444#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/level_26/article/details/53483444#)\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;16\u0026quot; height=\u0026quot;16\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - allprojects { - repositories { - jcenter() - maven { url \u0026amp;#8220;http://localhost:8081/artifactory/libs-release-local\u0026amp;#8221;} - } - } 若library不在同一台电脑上，将locahost改为IP地址即可\n在module的build.gralde中添加对library的依赖\n格式为\ncompile ‘groupId:artifactId:version’\n举例\ncompile ‘com.example.utils:utils:1.0.0’\n然后同步一下，就将对应的module集成到本项目中了\n总结\n使用Artifactory搭建本地仓库需要以下步骤\n1.下载Artifactory并运行\n2.在build.gradle当中配置maven及artifactory的属性\n3.使用gradle命令将library打包并上传到Artifactory\n4.在需要使用的app中，添加maven的路径，并在dependencies中添加library对应的路径，然后同步\n参考：http://blog.csdn.net/level_26/article/details/53483444\n参考：http://www.ituring.com.cn/article/211234\n参考：http://blog.csdn.net/zzulp/article/details/51385701\n参考：http://blog.csdn.net/qinxiandiqi/article/details/44458707\n方案一：\n先定义gradle.properties文件中定义变量\nartifactory_user=admin artifactory_password=xxxx artifactory_contextUrl=http://xxxxxx/artifactory/ artifactory_repoKey=libs-release-local 注意填写正确的artfactory的用户名、密码、地址及仓库名 以下是bintray.gradle文件 apply plugin: \u0026#34;com.jfrog.artifactory\u0026#34; apply plugin: \u0026#34;maven-publish\u0026#34; def packageName = \u0026#39;com.etongwl.commonbase_lib\u0026#39; def libraryVersion = \u0026#39;1.0.0\u0026#39; publishing { publications { aar(MavenPublication) { groupId packageName version = libraryVersion artifactId project.getName() // Tell maven to prepare the generated “*.aar” file for publishing artifact(\u0026#34;\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;buildDir/outputs/aar/\u0026lt;/span\u0026gt;{project.getName()}-release.aar\u0026#34;) artifact androidJavadocsJar//上传javadoc.jar artifact androidSourcesJar//上传sources.jar } } } artifactory { contextUrl = \u0026#34;\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{artifactory_contextUrl}\u0026#34; publish { repository { repoKey = \u0026#34;\u0026lt;/span\u0026gt;{artifactory_repoKey}\u0026#34; username = \u0026#34;\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;{artifactory_user}\u0026#34; password = \u0026#34;\u0026lt;/span\u0026gt;{artifactory_password}\u0026#34; maven = true } defaults { publications(\u0026#39;aar\u0026#39;) publishArtifacts = true properties = [\u0026#39;qa.level\u0026#39;: \u0026#39;basic\u0026#39;, \u0026#39;q.os\u0026#39;: \u0026#39;android\u0026#39;, \u0026#39;dev.team\u0026#39;: \u0026#39;core\u0026#39;] publishPom = true maven = true } } } task androidJavadocs(type: Javadoc) { source = android.sourceSets.main.java.srcDirs classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) } task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { classifier = \u0026#39;javadoc\u0026#39; from androidJavadocs.destinationDir } task androidSourcesJar(type: Jar) { classifier = \u0026#39;sources\u0026#39; from android.sourceSets.main.java.srcDirs } artifacts { archives androidSourcesJar archives androidJavadocsJar } 在模块的build.gradle文件中添加 apply from: \u0026#34;./bintray.gradle\u0026#34; 执行命令： gradle assembleRelease artifactoryPublish 方案二：\n以下是bintray.gradle文件内容 apply plugin: \u0026#39;maven-publish\u0026#39; apply plugin: \u0026#39;maven\u0026#39; def MAVEN_LOCAL_PATH =\u0026#39;http://xxxxx/android-dev-local\u0026#39; def ARTIFACT_ID = \u0026#39;common-utils\u0026#39; def VERSION_NAME = \u0026#39;1.0.0\u0026#39; def GROUP_ID = \u0026#39;com.etongwl.common.utils\u0026#39; uploadArchives { repositories { mavenDeployer { repository(url:MAVEN_LOCAL_PATH ){ authentication(userName: \u0026#39;admin\u0026#39;, password:\u0026#39;xxxx\u0026#39;) } pom.project { groupId GROUP_ID artifactId ARTIFACT_ID version VERSION_NAME packaging \u0026#39;aar\u0026#39; } } } } 自己别忘记写用户名密码及请求的仓库地址 在build.gradle中添加 apply from: \u0026#39;./bintray.gradle\u0026#39; 执行命令：gradle uploadArchives ","permalink":"https://blog.zdltech.com/posts/%E4%BD%BF%E7%94%A8artifactory%E6%90%AD%E5%BB%BA%E6%9C%AC%E5%9C%B0maven%E4%BB%93%E5%BA%93/","summary":"\u003cp\u003e\u003cstrong\u003e引言\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e前段日子，公司为了提高产品出产效率，想把公司每个产品各个小功能抽取出来，这样再做一个新产品的时候，重复的功能就可以直接使用之前写好的模块就行了。想法是不错的，但一开始实践起来很麻烦，同事A就将自己的模块做成module，为了图方便，将整个module项目直接发送给同事B和同事C，代码第一次写成以后一般都会有一些小bug的，这样，同事A在自己电脑上修改代码，然后再次修改代码分别传给B和C。B和C需要替换之前的module，重新运行。这相当的麻烦，如果还有同事D,E,F..做起来真是噩梦，可能有有人想问，为什么不用svn或者git，用版本控制工具当然会好非常多，但每次pull其实也比较麻烦。还有另一种方法，使用本地maven仓库，使用过android studio的开发者都应该体会过其中的好处，当需要依赖一个新的模块(或者叫library)时，只需要这样\u003c/p\u003e\n\u003cp\u003e填写需要的模块及对应的版本号，同步一下就行了，很方便。本篇文章就教各位如何使用Artifactory来搭建本地仓库，来完成上图的效果\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e什么是Artifactory?\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e一句话，开源的Maven仓库管理者\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e搭建Artifactory\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e1.检测你的jdk版本是否为1.8及以上\u003c/p\u003e\n\u003cp\u003e打开cmd，输入java -version，如果输出结果如下所示即可，如果是1.6或者1.7，去\u003ca href=\"http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html\"\u003e官网下载\u003c/a\u003e最新版本替换\u003c/p\u003e\n\u003cdiv\u003e\n  `java -version java version \u0026quot;1.8.0_31\u0026quot; Java(TM) SE Runtime Environment (build 1.8.0_31-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)\" data-snippet-id=\"ext.437a4825669d574acb250e72155a8b81\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003eC:\\Users\\Administrator\u0026gt;java -version\u0026lt;br /\u003e\njava version \"1.8.0_31\"\u0026lt;br /\u003e\nJava(TM) SE Runtime Environment (build 1.8.0_31-b13)\u0026lt;br /\u003e\nJava HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)`\n\u003c/div\u003e\n\u003cp\u003e2.下载\u003ca href=\"https://www.jfrog.com/open-source/\"\u003eArtifactory\u003c/a\u003e，解压下载好的安装包，打开解压后文件夹下的bin文件夹，运行artifactory.bat，大概等待1分钟左右就安装完成了\u003c/p\u003e\n\u003cp\u003e3.打开\u003ca href=\"http://localhost:8081/artifactory\"\u003ehttp://localhost:8081/artifactory\u003c/a\u003e将会看到管理界面，如果看到此界面，就表示artifactory已经安装成功了.如果不是该界面，则需要等待安装完成\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20161206105644367\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e上传library到maven\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e创建自己的library project(注意你的 module是apply plugin: ‘com.android.library’)，写好自己模块的代码后,准备上传\u003c/p\u003e\n\u003cp\u003e1.添加相关插件引用\u003c/p\u003e\n\u003cp\u003e在你library 项目中顶级的build.gradle文件中，添加一条新的classpath引用\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_plain\" style=\"box-sizing: border-box; margin: 18px 0px !important; padding: 1px 0px 0px; border: 0px; outline: 0px; font-size: 12px; vertical-align: baseline; background: #e7e5dc; font-family: Consolas, 'Courier New', Courier, mono, serif; width: 643.5px; overflow-x: auto; overflow-y: hidden; text-align: left; position: relative; color: #999999; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;\" data-original-code=\"[plain] view plain copy print?\u003cspan style=\u0026quot;font-family:Microsoft YaHei;font-size:14px;\u0026quot;\u003ebuildscript { dependencies { classpath \u0026quot;org.jfrog.buildinfo:build-info-extractor-gradle:3.1.1\u0026quot; } }\u003c/span\u003e \" data-snippet-id=\"ext.49eb87db4d6b6b04f41cab38e173b3fd\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n\u003cpre\u003e\u003ccode\u003e    **[plain]** [view plain](http://blog.csdn.net/level_26/article/details/53483444#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/level_26/article/details/53483444#)\u0026lt;/span\u0026gt;\n  \n\n  \n  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;16\u0026quot; height=\u0026quot;16\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026amp;#8221;font-family:Microsoft YaHei;font-size:14px;\u0026amp;#8221;\u0026gt;buildscript {\n\n- dependencies {\n\n- classpath \u0026amp;#8220;org.jfrog.buildinfo:build-info-extractor-gradle:4.4.0\u0026amp;#8221;\n\n- }\n\n- }\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e然后在你的library module的build.gradle中，添加两条语句\u003c/p\u003e","title":"使用Artifactory搭建本地maven仓库"},{"content":"打开终端，执行 /usr/libexec/java_home -V\nMacBook-Air:~ eng$ /usr/libexec/java_home -V\nMatching Java Virtual Machines (4):\n1.8.0_101, x86_64: “Java SE 8” /Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home\n1.7.0_79, x86_64: “Java SE 7” /Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home\n1.6.0_65-b14-466.1, x86_64: “Java SE 6” /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home\n1.6.0_65-b14-466.1, i386: “Java SE 6” /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home\n/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home\n默认JDK1.6(Apple自带JDK)路径： /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home\n默认JDK1.7、1.8(Oracle) Home : /Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home\n","permalink":"https://blog.zdltech.com/posts/mac-jdk%E9%BB%98%E8%AE%A4%E5%AE%89%E8%A3%85%E8%B7%AF%E5%BE%84-java%E8%B7%AF%E5%BE%84/","summary":"\u003cp\u003e打开终端，执行 /usr/libexec/java_home -V\u003c/p\u003e\n\u003cp\u003eMacBook-Air:~ eng$ /usr/libexec/java_home -V\u003cbr\u003e\nMatching Java Virtual Machines (4):\u003cbr\u003e\n1.8.0_101, x86_64: “Java SE 8” /Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home\u003cbr\u003e\n1.7.0_79, x86_64: “Java SE 7” /Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home\u003cbr\u003e\n1.6.0_65-b14-466.1, x86_64: “Java SE 6” /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home\u003cbr\u003e\n1.6.0_65-b14-466.1, i386: “Java SE 6” /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home\u003cbr\u003e\n/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home\u003c/p\u003e\n\u003cp\u003e默认JDK1.6(Apple自带JDK)路径： /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home\u003cbr\u003e\n默认JDK1.7、1.8(Oracle) Home : /Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home\u003c/p\u003e","title":"MAC JDK默认安装路径 JAVA路径"},{"content":" 问题：有个arr文件被放到Module A中引用，现在Module B又依赖了Module A，则在编译过程中会发生错误，Module B找不到aar文件。（同时如果又有Module C 依赖了Module B，C也会出同样的问题） ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeYAAABICAYAAAAj8lblAAAfbklEQVR4Ae2dCXAU15nH/yMElmTAII80QhKHwSCBETiAiUFiOQLZTbwWSA5UZdcOqfUBDthOdjdOxRAfHE7Zm1StsV2AHVfAzuaAGHHEccpcwkiY2EAM4rAENpeuGY3EYZDQNbP1ve7X09PqnhlJI4kZvq6CPt573/e933v9Xn9fvx7ZpuRM8yLKNu+A8cj71zvw+bv7cC7GFmW14+owASbABJhANBOI9UbZtDxsxr9j5hAbzn/8Hs7abECU1S+aOyPXjQkwASbABADb/dnR5zFzwzIBJsAEmAATiFQCMZFqONvNBJgAE2ACTCAaCfDEHI2tynViAkyACTCBiCXAE3PENh0bzgSYABNgAtFIIJZXR0Vjs3KdmAATYAJMIFIJxLpraiLVdrabCTABJsAEmEDUEYhNGZQasFL1X1/B6Ya+AfNwIhNgAkyACTABJhAeAvyOOTwcWQoTYAJMgAkwgbAQiA2LlE4Kie8bi2/MTsVd4wZioCNeSKurrsdXRy/h6J4qNFxr6aQGLs4EmAATYAJMIDII9PjEfPeEO/Hgf4zBjMypGJ04Fv17DxDkrjZfxqnpx1H4z59gxzsncOZIbWQQZSuZABNgAkyACXSCQK8hw+56MVD55qZG1LX0CZSlw2k0KT/2X9Pw8IR/Q3rfoegVE4sWb4v4R8cpt6fi3rSxSBjZgHPnalBX1dBhXT1V0Js2E2+sehiPpddh0xFXT5lx0+llLjddkwQ1SGuz7zjg/vAEvkIWlq15Aj9Wz8VP4AaVEjyD1zu2S+QG19zxHMHYfJU+SxkHJvTCkY/Poo5+Lvgm37Q6ddBmYztqDAL0l1mPLcevFo5BfMlnOPp19zLS6/68v9peAWztyubrMY85vl9vfHvhcMy8+5/QgkaU17jwWdHnKD9Xhfrr9YhPiEfqYAf+6dtTRJ4LCytRefoq6r9ubsND6QDzMMnQ2Q+9twIvf6Y0rswzsWQrHvrN8TYybtULzKVrWz4QX5lG/dbr/QJvPr0Je9Q+7PUm44fLnsDclLZpgSz2K1ddhJ+t3oMzhvsiUPmeSLv7wcV4ZTaw/dW12FgR3sFYMub7HqCJZ+k4H1/vsQLkvw0sWzMPzKcner61znZPzP+9cB7GjhxqKbHk9Hn8euNWy3SZMH5mChwp/XDF44SrAvjg//ZgoP0OTHngXtzeLx7Oi26cPn4OX148gzuH94UjpS/u/dYgHNh6QYpo195mO45Nu3IwcXYOFqaVhH0AaJcxN1Fm5tK1jREqX5stE/dPBvZ8ptqTfg8mOTpgm76cIwPZ6XtwpqIDckIoQnV7+Rn1IbcTk/8Qhx2AW9MYLrkkMFT+mvIwHYSzDmEyCXAW49mn9uC0iHTMw6RxeVg2eUWXjYs3JYOwwexaQe2emP/4t/1YMWIIYkz+nGKrx4M/frg/JIuHjx+I/n374Gz9SZzcXYXmmEZMzv8m4uJ6wettxJ1j4tEv8y40tF7C2frzIi8tDgs0MRu9DsAGehp/dU4SKnaux9LtRTg8ex5yv5OFjarXrD1RO4s170I+WUqPm86XZJUKj2a37NSaZ+PzdETo59lspJZsxZuYJ8q88Yr/d+JStlf1Zk5PXoCCRzI1ZqRzdeUsvEFynMV4syQDS+ckiXSqw1M7XNB7RZTg9db4eRuyTjKCQE/GFCUwXpfyTjMX4TVIXpKL1ii6g6Ds75vftj1N+OpEwltdg0qHHRPHZwGfKRPdyAkZSIUbFdV2pDqojZOxcNki5DrcWltLW/TXZLltO2sxd06mf1+n1yqB+lWQdL3NdCz700Qo9wZ5+/KaZKl4ZS7N+1fK+fqrvB+AJMz92fPI1XtxgeTqIgxS50S6h3fa8ap6P8l2NOvfwg5dfWU5eS9tSPXdlyRn6XaIOuhZ6/lv++0Xfng0m9Q67NanTl6ALQYbTceOpwoxZPkiETUxcjPm/9HYszjiugsTA/WPHXvpSQU2KE7KJHVcseKjNxlBbFbGFyXKk+vwHytl//BjoAqX9UijvnOsAG/6KfU/aZuXxljlftgAdczUj70B+JHktvL89RnPZJvKvi37lzFfOM7b/blUubMWHx8+Yaqbrle4QluklZiSgN59YtDibYXzYi3i02yo9HyFr+pP4mzDKVxoOI3qxou40nJJ5KG8Ax1xpnrlRfI6lr7+PLas+QXef20xFqb5/81H5enZDWSR16yk0bWDJQCEd6EMNvdnKRIHpTjEgDg4GYDTjfPi3Zd/yJx0LlmzALP0fz8zOQd5qgxpG+29980XoSRtUqb3Tg9n6LP4HdtScrRJmRJSZ+erdicjTedN2WxJyH1WscHYeaRAs+tpcxbhufu8qlfBXCQryUWe++8DsKeB3qQ9zfqdv8xaVDkBZI0W/YgG/OwsO+CsRZWa0WZzobjEDWrrSRPUxpfecUmRiAD5ypWiePspHKI+qcrU67PuV0quYOl6Wfpjsz6mpFsz05e3OjaTa3rfIQPP6Pinzp4ueAbn7ysn7qWFT/q1I913P0x3BuZf4wsRW9WDrhNb+eBA5757Wi3lN3aEwE3Nb7M14cyxwP1D2iWdFRqHNn0qowr+97/MS/ugNuszt+NYtOuz2aBJWegZl+cXateLCjlviPxClqcaYdYHA48Teuvbf9xuj5lUFOz+BPePG4W423yLwm40NqFg18F2WdDiaaEHOHi8HnjgBZ3T1nC5CYd/fxZejxf9HHG4d/4weDxeeFr9J9pQlJ3ZsQ75O3w5Tx8pReXsbDG4baxQFmNdcLphG5eENPFbK0kYpHkqNCNDTIKVu07gzDeni/fYcmKld3fKE38m8nId2H1E1eMADr26Uhks02YiX1wejWUPZyje7Ub1vV+qXXRK/ycvG5CmyNFHABQ9yqC8sUIXQoTy7mhJ1p0YnE53+mjFRtVLVi0CJs/3uy6fFunhA3CBuahRBdWLklw0fuoBDfJa+LYNe4v2BEz5+mS7cbDkTkxKUcLZuyuVMPbh3+1DxZwMTFQzUhtVzLYjNese3L3dCUzIEP3n0FF6srQBk6cL76pi5wmcsblwsITClYYQufB0fVEefb/aoPZfq34n0312G44mm/c9usetmG38zSpARKR8kQBgrL9gKVf3ztzvvtuuZlfvu6XlDtW7Ve+JiiD8HbUoeHotdtODMk0UKUmoem8Fln6qyJmboowNgfnP8rfZ4iwoW93YgRhg7zM+J4jqrN3nUr4uP93T0+ZY9w95z8uJ8PBO3/oDs/tfqghqs8zY3r2hXWWIXfZ3P3Gh5tXxCMhPjpMycqlGQk11kyFSv4w+Bhkn/GzvwEmHJuYr1+rxwceH8NCcqZrKHfs+w9Xr9dp5sAP6Trk+PR59bovB7cm3ofb817jRaEev3jGI7d8L31x8N8o+qkLd2Wto9rSiqdGDKzWNAcXqO5CSse1TrK1iLwpKsrGEnqa3K4tt5A2nDMZ2pDpLsd1lR25yEkamQ0zUh444MXLCnUJsZQkNfIpsmtQpDOe3qR6M/pptXCYm0aB4TPFuRNqnp3Do4QxMmrMIW+YAcsI/LQs63ZBv1PV6ZAiNFgbJTTrsI1MUGw/LwVrNIK/bxuVhy5o8WQxeBz18uMBc2nIhzrQwhkJXWohTHfTN2MOiPamvmPHVGgHAhe1FODR7nghnj0yhMHYpCj4FBs/x5dJkZNkxBA4MzrKLRWMHP1Xm5W+NV6Iv9CRP/Ulu+hC5uGbRr2R+ig6Z9Tst3eJA9jFj3wvUXy1E+V2WcoPed85SFJeTB+jCRXrm1keVTO57TYmsb3mNiFCker8AMdXkpCg5A/Knh+JQNqmL2jzI2BESN91YE9A+G0QffOqZvcJK8WDzyPN4PUV5PaaV1Y2LWnWC2axlbN9Bm3b1ulDhBCbq2k1KNOalcDw9eE40RiZ1PALxM8pDAN1kg8xvNX5KO8O1b3coWyr+W/ER1F35WpzWXv4aHx34h0wKaU8/HvL1tSY0tzYj9b4BaG5swakPy3HtUj2aWprhPncFdeeuISGpj8hDec+WXApJdrBMuz8sRiUyhJcr8pafwCEnhCfyw/EZoAFgw9FSJbw9wY5U1OJiOXC6WgnTp4rJTNGiLFwBqqopFmm90YS8rdoLalgKH9OmeF+rkPee8n6KQkavPK7raQ4agJX3iyK0CUXPyNx88a5x2ysrkP/0SrxxrG0kQQzGJuaQd05l5D/9CnXm4s9Ftg+xeuiZdSICEoi9zG/Vnm34+rVPifJKJSsHz1AYu+QUzN7J7T5aCrFQLFddHFZySqzkplCbfAXjJ5ZOjOFsi36llQuWrmU0PzD2vUDMzCX4X+3MfaeXFJi/Pqf1sRV/6xKGlHaw7Qi3UO2jfLTpxzJLPsFsTk7C3cIz8A+9G2pueeqzIXh5mTdgf1c1hcJPygOC6yaxgcZPywp2IKFDHjPpaW5pxaaPirF4/r9g80fF4rw9+o/trcY3vpWC3vGx6JPcCyPnOlB15ApK3i9Hy41WxN4Wg37pcUjPTkRDYzMuu1vw+W75xs1ck3zHvFRNJoivIV9b/EULp2hr+3SovL/LnZ0hvNqqo06g0i0m70k0T5YUKZ+xSI/I6HWqT9gI+NRcgw0bizHp2WxMfHgBZn26CbsNC7+MtTLWhyICwjvKpUldWSwzVy0kPWZayEGeF624lJ6xsgBHva7zpowRBuaiwDRyadsu5uxpDYF+IV+bcgavzTjx0mC5dFwm0lKAQzvFwgejCEivfFCWsjhs+4cyjG0eRpYhX1rxvbtSEWfZr9T+Gyy9rVHKFau+9zOndX+VsmR/lou/5HWxD3bf+WW2PjH2byN/65K6FNWWNvx1WQIdtpet5GK8zy11WNgn3pEuS8Km1eqqbPVdfKXT99sKVnwsbYYSYUij9+av52gmybFIu2BxICOVabqxirLK8vJdOI3jS9XXODIvRbAqyRcy8a716qz4BdOtl0HHWt8OMH4ay3TmvMMeMyn9+7Ey7Dp4FH8vKWu3DfQ98s6NX+GqG7jR2IrYxBgMnj0QmQ+nYOxjach8ZBDSZg1Eay+IPJTX7BvmditWC8gnS3o3TJt4xwJaAVuqTH6qF03vm5TQnOLhrn56q7KoRpUTbBBXs4kddfzXdtECDXXBmEefqoay36aBVtkotL1N9YaVUKoaeqfJV+29+jxUiry21a8Wo0L2blWW1XU1WdsxFw2F6YG4QS3YGwuIVxO69qR0I1+/MjSoer2+8LRfonJC7UiLFalfQg3dipDdHCWMLfuqLEr6aJs4Z5bq1Sj9zKxfyTL6PqXvdzLdam/Vx4IxI0/N2F/1OoTcTtx3elkB+eszWhyb8bfIanq5PWyDcTNTENA+RzZeff15FLyep603kc6KlGXGx8pm0S6/U/oXlT/03noRFZSygu1pPFyqK1+xs8CyvDFv5a4iHAqiIBA/o7xAukmNqKvJuBrEhA4n23Kmz2wbB9WJ6+q/LkXvbecsHIG4gUCvuFbYeimzlbc1Bq03euHGJeCjjV+G/Sc55fuHXPg+k9JVu0cP5SIN+lyqu38ggrl0bdOHg6/ekzAOrIGsD9avgqUHkh0paT3Jv7sYdbR/kH3h4NMd9ZTRqfY4Rt1hV7h0dMpjDocRp4/U4rfLjuDglmpUnWhBg/M2XK/sg/Jjzfjk/SqR1hW/k00LOzbsLBWfAjyjes3hqE+ky2AuXduCneVLAyetNyBPlhYk8tY+AtHOv7P9o7N82tcaoeemUPxzry0Xn8LS57DylVHlrn3ar+WFLu3mz9nhd8zhrBr99Sj64ZBAPx4STn1Slu2zzciXv7QkL/IezKVrO0FH+Srvi5WV+H6r+7vW3KiTHq38w9U/OsqnuzuK/AGo7tbbHfpuiom5OyoaSTro/Yf8rEF86B1JxnehrcxFgau9u1Y/2QsVeTB+wdJD1RPt+TrKv7u43Oz2dYQDvePVfwuvyPB9LtoRmTdzmR5/x3wzw2HbmAATYAJMgAl0N4GQPObxyb262y7WxwSYABNgAkzgliTQ44u/bknqXGkmwASYABNgAhYEeGK2AMOXmQATYAJMgAn0BAGemHuCOutkAkyACTABJmBBgCdmCzB8mQkwASbABJhATxDgibknqPeQTk/ydDy5aDochp/rDGROR8oEktddaZFkt9FW43l3MWuvnkixs7314vxMoKcJhLQqu6eNZP3+BGhAXPL4VCTrvmP11hRj/bpCOHXXZCmRPw94f4u8Ep69x5uM2YvnAgVvYY8rer8pDA+t4FK8yTPwZH742ym4Zs7BBJjAzUSAJ+abqTXaZUsZtqz8M0r0E7H+WCcrxrUPa9cDNEHzdvMSsLkKsXa9jdvp5m0itowJdAsBnpi7BXP3KHHMeByLc5I0Za6i32BtoUsM9EsMHrPi7T6KaUk28bvLRW/7vF6jR07euHHTl8cTyzCNfgBf9dqrHDM0j55+01kvWy9HevKldVORM6oMBav+jKNwYPZic7uy5v8c+RmKZ+5XNzV6YNTl9cZj8uLnkFD8Mv50XCnnGfsQXsx2i+hCVRBdeYkHLKMQZItMV+prR2lxIqap/L/YuhonRz8n7CW79r+1Fbb8x5BkYss6NZJh9JjvWfAcFmf4t4+R2a7iRMwJ0ObENnvkOZTWDoPNRLcxymKUH6xNZHvq+4O+Haz6JJUzbU8RhbFuf8ncLDIkbeE9E4h0AjwxR3oL6ux3Fr6NlwqVC8rkOhezTr6FXbo88nD8gkeRUfoOXlrvgpis8mbgxLpCiMkqbyrqtr2MtccV740mdeMWY3Nh17p3AEMo20OTnb48TYSqbNPB1D5VTFYrNtvob6th/HwLu7K+JybCdSvJxrGYPRMQk4GFLvrL3TZbA/5eVIbFY8YCx0+IKowfPQo1pftFyN9Kl6mdRgBtzkchA+/gpVUKz5fmLQO2rsZLm20K3/wxWGdiS2nxn1Ftm9FGGlQuVJ4mt0Va+wAyTTADcMCqzVUZK6UNo/05kG7TuobaJjqrrfqTZZ9MbtueJM5SjkU0SGcCHzKBqCHAi78itilHIf8Xy/DC8ufEv+fn3+NfE+cplLr9L8kzr/cejBlVhqK96l8nKvkCpfZRuIf+NLVjNDLsZTjp+7PQslhoeyqPAyiU5fWyzSS4fXk9gezSlY2xncCeQpdiazBdJadQOioTWV4vFPlulJ50qscWDACUbP4lVqzfZz5xmaW7D2CL5Olyw1VT7GPgcqOG7G9jSwDOOi5VJ8tQY7cjWTLQpclLYm9sc30+agc/DqHpDqVNAvYnvYFG+9Q02Z7BdAVrE70qPmYCkUyAPeaIbT2Td8w0r+rC2SKkaFY/RxISoUzs+Wo65RWTR7IdSW43XGblQrlG5aF/IqhBjduOJJpVggl12K3tKtmPouxHsfgX2cIKChX/AcF12WwncLJsLsZkAUeRiQx3GQrpeSSQrlDq2YE80pacmQ64MBUZZQfwp1A8QacbdbBbagylzWnyO1mWC6Nuv7I1xZBhdU1ZKJwC9SerPmnWnq4A7a8ZxAdMIPoJRPXEHGsDvjMgDhP73gZHrFJVZ0sLDl9rxIeXb6DFG10NTCHpRdl12LLyLfVd7VzzCjprUIcyFBkXj4Hew6renXnJ4FfJO1S9O8UfT0KS3Y2aYJMySRYTkLldFDrfs/6X2KMO9IuyZyBlS2i6jp4qQ97osRhUkwgtfBtAV/BKdjzH0X0HkJM3DRS8Lio4TgH34MLE5GieLeQ2B2CmWx9qJg30CsRvC8RJuvAB+pOVfabtuTZQv/Szik+YQFQTiNpQtr13L7yYfgcW3D0YWZMmIjV7qvhHxwtGpIk0ymO10fvLWYt+roWKKWT8/LKHREjUqkxPXx9kTwTKvlBWaouQtLlFiuc2SnhPMkfWfLVuNBDLsDaAQWNGwbecTOZW9jS41tSp3rBMEuHKUcJDFZeyFC/1hBo1l9nM9opXZ26XY8ZDmJWsPElVueuAOjeqXRSuD0GXCONORX5GnRaiD6SLbKOFSc8H+OY7WLpZ/cQ14gN6H12GUJhQmfHTpyJJtqtBcKht3lHdwTiR3ED9yco+s/Z0xZzEyTLz9ic9HWZuYManTOBmJxCVHnNvmw0/Sbkdw4ffhfi0NNEGiY/9ROxr3/o1+o3KxIi+FfhPnMOL5VfQFOAHNyhkKlf0CgGhhB57qNWr9h5A6fJcvLB8Lrw1pZbvmMm8o5veQdLiR/FCjuKxeUu3YYXNhhicwB+2ZeIldaW1q7RUCXFb1El4YY8/hxfm2bRV2bsKDmCJvOYtRcEq8++rzURa2eVxA4vl6m8h8zhibDaEokuGcfNwwO/zMitdZnaF65ryMAOUngrCxD5VC9srq92Pi8VxRjva0+Yh6zYoCYWTVR6PRZ+sMmlPWvxnJcdgEp8ygagmENLfY07od0dEQXhwYDzmD3Wg74gRmt1JS34ujmve/KV27dqXX2LzeSd2XGrQrskD+fmH/vMWmcZ7JtBRArTA6fvLM3FyleEb9I4KbEe5ntTdDjM5KxO45QlEpcd8X0Jv3JaYCM+NRq2BW69cFh6H/hrlua+mznRi1gqaHPgm7e3A3FxkuA9g3dqTGPskfafqu0bfiNKnPd9fnotM1dP2Cm9PGZRN5WwBHnpiFEp13xWbmMCXIpTAoJntWPQV5jr2pO4wV4XFMYGoJhCVE3NKH3p17oWn0ecJt9TVKBOz7hrlUfJat3HmvGV4YZ6SLsK9m5XvYelKxtxMFKx6Ways9diSMdZ4TZ2UE4vfwUv0eQ8trqHvepd/DxA/pqHI9ZNjXHyjZOH/o4QALbZa0UN16UndPVRlVssEIpJAVE7M1BKepibYdO+DW9wudWL2edFerxetQZqtzTtmXf7SbW3DkX7XxMKnA1hP37dKW9TPRMTnO+q3vvoy4uczV+8LbbWuzhY+ZAJMgAkwgeggEJUTc3VTKxLq6xGjfiJFTXVp+59Ei3mbm7WW87S0oKYp2NSsZQ/jQYifD4VRI4tiAkyACTCByCAQlZ9L/eN6M5qv18PT3Kz9sy/8Eeif/hrlobxdtolfvZqK/Jn0k1rqljUNOQE+laHvSJ9c9rj2aZAsFul7j3cGEh9ZjrgAK+AjvY5sPxNgAkwgHASi0mP+4Eoj7utbj9SYGMTEKt8qx40aI3iRl0ybp6UV1dfqQXkDbX7vmNU/yLArhG9ySSZ9pvOHVcD3l+s+S9J/PhTGHziJvXcdUsYN1qpSv/+7qDsbwo9XaCU6d+C5azmGTJviJ8R7eROqjw1GyrAiXDyfg/iLRaiTIX2/nHzCBJgAE2ACkkBUfi5FlUuOjcGPU25HSnwcetHkLCcEeq9Mk3LDDfxv9XW4WjySRUTuPd7hGDB3DeIuPA3X51+JOtAk7cgqR+27K3FD1ruLaxc34y/of9lng1EdpSecf6BbHxaMNvA5E2ACTCASCESlx0zgacJ9oeIaHhzQjInxvZEoVmoDdU0eHG5oxo7LjWiOgrBqwkz/SZnq3nTuEzRnTUGfgUD9pRmw/yAHuHg/EoYoHrTRm6ZJ025Io9BzsHKyg1PehMHluPH5l36L1qSM6xv3I2HwQdTvVZLN9ElZvGcCTIAJ3OoEonZipoaliXfLpRviXzQ2NIWP7xx8ELV7v/RFBLSKlqPpEoDhOUiwTUH9+e+ivNAG4U0PnQmcLYT0tmNLHmiTFqicpkIeDM9B/JVP4CR9+ug5Xb9YBPeIabDTHiMwIHcNTPVJWbxnAkyACdziBKJy8det0qYJQ+9Hc8nv24Sr+wybgt5XLoLeplMeo4cs+fT5xrPod/VXWni56Uq5TDIt13z5gpauPyAdtgELkLLwr0j/wQdIe2Qd+g/wChkN5/dq+0D69PL4mAkwASZwKxOIao85mhvWOnw8HAlD0tFQsgFNmIn+uhAyechK2l54vDPRPysdNttPkf6Dn2qo6vevFGn60LNSDrjxsX+omgpJO65uX4Srl33uMsm3Dz6I63tm4PYcZd9/obk+fzdbM4UPmAATYAK3JAGemKOs2YVXis1w0jowNZSsrYQeOA1x2Iw6Shs4FLFXNqN62wa0+C0Qs1mU+wR1xlA1sQs1jJ04DHdY6YuyNuDqMAEmwAQ6Q4BD2Z2h1+Nl0xE3zPeHOrTV2OpkSyFmCiXTJhZiPTgFNz7WTcR3DIZ8MvMMWIjEe4eLvPpydIFC4y0lunIil/If5W2+sN8wuSshdH0YW+S20KcTx4dMgAkwgVuegByXb3kQkQYgxlYI946hSHlwDdLHKSFk74X/QcV7hcpPj4qV0kDCkL8iYRrg9X6C2ncXae+jYy5vxNWLf4F94V9F1embY+e2L+HBTL8V1DSh988qR/27hoVdujC22WpsCoXLMDatxo6xmevTPmOLtAZge5kAE2ACXUQgar9j7iJeESOWVmwPHlqEisLCiLGZDWUCTIAJMAGAJ+YI7AW08jmatvJ3H4im6nBdmAATYAKdIsCh7E7h65nCPJH1DHfWygSYABPoDgK8+Ks7KLMOJsAEmAATYAIhEuCJOURQnI0JMAEmwASYQHcQ4Im5OyizDibABJgAE2ACIRLgiTlEUJyNCTABJsAEmEB3EOCJuTsosw4mwASYABNgAiES4Ik5RFCcjQkwASbABJhAdxDgibk7KLMOJsAEmAATYAIhEuCJOURQnI0JMAEmwASYQHcQ4Im5OyizDibABJgAE2ACIRLgiTlEUJyNCTABJsAEmEB3EOCJuTsosw4mwASYABNgAiES4Ik5RFCcjQkwASbABJhAdxD4f+DSlIjeDwOtAAAAAElFTkSuQmCC) 解法： 1、正常给一个module加入aar文件的步骤是： - 把aar文件放入module文件夹下libs包下 - 然后在项目的build.gradle文件的android节点下加入 - \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; ``` repositories { flatDir { dirs \u0026rsquo;libs' } }\n\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; - 然后继续在dependencies节点中加入：compile(name: \u0026amp;#8216;xxxxxxx\u0026amp;#8217;, ext: \u0026amp;#8216;aar\u0026amp;#8217;) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 2、就是这样会引发上面的问题，所以你要做的是，给所有依赖或间接依赖Module A 的Module的build.gradle的android节点下加入 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; repositories { \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; flatDir { dirs \u0026amp;#8216;../模块名称/libs\u0026amp;#8217;,\u0026amp;#8217;libs\u0026amp;#8217; } } \u0026lt;/div\u0026gt; 其中dirs前面一段路径是Module A的文件夹 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 问题原因： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 对于Module B和Module C来说，他们依赖了Module A，不管用不用，他们都会去把Module A的依赖走一遍，当走到你添加的aar本地依赖时，他们去找aar的路径也需要你给出，而且给的方式如果是libs这样的路径，它会去找自己包下的libs，里边自然没有，所以你要给出另一个相对路径：../模块名称/libs这样才能找到，而为了不影响自己这个Module对自己Module下的libs的引用，就使用逗号再添加一个路径 \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/androidstudio-%E5%A4%9A%E5%B1%82%E7%BA%A7-module-%E5%AF%B9-aar-%E5%BC%95%E7%94%A8/","summary":"\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e问题：有个arr文件被放到Module A中引用，现在Module B又依赖了Module A，则在编译过程中会发生错误，Module B找不到aar文件。（同时如果又有Module C 依赖了Module B，C也会出同样的问题）\n\n\n\n\n\n![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeYAAABICAYAAAAj8lblAAAfbklEQVR4Ae2dCXAU15nH/yMElmTAII80QhKHwSCBETiAiUFiOQLZTbwWSA5UZdcOqfUBDthOdjdOxRAfHE7Zm1StsV2AHVfAzuaAGHHEccpcwkiY2EAM4rAENpeuGY3EYZDQNbP1ve7X09PqnhlJI4kZvq6CPt573/e933v9Xn9fvx7ZpuRM8yLKNu+A8cj71zvw+bv7cC7GFmW14+owASbABJhANBOI9UbZtDxsxr9j5hAbzn/8Hs7abECU1S+aOyPXjQkwASbABADb/dnR5zFzwzIBJsAEmAATiFQCMZFqONvNBJgAE2ACTCAaCfDEHI2tynViAkyACTCBiCXAE3PENh0bzgSYABNgAtFIIJZXR0Vjs3KdmAATYAJMIFIJxLpraiLVdrabCTABJsAEmEDUEYhNGZQasFL1X1/B6Ya+AfNwIhNgAkyACTABJhAeAvyOOTwcWQoTYAJMgAkwgbAQiA2LlE4Kie8bi2/MTsVd4wZioCNeSKurrsdXRy/h6J4qNFxr6aQGLs4EmAATYAJMIDII9PjEfPeEO/Hgf4zBjMypGJ04Fv17DxDkrjZfxqnpx1H4z59gxzsncOZIbWQQZSuZABNgAkyACXSCQK8hw+56MVD55qZG1LX0CZSlw2k0KT/2X9Pw8IR/Q3rfoegVE4sWb4v4R8cpt6fi3rSxSBjZgHPnalBX1dBhXT1V0Js2E2+sehiPpddh0xFXT5lx0+llLjddkwQ1SGuz7zjg/vAEvkIWlq15Aj9Wz8VP4AaVEjyD1zu2S+QG19zxHMHYfJU+SxkHJvTCkY/Poo5+Lvgm37Q6ddBmYztqDAL0l1mPLcevFo5BfMlnOPp19zLS6/68v9peAWztyubrMY85vl9vfHvhcMy8+5/QgkaU17jwWdHnKD9Xhfrr9YhPiEfqYAf+6dtTRJ4LCytRefoq6r9ubsND6QDzMMnQ2Q+9twIvf6Y0rswzsWQrHvrN8TYybtULzKVrWz4QX5lG/dbr/QJvPr0Je9Q+7PUm44fLnsDclLZpgSz2K1ddhJ+t3oMzhvsiUPmeSLv7wcV4ZTaw/dW12FgR3sFYMub7HqCJZ+k4H1/vsQLkvw0sWzMPzKcner61znZPzP+9cB7GjhxqKbHk9Hn8euNWy3SZMH5mChwp/XDF44SrAvjg//ZgoP0OTHngXtzeLx7Oi26cPn4OX148gzuH94UjpS/u/dYgHNh6QYpo195mO45Nu3IwcXYOFqaVhH0AaJcxN1Fm5tK1jREqX5stE/dPBvZ8ptqTfg8mOTpgm76cIwPZ6XtwpqIDckIoQnV7+Rn1IbcTk/8Qhx2AW9MYLrkkMFT+mvIwHYSzDmEyCXAW49mn9uC0iHTMw6RxeVg2eUWXjYs3JYOwwexaQe2emP/4t/1YMWIIYkz+nGKrx4M/frg/JIuHjx+I/n374Gz9SZzcXYXmmEZMzv8m4uJ6wettxJ1j4tEv8y40tF7C2frzIi8tDgs0MRu9DsAGehp/dU4SKnaux9LtRTg8ex5yv5OFjarXrD1RO4s170I+WUqPm86XZJUKj2a37NSaZ+PzdETo59lspJZsxZuYJ8q88Yr/d+JStlf1Zk5PXoCCRzI1ZqRzdeUsvEFynMV4syQDS+ckiXSqw1M7XNB7RZTg9db4eRuyTjKCQE/GFCUwXpfyTjMX4TVIXpKL1ii6g6Ds75vftj1N+OpEwltdg0qHHRPHZwGfKRPdyAkZSIUbFdV2pDqojZOxcNki5DrcWltLW/TXZLltO2sxd06mf1+n1yqB+lWQdL3NdCz700Qo9wZ5+/KaZKl4ZS7N+1fK+fqrvB+AJMz92fPI1XtxgeTqIgxS50S6h3fa8ap6P8l2NOvfwg5dfWU5eS9tSPXdlyRn6XaIOuhZ6/lv++0Xfng0m9Q67NanTl6ALQYbTceOpwoxZPkiETUxcjPm/9HYszjiugsTA/WPHXvpSQU2KE7KJHVcseKjNxlBbFbGFyXKk+vwHytl//BjoAqX9UijvnOsAG/6KfU/aZuXxljlftgAdczUj70B+JHktvL89RnPZJvKvi37lzFfOM7b/blUubMWHx8+Yaqbrle4QluklZiSgN59YtDibYXzYi3i02yo9HyFr+pP4mzDKVxoOI3qxou40nJJ5KG8Ax1xpnrlRfI6lr7+PLas+QXef20xFqb5/81H5enZDWSR16yk0bWDJQCEd6EMNvdnKRIHpTjEgDg4GYDTjfPi3Zd/yJx0LlmzALP0fz8zOQd5qgxpG+29980XoSRtUqb3Tg9n6LP4HdtScrRJmRJSZ+erdicjTedN2WxJyH1WscHYeaRAs+tpcxbhufu8qlfBXCQryUWe++8DsKeB3qQ9zfqdv8xaVDkBZI0W/YgG/OwsO+CsRZWa0WZzobjEDWrrSRPUxpfecUmRiAD5ypWiePspHKI+qcrU67PuV0quYOl6Wfpjsz6mpFsz05e3OjaTa3rfIQPP6Pinzp4ueAbn7ysn7qWFT/q1I913P0x3BuZf4wsRW9WDrhNb+eBA5757Wi3lN3aEwE3Nb7M14cyxwP1D2iWdFRqHNn0qowr+97/MS/ugNuszt+NYtOuz2aBJWegZl+cXateLCjlviPxClqcaYdYHA48Teuvbf9xuj5lUFOz+BPePG4W423yLwm40NqFg18F2WdDiaaEHOHi8HnjgBZ3T1nC5CYd/fxZejxf9HHG4d/4weDxeeFr9J9pQlJ3ZsQ75O3w5Tx8pReXsbDG4baxQFmNdcLphG5eENPFbK0kYpHkqNCNDTIKVu07gzDeni/fYcmKld3fKE38m8nId2H1E1eMADr26Uhks02YiX1wejWUPZyje7Ub1vV+qXXRK/ycvG5CmyNFHABQ9yqC8sUIXQoTy7mhJ1p0YnE53+mjFRtVLVi0CJs/3uy6fFunhA3CBuahRBdWLklw0fuoBDfJa+LYNe4v2BEz5+mS7cbDkTkxKUcLZuyuVMPbh3+1DxZwMTFQzUhtVzLYjNese3L3dCUzIEP3n0FF6srQBk6cL76pi5wmcsblwsITClYYQufB0fVEefb/aoPZfq34n0312G44mm/c9usetmG38zSpARKR8kQBgrL9gKVf3ztzvvtuuZlfvu6XlDtW7Ve+JiiD8HbUoeHotdtODMk0UKUmoem8Fln6qyJmboowNgfnP8rfZ4iwoW93YgRhg7zM+J4jqrN3nUr4uP93T0+ZY9w95z8uJ8PBO3/oDs/tfqghqs8zY3r2hXWWIXfZ3P3Gh5tXxCMhPjpMycqlGQk11kyFSv4w+Bhkn/GzvwEmHJuYr1+rxwceH8NCcqZrKHfs+w9Xr9dp5sAP6Trk+PR59bovB7cm3ofb817jRaEev3jGI7d8L31x8N8o+qkLd2Wto9rSiqdGDKzWNAcXqO5CSse1TrK1iLwpKsrGEnqa3K4tt5A2nDMZ2pDpLsd1lR25yEkamQ0zUh444MXLCnUJsZQkNfIpsmtQpDOe3qR6M/pptXCYm0aB4TPFuRNqnp3Do4QxMmrMIW+YAcsI/LQs63ZBv1PV6ZAiNFgbJTTrsI1MUGw/LwVrNIK/bxuVhy5o8WQxeBz18uMBc2nIhzrQwhkJXWohTHfTN2MOiPamvmPHVGgHAhe1FODR7nghnj0yhMHYpCj4FBs/x5dJkZNkxBA4MzrKLRWMHP1Xm5W+NV6Iv9CRP/Ulu+hC5uGbRr2R+ig6Z9Tst3eJA9jFj3wvUXy1E+V2WcoPed85SFJeTB+jCRXrm1keVTO57TYmsb3mNiFCker8AMdXkpCg5A/Knh+JQNqmL2jzI2BESN91YE9A+G0QffOqZvcJK8WDzyPN4PUV5PaaV1Y2LWnWC2axlbN9Bm3b1ulDhBCbq2k1KNOalcDw9eE40RiZ1PALxM8pDAN1kg8xvNX5KO8O1b3coWyr+W/ER1F35WpzWXv4aHx34h0wKaU8/HvL1tSY0tzYj9b4BaG5swakPy3HtUj2aWprhPncFdeeuISGpj8hDec+WXApJdrBMuz8sRiUyhJcr8pafwCEnhCfyw/EZoAFgw9FSJbw9wY5U1OJiOXC6WgnTp4rJTNGiLFwBqqopFmm90YS8rdoLalgKH9OmeF+rkPee8n6KQkavPK7raQ4agJX3iyK0CUXPyNx88a5x2ysrkP/0SrxxrG0kQQzGJuaQd05l5D/9CnXm4s9Ftg+xeuiZdSICEoi9zG/Vnm34+rVPifJKJSsHz1AYu+QUzN7J7T5aCrFQLFddHFZySqzkplCbfAXjJ5ZOjOFsi36llQuWrmU0PzD2vUDMzCX4X+3MfaeXFJi/Pqf1sRV/6xKGlHaw7Qi3UO2jfLTpxzJLPsFsTk7C3cIz8A+9G2pueeqzIXh5mTdgf1c1hcJPygOC6yaxgcZPywp2IKFDHjPpaW5pxaaPirF4/r9g80fF4rw9+o/trcY3vpWC3vGx6JPcCyPnOlB15ApK3i9Hy41WxN4Wg37pcUjPTkRDYzMuu1vw+W75xs1ck3zHvFRNJoivIV9b/EULp2hr+3SovL/LnZ0hvNqqo06g0i0m70k0T5YUKZ+xSI/I6HWqT9gI+NRcgw0bizHp2WxMfHgBZn26CbsNC7+MtTLWhyICwjvKpUldWSwzVy0kPWZayEGeF624lJ6xsgBHva7zpowRBuaiwDRyadsu5uxpDYF+IV+bcgavzTjx0mC5dFwm0lKAQzvFwgejCEivfFCWsjhs+4cyjG0eRpYhX1rxvbtSEWfZr9T+Gyy9rVHKFau+9zOndX+VsmR/lou/5HWxD3bf+WW2PjH2byN/65K6FNWWNvx1WQIdtpet5GK8zy11WNgn3pEuS8Km1eqqbPVdfKXT99sKVnwsbYYSYUij9+av52gmybFIu2BxICOVabqxirLK8vJdOI3jS9XXODIvRbAqyRcy8a716qz4BdOtl0HHWt8OMH4ay3TmvMMeMyn9+7Ey7Dp4FH8vKWu3DfQ98s6NX+GqG7jR2IrYxBgMnj0QmQ+nYOxjach8ZBDSZg1Eay+IPJTX7BvmditWC8gnS3o3TJt4xwJaAVuqTH6qF03vm5TQnOLhrn56q7KoRpUTbBBXs4kddfzXdtECDXXBmEefqoay36aBVtkotL1N9YaVUKoaeqfJV+29+jxUiry21a8Wo0L2blWW1XU1WdsxFw2F6YG4QS3YGwuIVxO69qR0I1+/MjSoer2+8LRfonJC7UiLFalfQg3dipDdHCWMLfuqLEr6aJs4Z5bq1Sj9zKxfyTL6PqXvdzLdam/Vx4IxI0/N2F/1OoTcTtx3elkB+eszWhyb8bfIanq5PWyDcTNTENA+RzZeff15FLyep603kc6KlGXGx8pm0S6/U/oXlT/03noRFZSygu1pPFyqK1+xs8CyvDFv5a4iHAqiIBA/o7xAukmNqKvJuBrEhA4n23Kmz2wbB9WJ6+q/LkXvbecsHIG4gUCvuFbYeimzlbc1Bq03euHGJeCjjV+G/Sc55fuHXPg+k9JVu0cP5SIN+lyqu38ggrl0bdOHg6/ekzAOrIGsD9avgqUHkh0paT3Jv7sYdbR/kH3h4NMd9ZTRqfY4Rt1hV7h0dMpjDocRp4/U4rfLjuDglmpUnWhBg/M2XK/sg/Jjzfjk/SqR1hW/k00LOzbsLBWfAjyjes3hqE+ky2AuXduCneVLAyetNyBPlhYk8tY+AtHOv7P9o7N82tcaoeemUPxzry0Xn8LS57DylVHlrn3ar+WFLu3mz9nhd8zhrBr99Sj64ZBAPx4STn1Slu2zzciXv7QkL/IezKVrO0FH+Srvi5WV+H6r+7vW3KiTHq38w9U/OsqnuzuK/AGo7tbbHfpuiom5OyoaSTro/Yf8rEF86B1JxnehrcxFgau9u1Y/2QsVeTB+wdJD1RPt+TrKv7u43Oz2dYQDvePVfwuvyPB9LtoRmTdzmR5/x3wzw2HbmAATYAJMgAl0N4GQPObxyb262y7WxwSYABNgAkzgliTQ44u/bknqXGkmwASYABNgAhYEeGK2AMOXmQATYAJMgAn0BAGemHuCOutkAkyACTABJmBBgCdmCzB8mQkwASbABJhATxDgibknqPeQTk/ydDy5aDochp/rDGROR8oEktddaZFkt9FW43l3MWuvnkixs7314vxMoKcJhLQqu6eNZP3+BGhAXPL4VCTrvmP11hRj/bpCOHXXZCmRPw94f4u8Ep69x5uM2YvnAgVvYY8rer8pDA+t4FK8yTPwZH742ym4Zs7BBJjAzUSAJ+abqTXaZUsZtqz8M0r0E7H+WCcrxrUPa9cDNEHzdvMSsLkKsXa9jdvp5m0itowJdAsBnpi7BXP3KHHMeByLc5I0Za6i32BtoUsM9EsMHrPi7T6KaUk28bvLRW/7vF6jR07euHHTl8cTyzCNfgBf9dqrHDM0j55+01kvWy9HevKldVORM6oMBav+jKNwYPZic7uy5v8c+RmKZ+5XNzV6YNTl9cZj8uLnkFD8Mv50XCnnGfsQXsx2i+hCVRBdeYkHLKMQZItMV+prR2lxIqap/L/YuhonRz8n7CW79r+1Fbb8x5BkYss6NZJh9JjvWfAcFmf4t4+R2a7iRMwJ0ObENnvkOZTWDoPNRLcxymKUH6xNZHvq+4O+Haz6JJUzbU8RhbFuf8ncLDIkbeE9E4h0AjwxR3oL6ux3Fr6NlwqVC8rkOhezTr6FXbo88nD8gkeRUfoOXlrvgpis8mbgxLpCiMkqbyrqtr2MtccV740mdeMWY3Nh17p3AEMo20OTnb48TYSqbNPB1D5VTFYrNtvob6th/HwLu7K+JybCdSvJxrGYPRMQk4GFLvrL3TZbA/5eVIbFY8YCx0+IKowfPQo1pftFyN9Kl6mdRgBtzkchA+/gpVUKz5fmLQO2rsZLm20K3/wxWGdiS2nxn1Ftm9FGGlQuVJ4mt0Va+wAyTTADcMCqzVUZK6UNo/05kG7TuobaJjqrrfqTZZ9MbtueJM5SjkU0SGcCHzKBqCHAi78itilHIf8Xy/DC8ufEv+fn3+NfE+cplLr9L8kzr/cejBlVhqK96l8nKvkCpfZRuIf+NLVjNDLsZTjp+7PQslhoeyqPAyiU5fWyzSS4fXk9gezSlY2xncCeQpdiazBdJadQOioTWV4vFPlulJ50qscWDACUbP4lVqzfZz5xmaW7D2CL5Olyw1VT7GPgcqOG7G9jSwDOOi5VJ8tQY7cjWTLQpclLYm9sc30+agc/DqHpDqVNAvYnvYFG+9Q02Z7BdAVrE70qPmYCkUyAPeaIbT2Td8w0r+rC2SKkaFY/RxISoUzs+Wo65RWTR7IdSW43XGblQrlG5aF/IqhBjduOJJpVggl12K3tKtmPouxHsfgX2cIKChX/AcF12WwncLJsLsZkAUeRiQx3GQrpeSSQrlDq2YE80pacmQ64MBUZZQfwp1A8QacbdbBbagylzWnyO1mWC6Nuv7I1xZBhdU1ZKJwC9SerPmnWnq4A7a8ZxAdMIPoJRPXEHGsDvjMgDhP73gZHrFJVZ0sLDl9rxIeXb6DFG10NTCHpRdl12LLyLfVd7VzzCjprUIcyFBkXj4Hew6renXnJ4FfJO1S9O8UfT0KS3Y2aYJMySRYTkLldFDrfs/6X2KMO9IuyZyBlS2i6jp4qQ97osRhUkwgtfBtAV/BKdjzH0X0HkJM3DRS8Lio4TgH34MLE5GieLeQ2B2CmWx9qJg30CsRvC8RJuvAB+pOVfabtuTZQv/Szik+YQFQTiNpQtr13L7yYfgcW3D0YWZMmIjV7qvhHxwtGpIk0ymO10fvLWYt+roWKKWT8/LKHREjUqkxPXx9kTwTKvlBWaouQtLlFiuc2SnhPMkfWfLVuNBDLsDaAQWNGwbecTOZW9jS41tSp3rBMEuHKUcJDFZeyFC/1hBo1l9nM9opXZ26XY8ZDmJWsPElVueuAOjeqXRSuD0GXCONORX5GnRaiD6SLbKOFSc8H+OY7WLpZ/cQ14gN6H12GUJhQmfHTpyJJtqtBcKht3lHdwTiR3ED9yco+s/Z0xZzEyTLz9ic9HWZuYManTOBmJxCVHnNvmw0/Sbkdw4ffhfi0NNEGiY/9ROxr3/o1+o3KxIi+FfhPnMOL5VfQFOAHNyhkKlf0CgGhhB57qNWr9h5A6fJcvLB8Lrw1pZbvmMm8o5veQdLiR/FCjuKxeUu3YYXNhhicwB+2ZeIldaW1q7RUCXFb1El4YY8/hxfm2bRV2bsKDmCJvOYtRcEq8++rzURa2eVxA4vl6m8h8zhibDaEokuGcfNwwO/zMitdZnaF65ryMAOUngrCxD5VC9srq92Pi8VxRjva0+Yh6zYoCYWTVR6PRZ+sMmlPWvxnJcdgEp8ygagmENLfY07od0dEQXhwYDzmD3Wg74gRmt1JS34ujmve/KV27dqXX2LzeSd2XGrQrskD+fmH/vMWmcZ7JtBRArTA6fvLM3FyleEb9I4KbEe5ntTdDjM5KxO45QlEpcd8X0Jv3JaYCM+NRq2BW69cFh6H/hrlua+mznRi1gqaHPgm7e3A3FxkuA9g3dqTGPskfafqu0bfiNKnPd9fnotM1dP2Cm9PGZRN5WwBHnpiFEp13xWbmMCXIpTAoJntWPQV5jr2pO4wV4XFMYGoJhCVE3NKH3p17oWn0ecJt9TVKBOz7hrlUfJat3HmvGV4YZ6SLsK9m5XvYelKxtxMFKx6Ways9diSMdZ4TZ2UE4vfwUv0eQ8trqHvepd/DxA/pqHI9ZNjXHyjZOH/o4QALbZa0UN16UndPVRlVssEIpJAVE7M1BKepibYdO+DW9wudWL2edFerxetQZqtzTtmXf7SbW3DkX7XxMKnA1hP37dKW9TPRMTnO+q3vvoy4uczV+8LbbWuzhY+ZAJMgAkwgeggEJUTc3VTKxLq6xGjfiJFTXVp+59Ei3mbm7WW87S0oKYp2NSsZQ/jQYifD4VRI4tiAkyACTCByCAQlZ9L/eN6M5qv18PT3Kz9sy/8Eeif/hrlobxdtolfvZqK/Jn0k1rqljUNOQE+laHvSJ9c9rj2aZAsFul7j3cGEh9ZjrgAK+AjvY5sPxNgAkwgHASi0mP+4Eoj7utbj9SYGMTEKt8qx40aI3iRl0ybp6UV1dfqQXkDbX7vmNU/yLArhG9ySSZ9pvOHVcD3l+s+S9J/PhTGHziJvXcdUsYN1qpSv/+7qDsbwo9XaCU6d+C5azmGTJviJ8R7eROqjw1GyrAiXDyfg/iLRaiTIX2/nHzCBJgAE2ACkkBUfi5FlUuOjcGPU25HSnwcetHkLCcEeq9Mk3LDDfxv9XW4WjySRUTuPd7hGDB3DeIuPA3X51+JOtAk7cgqR+27K3FD1ruLaxc34y/of9lng1EdpSecf6BbHxaMNvA5E2ACTCASCESlx0zgacJ9oeIaHhzQjInxvZEoVmoDdU0eHG5oxo7LjWiOgrBqwkz/SZnq3nTuEzRnTUGfgUD9pRmw/yAHuHg/EoYoHrTRm6ZJ025Io9BzsHKyg1PehMHluPH5l36L1qSM6xv3I2HwQdTvVZLN9ElZvGcCTIAJ3OoEonZipoaliXfLpRviXzQ2NIWP7xx8ELV7v/RFBLSKlqPpEoDhOUiwTUH9+e+ivNAG4U0PnQmcLYT0tmNLHmiTFqicpkIeDM9B/JVP4CR9+ug5Xb9YBPeIabDTHiMwIHcNTPVJWbxnAkyACdziBKJy8det0qYJQ+9Hc8nv24Sr+wybgt5XLoLeplMeo4cs+fT5xrPod/VXWni56Uq5TDIt13z5gpauPyAdtgELkLLwr0j/wQdIe2Qd+g/wChkN5/dq+0D69PL4mAkwASZwKxOIao85mhvWOnw8HAlD0tFQsgFNmIn+uhAyechK2l54vDPRPysdNttPkf6Dn2qo6vevFGn60LNSDrjxsX+omgpJO65uX4Srl33uMsm3Dz6I63tm4PYcZd9/obk+fzdbM4UPmAATYAK3JAGemKOs2YVXis1w0jowNZSsrYQeOA1x2Iw6Shs4FLFXNqN62wa0+C0Qs1mU+wR1xlA1sQs1jJ04DHdY6YuyNuDqMAEmwAQ6Q4BD2Z2h1+Nl0xE3zPeHOrTV2OpkSyFmCiXTJhZiPTgFNz7WTcR3DIZ8MvMMWIjEe4eLvPpydIFC4y0lunIil/If5W2+sN8wuSshdH0YW+S20KcTx4dMgAkwgVuegByXb3kQkQYgxlYI946hSHlwDdLHKSFk74X/QcV7hcpPj4qV0kDCkL8iYRrg9X6C2ncXae+jYy5vxNWLf4F94V9F1embY+e2L+HBTL8V1DSh988qR/27hoVdujC22WpsCoXLMDatxo6xmevTPmOLtAZge5kAE2ACXUQgar9j7iJeESOWVmwPHlqEisLCiLGZDWUCTIAJMAGAJ+YI7AW08jmatvJ3H4im6nBdmAATYAKdIsCh7E7h65nCPJH1DHfWygSYABPoDgK8+Ks7KLMOJsAEmAATYAIhEuCJOURQnI0JMAEmwASYQHcQ4Im5OyizDibABJgAE2ACIRLgiTlEUJyNCTABJsAEmEB3EOCJuTsosw4mwASYABNgAiES4Ik5RFCcjQkwASbABJhAdxDgibk7KLMOJsAEmAATYAIhEuCJOURQnI0JMAEmwASYQHcQ4Im5OyizDibABJgAE2ACIRLgiTlEUJyNCTABJsAEmEB3EOCJuTsosw4mwASYABNgAiES4Ik5RFCcjQkwASbABJhAdxD4f+DSlIjeDwOtAAAAAElFTkSuQmCC)\n\n\n\n\n\n解法：\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  1、正常给一个module加入aar文件的步骤是：\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e- 把aar文件放入module文件夹下libs包下\n\n- 然后在项目的build.gradle文件的android节点下加入\n\n- \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td\u0026gt;\n        \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;top-box hide\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003erepositories {\nflatDir {\ndirs \u0026rsquo;libs'\n}\n}\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u0026lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026lt;/tr\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;/table\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - 然后继续在dependencies节点中加入：compile(name: \u0026amp;#8216;xxxxxxx\u0026amp;#8217;, ext: \u0026amp;#8216;aar\u0026amp;#8217;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  2、就是这样会引发上面的问题，所以你要做的是，给所有依赖或间接依赖Module A 的Module的build.gradle的android节点下加入\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   repositories {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e             flatDir {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e dirs \u0026amp;#8216;../模块名称/libs\u0026amp;#8217;,\u0026amp;#8217;libs\u0026amp;#8217;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    其中dirs前面一段路径是Module A的文件夹\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  问题原因：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  对于Module B和Module C来说，他们依赖了Module A，不管用不用，他们都会去把Module A的依赖走一遍，当走到你添加的aar本地依赖时，他们去找aar的路径也需要你给出，而且给的方式如果是libs这样的路径，它会去找自己包下的libs，里边自然没有，所以你要给出另一个相对路径：../模块名称/libs这样才能找到，而为了不影响自己这个Module对自己Module下的libs的引用，就使用逗号再添加一个路径\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"AndroidStudio 多层级 Module 对 aar 引用"},{"content":"监听工具类\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.util.Log;\npublic class HomeWatcher {\nstatic final String TAG = “HomeWatcher”;\nprivate Context mContext;\nprivate IntentFilter mFilter;\nprivate OnHomePressedListener mListener;\nprivate InnerRecevier mRecevier;\n// 回调接口\npublic interface OnHomePressedListener {\npublic void onHomePressed();\npublic void onHomeLongPressed();\n}\npublic HomeWatcher(Context context) {\nmContext = context;\nmRecevier = new InnerRecevier();\nmFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);\n}\n/**\n设置监听 @param listener\n*/\npublic void setOnHomePressedListener(OnHomePressedListener listener) {\nmListener = listener;\n} /**\n开始监听，注册广播\n*/\npublic void startWatch() {\nif (mRecevier != null) {\nmContext.registerReceiver(mRecevier, mFilter);\n}\n} /**\n停止监听，注销广播\n*/\npublic void stopWatch() {\nif (mRecevier != null) {\nmContext.unregisterReceiver(mRecevier);\n}\n} /**\n广播接收者\n*/\nclass InnerRecevier extends BroadcastReceiver {\nfinal String SYSTEM_DIALOG_REASON_KEY = “reason”;\nfinal String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = “globalactions”;\nfinal String SYSTEM_DIALOG_REASON_RECENT_APPS = “recentapps”;\nfinal String SYSTEM_DIALOG_REASON_HOME_KEY = “homekey”; @Override\npublic void onReceive(Context context, Intent intent) {\nString action = intent.getAction();\nif (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {\nString reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);\nif (reason != null) {\nLog.e(TAG, “action:” + action + “,reason:” + reason);\nif (mListener != null) {\nif (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {\n// 短按home键\nmListener.onHomePressed();\nIntent intents =new Intent(context,MainActivity.class);\nintents.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\ncontext.startActivity(intents);\n} else if (reason\n.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {\n// 长按home键\nmListener.onHomeLongPressed();\n}\n}\n}\n}\n}\n}\n}\n测试Activity\nimport android.os.Bundle;\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.View;\npublic class MainActivity extends Activity implements OnHomePressedListener {\npublic static final int FLAG_HOMEKEY_DISPATCHED = 0x80000000;\nprivate HomeWatcher mHomeWatcher = null;\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\nsuper.onCreate(savedInstanceState);\nthis.getWindow().setFlags(FLAG_HOMEKEY_DISPATCHED,\nFLAG_HOMEKEY_DISPATCHED);\nsetContentView(R.layout.activity_main);\n}\n@Override\npublic boolean onCreateOptionsMenu(Menu menu) {\n// Inflate the menu; this adds items to the action bar if it is present.\ngetMenuInflater().inflate(R.menu.main, menu);\nreturn true;\n}\n@Override\nprotected void onResume() {\nmHomeWatcher = new HomeWatcher(this);\nmHomeWatcher.setOnHomePressedListener(this);\nmHomeWatcher.startWatch();\nsuper.onResume();\n}\n@Override\nprotected void onPause() {\nsuper.onPause();\nmHomeWatcher.setOnHomePressedListener(null);\nmHomeWatcher.stopWatch();\n}\n@Override\npublic void onHomePressed() {\nLog.e(“onHomePressed”, “onHomePressed”);\n}\n@Override\npublic void onHomeLongPressed() {\nLog.e(“onHomeLongPressed”, “onHomeLongPressed”);\n}\n}\n","permalink":"https://blog.zdltech.com/posts/android-home%E9%94%AE%E7%9B%91%E5%90%AC/","summary":"\u003cp\u003e监听工具类\u003c/p\u003e\n\u003cp\u003eimport android.content.BroadcastReceiver;\u003cbr\u003e\nimport android.content.Context;\u003cbr\u003e\nimport android.content.Intent;\u003cbr\u003e\nimport android.content.IntentFilter;\u003cbr\u003e\nimport android.util.Log;\u003c/p\u003e\n\u003cp\u003epublic class HomeWatcher {\u003cbr\u003e\nstatic final String TAG = “HomeWatcher”;\u003cbr\u003e\nprivate Context mContext;\u003cbr\u003e\nprivate IntentFilter mFilter;\u003cbr\u003e\nprivate OnHomePressedListener mListener;\u003cbr\u003e\nprivate InnerRecevier mRecevier;\u003c/p\u003e\n\u003cp\u003e// 回调接口\u003cbr\u003e\npublic interface OnHomePressedListener {\u003cbr\u003e\npublic void onHomePressed();\u003c/p\u003e\n\u003cp\u003epublic void onHomeLongPressed();\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003epublic HomeWatcher(Context context) {\u003cbr\u003e\nmContext = context;\u003cbr\u003e\nmRecevier = new InnerRecevier();\u003cbr\u003e\nmFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e设置监听\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e@param listener\u003cbr\u003e\n*/\u003cbr\u003e\npublic void setOnHomePressedListener(OnHomePressedListener listener) {\u003cbr\u003e\nmListener = listener;\u003cbr\u003e\n}\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e/**\u003c/p\u003e","title":"android Home键监听"},{"content":"转载自：http://blog.csdn.net/chaoyue0071/article/details/43450183/\n本文简单结合两篇文章\nhttp://blog.csdn.net/hellogv/article/details/24267685\nhttp://blog.csdn.net/jimoduwu/article/details/21604215\n在BLE协议中，有两个角色，周边（Periphery）和中央（Central），一个中央可以同时连接多个周边，但是一个周边某一时刻只能连接一个中央。但是不管是Periphery还是Central都是可以实现 GATT server 和 GATT client去传输数据，但是无法同时都是。\n大概了解了概念后，看看Android BLE SDK的四个关键类（class）：\na) BluetoothGattServer作为周边来提供数据； BluetoothGattServerCallback返回周边的状态。\nb) BluetoothGatt作为中央来使用和处理数据；BluetoothGattCallback返回中央的状态和周边提供的数据。\n因为我们讨论的是Android的BLE SDK，下面所有的BluetoothGattServer代表周边，BluetoothGatt代表中央。\n一.创建一个周边（虽然目前周边API在Android手机上不工作，但还是看看）\na）先看看周边用到的class，蓝色椭圆\nb）说明：\n每一个周边BluetoothGattServer，包含多个服务Service，每一个Service包含多个特征Characteristic。\n1.new一个特征：character = new BluetoothGattCharacteristic(\nUUID.fromString(characteristicUUID),\nBluetoothGattCharacteristic.PROPERTY_NOTIFY,\nBluetoothGattCharacteristic.PERMISSION_READ);\n2.new一个服务：service = new BluetoothGattService(UUID.fromString(serviceUUID),\nBluetoothGattService.SERVICE_TYPE_PRIMARY);\n3.把特征添加到服务：service.addCharacteristic(character);\n4.获取BluetoothManager：manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);\n5.获取/打开周边：BluetoothGattServer server = manager.openGattServer(this,\nnew BluetoothGattServerCallback(){…});\n6.把service添加到周边：server.addService(service);\n7.开始广播service：Google还没有广播Service的API，等吧！！！！！所以目前我们还不能让一个Android手机作为周边来提供数据。\n二.创建一个中央（这次不会让你失望，可以成功创建并且连接到周边的）\na）先看看中央用到的class，蓝色椭圆\nb）说明：\n为了拿到中央BluetoothGatt，可要爬山涉水十八弯：\n1.先拿到BluetoothManager：bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);\n2.再拿到BluetoothAdapt：btAdapter = bluetoothManager.getAdapter();\n3.开始扫描：btAdapter.startLeScan( BluetoothAdapter.LeScanCallback);\n4.从LeScanCallback中得到BluetoothDevice：public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {…..}\n5.用BluetoothDevice得到BluetoothGatt：gatt = device.connectGatt(this, true, gattCallback);\n终于拿到中央BluetoothGatt了，它有一堆方法（查API吧），调用这些方法，你就可以通过BluetoothGattCallback和周边BluetoothGattServer交互了。\n官方有给出BLE 通信的sample ，下面是牛人简化了代码，简化得简单明了\n本文来自http://blog.csdn.net/hellogv/ ，引用必须注明出处！\n最近穿戴设备发展得很火，把相关技术也带旺了，其中一项是BLE（Bluetooth Low Energy）。BLE是蓝牙4.0的核心Profile，主打功能是快速搜索，快速连接，超低功耗保持连接和传输数据，弱点是数据传输速率低，由于BLE的低功耗特点，因此普遍用于穿戴设备。Android 4.3才开始支持BLE API，所以请各位客官把本文代码运行在蓝牙4.0和Android 4.3及其以上的系统，另外本文所用的BLE终端是一个蓝牙4.0的串口蓝牙模块。\nPS：我的i9100刷了4.4系统后，竟然也能跟BLE蓝牙模块通信。\nBLE分为三部分Service、Characteristic、Descriptor，这三部分都由UUID作为唯一标示符。一个蓝牙4.0的终端可以包含多个Service，一个Service可以包含多个Characteristic，一个Characteristic包含一个Value和多个Descriptor，一个Descriptor包含一个Value。一般来说，Characteristic是手机与BLE终端交换数据的关键，Characteristic有较多的跟权限相关的字段，例如PERMISSION和PROPERTY，而其中最常用的是PROPERTY，本文所用的BLE蓝牙模块竟然没有标准的Characteristic的PERMISSION。Characteristic的PROPERTY可以通过位运算符组合来设置读写属性，例如READ|WRITE、READ|WRITE_NO_RESPONSE|NOTIFY，因此读取PROPERTY后要分解成所用的组合（本文代码已含此分解方法）。\n本文代码改自Android 4.3 Sample的BluetoothLeGatt，把冗余代码去掉，获取的BLE设备信息都通过Log，还有一些必要的读写蓝牙方法，应该算是简化到大家一看就可以懂了。本文代码可以到http://download.csdn.net/detail/hellogv/7228819下载。接下来贴出本文运行的结果，首先是连接BLE设备后，枚举出设备所有Service、Characteristic、Descriptor，并且手机会往Characteristic uuid=0000ffe1-0000-1000-8000-00805f9b34fb写入“send data-\u0026gt;”字符串，BLE终端收到数据通过串口传到PC串口助手（见PC串口助手的截图）：\n04-21 18:28:25.465: E/DeviceScanActivity(12254): –\u0026gt;service type:PRIMARY\n04-21 18:28:25.465: E/DeviceScanActivity(12254): –\u0026gt;includedServices size:0\n04-21 18:28:25.465: E/DeviceScanActivity(12254): –\u0026gt;service uuid:00001800-0000-1000-8000-00805f9b34fb\n04-21 18:28:25.465: E/DeviceScanActivity(12254): —-\u0026gt;char uuid:00002a00-0000-1000-8000-00805f9b34fb\n04-21 18:28:25.465: E/DeviceScanActivity(12254): —-\u0026gt;char permission:UNKNOW\n04-21 18:28:25.465: E/DeviceScanActivity(12254): —-\u0026gt;char property:READ\n04-21 18:28:25.465: E/DeviceScanActivity(12254): —-\u0026gt;char uuid:00002a01-0000-1000-8000-00805f9b34fb\n04-21 18:28:25.470: E/DeviceScanActivity(12254): —-\u0026gt;char permission:UNKNOW\n04-21 18:28:25.470: E/DeviceScanActivity(12254): —-\u0026gt;char property:READ\n04-21 18:28:25.470: E/DeviceScanActivity(12254): —-\u0026gt;char uuid:00002a02-0000-1000-8000-00805f9b34fb\n04-21 18:28:25.470: E/DeviceScanActivity(12254): —-\u0026gt;char permission:UNKNOW\n04-21 18:28:25.470: E/DeviceScanActivity(12254): —-\u0026gt;char property:READ|WRITE|\n04-21 18:28:25.470: E/DeviceScanActivity(12254): —-\u0026gt;char uuid:00002a03-0000-1000-8000-00805f9b34fb\n04-21 18:28:25.470: E/DeviceScanActivity(12254): —-\u0026gt;char permission:UNKNOW\n04-21 18:28:25.475: E/DeviceScanActivity(12254): —-\u0026gt;char property:READ|WRITE|\n04-21 18:28:25.475: E/DeviceScanActivity(12254): —-\u0026gt;char uuid:00002a04-0000-1000-8000-00805f9b34fb\n04-21 18:28:25.475: E/DeviceScanActivity(12254): —-\u0026gt;char permission:UNKNOW\n04-21 18:28:25.475: E/DeviceScanActivity(12254): —-\u0026gt;char property:READ\n04-21 18:28:25.475: E/DeviceScanActivity(12254): –\u0026gt;service type:PRIMARY\n04-21 18:28:25.475: E/DeviceScanActivity(12254): –\u0026gt;includedServices size:0\n04-21 18:28:25.475: E/DeviceScanActivity(12254): –\u0026gt;service uuid:00001801-0000-1000-8000-00805f9b34fb\n04-21 18:28:25.480: E/DeviceScanActivity(12254): —-\u0026gt;char uuid:00002a05-0000-1000-8000-00805f9b34fb\n04-21 18:28:25.480: E/DeviceScanActivity(12254): —-\u0026gt;char permission:UNKNOW\n04-21 18:28:25.480: E/DeviceScanActivity(12254): —-\u0026gt;char property:INDICATE\n04-21 18:28:25.480: E/DeviceScanActivity(12254): ——–\u0026gt;desc uuid:00002902-0000-1000-8000-00805f9b34fb\n04-21 18:28:25.480: E/DeviceScanActivity(12254): ——–\u0026gt;desc permission:UNKNOW\n04-21 18:28:25.480: E/DeviceScanActivity(12254): –\u0026gt;service type:PRIMARY\n04-21 18:28:25.480: E/DeviceScanActivity(12254): –\u0026gt;includedServices size:0\n04-21 18:28:25.480: E/DeviceScanActivity(12254): –\u0026gt;service uuid:0000ffe0-0000-1000-8000-00805f9b34fb\n04-21 18:28:25.480: E/DeviceScanActivity(12254): —-\u0026gt;char uuid:0000ffe1-0000-1000-8000-00805f9b34fb\n04-21 18:28:25.480: E/DeviceScanActivity(12254): —-\u0026gt;char permission:UNKNOW\n04-21 18:28:25.480: E/DeviceScanActivity(12254): —-\u0026gt;char property:READ|WRITE_NO_RESPONSE|NOTIFY|\n04-21 18:28:25.490: E/DeviceScanActivity(12254): ——–\u0026gt;desc uuid:00002902-0000-1000-8000-00805f9b34fb\n04-21 18:28:25.490: E/DeviceScanActivity(12254): ——–\u0026gt;desc permission:UNKNOW\n04-21 18:28:25.490: E/DeviceScanActivity(12254): ——–\u0026gt;desc uuid:00002901-0000-1000-8000-00805f9b34fb\n04-21 18:28:25.490: E/DeviceScanActivity(12254): ——–\u0026gt;desc permission:UNKNOW\n04-21 18:28:26.025: E/DeviceScanActivity(12254): onCharRead BLE DEVICE read 0000ffe1-0000-1000-8000-00805f9b34fb -\u0026gt; 00\n这里红字是由BluetoothGattCallback的onCharacteristicRead()回调而打出Log\n以下Log是PC上的串口工具通过BLE模块发送过来，由BluetoothGattCallback的 onCharacteristicChanged（）打出Log\n04-21 18:30:18.260: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -\u0026gt; send data to phone\n04-21 18:30:18.745: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -\u0026gt; send data to phone\n04-21 18:30:19.085: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -\u0026gt; send data to phone\n04-21 18:30:19.350: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -\u0026gt; send data to phone\n04-21 18:30:19.605: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -\u0026gt; send data to phone\n04-21 18:30:19.835: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -\u0026gt; send data to phone\n04-21 18:30:20.055: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -\u0026gt; send data to phone\n04-21 18:30:20.320: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -\u0026gt; send data to phone\n04-21 18:30:20.510: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -\u0026gt; send data to phone\n04-21 18:30:20.735: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -\u0026gt; send data to phone\n04-21 18:30:21.000: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -\u0026gt; send data to phone\n接下来贴出本文核心代码：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DeviceScanActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ListActivity\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; String TAG = DeviceScanActivity.class.getSimpleName(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; String UUID_KEY_DATA = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;0000ffe1-0000-1000-8000-00805f9b34fb\u0026#34;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; LeDeviceListAdapter mLeDeviceListAdapter; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/**搜索BLE终端*/\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; BluetoothAdapter mBluetoothAdapter; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/**读写BLE终端*/\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; BluetoothLeClass mBLE; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; mScanning; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; Handler mHandler; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Stops scanning after 10 seconds. \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;long\u0026amp;lt;/span\u0026gt; SCAN_PERIOD = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;10000\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;(Bundle savedInstanceState) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreate(savedInstanceState); getActionBar().setTitle(R.string.title_devices); mHandler = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Handler(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Use this check to determine whether BLE is supported on the device. Then you can \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// selectively disable BLE-related features. \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); finish(); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// BluetoothAdapter through BluetoothManager. \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Checks if Bluetooth is supported on the device. \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mBluetoothAdapter == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { Toast.makeText(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show(); finish(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//开启蓝牙 \u0026amp;lt;/span\u0026gt; mBluetoothAdapter.enable(); mBLE = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; BluetoothLeClass(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!mBLE.initialize()) { Log.e(TAG, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Unable to initialize Bluetooth\u0026#34;\u0026amp;lt;/span\u0026gt;); finish(); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//发现BLE终端的Service时回调 \u0026amp;lt;/span\u0026gt; mBLE.setOnServiceDiscoverListener(mOnServiceDiscover); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//收到BLE终端数据交互的事件 \u0026amp;lt;/span\u0026gt; mBLE.setOnDataAvailableListener(mOnDataAvailable); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onResume\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onResume(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Initializes list view adapter. \u0026amp;lt;/span\u0026gt; mLeDeviceListAdapter = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; LeDeviceListAdapter(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;); setListAdapter(mLeDeviceListAdapter); scanLeDevice(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onPause\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onPause(); scanLeDevice(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;); mLeDeviceListAdapter.clear(); mBLE.disconnect(); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onStop\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onStop(); mBLE.close(); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onListItemClick\u0026amp;lt;/span\u0026gt;(ListView l, View v, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;long\u0026amp;lt;/span\u0026gt; id) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; BluetoothDevice device = mLeDeviceListAdapter.getDevice(position); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (device == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mScanning) { mBluetoothAdapter.stopLeScan(mLeScanCallback); mScanning = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; } mBLE.connect(device.getAddress()); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;scanLeDevice\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; enable) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (enable) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Stops scanning after a pre-defined scan period. \u0026amp;lt;/span\u0026gt; mHandler.postDelayed(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Runnable() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;run\u0026amp;lt;/span\u0026gt;() { mScanning = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; mBluetoothAdapter.stopLeScan(mLeScanCallback); invalidateOptionsMenu(); } }, SCAN_PERIOD); mScanning = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; mBluetoothAdapter.startLeScan(mLeScanCallback); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { mScanning = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; mBluetoothAdapter.stopLeScan(mLeScanCallback); } invalidateOptionsMenu(); } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * 搜索到BLE终端服务的事件 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; BluetoothLeClass.OnServiceDiscoverListener mOnServiceDiscover = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; OnServiceDiscoverListener(){ \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onServiceDiscover\u0026amp;lt;/span\u0026gt;(BluetoothGatt gatt) { displayGattServices(mBLE.getSupportedGattServices()); } }; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * 收到BLE终端数据交互的事件 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; BluetoothLeClass.OnDataAvailableListener mOnDataAvailable = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; OnDataAvailableListener(){ \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * BLE终端数据被读的事件 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCharacteristicRead\u0026amp;lt;/span\u0026gt;(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; status) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (status == BluetoothGatt.GATT_SUCCESS) Log.e(TAG,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;onCharRead \u0026#34;\u0026amp;lt;/span\u0026gt;+gatt.getDevice().getName() +\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; read \u0026#34;\u0026amp;lt;/span\u0026gt; +characteristic.getUuid().toString() +\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; -\u0026amp;gt; \u0026#34;\u0026amp;lt;/span\u0026gt; +Utils.bytesToHexString(characteristic.getValue())); } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * 收到BLE终端写入数据回调 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCharacteristicWrite\u0026amp;lt;/span\u0026gt;(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { Log.e(TAG,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;onCharWrite \u0026#34;\u0026amp;lt;/span\u0026gt;+gatt.getDevice().getName() +\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; write \u0026#34;\u0026amp;lt;/span\u0026gt; +characteristic.getUuid().toString() +\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; -\u0026amp;gt; \u0026#34;\u0026amp;lt;/span\u0026gt; +\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; String(characteristic.getValue())); } }; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Device scan callback. \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; BluetoothAdapter.LeScanCallback mLeScanCallback = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; BluetoothAdapter.LeScanCallback() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onLeScan\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; BluetoothDevice device, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; rssi, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;byte\u0026amp;lt;/span\u0026gt;[] scanRecord) { runOnUiThread(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Runnable() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;run\u0026amp;lt;/span\u0026gt;() { mLeDeviceListAdapter.addDevice(device); mLeDeviceListAdapter.notifyDataSetChanged(); } }); } }; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;displayGattServices\u0026amp;lt;/span\u0026gt;(List\u0026amp;lt;BluetoothGattService\u0026amp;gt; gattServices) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (gattServices == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (BluetoothGattService gattService : gattServices) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//-----Service的字段信息-----// \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; type = gattService.getType(); Log.e(TAG,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;--\u0026amp;gt;service type:\u0026#34;\u0026amp;lt;/span\u0026gt;+Utils.getServiceType(type)); Log.e(TAG,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;--\u0026amp;gt;includedServices size:\u0026#34;\u0026amp;lt;/span\u0026gt;+gattService.getIncludedServices().size()); Log.e(TAG,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;--\u0026amp;gt;service uuid:\u0026#34;\u0026amp;lt;/span\u0026gt;+gattService.getUuid()); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//-----Characteristics的字段信息-----// \u0026amp;lt;/span\u0026gt; List\u0026amp;lt;BluetoothGattCharacteristic\u0026amp;gt; gattCharacteristics =gattService.getCharacteristics(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; BluetoothGattCharacteristic gattCharacteristic: gattCharacteristics) { Log.e(TAG,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;----\u0026amp;gt;char uuid:\u0026#34;\u0026amp;lt;/span\u0026gt;+gattCharacteristic.getUuid()); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; permission = gattCharacteristic.getPermissions(); Log.e(TAG,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;----\u0026amp;gt;char permission:\u0026#34;\u0026amp;lt;/span\u0026gt;+Utils.getCharPermission(permission)); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; property = gattCharacteristic.getProperties(); Log.e(TAG,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;----\u0026amp;gt;char property:\u0026#34;\u0026amp;lt;/span\u0026gt;+Utils.getCharPropertie(property)); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;byte\u0026amp;lt;/span\u0026gt;[] data = gattCharacteristic.getValue(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (data != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; data.length \u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { Log.e(TAG,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;----\u0026amp;gt;char value:\u0026#34;\u0026amp;lt;/span\u0026gt;+\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; String(data)); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//UUID_KEY_DATA是可以跟蓝牙模块串口通信的Characteristic \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(gattCharacteristic.getUuid().toString().equals(UUID_KEY_DATA)){ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//测试读取当前Characteristic数据，会触发mOnDataAvailable.onCharacteristicRead() \u0026amp;lt;/span\u0026gt; mHandler.postDelayed(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Runnable() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;run\u0026amp;lt;/span\u0026gt;() { mBLE.readCharacteristic(gattCharacteristic); } }, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;500\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//接受Characteristic被写的通知,收到蓝牙模块的数据后会触发mOnDataAvailable.onCharacteristicWrite() \u0026amp;lt;/span\u0026gt; mBLE.setCharacteristicNotification(gattCharacteristic, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置数据内容 \u0026amp;lt;/span\u0026gt; gattCharacteristic.setValue(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;send data-\u0026amp;gt;\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//往蓝牙模块写入数据 \u0026amp;lt;/span\u0026gt; mBLE.writeCharacteristic(gattCharacteristic); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//-----Descriptors的字段信息-----// \u0026amp;lt;/span\u0026gt; List\u0026amp;lt;BluetoothGattDescriptor\u0026amp;gt; gattDescriptors = gattCharacteristic.getDescriptors(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (BluetoothGattDescriptor gattDescriptor : gattDescriptors) { Log.e(TAG, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;--------\u0026amp;gt;desc uuid:\u0026#34;\u0026amp;lt;/span\u0026gt; + gattDescriptor.getUuid()); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; descPermission = gattDescriptor.getPermissions(); Log.e(TAG,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;--------\u0026amp;gt;desc permission:\u0026#34;\u0026amp;lt;/span\u0026gt;+ Utils.getDescPermission(descPermission)); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;byte\u0026amp;lt;/span\u0026gt;[] desData = gattDescriptor.getValue(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (desData != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; desData.length \u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { Log.e(TAG, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;--------\u0026amp;gt;desc value:\u0026#34;\u0026amp;lt;/span\u0026gt;+ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; String(desData)); } } } }\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// \u0026amp;lt;/span\u0026gt; } } ` ","permalink":"https://blog.zdltech.com/posts/android-%E8%93%9D%E7%89%994-0-ble-%E7%90%86%E8%A7%A3/","summary":"\u003cp\u003e转载自：\u003ca href=\"http://blog.csdn.net/chaoyue0071/article/details/43450183/\"\u003ehttp://blog.csdn.net/chaoyue0071/article/details/43450183/\u003c/a\u003e\u003cbr\u003e\n本文简单结合两篇文章\u003cbr\u003e\n\u003ca href=\"http://blog.csdn.net/hellogv/article/details/24267685\"\u003ehttp://blog.csdn.net/hellogv/article/details/24267685\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"http://blog.csdn.net/jimoduwu/article/details/21604215\"\u003ehttp://blog.csdn.net/jimoduwu/article/details/21604215\u003c/a\u003e\u003cbr\u003e\n在BLE协议中，有两个角色，周边（Periphery）和中央（Central），一个中央可以同时连接多个周边，但是一个周边某一时刻只能连接一个中央。但是不管是Periphery还是Central都是可以实现 GATT server 和 GATT client去传输数据，但是无法同时都是。\u003cbr\u003e\n大概了解了概念后，看看\u003cspan style=\"color: red;\"\u003e\u003ca href=\"http://lib.csdn.net/base/android\"\u003eAndroid\u003c/a\u003e BLE SDK\u003c/span\u003e的四个关键类（class）：\u003cbr\u003e\na) \u003cspan style=\"color: pink;\"\u003eBluetoothGattServer\u003c/span\u003e作为周边来提供数据； \u003cspan style=\"color: pink;\"\u003eBluetoothGattServerCallback\u003c/span\u003e返回周边的状态。\u003cbr\u003e\nb) \u003cspan style=\"color: pink;\"\u003eBluetoothGatt\u003c/span\u003e作为中央来使用和处理数据；BluetoothGattCallback返回中央的状态和周边提供的数据。\u003cbr\u003e\n因为我们讨论的是Android的BLE SDK，下面所有的BluetoothGattServer代表周边，BluetoothGatt代表中央。\u003c/p\u003e\n\u003cp\u003e一.创建一个周边（虽然目前周边API在Android手机上不工作，但还是看看）\u003cbr\u003e\na）先看看周边用到的class，蓝色椭圆\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20140320112828250?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamltb2R1d3U=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003cbr\u003e\nb）说明：\u003cbr\u003e\n每一个周边BluetoothGattServer，包含多个服务Service，每一个Service包含多个特征Characteristic。\u003cbr\u003e\n1.new一个特征：character = new BluetoothGattCharacteristic(\u003cbr\u003e\nUUID.fromString(characteristicUUID),\u003cbr\u003e\nBluetoothGattCharacteristic.PROPERTY_NOTIFY,\u003cbr\u003e\nBluetoothGattCharacteristic.PERMISSION_READ);\u003cbr\u003e\n2.new一个服务：service = new BluetoothGattService(UUID.fromString(serviceUUID),\u003cbr\u003e\nBluetoothGattService.SERVICE_TYPE_PRIMARY);\u003cbr\u003e\n3.把特征添加到服务：service.addCharacteristic(character);\u003cbr\u003e\n4.获取BluetoothManager：manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);\u003cbr\u003e\n5.获取/打开周边：BluetoothGattServer server = manager.openGattServer(this,\u003cbr\u003e\nnew BluetoothGattServerCallback(){…});\u003cbr\u003e\n6.把service添加到周边：server.addService(service);\u003cbr\u003e\n7.开始广播service：Google还没有广播Service的API，等吧！！！！！所以目前我们还不能让一个Android手机作为周边来提供数据。\u003c/p\u003e\n\u003cp\u003e二.创建一个中央（这次不会让你失望，可以成功创建并且连接到周边的）\u003cbr\u003e\na）先看看中央用到的class，蓝色椭圆\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20140320112840468?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamltb2R1d3U=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003cbr\u003e\nb）说明：\u003cbr\u003e\n为了拿到中央BluetoothGatt，可要爬山涉水十八弯：\u003cbr\u003e\n1.先拿到BluetoothManager：bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);\u003cbr\u003e\n2.再拿到BluetoothAdapt：btAdapter = bluetoothManager.getAdapter();\u003cbr\u003e\n3.开始扫描：btAdapter.startLeScan( BluetoothAdapter.LeScanCallback);\u003cbr\u003e\n4.从LeScanCallback中得到BluetoothDevice：public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {…..}\u003cbr\u003e\n5.用BluetoothDevice得到BluetoothGatt：gatt = device.connectGatt(this, true, gattCallback);\u003cbr\u003e\n终于拿到中央BluetoothGatt了，它有一堆方法（查API吧），调用这些方法，你就可以通过BluetoothGattCallback和周边BluetoothGattServer交互了。\u003cbr\u003e\n官方有给出BLE 通信的sample ，下面是牛人简化了代码，简化得简单明了\u003cbr\u003e\n本文来自\u003ca href=\"http://blog.csdn.net/hellogv/\"\u003ehttp://blog.csdn.net/hellogv/\u003c/a\u003e ，引用必须注明出处！\u003cbr\u003e\n最近穿戴设备发展得很火，把相关技术也带旺了，其中一项是BLE（Bluetooth Low Energy）。BLE是蓝牙4.0的核心Profile，主打功能是快速搜索，快速连接，超低功耗保持连接和传输数据，弱点是数据传输速率低，由于BLE的低功耗特点，因此普遍用于穿戴设备。Android 4.3才开始支持BLE API，所以请各位客官把本文代码运行在蓝牙4.0和Android 4.3及其以上的系统，另外本文所用的BLE终端是一个蓝牙4.0的串口蓝牙模块。\u003cbr\u003e\nPS：我的i9100刷了4.4系统后，竟然也能跟BLE蓝牙模块通信。\u003c/p\u003e","title":"Android 蓝牙4.0 BLE 理解"},{"content":"这里以单个存储权限为例：\n· 在 Manifest 中添加访问权限：（只需设置可写，因为可写必定可读）\n动态申请权限的过程：\n= Build.VERSION_CODES.M) {\n// 检查该权限是否已经获取\nint i = ContextCompat.checkSelfPermission(this, permissions[0]);\n// 权限是否已经 授权 GRANTED—授权 DINIED—拒绝\nif (i != PackageManager.PERMISSION_GRANTED) {\n// 如果没有授予该权限，就去提示用户请求\nshowDialogTipUserRequestPermission();\n}\n}\n}\n// 提示用户该请求权限的弹出框\nprivate void showDialogTipUserRequestPermission() {\nnew AlertDialog.Builder(this)\n.setTitle(“存储权限不可用”)\n.setMessage(“由于支付宝需要获取存储空间，为你存储个人信息；\\n否则，您将无法正常使用支付宝”)\n.setPositiveButton(“立即开启”, new DialogInterface.OnClickListener() {\n@Override\npublic void onClick(DialogInterface dialog, int which) {\nstartRequestPermission();\n}\n})\n.setNegativeButton(“取消”, new DialogInterface.OnClickListener() {\n@Override\npublic void onClick(DialogInterface dialog, int which) {\nfinish();\n}\n}).setCancelable(false).show();\n}\n// 开始提交请求权限\nprivate void startRequestPermission() {\nActivityCompat.requestPermissions(this, permissions, 321);\n}\n// 用户权限 申请 的回调方法\n@Override\npublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\nsuper.onRequestPermissionsResult(requestCode, permissions, grantResults);\nif (requestCode == 321) {\nif (Build.VERSION.SDK_INT \u0026gt;= Build.VERSION_CODES.M) {\nif (grantResults[0] != PackageManager.PERMISSION_GRANTED) {\n// 判断用户是否 点击了不再提醒。(检测该权限是否还可以申请)\nboolean b = shouldShowRequestPermissionRationale(permissions[0]);\nif (!b) {\n// 用户还是想用我的 APP 的\n// 提示用户去应用设置界面手动开启权限\nshowDialogTipUserGoToAppSettting();\n} else\nfinish();\n} else {\nToast.makeText(this, “权限获取成功”, Toast.LENGTH_SHORT).show();\n}\n}\n}\n}\n// 提示用户去应用设置界面手动开启权限\nprivate void showDialogTipUserGoToAppSettting() {\ndialog = new AlertDialog.Builder(this)\n.setTitle(“存储权限不可用”)\n.setMessage(“请在-应用设置-权限-中，允许支付宝使用存储权限来保存用户数据”)\n.setPositiveButton(“立即开启”, new DialogInterface.OnClickListener() {\n@Override\npublic void onClick(DialogInterface dialog, int which) {\n// 跳转到应用设置界面\ngoToAppSetting();\n}\n})\n.setNegativeButton(“取消”, new DialogInterface.OnClickListener() {\n@Override\npublic void onClick(DialogInterface dialog, int which) {\nfinish();\n}\n}).setCancelable(false).show();\n}\n// 跳转到当前应用的设置界面\nprivate void goToAppSetting() {\nIntent intent = new Intent();\nintent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);\nUri uri = Uri.fromParts(“package”, getPackageName(), null);\nintent.setData(uri);\nstartActivityForResult(intent, 123);\n}\n//\n@Override\nprotected void onActivityResult(int requestCode, int resultCode, Intent data) {\nsuper.onActivityResult(requestCode, resultCode, data);\nif (requestCode == 123) {\nif (android.os.Build.VERSION.SDK_INT \u0026gt;= Build.VERSION_CODES.M) {\n// 检查该权限是否已经获取\nint i = ContextCompat.checkSelfPermission(this, permissions[0]);\n// 权限是否已经 授权 GRANTED—授权 DINIED—拒绝\nif (i != PackageManager.PERMISSION_GRANTED) {\n// 提示用户应该去应用设置界面手动开启权限\nshowDialogTipUserGoToAppSettting();\n} else {\nif (dialog != null \u0026amp;\u0026amp; dialog.isShowing()) {\ndialog.dismiss();\n}\nToast.makeText(this, “权限获取成功”, Toast.LENGTH_SHORT).show();\n}\n}\n}\n}\n}” data-snippet-id=”ext.3b91c13461c024f44500761dd25cf840″ data-snippet-saved=”false” data-codota-status=”done”\u0026gt; 1 package com.dragon.android.permissionrequest;\nimport android.Manifest;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.provider.Settings;\nimport android.support.annotation.NonNull;\nimport android.support.v4.app.ActivityCompat;\nimport android.support.v4.content.ContextCompat;\nimport android.support.v7.app.AlertDialog;\nimport android.support.v7.app.AppCompatActivity;\nimport android.widget.Toast;\npublic class MainActivity extends AppCompatActivity {\n// 要申请的权限\nprivate String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};\nprivate AlertDialog dialog;\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\nsuper.onCreate(savedInstanceState);\nsetContentView(R.layout.activity_main);\n// 版本判断。当手机系统大于 23 时，才有必要去判断权限是否获取\nif (Build.VERSION.SDK_INT \u0026gt;= Build.VERSION_CODES.M) {\n// 检查该权限是否已经获取\nint i = ContextCompat.checkSelfPermission(this, permissions[0]);\n// 权限是否已经 授权 GRANTED—授权 DINIED—拒绝\nif (i != PackageManager.PERMISSION_GRANTED) {\n// 如果没有授予该权限，就去提示用户请求\nshowDialogTipUserRequestPermission();\n}\n}\n}\n// 提示用户该请求权限的弹出框\nprivate void showDialogTipUserRequestPermission() {\nnew AlertDialog.Builder(this)\n.setTitle(“存储权限不可用”)\n.setMessage(“由于支付宝需要获取存储空间，为你存储个人信息；\\n否则，您将无法正常使用支付宝”)\n.setPositiveButton(“立即开启”, new DialogInterface.OnClickListener() {\n@Override\npublic void onClick(DialogInterface dialog, int which) {\nstartRequestPermission();\n}\n})\n.setNegativeButton(“取消”, new DialogInterface.OnClickListener() {\n@Override\npublic void onClick(DialogInterface dialog, int which) {\nfinish();\n}\n}).setCancelable(false).show();\n}\n// 开始提交请求权限\nprivate void startRequestPermission() {\nActivityCompat.requestPermissions(this, permissions, 321);\n}\n// 用户权限 申请 的回调方法\n@Override\npublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\nsuper.onRequestPermissionsResult(requestCode, permissions, grantResults);\nif (requestCode == 321) {\nif (Build.VERSION.SDK_INT \u0026gt;= Build.VERSION_CODES.M) {\nif (grantResults[0] != PackageManager.PERMISSION_GRANTED) {\n// 判断用户是否 点击了不再提醒。(检测该权限是否还可以申请)\nboolean b = shouldShowRequestPermissionRationale(permissions[0]);\nif (!b) {\n// 用户还是想用我的 APP 的\n// 提示用户去应用设置界面手动开启权限\nshowDialogTipUserGoToAppSettting();\n} else\nfinish();\n} else {\nToast.makeText(this, “权限获取成功”, Toast.LENGTH_SHORT).show();\n}\n}\n}\n}\n// 提示用户去应用设置界面手动开启权限\nprivate void showDialogTipUserGoToAppSettting() {\ndialog = new AlertDialog.Builder(this)\n.setTitle(“存储权限不可用”)\n.setMessage(“请在-应用设置-权限-中，允许支付宝使用存储权限来保存用户数据”)\n.setPositiveButton(“立即开启”, new DialogInterface.OnClickListener() {\n@Override\npublic void onClick(DialogInterface dialog, int which) {\n// 跳转到应用设置界面\ngoToAppSetting();\n}\n})\n.setNegativeButton(“取消”, new DialogInterface.OnClickListener() {\n@Override\npublic void onClick(DialogInterface dialog, int which) {\nfinish();\n}\n}).setCancelable(false).show();\n}\n// 跳转到当前应用的设置界面\nprivate void goToAppSetting() {\nIntent intent = new Intent();\nintent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);\nUri uri = Uri.fromParts(“package”, getPackageName(), null);\nintent.setData(uri);\nstartActivityForResult(intent, 123);\n}\n//\n@Override\nprotected void onActivityResult(int requestCode, int resultCode, Intent data) {\nsuper.onActivityResult(requestCode, resultCode, data);\nif (requestCode == 123) {\nif (android.os.Build.VERSION.SDK_INT \u0026gt;= Build.VERSION_CODES.M) {\n// 检查该权限是否已经获取\nint i = ContextCompat.checkSelfPermission(this, permissions[0]);\n// 权限是否已经 授权 GRANTED—授权 DINIED—拒绝\nif (i != PackageManager.PERMISSION_GRANTED) {\n// 提示用户应该去应用设置界面手动开启权限\nshowDialogTipUserGoToAppSettting();\n} else {\nif (dialog != null \u0026amp;\u0026amp; dialog.isShowing()) {\ndialog.dismiss();\n}\nToast.makeText(this, “权限获取成功”, Toast.LENGTH_SHORT).show();\n}\n}\n}\n}\n}\n——————————————————————————————————\n更多参考：http://www.cnblogs.com/dubo-/p/6018262.html\n","permalink":"https://blog.zdltech.com/posts/api-23%E4%B9%8B%E6%9D%83%E9%99%90/","summary":"\u003cp\u003e这里以单个存储权限为例：\u003c/p\u003e\n\u003cp\u003e· 在 Manifest 中添加访问权限：（只需设置可写，因为可写必定可读）\u003cbr\u003e\n\u003cuses-permission android:name=\"android.permission.WRITE\\_EXTERNAL\\_STORAGE\"/\u003e\u003c/p\u003e\n\u003cp\u003e动态申请权限的过程：\u003cbr\u003e\n= Build.VERSION_CODES.M) {\u003c/p\u003e\n\u003cp\u003e// 检查该权限是否已经获取\u003cbr\u003e\nint i = ContextCompat.checkSelfPermission(this, permissions[0]);\u003cbr\u003e\n// 权限是否已经 授权 GRANTED—授权 DINIED—拒绝\u003cbr\u003e\nif (i != PackageManager.PERMISSION_GRANTED) {\u003cbr\u003e\n// 如果没有授予该权限，就去提示用户请求\u003cbr\u003e\nshowDialogTipUserRequestPermission();\u003cbr\u003e\n}\u003cbr\u003e\n}\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e// 提示用户该请求权限的弹出框\u003cbr\u003e\nprivate void showDialogTipUserRequestPermission() {\u003c/p\u003e\n\u003cp\u003enew AlertDialog.Builder(this)\u003cbr\u003e\n.setTitle(“存储权限不可用”)\u003cbr\u003e\n.setMessage(“由于支付宝需要获取存储空间，为你存储个人信息；\\n否则，您将无法正常使用支付宝”)\u003cbr\u003e\n.setPositiveButton(“立即开启”, new DialogInterface.OnClickListener() {\u003cbr\u003e\n@Override\u003cbr\u003e\npublic void onClick(DialogInterface dialog, int which) {\u003cbr\u003e\nstartRequestPermission();\u003cbr\u003e\n}\u003cbr\u003e\n})\u003cbr\u003e\n.setNegativeButton(“取消”, new DialogInterface.OnClickListener() {\u003cbr\u003e\n@Override\u003cbr\u003e\npublic void onClick(DialogInterface dialog, int which) {\u003cbr\u003e\nfinish();\u003cbr\u003e\n}\u003cbr\u003e\n}).setCancelable(false).show();\u003cbr\u003e\n}\u003c/p\u003e","title":"Android 6.0 – 动态权限管理的解决方案"},{"content":"View view = getWindow().getDecorView().findViewById(R.id.activity_main);\nif (view == null) return;\nViewParent viewParent = view.getParent();\nif (viewParent instanceof FrameLayout) {\nfinal FrameLayout frameParent = (FrameLayout) viewParent;//整个父布局\nfinal LinearLayout linearLayout = new LinearLayout(this);//新建一个LinearLayout\nlinearLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));\nlinearLayout.setOrientation(LinearLayout.VERTICAL);\nlinearLayout.setBackgroundResource(#88000000);//背景设置灰色透明\nlinearLayout.setGravity(Gravity.CENTER_HORIZONTAL);\nlinearLayout.setOnClickListener(new View.OnClickListener() {\n@Override\npublic void onClick(View v) {\nframeParent.removeView(linearLayout);\n}\n});\nRect rect = new Rect();\nPoint point = new Point();\nnearby.getGlobalVisibleRect(rect, point);//获得nearby这个控件的宽高以及XY坐标 nearby这个控件对应就是需要高亮显示的地方\nImageView topGuideview = new ImageView(this);\ntopGuideview.setLayoutParams(new ViewGroup.LayoutParams(rect.width(), rect.height())); topGuideview.setBackgroundResource(R.drawable.iv_topguide);\nRect rt = new Rect();\ngetWindow().getDecorView().getWindowVisibleDisplayFrame(rt);\ntopGuideview.setY(point.y – rt.top);//rt.top是手机状态栏的高度\nImageView bottomGuideview = new ImageView(this);\nbottomGuideview.setLayoutParams(new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));\nbottomGuideview.setBackgroundResource(R.drawable.iv_bottomguide);\nbottomGuideview.setY(point.y + topGuideview.getHeight());\nlinearLayout.addView(topGuideview);\nlinearLayout.addView(bottomGuideview);\nframeParent.addView(linearLayout);\n}\n","permalink":"https://blog.zdltech.com/posts/android-%E4%B8%ADgitwindow%E5%8F%AF%E4%BB%A5%E5%81%9A%E7%9A%84%E4%BA%8B%E6%83%85/","summary":"\u003cp\u003eView view = getWindow().getDecorView().findViewById(R.id.activity_main);\u003cbr\u003e\nif (view == null) return;\u003c/p\u003e\n\u003cp\u003eViewParent viewParent = view.getParent();\u003cbr\u003e\nif (viewParent instanceof FrameLayout) {\u003cbr\u003e\nfinal FrameLayout frameParent = (FrameLayout) viewParent;//整个父布局\u003c/p\u003e\n\u003cp\u003efinal LinearLayout linearLayout = new LinearLayout(this);//新建一个LinearLayout\u003cbr\u003e\nlinearLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));\u003cbr\u003e\nlinearLayout.setOrientation(LinearLayout.VERTICAL);\u003cbr\u003e\nlinearLayout.setBackgroundResource(#88000000);//背景设置灰色透明\u003cbr\u003e\nlinearLayout.setGravity(Gravity.CENTER_HORIZONTAL);\u003cbr\u003e\nlinearLayout.setOnClickListener(new View.OnClickListener() {\u003cbr\u003e\n@Override\u003cbr\u003e\npublic void onClick(View v) {\u003cbr\u003e\nframeParent.removeView(linearLayout);\u003cbr\u003e\n}\u003cbr\u003e\n});\u003c/p\u003e\n\u003cp\u003eRect rect = new Rect();\u003cbr\u003e\nPoint point = new Point();\u003cbr\u003e\nnearby.getGlobalVisibleRect(rect, point);//获得nearby这个控件的宽高以及XY坐标 nearby这个控件对应就是需要高亮显示的地方\u003c/p\u003e\n\u003cp\u003eImageView topGuideview = new ImageView(this);\u003cbr\u003e\ntopGuideview.setLayoutParams(new ViewGroup.LayoutParams(rect.width(), rect.height())); topGuideview.setBackgroundResource(R.drawable.iv_topguide);\u003c/p\u003e","title":"Android 中gitWindow可以做的事情"},{"content":"由于使用总公司的SVN，有些新同事和其他组没有SVN，项目开发中没有版本控制，为了解决这个问题，我给公司搭建了内网git服务器进行版本控制，现在记录下安装配置过程\n第一步：登录官网点击下载，选择适合的操作系统\n例如centos https://about.gitlab.com/downloads/#centos7\n第二步：由于网络问题，我选择下载安装\n下载网址https://packages.gitlab.com/gitlab/gitlab-ce\n运行命令 rpm 安装\nrpm -i gitlab-ce-XXX.rpm\n第三步：配置请求地址和端口\n进入/etc/gitlab/gitlab.rb 下面修改\n1、external_url 表示请求的地址例如external_url ‘http://192.168.0.239’\n2、nginx[‘listen_port’] 表示端口 例如nginx[‘listen_port’] = 8999\n注意：要是有#号别忘记删除，修改gitlab.rb文件需要重新编辑和配置\n第四步：编译和配置（配置并启动gitlab）\nsudo gitlab-ctl reconfigure\n第五步：在浏览器输入地址，第一次是修改密码（对用的账号是root），根据提示修改密码\n第六步：登录OK\n第七步：gitlab仓库地址和备份\n1、gitlab默认参考地址：/var/opt/gitlab/git-data/repositories\n修改/etc/gitlab/gitlab.rb-\u0026gt;git_data_dirs(别忘记#去掉)\n2、备份命令：gitlab-rakegitlab:backup:create，\n默然的备份目录为： /var/opt/gitlab/backups\n备份目录的修改\nvi /etc/gitlab/gitlab.rb\ngitlab_rails[‘backup_path’] =’/mnt/gitlab_backups’\n3、恢复备份，需要先停止服务，恢复完成在启动服务\ngitlab-rake gitlab:backup:restore BACKUP=1458213020\nBACKUP后面跟的是备份文件的时间戳，\n比如恢复备份文件 1458213020_gitlab_backup.tar\n第八步：其他\n1、停服务\ngitlab-ctl stop unicorn\ngitlab-ctl stop sidekiq\n2、回复完启动服务\ngitlab-ctl start\nSSH key生成\n详细请参考：\nhttp://blog.csdn.net/lsyz0021/article/details/52064829\nhttp://blog.csdn.net/tanzhengyu/article/details/51064380\n安装git，从程序目录打开 “Git Bash”\n键入命令：ssh-keygen -t rsa -C “email@email.com”\n“email@email.com”是github账号\n提醒你输入key的名称，输入如id_rsa\n在C:\\Documents and Settings\\Administrator\\下产生两个文件：id_rsa和id_rsa.pub(mac 在~/.ssh目录下)\n把4中生成的密钥文件复制到C:\\Documents and Settings\\Administrator.ssh\\ 目 录下。\n用记事本打开id_rsa.pub文件，复制内容，在git的网站上到ssh密钥管理页面，添加新公钥，随便取个名字，内容粘贴刚才复制的内容。\n^_^ OK了\n需要注意步骤2中产生的密钥文件在当前用户的根目录，必须把这两个文件放到当前用户目录的“.ssh”目录下才能生效。\n在windows中只能在命令行下输入创建”.”开头的文件夹。命令为 mkdir .ssh\n关注公众号获取更多内容和反馈沟通\nPaste_Image.png -w200\n欢迎交流QQ:411437734\n转载请注明出处：http://www.jianshu.com/p/deef9c9284ff\n个人博客 个人博客\n","permalink":"https://blog.zdltech.com/posts/getlab%E5%AE%89%E8%A3%85%E4%BD%BF%E7%94%A8/","summary":"\u003cp\u003e由于使用总公司的SVN，有些新同事和其他组没有SVN，项目开发中没有版本控制，为了解决这个问题，我给公司搭建了内网git服务器进行版本控制，现在记录下安装配置过程\u003cbr\u003e\n第一步：登录官网点击下载，选择适合的操作系统\u003c/p\u003e\n\u003cp\u003e例如centos \u003ca href=\"https://about.gitlab.com/downloads/#centos7\"\u003ehttps://about.gitlab.com/downloads/#centos7\u003c/a\u003e\u003cbr\u003e\n第二步：由于网络问题，我选择下载安装\u003c/p\u003e\n\u003cp\u003e下载网址https://packages.gitlab.com/gitlab/gitlab-ce\u003cbr\u003e\n运行命令 rpm 安装\u003cbr\u003e\nrpm -i gitlab-ce-XXX.rpm\u003cbr\u003e\n第三步：配置请求地址和端口\u003c/p\u003e\n\u003cp\u003e进入/etc/gitlab/gitlab.rb 下面修改\u003cbr\u003e\n1、external_url 表示请求的地址例如external_url ‘http://192.168.0.239’\u003cbr\u003e\n2、nginx[‘listen_port’] 表示端口 例如nginx[‘listen_port’] = 8999\u003cbr\u003e\n注意：要是有#号别忘记删除，修改gitlab.rb文件需要重新编辑和配置\u003cbr\u003e\n第四步：编译和配置（配置并启动gitlab）\u003c/p\u003e\n\u003cp\u003esudo gitlab-ctl reconfigure\u003cbr\u003e\n第五步：在浏览器输入地址，第一次是修改密码（对用的账号是root），根据提示修改密码\u003c/p\u003e\n\u003cp\u003e第六步：登录OK\u003c/p\u003e\n\u003cp\u003e第七步：gitlab仓库地址和备份\u003c/p\u003e\n\u003cp\u003e1、gitlab默认参考地址：/var/opt/gitlab/git-data/repositories\u003c/p\u003e\n\u003cp\u003e修改/etc/gitlab/gitlab.rb-\u0026gt;git_data_dirs(别忘记#去掉)\u003c/p\u003e\n\u003cp\u003e2、备份命令：gitlab-rakegitlab:backup:create，\u003cbr\u003e\n默然的备份目录为： /var/opt/gitlab/backups\u003cbr\u003e\n备份目录的修改\u003cbr\u003e\nvi /etc/gitlab/gitlab.rb\u003cbr\u003e\ngitlab_rails[‘backup_path’] =’/mnt/gitlab_backups’\u003c/p\u003e\n\u003cp\u003e3、恢复备份，需要先停止服务，恢复完成在启动服务\u003cbr\u003e\ngitlab-rake gitlab:backup:restore BACKUP=1458213020\u003cbr\u003e\nBACKUP后面跟的是备份文件的时间戳，\u003cbr\u003e\n比如恢复备份文件 1458213020_gitlab_backup.tar\u003cbr\u003e\n第八步：其他\u003c/p\u003e\n\u003cp\u003e1、停服务\u003cbr\u003e\ngitlab-ctl stop unicorn\u003cbr\u003e\ngitlab-ctl stop sidekiq\u003cbr\u003e\n2、回复完启动服务\u003cbr\u003e\ngitlab-ctl start\u003cbr\u003e\nSSH key生成\u003c/p\u003e\n\u003cp\u003e详细请参考：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/lsyz0021/article/details/52064829\"\u003ehttp://blog.csdn.net/lsyz0021/article/details/52064829\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"http://blog.csdn.net/tanzhengyu/article/details/51064380\"\u003ehttp://blog.csdn.net/tanzhengyu/article/details/51064380\u003c/a\u003e\u003cbr\u003e\n安装git，从程序目录打开 “Git Bash”\u003cbr\u003e\n键入命令：ssh-keygen -t rsa -C “email@email.com”\u003cbr\u003e\n“email@email.com”是github账号\u003cbr\u003e\n提醒你输入key的名称，输入如id_rsa\u003cbr\u003e\n在C:\\Documents and Settings\\Administrator\\下产生两个文件：id_rsa和id_rsa.pub(mac 在~/.ssh目录下)\u003cbr\u003e\n把4中生成的密钥文件复制到C:\\Documents and Settings\\Administrator.ssh\\ 目 录下。\u003cbr\u003e\n用记事本打开id_rsa.pub文件，复制内容，在git的网站上到ssh密钥管理页面，添加新公钥，随便取个名字，内容粘贴刚才复制的内容。\u003cbr\u003e\n^_^ OK了\u003cbr\u003e\n需要注意步骤2中产生的密钥文件在当前用户的根目录，必须把这两个文件放到当前用户目录的“.ssh”目录下才能生效。\u003cbr\u003e\n在windows中只能在命令行下输入创建”.”开头的文件夹。命令为 mkdir .ssh\u003cbr\u003e\n关注公众号获取更多内容和反馈沟通\u003c/p\u003e","title":"GetLab安装使用"},{"content":"默认情况下，Nginx一个IP地址仅支持一个SSL证书，需要多个IP地址才能配置多个SSL证书，在公网IP地址有限的情况下，可以使用TLS Server Name Indication extension(SNI, RFC 6066)，它允许浏览器在SSL握手的时候发送请求的server name，也就是 Host，这样 Nginx 就能找到对应server 的SSL配置。\n配置步骤如下：\n1、检查Nginx是否支持TLS\nnginx -V … TLS SNI support enabled … nginx -V\n…\nTLS SNI support enabled\n…\n2、如果出现TLS SNI support disable，就得升级openssl版本，并且重新编译nginx。\n具体步骤如下：\n首先下载openssl（建议下载1.0.1h版本）\n#wget http://www.openssl.org/source/openssl-1.0.1h.tar.gz\n下载Nginx\n#wget http://nginx.org/download/nginx-1.9.9.tar.gz\n解压openssl\n#tar -zxvf openssl-1.0.1h.tar.gz\n解压nginx，并编译\n#tar -zxvf nginx-1.9.9.tar.gz\n#cd nginx-1.9.9\n#make \u0026amp;\u0026amp; make install\n#检查Nginx版本信息\n#/usr/local/nginx/sbin/nginx -V\nnginx version: nginx/1.9.9\nbuilt by gcc 4.1.2 20080704 (Red Hat 4.1.2-55)\nbuilt with OpenSSL 1.0.1h 5 Jun 2014\nTLS SNI support enabled\n配置Vhost中的域名证书\nserver\n{\n#########\nlisten 80;\nlisten 443 ssl;\n#listen [::]:80;\nserver_name we.baohua.me;\nroot /home/wwwroot/we.baohua.me;\nssl on;\nssl_certificate_key /home/wwwroot/cert/we.baohua.me.key;\nssl_certificate /home/wwwroot/cert/we.baohua.me.crt;\nssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;\nssl_ciphers HIGH:!aNULL:!MD5;\n###############\n}\n然后，重启Nginx即可。\n参考1：https://baohua.me/middleware/nginx/nginx-single-ip-address-to-configure-multiple-ssl-certificates/\n参考2：http://blog.chinaunix.net/uid-20639775-id-3213595.html\n参考3：http://blog.csdn.net/cccallen/article/details/6672451\n","permalink":"https://blog.zdltech.com/posts/nginx%E5%8D%95ip%E5%9C%B0%E5%9D%80%E9%85%8D%E7%BD%AE%E5%A4%9A%E4%B8%AAssl%E8%AF%81%E4%B9%A6/","summary":"\u003cp\u003e默认情况下，Nginx一个IP地址仅支持一个SSL证书，需要多个IP地址才能配置多个SSL证书，在公网IP地址有限的情况下，可以使用TLS Server Name Indication extension(SNI, RFC 6066)，它允许浏览器在SSL握手的时候发送请求的server name，也就是 Host，这样 Nginx 就能找到对应server 的SSL配置。\u003c/p\u003e\n\u003cp\u003e配置步骤如下：\u003c/p\u003e\n\u003cp\u003e1、检查Nginx是否支持TLS\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"katex math inline\"\u003enginx -V\n…\nTLS SNI support enabled\n…\u003c/span\u003e nginx -V\u003cbr\u003e\n…\u003cbr\u003e\nTLS SNI support enabled\u003cbr\u003e\n…\u003cbr\u003e\n2、如果出现TLS SNI support disable，就得升级openssl版本，并且重新编译nginx。\u003c/p\u003e\n\u003cp\u003e具体步骤如下：\u003cbr\u003e\n首先下载openssl（建议下载1.0.1h版本）\u003c/p\u003e\n\u003cp\u003e#wget \u003ca href=\"http://www.openssl.org/source/openssl-1.0.1h.tar.gz\"\u003ehttp://www.openssl.org/source/openssl-1.0.1h.tar.gz\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e下载Nginx\u003c/p\u003e\n\u003cp\u003e#wget \u003ca href=\"http://nginx.org/download/nginx-1.9.9.tar.gz\"\u003ehttp://nginx.org/download/nginx-1.9.9.tar.gz\u003c/a\u003e\u003cbr\u003e\n解压openssl\u003c/p\u003e\n\u003cp\u003e#tar -zxvf openssl-1.0.1h.tar.gz\u003cbr\u003e\n解压nginx，并编译\u003c/p\u003e\n\u003cp\u003e#tar -zxvf nginx-1.9.9.tar.gz\u003cbr\u003e\n#cd nginx-1.9.9\u003cbr\u003e\n#make \u0026amp;\u0026amp; make install\u003cbr\u003e\n#检查Nginx版本信息\u003c/p\u003e\n\u003cp\u003e#/usr/local/nginx/sbin/nginx -V\u003c/p\u003e\n\u003cp\u003enginx version: nginx/1.9.9\u003cbr\u003e\nbuilt by gcc 4.1.2 20080704 (Red Hat 4.1.2-55)\u003cbr\u003e\nbuilt with OpenSSL 1.0.1h 5 Jun 2014\u003cbr\u003e\nTLS SNI support enabled\u003c/p\u003e","title":"Nginx单IP地址配置多个SSL证书"},{"content":"Java Socket现实简单的HTTP服务\nhttp://jiangzhengjun.iteye.com/blog/512380\nJava socket 访问网页\nhttp://blog.csdn.net/yilip/article/details/45195713\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.net.Socket;\npublic class WebpageSocket {\nprivate static int port = 80;\nprivate static String hostname = “www.iteye.com”;\npublic static void main(String[] args) throws Exception{\nSocket socket = new Socket(hostname, port);\nBufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), “utf-8”));\nwriter.write(“GET ” + “/ask” + ” HTTP/1.0\\r\\n”);\nwriter.write(“HOST:” + hostname + “\\r\\n”);\nwriter.write(“Accept:*/*\\r\\n”);\nwriter.write(“\\r\\n”);\nwriter.flush();\nBufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), “utf-8”));\nString line = null;\nwhile ((line = reader.readLine()) != null) {\nSystem.out.println(line);\n}\nreader.close();\nwriter.close();\nsocket.close();\n}\n}\n第二种\npublic static void main(String[] args) throws IOException {\n//想要抓取的网页主机名\n//域名www.baidu.com,旗下有好多主机,例如tieba.baidu.com,map.baidu.com\nString host = “map.baidu.com”;\n//根据主机名获取ip地址\nInetAddress ip = InetAddress.getByName(host);\n//建立连接\nSocket s = new Socket(ip,80);\n//向服务器端写入http协议请求\nPrintWriter pw = new PrintWriter(s.getOutputStream());\n// “/”请求根页面\npw.println(“GET / HTTP/1.1”);\npw.println(“Host: “+host);\npw.println(“Content-Type: text/html”);\npw.println();\npw.flush();\n//将获取到的页面输出在控制台\nBufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));\nString str = “”;\nwhile((str=br.readLine())!=null){\nSystem.out.println(str);\n}\nbr.close();\npw.close();\ns.close();\n}\n第三种\nimport Java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.net.InetAddress;\nimport java.net.Socket;\n/**\nJava 通过 Socket 的形式抓取网页内容 创建日期：2011-1-20\n@author 何明旺\n*/\npublic class FetchHtmlBySocket {\npublic static void main(String[] args) {\nString html = new FetchHtmlBySocket().htmlContent(new HtmlPage(“blog.csdn.net”, “/hemingwang0902”));\nSystem.out.println(html);\n} /**\n抓取网页原代码 创建日期：2011-1-20\n@param hp @return 指定网页的源代码，如果抓取失败，则返回一个长度为 0 的空字符串 @author 何明旺\n*/\npublic String htmlContent(HtmlPage hp){\nStringBuffer html = new StringBuffer();\nSocket socket = null;\nBufferedWriter writer = null;\nBufferedReader reader = null;\ntry {\n// 建立一个Socket\nsocket = new Socket(InetAddress.getByName(hp.getServer()), hp.getPort()); StringBuffer command = new StringBuffer()\n.append(“GET ” + hp.getPath() + ” HTTP/1.0/r/n”)\n.append(“HOST:” + hp.getServer() + “/r/n”)\n.append(“/r/n”);\n// 发送命令\nwriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), hp.getCharset()));\nwriter.write(command.toString());\nwriter.flush();\n// 接收返回的结果\nreader = new BufferedReader(new InputStreamReader(socket.getInputStream(), hp.getCharset()));\nString line;\nwhile ((line = reader.readLine()) != null) {\nhtml.append(line).append(“/r/n”);\n}\n} catch (Exception e) {\ne.printStackTrace();\n} finally {\ntry {\nif (reader != null)\nreader.close();\nif (writer != null)\nwriter.close();\nif (socket != null)\nsocket.close();\n} catch (IOException e) {\ne.printStackTrace();\n}\n}\nreturn html.toString();\n}\nstatic class HtmlPage {\nprivate String server;\nprivate int port = 80;\nprivate String path;\nprivate String charset = “UTF-8”;\npublic HtmlPage() {\nsuper();\n}\npublic HtmlPage(String server, String path) {\nsuper();\nthis.server = server;\nthis.path = path;\n}\npublic HtmlPage(String server, String path, String charset) {\nsuper();\nthis.server = server;\nthis.path = path;\nthis.charset = charset;\n}\npublic HtmlPage(String server, int port, String path, String charset) {\nsuper();\nthis.server = server;\nthis.port = port;\nthis.path = path;\nthis.charset = charset;\n}\npublic String getServer() {\nreturn server;\n}\npublic void setServer(String server) {\nthis.server = server;\n}\npublic int getPort() {\nreturn port;\n}\npublic void setPort(int port) {\nthis.port = port;\n}\npublic String getPath() {\nreturn path;\n}\npublic void setPath(String path) {\nthis.path = path;\n}\npublic String getCharset() {\nreturn charset;\n}\npublic void setCharset(String charset) {\nthis.charset = charset;\n}\n}\n}\n","permalink":"https://blog.zdltech.com/posts/socket%E8%AF%B7%E6%B1%82%E7%BD%91%E9%A1%B5/","summary":"\u003cp\u003eJava Socket现实简单的HTTP服务\u003cbr\u003e\n\u003ca href=\"http://jiangzhengjun.iteye.com/blog/512380\"\u003ehttp://jiangzhengjun.iteye.com/blog/512380\u003c/a\u003e\u003cbr\u003e\nJava socket 访问网页\u003cbr\u003e\n\u003ca href=\"http://blog.csdn.net/yilip/article/details/45195713\"\u003ehttp://blog.csdn.net/yilip/article/details/45195713\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eimport java.io.BufferedReader;\u003cbr\u003e\nimport java.io.BufferedWriter;\u003cbr\u003e\nimport java.io.InputStreamReader;\u003cbr\u003e\nimport java.io.OutputStreamWriter;\u003cbr\u003e\nimport java.net.Socket;\u003c/p\u003e\n\u003cp\u003epublic class WebpageSocket {\u003cbr\u003e\nprivate static int port = 80;\u003cbr\u003e\nprivate static String hostname = “www.iteye.com”;\u003cbr\u003e\npublic static void main(String[] args) throws Exception{\u003cbr\u003e\nSocket socket = new Socket(hostname, port);\u003cbr\u003e\nBufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), “utf-8”));\u003cbr\u003e\nwriter.write(“GET ” + “/ask” + ” HTTP/1.0\\r\\n”);\u003cbr\u003e\nwriter.write(“HOST:” + hostname + “\\r\\n”);\u003cbr\u003e\nwriter.write(“Accept:*/*\\r\\n”);\u003cbr\u003e\nwriter.write(“\\r\\n”);\u003cbr\u003e\nwriter.flush();\u003c/p\u003e\n\u003cp\u003eBufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), “utf-8”));\u003cbr\u003e\nString line = null;\u003cbr\u003e\nwhile ((line = reader.readLine()) != null) {\u003cbr\u003e\nSystem.out.println(line);\u003cbr\u003e\n}\u003cbr\u003e\nreader.close();\u003cbr\u003e\nwriter.close();\u003cbr\u003e\nsocket.close();\u003cbr\u003e\n}\u003cbr\u003e\n}\u003c/p\u003e","title":"Socket请求网页"},{"content":"//设置缩放级别\naMap.moveCamera(CameraUpdateFactory.zoomTo(17));\n//将地图移动到定位点\naMap.moveCamera(CameraUpdateFactory.changeLatLng(new LatLng(amapLocation.getLatitude(), amapLocation.getLongitude())));\n//点击定位按钮 能够将地图的中心移动到定位点\nmListener.onLocationChanged(amapLocation);\n//添加图钉\naMap.addMarker(getMarkerOptions(amapLocation));\n//获取定位信息\nStringBuffer buffer = new StringBuffer();\nbuffer.append(amapLocation.getCountry() + “” + amapLocation.getProvince() + “” + amapLocation.getCity() + “” + amapLocation.getProvince() + “” + amapLocation.getDistrict() + “” + amapLocation.getStreet() + “” + amapLocation.getStreetNum());\nToast.makeText(getApplicationContext(), buffer.toString(), Toast.LENGTH_LONG).show();\nisFirstLoc = false;\n//定位的小图标 默认是蓝点 这里自定义一团火，其实就是一张图片\nMyLocationStyle myLocationStyle = new MyLocationStyle();\nmyLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromResource(R.mipmap.firetwo));\nmyLocationStyle.radiusFillColor(android.R.color.transparent);\nmyLocationStyle.strokeColor(android.R.color.transparent);\naMap.setMyLocationStyle(myLocationStyle);\n//定位\nprivate void initLoc() {\n//初始化定位\nmLocationClient = new AMapLocationClient(getApplicationContext());\n//设置定位回调监听\nmLocationClient.setLocationListener(this);\n//初始化定位参数\nmLocationOption = new AMapLocationClientOption();\n//设置定位模式为高精度模式，Battery_Saving为低功耗模式，Device_Sensors是仅设备模式\nmLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);\n//设置是否返回地址信息（默认返回地址信息）\nmLocationOption.setNeedAddress(true);\n//设置是否只定位一次,默认为false\nmLocationOption.setOnceLocation(false);\n//设置是否强制刷新WIFI，默认为强制刷新\nmLocationOption.setWifiActiveScan(true);\n//设置是否允许模拟位置,默认为false，不允许模拟位置\nmLocationOption.setMockEnable(false);\n//设置定位间隔,单位毫秒,默认为2000ms\nmLocationOption.setInterval(2000);\n//给定位客户端对象设置定位参数\nmLocationClient.setLocationOption(mLocationOption);\n//启动定位\nmLocationClient.startLocation();\n}\npublic void onLocationChanged(AMapLocation aMapLocation) {\nif (aMapLocation != null\n\u0026amp;\u0026amp; aMapLocation.getAMapException().getErrorCode() == 0) {\nif (listener != null) {\nlistener.onLocationChanged(aMapLocation);// 显示系统小蓝点\n}\nmyLocation = new LatLng(aMapLocation.getLatitude(),\naMapLocation.getLongitude());\nfixedMarker();\n}\n}\nprivate void fixedMarker() {\nMarkerOptions centerMarkerOption = new MarkerOptions().position(\nmyLocation).icon(chooseDescripter);\ncenterMarker = aMap.addMarker(centerMarkerOption);\ncenterMarker.setPositionByPixels(mapView.getWidth() / 2,\nmapView.getHeight() / 2);\nhandler.postDelayed(new Runnable() {\n@Override\npublic void run() {\nCameraUpdate update = CameraUpdateFactory.zoomTo(17f);\naMap.animateCamera(update, 1000, new AMap.CancelableCallback() {\n@Override\npublic void onFinish() {\naMap.setOnCameraChangeListener(MarkerFixedAty.this);\n}\n@Override\npublic void onCancel() {\n}\n});\n}\n}, 1000);\n}\n/监听定位和定位变化\npublic class MainActivity extends AppCompatActivity implements LocationSource, AMapLocationListener {\n//显示地图需要的变量\nprivate MapView mapView;//地图控件\nprivate AMap aMap;//地图对象\n//定位需要的声明\nprivate AMapLocationClient mLocationClient = null;//定位发起端\nprivate AMapLocationClientOption mLocationOption = null;//定位参数\nprivate OnLocationChangedListener mListener = null;//定位监听器\n//标识，用于判断是否只显示一次定位信息和用户重新定位\nprivate boolean isFirstLoc = true;\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\nsuper.onCreate(savedInstanceState);\nsetContentView(R.layout.activity_main);\n//显示地图\nmapView = (MapView) findViewById(R.id.map);\n//必须要写\nmapView.onCreate(savedInstanceState);\n//获取地图对象\naMap = mapView.getMap();\n//设置显示定位按钮 并且可以点击\nUiSettings settings = aMap.getUiSettings();\n//设置定位监听\naMap.setLocationSource(this);\n// 是否显示定位按钮\nsettings.setMyLocationButtonEnabled(true);\n// 是否可触发定位并显示定位层\naMap.setMyLocationEnabled(true);\n//定位的小图标 默认是蓝点 这里自定义一团火，其实就是一张图片\nMyLocationStyle myLocationStyle = new MyLocationStyle();\nmyLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromResource(R.mipmap.firetwo));\nmyLocationStyle.radiusFillColor(android.R.color.transparent);\nmyLocationStyle.strokeColor(android.R.color.transparent);\naMap.setMyLocationStyle(myLocationStyle);\n//开始定位\ninitLoc();\n}\n//定位\nprivate void initLoc() {\n//初始化定位\nmLocationClient = new AMapLocationClient(getApplicationContext());\n//设置定位回调监听\nmLocationClient.setLocationListener(this);\n//初始化定位参数\nmLocationOption = new AMapLocationClientOption();\n//设置定位模式为高精度模式，Battery_Saving为低功耗模式，Device_Sensors是仅设备模式\nmLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);\n//设置是否返回地址信息（默认返回地址信息）\nmLocationOption.setNeedAddress(true);\n//设置是否只定位一次,默认为false\nmLocationOption.setOnceLocation(false);\n//设置是否强制刷新WIFI，默认为强制刷新\nmLocationOption.setWifiActiveScan(true);\n//设置是否允许模拟位置,默认为false，不允许模拟位置\nmLocationOption.setMockEnable(false);\n//设置定位间隔,单位毫秒,默认为2000ms\nmLocationOption.setInterval(2000);\n//给定位客户端对象设置定位参数\nmLocationClient.setLocationOption(mLocationOption);\n//启动定位\nmLocationClient.startLocation();\n}\n//定位回调函数\n@Override\npublic void onLocationChanged(AMapLocation amapLocation) {\nif (amapLocation != null) {\nif (amapLocation.getErrorCode() == 0) {\n//定位成功回调信息，设置相关消息\namapLocation.getLocationType();//获取当前定位结果来源，如网络定位结果，详见官方定位类型表\namapLocation.getLatitude();//获取纬度\namapLocation.getLongitude();//获取经度\namapLocation.getAccuracy();//获取精度信息\nSimpleDateFormat df = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);\nDate date = new Date(amapLocation.getTime());\ndf.format(date);//定位时间\namapLocation.getAddress();//地址，如果option中设置isNeedAddress为false，则没有此结果，网络定位结果中会有地址信息，GPS定位不返回地址信息。\namapLocation.getCountry();//国家信息\namapLocation.getProvince();//省信息\namapLocation.getCity();//城市信息\namapLocation.getDistrict();//城区信息\namapLocation.getStreet();//街道信息\namapLocation.getStreetNum();//街道门牌号信息\namapLocation.getCityCode();//城市编码\namapLocation.getAdCode();//地区编码\n// 如果不设置标志位，此时再拖动地图时，它会不断将地图移动到当前的位置\nif (isFirstLoc) {\n//设置缩放级别\naMap.moveCamera(CameraUpdateFactory.zoomTo(17));\n//将地图移动到定位点\naMap.moveCamera(CameraUpdateFactory.changeLatLng(new LatLng(amapLocation.getLatitude(), amapLocation.getLongitude())));\n//点击定位按钮 能够将地图的中心移动到定位点\nmListener.onLocationChanged(amapLocation);\n//添加图钉\naMap.addMarker(getMarkerOptions(amapLocation));\n//获取定位信息\nStringBuffer buffer = new StringBuffer();\nbuffer.append(amapLocation.getCountry() + “” + amapLocation.getProvince() + “” + amapLocation.getCity() + “” + amapLocation.getProvince() + “” + amapLocation.getDistrict() + “” + amapLocation.getStreet() + “” + amapLocation.getStreetNum());\nToast.makeText(getApplicationContext(), buffer.toString(), Toast.LENGTH_LONG).show();\nisFirstLoc = false;\n}\n} else {\n//显示错误信息ErrCode是错误码，errInfo是错误信息，详见错误码表。\nLog.e(“AmapError”, “location Error, ErrCode:”\namapLocation.getErrorCode() + “, errInfo:” amapLocation.getErrorInfo()); Toast.makeText(getApplicationContext(), “定位失败”, Toast.LENGTH_LONG).show();\n}\n}\n}\n//自定义一个图钉，并且设置图标，当我们点击图钉时，显示设置的信息\nprivate MarkerOptions getMarkerOptions(AMapLocation amapLocation) {\n//设置图钉选项\nMarkerOptions options = new MarkerOptions();\n//图标\noptions.icon(BitmapDescriptorFactory.fromResource(R.mipmap.fire));\n//位置\noptions.position(new LatLng(amapLocation.getLatitude(), amapLocation.getLongitude()));\nStringBuffer buffer = new StringBuffer();\nbuffer.append(amapLocation.getCountry() + “” + amapLocation.getProvince() + “” + amapLocation.getCity() + “” + amapLocation.getDistrict() + “” + amapLocation.getStreet() + “” + amapLocation.getStreetNum());\n//标题\noptions.title(buffer.toString());\n//子标题\noptions.snippet(“这里好火”);\n//设置多少帧刷新一次图片资源\noptions.period(60);\nreturn options;\n}\n//激活定位\n@Override\npublic void activate(OnLocationChangedListener listener) {\nmListener = listener;\n}\n//停止定位\n@Override\npublic void deactivate() {\nmListener = null;\n}\n/**\n方法必须重写\n*/\n@Override\nprotected void onResume() {\nsuper.onResume();\nmapView.onResume();\n} /**\n方法必须重写\n*/\n@Override\nprotected void onPause() {\nsuper.onPause();\nmapView.onPause();\n} /**\n方法必须重写\n*/\n@Override\nprotected void onSaveInstanceState(Bundle outState) {\nsuper.onSaveInstanceState(outState);\nmapView.onSaveInstanceState(outState);\n} /**\n方法必须重写\n*/\n@Override\nprotected void onDestroy() {\nsuper.onDestroy();\nmapView.onDestroy();\n}\n} /**\n长按地图进行截屏 @param latLng\n*/\n@Override\npublic void onMapLongClick(LatLng latLng) { // 设置截屏监听接口，截取地图可视区域\n// 需要传入一个 AMap.OnMapLongClickListener 接口的实现者\naMap.getMapScreenShot(this);\n}\n/**\n截屏回调方法 保存截图\n*/ @Override\npublic void onMapScreenShot(Bitmap bitmap) {\nSimpleDateFormat sdf = new SimpleDateFormat(“yyyyMMddHHmmss”);\ntry {\n// 保存在SD卡根目录下，图片为png格式。\nFileOutputStream fos = new FileOutputStream(\nEnvironment.getExternalStorageDirectory() + “/test_”\nsdf.format(new Date()) + “.png”);\nboolean b = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);\ntry {\nfos.flush();\n} catch (IOException e) {\ne.printStackTrace();\n}\ntry {\nfos.close();\n} catch (IOException e) {\ne.printStackTrace();\n}\nif (b) Toast.makeText(MainActivity.this, “截屏成功”, Toast.LENGTH_LONG).show();\nelse {\nToast.makeText(MainActivity.this, “截屏失败”, Toast.LENGTH_LONG).show();\n}\n} catch (FileNotFoundException e) {\ne.printStackTrace();\n}\n}\nfor (int i = 0; i \u0026lt; positionEneityList.size(); i++) {\nif (positionEneityList.get(i).getType().equals(“1”)) {\nView view = View.inflate(getActivity(),R.layout.view_day, null);\nTextView tv_price = (TextView) view.findViewById(R.id.tv_price);\nTextView tv_price_status = (TextView) view.findViewById(R.id.tv_price_status);\ntv_price.setText(positionEneityList.get(i).getPrice());\ntv_price_status.setText(“元/时”);\nBitmap bitmap = CommentActivity.convertViewToBitmap(view);\ndrawMarkerOnMap(new LatLng(Double.parseDouble(positionEneityList.get(i).getLatitude())\n, Double.parseDouble(positionEneityList.get(i).getLongitude())), bitmap, positionEneityList.get(i).getId());\n}\n}\n//view 转bitmap\npublic static Bitmap convertViewToBitmap(View view) {\nview.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));\nview.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());\nview.buildDrawingCache();\nBitmap bitmap = view.getDrawingCache();\nreturn bitmap;\n}\n/**\n在地图上画marker @param point marker坐标点位置（example:LatLng point = new LatLng(39.963175, 116.400244); ） @param markerIcon 图标 @return Marker对象\n*/\nprivate Marker drawMarkerOnMap(LatLng point, Bitmap markerIcon, String id) {\nif (aMap != null \u0026amp;\u0026amp; point != null) {\nMarker marker = aMap.addMarker(new MarkerOptions().anchor(0.5f, 1)\n.position(point)\n.title(id)\n.icon(BitmapDescriptorFactory.fromBitmap(markerIcon))); return marker;\n}\nreturn null;\n}\n之前的博客里说了地图的嵌入和定位，今天就说说在地图上显示一些我们想要的。在地图中有自带的Markers（标记），但是它只显示一个椭圆的图标，一般是不符合我们的需求的，这样就要我们自己来自定义。首先标记有下面一些属性;\n1.position(Required) 在地图上标记位置的经纬度值。参数不能为空。\n2.title 当用户点击标记，在信息窗口上显示的字符串。\n3.snippet 附加文本，显示在标题下方。\n4.draggable 如果您允许用户可以自由移动标记，设置为“ true ”。默认情况下为“ false ”。\n5.visible 设置“ false ”，标记不可见。默认情况下为“ true ”。\n6.anchor图标摆放在地图上的基准点。默认情况下，锚点是从图片下沿的中间处。\n7.perspective设置 true，标记有近大远小效果。默认情况下为 false。\n8.可以通过Marker.setRotateAngle() 方法设置标记的旋转角度，从正北开始，逆时针计算。如设置旋转90度，Marker.setRotateAngle(90)\n9.通过setFlat() 方法设置标志是否贴地显示\n自定义图标通常由 BitmapDescriptor 设置。我们可以在类 BitmapDescriptorFactory 使用以下其中一种方法定义。\n1.fromAsset(String assetName) 在 assets 目录中使用图像创建自定义标记。\n2.fromBitmap (Bitmap image) 使用位图图像创建自定义标记。\n3.fromFile (String path) 指定路径的文件创建自定义图标。\n4.fromResource (int resourceId) 使用已经存在的资源创建自定义图标。\n","permalink":"https://blog.zdltech.com/posts/%E9%AB%98%E5%BE%B7%E5%9C%B0%E5%9B%BE%E7%9F%A5%E8%AF%86%E6%B1%87%E6%80%BB/","summary":"\u003cp\u003e//设置缩放级别\u003cbr\u003e\naMap.moveCamera(CameraUpdateFactory.zoomTo(17));\u003cbr\u003e\n//将地图移动到定位点\u003cbr\u003e\naMap.moveCamera(CameraUpdateFactory.changeLatLng(new LatLng(amapLocation.getLatitude(), amapLocation.getLongitude())));\u003cbr\u003e\n//点击定位按钮 能够将地图的中心移动到定位点\u003cbr\u003e\nmListener.onLocationChanged(amapLocation);\u003cbr\u003e\n//添加图钉\u003cbr\u003e\naMap.addMarker(getMarkerOptions(amapLocation));\u003cbr\u003e\n//获取定位信息\u003cbr\u003e\nStringBuffer buffer = new StringBuffer();\u003cbr\u003e\nbuffer.append(amapLocation.getCountry() + “” + amapLocation.getProvince() + “” + amapLocation.getCity() + “” + amapLocation.getProvince() + “” + amapLocation.getDistrict() + “” + amapLocation.getStreet() + “” + amapLocation.getStreetNum());\u003cbr\u003e\nToast.makeText(getApplicationContext(), buffer.toString(), Toast.LENGTH_LONG).show();\u003cbr\u003e\nisFirstLoc = false;\u003c/p\u003e\n\u003cp\u003e//定位的小图标 默认是蓝点 这里自定义一团火，其实就是一张图片\u003cbr\u003e\nMyLocationStyle myLocationStyle = new MyLocationStyle();\u003cbr\u003e\nmyLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromResource(R.mipmap.firetwo));\u003cbr\u003e\nmyLocationStyle.radiusFillColor(android.R.color.transparent);\u003cbr\u003e\nmyLocationStyle.strokeColor(android.R.color.transparent);\u003cbr\u003e\naMap.setMyLocationStyle(myLocationStyle);\u003cbr\u003e\n//定位\u003cbr\u003e\nprivate void initLoc() {\u003cbr\u003e\n//初始化定位\u003cbr\u003e\nmLocationClient = new AMapLocationClient(getApplicationContext());\u003cbr\u003e\n//设置定位回调监听\u003cbr\u003e\nmLocationClient.setLocationListener(this);\u003cbr\u003e\n//初始化定位参数\u003cbr\u003e\nmLocationOption = new AMapLocationClientOption();\u003cbr\u003e\n//设置定位模式为高精度模式，Battery_Saving为低功耗模式，Device_Sensors是仅设备模式\u003cbr\u003e\nmLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);\u003cbr\u003e\n//设置是否返回地址信息（默认返回地址信息）\u003cbr\u003e\nmLocationOption.setNeedAddress(true);\u003cbr\u003e\n//设置是否只定位一次,默认为false\u003cbr\u003e\nmLocationOption.setOnceLocation(false);\u003cbr\u003e\n//设置是否强制刷新WIFI，默认为强制刷新\u003cbr\u003e\nmLocationOption.setWifiActiveScan(true);\u003cbr\u003e\n//设置是否允许模拟位置,默认为false，不允许模拟位置\u003cbr\u003e\nmLocationOption.setMockEnable(false);\u003cbr\u003e\n//设置定位间隔,单位毫秒,默认为2000ms\u003cbr\u003e\nmLocationOption.setInterval(2000);\u003cbr\u003e\n//给定位客户端对象设置定位参数\u003cbr\u003e\nmLocationClient.setLocationOption(mLocationOption);\u003cbr\u003e\n//启动定位\u003cbr\u003e\nmLocationClient.startLocation();\u003cbr\u003e\n}\u003c/p\u003e","title":"高德地图知识汇总"},{"content":"import android.graphics.Color; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.ViewTreeObserver; import android.view.animation.LinearInterpolator; import android.widget.TextView; import android.widget.Toast; import com.amap.api.location.AMapLocation; import com.amap.api.location.AMapLocationClient; import com.amap.api.location.AMapLocationClientOption; import com.amap.api.location.AMapLocationListener; import com.amap.api.maps.AMap; import com.amap.api.maps.CameraUpdateFactory; import com.amap.api.maps.LocationSource; import com.amap.api.maps.MapView; import com.amap.api.maps.UiSettings; import com.amap.api.maps.model.CameraPosition; import com.amap.api.maps.model.LatLng; import com.amap.api.maps.model.Marker; import com.amap.api.maps.model.MarkerOptions; import com.amap.api.maps.model.animation.Animation; import com.amap.api.maps.model.animation.RotateAnimation; import com.amap.api.services.core.LatLonPoint; import com.amap.api.services.geocoder.GeocodeResult; import com.amap.api.services.geocoder.GeocodeSearch; import com.amap.api.services.geocoder.RegeocodeQuery; import com.amap.api.services.geocoder.RegeocodeResult; import com.tlh.gczp.R; import com.tlh.gczp.mvp.view.BaseUIActivity; import butterknife.BindView; import butterknife.ButterKnife; /** * 地图选点 */ public class AMapSelectPointActivity extends BaseUIActivity implements LocationSource { public static String TITLE_TAG = \u0026#34;title_str\u0026#34;;//标题key public static String RESULT_TAG = \u0026#34;result_str\u0026#34;;//返回数据key String titleStr = \u0026#34;地图\u0026#34;;//标题 @BindView(R.id.activity_amapselectpoint_map) MapView mMapView; @BindView(R.id.activity_amapselectpoint_text) TextView addressTxtView;//位置 AMap aMap;//地图 private UiSettings mUiSettings;//定义一个UiSettings对象 //声明AMapLocationClient类对象 public AMapLocationClient mLocationClient = null; //声明定位回调监听器 public AMapLocationListener mLocationListener; //声明AMapLocationClientOption对象 public AMapLocationClientOption mLocationOption = null; OnLocationChangedListener listener; MarkerOptions markerCenter = new MarkerOptions();//中心点 Marker marker;//中间 GeocodeSearch geocodeSearch;//地理位置查询 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentViewItem(R.layout.activity_amapselectpont); ButterKnife.bind(this); //在activity执行onCreate时执行mMapView.onCreate(savedInstanceState)，实现地图生命周期管理 mMapView.onCreate(savedInstanceState); rightBtn.setTextColor(Color.parseColor(\u0026#34;#fcc900\u0026#34;)); initData(); showPage(); } /** * 实例化数据 */ private void initData() { initMap(); titleStr = getIntent().getStringExtra(TITLE_TAG); if (TextUtils.isEmpty(titleStr)){ titleStr = \u0026#34;地图\u0026#34;; } setPageName(titleStr); currentPageName = titleStr; setRightTxt(getString(R.string.str_common_finish), new View.OnClickListener() { @Override public void onClick(View view) { searchAddressByLat(marker.getPosition()); } }); } private void initMap() {//实例化Map geocodeSearch = new GeocodeSearch(this); //初始化地图变量 if (aMap == null) { aMap = mMapView.getMap(); } aMap.setMapType(AMap.MAP_TYPE_NORMAL); mUiSettings = aMap.getUiSettings();//实例化UiSettings类 mUiSettings.setZoomControlsEnabled(true); //定位按钮 aMap.setLocationSource(this);// 设置定位监听 mUiSettings.setMyLocationButtonEnabled(true); // 显示默认的定位按钮 aMap.setMyLocationEnabled(true);// 可触发定位并显示定位层 mUiSettings.setScaleControlsEnabled(true);//显示比例尺控件 mUiSettings.setAllGesturesEnabled(true); mUiSettings.setCompassEnabled(true);//指南针 // LatLng latLng = new LatLng(39.906901, 116.397972); // final Marker marker = aMap.addMarker(new MarkerOptions(). // position(latLng). // title(\u0026#34;北京\u0026#34;). // snippet(\u0026#34;DefaultMarker\u0026#34;)); // final Marker marker = aMap.addMarker(new MarkerOptions()); // MarkerOptions markeroptions = new MarkerOptions(); // markeroptions.position(latLng); // markeroptions.title(\u0026#34;当前位置\u0026#34;); // markeroptions.visible(true); // BitmapDescriptor bitmapDescriptor= BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.positioning_normal)); // markeroptions.icon(bitmapDescriptor); // aMap.addMarker(markeroptions); mMapView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Log.e(\u0026#34;mMapView\u0026#34;,\u0026#34;onGlobalLayout===---123\u0026#34;); marker = aMap.addMarker(new MarkerOptions()); Animation animation = new RotateAnimation(marker.getRotateAngle(), marker.getRotateAngle() + 720, 0, 0, 0); long duration = 1000L; animation.setDuration(duration); animation.setInterpolator(new LinearInterpolator()); marker.setAnimation(animation); marker.startAnimation(); marker.setPositionByPixels(mMapView.getWidth()/2, mMapView.getHeight()/2); } }); LatLng ll = new LatLng(34.6006623972045,108.97923588752748); markerCenter.position(ll); markerCenter.visible(true); markerCenter.title(\u0026#34;中心点\u0026#34;); // BitmapDescriptor bitmapDescriptor= BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.icon_nearby)); // markerCenter.icon(bitmapDescriptor); aMap.addMarker(markerCenter); //初始化AMapLocationClientOption对象 mLocationOption = new AMapLocationClientOption(); //设置定位模式为AMapLocationMode.Hight_Accuracy，高精度模式。 // mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Battery_Saving); mLocationListener = new AMapLocationListener() { @Override public void onLocationChanged(AMapLocation aMapLocation) { if (aMapLocation != null) { if (listener != null) { listener.onLocationChanged(aMapLocation); } if (aMapLocation.getErrorCode() == 0) { //可在其中解析amapLocation获取相应内容。 Log.e(\u0026#34;AMapSelectPointActivity\u0026#34;, \u0026#34;aMapLocation=\u0026#34; + aMapLocation.getCity()); Log.e(\u0026#34;AMapSelectPointActivity\u0026#34;, \u0026#34;aMapLocation address=\u0026#34; + aMapLocation.getAddress()); } else { //定位失败时，可通过ErrCode（错误码）信息来确定失败的原因，errInfo是错误信息，详见错误码表。 Log.e(\u0026#34;AmapError\u0026#34;, \u0026#34;location Error, ErrCode:\u0026#34; + aMapLocation.getErrorCode() + \u0026#34;, errInfo:\u0026#34; + aMapLocation.getErrorInfo()); } } Log.e(\u0026#34;AMapSelectPointActivity\u0026#34;, \u0026#34;aMapLocation run onLocationChanged\u0026#34;); } }; //初始化定位 mLocationClient = new AMapLocationClient(getApplicationContext()); //设置定位回调监听 mLocationClient.setLocationListener(mLocationListener); mLocationClient.setLocationOption(mLocationOption);//设置模式 aMap.setOnCameraChangeListener(new AMap.OnCameraChangeListener() { @Override public void onCameraChange(CameraPosition cameraPosition) { LatLng target = cameraPosition.target; System.out.println(target.latitude + \u0026#34;jinjin------\u0026#34; + target.longitude); } @Override public void onCameraChangeFinish(CameraPosition cameraPosition) { LatLng target = cameraPosition.target; System.out.println(\u0026#34;changeFinish=\u0026#34;+target.latitude + \u0026#34;jinjin------\u0026#34; + target.longitude); LatLng ll = new LatLng(target.latitude,target.longitude); markerCenter.position(ll); searchAddressByLat(ll); // markerCenter.visible(true); // markerCenter.title(\u0026#34;中心点\u0026#34;); // BitmapDescriptor bitmapDescriptor= BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.icon_nearby)); // markerCenter.icon(bitmapDescriptor); // aMap.addMarker(markerCenter); } }); } @Override protected void onDestroy() { super.onDestroy(); //在activity执行onDestroy时执行mMapView.onDestroy()，实现地图生命周期管理 mMapView.onDestroy(); mLocationClient.onDestroy(); } @Override protected void onResume() { super.onResume(); //在activity执行onResume时执行mMapView.onResume ()，实现地图生命周期管理 mMapView.onResume(); //启动定位 mLocationClient.startLocation(); } @Override protected void onPause() { super.onPause(); //在activity执行onPause时执行mMapView.onPause ()，实现地图生命周期管理 mMapView.onPause(); mLocationClient.stopLocation(); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); //在activity执行onSaveInstanceState时执行mMapView.onSaveInstanceState (outState)，实现地图生命周期管理 mMapView.onSaveInstanceState(outState); } @Override public void activate(OnLocationChangedListener onLocationChangedListener) { Log.e(\u0026#34;AMapSelectPointActivity\u0026#34;, \u0026#34;activate is run\u0026#34;); listener = onLocationChangedListener; } @Override public void deactivate() {//高德地图位置监听 listener = null; } private void searchAddressByLat(final LatLng latLng){ geocodeSearch.setOnGeocodeSearchListener(new GeocodeSearch.OnGeocodeSearchListener() { @Override public void onRegeocodeSearched(RegeocodeResult result, int rCode) { if (rCode == 1000) { if (result != null \u0026amp;\u0026amp; result.getRegeocodeAddress() != null \u0026amp;\u0026amp; result.getRegeocodeAddress().getFormatAddress() != null) { String addressName = result.getRegeocodeAddress().getFormatAddress() + \u0026#34;附近\u0026#34;; aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15)); addressTxtView.setText(result.getRegeocodeAddress().getFormatAddress()); Toast.makeText(AMapSelectPointActivity.this, addressName,Toast.LENGTH_LONG).show(); } else { Toast.makeText(AMapSelectPointActivity.this, \u0026#34;未找到\u0026#34;,Toast.LENGTH_LONG).show(); } } else { Toast.makeText(AMapSelectPointActivity.this, \u0026#34;失败\u0026#34;,Toast.LENGTH_LONG).show(); } } @Override public void onGeocodeSearched(GeocodeResult geocodeResult, int i) { } }); LatLonPoint point = new LatLonPoint(latLng.latitude,latLng.longitude); RegeocodeQuery query = new RegeocodeQuery(point, 200,GeocodeSearch.AMAP); geocodeSearch.getFromLocationAsyn(query); } } ","permalink":"https://blog.zdltech.com/posts/%E9%AB%98%E5%BE%B7%E5%9C%B0%E5%9B%BE%E5%AE%9A%E4%BD%8D-%E4%B8%AD%E9%97%B4%E5%9B%BA%E5%AE%9A%E7%82%B9%E6%8B%96%E5%8A%A8%E8%8E%B7%E5%8F%96%E4%BD%8D%E7%BD%AE/","summary":"\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eColor;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eos\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBundle;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etext\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eTextUtils;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eutil\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLog;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eViewTreeObserver;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eanimation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLinearInterpolator;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eTextView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eToast;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elocation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAMapLocation;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elocation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAMapLocationClient;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elocation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAMapLocationClientOption;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elocation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAMapLocationListener;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emaps\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAMap;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emaps\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eCameraUpdateFactory;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emaps\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLocationSource;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emaps\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMapView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emaps\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eUiSettings;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emaps\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emodel\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eCameraPosition;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emaps\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emodel\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLatLng;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emaps\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emodel\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMarker;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emaps\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emodel\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMarkerOptions;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emaps\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emodel\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eanimation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAnimation;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emaps\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emodel\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eanimation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eRotateAnimation;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eservices\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecore\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLatLonPoint;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eservices\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egeocoder\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eGeocodeResult;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eservices\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egeocoder\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eGeocodeSearch;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eservices\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egeocoder\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eRegeocodeQuery;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eamap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapi\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eservices\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egeocoder\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eRegeocodeResult;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etlh\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egczp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eR;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etlh\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egczp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emvp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBaseUIActivity;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport butterknife\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBindView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport butterknife\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eButterKnife;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 地图选点\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e AMapSelectPointActivity \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e BaseUIActivity implements LocationSource {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e String TITLE_TAG \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;title_str\u0026#34;\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e标题key\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e String RESULT_TAG \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;result_str\u0026#34;\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e返回数据key\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    String titleStr \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;地图\u0026#34;\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e标题\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @BindView(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eactivity_amapselectpoint_map)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    MapView mMapView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @BindView(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eactivity_amapselectpoint_text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    TextView addressTxtView;\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e位置\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    AMap aMap;\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e地图\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private UiSettings mUiSettings;\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e定义一个UiSettings对象\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e声明AMapLocationClient类对象\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public AMapLocationClient mLocationClient \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e声明定位回调监听器\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public AMapLocationListener mLocationListener;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e声明AMapLocationClientOption对象\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public AMapLocationClientOption mLocationOption \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    OnLocationChangedListener listener;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    MarkerOptions markerCenter \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new MarkerOptions();\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e中心点\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    Marker marker;\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e中间\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    GeocodeSearch geocodeSearch;\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e地理位置查询\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    protected void onCreate(Bundle savedInstanceState) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonCreate(savedInstanceState);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        setContentViewItem(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elayout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eactivity_amapselectpont);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ButterKnife\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ebind(this);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e在activity执行onCreate时执行mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonCreate(savedInstanceState)，实现地图生命周期管理\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonCreate(savedInstanceState);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        rightBtn\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetTextColor(Color\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eparseColor(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;#fcc900\u0026#34;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        initData();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        showPage();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 实例化数据\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private void initData() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        initMap();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        titleStr \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e getIntent()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetStringExtra(TITLE_TAG);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (TextUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eisEmpty(titleStr)){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            titleStr \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;地图\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        setPageName(titleStr);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        currentPageName \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e titleStr;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        setRightTxt(getString(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003estring\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003estr_common_finish), new View\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eOnClickListener() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            public void onClick(View view) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                searchAddressByLat(marker\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetPosition());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        });\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private void initMap() {\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e实例化Map\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        geocodeSearch \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new GeocodeSearch(this);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e初始化地图变量\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (aMap \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            aMap \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetMap();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        aMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetMapType(AMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMAP_TYPE_NORMAL);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mUiSettings \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e aMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetUiSettings();\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e实例化UiSettings类\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mUiSettings\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetZoomControlsEnabled(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e定位按钮\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        aMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetLocationSource(this);\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 设置定位监听\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mUiSettings\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetMyLocationButtonEnabled(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e); \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 显示默认的定位按钮\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        aMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetMyLocationEnabled(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 可触发定位并显示定位层\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mUiSettings\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetScaleControlsEnabled(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e显示比例尺控件\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mUiSettings\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetAllGesturesEnabled(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mUiSettings\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetCompassEnabled(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e指南针\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        LatLng latLng \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new LatLng(\u003cspan style=\"color:#bd93f9\"\u003e39.906901\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e116.397972\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        final Marker marker \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e aMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddMarker(new MarkerOptions()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e                position(latLng)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e                title(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;北京\u0026#34;\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e                snippet(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;DefaultMarker\u0026#34;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        final Marker marker \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e aMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddMarker(new MarkerOptions());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        MarkerOptions markeroptions \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new MarkerOptions();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        markeroptions\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eposition(latLng);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        markeroptions\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etitle(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;当前位置\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        markeroptions\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003evisible(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        BitmapDescriptor bitmapDescriptor\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e BitmapDescriptorFactory\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003efromBitmap(BitmapFactory\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edecodeResource(getResources(),R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emipmap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epositioning_normal));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        markeroptions\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eicon(bitmapDescriptor);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        aMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddMarker(markeroptions);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetViewTreeObserver()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddOnGlobalLayoutListener(new ViewTreeObserver\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eOnGlobalLayoutListener() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           public void onGlobalLayout() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               Log\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ee(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;mMapView\u0026#34;\u003c/span\u003e,\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;onGlobalLayout===---123\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                marker \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e aMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddMarker(new MarkerOptions());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               Animation animation \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new RotateAnimation(marker\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetRotateAngle(), marker\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetRotateAngle() \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e720\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               long duration \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1000\u003c/span\u003eL;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               animation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetDuration(duration);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               animation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetInterpolator(new LinearInterpolator());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               marker\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetAnimation(animation);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               marker\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003estartAnimation();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               marker\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetPositionByPixels(mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetWidth()\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e, mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetHeight()\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       });\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        LatLng ll \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new LatLng(\u003cspan style=\"color:#bd93f9\"\u003e34.6006623972045\u003c/span\u003e,\u003cspan style=\"color:#bd93f9\"\u003e108.97923588752748\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        markerCenter\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eposition(ll);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        markerCenter\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003evisible(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        markerCenter\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etitle(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;中心点\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        BitmapDescriptor bitmapDescriptor\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e BitmapDescriptorFactory\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003efromBitmap(BitmapFactory\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edecodeResource(getResources(),R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emipmap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eicon_nearby));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        markerCenter\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eicon(bitmapDescriptor);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        aMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddMarker(markerCenter);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e初始化AMapLocationClientOption对象\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mLocationOption \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new AMapLocationClientOption();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e设置定位模式为AMapLocationMode\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eHight_Accuracy，高精度模式。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e        mLocationOption\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetLocationMode(AMapLocationClientOption\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAMapLocationMode\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBattery_Saving);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mLocationListener \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new AMapLocationListener() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            public void onLocationChanged(AMapLocation aMapLocation) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (aMapLocation \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (listener \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        listener\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonLocationChanged(aMapLocation);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (aMapLocation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetErrorCode() \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e可在其中解析amapLocation获取相应内容。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        Log\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ee(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;AMapSelectPointActivity\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;aMapLocation=\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e aMapLocation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetCity());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        Log\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ee(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;AMapSelectPointActivity\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;aMapLocation address=\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e aMapLocation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetAddress());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    } \u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e定位失败时，可通过ErrCode（错误码）信息来确定失败的原因，errInfo是错误信息，详见错误码表。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        Log\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ee(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;AmapError\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;location Error, ErrCode:\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                                \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e aMapLocation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetErrorCode() \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;, errInfo:\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                                \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e aMapLocation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetErrorInfo());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                Log\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ee(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;AMapSelectPointActivity\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;aMapLocation run  onLocationChanged\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        };\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e初始化定位\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mLocationClient \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new AMapLocationClient(getApplicationContext());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e设置定位回调监听\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mLocationClient\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetLocationListener(mLocationListener);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mLocationClient\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetLocationOption(mLocationOption);\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e设置模式\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        aMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetOnCameraChangeListener(new AMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eOnCameraChangeListener() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            public void onCameraChange(CameraPosition cameraPosition) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                LatLng target \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e cameraPosition\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etarget;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(target\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elatitude \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;jinjin------\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e target\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elongitude);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            public void onCameraChangeFinish(CameraPosition cameraPosition) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                LatLng target \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e cameraPosition\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etarget;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;changeFinish=\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003etarget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elatitude \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;jinjin------\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e target\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elongitude);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                LatLng ll \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new LatLng(target\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elatitude,target\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elongitude);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                markerCenter\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eposition(ll);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                searchAddressByLat(ll);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e                markerCenter\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003evisible(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e                markerCenter\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etitle(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;中心点\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e                BitmapDescriptor bitmapDescriptor\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e BitmapDescriptorFactory\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003efromBitmap(BitmapFactory\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edecodeResource(getResources(),R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emipmap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eicon_nearby));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e                markerCenter\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eicon(bitmapDescriptor);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e                aMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddMarker(markerCenter);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        });\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    protected void onDestroy() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonDestroy();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e在activity执行onDestroy时执行mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonDestroy()，实现地图生命周期管理\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonDestroy();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mLocationClient\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonDestroy();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    protected void onResume() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonResume();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e在activity执行onResume时执行mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonResume ()，实现地图生命周期管理\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonResume();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e启动定位\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mLocationClient\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003estartLocation();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    protected void onPause() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonPause();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e在activity执行onPause时执行mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonPause ()，实现地图生命周期管理\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonPause();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mLocationClient\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003estopLocation();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    protected void onSaveInstanceState(Bundle outState) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonSaveInstanceState(outState);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e在activity执行onSaveInstanceState时执行mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonSaveInstanceState (outState)，实现地图生命周期管理\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mMapView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonSaveInstanceState(outState);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public void activate(OnLocationChangedListener onLocationChangedListener) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Log\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ee(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;AMapSelectPointActivity\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;activate is run\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        listener \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e onLocationChangedListener;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public void deactivate() {\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e高德地图位置监听\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        listener \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private  void searchAddressByLat(final LatLng latLng){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        geocodeSearch\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetOnGeocodeSearchListener(new GeocodeSearch\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eOnGeocodeSearchListener() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            public void onRegeocodeSearched(RegeocodeResult result, int rCode) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (rCode \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1000\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (result \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e null \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e result\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetRegeocodeAddress() \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e null\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e result\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetRegeocodeAddress()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetFormatAddress() \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        String addressName \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e result\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetRegeocodeAddress()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetFormatAddress()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                                \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;附近\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        aMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eanimateCamera(CameraUpdateFactory\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003enewLatLngZoom(latLng, \u003cspan style=\"color:#bd93f9\"\u003e15\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        addressTxtView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetText(result\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetRegeocodeAddress()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetFormatAddress());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        Toast\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emakeText(AMapSelectPointActivity\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ethis, addressName,Toast\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLENGTH_LONG)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eshow();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    } \u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        Toast\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emakeText(AMapSelectPointActivity\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ethis, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;未找到\u0026#34;\u003c/span\u003e,Toast\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLENGTH_LONG)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eshow();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                } \u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    Toast\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emakeText(AMapSelectPointActivity\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ethis, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;失败\u0026#34;\u003c/span\u003e,Toast\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLENGTH_LONG)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eshow();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            public void onGeocodeSearched(GeocodeResult geocodeResult, int i) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        });\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        LatLonPoint point \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new LatLonPoint(latLng\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elatitude,latLng\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elongitude);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        RegeocodeQuery query \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new RegeocodeQuery(point, \u003cspan style=\"color:#bd93f9\"\u003e200\u003c/span\u003e,GeocodeSearch\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAMAP);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        geocodeSearch\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetFromLocationAsyn(query);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"高德地图，定位 ，中间固定点拖动获取位置"},{"content":"Compile，Provided，APK，Test compile，Debug compile，Release compile\nCompile compile是对所有的build type以及favlors都会参与编译并且打包到最终的apk文件中。\nProvided Provided是对所有的build type以及favlors只在编译时使用，类似eclipse中的external-libs,只参与编译，不打包到最终apk。\nAPK 只会打包到apk文件中，而不参与编译，所以不能再代码中直接调用jar中的类或方法，否则在编译时会报错\nTest compile Test compile 仅仅是针对单元测试代码的编译编译以及最终打包测试apk时有效，而对正常的debug或者release apk包不起作用。\nDebug compile Debug compile 仅仅针对debug模式的编译和最终的debug apk打包。\nRelease compile Release compile 仅仅针对Release 模式的编译和最终的Release apk打包。\n转自：http://www.cnblogs.com/kangyi/p/4449857.html\n[AndroidStudio中多个Module依赖同一个jar的解决方案](http://blog.csdn.net/u013134391/article/details/51538511) **方案****:** 将任意一个Module中的jar依赖为compile files(\u0026amp;#8216;your jar name\u0026amp;#8217;)，其他需要依赖的地方改为provided files(\u0026amp;#8216;your jar name\u0026amp;#8217;)并且删除compile fileTree(include: [\u0026amp;#8216;*.jar\u0026amp;#8217;], dir: \u0026amp;#8216;libs)。即可 下面详细介绍为什么这样做以及案例 **案例介绍** 如 环信Module和自己app的Module都要用到定位sdk **1、**在自己app的gradle中以compile引入如： compile files(\u0026amp;#8216;libs/AMap_Location_V2.4.1_20160414.jar\u0026amp;#8217;) **2、**在环信的Module的gradle中以provided的方式引入如： provided files(\u0026amp;#8216;libs/AMap_Location_V2.4.1_20160414.jar\u0026amp;#8217;) **3、**而且环信的gradle中不能存在compile fileTree(include: [\u0026amp;#8216;*.jar\u0026amp;#8217;], dir: \u0026amp;#8216;libs\u0026amp;#8217;) ==========================分割线================================= AndroidStudio中Module相当于Eclispe中的Library，这里不做过多介绍 多个Module依赖同一个jar，直接把jar放入对应需要的Module会导致编译报类冲突 这里就要讲一讲AndroidStudio中的依赖的几种方式 compile compile是对所有的build type以及favlors都会参与编译并且打包到最终的apk文件中。 Provided Provided是对所有的build type以及favlors只在编译时使用，类似eclipse中的external-libs,只参与编译，不打包到最终apk。 APK 只会打包到apk文件中，而不参与编译，所以不能再代码中直接调用jar中的类或方法，否则在编译时会报错 Test compile Test compile 仅仅是针对单元[测试](http://lib.csdn.net/base/softwaretest)代码的编译编译以及最终打包测试apk时有效，而对正常的debug或者release apk包不起作用。 Debug compile Debug compile 仅仅针对debug模式的编译和最终的debug apk打包 Release compile Release compile 仅仅针对Release 模式的编译和最终的Release apk打包。 我们需要用的是Provided，这样在写代码的时候可以在Module中正常使用jar中的类，但是要有一个Module以compile的方式依赖这个jar，这样编译的时候只有一个jar编译进apk。 注：使用Provided必须删除compile fileTree(include: [\u0026amp;#8216;*.jar\u0026amp;#8217;], dir: \u0026amp;#8216;libs\u0026amp;#8217;) 不然lib下的jar均按照compile方式引入到Module 搞定！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！ 转自：http://blog.csdn.net/u013134391/article/details/51538511 ","permalink":"https://blog.zdltech.com/posts/%E5%9C%A8android-studio%E4%B8%AD%E6%9C%89%E5%85%AD%E7%A7%8D%E4%BE%9D%E8%B5%96/","summary":"\u003cp\u003e\u003cspan class=\"s1\"\u003eCompile，Provided，APK，Test compile，Debug compile，Release compile\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog2015/54939/201504/231129521259725.png\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003ch2 class=\"p1\" id=\"compile\"\u003e\u003cspan class=\"s1\"\u003eCompile\u003c/span\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003ecompile是对所有的build type以及favlors都会参与编译并且打包到最终的apk文件中。\u003c/span\u003e\u003c/p\u003e\n\u003ch2 class=\"p1\" id=\"provided\"\u003e\u003cspan class=\"s1\"\u003eProvided\u003c/span\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003eProvided是对所有的build type以及favlors只在编译时使用，类似eclipse中的external-libs,只参与编译，不打包到最终apk。\u003c/span\u003e\u003c/p\u003e\n\u003ch2 class=\"p1\" id=\"apk\"\u003e\u003cspan class=\"s1\"\u003eAPK\u003c/span\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e只会打包到apk文件中，而不参与编译，所以不能再代码中直接调用jar中的类或方法，否则在编译时会报错\u003c/span\u003e\u003c/p\u003e\n\u003ch2 class=\"p1\" id=\"test-compile\"\u003e\u003cspan class=\"s1\"\u003eTest compile\u003c/span\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003eTest compile 仅仅是针对单元测试代码的编译编译以及最终打包测试apk时有效，而对正常的debug或者release apk包不起作用。\u003c/span\u003e\u003c/p\u003e\n\u003ch2 class=\"p1\" id=\"debug-compile\"\u003e\u003cspan class=\"s1\"\u003eDebug compile\u003c/span\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003eDebug compile 仅仅针对debug模式的编译和最终的debug apk打包。\u003c/span\u003e\u003c/p\u003e\n\u003ch2 class=\"p2\" id=\"release-compile\"\u003e\u003cspan class=\"s1\"\u003eRelease compile\u003c/span\u003e\u003c/h2\u003e\n\u003cp\u003eRelease compile 仅仅针对Release 模式的编译和最终的Release apk打包。\u003c/p\u003e\n\u003cp\u003e转自：http://www.cnblogs.com/kangyi/p/4449857.html\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  [AndroidStudio中多个Module依赖同一个jar的解决方案](http://blog.csdn.net/u013134391/article/details/51538511)\n\n\n\n\n\n  **方案****:** 将任意一个Module中的jar依赖为compile files(\u0026amp;#8216;your jar name\u0026amp;#8217;)，其他需要依赖的地方改为provided files(\u0026amp;#8216;your jar name\u0026amp;#8217;)并且删除compile fileTree(include: [\u0026amp;#8216;*.jar\u0026amp;#8217;], dir: \u0026amp;#8216;libs)。即可  下面详细介绍为什么这样做以及案例\n\n\n\n\n\n  **案例介绍**\n\n\n\n\n\n  如 环信Module和自己app的Module都要用到定位sdk\n\n\n\n\n\n  **1、**在自己app的gradle中以compile引入如：\n\n\n\n\n\n  compile files(\u0026amp;#8216;libs/AMap_Location_V2.4.1_20160414.jar\u0026amp;#8217;)\n\n\n\n\n\n  **2、**在环信的Module的gradle中以provided的方式引入如：\n\n\n\n\n\n  provided files(\u0026amp;#8216;libs/AMap_Location_V2.4.1_20160414.jar\u0026amp;#8217;)\n\n\n\n\n\n  **3、**而且环信的gradle中不能存在compile fileTree(include: [\u0026amp;#8216;*.jar\u0026amp;#8217;], dir: \u0026amp;#8216;libs\u0026amp;#8217;)\n\n\n\n\n\n  \n\n    ==========================分割线=================================\n  \n\n  \n  \n\n    AndroidStudio中Module相当于Eclispe中的Library，这里不做过多介绍\n  \n\n  \n  \n\n    多个Module依赖同一个jar，直接把jar放入对应需要的Module会导致编译报类冲突\n  \n\n  \n  \n\n    这里就要讲一讲AndroidStudio中的依赖的几种方式\n  \n\n  \n  \n\n    compile\n  \n\n  \n  \n\n    compile是对所有的build type以及favlors都会参与编译并且打包到最终的apk文件中。\n  \n\n  \n  \n\n    Provided\n  \n\n  \n  \n\n    Provided是对所有的build type以及favlors只在编译时使用，类似eclipse中的external-libs,只参与编译，不打包到最终apk。\n  \n\n  \n  \n\n    APK\n  \n\n  \n  \n\n    只会打包到apk文件中，而不参与编译，所以不能再代码中直接调用jar中的类或方法，否则在编译时会报错\n  \n\n  \n  \n\n    Test compile\n  \n\n  \n  \n\n    Test compile 仅仅是针对单元[测试](http://lib.csdn.net/base/softwaretest)代码的编译编译以及最终打包测试apk时有效，而对正常的debug或者release apk包不起作用。\n  \n\n  \n  \n\n    Debug compile\n  \n\n  \n  \n\n    Debug compile 仅仅针对debug模式的编译和最终的debug apk打包\n  \n\n  \n  \n\n    Release compile\n  \n\n  \n  \n\n    Release compile 仅仅针对Release 模式的编译和最终的Release apk打包。\n  \n\n  \n  \n\n    我们需要用的是Provided，这样在写代码的时候可以在Module中正常使用jar中的类，但是要有一个Module以compile的方式依赖这个jar，这样编译的时候只有一个jar编译进apk。\n  \n\n  \n  \n\n    注：使用Provided必须删除compile fileTree(include: [\u0026amp;#8216;*.jar\u0026amp;#8217;], dir: \u0026amp;#8216;libs\u0026amp;#8217;) 不然lib下的jar均按照compile方式引入到Module\n  \n\n  \n  \n\n    搞定！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！\n  \n\n  \n  \n\n    转自：http://blog.csdn.net/u013134391/article/details/51538511\n\u003c/code\u003e\u003c/pre\u003e","title":"在Android Studio中有六种依赖"},{"content":"第一步、先制做一个有我们需要的图片资源的APK 如下图，这里有个about_log.png,我们需要生成apk文件。 生成的apk文件如果你不到项目的文件夹里面去取apk，想通过命令放到手机里面去可以快速用下面命令\n1）、在手机里面通过包名找到apk路径，一定不要忘记有 -f - adb shell pm list package -f | grep com.example.testclassloader 得到如下结果\n- package:/data/app/com.example.testclassloader-2/\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;base.apk\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;com\u0026lt;/span\u0026gt;.example.testclassloader 2)、把base.apk拉到本地然后改名字，命令如下 - adb shell pull /data/app/com.example.testclassloader-2/base.apk testClassLoader.apk 3)、把testClassLoader.apk放到手机里面去，命令如下 - adb shell push testClassLoader.apk /sdcard/ 4)、去手机文件管理器里面找看是否有testClassLoader.apk文件 第二步、获取为安装apk包名的信息（假设前提不知道） 我们可以通过这个方法得到\npublic PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) 具体方法如下\n- /** - * 获取未安装apk的信息 - * @param context - * @param apkPath apk文件的path - * @return - */ - private Map\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;,String\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; getUninstallApkInfo(Context context, String apkPath) { - Map \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;hashMap\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;,String\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;(); - PackageManager \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;pm\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;context\u0026lt;/span\u0026gt;.getPackageManager(); - PackageInfo \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;pkgInfo\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;pm\u0026lt;/span\u0026gt;.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES); - if (null != pkgInfo) { - ApplicationInfo \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;appInfo\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;pkgInfo\u0026lt;/span\u0026gt;.applicationInfo; - String \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;pkgName\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;appInfo\u0026lt;/span\u0026gt;.packageName;//包名 - hashMap.put(PKG_NAME, pkgName); - } else { - Log.d(TAG, \u0026amp;#8220;program don\u0026amp;#8217;t get apk package information\u0026amp;#8221;); - } - return hashMap; - } 第三步、获取未安装apk(插件)的Resource 因为没有安装，所以不能得到context,所以我们需要未安装apk的Resource,我们可以通过反射来获取，代码如下\n- /** - * @param apkPath - * @return 得到对应插件的Resource对象 - */ - private Resources getPluginResources(String apkPath) { - try { - AssetManager \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;assetManager\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;AssetManager\u0026lt;/span\u0026gt;.class.newInstance(); - //反射调用方法addAssetPath(String path) - Method \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;addAssetPath\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;assetManager\u0026lt;/span\u0026gt;.getClass().getMethod(ADDSSETPATH, String.class); - //将未安装的Apk文件的添加进AssetManager中,第二个参数是apk的路径 - addAssetPath.invoke(assetManager, apkPath); - Resources \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;superRes\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getResources(); - Resources \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mResources\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration()); - return mResources; - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } 第四步、用DexClassLoader加载apk资源文件替换背景 如果你多DexClassLoader用法和原理不熟悉，可以参考我之前的博客 Android插件化开发之DexClassLoader动态加载dex、jar小Demo [http://blog.csdn.net/u011068702/article/details/53263442](http://blog.csdn.net/u011068702/article/details/53263442) Android插件化开发之动态加载基础之ClassLoader工作机制 [http://blog.csdn.net/u011068702/article/details/53248960](http://blog.csdn.net/u011068702/article/details/53248960) 代码如下： - /** - * 加载apk获得内部资源,并且替换背景 - * @param apkDir apk目录 - * @param apkName apk名字,带.apk - * @throws Exception - */ - private void dynamicLoadApk(String apkPath, String apkPackageName) throws Exception { - //在应用安装目录下创建一个名为app_dex文件夹目录,如果已经存在则不创建,这个目录主要是最优化目录，用于缓存dex文件 - File \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;optimizedDirectoryFile\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;getDir\u0026lt;/span\u0026gt;(DEX, Context.MODE_PRIVATE); - //打印路径 理论上是/data/data/package/app_dex - Log.v(TAG, optimizedDirectoryFile.getPath().toString()); - //构建DexClassLoader - DexClassLoader \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;dexClassLoader\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DexClassLoader(apkPath, optimizedDirectoryFile.getPath(), null, ClassLoader.getSystemClassLoader()); - //通过使用apk自己的类加载器，反射出R类中相应的内部类进而获取我们需要的资源id - Class\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;clazz\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;dexClassLoader\u0026lt;/span\u0026gt;.loadClass(apkPackageName + DRAWABLE); - //得到名为about_log的这张图片字段,这个图片是为安装apk里面的图片 - Field \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;field\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;clazz\u0026lt;/span\u0026gt;.getDeclaredField(IMAGE_ID); - //得到图片id - int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;resId\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;field\u0026lt;/span\u0026gt;.getInt(R.id.class); - //得到插件apk中的Resource - Resources \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mResources\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;getPluginResources\u0026lt;/span\u0026gt;(apkPath); - if (mResources != null) { - //通过插件apk中的Resource得到resId对应的资源 - Drawable \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;btnDrawable\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;mResources\u0026lt;/span\u0026gt;.getDrawable(resId); - mLayout.setBackgroundDrawable(btnDrawable); - } else { - Log.d(TAG, \u0026amp;#8220;mResources is null\u0026amp;#8221;); - } - } 第五步、爆出所有代码（为了详细点） - package com.chenyu.dexclassloaderapk; - - import java.io.File; - import java.lang.reflect.Field; - import java.lang.reflect.Method; - import java.util.HashMap; - import java.util.Map; - - import android.content.Context; - import android.content.pm.ApplicationInfo; - import android.content.pm.PackageInfo; - import android.content.pm.PackageManager; - import android.content.res.AssetManager; - import android.content.res.Resources; - import android.graphics.drawable.Drawable; - import android.os.Bundle; - import android.os.Environment; - import android.support.v7.app.ActionBarActivity; - import android.util.Log; - import android.view.View; - import android.view.View.OnClickListener; - import android.widget.ImageView; - import android.widget.RelativeLayout; - import android.widget.TextView; - - import com.example.dexclassloaderapk.R; - - import dalvik.system.DexClassLoader; - - public class MainActivity extends ActionBarActivity { - - public static final String \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;TAG\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;DexClassLoaderApk\u0026amp;#8221;\u0026lt;/span\u0026gt;; - public static final String \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;PKG_NAME\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;pkgName\u0026amp;#8221;\u0026lt;/span\u0026gt;; - public static final String \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;APK_PATH\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;testClassLoader.apk\u0026amp;#8221;\u0026lt;/span\u0026gt;; - public static final String \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;ADDSSETPATH\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;addAssetPath\u0026amp;#8221;\u0026lt;/span\u0026gt;; - public static final String \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;DEX\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;dex\u0026amp;#8221;\u0026lt;/span\u0026gt;; - //这个IMAGE_ID是只我放入手机里面APK 在代码里面这个图片的ID,这里我们拿到之后，然后去替换北京图片 - public static final String \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;IMAGE_ID\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;about_log\u0026amp;#8221;\u0026lt;/span\u0026gt;; - public static final String \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;DRAWABLE\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;.R$drawable\u0026amp;#8221;\u0026lt;/span\u0026gt;; - public TextView mTextView; - //背景的布局 - public RelativeLayout mLayout; - public Map\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;, String\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; apkInfo; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - final String \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;apkPath\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;Environment\u0026lt;/span\u0026gt;.getExternalStorageDirectory().toString() + File.separator + APK_PATH; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mTextView\u0026lt;/span\u0026gt; = (TextView)findViewById(R.id.text); - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mLayout\u0026lt;/span\u0026gt; = (RelativeLayout)findViewById(R.id.re_Layout); - mTextView.setOnClickListener(new OnClickListener(){ - @Override - public void onClick(View v) { - //一定要记得加上android.permission.READ_EXTERNAL_STORAGE权限，不然死活都拿不到数据 - //我就换了一个这个错误，如果发现代码没问题，网上找也没问题，这个时候应该思考是不是没有加权限 - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;apkInfo\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;getUninstallApkInfo\u0026lt;/span\u0026gt;(MainActivity.this, apkPath); - String \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;packageName\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;apkInfo\u0026lt;/span\u0026gt;.get(PKG_NAME); - if (null != packageName) { - try { - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;dynamicLoadApk(apkPath, packageName); - } catch (Exception e) { - e.printStackTrace(); - Log.i(TAG, \u0026amp;#8220;change image fail\u0026amp;#8221;); - } - } else { - Log.i(TAG, \u0026amp;#8220;package is null\u0026amp;#8221;); - } - } - }); - } - - /** - * 获取未安装apk的信息 - * @param context - * @param apkPath apk文件的path - * @return - */ - private Map\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;,String\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; getUninstallApkInfo(Context context, String apkPath) { - Map \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;hashMap\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;,String\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;(); - PackageManager \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;pm\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;context\u0026lt;/span\u0026gt;.getPackageManager(); - PackageInfo \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;pkgInfo\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;pm\u0026lt;/span\u0026gt;.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES); - if (null != pkgInfo) { - ApplicationInfo \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;appInfo\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;pkgInfo\u0026lt;/span\u0026gt;.applicationInfo; - String \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;pkgName\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;appInfo\u0026lt;/span\u0026gt;.packageName;//包名 - hashMap.put(PKG_NAME, pkgName); - } else { - Log.d(TAG, \u0026amp;#8220;program don\u0026amp;#8217;t get apk package information\u0026amp;#8221;); - } - return hashMap; - } - - /** - * @param apkPath - * @return 得到对应插件的Resource对象 - */ - private Resources getPluginResources(String apkPath) { - try { - AssetManager \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;assetManager\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;AssetManager\u0026lt;/span\u0026gt;.class.newInstance(); - //反射调用方法addAssetPath(String path) - Method \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;addAssetPath\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;assetManager\u0026lt;/span\u0026gt;.getClass().getMethod(ADDSSETPATH, String.class); - //将未安装的Apk文件的添加进AssetManager中,第二个参数是apk的路径 - addAssetPath.invoke(assetManager, apkPath); - Resources \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;superRes\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getResources(); - Resources \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mResources\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration()); - return mResources; - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - /** - * 加载apk获得内部资源,并且替换背景 - * @param apkDir apk目录 - * @param apkName apk名字,带.apk - * @throws Exception - */ - private void dynamicLoadApk(String apkPath, String apkPackageName) throws Exception { - //在应用安装目录下创建一个名为app_dex文件夹目录,如果已经存在则不创建,这个目录主要是最优化目录，用于缓存dex文件 - File \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;optimizedDirectoryFile\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;getDir\u0026lt;/span\u0026gt;(DEX, Context.MODE_PRIVATE); - //打印路径 理论上是/data/data/package/app_dex - Log.v(TAG, optimizedDirectoryFile.getPath().toString()); - //构建DexClassLoader - DexClassLoader \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;dexClassLoader\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DexClassLoader(apkPath, optimizedDirectoryFile.getPath(), null, ClassLoader.getSystemClassLoader()); - //通过使用apk自己的类加载器，反射出R类中相应的内部类进而获取我们需要的资源id - Class\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;clazz\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;dexClassLoader\u0026lt;/span\u0026gt;.loadClass(apkPackageName + DRAWABLE); - //得到名为about_log的这张图片字段,这个图片是为安装apk里面的图片 - Field \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;field\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;clazz\u0026lt;/span\u0026gt;.getDeclaredField(IMAGE_ID); - //得到图片id - int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;resId\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;field\u0026lt;/span\u0026gt;.getInt(R.id.class); - //得到插件apk中的Resource - Resources \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mResources\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;getPluginResources\u0026lt;/span\u0026gt;(apkPath); - if (mResources != null) { - //通过插件apk中的Resource得到resId对应的资源 - Drawable \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;btnDrawable\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;mResources\u0026lt;/span\u0026gt;.getDrawable(resId); - mLayout.setBackgroundDrawable(btnDrawable); - } else { - Log.d(TAG, \u0026amp;#8220;mResources is null\u0026amp;#8221;); - } - } - } 点击TextView内容“换皮肤”来触发的，当初背景是设置的一个机器人。 第六步：运行项目爆结果照片 点击换皮护之前背景图片如下 ![](http://img.blog.csdn.net/20161123212919989?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 点击换图片之后背景图片如下 ![](http://img.blog.csdn.net/20161123213141068?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) ok,说明获取到了这种图片资源，换皮肤成功，这里只是代表换皮肤意思，效果比较丑，不要喷哈。 第七步、总结 这样做资源和宿主分离了，减轻了apk负担，同时也有解耦和作用，我们手机一些浏览器换模式（日和夜）、QQ换皮肤、表情包、线上下载线下维护、是项目更加灵活，可扩展性更好，同时也复习了DexClassLoader和反射相关知识。 转载：http://blog.csdn.net/u011068702/article/details/53311437 ","permalink":"https://blog.zdltech.com/posts/android%E6%8F%92%E4%BB%B6%E5%8C%96%E5%BC%80%E5%8F%91%E4%B9%8B%E7%94%A8dexclassloader%E5%8A%A0%E8%BD%BD%E6%9C%AA%E5%AE%89%E8%A3%85%E7%9A%84apk%E6%9D%A5%E5%AE%9E%E7%8E%B0app%E5%88%87%E6%8D%A2%E8%83%8C/","summary":"\u003ch2 id=\"第一步先制做一个有我们需要的图片资源的apk\"\u003e第一步、先制做一个有我们需要的图片资源的APK\u003c/h2\u003e\n\u003cdiv\u003e\n  如下图，这里有个about_log.png,我们需要生成apk文件。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20161123204907181?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e生成的apk文件如果你不到项目的文件夹里面去取apk，想通过命令放到手机里面去可以快速用下面命令\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch3 id=\"1在手机里面通过包名找到apk路径一定不要忘记有--f\"\u003e1）、在手机里面通过包名找到apk路径，一定不要忘记有 -f\u003c/h3\u003e\n\u003cdiv class=\"dp-highlighter bg_html\" data-original-code=\"[html] view plain copy print?adb shell pm list package -f | grep com.example.testclassloader \" data-snippet-id=\"ext.27edca498992ebecb43b727aafc57792\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003e\n\u003cpre\u003e\u003ccode\u003e- adb shell pm list package -f | grep com.example.testclassloader\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e得到如下结果\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\" data-original-code=\"[html] view plain copy print?package:/data/app/com.example.testclassloader-2/base.apk=com.example.testclassloader \" data-snippet-id=\"ext.0c13c8f2d8ecb2a5dfbe586919a9ca7b\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- package:/data/app/com.example.testclassloader-2/\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;base.apk\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;com\u0026lt;/span\u0026gt;.example.testclassloader\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003ch3 id=\"2把baseapk拉到本地然后改名字命令如下\"\u003e2)、把base.apk拉到本地然后改名字，命令如下\u003c/h3\u003e\n\u003cdiv class=\"dp-highlighter bg_html\" data-original-code=\"[html] view plain copy print?adb shell pull /data/app/com.example.testclassloader-2/base.apk testClassLoader.apk \" data-snippet-id=\"ext.fd26d1a16b5f28a54b31f08447f77983\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- adb shell pull /data/app/com.example.testclassloader-2/base.apk  testClassLoader.apk\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003ch3 id=\"3把testclassloaderapk放到手机里面去命令如下\"\u003e3)、把testClassLoader.apk放到手机里面去，命令如下\u003c/h3\u003e\n\u003cdiv class=\"dp-highlighter bg_html\" data-original-code=\"[html] view plain copy print?adb shell push testClassLoader.apk /sdcard/ \" data-snippet-id=\"ext.14c34059f78270d5ebb426e218cc76d0\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- adb shell push testClassLoader.apk  /sdcard/\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003ch3 id=\"4去手机文件管理器里面找看是否有testclassloaderapk文件\"\u003e4)、去手机文件管理器里面找看是否有testClassLoader.apk文件\u003c/h3\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android插件化开发之用DexClassLoader加载未安装的APK来实现app切换背景皮肤"},{"content":"一直想把自己的写的开源小项目放到github中，这两天才花时间来学学Git。遇到些问题，百度了很多才解决。跟SVN一样，值得写一篇总结记录下，虽然上资源很多，但作为入门，自己遇到的写出来完全不一样。\n一、 Git与GitHub的简单介绍 Git是一个开源的分布式版本控制工具。\nGitHub是一个使用Git作为版本控制的项目托管平台，它是一个网站。\n详细请参考：http://www.cnblogs.com/cocowool/archive/2012/02/17/2356125.html\n二、 Git的安装 下载地址：https://git-scm.com/download/win 或 https://git-for-windows.github.io/\n安装时，全部默认选择即可。\n三、 AS中配置Git与GitHub 1. Git的配置 在Settings设置中。\nPath to Git executable: 【Git安装后的路径】\n然后“Test”测试一下，成功才可以。\n2. GitHub的配置 Host: github.com\nLogin: 【你的github用户名】\nPassword: 【github登录密码】\n填好后，也进行“Test”测试一下，同样成功才可以。\n测试完后按确定，会提示你是否设置密码，看个人需求。\n四、 上传代码到GitHub 1. 创建GitHub仓库 在Github上创建一个仓库：\n创建好后，将是这个样子，里面包括一个.gitignore忽略配置文件和一个README.md\ngit地址如下：\n2. 创建Git本地仓库 选择工程 —— VCS —— ……\n此时，VCS的5个图标显示出来了，且要提交的文件名都是暗红色\n3. 把工程add添加到仓库 选择工程 —— 右键 —— Git —— Add\nAdd后待提交的文件名是绿色\n4. commit提交 CommitMessage：填入提交说明信息。主要用于说明你做了哪些修改。\n按Commit提交即可。\n注：我每次都无法提交，commit后，进度对话框走到一半就立马消失了。解决办法见下面常见问题的“无法commit”。\n提交后的文件颜色是灰白色。修改过的文件时淡蓝色\n5. push推送到GitHub Commit后会自动弹出Push推送窗口，点“Define remote”。\nName：默认origin\nURL：就是github的网页地址，上面已提供获取方法\n上面的界面操作，等同于Git Bash中使用命令：\ngit remote add origin https://github.com/zjun615/GitHubTest.git\n然后“OK”再“Push”\n注：我这里的Push也会出问题，见下面的解决方法\n刷新github后，就能看到上传的工程文件：\n五、 常见问题 1. 无法commit 因为会检查代码，就算没有错误，只有警告它也会让你无法提交。不会像单个文件的提交一样，提示你选择Review还是继续commit。所以就取消提交页面的“Perform code analysis”选项\n2. 无法push推送 现象：\nPush的时候，弹出错误信息：Push rejected，Push to origin/master was rejected\n控制台输出的详细错误信息：\n原因：\n通过上述错误信息，告诉我们github中有我们本地没有的文件，需要先pull。在VCS —— Git —— Pull\nPull也会报错：Git Pull Failed，fatal: refusing to merge unrelated histories\n也就是说直接pull也是不行的。并提示拒绝合并两个不相关的仓库 * 解决办法： 打开Git Bush。本地资源管理器的工程目录下，右键——Git Bush Here。或直接打开Git Bash，然后用cd命令打开工程目录。 输入命令：**_git pull origin master –allow-unrelated-histories_** 表示允许不相关的仓库合并。 此时，你可以看到工程中多了两个github中的两个文件\n其中.gitignore文件是还没有添加的，需要添加然后提交。\n添加命令：git add .gitignore\n提交命令：git commit\n添加后提交，会弹出提交的提示信息： 这里是VIM文本编辑器让你提交。操作命令：\n进入到输入状态：按i键\n从输入状态退出：Esc键 —— Shift+;键 —— wq!(保存并退出)或q!(不保存退出) —— Enter\n最后使用提交，命令：**_git push –u origin master_** 上面信息代表上传成功，去github看看就知道了。\n此问题困扰了我很久才解决，最主要的就是这条命令： **_git pull origin master –allow-unrelated-histories_** 其他的命令都可以在界面上操作。 参考：\u0026lt;http://stackoverflow.com/questions/37937984/git-refusing-to-merge-unrelated-histories\u0026gt; ### \u0026lt;a name=\u0026quot;t14\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**3. 取消工程与Git的关联** {#3-取消工程与git的关联} 在本地项目工程下有一个.git文件夹，删除即可。 \u0026amp;nbsp; 转自：http://blog.csdn.net/a10615/article/details/52135617 ","permalink":"https://blog.zdltech.com/posts/as%E4%B8%ADgit%E4%B8%8Egithub%E7%9A%84%E4%BD%BF%E7%94%A8%E5%85%A5%E9%97%A8/","summary":"\u003cp\u003e一直想把自己的写的开源小项目放到github中，这两天才花时间来学学\u003ca href=\"http://lib.csdn.net/base/git\"\u003eGit\u003c/a\u003e。遇到些问题，百度了很多才解决。跟SVN一样，值得写一篇总结记录下，虽然上资源很多，但作为入门，自己遇到的写出来完全不一样。\u003c/p\u003e\n\u003ch2 id=\"一-git与github的简单介绍\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003e\u003cstrong\u003e一、 Git与GitHub的简单介绍\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eGit是一个开源的分布式\u003ca href=\"http://lib.csdn.net/base/git\"\u003e版本控制\u003c/a\u003e工具。\u003cbr\u003e\nGitHub是一个使用Git作为版本控制的项目托管平台，它是一个网站。\u003cbr\u003e\n详细请参考：\u003ca href=\"http://www.cnblogs.com/cocowool/archive/2012/02/17/2356125.html\"\u003ehttp://www.cnblogs.com/cocowool/archive/2012/02/17/2356125.html\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"二-git的安装\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e\u003cstrong\u003e二、 Git的安装\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e下载地址：\u003ca href=\"https://git-scm.com/download/win\"\u003ehttps://git-scm.com/download/win\u003c/a\u003e 或 \u003ca href=\"https://git-for-windows.github.io/\"\u003ehttps://git-for-windows.github.io/\u003c/a\u003e\u003cbr\u003e\n安装时，全部默认选择即可。\u003c/p\u003e\n\u003ch2 id=\"三-as中配置git与github\"\u003e\u003ca name=\"t2\"\u003e\u003c/a\u003e\u003cstrong\u003e三、 AS中配置Git与GitHub\u003c/strong\u003e\u003c/h2\u003e\n\u003ch3 id=\"1-git的配置\"\u003e\u003ca name=\"t3\"\u003e\u003c/a\u003e\u003cstrong\u003e1. Git的配置\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e在Settings设置中。\u003cbr\u003e\nPath to Git executable: 【Git安装后的路径】\u003cbr\u003e\n然后“Test”\u003ca href=\"http://lib.csdn.net/base/softwaretest\"\u003e测试\u003c/a\u003e一下，成功才可以。\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20160810014922627\"\u003e\u003c/p\u003e\n\u003ch3 id=\"2-github的配置\"\u003e\u003ca name=\"t4\"\u003e\u003c/a\u003e\u003cstrong\u003e2. GitHub的配置\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003eHost: github.com\u003cbr\u003e\nLogin: 【你的github用户名】\u003cbr\u003e\nPassword: 【github登录密码】\u003cbr\u003e\n填好后，也进行“Test”测试一下，同样成功才可以。\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20160810015011096\"\u003e\u003cbr\u003e\n测试完后按确定，会提示你是否设置密码，看个人需求。\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20160810015045245\"\u003e\u003c/p\u003e\n\u003ch2 id=\"四-上传代码到github\"\u003e\u003ca name=\"t5\"\u003e\u003c/a\u003e\u003cstrong\u003e四、 上传代码到GitHub\u003c/strong\u003e\u003c/h2\u003e\n\u003ch3 id=\"1-创建github仓库\"\u003e\u003ca name=\"t6\"\u003e\u003c/a\u003e\u003cstrong\u003e1. 创建GitHub仓库\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e在Github上创建一个仓库：\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20160810015152575\"\u003e\u003c/p\u003e\n\u003cp\u003e创建好后，将是这个样子，里面包括一个.gitignore忽略配置文件和一个README.md\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20160810015245310\"\u003e\u003c/p\u003e\n\u003cp\u003egit地址如下：\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20160810015310099\"\u003e\u003c/p\u003e\n\u003ch3 id=\"2-创建git本地仓库\"\u003e\u003ca name=\"t7\"\u003e\u003c/a\u003e\u003cstrong\u003e2. 创建Git本地仓库\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e选择工程 —— VCS —— ……\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20160810015357093\"\u003e\u003c/p\u003e\n\u003cp\u003e此时，VCS的5个图标显示出来了，且要提交的文件名都是暗红色\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20160810015612268\"\u003e\u003c/p\u003e\n\u003ch3 id=\"3-把工程add添加到仓库\"\u003e\u003ca name=\"t8\"\u003e\u003c/a\u003e\u003cstrong\u003e3. 把工程add添加到仓库\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e选择工程 —— 右键 —— Git —— Add\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20160810015525600\"\u003e\u003c/p\u003e\n\u003cp\u003eAdd后待提交的文件名是绿色\u003c/p\u003e\n\u003ch3 id=\"4-commit提交\"\u003e\u003ca name=\"t9\"\u003e\u003c/a\u003e\u003cstrong\u003e4. commit提交\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20160810015708207\"\u003e\u003c/p\u003e\n\u003cp\u003eCommitMessage：填入提交说明信息。主要用于说明你做了哪些修改。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20160810015741395\"\u003e\u003c/p\u003e\n\u003cp\u003e按Commit提交即可。\u003cbr\u003e\n注：我每次都无法提交，commit后，进度对话框走到一半就立马消失了。解决办法见下面常见问题的“无法commit”。\u003cbr\u003e\n提交后的文件颜色是灰白色。修改过的文件时淡蓝色\u003c/p\u003e\n\u003ch3 id=\"5-push推送到github\"\u003e\u003ca name=\"t10\"\u003e\u003c/a\u003e\u003cstrong\u003e5. push推送到GitHub\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003eCommit后会自动弹出Push推送窗口，点“Define remote”。\u003cbr\u003e\nName：默认origin\u003cbr\u003e\nURL：就是github的网页地址，上面已提供获取方法\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20160810020012414\"\u003e\u003c/p\u003e","title":"AS中Git与GitHub的使用入门"},{"content":" 打开网页时不调用系统浏览器， 而是在本WebView中显示： ![复制代码](http://common.cnblogs.com/images/copycode.gif) mWebView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } }); ![复制代码](http://common.cnblogs.com/images/copycode.gif) 通过java代码调用javascript ![复制代码](http://common.cnblogs.com/images/copycode.gif) WebSettings webSettings = mWebView .getSettings(); webSettings.setJavaScriptEnabled(true); mWebView.addJavascriptInterface(new Object() { public void clickOnAndroid() { mHandler.post(new Runnable() { public void run() { webview.loadUrl(\u0026#34;javascript:wave()\u0026#34;); } }); } }, \u0026#34;demo\u0026#34;); ![复制代码](http://common.cnblogs.com/images/copycode.gif) 按返回键时， 不退出程序而是返回上一浏览页面： ![复制代码](http://common.cnblogs.com/images/copycode.gif) public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK) \u0026amp;\u0026amp; mWebView.canGoBack()) { mWebView.goBack(); return true; } return super.onKeyDown(keyCode, event); } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 打开页面时， 自适应屏幕： WebSettings webSettings = mWebView .getSettings(); webSettings.setUseWideViewPort(true);//设置此属性，可任意比例缩放 webSettings.setLoadWithOverviewMode(true); 便页面支持缩放： WebSettings webSettings = mWebView .getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setBuiltInZoomControls(true); webSettings.setSupportZoom(true); 6.如果webView中需要用户手动输入用户名、密码或其他，则webview必须设置支持获取手势焦点。\n``` webview.requestFocusFromTouch(); ``` 7.WebView 加载界面主要调用三个方法：LoadUrl、LoadData、LoadDataWithBaseURL.\n1、LoadUrl 直接加载网页、图片并显示.（本地或是网络上的网页、图片、gif） 2、LoadData 显示文字与图片内容 （模拟器1.5、1.6） 3、LoadDataWithBase 显示文字与图片内容（支持多个模拟器版本） 8.WebSettings 的常用方法介绍\n![复制代码](http://common.cnblogs.com/images/copycode.gif) setJavaScriptEnabled(true); //支持js setPluginsEnabled(true); //支持插件 setUseWideViewPort(false); //将图片调整到适合webview的大小 setSupportZoom(true); //支持缩放 setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); //支持内容重新布局 supportMultipleWindows(); //多窗口 setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存 setAllowFileAccess(true); //设置可以访问文件 setNeedInitialFocus(true); //当webview调用requestFocus时为webview设置节点 webview webSettings.setBuiltInZoomControls(true); //设置支持缩放 setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口 setLoadWithOverviewMode(true); // 缩放至屏幕的大小 setLoadsImagesAutomatically(true); //支持自动加载图片 ![复制代码](http://common.cnblogs.com/images/copycode.gif) 9.WebViewClient 的方法全解\n![复制代码](http://common.cnblogs.com/images/copycode.gif) doUpdateVisitedHistory(WebView view, String url, boolean isReload) //(更新历史记录) onFormResubmission(WebView view, Message dontResend, Message resend) //(应用程序重新请求网页数据) onLoadResource(WebView view, String url) // 在加载页面资源时会调用，每一个资源（比如图片）的加载都会调用一次。 onPageStarted(WebView view, String url, Bitmap favicon) //这个事件就是开始载入页面调用的，通常我们可以在这设定一个loading的页面，告诉用户程序在等待网络响应。 onPageFinished(WebView view, String url) //在页面加载结束时调用。同样道理，我们知道一个页面载入完成，于是我们可以关闭loading 条，切换程序动作。 onReceivedError(WebView view, int errorCode, String description, String failingUrl)// (报告错误信息) onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host,String realm)//（获取返回信息授权请求） onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) //重写此方法可以让webview处理https请求。 onScaleChanged(WebView view, float oldScale, float newScale) // (WebView发生改变时调用) onUnhandledKeyEvent(WebView view, KeyEvent event) //（Key事件未被加载时调用） shouldOverrideKeyEvent(WebView view, KeyEvent event)//重写此方法才能够处理在浏览器中的按键事件。 shouldOverrideUrlLoading(WebView view, String url) //在点击请求的是链接是才会调用，重写此方法返回true表明点击网页里面的链接还是在当前的webview里跳转，不跳到浏览器那边。这个函数我们可以做很多操作，比如我们读取到某些特殊的URL，于是就可以不打开地址，取消这个操作，进行预先定义的其他操作，这对一个程序是非常必要的。 ![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` 1、width : 控制viewport的大小，可以指定一个值，如600， 或者特殊的值，如device-width为设备的宽度（单位为缩放为100%的CSS的像素） 2、height : 和width相对应，指定高度 3、initial-scale : 初始缩放比例，页面第一次加载时的缩放比例 4、maximum-scale : 允许用户缩放到的最大比例，范围从0到10.0 5、minimum-scale : 允许用户缩放到的最小比例，范围从0到10.0 6、user-scalable : 用户是否可以手动缩放，值可以是：①yes、 true允许用户缩放；②no、false不允许用户缩放\" data-snippet-id=\"ext.ccb8432def9ed981af59f83a732110e7\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003eandroid webview设置自适应任意大小的pc网页 webview自适应setUseWideViewPortsetLayoutAlgorithmwebSettingsandroid webview [html] view plaincopyprint? WebSettings webSettings = view.getSettings();\nwebSettings.setJavaScriptEnabled(true);\n// User settings\nwebSettings.setJavaScriptEnabled(true);\nwebSettings.setJavaScriptCanOpenWindowsAutomatically(true);\nwebSettings.setUseWideViewPort(true);//关键点\nwebSettings.setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);\nwebSettings.setDisplayZoomControls(false);\nwebSettings.setJavaScriptEnabled(true); // 设置支持javascript脚本\nwebSettings.setAllowFileAccess(true); // 允许访问文件\nwebSettings.setBuiltInZoomControls(true); // 设置显示缩放按钮\nwebSettings.setSupportZoom(true); // 支持缩放\nwebSettings.setLoadWithOverviewMode(true);\nDisplayMetrics metrics = new DisplayMetrics();\ngetWindowManager().getDefaultDisplay().getMetrics(metrics);\nint mDensity = metrics.densityDpi;\nLog.d(\u0026ldquo;maomao\u0026rdquo;, \u0026ldquo;densityDpi = \u0026quot; + mDensity);\nif (mDensity == 240) {\nwebSettings.setDefaultZoom(ZoomDensity.FAR);\n} else if (mDensity == 160) {\nwebSettings.setDefaultZoom(ZoomDensity.MEDIUM);\n} else if(mDensity == 120) {\nwebSettings.setDefaultZoom(ZoomDensity.CLOSE);\n}else if(mDensity == DisplayMetrics.DENSITY_XHIGH){\nwebSettings.setDefaultZoom(ZoomDensity.FAR);\n}else if (mDensity == DisplayMetrics.DENSITY_TV){\nwebSettings.setDefaultZoom(ZoomDensity.FAR);\n}else{\nwebSettings.setDefaultZoom(ZoomDensity.MEDIUM);\n}\n/**\n用WebView显示图片，可使用这个参数 设置网页布局类型： 1、LayoutAlgorithm.NARROW_COLUMNS ： 适应内容大小 2、LayoutAlgorithm.SINGLE_COLUMN:适应屏幕，内容将自动缩放\n*/\nwebSettings.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS); 其中关键是以下设置属性 webSettings.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS); webSettings.setUseWideViewPort(true);\n这样的话如果你的PC网页里面没有设置 meta标签 viewport的缩放设置也没有关系。\n常用的 viewport meta 如下：\n1 \u0026lt;meta name=\u0026ldquo;viewport\u0026rdquo; content=\u0026ldquo;width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\u0026rdquo; /\u0026gt;\n1、width : 控制viewport的大小，可以指定一个值，如600， 或者特殊的值，如device-width为设备的宽度（单位为缩放为100%的CSS的像素）\n2、height : 和width相对应，指定高度\n3、initial-scale : 初始缩放比例，页面第一次加载时的缩放比例\n4、maximum-scale : 允许用户缩放到的最大比例，范围从0到10.0\n5、minimum-scale : 允许用户缩放到的最小比例，范围从0到10.0\n6、user-scalable : 用户是否可以手动缩放，值可以是：①yes、 true允许用户缩放；②no、false不允许用户缩放\nWebSettings用于管理WebView状态配置，当WebView第一次被创建时，WebView包含着一个默认的配置，这些默认的配置将通过get方法返回，通过WebView中的getSettings方法获得一个WebSettings对象，如果一个WebView被销毁，在WebSettings中所有回调方法将抛出IllegalStateException异常。 1、setSupportZoom(boolean support) 设置WebView是否支持使用屏幕控件或手势进行缩放，默认是true，支持缩放。 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setSupportZoom(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 2、setMediaPlaybackRequiresUserGesture(boolean require) 设置WebView是否通过手势触发播放媒体，默认是true，需要手势触发。 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setMediaPlaybackRequiresUserGesture(false); \u0026#34; data-snippet-id=\u0026#34;ext.342589f5b082706e962e0694b0bb05f4\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setMediaPlaybackRequiresUserGesture(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 3、setBuiltInZoomControls(boolean enabled) 设置WebView是否使用其内置的变焦机制，该机制集合屏幕缩放控件使用，默认是false，不使用内置变焦机制。 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setBuiltInZoomControls(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 4、setDisplayZoomControls(boolean enabled) 设置WebView使用内置缩放机制时，是否展现在屏幕缩放控件上，默认true，展现在控件上。 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setDisplayZoomControls(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 5、setAllowFileAccess(boolean allow) 设置在WebView内部是否允许访问文件，默认允许访问。 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setAllowFileAccess(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 6、setAllowContentAccess(boolean allow) 设置WebView是否使用其内置的变焦机制，该机制结合屏幕缩放控件使用，默认是false，不使用内置变焦机制。 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setAllowContentAccess(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 7、setLoadWithOverviewMode(boolean overview) 设置WebView是否使用预览模式加载界面。 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setLoadWithOverviewMode(false); \u0026#34; data-snippet-id=\u0026#34;ext.c2f5f70d36700f3031c7fccf6d3ca68c\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setLoadWithOverviewMode(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 8、setSaveFormData(boolean save) 设置WebView是否保存表单数据，默认true，保存数据。 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setSaveFormData(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 9、setTextZoom(int textZoom) 设置WebView中加载页面字体变焦百分比，默认100，整型数。 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setTextZoom(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 10、setAcceptThirdPartyCookies(boolean accept) 设置WebView访问第三方Cookies策略，参考CookieManager提供的方法：setShouldAcceptThirdPartyCookies。 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setAcceptThirdPartyCookies(false); \u0026#34; data-snippet-id=\u0026#34;ext.37c3dae673198683080e0a9652f06380\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setAcceptThirdPartyCookies(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 11、setUseWideViewPort(boolean use) 设置WebView是否使用viewport，当该属性被设置为false时，加载页面的宽度总是适应WebView控件宽度；当被设置为true，当前页面包含viewport属性标签，在标签中指定宽度值生效，如果页面不包含viewport标签，无法提供一个宽度值，这个时候该方法将被使用。 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setUseWideViewPort(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;)； \u0026lt;/div\u0026gt; 12、setSupportMultipleWindows(boolean support) 设置WebView是否支持多屏窗口，参考WebChromeClient#onCreateWindow，默认false，不支持。 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setSupportMultipleWindows(true); \u0026#34; data-snippet-id=\u0026#34;ext.4dee8c96fbfe75879ab258a822a3d45d\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setSupportMultipleWindows(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 13、setLayoutAlgorithm(LayoutAlgorithm l) 设置WebView底层的布局算法，参考LayoutAlgorithm#NARROW_COLUMNS，将会重新生成WebView布局 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setLayoutAlgorithm(LayoutAlgorithm l)； \u0026#34; data-snippet-id=\u0026#34;ext.7339c879ba40f18da85489391822e7ad\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; - getSettings.setLayoutAlgorithm(LayoutAlgorithm l)； \u0026lt;/div\u0026gt; 14、setStandardFontFamily(String font) 设置WebView标准字体库字体，默认字体“sans-serif”。 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setStandardFontFamily(\u0026amp;quot;sans-serif\u0026amp;quot;); \u0026#34; data-snippet-id=\u0026#34;ext.429bac1e40341f6450d4006869897b1b\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setStandardFontFamily(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026amp;#8220;sans-serif\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 15、setFixedFontFamily(String font) 设置WebView固定的字体库字体，默认“monospace”。 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setFixedFontFamily(\u0026amp;quot;monospace\u0026amp;quot;); \u0026#34; data-snippet-id=\u0026#34;ext.370c848cf6baeb1849d9b139301455ba\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setFixedFontFamily(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026amp;#8220;monospace\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 16、setSansSerifFontFamily(String font) 设置WebView Sans SeriFontFamily字体库字体，默认“sans-serif”。 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setSansSerifFontFamily(\u0026amp;quot;sans-serif\u0026amp;quot;); \u0026#34; data-snippet-id=\u0026#34;ext.e7dd16a3cadd3fbe04f2a99c96b59974\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setSansSerifFontFamily(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026amp;#8220;sans-serif\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 17、setSerifFontFamily(String font) 设置WebView seri FontFamily字体库字体，默认“sans-serif”。 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setSansSerifFontFamily(\u0026amp;quot;sans-serif\u0026amp;quot;); \u0026#34; data-snippet-id=\u0026#34;ext.e7dd16a3cadd3fbe04f2a99c96b59974\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setSansSerifFontFamily(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026amp;#8220;sans-serif\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 18、setCursiveFontFamily(String font) 设置WebView字体库字体，默认“cursive” \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setCursiveFontFamily(\u0026amp;quot;cursive\u0026amp;quot;); \u0026#34; data-snippet-id=\u0026#34;ext.0e81e0cd838d419febd2608f44dbc4c0\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setCursiveFontFamily(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026amp;#8220;cursive\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 19、setFantasyFontFamily(String font) 设置WebView字体库字体，默认“fantasy”。 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setFantasyFontFamily(\u0026amp;quot;fantasy\u0026amp;quot;); \u0026#34; data-snippet-id=\u0026#34;ext.a168bb1a8233935ba8711446ddcbb397\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setFantasyFontFamily(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026amp;#8220;fantasy\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 20、setMinimumFontSize(int size) 设置WebView字体最小值，默认值8，取值1到72 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setMinimumFontSize(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 21、setMinimumLogicalFontSize(int size) 设置WebView逻辑上最小字体值，默认值8，取值1到72 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setMinimumLogicalFontSize(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 22、setDefaultFontSize(int size) 设置WebView默认值字体值，默认值16，取值1到72 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setDefaultFontSize(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 23、setDefaultFixedFontSize(int size) 设置WebView默认固定的字体值，默认值16，取值1到72 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setDefaultFixedFontSize(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 24、setLoadsImagesAutomatically(boolean flag) 设置WebView是否加载图片资源，默认true，自动加载图片 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setLoadsImagesAutomatically(false); \u0026#34; data-snippet-id=\u0026#34;ext.db53a3bb934fdc540ac4008e89cfd5b3\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setLoadsImagesAutomatically(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 25、setBlockNetworkImage(boolean flag) 设置WebView是否以http、https方式访问从网络加载图片资源，默认false \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setBlockNetworkImage(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 26、setBlockNetworkLoads(boolean flag) 设置WebView是否从网络加载资源，Application需要设置访问网络权限，否则报异常 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setBlockNetworkLoads(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 27、setJavaScriptEnabled(boolean flag) 设置WebView是否允许执行JavaScript脚本，默认false，不允许 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setJavaScriptEnabled(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 28、setAllowUniversalAccessFromFileURLs(boolean flag) 设置WebView运行中的脚本可以是否访问任何原始起点内容，默认true \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setAllowUniversalAccessFromFileURLs(false); \u0026#34; data-snippet-id=\u0026#34;ext.4238a9bd30d5dcb07027c59173bcd744\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setAllowUniversalAccessFromFileURLs(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 29、setAllowFileAccessFromFileURLs(boolean flag) 设置WebView运行中的一个文件方案被允许访问其他文件方案中的内容，默认值true \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setAllowFileAccessFromFileURLs(false); \u0026#34; data-snippet-id=\u0026#34;ext.3dd034da8b8b35572480ef9ada3e3a7b\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setAllowFileAccessFromFileURLs(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 30、setGeolocationDatabasePath(String databasePath) 设置WebView保存地理位置信息数据路径，指定的路径Application具备写入权限 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setGeolocationDatabasePath(String path); \u0026#34; data-snippet-id=\u0026#34;ext.071d81098e35cc28bc88f2f6f2a99a2e\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; - getSettings.setGeolocationDatabasePath(String path); \u0026lt;/div\u0026gt; 31、setAppCacheEnabled(boolean flag) 设置Application缓存API是否开启，默认false，设置有效的缓存路径参考setAppCachePath(String path)方法 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setAppCacheEnabled(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 32、setAppCachePath(String appCachePath) 设置当前Application缓存文件路径，Application Cache API能够开启需要指定Application具备写入权限的路径 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setAppCachePath(String appCachePath); \u0026#34; data-snippet-id=\u0026#34;ext.24285fb0b1a9b9b4381630fc6a21b7e7\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; - getSettings.setAppCachePath(String appCachePath); \u0026lt;/div\u0026gt; 33、setDatabaseEnabled(boolean flag) 设置是否开启数据库存储API权限，默认false，未开启，可以参考setDatabasePath(String path) \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setDatabaseEnabled(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 34、setDomStorageEnabled(boolean flag) 设置是否开启DOM存储API权限，默认false，未开启，设置为true，WebView能够使用DOM storage API \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setDomStorageEnabled(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 35、setGeolocationEnabled(boolean flag) 设置是否开启定位功能，默认true，开启定位 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setGeolocationEnabled(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 36、setJavaScriptCanOpenWindowsAutomatically(boolean flag) 设置脚本是否允许自动打开弹窗，默认false，不允许 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setJavaScriptCanOpenWindowsAutomatically(true); \u0026#34; data-snippet-id=\u0026#34;ext.d233c5f7e27c0368d20ac42d6b4e9cc8\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setJavaScriptCanOpenWindowsAutomatically(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 37、setDefaultTextEncodingName(String encoding) 设置WebView加载页面文本内容的编码，默认“UTF-8”。 \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setDefaultTextEncodingName(\u0026amp;quot;UTF-8\u0026amp;quot;); \u0026#34; data-snippet-id=\u0026#34;ext.027b71c6f5576d613b7aa4686e3361b2\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setDefaultTextEncodingName(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026amp;#8220;UTF-8\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 38、setUserAgentString(String ua) 设置WebView代理字符串，如果String为null或为空，将使用系统默认值 \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; - getSettings.setUserAgentString(String ua); \u0026lt;/div\u0026gt; 39、setNeedInitialFocus(boolean flag) 设置WebView是否需要设置一个节点获取焦点当被回调的时候，默认true \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; - getSettings.setNeedInitialFocus(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; 40、setCacheMode(int mode) 重写缓存被使用到的方法，该方法基于Navigation Type，加载普通的页面，将会检查缓存同时重新验证是否需要加载，如果不需要重新加载，将直接从缓存读取数据，允许客户端通过指定LOAD_DEFAULT、LOAD_CACHE_ELSE_NETWORK、LOAD_NO_CACHE、LOAD_CACHE_ONLY其中之一重写该行为方法，默认值LOAD_DEFAULT \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setCacheMode(WebSettings.LOAD_DEFAULT); \u0026#34; data-snippet-id=\u0026#34;ext.7445efb2477a16b7a2eb6cd0cb7fca82\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; - getSettings.setCacheMode(WebSettings.LOAD_DEFAULT); \u0026lt;/div\u0026gt; 41、setMixedContentMode(int mode) 设置当一个安全站点企图加载来自一个不安全站点资源时WebView的行为，android.os.Build.VERSION_CODES.KITKAT默认为MIXED_CONTENT_ALWAYS_ALLOW，android.os.Build.VERSION_CODES#LOLLIPOP默认为MIXED_CONTENT_NEVER_ALLOW，取值其中之一：MIXED_CONTENT_NEVER_ALLOW、MIXED_CONTENT_ALWAYS_ALLOW、MIXED_CONTENT_COMPATIBILITY_MODE. \u0026lt;div class=\u0026#34;top-box hide\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter\u0026#34; data-original-code=\u0026#34; getSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); \u0026#34; data-snippet-id=\u0026#34;ext.6529fa3720481ead6048f41f307618c6\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt; - getSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-webview%E4%BD%BF%E7%94%A8%E8%AF%A6%E8%A7%A3/","summary":"\u003col\u003e\n\u003cli\u003e打开网页时不调用系统浏览器， 而是在本WebView中显示：\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emWebView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetWebViewClient(new WebViewClient(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public boolean shouldOverrideUrlLoading(WebView view, String url) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        view\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eloadUrl(url);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e通过java代码调用javascript\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWebSettings webSettings \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e   mWebView \u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetSettings();       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewebSettings\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetJavaScriptEnabled(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e); \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emWebView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddJavascriptInterface(new Object() {       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          public void clickOnAndroid() {       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              mHandler\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epost(new Runnable() {       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  public void run() {       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      webview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eloadUrl(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;javascript:wave()\u0026#34;\u003c/span\u003e);       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  }       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              });       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          }       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      }, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;demo\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003col start=\"3\"\u003e\n\u003cli\u003e按返回键时， 不退出程序而是返回上一浏览页面：\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic boolean onKeyDown(int keyCode, KeyEvent event) {       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      if ((keyCode == KeyEvent.KEYCODE_BACK) \u0026amp;\u0026amp; mWebView.canGoBack()) {       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          mWebView.goBack();       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          return true;       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      }       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      return super.onKeyDown(keyCode, event);       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003col start=\"4\"\u003e\n\u003cli\u003e打开页面时， 自适应屏幕：\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWebSettings webSettings =   mWebView .getSettings();       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewebSettings.setUseWideViewPort(true);//设置此属性，可任意比例缩放\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewebSettings.setLoadWithOverviewMode(true);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003col start=\"5\"\u003e\n\u003cli\u003e便页面支持缩放：\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eWebSettings webSettings =   mWebView .getSettings();       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewebSettings.setJavaScriptEnabled(true);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewebSettings.setBuiltInZoomControls(true);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewebSettings.setSupportZoom(true);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp\u003e6.如果webView中需要用户手动输入用户名、密码或其他，则webview必须设置支持获取手势焦点。\u003c/p\u003e","title":"Android webview使用详解"},{"content":"直接上代码了，主要使用到onRequestPermissionsResult、requestPermissions和checkSelfPermission 方法\n@Override\npublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\nswitch (requestCode) {\ncase REQUEST_CODE_ASK_PERMISSIONS:\nif (grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n// Permission Granted\nscanIntent();\n} else {\n// Permission Denied\nToast.makeText(getActivity(), “您拒绝了权限(请到设置中设置权限)”, Toast.LENGTH_SHORT)\n.show();\n}\nbreak;\ncase 300:\ntest2();\nbreak;\ndefault:\nsuper.onRequestPermissionsResult(requestCode, permissions, grantResults);\n}\n}\npublic void checkPermission() {\nif (Build.VERSION.SDK_INT \u0026gt;= 23) {\n// int write = getActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);\n// int read = getActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE);\nint write = ContextCompat.checkSelfPermission(getActivity(),Manifest.permission.WRITE_EXTERNAL_STORAGE);\nint read = ContextCompat.checkSelfPermission(getActivity(),Manifest.permission.READ_EXTERNAL_STORAGE);\nif (write != PackageManager.PERMISSION_GRANTED || read != PackageManager.PERMISSION_GRANTED) {\nrequestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 300);\n} else {\ntest2();\n}\n} else {\ntest2();\n}\n}\nprivate void test2(){\nStringBuffer stringBuffer = new StringBuffer(Environment.getExternalStorageDirectory().getAbsolutePath());\n// StringBuffer stringBuffer = new StringBuffer(getActivity().getExternalFilesDir(null).getAbsolutePath());\nstringBuffer.append(“/export/”);\nString str= stringBuffer.toString();\nLog.e(“STATE”, Environment.getExternalStorageState());\nLog.e(“STATE”, getActivity().getExternalFilesDir(null).getAbsolutePath());\nLog.e(“STATE”, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath());\nLocalDBManagerTools localDBManagerTools = new LocalDBManagerTools();\nlocalDBManagerTools.exportAllDatabases(str,getActivity());\nLocalSharedPreferencesManagerTools localSharedPreferencesManagerTools = new LocalSharedPreferencesManagerTools();\nlocalSharedPreferencesManagerTools.exportAllSharedPrefrerences(str,getActivity());\n}\n","permalink":"https://blog.zdltech.com/posts/android23%E4%BB%A5%E4%B8%8A%E5%8A%A8%E6%80%81%E9%89%B4%E6%9D%83%E5%AE%9E%E7%8E%B0%E7%9A%84%E6%96%B9%E6%B3%95%E5%8F%8A%E6%80%9D%E8%B7%AF/","summary":"\u003cp\u003e直接上代码了，主要使用到onRequestPermissionsResult、requestPermissions和checkSelfPermission 方法\u003c/p\u003e\n\u003cp\u003e@Override\u003cbr\u003e\npublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\u003cbr\u003e\nswitch (requestCode) {\u003cbr\u003e\ncase REQUEST_CODE_ASK_PERMISSIONS:\u003cbr\u003e\nif (grantResults[0] == PackageManager.PERMISSION_GRANTED) {\u003cbr\u003e\n// Permission Granted\u003cbr\u003e\nscanIntent();\u003cbr\u003e\n} else {\u003cbr\u003e\n// Permission Denied\u003cbr\u003e\nToast.makeText(getActivity(), “您拒绝了权限(请到设置中设置权限)”, Toast.LENGTH_SHORT)\u003cbr\u003e\n.show();\u003cbr\u003e\n}\u003cbr\u003e\nbreak;\u003cbr\u003e\ncase 300:\u003cbr\u003e\ntest2();\u003cbr\u003e\nbreak;\u003cbr\u003e\ndefault:\u003cbr\u003e\nsuper.onRequestPermissionsResult(requestCode, permissions, grantResults);\u003cbr\u003e\n}\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003epublic void checkPermission() {\u003c/p\u003e\n\u003cp\u003eif (Build.VERSION.SDK_INT \u0026gt;= 23) {\u003cbr\u003e\n// int write = getActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);\u003cbr\u003e\n// int read = getActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE);\u003cbr\u003e\nint write = ContextCompat.checkSelfPermission(getActivity(),Manifest.permission.WRITE_EXTERNAL_STORAGE);\u003cbr\u003e\nint read = ContextCompat.checkSelfPermission(getActivity(),Manifest.permission.READ_EXTERNAL_STORAGE);\u003cbr\u003e\nif (write != PackageManager.PERMISSION_GRANTED || read != PackageManager.PERMISSION_GRANTED) {\u003cbr\u003e\nrequestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 300);\u003cbr\u003e\n} else {\u003cbr\u003e\ntest2();\u003cbr\u003e\n}\u003cbr\u003e\n} else {\u003cbr\u003e\ntest2();\u003cbr\u003e\n}\u003cbr\u003e\n}\u003c/p\u003e","title":"Android23以上动态鉴权实现的方法及思路"},{"content":"html中其实是无法判断应用是否安装，除非在webview中通过js bridge，这里通过一种方式达到此目的。\n1、编辑AndroidManifest.xml：\n主要是增加第二个，myapp用来标识schema，最好能保证手机系统唯一，那样就可以打开应用，而不是弹出一个选择框。\nAndroid:pathPrefix标识url的path，可以附带自己的数据通过string传递到activity，比如完整url为 myapp://xxx/openwith?data=mydata\n**[html]** [view plain](http://blog.csdn.net/vinrex/article/details/38082759#) [copy](http://blog.csdn.net/vinrex/article/details/38082759#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;com.abc.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:configChanges\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;orientation|keyboardHidden|navigation|screenSize\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:screenOrientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;landscape\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:theme\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Theme.NoTitleBar.Fullscreen\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;action\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.action.MAIN\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;category\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.category.LAUNCHER\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;action\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.action.VIEW\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;category\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.category.BROWSABLE\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;category\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.category.DEFAULT\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scheme\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;myapp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:pathPrefix\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;/xxx/openwith\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - t;/activity\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 然后通过activity获得data数据：\n**[java]** [view plain](http://blog.csdn.net/vinrex/article/details/38082759#) [copy](http://blog.csdn.net/vinrex/article/details/38082759#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - Uri uridata = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getIntent().getData(); - String mydata = uridata.getQueryParameter(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;data\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026amp;#8230; - } ** **\n** 2、编写html页面：**\n整个页面也许是某个app的详细介绍，这里只写出关键的js代码：\n","permalink":"https://blog.zdltech.com/posts/%E5%9C%A8html%E9%A1%B5%E9%9D%A2%E4%B8%AD%E5%88%A4%E6%96%AD%E6%9C%AC%E5%9C%B0app%E6%98%AF%E5%90%A6%E5%AE%89%E8%A3%85%E5%B9%B6%E6%89%93%E5%BC%80/","summary":"\u003cp\u003ehtml中其实是无法判断应用是否安装，除非在webview中通过js bridge，这里通过一种方式达到此目的。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1、编辑AndroidManifest.xml：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e主要是增加第二个\u003cintent-filter\u003e，myapp用来标识schema，最好能保证手机系统唯一，那样就可以打开应用，而不是弹出一个选择框。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://lib.csdn.net/base/android\"\u003eAndroid\u003c/a\u003e:pathPrefix标识url的path，可以附带自己的数据通过string传递到activity，比如完整url为 myapp://xxx/openwith?data=mydata\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"dp-highlighter bg_html\" style=\"font-family: Consolas, 'Courier New', Courier, mono, serif; font-size: 12px; background-color: #e7e5dc; width: 700.906px; overflow-x: auto; overflow-y: hidden; padding-top: 1px; text-align: left; margin: 18px 0px !important; position: relative; color: #333333; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;\" data-original-code=\"[html] view plain copy print?\u003cactivity  \n  android:name=\u0026quot;com.abc.MainActivity\u0026quot;  \n  android:configChanges=\u0026quot;orientation|keyboardHidden|navigation|screenSize\u0026quot;  \n  android:screenOrientation=\u0026quot;landscape\u0026quot;  \n  android:theme=\u0026quot;@android:style/Theme.NoTitleBar.Fullscreen\u0026quot; \u003e  \n  \u003cintent-filter\u003e  \n      \u003caction android:name=\u0026quot;android.intent.action.MAIN\u0026quot; /\u003e  \n      \u003ccategory android:name=\u0026quot;android.intent.category.LAUNCHER\u0026quot; /\u003e  \n  \u003c/intent-filter\u003e  \n  \u003cintent-filter\u003e  \n      \u003caction android:name=\u0026quot;android.intent.action.VIEW\u0026quot; /\u003e  \n      \u003ccategory android:name=\u0026quot;android.intent.category.BROWSABLE\u0026quot; /\u003e  \n      \u003ccategory android:name=\u0026quot;android.intent.category.DEFAULT\u0026quot;/\u003e  \n      \u003cdata android:scheme=\u0026quot;myapp\u0026quot; android:pathPrefix=\u0026quot;/xxx/openwith\u0026quot; /\u003e  \n  \u003c/intent-filter\u003e  \nt;/activity\u003e  \n\" data-snippet-id=\"ext.6fc3be68818d9b7514ecf10e22ed4651\" data-snippet-saved=\"false\" data-codota-status=\"done\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/vinrex/article/details/38082759#)\u003cspan data-mod=\"popu_168\"\u003e [copy](http://blog.csdn.net/vinrex/article/details/38082759#)\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot; data-mce-fragment=\u0026quot;1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;com.abc.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:configChanges\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;orientation|keyboardHidden|navigation|screenSize\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:screenOrientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;landscape\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:theme\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Theme.NoTitleBar.Fullscreen\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;action\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.action.MAIN\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;category\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.category.LAUNCHER\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;action\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.action.VIEW\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;category\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.category.BROWSABLE\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;category\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.category.DEFAULT\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scheme\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;myapp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:pathPrefix\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;/xxx/openwith\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- t;/activity\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e然后通过activity获得data数据：\u003c/p\u003e","title":"在html页面中判断本地app是否安装并打开"},{"content":"获取图片中点击的颜色\nimport android.os.Bundle;\nimport android.app.Activity;\nimport android.graphics.Bitmap;\nimport android.graphics.Matrix;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.View.OnTouchListener;\nimport android.widget.ImageView;\nimport android.widget.TextView;\npublic class MainActivity extends Activity {\nTextView touchedXY, invertedXY, imgSize, colorRGB;\nImageView imgSource1, imgSource2;\n@Override\npublic void onCreate(Bundle savedInstanceState) {\nsuper.onCreate(savedInstanceState);\nsetContentView(R.layout.activity_main);\ntouchedXY = (TextView)findViewById(R.id.xy);\ninvertedXY = (TextView)findViewById(R.id.invertedxy);\nimgSize = (TextView)findViewById(R.id.size);\ncolorRGB = (TextView)findViewById(R.id.colorrgb);\nimgSource1 = (ImageView)findViewById(R.id.source1);\nimgSource2 = (ImageView)findViewById(R.id.source2);\nimgSource1.setOnTouchListener(imgSourceOnTouchListener);\nimgSource2.setOnTouchListener(imgSourceOnTouchListener);\n}\nOnTouchListener imgSourceOnTouchListener = new OnTouchListener() {\n@Override\npublic boolean onTouch(View view, MotionEvent event) {\nfloat eventX = event.getX();\nfloat eventY = event.getY();\nfloat[] eventXY = new float[] {eventX, eventY};\nMatrix invertMatrix = new Matrix();\n((ImageView)view).getImageMatrix().invert(invertMatrix);\ninvertMatrix.mapPoints(eventXY);\nint x = Integer.valueOf((int)eventXY[0]);\nint y = Integer.valueOf((int)eventXY[1]);\ntouchedXY.setText( “touched position: ” + String.valueOf(eventX) + ” / ” + String.valueOf(eventY)); invertedXY.setText(“touched position: ” + String.valueOf(x) + ” / ” + String.valueOf(y));\nDrawable imgDrawable = ((ImageView)view).getDrawable();\nBitmap bitmap = ((BitmapDrawable)imgDrawable).getBitmap();\nimgSize.setText(“drawable size: “+ String.valueOf(bitmap.getWidth()) + ” / “+ String.valueOf(bitmap.getHeight()));\n//Limit x, y range within bitmap\nif(x \u0026lt; 0){x = 0; }\nelse if(x \u0026gt; bitmap.getWidth()-1) {\nx = bitmap.getWidth()-1;\n}\nif(y \u0026lt; 0){\ny = 0;\n}else if(y \u0026gt; bitmap.getHeight()-1) {\ny = bitmap.getHeight()-1;\n}\nint touchedRGB = bitmap.getPixel(x, y);\ncolorRGB.setText(“touched color: ” + “#” + Integer.toHexString(touchedRGB));\ncolorRGB.setTextColor(touchedRGB);\nreturn true;\n}\n};\n}\n布局\n\u0026lt;LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android” xmlns:tools=”http://schemas.android.com/tools” android:layout_width=”match_parent” android:layout_height=”match_parent” android:orientation=”vertical”\u0026gt; \u0026lt;TextView android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:text=”@string/hello_world” tools:context=”.MainActivity” /\u0026gt; \u0026lt;TextView android:id=”@+id/xy” android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:text=”touched position: “/\u0026gt; \u0026lt;TextView android:id=”@+id/invertedxy” android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:text=”inverted touched position: “/\u0026gt; \u0026lt;TextView android:id=”@+id/size” android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:text=”drawable size: “/\u0026gt; \u0026lt;TextView android:id=”@+id/colorrgb” android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:text=”touched color: “/\u0026gt; \u0026lt;ImageView android:id=”@+id/source1″ android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:src=”@drawable/ic_launcher”/\u0026gt; \u0026lt;ImageView android:id=”@+id/source2″ android:layout_width=”match_parent” android:layout_height=”match_parent” android:src=”@drawable/ic_launcher”/\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android%E8%8E%B7%E5%8F%96%E7%82%B9%E5%87%BB%E7%9A%84%E5%9B%BE%E7%89%87%E7%9A%84%E9%A2%9C%E8%89%B2/","summary":"\u003cp\u003e获取图片中点击的颜色\u003c/p\u003e\n\u003cp\u003eimport android.os.Bundle;\u003cbr\u003e\nimport android.app.Activity;\u003cbr\u003e\nimport android.graphics.Bitmap;\u003cbr\u003e\nimport android.graphics.Matrix;\u003cbr\u003e\nimport android.graphics.drawable.BitmapDrawable;\u003cbr\u003e\nimport android.graphics.drawable.Drawable;\u003cbr\u003e\nimport android.view.MotionEvent;\u003cbr\u003e\nimport android.view.View;\u003cbr\u003e\nimport android.view.View.OnTouchListener;\u003cbr\u003e\nimport android.widget.ImageView;\u003cbr\u003e\nimport android.widget.TextView;\u003c/p\u003e\n\u003cp\u003epublic class MainActivity extends Activity {\u003cbr\u003e\nTextView touchedXY, invertedXY, imgSize, colorRGB;\u003cbr\u003e\nImageView imgSource1, imgSource2;\u003c/p\u003e\n\u003cp\u003e@Override\u003cbr\u003e\npublic void onCreate(Bundle savedInstanceState) {\u003cbr\u003e\nsuper.onCreate(savedInstanceState);\u003cbr\u003e\nsetContentView(R.layout.activity_main);\u003cbr\u003e\ntouchedXY = (TextView)findViewById(R.id.xy);\u003cbr\u003e\ninvertedXY = (TextView)findViewById(R.id.invertedxy);\u003cbr\u003e\nimgSize = (TextView)findViewById(R.id.size);\u003cbr\u003e\ncolorRGB = (TextView)findViewById(R.id.colorrgb);\u003cbr\u003e\nimgSource1 = (ImageView)findViewById(R.id.source1);\u003cbr\u003e\nimgSource2 = (ImageView)findViewById(R.id.source2);\u003cbr\u003e\nimgSource1.setOnTouchListener(imgSourceOnTouchListener);\u003cbr\u003e\nimgSource2.setOnTouchListener(imgSourceOnTouchListener);\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003eOnTouchListener imgSourceOnTouchListener = new OnTouchListener() {\u003cbr\u003e\n@Override\u003cbr\u003e\npublic boolean onTouch(View view, MotionEvent event) {\u003cbr\u003e\nfloat eventX = event.getX();\u003cbr\u003e\nfloat eventY = event.getY();\u003cbr\u003e\nfloat[] eventXY = new float[] {eventX, eventY};\u003cbr\u003e\nMatrix invertMatrix = new Matrix();\u003cbr\u003e\n((ImageView)view).getImageMatrix().invert(invertMatrix);\u003cbr\u003e\ninvertMatrix.mapPoints(eventXY);\u003cbr\u003e\nint x = Integer.valueOf((int)eventXY[0]);\u003cbr\u003e\nint y = Integer.valueOf((int)eventXY[1]);\u003cbr\u003e\ntouchedXY.setText( “touched position: ” + String.valueOf(eventX) + ” / ” + String.valueOf(eventY)); invertedXY.setText(“touched position: ” + String.valueOf(x) + ” / ” + String.valueOf(y));\u003cbr\u003e\nDrawable imgDrawable = ((ImageView)view).getDrawable();\u003cbr\u003e\nBitmap bitmap = ((BitmapDrawable)imgDrawable).getBitmap();\u003cbr\u003e\nimgSize.setText(“drawable size: “+ String.valueOf(bitmap.getWidth()) + ” / “+ String.valueOf(bitmap.getHeight()));\u003cbr\u003e\n//Limit x, y range within bitmap\u003cbr\u003e\nif(x \u0026lt; 0){x = 0; }\u003cbr\u003e\nelse if(x \u0026gt; bitmap.getWidth()-1) {\u003cbr\u003e\nx = bitmap.getWidth()-1;\u003cbr\u003e\n}\u003cbr\u003e\nif(y \u0026lt; 0){\u003cbr\u003e\ny = 0;\u003cbr\u003e\n}else if(y \u0026gt; bitmap.getHeight()-1) {\u003cbr\u003e\ny = bitmap.getHeight()-1;\u003cbr\u003e\n}\u003cbr\u003e\nint touchedRGB = bitmap.getPixel(x, y);\u003cbr\u003e\ncolorRGB.setText(“touched color: ” + “#” + Integer.toHexString(touchedRGB));\u003cbr\u003e\ncolorRGB.setTextColor(touchedRGB);\u003cbr\u003e\nreturn true;\u003c/p\u003e","title":"Android获取点击的图片的颜色"},{"content":"我们经常在一些应用中见到输入框带有删除功能，今天我们就来实现这个功能（文字组织能力不强，大家随便看看）。主要是记录一下自己的学习经历，如果对大家有帮助，我会更开心的。\n先上图：\n实现要点：\n1、当输入框为空时，删除按钮隐藏；\n2、当输入框不为空时，显示删除按钮。\n核心代码：\n`001.``package` `com.example.view;` \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `002.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `com.example.ui.R;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `003.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.content.Context;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `004.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.graphics.Rect;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `005.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.graphics.drawable.Drawable;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `006.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.text.Editable;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `007.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.text.TextWatcher;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `008.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.util.AttributeSet;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `009.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.view.MotionEvent;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `010.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.view.View;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `011.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.widget.EditText;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `012.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.widget.Toast;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `013.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.view.View.OnFocusChangeListener;;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `014.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `class` `EditTextWithDelete ``extends` `EditText ``implements` `OnFocusChangeListener{`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `015.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `Drawable imgEnable;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `016.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `Context context;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `017.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `018.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `EditTextWithDelete(Context context) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `019.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`super``(context);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `020.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.context = context;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `021.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`init();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `022.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `023.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `EditTextWithDelete(Context context, AttributeSet attrs, ``int` `defStyle) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `024.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`super``(context, attrs, defStyle);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `025.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.context = context;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `026.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`init();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `027.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `028.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `EditTextWithDelete(Context context, AttributeSet attrs) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `029.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`super``(context, attrs);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `030.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.context = context;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `031.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`init();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `032.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `033.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `034.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `void` `init() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `035.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//获取图片资源`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `036.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`imgEnable = context.getResources().getDrawable(R.drawable.delete);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `037.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`addTextChangedListener(``new` `TextWatcher() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `038.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `039.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `040.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `onTextChanged(CharSequence s, ``int` `start, ``int` `before, ``int` `count) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `041.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `042.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `043.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `044.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `045.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `beforeTextChanged(CharSequence s, ``int` `start, ``int` `count,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `046.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`int` `after) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `047.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `048.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `049.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `050.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `051.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `afterTextChanged(Editable s) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `052.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setDrawable();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `053.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`Toast.makeText(context, getText(), ``10``).show();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `054.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `055.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`});`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `056.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setDrawable();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `057.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `058.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `059.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`/**`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `060.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* 设置删除图片`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `061.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`*/`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `062.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `void` `setDrawable() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `063.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`if``(length() == ````) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `064.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setCompoundDrawablesWithIntrinsicBounds(``null``, ``null``, ``null``, ``null``);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `065.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}``else` `{`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `066.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setCompoundDrawablesWithIntrinsicBounds(``null``, ``null``, imgEnable, ``null``);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `067.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `068.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `069.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `070.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`/**`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `071.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* event.getX() 获取相对应自身左上角的X坐标`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `072.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* event.getY() 获取相对应自身左上角的Y坐标`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `073.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* getWidth() 获取控件的宽度`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `074.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* getTotalPaddingRight() 获取删除图标左边缘到控件右边缘的距离`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `075.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* getPaddingRight() 获取删除图标右边缘到控件右边缘的距离`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `076.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* getWidth() - getTotalPaddingRight() 计算删除图标左边缘到控件左边缘的距离`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `077.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* getWidth() - getPaddingRight() 计算删除图标右边缘到控件左边缘的距离`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `078.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`*/`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `079.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `080.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `boolean` `onTouchEvent(MotionEvent event) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `081.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`if``(imgEnable != ``null` `\u0026amp;\u0026amp; event.getAction() == MotionEvent.ACTION_UP) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `082.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`int` `x = (``int``) event.getX() ;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `083.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//判断触摸点是否在水平范围内`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `084.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`boolean` `isInnerWidth = (x \u0026amp;gt; (getWidth() - getTotalPaddingRight())) \u0026amp;\u0026amp;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `085.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`(x \u0026amp;lt; (getWidth() - getPaddingRight()));`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `086.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//获取删除图标的边界，返回一个Rect对象`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `087.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`Rect rect = imgEnable.getBounds();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `088.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//获取删除图标的高度`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `089.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`int` `height = rect.height();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `090.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`int` `y = (``int``) event.getY();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `091.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//计算图标底部到控件底部的距离`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `092.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`int` `distance = (getHeight() - height) /``2``;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `093.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//判断触摸点是否在竖直范围内(可能会有点误差)`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `094.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//触摸点的纵坐标在distance到（distance+图标自身的高度）之内，则视为点中删除图标`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `095.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`boolean` `isInnerHeight = (y \u0026amp;gt; distance) \u0026amp;\u0026amp; (y \u0026amp;lt; (distance + height));`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `096.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `097.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`if``(isInnerWidth \u0026amp;\u0026amp; isInnerHeight) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `098.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setText(``\u0026quot;\u0026quot;``);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `099.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `100.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `101.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `102.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `103.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `super``.onTouchEvent(event);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `104.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `105.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `106.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `107.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`protected` `void` `finalize() ``throws` `Throwable {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `108.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`super``.finalize();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `109.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `110.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `111.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `onFocusChange(View v, ``boolean` `hasFocus) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `112.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`if``(hasFocus) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `113.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setDrawable();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `114.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}``else` `{`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `115.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setCompoundDrawablesWithIntrinsicBounds(``null``, ``null``, ``null``, ``null``);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `116.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `117.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `118.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `119.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 代码注释很清楚，相信以大家的水平都会看的懂的。在这边，我就不多做解释了。如果有不明白的，可以给我留言，大家交流交流。\n","permalink":"https://blog.zdltech.com/posts/android-edittext-%E8%87%AA%E5%AE%9A%E4%B9%89%E5%B8%A6%E5%88%A0%E9%99%A4%E5%8A%9F%E8%83%BD%E7%9A%84edittext/","summary":"\u003cp\u003e我们经常在一些应用中见到输入框带有删除功能，今天我们就来实现这个功能（文字组织能力不强，大家随便看看）。主要是记录一下自己的学习经历，如果对大家有帮助，我会更开心的。\u003c/p\u003e\n\u003cp\u003e先上图：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"wKiom1NoiWKxPyZ1AAF6K_ZbO_g941.jpg\" loading=\"lazy\" src=\"http://www.it165.net/uploadfile/files/2014/0507/20140507083013111.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e实现要点：\u003c/p\u003e\n\u003cp\u003e1、当输入框为空时，删除按钮隐藏；\u003c/p\u003e\n\u003cp\u003e2、当输入框不为空时，显示删除按钮。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e核心代码：\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv id=\"highlighter_173047\" class=\"syntaxhighlighter \"\u003e\n  \u003cdiv class=\"lines\"\u003e\n    \u003cdiv class=\"line alt1\"\u003e\n      `001.`\u003cspan class=\"content\"\u003e\u003cspan class=\"block\"\u003e`package` `com.example.view;`\u003c/span\u003e\u003c/span\u003e\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `002.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `com.example.ui.R;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `003.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.content.Context;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `004.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.graphics.Rect;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `005.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.graphics.drawable.Drawable;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `006.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.text.Editable;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `007.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.text.TextWatcher;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `008.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.util.AttributeSet;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `009.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.view.MotionEvent;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `010.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.view.View;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `011.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.widget.EditText;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `012.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.widget.Toast;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `013.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`import` `android.view.View.OnFocusChangeListener;;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `014.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `class` `EditTextWithDelete ``extends` `EditText ``implements` `OnFocusChangeListener{`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `015.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `Drawable imgEnable;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `016.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `Context context;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `017.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `018.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `EditTextWithDelete(Context context) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `019.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`super``(context);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `020.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.context = context;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `021.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`init();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `022.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `023.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `EditTextWithDelete(Context context, AttributeSet attrs, ``int` `defStyle) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `024.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`super``(context, attrs, defStyle);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `025.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.context = context;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `026.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`init();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `027.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `028.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `EditTextWithDelete(Context context, AttributeSet attrs) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `029.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`super``(context, attrs);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `030.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.context = context;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `031.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`init();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `032.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `033.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `034.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `void` `init() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `035.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//获取图片资源`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `036.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`imgEnable = context.getResources().getDrawable(R.drawable.delete);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `037.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`addTextChangedListener(``new` `TextWatcher() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `038.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `039.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `040.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `onTextChanged(CharSequence s, ``int` `start, ``int` `before, ``int` `count) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `041.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `042.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `043.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `044.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `045.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `beforeTextChanged(CharSequence s, ``int` `start, ``int` `count,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `046.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`int` `after) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `047.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `048.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `049.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `050.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `051.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `afterTextChanged(Editable s) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `052.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setDrawable();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `053.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`Toast.makeText(context, getText(), ``10``).show();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `054.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `055.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`});`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `056.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setDrawable();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `057.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `058.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `059.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`/**`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `060.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* 设置删除图片`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `061.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`*/`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `062.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `void` `setDrawable() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `063.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`if``(length() == ````) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `064.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setCompoundDrawablesWithIntrinsicBounds(``null``, ``null``, ``null``, ``null``);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `065.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}``else` `{`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `066.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setCompoundDrawablesWithIntrinsicBounds(``null``, ``null``, imgEnable, ``null``);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `067.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `068.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `069.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `070.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`/**`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `071.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* event.getX() 获取相对应自身左上角的X坐标`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `072.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* event.getY() 获取相对应自身左上角的Y坐标`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `073.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* getWidth() 获取控件的宽度`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `074.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* getTotalPaddingRight() 获取删除图标左边缘到控件右边缘的距离`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `075.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* getPaddingRight() 获取删除图标右边缘到控件右边缘的距离`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `076.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* getWidth() - getTotalPaddingRight() 计算删除图标左边缘到控件左边缘的距离`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `077.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* getWidth() - getPaddingRight() 计算删除图标右边缘到控件左边缘的距离`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `078.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`*/`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `079.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `080.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `boolean` `onTouchEvent(MotionEvent event) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `081.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`if``(imgEnable != ``null` `\u0026amp;\u0026amp; event.getAction() == MotionEvent.ACTION_UP) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `082.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`int` `x = (``int``) event.getX() ;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `083.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//判断触摸点是否在水平范围内`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `084.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`boolean` `isInnerWidth = (x \u0026amp;gt; (getWidth() - getTotalPaddingRight())) \u0026amp;\u0026amp;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `085.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`(x \u0026amp;lt; (getWidth() - getPaddingRight()));`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `086.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//获取删除图标的边界，返回一个Rect对象`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `087.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`Rect rect = imgEnable.getBounds();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `088.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//获取删除图标的高度`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `089.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`int` `height = rect.height();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `090.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`int` `y = (``int``) event.getY();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `091.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//计算图标底部到控件底部的距离`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `092.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`int` `distance = (getHeight() - height) /``2``;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `093.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//判断触摸点是否在竖直范围内(可能会有点误差)`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `094.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`//触摸点的纵坐标在distance到（distance+图标自身的高度）之内，则视为点中删除图标`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `095.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`boolean` `isInnerHeight = (y \u0026amp;gt; distance) \u0026amp;\u0026amp; (y \u0026amp;lt; (distance + height));`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `096.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `097.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`if``(isInnerWidth \u0026amp;\u0026amp; isInnerHeight) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `098.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setText(``\u0026quot;\u0026quot;``);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `099.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `100.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `101.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `102.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `103.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `super``.onTouchEvent(event);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `104.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `105.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `106.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `107.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`protected` `void` `finalize() ``throws` `Throwable {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `108.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`super``.finalize();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `109.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `110.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `111.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `onFocusChange(View v, ``boolean` `hasFocus) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `112.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`if``(hasFocus) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `113.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setDrawable();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `114.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}``else` `{`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `115.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setCompoundDrawablesWithIntrinsicBounds(``null``, ``null``, ``null``, ``null``);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `116.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `117.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  `118.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  `119.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e代码注释很清楚，相信以大家的水平都会看的懂的。在这边，我就不多做解释了。如果有不明白的，可以给我留言，大家交流交流。\u003c/p\u003e","title":"Android-EditText 自定义带删除功能的EditText"},{"content":" 在登陆界面获取验证码的时候: ``` `new Thread(){ @Override public void run() { try { SharedPreferences spf = getSharedPreferences(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;Cookie\u0026rdquo;\u0026lt;/span\u0026gt;, Context\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.MODE\u0026lt;/span\u0026gt;_PRIVATE)\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt;\nHttpClient client = new DefaultHttpClient()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; HttpGet get = new HttpGet(Gloable\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.DOLOAD\u0026amp;lt;/span\u0026gt;+\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;code.gif\u0026quot;\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; HttpResponse response = client\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.execute\u0026amp;lt;/span\u0026gt;(get)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; Cookie cookie = ((AbstractHttpClient) client)\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getCookieStore\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getCookies\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.get\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; String sessionId = cookie\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getValue\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; SharedPreferences\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.Editor\u0026amp;lt;/span\u0026gt; editor = spf\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.edit\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; editor\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.putString\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;sessionId\u0026quot;\u0026amp;lt;/span\u0026gt;, sessionId)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; String cookieString = cookie\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getName\u0026amp;lt;/span\u0026gt;()+\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;=\u0026quot;\u0026amp;lt;/span\u0026gt;+cookie\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getValue\u0026amp;lt;/span\u0026gt;()+ \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;;domain=\u0026quot;\u0026amp;lt;/span\u0026gt;+cookie\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getDomain\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; Log\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.e\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;test\u0026quot;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;cookieString:\u0026quot;\u0026amp;lt;/span\u0026gt;+cookieString)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; editor\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.putString\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;cookieString\u0026quot;\u0026amp;lt;/span\u0026gt;, cookieString)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; editor\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.commit\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; Log\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.i\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;info\u0026quot;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;b--JSESSIONID=\u0026quot;\u0026amp;lt;/span\u0026gt; + sessionId)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; if (response\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getStatusLine\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getStatusCode\u0026amp;lt;/span\u0026gt;() == \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;200\u0026amp;lt;/span\u0026gt;) { byte[] bytes = EntityUtils\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.toByteArray\u0026amp;lt;/span\u0026gt;(response\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getEntity\u0026amp;lt;/span\u0026gt;())\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; final Bitmap bitmap = BitmapFactory\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.decodeByteArray\u0026amp;lt;/span\u0026gt;(bytes, \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, bytes\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.length\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; runOnUiThread(new Runnable() { public void run() { Drawable drawable = new BitmapDrawable(bitmap)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; iv_showCode\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.setBackgroundDrawable\u0026amp;lt;/span\u0026gt;(drawable)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; } })\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.printStackTrace\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; } catch (IOException e) { // TODO Auto-generated catch block e\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.printStackTrace\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; } } }\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.start\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;` 在webview加载url之前: ``` `SharedPreferences spf = getSharedPreferences(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Cookie\u0026#34;\u0026amp;lt;/span\u0026gt;, Context\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.MODE\u0026amp;lt;/span\u0026gt;_PRIVATE)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; CookieSyncManager\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.createInstance\u0026amp;lt;/span\u0026gt;(this)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; CookieManager cookieManager = CookieManager\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.getInstance\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; String cookieString = spf\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.getString\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;cookieString\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; cookieManager\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.setCookie\u0026amp;lt;/span\u0026gt;(url, cookieString)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; CookieSyncManager\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.getInstance\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.sync\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; webview\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.loadUrl\u0026amp;lt;/span\u0026gt;(url)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt;` android客户端通过httpClient或者httpUrlConnection进行登录后，为了把登录状态同步到webView中，这时需要进行cookie的同步 一.cookie同步方式 下面是登录线程: public class LoginThread extends Thread{ private Handler loginHandler; public LoginThread(Handler loginHandler) { this.loginHandler = loginHandler; } @Override public void run() { List cookieLst = new ArrayList(); HttpParams httpParams = new BasicHttpParams(); ConnManagerParams.setMaxTotalConnections(httpParams, 5); ConnManagerParams.setTimeout(httpParams, 151000); HttpConnectionParams.setSoTimeout(httpParams, 101000); HttpConnectionParams.setTcpNoDelay(httpParams, true); HttpPost httpPost = new HttpPost(“http://192.168.1.107/cookie/login.php”); List nvPairs = new ArrayList(); nvPairs.add(new BasicNameValuePair(“name”, “lisi”)); nvPairs.add(new BasicNameValuePair(“age”,”22″)); nvPairs.add(new BasicNameValuePair(“gender”, “男”));\ntry { UrlEncodedFormEntity entity = new UrlEncodedFormEntity(nvPairs, HTTP.UTF_8); httpPost.setEntity(entity); HttpClient httpClient = new DefaultHttpClient(); HttpResponse httpResponse = httpClient.execute(httpPost); if(httpResponse!=null \u0026amp;\u0026amp; httpResponse.getStatusLine().getStatusCode()==HttpStatus.SC_OK) { String content = EntityUtils.toString(httpResponse.getEntity()); Log.d(“LOGIN”, content); Header[] allHeaders = httpResponse.getAllHeaders(); if(allHeaders!=null) { //获取cookie的第一种方式 for (Header header : allHeaders) { Log.d(“LOGIN”, header.getName()+”=”+header.getValue()); if(“Set-Cookie”.equalsIgnoreCase(header.getName())) { cookieLst.add(header.getValue()); } } } //获取cookie的第二种方式 AbstractHttpClient abstractHttpClient = (AbstractHttpClient) httpClient; CookieStore cookieStore = abstractHttpClient.getCookieStore(); List cookies = cookieStore.getCookies(); for (Cookie cookie : cookies) { Log.d(“LOGIN-COOKIE”, cookie.getName()+”=”+cookie.getValue()+”,path=”+cookie.getPath()+”,domain=”+cookie.getDomain()+”,expires=”+cookie.getExpiryDate()); }\nif(loginHandler!=null) { Message msg = new Message(); msg.obj = cookieLst; msg.what = 200; msg.setTarget(loginHandler); msg.sendToTarget(); } } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } 下面是WebView主页面Activity\n@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public class Main extends Activity implements DownloadListener {\nprivate WebView mWebView; //extraHeaders经测试不可以同步cookie private Map\u0026lt;String, String\u0026gt; extraHeaders;\nprivate final String TAG = \u0026amp;#8220;WEB_VIEW\u0026amp;#8221;; private final Handler loginHandler = new Handler(){ @Override public void handleMessage(Message msg) {\nif(msg.what==200) { List cookies = (List) msg.obj; if(cookies!=null) { syncCookieToWebView(cookies); mWebView.loadUrl(“http://192.168.1.107/cookie/read.php”); } }else{ super.handleMessage(msg); } }\n}; @SuppressLint(\u0026amp;#8220;SetJavaScriptEnabled\u0026amp;#8221;) @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mWebView = (WebView) findViewById(R.id.main_webview); WebSettings settings = mWebView.getSettings(); settings.setAppCacheEnabled(true); settings.setCacheMode(WebSettings.LOAD_DEFAULT); settings.setGeolocationEnabled(true); settings.setUseWideViewPort(true); settings.setSaveFormData(true); settings.setSavePassword(true); settings.setSupportZoom(false); settings.setLoadsImagesAutomatically(true); settings.setBlockNetworkImage(false); if(android.os.Build.VERSION.SDK_INT\u0026gt;=11) { settings.setEnableSmoothTransition(true); } settings.setJavaScriptCanOpenWindowsAutomatically(false); settings.setAllowFileAccess(false); settings.setJavaScriptEnabled(true); String userAgent = settings.getUserAgentString(); Log.d(TAG, userAgent); if(android.os.Build.VERSION.SDK_INT\u0026gt;=14) { mWebView.setFitsSystemWindows(true); } if(mWebView.isHardwareAccelerated()) { mWebView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } mWebView.setKeepScreenOn(true); extraHeaders = new IdentityHashMap\u0026lt;String, String\u0026gt;();\nmWebView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if(view!=null \u0026amp;\u0026amp; !TextUtils.isEmpty(url)) { extraHeaders.put(“control-cache”, “no-cache,private”); extraHeaders.put(“pragma”, “no-cache,no-store”); extraHeaders.put(“expires”, “0”); view.loadUrl(url, extraHeaders); return true; } return super.shouldOverrideUrlLoading(view, url); } });\nmWebView.setDownloadListener(this); //mWebView.loadUrl(\u0026amp;#8220;http://shouji.baidu.com/software/?from=web_alad_multi\u0026amp;#8221;); new LoginThread(loginHandler).start(); } //销毁webView @Override protected void onDestroy() { super.onDestroy(); mWebView.clearFormData(); mWebView.clearHistory(); mWebView.destroy(); }\n//监听文件下载，WebView不会自动下载，需要我们自己构建下载代码 @Override public void onDownloadStart(String url, String userAgent,String contentDisposition, String mimetype, long contentLength) { Log.d(TAG, “url=”+url); Log.d(TAG, “userAgent=”+url); Log.d(TAG, “contentDisposition=”+contentDisposition); Log.d(TAG, “mimetype=”+mimetype); Log.d(TAG, “contentLength=”+contentLength);\n//第一种下载方式是 自定义的http工具类 //new DownloadThread(url,contentDisposition,mimetype,contentLength).start();\n//第二种下载方式是调用系统的webView,具有默认的进度条 Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(url)); startActivity(intent);\n} /**\ncookie同步 */ private void syncCookieToWebView(List cookies) { CookieSyncManager.createInstance(Main.this); CookieManager cm = CookieManager.getInstance(); cm.setAcceptCookie(true); if(cookies!=null) { for (String cookie : cookies) { cm.setCookie(“http://192.168.1.107:80”,cookie);//注意端口号和域名，这种方式可以同步所有cookie，包括sessionid } } CookieSyncManager.getInstance().sync(); } }\n二.注意:平时开发中Cookie同步是最佳选项，但这并不意味着一定需要使用cookie同步，我们可以使用 token+用户id+登录时间校验码 进行同步登录\n三.对于使用javaInterface进行同步登录的问题\njavaInterface风险性很高，如果android平台是 4.2+比较安全，但4.2以下版本，安全性不容乐观，比如通过反射造成硬盘被读写的可能性很高！\n在android 4.2中增加了 @javainterface注解，并且将公开的方法异步化，这样有效的控制了某些没必要公开的方法被无意间作为接口公开，导致js发射到硬盘的读写io类，从而发生文件被窃取，垃圾文件堆积，有害文件被下载等问题！\n四.目前来说让所有人使用 4.2+以上版本可能性不大，但尽量少使用javainterface,转而使用 协议的方式，所谓协议，就是通信协议，我们可以分析url参数，从而进行webView和native代码的通信\nmWebView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) {\n//捕获url的参数值\nif(url.indexOf(“login”)\u0026gt;=0) {\n}else if(url.indexOf(“userCenter”)\u0026gt;=0){ } return super.shouldOverrideUrlLoading(view, url); } }); 当然，javainterface不推荐，但完全可以使用\n? 1 view.loadUrl(“javascript:dosometing(“+”‘参数\u0026rsquo;”+”)”);\n","permalink":"https://blog.zdltech.com/posts/android-webview-%E4%B8%8E%E7%99%BB%E5%BD%95%E7%8A%B6%E6%80%81%E4%BF%9D%E6%8C%81%E4%B8%80%E8%87%B4%E5%BB%BA%E7%AB%8Bsession%E4%BC%9A%E8%AF%9D/","summary":"\u003cdiv id=\"article_content\" class=\"article_content\"\u003e\n  \u003cdiv class=\"markdown_views\"\u003e\n\u003cpre\u003e\u003ccode\u003e  在登陆界面获取验证码的时候:\n\n\n\n```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e`new Thread(){\n@Override\npublic void run() {\ntry {\nSharedPreferences spf = getSharedPreferences(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;Cookie\u0026rdquo;\u0026lt;/span\u0026gt;, Context\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.MODE\u0026lt;/span\u0026gt;_PRIVATE)\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt;\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e                HttpClient client = new DefaultHttpClient()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                HttpGet get = new HttpGet(Gloable\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.DOLOAD\u0026amp;lt;/span\u0026gt;+\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;code.gif\u0026quot;\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                HttpResponse response = client\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.execute\u0026amp;lt;/span\u0026gt;(get)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                Cookie cookie = ((AbstractHttpClient) client)\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getCookieStore\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getCookies\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.get\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                String sessionId = cookie\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getValue\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                SharedPreferences\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.Editor\u0026amp;lt;/span\u0026gt; editor = spf\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.edit\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                editor\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.putString\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;sessionId\u0026quot;\u0026amp;lt;/span\u0026gt;, sessionId)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                String cookieString = cookie\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getName\u0026amp;lt;/span\u0026gt;()+\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;=\u0026quot;\u0026amp;lt;/span\u0026gt;+cookie\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getValue\u0026amp;lt;/span\u0026gt;()+\n                        \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;;domain=\u0026quot;\u0026amp;lt;/span\u0026gt;+cookie\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getDomain\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                Log\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.e\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;test\u0026quot;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;cookieString:\u0026quot;\u0026amp;lt;/span\u0026gt;+cookieString)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                editor\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.putString\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;cookieString\u0026quot;\u0026amp;lt;/span\u0026gt;, cookieString)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                editor\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.commit\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                Log\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.i\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;info\u0026quot;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;b--JSESSIONID=\u0026quot;\u0026amp;lt;/span\u0026gt; + sessionId)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                if (response\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getStatusLine\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getStatusCode\u0026amp;lt;/span\u0026gt;() == \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;200\u0026amp;lt;/span\u0026gt;) {\n                    byte[] bytes = EntityUtils\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.toByteArray\u0026amp;lt;/span\u0026gt;(response\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.getEntity\u0026amp;lt;/span\u0026gt;())\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                    final Bitmap bitmap = BitmapFactory\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.decodeByteArray\u0026amp;lt;/span\u0026gt;(bytes, \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, bytes\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.length\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                    runOnUiThread(new Runnable() {\n                        public void run() {\n                            Drawable drawable = new BitmapDrawable(bitmap)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                            iv_showCode\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.setBackgroundDrawable\u0026amp;lt;/span\u0026gt;(drawable)\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                        }\n                    })\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n                }\n            } catch (ClientProtocolException e) {\n                // TODO Auto-generated catch block\n                e\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.printStackTrace\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n            } catch (IOException e) {\n                // TODO Auto-generated catch block\n                e\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.printStackTrace\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n            }\n        }\n    }\u0026amp;lt;span class=\u0026quot;hljs-preprocessor\u0026quot;\u0026gt;.start\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;`\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      在webview加载url之前:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`SharedPreferences spf \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e getSharedPreferences(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Cookie\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e, Context\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-preprocessor\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;.\u003c/span\u003eMODE\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e_PRIVATE)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-comment\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        CookieSyncManager\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-preprocessor\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;.\u003c/span\u003ecreateInstance\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(this)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-comment\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        CookieManager cookieManager \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e CookieManager\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-preprocessor\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;.\u003c/span\u003egetInstance\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e()\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-comment\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String cookieString \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e spf\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-preprocessor\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;.\u003c/span\u003egetString\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cookieString\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e, \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-comment\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        cookieManager\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-preprocessor\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;.\u003c/span\u003esetCookie\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(url, cookieString)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-comment\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        CookieSyncManager\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-preprocessor\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;.\u003c/span\u003egetInstance\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e()\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-preprocessor\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;.\u003c/span\u003esync\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e()\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-comment\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        webview\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-preprocessor\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;.\u003c/span\u003eloadUrl\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(url)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-comment\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv id=\"digg\"\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  android客户端通过httpClient或者httpUrlConnection进行登录后，为了把登录状态同步到webView中，这时需要进行cookie的同步\n\u003cpre\u003e\u003ccode\u003e一.cookie同步方式\n\n\n\n\n\n下面是登录线程:\n\n\n\n\n\npublic class LoginThread extends Thread{\n\n\n\n\n\nprivate Handler loginHandler;\n\n\n\n\n\npublic  LoginThread(Handler loginHandler) {\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003ethis.loginHandler = loginHandler;\n}\n@Override\npublic void run()\n{\nList\u003cString\u003e cookieLst = new ArrayList\u003cString\u003e();\nHttpParams httpParams = new BasicHttpParams();\nConnManagerParams.setMaxTotalConnections(httpParams, 5);\nConnManagerParams.setTimeout(httpParams, 15\u003cem\u003e1000);\nHttpConnectionParams.setSoTimeout(httpParams, 10\u003c/em\u003e1000);\nHttpConnectionParams.setTcpNoDelay(httpParams, true);\nHttpPost httpPost = new HttpPost(“http://192.168.1.107/cookie/login.php”);\nList\u003cNameValuePair\u003e nvPairs = new ArrayList\u003cNameValuePair\u003e();\nnvPairs.add(new BasicNameValuePair(“name”, “lisi”));\nnvPairs.add(new BasicNameValuePair(“age”,”22″));\nnvPairs.add(new BasicNameValuePair(“gender”, “男”));\u003c/p\u003e","title":"Android WebView 与登录状态保持一致，建立SESSION会话"},{"content":"背景 React Native出来已经一段时间了，相对来说也算稳定了，在很多的企业中都实际使用他们，混合开发已经是未来的一种趋势，混合开发中使用的技术很多，不外乎Html5、JS框架通过一定的技术和原始交互，目前主流混合开发React Native、Cordova、APICloud、MUI、AppCan、Sencha Touch、jQuery Mobile等等（其他的小伙伴们自己收集），目前网上写教程的人很多，但是React Native更新速度很快，根据他们的教程，中间会遇到各种问题，今天我和大家一起踩踩各种坑，让小伙伴们快速集成到自己的APP中。后续持续更新，反馈发邮件411437734@qq.com共同探讨。\n集成步骤 参考官方文档-\u0026gt;react native 文档\n本文使用开发环境 Android studio\n注意最新的React Native支持的最新的SDK为16（android4.1）\nnpm环境，小伙伴们自己安装 nodeJS自己安装，可以参考官方文档安装环境，有问题可以发411437734@qq.com沟通\n创建Android项目（已有项目跳过） 打开Android studio￼ 输入项目名称，选择项目目录，点击next￼￼￼￼\n至此项目创建完成（需要注意的是最新的React Native支持最新SDK版本为16 android4.1） React Native集成到上面我们创建的ReactNativeAPPDemo中 参考Facebook react native文档\n进入项目根目录，添加JS到项目中-点击Android studio中的Terminal（如下图）\n￼\n分别执行一下语句\nnpm init npm install \u0026ndash;save react react-native curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig\ninit 主要根据提醒生成package.json文件\ncurl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig 下载.flowconfig文件\n参考图片￼\n查看项目中有node_modules，说明react和react native 安装完成￼ 在项目根目录添加.flowconfig 参考下图\n￼\n也可以手动创建在浏览器打开https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig网址复制内容创建文件￼\nReactNativeAppDemo配置相关内容 添加\u0026quot;start\u0026quot;: \u0026ldquo;node node_modules/react-native/local-cli/cli.js start\u0026rdquo; 到package.json 文件下 scripts标签 修改前￼修改后￼\n添加index.android.js文件到项目中￼\n\u0026gt; \u0026amp;#39;use strict\u0026amp;#39;; \u0026gt; import React from \u0026amp;#39;react\u0026amp;#39;; \u0026gt; import { \u0026gt; AppRegistry, \u0026gt; StyleSheet, \u0026gt; Text, \u0026gt; View \u0026gt; } from \u0026amp;#39;react-native\u0026amp;#39;; \u0026gt; class HelloWorld extends React.Component { \u0026gt; render() { \u0026gt; return ( \u0026gt; \u0026lt;View style={styles.container}\u0026gt; \u0026gt; \u0026lt;Text style={styles.hello}\u0026gt;Hello, World\u0026lt;/Text\u0026gt; \u0026gt; \u0026lt;/View\u0026gt; \u0026gt; ) \u0026gt; } \u0026gt; } \u0026gt; var styles = StyleSheet.create({ \u0026gt; container: { \u0026gt; flex: 1, \u0026gt; justifyContent: \u0026amp;#39;center\u0026amp;#39;, \u0026gt; }, \u0026gt; hello: { \u0026gt; fontSize: 20, \u0026gt; textAlign: \u0026amp;#39;center\u0026amp;#39;, \u0026gt; margin: 10, \u0026gt; }, \u0026gt; }); \u0026gt; AppRegistry.registerComponent(\u0026amp;#39;HelloWorld\u0026amp;#39;, () =\u0026gt; HelloWorld); \u0026gt; \u0026gt; \u0026gt; 至此React native配置基本完成 App build.gradle配置 \u0026gt; dependencies { \u0026gt; ... \u0026gt; compile \u0026quot;com.facebook.react:react-native:+\u0026quot; // From node_modules. \u0026gt; } \u0026gt; \u0026gt; \u0026gt; 这里注意不要使用maven中的，因为我们使用的是我们本地node_modules中的，**注意最新版本中支持的是23，appcompat-v7:23.0.1**，暂时没有试24的api![](http://www.etongwl.com/images/2016/10/14752229775637.jpg)￼ 整个工程build.gradle配置 \u0026gt; allprojects { \u0026gt; repositories { \u0026gt; ... \u0026gt; maven { \u0026gt; // All of React Native (JS, Android binaries) is installed from npm \u0026gt; url \u0026quot;$rootDir/node_modules/react-native/android\u0026quot; \u0026gt; } \u0026gt; } \u0026gt; ... \u0026gt; } \u0026gt; \u0026gt; \u0026gt;![](http://www.etongwl.com/images/2016/10/14752256546683.jpg) ￼ 添加\u0026lt;uses-permission android:name=\u0026quot;android.permission.INTERNET\u0026quot; /\u0026gt;到AndroidManifest.xml:\n确定External Libraries￼￼\n确定是下是最新的，例如确定是0.34.1而不是0.20.1，如果出现请检查\n``\nmaven {\n`url \u0026quot;$rootDir/../node_modules/react-native/android\u0026quot;`//地址是否正确 } 修改url \u0026ldquo;rootDir*/..*/node_modules/react-native/android\u0026quot;为url \u0026ldquo;rootDir/node_modules/react-native/android\u0026rdquo;\n``\n添加native code 官方给出的￼\n到时最新版本中提供了更加简单的方式，没错就是继承。\n￼\n在这里我们也需要自定义一个Application否则 运行时会报错，不信的小伙伴可以试一试￼￼\n到此为止，ReactNative 集成到已有项目中完成！！！迫不及待的运行试试吧！！\n￼\n在Terminal中运行 npm start，看到下图表示启动成功\n￼\n运行以后发现如下错误￼\nreact-native报错：Could not get BatchedBridge, make sure your bundle is packaged correctly\n莫紧张，这是因为bundle没有打包好。找不到编译打包后的js文件。其实就是android studio默认的寻找js文件地址和react-native自己的工具编译所使用的地址不同。\n解决方法 方法一 进入项目，在android/app/src/main下新建assets目录。执行以下命令\n$\u0026gt; react-native start \u0026gt; /dev/null 2\u0026gt;\u0026amp;1 \u0026amp; $\u0026gt; curl \u0026quot;http://localhost:8081/index.android.bundle?platform=android\u0026quot; -o \u0026gt; \u0026quot;app/src/main/assets/index.android.bundle\u0026quot; 在项目根目录下执行\n\u0026lt;!--\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;\u0026gt; (cd android/ \u0026amp;\u0026amp; ./gradlew assembleDebug)--\u0026gt;\u0026lt;/span\u0026gt;\u0026gt; (cd 项目名称/ \u0026amp;\u0026amp; ./gradlew assembleDebug) 把创建的apk安装到android设备\n方法二 进入项目，在android/app/src/main下新建assets目录\n启动服务器\n$\u0026gt;react-native start $\u0026gt;react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output app/src/main/assets/index.android.bundle --assets-dest app/src/main/res/ 在assets文件夹下会生成index.android.bundle文件，把创建的apk文件安装到android设备\n方法三 进入项目，在android/app/src/main下新建assets目录\n在package.json中配置下面代码\n`\n\u0026ldquo;scripts\u0026rdquo;: {\n\u0026quot;start\u0026quot;: \u0026quot;node node_modules/react-native/local-cli/cli.js start\u0026quot;, \u0026quot;bundle-android\u0026quot;: \u0026quot;react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output app/src/main/assets/index.android.bundle --sourcemap-output app/src/main/assets/index.android.map --assets-dest android/app/src/main/res/\u0026quot; },\n`\n个人推荐使用方法三,方法三解决不了推荐方法二 手动执行\n修改刚刚的package.json文件￼\n如果真机(模拟器)需要执行\nadb reverse tcp:8081 tcp:8081 一定要确定连接网络哦！！\n￼￼\n开心的进行开发吧！\n其他可能遇到的问题 ReactNative兼容64位Android手机 libgnustl_shared.so\u0026rdquo; is 32-bit instead of 64-bit类似错误\n解决方法 在项目的根目录的 gradle.properties 里面添加一行代码\n`android.useDeprecatedNdk=true. 2. 在build.gradle` 文件里添加以下代码\n` ... defaultConfig { ... ndk { abiFilters \u0026#34;armeabi-v7a\u0026#34;, \u0026#34;x86\u0026#34; } packagingOptions { exclude \u0026#34;lib/arm64-v8a/librealm-jni.so\u0026#34; } } } ` 最后感谢\nhttp://majing.io/questions/589 http://www.cnblogs.com/tony-yang-flutter/p/5864578.html https://blog.yourtion.com/update-react-native-029-bug.html http://stackoverflow.com/questions/38870710/error-could-not-get-batchedbridge-make-sure-your-bundle-is-packaged-properly/38874952 http://blog.csdn.net/b992379702b/article/details/52234479 关注公众号获取更多内容和反馈沟通\n","permalink":"https://blog.zdltech.com/posts/shi-shang-zui-xiang-xi-deandroid-yuan-shengapp-zho/","summary":"\u003ch2 id=\"toc_0\"\u003e背景\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003eReact Native出来已经一段时间了，相对来说也算稳定了，在很多的企业中都实际使用他们，混合开发已经是未来的一种趋势，混合开发中使用的技术很多，不外乎Html5、JS框架通过一定的技术和原始交互，目前主流混合开发React Native、Cordova、APICloud、MUI、AppCan、Sencha Touch、jQuery Mobile等等（其他的小伙伴们自己收集），目前网上写教程的人很多，但是React Native更新速度很快，根据他们的教程，中间会遇到各种问题，今天我和大家一起踩踩各种坑，让小伙伴们快速集成到自己的APP中。后续持续更新，反馈发邮件\u003ca href=\"mailto:411437734@qq.com\"\u003e411437734@qq.com\u003c/a\u003e共同探讨。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"toc_1\"\u003e集成步骤\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e参考官方文档-\u0026gt;\u003ca href=\"http://facebook.github.io/react-native/releases/next/docs/integration-with-existing-apps.html\"\u003ereact native 文档\u003c/a\u003e\u003cbr\u003e\n本文使用开发环境 Android studio\u003cbr\u003e\n注意最新的React Native支持的最新的SDK为16（android4.1）\u003cbr\u003e\nnpm环境，小伙伴们自己安装 nodeJS自己安装，可以参考官方文档安装环境，有问题可以发\u003ca href=\"mailto:411437734@qq.com\"\u003e411437734@qq.com\u003c/a\u003e沟通\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"toc_2\"\u003e创建Android项目（已有项目跳过）\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e打开Android studio\u003cimg loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/10/14752189589833.jpg\"\u003e￼\u003c/li\u003e\n\u003cli\u003e输入项目名称，选择项目目录，点击next\u003cimg loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/10/14752190447690.jpg\"\u003e￼\u003cimg loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/10/14752191238908.jpg\"\u003e￼\u003cimg loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/10/14752192158859.jpg\"\u003e￼\u003cimg loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/10/14752193112367.jpg\"\u003e￼\u003cbr\u003e\n至此项目创建完成（需要注意的是最新的React Native支持最新SDK版本为16 android4.1）\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"toc_3\"\u003eReact Native集成到上面我们创建的ReactNativeAPPDemo中\u003c/h3\u003e\n\u003cp\u003e参考Facebook react native文档\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e进入项目根目录，添加JS到项目中-点击Android studio中的Terminal（如下图）\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/10/14752200412681.jpg\"\u003e ￼\u003cbr\u003e\n分别执行一下语句\u003c/p\u003e\n\u003cp\u003enpm init\nnpm install \u0026ndash;save react react-native\ncurl -o .flowconfig \u003ca href=\"https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig\"\u003ehttps://raw.githubusercontent.com/facebook/react-native/master/.flowconfig\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003einit 主要根据提醒生成package.json文件\u003cbr\u003e\ncurl -o .flowconfig \u003ca href=\"https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig\"\u003ehttps://raw.githubusercontent.com/facebook/react-native/master/.flowconfig\u003c/a\u003e 下载.flowconfig文件\u003cbr\u003e\n参考图片\u003cimg loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/10/14752207192510.jpg\"\u003e￼\u003c/p\u003e\n\u003ch3 id=\"toc_4\"\u003e查看项目中有node_modules，说明react和react native 安装完成\u003cimg loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/10/14752214758622.jpg\"\u003e￼\u003c/h3\u003e\n\u003ch3 id=\"toc_5\"\u003e在项目根目录添加.flowconfig\u003c/h3\u003e\n\u003cp\u003e参考下图\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/10/14752216108448.jpg\"\u003e ￼\u003cbr\u003e\n也可以手动创建在浏览器打开\u003ca href=\"https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig%E7%BD%91%E5%9D%80%E5%A4%8D%E5%88%B6%E5%86%85%E5%AE%B9%E5%88%9B%E5%BB%BA%E6%96%87%E4%BB%B6!%5B%5D(media/14752155060355/14752217925862.jpg)%EF%BF%BC\"\u003ehttps://raw.githubusercontent.com/facebook/react-native/master/.flowconfig网址复制内容创建文件\u003cimg loading=\"lazy\" src=\"media/14752155060355/14752217925862.jpg\"\u003e￼\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"toc_6\"\u003eReactNativeAppDemo配置相关内容\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e添加\u0026quot;start\u0026quot;: \u0026ldquo;node node_modules/react-native/local-cli/cli.js start\u0026rdquo; 到\u003ccode\u003epackage.json\u003c/code\u003e 文件下 \u003ccode\u003escripts\u003c/code\u003e标签 修改前\u003cimg loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/10/14752220951994.jpg\"\u003e￼修改后\u003cimg loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/10/14752221462812.jpg\"\u003e￼\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e添加index.android.js文件到项目中\u003cimg loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/10/14752222197635.jpg\"\u003e￼\u003c/p\u003e","title":"史上最详细的Android原生APP中添加ReactNative 进行混合开发教程"},{"content":"Android 命令 ( adb push 文件 目标文件\n) adb shell pm install -r \u0026ldquo;/data/local/tmp/xxxx\u0026rdquo;\npkg: /data/local/tmp/xxxx\n启动指定Activity\n$ adb shell am start -n \u0026ldquo;package/package.Activity\u0026rdquo; -a android.intent.action.MAIN -c android.intent.category.LAUNCHER\nAndroid 动态权限 final private int REQUEST_CODE_ASK_PERMISSIONS = 123;\nprivate void insertDummyContactWrapper() {\nint hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS);\nif (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {\nif (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {\nshowMessageOKCancel(\u0026ldquo;You need to allow access to Contacts\u0026rdquo;,\nnew DialogInterface.OnClickListener() {\n@Override\npublic void onClick(DialogInterface dialog, int which) {\nrequestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},\nREQUEST_CODE_ASK_PERMISSIONS);\n}\n});\nreturn;\n}\nrequestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},\nREQUEST_CODE_ASK_PERMISSIONS);\nreturn;\n}\ninsertDummyContact();\n}\nprivate void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {\nnew AlertDialog.Builder(MainActivity.this)\n.setMessage(message)\n.setPositiveButton(\u0026ldquo;OK\u0026rdquo;, okListener)\n.setNegativeButton(\u0026ldquo;Cancel\u0026rdquo;, null)\n.create()\n.show();\n}\n@Override\npublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\nswitch (requestCode) {\ncase REQUEST_CODE_ASK_PERMISSIONS:\nif (grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n// Permission Granted\ninsertDummyContact();\n} else {\n// Permission Denied\nToast.makeText(MainActivity.this, \u0026ldquo;WRITE_CONTACTS Denied\u0026rdquo;, Toast.LENGTH_SHORT)\n.show();\n}\nbreak;\ndefault:\nsuper.onRequestPermissionsResult(requestCode, permissions, grantResults);\n}\n}\nfinal private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;\nprivate void insertDummyContactWrapper() {\nList permissionsNeeded = new ArrayList();\nfinal List permissionsList = new ArrayList();\nif (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))\npermissionsNeeded.add(\u0026ldquo;GPS\u0026rdquo;);\nif (!addPermission(permissionsList, Manifest.permission.READ_CONTACTS))\npermissionsNeeded.add(\u0026ldquo;Read Contacts\u0026rdquo;);\nif (!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS))\npermissionsNeeded.add(\u0026ldquo;Write Contacts\u0026rdquo;);\nif (permissionsList.size() \u0026gt; 0) {\nif (permissionsNeeded.size() \u0026gt; 0) {\n// Need Rationale\nString message = \u0026ldquo;You need to grant access to \u0026quot; + permissionsNeeded.get(0);\nfor (int i = 1; i \u0026lt; permissionsNeeded.size(); i++)\nmessage = message + \u0026ldquo;, \u0026quot; + permissionsNeeded.get(i);\nshowMessageOKCancel(message,\nnew DialogInterface.OnClickListener() {\n@Override\npublic void onClick(DialogInterface dialog, int which) {\nrequestPermissions(permissionsList.toArray(new String[permissionsList.size()]),\nREQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);\n}\n});\nreturn;\n}\nrequestPermissions(permissionsList.toArray(new String[permissionsList.size()]),\nREQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);\nreturn;\n}\ninsertDummyContact();\n}\nprivate boolean addPermission(List permissionsList, String permission) {\nif (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {\npermissionsList.add(permission);\n// Check for Rationale Option\nif (!shouldShowRequestPermissionRationale(permission))\nreturn false;\n}\nreturn true;\n}\n@Override\npublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\nswitch (requestCode) {\ncase REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:\n{\nMap\u0026lt;String, Integer\u0026gt; perms = new HashMap\u0026lt;String, Integer\u0026gt;();\n// Initial\nperms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);\nperms.put(Manifest.permission.READ_CONTACTS, PackageManager.PERMISSION_GRANTED);\nperms.put(Manifest.permission.WRITE_CONTACTS, PackageManager.PERMISSION_GRANTED);\n// Fill with results\nfor (int i = 0; i \u0026lt; permissions.length; i++)\nperms.put(permissions[i], grantResults[i]);\n// Check for ACCESS_FINE_LOCATION\nif (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED\n\u0026amp;\u0026amp; perms.get(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED\n\u0026amp;\u0026amp; perms.get(Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED) {\n// All Permissions Granted\ninsertDummyContact();\n} else {\n// Permission Denied\nToast.makeText(MainActivity.this, \u0026ldquo;Some Permission is Denied\u0026rdquo;, Toast.LENGTH_SHORT)\n.show();\n}\n}\nbreak;\ndefault:\nsuper.onRequestPermissionsResult(requestCode, permissions, grantResults);\n}\n}\n","permalink":"https://blog.zdltech.com/posts/android-shi-yong-gong-ju/","summary":"\u003ch2 id=\"toc_0\"\u003eAndroid 命令\u003c/h2\u003e\n\u003cp\u003e( adb push 文件 目标文件\u003cbr\u003e\n) adb shell pm install -r \u0026ldquo;/data/local/tmp/xxxx\u0026rdquo;\u003cbr\u003e\npkg: /data/local/tmp/xxxx\u003c/p\u003e\n\u003cp\u003e启动指定Activity\u003cbr\u003e\n$ adb shell am start -n \u0026ldquo;package/package.Activity\u0026rdquo; -a android.intent.action.MAIN -c android.intent.category.LAUNCHER\u003c/p\u003e\n\u003ch2 id=\"toc_1\"\u003eAndroid 动态权限\u003c/h2\u003e\n\u003cp\u003efinal private int REQUEST_CODE_ASK_PERMISSIONS = 123;\u003cbr\u003e\nprivate void insertDummyContactWrapper() {\u003cbr\u003e\nint hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS);\u003cbr\u003e\nif (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {\u003cbr\u003e\nif (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {\u003cbr\u003e\nshowMessageOKCancel(\u0026ldquo;You need to allow access to Contacts\u0026rdquo;,\u003cbr\u003e\nnew DialogInterface.OnClickListener() {\u003cbr\u003e\n@Override\u003cbr\u003e\npublic void onClick(DialogInterface dialog, int which) {\u003cbr\u003e\nrequestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},\u003cbr\u003e\nREQUEST_CODE_ASK_PERMISSIONS);\u003cbr\u003e\n}\u003cbr\u003e\n});\u003cbr\u003e\nreturn;\u003cbr\u003e\n}\u003cbr\u003e\nrequestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},\u003cbr\u003e\nREQUEST_CODE_ASK_PERMISSIONS);\u003cbr\u003e\nreturn;\u003cbr\u003e\n}\u003cbr\u003e\ninsertDummyContact();\u003cbr\u003e\n}\u003c/p\u003e","title":"Android实用工具"},{"content":"需求：我想根据不同的类型，打包不同的版本号，在Android中怎么实现？\n例如：release（发布）版本号 1.0.1,debug（测试）版本号1.0.1.20160924\n在Android开发中，我们会不断的进行版本打包，打包分为2类：\n1、release（正式发布上线版）\n2、debug（测试版）。\n我们可以通过每次打包前修改build.gradle中android-\u0026gt;versionName实现，作为一个程序员，有不断探索的精神，能懒就懒（重复没有意义的工作懒的做）。\n知识介绍 1、gradle中定义变量和函数 通过关键字 def 来定义 例如：def versionStr = \u0026quot;1.0.1\u0026quot; def myFunction() { return \u0026quot;xxxxx\u0026quot; } 2、gradle中时间使用 new Date().format(\u0026quot;yyyyMMdd\u0026quot;, TimeZone.getTimeZone(\u0026quot;UTC\u0026quot;); 这行代码的意思是“当前时间是UTC时区，已yyyyMMdd格式化时间输出” 3、gradle中variant.mergedFlavor使用 variant.mergedFlavor.versionName 表示修改打包时versionName的值 4、gradle中variant.outputs使用 variant.outputs表示输出相关配置 下面是我的build.gradle文件 apply plugin: \u0026amp;#39;com.android.application\u0026amp;#39; apply plugin: \u0026amp;#39;android-apt\u0026amp;#39; //定义时间 def releaseTime() { return new Date().format(\u0026quot;yyyyMMdd\u0026quot;, TimeZone.getTimeZone(\u0026quot;UTC\u0026quot;)) } //设置发布的显示的版本号 def getVersionName(){ return \u0026quot;1.2.0\u0026quot; } android { compileSdkVersion 23 buildToolsVersion \u0026quot;24.0.0\u0026quot; defaultConfig { applicationId \u0026quot;com.xxx.xxxx\u0026quot; minSdkVersion 14 targetSdkVersion 23 versionCode 3 //versionName getVersionName() } buildTypes { debug { buildConfigField(\u0026quot;boolean\u0026quot;,\u0026quot;API_DEBUG\u0026quot;,\u0026quot;true\u0026quot;) minifyEnabled false proguardFiles getDefaultProguardFile(\u0026amp;#39;proguard-android.txt\u0026amp;#39;), \u0026amp;#39;proguard-rules.pro\u0026amp;#39; } release { buildConfigField(\u0026quot;boolean\u0026quot;,\u0026quot;API_DEBUG\u0026quot;,\u0026quot;false\u0026quot;) minifyEnabled false proguardFiles getDefaultProguardFile(\u0026amp;#39;proguard-android.txt\u0026amp;#39;), \u0026amp;#39;proguard-rules.pro\u0026amp;#39; } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } //修改打包不能成功配置 lintOptions { checkReleaseBuilds false abortOnError false } //配置自定义打包名称 applicationVariants.all { variant -\u0026gt; variant.outputs.each { output -\u0026gt; def outputFile = output.outputFile def fileName if (outputFile != null \u0026amp;\u0026amp; outputFile.name.endsWith(\u0026amp;#39;.apk\u0026amp;#39;)) { if (variant.buildType.name.equals(\u0026amp;#39;release\u0026amp;#39;)) { variant.mergedFlavor.versionName = getVersionName() fileName = \u0026quot;XXXX_\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;{variant.mergedFlavor.versionName}_release.apk\u0026quot; } else if (variant.buildType.name.equals(\u0026amp;#39;debug\u0026amp;#39;)) { variant.mergedFlavor.versionName = getVersionName()+\u0026quot;.\u0026quot;+releaseTime() fileName = \u0026quot;XXXX_\u0026lt;/span\u0026gt;{variant.mergedFlavor.versionName}_debug.apk\u0026quot; } output.outputFile = new File(outputFile.parent, fileName) } } } } dependencies { compile fileTree(include: [\u0026amp;#39;*.jar\u0026amp;#39;], dir: \u0026amp;#39;libs\u0026amp;#39;) testCompile \u0026amp;#39;junit:junit:4.12\u0026amp;#39; } tasks.withType(JavaCompile) { options.encoding = \u0026quot;UTF-8\u0026quot; } 大家可以举一反三\n例如想修改versionCode可以这么写\nvariant.mergedFlavor.versionCode = xxxx；\n现在试试吧！\n打包输出apk效果图\n在应用程序中看效果图\n关注公众号获取更多内容和反馈沟通\n","permalink":"https://blog.zdltech.com/posts/android-shi-yonggradle-da-baoapp-ming-cheng-he-ban/","summary":"\u003cp\u003e需求：我想根据不同的类型，打包不同的版本号，在Android中怎么实现？\u003cbr\u003e\n例如：release（发布）版本号 1.0.1,debug（测试）版本号1.0.1.20160924\u003cbr\u003e\n在Android开发中，我们会不断的进行版本打包，打包分为2类：\u003cbr\u003e\n1、release（正式发布上线版）\u003cbr\u003e\n2、debug（测试版）。\u003cbr\u003e\n我们可以通过每次打包前修改build.gradle中android-\u0026gt;versionName实现，作为一个程序员，有不断探索的精神，能懒就懒（重复没有意义的工作懒的做）。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    知识介绍\n    1、gradle中定义变量和函数 通过关键字 def 来定义\n        例如：def versionStr = \u0026quot;1.0.1\u0026quot;  \n                   def myFunction() { return \u0026quot;xxxxx\u0026quot; }\n\n    2、gradle中时间使用\n          new Date().format(\u0026quot;yyyyMMdd\u0026quot;, TimeZone.getTimeZone(\u0026quot;UTC\u0026quot;);\n          这行代码的意思是“当前时间是UTC时区，已yyyyMMdd格式化时间输出”\n\n    3、gradle中variant.mergedFlavor使用\n          variant.mergedFlavor.versionName 表示修改打包时versionName的值\n\n    4、gradle中variant.outputs使用\n          variant.outputs表示输出相关配置\n\n   下面是我的build.gradle文件\n\n        apply plugin: \u0026amp;#39;com.android.application\u0026amp;#39;\n        apply plugin: \u0026amp;#39;android-apt\u0026amp;#39;\n\n//定义时间\ndef releaseTime() {\n   return new Date().format(\u0026quot;yyyyMMdd\u0026quot;, TimeZone.getTimeZone(\u0026quot;UTC\u0026quot;))\n}\n\n//设置发布的显示的版本号\ndef getVersionName(){\n    return \u0026quot;1.2.0\u0026quot;\n}\n\nandroid {\n   compileSdkVersion 23\n   buildToolsVersion \u0026quot;24.0.0\u0026quot;\n\n   defaultConfig {\n    applicationId \u0026quot;com.xxx.xxxx\u0026quot;\n    minSdkVersion 14\n    targetSdkVersion 23\n    versionCode 3\n    //versionName getVersionName()\n    }\nbuildTypes {\n    debug {\n        buildConfigField(\u0026quot;boolean\u0026quot;,\u0026quot;API_DEBUG\u0026quot;,\u0026quot;true\u0026quot;)\n        minifyEnabled false\n        proguardFiles getDefaultProguardFile(\u0026amp;#39;proguard-android.txt\u0026amp;#39;), \u0026amp;#39;proguard-rules.pro\u0026amp;#39;\n    }\n    release {\n        buildConfigField(\u0026quot;boolean\u0026quot;,\u0026quot;API_DEBUG\u0026quot;,\u0026quot;false\u0026quot;)\n        minifyEnabled false\n        proguardFiles getDefaultProguardFile(\u0026amp;#39;proguard-android.txt\u0026amp;#39;), \u0026amp;#39;proguard-rules.pro\u0026amp;#39;\n    }\n}\ncompileOptions {\n    sourceCompatibility JavaVersion.VERSION_1_7\n    targetCompatibility JavaVersion.VERSION_1_7\n}\n\n//修改打包不能成功配置\nlintOptions {\n    checkReleaseBuilds false\n    abortOnError false\n}\n//配置自定义打包名称\napplicationVariants.all { variant -\u0026gt;\n    variant.outputs.each { output -\u0026gt;\n        def outputFile = output.outputFile\n        def fileName\n        if (outputFile != null \u0026amp;\u0026amp; outputFile.name.endsWith(\u0026amp;#39;.apk\u0026amp;#39;)) {\n            if (variant.buildType.name.equals(\u0026amp;#39;release\u0026amp;#39;)) {\n                variant.mergedFlavor.versionName = getVersionName()\n                fileName = \u0026quot;XXXX_\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;{variant.mergedFlavor.versionName}_release.apk\u0026quot;\n            } else if (variant.buildType.name.equals(\u0026amp;#39;debug\u0026amp;#39;)) {\n                variant.mergedFlavor.versionName = getVersionName()+\u0026quot;.\u0026quot;+releaseTime()\n                fileName = \u0026quot;XXXX_\u0026lt;/span\u0026gt;{variant.mergedFlavor.versionName}_debug.apk\u0026quot;\n            }\n            output.outputFile = new File(outputFile.parent, fileName)\n        }\n    }\n}\n}\ndependencies {\n    compile fileTree(include: [\u0026amp;#39;*.jar\u0026amp;#39;], dir: \u0026amp;#39;libs\u0026amp;#39;)\n    testCompile \u0026amp;#39;junit:junit:4.12\u0026amp;#39;\n}\ntasks.withType(JavaCompile) {\n    options.encoding = \u0026quot;UTF-8\u0026quot;\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e大家可以举一反三\u003cbr\u003e\n例如想修改versionCode可以这么写\u003cbr\u003e\nvariant.mergedFlavor.versionCode = xxxx；\u003cbr\u003e\n现在试试吧！\u003c/p\u003e","title":"Android 使用Gradle打包APP名称和版本号"},{"content":"学习网站 http://wiki.jikexueyuan.com/project/react-native/ http://wiki.jikexueyuan.com/project/react-native-lesson/ 环境搭建 安装HomeBrew（brew -v查看brew）\n安装NodeJS （brew install NVM,nvm install node \u0026amp;\u0026amp; nvm alias default node）\n安装 watchman 和 flow(这两个包分别是监控文件变化和类型检查的)brew install watchman\nbrew install flow\n通过 npm安装react-native(\nnpm install -g react-native-cli)\ninit卡解决方案\n￼\n注意：App开发环境的设置 iOS XCode 6.3 及其以上即可。\nAndroid 这个比较麻烦。\n设置环境变量：ANDROID_HOME\nexport ANDROID_HOME=/usr/local/opt/android-sdk\nSDK Manager 安装以下包： Android SDK Build-tools version 23.0.1 Android 6.0 (API 23) Android Support Repository 使用步骤 react-native init 项目名称—-创建项目\n进入项目根目录，项目目录（如下）：\n￼\nreact-native run-android 运行android项目/run-ios 运行IOS项目\n项目中index.android.js和index.ios.js是我们的界面，以后的开发中都是对这些文件编写。例如：product.android.js/product.ios.js 由于android和ios的控件不同，需要根据不同情况添加控件。\n项目目录说明 android是android项目目录 index.android.js是android项目界面 index.ios.js是ios项目界面 node_modules是集成的使用到的node模板 package.json是项目的描述文件 ","permalink":"https://blog.zdltech.com/posts/react-native-ru-men-xue-xi/","summary":"\u003ch2 id=\"toc_0\"\u003e学习网站\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://wiki.jikexueyuan.com/project/react-native/\"\u003ehttp://wiki.jikexueyuan.com/project/react-native/\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://wiki.jikexueyuan.com/project/react-native-lesson/\"\u003ehttp://wiki.jikexueyuan.com/project/react-native-lesson/\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"toc_1\"\u003e环境搭建\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e安装HomeBrew（brew -v查看brew）\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e安装NodeJS （brew install NVM,nvm install node \u0026amp;\u0026amp; nvm alias default node）\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e安装 watchman 和 flow(这两个包分别是监控文件变化和类型检查的)brew install watchman\u003cbr\u003e\nbrew install flow\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e通过 npm安装react-native(\u003cbr\u003e\nnpm install -g react-native-cli)\u003c/p\u003e\n\u003cp\u003einit卡解决方案\u003cbr\u003e\n\u003cimg alt=\"14740321421766\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/09/14740321421766.jpg\"\u003e ￼\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"toc_2\"\u003e注意：App开发环境的设置\u003c/h3\u003e\n\u003ch4 id=\"toc_3\"\u003eiOS\u003c/h4\u003e\n\u003cp\u003eXCode 6.3 及其以上即可。\u003c/p\u003e\n\u003ch4 id=\"toc_4\"\u003eAndroid\u003c/h4\u003e\n\u003cp\u003e这个比较麻烦。\u003cbr\u003e\n设置环境变量：ANDROID_HOME\u003cbr\u003e\nexport ANDROID_HOME=/usr/local/opt/android-sdk\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eSDK Manager 安装以下包：\nAndroid SDK Build-tools   version 23.0.1\nAndroid 6.0 (API 23)\nAndroid Support Repository\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"toc_5\"\u003e使用步骤\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003ereact-native init 项目名称—-创建项目\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e进入项目根目录，项目目录（如下）：\u003cbr\u003e\n\u003cimg alt=\"14740362061031\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/09/14740362061031.jpg\"\u003e ￼\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ereact-native run-android 运行android项目/run-ios 运行IOS项目\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e项目中index.android.js和index.ios.js是我们的界面，以后的开发中都是对这些文件编写。例如：product.android.js/product.ios.js 由于android和ios的控件不同，需要根据不同情况添加控件。\u003c/p\u003e","title":"React Native入门学习"},{"content":"前阵子Android Studio 2.0正式版发布了，很高兴的就升到了最新版本。\n一编译就出现400多个错误提示，Gradle2.0编译速度也让人泪奔，哎，可能是技术太渣不懂那些配置，晚晚加班也没时间学习，还好debug方式编译正常运行\n今天老大叫发布APK，使用Android Studio2.0 release APK 时出现ExternalSystemException: String index out of range: -123错误提示，\n搞了一个晚上终于解决了，记忆不好，在这里记录一下，怕以后出现类似问题忘记怎么解决。\n解决方法：\n在主项目build.gradle的android标签里加上\nlintOptions { checkReleaseBuilds **false ** *// Or, if you prefer, you can continue to check for errors in release builds, ** // but continue the build even when errors are found: * abortOnError **false **} 如图： ![](http://img.blog.csdn.net/20160423152939548?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 转自：http://blog.csdn.net/jia__/article/details/51226475 ","permalink":"https://blog.zdltech.com/posts/android-studio-2-0%E5%8F%91%E5%B8%83apk%E5%87%BA%E7%8E%B0externalsystemexception-string-index-out-of-range-123%E9%94%99%E8%AF%AF/","summary":"\u003cp\u003e前阵子Android Studio 2.0正式版发布了，很高兴的就升到了最新版本。\u003c/p\u003e\n\u003cp\u003e一编译就出现400多个错误提示，Gradle2.0编译速度也让人泪奔，哎，可能是技术太渣不懂那些配置，晚晚加班也没时间学习，还好debug方式编译正常运行\u003c/p\u003e\n\u003cp\u003e今天老大叫发布APK，使用Android Studio2.0 release APK 时出现ExternalSystemException: String index out of range: -123错误提示，\u003c/p\u003e\n\u003cp\u003e搞了一个晚上终于解决了，记忆不好，在这里记录一下，怕以后出现类似问题忘记怎么解决。\u003c/p\u003e\n\u003cp\u003e解决方法：\u003c/p\u003e\n\u003cp\u003e在主项目build.gradle的android标签里加上\u003c/p\u003e\n\u003cdiv class=\"top-box hide\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elintOptions {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    checkReleaseBuilds **false\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e**    *// Or, if you prefer, you can continue to check for errors in release builds,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e**    // but continue the build even when errors are found:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e*    abortOnError **false\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e**}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e如图：\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e![](http://img.blog.csdn.net/20160423152939548?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e转自：http://blog.csdn.net/jia__/article/details/51226475\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"Android Studio 2.0+发布APK出现ExternalSystemException: String index out of range: -123错误"},{"content":"由于需要在项目中增加Websocket协议，与客户端进行通信，不想使用开源的库，比如WebSocketPP，就自己根据WebSocket协议实现一套函数，完全使用C++实现。\n代码已经实现，放在个人github上面，地址：https://github.com/jice1001/websocket.git。下面进行解释说明：\n一、原理\nWebsocket协议解析，已经在前面博客里面详细讲解过，可以参考博客http://www.cnblogs.com/jice1990/p/5435419.html，这里就不详细细说。\n服务器端实现就是使用TCP协议，使用传统的socket流程进行绑定监听，使用epoll控制多路并发，收到Websocket握手包时候进行握手处理，握手成功便可进行数据收发。\n二、实现\n1、服务器监听\n该部分使用的是TCP socket流程，首先是通过socket函数建立socket,通过bind函数绑定到某个端口，本例使用的是9000，然后通过listen函数开启监听，代码如下：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) listenfd_ = socket(AF_INET, SOCK_STREAM, 0); if(listenfd_ == -1){ DEBUG_LOG(\u0026#34;创建套接字失败!\u0026#34;); return -1; } struct sockaddr_in server_addr; memset(\u0026amp;server_addr, 0, sizeof(sockaddr_in)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(PORT); if(-1 == bind(listenfd_, (struct sockaddr *)(\u0026amp;server_addr), sizeof(server_addr))){ DEBUG_LOG(\u0026#34;绑定套接字失败!\u0026#34;); return -1; } if(-1 == listen(listenfd_, 5)){ DEBUG_LOG(\u0026#34;监听失败!\u0026#34;); return -1; } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 2、epoll控制多路并发\n该部分使用的是epoll流程，首先在初始化时候使用epoll_create创建epoll句柄\n``` epollfd_ = epoll_create(1024); ``` 然后通过epoll_wait等待fd事件来临，当监听到是listenfd事件时候，说明是客户端连接服务器，就使用accept接受连接，然后注册该连接EPOLLIN事件，当epoll监听到EPOLLIN事件时候，即可进行握手和数据读取。代码如下：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) void ctl_event(int fd, bool flag){ struct epoll_event ev; ev.data.fd = fd; ev.events = flag ? EPOLLIN : 0; epoll_ctl(epollfd_, flag ? EPOLL_CTL_ADD : EPOLL_CTL_DEL, fd, \u0026amp;ev); if(flag){ set_noblock(fd); websocket_handler_map_[fd] = new Websocket_Handler(fd); if(fd != listenfd_) DEBUG_LOG(\u0026#34;fd: %d 加入epoll循环\u0026#34;, fd); } else{ close(fd); delete websocket_handler_map_[fd]; websocket_handler_map_.erase(fd); DEBUG_LOG(\u0026#34;fd: %d 退出epoll循环\u0026#34;, fd); } } ![复制代码](http://common.cnblogs.com/images/copycode.gif) ![复制代码](http://common.cnblogs.com/images/copycode.gif) getbuff(), BUFFLEN)) \u0026lt;= 0){ ctl_event(fd, false); } else{ handler-\u0026gt;process(); } } } } return 0; }\u0026#34; data-snippet-id=\u0026#34;ext.51666c03e08fce92251ecc7459770145\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;int epoll_loop(){ struct sockaddr_in client_addr; socklen_t clilen; int nfds = 0; int fd = 0; int bufflen = 0; struct epoll_event events[MAXEVENTSSIZE]; while(true){ nfds = epoll_wait(epollfd_, events, MAXEVENTSSIZE, TIMEWAIT); for(int i = 0; i \u0026amp;lt; nfds; i++){ if(events[i].data.fd == listenfd_){ fd = accept(listenfd_, (struct sockaddr *)\u0026amp;client_addr, \u0026amp;clilen); ctl_event(fd, true); } else if(events[i].events \u0026amp; EPOLLIN){ if((fd = events[i].data.fd) \u0026amp;lt; 0) continue; Websocket_Handler *handler = websocket_handler_map_[fd]; if(handler == NULL) continue; if((bufflen = read(fd, handler-\u0026amp;gt;getbuff(), BUFFLEN)) \u0026amp;lt;= 0){ ctl_event(fd, false); } else{ handler-\u0026amp;gt;process(); } } } } return 0; } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 3、Websocket握手连接\n握手部分主要是根据Websocket握手包进行解析，然后根据Sec-WebSocket-Key进行SHA1哈希，生成相应的key,返回给客户端，与客户端进行握手。代码如下：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) //该函数是获取websocket握手包的信息，按照分割字符进行解析 int fetch_http_info(){ std::istringstream s(buff_); std::string request; std::getline(s, request); if (request[request.size()-1] == \u0026#39;\\r\u0026#39;) { request.erase(request.end()-1); } else { return -1; } std::string header; std::string::size_type end; while (std::getline(s, header) \u0026amp;\u0026amp; header != \u0026#34;\\r\u0026#34;) { if (header[header.size()-1] != \u0026#39;\\r\u0026#39;) { continue; //end } else { header.erase(header.end()-1); //remove last char } end = header.find(\u0026#34;: \u0026#34;,0); if (end != std::string::npos) { std::string key = header.substr(0,end); std::string value = header.substr(end+2); header_map_[key] = value; } } return 0; } ![复制代码](http://common.cnblogs.com/images/copycode.gif) ![复制代码](http://common.cnblogs.com/images/copycode.gif) (message_digest),20); server_key += \u0026amp;quot;\\r\\n\u0026amp;quot;; strcat(request, server_key.c_str()); strcat(request, \u0026amp;quot;Upgrade: websocket\\r\\n\\r\\n\u0026amp;quot;); }\u0026#34; data-snippet-id=\u0026#34;ext.1037e694d2a1acebfc3bc18153a74218\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;//该函数是根据websocket返回包的格式拼接相应的返回包 void parse_str(char *request){ strcat(request, \u0026#34;HTTP/1.1 101 Switching Protocols\\r\\n\u0026#34;); strcat(request, \u0026#34;Connection: upgrade\\r\\n\u0026#34;); strcat(request, \u0026#34;Sec-WebSocket-Accept: \u0026#34;); std::string server_key = header_map_[\u0026#34;Sec-WebSocket-Key\u0026#34;]; server_key += MAGIC_KEY; SHA1 sha; unsigned int message_digest[5]; sha.Reset(); sha \u0026amp;lt;\u0026amp;lt; server_key.c_str(); sha.Result(message_digest); for (int i = 0; i \u0026amp;lt; 5; i++) { message_digest[i] = htonl(message_digest[i]); } server_key = base64_encode(reinterpret_cast\u0026amp;lt;const unsigned char*\u0026amp;gt;(message_digest),20); server_key += \u0026#34;\\r\\n\u0026#34;; strcat(request, server_key.c_str()); strcat(request, \u0026#34;Upgrade: websocket\\r\\n\\r\\n\u0026#34;); } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 4、数据读取\n当服务器与客户端握手成功后，就可以进行正常的通信，读取数据了。使用的是TCP协议的方法，解析Websocket包根据协议格式，在前面博客里面有详细分析，这里只把实现代码贴出来。\n![复制代码](http://common.cnblogs.com/images/copycode.gif) \u0026gt; 7; return 0; } int fetch_opcode(char *msg, int \u0026amp;pos){ opcode_ = msg[pos] \u0026amp; 0x0f; pos++; return 0; } int fetch_mask(char *msg, int \u0026amp;pos){ mask_ = (unsigned char)msg[pos] \u0026gt;\u0026gt; 7; return 0; } int fetch_masking_key(char *msg, int \u0026amp;pos){ if(mask_ != 1) return 0; for(int i = 0; i \u0026lt; 4; i++) masking_key_[i] = msg[pos + i]; pos += 4; return 0; } int fetch_payload_length(char *msg, int \u0026amp;pos){ payload_length_ = msg[pos] \u0026amp; 0x7f; pos++; if(payload_length_ == 126){ uint16_t length = 0; memcpy(\u0026amp;length, msg + pos, 2); pos += 2; payload_length_ = ntohs(length); } else if(payload_length_ == 127){ uint32_t length = 0; memcpy(\u0026amp;length, msg + pos, 4); pos += 4; payload_length_ = ntohl(length); } return 0; } int fetch_payload(char *msg, int \u0026amp;pos){ memset(payload_, 0, sizeof(payload_)); if(mask_ != 1){ memcpy(payload_, msg + pos, payload_length_); } else { for(uint i = 0; i \u0026lt; payload_length_; i++){ int j = i % 4; payload_[i] = msg[pos + i] ^ masking_key_[j]; } } pos += payload_length_; return 0; }\u0026#34; data-snippet-id=\u0026#34;ext.87c0edbc59391ba5235ce52f85303829\u0026#34; data-snippet-saved=\u0026#34;false\u0026#34; data-codota-status=\u0026#34;done\u0026#34;\u0026gt;int fetch_websocket_info(char *msg){ int pos = 0; fetch_fin(msg, pos); fetch_opcode(msg, pos); fetch_mask(msg, pos); fetch_payload_length(msg, pos); fetch_masking_key(msg, pos); return fetch_payload(msg, pos); } int fetch_fin(char *msg, int \u0026amp;pos){ fin_ = (unsigned char)msg[pos] \u0026amp;gt;\u0026amp;gt; 7; return 0; } int fetch_opcode(char *msg, int \u0026amp;pos){ opcode_ = msg[pos] \u0026amp; 0x0f; pos++; return 0; } int fetch_mask(char *msg, int \u0026amp;pos){ mask_ = (unsigned char)msg[pos] \u0026amp;gt;\u0026amp;gt; 7; return 0; } int fetch_masking_key(char *msg, int \u0026amp;pos){ if(mask_ != 1) return 0; for(int i = 0; i \u0026amp;lt; 4; i++) masking_key_[i] = msg[pos + i]; pos += 4; return 0; } int fetch_payload_length(char *msg, int \u0026amp;pos){ payload_length_ = msg[pos] \u0026amp; 0x7f; pos++; if(payload_length_ == 126){ uint16_t length = 0; memcpy(\u0026amp;length, msg + pos, 2); pos += 2; payload_length_ = ntohs(length); } else if(payload_length_ == 127){ uint32_t length = 0; memcpy(\u0026amp;length, msg + pos, 4); pos += 4; payload_length_ = ntohl(length); } return 0; } int fetch_payload(char *msg, int \u0026amp;pos){ memset(payload_, 0, sizeof(payload_)); if(mask_ != 1){ memcpy(payload_, msg + pos, payload_length_); } else { for(uint i = 0; i \u0026amp;lt; payload_length_; i++){ int j = i % 4; payload_[i] = msg[pos + i] ^ masking_key_[j]; } } pos += payload_length_; return 0; } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 5、总结\n到此为止，完整实现了使用C++对Websocket协议进行解析，握手，数据收发，不借助开源库就实现了websocket相关功能，最大程度的与项目保存兼容。\n转自：http://www.cnblogs.com/jice1990/p/5436532.html\n","permalink":"https://blog.zdltech.com/posts/websocket%E7%9A%84c%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%E5%AE%9E%E7%8E%B0/","summary":"\u003cp\u003e由于需要在项目中增加Websocket协议，与客户端进行通信，不想使用开源的库，比如WebSocketPP，就自己根据WebSocket协议实现一套函数，完全使用C++实现。\u003c/p\u003e\n\u003cp\u003e代码已经实现，放在个人github上面，地址：https://github.com/jice1001/websocket.git。下面进行解释说明：\u003c/p\u003e\n\u003cp\u003e一、原理\u003c/p\u003e\n\u003cp\u003eWebsocket协议解析，已经在前面博客里面详细讲解过，可以参考博客http://www.cnblogs.com/jice1990/p/5435419.html，这里就不详细细说。\u003c/p\u003e\n\u003cp\u003e服务器端实现就是使用TCP协议，使用传统的socket流程进行绑定监听，使用epoll控制多路并发，收到Websocket握手包时候进行握手处理，握手成功便可进行数据收发。\u003c/p\u003e\n\u003cp\u003e二、实现\u003c/p\u003e\n\u003cp\u003e1、服务器监听\u003c/p\u003e\n\u003cp\u003e该部分使用的是TCP socket流程，首先是通过socket函数建立socket,通过bind函数绑定到某个端口，本例使用的是9000，然后通过listen函数开启监听，代码如下：\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"top-box hide\"\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  listenfd_ = socket(AF_INET, SOCK_STREAM, 0);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  if(listenfd_ == -1){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      DEBUG_LOG(\u0026#34;创建套接字失败!\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      return -1;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  struct sockaddr_in server_addr;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  memset(\u0026amp;server_addr, 0, sizeof(sockaddr_in));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  server_addr.sin_family = AF_INET;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  server_addr.sin_port = htons(PORT);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  if(-1 == bind(listenfd_, (struct sockaddr *)(\u0026amp;server_addr), sizeof(server_addr))){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      DEBUG_LOG(\u0026#34;绑定套接字失败!\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      return -1;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  if(-1 == listen(listenfd_, 5)){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      DEBUG_LOG(\u0026#34;监听失败!\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      return -1;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e2、epoll控制多路并发\u003c/p\u003e","title":"WebSocket的C++服务器端实现"},{"content":"自然图像抠图/视频抠像技术梳理（image matting, video matting)-计算机视视觉专题1\nhttp://download.csdn.net/detail/jlwyc/4676516\n学习opencv ,图像分割中分水岭算法的感性认识及cvWatershed例子\nOpenCV学习：轮廓\nOpenCV函数cvFindContours\n提取轮廓两种方法及绘制轮廓中最大等级分析\n【OpenCV入门指南】第三篇Canny边缘检测\n【OpenCV入门指南】第四篇 图像的二值化\n【OpenCV入门指南】第五篇 轮廓检测 上\n【OpenCV入门指南】第六篇 轮廓检测 下\n在图像中寻找轮廓\nOPENCV中cvFindContours函数说明\n给轮廓画出矩形和圆形边界\n（转）提取不规则图像\nOpenCv的连通域操作\nopencv图像剪切，保存局部，图像抠取\nOpenCV中Mat类的图像如何设置ROI\nOpenCV中图像及子图像ROI之间的复制\nOpenCV2 图像叠加 给照片加水印\n转自：http://blog.csdn.net/xdonx/article/details/21557625\n","permalink":"https://blog.zdltech.com/posts/opencv%E6%8F%90%E5%8F%96%E8%BD%AE%E5%BB%93%E4%B8%8E%E6%8A%A0%E5%9B%BE/","summary":"\u003cp\u003e\u003ca href=\"http://www.sigvc.org/bbs/thread-554-1-1.html\"\u003e自然图像抠图/视频抠像技术梳理（image matting, video matting)-计算机视视觉专题1\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://download.csdn.net/detail/jlwyc/4676516\"\u003ehttp://download.csdn.net/detail/jlwyc/4676516\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/fdl19881/article/details/6749976\"\u003e学习opencv ,图像分割中分水岭算法的感性认识及cvWatershed例子\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/honpey/article/details/8575507\"\u003eOpenCV学习：轮廓\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/augusdi/article/details/9000893\"\u003eOpenCV函数cvFindContours\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/zcube/article/details/7357602\"\u003e提取轮廓两种方法及绘制轮廓中最大等级分析\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/morewindows/article/details/8239625\"\u003e【OpenCV入门指南】第三篇Canny边缘检测\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/morewindows/article/details/8239678\"\u003e【OpenCV入门指南】第四篇 图像的二值化\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/morewindows/article/details/8253137\"\u003e【OpenCV入门指南】第五篇 轮廓检测 上\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/morewindows/article/details/8253174\"\u003e【OpenCV入门指南】第六篇 轮廓检测 下\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.html#find-contours\"\u003e在图像中寻找轮廓\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.sina.com.cn/s/blog_61d013150100uckn.html\"\u003eOPENCV中cvFindContours函数说明\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/jaguarcxj/article/details/8085140\"\u003e给轮廓画出矩形和圆形边界\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://hi.baidu.com/rockyzhou1984/item/158b61f87225e5c3a835a29e\"\u003e（转）提取不规则图像\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/augusdi/article/details/8864748\"\u003eOpenCv的连通域操作\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/ecocn/article/details/8077007\"\u003eopencv图像剪切，保存局部，图像抠取\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/masibuaa/article/details/9017383\"\u003eOpenCV中Mat类的图像如何设置ROI\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/viewcode/article/details/7823237\"\u003eOpenCV中图像及子图像ROI之间的复制\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://wenku.baidu.com/link?url=O3edZjoFH_n3tWV3fVK66oiyvZdtZjn4BjyHcYlXdCQoTRO5yfGmYK2CSWR0RcosmzbwngqxYarhP7_kX-OMAHRvPayRllEAeFFXKMOKGNy\"\u003eOpenCV2 图像叠加 给照片加水印\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e转自：http://blog.csdn.net/xdonx/article/details/21557625\u003c/p\u003e","title":"opencv提取轮廓与抠图"},{"content":"比如比较字符串、判断文件是否存在及是否可读等，通常用”[]”来表示条件测试。\n注意：这里的空格很重要。要确保方括号的空格。笔者就曾因为空格缺少或位置不对，而浪费好多宝贵的时间。\nif ….; then\n….\nelif ….; then\n….\nelse\n….\nfi\n[ -f “somefile” ] ：判断是否是一个文件\n[ -x “/bin/ls” ] ：判断/bin/ls是否存在并有可执行权限\n[ -n “var” ] ：判断var变量是否有值\n[ “a” = “b” ] ：判断a和b是否相等\n-r file　用户可读为真\n-w file　用户可写为真\n-x file　用户可执行为真\n-f file　文件为正规文件为真\n-d file　文件为目录为真\n-c file　文件为字符特殊文件为真\n-b file　文件为块特殊文件为真\n-s file　文件大小非0时为真\n-t file　当文件描述符(默认为1)指定的设备为终端时为真\n** 字符串判断**\nstr1 = str2　当两个串有相同内容、长度时为真\nstr1 != str2　当串str1和str2不等时为真\n-n str1　当串的长度大于0时为真(串非空)\n-z str1　当串的长度为0时为真(空串)\nstr1　当串str1为非空时为真\n含条件选择的shell脚本 对于不含变量的任务简单shell脚本一般能胜任。但在执行一些决策任务时，就需要包含if/then的条件判断了。shell脚本编程支持此类运算，包括比较运算、判断文件是否存在等。\n基本的if条件命令选项有： – eq —比较两个参数是否相等（例如，if [ 2 –eq 5 ]）\n-ne —比较两个参数是否不相等\n-lt —参数1是否小于参数2\n-le —参数1是否小于等于参数2\n-gt —参数1是否大于参数2\n-ge —参数1是否大于等于参数2\n-f — 检查某文件是否存在（例如，if [ -f “filename” ]）\n-d — 检查目录是否存在\n几乎所有的判断都可以用这些比较运算符实现。脚本中常用-f命令选项在执行某一文件之前检查它是否存在。\n——————————————————————————————-\n由于程序需要，我要判断一个浮点数是否大于另一个浮点数。\n大概情况描述如下：\n变量 mya的值为一个两位小数，这个值是这么取的：\nShell代码 - [nigelzeng@ubuntu \u0026lt;wbr /\u0026gt;~]$ \u0026lt;wbr /\u0026gt;df \u0026lt;wbr /\u0026gt;-h \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - Filesystem \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;Size \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;Used \u0026lt;wbr /\u0026gt;Avail \u0026lt;wbr /\u0026gt;Use% \u0026lt;wbr /\u0026gt;Mounted \u0026lt;wbr /\u0026gt;on \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - /dev/sda1 \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;5.7G \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;3.0G \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;2.5G \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;55% \u0026lt;wbr /\u0026gt;/ \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - [nigelzeng@ubuntu \u0026lt;wbr /\u0026gt;~]$df \u0026lt;wbr /\u0026gt;-h \u0026lt;wbr /\u0026gt;| \u0026lt;wbr /\u0026gt;grep \u0026lt;wbr /\u0026gt;xvda2 \u0026lt;wbr /\u0026gt;| \u0026lt;wbr /\u0026gt;awk \u0026lt;wbr /\u0026gt;\u0026amp;#8216;{print \u0026lt;wbr /\u0026gt;$2}\u0026amp;#8217; \u0026lt;wbr /\u0026gt;| \u0026lt;wbr /\u0026gt;sed \u0026lt;wbr /\u0026gt;\u0026amp;#8216;s/G//\u0026amp;#8217; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - 5.7 \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; mya=` df -h | grep xvda2 | awk ‘{print $2}’ | sed ‘s/G//’ `\n然后我希望让它跟4进行判断，\n一开始是想利用整数来进行判断，但是不行：\nShell代码 - [nigelzeng@ubuntu \u0026lt;wbr /\u0026gt;~]$if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;$mya \u0026lt;wbr /\u0026gt;-le \u0026lt;wbr /\u0026gt;4 \u0026lt;wbr /\u0026gt;]; \u0026lt;wbr /\u0026gt;then \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;ok\u0026amp;#8221;;else \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;fail\u0026amp;#8221;; \u0026lt;wbr /\u0026gt;fi \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - -bash: \u0026lt;wbr /\u0026gt;[: \u0026lt;wbr /\u0026gt;5.7: \u0026lt;wbr /\u0026gt;integer \u0026lt;wbr /\u0026gt;expression \u0026lt;wbr /\u0026gt;expected \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; shell 会报错，提示integer expression expected，\n只能判断整数，而不是5.7这个浮点数。\n但是shell里面是没有变量类型的，所以需要想个别的办法。\n参考了CU里的大牛们的建议，这样写这个比较就可以了：\nShell代码 - [nigelzeng@ubuntu \u0026lt;wbr /\u0026gt;~]$\u0026lt;span style=\u0026quot;color: #fe4c09;\u0026quot;\u0026gt;if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;$(echo \u0026lt;wbr /\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #fe4c09;\u0026quot;\u0026gt;\u0026amp;#8220;$mya \u0026lt;wbr /\u0026gt;\u0026lt;= \u0026lt;wbr /\u0026gt;4\u0026amp;#8243;|bc) \u0026lt;wbr /\u0026gt;= \u0026lt;wbr /\u0026gt;1 \u0026lt;wbr /\u0026gt;]; \u0026lt;wbr /\u0026gt;then \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;ok\u0026amp;#8221;;else \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;fail\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #fe4c09;\u0026quot;\u0026gt;;fi \u0026lt;wbr /\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;wbr /\u0026gt; 这里借助了bc这个命令（bc是一个计算器，Bash内置了对整数四则运算的支持，但是并不支持浮点运算，而bc命令可以很方便的进行浮点运算，当然整数运算也不再话下。）\nshell脚本—-if（数字条件，字符串条件，字符串为空） 二元比较操作符,比较变量或者比较数字.\n注意数字与字符串的区别.\n1.整数比较 **[cpp]** [view plain](http://blog.csdn.net/yf210yf/article/details/9207147#)[copy](http://blog.csdn.net/yf210yf/article/details/9207147#)[print](http://blog.csdn.net/yf210yf/article/details/9207147#)[?](http://blog.csdn.net/yf210yf/article/details/9207147#) - -eq \u0026lt;wbr /\u0026gt;等于,如:if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;-eq \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$b\u0026amp;#8221; \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - -ne \u0026lt;wbr /\u0026gt;不等于,如:if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;-ne \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$b\u0026amp;#8221; \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - -gt \u0026lt;wbr /\u0026gt;大于,如:if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;-gt \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$b\u0026amp;#8221; \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - -ge \u0026lt;wbr /\u0026gt;大于等于,如:if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;-ge \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$b\u0026amp;#8221; \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - -lt \u0026lt;wbr /\u0026gt;小于,如:if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;-lt \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$b\u0026amp;#8221; \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - -le \u0026lt;wbr /\u0026gt;小于等于,如:if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;-le \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$b\u0026amp;#8221; \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;小于(需要双括号),如:((\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;\u0026lt; \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$b\u0026amp;#8221;)) \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;= \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;小于等于(需要双括号),如:((\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;\u0026lt;= \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$b\u0026amp;#8221;)) \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;大于(需要双括号),如:((\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;\u0026gt; \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$b\u0026amp;#8221;)) \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026gt;= \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;大于等于(需要双括号),如:((\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;\u0026gt;= \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$b\u0026amp;#8221;)) \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; 小数据比较可使用AWK 2.字符串比较\n**[cpp]** [view plain](http://blog.csdn.net/yf210yf/article/details/9207147#)[copy](http://blog.csdn.net/yf210yf/article/details/9207147#)[print](http://blog.csdn.net/yf210yf/article/details/9207147#)[?](http://blog.csdn.net/yf210yf/article/details/9207147#) - = \u0026lt;wbr /\u0026gt;等于,如:if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;= \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$b\u0026amp;#8221; \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - == \u0026lt;wbr /\u0026gt;等于,如:if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;== \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$b\u0026amp;#8221; \u0026lt;wbr /\u0026gt;],与=等价 \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; 注意：\n比较两个字符串是否相等的办法是： if [ \u0026#8220;$test\u0026#8221;x = \u0026#8220;test\u0026#8221;x ]; then 这里的关键有几点： 1 使用单个等号 2 注意到等号两边各有一个空格：这是unix shell的要求 3 注意到\u0026#8221;test\u0026#8221;x最后的x，这是特意安排的，因为当test为空的时候，上面的表达式就变成了x = testx，显然是不相等的。而如果没有这个x，表达式就会报错：[: =: unary operator expected 注意:==的功能在[[]]和[]中的行为是不同的,如下:\n**[cpp]** [view plain](http://blog.csdn.net/yf210yf/article/details/9207147#)[copy](http://blog.csdn.net/yf210yf/article/details/9207147#)[print](http://blog.csdn.net/yf210yf/article/details/9207147#)[?](http://blog.csdn.net/yf210yf/article/details/9207147#) - [[ \u0026lt;wbr /\u0026gt;$a \u0026lt;wbr /\u0026gt;== \u0026lt;wbr /\u0026gt;z* \u0026lt;wbr /\u0026gt;]] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;# \u0026lt;wbr /\u0026gt;如果$a以\u0026amp;#8221;z\u0026amp;#8221;开头(模式匹配)那么将为true \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - [[ \u0026lt;wbr /\u0026gt;$a \u0026lt;wbr /\u0026gt;== \u0026lt;wbr /\u0026gt;\u0026amp;#8220;z*\u0026amp;#8221; \u0026lt;wbr /\u0026gt;]] \u0026lt;wbr /\u0026gt;# \u0026lt;wbr /\u0026gt;如果$a等于z*(字符匹配),那么结果为true \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - [ \u0026lt;wbr /\u0026gt;$a \u0026lt;wbr /\u0026gt;== \u0026lt;wbr /\u0026gt;z* \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;# \u0026lt;wbr /\u0026gt;File \u0026lt;wbr /\u0026gt;globbing \u0026lt;wbr /\u0026gt;和word \u0026lt;wbr /\u0026gt;splitting将会发生 \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - [ \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;== \u0026lt;wbr /\u0026gt;\u0026amp;#8220;z*\u0026amp;#8221; \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt;# \u0026lt;wbr /\u0026gt;如果$a等于z*(字符匹配),那么结果为true \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; 一点解释,关于File globbing是一种关于文件的速记法,比如”*.c”就是,再如~也是.\n但是file globbing并不是严格的正则表达式,虽然绝大多数情况下结构比较像.\n!= 不等于,如:if [ “a” != “b” ]\n这个操作符将在[[]]结构中使用模式匹配.\n\u0026lt; 小于,在ASCII字母顺序下.如:\nif [[ “a”\u0026lt;\u0026quot;b” ]]\nif [ “a” \u0026lt; “b” ]\n注意:在[]结构中”\u0026lt;“需要被转义.\n大于,在ASCII字母顺序下.如:\nif [[ “a”\u0026gt;”b” ]]\nif [ “a” \u0026gt; “b” ]\n注意:在[]结构中”\u0026gt;”需要被转义.\n具体参考Example 26-11来查看这个操作符应用的例子.\n-z 字符串为”null”.就是长度为0.\n-n 字符串不为”null”\n注意:\n使用-n在[]结构中测试必须要用””把变量引起来.使用一个未被””的字符串来使用! -z\n或者就是未用””引用的字符串本身,放到[]结构中。虽然一般情况下可\n以工作,但这是不安全的.习惯于使用””来测试字符串是一种好习惯.\n举例：\n1.数字比较\n- #!/bin/bash \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - i=6 \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - a=10 \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;$a \u0026lt;wbr /\u0026gt;-eq \u0026lt;wbr /\u0026gt;10 \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - then \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;a \u0026lt;wbr /\u0026gt;= \u0026lt;wbr /\u0026gt;10\u0026amp;#8243; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - fi \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;$a \u0026lt;wbr /\u0026gt;-ne \u0026lt;wbr /\u0026gt;$i \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - then \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;a \u0026lt;wbr /\u0026gt;!= \u0026lt;wbr /\u0026gt;$i\u0026amp;#8221; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - fi \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;$a \u0026lt;wbr /\u0026gt;-gt \u0026lt;wbr /\u0026gt;$i \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - then \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;a \u0026lt;wbr /\u0026gt;\u0026gt; \u0026lt;wbr /\u0026gt;i\u0026amp;#8221; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - fi \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;$a \u0026lt;wbr /\u0026gt;-lt \u0026lt;wbr /\u0026gt;$i \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - then \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;a \u0026lt;wbr /\u0026gt;\u0026lt; \u0026lt;wbr /\u0026gt;i\u0026amp;#8221; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - else \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;a \u0026lt;wbr /\u0026gt;\u0026gt; \u0026lt;wbr /\u0026gt;i\u0026amp;#8221; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - fi \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - if((\u0026amp;#8220;$a\u0026amp;#8221; \u0026lt;wbr /\u0026gt;\u0026gt; \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$i\u0026amp;#8221;)) \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - then \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;(())a\u0026gt;i\u0026amp;#8221; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - fi \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - if(($a \u0026lt;wbr /\u0026gt;!= \u0026lt;wbr /\u0026gt;$i)) \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - then \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;(())a!=i\u0026amp;#8221; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - fi \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; 备注：通过sh运行脚本，[ ]运算是可以的，而（（））运行出错\nchmod 777 后，直接./ 运行，都可以\n2.字符串比较\n- #!/bin/bash \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - a=\u0026amp;#8221;123\u0026amp;#8243; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - b=\u0026amp;#8221;1234\u0026amp;#8243; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - c=\u0026amp;#8221;123\u0026amp;#8243; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$a\u0026amp;#8221;x \u0026lt;wbr /\u0026gt;!= \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$b\u0026amp;#8221;x \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - then \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;a \u0026lt;wbr /\u0026gt;!= \u0026lt;wbr /\u0026gt;b\u0026amp;#8221; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - fi \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$a\u0026amp;#8221;x \u0026lt;wbr /\u0026gt;= \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$c\u0026amp;#8221;x \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - then \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;a \u0026lt;wbr /\u0026gt;== \u0026lt;wbr /\u0026gt;c\u0026amp;#8221; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - fi \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; 判断字符串为空\n**[cpp]** [view plain](http://blog.csdn.net/yf210yf/article/details/9207147#)[copy](http://blog.csdn.net/yf210yf/article/details/9207147#)[print](http://blog.csdn.net/yf210yf/article/details/9207147#)[?](http://blog.csdn.net/yf210yf/article/details/9207147#) - if \u0026lt;wbr /\u0026gt;[ \u0026lt;wbr /\u0026gt;-z \u0026lt;wbr /\u0026gt;\u0026amp;#8220;$d\u0026amp;#8221; \u0026lt;wbr /\u0026gt;] \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - then \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt;echo \u0026lt;wbr /\u0026gt;\u0026amp;#8220;d \u0026lt;wbr /\u0026gt;is \u0026lt;wbr /\u0026gt;empty\u0026amp;#8221; \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; - fi \u0026lt;wbr /\u0026gt; \u0026lt;wbr /\u0026gt; 备注：\n-e 文件存在\n-a 文件存在（已被弃用）\n-f 被测文件是一个regular文件（正常文件，非目录或设备）\n-s 文件长度不为0\n-d 被测对象是目录\n-b 被测对象是块设备\n-c 被测对象是字符设备\n-p 被测对象是管道\n-h 被测文件是符号连接\n-L 被测文件是符号连接\n-S(大写) 被测文件是一个socket\n-t 关联到一个终端设备的文件描述符。用来检测脚本的stdin[-t0]或[-t1]是一个终端\n-r 文件具有读权限，针对运行脚本的用户\n-w 文件具有写权限，针对运行脚本的用户\n-x 文件具有执行权限，针对运行脚本的用户\n-u set-user-id(suid)标志到文件，即普通用户可以使用的root权限文件，通过chmod +s file实现\n-k 设置粘贴位\n-O 运行脚本的用户是文件的所有者\n-G 文件的group-id和运行脚本的用户相同\n-N 从文件最后被阅读到现在，是否被修改\nf1 -nt f2 文件f1是否比f2新\nf1 -ot f2 文件f1是否比f2旧\nf1 -ef f2 文件f1和f2是否硬连接到同一个文件\n二元比较操作符，比较变量或比较数字\n整数比较：\n-eq 等于 if [ “a” -eq “b” ]\n-ne 不等于 if [ “a” -ne “b” ]\n-gt 大于 if [ “a” -gt “b” ]\n-ge 大于等于 if [ “a” -ge “b” ]\n-lt 小于 if [ “a” -lt “b” ]\n-le 小于等于 if [ “a” -le “b” ]\n\u0026lt; 小于（需要双括号） (( “a”\u0026lt;\u0026quot;b” ))\n\u0026lt;= 小于等于(…) (( “a” \u0026lt;= “b” ))\n大于(…) (( “a”\u0026gt;”b” ))\n= 大于等于(…) (( “a” \u0026gt;= “b” ))\n字符串比较：\n= 等于 if [ “a” = “b” ]\n== 与=等价\n!= 不等于 if [ “a” = “b” ]\n\u0026lt; 小于，在ASCII字母中的顺序：\nif [[ “a”\u0026lt;\u0026quot;b” ]]\nif [ “a” \u0026lt; “b” ] #需要对\u0026lt;进行转义\n大于\n-z 字符串为null，即长度为0\n-n 字符串不为null，即长度不为0\n","permalink":"https://blog.zdltech.com/posts/linux-shell%E4%B8%AD-if-else%E4%BB%A5%E5%8F%8A%E5%A4%A7%E4%BA%8E%E5%B0%8F%E4%BA%8E%E7%AD%89%E4%BA%8E%E9%80%BB%E8%BE%91%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%BB%8B%E7%BB%8D/","summary":"\u003cp\u003e比如比较字符串、判断文件是否存在及是否可读等，通常用”[]”来表示条件测试。\u003c/p\u003e\n\u003cp\u003e注意：这里的空格很重要。要确保方括号的空格。笔者就曾因为空格缺少或位置不对，而浪费好多宝贵的时间。\u003c/p\u003e\n\u003cp\u003eif ….; then\u003cbr\u003e\n….\u003cbr\u003e\nelif ….; then\u003cbr\u003e\n….\u003cbr\u003e\nelse\u003cbr\u003e\n….\u003cbr\u003e\nfi\u003cbr\u003e\n[ -f “somefile” ] ：判断是否是一个文件\u003cbr\u003e\n[ -x “/bin/ls” ] ：判断/bin/ls是否存在并有可执行权限\u003cbr\u003e\n[ -n “\u003cspan class=\"katex math inline\"\u003evar” ] ：判断\u003c/span\u003evar变量是否有值\u003cbr\u003e\n[ “\u003cspan class=\"katex math inline\"\u003ea” = “\u003c/span\u003eb” ] ：判断\u003cspan class=\"katex math inline\"\u003ea和\u003c/span\u003eb是否相等\u003cbr\u003e\n-r file　　　　　用户可读为真\u003cbr\u003e\n-w file　　　　　用户可写为真\u003cbr\u003e\n-x file　　　　　用户可执行为真\u003cbr\u003e\n-f file　　　　　文件为正规文件为真\u003cbr\u003e\n-d file　　　　　文件为目录为真\u003cbr\u003e\n-c file　　　　　文件为字符特殊文件为真\u003cbr\u003e\n-b file　　　　　文件为块特殊文件为真\u003cbr\u003e\n-s file　　　　　文件大小非0时为真\u003cbr\u003e\n-t file　　　　　当文件描述符(默认为1)指定的设备为终端时为真\u003c/p\u003e\n\u003cp\u003e** \u003cwbr /\u003e字符串判断**\u003c/p\u003e\n\u003cp\u003estr1 = str2　　　　　　当两个串有相同内容、长度时为真\u003cbr\u003e\nstr1 != str2　　　　　 当串str1和str2不等时为真\u003cbr\u003e\n-n str1　　　　　　　 当串的长度大于0时为真(串非空)\u003cbr\u003e\n-z str1　　　　　　　 当串的长度为0时为真(空串)\u003cbr\u003e\nstr1　　　　　　　　 \u003cwbr /\u003e \u003cwbr /\u003e 当串str1为非空时为真\u003c/p\u003e","title":"linux shell中 if else以及大于、小于、等于逻辑表达式介绍"},{"content":"\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt; \u0026amp;lt;selector xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;gt; \u0026amp;lt;!-- focused --\u0026amp;gt; \u0026amp;lt;item android:drawable=\u0026#34;@drawable/orderboard_detail_tab_middle_selected\u0026#34; android:state_checked=\u0026#34;true\u0026#34; /\u0026amp;gt; \u0026amp;lt;item android:drawable=\u0026#34;@drawable/orderboard_detail_tab_middle_selected\u0026#34; android:state_selected=\u0026#34;true\u0026#34; /\u0026amp;gt; \u0026amp;lt;!-- default --\u0026amp;gt; \u0026amp;lt;item \u0026amp;gt; \u0026amp;lt;layer-list xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;gt; \u0026amp;lt;item android:left=\u0026#34;-1dp\u0026#34; android:right=\u0026#34;-1dp\u0026#34; \u0026amp;gt; \u0026amp;lt;shape android:shape=\u0026#34;rectangle\u0026#34;\u0026amp;gt; \u0026amp;lt;solid android:color=\u0026#34;@color/text_color_white\u0026#34; /\u0026amp;gt; \u0026amp;lt;stroke android:width=\u0026#34;1dp\u0026#34; android:color=\u0026#34;@color/text_color_blue\u0026#34; /\u0026amp;gt; \u0026amp;lt;padding android:left=\u0026#34;0dp\u0026#34; android:right=\u0026#34;0dp\u0026#34; /\u0026amp;gt; \u0026amp;lt;corners android:radius=\u0026#34;0dp\u0026#34;/\u0026amp;gt; \u0026amp;lt;/shape\u0026amp;gt; \u0026amp;lt;/item\u0026amp;gt; \u0026amp;lt;/layer-list\u0026amp;gt; \u0026amp;lt;/item\u0026amp;gt; \u0026amp;lt;/selector\u0026amp;gt; 上面执行的结果：只画上下线 [![QQ20160830-0@2x](http://www.etongwl.com/images/2016/08/QQ20160830-0@2x-300x289.png)](http://www.etongwl.com/images/2016/08/QQ20160830-0@2x.png) ","permalink":"https://blog.zdltech.com/posts/android-shape%E5%8F%AA%E6%98%BE%E7%A4%BA%E6%8C%87%E5%AE%9A%E8%BE%B9%E6%A1%86%E7%94%A8%E6%B3%95/","summary":"\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;selector xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;!-- focused --\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;item android:drawable=\u0026#34;@drawable/orderboard_detail_tab_middle_selected\u0026#34; android:state_checked=\u0026#34;true\u0026#34; /\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;item android:drawable=\u0026#34;@drawable/orderboard_detail_tab_middle_selected\u0026#34; android:state_selected=\u0026#34;true\u0026#34; /\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;!-- default --\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;item \u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;layer-list xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;item android:left=\u0026#34;-1dp\u0026#34; android:right=\u0026#34;-1dp\u0026#34;  \u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;shape  android:shape=\u0026#34;rectangle\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u0026amp;lt;solid android:color=\u0026#34;@color/text_color_white\u0026#34; /\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u0026amp;lt;stroke\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        android:width=\u0026#34;1dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        android:color=\u0026#34;@color/text_color_blue\u0026#34; /\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u0026amp;lt;padding\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        android:left=\u0026#34;0dp\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        android:right=\u0026#34;0dp\u0026#34; /\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u0026amp;lt;corners android:radius=\u0026#34;0dp\u0026#34;/\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;/shape\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;/item\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;/layer-list\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;/item\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/selector\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e上面执行的结果：只画上下线\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[![QQ20160830-0@2x](http://www.etongwl.com/images/2016/08/QQ20160830-0@2x-300x289.png)](http://www.etongwl.com/images/2016/08/QQ20160830-0@2x.png)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"android Shape只显示指定边框用法"},{"content":" ![](http://upload-images.jianshu.io/upload_images/828721-e0fc168c7e6ce054.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 之前写过一篇没时间解释了，快使用Snackbar!——Android Snackbar花式使用指南。Toast的自定义使用原理与其类似。\n1.Toast源码分析 老规矩，我们先去看Toast的源码。\nToast有两种显示布局方式，一种最常见调用Toast.makeText(),看源码是这样写的\n`\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; Toast \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;makeText\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;Context context, CharSequence text, @Duration \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; duration\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;/span\u0026gt;{ Toast result = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Toast(context); LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View v = inflate.inflate(com.android.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;internal\u0026amp;lt;/span\u0026gt;.R.layout.transient_notification, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); TextView tv = (TextView)v.findViewById(com.android.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;internal\u0026amp;lt;/span\u0026gt;.R.id.message); tv.setText(text); result.mNextView = v; result.mDuration = duration; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; result; }` transient_notification这个布局文件代码是这样的\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:orientation\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;vertical\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;?android:attr/toastFrameBackground\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;TextView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@android:id/message\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_weight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;1\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;center_horizontal\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:textAppearance\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@style/TextAppearance.Toast\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:textColor\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@color/bright_foreground_dark\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:shadowColor\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#BB000000\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:shadowRadius\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;2.75\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 那么我们想要修改Toast的文字消息样式，其实就是修改Toast根布局和message这个TextView。\nToast的另外一种显示模式就是自定义布局显示。这个方法不调用Toast.makeText()方法，而是new一个Toast对象，然后调用setView()方法。当然自定义布局就不会加载transient_notification布局了。\n2.实现花式Toast 先给大家看下我封装的工具类ToastUtil。\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.content.Context; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.View; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.widget.LinearLayout; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.widget.TextView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.widget.Toast; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * Created by 赵晨璞 on 2016/8/11. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ToastUtil\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; Toast toast; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; LinearLayout toastView; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 修改原布局的Toast */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ToastUtil\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 完全自定义布局Toast * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; context * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; view */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ToastUtil\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context, View view,\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; duration)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ toast=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Toast(context); toast.setView(view); toast.setDuration(duration); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 向Toast中添加自定义view * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; view * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; postion * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ToastUtil \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;addView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(View view,\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; postion)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ toastView = (LinearLayout) toast.getView(); toastView.addView(view, postion); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 设置Toast字体及背景颜色 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; messageColor * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; backgroundColor * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ToastUtil \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setToastColor\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; messageColor, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; backgroundColor)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ View view = toast.getView(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(view!=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){ TextView message=((TextView) view.findViewById(android.R.id.message)); message.setBackgroundColor(backgroundColor); message.setTextColor(messageColor); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 设置Toast字体及背景 * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; messageColor * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; background * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ToastUtil \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setToastBackground\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; messageColor, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; background)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ View view = toast.getView(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(view!=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;){ TextView message=((TextView) view.findViewById(android.R.id.message)); message.setBackgroundResource(background); message.setTextColor(messageColor); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 短时间显示Toast */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ToastUtil \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Short\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context, CharSequence message)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(toast==\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;||(toastView!=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;\u0026amp;toastView.getChildCount()\u0026amp;gt;\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;)){ toast= Toast.makeText(context, message, Toast.LENGTH_SHORT); toastView=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{ toast.setText(message); toast.setDuration(Toast.LENGTH_SHORT); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 短时间显示Toast */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ToastUtil \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Short\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; message)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(toast==\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;||(toastView!=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;\u0026amp;toastView.getChildCount()\u0026amp;gt;\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;)){ toast= Toast.makeText(context, message, Toast.LENGTH_SHORT); toastView=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{ toast.setText(message); toast.setDuration(Toast.LENGTH_SHORT); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 长时间显示Toast */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ToastUtil \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Long\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context, CharSequence message)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(toast==\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;||(toastView!=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;\u0026amp;toastView.getChildCount()\u0026amp;gt;\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;)){ toast= Toast.makeText(context, message, Toast.LENGTH_LONG); toastView=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{ toast.setText(message); toast.setDuration(Toast.LENGTH_LONG); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 长时间显示Toast * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; context * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; message */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ToastUtil \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Long\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; message)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(toast==\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;||(toastView!=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;\u0026amp;toastView.getChildCount()\u0026amp;gt;\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;)){ toast= Toast.makeText(context, message, Toast.LENGTH_LONG); toastView=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{ toast.setText(message); toast.setDuration(Toast.LENGTH_LONG); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 自定义显示Toast时间 * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; context * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; message * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; duration */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ToastUtil \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Indefinite\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context, CharSequence message, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; duration)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(toast==\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;||(toastView!=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;\u0026amp;toastView.getChildCount()\u0026amp;gt;\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;)){ toast= Toast.makeText(context, message,duration); toastView=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{ toast.setText(message); toast.setDuration(duration); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 自定义显示Toast时间 * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; context * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; message * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; duration */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ToastUtil \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Indefinite\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; message, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; duration)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;(toast==\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;||(toastView!=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;\u0026amp;toastView.getChildCount()\u0026amp;gt;\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;)){ toast= Toast.makeText(context, message,duration); toastView=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; }\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt;{ toast.setText(message); toast.setDuration(duration); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 显示Toast * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ToastUtil \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;show\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ toast.show(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * 获取Toast * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Toast \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getToast\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; toast; } }` 修改Toast背景色的使用法方法如下：\n`\u0026amp;lt;span class=\u0026#34;hljs-type\u0026#34;\u0026gt;ToastUtil\u0026amp;lt;/span\u0026gt; toastUtil=\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-type\u0026#34;\u0026gt;ToastUtil\u0026amp;lt;/span\u0026gt;(); toastUtil.\u0026amp;lt;span class=\u0026#34;hljs-type\u0026#34;\u0026gt;Short\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-type\u0026#34;\u0026gt;MainActivity\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;自定义message字体、背景色\u0026#34;\u0026amp;lt;/span\u0026gt;).setToastColor(\u0026amp;lt;span class=\u0026#34;hljs-type\u0026#34;\u0026gt;Color\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;hljs-type\u0026#34;\u0026gt;WHITE\u0026amp;lt;/span\u0026gt;, getResources().getColor(\u0026amp;lt;span class=\u0026#34;hljs-type\u0026#34;\u0026gt;R\u0026amp;lt;/span\u0026gt;.color.colorAccent)).show();` ![](http://upload-images.jianshu.io/upload_images/828721-66195248a10c3434.gif?imageMogr2/auto-orient/strip) 修改Toast背景色 方形的Toast看上去有些呆板，我自定义了一个名为toast_radius.xml的背景，代码如下：\n`\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;shape\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:shape\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;rectangle\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;\u0026amp;lt;!-- 填充的颜色 --\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;solid\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:color\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#ffc107\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;\u0026amp;lt;!-- android:radius 弧形的半径 --\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;corners\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:radius\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;20dip\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;shape\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 然后上面设置背景的代码改成:\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;toastUtil\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;.Short\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;MainActivity\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;.this\u0026amp;lt;/span\u0026gt;,\u0026#34;自定义\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;message\u0026amp;lt;/span\u0026gt;字体颜色和背景\u0026#34;)\u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;.setToastBackground\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;Color\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;.WHITE\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;.drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;.toast_radius\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;.show\u0026amp;lt;/span\u0026gt;();` ![](http://upload-images.jianshu.io/upload_images/828721-575d63beed215b00.gif?imageMogr2/auto-orient/strip) 修改了背景的Toast 虽然官方认为Toast和Snackbar都应该是短文本的形式，不能包含图标，但是个人感觉加上图标还是挺好玩的…\n向Toast中添加图标可以这样:\n` ImageView toastImage = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ImageView(getApplicationContext()); toastImage.setImageResource(R.mipmap.ic_launcher); toastUtil.Short(MainActivity.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;向Toast添加了一个ImageView\u0026#34;\u0026amp;lt;/span\u0026gt;).setToastBackground(Color.WHITE,R.drawable.toast_radius).addView(toastImage,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;).show();` ![](http://upload-images.jianshu.io/upload_images/828721-ada7364a24c915ae.gif?imageMogr2/auto-orient/strip) 添加图标的Toast 如果你想要Toast显示自定义的布局，可以这样：\n` View view = LayoutInflater.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt;(MainActivity.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;).inflate(R.layout.image,\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ToastUtil(MainActivity.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,view,Toast.LENGTH_SHORT).show();` ![](http://upload-images.jianshu.io/upload_images/828721-f95a07f3fe9144af.gif?imageMogr2/auto-orient/strip) 自定义布局Toast，我的布局文件中只有一个默认图标的ImageView 大家都知道，连续触发Toast的show()方法的时候，Toast就会排着队连续展示，感觉上不太友好。所以我先判断了toast是否没被创建或者是否被添加了额外的view，如果是的话就重新生成一个toast对象；如果否的话就只修改message文字和显示时间。\n![](http://upload-images.jianshu.io/upload_images/828721-ccb92e45086fe98a.gif?imageMogr2/auto-orient/strip) Toast布局修改，不排队显示 我这个工具类不是完全体，大家再根据自己项目的具体需求进行修改。 [](￣▽￣)*\n转自：http://www.jianshu.com/p/5c5c8ee31ddb ","permalink":"https://blog.zdltech.com/posts/android-toast%E8%8A%B1%E5%BC%8F%E4%BD%BF%E7%94%A8/","summary":"\u003cdiv class=\"image-package imagebubble\"\u003e\n\u003cpre\u003e\u003ccode\u003e![](http://upload-images.jianshu.io/upload_images/828721-e0fc168c7e6ce054.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"image-caption\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e之前写过一篇\u003ca href=\"http://www.jianshu.com/p/cd1e80e64311\"\u003e没时间解释了，快使用Snackbar!——Android Snackbar花式使用指南\u003c/a\u003e。Toast的自定义使用原理与其类似。\u003c/p\u003e\n\u003ch2 id=\"1toast源码分析\"\u003e1.Toast源码分析\u003c/h2\u003e\n\u003cp\u003e老规矩，我们先去看Toast的源码。\u003c/p\u003e\n\u003cp\u003eToast有两种显示布局方式，一种最常见调用Toast.makeText(),看源码是这样写的\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; Toast \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;makeText\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;Context context, CharSequence text, @Duration \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; duration\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;/span\u0026gt;{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eToast result = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Toast(context);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eLayoutInflater inflate = (LayoutInflater)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003econtext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eView v = inflate.inflate(com.android.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;internal\u0026amp;lt;/span\u0026gt;.R.layout.transient_notification, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eTextView tv = (TextView)v.findViewById(com.android.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;internal\u0026amp;lt;/span\u0026gt;.R.id.message);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etv.setText(text);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult.mNextView = v;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eresult.mDuration = duration;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; result;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003etransient_notification这个布局文件代码是这样的\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:orientation\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;vertical\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;?android:attr/toastFrameBackground\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;TextView\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@android:id/message\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_weight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;1\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;center_horizontal\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:textAppearance\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@style/TextAppearance.Toast\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:textColor\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@color/bright_foreground_dark\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:shadowColor\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#BB000000\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:shadowRadius\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;2.75\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e/\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e那么我们想要修改Toast的文字消息样式，其实就是修改Toast根布局和message这个TextView。\u003c/p\u003e","title":"Android Toast花式使用"},{"content":"今天帮助网友解决了一个在应用中登录后进应用的网页自动登录。\n在这里分享给大家，希望能帮助更多的人。直接上代码：\n/** * 网页自动登录 * http://haohailai.taobao.com/ * @author xiehaibo * */ public class MainActivity extends Activity { private WebView webView1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); webView1 = (WebView) findViewById(R.id.webView1); // 设置支持JavaScript脚本 WebSettings webSettings = webView1.getSettings(); webSettings.setJavaScriptEnabled(true); // 设置可以访问文件 webSettings.setAllowFileAccess(true); // 设置支持缩放 webSettings.setBuiltInZoomControls(true); // 设置WebViewClient webView1.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } @Override public void onPageFinished(WebView view, String url) { Log.d(\u0026#34;admin\u0026#34;, \u0026#34;网页加载完了\u0026#34;); String uname = \u0026#34;帐号\u0026#34;; String password = \u0026#34;密码\u0026#34;; // 加载完了再调用js登录代码 view.loadUrl(\u0026#34;javascript: {\u0026#34; + \u0026#34;document.getElementById(\u0026#39;username\u0026#39;).value = \u0026#39;\u0026#34; + uname + \u0026#34;\u0026#39;;\u0026#34; + \u0026#34;document.getElementById(\u0026#39;password\u0026#39;).value = \u0026#39;\u0026#34; + password + \u0026#34;\u0026#39;;\u0026#34; + \u0026#34;var frms = document.getElementsByName(\u0026#39;tableForm\u0026#39;);\u0026#34; + \u0026#34;frms[0].submit(); };\u0026#34;); // 登录成功后加载框取消 super.onPageFinished(view, url); } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { Log.d(\u0026#34;admin\u0026#34;, \u0026#34;网页开始加载\u0026#34;); // 在这里可以创建一个加载框。。。 super.onPageStarted(view, url, favicon); } }); webView1.loadUrl(\u0026#34;网页地址，包含登录表单\u0026#34;); } } 注意的是：\nview.loadUrl(\u0026#34;javascript: {\u0026#34; + \u0026#34;document.getElementById(\u0026#39;username\u0026#39;).value = \u0026#39;\u0026#34; + uname + \u0026#34;\u0026#39;;\u0026#34; + \u0026#34;document.getElementById(\u0026#39;password\u0026#39;).value = \u0026#39;\u0026#34; + password + \u0026#34;\u0026#39;;\u0026#34; + \u0026#34;var frms = document.getElementsByName(\u0026#39;tableForm\u0026#39;);\u0026#34; + \u0026#34;frms[0].submit(); };\u0026#34;); username、password、tableForm要该为你自己网页的表单里的id值。\n","permalink":"https://blog.zdltech.com/posts/android-webview%E7%BD%91%E9%A1%B5%E8%A1%A8%E5%8D%95%E8%87%AA%E5%8A%A8%E7%99%BB%E5%BD%95%E5%8D%95%E7%82%B9%E7%99%BB%E5%BD%95/","summary":"\u003cp\u003e今天帮助网友解决了一个在应用中登录后进应用的网页自动登录。\u003c/p\u003e\n\u003cp\u003e在这里分享给大家，希望能帮助更多的人。直接上代码：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 网页自动登录\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e http:\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003ehaohailai\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etaobao\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecom\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @author xiehaibo\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e MainActivity \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e Activity {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tprivate WebView webView1;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tprotected void onCreate(Bundle savedInstanceState) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tsuper\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonCreate(savedInstanceState);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tsetContentView(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elayout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eactivity_main);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\twebView1 \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (WebView) findViewById(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewebView1);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 设置支持JavaScript脚本\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tWebSettings webSettings \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e webView1\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetSettings();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\twebSettings\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetJavaScriptEnabled(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 设置可以访问文件\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\twebSettings\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetAllowFileAccess(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 设置支持缩放\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\twebSettings\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetBuiltInZoomControls(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 设置WebViewClient\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\twebView1\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetWebViewClient(new WebViewClient() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tpublic boolean shouldOverrideUrlLoading(WebView view, String url) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eloadUrl(url);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t@Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tpublic void onPageFinished(WebView view, String url) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tLog\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ed(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;admin\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;网页加载完了\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tString uname \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;帐号\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tString password \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;密码\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 加载完了再调用js登录代码\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eloadUrl(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;javascript: {\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\t\t\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;document.getElementById(\u0026#39;username\u0026#39;).value = \u0026#39;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\t\t\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e uname \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#39;;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\t\t\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;document.getElementById(\u0026#39;password\u0026#39;).value = \u0026#39;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\t\t\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e password \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#39;;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\t\t\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;var frms = document.getElementsByName(\u0026#39;tableForm\u0026#39;);\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\t\t\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;frms[0].submit(); };\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 登录成功后加载框取消\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tsuper\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonPageFinished(view, url);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t@Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tpublic void onPageStarted(WebView view, String url, Bitmap favicon) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tLog\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ed(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;admin\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;网页开始加载\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 在这里可以创建一个加载框。。。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tsuper\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonPageStarted(view, url, favicon);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\twebView1\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eloadUrl(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;网页地址，包含登录表单\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e注意的是：\u003c/p\u003e","title":"android webView网页表单自动登录（单点登录）"},{"content":"传统网页实现用户登陆一般采用session或cookie记录用户基本信息又或者两者结合起来使用。android也可以采用session实现用户登陆验证并记录用户登陆状态时的基本信息，session是在服务器端的;而类似cookie的记录方式，则可以在客户端采用xml文件记录用户基本信息,重要数据则可以加密存放客户端。android实现的session登陆功能与网页请求不同的是，网页形式的一次成功的登陆请求后，再点击其他页面时，session一直是存在的，在一定时间内是有效的；而采用android客户端请求的一次成功登陆后，再次发送新的请求，则会产生新的session，而不是原来的。这就需要记录session的id号，并在整个请求过程中都记录并传递这个id号，才能保证session的一致性。\n以获取php session为例，主要思路实现分为客户端与服务器端3个步骤。\n附件:源码下载 1.）客户端（ANDROID） 建立一个名为GetWebSession的android项目，编写GetWebSession.java,LoginSuccessActivity.java,GetUserInfoActivity.java三个activity类。\nGetWebSession.java主要是实现布局界面以及发送用户名和密码到php服务器端验证，如果验证成功则跳转到LoginSuccessActivity.java类。GetWebSession.java主要涉及到与服务器端连接请求，对从服务器端返回的json数据(如用户id,session等)进行解析，并存入HashMap,传递到LoginSuccessActivity.java 代码如下:\n[view plain](http://www.yoyong.com/archives/178#)[copy to clipboard](http://www.yoyong.com/archives/178#)[print](http://www.yoyong.com/archives/178#)[?](http://www.yoyong.com/archives/178#) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.login.main; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.IOException; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.UnsupportedEncodingException; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.HashMap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.HttpEntity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.HttpResponse; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.client.ClientProtocolException; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.client.entity.UrlEncodedFormEntity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.client.methods.HttpPost; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.impl.client.DefaultHttpClient; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.message.BasicNameValuePair; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.protocol.HTTP; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.util.EntityUtils; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.json.JSONException; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.json.JSONObject; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Button; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.EditText; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; GetWebSession \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** Called when the activity is first created. */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; EditText user; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; EditText password; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Button loginBtn; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Button logoutBtn; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//主要是记录用户会话过程中的一些用户的基本信息\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; HashMap\u0026lt;String, String\u0026gt; session =\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;String, String\u0026gt;(); - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.main); - user=(EditText)findViewById(R.id.user); - password=(EditText)findViewById(R.id.password); - loginBtn=(Button)findViewById(R.id.loginBtn); - loginBtn.setOnClickListener(loginClick); - logoutBtn=(Button)findViewById(R.id.logoutBtn); - logoutBtn.setOnClickListener(logoutClick); - } - OnClickListener loginClick=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(checkUser()){ - Toast.makeText(v.getContext(), \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;用户登录成功！\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - Context context = v.getContext(); - Intent intent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(context, - LoginSuccessActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//传递session参数,在用户登录成功后为session初始化赋值,即传递HashMap的值\u0026lt;/span\u0026gt; - Bundle map = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Bundle(); - map.putSerializable(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;, session); - intent.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;session\u0026amp;#8221;\u0026lt;/span\u0026gt;, map); - context.startActivity(intent); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 跳转到成功页面\u0026lt;/span\u0026gt; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - Toast.makeText(v.getContext(), \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;用户验证失败！\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - } - }; - OnClickListener logoutClick=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - System.exit(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - } - }; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; checkUser(){ - String username=user.getText().toString(); - String pass=password.getText().toString(); - DefaultHttpClient mHttpClient = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DefaultHttpClient(); - HttpPost mPost = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HttpPost(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://10.0.2.2/web/php/login.php\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//传递用户名和密码相当于\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//http://10.0.2.2/web/php/login.php?username=\u0026amp;#8221;\u0026amp;password=\u0026amp;#8221;\u0026lt;/span\u0026gt; - List\u0026lt;BasicNameValuePair\u0026gt; pairs = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;BasicNameValuePair\u0026gt;(); - pairs.add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BasicNameValuePair(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;username\u0026amp;#8221;\u0026lt;/span\u0026gt;, username)); - pairs.add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BasicNameValuePair(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;password\u0026amp;#8221;\u0026lt;/span\u0026gt;, pass)); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - mPost.setEntity(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; UrlEncodedFormEntity(pairs, HTTP.UTF_8)); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (UnsupportedEncodingException e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated catch block\u0026lt;/span\u0026gt; - e.printStackTrace(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - HttpResponse response = mHttpClient.execute(mPost); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; res = response.getStatusLine().getStatusCode(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (res == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;) { - HttpEntity entity = response.getEntity(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (entity != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - String info = EntityUtils.toString(entity); - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;info\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8211;\u0026amp;#8220;\u0026lt;/span\u0026gt;+info); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//以下主要是对服务器端返回的数据进行解析\u0026lt;/span\u0026gt; - JSONObject jsonObject=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//flag为登录成功与否的标记,从服务器端返回的数据\u0026lt;/span\u0026gt; - String flag=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;; - String name=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;; - String userid=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;; - String sessionid=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - jsonObject = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; JSONObject(info); - flag = jsonObject.getString(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;flag\u0026amp;#8221;\u0026lt;/span\u0026gt;); - name = jsonObject.getString(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;name\u0026amp;#8221;\u0026lt;/span\u0026gt;); - userid = jsonObject.getString(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;userid\u0026amp;#8221;\u0026lt;/span\u0026gt;); - sessionid = jsonObject.getString(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (JSONException e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated catch block\u0026lt;/span\u0026gt; - e.printStackTrace(); - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//根据服务器端返回的标记,判断服务端端验证是否成功\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(flag.equals(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;success\u0026amp;#8221;\u0026lt;/span\u0026gt;)){ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//为session传递相应的值,用于在session过程中记录相关用户信息\u0026lt;/span\u0026gt; - session.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s_userid\u0026amp;#8221;\u0026lt;/span\u0026gt;, userid); - session.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s_username\u0026amp;#8221;\u0026lt;/span\u0026gt;, name); - session.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s_sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;, sessionid); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (ClientProtocolException e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated catch block\u0026lt;/span\u0026gt; - e.printStackTrace(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated catch block\u0026lt;/span\u0026gt; - e.printStackTrace(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } LoginSuccessActivity.java主要获取php的session唯一的标识id以及用户的一些基本信息，session id则作为本次用户登录状态在服务器的唯一标识，即确定用户的唯一状态进行相关操作。LoginSuccessActivity.java类的方法与GetWebSession.java类似。其主要功能是获取session id后再次发送session id到服务器进行验证，根据封装的session数据验证用户操作权限等。 代码如下：\n[view plain](http://www.yoyong.com/archives/178#)[copy to clipboard](http://www.yoyong.com/archives/178#)[print](http://www.yoyong.com/archives/178#)[?](http://www.yoyong.com/archives/178#) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.login.main; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.IOException; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.UnsupportedEncodingException; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.HashMap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.HttpEntity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.HttpResponse; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.client.ClientProtocolException; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.client.entity.UrlEncodedFormEntity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.client.methods.HttpPost; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.impl.client.DefaultHttpClient; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.message.BasicNameValuePair; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.protocol.HTTP; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.util.EntityUtils; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.json.JSONException; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.json.JSONObject; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Button; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; LoginSuccessActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; HashMap\u0026lt;String, String\u0026gt;session; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@SuppressWarnings\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;unchecked\u0026amp;#8221;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.login_success); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取从登录成功后界面的传递的参数\u0026lt;/span\u0026gt; - session = (HashMap\u0026lt;String, String\u0026gt;) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getIntent() - .getBundleExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;session\u0026amp;#8221;\u0026lt;/span\u0026gt;).getSerializable(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//读取session的基本信息，并显示相应的控件\u0026lt;/span\u0026gt; - String userid_info=session.get(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s_userid\u0026amp;#8221;\u0026lt;/span\u0026gt;); - String username_info=session.get(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s_username\u0026amp;#8221;\u0026lt;/span\u0026gt;); - String session_id=session.get(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s_sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//显示相应的内容到控件\u0026lt;/span\u0026gt; - TextView userid_show=(TextView)findViewById(R.id.userid_show); - userid_show.setText(userid_info); - TextView username_show=(TextView)findViewById(R.id.username_show); - username_show.setText(username_info); - TextView sessionid_show=(TextView)findViewById(R.id.sessionid_show); - sessionid_show.setText(session_id); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//根据本次session再次获取用户信息\u0026lt;/span\u0026gt; - Button getInfo=(Button)findViewById(R.id.getinfo); - getInfo.setOnClickListener(getInfoClick); - } - OnClickListener getInfoClick=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(getUserInfo()){ - Context context = v.getContext(); - Intent intent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(context, - GetUserInfoActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//传递session参数,在用户登录成功后为session初始化赋值,即传递HashMap的值\u0026lt;/span\u0026gt; - Bundle map = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Bundle(); - map.putSerializable(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;, session); - intent.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;session\u0026amp;#8221;\u0026lt;/span\u0026gt;, map); - context.startActivity(intent); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 跳转到成功页面\u0026lt;/span\u0026gt; - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - Toast.makeText(v.getContext(), \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;数据为空！\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - } - } - }; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; getUserInfo(){ - String sess_username=session.get(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s_username\u0026amp;#8221;\u0026lt;/span\u0026gt;); - String sess_userid=session.get(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s_userid\u0026amp;#8221;\u0026lt;/span\u0026gt;); - String sess_id=session.get(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s_sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;); - DefaultHttpClient mHttpClient = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DefaultHttpClient(); - HttpPost mPost = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HttpPost(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://10.0.2.2/web/php/getinfo.php\u0026amp;#8221;\u0026lt;/span\u0026gt;); - List\u0026lt;BasicNameValuePair\u0026gt; pairs = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;BasicNameValuePair\u0026gt;(); - pairs.add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BasicNameValuePair(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sess_userid\u0026amp;#8221;\u0026lt;/span\u0026gt;, sess_userid)); - pairs.add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BasicNameValuePair(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sess_username\u0026amp;#8221;\u0026lt;/span\u0026gt;, sess_username)); - pairs.add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BasicNameValuePair(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sess_sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;, sess_id)); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - mPost.setEntity(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; UrlEncodedFormEntity(pairs, HTTP.UTF_8)); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (UnsupportedEncodingException e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated catch block\u0026lt;/span\u0026gt; - e.printStackTrace(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - HttpResponse response = mHttpClient.execute(mPost); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; res = response.getStatusLine().getStatusCode(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (res == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;) { - HttpEntity entity = response.getEntity(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (entity != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - String info = EntityUtils.toString(entity); - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;info\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8211;\u0026amp;#8220;\u0026lt;/span\u0026gt;+info); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//以下主要是对服务器端返回的数据进行解析\u0026lt;/span\u0026gt; - JSONObject jsonObject=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//flag为登录成功与否的标记,从服务器端返回的数据\u0026lt;/span\u0026gt; - String flag=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;; - String userinfo=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;; - String level=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;; - String sessionid=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - jsonObject = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; JSONObject(info); - flag = jsonObject.getString(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;flag\u0026amp;#8221;\u0026lt;/span\u0026gt;); - userinfo = jsonObject.getString(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;info\u0026amp;#8221;\u0026lt;/span\u0026gt;); - level = jsonObject.getString(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;level\u0026amp;#8221;\u0026lt;/span\u0026gt;); - sessionid = jsonObject.getString(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (JSONException e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated catch block\u0026lt;/span\u0026gt; - e.printStackTrace(); - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//根据服务器端返回的标记,判断服务端端验证是否成功\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(flag.equals(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;notempty\u0026amp;#8221;\u0026lt;/span\u0026gt;)){ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//为session传递相应的值,用于在session过程中记录相关用户信息\u0026lt;/span\u0026gt; - session.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;info_userinfo\u0026amp;#8221;\u0026lt;/span\u0026gt;, userinfo); - session.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;info_level\u0026amp;#8221;\u0026lt;/span\u0026gt;, level); - session.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;info_sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;, sessionid); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (ClientProtocolException e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated catch block\u0026lt;/span\u0026gt; - e.printStackTrace(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated catch block\u0026lt;/span\u0026gt; - e.printStackTrace(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } 3.GetUserInfoActivity.java类是根据用户登录后产生唯一session 标识进行操作获取用户详细信息的类。\n代码如下:\n[view plain](http://www.yoyong.com/archives/178#)[copy to clipboard](http://www.yoyong.com/archives/178#)[print](http://www.yoyong.com/archives/178#)[?](http://www.yoyong.com/archives/178#) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.login.main; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.HashMap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; GetUserInfoActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; HashMap\u0026lt;String, String\u0026gt;session; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@SuppressWarnings\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;unchecked\u0026amp;#8221;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.get_info); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取从登录成功后界面的再次传递的参数\u0026lt;/span\u0026gt; - session = (HashMap\u0026lt;String, String\u0026gt;) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getIntent(). - getBundleExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;session\u0026amp;#8221;\u0026lt;/span\u0026gt;).getSerializable(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//读取session的基本信息，并显示相应的控件\u0026lt;/span\u0026gt; - String session_info=session.get(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;info_userinfo\u0026amp;#8221;\u0026lt;/span\u0026gt;); - String session_level=session.get(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;info_level\u0026amp;#8221;\u0026lt;/span\u0026gt;); - String session_id=session.get(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;info_sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//显示相应的内容到控件\u0026lt;/span\u0026gt; - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;session_info\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8211;\u0026amp;#8220;\u0026lt;/span\u0026gt;+session_info); - TextView get_info=(TextView)findViewById(R.id.get_info); - get_info.setText(session_info); - TextView get_level=(TextView)findViewById(R.id.get_level); - get_level.setText(session_level); - TextView get_sessionid=(TextView)findViewById(R.id.get_sessionid); - get_sessionid.setText(session_id); - } - } 4.三个布局的xml文件\n(1.)main.xml\n[view plain](http://www.yoyong.com/archives/178#)[copy to clipboard](http://www.yoyong.com/archives/178#)[print](http://www.yoyong.com/archives/178#)[?](http://www.yoyong.com/archives/178#) - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;用户\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;EditText\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:singleLine\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/user\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;EditText\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;密码\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;EditText\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/password\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:password\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:singleLine\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;EditText\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TableRow\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;登录\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/loginBtn\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_weight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;退出\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/logoutBtn\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_weight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TableRow\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; (2.)login_success.xml\n[view plain](http://www.yoyong.com/archives/178#)[copy to clipboard](http://www.yoyong.com/archives/178#)[print](http://www.yoyong.com/archives/178#)[?](http://www.yoyong.com/archives/178#) - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;用户ID:\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/userid_show\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;用户名: \u0026amp;#8220;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/username_show\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;本次会话：\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/sessionid_show\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/getinfo\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;根据本次会话再次获取用户信息\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; (3.)get_info.xml\n[view plain](http://www.yoyong.com/archives/178#)[copy to clipboard](http://www.yoyong.com/archives/178#)[print](http://www.yoyong.com/archives/178#)[?](http://www.yoyong.com/archives/178#) - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;用户信息: \u0026amp;#8220;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/get_info\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;用户级别：\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/get_level\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;本次会话：\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/get_sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 2.）服务器端（PHP） php服务器端主要有三个文件,conn.php,login.php和getinfo.php。\nconn.php是连接数据库的配置文件。\nlogin.php主要是用来验证android客户端发送的请求,请求成功则返回flag=’success’的状态标识,采用数组记录用户基本信息，存储用户数据到session，并且记录本次产生的session id。用户基本数据及本次session产生的id均封装成json格式(json_encode(arr)),发送android客户端。产生本次session id的方法sessionid=session_id();//注意没有参数\n具体代码如下：\n[view plain](http://www.yoyong.com/archives/178#)[copy to clipboard](http://www.yoyong.com/archives/178#)[print](http://www.yoyong.com/archives/178#)[?](http://www.yoyong.com/archives/178#) - \u0026lt;?php - header(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Content-Type: text/html; charset=utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;) ; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//包含数据库连接文件\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;include\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;conn.php\u0026amp;#8217;\u0026lt;/span\u0026gt;); - session_start(); - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$username\u0026lt;/span\u0026gt; = htmlspecialchars(\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$_POST\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;username\u0026amp;#8221;\u0026lt;/span\u0026gt;]); - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$password\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$_POST\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;password\u0026amp;#8221;\u0026lt;/span\u0026gt;]; - mysql_query(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;set names utf8\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//检测用户名及密码是否正确\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$check_query\u0026lt;/span\u0026gt; = mysql_query(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;select id ,name from user where name=\u0026amp;#8217;$username\u0026amp;#8217; and\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;password=\u0026amp;#8217;$password\u0026amp;#8217; limit 1\u0026amp;#8243;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$arr\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;array\u0026lt;/span\u0026gt;();\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//空的数组,该数组主要是格式化数据并封装成json格式发送到客户端\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$result\u0026lt;/span\u0026gt; = mysql_fetch_array(\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$check_query\u0026lt;/span\u0026gt;)){ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//登录成功\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$_SESSION\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;username\u0026amp;#8217;\u0026lt;/span\u0026gt;] = \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$result\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;name\u0026amp;#8217;\u0026lt;/span\u0026gt;]; - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$_SESSION\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;userid\u0026amp;#8217;\u0026lt;/span\u0026gt;] = \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$result\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;id\u0026amp;#8217;\u0026lt;/span\u0026gt;]; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取当前session id\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$sessionid\u0026lt;/span\u0026gt;=session_id(); - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$_SESSION\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;$sessionid\u0026amp;#8217;\u0026lt;/span\u0026gt;] = \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$sessionid\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$arr\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;array\u0026lt;/span\u0026gt;( - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;flag\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;success\u0026amp;#8217;\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;name\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$result\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;name\u0026amp;#8217;\u0026lt;/span\u0026gt;], - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;userid\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$result\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;id\u0026amp;#8217;\u0026lt;/span\u0026gt;], - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;sessionid\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$sessionid\u0026lt;/span\u0026gt; - ); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//封装json,如果php版本低于5.2，则不支持json_encode()方法，\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//可以参考本文件夹中php_json_encode.php中php_json_encode()方法代替json_encode();\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;func\u0026quot;\u0026gt;echo\u0026lt;/span\u0026gt; json_encode(\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$arr\u0026lt;/span\u0026gt;); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$arr\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;array\u0026lt;/span\u0026gt;( - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;flag\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;error\u0026amp;#8217;\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;name\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221;\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;userid\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221;\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;sessionid\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221;\u0026lt;/span\u0026gt; - ); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//封装json,如果php版本低于5.2，则不支持json_encode()方法，\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//可以参考本文件夹中php_json_encode.php中php_json_encode()方法代替json_encode();\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;func\u0026quot;\u0026gt;echo\u0026lt;/span\u0026gt; json_encode(\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$arr\u0026lt;/span\u0026gt;); - } - ?\u0026gt; getinfo.php文件主要是用户再次查询信息验证session，而不是重新产生session，以记录用户状态。通过验证flag是否为empty判断数据是否显示。最后封装成json发送到客户端 获取本次session的方法：\nsessionid=_POST[“sess_sessionid”];//获取android客户端的sessionid\nsession_id($sessionid);//有参数\nsession_start();//启动session\n具体代码如下:\n[view plain](http://www.yoyong.com/archives/178#)[copy to clipboard](http://www.yoyong.com/archives/178#)[print](http://www.yoyong.com/archives/178#)[?](http://www.yoyong.com/archives/178#) - \u0026lt;?php - header(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Content-Type: text/html; charset=utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;) ; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;include\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;conn.php\u0026amp;#8217;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取从客户端LoginSuccessActivity类传递的参数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$userid\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$_POST\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sess_userid\u0026amp;#8221;\u0026lt;/span\u0026gt;]; - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$username\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$_POST\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sess_username\u0026amp;#8221;\u0026lt;/span\u0026gt;]; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取客户端传递的session标识\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$sessionid\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$_POST\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sess_sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;]; - session_id(\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$sessionid\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将会根据session id获得原来的session\u0026lt;/span\u0026gt; - session_start(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取服务器端原来session记录的username,并且根据客户端传过来的username比较进行验证操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$sess_username\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$_SESSION\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;username\u0026amp;#8217;\u0026lt;/span\u0026gt;]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$username\u0026lt;/span\u0026gt;==\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$sess_username\u0026lt;/span\u0026gt;){ - mysql_query(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;set names utf8\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//查询用户基本信息\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$check_query\u0026lt;/span\u0026gt; = mysql_query(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;select userinfo,level from info where userid=\u0026amp;#8217;$userid\u0026amp;#8217; limit 1\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$arr\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;array\u0026lt;/span\u0026gt;();\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//空的数组\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$result\u0026lt;/span\u0026gt; = mysql_fetch_array(\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$check_query\u0026lt;/span\u0026gt;)){ - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$arr\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;array\u0026lt;/span\u0026gt;( - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;flag\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;notempty\u0026amp;#8217;\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;info\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$result\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;userinfo\u0026amp;#8217;\u0026lt;/span\u0026gt;], - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;level\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$result\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;level\u0026amp;#8217;\u0026lt;/span\u0026gt;], - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;sessionid\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$sessionid\u0026lt;/span\u0026gt; - ); - \u0026lt;span class=\u0026quot;func\u0026quot;\u0026gt;echo\u0026lt;/span\u0026gt; json_encode(\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$arr\u0026lt;/span\u0026gt;); - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$arr\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;array\u0026lt;/span\u0026gt;( - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;flag\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8217;empty\u0026amp;#8217;\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;name\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221;\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;userid\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221;\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;sessionid\u0026amp;#8217;\u0026lt;/span\u0026gt;=\u0026gt;\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$sessionid\u0026lt;/span\u0026gt; - ); - \u0026lt;span class=\u0026quot;func\u0026quot;\u0026gt;echo\u0026lt;/span\u0026gt; json_encode(\u0026lt;span class=\u0026quot;vars\u0026quot;\u0026gt;$arr\u0026lt;/span\u0026gt;); - } - ?\u0026gt; 3.）数据库端（MYSQL） 采用mysql建立数据库，建立两个简单的数据表：user和info。\n[view plain](http://www.yoyong.com/archives/178#)[copy to clipboard](http://www.yoyong.com/archives/178#)[print](http://www.yoyong.com/archives/178#)[?](http://www.yoyong.com/archives/178#) - /* - MySQL Data Transfer - Source Host: localhost - Source \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;Database\u0026lt;/span\u0026gt;: login - Target Host: localhost - Target \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;Database\u0026lt;/span\u0026gt;: login - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;Date\u0026lt;/span\u0026gt;: 2011-6-14 11:10:46 - */ - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;SET\u0026lt;/span\u0026gt; FOREIGN_KEY_CHECKS=0; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026amp;#8212; \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;-\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026amp;#8212; Table structure for info\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026amp;#8212; \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;-\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;CREATE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;TABLE\u0026lt;/span\u0026gt; `info` ( - `id` \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;(12) \u0026lt;span class=\u0026quot;op\u0026quot;\u0026gt;NOT\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;op\u0026quot;\u0026gt;NULL\u0026lt;/span\u0026gt; AUTO_INCREMENT, - `userid` \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;(12) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;DEFAULT\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;op\u0026quot;\u0026gt;NULL\u0026lt;/span\u0026gt;, - `userinfo` \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;varchar\u0026lt;/span\u0026gt;(100) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;DEFAULT\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;op\u0026quot;\u0026gt;NULL\u0026lt;/span\u0026gt;, - `\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;level\u0026lt;/span\u0026gt;` \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;(2) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;DEFAULT\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;op\u0026quot;\u0026gt;NULL\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;PRIMARY\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;KEY\u0026lt;/span\u0026gt; (`id`), - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;KEY\u0026lt;/span\u0026gt; `useid` (`userid`), - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;CONSTRAINT\u0026lt;/span\u0026gt; `useid` \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;FOREIGN\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;KEY\u0026lt;/span\u0026gt; (`userid`) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;REFERENCES\u0026lt;/span\u0026gt; `\u0026lt;span class=\u0026quot;func\u0026quot;\u0026gt;user\u0026lt;/span\u0026gt;` (`id`) - ) ENGINE=InnoDB AUTO_INCREMENT=3 \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;DEFAULT\u0026lt;/span\u0026gt; CHARSET=utf8; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026amp;#8212; \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;-\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026amp;#8212; Table structure for user\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026amp;#8212; \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;-\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;CREATE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;TABLE\u0026lt;/span\u0026gt; `\u0026lt;span class=\u0026quot;func\u0026quot;\u0026gt;user\u0026lt;/span\u0026gt;` ( - `id` \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;(12) \u0026lt;span class=\u0026quot;op\u0026quot;\u0026gt;NOT\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;op\u0026quot;\u0026gt;NULL\u0026lt;/span\u0026gt; AUTO_INCREMENT, - `\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;` \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;varchar\u0026lt;/span\u0026gt;(20) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;DEFAULT\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;op\u0026quot;\u0026gt;NULL\u0026lt;/span\u0026gt;, - `\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;password\u0026lt;/span\u0026gt;` \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;varchar\u0026lt;/span\u0026gt;(20) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;DEFAULT\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;op\u0026quot;\u0026gt;NULL\u0026lt;/span\u0026gt;, - `status` \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;(2) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;DEFAULT\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;op\u0026quot;\u0026gt;NULL\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;PRIMARY\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;KEY\u0026lt;/span\u0026gt; (`id`) - ) ENGINE=InnoDB AUTO_INCREMENT=3 \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;DEFAULT\u0026lt;/span\u0026gt; CHARSET=utf8; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026amp;#8212; \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;-\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026amp;#8212; Records\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026amp;#8212; \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;-\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;INSERT\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;INTO\u0026lt;/span\u0026gt; `info` \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;VALUES\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;1\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;1\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;charlie is a developer.\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;1\u0026amp;#8217;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;INSERT\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;INTO\u0026lt;/span\u0026gt; `info` \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;VALUES\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;2\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;2\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;william is a boss.\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8217;20\u0026amp;#8217;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;INSERT\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;INTO\u0026lt;/span\u0026gt; `\u0026lt;span class=\u0026quot;func\u0026quot;\u0026gt;user\u0026lt;/span\u0026gt;` \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;VALUES\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;1\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;charlie\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;password\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;1\u0026amp;#8217;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;INSERT\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;INTO\u0026lt;/span\u0026gt; `\u0026lt;span class=\u0026quot;func\u0026quot;\u0026gt;user\u0026lt;/span\u0026gt;` \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;VALUES\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;2\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;william\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;mypassword\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;2\u0026amp;#8217;\u0026lt;/span\u0026gt;); 运行效果如图：\n图 -1 GetWebSession.java类的布局\n图 -2 LoginSuccessActivity.java类获取的session id以及用户基本信息\n图 -3 GetWebSession.java获取用户详细信息及本次session的一致性\n转自：http://www.yoyong.com/archives/178\n","permalink":"https://blog.zdltech.com/posts/android%E8%8E%B7%E5%8F%96web%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AFsession%E5%B9%B6%E9%AA%8C%E8%AF%81%E7%99%BB%E9%99%86/","summary":"\u003cp\u003e传统网页实现用户登陆一般采用session或cookie记录用户基本信息又或者两者结合起来使用。android也可以采用session实现用户登陆验证并记录用户登陆状态时的基本信息，session是在服务器端的;而类似cookie的记录方式，则可以在客户端采用xml文件记录用户基本信息,重要数据则可以加密存放客户端。android实现的session登陆功能与网页请求不同的是，网页形式的一次成功的登陆请求后，再点击其他页面时，session一直是存在的，在一定时间内是有效的；而采用android客户端请求的一次成功登陆后，再次发送新的请求，则会产生新的session，而不是原来的。这就需要记录session的id号，并在整个请求过程中都记录并传递这个id号，才能保证session的一致性。\u003c/p\u003e\n\u003cp\u003e以获取php session为例，主要思路实现分为客户端与服务器端3个步骤。\u003c/p\u003e\n\u003ch4 id=\"附件源码下载\"\u003e附件:\u003ca href=\"http://www.yoyong.com/upload/GetWebSession.zip\" title=\"download source\"\u003e源码下载\u003c/a\u003e\u003c/h4\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch3 id=\"1客户端android\"\u003e1.）\u003cstrong\u003e客户端（ANDROID）\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e建立一个名为GetWebSession的android项目，编写GetWebSession.java,LoginSuccessActivity.java,GetUserInfoActivity.java三个activity类。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eGetWebSession.java主要是实现布局界面以及发送用户名和密码到php服务器端验证，如果验证成功则跳转到LoginSuccessActivity.java类。GetWebSession.java主要涉及到与服务器端连接请求，对从服务器端返回的json数据(如用户id,session等)进行解析，并存入HashMap,传递到LoginSuccessActivity.java\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e代码如下:\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      [view plain](http://www.yoyong.com/archives/178#)[copy to clipboard](http://www.yoyong.com/archives/178#)[print](http://www.yoyong.com/archives/178#)[?](http://www.yoyong.com/archives/178#)\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.login.main;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.IOException;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.UnsupportedEncodingException;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.HashMap;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.HttpEntity;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.HttpResponse;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.client.ClientProtocolException;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.client.entity.UrlEncodedFormEntity;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.client.methods.HttpPost;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.impl.client.DefaultHttpClient;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.message.BasicNameValuePair;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.protocol.HTTP;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.http.util.EntityUtils;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.json.JSONException;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.json.JSONObject;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Button;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.EditText;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; GetWebSession \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** Called when the activity is first created. */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; EditText user;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; EditText password;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Button loginBtn;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Button logoutBtn;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//主要是记录用户会话过程中的一些用户的基本信息\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; HashMap\u0026lt;String, String\u0026gt; session =\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;String, String\u0026gt;();\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);\n\n- setContentView(R.layout.main);\n\n- user=(EditText)findViewById(R.id.user);\n\n- password=(EditText)findViewById(R.id.password);\n\n- loginBtn=(Button)findViewById(R.id.loginBtn);\n\n- loginBtn.setOnClickListener(loginClick);\n\n- logoutBtn=(Button)findViewById(R.id.logoutBtn);\n\n- logoutBtn.setOnClickListener(logoutClick);\n\n- }\n\n- OnClickListener loginClick=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(checkUser()){\n\n- Toast.makeText(v.getContext(), \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;用户登录成功！\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show();\n\n- Context context = v.getContext();\n\n- Intent intent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(context,\n\n- LoginSuccessActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//传递session参数,在用户登录成功后为session初始化赋值,即传递HashMap的值\u0026lt;/span\u0026gt;\n\n- Bundle map = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Bundle();\n\n- map.putSerializable(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;, session);\n\n- intent.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;session\u0026amp;#8221;\u0026lt;/span\u0026gt;, map);\n\n- context.startActivity(intent); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 跳转到成功页面\u0026lt;/span\u0026gt;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n\n- Toast.makeText(v.getContext(), \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;用户验证失败！\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show();\n\n- }\n\n- };\n\n- OnClickListener logoutClick=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- System.exit(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- }\n\n- };\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; checkUser(){\n\n- String username=user.getText().toString();\n\n- String pass=password.getText().toString();\n\n- DefaultHttpClient mHttpClient = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DefaultHttpClient();\n\n- HttpPost mPost = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HttpPost(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://10.0.2.2/web/php/login.php\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//传递用户名和密码相当于\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//http://10.0.2.2/web/php/login.php?username=\u0026amp;#8221;\u0026amp;password=\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- List\u0026lt;BasicNameValuePair\u0026gt; pairs = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;BasicNameValuePair\u0026gt;();\n\n- pairs.add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BasicNameValuePair(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;username\u0026amp;#8221;\u0026lt;/span\u0026gt;, username));\n\n- pairs.add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BasicNameValuePair(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;password\u0026amp;#8221;\u0026lt;/span\u0026gt;, pass));\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\n- mPost.setEntity(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; UrlEncodedFormEntity(pairs, HTTP.UTF_8));\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (UnsupportedEncodingException e) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated catch block\u0026lt;/span\u0026gt;\n\n- e.printStackTrace();\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\n- HttpResponse response = mHttpClient.execute(mPost);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; res = response.getStatusLine().getStatusCode();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (res == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;) {\n\n- HttpEntity entity = response.getEntity();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (entity != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n\n- String info = EntityUtils.toString(entity);\n\n- System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;info\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8211;\u0026amp;#8220;\u0026lt;/span\u0026gt;+info);\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//以下主要是对服务器端返回的数据进行解析\u0026lt;/span\u0026gt;\n\n- JSONObject jsonObject=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//flag为登录成功与否的标记,从服务器端返回的数据\u0026lt;/span\u0026gt;\n\n- String flag=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n\n- String name=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n\n- String userid=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n\n- String sessionid=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\n- jsonObject = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; JSONObject(info);\n\n- flag = jsonObject.getString(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;flag\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- name = jsonObject.getString(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;name\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- userid = jsonObject.getString(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;userid\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- sessionid = jsonObject.getString(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (JSONException e) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated catch block\u0026lt;/span\u0026gt;\n\n- e.printStackTrace();\n\n- }\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//根据服务器端返回的标记,判断服务端端验证是否成功\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(flag.equals(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;success\u0026amp;#8221;\u0026lt;/span\u0026gt;)){\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//为session传递相应的值,用于在session过程中记录相关用户信息\u0026lt;/span\u0026gt;\n\n- session.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s_userid\u0026amp;#8221;\u0026lt;/span\u0026gt;, userid);\n\n- session.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s_username\u0026amp;#8221;\u0026lt;/span\u0026gt;, name);\n\n- session.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;s_sessionid\u0026amp;#8221;\u0026lt;/span\u0026gt;, sessionid);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- }\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (ClientProtocolException e) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated catch block\u0026lt;/span\u0026gt;\n\n- e.printStackTrace();\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated catch block\u0026lt;/span\u0026gt;\n\n- e.printStackTrace();\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003eLoginSuccessActivity.java主要获取php的session唯一的标识id以及用户的一些基本信息，session id则作为本次用户登录状态在服务器的唯一标识，即确定用户的唯一状态进行相关操作。LoginSuccessActivity.java类的方法与GetWebSession.java类似。其主要功能是获取session id后再次发送session id到服务器进行验证，根据封装的session数据验证用户操作权限等。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e代码如下：\u003c/p\u003e","title":"android获取web服务器端session并验证登陆"},{"content":"构建 这里搜集了用来构建应用程序的工具。\nApache Maven：Maven使用声明进行构建并进行依赖管理，偏向于使用约定而不是配置进行构建。Maven优于Apache Ant。后者采用了一种过程化的方式进行配置，所以维护起来相当困难。 Gradle：Gradle采用增量构建。Gradle通过Groovy编程而不是传统的XML声明进行配置。Gradle可以很好地配合Maven进行依赖管理，并且把Ant脚本当作头等公民。 字节码操作 编程操作Java字节码的函数库。\nASM：通用底层字节码操作及分析。 Javassist：尝试简化字节码编辑。 Byte Buddy：使用“流式API”进一步简化字节码生成。 代码分析 软件度量和质量评估工具。\nCheckstyle：对编程规范和标准进行静态分析。 FindBugs：通过字节码静态分析找出潜在Bug。 PMD：对源代码中不良编程习惯进行分析。 SonarQube：通过插件集成其它分析组件，提供评估最终结果报告。 编译器 创建分析器、解释器和编译器的框架。\nANTLR：功能完备的自顶向下分析复杂框架。 JavaCC：相对ANTLR更具体，上手略为简单。支持语法语法超前预测（syntactic lookahead）。 持续集成 支持持续集成、测试和应用发布的工具。\nBamboo：Atlassian的持续集成（CI）解决方案，包含很多其它产品。 CircleCI：提供托管服务，可免费试用。 Codeship：提供托管服务，提供有限免费计划。 Go：ThoughtWork开源持续集成解决方案。 Jenkins：提供基于服务器的部署服务。 TeamCity：JetBrain持续集成方案，提供免费版。 Travis：提供托管服务，常用于开源项目。 数据库 简化数据库交互的工具、库。\nFlyway：使用Java API轻松完成数据库迁移。 H2：小型SQL数据库，以内存操作著称。 JDBI：便捷的JDBC抽象。 jOOQ：基于SQL schema生成类型安全代码。 Presto：针对大数据的分布式SQL查询引擎。 Querydsl：针对Java的类型安全统一查询。 日期和时间 处理日期和时间的函数库。\nJoda-Time：Java 8出现之前，它是日期、时间处理的标准函数库。 Time4J：Java高级日期、时间函数库。 依赖注入 帮助代码实现控制反转模式的函数库。\nDagger ：编译期的注入框架，没有使用反射，主要用于Android开发。 Guice：轻量级注入框架，功能强大可与Dagger媲美。 开发库 从基础层次上改进开发流程。\nAspectJ：面向切面编程扩展，与程序无缝连接。 Auto：源代码生成器集合。 DCEVM：通过修改JVM，在运行时可无限次重定义已加载的类。OpenJDK 7、8已提供支持，详情可查看这个分支（fork）。 JRebel：商用软件，无需重新部署可即时重新加载代码及配置。 Lombok：代码生成器，旨在减少Java冗余代码。 RxJava：使用JVM中可观察序列，创建异步、基于事件应用程序的函数库。 Spring Loaded：另一个JVM类重载代理。 vert.x：JVM多语言事件驱动应用框架。 分布式应用 用来开发分布式、具有容错性应用程序的函数库和框架。\nAkka：构建并发、分布式和具有容错功能的事件驱动应用程序所需的工具包和运行时。 Apache Storm：分布式实时计算系统。 Apache ZooKeeper：为大型分布式系统，使用分布式配置、同步和命名注册提供协调服务。 Hazelcast：分布式、高可扩展性内存网格。 Hystrix：为分布式系统提供延迟和容错处理。 JGroups：一组提供可靠消息传输的工具包，可用来创建集群。集群中的节点可互相发送消息。 Quasar：为JVM提供轻量级线程和Actor。 发布 使用本机格式分发Java应用程序的工具。\nBintray：对二进制发布进行版本控制，可与Maven或Gradle配合使用。 IzPack：为跨平台部署建立授权工具。 Launch4j：将JAR包装为小巧的Windows可执行文件。 packr：将程序JAR、资源和JVM打包成Windows、Linux和Mac OS X的本机文件。 文档处理 用来处理Office格式文档的函数库。\nApache POI：支持OOXML （XLSX、DOCX、PPTX）以及 OLE2 （XLS, DOC or PPT）格式的文档。 jOpenDocument：处理OpenDocument格式文档。 游戏开发 游戏开发框架。\njMonkeyEngine：支持现代3D开发的游戏引擎。 libGDX：全面的跨平台高级开发框架。 LWJGL：抽象了OpenGL、CL、AL等函数库的健壮框架。 GUI 用来创建现代图形用户界面的函数库。\nJavaFX：Swing的继承者。 Scene Builder：JavaFX虚拟布局工具。 高性能 与高性能计算有关的资源，包括集合以及很多具体功能的函数库。\nDisruptor：线程间消息函数库。 fastutil：快速紧凑的Java类型安全集合。 GS Collections：受Smalltalk启发的集合框架。 hftc：Hash set和hash map。 HPPC：基本类型集合。 Javolution：针对实时嵌入式系统的函数库。 Trove：基本类型集合。 IDE 视图简化开发的集成开发环境。\nEclipse：后台做了很多工作，以其丰富插件著称。 IntelliJ IDEA：支持很多JVM语言，为Android开发提供了很多不错的选项。其商业版本主要面向企业用户。 NetBeans：集成了很多Java SE和Java EE特性，包括数据库访问、服务器、HTML5以及AngularJS。 图像处理 用来帮助创建、评估或操作图形的函数库。\nPicasso：Android下载图像和图像缓存函数库。 ZXing：多种格式的一维、二维条形码处理函数库。 JSON 简化JSON处理的函数库。\nGson：将Java对象序列化为JSON及反向操作。使用时提供了很好的性能。 Jackson：与GSON类似，但如果需要频繁初始化Jackson库会带来性能问题。 JVM和JDK 目前的JVM、JDK实现。\nJDK 9：JDK 9早期访问版本。 OpenJDK：开源实现。 日志 记录应用程序的日志函数库。\nApache Log4j 2：对之前版本进行了完全重写。现在的版本具备一个强大的插件和配置架构。 kibana：对日志进行分析并进行可视化。 Logback：log4j原班人马作品。被证明是一个强健的日志函数库，通过Groovy提供了很多有意思的配置选项。 logstash：日志文件管理工具。 SLF4J：日志抽象层，需要与某个具体日志框架配合使用。 机器学习 提供具体统计算法的工具。其算法可从数据中学习。\nApache Hadoop：对商用硬件集群上大规模数据存储和处理的开源软件框架。 Apache Mahout：专注协同过滤、聚类和分类的可扩展算法。 Apache Spark：开源数据分析集群计算框架。 h2o：用作大数据统计的分析引擎。 Weka：用作数据挖掘的算法集合，包括从预处理到可视化的各个层次。 消息 在客户端之间进行消息传递，确保协议独立性的工具。\nApache ActiveMQ：实现JMS的开源消息代理（broker），可将同步通讯转为异步通讯。 Apache Kafka：高吞吐量分布式消息系统。 JBoss HornetQ：清晰、准确、模块化且方便嵌入的消息工具。 JeroMQ：ZeroMQ的纯Java实现。 其它 其它资源。\nDesign Patterns：实现并解释了最常见的设计模式。 Jimfs：内存文件系统。 Lanterna：类似curses的简单console文本GUI函数库。 LightAdmin：可插入式CRUD UI函数库，可用于快速应用开发。 Metrics：创建自己的软件度量或者为支持框架添加度量信息，通过JMX或HTTP进行发布或者发送到数据库。 OpenRefine：用来处理混乱数据的工具，包括清理、转换、使用Web Service进行扩展并将其关联到数据库。 RoboVM：Java编写原生iOS应用。 自然语言处理 用来专门处理文本的函数库。\nApache OpenNL：处理类似分词等常见任务的工具。 CoreNLP：斯坦佛的CoreNLP提供了一组基础工具，可以处理类似标签、实体名识别和情感分析这样的任务。 LingPipe：一组可以处理各种任务的工具集，支持POS标签、情感分析等。 Mallet：统计学自然语言处理、文档分类、聚类、主题建模等。 网络 网络编程函数库。\nNetty：构建高性能网络应用程序开发框架。 OkHttp ：一个Android和Java应用的HTTP+SPDY客户端。 ORM 处理对象持久化的API。\nEclipseLink：支持许多持久化标准，JPA、JAXB、JCA和SDO。 Hibernate：广泛使用、强健的持久化框架。Hibernate的技术社区非常活跃。 Ebean：支持快速数据访问和编码的ORM框架。 PDF 用来帮助创建PDF文件的资源。\nApache FOP：从XSL-FO创建PDF。 Apache PDFBox：用来创建和操作PDF的工具集。 DynamicReports：JasperReports的精简版。 iText：一个易于使用的PDF函数库，用来编程创建PDF文件。注意，用于商业用途时需要许可证。 JasperReports：一个复杂的报表引擎。 REST框架 用来创建RESTful 服务的框架。\nDropwizard：偏向于自己使用的Web框架。用来构建Web应用程序，使用了Jetty、Jackson、Jersey和Metrics。 Jersey：JAX-RS参考实现。 RESTEasy：经过JAX-RS规范完全认证的可移植实现。 Retrofit：一个Java类型安全的REST客户端。 Spark：受到Sinatra启发的Java REST框架。 Swagger：Swagger是一个规范且完整的框架，提供描述、生产、消费和可视化RESTful Web Service。 科学 用于科学计算和分析的函数库。\nSCaVis：用于科学计算、数据分析和数据可视化环境。 搜索 文档索引引擎，用于搜索和分析。\nApache Solr ：一个完全的企业搜索引擎。为高吞吐量通信进行了优化。 Elasticsearch：一个分布式、支持多租户（multitenant）全文本搜索引擎。提供了RESTful Web接口和无schema的JSON文档。 安全 用于处理安全、认证、授权或会话管理的函数库。\nApache Shiro：执行认证、授权、加密和会话管理。 Cryptomator：在云上进行客户端跨平台透明加密。 Keycloak：为浏览器应用和RESTful Web Service集成SSO和IDM。目前还处于beta版本，但是看起来非常有前途。 PicketLink：PicketLink是一个针对Java应用进行安全和身份认证管理的大型项目（Umbrella Project）。 Spring Security：专注认证、授权和多维度攻击防护框架。 序列化 用来高效处理序列化的函数库。\nFlatBuffers：序列化函数库，高效利用内存，无需解包和解析即可高效访问序列化数据。 Kryo：快速和高效的对象图形序列化框架。 MessagePack：一种高效的二进制序列化格式。 服务器 用来部署应用程序的服务器。\nApache Tomcat：针对Servlet和JSP的应用服务器，健壮性好且适用性强。 Apache TomEE：Tomcat加Java EE。 GlassFish：Java EE开源参考实现，由Oracle资助开发。 Jetty：轻量级、小巧的应用服务器，通常会嵌入到项目中。 WildFly：之前被称作JBoss，由Red Hat开发。支持很多Java EE功能。 模版引擎 对模板中表达式进行替换的工具。\nApache Velocity：提供HTML页面模板、email模板和通用开源代码生成器模板。 FreeMarker：通用模板引擎，不需要任何重量级或自己使用的依赖关系。 Handlebars.java：使用Java编写的模板引擎，逻辑简单，支持语义扩展（Semantic Mustache）。 JavaServer Pages：通用网站模板，支持自定义标签库。 Thymeleaf：旨在替换JSP，支持XML文件。 测试 测试内容从对象到接口，涵盖性能测试和基准测试工具。\nApache JMeter：功能性测试和性能评测。 Arquillian：集成测试和功能行测试平台，集成Java EE容器。 AssertJ：支持流式断言提高测试的可读性。 JMH：JVM微基准测试工具。 JUnit：通用测试框架。 Mockito：在自动化单元测试中创建测试对象，为TDD或BDD提供支持。 Selenium：为Web应用程序提供可移植软件测试框架。 Selenide：为Selenium提供精准的周边API，用来编写稳定且可读的UI测试。 TestNG ：测试框架。 VisualVM：提供可视化方式查看运行中的应用程序信息。 工具类 通用工具类函数库。\nApache Commons：提供各种用途的函数，比如配置、验证、集合、文件上传或XML处理等。 Guava：集合、缓存、支持基本类型、并发函数库、通用注解、字符串处理、I/O等。 javatuples：正如名字表示的那样，提供tuple支持。尽管目前tuple的概念还有留有争议。 网络爬虫 用于分析网站内容的函数库。\nApache Nutch ：可用于生产环境的高度可扩展、可伸缩的网络爬虫。 Crawler4j：简单的轻量级爬虫。 JSoup ：刮取、解析、操作和清理HTML。 Web框架 用于处理Web应用程序不同层次间通讯的框架。\nApache Tapestry：基于组件的框架，使用Java创建动态、强健的、高度可扩展的Web应用程序。 Apache Wicket：基于组件的Web应用框架，与Tapestry类似带有状态显示GUI。 Google Web Toolkit：一组Web开发工具集，包含在客户端将Java代码转为JavaScript的编译器、XML解析器、RCP API、JUnit集成、国际化支持和GUI控件。 Grails：Groovy框架，旨在提供一个高效开发环境，使用约定而非配置、没有XML并支持混入（mixin）。 Play： 使用约定而非配置，支持代码热加载并在浏览器中显示错误。 PrimeFaces：JSF框架，提供免费版和带技术支持的商业版。包含一些前端组件。 Spring Boot：微框架，简化了Spring新程序的开发过程。 Spring：旨在简化Java EE的开发过程，提供依赖注入相关组件并支持面向切面编程。 Vaadin：基于GWT构建的事件驱动框架。使用服务端架构，客户端使用Ajax。 Ninja：Java全栈Web开发框架。非常稳固、快速和高效。 Ratpack：一组Java开发函数库，用于构建快速、高效、可扩展且测试完备的HTTP应用程序。 资源 社区 活跃的讨论区。\nr/java：Java社区的Subreddit。 stackoverflow：问答平台。 有影响的书籍 具有广泛影响且值得阅读的Java经典书籍。\nEffective Java (2nd Edition) Java Concurrency in Practice | Java并发编程实战 Thinking in Java | 中文版 播客 可以一边编程一边听的东西。\nThe Java Posse Twitter 值得关注的帐号。\nAdam Bien：自由职业者、作家、JavaONE明星演讲者、顾问、Java Champion。 Antonio Goncalves：Java Champion、JUG Leader、Devoxx France、Java EE 6/7、JCP、作家。 Arun Gupta：Java Champion、JavaONE明星演讲者、JUG Leader、Devoxx4Kids成员、Red Hatter。 Bruno Borges：Oracle产品经理、Java Jock。 Ed Burns：Oracle技术团队顾问。 Eugen Paraschiv：Spring安全课程作者。 James Weaver：Java、JavaFX、IoT开发者、作者和演讲者。 Java EE：Java EE Twitter官方账号。 Java Magazine：Java杂志官方账号。 Java.net：Java.net官方账号。 Java：Java Twitter官方账号。 Javin Paul：知名Java博客作者。 Lukas Eder：Data Geekery（jOOQ）创始人兼CEO。 Mario Fusco：RedHatter、JUG协调、活跃讲师和作者。 Mark Reinhold：Oracle首席架构师、Java平台开发组。 Martijn Verburg：London JUG co-leader、演讲者、作家、Java Champion等。 OpenJDK：OpenJDK官方账号。 Reza Rahman：Java EE、GlassFish、WebLogic传道者、作家、演讲者、开源黑客。 Simon Maple：Java Champion、virtualJUG创始人、LJC leader、RebelLabs作者。 Stephen Colebourne： Java Champion、演讲者。 Tim Boudreau：作家、NetBeans大牛。 Trisha Gee：Java Champion、演讲者。 网站 值得阅读的网站。\nGoogle Java Style InfoQ Java Code Geeks Java.net Javalobby JavaWorld RebelLabs The Java Specialist’ Newsletter TheServerSide.com Thoughts On Java 参与贡献 热烈欢迎参与贡献此列表！\n请参阅CONTRIBUTING加入贡献。\n","permalink":"https://blog.zdltech.com/posts/%E6%8E%A8%E8%8D%90%E5%9B%BD%E5%A4%96%E7%A8%8B%E5%BA%8F%E5%91%98%E6%95%B4%E7%90%86%E7%9A%84java%E8%B5%84%E6%BA%90%E5%A4%A7%E5%85%A8/","summary":"\u003ch2 id=\"构建\"\u003e构建\u003c/h2\u003e\n\u003cp\u003e这里搜集了用来构建应用程序的工具。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://maven.apache.org/\"\u003eApache Maven\u003c/a\u003e：Maven使用声明进行构建并进行依赖管理，偏向于使用约定而不是配置进行构建。Maven优于Apache Ant。后者采用了一种过程化的方式进行配置，所以维护起来相当困难。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.gradle.org/\"\u003eGradle\u003c/a\u003e：Gradle采用增量构建。Gradle通过Groovy编程而不是传统的XML声明进行配置。Gradle可以很好地配合Maven进行依赖管理，并且把Ant脚本当作头等公民。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"字节码操作\"\u003e字节码操作\u003c/h2\u003e\n\u003cp\u003e编程操作Java字节码的函数库。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://asm.ow2.org/\"\u003eASM\u003c/a\u003e：通用底层字节码操作及分析。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/\"\u003eJavassist\u003c/a\u003e：尝试简化字节码编辑。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://bytebuddy.net/\"\u003eByte Buddy\u003c/a\u003e：使用“流式API”进一步简化字节码生成。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"代码分析\"\u003e代码分析\u003c/h2\u003e\n\u003cp\u003e软件度量和质量评估工具。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://checkstyle.sourceforge.net/\"\u003eCheckstyle\u003c/a\u003e：对编程规范和标准进行静态分析。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://findbugs.sourceforge.net/\"\u003eFindBugs\u003c/a\u003e：通过字节码静态分析找出潜在Bug。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://pmd.sourceforge.net/\"\u003ePMD\u003c/a\u003e：对源代码中不良编程习惯进行分析。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.sonarqube.org/\"\u003eSonarQube\u003c/a\u003e：通过插件集成其它分析组件，提供评估最终结果报告。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"编译器\"\u003e编译器\u003c/h2\u003e\n\u003cp\u003e创建分析器、解释器和编译器的框架。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.antlr.org/\"\u003eANTLR\u003c/a\u003e：功能完备的自顶向下分析复杂框架。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://javacc.java.net/\"\u003eJavaCC\u003c/a\u003e：相对ANTLR更具体，上手略为简单。支持语法语法超前预测（syntactic lookahead）。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"持续集成\"\u003e持续集成\u003c/h2\u003e\n\u003cp\u003e支持持续集成、测试和应用发布的工具。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.atlassian.com/software/bamboo\"\u003eBamboo\u003c/a\u003e：Atlassian的持续集成（CI）解决方案，包含很多其它产品。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://circleci.com/\"\u003eCircleCI\u003c/a\u003e：提供托管服务，可免费试用。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.codeship.io/features\"\u003eCodeship\u003c/a\u003e：提供托管服务，提供有限免费计划。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.thoughtworks.com/products/go-continuous-delivery\"\u003eGo\u003c/a\u003e：ThoughtWork开源持续集成解决方案。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://jenkins-ci.org/\"\u003eJenkins\u003c/a\u003e：提供基于服务器的部署服务。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.jetbrains.com/teamcity/\"\u003eTeamCity\u003c/a\u003e：JetBrain持续集成方案，提供免费版。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://travis-ci.org/\"\u003eTravis\u003c/a\u003e：提供托管服务，常用于开源项目。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"数据库\"\u003e数据库\u003c/h2\u003e\n\u003cp\u003e简化数据库交互的工具、库。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://flywaydb.org/\"\u003eFlyway\u003c/a\u003e：使用Java API轻松完成数据库迁移。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://h2database.com/\"\u003eH2\u003c/a\u003e：小型SQL数据库，以内存操作著称。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://jdbi.org/\"\u003eJDBI\u003c/a\u003e：便捷的JDBC抽象。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.jooq.org/\"\u003ejOOQ\u003c/a\u003e：基于SQL schema生成类型安全代码。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/facebook/presto\"\u003ePresto\u003c/a\u003e：针对大数据的分布式SQL查询引擎。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.querydsl.com/\"\u003eQuerydsl\u003c/a\u003e：针对Java的类型安全统一查询。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"日期和时间\"\u003e日期和时间\u003c/h2\u003e\n\u003cp\u003e处理日期和时间的函数库。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.joda.org/joda-time/\"\u003eJoda-Time\u003c/a\u003e：Java 8出现之前，它是日期、时间处理的标准函数库。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/MenoData/Time4J\"\u003eTime4J\u003c/a\u003e：Java高级日期、时间函数库。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"依赖注入\"\u003e依赖注入\u003c/h2\u003e\n\u003cp\u003e帮助代码实现\u003ca href=\"http://en.wikipedia.org/wiki/Inversion_of_control\"\u003e控制反转\u003c/a\u003e模式的函数库。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://square.github.io/dagger/\"\u003eDagger\u003c/a\u003e ：编译期的注入框架，没有使用反射，主要用于Android开发。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/google/guice\"\u003eGuice\u003c/a\u003e：轻量级注入框架，功能强大可与Dagger媲美。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"开发库\"\u003e开发库\u003c/h2\u003e\n\u003cp\u003e从基础层次上改进开发流程。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://eclipse.org/aspectj/\"\u003eAspectJ\u003c/a\u003e：面向切面编程扩展，与程序无缝连接。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/google/auto\"\u003eAuto\u003c/a\u003e：源代码生成器集合。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://ssw.jku.at/dcevm/\"\u003eDCEVM\u003c/a\u003e：通过修改JVM，在运行时可无限次重定义已加载的类。OpenJDK 7、8已提供支持，详情可查看\u003ca href=\"http://dcevm.github.io/\"\u003e这个分支（fork）\u003c/a\u003e。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://zeroturnaround.com/software/jrebel/\"\u003eJRebel\u003c/a\u003e：商用软件，无需重新部署可即时重新加载代码及配置。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://projectlombok.org/\"\u003eLombok\u003c/a\u003e：代码生成器，旨在减少Java冗余代码。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/Netflix/RxJava\"\u003eRxJava\u003c/a\u003e：使用JVM中可观察序列，创建异步、基于事件应用程序的函数库。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/spring-projects/spring-loaded\"\u003eSpring Loaded\u003c/a\u003e：另一个JVM类重载代理。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://vertx.io/\"\u003evert.x\u003c/a\u003e：JVM多语言事件驱动应用框架。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"分布式应用\"\u003e分布式应用\u003c/h2\u003e\n\u003cp\u003e用来开发分布式、具有容错性应用程序的函数库和框架。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://akka.io/\"\u003eAkka\u003c/a\u003e：构建并发、分布式和具有容错功能的事件驱动应用程序所需的工具包和运行时。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://storm.incubator.apache.org/\"\u003eApache Storm\u003c/a\u003e：分布式实时计算系统。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://zookeeper.apache.org/\"\u003eApache ZooKeeper\u003c/a\u003e：为大型分布式系统，使用分布式配置、同步和命名注册提供协调服务。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://hazelcast.org/\"\u003eHazelcast\u003c/a\u003e：分布式、高可扩展性内存网格。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/Netflix/Hystrix\"\u003eHystrix\u003c/a\u003e：为分布式系统提供延迟和容错处理。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.jgroups.org/\"\u003eJGroups\u003c/a\u003e：一组提供可靠消息传输的工具包，可用来创建集群。集群中的节点可互相发送消息。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.paralleluniverse.co/quasar/\"\u003eQuasar\u003c/a\u003e：为JVM提供轻量级线程和Actor。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"发布\"\u003e发布\u003c/h2\u003e\n\u003cp\u003e使用本机格式分发Java应用程序的工具。\u003c/p\u003e","title":"推荐！国外程序员整理的Java资源大全"},{"content":"Nginx负载均衡的理解\nNginx是一个轻量级的、高性能的WebServer，他主要可以干下面两件事：\n作为http服务器（和apache的效果一样）\n作为反向代理服务器实现负载均衡\n现在Nginx到处都可以见到，经常会看到宕机后的网页会显示nginx的字样，这也说明Nginx由于高性能、使用配置简、开源单这些特点被越来越多的用户所接受，所使用。\n其中第一种作为http服务器，结合php-fpm进程，对发来的请求进行处理，nginx本身并不会解析php，他只是作为一个服务器，接受客户端发来的请求，如果是php请求，则交给php进程处理，并将php处理完成之后的结果发送给客户端。这个很简单，安装好nginx+php-fpm之后配置好各自的配置文件，启动就可以实现。运行原理可以看下面这段解释：\nNginx不支持对外部程序的直接调用或者解析，所有的外部程序（包括PHP）必须通过FastCGI接口来调用。FastCGI接口在Linux下是socket（这个socket可以是文件socket，也可以是ip socket）。为了调用CGI程序，还需要一个FastCGI的wrapper（wrapper可以理解为用于启动另一个程序的程序），这个wrapper绑定在某个固定socket上，如端口或者文件socket。当Nginx将CGI请求发送给这个socket的时候，通过FastCGI接口，wrapper接收到请求，然后派生出一个新的线程，这个线程调用解释器或者外部程序处理脚本并读取返回数据；接着，wrapper再将返回的数据通过FastCGI接口，沿着固定的socket传递给Nginx；最后，Nginx将返回的数据发送给客户端。这就是Nginx+FastCGI的整个运作过程，如图下图所示。\n[][1]\n上面这段话解释了nginx+fastcgi的运行机制，在nginx配置文件中会对请求进行匹配，并作做出相应的处理，比如说直接返回错误文件（这里和上面说的有点区别，我估计是nginx内部对html等这些静态文件可以做类似上图的解析），使用php进程对php请求进行处理（这里的php进程可以是多个）。\n第二种是用反向代理事项负载均衡，这个其实其实很简单，说起来就是自己定义一组server，对请求进行匹配，并将请求转给server中的任意一个处理，来减轻每个server的压力，先看看网上对反向向代理的定义：\n反向代理（Reverse Proxy）方式是指以代理服务器来接受internet上的连接请求，然后将请求转发给内部网络上的服务器，并将从服务器上得到的结果返回给internet上请求连接的客户端，此时代理服务器对外就表现为一个反向代理服务器。\n反向代理是和正向代理（或者叫代理） 相反的，代理大家定听过吧，为了更方便的访问B资源，通过A资源间接的访问B资源，特点就是用户知道自己最终要访问的网站是什么，但是反向代理用户是不知道代理服务器后边做了什么处理的，反向代理中服务真正的处理服务器放在内网，对外网而言只可以访问反向代理服务器，这也大大提高了安全性。\n安装软件\nnginx安装很简单\n1、安装nginx需要的环境，pcre（作用rewrite）、zlib（作用压缩）、ssl，这个也可以自己下载编译安装\nyum -y install zlib;\nyum –y install pcre;\nyum –y install openssl;\n2、下载安装nginx-*.tar.gz。\ntar –zxvf nginx-1.2.8.tar.gz –C ./;\ncd nginx-1.2.8;\n./congigure –prefix=/usr/local/nginx;\nmake \u0026amp;\u0026amp; make install;\n3、配置\n这里配置的时候只需要修改http{}之间的内容就行了，修改的第一个地方就是设置服务器组，在http节点之间添加\nupstream myServer{\nserver www.88181.com:80; #这里是你自己要做负载均衡的服务器地址1\nserver www.linux.com:8080; #这里是要参与负载均衡的地址2\n}\nnginx中的upstream支持下面几种方式：轮询（默认，按照时间顺序对所有服务器一个一个的访问，如果有服务器宕机，会自动剔除）、weight（服务器的方位几率和weight成正比，这个可以在服务器配置不均的时候进行配置）、ip_hash（对每个请求的ip进行hash计算，并按照一定的规则分配对应的服务器）、fair（按照每台服务器的响应时间（rt）来分配请求，rt晓得优先分配）、url_hash（按照访问url的hash值来分配请求），我这里使用了默认的轮训方式。\n将请求指向myServer\nlocation / {\nproxy_pass http://myServer;\n}\n完整的文件（删除注释）如下：\nworker_processes 1;\nevents {\nworker_connections 1024;\n}\nhttp {\ninclude mime.types;\ndefault_type application/octet-stream;\nsendfile on;\nkeepalive_timeout 65;\nupstream myServer{\nserver www.linux.com:80;\nserver www.88181.com:8080;\n}\nserver {\nlisten 80;\nserver_name my22;\nlocation / {\nproxy_pass http://myServer;\n}\n}\n}\n设置反向代理后端作为负载均衡的两个服务器\n可以看到上一步骤有两个服务器地址，www.linux.com:80和www.88181.com:8080，上面的nginx我是安装在虚拟机上面的，这两个服务器我是安装在本机win8系统中的，使用apache的virtualhost，设置了两个域名，这两个域名下的代码是互相独立的，设置也很简单：\n1、设置apache配置文件\n我使用的是xampp集成环境，要修改的地方有两个，在httpd.conf中监听端口的地方添加\nListen 8080\n也就是说这个地方监听了两个端口\nListen 80\nListen 8080\n看看下面这个句是否打开，没有打开的话，打开，打开如下面所示\n# Virtual hosts\nInclude conf/extra/httpd-vhosts.conf\n在httpd-vhosts.conf中添加下面的内容，\n\u0026lt;VirtualHost *:80\u0026gt;\nServerName www.linux.com #对应的域名，负载均衡的服务器地址\nDocumentRoot E:\\soft\\xampp\\htdocs\\www.linux.com #代码文件夹\n\u0026lt;VirtualHost *:8080\u0026gt;\nServerName www.88181.com\nDocumentRoot E:\\soft\\xampp\\htdocs\\www.88181.com\n修改windows的hosts文件，追加下面的内容\n127.0.0.1 www.linux.com\n127.0.0.1 www.88181.com\n修改linux的/etc/hosts文件，追加下面的内容\n192.168.1.12 www.linux.com #这里前面的地址对应我win8本机的ip地址\n192.168.1.12 www.88181.com\n我在www.linux.com:80中放了一个文件index.php【E:\\soft\\xampp\\htdocs\\www.linux.com\\index.php】\nwww.88181.com:8080中也放了一个文件index.php【E:\\soft\\xampp\\htdocs\\www.88181.com\\index.php】\n文件中的内容基本相同，只是I’m the 88181这个地方有区别，一个是linux，另一个是88181。\n如果你可以在win8浏览器中输入www.linux.com:80和www.88181.com:8080看到不同的效果\n并且在CentOS下面看到下面的结果（自己美化了下）说明配置成功了\n[root@bogon nginx]# curl www.linux.com:80\nI’m the linux 【view】1\n[root@bogon nginx]# curl www.88181.com:8080\nI’m the 88181 【view】1\n\u003c?php session\\_save\\_path(\u0026#8220;./\u0026#8221;); session_start(); header(\u0026#8220;Content-type:text/html;charset=utf-8\u0026#8221;); if(isset(_SESSION[\u0026#8216;view\u0026#8217;])){_SESSION[\u0026#8216;view\u0026#8217;] = _SESSION[\u0026#8216;view\u0026#8217;] + 1; }else{_SESSION[\u0026#8216;view\u0026#8217;] = 1; } echo \u0026#8220;I\u0026#8217;m the 88181 \u0026#8221;; echo \u0026#8220;【view】{$_SESSION[\u0026#8216;view\u0026#8217;]}\u0026#8221;; 看看效果 等所有都ok之后可硬通过浏览器访问看看效果 忘了说了，nginx代理服务器的地址为http://192.168.1.113， 浏览器输入http://192.168.1.113/index.php之后，不停的刷新，你会发现，会在 I\u0026#8217;m the 88181、I\u0026#8217;m the linux 这两个页面之间来回交换，view会没刷新两下增加一次，这也证明了前面所说的默认是轮训的方式，但这里又有一个比较常见的问题了，当用户访问网站时，未做处理的情况下，session会保存在不同的服务器上（我这里用两个不同的文件夹模拟两台服务器），session数据可能出现多套，这个问题怎么解决呢，下篇文章说说这个问题，其实也很简单。 \u0026nbsp; 转自：http://www.linuxdiyf.com/linux/10205.html [1]: http://www.linuxdiyf.com/linux/","permalink":"https://blog.zdltech.com/posts/centosnginx%E4%B8%80%E6%AD%A5%E4%B8%80%E6%AD%A5%E5%BC%80%E5%A7%8B%E9%85%8D%E7%BD%AE%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1/","summary":"\u003cp\u003eNginx负载均衡的理解\u003c/p\u003e\n\u003cp\u003eNginx是一个轻量级的、高性能的WebServer，他主要可以干下面两件事：\u003c/p\u003e\n\u003cp\u003e作为http服务器（和apache的效果一样）\u003cbr\u003e\n作为反向代理服务器实现负载均衡\u003c/p\u003e\n\u003cp\u003e现在Nginx到处都可以见到，经常会看到宕机后的网页会显示nginx的字样，这也说明Nginx由于高性能、使用配置简、开源单这些特点被越来越多的用户所接受，所使用。\u003c/p\u003e\n\u003cp\u003e其中第一种作为http服务器，结合php-fpm进程，对发来的请求进行处理，nginx本身并不会解析php，他只是作为一个服务器，接受客户端发来的请求，如果是php请求，则交给php进程处理，并将php处理完成之后的结果发送给客户端。这个很简单，安装好nginx+php-fpm之后配置好各自的配置文件，启动就可以实现。运行原理可以看下面这段解释：\u003c/p\u003e\n\u003cp\u003eNginx不支持对外部程序的直接调用或者解析，所有的外部程序（包括PHP）必须通过FastCGI接口来调用。FastCGI接口在Linux下是socket（这个socket可以是文件socket，也可以是ip socket）。为了调用CGI程序，还需要一个FastCGI的wrapper（wrapper可以理解为用于启动另一个程序的程序），这个wrapper绑定在某个固定socket上，如端口或者文件socket。当Nginx将CGI请求发送给这个socket的时候，通过FastCGI接口，wrapper接收到请求，然后派生出一个新的线程，这个线程调用解释器或者外部程序处理脚本并读取返回数据；接着，wrapper再将返回的数据通过FastCGI接口，沿着固定的socket传递给Nginx；最后，Nginx将返回的数据发送给客户端。这就是Nginx+FastCGI的整个运作过程，如图下图所示。\u003cbr\u003e\n[\u003cimg loading=\"lazy\" src=\"http://www.linuxdiyf.com/linux/uploads/allimg/150328/2-15032R23415629.jpg\"\u003e][1]\u003c/p\u003e\n\u003cp\u003e上面这段话解释了nginx+fastcgi的运行机制，在nginx配置文件中会对请求进行匹配，并作做出相应的处理，比如说直接返回错误文件（这里和上面说的有点区别，我估计是nginx内部对html等这些静态文件可以做类似上图的解析），使用php进程对php请求进行处理（这里的php进程可以是多个）。\u003c/p\u003e\n\u003cp\u003e第二种是用反向代理事项负载均衡，这个其实其实很简单，说起来就是自己定义一组server，对请求进行匹配，并将请求转给server中的任意一个处理，来减轻每个server的压力，先看看网上对反向向代理的定义：\u003c/p\u003e\n\u003cp\u003e反向代理（Reverse Proxy）方式是指以代理服务器来接受internet上的连接请求，然后将请求转发给内部网络上的服务器，并将从服务器上得到的结果返回给internet上请求连接的客户端，此时代理服务器对外就表现为一个反向代理服务器。\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://www.linuxdiyf.com/linux/uploads/allimg/150328/2-15032R23430608.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e反向代理是和正向代理（或者叫代理） 相反的，代理大家定听过吧，为了更方便的访问B资源，通过A资源间接的访问B资源，特点就是用户知道自己最终要访问的网站是什么，但是反向代理用户是不知道代理服务器后边做了什么处理的，反向代理中服务真正的处理服务器放在内网，对外网而言只可以访问反向代理服务器，这也大大提高了安全性。\u003cbr\u003e\n安装软件\u003c/p\u003e\n\u003cp\u003enginx安装很简单\u003c/p\u003e\n\u003cp\u003e1、安装nginx需要的环境，pcre（作用rewrite）、zlib（作用压缩）、ssl，这个也可以自己下载编译安装\u003c/p\u003e\n\u003cp\u003eyum -y install zlib;\u003c/p\u003e\n\u003cp\u003eyum –y install pcre;\u003c/p\u003e\n\u003cp\u003eyum –y install openssl;\u003c/p\u003e\n\u003cp\u003e2、下载安装nginx-*.tar.gz。\u003c/p\u003e\n\u003cp\u003etar –zxvf nginx-1.2.8.tar.gz –C ./;\u003c/p\u003e\n\u003cp\u003ecd nginx-1.2.8;\u003c/p\u003e\n\u003cp\u003e./congigure –prefix=/usr/local/nginx;\u003c/p\u003e\n\u003cp\u003emake \u0026amp;\u0026amp; make install;\u003c/p\u003e\n\u003cp\u003e3、配置\u003c/p\u003e\n\u003cp\u003e这里配置的时候只需要修改http{}之间的内容就行了，修改的第一个地方就是设置服务器组，在http节点之间添加\u003c/p\u003e\n\u003cp\u003eupstream myServer{\u003c/p\u003e\n\u003cp\u003eserver \u003ca href=\"https://www.88181.com\"\u003ewww.88181.com\u003c/a\u003e:80;  #这里是你自己要做负载均衡的服务器地址1\u003c/p\u003e\n\u003cp\u003eserver \u003ca href=\"https://www.linux.com\"\u003ewww.linux.com\u003c/a\u003e:8080; #这里是要参与负载均衡的地址2\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003enginx中的upstream支持下面几种方式：轮询（默认，按照时间顺序对所有服务器一个一个的访问，如果有服务器宕机，会自动剔除）、weight（服务器的方位几率和weight成正比，这个可以在服务器配置不均的时候进行配置）、ip_hash（对每个请求的ip进行hash计算，并按照一定的规则分配对应的服务器）、fair（按照每台服务器的响应时间（rt）来分配请求，rt晓得优先分配）、url_hash（按照访问url的hash值来分配请求），我这里使用了默认的轮训方式。\u003c/p\u003e\n\u003cp\u003e将请求指向myServer\u003c/p\u003e\n\u003cp\u003elocation / {\u003c/p\u003e\n\u003cp\u003eproxy_pass  http://myServer;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e完整的文件（删除注释）如下：\u003c/p\u003e\n\u003cp\u003eworker_processes  1;\u003cbr\u003e\nevents {\u003cbr\u003e\nworker_connections  1024;\u003cbr\u003e\n}\u003cbr\u003e\nhttp {\u003cbr\u003e\ninclude      mime.types;\u003cbr\u003e\ndefault_type  application/octet-stream;\u003cbr\u003e\nsendfile        on;\u003cbr\u003e\nkeepalive_timeout  65;\u003cbr\u003e\nupstream myServer{\u003cbr\u003e\nserver \u003ca href=\"https://www.linux.com\"\u003ewww.linux.com\u003c/a\u003e:80;\u003cbr\u003e\nserver \u003ca href=\"https://www.88181.com\"\u003ewww.88181.com\u003c/a\u003e:8080;\u003cbr\u003e\n}\u003cbr\u003e\nserver {\u003cbr\u003e\nlisten      80;\u003cbr\u003e\nserver_name  my22;\u003cbr\u003e\nlocation / {\u003cbr\u003e\nproxy_pass  http://myServer;\u003cbr\u003e\n}\u003cbr\u003e\n}\u003cbr\u003e\n}\u003cbr\u003e\n设置反向代理后端作为负载均衡的两个服务器\u003c/p\u003e","title":"CentOS+Nginx一步一步开始配置负载均衡"},{"content":"String filePath=””;\nFile file=new File(filePath);\n//解决乱码问题\nString filename=URLEncoder.encode(file.getName(),”utf-8″);\n//重置输出流\nresponse.reset();\nResponse.AddHeader(“Content-Disposition”, “attachment;filename=”+filename);//设置文件名\nresponse.addHeader(“Content-Length”,file.length);//设置下载文件大小\nresponse.setContentType(“application/octet-stream”);//设置文件类型\nOutputStream toClient=new BufferedOuntputStream( response.getOutputStream() );//获取二进制输出流\n//读取文件数据\nInputStream fis=new BufferedInputStream(new FileInputStream(filePath));\nbyte[] buffer=new byte[file.length()];\nfis.read(buffer);\nfis.close();\n//输出文件数据\ntoClient.write(buffer);\ntoClient.close();\n文件类型如下:\n“.*”=”application/octet-stream”\n“.001″=”application/x-001”\n“.301″=”application/x-301”\n“.323″=”text/h323”\n“.906″=”application/x-906”\n“.907″=”drawing/907”\n“.a11″=”application/x-a11”\n“.acp”=”audio/x-mei-aac”\n“.ai”=”application/postscript”\n“.aif”=”audio/aiff”\n“.aifc”=”audio/aiff”\n“.aiff”=”audio/aiff”\n“.anv”=”application/x-anv”\n“.asa”=”text/asa”\n“.asf”=”video/x-ms-asf”\n“.asp”=”text/asp”\n“.asx”=”video/x-ms-asf”\n“.au”=”audio/basic”\n“.avi”=”video/avi”\n“.awf”=”application/vnd.adobe.workflow”\n“.biz”=”text/xml”\n“.bmp”=”application/x-bmp”\n“.bot”=”application/x-bot”\n“.c4t”=”application/x-c4t”\n“.c90″=”application/x-c90”\n“.cal”=”application/x-cals”\n“.cat”=”application/vnd.ms-pki.seccat”\n“.cdf”=”application/x-netcdf”\n“.cdr”=”application/x-cdr”\n“.cel”=”application/x-cel”\n“.cer”=”application/x-x509-ca-cert”\n“.cg4″=”application/x-g4”\n“.cgm”=”application/x-cgm”\n“.cit”=”application/x-cit”\n“.class”=”java/*”\n“.cml”=”text/xml”\n“.cmp”=”application/x-cmp”\n“.cmx”=”application/x-cmx”\n“.cot”=”application/x-cot”\n“.crl”=”application/pkix-crl”\n“.crt”=”application/x-x509-ca-cert”\n“.csi”=”application/x-csi”\n“.css”=”text/css”\n“.cut”=”application/x-cut”\n“.dbf”=”application/x-dbf”\n“.dbm”=”application/x-dbm”\n“.dbx”=”application/x-dbx”\n“.dcd”=”text/xml”\n“.dcx”=”application/x-dcx”\n“.der”=”application/x-x509-ca-cert”\n“.dgn”=”application/x-dgn”\n“.dib”=”application/x-dib”\n“.dll”=”application/x-msdownload”\n“.doc”=”application/msword”\n“.dot”=”application/msword”\n“.drw”=”application/x-drw”\n“.dtd”=”text/xml”\n“.dwf”=”Model/vnd.dwf”\n“.dwf”=”application/x-dwf”\n“.dwg”=”application/x-dwg”\n“.dxb”=”application/x-dxb”\n“.dxf”=”application/x-dxf”\n“.edn”=”application/vnd.adobe.edn”\n“.emf”=”application/x-emf”\n“.eml”=”message/rfc822”\n“.ent”=”text/xml”\n“.epi”=”application/x-epi”\n“.eps”=”application/x-ps”\n“.eps”=”application/postscript”\n“.etd”=”application/x-ebx”\n“.exe”=”application/x-msdownload”\n“.fax”=”image/fax”\n“.fdf”=”application/vnd.fdf”\n“.fif”=”application/fractals”\n“.fo”=”text/xml”\n“.frm”=”application/x-frm”\n“.g4″=”application/x-g4”\n“.gbr”=”application/x-gbr”\n“.gcd”=”application/x-gcd”\n“.gif”=”image/gif”\n“.gl2″=”application/x-gl2”\n“.gp4″=”application/x-gp4”\n“.hgl”=”application/x-hgl”\n“.hmr”=”application/x-hmr”\n“.hpg”=”application/x-hpgl”\n“.hpl”=”application/x-hpl”\n“.hqx”=”application/mac-binhex40”\n“.hrf”=”application/x-hrf”\n“.hta”=”application/hta”\n“.htc”=”text/x-component”\n“.htm”=”text/html”\n“.html”=”text/html”\n“.htt”=”text/webviewhtml”\n“.htx”=”text/html”\n“.icb”=”application/x-icb”\n“.ico”=”image/x-icon”\n“.ico”=”application/x-ico”\n“.iff”=”application/x-iff”\n“.ig4″=”application/x-g4”\n“.igs”=”application/x-igs”\n“.iii”=”application/x-iphone”\n“.img”=”application/x-img”\n“.ins”=”application/x-internet-signup”\n“.isp”=”application/x-internet-signup”\n“.IVF”=”video/x-ivf”\n“.java”=”java/*”\n“.jfif”=”image/jpeg”\n“.jpe”=”image/jpeg”\n“.jpe”=”application/x-jpe”\n“.jpeg”=”image/jpeg”\n“.jpg”=”image/jpeg”\n“.jpg”=”application/x-jpg”\n“.js”=”application/x-javascript”\n“.jsp”=”text/html”\n“.la1″=”audio/x-liquid-file”\n“.lar”=”application/x-laplayer-reg”\n“.latex”=”application/x-latex”\n“.lavs”=”audio/x-liquid-secure”\n“.lbm”=”application/x-lbm”\n“.lmsff”=”audio/x-la-lms”\n“.ls”=”application/x-javascript”\n“.ltr”=”application/x-ltr”\n“.m1v”=”video/x-mpeg”\n“.m2v”=”video/x-mpeg”\n“.m3u”=”audio/mpegurl”\n“.m4e”=”video/mpeg4”\n“.mac”=”application/x-mac”\n“.man”=”application/x-troff-man”\n“.math”=”text/xml”\n“.mdb”=”application/msaccess”\n“.mdb”=”application/x-mdb”\n“.mfp”=”application/x-shockwave-flash”\n“.mht”=”message/rfc822”\n“.mhtml”=”message/rfc822”\n“.mi”=”application/x-mi”\n“.mid”=”audio/mid”\n“.midi”=”audio/mid”\n“.mil”=”application/x-mil”\n“.mml”=”text/xml”\n“.mnd”=”audio/x-musicnet-download”\n“.mns”=”audio/x-musicnet-stream”\n“.mocha”=”application/x-javascript”\n“.movie”=”video/x-sgi-movie”\n“.mp1″=”audio/mp1”\n“.mp2″=”audio/mp2”\n“.mp2v”=”video/mpeg”\n“.mp3″=”audio/mp3”\n“.mp4″=”video/mpeg4”\n“.mpa”=”video/x-mpg”\n“.mpd”=”application/vnd.ms-project”\n“.mpe”=”video/x-mpeg”\n“.mpeg”=”video/mpg”\n“.mpg”=”video/mpg”\n“.mpga”=”audio/rn-mpeg”\n“.mpp”=”application/vnd.ms-project”\n“.mps”=”video/x-mpeg”\n“.mpt”=”application/vnd.ms-project”\n“.mpv”=”video/mpg”\n“.mpv2″=”video/mpeg”\n“.mpw”=”application/vnd.ms-project”\n“.mpx”=”application/vnd.ms-project”\n“.mtx”=”text/xml”\n“.mxp”=”application/x-mmxp”\n“.net”=”image/pnetvue”\n“.nrf”=”application/x-nrf”\n“.nws”=”message/rfc822”\n“.odc”=”text/x-ms-odc”\n“.out”=”application/x-out”\n“.p10″=”application/pkcs10”\n“.p12″=”application/x-pkcs12”\n“.p7b”=”application/x-pkcs7-certificates”\n“.p7c”=”application/pkcs7-mime”\n“.p7m”=”application/pkcs7-mime”\n“.p7r”=”application/x-pkcs7-certreqresp”\n“.p7s”=”application/pkcs7-signature”\n“.pc5″=”application/x-pc5”\n“.pci”=”application/x-pci”\n“.pcl”=”application/x-pcl”\n“.pcx”=”application/x-pcx”\n“.pdf”=”application/pdf”\n“.pdf”=”application/pdf”\n“.pdx”=”application/vnd.adobe.pdx”\n“.pfx”=”application/x-pkcs12”\n“.pgl”=”application/x-pgl”\n“.pic”=”application/x-pic”\n“.pko”=”application/vnd.ms-pki.pko”\n“.pl”=”application/x-perl”\n“.plg”=”text/html”\n“.pls”=”audio/scpls”\n“.plt”=”application/x-plt”\n“.png”=”image/png”\n“.png”=”application/x-png”\n“.pot”=”application/vnd.ms-powerpoint”\n“.ppa”=”application/vnd.ms-powerpoint”\n“.ppm”=”application/x-ppm”\n“.pps”=”application/vnd.ms-powerpoint”\n“.ppt”=”application/vnd.ms-powerpoint”\n“.ppt”=”application/x-ppt”\n“.pr”=”application/x-pr”\n“.prf”=”application/pics-rules”\n“.prn”=”application/x-prn”\n“.prt”=”application/x-prt”\n“.ps”=”application/x-ps”\n“.ps”=”application/postscript”\n“.ptn”=”application/x-ptn”\n“.pwz”=”application/vnd.ms-powerpoint”\n“.r3t”=”text/vnd.rn-realtext3d”\n“.ra”=”audio/vnd.rn-realaudio”\n“.ram”=”audio/x-pn-realaudio”\n“.ras”=”application/x-ras”\n“.rat”=”application/rat-file”\n“.rdf”=”text/xml”\n“.rec”=”application/vnd.rn-recording”\n“.red”=”application/x-red”\n“.rgb”=”application/x-rgb”\n“.rjs”=”application/vnd.rn-realsystem-rjs”\n“.rjt”=”application/vnd.rn-realsystem-rjt”\n“.rlc”=”application/x-rlc”\n“.rle”=”application/x-rle”\n“.rm”=”application/vnd.rn-realmedia”\n“.rmf”=”application/vnd.adobe.rmf”\n“.rmi”=”audio/mid”\n“.rmj”=”application/vnd.rn-realsystem-rmj”\n“.rmm”=”audio/x-pn-realaudio”\n“.rmp”=”application/vnd.rn-rn_music_package”\n“.rms”=”application/vnd.rn-realmedia-secure”\n“.rmvb”=”application/vnd.rn-realmedia-vbr”\n“.rmx”=”application/vnd.rn-realsystem-rmx”\n“.rnx”=”application/vnd.rn-realplayer”\n“.rp”=”image/vnd.rn-realpix”\n“.rpm”=”audio/x-pn-realaudio-plugin”\n“.rsml”=”application/vnd.rn-rsml”\n“.rt”=”text/vnd.rn-realtext”\n“.rtf”=”application/msword”\n“.rtf”=”application/x-rtf”\n“.rv”=”video/vnd.rn-realvideo”\n“.sam”=”application/x-sam”\n“.sat”=”application/x-sat”\n“.sdp”=”application/sdp”\n“.sdw”=”application/x-sdw”\n“.sit”=”application/x-stuffit”\n“.slb”=”application/x-slb”\n“.sld”=”application/x-sld”\n“.slk”=”drawing/x-slk”\n“.smi”=”application/smil”\n“.smil”=”application/smil”\n“.smk”=”application/x-smk”\n“.snd”=”audio/basic”\n“.sol”=”text/plain”\n“.sor”=”text/plain”\n“.spc”=”application/x-pkcs7-certificates”\n“.spl”=”application/futuresplash”\n“.spp”=”text/xml”\n“.ssm”=”application/streamingmedia”\n“.sst”=”application/vnd.ms-pki.certstore”\n“.stl”=”application/vnd.ms-pki.stl”\n“.stm”=”text/html”\n“.sty”=”application/x-sty”\n“.svg”=”text/xml”\n“.swf”=”application/x-shockwave-flash”\n“.tdf”=”application/x-tdf”\n“.tg4″=”application/x-tg4”\n“.tga”=”application/x-tga”\n“.tif”=”image/tiff”\n“.tif”=”application/x-tif”\n“.tiff”=”image/tiff”\n“.tld”=”text/xml”\n“.top”=”drawing/x-top”\n“.torrent”=”application/x-bittorrent”\n“.tsd”=”text/xml”\n“.txt”=”text/plain”\n“.uin”=”application/x-icq”\n“.uls”=”text/iuls”\n“.vcf”=”text/x-vcard”\n“.vda”=”application/x-vda”\n“.vdx”=”application/vnd.visio”\n“.vml”=”text/xml”\n“.vpg”=”application/x-vpeg005”\n“.vsd”=”application/vnd.visio”\n“.vsd”=”application/x-vsd”\n“.vss”=”application/vnd.visio”\n“.vst”=”application/vnd.visio”\n“.vst”=”application/x-vst”\n“.vsw”=”application/vnd.visio”\n“.vsx”=”application/vnd.visio”\n“.vtx”=”application/vnd.visio”\n“.vxml”=”text/xml”\n“.wav”=”audio/wav”\n“.wax”=”audio/x-ms-wax”\n“.wb1″=”application/x-wb1”\n“.wb2″=”application/x-wb2”\n“.wb3″=”application/x-wb3”\n“.wbmp”=”image/vnd.wap.wbmp”\n“.wiz”=”application/msword”\n“.wk3″=”application/x-wk3”\n“.wk4″=”application/x-wk4”\n“.wkq”=”application/x-wkq”\n“.wks”=”application/x-wks”\n“.wm”=”video/x-ms-wm”\n“.wma”=”audio/x-ms-wma”\n“.wmd”=”application/x-ms-wmd”\n“.wmf”=”application/x-wmf”\n“.wml”=”text/vnd.wap.wml”\n“.wmv”=”video/x-ms-wmv”\n“.wmx”=”video/x-ms-wmx”\n“.wmz”=”application/x-ms-wmz”\n“.wp6″=”application/x-wp6”\n“.wpd”=”application/x-wpd”\n“.wpg”=”application/x-wpg”\n“.wpl”=”application/vnd.ms-wpl”\n“.wq1″=”application/x-wq1”\n“.wr1″=”application/x-wr1”\n“.wri”=”application/x-wri”\n“.wrk”=”application/x-wrk”\n“.ws”=”application/x-ws”\n“.ws2″=”application/x-ws”\n“.wsc”=”text/scriptlet”\n“.wsdl”=”text/xml”\n“.wvx”=”video/x-ms-wvx”\n“.xdp”=”application/vnd.adobe.xdp”\n“.xdr”=”text/xml”\n“.xfd”=”application/vnd.adobe.xfd”\n“.xfdf”=”application/vnd.adobe.xfdf”\n“.xhtml”=”text/html”\n“.xls”=”application/vnd.ms-excel”\n“.xls”=”application/x-xls”\n“.xlw”=”application/x-xlw”\n“.xml”=”text/xml”\n“.xpl”=”audio/scpls”\n“.xq”=”text/xml”\n“.xql”=”text/xml”\n“.xquery”=”text/xml”\n“.xsd”=”text/xml”\n“.xsl”=”text/xml”\n“.xslt”=”text/xml”\n“.xwd”=”application/x-xwd”\n“.x_b”=”application/x-x_b”\n“.x_t”=”application/x-x_t”\n","permalink":"https://blog.zdltech.com/posts/java%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BDcontenttype%E8%AE%BE%E7%BD%AE/","summary":"\u003cp\u003eString filePath=””;\u003c/p\u003e\n\u003cp\u003eFile file=new File(filePath);\u003c/p\u003e\n\u003cp\u003e//解决乱码问题\u003c/p\u003e\n\u003cp\u003eString filename=URLEncoder.encode(file.getName(),”utf-8″);\u003c/p\u003e\n\u003cp\u003e//重置输出流\u003c/p\u003e\n\u003cp\u003eresponse.reset();\u003c/p\u003e\n\u003cp\u003eResponse.AddHeader(“Content-Disposition”, “attachment;filename=”+filename);//设置文件名\u003c/p\u003e\n\u003cp\u003eresponse.addHeader(“Content-Length”,file.length);//设置下载文件大小\u003c/p\u003e\n\u003cp\u003eresponse.setContentType(“application/octet-stream”);//设置文件类型\u003c/p\u003e\n\u003cp\u003eOutputStream toClient=new BufferedOuntputStream( response.getOutputStream() );//获取二进制输出流\u003c/p\u003e\n\u003cp\u003e//读取文件数据\u003c/p\u003e\n\u003cp\u003eInputStream fis=new BufferedInputStream(new FileInputStream(filePath));\u003c/p\u003e\n\u003cp\u003ebyte[] buffer=new byte[file.length()];\u003c/p\u003e\n\u003cp\u003efis.read(buffer);\u003c/p\u003e\n\u003cp\u003efis.close();\u003c/p\u003e\n\u003cp\u003e//输出文件数据\u003c/p\u003e\n\u003cp\u003etoClient.write(buffer);\u003c/p\u003e\n\u003cp\u003etoClient.close();\u003c/p\u003e\n\u003cp\u003e文件类型如下:\u003c/p\u003e\n\u003cp\u003e“.*”=”application/octet-stream”\u003c/p\u003e\n\u003cp\u003e“.001″=”application/x-001”\u003c/p\u003e\n\u003cp\u003e“.301″=”application/x-301”\u003c/p\u003e\n\u003cp\u003e“.323″=”text/h323”\u003c/p\u003e\n\u003cp\u003e“.906″=”application/x-906”\u003c/p\u003e\n\u003cp\u003e“.907″=”drawing/907”\u003c/p\u003e\n\u003cp\u003e“.a11″=”application/x-a11”\u003c/p\u003e\n\u003cp\u003e“.acp”=”audio/x-mei-aac”\u003c/p\u003e\n\u003cp\u003e“.ai”=”application/postscript”\u003c/p\u003e\n\u003cp\u003e“.aif”=”audio/aiff”\u003c/p\u003e\n\u003cp\u003e“.aifc”=”audio/aiff”\u003c/p\u003e\n\u003cp\u003e“.aiff”=”audio/aiff”\u003c/p\u003e\n\u003cp\u003e“.anv”=”application/x-anv”\u003c/p\u003e\n\u003cp\u003e“.asa”=”text/asa”\u003c/p\u003e\n\u003cp\u003e“.asf”=”video/x-ms-asf”\u003c/p\u003e\n\u003cp\u003e“.asp”=”text/asp”\u003c/p\u003e\n\u003cp\u003e“.asx”=”video/x-ms-asf”\u003c/p\u003e\n\u003cp\u003e“.au”=”audio/basic”\u003c/p\u003e\n\u003cp\u003e“.avi”=”video/avi”\u003c/p\u003e\n\u003cp\u003e“.awf”=”application/vnd.adobe.workflow”\u003c/p\u003e\n\u003cp\u003e“.biz”=”text/xml”\u003c/p\u003e\n\u003cp\u003e“.bmp”=”application/x-bmp”\u003c/p\u003e\n\u003cp\u003e“.bot”=”application/x-bot”\u003c/p\u003e\n\u003cp\u003e“.c4t”=”application/x-c4t”\u003c/p\u003e\n\u003cp\u003e“.c90″=”application/x-c90”\u003c/p\u003e\n\u003cp\u003e“.cal”=”application/x-cals”\u003c/p\u003e\n\u003cp\u003e“.cat”=”application/vnd.ms-pki.seccat”\u003c/p\u003e\n\u003cp\u003e“.cdf”=”application/x-netcdf”\u003c/p\u003e\n\u003cp\u003e“.cdr”=”application/x-cdr”\u003c/p\u003e\n\u003cp\u003e“.cel”=”application/x-cel”\u003c/p\u003e\n\u003cp\u003e“.cer”=”application/x-x509-ca-cert”\u003c/p\u003e\n\u003cp\u003e“.cg4″=”application/x-g4”\u003c/p\u003e\n\u003cp\u003e“.cgm”=”application/x-cgm”\u003c/p\u003e\n\u003cp\u003e“.cit”=”application/x-cit”\u003c/p\u003e\n\u003cp\u003e“.class”=”java/*”\u003c/p\u003e\n\u003cp\u003e“.cml”=”text/xml”\u003c/p\u003e\n\u003cp\u003e“.cmp”=”application/x-cmp”\u003c/p\u003e","title":"Java文件下载ContentType设置"},{"content":" SQL标准中有**TRUNCATE TABLE**语句，用来清空表的所有内容。但SQLite不支持这个语句。在SQLite中直接使用“**DELETE FROM TableName**”就可以了。对于大多数DBMS来说，用DELETE不如用TRUNCATE 速度快，因为TRUNCATE 不用访问整个表，不用记录数据的变动。 SQLite虽然不支持TRUNCATE，但它对DELETE做了优化：“When the WHERE is omitted(略去) from a DELETE statement and the table being deleted has no triggers(触发器), SQLite uses an optimization(优化) to erase the entire table content without having to visit each row of the table individually. **This “truncate” optimization makes the delete run much faster**.” 通常在清空表的时候，还需要把自增列归零。在SQLite中定义自增列的方法如下： \u0026lt;div id=\u0026quot;crayon-51c50d9e7aa71\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt; \u0026lt;table class=\u0026quot;crayon-table \u0026quot;\u0026gt; \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;crayon-nums \u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-51c50d9e7aa71-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;CREATE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;TABLE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;e\u0026quot;\u0026gt;TableName \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;INTEGER\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;PRIMARY\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;KEY\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;AUTOINCREMENT\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 当SQLite数据库中包含自增列时，会自动建立一个名为 sqlite_sequence 的表。这个表包含两个列：name和seq。name记录自增列所在的表，seq记录当前序号（下一条记录的编号就是当前序号加1）。如果想把某个自增列的序号归零，只需要修改 sqlite_sequence表就可以了。 \u0026lt;div id=\u0026quot;crayon-51c50d9e7aa8a\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt; \u0026lt;table class=\u0026quot;crayon-table \u0026quot;\u0026gt; \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;crayon-nums \u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-51c50d9e7aa8a-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;UPDATE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;sqlite_sequence\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;SET\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;seq\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;cn\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;WHERE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026amp;#8216;TableName\u0026amp;#8217;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 也可以直接把该记录删掉： \u0026lt;div id=\u0026quot;crayon-51c50d9e7aab0\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt; \u0026lt;table class=\u0026quot;crayon-table \u0026quot;\u0026gt; \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;crayon-nums \u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-51c50d9e7aab0-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;DELETE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;FROM\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;sqlite_sequence\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;WHERE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026amp;#8216;TableName\u0026amp;#8217;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 要想将所有表的自增列都归零，直接清空sqlite_sequence表就可以了： \u0026lt;div id=\u0026quot;crayon-51c50d9e7aac0\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-toolbar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-tools\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-language\u0026quot;\u0026gt;Transact-SQL\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt; \u0026lt;table class=\u0026quot;crayon-table \u0026quot;\u0026gt; \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;crayon-nums \u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-51c50d9e7aac0-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;DELETE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;FROM\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;sqlite_sequence\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; \u0026lt;/div\u0026gt; 来自：http://zhuyanfeng.com/archives/516\n","permalink":"https://blog.zdltech.com/posts/sqlite%E6%B8%85%E7%A9%BA%E8%A1%A8%E5%B9%B6%E5%B0%86%E8%87%AA%E5%A2%9E%E5%88%97%E5%BD%92%E9%9B%B6/","summary":"\u003cdiv class=\"left\"\u003e\n  \u003cdiv class=\"article\"\u003e\n    \u003cdiv class=\"context\"\u003e\n\u003cpre\u003e\u003ccode\u003e    SQL标准中有**TRUNCATE TABLE**语句，用来清空表的所有内容。但SQLite不支持这个语句。在SQLite中直接使用“**DELETE FROM TableName**”就可以了。对于大多数DBMS来说，用DELETE不如用TRUNCATE 速度快，因为TRUNCATE 不用访问整个表，不用记录数据的变动。\n  \n\n  \n  \n\n    SQLite虽然不支持TRUNCATE，但它对DELETE做了优化：“When the WHERE is omitted(略去) from a DELETE statement and the table being deleted has no triggers(触发器), SQLite uses an optimization(优化) to erase the entire table content without having to visit each row of the table individually. **This “truncate” optimization makes the delete run much faster**.”\n  \n\n  \n  \n\n    通常在清空表的时候，还需要把自增列归零。在SQLite中定义自增列的方法如下：\n  \n\n  \n  \u0026lt;div id=\u0026quot;crayon-51c50d9e7aa71\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt;\n      \u0026lt;table class=\u0026quot;crayon-table \u0026quot;\u0026gt;\n        \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt;\n          \u0026lt;td class=\u0026quot;crayon-nums \u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt;\n              \u0026lt;div class=\u0026quot;crayon-num\u0026quot;\u0026gt;\n                1\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n          \n          \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt;\n              \u0026lt;div id=\u0026quot;crayon-51c50d9e7aa71-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt;\n                \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;CREATE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;TABLE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;e\u0026quot;\u0026gt;TableName \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;INTEGER\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;PRIMARY\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;KEY\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;AUTOINCREMENT\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n        \u0026lt;/tr\u0026gt;\n      \u0026lt;/table\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n\n    当SQLite数据库中包含自增列时，会自动建立一个名为 sqlite_sequence 的表。这个表包含两个列：name和seq。name记录自增列所在的表，seq记录当前序号（下一条记录的编号就是当前序号加1）。如果想把某个自增列的序号归零，只需要修改 sqlite_sequence表就可以了。\n  \n\n  \n  \u0026lt;div id=\u0026quot;crayon-51c50d9e7aa8a\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt;\n      \u0026lt;table class=\u0026quot;crayon-table \u0026quot;\u0026gt;\n        \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt;\n          \u0026lt;td class=\u0026quot;crayon-nums \u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt;\n              \u0026lt;div class=\u0026quot;crayon-num\u0026quot;\u0026gt;\n                1\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n          \n          \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt;\n              \u0026lt;div id=\u0026quot;crayon-51c50d9e7aa8a-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt;\n                \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;UPDATE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;sqlite_sequence\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;SET\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;seq\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;cn\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;WHERE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026amp;#8216;TableName\u0026amp;#8217;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n        \u0026lt;/tr\u0026gt;\n      \u0026lt;/table\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n\n    也可以直接把该记录删掉：\n  \n\n  \n  \u0026lt;div id=\u0026quot;crayon-51c50d9e7aab0\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt;\n      \u0026lt;table class=\u0026quot;crayon-table \u0026quot;\u0026gt;\n        \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt;\n          \u0026lt;td class=\u0026quot;crayon-nums \u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt;\n              \u0026lt;div class=\u0026quot;crayon-num\u0026quot;\u0026gt;\n                1\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n          \n          \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt;\n              \u0026lt;div id=\u0026quot;crayon-51c50d9e7aab0-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt;\n                \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;DELETE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;FROM\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;sqlite_sequence\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;WHERE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026amp;#8216;TableName\u0026amp;#8217;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n        \u0026lt;/tr\u0026gt;\n      \u0026lt;/table\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n\n    要想将所有表的自增列都归零，直接清空sqlite_sequence表就可以了：\n  \n\n  \n  \u0026lt;div id=\u0026quot;crayon-51c50d9e7aac0\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;crayon-toolbar\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;crayon-tools\u0026quot;\u0026gt;\n        \u0026lt;span class=\u0026quot;crayon-language\u0026quot;\u0026gt;Transact-SQL\u0026lt;/span\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt;\n      \u0026lt;table class=\u0026quot;crayon-table \u0026quot;\u0026gt;\n        \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt;\n          \u0026lt;td class=\u0026quot;crayon-nums \u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt;\n              \u0026lt;div class=\u0026quot;crayon-num\u0026quot;\u0026gt;\n                1\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n          \n          \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt;\n              \u0026lt;div id=\u0026quot;crayon-51c50d9e7aac0-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt;\n                \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;DELETE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;FROM\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;i\u0026quot;\u0026gt;sqlite_sequence\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n        \u0026lt;/tr\u0026gt;\n      \u0026lt;/table\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n\n    \u0026amp;nbsp;\n  \n\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e来自：http://zhuyanfeng.com/archives/516\u003c/p\u003e","title":"SQLite清空表并将自增列归零"},{"content":"JFinal官方的教程都是使用Eclipse进行开发的，而使用Intellij IDEA来做开发，不少地方和Eclipse区别还是很大的。\n本文参考了网上不少文章，主要沿用了网友的内容，一步一步做了尝试后记录下来，感谢万能的互联网。\n分别做了两个Module，分别使用Jetty和tomcat来运行。均测试均可正常跑起来。\n本文看起来虽然很长，但实际上步骤不多，为便于初学者了解Intellij IDEA,所以细节写的非常完善，每一步都有截图。\n本文使用的开发环境是Intellij IDEA 14.1.4版本。JFinal是2.0版。\n请大家注意：不是Intellij IDEA配置繁琐，而是我为了便于入门初学者少走弯路，写得非常细，凡是每一个出现的界面，我都截了图，而且文章里面包含了jetty和tomcat的两个项目。所以看起来比Eclipse好像复杂，其实不是的。简单地说，就五个步骤：建项目(类比于Eclipse的Workspace)，建模块(类比于Eclipse的Project)，引入Jar包，建Artifacts，写代码。就可以运行了。\n一、新建项目 新建一个项目，可以是空项目，也可以是连模块一起建的项目，本文为了演示Jetty和tomcat均能运行的效果，所以先建一个空项目，再分别建两个不同的module，以便区分。\n如果项目和模块一起建，可以把Web Application选上，其他的默认就行。\n因为我们要分别测试jetty和tomcat的效果，要建两个模块，所以先建一个空项目。\n点击“Next”进入下一步。\n输入项目名称和项目所在目录，点击“Finish”即可。\n二、项目参数配置 1．新建Module 如果新建一个空项目，会立即出来一个Project Structure的配置窗口。如果是连模块一起建的，请从【File】-【Project Structure】中选择，对项目参数进行配置。\n首先指定项目所使用的JDK版本：\n如果要单独为每个模块指定JDK版本，也可以在模块中进行配置(要在下面的新建模块步骤之后才能操作)。\n下面开始新建模块。\n选择Modules，准备新建Module。\n2．建Jetty运行模块 （1）新建模块 我们先新建一个module，用于使用jetty来运行。\n选上“Web Application”后，点击Next。\n在出现的窗口中，直接在Module name中输入想要新建的module名字，下面的Content root和Module file location中会自动把路径填进去。\n为了便于区分，我们把jetty运行的module命名为jf_jt。\n点击“Finish”。\n此时会出现如下界面；\n选择“Paths”选项卡，选中“Use module compile output path”后，在“Output path”和“Test output path”中均写上类输出的路径。按照一般常规写法，我把这个目录放在module下，web\\WEB-INF路径下的classes目录下。\n点击“Apply”，把配置启用起来；\n（2）导入类库 然后点击左侧的Libraries选项卡；\n在做这一步之前，我们先要把需要的类库分别拷贝到我们建立的类库目录中。\n这个模块是需要jetty来运行的，所以需要JFinal的类库和jetty的类库，事先准备好这几个类库。\nJfinal-2.0-all目录下有需要的类库文件。\n“jfinal-2.0-bin.jar”或“jfinal-2.0-bin-with-src.jar”是jfinal本身的jar包，任选一个都可以，为了方便调试，可以选择“jfinal-2.0-bin-with-src.jar”。\n目前这个项目是为了Jetty而建的，所以要把“jetty-server-8.1.8.jar”也要包含进去。\n在电脑中找到项目目录，进入到Module路径中，新建文件夹；\n新建一个classes目录(上文新建module时设置的输出目录)和lib目录；\n把“jfinal-2.0-bin.jar”和“jetty-server-8.1.8.jar”两个文件拷贝到刚才新建的lib目录下(注意，使用jfinal-2.0-bin.jar和使用jfinal-2.0-bin-src.jar，后续界面会略有不同，但差异不大)。\n回到Intellij IDEA配置界面。\n选择左侧的Libraries选项卡，点击中间的“+”号，新增java类库。\n在弹出的窗口中，找到lib目录并选中刚才拷进去的“jfinal-2.0-bin-with-src.jar”包。\n点击“OK”。\n此时会让你选择这些类库将用于哪些module（如果你在项目中有多个module,在此均会列出来）在这里，我们选择这些类库用于“jf_jt”module。\n此时类库就会出现在列表里。\n点击“Apply”，保存配置。\n再重复上述步骤，导入jetty的jar包。导入后如下图所示：\n再选择左侧的“Artifacts”选项卡，此时会出现空白的Artifacts界面。\n或出现已经有一个“jf_ft.war exploded”的界面(如果关闭后重新打开Project Structure界面就会出现)。建议：最好在导入类库后，点击“OK”，关闭本界面后，重新通过【File】-【Project Structure】菜单打开本界面后，选“Artifacts”选项卡进行操作，避免重复建立jf-ft.war exploded。\n重新打开界面，并选择Artifacts选项卡后，界面会如下图所示：\n此时窗口下部会出现一条告警信息。如上图红框部分。\n此时点击“Fix…”按键，选择“Add‘jfinal-2.0-bin-with-src’to the artifact”，即可。\n设置好的界面如下图所示（把Build on make选上）；\n点击“Apply”按钮保存设置；\n再点击“+”号，添加一个“Web Application：Archive”，此时选“For ‘jfjt:war exploded’”；\n建好后，界面如下图所示(如果还有告警提示，按照上面步骤，点击“Fix”按键把类库添加进Artifact中);\n选中“Build on make”选项后，点“OK”按键保存并退出配置界面。\n至此Jetty运行的模块已经建好。\n3．建Tomcat运行模块 （1）新建模块 点击【File】-【New】-【Module】：\n选上“Web Application”，并点“Next”：\n填上Module的名称，这里起名为jf-tc,然后点击“Finish”：\n此时的界面是这样：\n（2）导入类库 现在可以直接在IDEA的界面建目录classes和lib。\n鼠标右键点击[jf-tc]-[web]-[WEB-INF]目录，在出来的菜单里点击【New】-【Directory】。\n输入classes和lib目录的名称：\n建好目录后的模块如下所示:\n点击【File】-【Project Structure】进入项目，步骤和上一个模块建立的时候一样，此时界面里已经有两个模块，选中jf-tc模块后，设置Path：\n接下来再设置Libraries，在此之前，需要把jfinal-2.0-bin-with-src.jar拷贝到lib目录下。\n在“Libraries”选项卡中点“+”号，选“Java”：\n这里只需要导入一个jar包即可(记住，目录不要选错，要选刚才拷进去的jf-tc模块下lib目录的jfinal-2.0-bin-with-src.jar文件)。\n注意：选中目标Jar包后，选模块的时候，一定不要选错。\n点“OK”后，来到Artifacts选项卡：\n添加一个Artifact\n记住不要选错模块。\n添加成功后，记住Fix掉警告信息(新加的两个Artifact都要fix)。然后都选上“Build on make”选项。\n至此，两个模块都建好，可以开始真正的编写代码之旅了。\n三、修改运行配置 1．创建Jetty运行配置 点击【run】-【Edit Configurations】菜单：\n出现下面的界面，并点击左上角的“+”号，选“Application”选项：\n设置一个名称，在这里命名为“jf-jt-jetty”。\n设置Main Class(在出来的“Choose Main Class”窗口里直接输入com.jfinal……,下面会直接把class列出来，不用搜索和查找).\n设好Main Class以后，设置“working directory”和“Use classpath of module”两项，如下图所示：\n点击“OK”，设置完成。\n2．创建tomcat运行配置 点击【run】-【Edit Configurations】菜单：\n选择【Tomcat Server】-【local】菜单：\n配置Tomcat参数，起一个名字，然后点击最右边的“+”号，增加一个Artifact：\n在出来的窗口中，选“jf-tc:war exploded”即exploded的那个war。\n点击“OK”后，就配置完成了。\n注意，这个Application context里填写的路径，是你调试或运行时出现的url的后缀，比如，如果你在此设置“/”，则最后是通过“http://localhost:8080/”运行和调试；假如你在此设置为“/test”，则最后是通过“http://localhost:8080/test”进行访问和调试。\n四、添加源文件 现在可以添加源文件了。我们可以分别在两个项目下建立源文件(建源文件的过程不管上面jetty和tomcat项目都是一样的，我们以tomcat项目来举例):\n我们在src路径下，添加一个package名称为com.demo.\n再在这个package下建三个类：\n内容如下：\n另外再建两个类HelloController.java和Indexcontroller.java,内容分别如下：\n编辑模块下，web\\WEB-INF路径下的web.xml文件，内容如下：\n至此，tomcat部分已经完成，按同样的方式配置jetty部分(也可以直接把package和web.xml文件直接拷贝过去)。\n五、运行项目 1．在jetty下运行 点击【Run】-【Run】菜单：\n页面中间会出现让你选择运行哪个模块的选项，我们选择jetty的模块。\n此时IDEA界面下半部会显示jetty的启动信息，如下：\n说明jetty已经正常启动了。\n此时需要手动打开浏览器页面，输入“http://localhost”，就会出现Index控制器对应的页面。(注意，如果你的电脑上装了别的Web服务器，注意端口冲突)。\nIDEA下部窗口会出现相应的调试信息。\n输入http://localhost/hello,会出现hello控制器对应的页面。\n2．在tomcat下运行 同样点击【Run】-【Run】菜单，在页面中心的弹出菜单选“jf-tc-tomcat”。\nIDEA界面下半部分会显示启动tomcat过程中的日志，等待tomcat启动后，会自动调用本地浏览器窗口，把index页面内容显示出来。\n输入http://loaclhost:8080/hello\n出来hello控制器中的内容：\n六、项目实际部署 Intellij IDEA打包的war文件位于项目根目录的out目录下。\n把此文件拷贝到tomcat的webapps目录下(可以改名，例如改名为test.war),无需做任何修改，启动tomcat后，直接访问：http://ip:8080/test/即可正常访问页面。\n要更改输出目录，请在【File】-【Project Structure】-【Project】标签页修改即可。\n大家可以加入QQ群进行交流【IntelliJ IDEA交流群 460969110】\n转自：http://my.oschina.net/chixn/blog/471755\n","permalink":"https://blog.zdltech.com/posts/intellij-idea-14-1%E4%B8%8Ajfinal%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E6%89%8B%E5%86%8C/","summary":"\u003cp\u003eJFinal官方的教程都是使用Eclipse进行开发的，而使用Intellij IDEA来做开发，不少地方和Eclipse区别还是很大的。\u003c/p\u003e\n\u003cp\u003e本文参考了网上不少文章，主要沿用了网友的内容，一步一步做了尝试后记录下来，感谢万能的互联网。\u003c/p\u003e\n\u003cp\u003e分别做了两个Module，分别使用Jetty和tomcat来运行。均测试均可正常跑起来。\u003c/p\u003e\n\u003cp\u003e本文看起来虽然很长，但实际上步骤不多，为便于初学者了解Intellij IDEA,所以细节写的非常完善，每一步都有截图。\u003c/p\u003e\n\u003cp\u003e本文使用的开发环境是Intellij IDEA 14.1.4版本。JFinal是2.0版。\u003c/p\u003e\n\u003cp\u003e请大家注意：不是Intellij IDEA配置繁琐，而是我为了便于入门初学者少走弯路，写得非常细，凡是每一个出现的界面，我都截了图，而且文章里面包含了jetty和tomcat的两个项目。所以看起来比Eclipse好像复杂，其实不是的。简单地说，就五个步骤：建项目(类比于Eclipse的Workspace)，建模块(类比于Eclipse的Project)，引入Jar包，建Artifacts，写代码。就可以运行了。\u003c/p\u003e\n\u003ch3 id=\"一新建项目\"\u003e\u003ca rel=\"nofollow\" name=\"_Toc17587\"\u003e\u003c/a\u003e一、新建项目\u003c/h3\u003e\n\u003cp\u003e新建一个项目，可以是空项目，也可以是连模块一起建的项目，本文为了演示Jetty和tomcat均能运行的效果，所以先建一个空项目，再分别建两个不同的module，以便区分。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201506/28235100_3rgx.jpg\"\u003e\u003cimg alt=\"wpsF73C.tmp\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201506/28235100_vmPq.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e如果项目和模块一起建，可以把Web Application选上，其他的默认就行。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201506/28235101_AGio.jpg\"\u003e\u003cimg alt=\"wpsF76C.tmp\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201506/28235101_qRog.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e因为我们要分别测试jetty和tomcat的效果，要建两个模块，所以先建一个空项目。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201506/28235102_J9q3.jpg\"\u003e\u003cimg alt=\"wpsF77D.tmp\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201506/28235103_e5lc.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e点击“Next”进入下一步。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201506/28235104_F0nO.jpg\"\u003e\u003cimg alt=\"wpsF79D.tmp\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201506/28235104_gse8.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e输入项目名称和项目所在目录，点击“Finish”即可。\u003c/p\u003e\n\u003ch3 id=\"二项目参数配置\"\u003e\u003ca rel=\"nofollow\" name=\"_Toc29753\"\u003e\u003c/a\u003e二、项目参数配置\u003c/h3\u003e\n\u003ch4 id=\"1新建module\"\u003e\u003ca rel=\"nofollow\" name=\"_Toc4455\"\u003e\u003c/a\u003e1．新建Module\u003c/h4\u003e\n\u003cp\u003e如果新建一个空项目，会立即出来一个Project Structure的配置窗口。如果是连模块一起建的，请从【File】-【Project Structure】中选择，对项目参数进行配置。\u003c/p\u003e\n\u003cp\u003e首先指定项目所使用的JDK版本：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://static.oschina.net/uploads/space/2015/0629/172633_oAbn_97615.png\"\u003e\u003c/p\u003e\n\u003cp\u003e如果要单独为每个模块指定JDK版本，也可以在模块中进行配置(要在下面的新建模块步骤之后才能操作)。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://static.oschina.net/uploads/space/2015/0629/172735_2yEM_97615.png\"\u003e\u003c/p\u003e\n\u003cp\u003e下面开始新建模块。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201506/28235105_RFMm.jpg\"\u003e\u003cimg alt=\"wpsF7BD.tmp\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201506/28235105_a3bo.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e选择Modules，准备新建Module。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201506/28235105_iZhm.jpg\"\u003e\u003cimg alt=\"wpsF7CE.tmp\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201506/28235106_b2IM.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch4 id=\"2建jetty运行模块\"\u003e\u003ca rel=\"nofollow\" name=\"_Toc18639\"\u003e\u003c/a\u003e2．建Jetty运行模块\u003c/h4\u003e\n\u003ch5 id=\"1新建模块\"\u003e\u003ca rel=\"nofollow\" name=\"_Toc32556\"\u003e\u003c/a\u003e（1）新建模块\u003c/h5\u003e\n\u003cp\u003e我们先新建一个module，用于使用jetty来运行。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201506/28235112_EKdy.jpg\"\u003e\u003cimg alt=\"wpsF7DE.tmp\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201506/28235112_e6j6.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e选上“Web Application”后，点击Next。\u003c/p\u003e\n\u003cp\u003e在出现的窗口中，直接在Module name中输入想要新建的module名字，下面的Content root和Module file location中会自动把路径填进去。\u003c/p\u003e\n\u003cp\u003e为了便于区分，我们把jetty运行的module命名为jf_jt。\u003c/p\u003e\n\u003cp\u003e点击“Finish”。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201506/28235113_xIxo.jpg\"\u003e\u003cimg alt=\"wpsF81E.tmp\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201506/28235113_BnoA.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e此时会出现如下界面；\u003c/p\u003e\n\u003cp\u003e选择“Paths”选项卡，选中“Use module compile output path”后，在“Output path”和“Test output path”中均写上类输出的路径。按照一般常规写法，我把这个目录放在module下，web\\WEB-INF路径下的classes目录下。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201506/28235114_t5IN.jpg\"\u003e\u003cimg alt=\"wpsF83E.tmp\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201506/28235115_2IQs.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e点击“Apply”，把配置启用起来；\u003c/p\u003e\n\u003ch5 id=\"2导入类库\"\u003e\u003ca rel=\"nofollow\" name=\"_Toc27141\"\u003e\u003c/a\u003e（2）导入类库\u003c/h5\u003e\n\u003cp\u003e然后点击左侧的Libraries选项卡；\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201506/28235115_bT0F.jpg\"\u003e\u003cimg alt=\"wpsF8AC.tmp\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201506/28235116_R8z6.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e在做这一步之前，我们先要把需要的类库分别拷贝到我们建立的类库目录中。\u003c/p\u003e\n\u003cp\u003e这个模块是需要jetty来运行的，所以需要JFinal的类库和jetty的类库，事先准备好这几个类库。\u003c/p\u003e\n\u003cp\u003eJfinal-2.0-all目录下有需要的类库文件。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201506/28235117_pBti.jpg\"\u003e\u003cimg alt=\"wpsF8DC.tmp\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201506/28235118_5V4U.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e“jfinal-2.0-bin.jar”或“jfinal-2.0-bin-with-src.jar”是jfinal本身的jar包，任选一个都可以，为了方便调试，可以选择“jfinal-2.0-bin-with-src.jar”。\u003c/p\u003e\n\u003cp\u003e目前这个项目是为了Jetty而建的，所以要把“jetty-server-8.1.8.jar”也要包含进去。\u003c/p\u003e\n\u003cp\u003e     在电脑中找到项目目录，进入到Module路径中，新建文件夹；\u003c/p\u003e","title":"IntelliJ IDEA 14.1上JFinal开发环境搭建手册"},{"content":"下面是一个android HttpsURLConnection忽略Https证书是否正确的Https请求工具类，不需要验证服务器端证书是否正确\nimport Java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Map; import java.util.Map.Entry; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; /** * 忽略Https证书是否正确的Https Post请求工具类 * \u0026amp;lt;p/\u0026amp;gt; * created by OuyangPeng on 2016/1/17. */ public class HttpUtil { private static final String DEFAULT_CHARSET = \u0026#34;UTF-8\u0026#34;; // 默认字符集 private static final String _GET = \u0026#34;GET\u0026#34;; // GET private static final String _POST = \u0026#34;POST\u0026#34;;// POST /** * 初始化http请求参数 */ private static HttpURLConnection initHttp(String url, String method, Map\u0026amp;lt;String, String\u0026amp;gt; headers) throws IOException { URL _url = new URL(url); HttpURLConnection http = (HttpURLConnection) _url.openConnection(); // 连接超时 http.setConnectTimeout(25000); // 读取超时 --服务器响应比较慢，增大时间 http.setReadTimeout(25000); http.setRequestMethod(method); http.setRequestProperty(\u0026#34;Content-Type\u0026#34;, \u0026#34;application/x-www-form-urlencoded\u0026#34;); http.setRequestProperty(\u0026#34;User-Agent\u0026#34;, \u0026#34;Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) [chrome](http://www.07net01.com/tags-chrome-0.html)/33.0.1750.146 Safari/537.36\u0026#34;); if (null != headers \u0026amp;\u0026amp; !headers.isEmpty()) { for (Entry\u0026amp;lt;String, String\u0026amp;gt; entry : headers.entrySet()) { http.setRequestProperty(entry.getKey(), entry.getValue()); } } http.setDoOutput(true); http.setDoInput(true); http.connect(); return http; } /** * 初始化http请求参数 */ private static HttpsURLConnection initHttps(String url, String method, Map\u0026amp;lt;String, String\u0026amp;gt; headers) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException { TrustManager[] tm = {new MyX509TrustManager()}; SSLContext sslContext = SSLContext.getInstance(\u0026#34;SSL\u0026#34;); sslContext.init(null, tm, new java.security.SecureRandom()); // 从上述SSLContext对象中得到SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL _url = new URL(url); HttpsURLConnection http = (HttpsURLConnection) _url.openConnection(); // 设置域名校验 http.setHostnameVerifier(new TrustAnyHostnameVerifier()); http.setSSLSocketFactory(ssf); // 连接超时 http.setConnectTimeout(25000); // 读取超时 --服务器响应比较慢，增大时间 http.setReadTimeout(25000); http.setRequestMethod(method); http.setRequestProperty(\u0026#34;Content-Type\u0026#34;, \u0026#34;application/x-www-form-urlencoded\u0026#34;); http.setRequestProperty(\u0026#34;User-Agent\u0026#34;, \u0026#34;Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36\u0026#34;); if (null != headers \u0026amp;\u0026amp; !headers.isEmpty()) { for (Entry\u0026amp;lt;String, String\u0026amp;gt; entry : headers.entrySet()) { http.setRequestProperty(entry.getKey(), entry.getValue()); } } http.setDoOutput(true); http.setDoInput(true); http.connect(); return http; } /** * get请求 */ public static String get(String url, Map\u0026amp;lt;String, String\u0026amp;gt; params, Map\u0026amp;lt;String, String\u0026amp;gt; headers) { StringBuffer bufferRes = null; try { HttpURLConnection http = null; if (isHttps(url)) { http = initHttps(initParams(url, params), _GET, headers); } else { http = initHttp(initParams(url, params), _GET, headers); } InputStream in = http.getInputStream(); BufferedReader read = new BufferedReader(new InputStreamReader(in, DEFAULT_CHARSET)); String valueString = null; bufferRes = new StringBuffer(); while ((valueString = read.readLine()) != null) { bufferRes.append(valueString); } in.close(); if (http != null) { http.disconnect();// 关闭连接 } return bufferRes.toString(); } catch (Exception e) { e.printStackTrace(); return null; } } /** * get请求 */ public static String get(String url) { return get(url, null); } /** * get请求 */ public static String get(String url, Map\u0026amp;lt;String, String\u0026amp;gt; params) { return get(url, params, null); } /** * post请求 */ public static String post(String url, String params, Map\u0026amp;lt;String, String\u0026amp;gt; headers) { StringBuffer bufferRes = null; try { HttpURLConnection http = null; if (isHttps(url)) { http = initHttps(url, _POST, headers); } else { http = initHttp(url, _POST, headers); } OutputStream out = http.getOutputStream(); out.write(params.getBytes(DEFAULT_CHARSET)); out.flush(); out.close(); InputStream in = http.getInputStream(); BufferedReader read = new BufferedReader(new InputStreamReader(in, DEFAULT_CHARSET)); String valueString = null; bufferRes = new StringBuffer(); while ((valueString = read.readLine()) != null) { bufferRes.append(valueString); } in.close(); if (http != null) { http.disconnect();// 关闭连接 } return bufferRes.toString(); } catch (Exception e) { e.printStackTrace(); return null; } } /** * post请求 */ public static String post(String url, Map\u0026amp;lt;String, String\u0026amp;gt; params) { return post(url, map2Url(params), null); } /** * post请求 */ public static String post(String url, Map\u0026amp;lt;String, String\u0026amp;gt; params, Map\u0026amp;lt;String, String\u0026amp;gt; headers) { return post(url, map2Url(params), headers); } /** * 初始化参数 */ public static String initParams(String url, Map\u0026amp;lt;String, String\u0026amp;gt; params) { if (null == params || params.isEmpty()) { return url; } StringBuilder sb = new StringBuilder(url); if (url.indexOf(\u0026#34;?\u0026#34;) == -1) { sb.append(\u0026#34;?\u0026#34;); } sb.append(map2Url(params)); return sb.toString(); } /** * map转url参数 */ public static String map2Url(Map\u0026amp;lt;String, String\u0026amp;gt; paramToMap) { if (null == paramToMap || paramToMap.isEmpty()) { return null; } StringBuffer url = new StringBuffer(); boolean isfist = true; for (Entry\u0026amp;lt;String, String\u0026amp;gt; entry : paramToMap.entrySet()) { if (isfist) { isfist = false; } else { url.append(\u0026#34;\u0026amp;\u0026#34;); } url.append(entry.getKey()).append(\u0026#34;=\u0026#34;); String value = http://blog.csdn.net/ouyang_peng/article/details/entry.getValue(); if (null == value || \u0026#34;\u0026#34;.equals(value.trim())) { try { url.append(URLEncoder.encode(value, DEFAULT_CHARSET)); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } return url.toString(); } /** * 检测是否https */ private static boolean isHttps(String url) { return url.startsWith(\u0026#34;https\u0026#34;); } /** * 不进行主机名确认 */ private static class TrustAnyHostnameVerifier implements HostnameVerifier { public boolean verify(String hostname, SSLSession session) { return true; } } /** * 信任所有主机 对于任何证书都不做SSL检测 * 安全验证机制，而Android采用的是X509验证 */ private static class MyX509TrustManager implements X509TrustManager { public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } } } 可以参考以下几篇文章：\nhttp://www.blogjava.net/stevenjohn/archive/2012/08/16/385569.html\nhttp://blog.csdn.net/sunny243788557/article/details/38874153\nhttp://blog.csdn.net/liangweiwei130/article/details/8845024\nhttp://www.xuebuyuan.com/1788389.html\n","permalink":"https://blog.zdltech.com/posts/%E6%88%91%E7%9A%84android%E8%BF%9B%E9%98%B6%E4%B9%8B%E6%97%85-android%E5%85%B3%E4%BA%8Ehttpsurlconnection%E4%B8%80%E4%B8%AA%E5%BF%BD%E7%95%A5https%E8%AF%81%E4%B9%A6%E6%98%AF%E5%90%A6%E6%AD%A3/","summary":"\u003cp\u003e下面是一个android HttpsURLConnection忽略Https证书是否正确的Https请求工具类，不需要验证服务器端证书是否正确\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport Java.io.BufferedReader;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.io.IOException;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.io.InputStream;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.io.InputStreamReader;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.io.OutputStream;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.io.UnsupportedEncodingException;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.net.HttpURLConnection;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.net.URL;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.net.URLEncoder;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.KeyManagementException;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.NoSuchAlgorithmException;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.NoSuchProviderException;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.cert.CertificateException;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.security.cert.X509Certificate;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.util.Map;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java.util.Map.Entry;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport javax.net.ssl.HostnameVerifier;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport javax.net.ssl.HttpsURLConnection;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport javax.net.ssl.SSLContext;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport javax.net.ssl.SSLSession;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport javax.net.ssl.SSLSocketFactory;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport javax.net.ssl.TrustManager;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport javax.net.ssl.X509TrustManager;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e * 忽略Https证书是否正确的Https Post请求工具类\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e * \u0026amp;lt;p/\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e * created by OuyangPeng on 2016/1/17.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic class HttpUtil {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private static final String DEFAULT_CHARSET = \u0026#34;UTF-8\u0026#34;; // 默认字符集\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private static final String _GET = \u0026#34;GET\u0026#34;; // GET\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private static final String _POST = \u0026#34;POST\u0026#34;;// POST\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * 初始化http请求参数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private static HttpURLConnection initHttp(String url, String method, Map\u0026amp;lt;String, String\u0026amp;gt; headers)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            throws IOException {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        URL _url = new URL(url);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        HttpURLConnection http = (HttpURLConnection) _url.openConnection();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        // 连接超时\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setConnectTimeout(25000);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        // 读取超时 --服务器响应比较慢，增大时间\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setReadTimeout(25000);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setRequestMethod(method);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setRequestProperty(\u0026#34;Content-Type\u0026#34;, \u0026#34;application/x-www-form-urlencoded\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setRequestProperty(\u0026#34;User-Agent\u0026#34;,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026#34;Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) [chrome](http://www.07net01.com/tags-chrome-0.html)/33.0.1750.146 Safari/537.36\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        if (null != headers \u0026amp;\u0026amp; !headers.isEmpty()) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            for (Entry\u0026amp;lt;String, String\u0026amp;gt; entry : headers.entrySet()) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                http.setRequestProperty(entry.getKey(), entry.getValue());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setDoOutput(true);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setDoInput(true);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.connect();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return http;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * 初始化http请求参数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private static HttpsURLConnection initHttps(String url, String method, Map\u0026amp;lt;String, String\u0026amp;gt; headers)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        TrustManager[] tm = {new MyX509TrustManager()};\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        SSLContext sslContext = SSLContext.getInstance(\u0026#34;SSL\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        sslContext.init(null, tm, new java.security.SecureRandom());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        // 从上述SSLContext对象中得到SSLSocketFactory对象  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        SSLSocketFactory ssf = sslContext.getSocketFactory();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        URL _url = new URL(url);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        HttpsURLConnection http = (HttpsURLConnection) _url.openConnection();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        // 设置域名校验\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setHostnameVerifier(new TrustAnyHostnameVerifier());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setSSLSocketFactory(ssf);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        // 连接超时\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setConnectTimeout(25000);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        // 读取超时 --服务器响应比较慢，增大时间\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setReadTimeout(25000);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setRequestMethod(method);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setRequestProperty(\u0026#34;Content-Type\u0026#34;, \u0026#34;application/x-www-form-urlencoded\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setRequestProperty(\u0026#34;User-Agent\u0026#34;,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026#34;Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        if (null != headers \u0026amp;\u0026amp; !headers.isEmpty()) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            for (Entry\u0026amp;lt;String, String\u0026amp;gt; entry : headers.entrySet()) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                http.setRequestProperty(entry.getKey(), entry.getValue());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setDoOutput(true);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.setDoInput(true);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        http.connect();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return http;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * get请求\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static String get(String url, Map\u0026amp;lt;String, String\u0026amp;gt; params, Map\u0026amp;lt;String, String\u0026amp;gt; headers) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        StringBuffer bufferRes = null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        try {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            HttpURLConnection http = null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            if (isHttps(url)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                http = initHttps(initParams(url, params), _GET, headers);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            } else {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                http = initHttp(initParams(url, params), _GET, headers);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            InputStream in = http.getInputStream();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            BufferedReader read = new BufferedReader(new InputStreamReader(in, DEFAULT_CHARSET));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            String valueString = null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            bufferRes = new StringBuffer();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            while ((valueString = read.readLine()) != null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                bufferRes.append(valueString);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            in.close();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            if (http != null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                http.disconnect();// 关闭连接\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            return bufferRes.toString();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } catch (Exception e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            e.printStackTrace();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            return null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * get请求\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static String get(String url) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return get(url, null);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * get请求\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static String get(String url, Map\u0026amp;lt;String, String\u0026amp;gt; params) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return get(url, params, null);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * post请求\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static String post(String url, String params, Map\u0026amp;lt;String, String\u0026amp;gt; headers) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        StringBuffer bufferRes = null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        try {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            HttpURLConnection http = null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            if (isHttps(url)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                http = initHttps(url, _POST, headers);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            } else {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                http = initHttp(url, _POST, headers);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            OutputStream out = http.getOutputStream();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            out.write(params.getBytes(DEFAULT_CHARSET));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            out.flush();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            out.close();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            InputStream in = http.getInputStream();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            BufferedReader read = new BufferedReader(new InputStreamReader(in, DEFAULT_CHARSET));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            String valueString = null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            bufferRes = new StringBuffer();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            while ((valueString = read.readLine()) != null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                bufferRes.append(valueString);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            in.close();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            if (http != null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                http.disconnect();// 关闭连接\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            return bufferRes.toString();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } catch (Exception e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            e.printStackTrace();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            return null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * post请求\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static String post(String url, Map\u0026amp;lt;String, String\u0026amp;gt; params) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return post(url, map2Url(params), null);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * post请求\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static String post(String url, Map\u0026amp;lt;String, String\u0026amp;gt; params, Map\u0026amp;lt;String, String\u0026amp;gt; headers) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return post(url, map2Url(params), headers);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * 初始化参数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static String initParams(String url, Map\u0026amp;lt;String, String\u0026amp;gt; params) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        if (null == params || params.isEmpty()) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            return url;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        StringBuilder sb = new StringBuilder(url);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        if (url.indexOf(\u0026#34;?\u0026#34;) == -1) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            sb.append(\u0026#34;?\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        sb.append(map2Url(params));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return sb.toString();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * map转url参数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public static String map2Url(Map\u0026amp;lt;String, String\u0026amp;gt; paramToMap) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        if (null == paramToMap || paramToMap.isEmpty()) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            return null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        StringBuffer url = new StringBuffer();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        boolean isfist = true;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        for (Entry\u0026amp;lt;String, String\u0026amp;gt; entry : paramToMap.entrySet()) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            if (isfist) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                isfist = false;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            } else {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                url.append(\u0026#34;\u0026amp;\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            url.append(entry.getKey()).append(\u0026#34;=\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            String value = http://blog.csdn.net/ouyang_peng/article/details/entry.getValue();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            if (null == value || \u0026#34;\u0026#34;.equals(value.trim())) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                try {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    url.append(URLEncoder.encode(value, DEFAULT_CHARSET));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                } catch (UnsupportedEncodingException e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    e.printStackTrace();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return url.toString();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * 检测是否https\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private static boolean isHttps(String url) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return url.startsWith(\u0026#34;https\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * 不进行主机名确认\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private static class TrustAnyHostnameVerifier implements HostnameVerifier {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        public boolean verify(String hostname, SSLSession session) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            return true;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * 信任所有主机 对于任何证书都不做SSL检测\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * 安全验证机制，而Android采用的是X509验证\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private static class MyX509TrustManager implements X509TrustManager {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        public X509Certificate[] getAcceptedIssuers() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            return null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e \u003c/p\u003e","title":"我的Android进阶之旅——\u003eAndroid关于HttpsURLConnection一个忽略Https证书是否正确的Https请求工具类"},{"content":" https://github.com/JakeWharton/butterknife\n最近使用的新版的ButterKnife，跟之前有点不一样的地方。记录一下!\n导入依赖项：Project Structure→app→Dependencies→add→Library Dependence然后搜索ButterKnife导入对应的依赖。 需要添加的一些插件 Project的build.gradle文件中增加classpath内容： ``` buildscript { repositories { jcenter() } dependencies { classpath \u0026amp;lt;span class=\u0026quot;hljs-symbol\u0026quot;\u0026gt;'com\u0026amp;lt;/span\u0026gt;.android.tools.build:gradle:\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;2.0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;.0\u0026amp;lt;/span\u0026gt;' classpath \u0026amp;lt;span class=\u0026quot;hljs-symbol\u0026quot;\u0026gt;'com\u0026amp;lt;/span\u0026gt;.neenbedankt.gradle.plugins:android-apt:\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1.8\u0026amp;lt;/span\u0026gt;' \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//增加这一句\u0026amp;lt;/span\u0026gt; } } allprojects { repositories { jcenter() } } task clean(\u0026amp;lt;span class=\u0026quot;hljs-class\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;type\u0026amp;lt;/span\u0026gt;:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-type\u0026quot;\u0026gt;Delete\u0026amp;lt;/span\u0026gt;) { delete rootProject.buildDir } 2. app的build.gradle文件中增加classpath内容： ``` `apply plugin: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;com.neenbedankt.android-apt\u0026#39;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//增加这一句\u0026amp;lt;/span\u0026gt; dependencies { compile fileTree(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;include\u0026amp;lt;/span\u0026gt;: [\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;*.jar\u0026#39;\u0026amp;lt;/span\u0026gt;], dir: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;libs\u0026#39;\u0026amp;lt;/span\u0026gt;) testCompile \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;junit:junit:4.12\u0026#39;\u0026amp;lt;/span\u0026gt; compile \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;com.android.support:appcompat-v7:23.4.0\u0026#39;\u0026amp;lt;/span\u0026gt; compile \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;com.jakewharton:butterknife:8.1.0\u0026#39;\u0026amp;lt;/span\u0026gt; apt \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;com.jakewharton:butterknife-compiler:8.1.0\u0026#39;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//增加这一句\u0026amp;lt;/span\u0026gt; }` 代码中的使用，具体就是之前的inject变成了现在的bind，其他变化不大： ``` `public \u0026lt;span class=\u0026ldquo;hljs-class\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;MainActivity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;extends\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;AppCompatActivity\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-annotation\u0026rdquo;\u0026gt;@BindView\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026ldquo;hljs-type\u0026rdquo;\u0026gt;R\u0026lt;/span\u0026gt;.id.btn_qq) \u0026lt;span class=\u0026ldquo;hljs-type\u0026rdquo;\u0026gt;Button\u0026lt;/span\u0026gt; qqBtn; \u0026lt;span class=\u0026ldquo;hljs-annotation\u0026rdquo;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;protected\u0026lt;/span\u0026gt; void onCreate(\u0026lt;span class=\u0026ldquo;hljs-type\u0026rdquo;\u0026gt;Bundle\u0026lt;/span\u0026gt; savedInstanceState) { \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(\u0026lt;span class=\u0026ldquo;hljs-type\u0026rdquo;\u0026gt;R\u0026lt;/span\u0026gt;.layout.activity_main);\n\u0026amp;lt;span class=\u0026quot;hljs-type\u0026quot;\u0026gt;ButterKnife\u0026amp;lt;/span\u0026gt;.bind(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;this\u0026amp;lt;/span\u0026gt;); } \u0026lt;span class=\u0026ldquo;hljs-annotation\u0026rdquo;\u0026gt;@OnClick\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026ldquo;hljs-type\u0026rdquo;\u0026gt;R\u0026lt;/span\u0026gt;.id.btn_qq) void qqBtnClick(){ \u0026lt;span class=\u0026ldquo;hljs-type\u0026rdquo;\u0026gt;Log\u0026lt;/span\u0026gt;.d(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;zwf\u0026rdquo;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;1111111111111111111\u0026rdquo;\u0026lt;/span\u0026gt;); } }`\n\u0026amp;nbsp; \u0026lt;div\u0026gt; 原文链接：http://www.jianshu.com/p/0392199a682b \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/butterknife8-1-0%E7%9A%84%E4%BD%BF%E7%94%A8/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/JakeWharton/butterknife\"\u003ehttps://github.com/JakeWharton/butterknife\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e最近使用的新版的ButterKnife，跟之前有点不一样的地方。记录一下!\u003c/p\u003e\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e导入依赖项：Project Structure→app→Dependencies→add→Library Dependence然后搜索ButterKnife导入对应的依赖。\u003c/li\u003e\n\u003cli\u003e需要添加的一些插件\n\u003col\u003e\n\u003cli\u003eProject的build.gradle文件中增加classpath内容： ```\n\u003ccode\u003ebuildscript { repositories { jcenter() } dependencies { classpath \u0026amp;lt;span class=\u0026quot;hljs-symbol\u0026quot;\u0026gt;'com\u0026amp;lt;/span\u0026gt;.android.tools.build:gradle:\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;2.0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;.0\u0026amp;lt;/span\u0026gt;' classpath \u0026amp;lt;span class=\u0026quot;hljs-symbol\u0026quot;\u0026gt;'com\u0026amp;lt;/span\u0026gt;.neenbedankt.gradle.plugins:android-apt:\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1.8\u0026amp;lt;/span\u0026gt;' \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//增加这一句\u0026amp;lt;/span\u0026gt; } } allprojects { repositories { jcenter() } } task clean(\u0026amp;lt;span class=\u0026quot;hljs-class\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;type\u0026amp;lt;/span\u0026gt;:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-type\u0026quot;\u0026gt;Delete\u0026amp;lt;/span\u0026gt;) { delete rootProject.buildDir }\u003c/code\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      2. app的build.gradle文件中增加classpath内容： ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`apply plugin: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;com.neenbedankt.android-apt\u0026#39;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//增加这一句\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edependencies {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecompile fileTree(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;include\u0026amp;lt;/span\u0026gt;: [\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;*.jar\u0026#39;\u0026amp;lt;/span\u0026gt;], dir: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;libs\u0026#39;\u0026amp;lt;/span\u0026gt;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etestCompile \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;junit:junit:4.12\u0026#39;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecompile \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;com.android.support:appcompat-v7:23.4.0\u0026#39;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecompile \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;com.jakewharton:butterknife:8.1.0\u0026#39;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapt \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;com.jakewharton:butterknife-compiler:8.1.0\u0026#39;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//增加这一句\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e代码中的使用，具体就是之前的inject变成了现在的bind，其他变化不大： ```\n`public \u0026lt;span class=\u0026ldquo;hljs-class\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;MainActivity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;extends\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;AppCompatActivity\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u0026lt;span class=\u0026ldquo;hljs-annotation\u0026rdquo;\u0026gt;@BindView\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026ldquo;hljs-type\u0026rdquo;\u0026gt;R\u0026lt;/span\u0026gt;.id.btn_qq) \u0026lt;span class=\u0026ldquo;hljs-type\u0026rdquo;\u0026gt;Button\u0026lt;/span\u0026gt; qqBtn;\n\u0026lt;span class=\u0026ldquo;hljs-annotation\u0026rdquo;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;protected\u0026lt;/span\u0026gt; void onCreate(\u0026lt;span class=\u0026ldquo;hljs-type\u0026rdquo;\u0026gt;Bundle\u0026lt;/span\u0026gt; savedInstanceState) {\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);\nsetContentView(\u0026lt;span class=\u0026ldquo;hljs-type\u0026rdquo;\u0026gt;R\u0026lt;/span\u0026gt;.layout.activity_main);\u003c/p\u003e","title":"ButterKnife：8.1.0的使用"},{"content":"作为一名做为在前端死缠烂打6年并且懒到不行的攻城士，这几年我还是阅过很多同门从知名到很知名的各种前端框架，本来想拿15-20个框架来分享一下，但在跟几个前辈讨教写文章的技巧时果断被无情的打击了，所以这里我还是低调的只拿出10个框架来个大锅乱炖来简单介绍，凑够字数也就全剧终了。\n原本写这篇文章想围绕着 CSS 框架来的，但因为目前界内比较流行并遍地开花的主要还是 JS+CSS 模式的框架，并且自己靠着一点 JS 功底，就想专门针对 CSS，所以最后来个大锅乱炖都大致聊聊。下面的框架也没有什么先后顺序之分，我想到啥就写啥啦( 作为前端，我一向都这么的任性 ^_^ )。\nBootstrap\n首先说 Bootstrap，估计你也猜到会先说或者一定会有这个( 呵呵了 )，这是说明它的强大之处，拥有框架一壁江山的势气。自己刚入道的时候本着代码任何一个字母都得自己敲出来挡我者废的决心，来让自己成长。结果受到周围各种基友的引诱开始了 Bootstrap 旅程。本人虽然是个设计+前端的万里有一的人才，但是老天只让我会用 PS 和各种设计工具却不给我跟设计妹子一样的审美，所以这也是我最初选择 Bootstrap 的原因之一，它让我做出来的东西好歹能在妹子面前装个逼，不过时间长了难免觉得 Bootstrap 美的让人烦躁， 但好在它的每个版本都会有很大的改变，不会让人觉得自己做的网站会跟很多网站撞脸。Bootstrap 的用法及其简单( 这也可能就是 Bootstrap 作者阅攻城士无数，了解他们痛的结果 )，以至于是个小前端都可以快速上手，几乎没什么学习成本。\n官网：http://getbootstrap.com/\nGithub：https://github.com/twbs/bootstrap/\n作者：Mark Otto 和Jacob Thornton Star：93,112\n总结：Bootstrap 最大的优势就是它非常流行，流行就代表你有问题就有很多人帮你解决问题，就代表装逼它就是利器，还有就是界面比较和谐，容易上手，关注它的童鞋应该发现最新 V4 版也开始支持 FlexBox 布局，这是非常好的升级体验。 劣势是 class 命名不够语义化，并且各种缩写，以至于我离了文档就是个菜，最近开始整混合 APP，选框架的时候首选就是它，但之前搞 PC 一直没注意，后来搞混合右键属性看它的时候，瞬间一阵凉风袭来，Bootstrap 好小，小到我只好选择别的框架。\nAUI\n第三个是最近刚起来的AUI，虽然作者声称是专为APICloud开发者设计的一套UI框架，但实际它还是解决了很多移动前端开发的普遍问题，是主要面向混合开发的 CSS 框架。看起来作者比较猖狂，各种高级 CSS3 遍地使用，这让我也不得不去查查这些个 CSS3 的兼容性。不负众望果然选的都是兼容不错的属性，哈哈了一顿激动从前辈手上大胆认识了几个好东西，并且框架还提供了聊天界面、计数列表等组件，解决了很多复杂的让我骂娘的布局，现在可以直接拿走就用。\nGithub：https://github.com/liulangnan/aui\n官网：http://www.auicss.com/\n作者：流浪男 Star：92\n总结：这个框架对我来说有个优点就是纯 CSS 框架，自己以前也就用过 Pure，自己有点 JS 能力，如果不是复杂的效果，找个纯 CSS 框架自己随便改改就可以，而现在 CSS3 也已经能够做到动画，效率、质量、高效全兼顾，所以还是选择了这种 CSS 框架。有一点觉得不满的是这框架的文档真的好那什么，说好的高大上呢。\nAmaze UI\n第二个介绍的是妹子UI，最初使用它是因为本尊遇到了一个爱纠结细节设计士，有一次她跟我的字体较上真了，结果一句顶万句的 BOOS 夸了她，我只好根据她的想法去解决，结果最后找到了Amaze UI 框架( 我不介意你叫我懒淫 )，按照官方的话说就是 “基于社区开源项目构建的一个跨屏前端框架，以移动优先，从小屏到大屏，最终实现所有屏幕适配，适应移动互联潮流” 。但其实我就是看中它能解决国内浏览器存在的跨屏适配和兼容性问题。\n官网：http://amazeui.org/\nGithub：https://github.com/amazeui/amazeui\n所属公司：云适配 Star：6710\n总结：Amaze UI 总的来说就是加入更多符合中国市场特性的元素，框架对跨屏、适配都做了的比较好的处理并且准备一了一系列的常用的网页组件，为减少搞兼容、适配各种敲键盘的加班狗们的工作时间做了不小的贡献。，框架还对中文排版优化，兼容中国本土主流浏览器、轻量化，不仅适用于桌面端，还更更适合移动端、包含一些封装好的Widgets。不过自也就我感觉 Amaze UI 文档是否有点太那什么了，比如 “人们不会在乎jQuery的那点流量。”，说实的在这真没啥，不过我从来不会说出来( 哈哈 )，代码和设计上感觉没太多突出的点。\nFrozen UI\n有段时间看到 QQ 瞬间高大上了，后来四处打听，原来 QQ 客服端也用了 混合开发，其中QQ会员前端用的是 Frozen UI，并且这套框架开源，欣喜若狂耐不住心里的寂寞直接上手试了一遍，初体验感觉基础样式效果简单色调清爽，有个比较活跃的社区所以组件什么的也比较丰富。\nGithub：https://github.com/frozenui/frozenui\n官网：http://frozenui.github.io/\n作者： QQVIP FD Team Star：1,067\n总结：如果拿 Frozen UI 配合一些如 APICloud 用来做混合 APP 感觉就太酷了，或者原生的火鸡们拿去嵌套在应用中做前端开发，这个框架对 android 2.3 +、ios 4.0 + 做了兼容，或者拿来做 Web App 也是极好的选择，劣势的话从 UI 层面就可以看到了，谁让它是出生在QQ会员前端的呢。\nFrozen UI\n第三个是Frozen UI，有段时间看到 QQ 瞬间高大上了，后来四处打听，原来 QQ 客服端也用了 HTML 混合开发，其中QQ会员前端就是用的 Frozen UI，并且这套框架开源，欣喜若狂耐不住心里的寂寞直接上手三下五除二试了一遍就开始试用，初体验的就是基础样式效果简单色调清爽，有个比较活跃的社区所以组件什么的也比较丰富。\nGithub：https://github.com/frozenui/frozenui\n官网：http://frozenui.github.io/\n作者： QQVIP FD Team Star：1,067\n总结：如果拿 Frozen UI 配合一些如 APICloud 用来做混合 APP 感觉就太酷了，或者原生的火鸡们拿去嵌套在应用中做前端开发，并且这个框架对 android 2.3 +、ios 4.0 + 做了兼容，或者拿来做 Web app 也是极好的选择，不过要是放在微信里比这更合适的 WeUI 框架更是首选了，劣势的话从 UI 层面就可以看到了，谁让它是出生在QQ会员前端的呢。\nWeUIi\n第四个是WeUI和同 FrozenUI都属于 差不多的 WeUi了，也是一个比较专一的框架，WeUI应该说比FrozenUI前者更专一，话说连个官网都不搞，所有答疑都在 gitHub Issues 解决了，这个框架极其简单，体积当然就不用说了，模块也就 7 个左右，不过体量虽然小做的却不错，口碑看 star 就够了，框架从 16/1/23 发版至今 github star 超过 7K,不过也不排除用户没地方发泄所以都跑到 git 上来，哈哈。\nGithub：https://github.com/weui/weui\nDEMO：http://weui.github.io/weui/\nStar：7,129\n总结：看完微信设计团队设计的这套 DEMO，二话不说如果要做微信公众，这个二话不说必然是首选了。框架不好的地方简而言之就是框架本身应该就没考虑过让用户用到非微信的场景之下。\nSUI\n“SUI 是一套基于bootstrap开发的前端组件库，同时它她也是一套设计规范。通过SUI，可以非常方便的设计和实现精美的页面”。 果然还是直接引用官方给的枯燥无味广告要节省自己的脑细胞( 囧… )，当然了就像广告说的，如果你之前用过 Bootstrap， 那么可以轻松转向 SUI，这可能就是淘宝给前端屌丝们的福利了。。\nGithub：https://github.com/sdc-alibaba/sui\n官网：http://sui.taobao.org/sui/docs/index.html\nStar：120\nAUI\n第六个是最近刚起来的最近刚起来的 AUI，虽然作者声称是专为APICloud开发者设计的一套UI框架，但实际它还是解决了很多移动前端开发的普遍问题，是它主要面向混合开发的 CSS 框架。，所以看起来作者比较猖狂，各种高级 CSS3 遍地使用，这也使得我不得不去查查这些个 CSS3 的兼容性。不负众望果然选的都是兼容不错的属性，哈哈了一顿激动从前辈手上大胆认识了几个好东西，并且框架还提供了聊天界面、计数列表等组件，解决了很多复杂的让我骂娘的布局，现在可以直接拿走就用。\nGithub：https://github.com/liulangnan/aui\n官网：http://www.auicss.com/\n作者：流浪男 Star：92\n总结：这个框架对我来说有个优点就是纯 CSS 框架，自己以前也就用过 Pure，自己有点 js 能力，如果不是复杂的效果自己找个纯 CSS 框架自己随便改改就能达到效果，而现在 CSS3 也已经能够做到各种动画，效率、质量、高效各种一顿考虑所以还是选择了这种 CSS 框架。而一直觉得不满的是这框架的文档真的好那什么，说好的高大上呢。\nMUI\n曾经一直使用 Android 系统的我，后来见到 IOS，果断移情别恋了，不知道为什么苹果每次调整系统我都特别喜欢，后来一段时间因为缺设计我专门模仿 IOS 系统做 UI，但始终不能够做到很好，无意间就发现了 MUI 这个框架，这个框架给我的吸引之处就是它的 UI 是以 IOS 为主体设计的，当然它也补充了android特有UI样式。并且MUI官方声称用来开发深入以后发现拿它做 APP 还能够提高用户使用流畅度，然后便试着更深入的了解和使用一段时间。\n官网：http://dev.dcloud.net.cn/mui/\nGithub：https://github.com/dcloudio/mui\nStar：2,450\n总结：就像之前说的这个框架是以两大系统为参照来封装UI组件，框架自身还有一个较为活跃的社区，不太好的地方这也是我特别关注的一点，关于开发应用的流畅度，我当然知道这是 H5 目前的劣势，但是看到官网给的描述，还是抱着期待的心理试试看能否提升，然而它其实还是需要是借助 Webview来提升，而不是框架本身。\nSemantic UI\n倒数第三个是 Semantic UI，接触这个框架还是因为 Bootstrap，Semantic UI 刚上线 github 就受到大量开发者的关注，以至于很多人拿它俩对比各种挑刺各种夸，是好是坏不能单凭别人三句四句就抬起手指开始赞，用了以后感觉 UI 上跟 Bootstrap 没太多的区别，不过代码命名规范上却相差甚大，本人认为 Semantic UI 是不是就想做的不一样，它的命名全是采用复合的方式，类名特别的离散，用的时候你得很小心自己扩展或者新增的 class 命名与它的类名冲突。\n官网：http://www.semantic-ui.cn/\nGithub：https://github.com/semantic-org/semantic-ui/\n** Foundation**\nFoundation 算是框架界的元老啦，都说框架去的早，而这个框架一直到现在依然这么的热门，如果你比较介意 Bootstrap 开发撞脸的尴尬事情，那么你可以考虑使用 Foundation 。即使你使用预定义的 UI 元素, 也不会与其他网站太像，就像官方说的给开发者更灵活的框架体验。\n官网：http://foundation.zurb.com/\nGithub：https://github.com/zurb/foundation-sites\nStar：22,736\nUiKit\nUIkit是YOOtheme团队开发的，在许多WordPress主题中都有应用(也就是如果你是个 WordPress 爱好者，那么这个框架应该比较适合深究)，并且框架能够通过GUI编辑器和手动编辑，所以它提供了一个灵活、强大的自定义机制。框架借助LESS、jQuery、normalize.css及FontAwesome开源项目的独有特点，整合成了这么一款轻量级、模块化的前端框架。\n官网：http://www.getuikit.com/\nGithub：https://github.com/uikit/uikit\n作者：YOOtheme Star：6,372\nPure\n终于最后一个了，我和你一样好开森 (～￣▽￣)～)，这个框架是我在做管理系统时接触的，选择使用也是因为框架小巧，并且是纯 CSS，没有太多的牵扯，好用来与其他框架快速结合使用。\n官网：http://purecss.io/\nGithub：https://github.com/yahoo/pure/\nStar：13,592\n介绍完毕，估计你应该看出来了，我使用框架真的也就是遇到了需求，才选择了某个框架，所以框架之间并没有什么好与特好之分，只能说你的需求是什么，这个框架合适不合适你去用，各种框架用起来也都大致差不多，会用一个其他的上手也就都变得简单容易上手，我觉得能写框架的人都是室外高仁。\n转自：http://www.cnblogs.com/kingboy2008/p/5261771.html\n","permalink":"https://blog.zdltech.com/posts/10%E5%A4%A7h5%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/","summary":"\u003cp\u003e作为一名做为在前端死缠烂打6年并且懒到不行的攻城士，这几年我还是阅过很多同门从知名到很知名的各种前端框架，本来想拿15-20个框架来分享一下，但在跟几个前辈讨教写文章的技巧时果断被无情的打击了，所以这里我还是低调的只拿出10个框架来个大锅乱炖来简单介绍，凑够字数也就全剧终了。\u003c/p\u003e\n\u003cp\u003e原本写这篇文章想围绕着 CSS 框架来的，但因为目前界内比较流行并遍地开花的主要还是 JS+CSS 模式的框架，并且自己靠着一点 JS 功底，就想专门针对 CSS，所以最后来个大锅乱炖都大致聊聊。下面的框架也没有什么先后顺序之分，我想到啥就写啥啦( 作为前端，我一向都这么的任性 ^_^ )。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBootstrap\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e首先说 Bootstrap，估计你也猜到会先说或者一定会有这个( 呵呵了 )，这是说明它的强大之处，拥有框架一壁江山的势气。自己刚入道的时候本着代码任何一个字母都得自己敲出来挡我者废的决心，来让自己成长。结果受到周围各种基友的引诱开始了 Bootstrap 旅程。本人虽然是个设计+前端的万里有一的人才，但是老天只让我会用 PS 和各种设计工具却不给我跟设计妹子一样的审美，所以这也是我最初选择 Bootstrap 的原因之一，它让我做出来的东西好歹能在妹子面前装个逼，不过时间长了难免觉得 Bootstrap 美的让人烦躁， 但好在它的每个版本都会有很大的改变，不会让人觉得自己做的网站会跟很多网站撞脸。Bootstrap 的用法及其简单( 这也可能就是 Bootstrap 作者阅攻城士无数，了解他们痛的结果 )，以至于是个小前端都可以快速上手，几乎没什么学习成本。\u003c/p\u003e\n\u003cp\u003e官网：\u003ca href=\"http://getbootstrap.com/\"\u003ehttp://getbootstrap.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eGithub：\u003ca href=\"https://github.com/twbs/bootstrap/\"\u003ehttps://github.com/twbs/bootstrap/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e作者：Mark Otto 和Jacob Thornton Star：93,112\u003c/p\u003e\n\u003cp\u003e总结：Bootstrap 最大的优势就是它非常流行，流行就代表你有问题就有很多人帮你解决问题，就代表装逼它就是利器，还有就是界面比较和谐，容易上手，关注它的童鞋应该发现最新 V4 版也开始支持 FlexBox 布局，这是非常好的升级体验。 劣势是 class 命名不够语义化，并且各种缩写，以至于我离了文档就是个菜，最近开始整混合 APP，选框架的时候首选就是它，但之前搞 PC 一直没注意，后来搞混合右键属性看它的时候，瞬间一阵凉风袭来，Bootstrap 好小，小到我只好选择别的框架。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAUI\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e第三个是最近刚起来的AUI，虽然作者声称是专为APICloud开发者设计的一套UI框架，但实际它还是解决了很多移动前端开发的普遍问题，是主要面向混合开发的 CSS 框架。看起来作者比较猖狂，各种高级 CSS3 遍地使用，这让我也不得不去查查这些个 CSS3 的兼容性。不负众望果然选的都是兼容不错的属性，哈哈了一顿激动从前辈手上大胆认识了几个好东西，并且框架还提供了聊天界面、计数列表等组件，解决了很多复杂的让我骂娘的布局，现在可以直接拿走就用。\u003c/p\u003e\n\u003cp\u003eGithub：\u003ca href=\"https://github.com/liulangnan/aui\"\u003ehttps://github.com/liulangnan/aui\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e官网：\u003ca href=\"http://www.auicss.com/\"\u003ehttp://www.auicss.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e作者：流浪男 Star：92\u003c/p\u003e\n\u003cp\u003e总结：这个框架对我来说有个优点就是纯 CSS 框架，自己以前也就用过 Pure，自己有点 JS 能力，如果不是复杂的效果，找个纯 CSS 框架自己随便改改就可以，而现在 CSS3 也已经能够做到动画，效率、质量、高效全兼顾，所以还是选择了这种 CSS 框架。有一点觉得不满的是这框架的文档真的好那什么，说好的高大上呢。\u003c/p\u003e","title":"10大H5前端框架"},{"content":"1、第一种方式\nedittext.setRawInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE); edittext.setTextIsSelectable(true); 2、第二种方式 /** * 禁止Edittext弹出软件盘，光标依然正常显示。 */ public void disableShowSoftInput(EditText editText) { if (android.os.Build.VERSION.SDK_INT \u0026amp;lt;= 10) { // editText.setInputType(InputType.TYPE_NULL); editText.setRawInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE); editText.setTextIsSelectable(true); } else { Class\u0026amp;lt;EditText\u0026amp;gt; cls = EditText.class; Method method; try { method = cls.getMethod(\u0026#34;setShowSoftInputOnFocus\u0026#34;,boolean.class); method.setAccessible(true); method.invoke(editText, false); }catch (Exception e) { // TODO: handle exception } try { method = cls.getMethod(\u0026#34;setSoftInputShownOnFocus\u0026#34;,boolean.class); method.setAccessible(true); method.invoke(editText, false); }catch (Exception e) { // TODO: handle exception } } } ","permalink":"https://blog.zdltech.com/posts/%E9%9A%90%E8%97%8F%E5%BC%B9%E5%87%BA%E9%94%AE%E7%9B%98edittext%E6%9C%89%E5%85%89%E6%A0%87%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F/","summary":"\u003cp\u003e1、第一种方式\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eedittext.setRawInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eedittext.setTextIsSelectable(true);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e2、第二种方式\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * 禁止Edittext弹出软件盘，光标依然正常显示。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public void disableShowSoftInput(EditText editText)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        if (android.os.Build.VERSION.SDK_INT \u0026amp;lt;= 10)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e//            editText.setInputType(InputType.TYPE_NULL);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            editText.setRawInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            editText.setTextIsSelectable(true);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        else {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            Class\u0026amp;lt;EditText\u0026amp;gt; cls = EditText.class;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            Method method;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            try {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                method = cls.getMethod(\u0026#34;setShowSoftInputOnFocus\u0026#34;,boolean.class);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                method.setAccessible(true);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                method.invoke(editText, false);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }catch (Exception e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                // TODO: handle exception\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            try {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                method = cls.getMethod(\u0026#34;setSoftInputShownOnFocus\u0026#34;,boolean.class);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                method.setAccessible(true);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                method.invoke(editText, false);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }catch (Exception e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                // TODO: handle exception\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"隐藏弹出键盘，Edittext有光标实现方式"},{"content":"1. 两种方案 （1） 监听BroadcastReceiver\n（2）获取PowerManager事件\n### 2. BroadcastReceiver {#articleHeader1}\n#### 2.1. 事件\n总共有3个事件：\nIntent.ACTION_SCREEN_ON ： 屏幕点亮 Intent.ACTION_SCREEN_OFF ：屏幕关闭 Intent.ACTION_USER_PRESENT： 用户解锁 #### 2.2. 权限\n监听用户解锁需要在AndroidManifest中注册权限\n\u0026amp;lt;uses-permission android:name=\u0026#34;android.permission.RECEIVE_USER_PRESENT\u0026#34; /\u0026amp;gt; #### 2.3. IntentFilter代码\nif (mContext != null) { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_USER_PRESENT); mContext.registerReceiver(mScreenReceiver, filter); } ### 3. PowerManager {#articleHeader2}\nPowerManager manager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); if (manager.isScreenOn()) { if (mScreenStateListener != null) { mScreenStateListener.onScreenOn(); } } else { if (mScreenStateListener != null) { mScreenStateListener.onScreenOff(); } } 4. Code import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.PowerManager; /** * Created by xiyanglu on 4/11/15. */ public class ScreenObserver { private Context mContext; private ScreenBroadcastReceiver mScreenReceiver; private ScreenStateListener mScreenStateListener; public ScreenObserver(Context context) { mContext = context; mScreenReceiver = new ScreenBroadcastReceiver(); } public void startObserver(ScreenStateListener listener) { mScreenStateListener = listener; registerListener(); getScreenState(); } public void shutdownObserver() { unregisterListener(); } /** * 获取screen状态 */ @SuppressLint(\u0026#34;NewApi\u0026#34;) private void getScreenState() { if (mContext == null) { return; } PowerManager manager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); if (manager.isScreenOn()) { if (mScreenStateListener != null) { mScreenStateListener.onScreenOn(); } } else { if (mScreenStateListener != null) { mScreenStateListener.onScreenOff(); } } } private void registerListener() { if (mContext != null) { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_USER_PRESENT); mContext.registerReceiver(mScreenReceiver, filter); } } private void unregisterListener() { if (mContext != null) mContext.unregisterReceiver(mScreenReceiver); } private class ScreenBroadcastReceiver extends BroadcastReceiver { private String action = null; @Override public void onReceive(Context context, Intent intent) { action = intent.getAction(); if (Intent.ACTION_SCREEN_ON.equals(action)) { // 开屏 mScreenStateListener.onScreenOn(); } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { // 锁屏 mScreenStateListener.onScreenOff(); } else if (Intent.ACTION_USER_PRESENT.equals(action)) { // 解锁 mScreenStateListener.onUserPresent(); } } } public interface ScreenStateListener {// 返回给调用者屏幕状态信息 public void onScreenOn(); public void onScreenOff(); public void onUserPresent(); } } Android监听锁屏键、Home键 项目用到了，记录下，返回键什么的物理按键使用onKeyDown监听就可以了，但是锁屏键、Home键不可以，这里使用广播监听两者状态变化\nfinal String SYSTEM_DIALOG_REASON_KEY = \u0026#34;reason\u0026#34;; final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = \u0026#34;globalactions\u0026#34;; final String SYSTEM_DIALOG_REASON_RECENT_APPS = \u0026#34;recentapps\u0026#34;; final String SYSTEM_DIALOG_REASON_HOME_KEY = \u0026#34;homekey\u0026#34;; IntentFilter片段:\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `mFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);``//home键` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``mFilter.addAction(Intent.ACTION_SCREEN_ON); ``//开屏` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``mFilter.addAction(Intent.ACTION_SCREEN_OFF);``//锁屏` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``mFilter.addAction(Intent.ACTION_USER_PRESENT);``//解锁` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; onRecevier片段：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `void` `onReceive(Context context, Intent intent) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``String action = intent.getAction();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``if` `(action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``if` `(reason != ``null``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``if` `(mListener != ``null``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``if` `(reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``// 短按home键 ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``mListener.onHomePressed();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``} ``else` `if` `(reason` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``// 长按home键 ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``mListener.onHomeLongPressed();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``if``(action.equals(Intent.ACTION_SCREEN_ON)){ ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``mListener.onScreenOn(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``}``else` `if``(action.equals(Intent.ACTION_SCREEN_OFF)){ ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``mListener.onScreenOff(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``} ``else``{``// 解锁` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``//TODO` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 最后提醒下，对于锁屏操作，由于先走的activity的onPause，onStop，所以不可以像以往反注册广播样在onPause里进行反注册，否则的话会接收不到锁屏操作\n","permalink":"https://blog.zdltech.com/posts/android-%E7%9B%91%E5%90%AC%E9%94%81%E5%B1%8F%E5%BC%80%E5%B1%8F%E4%BA%8B%E4%BB%B6/","summary":"\u003ch3 id=\"articleHeader0\"\u003e1. 两种方案\u003c/h3\u003e\n\u003cp\u003e（1） 监听BroadcastReceiver\u003c/p\u003e\n\u003cp\u003e（2）获取PowerManager事件\u003c/p\u003e\n\u003cp\u003e###\u003cimg loading=\"lazy\" src=\"http://www.open-open.com/lib/kindeditor4/themes/common/anchor.gif\"\u003e 2.  BroadcastReceiver {#articleHeader1}\u003c/p\u003e\n\u003cp\u003e####\u003cimg loading=\"lazy\" src=\"http://www.open-open.com/lib/kindeditor4/themes/common/anchor.gif\"\u003e 2.1. 事件\u003c/p\u003e\n\u003cp\u003e总共有3个事件：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eIntent.ACTION_SCREEN_ON ： 屏幕点亮\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eIntent.ACTION_SCREEN_OFF ：屏幕关闭\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eIntent.ACTION_USER_PRESENT： 用户解锁\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e####\u003cimg loading=\"lazy\" src=\"http://www.open-open.com/lib/kindeditor4/themes/common/anchor.gif\"\u003e 2.2. 权限\u003c/p\u003e\n\u003cp\u003e监听用户解锁需要在AndroidManifest中注册权限\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zed\" data-lang=\"zed\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;uses\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epermission\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e:\u003c/span\u003ename\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026#34;android.\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epermission\u003c/span\u003e.RECEIVE_USER_PRESENT\u0026#34; \u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e####\u003cimg loading=\"lazy\" src=\"http://www.open-open.com/lib/kindeditor4/themes/common/anchor.gif\"\u003e 2.3. IntentFilter代码\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eif (mContext != null) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        IntentFilter filter = new IntentFilter();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        filter.addAction(Intent.ACTION_SCREEN_ON);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        filter.addAction(Intent.ACTION_SCREEN_OFF);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        filter.addAction(Intent.ACTION_USER_PRESENT);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mContext.registerReceiver(mScreenReceiver, filter);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e###\u003cimg loading=\"lazy\" src=\"http://www.open-open.com/lib/kindeditor4/themes/common/anchor.gif\"\u003e 3. PowerManager {#articleHeader2}\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ePowerManager manager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    if (manager.isScreenOn()) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        if (mScreenStateListener != null) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mScreenStateListener.onScreenOn();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } else {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        if (mScreenStateListener != null) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mScreenStateListener.onScreenOff();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e \u003c/p\u003e","title":"Android 监听锁屏/开屏事件"},{"content":"最近要弄一下Java读取文件MD5，注意这里是小文件，网上找了一下，有两种解决方案，一种是用MessageDigest来实现，另种是用org.apache.commons.codec.digest来实现，代码如下：\n**[java]** [view plain](http://blog.csdn.net/wangqiuyun/article/details/22941433#) [copy](http://blog.csdn.net/wangqiuyun/article/details/22941433#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/274974)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/274974/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; cdm; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.File; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.FileInputStream; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.FileNotFoundException; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.IOException; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.math.BigInteger; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.nio.MappedByteBuffer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.nio.channels.FileChannel; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.security.MessageDigest; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.commons.codec.digest.*; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.commons.io.IOUtils; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; testMD5 { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String getMd5ByFile(File file) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; FileNotFoundException { - String value = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - FileInputStream in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; FileInputStream(file); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, file.length()); - MessageDigest md5 = MessageDigest.getInstance(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MD5\u0026amp;#8221;\u0026lt;/span\u0026gt;); - md5.update(byteBuffer); - BigInteger bi = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BigInteger(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, md5.digest()); - value = bi.toString(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) { - e.printStackTrace(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;finally\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; != in) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - in.close(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) { - e.printStackTrace(); - } - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; value; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; main(String[] args) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; IOException { - - String path=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;E:\\\\commons-codec-1.9-bin.zip\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - String v = getMd5ByFile(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; File(path)); - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MD5:\u0026amp;#8221;\u0026lt;/span\u0026gt;+v.toUpperCase()); - - FileInputStream fis= \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; FileInputStream(path); - String md5 = DigestUtils.md5Hex(IOUtils.toByteArray(fis)); - IOUtils.closeQuietly(fis); - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MD5:\u0026amp;#8221;\u0026lt;/span\u0026gt;+md5); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//System.out.println(\u0026amp;#8220;MD5:\u0026amp;#8221;+DigestUtils.md5Hex(\u0026amp;#8220;WANGQIUYUN\u0026amp;#8221;));\u0026lt;/span\u0026gt; - } - - } \u0026lt;/div\u0026gt; 运行： ![](http://img.blog.csdn.net/20140404160025078?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2FuZ3FpdXl1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 结果在官网提供的MD5一致。 附commons-codec-1.9.jar下载地址：[http://commons.apache.org/proper/commons-codec/download_codec.cgi](http://commons.apache.org/proper/commons-codec/download_codec.cgi) 如果要处理过G的文件，请参照：[http://www.cnblogs.com/yaowukonga/p/3523668.html](http://www.cnblogs.com/yaowukonga/p/3523668.html) ","permalink":"https://blog.zdltech.com/posts/java%E8%AF%BB%E5%8F%96%E6%96%87%E4%BB%B6md5%E7%9A%84%E4%B8%A4%E7%A7%8D%E6%96%B9%E6%A1%88/","summary":"\u003cp\u003e最近要弄一下Java读取文件MD5，注意这里是小文件，网上找了一下，有两种解决方案，一种是用MessageDigest来实现，另种是用org.apache.commons.codec.digest来实现，代码如下：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/wangqiuyun/article/details/22941433#)\u003cspan data-mod=\"popu_168\"\u003e\u003cspan data-mod=\"popu_168\"\u003e [copy](http://blog.csdn.net/wangqiuyun/article/details/22941433#)\u003c/span\u003e\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n\n    \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/274974)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/274974/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \n    \n    \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; cdm;\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.File;\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.FileInputStream;\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.FileNotFoundException;\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.IOException;\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.math.BigInteger;\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.nio.MappedByteBuffer;\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.nio.channels.FileChannel;\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.security.MessageDigest;\n      \n      - \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.commons.codec.digest.*;\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.apache.commons.io.IOUtils;\n      \n      - \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; testMD5 {\n      \n      - \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String getMd5ByFile(File file) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; FileNotFoundException {\n      \n      - String value = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n      \n      - FileInputStream in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; FileInputStream(file);\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n      \n      - MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, file.length());\n      \n      - MessageDigest md5 = MessageDigest.getInstance(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MD5\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n      \n      - md5.update(byteBuffer);\n      \n      - BigInteger bi = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BigInteger(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, md5.digest());\n      \n      - value = bi.toString(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;);\n      \n      - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) {\n      \n      - e.printStackTrace();\n      \n      - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;finally\u0026lt;/span\u0026gt; {\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; != in) {\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n      \n      - in.close();\n      \n      - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) {\n      \n      - e.printStackTrace();\n      \n      - }\n      \n      - }\n      \n      - }\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; value;\n      \n      - }\n      \n      - \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; main(String[] args) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; IOException {\n      \n      - \n      - String path=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;E:\\\\commons-codec-1.9-bin.zip\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n      \n      - \n      - String v = getMd5ByFile(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; File(path));\n      \n      - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MD5:\u0026amp;#8221;\u0026lt;/span\u0026gt;+v.toUpperCase());\n      \n      - \n      - FileInputStream fis= \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; FileInputStream(path);\n      \n      - String md5 = DigestUtils.md5Hex(IOUtils.toByteArray(fis));\n      \n      - IOUtils.closeQuietly(fis);\n      \n      - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MD5:\u0026amp;#8221;\u0026lt;/span\u0026gt;+md5);\n      \n      - \n      - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//System.out.println(\u0026amp;#8220;MD5:\u0026amp;#8221;+DigestUtils.md5Hex(\u0026amp;#8220;WANGQIUYUN\u0026amp;#8221;));\u0026lt;/span\u0026gt;\n      \n      - }\n      \n      - \n      - }\n      \n    \u0026lt;/div\u0026gt; \n    \n    \n\n      运行：\n    \n\n    \n    \n\n      ![](http://img.blog.csdn.net/20140404160025078?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2FuZ3FpdXl1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n    \n\n    \n    \n\n      结果在官网提供的MD5一致。\n    \n\n    \n    \n\n      附commons-codec-1.9.jar下载地址：[http://commons.apache.org/proper/commons-codec/download_codec.cgi](http://commons.apache.org/proper/commons-codec/download_codec.cgi)\n    \n\n    \n    \n\n      如果要处理过G的文件，请参照：[http://www.cnblogs.com/yaowukonga/p/3523668.html](http://www.cnblogs.com/yaowukonga/p/3523668.html)\n\u003c/code\u003e\u003c/pre\u003e","title":"Java读取文件MD5的两种方案"},{"content":"这个首先从一个bug说起，如图:\n我们都知道fragment切换有两种方式：\nreplace方式 transaction.replace(R.id.content, IndexFragment); add－hide－show方式 transaction.add(R.id.content, IndexFragment); transaction.hide(otherfragment); transaction.show(thisfragment); 而上面按钮中出现bug的就是采用第二种方式。然后我们来分析下用add，hide，show为什么出现这种bug，我把每个操作都打印出了以下日志：\n复现bug的操作是：\n1.首先打开，默认选中的是第一个tab，如上面的一张图片正常那样。\n2.切换到tab2，并把tab1 hide掉；\n3.再切回到tab1，并不会触发tab1对应fragment的任何生命周期；\n4.然后home键进入后台，我在activity的onPause()中手动对IndexFragment赋空，模拟长时间后台，系统销毁了该引用。\nIndexFragment=null; 5.再次启动，其实tab1 的fragment实例在内存中还在，只是他的引用被销毁了。\n6.再切到tab2，这里其实是先把tab1的hide，在show tab2，但是tab1 的fragment引用为空，所以无法hide，就出现了tab2叠在tab1上的花屏情况。\n7.再切到tab1，tab1就会重复创建对象。\n同样的操作，我们使用replace的方式\n使用replace方式，虽然这种方式会避免上述的bug，但也是重复创建了对象。因为replace方式，对应的FrameLayout只有一 层，而add方式，这个FrameLayout其实有2层。但是这种方式的缺点是：每次replace会把生命周期全部执行一遍，如果在这些生命周期函数 里拉取数据的话，就会不断重复的加载刷新数据。\n那么最合适的处理方式是这样的：\n1.在add的时候，加上一个tab参数\ntransaction.add(R.id.content, IndexFragment,”Tab1″);\n2.然后当IndexFragment引用被回收置空的话，先通过\nIndexFragment＝FragmentManager.findFragmentByTag(“Tab1″);\n找到对应的引用，然后继续上面的hide,show;\n","permalink":"https://blog.zdltech.com/posts/fragment%E9%94%80%E6%AF%81%E6%97%B6replace%E5%92%8Cadd%E4%B8%A4%E4%B8%AA%E6%96%B9%E6%B3%95%E7%9A%84%E5%8C%BA%E5%88%AB/","summary":"\u003cp\u003e这个首先从一个bug说起，如图:\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://www.ithtw.com/images/2015/03/2015032611145532.gif\"\u003e\u003cimg loading=\"lazy\" src=\"http://www.ithtw.com/images/2015/03/2015032611145564.png\"\u003e  \u003cimg loading=\"lazy\" src=\"http://www.ithtw.com/images/2015/03/2015032611150084.png\"\u003e\u003c/p\u003e\n\u003cp\u003e我们都知道fragment切换有两种方式：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ereplace方式\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etransaction.replace(R.id.content, IndexFragment);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"2\"\u003e\n\u003cli\u003eadd－hide－show方式\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etransaction.add(R.id.content, IndexFragment);  transaction.hide(otherfragment);  transaction.show(thisfragment);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e而上面按钮中出现bug的就是采用第二种方式。然后我们来分析下用add，hide，show为什么出现这种bug，我把每个操作都打印出了以下日志：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://www.ithtw.com/images/2015/03/2015032611150350.png\"\u003e\u003c/p\u003e\n\u003cp\u003e复现bug的操作是：\u003cbr\u003e\n1.首先打开，默认选中的是第一个tab，如上面的一张图片正常那样。\u003cbr\u003e\n2.切换到tab2，并把tab1 hide掉；\u003cbr\u003e\n3.再切回到tab1，并不会触发tab1对应fragment的任何生命周期；\u003cbr\u003e\n4.然后home键进入后台，我在activity的onPause()中手动对IndexFragment赋空，模拟长时间后台，系统销毁了该引用。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eIndexFragment=null;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e5.再次启动，其实tab1 的fragment实例在内存中还在，只是他的引用被销毁了。\u003cbr\u003e\n6.再切到tab2，这里其实是先把tab1的hide，在show tab2，但是tab1 的fragment引用为空，所以无法hide，就出现了tab2叠在tab1上的花屏情况。\u003cbr\u003e\n7.再切到tab1，tab1就会重复创建对象。\u003c/p\u003e\n\u003cp\u003e同样的操作，我们使用replace的方式\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://www.ithtw.com/images/2015/03/2015032611150428.png\"\u003e\u003c/p\u003e\n\u003cp\u003e使用replace方式，虽然这种方式会避免上述的bug，但也是重复创建了对象。因为replace方式，对应的FrameLayout只有一 层，而add方式，这个FrameLayout其实有2层。但是这种方式的缺点是：每次replace会把生命周期全部执行一遍，如果在这些生命周期函数 里拉取数据的话，就会不断重复的加载刷新数据。\u003c/p\u003e\n\u003cp\u003e那么最合适的处理方式是这样的：\u003c/p\u003e\n\u003cp\u003e1.在add的时候，加上一个tab参数\u003cbr\u003e\ntransaction.add(R.id.content, IndexFragment,”Tab1″);\u003cbr\u003e\n2.然后当IndexFragment引用被回收置空的话，先通过\u003cbr\u003e\nIndexFragment＝FragmentManager.findFragmentByTag(“Tab1″);\u003cbr\u003e\n找到对应的引用，然后继续上面的hide,show;\u003c/p\u003e","title":"Fragment销毁时replace和add两个方法的区别"},{"content":" 只允许EditText输入数字或者email格式字符是非常简单的（详见API文档）。 要实现只允许输入自定的数字字符也是很容易的（详见API文档，[setKeyListener(KeyListener)](http://blog.csdn.net/reference/android/widget/TextView.html#setKeyListener(android.text.method.KeyListener)) 和\u0026lt;span class=\u0026quot;sympad\u0026quot;\u0026gt;setFilters\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;normal\u0026quot;\u0026gt;([InputFilter[]](http://blog.csdn.net/reference/android/text/InputFilter.html) filters)\u0026lt;/span\u0026gt; ）。 但是要限制只能输入指定的字母字符就非常的困难。 /** InputFilter[] ifs = {new InputFilter.LengthFilter(10),new DigitsKeyListener(true,true)}; editText01.setFilters(ifs);\n**/ \u0026amp;nbsp; 发现，**[Android](http://lib.csdn.net/base/15):digits**的参数是一个字符串，没有更多的语义检查，因此想到内部处理很可能仅是简单的检查，输入的字符是否在给定的字符串中（要我设计，我就这样做）。尝试着给它指定带有英文字符的参数，发现果然如此。万幸，万幸！ 在layout.xml里 **[xml]** [view plain](http://blog.csdn.net/jdsjlzx/article/details/6762751#) [copy](http://blog.csdn.net/jdsjlzx/article/details/6762751#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;EditText\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/register_userName_editText\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@style/register_editText_style\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:digits\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@string/register_name_digits\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/register_edit_text_textColor\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColorHint\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/register_hint_text_textColor\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:hint\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@string/register_name_hint_text\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;nbsp; 在string.xml里 \u0026amp;nbsp; **[xml]** [view plain](http://blog.csdn.net/jdsjlzx/article/details/6762751#) [copy](http://blog.csdn.net/jdsjlzx/article/details/6762751#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;string\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;register_name_digits\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - ._0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLIMNOPQRSTUVWXYZ - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;string\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;nbsp; \u0026amp;nbsp; \u0026amp;nbsp; \u0026amp;nbsp; Java代码 - editText01.addTextChangedListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TextWatcher() { - String tmp = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;; - String digits = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;abcdef\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTextChanged(CharSequence s, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; start, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; before, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; count) { - } - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; beforeTextChanged(CharSequence s, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; start, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; count, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; after) { - tmp = s.toString(); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; afterTextChanged(Editable s) { - Log.d(Sample4Main.TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;\u0026gt;\u0026lt;\u0026gt;afterTextChanged\u0026lt;\u0026gt;\u0026lt;\u0026gt;\u0026amp;#8221;\u0026lt;/span\u0026gt; + s.toString()); - - String str = s.toString(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(str.equals(tmp)){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - } - - StringBuffer sb = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringBuffer(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; str.length(); i++){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(digits.indexOf(str.charAt(i)) \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){ - sb.append(str.charAt(i)); - } - } - tmp = sb.toString(); - editText01.setText(tmp); - } - }); ","permalink":"https://blog.zdltech.com/posts/android-edittext%E7%A6%81%E6%AD%A2%E8%BE%93%E5%85%A5%E4%B8%AD%E6%96%87%E5%AD%97%E7%AC%A6/","summary":"\u003cdiv id=\"article_content\" class=\"article_content\"\u003e\n\u003cpre\u003e\u003ccode\u003e只允许EditText输入数字或者email格式字符是非常简单的（详见API文档）。\n\n\n\n\n\n要实现只允许输入自定的数字字符也是很容易的（详见API文档，[setKeyListener(KeyListener)](http://blog.csdn.net/reference/android/widget/TextView.html#setKeyListener(android.text.method.KeyListener)) 和\u0026lt;span class=\u0026quot;sympad\u0026quot;\u0026gt;setFilters\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;normal\u0026quot;\u0026gt;([InputFilter[]](http://blog.csdn.net/reference/android/text/InputFilter.html) filters)\u0026lt;/span\u0026gt; ）。\n\n\n\n\n\n但是要限制只能输入指定的字母字符就非常的困难。\n\n\n\n\n\n/**\n\n\n\n\n\nInputFilter[] ifs = {new InputFilter.LengthFilter(10),new DigitsKeyListener(true,true)};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eeditText01.setFilters(ifs);\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**/\n\n\n\n\n\n\u0026amp;nbsp;\n\n\n\n\n\n发现，**[Android](http://lib.csdn.net/base/15):digits**的参数是一个字符串，没有更多的语义检查，因此想到内部处理很可能仅是简单的检查，输入的字符是否在给定的字符串中（要我设计，我就这样做）。尝试着给它指定带有英文字符的参数，发现果然如此。万幸，万幸！\n\n\n\n\n\n在layout.xml里\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_xml\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\"\u003e\n        **[xml]** [view plain](http://blog.csdn.net/jdsjlzx/article/details/6762751#)\u003cspan data-mod=\"popu_168\"\u003e\u003cspan data-mod=\"popu_168\"\u003e [copy](http://blog.csdn.net/jdsjlzx/article/details/6762751#)\u003c/span\u003e\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n      \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n      \u0026lt;/embed\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;EditText\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/register_userName_editText\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@style/register_editText_style\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:digits\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@string/register_name_digits\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/register_edit_text_textColor\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColorHint\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/register_hint_text_textColor\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:hint\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@string/register_name_hint_text\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026amp;nbsp;\n\n\n\n\n\n在string.xml里\n\n\n\n\n\n\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_xml\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\"\u003e\n        **[xml]** [view plain](http://blog.csdn.net/jdsjlzx/article/details/6762751#)\u003cspan data-mod=\"popu_168\"\u003e\u003cspan data-mod=\"popu_168\"\u003e [copy](http://blog.csdn.net/jdsjlzx/article/details/6762751#)\u003c/span\u003e\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n      \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n      \u0026lt;/embed\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;string\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;register_name_digits\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n  \n  - \n  - ._0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLIMNOPQRSTUVWXYZ\n  \n  - \n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;string\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026amp;nbsp;\n\n\n\n\n\n\u0026amp;nbsp;\n\n\n\n\n\n\u0026amp;nbsp;\n\n\n\n\n\n\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\"\u003e\n        Java代码\n      \u003c/div\u003e\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e  - editText01.addTextChangedListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TextWatcher() {\n  \n  - String tmp = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n  \n  - String digits = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;abcdef\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n  \n  - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTextChanged(CharSequence s, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; start, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; before, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; count) {\n  \n  - }\n  \n  - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; beforeTextChanged(CharSequence s, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; start, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; count, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; after) {\n  \n  - tmp = s.toString();\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; afterTextChanged(Editable s) {\n  \n  - Log.d(Sample4Main.TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;\u0026gt;\u0026lt;\u0026gt;afterTextChanged\u0026lt;\u0026gt;\u0026lt;\u0026gt;\u0026amp;#8221;\u0026lt;/span\u0026gt; + s.toString());\n  \n  - \n  - String str = s.toString();\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(str.equals(tmp)){\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;;\n  \n  - }\n  \n  - \n  - StringBuffer sb = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringBuffer();\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; str.length(); i++){\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(digits.indexOf(str.charAt(i)) \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){\n  \n  - sb.append(str.charAt(i));\n  \n  - }\n  \n  - }\n  \n  - tmp = sb.toString();\n  \n  - editText01.setText(tmp);\n  \n  - }\n  \n  - });\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"bdsharebuttonbox tracking-ad bdshare-button-style0-16\" data-mod=\"popu_172\" data-bd-bind=\"1469007867661\"\u003e\n\u003c/div\u003e\n\u003cdiv id=\"digg\"\u003e\n\u003c/div\u003e","title":"Android EditText禁止输入中文字符"},{"content":"前言\nTextView的drawableLeft、drawableRight和drawableTop是一个常用、好用的属性，可以在文本的上下左右放置一个图片，而不使用更加复杂布局就能达到，我也常常喜欢用RadioButton的这几个属性实现很多效果，但是苦于不支持让drawbleLeft与文本一起居中，设置gravity为center也无济于事，终于有空研究了一下，这里与大家一起分享。\n声明\n欢迎转载，请注明出处！\n博客园：http://www.cnblogs.com/\n农民伯伯： http://www.cnblogs.com/over140/\n正文\n一、效果图\n二、实现代码\n自定义控件\n![复制代码](http://common.cnblogs.com/images/copycode.gif) /** * drawableLeft与文本一起居中显示 * * @author 农民伯伯 * @see http://www.cnblogs.com/over140/p/3464348.html * */ public class DrawableCenterTextView extends TextView { public DrawableCenterTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }\npublic DrawableCenterTextView(Context context, AttributeSet attrs) { super(context, attrs); }\npublic DrawableCenterTextView(Context context) { super(context); }\n@Override protected void onDraw(Canvas canvas) { Drawable[] drawables = getCompoundDrawables(); if (drawables != null) { Drawable drawableLeft = drawables[0]; if (drawableLeft != null) { float textWidth = getPaint().measureText(getText().toString()); int drawablePadding = getCompoundDrawablePadding(); int drawableWidth = 0; drawableWidth = drawableLeft.getIntrinsicWidth(); float bodyWidth = textWidth + drawableWidth + drawablePadding; } } super.onDraw(canvas); } }\n![复制代码](http://common.cnblogs.com/images/copycode.gif) 和普通TextView用法一致，无需额外增加属性。\n2013-12-13注意，drawableRight不管用！感谢网友提醒，后续有进展了再更新文章。\n结束\n那些让你难受的技术问题一定要找时间想办法摆平TA！\n","permalink":"https://blog.zdltech.com/posts/android%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6%E8%AE%A9textview%E7%9A%84drawableleft%E4%B8%8E%E6%96%87%E6%9C%AC%E4%B8%80%E8%B5%B7%E5%B1%85%E4%B8%AD%E6%98%BE%E7%A4%BA/","summary":"\u003cp\u003e\u003cstrong\u003e前言\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eTextView的drawableLeft、drawableRight和drawableTop是一个常用、好用的属性，可以在文本的上下左右放置一个图片，而不使用更加复杂布局就能达到，我也常常喜欢用RadioButton的这几个属性实现很多效果，但是苦于不支持让drawbleLeft与文本一起居中，设置gravity为center也无济于事，终于有空研究了一下，这里与大家一起分享。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e声明\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e欢迎转载，请注明出处！\u003c/p\u003e\n\u003cp\u003e博客园：http://www.cnblogs.com/\u003c/p\u003e\n\u003cp\u003e农民伯伯： http://www.cnblogs.com/over140/\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e正文\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e一、效果图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/25060/201312/08221020-8d285ead3bd7425f9f5eccd67cb918f5.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e二、实现代码\u003c/p\u003e\n\u003cp\u003e自定义控件\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    /**\n * drawableLeft与文本一起居中显示\n *\n * @author 农民伯伯\n * @see http://www.cnblogs.com/over140/p/3464348.html\n *\n */\n public class DrawableCenterTextView extends TextView {\n\u003cpre\u003e\u003ccode\u003e  public DrawableCenterTextView(Context context, AttributeSet attrs,\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eint defStyle) {\nsuper(context, attrs, defStyle);\n}\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  public DrawableCenterTextView(Context context, AttributeSet attrs) {\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003esuper(context, attrs);\n}\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  public DrawableCenterTextView(Context context) {\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003esuper(context);\n}\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  @Override\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eprotected void onDraw(Canvas canvas) {\nDrawable[] drawables = getCompoundDrawables();\nif (drawables != null) {\nDrawable drawableLeft = drawables[0];\nif (drawableLeft != null) {\nfloat textWidth = getPaint().measureText(getText().toString());\nint drawablePadding = getCompoundDrawablePadding();\nint drawableWidth = 0;\ndrawableWidth = drawableLeft.getIntrinsicWidth();\nfloat bodyWidth = textWidth + drawableWidth + drawablePadding;\n}\n}\nsuper.onDraw(canvas);\n}\n}\u003c/p\u003e","title":"【Android】自定义控件让TextView的drawableLeft与文本一起居中显示"},{"content":"可以说这是一个Bug, 据说在4.0以上机器会出现，我测试是android 4.4.2\nXml代码 \u0026lt;embed src=\u0026quot;http://wv1124.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;a title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://wv1124.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:shape\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;line\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;stroke\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:dashGap\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;3dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:dashWidth\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;8dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:color\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#999999\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;size\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1dp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; layout中引用：\nXml代码 \u0026lt;embed src=\u0026quot;http://wv1124.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;a title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://wv1124.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;3dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/left_menu_dash_line\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; 在4.4.2上显示实线。\n解决：\nXml代码 \u0026lt;embed src=\u0026quot;http://wv1124.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;a title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://wv1124.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layerType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;software\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;3dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/left_menu_dash_line\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; 重点：\nXml代码 \u0026lt;embed src=\u0026quot;http://wv1124.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;a title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://wv1124.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layerType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;software\u0026amp;#8221;\u0026lt;/span\u0026gt; 也可以：\nJava代码 \u0026lt;embed src=\u0026quot;http://wv1124.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;a title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://wv1124.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;activity android:name=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;.TestActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; android:label=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Test\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:hardwareAccelerated=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; 重点关闭硬件加速：\nJava代码 \u0026lt;embed src=\u0026quot;http://wv1124.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;a title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://wv1124.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; - android:hardwareAccelerated=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;pln\u0026#34;\u0026gt;divider_under_pic\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34;\u0026gt;setLayerType\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;typ\u0026#34;\u0026gt;View\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34;\u0026gt;LAYER_TYPE_SOFTWARE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026lt;/span\u0026gt; 代码中使用setLayerType设置。\n参考：\nhttp://developer.android.com/guide/topics/graphics/hardware-accel.html\n","permalink":"https://blog.zdltech.com/posts/android-share%E7%BB%98%E5%88%B6%E8%99%9A%E7%BA%BF%E5%9C%A8%E6%89%8B%E6%9C%BA%E4%B8%8A%E6%98%BE%E7%A4%BA%E5%AE%9E%E7%BA%BF%E9%97%AE%E9%A2%98/","summary":"\u003cp\u003e可以说这是一个Bug, 据说在4.0以上机器会出现，我测试是android 4.4.2\u003c/p\u003e\n\u003cdiv id=\"\" class=\"dp-highlighter\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      Xml代码 \n\u003cpre\u003e\u003ccode\u003e  \u0026lt;embed src=\u0026quot;http://wv1124.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt;\n  \u0026lt;/embed\u0026gt; \n  \n  \u0026lt;a title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://wv1124.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:shape\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;line\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;stroke\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:dashGap\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;3dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:dashWidth\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;8dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:color\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#999999\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;size\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1dp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003elayout中引用：\u003c/p\u003e","title":"Android share绘制虚线在手机上显示实线问题"},{"content":"1.下载charles\n可以去charles官网下载,下载地址:http://www.charlesproxy.com/download/ 根据自己的操作系统下载对应的版本,然后进行安装,然后打开charles工具\n2.设置代理（记住手机跟电脑要在同一个网络,用的同一个路由器）\n1).查看默认端口 Proxy-\u0026gt;Proxy Settings 在这个页面会看到HTTP Proxy的默认端口是8888 我们不需要修改,只需要知道有这个值就行\n2).查看当前电脑的ip 例如我这里的是:192.168.9.129\n3).知道了默认端口跟ip地址,我们就可以手机上设置代理了。设置步骤我录制了gif动画。(我用的是genymotion模拟器,真机也是一样的)\n完成了以上两个步骤就可以抓到http请求的数据了,效果图如下:\n接下来讲解如何抓取https协议的包,如果你没有这个需求,请不要继续浏览下面的内容\n3.设置charles ssl代理\nProxy-\u0026gt;SSL Proxy Settings 弹出一个ssl代理设置界面\n1).Enable SSL Proxying复选框打上勾\n2).添加你想要的设置代理的域名,端口默认443\n设置过后效果图如下:\n4.手机下载ssl证书\n1).Help-\u0026gt;SSL Proxying -\u0026gt;Install Charles Root Certificate on a Mobile Device or Remote Browser…\n会弹出一个提示框,如下显示:\n浏览器输入这个地址即可下载证书,记住要用Android自带的浏览器. 地址是:http://charlesproxy.com/getssl 扫一扫二维码安装ssl\n2).然后按照他的提示安装证书即可.\n做完第三步跟第四步就可以抓包https数据了.如果还有问题请留言。。。下面是我抓包截图。\n方法二\nHTTP包：\n1.安装抓包工具 Charles , 到官网http://www.charlesproxy.com/可下载到最新版本\n2.用安装了charles的电脑，代理待抓包anroid手机的网络连接：\n首先查看pc的网络IP地址；打开手机设置，进入当前wifi连接，设置代理为手动，将服务器填为上一步中获得的IP，端口默认为8888（在charles的proxy setting中可以改这个端口号）。这时Charles弹出确认框，点击Allow按钮即可\n3.中文乱码问题解决\n在charles的content/info.plist 中 的vmoption 添加-Dfile.encoding=UTF-8\nHTTPS抓包:\n下载Charles证书http://www.charlesproxy.com/ssl.zip，解压后导入到手机中，然后设置-\u0026gt;安全-\u0026gt;凭据存储-\u0026gt;从存储设备安装，选中证书。 在Charles的工具栏上点击设置按钮，选择Proxy Settings；切换到SSL选项卡，选中Enable SSL Proxying，选项卡的Locations表单可以填写要抓包的域名和端口，点击Add按钮，在弹出的表单中Host填写域名，比如填api.instagram.com，Port填443。默认的..表示应用于所有地址 ","permalink":"https://blog.zdltech.com/posts/charles%E5%B7%A5%E5%85%B7%E6%8A%93%E5%8C%85%E6%95%99%E7%A8%8Bhttp%E8%B7%9Fhttps/","summary":"\u003cp\u003e\u003cstrong\u003e1.下载charles\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e可以去charles官网下载,下载地址:http://www.charlesproxy.com/download/    根据自己的操作系统下载对应的版本,然后进行安装,然后打开charles工具\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2.设置代理（记住手机跟电脑要在同一个网络,用的同一个路由器）\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e1).查看默认端口    Proxy-\u0026gt;Proxy Settings  在这个页面会看到HTTP Proxy的默认端口是8888   我们不需要修改,只需要知道有这个值就行\u003c/p\u003e\n\u003cp\u003e2).查看当前电脑的ip    例如我这里的是:192.168.9.129\u003c/p\u003e\n\u003cp\u003e3).知道了默认端口跟ip地址,我们就可以手机上设置代理了。设置步骤我录制了gif动画。(我用的是genymotion模拟器,真机也是一样的)\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20151016112543791\"\u003e\u003c/p\u003e\n\u003cp\u003e完成了以上两个步骤就可以抓到http请求的数据了,效果图如下:\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20150724120430269?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e接下来讲解如何抓取https协议的包,如果你没有这个需求,请不要继续浏览下面的内容\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3.设置charles ssl代理\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eProxy-\u0026gt;SSL Proxy Settings    弹出一个ssl代理设置界面\u003c/p\u003e\n\u003cp\u003e1).Enable SSL Proxying复选框打上勾\u003c/p\u003e\n\u003cp\u003e2).添加你想要的设置代理的域名,端口默认443\u003c/p\u003e\n\u003cp\u003e设置过后效果图如下:\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20150724133119860?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4.手机下载ssl证书\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e1).Help-\u0026gt;SSL Proxying -\u0026gt;Install Charles Root Certificate on a Mobile Device or Remote Browser…\u003c/p\u003e\n\u003cp\u003e会弹出一个提示框,如下显示:\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20150724133439949?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e浏览器输入这个地址即可下载证书,记住要用Android自带的浏览器.   地址是:http://charlesproxy.com/getssl   扫一扫二维码安装ssl\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.etongwl.com/images/2016/07/Charlessslurl.png\"\u003e\u003cimg alt=\"Charlessslurl\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2016/07/Charlessslurl.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e2).然后按照他的提示安装证书即可.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e做完第三步跟第四步就可以抓包https数据了.如果还有问题请留言。。。下面是我抓包截图。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20150724140858950?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e方法二\u003c/p\u003e\n\u003cp\u003eHTTP包：\u003c/p\u003e\n\u003cp\u003e1.安装抓包工具 Charles , 到官网\u003ca href=\"http://www.charlesproxy.com/\"\u003ehttp://www.charlesproxy.com/\u003c/a\u003e可下载到最新版本\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e2.用安装了charles的电脑，代理待抓包anroid手机的网络连接：\u003c/p\u003e\n\u003cp\u003e首先查看pc的网络IP地址；打开手机设置，进入当前wifi连接，设置代理为手动，将服务器填为上一步中获得的IP，端口默认为8888（在charles的proxy setting中可以改这个端口号）。这时Charles弹出确认框，点击Allow按钮即可\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e3.中文乱码问题解决\u003c/p\u003e\n\u003cp\u003e在charles的content/info.plist 中 的vmoption 添加-Dfile.encoding=UTF-8\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://dl2.iteye.com/upload/attachment/0106/1561/a0cc411d-482a-3fe7-a57e-d98470405d71.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eHTTPS抓包:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e下载Charles证书\u003ca href=\"http://www.charlesproxy.com/ssl.zip\"\u003ehttp://www.charlesproxy.com/ssl.zip\u003c/a\u003e，解压后导入到手机中，然后设置-\u0026gt;安全-\u0026gt;凭据存储-\u0026gt;从存储设备安装，选中证书。\u003c/li\u003e\n\u003cli\u003e在Charles的工具栏上点击设置按钮，选择Proxy Settings；切换到SSL选项卡，选中Enable SSL Proxying，选项卡的Locations表单可以填写要抓包的域名和端口，点击Add按钮，在弹出的表单中Host填写域名，比如填api.instagram.com，Port填443。默认的..表示应用于所有地址\u003c/li\u003e\n\u003c/ol\u003e","title":"charles工具抓包教程(http跟https)"},{"content":"本文将介绍InputStream与String,Byte之间的相互转换。以代码来说明：\n**[html]** [view plain](http://blog.csdn.net/cjjky/article/details/6892443#) [copy](http://blog.csdn.net/cjjky/article/details/6892443#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - import java.io.ByteArrayInputStream; - import java.io.ByteArrayOutputStream; - import java.io.IOException; - import java.io.InputStream; - - /** - * - * @author Andy.Chen - * @mail Chenjunjun.ZJ@gmail.com - * - */ - public class InputStreamUtils { - - final static int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;BUFFER_SIZE\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;4096\u0026lt;/span\u0026gt;; - - /** - * 将InputStream转换成String - * @param in InputStream - * @return String - * @throws Exception - * - */ - public static String InputStreamTOString(InputStream in) throws Exception{ - - ByteArrayOutputStream \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;outStream\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ByteArrayOutputStream(); - byte[] \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; byte[BUFFER_SIZE]; - int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt; = -1; - while((\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;in\u0026lt;/span\u0026gt;.read(data,0,BUFFER_SIZE)) != -1) - outStream.write(data, 0, count); - - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - return new String(outStream.toByteArray(),\u0026amp;#8221;ISO-8859-1\u0026amp;#8243;); - } - - /** - * 将InputStream转换成某种字符编码的String - * @param in - * @param encoding - * @return - * @throws Exception - */ - public static String InputStreamTOString(InputStream in,String encoding) throws Exception{ - - ByteArrayOutputStream \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;outStream\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ByteArrayOutputStream(); - byte[] \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; byte[BUFFER_SIZE]; - int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt; = -1; - while((\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;in\u0026lt;/span\u0026gt;.read(data,0,BUFFER_SIZE)) != -1) - outStream.write(data, 0, count); - - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - return new String(outStream.toByteArray(),\u0026amp;#8221;ISO-8859-1\u0026amp;#8243;); - } - - /** - * 将String转换成InputStream - * @param in - * @return - * @throws Exception - */ - public static InputStream StringTOInputStream(String in) throws Exception{ - - ByteArrayInputStream \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;is\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ByteArrayInputStream(in.getBytes(\u0026amp;#8220;ISO-8859-1\u0026amp;#8221;)); - return is; - } - - /** - * 将InputStream转换成byte数组 - * @param in InputStream - * @return byte[] - * @throws IOException - */ - public static byte[] InputStreamTOByte(InputStream in) throws IOException{ - - ByteArrayOutputStream \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;outStream\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ByteArrayOutputStream(); - byte[] \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; byte[BUFFER_SIZE]; - int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt; = -1; - while((\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;in\u0026lt;/span\u0026gt;.read(data,0,BUFFER_SIZE)) != -1) - outStream.write(data, 0, count); - - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - return outStream.toByteArray(); - } - - /** - * 将byte数组转换成InputStream - * @param in - * @return - * @throws Exception - */ - public static InputStream byteTOInputStream(byte[] in) throws Exception{ - - ByteArrayInputStream \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;is\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ByteArrayInputStream(in); - return is; - } - - /** - * 将byte数组转换成String - * @param in - * @return - * @throws Exception - */ - public static String byteTOString(byte[] in) throws Exception{ - - InputStream \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;is\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;byteTOInputStream\u0026lt;/span\u0026gt;(in); - return InputStreamTOString(is); - } - - } ","permalink":"https://blog.zdltech.com/posts/inputstream%E4%B8%8Estringbyte%E4%B9%8B%E9%97%B4%E4%BA%92%E8%BD%AC/","summary":"\u003cp\u003e本文将介绍InputStream与String,Byte之间的相互转换。以代码来说明：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/cjjky/article/details/6892443#)\u003cspan data-mod=\"popu_168\"\u003e\u003cspan data-mod=\"popu_168\"\u003e [copy](http://blog.csdn.net/cjjky/article/details/6892443#)\u003c/span\u003e\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- import java.io.ByteArrayInputStream;\n\n- import java.io.ByteArrayOutputStream;\n\n- import java.io.IOException;\n\n- import java.io.InputStream;\n\n- \n- /**\n\n- *\n\n- * @author Andy.Chen\n\n- * @mail Chenjunjun.ZJ@gmail.com\n\n- *\n\n- */\n\n- public class InputStreamUtils {\n\n- \n- final static int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;BUFFER_SIZE\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;4096\u0026lt;/span\u0026gt;;\n\n- \n- /**\n\n- * 将InputStream转换成String\n\n- * @param in InputStream\n\n- * @return String\n\n- * @throws Exception\n\n- *\n\n- */\n\n- public static String InputStreamTOString(InputStream in) throws Exception{\n\n- \n- ByteArrayOutputStream \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;outStream\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ByteArrayOutputStream();\n\n- byte[] \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; byte[BUFFER_SIZE];\n\n- int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt; = -1;\n\n- while((\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;in\u0026lt;/span\u0026gt;.read(data,0,BUFFER_SIZE)) != -1)\n\n- outStream.write(data, 0, count);\n\n- \n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n- return new String(outStream.toByteArray(),\u0026amp;#8221;ISO-8859-1\u0026amp;#8243;);\n\n- }\n\n- \n- /**\n\n- * 将InputStream转换成某种字符编码的String\n\n- * @param in\n\n- * @param encoding\n\n- * @return\n\n- * @throws Exception\n\n- */\n\n- public static String InputStreamTOString(InputStream in,String encoding) throws Exception{\n\n- \n- ByteArrayOutputStream \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;outStream\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ByteArrayOutputStream();\n\n- byte[] \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; byte[BUFFER_SIZE];\n\n- int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt; = -1;\n\n- while((\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;in\u0026lt;/span\u0026gt;.read(data,0,BUFFER_SIZE)) != -1)\n\n- outStream.write(data, 0, count);\n\n- \n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n- return new String(outStream.toByteArray(),\u0026amp;#8221;ISO-8859-1\u0026amp;#8243;);\n\n- }\n\n- \n- /**\n\n- * 将String转换成InputStream\n\n- * @param in\n\n- * @return\n\n- * @throws Exception\n\n- */\n\n- public static InputStream StringTOInputStream(String in) throws Exception{\n\n- \n- ByteArrayInputStream \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;is\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ByteArrayInputStream(in.getBytes(\u0026amp;#8220;ISO-8859-1\u0026amp;#8221;));\n\n- return is;\n\n- }\n\n- \n- /**\n\n- * 将InputStream转换成byte数组\n\n- * @param in InputStream\n\n- * @return byte[]\n\n- * @throws IOException\n\n- */\n\n- public static byte[] InputStreamTOByte(InputStream in) throws IOException{\n\n- \n- ByteArrayOutputStream \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;outStream\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ByteArrayOutputStream();\n\n- byte[] \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; byte[BUFFER_SIZE];\n\n- int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt; = -1;\n\n- while((\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;in\u0026lt;/span\u0026gt;.read(data,0,BUFFER_SIZE)) != -1)\n\n- outStream.write(data, 0, count);\n\n- \n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n- return outStream.toByteArray();\n\n- }\n\n- \n- /**\n\n- * 将byte数组转换成InputStream\n\n- * @param in\n\n- * @return\n\n- * @throws Exception\n\n- */\n\n- public static InputStream byteTOInputStream(byte[] in) throws Exception{\n\n- \n- ByteArrayInputStream \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;is\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ByteArrayInputStream(in);\n\n- return is;\n\n- }\n\n- \n- /**\n\n- * 将byte数组转换成String\n\n- * @param in\n\n- * @return\n\n- * @throws Exception\n\n- */\n\n- public static String byteTOString(byte[] in) throws Exception{\n\n- \n- InputStream \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;is\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;byteTOInputStream\u0026lt;/span\u0026gt;(in);\n\n- return InputStreamTOString(is);\n\n- }\n\n- \n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"InputStream与String,Byte之间互转"},{"content":" 有时候在开发中会遇到一些“诡异”的要求，比如在ViewPager中嵌入ListView，或者再嵌入一个ViewPager，那么在滑动的时候就会造成被嵌入的XXView不能滑动了，那么现在就把最外层的ViewPager禁止滑动吧，让被嵌入的XXView获得滑动事件好了。关于解决方法，网上也有很多说法，基本上是一致的，但是需要理解这个[Android](http://lib.csdn.net/base/15)下的事件分发机制才行，不明白事件分发机制的，上网查些资料看看，然后我这里也有简单的介绍，请参看博客Android自定义控件——侧滑菜单的下方。 怎样禁止ViewPager左右滑动呢？大致就是重写ViewPager，覆盖ViewPager的onInterceptTouchEvent(MotionEvent arg0)方法和onTouchEvent(MotionEvent arg0)方法，这两个方法的返回值都是boolean类型的，只需要将返回值改为false，那么ViewPager就不会消耗掉手指滑动的事件了，转而传递给上层View去处理或者该事件就直接终止了。下面是我的自定义ViewPager。 ``` `\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-class\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;NoScrollViewPager\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;ViewPager\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;boolean\u0026lt;/span\u0026gt; noScroll = \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;false\u0026lt;/span\u0026gt;;\n\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;NoScrollViewPager\u0026amp;lt;/span\u0026gt;(Context context, AttributeSet attrs) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;(context, attrs); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// TODO Auto-generated constructor stub\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;NoScrollViewPager\u0026amp;lt;/span\u0026gt;(Context context) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;(context); } \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;setNoScroll\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; noScroll) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;this\u0026amp;lt;/span\u0026gt;.noScroll = noScroll; } \u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;scrollTo\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; x, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; y) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;.scrollTo(x, y); } \u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onTouchEvent\u0026amp;lt;/span\u0026gt;(MotionEvent arg0) { \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;/* return false;//super.onTouchEvent(arg0); */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt; (noScroll) \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onTouchEvent(arg0); } \u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onInterceptTouchEvent\u0026amp;lt;/span\u0026gt;(MotionEvent arg0) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt; (noScroll) \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onInterceptTouchEvent(arg0); } \u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;setCurrentItem\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; item, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; smoothScroll) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;.setCurrentItem(item, smoothScroll); } \u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;setCurrentItem\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; item) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;.setCurrentItem(item); } }`\n以上代码特别简单，大家可以直接拷贝使用，无需做任何修改。为了操作方便，我在这个自定义的ViewPager里设置了一个boolean类型的控制变量，并且向外提供了控制ViewPager是否禁止滑动的方法，这样就显得灵活一点了。以下是自定义ViewPager在布局文件中的定义。 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;bdsharebuttonbox tracking-ad bdshare-button-style0-16\u0026#34; data-mod=\u0026#34;popu_172\u0026#34; data-bd-bind=\u0026#34;1468568592292\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026#34;digg\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android%E7%A6%81%E6%AD%A2viewpager%E7%9A%84%E5%B7%A6%E5%8F%B3%E6%BB%91%E5%8A%A8/","summary":"\u003cdiv id=\"article_content\" class=\"article_content\"\u003e\n  \u003cdiv class=\"markdown_views\"\u003e\n\u003cpre\u003e\u003ccode\u003e  有时候在开发中会遇到一些“诡异”的要求，比如在ViewPager中嵌入ListView，或者再嵌入一个ViewPager，那么在滑动的时候就会造成被嵌入的XXView不能滑动了，那么现在就把最外层的ViewPager禁止滑动吧，让被嵌入的XXView获得滑动事件好了。关于解决方法，网上也有很多说法，基本上是一致的，但是需要理解这个[Android](http://lib.csdn.net/base/15)下的事件分发机制才行，不明白事件分发机制的，上网查些资料看看，然后我这里也有简单的介绍，请参看博客Android自定义控件——侧滑菜单的下方。\n\n\n\n\n\n  怎样禁止ViewPager左右滑动呢？大致就是重写ViewPager，覆盖ViewPager的onInterceptTouchEvent(MotionEvent arg0)方法和onTouchEvent(MotionEvent arg0)方法，这两个方法的返回值都是boolean类型的，只需要将返回值改为false，那么ViewPager就不会消耗掉手指滑动的事件了，转而传递给上层View去处理或者该事件就直接终止了。下面是我的自定义ViewPager。\n\n\n\n```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e`\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-class\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;NoScrollViewPager\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;ViewPager\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;boolean\u0026lt;/span\u0026gt; noScroll = \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;false\u0026lt;/span\u0026gt;;\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;NoScrollViewPager\u0026amp;lt;/span\u0026gt;(Context context, AttributeSet attrs) {\n    \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;(context, attrs);\n    \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// TODO Auto-generated constructor stub\u0026amp;lt;/span\u0026gt;\n}\n\n\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;NoScrollViewPager\u0026amp;lt;/span\u0026gt;(Context context) {\n    \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;(context);\n}\n\n\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;setNoScroll\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; noScroll) {\n    \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;this\u0026amp;lt;/span\u0026gt;.noScroll = noScroll;\n}\n\n\u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;scrollTo\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; x, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; y) {\n    \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;.scrollTo(x, y);\n}\n\n\u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onTouchEvent\u0026amp;lt;/span\u0026gt;(MotionEvent arg0) {\n    \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;/* return false;//super.onTouchEvent(arg0); */\u0026amp;lt;/span\u0026gt;\n    \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt; (noScroll)\n        \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;;\n    \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026amp;lt;/span\u0026gt;\n        \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onTouchEvent(arg0);\n}\n\n\u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onInterceptTouchEvent\u0026amp;lt;/span\u0026gt;(MotionEvent arg0) {\n    \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt; (noScroll)\n        \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;;\n    \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026amp;lt;/span\u0026gt;\n        \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onInterceptTouchEvent(arg0);\n}\n\n\u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;setCurrentItem\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; item, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; smoothScroll) {\n    \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;.setCurrentItem(item, smoothScroll);\n}\n\n\u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;setCurrentItem\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; item) {\n    \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;.setCurrentItem(item);\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e}`\u003c/p\u003e","title":"Android禁止ViewPager的左右滑动"},{"content":"查询了google发现在android一下有几种方法可以做到，但是经过实际测试发现下面这种方法是最准确的\nRect bounds = new Rect(); String text = \u0026#34;Hello World\u0026#34;; TextPaint paint; paint = findViewById(R.id.hello_world).getPaint(); paint.getTextBounds(text, 0, text.length(), bounds); int width = bounds.width(); ``` Paint pFont = new Paint(); Rect rect = new Rect(); pFont.getTextBounds(\"豆\", 0, 1, rect); Log.v(TAG, \"height:\"+rect.height()+\"width:\"+rect.width()); ## Android_FontMetrics对象的各种基准线(以及怎么获取文字的width和height) \u0026lt;/div\u0026gt; Canvas 作为绘制文本时，使用FontMetrics对象，计算位置的坐标。 public static class FontMetrics { /** * The maximum distance above the baseline for the tallest glyph in * the font at a given text size. / public float top; /* * The recommended distance above the baseline for singled spaced text. / public float ascent; /* * The recommended distance below the baseline for singled spaced text. / public float descent; /* * The maximum distance below the baseline for the lowest glyph in * the font at a given text size. / public float bottom; /* * The recommended additional space to add between lines of text. */ public float leading; }\n它的各基准线可以参考下图： ![](http://my.csdn.net/uploads/201206/07/1339061786_4121.PNG) 上图其实是通过\u0026lt;span class=\u0026#34;wp_keywordlink\u0026#34;\u0026gt;[代码](http://www.xuebuyuan.com/)\u0026lt;/span\u0026gt;画出来的，具体代码如下： /** 绘制FontMetrics对象的各种线 */ mPaint.reset(); mPaint.setColor(Color.WHITE); mPaint.setTextSize(80); // FontMetrics对象 FontMetrics fontMetrics = mPaint.getFontMetrics(); String text = \u0026ldquo;abcdefg\u0026rdquo;; // 计算每一个坐标 float textWidth = mPaint.measureText(text); float baseX = 30; float baseY = 700; float topY = baseY + fontMetrics.top; float ascentY = baseY + fontMetrics.ascent; float descentY = baseY + fontMetrics.descent; float bottomY = baseY + fontMetrics.bottom; // 绘制文本 canvas.drawText(text, baseX, baseY, mPaint); // BaseLine描画 mPaint.setColor(Color.RED); canvas.drawLine(baseX, baseY, baseX + textWidth, baseY, mPaint); mPaint.setTextSize(20); canvas.drawText(\u0026ldquo;base\u0026rdquo;, baseX + textWidth, baseY, mPaint); // Base描画 canvas.drawCircle(baseX, baseY, 5, mPaint); // TopLine描画 mPaint.setColor(Color.LTGRAY); canvas.drawLine(baseX, topY, baseX + textWidth, topY, mPaint); canvas.drawText(\u0026ldquo;top\u0026rdquo;, baseX + textWidth, topY, mPaint); // AscentLine描画 mPaint.setColor(Color.GREEN); canvas.drawLine(baseX, ascentY, baseX + textWidth, ascentY, mPaint); canvas.drawText(\u0026ldquo;ascent\u0026rdquo;, baseX + textWidth, ascentY + 10, mPaint); // DescentLine描画 mPaint.setColor(Color.YELLOW); canvas.drawLine(baseX, descentY, baseX + textWidth, descentY, mPaint); canvas.drawText(\u0026ldquo;descent\u0026rdquo;, baseX + textWidth, descentY, mPaint); // ButtomLine描画 mPaint.setColor(Color.MAGENTA); canvas.drawLine(baseX, bottomY, baseX + textWidth, bottomY, mPaint); canvas.drawText(\u0026ldquo;buttom\u0026rdquo;, baseX + textWidth, bottomY + 10, mPaint);\n相信通过以上\u0026lt;span class=\u0026#34;wp_keywordlink\u0026#34;\u0026gt;[程序](http://www.xuebuyuan.com/)\u0026lt;/span\u0026gt;，能够很好的理解topLine，buttomLine，baseLine，ascentLine，descentLine。 另外：Paint类有两个方法 /**\nReturn the distance above (negative) the baseline (ascent) based on the current typeface and text size. @return the distance above (negative) the baseline (ascent) based on the current typeface and text size. */ public native float ascent();\n/**\nReturn the distance below (positive) the baseline (descent) based on the current typeface and text size. @return the distance below (positive) the baseline (descent) based on the current typeface and text size. */ public native float descent();\nascent()：the distance above the baseline（baseline以上的height） descent()：the distance below the baseline（baseline以下的height） 所以ascent() + descent() 可以看成文字的height。 到此为止，怎么获取文字的height和width都已经揭晓了： 获取height ： mPaint.ascent() + mPaint.descent() 获取width ： mPaint.measureText(text) \u0026amp;nbsp; ","permalink":"https://blog.zdltech.com/posts/android%E4%B8%8B%E5%A6%82%E4%BD%95%E8%AE%A1%E7%AE%97%E8%A6%81%E6%98%BE%E7%A4%BA%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%89%80%E5%8D%A0%E7%9A%84%E5%AE%BD%E5%BA%A6%E5%92%8C%E9%AB%98%E5%BA%A6/","summary":"\u003cp\u003e查询了google发现在android一下有几种方法可以做到，但是经过实际测试发现下面这种方法是最准确的\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eRect bounds = new Rect();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eString text = \u0026#34;Hello World\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eTextPaint paint;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epaint = findViewById(R.id.hello_world).getPaint();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epaint.getTextBounds(text, 0, text.length(), bounds);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eint width = bounds.width();\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  ```\nPaint pFont = new Paint();\nRect rect = new Rect();\npFont.getTextBounds(\"豆\", 0, 1, rect);\nLog.v(TAG, \"height:\"+rect.height()+\"width:\"+rect.width());\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  ## Android_FontMetrics对象的各种基准线(以及怎么获取文字的width和height)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eCanvas 作为绘制文本时，使用FontMetrics对象，计算位置的坐标。\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003epublic static class FontMetrics {\n/**\n* The maximum distance above the baseline for the tallest glyph in\n* the font at a given text size.\n\u003cem\u003e/\npublic float   top;\n/\u003c/em\u003e*\n* The recommended distance above the baseline for singled spaced text.\n\u003cem\u003e/\npublic float   ascent;\n/\u003c/em\u003e*\n* The recommended distance below the baseline for singled spaced text.\n\u003cem\u003e/\npublic float   descent;\n/\u003c/em\u003e*\n* The maximum distance below the baseline for the lowest glyph in\n* the font at a given text size.\n\u003cem\u003e/\npublic float   bottom;\n/\u003c/em\u003e*\n* The recommended additional space to add between lines of text.\n*/\npublic float   leading;\n}\u003c/p\u003e","title":"Android下如何计算要显示的字符串所占的宽度和高度"},{"content":"//间隔发送心跳包数据给服务器，服务器在一定时间内发回心跳包响应，对比超时限定，如果超过设定的超时时间，则认为当前与服务器的websocket连接已经断开，关闭当前web socket连接，善后处理，例如重新连接，或者弹出提示……\nfunction keepalive(ws) {\nvar time = new Date();\n//连接断开，可设置重连或者关闭连接\n(“#keeplive_box”).html(“服务器没有响应.”).css({ “color” : “red” }); //ws.close(); } else {(“#keeplive_box”).html(“连接正常”).css({\n“color” : “green”\n});\nif (ws.bufferedAmount == 0) {\nws.send(‘H#C’);\n}\n}\n}\nvar ws = new WebSocket(to_url);\nws.onopen = function () {\n(“#statustxt”).html(“connected.”);(“#send_btn”).attr(“disabled”, false);\nheartbeat_timer = setInterval(function () {\nkeepalive(ws)\n}, 3000);\n}\n","permalink":"https://blog.zdltech.com/posts/websocket%E5%BF%83%E8%B7%B3%E5%AE%9E%E7%8E%B0/","summary":"\u003cp\u003e//间隔发送心跳包数据给服务器，服务器在一定时间内发回心跳包响应，对比超时限定，如果超过设定的超时时间，则认为当前与服务器的websocket连接已经断开，关闭当前web socket连接，善后处理，例如重新连接，或者弹出提示……\u003cbr\u003e\nfunction keepalive(ws) {\u003cbr\u003e\nvar time = new Date();\u003cbr\u003e\n//连接断开，可设置重连或者关闭连接\u003cbr\u003e\n\u003cspan class=\"katex math inline\"\u003e(“#keeplive_box”).html(“服务器没有响应.”).css({\n“color” : “red”\n});\n//ws.close();\n} else {\u003c/span\u003e(“#keeplive_box”).html(“连接正常”).css({\u003cbr\u003e\n“color” : “green”\u003cbr\u003e\n});\u003cbr\u003e\nif (ws.bufferedAmount == 0) {\u003cbr\u003e\nws.send(‘\u003cdel\u003eH#C\u003c/del\u003e’);\u003cbr\u003e\n}\u003cbr\u003e\n}\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003evar ws = new WebSocket(to_url);\u003cbr\u003e\nws.onopen = function () {\u003cbr\u003e\n\u003cspan class=\"katex math inline\"\u003e(“#statustxt”).html(“connected.”);\u003c/span\u003e(“#send_btn”).attr(“disabled”, false);\u003cbr\u003e\nheartbeat_timer = setInterval(function () {\u003cbr\u003e\nkeepalive(ws)\u003cbr\u003e\n}, 3000);\u003cbr\u003e\n}\u003c/p\u003e","title":"WebSocket心跳实现"},{"content":"优点：\n耦合性低 重用性高 生命周期成本低 部署快 可维护性高 有利软件工程化管理 缺点：\n没有明确的定义 不适合小型、中等规模 增加系统结构和实现的复杂性 视图与控制器间过于紧密的连接 视图对模型数据的低效率访问 一般高级的界面工具或构造器不支持模式 ","permalink":"https://blog.zdltech.com/posts/mvc%E6%A8%A1%E5%BC%8F%E4%BC%98%E7%BC%BA%E7%82%B9/","summary":"\u003cp\u003e优点：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e耦合性低\u003c/li\u003e\n\u003cli\u003e重用性高\u003c/li\u003e\n\u003cli\u003e生命周期成本低\u003c/li\u003e\n\u003cli\u003e部署快\u003c/li\u003e\n\u003cli\u003e可维护性高\u003c/li\u003e\n\u003cli\u003e有利软件工程化管理\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e缺点：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e没有明确的定义\u003c/li\u003e\n\u003cli\u003e不适合小型、中等规模\u003c/li\u003e\n\u003cli\u003e增加系统结构和实现的复杂性\u003c/li\u003e\n\u003cli\u003e视图与控制器间过于紧密的连接\u003c/li\u003e\n\u003cli\u003e视图对模型数据的低效率访问\u003c/li\u003e\n\u003cli\u003e一般高级的界面工具或构造器不支持模式\u003c/li\u003e\n\u003c/ol\u003e","title":"MVC模式优缺点"},{"content":"//判断android 版本然后设置Systembar颜色-设置透明 public void initSystemBar() { Window window = getWindow(); //4.4版本及以上 if (Build.VERSION.SDK_INT \u0026amp;gt;= Build.VERSION_CODES.KITKAT) { window.setFlags( WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } //5.0版本及以上 if (Build.VERSION.SDK_INT \u0026amp;gt;= Build.VERSION_CODES.LOLLIPOP) { window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(Color.TRANSPARENT); } } ","permalink":"https://blog.zdltech.com/posts/android-sdk-19%E4%BB%A5%E4%B8%8A%E4%BB%A3%E7%A0%81%E8%AE%BE%E7%BD%AE%E7%8A%B6%E6%80%81%E6%A0%8F%E9%80%8F%E6%98%8E/","summary":"\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e//判断android 版本然后设置Systembar颜色-设置透明\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   public void initSystemBar() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       Window window = getWindow();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       //4.4版本及以上\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        if (Build.VERSION.SDK_INT \u0026amp;gt;= Build.VERSION_CODES.KITKAT) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           window.setFlags(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                   WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       //5.0版本及以上\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        if (Build.VERSION.SDK_INT \u0026amp;gt;= Build.VERSION_CODES.LOLLIPOP) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                   | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                   | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           window.setStatusBarColor(Color.TRANSPARENT);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"android SDK 19以上代码设置状态栏透明"},{"content":"The user guide for this mirror\nPowered by Tencent Bugly (bugly.qq.com)\n- [ANDROID SDK](http://android-mirror.bugly.qq.com:8080/include/usage.html#androidsdk) - [Android Studio](http://android-mirror.bugly.qq.com:8080/include/usage.html#ASD) \u0026lt;div class=\u0026quot;tab-content\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;androidsdk\u0026quot; class=\u0026quot;tab active\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;subtitle\u0026quot;\u0026gt;☀ Windows\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**A. 打开Android SDK Manager**\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**B. 设置代理**\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;请务必选择: Force https://\u0026amp;#8230; sources to be fetched using http://\u0026amp;#8230;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**C. 检查代理是否正常工作**\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;点击菜单Package\u0026gt;Reload，如果能获取新版本，表明可以正常访问镜像\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**D. 选择包进行安装**\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;subtitle\u0026quot;\u0026gt;☀ Mac\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**A. Terminal下，cd到android sdk部署目录**\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**B. 打开Android SDK Manager**\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**C. SDK Manager的菜单**\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;注意：在Mac上第一次打开SDK Manager的时候，SDK Manager的窗口是模态的，此时的菜单是无法点击的，你需要先切换到其他窗口，再切回SDK Manager，菜单项就可以正常使用了\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**D. 打开Preferences**\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**E. 设置代理**\u0026lt;/span\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-sdk%E6%9B%B4%E6%96%B0-%E9%95%9C%E5%83%8F%E8%AE%BE%E7%BD%AE/","summary":"\u003cp\u003e\u003cspan class=\"headline\"\u003eThe user guide for this mirror\u003c/span\u003e\u003cbr\u003e\n\u003cspan class=\"ts\"\u003ePowered by Tencent Bugly (\u003ca href=\"http://bugly.qq.com/\"\u003ebugly.qq.com\u003c/a\u003e)\u003c/span\u003e\u003c/p\u003e\n\u003cdiv class=\"main\"\u003e\n  \u003cdiv class=\"tabs animated-fade\"\u003e\n\u003cpre\u003e\u003ccode\u003e  - [ANDROID SDK](http://android-mirror.bugly.qq.com:8080/include/usage.html#androidsdk)\n  \n  - [Android Studio](http://android-mirror.bugly.qq.com:8080/include/usage.html#ASD)\n  \n\n\n\u0026lt;div class=\u0026quot;tab-content\u0026quot;\u0026gt;\n  \u0026lt;div id=\u0026quot;androidsdk\u0026quot; class=\u0026quot;tab active\u0026quot;\u0026gt;\n    \u0026lt;span class=\u0026quot;subtitle\u0026quot;\u0026gt;☀ Windows\u0026lt;/span\u0026gt;\n\n    \n    \n\n      \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**A. 打开Android SDK Manager**\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://android-mirror.bugly.qq.com:8080/include/images/sdk_manager.png\"\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**B. 设置代理**\u0026lt;/span\u0026gt;\n    \n\n    \n    \n\n      \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;请务必选择: Force https://\u0026amp;#8230; sources to be fetched using http://\u0026amp;#8230;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://android-mirror.bugly.qq.com:8080/include/images/proxy.png\"\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**C. 检查代理是否正常工作**\u0026lt;/span\u0026gt;\n    \n\n    \n    \n\n      \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;点击菜单Package\u0026gt;Reload，如果能获取新版本，表明可以正常访问镜像\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://android-mirror.bugly.qq.com:8080/include/images/7_reload_check.png\"\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**D. 选择包进行安装**\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://android-mirror.bugly.qq.com:8080/include/images/8_install.png\"\u003e\n\u003cimg loading=\"lazy\" src=\"http://android-mirror.bugly.qq.com:8080/include/images/9_install.png\"\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;span class=\u0026quot;subtitle\u0026quot;\u0026gt;☀ Mac\u0026lt;/span\u0026gt;\n    \n\n    \n    \n\n      \u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;**A. Terminal下，cd到android sdk部署目录**\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://android-mirror.bugly.qq.com:8080/include/images/4_cdtoandroidhome.png\"\u003e\u003c/p\u003e","title":"android SDK更新 镜像设置"},{"content":" *原文* [http://chensd.com/2015-07/websocket-stress-test-and-performance-test.html](http://chensd.com/2015-07/websocket-stress-test-and-performance-test.html?utm_source=tuicool\u0026utm_medium=referral) 主题 [WebSocket](http://www.tuicool.com/topics/11060032)[压力测试](http://www.tuicool.com/topics/11350019) 相对于短连接应用，长连接应用的测试要麻烦得多——尤其是性能和压力测试。此前，甚至从来没有给任何一个上线的 WebSocket 应用做过这方面的测试，前两天，看到有人在 [SegmentFault 上问](http://segmentfault.com/q/1010000003028043) 这方面的问题，刚好又有空，于是想着，还是来查查这方面的资料吧。在 Github 上一搜，还真有现成的工具，名字很简单，直接就叫[websocket-bench](https://github.com/M6Web/websocket-bench) ， websocket-bench 是个用 Node.js 编写的命令行工具，可以对使用 Socket.io、[faye](https://github.com/faye/faye) 、 [Primus](https://github.com/primus/primus) 、 [WAMP](https://github.com/tavendo/WAMP) 编写的长连接应用进行性能和压力测试，用法和参数与 ab 差不多，多了一个指定连接成功后进行的操作的定义。 ### websocket-bench 安装 需要使用 npm 以全局的方式来安装 websocket-bench，当然要用阿里提供的 []福利服务器](http://npm.taobao.org/) ，如下： \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; ``` npm install -g websocket-bench \u0026ndash;registry=http://registry.npm.taobao.org\n\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ### 基本使用 这里以在 CentOS 6.5 上进行测试为便进行说明。首先要修改一下文件打开数，默认是1024，修改为一个比较大的值就行，总共65535个端口，我们测试也不会用太大的并发，websocket-bench 推荐设置的是 60000 ，命令如下： \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; ``` ulimit -n 60000 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; websocket-bench 的参数与 ab 基本一致，像这样 \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; ``` websocket-bench -a 300 -c 29 http://localhost:8100 -o opt.log\n\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; `-a` 参数用于指定总共的测试次数， `-c` 参数指定并发连接数。我这里测试的是一个 Socket.io 的服务器，所以不需要使用 `-t` 参数指定类型，如果是其它的，则需要使用 `engine.io` `faye` `primus` `wamp` 进行指定。运行完成后，会打印报告，报告分两小部分，前一部分是以 `-c` 指定的数量组织的表格，后一部分是整个测试的统计，数据包括错误数和消耗时间。 使用 `-o` 参数可以将报告保存到单独的文件中。 ### 使用 generator 来自定义测试逻辑 长连接压力测试麻烦的一部分，就在于连接完成后需要完成一定的交互操作，websocket-bench 通过 `generator` 文件来方便测试人员编写连接上服务器后所需要执行的操作。下面是我为了简单的测试一个2D地图移动游戏的简单测试文件： \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; ``` module.exports = { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//可选，在建立连接之前会执行\u0026lt;/span\u0026gt; beforeConnect: \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;function\u0026lt;/span\u0026gt;(client){ }, \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//必选，建立连接后所要做的事情\u0026lt;/span\u0026gt; onConnect: \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;function\u0026lt;/span\u0026gt;(client, done){ \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//向服务器发送消息\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//client 为客户端的连接实例\u0026lt;/span\u0026gt; client.emit(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#39;setTitle\u0026#39;\u0026lt;/span\u0026gt;, {title: \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#39;bench_\u0026#39;\u0026lt;/span\u0026gt; + randomNumber(), pVer: \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;}); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//回调函数\u0026lt;/span\u0026gt; done(); }, \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//必选，向服务器民送消息时运行的代码\u0026lt;/span\u0026gt; sendMessage: \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;function\u0026lt;/span\u0026gt;(client, done) { client.emit(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#39;moveTo\u0026#39;\u0026lt;/span\u0026gt;, {x: randomNumber(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;3500\u0026lt;/span\u0026gt;), y: randomNumber(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;3500\u0026lt;/span\u0026gt;)}); done(); } }; \u0026lt;span class=\u0026#34;function\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;function\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;function\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;randomNumber\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;params\u0026#34;\u0026gt;(max)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;function\u0026#34;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; Math.floor(Math.random()* (max || \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100000\u0026lt;/span\u0026gt;)); } \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 编写完成后，在运行 websocket-bench 时，使用 `-g` 参数指定 generator 文件即可。 另外，测试的时候，可以使用 [iptraf](http://iptraf.seul.org/) 工具来看看带宽的占用情况。 ","permalink":"https://blog.zdltech.com/posts/websocket-%E7%9A%84%E6%80%A7%E8%83%BD%E4%B8%8E%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95/","summary":"\u003cdiv class=\"article_meta\"\u003e\n  \u003cdiv class=\"source\"\u003e\n    *原文*  [http://chensd.com/2015-07/websocket-stress-test-and-performance-test.html](http://chensd.com/2015-07/websocket-stress-test-and-performance-test.html?utm_source=tuicool\u0026utm_medium=referral)\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    主题 [\u003cspan class=\"new-label\"\u003eWebSocket\u003c/span\u003e](http://www.tuicool.com/topics/11060032)[\u003cspan class=\"new-label\"\u003e压力测试\u003c/span\u003e](http://www.tuicool.com/topics/11350019)\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv id=\"nei\" class=\"article_body\"\u003e\n  \u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e  相对于短连接应用，长连接应用的测试要麻烦得多——尤其是性能和压力测试。此前，甚至从来没有给任何一个上线的 WebSocket 应用做过这方面的测试，前两天，看到有人在 [SegmentFault 上问](http://segmentfault.com/q/1010000003028043) 这方面的问题，刚好又有空，于是想着，还是来查查这方面的资料吧。在 Github 上一搜，还真有现成的工具，名字很简单，直接就叫[websocket-bench](https://github.com/M6Web/websocket-bench) ，\n\n\n\n\n\n  websocket-bench 是个用 Node.js 编写的命令行工具，可以对使用 Socket.io、[faye](https://github.com/faye/faye) 、 [Primus](https://github.com/primus/primus) 、 [WAMP](https://github.com/tavendo/WAMP) 编写的长连接应用进行性能和压力测试，用法和参数与 ab 差不多，多了一个指定连接成功后进行的操作的定义。\n\n\n\n### websocket-bench 安装\n\n\n\n  需要使用 npm 以全局的方式来安装 websocket-bench，当然要用阿里提供的 []福利服务器](http://npm.taobao.org/) ，如下：\n\n\n\n\u0026lt;div\u0026gt;\n  \u0026lt;div\u0026gt;\n    ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003enpm install -g websocket-bench \u0026ndash;registry=http:\u003cspan class=\"comment\"\u003e//registry.npm.taobao.org\u003c/span\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ### 基本使用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      这里以在 CentOS 6.5 上进行测试为便进行说明。首先要修改一下文件打开数，默认是1024，修改为一个比较大的值就行，总共65535个端口，我们测试也不会用太大的并发，websocket-bench 推荐设置的是 60000 ，命令如下：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eulimit -n 60000\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n\n  websocket-bench 的参数与 ab 基本一致，像这样\n\n\n\n\u0026lt;div\u0026gt;\n  \u0026lt;div\u0026gt;\n    ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003ewebsocket-bench -a \u003cspan class=\"number\"\u003e300\u003c/span\u003e -c \u003cspan class=\"number\"\u003e29\u003c/span\u003e http:\u003cspan class=\"comment\"\u003e//localhost:8100 -o opt.log\u003c/span\u003e\u003c/p\u003e","title":"WebSocket 的性能与压力测试"},{"content":"1、MongoDB 介绍\nMongoDB是一个基于分布式文件存储的数据库。由C++语言编写。主要解决的是海量数据的访问效率问题，为WEB应用提供可扩展的高性能数据存储解决方案。当数据量达到50GB以上的时候，MongoDB的数据库访问速度是MySQL的10倍以上。MongoDB的并发读写效率不是特别出色，根据官方提供的性能测试表明，大约每秒可以处理0.5万~1.5万次读写请求。MongoDB还自带了一个出色的分布式文件系统GridFS，可以支持海量的数据存储。\nMongoDB也有一个Ruby的项目MongoMapper，是模仿Merb的DataMapper编写的MongoDB接口，使用起来非常简单，几乎和DataMapper一模一样，功能非常强大。\nMongoDB是一个介于关系数据库和非关系数据库之间的产品，是非关系数据库当中功能最丰富，最像关系数据库的。他支持的数据结构非常松散，是类似json的bjson格式，因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大，其语法有点类似于面向对象的查询语言，几乎可以实现类似关系数据库单表查询的绝大部分功能，而且还支持对数据建立索引。\n所谓“面向集合”（Collenction-Orented），意思是数据被分组存储在数据集中，被称为一个集合（Collenction)。每个 集合在数据库中都有一个唯一的标识名，并且可以包含无限数目的文档。集合的概念类似关系型数据库（RDBMS）里的表（table），不同的是它不需要定 义任何模式（schema)。\n模式自由（schema-free)，意味着对于存储在mongodb数据库中的文件，我们不需要知道它的任何结构定义。如果需要的话，你完全可以把不同结构的文件存储在同一个数据库里。\n存储在集合中的文档，被存储为键-值对的形式。键用于唯一标识一个文档，为字符串类型，而值则可以是各中复杂的文件类型。我们称这种存储形式为BSON（Binary Serialized dOcument Format）。\nMongoDB服务端可运行在Linux、Windows或OS X平台，支持32位和64位应用，默认端口为27017。推荐运行在64位平台，因为MongoDB在32位模式运行时支持的最大文件尺寸为2GB。\nMongoDB把数据存储在文件中（默认路径为：/data/db），为提高效率使用内存映射文件进行管理。\n**特性\n**\n它的特点是高性能、易部署、易使用，存储数据非常方便。主要功能特性有：\n面向集合存储，易存储对象类型的数据。 模式自由。 支持动态查询。 支持完全索引，包含内部对象。 支持查询。 支持复制和故障恢复。 使用高效的二进制数据存储，包括大型对象（如视频等）。 自动处理碎片，以支持云计算层次的扩展性。 支持RUBY，PYTHON，JAVA，C++，PHP,C#等多种语言。 文件存储格式为BSON（一种JSON的扩展）。 可通过网络访问。 **官方网站\n**\nhttp://www.mongodb.org/\n2、CouchDB 介绍\nApache CouchDB 是一个面向文档的数据库管理系统。它提供以 JSON 作为数据格式的 REST 接口来对其进行操作，并可以通过视图来操纵文档的组织和呈现。 CouchDB 是 Apache 基金会的顶级开源项目。\nCouchDB是用Erlang开发的面向文档的数据库系统，其数据存储方式类似Lucene的Index文件格式。CouchDB最大的意义在于它是一个面向Web应用的新一代存储系统，事实上，CouchDB的口号就是：下一代的Web应用存储系统。\n**特性\n**\n主要功能特性有：\nCouchDB是分布式的数据库，他可以把存储系统分布到n台物理的节点上面，并且很好的协调和同步节点之间的数据读写一致性。这当然也得以于Erlang无与伦比的并发特性才能做到。对于基于web的大规模应用文档应用，然的分布式可以让它不必像传统的关系数据库那样分库拆表，在应用代码层进行大量的改动。 CouchDB是面向文档的数据库，存储半结构化的数据，比较类似lucene的index结构，特别适合存储文档，因此很适合CMS，电话本，地址本等应用，在这些应用场合，文档数据库要比关系数据库更加方便，性能更好。 CouchDB支持REST API，可以让用户使用JavaScript来操作CouchDB数据库，也可以用JavaScript编写查询语句，我们可以想像一下，用AJAX技术结合CouchDB开发出来的CMS系统会是多么的简单和方便。其实CouchDB只是Erlang应用的冰山一角，在最近几年，基于Erlang的应用也得到的蓬勃的发展，特别是在基于web的大规模，分布式应用领域，几乎都是Erlang的优势项目。 官方网站\nhttp://couchdb.apache.org/\n3、Hbase 介绍\nHBase是一个分布式的、面向列的开源数据库，该技术来源于Chang et al所撰写的Google论文“Bigtable：一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统（File System）所提供的分布式数据存储一样，HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库.另一个不同的是HBase基于列的而不是基于行的模式。\nHBase – Hadoop Database，是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统，利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。 HBase是Google Bigtable的开源实现，类似Google Bigtable利用GFS作为其文件存储系统，HBase利用Hadoop HDFS作为其文件存储系统；Google运行MapReduce来处理Bigtable中的海量数据，HBase同样利用Hadoop MapReduce来处理HBase中的海量数据；Google Bigtable利用 Chubby作为协同服务，HBase利用Zookeeper作为对应。\nHBase访问接口 Native Java API，最常规和高效的访问方式，适合Hadoop MapReduce Job并行批处理HBase表数据 HBase Shell，HBase的命令行工具，最简单的接口，适合HBase管理使用 Thrift Gateway，利用Thrift序列化技术，支持C++，PHP，Python等多种语言，适合其他异构系统在线访问HBase表数据 REST Gateway，支持REST 风格的Http API访问HBase, 解除了语言限制 Pig，可以使用Pig Latin流式编程语言来操作HBase中的数据，和Hive类似，本质最终也是编译成MapReduce Job来处理HBase表数据，适合做数据统计 Hive，当前Hive的Release版本尚没有加入对HBase的支持，但在下一个版本Hive 0.7.0中将会支持HBase，可以使用类似SQL语言来访问HBase **特性\n**\n主要功能特性有：\n支持数十亿行X上百万列\n采用分布式架构 Map/reduce\n对实时查询进行优化\n高性能 Thrift网关\n通过在server端扫描及过滤实现对查询操作预判\n支持 XML, Protobuf, 和binary的HTTP\n基于 Jruby（ JIRB）的shell\n对配置改变和较小的升级都会重新回滚\n不会出现单点故障\n堪比MySQL的随机访问性能\n**官方网站\n**\nhttp://hbase.apache.org/\n4、cassandra 介绍\nCassandra是一个混合型的非关系的数据库，类似于Google的BigTable。其主要功能比Dynomite（分布式的Key-Value存储系统）更丰富，但支持度却不如文档存储MongoDB（介于关系数据库和非关系数据库之间的开源产品，是非关系数据库当中功能最丰富，最像关系数据库的。支持的数据结构非常松散，是类似json的bjson格式，因此可以存储比较复杂的数据类型。）Cassandra最初由Facebook开发，后转变成了开源项目。它是一个网络社交云计算方面理想的数据库。以Amazon专有的完全分布式的Dynamo为基础，结合了Google BigTable基于列族（Column Family）的数据模型。P2P去中心化的存储。很多方面都可以称之为Dynamo 2.0。\n**特性\n**\n和其他数据库比较，有几个突出特点：\n模式灵活 ：使用Cassandra，像文档存储，你不必提前解决记录中的字段。你可以在系统运行时随意的添加或移除字段。这是一个惊人的效率提升，特别是在大型部 署上。\n真正的可扩展性 ：Cassandra是纯粹意义上的水平扩展。为给集群添加更多容量，可以指向另一台电脑。你不必重启任何进程，改变应用查询，或手动迁移任何数据。\n多数据中心识别 ：你可以调整你的节点布局来避免某一个数据中心起火，一个备用的数据中心将至少有每条记录的完全复制。\n一些使Cassandra提高竞争力的其他功能：\n范围查询 ：如果你不喜欢全部的键值查询，则可以设置键的范围来查询。\n列表数据结构 ：在混合模式可以将超级列添加到5维。对于每个用户的索引，这是非常方便的。\n分布式写操作 ：有可以在任何地方任何时间集中读或写任何数据。并且不会有任何单点失败。\n官方网站\nhttp://cassandra.apache.org/\n5、Hypertable 介绍\nHypertable是一个开源、高性能、可伸缩的数据库，它采用与Google的Bigtable相似的模型。在过去数年中，Google为在 PC集群 上运行的可伸缩计算基础设施设计建造了三个关键部分。第一个关键的基础设施是Google File System（GFS），这是一个高可用的文件系统，提供了一个全局的命名空间。它通过跨机器（和跨机架）的文件数据复制来达到高可用性，并因此免受传统 文件存储系统无法避免的许多失败的影响，比如电源、内存和网络端口等失败。第二个基础设施是名为Map-Reduce的计算框架，它与GFS紧密协作，帮 助处理收集到的海量数据。第三个基础设施是Bigtable，它是传统数据库的替代。Bigtable让你可以通过一些主键来组织海量数据，并实现高效的 查询。Hypertable是Bigtable的一个开源实现，并且根据我们的想法进行了一些改进。\n**特性\n**\n主要功能特点：\n负载均衡的处理\n版本控制和一致性\n可靠性\n分布为多个节点\n官方网站\nhttp://hypertable.org/\n6、Redis 介绍\nredis是一个key-value存储系统。和Memcached类似，它支持存储的value类型相对更多，包括string(字符串)、list(链表)、set(集合)和zset(有序集合)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作，而且这些操作都是原子性的。在此基础上，redis支持各种不同方式的排序。与memcached一样，为了保证效率，数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件，并且在此基础上实现了master-slave(主从)同步。\n性能测试结果：\nSET操作每秒钟 110000 次，GET操作每秒钟 81000 次，服务器配置如下：\nLinux 2.6, Xeon X3320 2.5Ghz.\nstackoverflow 网站使用 Redis 做为缓存服务器。\n**特点\n**\n主要功能特点：\n安全性\n主从复制\n运行异常快\n支持 sets（同时也支持 union/diff/inter）\n支持列表（同时也支持队列；阻塞式 pop操作）\n支持哈希表（带有多个域的对象）\n支持排序 sets（高得分表，适用于范围查询）\nRedis支持事务\n支持将数据设置成过期数据（类似快速缓冲区设计）\nPub/Sub允许用户实现消息机制\n官方网站\nhttp://redis.io/\n7、Tokyo Cabinet/Tokyo Tyant 介绍\nTokyo Cabinet（TC）和Tokyo Tyrant（TT）的开发者是日本人Mikio Hirabayashi，主要用于日本最大的SNS网站mixi.jp。TC出现的时间最早，现在已经是一个非常成熟的项目，也是Key-Value数据库领域最大的热点，现在广泛应用于网站。TC是一个高性能的存储引擎，而TT提供了多线程高并发服务器，性能也非常出色，每秒可以处理4万~5万次读写操作。\nTC除了支持Key-Value存储之外，还支持Hashtable数据类型，因此很像一个简单的数据库表，并且还支持基于Column的条件查询、分页查询和排序功能，基本上相当于支持单表的基础查询功能，所以可以简单地替代关系数据库的很多操作，这也是TC受到大家欢迎的主要原因之一。有一个Ruby项目miyazakiresistance将TT的Hashtable的操作封装成和ActiveRecord一样的操作，用起来非常高效。\n**特性\n**\nTC/TT在Mixi的实际应用当中，存储了2000万条以上的数据，同时支撑了上万个并发连接，是一个久经考验的项目。TC在保证了极高的并发读写性能的同时，还具有可靠的数据持久化机制，同时还支持类似关系数据库表结构的Hashtable以及简单的条件、分页和排序操作，是一个很优越的NoSQL数据库。\nTC的主要缺点是，在数据量达到上亿级别以后，并发写数据性能会大幅度下降，开发人员发现在TC里面插入1.6亿条2KB~20KB数据的时候，写入性能开始急剧下降。即当数据量达到上亿条的时候，TC性能便开始大幅度下降，从TC作者自己提供的Mixi数据来看，至少上千万条数据量的时候还没有遇到这么明显的写入性能瓶颈。\n官方网站\nhttp://fallabs.com/tokyocabinet/\n8、Flare 介绍\nTC是日本第一大SNS网站mixi.jp开发的，而Flare是日本第二大SNS网站green.jp开发的。简单地说，Flare就是给TC添加了scale（可扩展）功能。它替换了TT部分，自己另外给TC写了网络服务器。Flare的主要特点就是支持scale能力，它在网络服务端之前添加了一个Node Server，用来管理后端的多个服务器节点，因此可以动态添加数据库服务节点、删除服务器节点，也支持Failover。如果你的使用场景必须让TC可以scale，那么可以考虑Flare。\nflare唯一的缺点就是他只支持memcached协议，因此当你使用flare的时候，就不能使用TC的table数据结构了，只能使用TC的key-value数据结构存储。\n**特性\n**\n没找到相关的介绍。\n官方网站\nhttp://flare.prefuse.org/\n9、Berkeley DB 介绍\nBerkeley DB (DB)是一个高性能的，嵌入数据库编程库，和C语言，C++，Java，Perl，Python，PHP，Tcl以及其他很多语言都有绑定。Berkeley DB可以保存任意类型的键/值对，而且可以为一个键保存多个数据。Berkeley DB可以支持数千的并发线程同时操作数据库，支持最大256TB的数据，广泛 用于各种操作系统包括大多数Unix类操作系统和Windows操作系统以及实时操作系统。\nBerkeley DB最初开发的目的是以新的HASH访问算法来代替旧的hsearch函数和大量的dbm实现（如AT\u0026amp;T的dbm，Berkeley的 ndbm，GNU项目的gdbm），Berkeley DB的第一个发行版在1991年出现，当时还包含了B+树数据访问算法。在1992年，BSD UNIX第4.4发行版中包含了Berkeley DB1.85版。基本上认为这是Berkeley DB的第一个正式版。在1996年中期，Sleepycat软件公司成立，提供对Berkeley DB的商业支持。在这以后，Berkeley DB得到了广泛的应用，成为一款独树一帜的嵌入式数据库系统。2006年Sleepycat公司被Oracle 公司收购，Berkeley DB成为Oracle数据库家族的一员，Sleepycat原有开发者继续在Oracle开发Berkeley DB，Oracle继续原来的授权方式并且加大了对Berkeley DB的开发力度，继续提升了Berkeley DB在软件行业的声誉。Berkeley DB的当前最新发行版本是4.7.25。\n**特性\n**\n主要特点：\n访问速度快\n省硬盘空间\n官方网站\nhttp://www.oracle.com/us/products/database/overview/index.html?origref=http://www.oschina.net/p/berkeley+db\n10、memcachedb 介绍\nMemcacheDB是一个分布式、key-value形式的持久存储系统。它不是一个缓存组件，而是一个基于对象存取的、可靠的、快速的持久存储引擎。协议跟memcache一致（不完整），所以很多memcached客户端都可以跟它连接。MemcacheDB采用Berkeley DB作为持久存储组件，故很多Berkeley DB的特性的他都支持。\n**特性\n**\nMemcacheDB是一个分布式、key-value形式的持久存储系统。它不是一个缓存组件，而是一个基于对象存取的、可靠的、快速的持久存储引擎。 协议跟memcache一致（不完整），所以很多memcached客户端都可以跟它连接。MemcacheDB采用Berkeley DB作为持久存储组件，故很多Berkeley DB的特性的他都支持。 我们是站在巨人的肩膀上的。MemcacheDB的前端缓存是Memcached 前端：memcached的网络层 后端：BerkeleyDB存储\n写速度：从本地服务器通过memcache客户端（libmemcache）set2亿条16字节长的key，10字节长的Value的记录，耗时 16572秒，平均速度12000条记录/秒。\n读速度：从本地服务器通过memcache客户端（libmemcache）get100万条16字节长的key，10字节长的Value的记录，耗 时103秒，平均速度10000条记录/秒。 ·支持的memcache命令\n官方网站\nhttp://memcachedb.org/\n11、Memlink 介绍\nMemlink 是天涯社区开发的一个高性能、持久化、分布式的Key-list/queue数据引擎。正如名称中的memlink所示，所有数据都建构在内存中，保证了 系统的高性能 (大约是redis几倍)，同时使用了redo-log技术保证数据的持久化。Memlink还支持主从复制、读写分离、List过滤操作等功能。\n与Memcached不同的是，它的value是一个list/queue。并且提供了诸如持久化，分布式的功能。听起来有点像Redis，但它号称比Redis更好，在很多Redis做得还不好的地方进行了改进和完善。提供的客户端开发包包括 c,python,php,java 四种语言。\n**特性\n**\n特点：\n内存数据引擎，性能极为高效 List块链结构，精简内存，优化查找效率 Node数据项可定义，支持多种过滤操作 支持redo-log，数据持久化，非Cache模式 分布式，主从同步 官方网站\nhttp://code.google.com/p/memlink/\n12、db4o 介绍\n“利用表格存储对象，就像是将汽车开回家，然后拆成零件放进车库里，早晨可以再把汽车装配起来。但是人们不禁要问，这是不是泊车的最有效的方法呢。” – Esther Dyson db4o 是一个开源的纯面向对象数据库引擎，对于 Java 与 .NET 开发者来说都是一个简单易用的对象持久化工具，使用简单。同时，db4o 已经被第三方验证为具有优秀性能的面向对象数据库， 下面的基准测试图对 db4o 和一些传统的持久方案进行了比较。db4o 在这次比较中排名第二，仅仅落后于JDBC。通过图 1 的基准测试结果，值得我们细细品味的是采用 Hibernate/HSQLDB 的方案和 JDBC/HSQLDB 的方案在性能方面有着显著差距，这也证实了业界对 Hibernate 的担忧。而 db4o 的优异性能，让我们相信： 更 OO 并不一定会牺牲性能。\n同时，db4o 的一个特点就是无需 DBA 的管理，占用资源很小，这很适合嵌入式应用以及 Cache 应用， 所以自从 db4o 发布以来，迅速吸引了大批用户将 db4o 用于各种各样的嵌入式系统，包括流动软件、医疗设备和实时控制系统。 db4o 由来自加州硅谷的开源数据库公司 db4objects 开发并负责商业运营和支持。db4o 是基于 GPL 协议。db4objects 于 2004 年在 CEO Christof Wittig 的领导下组成，资金背景包括 Mark Leslie 、 Veritas 软件公司 CEO 、 Vinod Khosla （ Sun 公司创始人之一）、 Sun 公司 CEO 在内的硅谷高层投资人组成。毫无疑问，今天 db4objects 公司是硅谷炙手可热的技术创新者之一。\n**特性\n**\ndb4o 的目标是提供一个功能强大的，适合嵌入的数据库引擎，可以工作在设备，移动产品，桌面以及服务器等各种平台。主要特性如下： 开源模式。与其他 ODBMS 不同，db4o 为开源软件，通过开源社区的力量驱动开发 db4o 产品。 原生数据库。db4o 是 100% 原生的面向对象数据库，直接使用编程语言来操作数据库。程序员无需进行 OR 映射来存储对象，大大节省了程序员在存储数据的开发时间。 高性能。 下图为 db4o 官方公布的基准测试数据，db4o 比采用 Hibernate/MySQL 方案在某些测试线路上速度高出 44 倍之多！并且安装简单，仅仅需要 400Kb 左右的 .jar 或 .dll 库文件。在接下来的系列文章中，我们将只关注在 Java 平台的应用，但是实际上 db4o 毫无疑问会很好地在 .NET平台工作。\n图：官方测试数据\n易嵌入。使用 db4o 仅需引入 400 多 k 的 jar 文件或是 dll 文件，内存消耗极小。 零管理。使用 db4o 无需 DBA，实现零管理。 支持多种平台。db4o 支持从 Java 1.1 到 Java 5.0，此外还支持 .NET 、 CompactFramework 、 Mono 等 .NET 平台，也可以运行在 CDC 、 PersonalProfile 、 Symbian 、 Savaje 以及 Zaurus 这种支持反射的 J2ME 方言环境中，还可以运行在 CLDC 、 MIDP 、 RIM/Blackberry 、 Palm OS 这种不支持反射的 J2ME 环境中。 或许开发者会问，如果现有的应用环境已经有了关系型数据库怎么办？没关系，db4o 的 dRS（db4o Replication System）可实现 db4o 与关系型数据库的双向同步（复制），如图 3 。 dRS 是基于 Hibernate 开发，目前的版本是 1.0 ，并运行在 Java 1.2 或更高版本平台上，基于 dRS 可实现 db4o 到 Hibernate/RDBMS 、 db4o 到 db4o 以及 Hibernate/RDBMS 到 Hibernate/RDBMS 的双向复制。dRS 模型如图\n图：DRS模型\n官方网站\nhttp://www.db4o.com/china/\n13、Versant 介绍\nVersant Object Database (V/OD) 提供强大的数据管理，面向 C++, Java or .NET 的对象模型，支持大并发和大规模数据集合。 Versant对象数据库是一个对象数据库管理系统(ODBMS：Object Database Management System)。它主要被用在复杂的、分布式的和异构的环境中，用来减少开发量和提高性能。尤其当程序是使用Java和（或）C＋＋语言编写的时候，尤其有用。\n它是一个完整的，电子基础设施软件，简化了事务的构建和部署的分布式应用程序。\n作为一个卓越的数据库产品，Versant ODBMS在设计时的目标就是为了满足客户在异类处理平台和企业级信息系统中对于高性能、可量测性、可靠性和兼容性方面的需求。\nVersant对象数据库已经在为企业业务应用提供可靠性、完整性和高性能方面获得了建树，Versant ODBMS所表现出的高效的多线程架构、internal parallelism 、平稳的Client－Server结构和高效的查询优化，都体现了其非常卓越的性能和可扩展性。\nVersant对象数据库包括Versant ODBMS，C++和Java语言接口，XML工具包和异步复制框架。\n**特性\n**\n一、强有力的优势\nVersant Object Database8.0，适用于应用环境中包含复杂对象模型的数据库，其设计目标是能够处理这些应用经常需要的导航式访问，无缝的数据分发，和企业级的规模。\n对于很多应用程序而言，最具挑战性的方面是控制业务模型本身的内在复杂性。 电信基础设施，交通运输网络，仿真，金融工具以及其它领域的复杂性必须得到支持， 而且这种支持复杂性的方式还要能够随着环境和需求变化而不断地改进应用程序。 这些应用程序的重点是领域和这些领域的逻辑。 复杂的设计应当以对象模型为基础。将技术需求例如持久性（和SQL）与领域模型混合在一起的架构会带来灾难性的后果。\nVersant对象数据库使您可以使用那些只含有域行为信息的对象，而不用考虑持久性。同时，Versant对象数据库还能提供跨多个数据库的无缝的数据分发，高并发性，细粒度锁，顶级性能， 以及通过复制和其它技术提供的高可用性。现代Java中的对象关系映射工具已经简化了很多映射的问题， 但是它们还不能提供Versant所能提供的无缝数据分发的功能和高性能。\n二、主要特性\nC++、Java及.NET 的透明对象持久\n支持对象持久标准，如JDO\n跨多数据库的无缝数据分发\n企业级的高可用性选项\n动态模式更新\n管理工作量少（或不需要）\n端到端的对象支持架构\n细粒度并发控制\n多线程，多会话\n支持国际字符集\n高速数据采集\n三、优势\n对象层次结构的快速存储、检索和浏览\n性能高于关系型数据库10 倍以上\n减少开发时间\n四、8.0的新特性\n增强的多核线性扩展能力\n增强的数据库管理工具（监控、数据库检查、数据重组）\n支持基于LINQ的.NET绑定机制\n支持.NET和JDO应用的FTS基于“Black Box”工具的数据库活动记录与分析\n五、Versant对象数据库特性\n动态模式更新\nVersant支持缓慢模式更新，这意味着当被使用时，对象才会从旧的模式转为新的模式，就不需要映射了。所有这些都支持数据库模式的更新与敏捷开发。\n跨多数据库的无缝数据分发\n客户端与一个或多个数据库进行无缝交互。单个的数据库无缝地联合在一起，使您能够给数据分区，提高读写能力，增大总体的数据库的大小。这些数据库上的数据分发是透明的。它们被结合在一起形成一个\n无缝的数据库，提供巨大的可扩展性。\n并发控制\n对象级锁确保只有在两个应用程序试图更新同一对象时才会有冲突的发生，这与基于页的锁机制不同。基于页的锁机制可能会导致并发热点的假象。\n透明的C++对象持久性\nC++对象，STL类，标准C++集合如字典，映射，映射的映射，诸如此类，以原样保存在数据库中。状态变化在后台被自动追踪。当相关的事务提交后，所有的变化将会被自动发送到数据库。因此就能形成一种非常自然的，低干扰的编程风格，这样，就能实现应用程序的快速开发，同时当需求发生变化时，应用程序就能够灵活地修改。\n透明的Java对象持久性\nV/OD的JVI \u0026amp; JDO 2.0 API 提供了透明的简单对象（POJO）的持久性，包括 Java 2 持久类，接口，以及任何用户定义的类。状态变化\n在后台被自动追踪。事务提交后，自动把所有变化写入数据库。因此，对于托管和非托管部署，您都能获得轻量级的编程风格。\n可完全嵌入Versant 可以被嵌入到应用程序中，数据库规模可以达到TB 级别。\n并且可以自主运行，不需要任何管理。\n六、企业级的特性\n对象端到端\n对象端到端意味着你的应用对象存在于客户端，网络上，以及数据库中。与关系型数据库不同的是，对象在内存中和数据库中的表示之间不需要任何映射或转换。\n应用的客户端缓存透明地缓存对象以提高速度。数据库支持对象，它能执行查询，建立索引，使应用能够平衡它和数据库间的进程执行。XA的支持使与其它事务数据源协调成为可能。\n七、V/OD 8数据库体系架构\n高可用性\n通过在线进行数据库管理实现数据库的高可用性。\n容错服务器\n容错服务器选项可以在Versant数据库的硬件或是软件出现故障的时候，自动进行失效转移和数据恢复。容错服务器使用的是在两个数据库实例之间进行同步复制，一旦出现故障，容错服务器也会支持透明重同步。\n异步数据复制\n异步数据复制选项支持多个对象服务器之间的主从异步复制和点对点异步复制。可以使用异步数据复制将数据复制到一个分布式恢复站点或者将数据在多个本地的对象数据库之间进行复制，以提高性能和可靠性。\n高可用性备份\n高可用性数据备份选项使Versant可以使用EMC Symmetrix或其它企业级存储系统的磁盘镜像的特性，来对很大的数据卷进行在线备份，同时又不会影响到可用性。\n在线再组织\nVersant 数据库再组织选项为了会删除大量对象的应用而设计的。它使用户能够收回数据库中未使用的空间，同时使数据库保持正常运作，增加可用空间，改善数据库的性能。\n八、为什么要使用Versant面向对象数据库？\n通过缩短研发时间来加速上市\n对象关系映射代码可能占用了你的应用的40%或更多。有了Versant面向对象数据库，映射代码就不再需要了。\n极大地提高了性能和数据吞吐能力\n当应用中涉及到复杂的内存对象模式，尤其是关联访问时，对象数据库要比映射到关系数据库表现得更好。例如，当应用程序需要从对象数据库里检索一个对象时，只要执行单条查询即可找到该对象。当映射到一个关系数据库时，如果对象包含多对多关联，那么就必须通过一个或多个连接才能检索到关联表中的数据。使用了对象数据库，对于一般复杂性的对象的检索，速度则提高了三倍，对于复杂性很高的对象的检索，例如多对多关联，搜索的速度则提高了三十倍。而对于集合的集合和递归联系，检索的速度有可能提高五十倍。\n根据需求的变化，快速改进应用\n今天，商业进程、结构和应用要求的变化的速度使得适应变化的能力变得极为重要。对象关系映射和其它适用于刚性存储结构的方法，让变化变得困难。而Versant对象数据库极大的提升了你的应用满足当前和未来的商业需求的能力。\n投资回报率\n当用户遇到了复杂的对象模型和大的数据集，对象数据库就是首选的解决方案。对象数据库主要的优点在于，它能够缩小代码的规模，降低研发成本，缩短上市的时间，减少或根本没有管理的要求以及降低购置硬件和服务器软件许可证的成本。性能上的优势还可以大大降低高负载动作应用所消耗的成本。大型的关系数据库成本高非常昂贵，还需要昂贵的硬件支持\n官方网站\nhttp://www.versant.com/index.aspx\n14、Neo4j 介绍\nNeo4j是一个嵌入式，基于磁盘的，支持完整事务的Java持久化引擎，它在图像中而不是表中存储数据。Neo4j提供了大规模可扩展性，在一台机器上可以处理数十亿节点/关系/属性的图像，可以扩展到多台机器并行运行。相对于关系数据库来说，图形数据库善于处理大量复杂、互连接、低结构化的数据，这些数据变化迅速，需要频繁的查询——在关系数据库中，这些查询会导致大量的表连接，因此会产生性能上的问题。Neo4j重点解决了拥有大量连接的传统RDBMS在查询时出现的性能衰退问题。通过围绕图形进行数据建模，Neo4j会以相同的速度遍历节点与边，其遍历速度与构成图形的数据量没有任何关系。此外，Neo4j还提供了非常快的图形算法、推荐系统和OLAP风格的分析，而这一切在目前的RDBMS系统中都是无法实现的。\nNeo是一个网络——面向网络的数据库——也就是说，它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎，但是它将结构化数据存储在网络上而不是表中。网络（从数学角度叫做图）是一个灵活的数据结构，可以应用更加敏捷和快速的开发模式。\n你可以把Neo看作是一个高性能的图引擎，该引擎具有成熟和健壮的数据库的所有特性。程序员工作在一个面向对象的、灵活的网络结构下而不是严格、静态的表中——但是他们可以享受到具备完全的事务特性、企业级的数据库的所有好处。\n由于使用了“面向网络的数据库”，人们对Neo充满了好奇。在该模型中，以“节点空间”来表达领域数据——相对于传统的模型表、行和列来说，节点空间是很多节点、关系和属性（键值对）构成的网络。关系是第一级对象，可以由属性来注解，而属性则表明了节点交互的上下文。网络模型完美的匹配了本质上就是继承关系的问题域，例如语义Web应用。Neo的创建者发现继承和结构化数据并不适合传统的关系数据库模型：\n1.对象关系的不匹配使得把面向对象的“圆的对象”挤到面向关系的“方的表”中是那么的困难和费劲，而这一切是可以避免的。\n2.关系模型静态、刚性、不灵活的本质使得改变schemas以满足不断变化的业务需求是非常困难的。由于同样的原因，当开发小组想应用敏捷软件开发时，数据库经常拖后腿。\n3.关系模型很不适合表达半结构化的数据——而业界的分析家和研究者都认为半结构化数据是信息管理中的下一个重头戏。\n4.网络是一种非常高效的数据存储结构。人脑是一个巨大的网络，万维网也同样构造成网状，这些都不是巧合。关系模型可以表达面向网络的数据，但是在遍历网络并抽取信息的能力上关系模型是非常弱的。\n虽然Neo是一个比较新的开源项目，但它已经在具有1亿多个节点、关系和属性的产品中得到了应用，并且能满足企业的健壮性和性能的需求：\n完全支持JTA和JTS、2PC分布式ACID事务、可配置的隔离级别和大规模、可测试的事务恢复。这些不仅仅是口头上的承诺：Neo已经应用在高请求的24/7环境下超过3年了。它是成熟、健壮的，完全达到了部署的门槛。\n**特性\n**\nNeo4j是一个用Java实现、完全兼容ACID的图形数据库。数据以一种针对图形网络进行过优化的格式保存在磁盘上。Neo4j的内核是一种极快的图形引擎，具有数据库产品期望的所有特性，如恢复、两阶段提交、符合XA等。\nNeo4j既可作为无需任何管理开销的内嵌数据库使用；也可以作为单独的服务器使用，在这种使用场景下，它提供了广泛使用的REST接口，能够方便地集成到基于PHP、.NET和JavaScript的环境里。但本文的重点主要在于讨论Neo4j的直接使用。\nNeo4j的典型数据特征：\n•数据结构不是必须的，甚至可以完全没有，这可以简化模式变更和延迟数据迁移。\n•可以方便建模常见的复杂领域数据集，如CMS里的访问控制可被建模成细粒度的访问控制表，类对象数据库的用例、TripleStores以及其他例子。\n•典型使用的领域如语义网和RDF、LinkedData、GIS、基因分析、社交网络数据建模、深度推荐算法以及其他领域。\n围绕内核，Neo4j提供了一组可选的组件。其中有支持通过元模型构造图形结构、SAIL – 一种SparQL兼容的RDF TripleStore实现或一组公共图形算法的实现。\n高性能？\n要给出确切的性能基准数据很难，因为它们跟底层的硬件、使用的数据集和其他因素关联很大。自适应规模的Neo4j无需任何额外的工作便可以处理包含数十亿节点、关系和属性的图。它的读性能可以很轻松地实现每毫秒（大约每秒1-2百万遍历步骤）遍历2000关系，这完全是事务性的，每个线程都有热缓存。使用最短路径计算，Neo4j在处理包含数千个节点的小型图时，甚至比MySQL快1000倍，随着图规模的增加，差距也越来越大。\n这其中的原因在于，在Neo4j里，图遍历执行的速度是常数，跟图的规模大小无关。不象在RDBMS里常见的联结操作那样，这里不涉及降低性能的集合操作。Neo4j以一种延迟风格遍历图 – 节点和关系只有在结果迭代器需要访问它们的时候才会被遍历并返回，对于大规模深度遍历而言，这极大地提高了性能。\n写速度跟文件系统的查找时间和硬件有很大关系。Ext3文件系统和SSD磁盘是不错的组合，这会导致每秒大约100,000写事务操作。\n官方网站\nhttp://neo4j.org/\n15、BaseX 介绍\nBaseX 是一个XML数据库，用来存储紧缩的XML数据，提供了高效的 XPath 和 XQuery 的实现，还包括一个前端操作界面。 **特性\n**\nBaseX一个比较显著地优点是有了GUI，界面中有查询窗口，可采用XQuery查询相关数据库中的XML文件；也有能够动态展示xml文件层次和节点关系的图。但我感觉也就这点好处了，编程时和GUI无关了。\n和Xindice相比，BaseX更能支持大型XML文档的存储，而Xindice对大型xml没有很好的支持，为管理中小型文档的集合而设计。\nBaseX 是一个XML数据库，用来存储紧缩的XML数据，提供了高效的 XPath 和 XQuery 的实现，还包括一个前端操作界面。\n官方网站\nhttp://basex.org/\n","permalink":"https://blog.zdltech.com/posts/15%E4%B8%AAnosql%E6%95%B0%E6%8D%AE%E5%BA%93/","summary":"\u003ch1 id=\"1mongodb\"\u003e1、MongoDB\u003c/h1\u003e\n\u003cp\u003e\u003cstrong\u003e介绍\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eMongoDB是一个基于分布式文件存储的数据库。由C++语言编写。主要解决的是海量数据的访问效率问题，为WEB应用提供可扩展的高性能数据存储解决方案。当数据量达到50GB以上的时候，MongoDB的数据库访问速度是MySQL的10倍以上。MongoDB的并发读写效率不是特别出色，根据官方提供的性能测试表明，大约每秒可以处理0.5万~1.5万次读写请求。MongoDB还自带了一个出色的分布式文件系统GridFS，可以支持海量的数据存储。\u003c/p\u003e\n\u003cp\u003eMongoDB也有一个Ruby的项目MongoMapper，是模仿Merb的DataMapper编写的MongoDB接口，使用起来非常简单，几乎和DataMapper一模一样，功能非常强大。\u003c/p\u003e\n\u003cp\u003eMongoDB是一个介于关系数据库和非关系数据库之间的产品，是非关系数据库当中功能最丰富，最像关系数据库的。他支持的数据结构非常松散，是类似json的bjson格式，因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大，其语法有点类似于面向对象的查询语言，几乎可以实现类似关系数据库单表查询的绝大部分功能，而且还支持对数据建立索引。\u003c/p\u003e\n\u003cp\u003e所谓“面向集合”（Collenction-Orented），意思是数据被分组存储在数据集中，被称为一个集合（Collenction)。每个 集合在数据库中都有一个唯一的标识名，并且可以包含无限数目的文档。集合的概念类似关系型数据库（RDBMS）里的表（table），不同的是它不需要定 义任何模式（schema)。\u003cbr\u003e\n模式自由（schema-free)，意味着对于存储在mongodb数据库中的文件，我们不需要知道它的任何结构定义。如果需要的话，你完全可以把不同结构的文件存储在同一个数据库里。\u003cbr\u003e\n存储在集合中的文档，被存储为键-值对的形式。键用于唯一标识一个文档，为字符串类型，而值则可以是各中复杂的文件类型。我们称这种存储形式为BSON（Binary Serialized dOcument Format）。\u003c/p\u003e\n\u003cp\u003eMongoDB服务端可运行在Linux、Windows或OS X平台，支持32位和64位应用，默认端口为27017。推荐运行在64位平台，因为MongoDB在32位模式运行时支持的最大文件尺寸为2GB。\u003c/p\u003e\n\u003cp\u003eMongoDB把数据存储在文件中（默认路径为：/data/db），为提高效率使用内存映射文件进行管理。\u003c/p\u003e\n\u003cp\u003e**特性\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e它的特点是高性能、易部署、易使用，存储数据非常方便。主要功能特性有：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e面向集合存储，易存储对象类型的数据。\u003c/li\u003e\n\u003cli\u003e模式自由。\u003c/li\u003e\n\u003cli\u003e支持动态查询。\u003c/li\u003e\n\u003cli\u003e支持完全索引，包含内部对象。\u003c/li\u003e\n\u003cli\u003e支持查询。\u003c/li\u003e\n\u003cli\u003e支持复制和故障恢复。\u003c/li\u003e\n\u003cli\u003e使用高效的二进制数据存储，包括大型对象（如视频等）。\u003c/li\u003e\n\u003cli\u003e自动处理碎片，以支持云计算层次的扩展性。\u003c/li\u003e\n\u003cli\u003e支持RUBY，PYTHON，JAVA，C++，PHP,C#等多种语言。\u003c/li\u003e\n\u003cli\u003e文件存储格式为BSON（一种JSON的扩展）。\u003c/li\u003e\n\u003cli\u003e可通过网络访问。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e**官方网站\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.mongodb.org/\"\u003ehttp://www.mongodb.org/\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"2couchdb\"\u003e2、CouchDB\u003c/h1\u003e\n\u003cp\u003e\u003cstrong\u003e介绍\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eApache CouchDB 是一个面向文档的数据库管理系统。它提供以 JSON 作为数据格式的 REST 接口来对其进行操作，并可以通过视图来操纵文档的组织和呈现。 CouchDB 是 Apache 基金会的顶级开源项目。\u003c/p\u003e\n\u003cp\u003eCouchDB是用Erlang开发的面向文档的数据库系统，其数据存储方式类似Lucene的Index文件格式。CouchDB最大的意义在于它是一个面向Web应用的新一代存储系统，事实上，CouchDB的口号就是：下一代的Web应用存储系统。\u003c/p\u003e\n\u003cp\u003e**特性\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e主要功能特性有：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eCouchDB是分布式的数据库，他可以把存储系统分布到n台物理的节点上面，并且很好的协调和同步节点之间的数据读写一致性。这当然也得以于Erlang无与伦比的并发特性才能做到。对于基于web的大规模应用文档应用，然的分布式可以让它不必像传统的关系数据库那样分库拆表，在应用代码层进行大量的改动。\u003c/li\u003e\n\u003cli\u003eCouchDB是面向文档的数据库，存储半结构化的数据，比较类似lucene的index结构，特别适合存储文档，因此很适合CMS，电话本，地址本等应用，在这些应用场合，文档数据库要比关系数据库更加方便，性能更好。\u003c/li\u003e\n\u003cli\u003eCouchDB支持REST API，可以让用户使用JavaScript来操作CouchDB数据库，也可以用JavaScript编写查询语句，我们可以想像一下，用AJAX技术结合CouchDB开发出来的CMS系统会是多么的简单和方便。其实CouchDB只是Erlang应用的冰山一角，在最近几年，基于Erlang的应用也得到的蓬勃的发展，特别是在基于web的大规模，分布式应用领域，几乎都是Erlang的优势项目。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cstrong\u003e官方网站\u003c/strong\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://couchdb.apache.org/\"\u003ehttp://couchdb.apache.org/\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"3hbase\"\u003e3、Hbase\u003c/h1\u003e\n\u003cp\u003e\u003cstrong\u003e介绍\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eHBase是一个分布式的、面向列的开源数据库，该技术来源于Chang et al所撰写的Google论文“Bigtable：一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统（File System）所提供的分布式数据存储一样，HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库.另一个不同的是HBase基于列的而不是基于行的模式。\u003c/p\u003e\n\u003cp\u003eHBase – Hadoop Database，是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统，利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。 　　HBase是Google Bigtable的开源实现，类似Google Bigtable利用GFS作为其文件存储系统，HBase利用Hadoop HDFS作为其文件存储系统；Google运行MapReduce来处理Bigtable中的海量数据，HBase同样利用Hadoop MapReduce来处理HBase中的海量数据；Google Bigtable利用 Chubby作为协同服务，HBase利用Zookeeper作为对应。\u003c/p\u003e","title":"15个nosql数据库"},{"content":"NoSQL的运动不止，MongoDB 作为其中的主力军发展迅猛，也带起了一股开发图形化工具的风潮；气死反过来说，看一个产品是否得到认可,可以侧面看其第三方工具的数量和成熟程度；简单的收集了MongoDB的管理工具，若将来有新的发现则继续更新\n一、Try MongoDB\n不需要安装，直接通过浏览器访问即可的工具；和tryredis一样，Try MongoDB 是一个基于web的shell模拟工具，可以让你在不用安装MongoDB的情况下试用MongoDB的各种功能。Just Try It！\n开源地址：http://try.mongodb.org/\n如图所示：\n二、Mongo3\nMongo3 是一个MongoDB 集群管理工具，界面超炫的\n下载地址：http://www.mongo3.com/\n如图所示：\n三、Mongodb Management Studio\nMongodb Management Studio 针对在DBA/开发/管理员三个维度提供一定层次的管理功能，功能如下:\n服务器管理功能：添加服务器,删除服务器 服务器,数据库,表,列,索引,树形显示和状态信息查看 查询分析器功能：支持select,insert,Delete,update 索引管理功能：支持列名的显示,索引的创建,查看,删除\n数据库Profile管理 可以设置Profile开关,查看Profile信息，自定义分页大小 master/slave信息显示 如图所示：\n四、MongoVue\n这是一个很不错的MongoDB客户端工具，不过1.0以后的版本都开始收费了，所幸费用也不贵才35$。\n下载地址：http://www.mongovue.com/\n如图所示：\n五、MongodbHUB\n有不同的版本，分别可以支持在mac和Windows操作系统工作。\n开源地址: http://github.com/bububa/MongoHub-Mac\n下载地址: http://github.com/downloads/bububa/MongoHub-Mac/MongoHub.zip\nhttp://cloud2.appcelerator.net/win32_win32/1bdd2f931d52d518c0b25b31c1f30182/9092b680-4ec3-4538-91ec-b937e644eb79/MongoHub.exe\n另外还有之前用Titanium Desktop做的，用Win或Linux的可以试试。\nhttp://github.com/bububa/MongoHub\n如图所示：\n六、RockMongo\n** ** RockMongo 是一个PHP5写的MongoDB管理工具。支持中文，这一点很对国人胃口，呵呵。运行速度快，安装也简单，还可以查看 GridFS 分块。\n下载地址：http://code.google.com/p/rock-php/downloads/list\n如图所示：\n七、MongoDB可视化管理工具 MongoCola\n1、安装mongodb：\n想要在电脑里运行MongoCola，首先电脑中要装有mongodb，可以去官网下载适合自己系统的mongodb。官方网站下载地址：http://www.mongodb.org/downloads\n因文件太大，就不放到附件中了，请自行去官网下载。\n下载后的文件是一个压缩包，直接解压，然后移动到自己习惯的目录下。启动MongoCola的时候需要指定这个目录。\n2、安装MongoCola\n你可以从Github下载：https://github.com/magicdict/MagicMongoDBTool/downloads\n附件中中是目前的最新版本，可直接下载：MongoCola-1.22.zip\n解压后运行Mongo-Cola.exe，第一次运行会弹出Language选择框进行语言设置：\n![MongoDB可视化管理工具 MongoCola - 波 - 悦波涌动](http://img2.ph.126.net/5zlCrGUDHYpGD7nMNajAUQ==/6598262736773874980.png) 下一步我们要设置mongodb的安装目录：\n![MongoDB可视化管理工具 MongoCola - 波 - 悦波涌动](http://img1.ph.126.net/iDsgF-Ud6BiObnl-BspdDA==/1883630544247764439.png) 下一步，选择链接数据库，第一次连接，需要添加一个链接：\n![MongoDB可视化管理工具 MongoCola - 波 - 悦波涌动](http://img1.ph.126.net/0kq-zELGb2p8cVhnjdM0Hw==/3905465301960390430.png) 点击添加，按要求填写配置信息。填写完成后可以点击测试检查是否能连接成功：\n![MongoDB可视化管理工具 MongoCola - 波 - 悦波涌动](http://img1.ph.126.net/_wap_GZD3H2MU9UdOHfNnw==/1704893934036499195.png) 如果是用replicaSet方式搭建的mongo集群，还需要设置”replicaSet”选项卡的内容：\n![MongoDB可视化管理工具 MongoCola - 波 - 悦波涌动](http://img1.ph.126.net/ntUaCQQYPLTfUHXFIVue-A==/6597926286215996296.png) 设置完成后，我们便可以启动MongoCola登陆所设置的mongodb了。界面使用很简单，容易上手，各位自己试一下吧！\n![MongoDB可视化管理工具 MongoCola - 波 - 悦波涌动](http://img1.ph.126.net/LTQUzT_-dRRm0f9_MrRWmg==/3871125354801683053.png) ","permalink":"https://blog.zdltech.com/posts/mongodb%E5%9B%BE%E5%BD%A2%E5%8C%96%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7/","summary":"\u003cp\u003eNoSQL的运动不止，MongoDB 作为其中的主力军发展迅猛，也带起了一股开发图形化工具的风潮；气死反过来说，看一个产品是否得到认可,可以侧面看其第三方工具的数量和成熟程度；简单的收集了MongoDB的管理工具，若将来有新的发现则继续更新\u003c/p\u003e\n\u003cp\u003e    \u003cspan lang=\"EN-US\" xml:lang=\"EN-US\"\u003e\u003cspan lang=\"EN-US\" xml:lang=\"EN-US\"\u003e一、Try MongoDB\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e \u003cspan lang=\"EN-US\" xml:lang=\"EN-US\"\u003e\u003cspan lang=\"EN-US\" xml:lang=\"EN-US\"\u003e    不需要安装，直接通过浏览器访问即可的工具；和tryredis一样，Try MongoDB 是一个基于web的shell模拟工具，可以让你在不用安装MongoDB的情况下试用MongoDB的各种功能。Just Try It！\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan lang=\"EN-US\" xml:lang=\"EN-US\"\u003e    开源地址：\u003ca href=\"http://try.mongodb.org/\"\u003ehttp://try.mongodb.org/\u003c/a\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e    如图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images0.cnblogs.com/blog2015/299408/201508/120900182547610.png\"\u003e\u003c/p\u003e\n\u003cp\u003e二、Mongo3\u003c/p\u003e\n\u003cp\u003e    Mongo3 是一个MongoDB 集群管理工具，界面超炫的\u003c/p\u003e\n\u003cp\u003e下载地址：\u003ca href=\"http://www.mongo3.com/\"\u003ehttp://www.mongo3.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e如图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images0.cnblogs.com/blog2015/299408/201508/120900492078989.png\"\u003e\u003c/p\u003e\n\u003cp\u003e三、Mongodb Management Studio\u003c/p\u003e\n\u003cp\u003eMongodb Management Studio 针对在DBA/开发/管理员三个维度提供一定层次的管理功能，功能如下:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e服务器管理功能：添加服务器,删除服务器\u003c/li\u003e\n\u003cli\u003e服务器,数据库,表,列,索引,树形显示和状态信息查看\u003c/li\u003e\n\u003cli\u003e查询分析器功能：支持select,insert,Delete,update\u003c/li\u003e\n\u003cli\u003e索引管理功能：支持列名的显示,索引的创建,查看,删除\u003cbr\u003e\n数据库Profile管理\u003c/li\u003e\n\u003cli\u003e可以设置Profile开关,查看Profile信息，自定义分页大小\u003c/li\u003e\n\u003cli\u003emaster/slave信息显示\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e如图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images0.cnblogs.com/blog2015/299408/201508/120901212708992.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e四、MongoVue\u003c/p\u003e\n\u003cp\u003e这是一个很不错的MongoDB客户端工具，不过1.0以后的版本都开始收费了，所幸费用也不贵才35$。\u003c/p\u003e\n\u003cp\u003e下载地址：\u003ca href=\"http://www.mongovue.com/\" title=\"http://www.mongovue.com/\"\u003ehttp://www.mongovue.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e如图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images0.cnblogs.com/blog2015/299408/201508/120901484268829.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e五、MongodbHUB\u003c/p\u003e\n\u003cp\u003e有不同的版本，分别可以支持在mac和Windows操作系统工作。\u003c/p\u003e\n\u003cp\u003e开源地址: \u003ca target=\"_blank\"\u003e\u003ca href=\"http://github.com/bububa/MongoHub-Mac\"\u003ehttp://github.com/bububa/MongoHub-Mac\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\n下载地址: \u003ca target=\"_blank\"\u003e\u003ca href=\"http://github.com/downloads/bububa/MongoHub-Mac/MongoHub.zip\"\u003ehttp://github.com/downloads/bububa/MongoHub-Mac/MongoHub.zip\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"http://cloud2.appcelerator.net/win32_win32/1bdd2f931d52d518c0b25b31c1f30182/9092b680-4ec3-4538-91ec-b937e644eb79/MongoHub.exe\"\u003ehttp://cloud2.appcelerator.net/win32_win32/1bdd2f931d52d518c0b25b31c1f30182/9092b680-4ec3-4538-91ec-b937e644eb79/MongoHub.exe\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e另外还有之前用Titanium Desktop做的，用Win或Linux的可以试试。\u003cbr\u003e\n\u003ca href=\"http://github.com/bububa/MongoHub\"\u003ehttp://github.com/bububa/MongoHub\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e如图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images0.cnblogs.com/blog2015/299408/201508/120902268326931.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e六、RockMongo\u003c/p\u003e\n\u003cp\u003e**   ** RockMongo 是一个PHP5写的MongoDB管理工具。支持中文，这一点很对国人胃口，呵呵。运行速度快，安装也简单，还可以查看 GridFS 分块。\u003c/p\u003e\n\u003cp\u003e下载地址：\u003ca href=\"http://code.google.com/p/rock-php/downloads/list\"\u003ehttp://code.google.com/p/rock-php/downloads/list\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e如图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images0.cnblogs.com/blog2015/299408/201508/120903024105561.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e七、MongoDB可视化管理工具 \u003cu\u003eMongoCola\u003c/u\u003e\u003c/p\u003e\n\u003cp\u003e1、安装mongodb：\u003c/p\u003e\n\u003cp\u003e想要在电脑里运行MongoCola，首先电脑中要装有mongodb，可以去官网下载适合自己系统的mongodb。官方网站下载地址：\u003ca href=\"http://www.mongodb.org/downloads\"\u003ehttp://www.mongodb.org/downloads\u003c/a\u003e\u003cbr\u003e\n因文件太大，就不放到附件中了，请自行去官网下载。\u003cbr\u003e\n下载后的文件是一个压缩包，直接解压，然后移动到自己习惯的目录下。启动MongoCola的时候需要指定这个目录。\u003c/p\u003e\n\u003cp\u003e2、安装MongoCola\u003c/p\u003e","title":"MongoDB图形化管理工具"},{"content":"一、配置防火墙，开启80端口、3306端口\nCentOS 7.0默认使用的是firewall作为防火墙，这里改为iptables防火墙。\n1、关闭firewall：\n#停止firewall服务\n- **systemctl stop firewalld.service** #禁止firewall开机启动\n- **systemctl disable firewalld.service** 2、安装iptables防火墙\n#安装\n- **yum install iptables-services** #编辑防火墙配置文件\n- **vi /etc/sysconfig/iptables** # Firewall configuration written by system-config-firewall\n# Manual customization of this file is not recommended.\n*filter\n:INPUT ACCEPT [0:0]\n:FORWARD ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n-A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT\n-A INPUT -p icmp -j ACCEPT\n-A INPUT -i lo -j ACCEPT\n-A INPUT -m state –state NEW -m tcp -p tcp –dport 22 -j ACCEPT\n-A INPUT -m state –state NEW -m tcp -p tcp –dport 80 -j ACCEPT\n-A INPUT -m state –state NEW -m tcp -p tcp –dport 3306 -j ACCEPT\n-A INPUT -j REJECT –reject-with icmp-host-prohibited\n-A FORWARD -j REJECT –reject-with icmp-host-prohibited\nCOMMIT\n:wq! #保存退出\n** #最后重启防火墙使配置生效**\n- **systemctl restart iptables.service** #设置防火墙开机启动\n- **systemctl enable iptables.service** 二、关闭SELINUX\n#修改配置文件\n- **vi /etc/selinux/config** #SELINUX=enforcing #注释掉\n#SELINUXTYPE=targeted #注释掉\nSELINUX=disabled #增加\n:wq! #保存退出\n#使配置立即生效\n- **setenforce 0** 三.安装apache\n- **yum install httpd** 可能会用到的：\nsystemctl start httpd.service #启动apache\nsystemctl stop httpd.service #停止apache\nsystemctl restart httpd.service #重启apache\nsystemctl enable httpd.service #设置apache开机启动\nrestart一下，然后：\n输入localhost\n出现之后代表已经安装上去了。\n四.安装mysql\n方法参考\nhttp://blog.itpub.net/29773961/viewspace-1248176/\n**\n方法大致相同**\n在centos7中可以用：\n- **rpm -ivh mysql-community-release-el6-5.noarch.rpm** 关于这一步骤，在目前能够找到的centos7配置教程上，大多都是安装mariadb，因为centos7默认将mariadb视作mysql。\np.s.因为mysql被oracle收购后，原作者担心mysql闭源，所以又写了一个mariadb，这个数据库可以理解为mysql的分支。\n我在此处还是安装mysql\n如果需要安装mariadb，只需通过yum就可。\n五.安装php\n- **yum install php** 安装PHP组件，使PHP支持mysql\n- **yum install php-mysql php-gd libjpeg* php-ldap php-odbc php-pear php-xml php-xmlrpc php-mbstring php-bcmath php-mhash** 重启对应服务\n- **systemctl restart mysqld.service** - **systemctl restart httpd.service** ","permalink":"https://blog.zdltech.com/posts/centos-7-64bit-%E9%85%8D%E7%BD%AEapache-mysql-php/","summary":"\u003cp\u003e\u003cstrong\u003e一、配置防火墙，开启80端口、3306端口\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eCentOS 7.0默认使用的是firewall作为防火墙，这里改为iptables防火墙。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1、关闭firewall：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e#停止firewall服务\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv id=\"codeText\" class=\"codeText\"\u003e\n\u003cpre\u003e\u003ccode\u003e- **systemctl stop firewalld.service**\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003e#禁止firewall开机启动\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv id=\"codeText\" class=\"codeText\"\u003e\n\u003cpre\u003e\u003ccode\u003e- **systemctl disable firewalld.service**\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2、安装iptables防火墙\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e#安装\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv id=\"codeText\" class=\"codeText\"\u003e\n\u003cpre\u003e\u003ccode\u003e- **yum install iptables-services**\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003e#编辑防火墙配置文件\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv id=\"codeText\" class=\"codeText\"\u003e\n\u003cpre\u003e\u003ccode\u003e- **vi /etc/sysconfig/iptables**\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e# Firewall configuration written by system-config-firewall\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e# Manual customization of this file is not recommended.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e*\u003cstrong\u003efilter\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e:INPUT ACCEPT [0:0]\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e:FORWARD ACCEPT [0:0]\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e:OUTPUT ACCEPT [0:0]\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e-A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e-A INPUT -p icmp -j ACCEPT\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e-A INPUT -i lo -j ACCEPT\u003c/strong\u003e\u003c/p\u003e","title":"CentOS-7-64bit 配置Apache + MySQL + PHP"},{"content":"作为开发者平时可能想写点(非开源)的小东西，或者想保存一些私人配置什么的，这些也应该以 Git 的形式长期保存。毕竟 Git 的用途很广，有一份云端备份也很明智。但 Github 等服务只对开源项目免费，私有项目是按月收费的，并且还有仓库数量限制。自己的一些小作品或个人记录一般没有多大商业价值，项目本身又非常小，所以不值得花钱购买 Git 服务，但又不太适合公开。这种情况下你就需要一些可靠的免费私有 Git 仓库了。\n其实，Google 云平台上有一个 Cloud Source Repositories 服务，这就是我们需要的私有 Git 仓库功能。这个服务本意是让你的项目方便地在 Google Cloud 上集成和调试，但是你也可以只使用这个服务，当成你的免费私有仓库。以前 Google Cloud 中一个项目只能有一个仓库，用起来不方便，现在一个项目中可以建任意多个私有仓库了。Cloud Source Repositories beta 版服务是完全免费的，存储上限是 1 G ，一般存储源码等文本文件是足够用的。\n除了私有、免费之外，Cloud Source Repositories 还有以下优点：\n作为 Google 的服务，存储绝对安全、可靠。 一个 Cloud 项目下可以创建任意多个仓库。 支持代码编辑器，可以用浏览器在线查看、编辑、提交和仓库管理。 可以多人协作，访问私有仓库。 支持 GitHub 和 Bitbucket 仓库同步。 与 Google Cloud 的其它服务无缝集成。 使用方法和标准 Git 没有不同，唯一的差异是初始的账号认证方式不同。假设你已经本地安装了 Git ，然后你需要安装 Google Cloud SDK (一个命令行工具) 来初始化项目和账号认证，仅第一次需要。当然，你还需要在 Google Cloud 上新建一个项目作为服务的归属，并设置你的收费方式(不使用其他收费服务的话不用担心扣费)。具体 Git 服务的使用 Google 官方文档已经写地非常细致了，控制台上也一目了然(Git 服务是控制台菜单中的 Development)。\n官网链接：https://cloud.google.com/source-repositories/\n回答几个问题：1. 存储上限已提升为 1G 。2. 仓库数量和协作者数量没有限制。3. 和使用标准 Git 完全一样，只是初始的账号认证的方式不同。4. Git 服务完全免费，只要不使用 Cloud 中的其它收费业务就不会扣费。5. vpn 或 proxychains 可以帮你解决的第一步。\n转自:http://chinagdg.org/2016/04/%E7%94%A8-google-cloud-%E6%89%93%E9%80%A0%E4%BD%A0%E7%9A%84%E7%A7%81%E6%9C%89%E5%85%8D%E8%B4%B9-git-%E4%BB%93%E5%BA%93/\n","permalink":"https://blog.zdltech.com/posts/%E7%94%A8-google-cloud-%E6%89%93%E9%80%A0%E4%BD%A0%E7%9A%84%E7%A7%81%E6%9C%89%E5%85%8D%E8%B4%B9-git-%E4%BB%93%E5%BA%93/","summary":"\u003cp\u003e作为开发者平时可能想写点(非开源)的小东西，或者想保存一些私人配置什么的，这些也应该以 Git 的形式长期保存。毕竟 Git 的用途很广，有一份云端备份也很明智。但 Github 等服务只对开源项目免费，私有项目是按月收费的，并且还有仓库数量限制。自己的一些小作品或个人记录一般没有多大商业价值，项目本身又非常小，所以不值得花钱购买 Git 服务，但又不太适合公开。这种情况下你就需要一些可靠的免费私有 Git 仓库了。\u003c/p\u003e\n\u003cp\u003e其实，Google 云平台上有一个 Cloud Source Repositories 服务，这就是我们需要的私有 Git 仓库功能。这个服务本意是让你的项目方便地在 Google Cloud 上集成和调试，但是你也可以只使用这个服务，当成你的免费私有仓库。以前 Google Cloud 中一个项目只能有一个仓库，用起来不方便，现在一个项目中可以建任意多个私有仓库了。Cloud Source Repositories beta 版服务是完全免费的，存储上限是 1 G ，一般存储源码等文本文件是足够用的。\u003c/p\u003e\n\u003cp\u003e除了私有、免费之外，Cloud Source Repositories 还有以下优点：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e作为 Google 的服务，存储绝对安全、可靠。\u003c/li\u003e\n\u003cli\u003e一个 Cloud 项目下可以创建任意多个仓库。\u003c/li\u003e\n\u003cli\u003e支持代码编辑器，可以用浏览器在线查看、编辑、提交和仓库管理。\u003c/li\u003e\n\u003cli\u003e可以多人协作，访问私有仓库。\u003c/li\u003e\n\u003cli\u003e支持 GitHub 和 Bitbucket 仓库同步。\u003c/li\u003e\n\u003cli\u003e与 Google Cloud 的其它服务无缝集成。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e使用方法和标准 Git 没有不同，唯一的差异是初始的账号认证方式不同。假设你已经本地安装了 Git ，然后你需要安装 Google Cloud SDK (一个命令行工具) 来初始化项目和账号认证，仅第一次需要。当然，你还需要在 Google Cloud 上新建一个项目作为服务的归属，并设置你的收费方式(不使用其他收费服务的话不用担心扣费)。具体 Git 服务的使用 Google 官方文档已经写地非常细致了，控制台上也一目了然(Git 服务是控制台菜单中的 Development)。\u003c/p\u003e","title":"用 Google Cloud 打造你的私有免费 Git 仓库"},{"content":"2016年Qcon大会首日，阿里巴巴资深总监、淘宝移动平台、阿里百川负责人庄卓然宣布移动端高性能动态化方案Weex即时内测，并将于6月开源。此消息一出，群情汹涌，在座的程序猿、攻城狮们纷纷拿起手机扫码，以期第一时间感受Weex的神奇之力。\n在第二天的主题分享会上，阿里巴巴前端开发专家赵锦江和技术专家徐凯对Weex进行了深入的解析。以下为演讲速记整理后的成文。\n阿里怎么看待移动开发？\n目前的移动开发者面临的最大痛点就是面对极其复杂的环境，对此，庄卓然给出一个公式，移动开发的复杂度=应用数量×平台数量×要适配的各种各样的机型。\n如何解决这个问题呢？在解决问题之前，首先要对移动开发的未来有着精准的研判。\n阿里认为，移动开发的未来必定更加平衡，也就是说必须是性能与动态兼得，如此，才能够满足未来用户的需求。另外，移动开发在未来也必定是开放互联的状态，移动互联网将来肯定是基于更加大众化的技术体系，没有平台之间的隔阂，而且简单易用。\n所以，阿里结合移动开发的现状并围绕其愿景推出了Weex解决方案。\n事实上，在去年的双11活动中，Weex就得到了实战的验证，且表现不俗。时至今日，Weex已经被阿里技术团队多次运用，并“创造”出各种丰富的场景，整体的表现非常优异。\n把移动端所有界面拆分成各个page，然后中间设置有路由的控制逻辑，同时，将移动端各种各样的能力通过各种API提供给开发者。这是阿里对移动开发模型的理解。\nWeex通过标准化的东西，包括HTML、CSS和JS这些前端非常快速易用好学的语法作为开发体验，提供给开发者。另外，Weex的语法设计尊重还Web的标准。\nWeex的工作原理\nWeex设计之初就考虑到在三端（iOS、安卓和H5）上能够得到展现。在最上面的DSL，阿里一般称之为Weex文件（.we），通过Transformer转换成js-bundle，再部署到服务器，这样服务端就完成了。在客户端，第一层是JS-Framework，最后到RenderRengine。\n输入是Virtual DOM输出是native或者H5 view，还原成内存中的树型数据结构，再创建view，把事件绑定在view上，把view基本属性设上去。Weex Render会分三个线程，不同的线程负责不同的事情，让JS线程优先保障流畅性。\nWeex的性能、扩展性以及可用性究竟怎样呢？\n性能方面，阿里对Weex做了多次压测。在加载时间、帧率、内存消耗、CPU占用（包括静默和峰值）等多个方面，Weex都表现得非常出色。\n在谈及性能之时，帧率和加载时间几乎都会被提及，但是往往忽略了一个事实，那就是Native UI开发中通常没有JS资源在服务器端加载。Weex会把JS内置到客户端里，以免除下载的问题，从而更为有效地提升性能。\n兼容性是Weex非常重视的问题，对此，阿里是这样来解决的。\n首先是单测保证，包括JS和H5的单测，保证最基础的UT（Unit Test）本身所带来的含义。\n其次是UI的自动化，分为两个部分，一是截图对比，将最终产生的结果和意料中的结果进行图形对比；二是Layout Results，包括Model以及其他的布局类的，通过基本的信息完成测试的过程。\n在扩展性方面，Weex可以写很多页面，而且通过路由机制帮助开发者将页面进行串联。\nWeex已开放内测，可用性方面正在逐步完善。包括Playground、调试工具、脚手架、AppHub、编辑器等多个方面，一些工作已经完成就绪，绝大部分工作将在5、6月份完成。\n最后，是Weex的三种工作模式。\n1. 全页模式\n目前支持单页使用或整个App使用Weex开发（还不完善，需要开发Router和生命周期管理），这是主推的模式，可以类比RN。\n2. Native Component模式\n把Weex当作一个iOS/Android组件来使用，类比ImageView。这类需求遍布手淘主链路，如首页、主搜结果、交易组件化等，这类Native页面主体已经很稳定，但是局部动态化需求旺盛导致频繁发版，解决这类问题也是Weex的重点。\n3. H5 Component模式\n在H5种使用Weex，类比WVC。一些较复杂或特殊的H5页面短期内无法完全转为Weex全页模式（或RN），比如互动类页面、一些复杂频道页等。这个痛点的解决办法是：在现有的H5页面上做微调，引入Native解决长列表内存暴增、滚动不流畅、动画/手势体验差等问题。\n另外，WVC将会融入到Weex中，成为Weex的H5 Components模式。\n转自：http://mp.weixin.qq.com/s?__biz=MzA4MjA0MTc4NQ==\u0026amp;mid=504089602\u0026amp;idx=1\u0026amp;sn=7ad9a1820baa153a8dc051e9c4f16d25#rd\n","permalink":"https://blog.zdltech.com/posts/%E6%B7%B1%E5%BA%A6%E6%8F%AD%E7%A7%98%E9%98%BF%E9%87%8C%E7%A7%BB%E5%8A%A8%E7%AB%AF%E9%AB%98%E6%80%A7%E8%83%BD%E5%8A%A8%E6%80%81%E5%8C%96%E6%96%B9%E6%A1%88weex/","summary":"\u003cp\u003e2016年Qcon大会首日，阿里巴巴资深总监、淘宝移动平台、阿里百川负责人庄卓然宣布移动端高性能动态化方案Weex即时内测，并将于6月开源。此消息一出，群情汹涌，在座的程序猿、攻城狮们纷纷拿起手机扫码，以期第一时间感受Weex的神奇之力。\u003c/p\u003e\n\u003cp\u003e在第二天的主题分享会上，阿里巴巴前端开发专家赵锦江和技术专家徐凯对Weex进行了深入的解析。以下为演讲速记整理后的成文。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e阿里怎么看待移动开发？\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e目前的移动开发者面临的最大痛点就是面对极其复杂的环境，对此，庄卓然给出一个公式，移动开发的复杂度=应用数量×平台数量×要适配的各种各样的机型。\u003c/p\u003e\n\u003cp\u003e如何解决这个问题呢？在解决问题之前，首先要对移动开发的未来有着精准的研判。\u003c/p\u003e\n\u003cp\u003e阿里认为，移动开发的未来必定更加平衡，也就是说必须是性能与动态兼得，如此，才能够满足未来用户的需求。另外，移动开发在未来也必定是开放互联的状态，移动互联网将来肯定是基于更加大众化的技术体系，没有平台之间的隔阂，而且简单易用。\u003c/p\u003e\n\u003cp\u003e所以，阿里结合移动开发的现状并围绕其愿景推出了Weex解决方案。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://mmbiz.qpic.cn/mmbiz/yh0sDLwcT2Enq5vWqEcuRftdPXxDqYrrMyLaXpwY7pDRszzFeygvoEdkkYxXNFWBQYQPcIkaMeKjKpILHViczIA/640?wx_fmt=jpeg\u0026tp=webp\u0026wxfrom=5\u0026wx_lazy=1\"\u003e\u003c/p\u003e\n\u003cp\u003e事实上，在去年的双11活动中，Weex就得到了实战的验证，且表现不俗。时至今日，Weex已经被阿里技术团队多次运用，并“创造”出各种丰富的场景，整体的表现非常优异。\u003c/p\u003e\n\u003cp\u003e把移动端所有界面拆分成各个page，然后中间设置有路由的控制逻辑，同时，将移动端各种各样的能力通过各种API提供给开发者。这是阿里对移动开发模型的理解。\u003c/p\u003e\n\u003cp\u003eWeex通过标准化的东西，包括HTML、CSS和JS这些前端非常快速易用好学的语法作为开发体验，提供给开发者。另外，Weex的语法设计尊重还Web的标准。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWeex的工作原理\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://mmbiz.qpic.cn/mmbiz/WnbJRVnA42libMW4hQpibOaKnrwWGdsIEsRod5bic2otxkVTR9iclK0ZqK6iaZ0P4rftibMJFIKy9xibj79XYLLvyB7FA/640?wx_fmt=png\u0026tp=webp\u0026wxfrom=5\u0026wx_lazy=1\"\u003e\u003c/p\u003e\n\u003cp\u003eWeex设计之初就考虑到在三端（iOS、安卓和H5）上能够得到展现。在最上面的DSL，阿里一般称之为Weex文件（.we），通过Transformer转换成js-bundle，再部署到服务器，这样服务端就完成了。在客户端，第一层是JS-Framework，最后到RenderRengine。\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://mmbiz.qpic.cn/mmbiz/WnbJRVnA42libMW4hQpibOaKnrwWGdsIEs6ZhwckGBEcOD7PugUc7K40mCTg1Jg6nBZAXYAEO4M08MMGFD3XDFcA/640?wx_fmt=png\u0026tp=webp\u0026wxfrom=5\u0026wx_lazy=1\"\u003e\u003c/p\u003e\n\u003cp\u003e输入是Virtual DOM输出是native或者H5 view，还原成内存中的树型数据结构，再创建view，把事件绑定在view上，把view基本属性设上去。Weex Render会分三个线程，不同的线程负责不同的事情，让JS线程优先保障流畅性。\u003c/p\u003e\n\u003cp\u003eWeex的性能、扩展性以及可用性究竟怎样呢？\u003c/p\u003e\n\u003cp\u003e性能方面，阿里对Weex做了多次压测。在加载时间、帧率、内存消耗、CPU占用（包括静默和峰值）等多个方面，Weex都表现得非常出色。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://mmbiz.qpic.cn/mmbiz/WnbJRVnA42libMW4hQpibOaKnrwWGdsIEsg5iceSWhQKj2fmXzaZGG9ul9O3ibIMuOibzrhYAQLSWdlUbSMiaQiaBsEzQ/640?wx_fmt=png\u0026tp=webp\u0026wxfrom=5\u0026wx_lazy=1\"\u003e\u003c/p\u003e\n\u003cp\u003e在谈及性能之时，帧率和加载时间几乎都会被提及，但是往往忽略了一个事实，那就是Native UI开发中通常没有JS资源在服务器端加载。Weex会把JS内置到客户端里，以免除下载的问题，从而更为有效地提升性能。\u003c/p\u003e\n\u003cp\u003e兼容性是Weex非常重视的问题，对此，阿里是这样来解决的。\u003c/p\u003e\n\u003cp\u003e首先是单测保证，包括JS和H5的单测，保证最基础的UT（Unit Test）本身所带来的含义。\u003c/p\u003e\n\u003cp\u003e其次是UI的自动化，分为两个部分，一是截图对比，将最终产生的结果和意料中的结果进行图形对比；二是Layout Results，包括Model以及其他的布局类的，通过基本的信息完成测试的过程。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://mmbiz.qpic.cn/mmbiz/WnbJRVnA42libMW4hQpibOaKnrwWGdsIEs9OJiarFuGL4StHV3AXh3mMosRUGzVgZaceibPTiayHdHft2cz3XEeBOhw/640?wx_fmt=png\u0026tp=webp\u0026wxfrom=5\u0026wx_lazy=1\"\u003e\u003c/p\u003e\n\u003cp\u003e在扩展性方面，Weex可以写很多页面，而且通过路由机制帮助开发者将页面进行串联。\u003c/p\u003e\n\u003cp\u003eWeex已开放内测，可用性方面正在逐步完善。包括Playground、调试工具、脚手架、AppHub、编辑器等多个方面，一些工作已经完成就绪，绝大部分工作将在5、6月份完成。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://mmbiz.qpic.cn/mmbiz/WnbJRVnA42libMW4hQpibOaKnrwWGdsIEsiaf0E3ADVNSLb6spaFs8UcChypnGu6lCfwYOs9ZIOtPMxNy3u3NnAIw/640?wx_fmt=png\u0026tp=webp\u0026wxfrom=5\u0026wx_lazy=1\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e最后，是Weex的三种工作模式。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. 全页模式\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e目前支持单页使用或整个App使用Weex开发（还不完善，需要开发Router和生命周期管理），这是主推的模式，可以类比RN。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. Native Component模式\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e把Weex当作一个iOS/Android组件来使用，类比ImageView。这类需求遍布手淘主链路，如首页、主搜结果、交易组件化等，这类Native页面主体已经很稳定，但是局部动态化需求旺盛导致频繁发版，解决这类问题也是Weex的重点。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. H5 Component模式\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在H5种使用Weex，类比WVC。一些较复杂或特殊的H5页面短期内无法完全转为Weex全页模式（或RN），比如互动类页面、一些复杂频道页等。这个痛点的解决办法是：在现有的H5页面上做微调，引入Native解决长列表内存暴增、滚动不流畅、动画/手势体验差等问题。\u003c/p\u003e\n\u003cp\u003e另外，WVC将会融入到Weex中，成为Weex的H5 Components模式。\u003c/p\u003e\n\u003cp\u003e转自：http://mp.weixin.qq.com/s?__biz=MzA4MjA0MTc4NQ==\u0026amp;mid=504089602\u0026amp;idx=1\u0026amp;sn=7ad9a1820baa153a8dc051e9c4f16d25#rd\u003c/p\u003e","title":"深度揭秘阿里移动端高性能动态化方案Weex"},{"content":"我一般都喜欢去一些技术类博客社区或者 UGC 社区浏览文章，相信与我同类的你应该也有这爱好。为了方便自己的阅读，而不用一个一个打开目标网站的地址，就基于 Node+React 写了一个小爬虫: Tech-Read，用于抓取常去的 UGC 社区的文章摘要。目前的版本大概样子如下：\n在线地址：Tech-Read\ngithub 地址：tech-read\n开发 Tech-Read 是个人的一个业余项目，初衷是方便自己阅读，实在是懒于去社区网站阅读，其次用于练手喽，毕竟最近在学点新东西。\n在工作上，接触的技术栈是 Node + React，所以 TR 也采用了 Node + React 的技术栈。React 用于前端界面渲染，Node 用于抓取网页，并将解析后的 DOM 数据返回给前端调用。\n前端的请求是用 fetch 发起的，由于部分社区做了跨域设置，So 用 Node 能帮我解决一些跨域的问题：\n以及在 fetch 中解析 DOM 时碰到的诸如 Uncaught (in promise) TypeError: unexpected token \u0026lt;... 等杂七杂八的错误。\n并且 Node 端提供了直接操作 DOM 节点的 cheerio，它是 jQuery 的一个子集实现，能非常方便的操作 DOM 元素。所以，目前我把 DOM 解析放在了 Node 端，前端只负责渲染。\n所以，现在的处理流程如下：\n由于目前业务比较简单，前端的状态管理就用 Flux。Node 使用 Koa，匹配到 fetch发起的路由后，通过 request向目标网站发起请求，然后通过 cheerio 解析 body，获取 DOM 元素数据，以 json 形式返回给前端进行展示。\nrequest 发起的异步请求的返回对象不带 Promise/Generator 等特性，所以不能同步写，但利用 Promise 简单封装下：\nexports.parseBody = function (url) { return new Promise(function (resolve, reject) { request(url, (error, res, body) =\u0026gt; { if(!error \u0026amp;\u0026amp; res.statusCode === 200) { resolve(body); } else { reject(error); } }); }); }; 就能同步的来写异步请求了：\nlet resBody = yield lib.parseBody('http://toutiao.io/').then((body) =\u0026gt; { return body; }); 另外一个选择是，利用 co-request，基于 generator 的一个网络请求库。\n我个人很喜欢开发者头条，所以第一个抓取的也是开发者头条。由于我想在 TR 上直接看原文，就像这样子：\n所以我需要拿到原文链接，插入到 Iframe 里面去。抓取其它社区时，能在抓取首页时顺便拿到原文链接，但是抓取开发者头条的时候，并不能，因为它的 DOM 结构是这样的：\n这个 a 的 href 属性并不是原文的链接，要想拿到原文链接，还需要再向 http://toutiao.io/r/b04ku7/r/b04ku7发起一次 get 请求：\n但这个 Location 是不能直接拿到的，因为返回的状态码是 302，页面会被直接跳转到了 Location 指向的页面。但是，request 发起请求后的 response 中则包含了 host 和 path 信息：\nreq.on('response', (res) =\u0026gt; { if(res.statusCode === 200) { urlPath = res.client._httpMessage._headers.host + res.client._httpMessage.path; resolve(urlPath); } }); 将二者拼接，就能得到原文的 URL 了。\n开发者头条部分实现了无限加载：\nlet contents = document.getElementsByClassName('toutiao-contents')[0]; let contentsHeight = contents.getBoundingClientRect().height; contents.addEventListener('scroll', (e) =\u0026gt; { let triggerNextMinHeight = e.target.scrollHeight - e.target.scrollTop - contentsHeight; if(triggerNextMinHeight \u0026lt; 22) { //fetch data \u0026amp; update component state } },false); 无限加载调用的接口是：\nhttp://toutiao.io/prev/date //date 形如 2016-04-26 部署 前文以抓取开发者头条为例，简单讲述了爬虫的实现思路，接下来就简单说说怎么部署 Node 服务。\n由于服务器上已经跑了自己的博客，端口 80 已经被Apache 监听了，所以，你看到的 TR 的线上端口就是奇怪的 8080 了，这是 Nginx 监听的，然后被代理到本地的 9000 端口，这也是开发用的端口。\n部署之前，先安装下 Node(系统是 CentOS 6.5 64bit)。\n1、安装nvm\ncurl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.0/install.sh | bash 或者：\nwget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.31.0/install.sh | bash 建议使用 nvm 安装 Node，因为 nvm 会安装到用户的目录，而 n 会安装到全局的 /usr/ 目录下去。\n2、安装 Node\nnvm install 4.4.2 如果安装了多版本，则可以将默认的 Node 版本设置成 4.4.2：\nnvm alias default 4.4.2 3、安装Nginx\n切换到 /etc/yum.repos.d/ 创建文件 nginx.repo ，将下面的粘贴到文件中：\n[nginx] name=nginx repo baseurl=http://nginx.org/packages/centos/\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;releasever/\u0026lt;/span\u0026gt;basearch/ gpgcheck=0 enabled=1 然后安装 Nginx:\nyum install nginx Nginx 的相关配置:\n/etc/init.d/nginx start/restart # 启动/重启Nginx服务 /etc/init.d/nginx stop # 停止Nginx服务 /etc/nginx/nginx.conf # Nginx配置文件位置 4、配置 Nginx\n切换到 /etc/nginx/conf.d ，复制 default.conf 文件，按照需要配置新的 conf 文件：\ntechread.conf 配置文件如下：\nlisten: 监听的线上端口\nserver_name: 访问的域名\nroot: 根目录\nindex: 默认访问的文件\nnginx 可以有多个虚拟主机，每个虚拟主机一个对应的server配置项。\n红框部分是 Nginx 的反向代理配置：\nproxy_set_header X-Real-IP \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;remote_addr; proxy_set_header X-Forwarded-For\u0026lt;/span\u0026gt;proxy_add_x_forwarded_for; proxy_set_header HOST $http_host; proxy_set_header X-Nginx_Proxy true; proxy_pass http://127.0.0.1:9000/; proxy_redirect off; proxy_pass 是必备项，表示要被代理的服务地址，其它可有可无(至少对于 TR 来说)。\n安利一份关于解读 Nginx 源码的资源：Nginx 福利\n启动 Nginx 时，默认是读取 default.conf，现在需要将其更改为读取 techread.conf。 回到 /etc/nginx 下，修改 nginx.conf 文件， 将 include 的引用改为新建的文件：techread.conf：\n重启 nginx，线上部署就 OK 了。\nTODO 目前的 Tech-Read 还有很多可以改进的地方，以及一些等待完善的功能:\n浏览器路由 无限加载(目前只做了开发者头条的) iframe禁用处理 缓存优化 丰富内容和内容分类 研究下怎么抓稀土的 待续。。。 转载请注明：淡忘~浅思 » Node+React小爬虫：从开发到部署\n","permalink":"https://blog.zdltech.com/posts/nodereact%E5%B0%8F%E7%88%AC%E8%99%AB%E4%BB%8E%E5%BC%80%E5%8F%91%E5%88%B0%E9%83%A8%E7%BD%B2/","summary":"\u003cp\u003e我一般都喜欢去一些技术类博客社区或者 UGC 社区浏览文章，相信与我同类的你应该也有这爱好。为了方便自己的阅读，而不用一个一个打开目标网站的地址，就基于 Node+React 写了一个小爬虫: \u003ca href=\"http://tech-read.ido321.com:8080/\"\u003eTech-Read\u003c/a\u003e，用于抓取常去的 UGC 社区的文章摘要。目前的版本大概样子如下：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"version\" loading=\"lazy\" src=\"https://segmentfault.com/img/bVu8GE\"\u003e\u003c/p\u003e\n\u003cp\u003e在线地址：\u003ca href=\"http://tech-read.ido321.com:8080/\"\u003eTech-Read\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003egithub 地址：\u003ca href=\"https://github.com/dwqs/tech-read\"\u003etech-read\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"toc_0\"\u003e开发\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://tech-read.ido321.com:8080/\"\u003eTech-Read\u003c/a\u003e 是个人的一个业余项目，初衷是方便自己阅读，实在是懒于去社区网站阅读，其次用于练手喽，毕竟最近在学点新东西。\u003c/p\u003e\n\u003cp\u003e在工作上，接触的技术栈是 Node + React，所以 TR 也采用了 Node + React 的技术栈。React 用于前端界面渲染，Node 用于抓取网页，并将解析后的 DOM 数据返回给前端调用。\u003c/p\u003e\n\u003cp\u003e前端的请求是用 \u003ca href=\"http://www.ido321.com/1673.html\"\u003e\u003ccode\u003efetch\u003c/code\u003e\u003c/a\u003e 发起的，由于部分社区做了跨域设置，So 用 Node 能帮我解决一些跨域的问题：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"cors\" loading=\"lazy\" src=\"https://segmentfault.com/img/bVu8Hb\"\u003e\u003c/p\u003e\n\u003cp\u003e以及在 \u003ccode\u003efetch\u003c/code\u003e 中解析 DOM 时碰到的诸如 \u003ccode\u003eUncaught (in promise) TypeError: unexpected token \u0026lt;...\u003c/code\u003e 等杂七杂八的错误。\u003c/p\u003e\n\u003cp\u003e并且 Node 端提供了直接操作 DOM 节点的 \u003ca href=\"https://github.com/cheeriojs/cheerio\"\u003e\u003ccode\u003echeerio\u003c/code\u003e\u003c/a\u003e，它是 jQuery 的一个子集实现，能非常方便的操作 DOM 元素。所以，目前我把 DOM 解析放在了 Node 端，前端只负责渲染。\u003c/p\u003e\n\u003cp\u003e所以，现在的处理流程如下：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"process\" loading=\"lazy\" src=\"https://segmentfault.com/img/bVvezP\"\u003e\u003c/p\u003e\n\u003cp\u003e由于目前业务比较简单，前端的状态管理就用 Flux。Node 使用 Koa，匹配到 \u003ca href=\"http://www.ido321.com/1673.html\"\u003e\u003ccode\u003efetch\u003c/code\u003e\u003c/a\u003e发起的路由后，通过 \u003ca href=\"https://github.com/request/request\"\u003e\u003ccode\u003erequest\u003c/code\u003e\u003c/a\u003e向目标网站发起请求，然后通过 \u003ccode\u003echeerio\u003c/code\u003e 解析 body，获取 DOM 元素数据，以 json 形式返回给前端进行展示。\u003c/p\u003e","title":"Node+React小爬虫：从开发到部署"},{"content":"Java源代码搜索 Grepcode是一个面向于Java开发人员的网站，在这里你可以通过Java的projects、classes等各种关键字在线查看它对应的源码，知道对应的project、classes等信息。 更方便的是，能提供非常多不同版本的源码在线查看、jar包、源码jar包、doc的下载。 同样，你也可以之间使用xxx-1.1.1.jar类似这样的名字直接找到对应的jar包，从而下载。\n开源代码及文档搜索 SearchCode 是一个源码搜索引擎，目前支持从 Github、Bitbucket、Google Code、CodePlex、SourceForge 和 Fedora Project 平台搜索公开的源码。\n在线UML制图 ProcessOn是一个在线协作绘图平台,为用户提供最强大、易用的作图工具!支持在线创作流程图、BPMN、UML图、UI界面原型设计、iOS界面原型设计等。\nJson在线验证及格式化 我用过很多json在线格式化的工具，经过实践，json.cn是比较不错的，不仅支持json格式的验证及格式化，还可以将json格式压缩成普通文本等好用功能。\nDiff Check 使用过svn或者git的人对diffcheck肯定不陌生，但有时候我们修改的文本内容并没有被版本控制，那么就可以使用在线的网站查看文件的修改情况。https://www.diffchecker.com/很不错。\nMarkDown编辑器 MaHua\n马克飞象\nCmd\n以上这几个我都用过，都还好吧，因为我一般都喜欢把自己写过的东西保存下来，所以就用了客户端的，我是用的是MacDown\nMaven依赖查询 mvnrepository这个不用详细解释了，就是查询maven的gav信息一类的。因为我们公司有内部的Nexus仓库，所以很少用这个。\n在线代码运行 http://tool.lu/coderunner/可以在线运行php,c,c++,go,python,java,groovy等代码。基本是很少使用。\n在线翻译 Google翻译 百度翻译 有道翻译 爱词霸翻译\n说不出具体哪个好，其实都不太准确，还是需要自己根据语境进行翻译。\n不过忍不住吐槽一句国内的这几个翻译网站，既然是做翻译的，域名竟然用拼音，我也是醉了。\nSQL自动生成Java代码 AutoJCode可以从sql的建表语句中生成一个DO类。\njson生成java类 http://www.bejson.com/json2javapojo/\nSQL美化/格式化/压缩 sql在线美化，格式化，压缩\n编码转换 站长工具的编码转换比较全面，提供了Unicode编码、UFT8编码、URL编码/解码等功能。\nCorn表达式生成 Cron一般用于配置定时任务的执行。没有什么特别好的网站，http://www.pdtools.net/tools/becron.jsp还可以吧，基本可以满足需求。\n正则验证 Java开发对正则表达式肯定不陌生。站长工具提供的正则验证还不错。\n正则代码生成 站长工具提供的正则代码生成。\n时间戳转换 时间戳(英语：Timestamp）是指在一连串的资料中加入辨识文字，如时间或日期，用以保障本地端（local）资料更新顺序与远端（remote）一致。\n站长工具提供的时间戳转换。\n世界时间转换 世界各地时间转换，我比较常用的是北京时间转纽约时间，北京时间转洛杉矶时间。 timebie提供了世界时间相互转换的功能。\n加密解密 站长工具中的加密解密\n查看网页源代码 查看网页源代码\n单位换算 convertworld是一个比较全的单位换算的网站。我经常用它进行时间单位和货币单位的换算。\n在线调色板 在线调色板\n常用对照表 ASCII对照表\nHTTP状态码\nHTTP Content-type\nTCP/UDP常见端口参考\nHTML转义字符\nRGB颜色参考\n欢迎补充~ 转自：http://www.hollischuang.com/archives/1459\n","permalink":"https://blog.zdltech.com/posts/java%E5%BC%80%E5%8F%91%E5%B8%B8%E7%94%A8%E7%9A%84%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/","summary":"\u003ch2 id=\"java源代码搜索\"\u003eJava源代码搜索\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://grepcode.com/\"\u003eGrepcode\u003c/a\u003e是一个面向于Java开发人员的网站，在这里你可以通过Java的projects、classes等各种关键字在线查看它对应的源码，知道对应的project、classes等信息。 更方便的是，能提供非常多不同版本的源码在线查看、jar包、源码jar包、doc的下载。 同样，你也可以之间使用xxx-1.1.1.jar类似这样的名字直接找到对应的jar包，从而下载。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.hollischuang.com/images/2016/04/grepcode1.png\"\u003e\u003cimg alt=\"grepcode1\" loading=\"lazy\" src=\"http://www.hollischuang.com/images/2016/04/grepcode1-1024x279.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"开源代码及文档搜索\"\u003e开源代码及文档搜索\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://searchcode.com/\"\u003eSearchCode\u003c/a\u003e 是一个源码搜索引擎，目前支持从 Github、Bitbucket、Google Code、CodePlex、SourceForge 和 Fedora Project 平台搜索公开的源码。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.hollischuang.com/images/2016/04/searchcode.png\"\u003e\u003cimg alt=\"searchcode\" loading=\"lazy\" src=\"http://www.hollischuang.com/images/2016/04/searchcode-1024x651.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"在线uml制图\"\u003e在线UML制图\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://www.processon.com/\"\u003eProcessOn\u003c/a\u003e是一个在线协作绘图平台,为用户提供最强大、易用的作图工具!支持在线创作流程图、BPMN、UML图、UI界面原型设计、iOS界面原型设计等。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.hollischuang.com/images/2016/04/processon.png\"\u003e\u003cimg alt=\"processon\" loading=\"lazy\" src=\"http://www.hollischuang.com/images/2016/04/processon.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"json在线验证及格式化\"\u003eJson在线验证及格式化\u003c/h2\u003e\n\u003cp\u003e我用过很多json在线格式化的工具，经过实践，\u003ca href=\"http://json.cn/\"\u003ejson.cn\u003c/a\u003e是比较不错的，不仅支持json格式的验证及格式化，还可以将json格式压缩成普通文本等好用功能。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.hollischuang.com/images/2016/04/json.png\"\u003e\u003cimg alt=\"json\" loading=\"lazy\" src=\"http://www.hollischuang.com/images/2016/04/json-1024x331.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.hollischuang.com/images/2016/04/json1.png\"\u003e\u003cimg alt=\"json1\" loading=\"lazy\" src=\"http://www.hollischuang.com/images/2016/04/json1-1024x167.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"diff-check\"\u003eDiff Check\u003c/h2\u003e\n\u003cp\u003e使用过svn或者git的人对diffcheck肯定不陌生，但有时候我们修改的文本内容并没有被版本控制，那么就可以使用在线的网站查看文件的修改情况。\u003ca href=\"https://www.diffchecker.com/\"\u003ehttps://www.diffchecker.com/\u003c/a\u003e很不错。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.hollischuang.com/images/2016/04/differ.png\"\u003e\u003cimg alt=\"differ\" loading=\"lazy\" src=\"http://www.hollischuang.com/images/2016/04/differ-1024x612.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"markdown编辑器\"\u003eMarkDown编辑器\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://mahua.jser.me/\"\u003eMaHua\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"https://maxiang.io/\"\u003e马克飞象\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"https://www.zybuluo.com/mdeditor\"\u003eCmd\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e以上这几个我都用过，都还好吧，因为我一般都喜欢把自己写过的东西保存下来，所以就用了客户端的，我是用的是\u003ca href=\"http://macdown.uranusjr.com/\"\u003eMacDown\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"maven依赖查询\"\u003eMaven依赖查询\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://mvnrepository.com/\"\u003emvnrepository\u003c/a\u003e这个不用详细解释了，就是查询maven的gav信息一类的。因为我们公司有内部的Nexus仓库，所以很少用这个。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.hollischuang.com/images/2016/04/log4j1.png\"\u003e\u003cimg alt=\"log4j1\" loading=\"lazy\" src=\"http://www.hollischuang.com/images/2016/04/log4j1.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"在线代码运行\"\u003e在线代码运行\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://tool.lu/coderunner/\"\u003ehttp://tool.lu/coderunner/\u003c/a\u003e可以在线运行php,c,c++,go,python,java,groovy等代码。基本是很少使用。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.hollischuang.com/images/2016/04/coderunner.png\"\u003e\u003cimg alt=\"coderunner\" loading=\"lazy\" src=\"http://www.hollischuang.com/images/2016/04/coderunner-1024x178.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"在线翻译\"\u003e在线翻译\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://translate.google.cn/\"\u003eGoogle翻译\u003c/a\u003e \u003ca href=\"http://fanyi.baidu.com/\"\u003e百度翻译\u003c/a\u003e \u003ca href=\"http://fanyi.youdao.com/\"\u003e有道翻译\u003c/a\u003e \u003ca href=\"http://fy.iciba.com/\"\u003e爱词霸翻译\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e说不出具体哪个好，其实都不太准确，还是需要自己根据语境进行翻译。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e不过忍不住吐槽一句国内的这几个翻译网站，既然是做翻译的，域名竟然用拼音，我也是醉了。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"sql自动生成java代码\"\u003eSQL自动生成Java代码\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://www.autojcode.com/code/sql2class.jsp\"\u003eAutoJCode\u003c/a\u003e可以从sql的建表语句中生成一个DO类。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.hollischuang.com/images/2016/04/autojcode.png\"\u003e\u003cimg alt=\"autojcode\" loading=\"lazy\" src=\"http://www.hollischuang.com/images/2016/04/autojcode.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"json生成java类\"\u003ejson生成java类\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://www.bejson.com/json2javapojo/\"\u003ehttp://www.bejson.com/json2javapojo/\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"sql美化格式化压缩\"\u003eSQL美化/格式化/压缩\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://tool.lu/sql/\"\u003esql在线美化，格式化，压缩\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"编码转换\"\u003e编码转换\u003c/h2\u003e\n\u003cp\u003e站长工具的\u003ca href=\"http://tool.chinaz.com/tools/unicode.aspx\"\u003e编码转换\u003c/a\u003e比较全面，提供了Unicode编码、UFT8编码、URL编码/解码等功能。\u003c/p\u003e\n\u003ch2 id=\"corn表达式生成\"\u003eCorn表达式生成\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://zh.wikipedia.org/zh-sg/Cron\"\u003eCron\u003c/a\u003e一般用于配置定时任务的执行。没有什么特别好的网站，\u003ca href=\"http://www.pdtools.net/tools/becron.jsp\"\u003ehttp://www.pdtools.net/tools/becron.jsp\u003c/a\u003e还可以吧，基本可以满足需求。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.hollischuang.com/images/2016/04/corn.png\"\u003e\u003cimg alt=\"corn\" loading=\"lazy\" src=\"http://www.hollischuang.com/images/2016/04/corn.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"正则验证\"\u003e正则验证\u003c/h2\u003e\n\u003cp\u003eJava开发对\u003ca href=\"https://zh.wikipedia.org/wiki/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F\"\u003e正则表达式\u003c/a\u003e肯定不陌生。\u003ca href=\"http://tool.chinaz.com/regex\"\u003e站长工具\u003c/a\u003e提供的正则验证还不错。\u003c/p\u003e\n\u003ch2 id=\"正则代码生成\"\u003e正则代码生成\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://tool.chinaz.com/tools/regexgenerate\"\u003e站长工具\u003c/a\u003e提供的正则代码生成。\u003c/p\u003e\n\u003ch2 id=\"时间戳转换\"\u003e时间戳转换\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://zh.wikipedia.org/wiki/%E6%99%82%E9%96%93%E6%88%B3\"\u003e时间戳\u003c/a\u003e(英语：Timestamp）是指在一连串的资料中加入辨识文字，如时间或日期，用以保障本地端（local）资料更新顺序与远端（remote）一致。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://tool.chinaz.com/Tools/unixtime.aspx\"\u003e站长工具\u003c/a\u003e提供的时间戳转换。\u003c/p\u003e\n\u003ch2 id=\"世界时间转换\"\u003e世界时间转换\u003c/h2\u003e\n\u003cp\u003e世界各地时间转换，我比较常用的是\u003ca href=\"http://www.timebie.com/cn/beijingnewyork.php\"\u003e北京时间转纽约时间\u003c/a\u003e，\u003ca href=\"http://www.timebie.com/cn/beijinglosangeles.php\"\u003e北京时间转洛杉矶\u003c/a\u003e时间。 \u003ca href=\"http://www.timebie.com/cn/easternbeijing.php\"\u003etimebie\u003c/a\u003e提供了世界时间相互转换的功能。\u003c/p\u003e\n\u003ch2 id=\"加密解密\"\u003e加密解密\u003c/h2\u003e\n\u003cp\u003e站长工具中的\u003ca href=\"http://tool.chinaz.com/tools/textencrypt.aspx\"\u003e加密解密\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"查看网页源代码\"\u003e查看网页源代码\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://s.tool.chinaz.com/tools/pagecode.aspx\"\u003e查看网页源代码\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"单位换算\"\u003e单位换算\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://www.convertworld.com/zh-hans/\"\u003econvertworld\u003c/a\u003e是一个比较全的单位换算的网站。我经常用它进行时间单位和货币单位的换算。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.hollischuang.com/images/2016/04/convertworld.png\"\u003e\u003cimg alt=\"convertworld\" loading=\"lazy\" src=\"http://www.hollischuang.com/images/2016/04/convertworld.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"在线调色板\"\u003e在线调色板\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://tool.chinaz.com/Tools/OnlineColor.aspx\"\u003e在线调色板\u003c/a\u003e\u003c/p\u003e","title":"Java开发常用的在线工具"},{"content":"如何优雅的使用 phpStorm 开发工具 按照惯例依然是从百科上复制一条简介: PhpStorm 是 JetBrains 公司开发的一款商业的 PHP 集成开发工具。PhpStorm可随时帮助用户对其编码进行调整，运行单元测试或者提供可视化debug功能和智能HTML/CSS/JavaScript/PHP编辑、代码质量分析、版本控制集成（SVN、GIT）、调试和测试等功能。另外，它还是跨平台。在Windows和MacOS下都可以使用。PhpStorm-让开发更智能，而不是更困难。\n听说phpStorm 10支持php7呃\n优点 跨平台。 对PHP支持refactor功能。 自动生成phpdoc的注释，非常方便进行大型编程。 内置支持Zencode。 生成类的继承关系图，如果有一个类，多次继承之后，可以通过这个功能查看他所有的父级关系。 支持代码重构，方便修改代码。 拥有本地历史记录功能（local history功能）。 方便的部署，可以直接将代码直接upload到服务器。 总之它很牛逼就是了，什么都能干\n快捷键 phpStorm有非常非常多并且好用的的快捷键，我下面就举一些经常用的的快捷键演示，还有一些不常用的就不举例了，绝对能提高你开发的效力率…\n(Windows与Mac类似，只要把command键换成ctrl)\n查询相关 command + f 查找当前文件 command + r 查找替换 command + e 打开最近的文件 command + shift + o 快速查询文件 command + shift + f 关键字查找,更强大的查询器(机器不好的，最好还是先确定一下目录) command + shift + r 高级替换 command + alt + b 找到当剪类的所有子类 alt + shift + c 查找最近修改的文件 alt + f7 直接查询选中的字符 ctrl + f7 文件中查询选中字符 command + 鼠标点击 跳到类或方法或变量等声明处 command + shift + tab 切换tab页文件 command + shift + +,- 展开或缩起 command + . 折叠或展开选中的代码 自动代码 alt + 回车 导入包，自动修正 command + n 快事为每个成员属性生成 getter 及 setter 方法 ctrl + i 快速生成插入魔术方法 ctrol + o 复写父类方法 command + alt + l 对当前文件进行格式化排版 command + d 复制当剪行 command + / // 注释 command + shift + / / / 注释 以command + n举个例子\n我创建了一个Person类在/Entity/目录下,然后我设置一些私有的属性如下代码:\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;namespace\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Entity\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Person\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;$sign\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;\u0026#39;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;$name\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;\u0026#39;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;$age\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;$work\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;\u0026#39;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;$sex\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;女\u0026#39;\u0026amp;lt;/span\u0026gt;; }` 然后咱们使用command + n 在弹出来的窗口选择”PHPDoc Blocks…” 如下图:\n再再弹出的窗口选择所有属性再点”OK”:\n`namespace Entity; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * Class Person *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @package\u0026amp;lt;/span\u0026gt; Entity */\u0026amp;lt;/span\u0026gt; class Person { \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @var\u0026amp;lt;/span\u0026gt; string */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; $sign = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;\u0026#39;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @var\u0026amp;lt;/span\u0026gt; string */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; $name = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;\u0026#39;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @var\u0026amp;lt;/span\u0026gt; int */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; $age = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @var\u0026amp;lt;/span\u0026gt; string */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; $work = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;\u0026#39;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @var\u0026amp;lt;/span\u0026gt; string */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; $sex = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;女\u0026#39;\u0026amp;lt;/span\u0026gt;; }` 然后它就对刚刚所选择属性加上了注释…… 是不是灰常神奇。\nok，咱们继续，再次使用command + n键选择Contructor...弹出需要进行传参赋值的属性:\n` \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * Person constructor. *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; string $sign */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; function \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;__construct\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;sign) {\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;-\u0026amp;gt;sign = $sign; }` 如果不选择的话将不需要对成员属性进行设置。\n然后咱们再来看看其他功能，比如”Implement Methods…”这个是快速生成魔术方法。\n通常咱们设置、获取一个成员属性时最好不要直接使用$person-\u0026gt;name = $name 这种方式进行设置参数或取得参数值，建议是对每个属性都开放一个 getter 跟 setter 方法，这样可以很方便得对传进或传出去的值进行处理，这就是上面我为什么要把成员属性设置置为私有的原因之一\n同样的command + n 选择”Getters and Stetters” 然后选择所有属性，它就会把所有的属性设置getter及setter方法，这里要注意的是Person的sign是唯一的，不可进行修改，所以咱们要把设置sign的方法去掉。注意: 最好setter方法设置完后返回当剪对象，这样的话咱们就可以连写了并且phpStorm的提示还相当友好下面有例子:\n` \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; string */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; function \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getSign\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; $\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;-\u0026amp;gt;sign; } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; string */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; function \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getName\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; $\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;-\u0026amp;gt;name; } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; string $name *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; $this */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; function \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setName\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;name) {\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;-\u0026amp;gt;name = $name; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; $\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; int */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; function \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getAge\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; $\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;-\u0026amp;gt;age; } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; int $age *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; $this */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; function \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setAge\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;age) {\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;-\u0026amp;gt;age = $age; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; $\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; string */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; function \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getWork\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; $\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;-\u0026amp;gt;work; } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; string $work *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; $this */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; function \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setWork\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;work) {\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;-\u0026amp;gt;work = $work; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; $\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @var\u0026amp;lt;/span\u0026gt; string */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; $sex = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;女\u0026#39;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; string */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; function \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getSex\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; $\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;-\u0026amp;gt;sex; } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; string $sex *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; $this */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; function \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setSex\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;sex) {\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;-\u0026amp;gt;sex = $sex; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; $\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; }` 连写的例子:\n`use Entity\\Person; $person = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Person(); $person-\u0026amp;gt;setName\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;蛋蛋\u0026#34;\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;/span\u0026gt; -\u0026amp;gt;\u0026amp;lt;/span\u0026gt;setAge\u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;17\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;/span\u0026gt; -\u0026amp;gt;\u0026amp;lt;/span\u0026gt;setWork(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;student\u0026#39;\u0026amp;lt;/span\u0026gt;);` 最后再演示一个快速复写被继承类的功能。咱们新建一个Man类，然后继承Person类，上面的Person类缺省是女性别，所以我们需要重写它并且加上”中国男人”。同样的使用command + n打开快捷窗口选择 “Override Methods…” 弹出来可被复写的方法:\n然后咱们选择getSex跟setSex方法，然后确定，在Man方法下生成以下方法。\n`namespace Entity; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * Class Man * \u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt;@package\u0026amp;lt;/span\u0026gt; Entity */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Man\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Person\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * \u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; string */\u0026amp;lt;/span\u0026gt; public function getSex() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; parent::getSex(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO: Change the autogenerated stub\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * \u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; int $sex * \u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt;@return\u0026amp;lt;/span\u0026gt; $this */\u0026amp;lt;/span\u0026gt; public function setSex($sex) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; parent::setSex($sex); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// TODO: Change the autogenerated stub\u0026amp;lt;/span\u0026gt; } }` 咱们把return parent::getSex()跟return parent::setSex( $age )删除掉，不需要这样，然后改成如下模式。\n` \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; string */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; function \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getSex\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; ( ! mb_strpos(parent::getSex(), \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;中国\u0026#34;\u0026amp;lt;/span\u0026gt;) ) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;中国\u0026#34;\u0026amp;lt;/span\u0026gt;.parent::getSex(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; parent::getSex(); } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; int $sex *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; $this */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; function \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setSex\u0026amp;lt;/span\u0026gt;($sex) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;( ! mb_strpos($sex, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;中国\u0026#34;\u0026amp;lt;/span\u0026gt;) ) $sex = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;中国\u0026#34;\u0026amp;lt;/span\u0026gt;.$sex; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; parent::setSex($sex); }` 碉堡了有木有。\n工具类等 看起来好多的样纸，我懒，不想讲可不可以？我就挑几个好不好？\n连拉ssh 照着配就行了，很简单 composer 这个也很明了吧，不多说了，平时咱们都是通过命令行来实现的 vagrant 这个phpstorm 10集成了vagrant，介于咱们自己已经搭建好了自己的vagrant环境，就不使用phpstorm所集成的啦 参考: 《使用Virtual Box和Vagrant搭建开发环境》\nDatabase 工具 phpStorm所集成的database工具十分强大，当然它还有单独的database工具叫做: DataGrip，当然需要独立购买，咱们phpStorm有集成，就使用它好啦哈哈….(咱们的PhpStorm可是花钱买的，请支持正版)\nDatabase工具一般在右侧栏，如果没有的话搜一下就好了，多简单的事儿呀…\n开始创建一个数据库连接吧…\n选择如上图的那个”+”号，然后选择Data Source数据来源，再选择数据库类型，一般咱们都是使用mysql吧，这次咱们试试新的，比如_SQLite_\n选择sqlite数据文件的地址，然后选择驱动，如果没有的话得先下载安装sqlite的驱动插件，这个很简单，在Driver下有提示，照做就是了…\n咱们先看一下mysql的配制吧…\nmysql的也非常简单，如果需要ssh/ssl连接的话，需要在SSH/SSL选项卡上配配地址入连接密码或sshkey…\n配制好了，打开选择的数据库:\n上图是连接的数据库的表及表字段信息… 来演示一下查询… 点击那”QL”样的dos窗口图标会弹出一个tab页，咱们可以在这里写sql语句。\n咱们查询User表下的所有数据，可以看到会有相当提示，这是相当的好使啊…查询完成后在下面的Database Console上会有显示表数据，可对它进行修改，等等操作增加数据也可以。\n快捷键command + alt + l不但对代码进行格式化，也sql语句也是非常有效的，如上图。\n在”Database Console”栏上点”Output”选项卡可以查看sql语句执行的情况、记录及所消耗的时间等等信息…\ncommand + 回车 执行sql语句或执行选中的sql语句 关于database工具的用法还有很多很多，我就不一一讲解了，大家可以自己慢慢去研究，真的非常好用\nCVS 和 Git command + k command + shift + k 关于FTP的配制，由于我不推荐使用，所以这里就不多说啦！\n都到这了，那咱们就说说在phpStorm上如何使用git工具吧\n算了，还是举一个例子吧，配辣么多太累了，一会我看下有没有已经配好的，如果有的话一会拉出来截个图看看就行吧，反正现在svn用得也比较少了，还是git用得爽，分布式嘛，离线嘛，多好…关于svn -\u0026gt; git可以参考我之前写的一篇文章\n《将代码库从Svn迁移Git》\n从git服务器上把代码抓到本地 选择CVS -\u0026gt; Checkout from Version Control -\u0026gt; Git\n在弹出的窗口输入自己的git仓库信息:\n注意 conle 的时间如果没有设置你的github账号的话可能会提示你输入账号信息，咱们输入就行了。如果需要修改的话则在设置里面进行修改，咱们可以使用command + ,打开”Preferences” 然后找到”Version Control”选项目的”GitHub”进行设置，还有”Git”路径。\n从mster创建分支 创建分支以通过命令行进行创建，咱们可以通过phpstrom的窗口进行创建，如下:\n这个东西在右下角，”Git:master” 然后弹出上面窗口选择”New Branch” 然后输入新分支的名称就好了，它会自动切换到新分支下。\n是不是超级简单呀…\n提交代码至远程分支 当咱们修改完代码后，咱们需要把代码提交到远程分支上，使用快捷键command + k提交相当修改后的代码，双击文件可以进行对比。在”Commit Message”写上修改的东西然后点提交，这时就把代码提交到本地分支上了。\n不使用快捷键的话，可以使用”CVS -\u0026gt; Commit Changes”提交，也会弹出下面窗口…\n￼\n提交到本地分支后，咱们需要把代码推到远程分支上，所以需要使用快捷键: command + shif + k提交远程分支…\n￼\n也可以使用”CVS -\u0026gt; Git -\u0026gt; Push”进行提交…效果是一样的\n注意svn木有 command + shift + k这一步\n合并分支 分并非常简单，只要选择需要合并的分支，然后merge就行了，如下图:\n这样就合并完成，当然，如果有冲突的话会提交有冲突，并让你解决，如果没有的话就直接合并成功了…然后就可以push了……\nCompare 是对合并的分支进行对比…\n使用svn… 灰常抱歉，我电脑上木有找到相关Svn项目的代码，就不多说了…\n安装插件 这里讲一个javascript 的安装，使用快捷键cmd + , 打开 Preferances\n安装 JavaScript 插件\nLanguages \u0026amp; Frameworks -\u0026gt; Javascript -\u0026gt; Libraries\n选择add需要的框架\n安装symfony2插件，搜索插件，然后点install\n然后重启phpStorm 就完事了….\n注意 灰色＋波浪线: 变量未使用 黄色波浪线: 变量未名单词拼写问题 红色波浪线: 变量未定义 还有好多我就不一一举例了，可能是因为我代码写得太好，出错的东西比较少吧… 右边栏出现红色，这点是必须要杜绝的，好的代码不应该出现红色的任何提示…一旦出现一定要马上解决，好的代码不应该出现一个黄、红色的提示。\nTODO 表示待办事件，当提交到vcs、svn或git的时候，会提示是还有未处理的事件，需要确认提交。\n写得有点多了，想写的东西比较多，要不分两篇写好了？算了，我比较懒，就这样吧，等我以后想写了再写吧，谢谢阅读\n转自：http://lattecake.com/post/20075\n","permalink":"https://blog.zdltech.com/posts/%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E7%9A%84%E4%BD%BF%E7%94%A8-phpstorm-%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/","summary":"\u003ch2 id=\"如何优雅的使用-phpstorm-开发工具\"\u003e如何优雅的使用 phpStorm 开发工具\u003c/h2\u003e\n\u003cp\u003e按照惯例依然是从百科上复制一条简介: PhpStorm 是 JetBrains 公司开发的一款商业的 PHP 集成开发工具。PhpStorm可随时帮助用户对其编码进行调整，运行单元测试或者提供可视化debug功能和智能HTML/CSS/JavaScript/PHP编辑、代码质量分析、版本控制集成（SVN、GIT）、调试和测试等功能。另外，它还是跨平台。在Windows和MacOS下都可以使用。PhpStorm-让开发更智能，而不是更困难。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://source.lattecake.com/images/2016/01/72a22e5a787016441080421fc35e2bd2.jpeg\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e听说phpStorm 10支持php7呃\u003c/em\u003e\u003c/p\u003e\n\u003ch3 id=\"优点\"\u003e优点\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e跨平台。\u003c/li\u003e\n\u003cli\u003e对PHP支持refactor功能。\u003c/li\u003e\n\u003cli\u003e自动生成phpdoc的注释，非常方便进行大型编程。\u003c/li\u003e\n\u003cli\u003e内置支持Zencode。\u003c/li\u003e\n\u003cli\u003e生成类的继承关系图，如果有一个类，多次继承之后，可以通过这个功能查看他所有的父级关系。\u003c/li\u003e\n\u003cli\u003e支持代码重构，方便修改代码。\u003c/li\u003e\n\u003cli\u003e拥有本地历史记录功能（local history功能）。\u003c/li\u003e\n\u003cli\u003e方便的部署，可以直接将代码直接upload到服务器。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cblockquote\u003e\n\u003cp\u003e总之它很牛逼就是了，什么都能干\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"快捷键\"\u003e快捷键\u003c/h3\u003e\n\u003cp\u003ephpStorm有非常非常多并且好用的的快捷键，我下面就举一些经常用的的快捷键演示，还有一些不常用的就不举例了，绝对能提高你开发的效力率…\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e(Windows与Mac类似，只要把\u003ccode\u003ecommand\u003c/code\u003e键换成\u003ccode\u003ectrl\u003c/code\u003e)\u003c/em\u003e\u003c/p\u003e\n\u003ch4 id=\"查询相关\"\u003e查询相关\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003ecommand + f\u003c/code\u003e 查找当前文件\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand + r\u003c/code\u003e 查找替换\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand + e\u003c/code\u003e 打开最近的文件\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand + shift + o\u003c/code\u003e 快速查询文件\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand + shift + f\u003c/code\u003e 关键字查找,更强大的查询器(机器不好的，最好还是先确定一下目录)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand + shift + r\u003c/code\u003e 高级替换\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand + alt + b\u003c/code\u003e 找到当剪类的所有子类\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ealt + shift + c\u003c/code\u003e 查找最近修改的文件\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ealt + f7\u003c/code\u003e 直接查询选中的字符\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ectrl + f7\u003c/code\u003e 文件中查询选中字符\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand + 鼠标点击\u003c/code\u003e 跳到类或方法或变量等声明处\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand + shift + tab\u003c/code\u003e 切换tab页文件\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand + shift + +,-\u003c/code\u003e 展开或缩起\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand + .\u003c/code\u003e 折叠或展开选中的代码\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://source.lattecake.com/images/2016/01/242e3436ac59061f7f14562543932688.jpeg?imageView2/2/w/800\"\u003e\u003c/p\u003e","title":"如何优雅的使用 phpStorm 开发工具"},{"content":"http://blog.csdn.net/sunyubo458/article/details/6680840\n作为程序员，了解diff\u0026amp;patch命 令是非常必要的。比如说我们发现某个项目有bug代码，而自己又没有svn的提交权限，那么此时最合适的解决方法就是用diff命令做一个补丁发给项目成 员。项目成员通过patch命令可以立刻知道你的意图。有人会说直接传一个新文件不是更简单？不要忘了，一个patch文件尺寸更小传输更快，而且可以明 显的看到都做了哪些修改。\n保证当前目录是demo名录：\n# mkdir demo\n# cd demo\n先模拟一个项目目录old：\n# mkdir -p old/a/b\n# vi old/a/b/foo.txt\nold_line_1\nold_line_2\n假设我们发现项目old有bug代码，下面我们先拷贝一个新目录new，并在此修改bug代码：\n# cp -r old new\n# vi new/a/b/foo.txt\nnew_line_1\nnew_line_2\n保证old和new两个目录都在当前目录下，下面就可以使用diff命令了，不要使用绝对路径，而应该使用相对路径，至于原因，看到文章结尾你就清楚了：\n# LC_ALL=C TZ=UTC0 diff -Naur old new \u0026gt; foo.patch\n如果不在意字符集，时差等问题，也可以省略LC_ALL=C TZ=UTC0环境变量：\n# diff -Naur old new \u0026gt; foo.patch\n其中-Naur参数属于固定打法，不管是对一个文件，还是对一个目录，在使用这个参数基本就可以了。\n大概浏览一下补丁文件：\n# cat foo.patch\ndiff -Naur old/a/b/foo.txt new/a/b/foo.txt\n— old/a/b/foo.txt 2009-12-07 20:40:07.000000000 +0800\n+++ new/a/b/foo.txt 2009-12-07 20:41:51.000000000 +0800\n@@ -1,2 +1,2 @@\n-old_line_1\n-old_line_2\n+new_line_1\n+new_line_2\n加减号后面的内容是有用的内容，其他的内容是方便你查阅的相关信息内容，补丁制作完成。\n此时的文件目录结构大概如下所示：\n#tree\ndemo\n下面看看如何使用patch来应用补丁，要注意的是当前目录是demo，试试下面命令：\n# patch -p0 \u0026lt; foo.patch\npatching file old/a/b/foo.txt\n这里唯一需要说明的是p0的含义，因为在foo.patch补丁文件里的路径信息是这样的：\n— old/a/b/foo.txt\np表示跳过几级目录，因为是在demo目录下使用的patch命令，old目录就在demo目录下，所以不必跳过任何目录，而应该使用old/a/b/foo.txt完整路径，所以此时使用的是p0。\n查看一下目标文件，你会发现内容已经修改成新的了：\n# cat old/a/b/foo.txt\nnew_line_1\nnew_line_2\n此时如果你再次使用patch命令，系统会问你是否想还原：\n# patch -p0 \u0026lt; foo.patch\npatching file old/a/b/foo.txt\nReversed (or previously applied) patch detected! Assume -R? [n] y\n查看一下目标文件，你会发现内容已经还原成旧的了：\n# cat old/a/b/foo.txt\nold_line_1\nold_line_2\n如果你想严格指定是应用补丁可以使用下面命令（就是增加N参数）：\n# patch -Np0 \u0026lt; foo.patch\n如果你想严格指定是还原补丁可以使用下面命令（就是增加R参数）：\n# patch -Rp0 \u0026lt; foo.patch\n注释：在本例中，每次应用补丁后，自己还原补丁，以备后用继续试验，我就不多说了。\n看到这里如果你对patch的p参数还不太清楚的话，接着往下看，我们改变一下当前路径：\n# cd old\n此时就应该是p1，而不是p0了，引用foo.patch文件的路径也要相对变一下，因为当前目录已经是old了：\n# patch -p1 \u0026lt; ../foo.patch\npatching file a/b/foo.txt\n因为此时我们是在old下使用patch命令，和a子目录平级，而补丁文件foo.patch里的路径声明是：\n— old/a/b/foo.txt\n也就是说第一个斜线左边的old/部分已经没用了，这就是p1的含义！\n继续往深度变换路径，依次测试使用p2,p3参数：\n# cd a\n# patch -p2 \u0026lt; ../../foo.patch\npatching file b/foo.txt\n# cd b\n# patch -p3 \u0026lt; ../../../foo.patch\npatching file foo.txt\n在本例中，p3已经是最深目录了，此时可以省略p参数：\n# patch \u0026lt; ../../../foo.patch\npatching file foo.txt\n也就是说，不使用p参数的时候，patch命令会忽略任何目录，直接使用文件。\n下面接着文章前面说的为什么使用diff命令时最好不要使用绝对路径，而应该使用相对路径？\n答：如果你在使用diff的时候使用的是绝对路径，那么补丁文件里的文件路径信息会类似下面的样子：\n— /a/b/c/d/e/f/g/bar.txt\n如此一来，当别人想应用你的补丁时，因为目录结构肯定有差异，所以就不得不费力判断到底使用p几。这样一来就很容易出错，相反，如果使用相对路径的话，大多数时候，p0或者p1就足够了，不易出错。\n跟着本文的步骤操作一下，肯定能掌握diff\u0026amp;patch用法，基本上使用diff时就是”diff -Naur FROM TO”（FROM, TO为变量）这样的固定打法，然后在使用patch的时候，先看看补丁文件的大致内容，结合当前目录以确定需要跳过的目录数，然后套用”patch -pN \u0026lt; patch.file”（N为变量）即可。\n－－－－－－－－－－－－－－－－－－－\n总结一下：\n单个文件\ndiff –uN from-file to-file \u0026gt;to-file.patch\npatch –p0 \u0026lt; to-file.patch\npatch –RE –p0 \u0026lt; to-file.patch\n多个文件\ndiff –uNr from-docu to-docu \u0026gt;to-docu.patch\npatch –p1 \u0026lt; to-docu.patch\npatch –R –p1\n－－－－－－－－－－－－－－－－－－－\n应用\n为内核打补丁。前面在创建交叉编译工具链时，其中有一步就是为内核打补丁。当时还不是特别了解，现在很清晰了。参考前面的文章《基于ARM+Linux嵌入式开发的开发工具链的建立》。\n1、首先是解压，因为发布的补丁文件都是使用gzip压缩的。\ngunzip ../setup-dir/ patch-2.4.21-rmk1.gz\n2、然后进入你的内核源代码目录cd linux-2.4.21\n3、打补丁\npatch –p1\u0026lt;../../setup-dir/patch-2.4.21-rmk1 打完补丁后，需要检查一下有没有拒绝执行的文件，即检查.rej文件的存在。使用命令：find . -name *.rej\n如果发现，会将其输出到标准输出终端，默认屏幕。当然，你也可以采用重定向，输出到指定文件，比如reject。\n$fine . -name *.rej \u0026gt;reject\n然后可以查看reject的内容了。\n","permalink":"https://blog.zdltech.com/posts/android-%E6%89%93patch%E7%9A%84%E6%96%B9%E6%B3%95/","summary":"\u003cp\u003e\u003ca href=\"http://blog.csdn.net/sunyubo458/article/details/6680840\"\u003ehttp://blog.csdn.net/sunyubo458/article/details/6680840\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e作为程序员，了解diff\u0026amp;patch命 令是非常必要的。比如说我们发现某个项目有bug代码，而自己又没有svn的提交权限，那么此时最合适的解决方法就是用diff命令做一个补丁发给项目成 员。项目成员通过patch命令可以立刻知道你的意图。有人会说直接传一个新文件不是更简单？不要忘了，一个patch文件尺寸更小传输更快，而且可以明 显的看到都做了哪些修改。\u003c/p\u003e\n\u003cp\u003e保证当前目录是demo名录：\u003c/p\u003e\n\u003cp\u003e# mkdir demo\u003cbr\u003e\n# cd demo\u003c/p\u003e\n\u003cp\u003e先模拟一个项目目录old：\u003c/p\u003e\n\u003cp\u003e# mkdir -p old/a/b\u003cbr\u003e\n# vi old/a/b/foo.txt\u003cbr\u003e\nold_line_1\u003cbr\u003e\nold_line_2\u003c/p\u003e\n\u003cp\u003e假设我们发现项目old有bug代码，下面我们先拷贝一个新目录new，并在此修改bug代码：\u003c/p\u003e\n\u003cp\u003e# cp -r old new\u003cbr\u003e\n# vi new/a/b/foo.txt\u003cbr\u003e\nnew_line_1\u003cbr\u003e\nnew_line_2\u003c/p\u003e\n\u003cp\u003e保证old和new两个目录都在当前目录下，下面就可以使用diff命令了，不要使用绝对路径，而应该使用相对路径，至于原因，看到文章结尾你就清楚了：\u003c/p\u003e\n\u003cp\u003e# LC_ALL=C TZ=UTC0 diff -Naur old new \u0026gt; foo.patch\u003c/p\u003e\n\u003cp\u003e如果不在意字符集，时差等问题，也可以省略LC_ALL=C TZ=UTC0环境变量：\u003c/p\u003e\n\u003cp\u003e# diff -Naur old new \u0026gt; foo.patch\u003c/p\u003e\n\u003cp\u003e其中-Naur参数属于固定打法，不管是对一个文件，还是对一个目录，在使用这个参数基本就可以了。\u003c/p\u003e\n\u003cp\u003e大概浏览一下补丁文件：\u003c/p\u003e\n\u003cp\u003e# cat foo.patch\u003cbr\u003e\ndiff -Naur old/a/b/foo.txt new/a/b/foo.txt\u003cbr\u003e\n— old/a/b/foo.txt 2009-12-07 20:40:07.000000000 +0800\u003cbr\u003e\n+++ new/a/b/foo.txt 2009-12-07 20:41:51.000000000 +0800\u003cbr\u003e\n@@ -1,2 +1,2 @@\u003cbr\u003e\n-old_line_1\u003cbr\u003e\n-old_line_2\u003cbr\u003e\n+new_line_1\u003cbr\u003e\n+new_line_2\u003c/p\u003e","title":"android 打Patch的方法 ."},{"content":" 转自：http://www.jianshu.com/p/2a7d16ab29e8 本教程采用阿里dexposed开源库实现。 https://github.com/alibaba/dexposed\n\u0026lt;/blockquote\u0026gt; ## 主APP实现： ### 主程序Application onCreate方法中初始化dexposed ``` \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;DexposedBridge\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-class\u0026quot;\u0026gt;.canDexposed\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;context\u0026amp;lt;/span\u0026gt;);\n### Patch apk下载及修复： - 为保证修复patch的及时性，使用push推送patch，客户端收到消息后立即完成patch的下载及修复； - 客户端版本管理模块在程序入口Activity中检测是否有需要修复的patch； - 下载完patch apk到程序私有目录，即/data/data/packageName/files目录，同时可在xml中保存patch apk本地存储路径、方便下载启动app时加载补丁patch。 ``` ` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;HotPatchManager\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; canDexposed = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; String SP_KEY_HOT_PATCH = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;hot_patch_path\u0026#34;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * init hotPatch library. * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; context */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;init\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// aop init.\u0026amp;lt;/span\u0026gt; canDexposed = DexposedBridge.canDexposed(context); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (canDexposed) { List\u0026amp;lt;String\u0026amp;gt; list = getHotPatchPaths(context); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (list != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; list.size() \u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (String path : list) { runPatchApk(context, path); } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (LogUtils.DEBUG) { LogUtils.d(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;==========your device not support dexposed aop.==========\u0026#34;\u0026amp;lt;/span\u0026gt;); } } } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * /data/data/package/files * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; context * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; apkPath */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;runPatchApk\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context, String apkPath)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (Build.VERSION.SDK_INT \u0026amp;gt;= \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;21\u0026amp;lt;/span\u0026gt; || !canDexposed) { LogUtils.d(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;This device doesn\u0026#39;t support dexposed.\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!pathIsValid(context, apkPath)) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { PatchResult result = PatchMain.load(context, apkPath, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (result.isSuccess()) { LogUtils.d(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;hotPath load apk success.\u0026#34;\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { LogUtils.e(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;hotPath load apk error.\u0026#34;\u0026amp;lt;/span\u0026gt;, result.getErrorInfo()); result.getThrowbale().printStackTrace(); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (Exception e) { e.printStackTrace(); } } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/** * download hotPatch and auto mege. * * \u0026amp;lt;span class=\u0026#34;hljs-doctag\u0026#34;\u0026gt;@param\u0026amp;lt;/span\u0026gt; context */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;downloadHotPatch\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; Context context, String downloadUrl)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (TextUtils.isEmpty(downloadUrl)) { LogUtils.d(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;downloadUrl is null.\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;; } DownloadInfo downloadInfo = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DownloadInfo(); downloadInfo.setDownloadUrl(downloadUrl); String fileName = downloadUrl.substring(downloadUrl.lastIndexOf(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;/\u0026#34;\u0026amp;lt;/span\u0026gt;) + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;); String fileSavePath = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File(context.getFilesDir(), fileName).getAbsolutePath(); downloadInfo.setFileSavePath(fileSavePath); downloadInfo.setDaoCallback( \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Task.Callback() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onSuccess\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(DownloadInfo downloadInfo)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ LogUtils.d(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;runPatchApk begin.\u0026#34;\u0026amp;lt;/span\u0026gt;, downloadInfo.getFileSavePath()); runPatchApk(context, downloadInfo.getFileSavePath()); appendHotPatchPath(context, downloadInfo.getFileSavePath()); LogUtils.d(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;runPatchApk end.\u0026#34;\u0026amp;lt;/span\u0026gt;, downloadInfo.getFileSavePath()); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onStart\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(DownloadInfo downloadInfo)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onFailure\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(DownloadInfo downloadInfo)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onLoading\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;long\u0026amp;lt;/span\u0026gt; total, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;long\u0026amp;lt;/span\u0026gt; current)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCancelled\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(DownloadInfo downloadInfo)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ } } ); DownloadManager dm = DownloadService.getDownloadManager(context, DownloadService.ACTION); dm.addDownloadTask(downloadInfo); } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;clearHotPatchFiles\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ List\u0026amp;lt;String\u0026amp;gt; list = getHotPatchPaths(context); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (list != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; list.size() \u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (String path : list) { FileUtils.delFile(path); } } } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;pathIsValid\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context, String apkPath)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (TextUtils.isEmpty(apkPath)) { LogUtils.d(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;apkPath is null.\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; } String parentDir = String.format(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;/data/data/%s/files\u0026#34;\u0026amp;lt;/span\u0026gt;, context.getPackageName()); File apkFile = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File(apkPath); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!parentDir.equals(apkFile.getParent())) { LogUtils.d(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;apkPath is error.\u0026#34;\u0026amp;lt;/span\u0026gt;, apkPath); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!apkFile.exists()){ LogUtils.d(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;apkPath is not exist.\u0026#34;\u0026amp;lt;/span\u0026gt;, apkPath); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getHotPatchPaths\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ List\u0026amp;lt;String\u0026amp;gt; list = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; SP sp = SP.getInstance(context); String paths = sp.getString(SP_KEY_HOT_PATCH, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!TextUtils.isEmpty(paths)) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (paths.indexOf(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;,\u0026#34;\u0026amp;lt;/span\u0026gt;) != -\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) { String[] pathArr = paths.split(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;,\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (pathArr != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; pathArr.length \u0026amp;gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { list = Arrays.asList(paths); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { list = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;String\u0026amp;gt;(); list.add(paths); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; list; } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;appendHotPatchPath\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context, String apkPath)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!pathIsValid(context, apkPath)) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;; } SP sp = SP.getInstance(context); String paths = sp.getString(SP_KEY_HOT_PATCH, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!TextUtils.isEmpty(paths)) { String allPath = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; StringBuilder(apkPath).append(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;,\u0026#34;\u0026amp;lt;/span\u0026gt;).append(apkPath).toString(); sp.commit(SP_KEY_HOT_PATCH, allPath); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { sp.commit(SP_KEY_HOT_PATCH, apkPath); } } \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;clearHotPatchPaths\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-params\u0026#34;\u0026gt;(Context context)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;{ SP sp = SP.getInstance(context); sp.commit(SP_KEY_HOT_PATCH, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;); } }` ## Patch Apk部分： \u0026lt;blockquote\u0026gt; dexpose支持方法粒度的patch，可以实现整个方法的替换或方法前、后执行修复代码。 以下实例为方法替换实例，其它只需实现相应的回调接口即可。\n\u0026lt;/blockquote\u0026gt; ### 方法替换实例： - 新建Android工程，引入patchloader.jar、dexposedbridge.jar； - 创建Patch修复类实现IPatch接口； ``` ` \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-class\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;HotPatch\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;IPatch\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n\u0026lt;span class=\u0026ldquo;hljs-annotation\u0026rdquo;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;handlePatch\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;(\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt; PatchParam arg0)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;throws\u0026lt;/span\u0026gt; Throwable \u0026lt;/span\u0026gt;{ Class\u0026lt;?\u0026gt; cls = \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;try\u0026lt;/span\u0026gt; { cls= arg0.context.getClassLoader() .loadClass(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;com.zaozuo.app.MainActivity\u0026rdquo;\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;catch\u0026lt;/span\u0026gt; (ClassNotFoundException e) { e.printStackTrace(); \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;return\u0026lt;/span\u0026gt;; } DexposedBridge.findAndHookMethod(cls, \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;bindData\u0026rdquo;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt; XC_MethodReplacement() { \u0026lt;span class=\u0026ldquo;hljs-annotation\u0026rdquo;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;protected\u0026lt;/span\u0026gt; Object \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;replaceHookedMethod\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;(MethodHookParam param)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;throws\u0026lt;/span\u0026gt; Throwable \u0026lt;/span\u0026gt;{ Activity mainActivity = (Activity) param.thisObject; Toast.makeText(mainActivity, \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;test show hotPatch.\u0026quot;\u0026lt;/span\u0026gt;,Toast.LENGTH_LONG).show(); \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;null\u0026lt;/span\u0026gt;; } }); }\n}`\n- 打包patch apk，上传到服务器并通知客户端下载。 ### Patch Apk安全性： - 打包apk必须使用主app签名文件签名； - 主app对加载的patch apk做签名和无篡改校验： \u0026lt;div class=\u0026#34;image-package imagebubble\u0026#34;\u0026gt; ![](http://upload-images.jianshu.io/upload_images/711578-70dc9b6a8049b976.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \u0026lt;div class=\u0026#34;image-caption\u0026#34;\u0026gt; 手机扫码快速访问 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;visitor_edit\u0026#34;\u0026gt; \u0026lt;!-- further readings --\u0026gt; \u0026lt;div id=\u0026#34;further-readings\u0026#34; data-user-slug=\u0026#34;\u0026#34; data-user-nickname=\u0026#34;\u0026#34;\u0026gt; \u0026lt;div id=\u0026#34;further-reading-line\u0026#34; class=\u0026#34;hide further-reading-line\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026#34;further-reading-new\u0026#34; class=\u0026#34;reading-edit\u0026#34;\u0026gt; [** 推荐拓展阅读](/sign_in) \u0026lt;div id=\u0026#34;further-reading-form\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;pull-right\u0026#34;\u0026gt; \u0026lt;!-- copyright --\u0026gt; \u0026lt;div class=\u0026#34;author-copyright pull-right\u0026#34; title=\u0026#34;\u0026#34; data-toggle=\u0026#34;tooltip\u0026#34; data-html=\u0026#34;true\u0026#34; data-original-title=\u0026#34;转载请联系作者获得授权，并标注“简书作者”。\u0026#34;\u0026gt; \u0026lt;a\u0026gt;** 著作权归作者所有\u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;!-- Reward / Support Author --\u0026gt; \u0026lt;div class=\u0026#34;support-author\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; \u0026lt;div\u0026gt; 文／ancode（简书作者） 原文链接：http://www.jianshu.com/p/2a7d16ab29e8 著作权归作者所有，转载请联系作者获得授权，并标注“简书作者”。 \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-hotpatch%E5%9C%A8%E7%BA%BF%E7%83%AD%E8%A1%A5%E4%B8%81%E6%96%B9%E6%A1%88/","summary":"\u003cdiv class=\"article\"\u003e\n  \u003cdiv class=\"preview\"\u003e\n    \u003cdiv class=\"show-content\"\u003e\n      \u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003e      转自：http://www.jianshu.com/p/2a7d16ab29e8\n    \n\n    \n    \n\n      本教程采用阿里dexposed开源库实现。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/alibaba/dexposed\"\u003ehttps://github.com/alibaba/dexposed\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;/blockquote\u0026gt;\n  \n  ## 主APP实现：\n  \n  ### 主程序Application onCreate方法中初始化dexposed\n  \n  ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003e    \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;DexposedBridge\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-class\u0026quot;\u0026gt;.canDexposed\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;context\u0026amp;lt;/span\u0026gt;);\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#6272a4\"\u003e### Patch apk下载及修复：\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e 为保证修复patch的及时性，使用push推送patch，客户端收到消息后立即完成patch的下载及修复；\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e 客户端版本管理模块在程序入口Activity中检测是否有需要修复的patch；\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e 下载完patch apk到程序私有目录，即\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edata\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edata\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003epackageName\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003efiles目录，同时可在xml中保存patch apk本地存储路径、方便下载启动app时加载补丁patch。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-class\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eHotPatchManager\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eboolean\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e canDexposed \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eprivate\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003efinal\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e String SP_KEY_HOT_PATCH \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hot_patch_path\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-comment\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e init hotPatch library\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-doctag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@param\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e context\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*/\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-function\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003einit\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-params\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(Context context)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-comment\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;//\u003c/span\u003e aop init\u003cspan style=\"color:#ff79c6\"\u003e.\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        canDexposed \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e DexposedBridge\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecanDexposed(context);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (canDexposed) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            List\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;String\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt; list \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e getHotPatchPaths(context);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (list \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enull\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e list\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esize() \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt; \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-number\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (String path : list) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    runPatchApk(context, path);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (LogUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eDEBUG) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                LogUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ed(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;==========your device not support dexposed aop.==========\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-comment\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edata\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003edata\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003epackage\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003efiles\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-doctag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@param\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e context\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-doctag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@param\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e apkPath\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*/\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-function\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003erunPatchApk\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-params\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(Context context, String apkPath)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (Build\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eVERSION\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eSDK_INT \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-number\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e21\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003ecanDexposed) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            LogUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ed(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;This device doesn\u0026#39;t support dexposed.\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003epathIsValid(context, apkPath)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003etry\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            PatchResult result \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e PatchMain\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eload(context, apkPath, \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enull\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (result\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eisSuccess()) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                LogUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ed(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hotPath load apk success.\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            } \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                LogUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ee(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hotPath load apk error.\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e, result\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetErrorInfo());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                result\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetThrowbale()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintStackTrace();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ecatch\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (Exception e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintStackTrace();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-comment\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e download hotPatch \u003cspan style=\"color:#ff79c6\"\u003eand\u003c/span\u003e auto mege\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-doctag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@param\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e context\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*/\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-function\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003edownloadHotPatch\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-params\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003efinal\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e Context context, String downloadUrl)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (TextUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eisEmpty(downloadUrl)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            LogUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ed(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;downloadUrl is null.\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        DownloadInfo downloadInfo \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e DownloadInfo();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        downloadInfo\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetDownloadUrl(downloadUrl);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String fileName \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e downloadUrl\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esubstring(downloadUrl\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elastIndexOf(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e) \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-number\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String fileSavePath \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e File(context\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetFilesDir(), fileName)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetAbsolutePath();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        downloadInfo\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetFileSavePath(fileSavePath);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        downloadInfo\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetDaoCallback(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e Task\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eCallback() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-annotation\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@Override\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-function\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eonSuccess\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-params\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(DownloadInfo downloadInfo)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        LogUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ed(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;runPatchApk begin.\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e, downloadInfo\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetFileSavePath());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        runPatchApk(context, downloadInfo\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetFileSavePath());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        appendHotPatchPath(context, downloadInfo\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetFileSavePath());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        LogUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ed(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;runPatchApk end.\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e, downloadInfo\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetFileSavePath());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-annotation\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@Override\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-function\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eonStart\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-params\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(DownloadInfo downloadInfo)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-annotation\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@Override\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-function\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eonFailure\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-params\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(DownloadInfo downloadInfo)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-annotation\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@Override\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-function\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eboolean\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eonLoading\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-params\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003elong\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e total, \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003elong\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e current)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-annotation\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@Override\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-function\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eonCancelled\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-params\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(DownloadInfo downloadInfo)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        );\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        DownloadManager dm \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e DownloadService\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetDownloadManager(context, DownloadService\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eACTION);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        dm\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddDownloadTask(downloadInfo);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-function\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eclearHotPatchFiles\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-params\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(Context context)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        List\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;String\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt; list \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e getHotPatchPaths(context);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (list \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enull\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e list\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esize() \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt; \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-number\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (String path : list) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                FileUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edelFile(path);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-function\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eboolean\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epathIsValid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-params\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(Context context, String apkPath)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (TextUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eisEmpty(apkPath)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            LogUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ed(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;apkPath is null.\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String parentDir \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e String\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eformat(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;/data/data/\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e%s\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e/files\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e, context\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetPackageName());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        File apkFile \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e File(apkPath);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003eparentDir\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eequals(apkFile\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetParent())) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            LogUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ed(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;apkPath is error.\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e, apkPath);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003eapkFile\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eexists()){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            LogUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ed(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;apkPath is not exist.\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e, apkPath);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-function\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e List\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;String\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt; \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003egetHotPatchPaths\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-params\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(Context context)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        List\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;String\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt; list \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enull\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        SP sp \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e SP\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetInstance(context);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String paths \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e sp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetString(SP_KEY_HOT_PATCH, \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enull\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003eTextUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eisEmpty(paths)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (paths\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eindexOf(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;,\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e) \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e-\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-number\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                String[] pathArr \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e paths\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;,\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (pathArr \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enull\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e pathArr\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elength \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt; \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-number\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    list \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Arrays\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003easList(paths);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            } \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                list \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e ArrayList\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;String\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                list\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eadd(paths);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e list;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-function\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eappendHotPatchPath\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-params\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(Context context, String apkPath)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003epathIsValid(context, apkPath)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        SP sp \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e SP\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetInstance(context);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String paths \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e sp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetString(SP_KEY_HOT_PATCH, \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enull\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003eTextUtils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eisEmpty(paths)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            String allPath \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e StringBuilder(apkPath)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eappend(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;,\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eappend(apkPath)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etoString();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            sp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecommit(SP_KEY_HOT_PATCH, allPath);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            sp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecommit(SP_KEY_HOT_PATCH, apkPath);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-function\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eclearHotPatchPaths\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-params\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(Context context)\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        SP sp \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e SP\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetInstance(context);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        sp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecommit(SP_KEY_HOT_PATCH, \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e  ## Patch Apk部分：\n  \n  \u0026lt;blockquote\u0026gt;\n    \n\n      dexpose支持方法粒度的patch，可以实现整个方法的替换或方法前、后执行修复代码。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e以下实例为方法替换实例，其它只需实现相应的回调接口即可。\u003c/p\u003e","title":"Android-HotPatch在线热补丁方案"},{"content":" 转载[http://blog.csdn.net/zhongkejingwang/article/details/38868463](http://blog.csdn.net/zhongkejingwang/article/details/38868463) 前面写过一篇关于下拉刷新控件的博客[下拉刷新控件终结者：PullToRefreshLayout](http://blog.csdn.net/zhongkejingwang/article/details/38340701)，后来看到好多人还有上拉加载更多的需求，于是就在前面下拉刷新控件的基础上进行了改进，加了上拉加载的功能。不仅如此，我已经把它改成了对所有View都通用！可以随心所欲使用这两个功能~~ 我做了一个大集合的demo，实现了ListView、GridView、ExpandableListView、ScrollView、WebView、ImageView、TextView的下拉刷新和上拉加载。后面会提供demo的下载地址。（csdn上的demo有小bug，最新代码已上传到github：[https://github.com/jingchenUSTC/PullToRefreshAndLoad](https://github.com/jingchenUSTC/PullToRefreshAndLoad)) 依照惯例，下面将会是一大波效果图： demo首页也是可下拉的ListView，在底下可以加入table： ![](http://img.blog.csdn.net/20140827132732390?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ListView： ![](http://img.blog.csdn.net/20140827133113883?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) GridView： ![](http://img.blog.csdn.net/20140827133157922?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ExpandableListView： ![](http://img.blog.csdn.net/20140827133245580?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ScrollView： ![](http://img.blog.csdn.net/20140827134146109?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) WebView： ![](http://img.blog.csdn.net/20140827134443946?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ImageView： ![](http://img.blog.csdn.net/20140827135142900?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) TextView： ![](http://img.blog.csdn.net/20140827135212228?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 很不错吧？最后的ImageView和TextView是最简单的，直接在下面的接口方法里返回true。 增加上拉加载很简单，和管理下拉头一样，再多管理一个上拉头，也不费事；至于把它改成通用的就需要统一一下View的行为了，为此，我定义了这样一个接口： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; Pullable - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 判断是否可以下拉，如果不需要下拉功能可以直接return false\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return true如果可以下拉否则返回false\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 判断是否可以上拉，如果不需要上拉功能可以直接return false\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return true如果可以上拉否则返回false\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp(); - } \u0026lt;/div\u0026gt; 从接口名就可以看出它是一个提供判断是否可拉的方法的接口。这个接口的两个方法，canPullDown()是判断何时可以下拉的方法，canPullUp()则是判断何时可以上拉，我在demo中的判断是滑到顶部的时候可以下拉，滑到底部的时候可以上拉。所有需要上拉和下拉的View都需要实现这个接口。后面会给出一些View的实现。先来看看改进后的自定义的布局PullToRefreshLayout，增加了一个上拉头，下拉头和上拉头之间的View是实现了Pullable接口的pullableView。相比前面的版本，这里有改动的需要注意的地方如下：1、增加了上拉头，相应的也增加了控制变量。 2、拉动时消除content_view事件防止误触发不再使用反射，直接设置 event.setAction(MotionEvent.ACTION_CANCEL)。 3、消除了拉动过程中的多点触碰导致的剧变。 4、不再设置content_view的onTouListener，让使用者可以更加自由的设置监听器。 这个PullToRefreshLayout只负责管理三个控件，如果一个View需要有上拉下拉功能则只需实现接口就行了。下面看PullToRefreshLayout的代码，注释写了好多： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Timer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.TimerTask; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;a href=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://lib.csdn.net/base/15\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;replace_word\u0026amp;#8221;\u0026lt;/span\u0026gt; title=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;undefined\u0026amp;#8221;\u0026lt;/span\u0026gt; target=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;_blank\u0026amp;#8221;\u0026lt;/span\u0026gt; style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;color:#df3434; font-weight:bold;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;android\u0026lt;/a\u0026gt;.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.LinearGradient; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint.Style; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.RectF; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Shader.TileMode; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.AnimationUtils; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.LinearInterpolator; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.RotateAnimation; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.RelativeLayout; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview.Pullable; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 自定义的布局，用来管理三个子控件，其中一个是下拉头，一个是包含内容的pullableView（可以是实现Pullable接口的的任何View），\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 还有一个上拉头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author 陈靖\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullToRefreshLayout \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; RelativeLayout - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;PullToRefreshLayout\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; INIT = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; RELEASE_TO_REFRESH = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; REFRESHING = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; RELEASE_TO_LOAD = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; LOADING = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 操作完毕\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; DONE = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 当前状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; state = INIT; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnRefreshListener mListener; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新成功\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; SUCCEED = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; FAIL = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 按下Y坐标，上一个事件点Y坐标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; downY, lastY; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉的距离。注意：pullDownY和pullUpY不可能同时不为0\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; pullDownY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; pullUpY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放刷新的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; refreshDist = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放加载的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; loadmoreDist = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTimer timer; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 回滚速度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; MOVE_SPEED = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 第一次执行布局\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isLayout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 在刷新过程中滑动操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 手指滑动距离与下拉头的滑动距离比，中间会随正切函数变化\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; radio = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉箭头的转180°动画\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; RotateAnimation rotateAnimation; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 均匀旋转动画\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; RotateAnimation refreshingAnimation; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View refreshView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉的箭头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View pullView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新的图标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View refreshingView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果图标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View refreshStateImageView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果：成功或失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView refreshStateTextView; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View loadmoreView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉的箭头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View pullUpView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载的图标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View loadingView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载结果图标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View loadStateImageView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载结果：成功或失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView loadStateTextView; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 实现了Pullable接口的View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View pullableView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 过滤多点触碰\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mEvents; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这两个变量用来控制pull的方向，如果不加控制，当情况满足可上拉又可下拉时没法下拉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 执行自动回滚的handler\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - Handler updateHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 回弹速度随下拉距离moveDeltaY增大而增大\u0026lt;/span\u0026gt; - MOVE_SPEED = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt; * Math.tan(Math.PI / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; - / getMeasuredHeight() * (pullDownY + Math.abs(pullUpY)))); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isTouch) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新，且没有往上推的话则悬停，显示\u0026amp;#8221;正在刷新\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == REFRESHING \u0026amp;\u0026amp; pullDownY \u0026lt;= refreshDist) - { - pullDownY = refreshDist; - timer.cancel(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == LOADING \u0026amp;\u0026amp; -pullUpY \u0026lt;= loadmoreDist) - { - pullUpY = -loadmoreDist; - timer.cancel(); - } - - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - pullDownY -= MOVE_SPEED; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - pullUpY += MOVE_SPEED; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 已完成回弹\u0026lt;/span\u0026gt; - pullDownY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - pullView.clearAnimation(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 隐藏下拉头时有可能还在刷新，只有当前状态不是正在刷新时才改变状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state != REFRESHING \u0026amp;\u0026amp; state != LOADING) - changeState(INIT); - timer.cancel(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 已完成回弹\u0026lt;/span\u0026gt; - pullUpY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - pullUpView.clearAnimation(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 隐藏下拉头时有可能还在刷新，只有当前状态不是正在刷新时才改变状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state != REFRESHING \u0026amp;\u0026amp; state != LOADING) - changeState(INIT); - timer.cancel(); - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新布局,会自动调用onLayout\u0026lt;/span\u0026gt; - requestLayout(); - } - - }; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnRefreshListener(OnRefreshListener listener) - { - mListener = listener; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullToRefreshLayout(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - initView(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullToRefreshLayout(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - initView(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullToRefreshLayout(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - initView(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView(Context context) - { - timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTimer(updateHandler); - rotateAnimation = (RotateAnimation) AnimationUtils.loadAnimation( - context, R.anim.reverse_anim); - refreshingAnimation = (RotateAnimation) AnimationUtils.loadAnimation( - context, R.anim.rotating); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 添加匀速转动动画\u0026lt;/span\u0026gt; - LinearInterpolator lir = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearInterpolator(); - rotateAnimation.setInterpolator(lir); - refreshingAnimation.setInterpolator(lir); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; hide() - { - timer.schedule(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 完成刷新操作，显示刷新结果。注意：刷新完成后一定要调用这个方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param refreshResult\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * PullToRefreshLayout.SUCCEED代表成功，PullToRefreshLayout.FAIL代表失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; refreshFinish(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; refreshResult) - { - refreshingView.clearAnimation(); - refreshingView.setVisibility(View.GONE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (refreshResult) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; SUCCEED: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新成功\u0026lt;/span\u0026gt; - refreshStateImageView.setVisibility(View.VISIBLE); - refreshStateTextView.setText(R.string.refresh_succeed); - refreshStateImageView - .setBackgroundResource(R.drawable.refresh_succeed); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; FAIL: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新失败\u0026lt;/span\u0026gt; - refreshStateImageView.setVisibility(View.VISIBLE); - refreshStateTextView.setText(R.string.refresh_fail); - refreshStateImageView - .setBackgroundResource(R.drawable.refresh_failed); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果停留1秒\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() - { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) - { - changeState(DONE); - hide(); - } - }.sendEmptyMessageDelayed(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 加载完毕，显示加载结果。注意：加载完成后一定要调用这个方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param refreshResult\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * PullToRefreshLayout.SUCCEED代表成功，PullToRefreshLayout.FAIL代表失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; loadmoreFinish(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; refreshResult) - { - loadingView.clearAnimation(); - loadingView.setVisibility(View.GONE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (refreshResult) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; SUCCEED: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载成功\u0026lt;/span\u0026gt; - loadStateImageView.setVisibility(View.VISIBLE); - loadStateTextView.setText(R.string.load_succeed); - loadStateImageView.setBackgroundResource(R.drawable.load_succeed); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; FAIL: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载失败\u0026lt;/span\u0026gt; - loadStateImageView.setVisibility(View.VISIBLE); - loadStateTextView.setText(R.string.load_fail); - loadStateImageView.setBackgroundResource(R.drawable.load_failed); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果停留1秒\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() - { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) - { - changeState(DONE); - hide(); - } - }.sendEmptyMessageDelayed(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; changeState(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; to) - { - state = to; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (state) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; INIT: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉布局初始状态\u0026lt;/span\u0026gt; - refreshStateImageView.setVisibility(View.GONE); - refreshStateTextView.setText(R.string.pull_to_refresh); - pullView.clearAnimation(); - pullView.setVisibility(View.VISIBLE); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉布局初始状态\u0026lt;/span\u0026gt; - loadStateImageView.setVisibility(View.GONE); - loadStateTextView.setText(R.string.pullup_to_load); - pullUpView.clearAnimation(); - pullUpView.setVisibility(View.VISIBLE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; RELEASE_TO_REFRESH: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放刷新状态\u0026lt;/span\u0026gt; - refreshStateTextView.setText(R.string.release_to_refresh); - pullView.startAnimation(rotateAnimation); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; REFRESHING: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新状态\u0026lt;/span\u0026gt; - pullView.clearAnimation(); - refreshingView.setVisibility(View.VISIBLE); - pullView.setVisibility(View.INVISIBLE); - refreshingView.startAnimation(refreshingAnimation); - refreshStateTextView.setText(R.string.refreshing); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; RELEASE_TO_LOAD: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放加载状态\u0026lt;/span\u0026gt; - loadStateTextView.setText(R.string.release_to_load); - pullUpView.startAnimation(rotateAnimation); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; LOADING: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载状态\u0026lt;/span\u0026gt; - pullUpView.clearAnimation(); - loadingView.setVisibility(View.VISIBLE); - pullUpView.setVisibility(View.INVISIBLE); - loadingView.startAnimation(refreshingAnimation); - loadStateTextView.setText(R.string.loading); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; DONE: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新或加载完毕，啥都不做\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 不限制上拉或下拉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; releasePull() - { - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * （非 Javadoc）由父控件决定是否分发事件，防止事件冲突\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (ev.getActionMasked()) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: - downY = ev.getY(); - lastY = downY; - timer.cancel(); - mEvents = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - releasePull(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_DOWN: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_UP: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 过滤多点触碰\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mEvents == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (((Pullable) pullableView).canPullDown() \u0026amp;\u0026amp; canPullDown - \u0026amp;\u0026amp; state != LOADING) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 可以下拉，正在加载时不能下拉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 对实际滑动距离做缩小，造成用力拉的感觉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - pullDownY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt; getMeasuredHeight()) - pullDownY = getMeasuredHeight(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == REFRESHING) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新的时候触摸移动\u0026lt;/span\u0026gt; - isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (((Pullable) pullableView).canPullUp() \u0026amp;\u0026amp; canPullUp - \u0026amp;\u0026amp; state != REFRESHING) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 可以上拉，正在刷新时不能上拉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - pullUpY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026lt; -getMeasuredHeight()) - pullUpY = -getMeasuredHeight(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == LOADING) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载的时候触摸移动\u0026lt;/span\u0026gt; - isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - releasePull(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - mEvents = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - lastY = ev.getY(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 根据下拉距离改变比例\u0026lt;/span\u0026gt; - radio = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; * Math.tan(Math.PI / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; / getMeasuredHeight() - * (pullDownY + Math.abs(pullUpY)))); - requestLayout(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026lt;= refreshDist - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026amp;\u0026amp; (state == RELEASE_TO_REFRESH || state == DONE)) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果下拉距离没达到刷新的距离且当前状态是释放刷新，改变状态为下拉刷新\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;changeState(INIT); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt;= refreshDist \u0026amp;\u0026amp; (state == INIT || state == DONE)) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果下拉距离达到刷新的距离且当前状态是初始状态刷新，改变状态为释放刷新\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;changeState(RELEASE_TO_REFRESH); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下面是判断上拉加载的，同上，注意pullUpY是负值\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (-pullUpY \u0026lt;= loadmoreDist - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026amp;\u0026amp; (state == RELEASE_TO_LOAD || state == DONE)) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;changeState(INIT); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (-pullUpY \u0026gt;= loadmoreDist \u0026amp;\u0026amp; (state == INIT || state == DONE)) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;changeState(RELEASE_TO_LOAD); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 因为刷新和加载操作不能同时进行，所以pullDownY和pullUpY不会同时不为0，因此这里用(pullDownY +\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Math.abs(pullUpY))就可以不对当前状态作区分了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((pullDownY + Math.abs(pullUpY)) \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止下拉过程中误触发长按事件和点击事件\u0026lt;/span\u0026gt; - ev.setAction(MotionEvent.ACTION_CANCEL); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt; refreshDist || -pullUpY \u0026gt; loadmoreDist) - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新时往下拉（正在加载时往上拉），释放后下拉头（上拉头）不隐藏\u0026lt;/span\u0026gt; - isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == RELEASE_TO_REFRESH) - { - changeState(REFRESHING); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - mListener.onRefresh(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == RELEASE_TO_LOAD) - { - changeState(LOADING); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - mListener.onLoadMore(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - } - hide(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 事件分发交给父类\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(ev); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始化下拉布局\u0026lt;/span\u0026gt; - pullView = refreshView.findViewById(R.id.pull_icon); - refreshStateTextView = (TextView) refreshView - .findViewById(R.id.state_tv); - refreshingView = refreshView.findViewById(R.id.refreshing_icon); - refreshStateImageView = refreshView.findViewById(R.id.state_iv); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始化上拉布局\u0026lt;/span\u0026gt; - pullUpView = loadmoreView.findViewById(R.id.pullup_icon); - loadStateTextView = (TextView) loadmoreView - .findViewById(R.id.loadstate_tv); - loadingView = loadmoreView.findViewById(R.id.loading_icon); - loadStateImageView = loadmoreView.findViewById(R.id.loadstate_iv); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isLayout) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这里是第一次进来的时候做一些初始化\u0026lt;/span\u0026gt; - refreshView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - pullableView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - loadmoreView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); - isLayout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - initView(); - refreshDist = ((ViewGroup) refreshView).getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - .getMeasuredHeight(); - loadmoreDist = ((ViewGroup) loadmoreView).getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - .getMeasuredHeight(); - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 改变子控件的布局，这里直接用(pullDownY + pullUpY)作为偏移量，这样就可以不对当前状态作区分\u0026lt;/span\u0026gt; - refreshView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, - refreshView.getMeasuredWidth(), (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY)); - pullableView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY), - pullableView.getMeasuredWidth(), (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY) - + pullableView.getMeasuredHeight()); - loadmoreView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, - (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY) + pullableView.getMeasuredHeight(), - loadmoreView.getMeasuredWidth(), - (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY) + pullableView.getMeasuredHeight() - + loadmoreView.getMeasuredHeight()); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTimer - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Timer timer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTask mTask; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTimer(Handler handler) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler; - timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Timer(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; schedule(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; period) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - mTask.cancel(); - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTask(handler); - timer.schedule(mTask, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, period); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; cancel() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - mTask.cancel(); - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTask \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; TimerTask - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTask(Handler handler) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() - { - handler.obtainMessage().sendToTarget(); - } - - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 刷新加载回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author chenjing\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnRefreshListener - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 刷新操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onRefresh(PullToRefreshLayout pullToRefreshLayout); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 加载操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLoadMore(PullToRefreshLayout pullToRefreshLayout); - } - - } \u0026lt;/div\u0026gt; 上面就是整个布局的代码，并不是很难。下面看各个View对Pullable接口的实现，ListView和GridView还有ExpandableListView的判断方法是一样的： PullableListView： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableListView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableListView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableListView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以下拉刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getFirstVisiblePosition() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getTop() \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到ListView的顶部了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以上拉加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到底部了\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt( - getLastVisiblePosition() - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } \u0026lt;/div\u0026gt; PullableExpandableListView： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ExpandableListView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableExpandableListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ExpandableListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; - Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableExpandableListView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableExpandableListView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableExpandableListView(Context context, AttributeSet attrs, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以下拉刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getFirstVisiblePosition() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getTop() \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到顶部了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以上拉加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到底部了\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt( - getLastVisiblePosition() - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - } \u0026lt;/div\u0026gt; PullableGridView： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableGridView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; GridView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableGridView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableGridView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableGridView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以下拉刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getFirstVisiblePosition() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getTop() \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到顶部了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以上拉加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到底部了\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt( - getLastVisiblePosition() - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - } \u0026lt;/div\u0026gt; PullableScrollView： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ScrollView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableScrollView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ScrollView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableScrollView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableScrollView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableScrollView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollY() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - } \u0026lt;/div\u0026gt; PullableWebView： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.webkit.WebView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableWebView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; WebView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableWebView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableWebView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableWebView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollY() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollY() \u0026gt;= getContentHeight() * getScale() - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } \u0026lt;/div\u0026gt; ImageView和TextView就不贴了，我直接在方法里返回了true。OK了，整个demo的代码有点多，就不贴了。 [源码下载](http://download.csdn.net/detail/zhongkejingwang/7828061) ","permalink":"https://blog.zdltech.com/posts/android%E4%B8%8B%E6%8B%89%E5%88%B7%E6%96%B0%E4%B8%8A%E6%8B%89%E5%8A%A0%E8%BD%BD%E6%8E%A7%E4%BB%B6%E5%AF%B9%E6%89%80%E6%9C%89view%E9%80%9A%E7%94%A8-3/","summary":"\u003cdiv id=\"article_details\" class=\"details\"\u003e\n  \u003cdiv id=\"article_content\" class=\"article_content\"\u003e\n\u003cpre\u003e\u003ccode\u003e  转载[http://blog.csdn.net/zhongkejingwang/article/details/38868463](http://blog.csdn.net/zhongkejingwang/article/details/38868463)\n\n\n\n\n\n  前面写过一篇关于下拉刷新控件的博客[下拉刷新控件终结者：PullToRefreshLayout](http://blog.csdn.net/zhongkejingwang/article/details/38340701)，后来看到好多人还有上拉加载更多的需求，于是就在前面下拉刷新控件的基础上进行了改进，加了上拉加载的功能。不仅如此，我已经把它改成了对所有View都通用！可以随心所欲使用这两个功能~~\n\n\n\n\n\n  我做了一个大集合的demo，实现了ListView、GridView、ExpandableListView、ScrollView、WebView、ImageView、TextView的下拉刷新和上拉加载。后面会提供demo的下载地址。（csdn上的demo有小bug，最新代码已上传到github：[https://github.com/jingchenUSTC/PullToRefreshAndLoad](https://github.com/jingchenUSTC/PullToRefreshAndLoad))\n\n\n\n\n\n  依照惯例，下面将会是一大波效果图：\n\n\n\n\n\n  demo首页也是可下拉的ListView，在底下可以加入table：\n\n\n\n\n\n  ![](http://img.blog.csdn.net/20140827132732390?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\n\n\n\n\n  ListView：\n\n\n\n\n\n  ![](http://img.blog.csdn.net/20140827133113883?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\n\n\n\n\n  GridView：\n\n\n\n\n\n  ![](http://img.blog.csdn.net/20140827133157922?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\n\n\n\n\n  ExpandableListView：\n\n\n\n\n\n  ![](http://img.blog.csdn.net/20140827133245580?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\n\n\n\n\n  ScrollView：\n\n\n\n\n\n  ![](http://img.blog.csdn.net/20140827134146109?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\n\n\n\n\n  WebView：\n\n\n\n\n\n  ![](http://img.blog.csdn.net/20140827134443946?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\n\n\n\n\n  ImageView：\n\n\n\n\n\n  ![](http://img.blog.csdn.net/20140827135142900?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\n\n\n\n\n  TextView：\n\n\n\n\n\n  ![](http://img.blog.csdn.net/20140827135212228?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\n\n\n\n\n  很不错吧？最后的ImageView和TextView是最简单的，直接在下面的接口方法里返回true。\n\n\n\n\n\n  增加上拉加载很简单，和管理下拉头一样，再多管理一个上拉头，也不费事；至于把它改成通用的就需要统一一下View的行为了，为此，我定义了这样一个接口：\n\n\n\n\u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n      \n\n        **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n      \n\n      \n      \u0026lt;div\u0026gt;\n        \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n        \u0026lt;/embed\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; Pullable\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 判断是否可以下拉，如果不需要下拉功能可以直接return false\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return true如果可以下拉否则返回false\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown();\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 判断是否可以上拉，如果不需要上拉功能可以直接return false\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return true如果可以上拉否则返回false\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp();\n    \n    - }\n    \n  \n\u0026lt;/div\u0026gt;\n\n\n\n  从接口名就可以看出它是一个提供判断是否可拉的方法的接口。这个接口的两个方法，canPullDown()是判断何时可以下拉的方法，canPullUp()则是判断何时可以上拉，我在demo中的判断是滑到顶部的时候可以下拉，滑到底部的时候可以上拉。所有需要上拉和下拉的View都需要实现这个接口。后面会给出一些View的实现。先来看看改进后的自定义的布局PullToRefreshLayout，增加了一个上拉头，下拉头和上拉头之间的View是实现了Pullable接口的pullableView。相比前面的版本，这里有改动的需要注意的地方如下：1、增加了上拉头，相应的也增加了控制变量。\n\n\n\n\n\n  2、拉动时消除content_view事件防止误触发不再使用反射，直接设置                       event.setAction(MotionEvent.ACTION_CANCEL)。\n\n\n\n\n\n  3、消除了拉动过程中的多点触碰导致的剧变。\n\n\n\n\n\n  4、不再设置content_view的onTouListener，让使用者可以更加自由的设置监听器。\n\n\n\n\n\n  这个PullToRefreshLayout只负责管理三个控件，如果一个View需要有上拉下拉功能则只需实现接口就行了。下面看PullToRefreshLayout的代码，注释写了好多：\n\n\n\n\u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n      \n\n        **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n      \n\n      \n      \u0026lt;div\u0026gt;\n        \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n        \u0026lt;/embed\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Timer;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.TimerTask;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;a href=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://lib.csdn.net/base/15\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;replace_word\u0026amp;#8221;\u0026lt;/span\u0026gt; title=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;undefined\u0026amp;#8221;\u0026lt;/span\u0026gt; target=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;_blank\u0026amp;#8221;\u0026lt;/span\u0026gt; style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;color:#df3434; font-weight:bold;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;android\u0026lt;/a\u0026gt;.content.Context;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.LinearGradient;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint.Style;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.RectF;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Shader.TileMode;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.AnimationUtils;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.LinearInterpolator;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.RotateAnimation;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.RelativeLayout;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview.Pullable;\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 自定义的布局，用来管理三个子控件，其中一个是下拉头，一个是包含内容的pullableView（可以是实现Pullable接口的的任何View），\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 还有一个上拉头\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author 陈靖\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullToRefreshLayout \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; RelativeLayout\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;PullToRefreshLayout\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始状态\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; INIT = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放刷新\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; RELEASE_TO_REFRESH = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; REFRESHING = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放加载\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; RELEASE_TO_LOAD = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; LOADING = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 操作完毕\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; DONE = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 当前状态\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; state = INIT;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新回调接口\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnRefreshListener mListener;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新成功\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; SUCCEED = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新失败\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; FAIL = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 按下Y坐标，上一个事件点Y坐标\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; downY, lastY;\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉的距离。注意：pullDownY和pullUpY不可能同时不为0\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; pullDownY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉的距离\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; pullUpY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放刷新的距离\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; refreshDist = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放加载的距离\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; loadmoreDist = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTimer timer;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 回滚速度\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; MOVE_SPEED = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 第一次执行布局\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isLayout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 在刷新过程中滑动操作\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 手指滑动距离与下拉头的滑动距离比，中间会随正切函数变化\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; radio = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;;\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉箭头的转180°动画\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; RotateAnimation rotateAnimation;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 均匀旋转动画\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; RotateAnimation refreshingAnimation;\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉头\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View refreshView;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉的箭头\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View pullView;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新的图标\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View refreshingView;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果图标\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View refreshStateImageView;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果：成功或失败\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView refreshStateTextView;\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉头\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View loadmoreView;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉的箭头\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View pullUpView;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载的图标\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View loadingView;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载结果图标\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View loadStateImageView;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载结果：成功或失败\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView loadStateTextView;\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 实现了Pullable接口的View\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View pullableView;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 过滤多点触碰\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mEvents;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这两个变量用来控制pull的方向，如果不加控制，当情况满足可上拉又可下拉时没法下拉\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 执行自动回滚的handler\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n    \n    - Handler updateHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler()\n    \n    - {\n    \n    - \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 回弹速度随下拉距离moveDeltaY增大而增大\u0026lt;/span\u0026gt;\n    \n    - MOVE_SPEED = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt; * Math.tan(Math.PI / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;\n    \n    - / getMeasuredHeight() * (pullDownY + Math.abs(pullUpY))));\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isTouch)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新，且没有往上推的话则悬停，显示\u0026amp;#8221;正在刷新\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == REFRESHING \u0026amp;\u0026amp; pullDownY \u0026lt;= refreshDist)\n    \n    - {\n    \n    - pullDownY = refreshDist;\n    \n    - timer.cancel();\n    \n    - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == LOADING \u0026amp;\u0026amp; -pullUpY \u0026lt;= loadmoreDist)\n    \n    - {\n    \n    - pullUpY = -loadmoreDist;\n    \n    - timer.cancel();\n    \n    - }\n    \n    - \n    - }\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - pullDownY -= MOVE_SPEED;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - pullUpY += MOVE_SPEED;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 已完成回弹\u0026lt;/span\u0026gt;\n    \n    - pullDownY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n    \n    - pullView.clearAnimation();\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 隐藏下拉头时有可能还在刷新，只有当前状态不是正在刷新时才改变状态\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state != REFRESHING \u0026amp;\u0026amp; state != LOADING)\n    \n    - changeState(INIT);\n    \n    - timer.cancel();\n    \n    - }\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 已完成回弹\u0026lt;/span\u0026gt;\n    \n    - pullUpY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n    \n    - pullUpView.clearAnimation();\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 隐藏下拉头时有可能还在刷新，只有当前状态不是正在刷新时才改变状态\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state != REFRESHING \u0026amp;\u0026amp; state != LOADING)\n    \n    - changeState(INIT);\n    \n    - timer.cancel();\n    \n    - }\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新布局,会自动调用onLayout\u0026lt;/span\u0026gt;\n    \n    - requestLayout();\n    \n    - }\n    \n    - \n    - };\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnRefreshListener(OnRefreshListener listener)\n    \n    - {\n    \n    - mListener = listener;\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullToRefreshLayout(Context context)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context);\n    \n    - initView(context);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullToRefreshLayout(Context context, AttributeSet attrs)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);\n    \n    - initView(context);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullToRefreshLayout(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle);\n    \n    - initView(context);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView(Context context)\n    \n    - {\n    \n    - timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTimer(updateHandler);\n    \n    - rotateAnimation = (RotateAnimation) AnimationUtils.loadAnimation(\n    \n    - context, R.anim.reverse_anim);\n    \n    - refreshingAnimation = (RotateAnimation) AnimationUtils.loadAnimation(\n    \n    - context, R.anim.rotating);\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 添加匀速转动动画\u0026lt;/span\u0026gt;\n    \n    - LinearInterpolator lir = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearInterpolator();\n    \n    - rotateAnimation.setInterpolator(lir);\n    \n    - refreshingAnimation.setInterpolator(lir);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; hide()\n    \n    - {\n    \n    - timer.schedule(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 完成刷新操作，显示刷新结果。注意：刷新完成后一定要调用这个方法\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param refreshResult\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     *            PullToRefreshLayout.SUCCEED代表成功，PullToRefreshLayout.FAIL代表失败\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; refreshFinish(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; refreshResult)\n    \n    - {\n    \n    - refreshingView.clearAnimation();\n    \n    - refreshingView.setVisibility(View.GONE);\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (refreshResult)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; SUCCEED:\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新成功\u0026lt;/span\u0026gt;\n    \n    - refreshStateImageView.setVisibility(View.VISIBLE);\n    \n    - refreshStateTextView.setText(R.string.refresh_succeed);\n    \n    - refreshStateImageView\n    \n    - .setBackgroundResource(R.drawable.refresh_succeed);\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; FAIL:\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;:\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新失败\u0026lt;/span\u0026gt;\n    \n    - refreshStateImageView.setVisibility(View.VISIBLE);\n    \n    - refreshStateTextView.setText(R.string.refresh_fail);\n    \n    - refreshStateImageView\n    \n    - .setBackgroundResource(R.drawable.refresh_failed);\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果停留1秒\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler()\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg)\n    \n    - {\n    \n    - changeState(DONE);\n    \n    - hide();\n    \n    - }\n    \n    - }.sendEmptyMessageDelayed(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 加载完毕，显示加载结果。注意：加载完成后一定要调用这个方法\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param refreshResult\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     *            PullToRefreshLayout.SUCCEED代表成功，PullToRefreshLayout.FAIL代表失败\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; loadmoreFinish(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; refreshResult)\n    \n    - {\n    \n    - loadingView.clearAnimation();\n    \n    - loadingView.setVisibility(View.GONE);\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (refreshResult)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; SUCCEED:\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载成功\u0026lt;/span\u0026gt;\n    \n    - loadStateImageView.setVisibility(View.VISIBLE);\n    \n    - loadStateTextView.setText(R.string.load_succeed);\n    \n    - loadStateImageView.setBackgroundResource(R.drawable.load_succeed);\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; FAIL:\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;:\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载失败\u0026lt;/span\u0026gt;\n    \n    - loadStateImageView.setVisibility(View.VISIBLE);\n    \n    - loadStateTextView.setText(R.string.load_fail);\n    \n    - loadStateImageView.setBackgroundResource(R.drawable.load_failed);\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果停留1秒\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler()\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg)\n    \n    - {\n    \n    - changeState(DONE);\n    \n    - hide();\n    \n    - }\n    \n    - }.sendEmptyMessageDelayed(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; changeState(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; to)\n    \n    - {\n    \n    - state = to;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (state)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; INIT:\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉布局初始状态\u0026lt;/span\u0026gt;\n    \n    - refreshStateImageView.setVisibility(View.GONE);\n    \n    - refreshStateTextView.setText(R.string.pull_to_refresh);\n    \n    - pullView.clearAnimation();\n    \n    - pullView.setVisibility(View.VISIBLE);\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉布局初始状态\u0026lt;/span\u0026gt;\n    \n    - loadStateImageView.setVisibility(View.GONE);\n    \n    - loadStateTextView.setText(R.string.pullup_to_load);\n    \n    - pullUpView.clearAnimation();\n    \n    - pullUpView.setVisibility(View.VISIBLE);\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; RELEASE_TO_REFRESH:\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放刷新状态\u0026lt;/span\u0026gt;\n    \n    - refreshStateTextView.setText(R.string.release_to_refresh);\n    \n    - pullView.startAnimation(rotateAnimation);\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; REFRESHING:\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新状态\u0026lt;/span\u0026gt;\n    \n    - pullView.clearAnimation();\n    \n    - refreshingView.setVisibility(View.VISIBLE);\n    \n    - pullView.setVisibility(View.INVISIBLE);\n    \n    - refreshingView.startAnimation(refreshingAnimation);\n    \n    - refreshStateTextView.setText(R.string.refreshing);\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; RELEASE_TO_LOAD:\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放加载状态\u0026lt;/span\u0026gt;\n    \n    - loadStateTextView.setText(R.string.release_to_load);\n    \n    - pullUpView.startAnimation(rotateAnimation);\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; LOADING:\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载状态\u0026lt;/span\u0026gt;\n    \n    - pullUpView.clearAnimation();\n    \n    - loadingView.setVisibility(View.VISIBLE);\n    \n    - pullUpView.setVisibility(View.INVISIBLE);\n    \n    - loadingView.startAnimation(refreshingAnimation);\n    \n    - loadStateTextView.setText(R.string.loading);\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; DONE:\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新或加载完毕，啥都不做\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 不限制上拉或下拉\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; releasePull()\n    \n    - {\n    \n    - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * （非 Javadoc）由父控件决定是否分发事件，防止事件冲突\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent)\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (ev.getActionMasked())\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN:\n    \n    - downY = ev.getY();\n    \n    - lastY = downY;\n    \n    - timer.cancel();\n    \n    - mEvents = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n    \n    - releasePull();\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_DOWN:\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_UP:\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 过滤多点触碰\u0026lt;/span\u0026gt;\n    \n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE:\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mEvents == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (((Pullable) pullableView).canPullDown() \u0026amp;\u0026amp; canPullDown\n    \n    - \u0026amp;\u0026amp; state != LOADING)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 可以下拉，正在加载时不能下拉\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 对实际滑动距离做缩小，造成用力拉的感觉\u0026lt;/span\u0026gt;\n    \n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - pullDownY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n    \n    - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt; getMeasuredHeight())\n    \n    - pullDownY = getMeasuredHeight();\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == REFRESHING)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新的时候触摸移动\u0026lt;/span\u0026gt;\n    \n    - isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (((Pullable) pullableView).canPullUp() \u0026amp;\u0026amp; canPullUp\n    \n    - \u0026amp;\u0026amp; state != REFRESHING)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 可以上拉，正在刷新时不能上拉\u0026lt;/span\u0026gt;\n    \n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - pullUpY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n    \n    - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026lt; -getMeasuredHeight())\n    \n    - pullUpY = -getMeasuredHeight();\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == LOADING)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载的时候触摸移动\u0026lt;/span\u0026gt;\n    \n    - isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n    \n    - releasePull();\n    \n    - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n    \n    - mEvents = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n    \n    - lastY = ev.getY();\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 根据下拉距离改变比例\u0026lt;/span\u0026gt;\n    \n    - radio = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; * Math.tan(Math.PI / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; / getMeasuredHeight()\n    \n    - * (pullDownY + Math.abs(pullUpY))));\n    \n    - requestLayout();\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026lt;= refreshDist\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;                    \u0026lt;/span\u0026gt;\u0026amp;\u0026amp; (state == RELEASE_TO_REFRESH || state == DONE)) {\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;                \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果下拉距离没达到刷新的距离且当前状态是释放刷新，改变状态为下拉刷新\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;                \u0026lt;/span\u0026gt;changeState(INIT);\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;            \u0026lt;/span\u0026gt;}\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;            \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt;= refreshDist \u0026amp;\u0026amp; (state == INIT || state == DONE)) {\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;                \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果下拉距离达到刷新的距离且当前状态是初始状态刷新，改变状态为释放刷新\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;                \u0026lt;/span\u0026gt;changeState(RELEASE_TO_REFRESH);\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;            \u0026lt;/span\u0026gt;}\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;            \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下面是判断上拉加载的，同上，注意pullUpY是负值\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;            \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (-pullUpY \u0026lt;= loadmoreDist\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;                    \u0026lt;/span\u0026gt;\u0026amp;\u0026amp; (state == RELEASE_TO_LOAD || state == DONE)) {\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;                \u0026lt;/span\u0026gt;changeState(INIT);\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;            \u0026lt;/span\u0026gt;}\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;            \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (-pullUpY \u0026gt;= loadmoreDist \u0026amp;\u0026amp; (state == INIT || state == DONE)) {\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;                \u0026lt;/span\u0026gt;changeState(RELEASE_TO_LOAD);\n    \n    - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;            \u0026lt;/span\u0026gt;}\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 因为刷新和加载操作不能同时进行，所以pullDownY和pullUpY不会同时不为0，因此这里用(pullDownY +\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Math.abs(pullUpY))就可以不对当前状态作区分了\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((pullDownY + Math.abs(pullUpY)) \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止下拉过程中误触发长按事件和点击事件\u0026lt;/span\u0026gt;\n    \n    - ev.setAction(MotionEvent.ACTION_CANCEL);\n    \n    - }\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP:\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt; refreshDist || -pullUpY \u0026gt; loadmoreDist)\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新时往下拉（正在加载时往上拉），释放后下拉头（上拉头）不隐藏\u0026lt;/span\u0026gt;\n    \n    - isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == RELEASE_TO_REFRESH)\n    \n    - {\n    \n    - changeState(REFRESHING);\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新操作\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)\n    \n    - mListener.onRefresh(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);\n    \n    - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == RELEASE_TO_LOAD)\n    \n    - {\n    \n    - changeState(LOADING);\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载操作\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)\n    \n    - mListener.onLoadMore(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);\n    \n    - }\n    \n    - hide();\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;:\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 事件分发交给父类\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(ev);\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView()\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始化下拉布局\u0026lt;/span\u0026gt;\n    \n    - pullView = refreshView.findViewById(R.id.pull_icon);\n    \n    - refreshStateTextView = (TextView) refreshView\n    \n    - .findViewById(R.id.state_tv);\n    \n    - refreshingView = refreshView.findViewById(R.id.refreshing_icon);\n    \n    - refreshStateImageView = refreshView.findViewById(R.id.state_iv);\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始化上拉布局\u0026lt;/span\u0026gt;\n    \n    - pullUpView = loadmoreView.findViewById(R.id.pullup_icon);\n    \n    - loadStateTextView = (TextView) loadmoreView\n    \n    - .findViewById(R.id.loadstate_tv);\n    \n    - loadingView = loadmoreView.findViewById(R.id.loading_icon);\n    \n    - loadStateImageView = loadmoreView.findViewById(R.id.loadstate_iv);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isLayout)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这里是第一次进来的时候做一些初始化\u0026lt;/span\u0026gt;\n    \n    - refreshView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n    \n    - pullableView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);\n    \n    - loadmoreView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;);\n    \n    - isLayout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - initView();\n    \n    - refreshDist = ((ViewGroup) refreshView).getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - .getMeasuredHeight();\n    \n    - loadmoreDist = ((ViewGroup) loadmoreView).getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - .getMeasuredHeight();\n    \n    - }\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 改变子控件的布局，这里直接用(pullDownY + pullUpY)作为偏移量，这样就可以不对当前状态作区分\u0026lt;/span\u0026gt;\n    \n    - refreshView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;,\n    \n    \n    - refreshView.getMeasuredWidth(), (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY));\n    \n    - pullableView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY),\n    \n    - pullableView.getMeasuredWidth(), (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY)\n    \n    - + pullableView.getMeasuredHeight());\n    \n    - loadmoreView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;,\n    \n    - (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY) + pullableView.getMeasuredHeight(),\n    \n    - loadmoreView.getMeasuredWidth(),\n    \n    - (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY) + pullableView.getMeasuredHeight()\n    \n    - + loadmoreView.getMeasuredHeight());\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTimer\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Timer timer;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTask mTask;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTimer(Handler handler)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler;\n    \n    - timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Timer();\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; schedule(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; period)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - mTask.cancel();\n    \n    - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTask(handler);\n    \n    - timer.schedule(mTask, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, period);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; cancel()\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - mTask.cancel();\n    \n    - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTask \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; TimerTask\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTask(Handler handler)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler;\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run()\n    \n    - {\n    \n    - handler.obtainMessage().sendToTarget();\n    \n    - }\n    \n    - \n    - }\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 刷新加载回调接口\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @author chenjing\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnRefreshListener\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         * 刷新操作\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         */\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onRefresh(PullToRefreshLayout pullToRefreshLayout);\n    \n    - \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         * 加载操作\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         */\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLoadMore(PullToRefreshLayout pullToRefreshLayout);\n    \n    - }\n    \n    - \n    - }\n    \n  \n\u0026lt;/div\u0026gt;\n\n\n\n  上面就是整个布局的代码，并不是很难。下面看各个View对Pullable接口的实现，ListView和GridView还有ExpandableListView的判断方法是一样的：\n\n\n\n\n\n  PullableListView：\n\n\n\n\u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n      \n\n        **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n      \n\n      \n      \u0026lt;div\u0026gt;\n        \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt;\n        \u0026lt;/embed\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable\n    \n    - {\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableListView(Context context)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableListView(Context context, AttributeSet attrs)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableListView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown()\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以下拉刷新\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getFirstVisiblePosition() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;\n    \n    - \u0026amp;\u0026amp; getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getTop() \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到ListView的顶部了\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp()\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以上拉加载\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到底部了\u0026lt;/span\u0026gt;\n    \n    \n    - \u0026amp;\u0026amp; getChildAt(\n    \n    - getLastVisiblePosition()\n    \n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - }\n    \n  \n\u0026lt;/div\u0026gt;\n\n\n\n  PullableExpandableListView：\n\n\n\n\u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n      \n\n        **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n      \n\n      \n      \u0026lt;div\u0026gt;\n        \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt;\n        \u0026lt;/embed\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ExpandableListView;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableExpandableListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ExpandableListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt;\n    \n    - Pullable\n    \n    - {\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableExpandableListView(Context context)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableExpandableListView(Context context, AttributeSet attrs)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableExpandableListView(Context context, AttributeSet attrs,\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown()\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以下拉刷新\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getFirstVisiblePosition() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;\n    \n    - \u0026amp;\u0026amp; getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getTop() \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到顶部了\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp()\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以上拉加载\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到底部了\u0026lt;/span\u0026gt;\n    \n    \n    - \u0026amp;\u0026amp; getChildAt(\n    \n    - getLastVisiblePosition()\n    \n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \n    - }\n    \n  \n\u0026lt;/div\u0026gt;\n\n\n\n  PullableGridView：\n\n\n\n\u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n      \n\n        **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n      \n\n      \n      \u0026lt;div\u0026gt;\n        \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt;\n        \u0026lt;/embed\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableGridView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; GridView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable\n    \n    - {\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableGridView(Context context)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableGridView(Context context, AttributeSet attrs)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableGridView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown()\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以下拉刷新\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getFirstVisiblePosition() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;\n    \n    - \u0026amp;\u0026amp; getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getTop() \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到顶部了\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp()\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以上拉加载\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到底部了\u0026lt;/span\u0026gt;\n    \n    \n    - \u0026amp;\u0026amp; getChildAt(\n    \n    - getLastVisiblePosition()\n    \n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \n    - }\n    \n  \n\u0026lt;/div\u0026gt;\n\n\n\n  PullableScrollView：\n\n\n\n\u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n      \n\n        **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n      \n\n      \n      \u0026lt;div\u0026gt;\n        \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt;\n        \u0026lt;/embed\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ScrollView;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableScrollView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ScrollView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable\n    \n    - {\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableScrollView(Context context)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableScrollView(Context context, AttributeSet attrs)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableScrollView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown()\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollY() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp()\n    \n    - {\n    \n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \n    - }\n    \n  \n\u0026lt;/div\u0026gt;\n\n\n\n  PullableWebView：\n\n\n\n\u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n      \n\n        **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n      \n\n      \n      \u0026lt;div\u0026gt;\n        \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt;\n        \u0026lt;/embed\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.webkit.WebView;\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableWebView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; WebView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable\n    \n    - {\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableWebView(Context context)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableWebView(Context context, AttributeSet attrs)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableWebView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle)\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle);\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown()\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollY() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - \n    - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp()\n    \n    - {\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollY() \u0026gt;= getContentHeight() * getScale()\n    \n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n    \n    - }\n    \n    - }\n    \n  \n\u0026lt;/div\u0026gt;\n\n\n\n  ImageView和TextView就不贴了，我直接在方法里返回了true。OK了，整个demo的代码有点多，就不贴了。\n\n\n\n\n\n  [源码下载](http://download.csdn.net/detail/zhongkejingwang/7828061)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"bdsharebuttonbox tracking-ad bdshare-button-style0-16\" data-mod=\"popu_172\" data-bd-bind=\"1460526142165\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e","title":"Android下拉刷新上拉加载控件，对所有View通用！"},{"content":" win R -\u0026gt; 输入 cmd 回车 ，打开命令行界面 在标题栏上右键，属性 勾选使用旧版控制台 ![](http://upload-images.jianshu.io/upload_images/1181400-c3c27b0c43937ea3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 转自：http://www.jianshu.com/p/0ed41f13fd6a ","permalink":"https://blog.zdltech.com/posts/win10-android-studio-terminal%E6%97%A0%E6%B3%95%E8%BE%93%E5%85%A5/","summary":"\u003col\u003e\n\u003cli\u003ewin R -\u0026gt; 输入 cmd 回车 ，打开命令行界面\u003c/li\u003e\n\u003cli\u003e在标题栏上右键，属性\u003c/li\u003e\n\u003cli\u003e勾选使用旧版控制台\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"image-package imagebubble\"\u003e\n  ![](http://upload-images.jianshu.io/upload_images/1181400-c3c27b0c43937ea3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n  \u003cdiv class=\"image-caption\"\u003e\n    转自：http://www.jianshu.com/p/0ed41f13fd6a\n  \u003c/div\u003e\n\u003c/div\u003e","title":"win10 android studio Terminal无法输入"},{"content":"Android 高清加载巨图方案 拒绝压缩图片 转载请标明出处：http://blog.csdn.net/lmj623565791/article/details/49300989；\n一、概述 距离上一篇博客有段时间没更新了，主要是最近有些私事导致的，那么就先来一篇简单一点的博客脉动回来。\n对于加载图片，大家都不陌生，一般为了尽可能避免OOM都会按照如下做法：\n对于图片显示：根据需要显示图片控件的大小对图片进行压缩显示。 如果图片数量非常多：则会使用LruCache等缓存机制，将所有图片占据的内容维持在一个范围内。 其实对于图片加载还有种情况，就是单个图片非常巨大，并且还不允许压缩。比如显示：世界地图、清明上河图、微博长图等。\n那么对于这种需求，该如何做呢？\n首先不压缩，按照原图尺寸加载，那么屏幕肯定是不够大的，并且考虑到内存的情况，不可能一次性整图加载到内存中，所以肯定是局部加载，那么就需要用到一个类：\nBitmapRegionDecoder 其次，既然屏幕显示不完，那么最起码要添加一个上下左右拖动的手势，让用户可以拖动查看。\n那么综上，本篇博文的目的就是去自定义一个显示巨图的View，支持用户去拖动查看，大概的效果图如下：\n好吧，这清明上河图太长了，想要观看全图，文末下载，图片在assets目录。当然如果你的图，高度也很大，肯定也是可以上下拖动的。\n二、初识BitmapRegionDecoder BitmapRegionDecoder主要用于显示图片的某一块矩形区域，如果你需要显示某个图片的指定区域，那么这个类非常合适。\n对于该类的用法，非常简单，既然是显示图片的某一块区域，那么至少只需要一个方法去设置图片；一个方法传入显示的区域即可；详见：\nBitmapRegionDecoder提供了一系列的newInstance方法来构造对象，支持传入文件路径，文件描述符，文件的inputstrem等。例如： ``` BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;); * 上述解决了传入我们需要处理的图片，那么接下来就是显示指定的区域。 ``` `bitmapRegionDecoder.decodeRegion(rect, options);` 参数一很明显是一个rect，参数二是BitmapFactory.Options，你可以控制图片的`inSampleSize`,`inPreferredConfig`等。 那么下面看一个超级简单的例子： ``` `\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.blogcodes.largeImage;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.BitmapFactory; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.BitmapRegionDecoder; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Rect; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v7.app.AppCompatActivity; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.blogcodes.R;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; java.io.IOException; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; java.io.InputStream;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-class\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;LargeImageViewActivity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;AppCompatActivity\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt; ImageView mImageView;\n\u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;(Bundle savedInstanceState) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(R.layout.activity_large_image_view); mImageView = (ImageView) findViewById(R.id.id_imageview); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;try\u0026amp;lt;/span\u0026gt; { InputStream inputStream = getAssets().open(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;tangyan.jpg\u0026quot;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//获得图片的宽、高\u0026amp;lt;/span\u0026gt; BitmapFactory.Options tmpOptions = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; BitmapFactory.Options(); tmpOptions.inJustDecodeBounds = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;true\u0026amp;lt;/span\u0026gt;; BitmapFactory.decodeStream(inputStream, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;, tmpOptions); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; width = tmpOptions.outWidth; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; height = tmpOptions.outHeight; \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//设置显示图片的中心区域\u0026amp;lt;/span\u0026gt; BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;); BitmapFactory.Options options = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.RGB_565; Bitmap bitmap = bitmapRegionDecoder.decodeRegion(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; Rect(width / \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;2\u0026amp;lt;/span\u0026gt; - \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;100\u0026amp;lt;/span\u0026gt;, height / \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;2\u0026amp;lt;/span\u0026gt; - \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;100\u0026amp;lt;/span\u0026gt;, width / \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;2\u0026amp;lt;/span\u0026gt; + \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;100\u0026amp;lt;/span\u0026gt;, height / \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;2\u0026amp;lt;/span\u0026gt; + \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;100\u0026amp;lt;/span\u0026gt;), options); mImageView.setImageBitmap(bitmap); } \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (IOException e) { e.printStackTrace(); } } }`\n上述代码，就是使用BitmapRegionDecoder去加载assets中的图片，调用`bitmapRegionDecoder.decodeRegion`解析图片的中间矩形区域，返回bitmap，最终显示在ImageView上。 效果图： ![](http://img.blog.csdn.net/20151021103048017) 上面的小图显示的即为下面的大图的中间区域。 ok，那么目前我们已经了解了`BitmapRegionDecoder`的基本用户，那么往外扩散，我们需要自定义一个控件去显示巨图就很简单了，首先Rect的范围就是我们View的大小，然后根据用户的移动手势，不断去更新我们的Rect的参数即可。 ## \u0026lt;a name=\u0026#34;t3\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;三、自定义显示大图控件 {#三自定义显示大图控件} 根据上面的分析呢，我们这个自定义控件思路就非常清晰了： * 提供一个设置图片的入口 * 重写onTouchEvent，在里面根据用户移动的手势，去更新显示区域的参数 * 每次更新区域参数后，调用invalidate，onDraw里面去regionDecoder.decodeRegion拿到bitmap，去draw 理清了，发现so easy，下面上代码： ``` `\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;package\u0026amp;lt;/span\u0026gt; com.zhy.blogcodes.largeImage.view; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.content.Context; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Bitmap; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.BitmapFactory; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.BitmapRegionDecoder; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Canvas; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Rect; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.util.AttributeSet; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.MotionEvent; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.View; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.IOException; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.InputStream; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * Created by zhy on 15/5/16. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LargeImageView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;View\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; BitmapRegionDecoder mDecoder; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * 图片的宽度和高度 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mImageWidth, mImageHeight; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * 绘制的区域 */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;volatile\u0026amp;lt;/span\u0026gt; Rect mRect = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Rect(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; MoveGestureDetector mDetector; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; BitmapFactory.Options options = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; BitmapFactory.Options(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; { options.inPreferredConfig = Bitmap.Config.RGB_565; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setInputStream\u0026amp;lt;/span\u0026gt;(InputStream is) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { mDecoder = BitmapRegionDecoder.newInstance(is, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;); BitmapFactory.Options tmpOptions = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; BitmapFactory.Options(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Grab the bounds for the scene dimensions\u0026amp;lt;/span\u0026gt; tmpOptions.inJustDecodeBounds = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; BitmapFactory.decodeStream(is, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;, tmpOptions); mImageWidth = tmpOptions.outWidth; mImageHeight = tmpOptions.outHeight; requestLayout(); invalidate(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (IOException e) { e.printStackTrace(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;finally\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (is != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) is.close(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (Exception e) { } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;init\u0026amp;lt;/span\u0026gt;() { mDetector = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; MoveGestureDetector(getContext(), \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; MoveGestureDetector.SimpleMoveGestureDetector() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onMove\u0026amp;lt;/span\u0026gt;(MoveGestureDetector detector) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; moveX = (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;) detector.getMoveX(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; moveY = (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;) detector.getMoveY(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mImageWidth \u0026amp;gt; getWidth()) { mRect.offset(-moveX, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); checkWidth(); invalidate(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mImageHeight \u0026amp;gt; getHeight()) { mRect.offset(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, -moveY); checkHeight(); invalidate(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } }); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;checkWidth\u0026amp;lt;/span\u0026gt;() { Rect rect = mRect; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; imageWidth = mImageWidth; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; imageHeight = mImageHeight; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (rect.right \u0026amp;gt; imageWidth) { rect.right = imageWidth; rect.left = imageWidth - getWidth(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (rect.left \u0026amp;lt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { rect.left = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; rect.right = getWidth(); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;checkHeight\u0026amp;lt;/span\u0026gt;() { Rect rect = mRect; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; imageWidth = mImageWidth; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; imageHeight = mImageHeight; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (rect.bottom \u0026amp;gt; imageHeight) { rect.bottom = imageHeight; rect.top = imageHeight - getHeight(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (rect.top \u0026amp;lt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { rect.top = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; rect.bottom = getHeight(); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LargeImageView\u0026amp;lt;/span\u0026gt;(Context context, AttributeSet attrs) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;(context, attrs); init(); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onTouchEvent\u0026amp;lt;/span\u0026gt;(MotionEvent event) { mDetector.onToucEvent(event); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDraw\u0026amp;lt;/span\u0026gt;(Canvas canvas) { Bitmap bm = mDecoder.decodeRegion(mRect, options); canvas.drawBitmap(bm, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onMeasure\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; widthMeasureSpec, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; heightMeasureSpec) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onMeasure(widthMeasureSpec, heightMeasureSpec); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; width = getMeasuredWidth(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; height = getMeasuredHeight(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; imageWidth = mImageWidth; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; imageHeight = mImageHeight; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//默认直接显示图片的中心区域，可以自己去调节\u0026amp;lt;/span\u0026gt; mRect.left = imageWidth / \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt; - width / \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;; mRect.top = imageHeight / \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt; - height / \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;; mRect.right = mRect.left + width; mRect.bottom = mRect.top + height; } }` 根据上述源码: 1. setInputStream里面去获得图片的真实的宽度和高度，以及初始化我们的mDecoder 2. onMeasure里面为我们的显示区域的rect赋值，大小为view的尺寸 3. onTouchEvent里面我们监听move的手势，在监听的回调里面去改变rect的参数，以及做边界检查，最后invalidate 4. 在onDraw里面就是根据rect拿到bitmap，然后draw了 ok，上面并不复杂，不过大家有没有注意到，这个监听用户move手势的代码写的有点奇怪，恩，这里模仿了系统的`ScaleGestureDetector`，编写了`MoveGestureDetector`，代码如下： * MoveGestureDetector ``` ` \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.blogcodes.largeImage.view;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.PointF; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-class\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;MoveGestureDetector\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;BaseGestureDetector\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt; PointF mCurrentPointer; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt; PointF mPrePointer; \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//仅仅为了减少创建内存\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt; PointF mDeltaPointer = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; PointF(); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//用于记录最终结果，并返回\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt; PointF mExtenalPointer = \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; PointF(); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt; OnMoveGestureListener mListenter; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;MoveGestureDetector\u0026amp;lt;/span\u0026gt;(Context context, OnMoveGestureListener listener) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;(context); mListenter = listener; } \u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;handleInProgressEvent\u0026amp;lt;/span\u0026gt;(MotionEvent event) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; actionCode = event.getAction() \u0026amp; MotionEvent.ACTION_MASK; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (actionCode) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026amp;lt;/span\u0026gt; MotionEvent.ACTION_CANCEL: \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026amp;lt;/span\u0026gt; MotionEvent.ACTION_UP: mListenter.onMoveEnd(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;this\u0026amp;lt;/span\u0026gt;); resetState(); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026amp;lt;/span\u0026gt; MotionEvent.ACTION_MOVE: updateStateByEvent(event); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; update = mListenter.onMove(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;this\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt; (update) { mPreMotionEvent.recycle(); mPreMotionEvent = MotionEvent.obtain(event); } \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } } \u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;handleStartProgressEvent\u0026amp;lt;/span\u0026gt;(MotionEvent event) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; actionCode = event.getAction() \u0026amp; MotionEvent.ACTION_MASK; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (actionCode) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026amp;lt;/span\u0026gt; MotionEvent.ACTION_DOWN: resetState();\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//防止没有接收到CANCEL or UP ,保险起见\u0026amp;lt;/span\u0026gt; mPreMotionEvent = MotionEvent.obtain(event); updateStateByEvent(event); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026amp;lt;/span\u0026gt; MotionEvent.ACTION_MOVE: mGestureInProgress = mListenter.onMoveBegin(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;this\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } } \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;updateStateByEvent\u0026amp;lt;/span\u0026gt;(MotionEvent event) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;final\u0026amp;lt;/span\u0026gt; MotionEvent prev = mPreMotionEvent; mPrePointer = caculateFocalPointer(prev); mCurrentPointer = caculateFocalPointer(event); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//Log.e(\u0026quot;TAG\u0026quot;, mPrePointer.toString() + \u0026quot; , \u0026quot; + mCurrentPointer);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; mSkipThisMoveEvent = prev.getPointerCount() != event.getPointerCount(); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//Log.e(\u0026quot;TAG\u0026quot;, \u0026quot;mSkipThisMoveEvent = \u0026quot; + mSkipThisMoveEvent);\u0026amp;lt;/span\u0026gt; mExtenalPointer.x = mSkipThisMoveEvent ? \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt; : mCurrentPointer.x - mPrePointer.x; mExtenalPointer.y = mSkipThisMoveEvent ? \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt; : mCurrentPointer.y - mPrePointer.y; } \u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/** * 根据event计算多指中心点 * *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @param\u0026amp;lt;/span\u0026gt; event *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt; PointF \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;caculateFocalPointer\u0026amp;lt;/span\u0026gt;(MotionEvent event) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; count = event.getPointerCount(); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026amp;lt;/span\u0026gt; x = \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;, y = \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; count; i++) { x += event.getX(i); y += event.getY(i); } x /= count; y /= count; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; PointF(x, y); } \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;getMoveX\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; mExtenalPointer.x; } \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;getMoveY\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; mExtenalPointer.y; } \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-class\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;interface\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;OnMoveGestureListener\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onMoveBegin\u0026amp;lt;/span\u0026gt;(MoveGestureDetector detector); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onMove\u0026amp;lt;/span\u0026gt;(MoveGestureDetector detector); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onMoveEnd\u0026amp;lt;/span\u0026gt;(MoveGestureDetector detector); } \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-class\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;SimpleMoveGestureDetector\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;implements\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;OnMoveGestureListener\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onMoveBegin\u0026amp;lt;/span\u0026gt;(MoveGestureDetector detector) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onMove\u0026amp;lt;/span\u0026gt;(MoveGestureDetector detector) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onMoveEnd\u0026amp;lt;/span\u0026gt;(MoveGestureDetector detector) { } } }`\n* BaseGestureDetector ``` `package com.zhy.blogcodes.largeImage.view; import android.content.Context; import android.view.MotionEvent; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;abstract\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; BaseGestureDetector { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; boolean mGestureInProgress; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; MotionEvent mPreMotionEvent; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; MotionEvent mCurrentMotionEvent; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; Context mContext; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;BaseGestureDetector\u0026amp;lt;/span\u0026gt;(Context context) { mContext = context; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; boolean \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onToucEvent\u0026amp;lt;/span\u0026gt;(MotionEvent \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;event\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!mGestureInProgress) { handleStartProgressEvent(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;event\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { handleInProgressEvent(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;event\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;abstract\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;handleInProgressEvent\u0026amp;lt;/span\u0026gt;(MotionEvent \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;event\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;abstract\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;handleStartProgressEvent\u0026amp;lt;/span\u0026gt;(MotionEvent \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;event\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;abstract\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;updateStateByEvent\u0026amp;lt;/span\u0026gt;(MotionEvent \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;event\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resetState\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mPreMotionEvent != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { mPreMotionEvent.recycle(); mPreMotionEvent = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mCurrentMotionEvent != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { mCurrentMotionEvent.recycle(); mCurrentMotionEvent = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; } mGestureInProgress = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; } }` 你可能会说，一个move手势搞这么多代码，太麻烦了。的确是的，move手势的检测非常简单，那么之所以这么写呢，主要是为了可以复用，比如现在有一堆的`XXXGestureDetector`，当我们需要监听什么手势，就直接拿个detector来检测多方便。我相信大家肯定也郁闷过Google，为什么只有`ScaleGestureDetector`而没有`RotateGestureDetector`呢。 根据上述，大家应该理解了为什么要这么做，当时不强制，每个人都有个性。 \u0026gt; 不过值得一提的是：上面这个手势检测的写法，不是我想的，而是一个开源的项目\u0026lt;https://github.com/rharter/android-gesture-detectors\u0026gt;，里面包含很多的手势检测。对应的博文是：\u0026lt;http://code.almeros.com/android-multitouch-gesture-detectors#.VibzzhArJXg\u0026gt;那面上面两个类就是我偷学了的~ 哈 ## \u0026lt;a name=\u0026quot;t4\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;四、测试 {#四测试} 测试其实没撒好说的了，就是把我们的LargeImageView放入布局文件，然后Activity里面去设置inputstream了。 ``` `\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;http://schemas.android.com/tools\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;com.zhy.blogcodes.largeImage.view.LargeImageView \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026rdquo;@+id/id_largetImageview\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;`\n然后在Activity里面去设置图片： ``` `\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;package\u0026amp;lt;/span\u0026gt; com.zhy.blogcodes.largeImage; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.os.Bundle; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.app.AppCompatActivity; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; com.zhy.blogcodes.R; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; com.zhy.blogcodes.largeImage.view.LargeImageView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.IOException; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.InputStream; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LargeImageViewActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AppCompatActivity\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; LargeImageView mLargeImageView; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;(Bundle savedInstanceState) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(R.layout.activity_large_image_view); mLargeImageView = (LargeImageView) findViewById(R.id.id_largetImageview); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { InputStream inputStream = getAssets().open(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;world.jpg\u0026#34;\u0026amp;lt;/span\u0026gt;); mLargeImageView.setInputStream(inputStream); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (IOException e) { e.printStackTrace(); } } }` 效果图： ok，那么到此，显示巨图的方案以及详细的代码就描述完成了，总体还是非常简单的。 但是，在实际的项目中，可能会有更多的需求，比如增加放大、缩小；增加快滑手势等等，那么大家可以去参考这个库：\u0026lt;https://github.com/johnnylambada/WorldMap\u0026gt;，该库基本实现了绝大多数的需求，大家根据本文这个思路再去看这个库，也会简单很多，定制起来也容易。我这个地图的图就是该库里面提供的。 哈，掌握了这个，以后面试过程中也可以悄悄的装一把了，当你优雅的答完android加载图片的方案以后，然后接一句，其实还有一种情况，就是高清显示巨图，那么我们应该…相信面试官对你的印象会好很多~ have a nice day ~ [源码点击下载][1] * * * ## \u0026lt;a name=\u0026quot;t5\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;参考链接 {#参考链接} * \u0026lt;http://code.almeros.com/android-multitouch-gesture-detectors#.VibzzhArJXg\u0026gt; * \u0026lt;https://github.com/rharter/android-gesture-detectors\u0026gt; * \u0026lt;https://github.com/johnnylambada/WorldMap\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-%E9%AB%98%E6%B8%85%E5%8A%A0%E8%BD%BD%E5%B7%A8%E5%9B%BE%E6%96%B9%E6%A1%88-%E6%8B%92%E7%BB%9D%E5%8E%8B%E7%BC%A9%E5%9B%BE%E7%89%87/","summary":"\u003ch1 id=\"android-高清加载巨图方案-拒绝压缩图片\"\u003eAndroid 高清加载巨图方案 拒绝压缩图片\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e转载请标明出处：\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/49300989\"\u003ehttp://blog.csdn.net/lmj623565791/article/details/49300989\u003c/a\u003e；\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"一概述\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e一、概述\u003c/h2\u003e\n\u003cp\u003e距离上一篇博客有段时间没更新了，主要是最近有些私事导致的，那么就先来一篇简单一点的博客脉动回来。\u003c/p\u003e\n\u003cp\u003e对于加载图片，大家都不陌生，一般为了尽可能避免OOM都会按照如下做法：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e对于图片显示：根据需要显示图片控件的大小对图片进行压缩显示。\u003c/li\u003e\n\u003cli\u003e如果图片数量非常多：则会使用LruCache等缓存机制，将所有图片占据的内容维持在一个范围内。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e其实对于图片加载还有种情况，就是单个图片非常巨大，并且还不允许压缩。比如显示：世界地图、清明上河图、微博长图等。\u003c/p\u003e\n\u003cp\u003e那么对于这种需求，该如何做呢？\u003c/p\u003e\n\u003cp\u003e首先不压缩，按照原图尺寸加载，那么屏幕肯定是不够大的，并且考虑到内存的情况，不可能一次性整图加载到内存中，所以肯定是局部加载，那么就需要用到一个类：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eBitmapRegionDecoder\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e其次，既然屏幕显示不完，那么最起码要添加一个上下左右拖动的手势，让用户可以拖动查看。\u003c/p\u003e\n\u003cp\u003e那么综上，本篇博文的目的就是去自定义一个显示巨图的View，支持用户去拖动查看，大概的效果图如下：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20151021103013582\"\u003e\u003c/p\u003e\n\u003cp\u003e好吧，这清明上河图太长了，想要观看全图，文末下载，图片在assets目录。当然如果你的图，高度也很大，肯定也是可以上下拖动的。\u003c/p\u003e\n\u003ch2 id=\"二初识bitmapregiondecoder\"\u003e\u003ca name=\"t2\"\u003e\u003c/a\u003e二、初识BitmapRegionDecoder\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eBitmapRegionDecoder\u003c/code\u003e主要用于显示图片的某一块矩形区域，如果你需要显示某个图片的指定区域，那么这个类非常合适。\u003c/p\u003e\n\u003cp\u003e对于该类的用法，非常简单，既然是显示图片的某一块区域，那么至少只需要一个方法去设置图片；一个方法传入显示的区域即可；详见：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eBitmapRegionDecoder提供了一系列的newInstance方法来构造对象，支持传入文件路径，文件描述符，文件的inputstrem等。例如： ```\n\u003ccode\u003e BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;);\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  * 上述解决了传入我们需要处理的图片，那么接下来就是显示指定的区域。 ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`bitmapRegionDecoder.decodeRegion(rect, options);`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e参数一很明显是一个rect，参数二是BitmapFactory.Options，你可以控制图片的`inSampleSize`,`inPreferredConfig`等。  \n\n那么下面看一个超级简单的例子：\n\n```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e`\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.blogcodes.largeImage;\u003c/p\u003e\n\u003cp\u003e\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.BitmapFactory;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.BitmapRegionDecoder;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Rect;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v7.app.AppCompatActivity;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView;\u003c/p\u003e\n\u003cp\u003e\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.blogcodes.R;\u003c/p\u003e\n\u003cp\u003e\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; java.io.IOException;\n\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;import\u0026lt;/span\u0026gt; java.io.InputStream;\u003c/p\u003e","title":"Android 高清加载巨图方案 拒绝压缩图片"},{"content":" 对于图片加载有一种这样的情况，就是单个图片非常巨大，并且还不允许压缩。比如显示：世界地图、微博长图等。首先不压缩，按照原图尺寸加载，那么屏幕肯定是不够大的，并且考虑到内存的情况，不可能一次性整图加载到内存中，所以肯定是局部加载。这就需要用到Api提供的这个类：BitmapRegionDecoder。 ### \u0026lt;a name=\u0026quot;t1\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;BitmapRegionDecoder 我们来看一下官方的介绍： ``` `BitmapRegionDecoder can be used \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;to\u0026lt;/span\u0026gt; decode \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;a\u0026lt;/span\u0026gt; rectangle region \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;from\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;an\u0026lt;/span\u0026gt; image. BitmapRegionDecoder is particularly useful when \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;an\u0026lt;/span\u0026gt; original image is large \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;and\u0026lt;/span\u0026gt; you only need parts \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;of\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;the\u0026lt;/span\u0026gt; image.\nTo \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;create\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;a\u0026lt;/span\u0026gt; BitmapRegionDecoder, call newInstance(\u0026hellip;). Given \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;a\u0026lt;/span\u0026gt; BitmapRegionDecoder, users can call decodeRegion() repeatedly \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;to\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;get\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;a\u0026lt;/span\u0026gt; decoded Bitmap \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;of\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;the\u0026lt;/span\u0026gt; specified region.`\n- 1 - 2 - 3 **BitmapRegionDecoder主要用于显示图片的某一块矩形区域，如果你需要显示某个图片的指定区域，或者你需要显示一张非常大的图片，那么这个类非常合适。我们可以调用newInstance(…)方法来获得一个BitmapRegionDecoder对象，然后调用decodeRegion()方法就可以获得指定位置的图片了。** 接下来看一个简单的例子 ``` `\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;package\u0026amp;lt;/span\u0026gt; oracleen.decoder; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.app.Activity; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Bitmap; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.BitmapFactory; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.BitmapRegionDecoder; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Rect; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.os.Bundle; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.widget.ImageView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.IOException; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.InputStream; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;MainActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Activity\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ImageView decoder; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;(Bundle savedInstanceState) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(R.layout.activity_main); decoder = (ImageView) findViewById(R.id.decoder); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { InputStream inputStreamF = getAssets().open(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;datu.png\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获得图片的宽、高\u0026amp;lt;/span\u0026gt; BitmapFactory.Options tmpOptions = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; BitmapFactory.Options(); tmpOptions.inJustDecodeBounds = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; BitmapFactory.decodeStream(inputStreamF, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;, tmpOptions); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; width = tmpOptions.outWidth; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; height = tmpOptions.outHeight; InputStream inputStreamS = getAssets().open(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;datu.png\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置显示图片的中心区域\u0026amp;lt;/span\u0026gt; BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStreamS, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;); BitmapFactory.Options options = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.RGB_565; Bitmap bitmap = bitmapRegionDecoder.decodeRegion(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Rect(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, width / \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;, height), options); decoder.setImageBitmap(bitmap); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (IOException e) { e.printStackTrace(); } } } ` - 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 这里我们截取了一个高度等于大图高度，长度等于大图长度一般的图片。 这里注意一下，有时候会抛 ``` Throws IOException \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-operator\u0026quot;\u0026gt;the\u0026amp;lt;/span\u0026gt; image \u0026amp;lt;span class=\u0026quot;hljs-built_in\u0026quot;\u0026gt;format\u0026amp;lt;/span\u0026gt; is \u0026amp;lt;span class=\u0026quot;hljs-operator\u0026quot;\u0026gt;not\u0026amp;lt;/span\u0026gt; supported \u0026amp;lt;span class=\u0026quot;hljs-operator\u0026quot;\u0026gt;or\u0026amp;lt;/span\u0026gt; can \u0026amp;lt;span class=\u0026quot;hljs-operator\u0026quot;\u0026gt;not\u0026amp;lt;/span\u0026gt; be decoded.\n- 1 - 2 这个异常，这里需要重新初始化一下我们的输入流，保证它是初始的可读状态。 ![这里写图片描述](http://img.blog.csdn.net/20160318151945160) ### \u0026lt;a name=\u0026#34;t2\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;小B的总结 对于小B的问题有两种解决办法： 1.把原始的长图切成5张小图，分别设置给5个ImageView，这样每个imageview加载的图都不会超出阈值。 但是问题是整张图会全部加载出来，可能会出现OOM。 2.重写HorizontalScrollView，根据左右滑动的距离用BitmapRegionDecoder去分区域显示。 3.自定义view，在view内部用BitmapRegionDecoder去分区域显示。然后对外提供一个设置图片资源的方法。 参考链接： [http://blog.csdn.net/lmj623565791/article/details/49300989](http://blog.csdn.net/lmj623565791/article/details/49300989) [http://developer.android.com/reference/android/graphics/BitmapRegionDecoder.html#newInstance%28java.io.InputStream,%20boolean%29](http://developer.android.com/reference/android/graphics/BitmapRegionDecoder.html#newInstance%28java.io.InputStream,%20boolean%29) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;bdsharebuttonbox tracking-ad bdshare-button-style0-16\u0026#34; data-mod=\u0026#34;popu_172\u0026#34; data-bd-bind=\u0026#34;1459929845641\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026#34;digg\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android%E5%8A%A0%E8%BD%BD%E9%95%BF%E5%9B%BE%E9%82%A3%E4%BA%9B%E4%BA%8B/","summary":"\u003cdiv id=\"article_content\" class=\"article_content\"\u003e\n  \u003cdiv class=\"markdown_views\"\u003e\n\u003cpre\u003e\u003ccode\u003e  对于图片加载有一种这样的情况，就是单个图片非常巨大，并且还不允许压缩。比如显示：世界地图、微博长图等。首先不压缩，按照原图尺寸加载，那么屏幕肯定是不够大的，并且考虑到内存的情况，不可能一次性整图加载到内存中，所以肯定是局部加载。这就需要用到Api提供的这个类：BitmapRegionDecoder。\n\n\n\n### \u0026lt;a name=\u0026quot;t1\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;BitmapRegionDecoder\n\n\n\n  我们来看一下官方的介绍：\n\n\n\n```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e`BitmapRegionDecoder can be used \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;to\u0026lt;/span\u0026gt; decode \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;a\u0026lt;/span\u0026gt; rectangle region \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;from\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;an\u0026lt;/span\u0026gt; image. BitmapRegionDecoder is particularly useful when \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;an\u0026lt;/span\u0026gt; original image is large \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;and\u0026lt;/span\u0026gt; you only need parts \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;of\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;the\u0026lt;/span\u0026gt; image.\u003c/p\u003e\n\u003cp\u003eTo \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;create\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;a\u0026lt;/span\u0026gt; BitmapRegionDecoder, call newInstance(\u0026hellip;). Given \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;a\u0026lt;/span\u0026gt; BitmapRegionDecoder, users can call decodeRegion() repeatedly \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;to\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;get\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;a\u0026lt;/span\u0026gt; decoded Bitmap \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;of\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;the\u0026lt;/span\u0026gt; specified region.`\u003c/p\u003e","title":"Android加载长图那些事"},{"content":"这一次我们将会实现一个完整纯粹的自定义控件，而不是像之前的组合控件一样，拿系统的控件来实现；计划分为三部分：自定义控件的基本部分，自定义控件的触摸事件的处理和自定义控件的自定义属性；\n下面就开始第一部分的编写，本次以一个定义的开关按钮为例，下面就开始吧：\n先看看效果，一个点击开关按钮，实现点击切换开关状态：\n为了能够讲解清晰，还是来一些基本的介绍。\n首先需要明确的就是自定义控件还是继承自View这个类，Google在View这个类里面提供了相当多的方法供我们使用，使用这些方法我们可以实现相当多的效果和功能，在这里需要用到几个主要的方法；\n自定义控件的步骤、用到的主要方法：\n1、首先需要定义一个类，继承自View；对于继承View的类，会需要实现至少一个构造方法；实际上这里一共有三个构造方法：\n**public View (Context context)**是在java代码创建视图的时候被调用(使用new的方式)，如果是从xml填充的视图，就不会调用这个\n**public View (Context context, AttributeSet attrs)**这个是在xml创建但是没有指定style的时候被调用\n**public View (Context context, AttributeSet attrs, int defStyle)**这个是在第二个基础上添加style的时候被调用的\n所以对于这里来说，如果不使用style， 我们重点关注第二个构造方法即可\n2、对于任何一个控件来说，它需要显示在我们的界面上，那么肯定需要定义它的大小；\n在这里Google提供了一个方法：**protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)；我们去看这个方法的内部，实际上是调用了protected final void setMeasuredDimension(int measuredWidth, int measuredHeight);**这个方法，其中第一个参数是view的宽，第二个参数是view的高，这样我们就可以设置view的宽高了，但是要注意，这样设置的单位都是像素\n3、对于一个需要显示的控件来说，我们往往还需要确定它的位置：\n这就要求重写onLayout方法；但是实际上这个方法在自定义view的时候使用的不多，原因是因为对于位置来说，控件只有建议权而没有决定权，决定权一般在父控件那里。\n4、对于一个控件，需要显示，我们当然需要将它绘制出来，这里就需要重写onDraw方法，来将这个控件绘制出来\n5、当控件状态改变的时候，我们很可能需要刷新view的显示状态，这时候就需要调用invalidate()方法，这个方法实际上会重新调用onDraw方法来重绘控件\n6、在定义控件的过程中，如果需要对view设置点击事件，可以直接使用setOnClickListener方法，而不需要写view.setOnClickListener；\n**7、在布局文件中将这个自定义控件定义出来，注意名字要使用全类名；**而且，由于是继承自view控件，所以在xml文件中如果是view本身的属性都可以直接使用，比如：android:layout_width等等\n这里比较关键的地方就在于这个onDraw方法，我们一起来看一下：\n**[java]** [view plain](http://blog.csdn.net/cyp331203/article/details/40736027#) [copy](http://blog.csdn.net/cyp331203/article/details/40736027#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/505895)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/505895/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 画view的方法,绘制当前view的内容\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// super.onDraw(canvas);\u0026lt;/span\u0026gt; - - - Paint paint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 打开抗锯齿\u0026lt;/span\u0026gt; - paint.setAntiAlias(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 画背景\u0026lt;/span\u0026gt; - canvas.drawBitmap(backgroundBitmap, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, paint); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 画滑块\u0026lt;/span\u0026gt; - canvas.drawBitmap(slideButton, slideBtn_left, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, paint); - } \u0026lt;/div\u0026gt; \u0026amp;nbsp; **onDraw**方法传入的参数是一个**Canvas**画布对象，这个实际上跟Java中的差不太多，我们要在画布上画画也需要一个画笔，我们这里也将其初始化出来**Paint paint = new Paint()**，同时设置了一个抗锯齿效果**paint.setAntiAlias(true)**，然后调用**drawBitmap**的方法，先后绘制了开关的背景和开关的滑块，分别入下图： ![](http://img.blog.csdn.net/20141103103403203?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3lwMzMxMjAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) ![](http://img.blog.csdn.net/20141103103342450?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3lwMzMxMjAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 这里要注意的一点就是，**drawBitmap(Bitmap bitmap, float left, float top, Paint paint)**方法中间的两个float类型的参数，分别代表绘制图形的左上角的x和y的坐标（原点设置在左上角），所以这里如果我们个绘制坐标都传入0,0，那么开关会处在一个关的状态，这里，我们对于滑块使用了一个变量**slideBtn_left**来设置其位置，**那么对于关闭状态，slideBtn_left的值就应该为0，对于开启状态，slideBtn_left的值就应该是backgroundBitmap(背景)的宽度减去slideButton(滑块)的宽度**； 那么这样一来，机制就比较清楚了，我们只需要在控件上设置一个点击事件，同时设置一个boolean变量代表开关的状态，当点击的时候，切换这个boolean类型的变量为true或者false，同时变化**slideButton**的值为****或者**backgroundBitmap.getWidth()-slideButton.getWidth()**，然后再调用**invalidate()**方法刷新控件，就可以实现基本的开关功能了 下面来看具体的代码，注解比较详细： 自定义控件的类MyToggleButton.java，继承自View： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/cyp331203/article/details/40736027#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/cyp331203/article/details/40736027#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/505895)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/505895/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.togglebutton.ui; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.togglebutton.R; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.BitmapFactory; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 自定义view的几个步骤：\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 1、首先需要写一个类来继承自View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 2、需要得到view的对象，那么需要重写构造方法，其中一参的构造方法用于new，二参的构造方法用于xml布局文件使用，三参的构造方法可以传入一个样式\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 3、需要设置view的大小，那么需要重写onMeasure方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 4、需要设置view的位置，那么需要重写onLayout方法，但是这个方法在自定义view的时候用的不多，原因主要在于view的位置主要是由父控件来决定\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 5、需要绘制出所需要显示的view，那么需要重写onDraw方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 6、当控件状态改变的时候，需要重绘view，那么调用invalidate();方法，这个方法实际上会重新调用onDraw方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 7、在这其中，如果需要对view设置点击事件，可以直接调用setOnClickListener方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyToggleButton \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; View { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 开关按钮的背景\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap backgroundBitmap; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 开关按钮的滑动部分\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap slideButton; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 滑动按钮的左边界\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; slideBtn_left; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 当前开关的状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; currentState = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 在代码里面创建对象的时候，使用此构造方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyToggleButton(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 在布局文件中声明的view，创建时由系统自动调用\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param attrs\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyToggleButton(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - initView(); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 测量尺寸时的回调方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// super.onMeasure(widthMeasureSpec, heightMeasureSpec);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置当前view的大小 width:view的宽，单位都是像素值 heigth:view的高，单位都是像素值\u0026lt;/span\u0026gt; - setMeasuredDimension(backgroundBitmap.getWidth(), - backgroundBitmap.getHeight()); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这个方法对于自定义view的时候帮助不大，因为view的位置一般由父组件来决定的\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; left, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; top, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; right, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bottom) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onLayout(changed, left, top, right, bottom); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 画view的方法,绘制当前view的内容\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// super.onDraw(canvas);\u0026lt;/span\u0026gt; - - Paint paint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 打开抗锯齿\u0026lt;/span\u0026gt; - paint.setAntiAlias(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 画背景\u0026lt;/span\u0026gt; - canvas.drawBitmap(backgroundBitmap, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, paint); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 画滑块\u0026lt;/span\u0026gt; - canvas.drawBitmap(slideButton, slideBtn_left, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, paint); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 初始化view\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() { - backgroundBitmap = BitmapFactory.decodeResource(getResources(), - R.drawable.switch_background); - slideButton = BitmapFactory.decodeResource(getResources(), - R.drawable.slide_button); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 点击事件\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - - currentState = !currentState; - flushState(); - flushView(); - } - }); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 刷新视图\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; flushView() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新当前view会导致ondraw方法的执行\u0026lt;/span\u0026gt; - invalidate(); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 刷新当前的状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; flushState() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (currentState) { - slideBtn_left = backgroundBitmap.getWidth() - \u0026amp;#8211; slideButton.getWidth(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - slideBtn_left = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - } - } - - } \u0026lt;/div\u0026gt; \u0026amp;nbsp; 在布局文件中将其定义出来： \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/cyp331203/article/details/40736027#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/cyp331203/article/details/40736027#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/505895)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/505895/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;{relativePackage}.\u0026lt;/span\u0026gt;{activityClass}\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.togglebutton.ui.MyToggleButton\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/my_toggle_btn\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerInParent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; 在这里由于没有写任何点击触发业务的逻辑，只是一个单纯的控件，所以在MainActivity里面没有加入多的代码： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/cyp331203/article/details/40736027#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/cyp331203/article/details/40736027#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/505895)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/505895/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.togglebutton; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - } - } \u0026lt;/div\u0026gt; 至此一个自定义的开关按钮就完成了，后面两篇将会介绍如何在上面实现 **[点击拖动开关的效果](http://blog.csdn.net/cyp331203/article/details/40779335)** 和如何实现自定义属性，谢谢支持！ ","permalink":"https://blog.zdltech.com/posts/android%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6%E7%B3%BB%E5%88%97%E4%BA%8C%E8%87%AA%E5%AE%9A%E4%B9%89%E5%BC%80%E5%85%B3%E6%8C%89%E9%92%AE%E4%B8%80/","summary":"\u003cp\u003e这一次我们将会实现一个完整纯粹的自定义控件，而不是像之前的组合控件一样，拿系统的控件来实现；计划分为三部分：\u003cstrong\u003e自定义控件的基本部分\u003c/strong\u003e，\u003cstrong\u003e\u003ca href=\"http://blog.csdn.net/cyp331203/article/details/40779335\"\u003e自定义控件的触摸事件的处理\u003c/a\u003e\u003cstrong\u003e和\u003c/strong\u003e自定义控件的自定义属性\u003c/strong\u003e；\u003c/p\u003e\n\u003cp\u003e下面就开始第一部分的编写，本次以一个定义的开关按钮为例，下面就开始吧：\u003c/p\u003e\n\u003cp\u003e先看看效果，一个点击开关按钮，实现点击切换开关状态：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20141103105931471\"\u003e\u003c/p\u003e\n\u003cp\u003e为了能够讲解清晰，还是来一些基本的介绍。\u003c/p\u003e\n\u003cp\u003e首先需要明确的就是自定义控件还是继承自View这个类，Google在View这个类里面提供了相当多的方法供我们使用，使用这些方法我们可以实现相当多的效果和功能，在这里需要用到几个主要的方法；\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e自定义控件的步骤、用到的主要方法：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1、首先需要定义一个类，继承自View；对于继承View的类，会需要实现至少一个构造方法；实际上这里一共有三个构造方法：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e**public View (Context context)**是在java代码创建视图的时候被调用(使用new的方式)，如果是从xml填充的视图，就不会调用这个\u003cbr\u003e\n**public View (Context context, AttributeSet attrs)**这个是在xml创建但是没有指定style的时候被调用\u003cbr\u003e\n**public View (Context context, AttributeSet attrs, int defStyle)**这个是在第二个基础上添加style的时候被调用的\u003c/p\u003e\n\u003cp\u003e所以对于这里来说，如果不使用style， 我们重点关注第二个构造方法即可\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2、对于任何一个控件来说，它需要显示在我们的界面上，那么肯定需要定义它的大小；\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在这里Google提供了一个方法：**protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)；\u003cstrong\u003e我们去看这个方法的内部，实际上是调用了\u003c/strong\u003eprotected final void setMeasuredDimension(int measuredWidth, int measuredHeight);**这个方法，其中第一个参数是view的宽，第二个参数是view的高，这样我们就可以设置view的宽高了，\u003cstrong\u003e但是要注意，这样设置的单位都是像素\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3、对于一个需要显示的控件来说，我们往往还需要确定它的位置：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e这就要求重写\u003cstrong\u003eonLayout\u003c/strong\u003e方法；但是实际上这个方法在自定义view的时候使用的不多，原因是因为对于位置来说，控件只有建议权而没有决定权，决定权一般在父控件那里。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4、对于一个控件，需要显示，我们当然需要将它绘制出来，这里就需要重写onDraw方法，来将这个控件绘制出来\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e5、当控件状态改变的时候，我们很可能需要刷新view的显示状态，这时候就需要调用invalidate()方法，这个方法实际上会重新调用onDraw方法来重绘控件\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e6、在定义控件的过程中，如果需要对view设置点击事件，可以直接使用setOnClickListener方法，而不需要写view.setOnClickListener；\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e**7、在布局文件中将这个自定义控件定义出来，注意名字要使用全类名；**而且，由于是继承自view控件，所以在xml文件中如果是view本身的属性都可以直接使用，比如：\u003cstrong\u003eandroid:layout_width\u003c/strong\u003e等等\u003c/p\u003e\n\u003cp\u003e这里比较\u003cstrong\u003e关键的地方\u003c/strong\u003e就在于这个\u003cstrong\u003eonDraw\u003c/strong\u003e方法，我们一起来看一下：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/cyp331203/article/details/40736027#)\u003cspan class=\"tracking-ad\" data-mod=\"popu_168\"\u003e\u003cspan class=\"tracking-ad\" data-mod=\"popu_168\"\u003e [copy](http://blog.csdn.net/cyp331203/article/details/40736027#)\u003c/span\u003e\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n\n    \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/505895)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/505895/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \n    \n    \n      - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 画view的方法,绘制当前view的内容\u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) {\n      \n      - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// super.onDraw(canvas);\u0026lt;/span\u0026gt;\n      \n      - \n      - \n      - Paint paint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint();\n      \n      - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 打开抗锯齿\u0026lt;/span\u0026gt;\n      \n      - paint.setAntiAlias(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n      \n      - \n      - \n      - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 画背景\u0026lt;/span\u0026gt;\n      \n      - canvas.drawBitmap(backgroundBitmap, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, paint);\n      \n      - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 画滑块\u0026lt;/span\u0026gt;\n      \n      - canvas.drawBitmap(slideButton, slideBtn_left, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, paint);\n      \n      - }\n      \n    \u0026lt;/div\u0026gt; \n    \n    \n\n      \u0026amp;nbsp;\n    \n\n    \n    \n\n      **onDraw**方法传入的参数是一个**Canvas**画布对象，这个实际上跟Java中的差不太多，我们要在画布上画画也需要一个画笔，我们这里也将其初始化出来**Paint paint = new Paint()**，同时设置了一个抗锯齿效果**paint.setAntiAlias(true)**，然后调用**drawBitmap**的方法，先后绘制了开关的背景和开关的滑块，分别入下图：\n    \n\n    \n    \n\n      ![](http://img.blog.csdn.net/20141103103403203?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3lwMzMxMjAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)                          ![](http://img.blog.csdn.net/20141103103342450?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3lwMzMxMjAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n    \n\n    \n    \n\n      这里要注意的一点就是，**drawBitmap(Bitmap bitmap, float left, float top, Paint paint)**方法中间的两个float类型的参数，分别代表绘制图形的左上角的x和y的坐标（原点设置在左上角），所以这里如果我们个绘制坐标都传入0,0，那么开关会处在一个关的状态，这里，我们对于滑块使用了一个变量**slideBtn_left**来设置其位置，**那么对于关闭状态，slideBtn_left的值就应该为0，对于开启状态，slideBtn_left的值就应该是backgroundBitmap(背景)的宽度减去slideButton(滑块)的宽度**；\n    \n\n    \n    \n\n      那么这样一来，机制就比较清楚了，我们只需要在控件上设置一个点击事件，同时设置一个boolean变量代表开关的状态，当点击的时候，切换这个boolean类型的变量为true或者false，同时变化**slideButton**的值为****或者**backgroundBitmap.getWidth()-slideButton.getWidth()**，然后再调用**invalidate()**方法刷新控件，就可以实现基本的开关功能了\n    \n\n    \n    \n\n      下面来看具体的代码，注解比较详细：\n    \n\n    \n    \n\n      自定义控件的类MyToggleButton.java，继承自View：\n    \n\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/cyp331203/article/details/40736027#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/cyp331203/article/details/40736027#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n          \n          \u0026lt;div\u0026gt;\n            \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n            \u0026lt;/embed\u0026gt;\n          \u0026lt;/div\u0026gt;\n          \n          \n\n            \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/505895)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/505895/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \n            \n            \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.togglebutton.ui;\n              \n              - \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.togglebutton.R;\n              \n              - \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.BitmapFactory;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\n              \n              - \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 自定义view的几个步骤：\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 1、首先需要写一个类来继承自View\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 2、需要得到view的对象，那么需要重写构造方法，其中一参的构造方法用于new，二参的构造方法用于xml布局文件使用，三参的构造方法可以传入一个样式\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 3、需要设置view的大小，那么需要重写onMeasure方法\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 4、需要设置view的位置，那么需要重写onLayout方法，但是这个方法在自定义view的时候用的不多，原因主要在于view的位置主要是由父控件来决定\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 5、需要绘制出所需要显示的view，那么需要重写onDraw方法\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 6、当控件状态改变的时候，需要重绘view，那么调用invalidate();方法，这个方法实际上会重新调用onDraw方法\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 7、在这其中，如果需要对view设置点击事件，可以直接调用setOnClickListener方法\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n              \n              - \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyToggleButton \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; View {\n              \n              - \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 开关按钮的背景\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap backgroundBitmap;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 开关按钮的滑动部分\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap slideButton;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 滑动按钮的左边界\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; slideBtn_left;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 当前开关的状态\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; currentState = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n              \n              - \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 在代码里面创建对象的时候，使用此构造方法\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param context\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyToggleButton(Context context) {\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context);\n              \n              - }\n              \n              - \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 在布局文件中声明的view，创建时由系统自动调用\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param context\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param attrs\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyToggleButton(Context context, AttributeSet attrs) {\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);\n              \n              - initView();\n              \n              - }\n              \n              - \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 测量尺寸时的回调方法\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) {\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// super.onMeasure(widthMeasureSpec, heightMeasureSpec);\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置当前view的大小 width:view的宽，单位都是像素值 heigth:view的高，单位都是像素值\u0026lt;/span\u0026gt;\n              \n              - setMeasuredDimension(backgroundBitmap.getWidth(),\n              \n              - backgroundBitmap.getHeight());\n              \n              - }\n              \n              - \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这个方法对于自定义view的时候帮助不大，因为view的位置一般由父组件来决定的\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; left, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; top, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; right,\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bottom) {\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onLayout(changed, left, top, right, bottom);\n              \n              - }\n              \n              - \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 画view的方法,绘制当前view的内容\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) {\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// super.onDraw(canvas);\u0026lt;/span\u0026gt;\n              \n              - \n              - Paint paint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint();\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 打开抗锯齿\u0026lt;/span\u0026gt;\n              \n              - paint.setAntiAlias(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n              \n              - \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 画背景\u0026lt;/span\u0026gt;\n              \n              - canvas.drawBitmap(backgroundBitmap, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, paint);\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 画滑块\u0026lt;/span\u0026gt;\n              \n              - canvas.drawBitmap(slideButton, slideBtn_left, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, paint);\n              \n              - }\n              \n              - \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 初始化view\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() {\n              \n              - backgroundBitmap = BitmapFactory.decodeResource(getResources(),\n              \n              - R.drawable.switch_background);\n              \n              - slideButton = BitmapFactory.decodeResource(getResources(),\n              \n              - R.drawable.slide_button);\n              \n              - \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         * 点击事件\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         */\u0026lt;/span\u0026gt;\n              \n              - setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n              \n              - \n              - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) {\n              \n              - \n              - currentState = !currentState;\n              \n              - flushState();\n              \n              - flushView();\n              \n              - }\n              \n              - });\n              \n              - }\n              \n              - \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 刷新视图\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; flushView() {\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新当前view会导致ondraw方法的执行\u0026lt;/span\u0026gt;\n              \n              - invalidate();\n              \n              - }\n              \n              - \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 刷新当前的状态\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; flushState() {\n              \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (currentState) {\n              \n              - slideBtn_left = backgroundBitmap.getWidth()\n              \n              - \u0026amp;#8211; slideButton.getWidth();\n              \n              - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n              \n              - slideBtn_left = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n              \n              - }\n              \n              - }\n              \n              - \n              - }\n              \n            \u0026lt;/div\u0026gt; \n            \n            \n\n              \u0026amp;nbsp;\n            \n\n            \n            \n\n              在布局文件中将其定义出来：\n            \n\n            \n            \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt;\n              \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n                \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n                  **[html]** [view plain](http://blog.csdn.net/cyp331203/article/details/40736027#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/cyp331203/article/details/40736027#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n                  \n                  \u0026lt;div\u0026gt;\n                    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt;\n                    \u0026lt;/embed\u0026gt;\n                  \u0026lt;/div\u0026gt;\n                  \n                  \n\n                    \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/505895)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/505895/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \n                    \n                    \n                      - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;{relativePackage}.\u0026lt;/span\u0026gt;{activityClass}\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n                      \n                      - \n                      - \n                      - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.togglebutton.ui.MyToggleButton\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/my_toggle_btn\u0026amp;#8221;\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerInParent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n                      \n                      - \n                      - \n                      - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n                      \n                    \u0026lt;/div\u0026gt; \n                    \n                    \n\n                      \u0026amp;nbsp;\n                    \n\n                    \n                    \n\n                      在这里由于没有写任何点击触发业务的逻辑，只是一个单纯的控件，所以在MainActivity里面没有加入多的代码：\n                    \n\n                    \n                    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n                      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n                        \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n                          **[java]** [view plain](http://blog.csdn.net/cyp331203/article/details/40736027#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/cyp331203/article/details/40736027#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n                          \n                          \u0026lt;div\u0026gt;\n                            \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt;\n                            \u0026lt;/embed\u0026gt;\n                          \u0026lt;/div\u0026gt;\n                          \n                          \n\n                            \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/505895)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/505895/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \n                            \n                            \n                              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.togglebutton;\n                              \n                              - \n                              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;\n                              \n                              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;\n                              \n                              - \n                              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity {\n                              \n                              - \n                              - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n                              \n                              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) {\n                              \n                              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);\n                              \n                              - setContentView(R.layout.activity_main);\n                              \n                              - \n                              - }\n                              \n                              - }\n                              \n                            \u0026lt;/div\u0026gt; \n                            \n                            \n\n                              至此一个自定义的开关按钮就完成了，后面两篇将会介绍如何在上面实现 **[点击拖动开关的效果](http://blog.csdn.net/cyp331203/article/details/40779335)** 和如何实现自定义属性，谢谢支持！\n\u003c/code\u003e\u003c/pre\u003e","title":"Android自定义控件系列二：自定义开关按钮（一）"},{"content":"转载请注明出处：http://blog.csdn.net/cyp331203/article/details/45027641\n自定义view/viewgroup要重写的几个方法：onMeasure()，onLayout()，onDraw()。(不熟悉的话可以查看专栏的前几篇文章：Android自定义控件系列二：自定义开关按钮（一）)。\n今天的任务就是详细研究一下protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法。\n如果只是说要重写什么方法有什么用的话，还是不太清楚。先去源码中看看为什么要重写onMeasure()方法，这个方法是在哪里调用的：\n一、源码中的measure/onMeasure方法： **[java]** [view plain](http://blog.csdn.net/cyp331203/article/details/45027641#) [copy](http://blog.csdn.net/cyp331203/article/details/45027641#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/642862)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/642862/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) { - setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), - getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); - } \u0026lt;/div\u0026gt; \u0026amp;nbsp; 实际上是在View这个类中的public final void measure(int widthMeasureSpec, int heightMeasureSpec)方法中被调用的： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/cyp331203/article/details/45027641#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/cyp331203/article/details/45027641#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/642862)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/642862/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; measure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) { - \u0026amp;#8230; - - onMeasure(widthMeasureSpec, heightMeasureSpec); - \u0026amp;#8230; - - } \u0026lt;/div\u0026gt; \u0026amp;nbsp; ## \u0026lt;a name=\u0026quot;t1\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;1、measure() 可以看到，measure()这个方法是一个由final来修饰的方法，意味着不能够被子类重写.measure()方法的作用是：测量出一个View的实际大小，而实际性的测量工作，Android系统却并没有帮我们完成，因为这个工作交给了onMeasure()来作，所以我们需要在自定义View的时候按照自己的需求，重写onMeasure方法.而子控件又分为view和viewGroup两种情况，那么测量的流程是怎样的呢，看一下下面这个图你就明白了： ![](http://img.blog.csdn.net/20150413165429783) ## \u0026lt;a name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt; ## \u0026lt;a name=\u0026quot;t3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;2、onMeasure onMeasure(int widthMeasureSpec, int heightMeasureSpec)中，两个参数的作用： widthMeasureSpec和heightMeasureSpec这两个int类型的参数，看名字应该知道是跟宽和高有关系，但它们其实不是宽和高，而是由宽、高和各自方向上对应的模式来合成的一个值：其中，在int类型的32位二进制位中，31-30这两位表示模式，0~29这三十位表示宽和高的实际值.其中模式一共有三种，被定义在Android中的View类的一个内部类中：View.MeasureSpec： ①UNSPECIFIED：表示默认值，父控件没有给子view任何限制。\u0026amp;#8212;\u0026amp;#8212;二进制表示：00 ②EXACTLY：表示父控件给子view一个具体的值，子view要设置成这些值的大小。\u0026amp;#8212;\u0026amp;#8212;二进制表示：01 ③AT_MOST：表示父控件个子view一个最大的特定值，而子view不能超过这个值的大小。\u0026amp;#8212;\u0026amp;#8212;二进制表示：10 # \u0026lt;a name=\u0026quot;t4\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;二、MeasureSpec MeasureSpe描述了父View对子View大小的期望.里面包含了测量模式和大小.我们可以通过以下方式从MeasureSpec中提取模式和大小，该方法内部是采用位移计算. int specMode = MeasureSpec.getMode(measureSpec);//得到模式 int specSize = MeasureSpec.getSize(measureSpec);//得到大小 也可以通过MeasureSpec的静态方法把大小和模式合成，该方法内部只是简单的相加. MeasureSpec.makeMeasureSpec(specSize,specMode); 每个View都包含一个ViewGroup.LayoutParams类或者其派生类，LayoutParams中包含了View和它的父View之间的关系，而View大小正是View和它的父View共同决定的。 我们平常使用类似于RelativeLayout和LinearLayout的时候，在其内部添加view的时候，不管是布局文件中加入还是在代码中使用addView方法添加，实际上都会调用这个onMeasure方法，而measure和onMeasure中的两个参数，是由各级父控件往子控件/子view进行一层层传递的。我们可以在xml中定义Layout的宽和高的具体的值或宽高的填充方式：matchparent/wrapcontent，也可以在代码中使用LayoutParams设置，而实际上这里设置的值就会对应到上面的measure和onMeasure方法中的两个参数的模式，对应关系如下： 具体的值(如width=200dp)和matchparent/fillparent，对应模式中的MeasureSpec.EXACTLY 包裹内容(width=wrapcontent)则对应模式中的MeasureSpec.AT_MOST 系统调用measure方法，从父控件到子控件的heightMeasureSpec的传递是有一套对应的判断规则的，列表如下： ![](http://img.blog.csdn.net/20150413170503566) 一个view的宽高尺寸，只有在测量之后才能得到，也就是measure方法被调用之后。大家都应该使用过View.getWidth()和View.getHeight()方法，这两个方法可以返回view的宽和高，但是它们也不是在一开始就可以得到的，比如oncreate方法中，因为这时候measure方法还没有被执行，测量还没有完成，我们可以来作一个简单的实验：自定义一个MyView，继承View类，然后在OnCreate方法中，将其new出来，通过addview方法，添加到现在的布局中。然后调用MyView对象的getWidth()和getHeight()方法，会发现得到的都是0。 onMeasure通过父View传递过来的大小和模式，以及自身的背景图片的大小得出自身最终的大小，然后通过setMeasuredDimension()方法设置给mMeasuredWidth和mMeasuredHeight. 普通View的onMeasure逻辑大同小异，基本都是测量自身内容和背景，然后根据父View传递过来的MeasureSpec进行最终的大小判定，例如TextView会根据文字的长度，文字的大小，文字行高，文字的行宽，显示方式，背景图片，以及父View传递过来的模式和大小最终确定自身的大小. # \u0026lt;a name=\u0026quot;t5\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;三、ViewGroup的onMeasure ViewGroup是个抽象类，本身没有实现onMeasure，但是他的子类都有各自的实现，通常他们都是通过measureChildWithMargins函数或者其他类似于measureChild的函数来遍历测量子View，被GONE的子View将不参与测量，当所有的子View都测量完毕后，才根据父View传递过来的模式和大小来最终决定自身的大小. 在测量子View时，会先获取子View的LayoutParams，从中取出宽高，如果是大于0，将会以精确的模式加上其值组合成MeasureSpec传递子View，如果是小于0，将会把自身的大小或者剩余的大小传递给子View，其模式判定在前面表中有对应关系. ViewGroup一般都在测量完所有子View后才会调用setMeasuredDimension()设置自身大小，如第一张图所示. 可能看到现在，还是没搞清楚Android系统通过measure和onmeasure一层层传递参数的具体方法。在研究这个问题之前，先来看一下最简单的helloworld的UI层级关系图： 为了方便起见，这里我们使用requestWindowFeature(Window.FEATURE_NO_TITLE);去除标题栏的影响，只看层级关系。 \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/cyp331203/article/details/45027641#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/cyp331203/article/details/45027641#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/642862)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/642862/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;{relativePackage}.\u0026lt;/span\u0026gt;{activityClass}\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@string/hello_world\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/cyp331203/article/details/45027641#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/cyp331203/article/details/45027641#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/642862)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/642862/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.hello; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.activity_main); - } - } \u0026lt;/div\u0026gt; UI层级关系图: ![](http://img.blog.csdn.net/20150413172415210) 可以发现最简单的helloworld的层级关系图是这样的，最开始是一个PhoneWindow的内部类DecorView，这个DecorView实际上是系统最开始加载的最底层的一个viewGroup，它是FrameLayout的子类，然后加载了一个LinearLayout，然后在这个LinearLayout上加载了一个id为content的FrameLayout和一个ViewStub，这个实际上是原本为ActionBar的位置，由于我们使用了requestWindowFeature(Window.FEATURE_NO_TITLE)，于是变成了空的ViewStub；然后在id为content的FrameLayout才加载了我们的布局XML文件中写的RelativeLayout和TextView。 那么measure方法在系统中传递尺寸和模式，必定是从DecorView这一层开始的，我们假定手机屏幕是320*480，那么DecorView最开始是从硬件的配置文件中读取手机的尺寸，然后设置measure的参数大小为320*480，而模式是EXCACTLY，传递关系可以由下图示意： ![](http://img.blog.csdn.net/20150413174301575) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; 好了，原理将到这里，下一篇将看到利用onMeasure来测量一个自定义一个ImageView，使其能够自动填满屏幕的宽度，且能通过measure测量高度，自适应的调整高度，永远不出现拉伸/压缩变形的情况，敬请关注，谢谢。 [Android自定义控件系列八：详解onMeasure()(二)\u0026amp;#8211;利用onMeasure测量来实现图片拉伸永不变形，解决屏幕适配问题](http://blog.csdn.net/cyp331203/article/details/45038329) **转载请注明出处：[http://blog.csdn.net/cyp331203/article/details/45027641](http://blog.csdn.net/cyp331203/article/details/45027641)** ","permalink":"https://blog.zdltech.com/posts/android%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6%E7%B3%BB%E5%88%97%E4%B8%83%E8%AF%A6%E8%A7%A3onmeasure%E6%96%B9%E6%B3%95%E4%B8%AD%E5%A6%82%E4%BD%95%E6%B5%8B%E9%87%8F%E4%B8%80%E4%B8%AA/","summary":"\u003cp\u003e\u003cstrong\u003e转载请注明出处：\u003ca href=\"http://blog.csdn.net/cyp331203/article/details/45027641\"\u003ehttp://blog.csdn.net/cyp331203/article/details/45027641\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e自定义view/viewgroup要重写的几个方法：onMeasure()，onLayout()，onDraw()。(不熟悉的话可以查看专栏的前几篇文章：\u003cstrong\u003e\u003ca href=\"http://blog.csdn.net/cyp331203/article/details/40736027\"\u003eAndroid自定义控件系列二：自定义开关按钮（一）\u003c/a\u003e\u003c/strong\u003e)。\u003c/p\u003e\n\u003cp\u003e今天的任务就是详细研究一下protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法。\u003c/p\u003e\n\u003cp\u003e如果只是说要重写什么方法有什么用的话，还是不太清楚。先去源码中看看为什么要重写onMeasure()方法，这个方法是在哪里调用的：\u003c/p\u003e\n\u003ch1 id=\"一源码中的measureonmeasure方法\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003e一、源码中的measure/onMeasure方法：\u003c/h1\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/cyp331203/article/details/45027641#)\u003cspan class=\"tracking-ad\" data-mod=\"popu_168\"\u003e\u003cspan class=\"tracking-ad\" data-mod=\"popu_168\"\u003e [copy](http://blog.csdn.net/cyp331203/article/details/45027641#)\u003c/span\u003e\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n\n    \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/642862)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/642862/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \n    \n    \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) {\n      \n      - setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),\n      \n      - getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));\n      \n      - }\n      \n    \u0026lt;/div\u0026gt; \n    \n    \n\n      \u0026amp;nbsp;\n    \n\n    \n    \n\n      实际上是在View这个类中的public final void measure(int widthMeasureSpec, int heightMeasureSpec)方法中被调用的：\n    \n\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/cyp331203/article/details/45027641#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/cyp331203/article/details/45027641#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n          \n          \u0026lt;div\u0026gt;\n            \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n            \u0026lt;/embed\u0026gt;\n          \u0026lt;/div\u0026gt;\n          \n          \n\n            \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/642862)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/642862/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \n            \n            \n              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; measure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) {\n              \n              - \u0026amp;#8230;\n              \n              - \n              - onMeasure(widthMeasureSpec, heightMeasureSpec);\n              \n              - \u0026amp;#8230;\n              \n              - \n              - }\n              \n            \u0026lt;/div\u0026gt; \n            \n            \n\n              \u0026amp;nbsp;\n            \n\n            \n            ## \u0026lt;a name=\u0026quot;t1\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;1、measure()\n            \n            \n\n              可以看到，measure()这个方法是一个由final来修饰的方法，意味着不能够被子类重写.measure()方法的作用是：测量出一个View的实际大小，而实际性的测量工作，Android系统却并没有帮我们完成，因为这个工作交给了onMeasure()来作，所以我们需要在自定义View的时候按照自己的需求，重写onMeasure方法.而子控件又分为view和viewGroup两种情况，那么测量的流程是怎样的呢，看一下下面这个图你就明白了：\n            \n\n            \n            \n\n              ![](http://img.blog.csdn.net/20150413165429783)\n            \n\n            \n            ## \u0026lt;a name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;\n            \n            ## \u0026lt;a name=\u0026quot;t3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;2、onMeasure\n            \n            \n\n              onMeasure(int widthMeasureSpec, int heightMeasureSpec)中，两个参数的作用：        widthMeasureSpec和heightMeasureSpec这两个int类型的参数，看名字应该知道是跟宽和高有关系，但它们其实不是宽和高，而是由宽、高和各自方向上对应的模式来合成的一个值：其中，在int类型的32位二进制位中，31-30这两位表示模式，0~29这三十位表示宽和高的实际值.其中模式一共有三种，被定义在Android中的View类的一个内部类中：View.MeasureSpec：\n            \n\n            \n            \n\n              ①UNSPECIFIED：表示默认值，父控件没有给子view任何限制。\u0026amp;#8212;\u0026amp;#8212;二进制表示：00\n            \n\n            \n            \n\n              ②EXACTLY：表示父控件给子view一个具体的值，子view要设置成这些值的大小。\u0026amp;#8212;\u0026amp;#8212;二进制表示：01\n            \n\n            \n            \n\n              ③AT_MOST：表示父控件个子view一个最大的特定值，而子view不能超过这个值的大小。\u0026amp;#8212;\u0026amp;#8212;二进制表示：10\n            \n\n            \n            # \u0026lt;a name=\u0026quot;t4\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;二、MeasureSpec\n            \n            \n\n              MeasureSpe描述了父View对子View大小的期望.里面包含了测量模式和大小.我们可以通过以下方式从MeasureSpec中提取模式和大小，该方法内部是采用位移计算.\n            \n\n            \n            \n\n              int specMode = MeasureSpec.getMode(measureSpec);//得到模式\n            \n\n            \n            \n\n              int specSize = MeasureSpec.getSize(measureSpec);//得到大小\n            \n\n            \n            \n\n              也可以通过MeasureSpec的静态方法把大小和模式合成，该方法内部只是简单的相加.\n            \n\n            \n            \n\n              MeasureSpec.makeMeasureSpec(specSize,specMode);\n            \n\n            \n            \n\n              每个View都包含一个ViewGroup.LayoutParams类或者其派生类，LayoutParams中包含了View和它的父View之间的关系，而View大小正是View和它的父View共同决定的。\n            \n\n            \n            \n\n              我们平常使用类似于RelativeLayout和LinearLayout的时候，在其内部添加view的时候，不管是布局文件中加入还是在代码中使用addView方法添加，实际上都会调用这个onMeasure方法，而measure和onMeasure中的两个参数，是由各级父控件往子控件/子view进行一层层传递的。我们可以在xml中定义Layout的宽和高的具体的值或宽高的填充方式：matchparent/wrapcontent，也可以在代码中使用LayoutParams设置，而实际上这里设置的值就会对应到上面的measure和onMeasure方法中的两个参数的模式，对应关系如下：\n            \n\n            \n            \n\n              具体的值(如width=200dp)和matchparent/fillparent，对应模式中的MeasureSpec.EXACTLY\n            \n\n            \n            \n\n              包裹内容(width=wrapcontent)则对应模式中的MeasureSpec.AT_MOST\n            \n\n            \n            \n\n              系统调用measure方法，从父控件到子控件的heightMeasureSpec的传递是有一套对应的判断规则的，列表如下：\n            \n\n            \n            \n\n              ![](http://img.blog.csdn.net/20150413170503566)\n            \n\n            \n            \n\n              一个view的宽高尺寸，只有在测量之后才能得到，也就是measure方法被调用之后。大家都应该使用过View.getWidth()和View.getHeight()方法，这两个方法可以返回view的宽和高，但是它们也不是在一开始就可以得到的，比如oncreate方法中，因为这时候measure方法还没有被执行，测量还没有完成，我们可以来作一个简单的实验：自定义一个MyView，继承View类，然后在OnCreate方法中，将其new出来，通过addview方法，添加到现在的布局中。然后调用MyView对象的getWidth()和getHeight()方法，会发现得到的都是0。\n            \n\n            \n            \n\n              onMeasure通过父View传递过来的大小和模式，以及自身的背景图片的大小得出自身最终的大小，然后通过setMeasuredDimension()方法设置给mMeasuredWidth和mMeasuredHeight.\n            \n\n            \n            \n\n              普通View的onMeasure逻辑大同小异，基本都是测量自身内容和背景，然后根据父View传递过来的MeasureSpec进行最终的大小判定，例如TextView会根据文字的长度，文字的大小，文字行高，文字的行宽，显示方式，背景图片，以及父View传递过来的模式和大小最终确定自身的大小.\n            \n\n            \n            # \u0026lt;a name=\u0026quot;t5\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;三、ViewGroup的onMeasure\n            \n            \n\n              ViewGroup是个抽象类，本身没有实现onMeasure，但是他的子类都有各自的实现，通常他们都是通过measureChildWithMargins函数或者其他类似于measureChild的函数来遍历测量子View，被GONE的子View将不参与测量，当所有的子View都测量完毕后，才根据父View传递过来的模式和大小来最终决定自身的大小.\n            \n\n            \n            \n\n              在测量子View时，会先获取子View的LayoutParams，从中取出宽高，如果是大于0，将会以精确的模式加上其值组合成MeasureSpec传递子View，如果是小于0，将会把自身的大小或者剩余的大小传递给子View，其模式判定在前面表中有对应关系.\n            \n\n            \n            \n\n              ViewGroup一般都在测量完所有子View后才会调用setMeasuredDimension()设置自身大小，如第一张图所示.\n            \n\n            \n            \n\n              可能看到现在，还是没搞清楚Android系统通过measure和onmeasure一层层传递参数的具体方法。在研究这个问题之前，先来看一下最简单的helloworld的UI层级关系图：\n            \n\n            \n            \n\n              为了方便起见，这里我们使用requestWindowFeature(Window.FEATURE_NO_TITLE);去除标题栏的影响，只看层级关系。\n            \n\n            \n            \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt;\n              \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n                \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n                  **[html]** [view plain](http://blog.csdn.net/cyp331203/article/details/45027641#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/cyp331203/article/details/45027641#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n                  \n                  \u0026lt;div\u0026gt;\n                    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt;\n                    \u0026lt;/embed\u0026gt;\n                  \u0026lt;/div\u0026gt;\n                  \n                  \n\n                    \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/642862)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/642862/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \n                    \n                    \n                      - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;{relativePackage}.\u0026lt;/span\u0026gt;{activityClass}\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n                      \n                      - \n                      - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n                      \n                      - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@string/hello_world\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n                      \n                      - \n                      - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n                      \n                    \u0026lt;/div\u0026gt; \n                    \n                    \n\n                      \u0026amp;nbsp;\n                    \n\n                    \n                    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n                      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n                        \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n                          **[java]** [view plain](http://blog.csdn.net/cyp331203/article/details/45027641#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/cyp331203/article/details/45027641#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n                          \n                          \u0026lt;div\u0026gt;\n                            \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt;\n                            \u0026lt;/embed\u0026gt;\n                          \u0026lt;/div\u0026gt;\n                          \n                          \n\n                            \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/642862)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/642862/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \n                            \n                            \n                              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.hello;\n                              \n                              - \n                              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;\n                              \n                              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;\n                              \n                              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window;\n                              \n                              - \n                              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity {\n                              \n                              - \n                              - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n                              \n                              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) {\n                              \n                              - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);\n                              \n                              - requestWindowFeature(Window.FEATURE_NO_TITLE);\n                              \n                              - setContentView(R.layout.activity_main);\n                              \n                              - }\n                              \n                              - }\n                              \n                            \u0026lt;/div\u0026gt; \n                            \n                            \n\n                              UI层级关系图:\n                            \n\n                            \n                            \n\n                              ![](http://img.blog.csdn.net/20150413172415210)\n                            \n\n                            \n                            \n\n                              可以发现最简单的helloworld的层级关系图是这样的，最开始是一个PhoneWindow的内部类DecorView，这个DecorView实际上是系统最开始加载的最底层的一个viewGroup，它是FrameLayout的子类，然后加载了一个LinearLayout，然后在这个LinearLayout上加载了一个id为content的FrameLayout和一个ViewStub，这个实际上是原本为ActionBar的位置，由于我们使用了requestWindowFeature(Window.FEATURE_NO_TITLE)，于是变成了空的ViewStub；然后在id为content的FrameLayout才加载了我们的布局XML文件中写的RelativeLayout和TextView。\n                            \n\n                            \n                            \n\n                              那么measure方法在系统中传递尺寸和模式，必定是从DecorView这一层开始的，我们假定手机屏幕是320*480，那么DecorView最开始是从硬件的配置文件中读取手机的尺寸，然后设置measure的参数大小为320*480，而模式是EXCACTLY，传递关系可以由下图示意：\n                            \n\n                            \n                            \n\n                              ![](http://img.blog.csdn.net/20150413174301575)\n                            \n\n                            \n                            \u0026lt;div\u0026gt;\n                            \u0026lt;/div\u0026gt;\n                            \n                            \n\n                              \u0026amp;nbsp;\n                            \n\n                            \n                            \n\n                              好了，原理将到这里，下一篇将看到利用onMeasure来测量一个自定义一个ImageView，使其能够自动填满屏幕的宽度，且能通过measure测量高度，自适应的调整高度，永远不出现拉伸/压缩变形的情况，敬请关注，谢谢。\n                            \n\n                            \n                            \n\n                              [Android自定义控件系列八：详解onMeasure()(二)\u0026amp;#8211;利用onMeasure测量来实现图片拉伸永不变形，解决屏幕适配问题](http://blog.csdn.net/cyp331203/article/details/45038329)\n                            \n\n                            \n                            \n\n                              **转载请注明出处：[http://blog.csdn.net/cyp331203/article/details/45027641](http://blog.csdn.net/cyp331203/article/details/45027641)**\n\u003c/code\u003e\u003c/pre\u003e","title":"Android自定义控件系列七：详解onMeasure()方法中如何测量一个控件尺寸(一)"},{"content":"使用ImageView会遇到的问题 转载请注明出处：http://blog.csdn.net/cyp331203/article/details/45038329\n在Android应用中，都少不了图片的显示，ImageView，轮播图，ViewPager等等，很多都是来显示图片的，比如一个广告条的轮播效果，参看博客：广告条效果实现—-ViewPager加载大图片(LruCache)以及定时刷新，很多时候，我们都希望图片能够在宽度上填充父窗体，这样比较符合人的审美观点，但是问题就随之而来了，那就是高度如何定义？？先来看一个普通的ImageView的 Xml布局文件的定义：\n**[html]** [view plain](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[copy](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/643475)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/643475/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/recommend_39\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;描述文字信息\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;.\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 为了方便查看，我在ImageView下面又加上了一句描述的信息的TextView，这时，父控件都是填充父窗体，而ImageView则是：横向填充父窗体，纵向包裹内容；text都是包裹内容；那么来看看显示效果：\n上面那个蓝色的小框就是ImageView的范围，这种效果一般都不会是我们想要的，那么如果想要ImageView中的图片能够填满ImageView的整个窗体怎么办？添加一个属性：scaleType，如下：\n**[html]** [view plain](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[copy](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/643475)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/643475/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scaleType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fitXY\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/recommend_39\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; 效果如图：\n可以看到，填是填满了，但是也由于纵向拉伸而使图片变形了。那要怎么做呢？\n我们仔细观察一下，不难发现ImageView的纵向高度是包裹内容：wrapcontent，有些同学可能想到，能够直接在这里给ImageView一个特定的dip值，让这个ImageView符合图片的宽高比呢？这样做无疑是可以的，但是却不具有通用性。。。下面还是用上面的例子来讲解：\n我们先来实现一下，制定ImageView的高度，来达到让这张图片在这个特定模拟器下显示比例正常的过程：\n上面的图片实际像素的尺寸是：828*314，宽度和高度的比例大约是2.43，而我们这里使用的模拟器的尺寸是480*800(单位是px，也就是像素)，也就是说宽度上的像素是480，那么我们要设置这个ImageView的高度为多少dip才能够让其正好符合2.43的比例呢。\nAndroid设备上px(像素)、dpi(像素密度)、dip(密度无关像素)之间的关系： 这里又要牵扯出另外一块知识点，dip和dpi的联系：\n分辨率(Resolution)：表示设备屏幕上像素点的总数，比如上面的模拟器，屏幕像素尺寸是480(px)*800(px)\ndpi(像素密度)：是指每英寸的像素，所以同分辨率的两个设备，它们的dpi很可能不一样；如果一个手机分辨率5寸是1080*1920，而一个平板9.7寸分辨率也是1080*1920，那么 手机的dpi会比平板高出很多。\ndp/dip：全称是Density-independent pixel ，中文名是 “密度无关像素”，也就是我们经常在xml文件中写的长度单位dp。为什么叫做密度无关像素呢，这其实是为了解决不同分辨率设备显示效果统一的一个解决方案，试想，如果一个两个手机屏幕都是一样大小，比如5寸，A手机的分辨率是 720*1280，而B手机的分辨率是1080*1920；那么如果我们想在上面显示一个图片分辨率为：200*200的图片，就会发现，在A手机上显示的图片，比B手机上显示的图片要小了很多；直观的来看，A手机的宽度是720，显示200*200的图片差不多要占据将近1/3的宽度，而反观B手机，宽度是1080，显示200*200的图片，则只需要占据1/5不到的宽度，而两个手机的尺寸又都是5寸，所以就会在显示同样分辨率的图片时，产生大小的差异。这种差异明显不是我们想要的。\n所以dip/dp，密度无关像素就应运而生；它是这样规定的，dip与一个dpi(像素密度)为160dpi的设备的px(像素)值是相等的，而对于其他像素密度的设备，则依据转换公式来计算对应的dip值，这个公式是根据dpi(相当于比例)，来转换px(像素)和dip(密度无关像素)的：\n**[java]** [view plain](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[copy](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/643475)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/643475/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - px = dip * (dpi / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;160\u0026lt;/span\u0026gt;) - - dip = px / (dpi / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;160\u0026lt;/span\u0026gt;) 经过上面的转换之后，由于dip和px的转换是按照比例来的，而这个比例又是dpi/160，而dpi又是根据各个设备的分辨率和尺寸的比例得来的，所以使用相同的dip来设置的尺寸的控件，在相同尺寸大小的设备上，不论设备的分辨率是多少，它们显示的大小都会是一样的。\n计算ImageView的合适高度的方法 有了上面的知识之后，我们就可以来转换一下我们的ImageView的大小了：\n首先，图片的宽高比是2.43，而模拟器屏幕的宽度是480px，于是计算得到图片应该显示的高度是：480/2.43=197.53px(像素)，但是一般时候，我们在xml文件中，设定的高度单位都是dip，所以这里要需要使用上面的转换公式：dip = px / (dpi / 160)，而在这个模拟器的参数上可以查询到，它的dpi是240，所以计算得到高度应该是:\n197.53/(240/160)=131.68(dip)，约等于132dp，于是我们将上面的ImageView的高度设置成132dp:\n**[html]** [view plain](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[copy](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/643475)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/643475/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;132dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scaleType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fitXY\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/recommend_39\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; 再来看一下显示效果：\n这样显示比例就完全正常了。\n但是这样问题就解决了吗？答案是没有，我们不妨来换一个模拟器来显示，这次选用Nexus7的模拟器，分辨率为1200*1920，dpi为320，ImageView的参数不变，再来看看效果：\n会发现图片被拉长了，这是为什么 呢，我们可以简单的再算一下：\nnexus7 宽度为1200px，而dpi为320，图片比例为2.43，那么应该设置ImageView的高度dp值是：1200/2.43/(320/160)=246.91dp，而我们现在的高度却还是之前的132dp，当然会发现被拉伸了。\n那怎么办，有点让人抓狂！！！\n重写onMeasure方法，重新测量控件高度，实现多种屏幕下自适应图片显示 其实办法是有的，思路就是让控件(ImageView)自己根据不同的设备帮我们来计算这个高度，而不需要我们自己去计算，那要怎么做呢？就得用到上一篇博文中说到的onMeasure方法了，对measure/onMeasure方法不熟悉的同学，可以再去看一下Android自定义控件系列七：详解onMeasure()方法中如何测量一个控件尺寸(一)和Android自定义控件系列二：自定义开关按钮（一）等几篇文章，下面就开始：\n首先要明确的一点就是，自定的view在调用view.measure()之前，是得不到控件的宽和高的，下面就一步步来写：\n思路是首先写一个SmartImageView来继承自ImageView，并且添加相应的构造：\n**[java]** [view plain](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[copy](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/643475)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/643475/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.imageviewdemo; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author : 苦咖啡\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @version : 1.0\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @date ：2015年4月14日\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog : http://blog.csdn.net/cyp331203\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @desc : SmartImageView，能根据给定的图片比例，自动调整宽高，解决拉伸变形的屏幕适配问题\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SmartImageView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ImageView { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SmartImageView(Context context, AttributeSet attrs, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyleAttr, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyleRes) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyleAttr, defStyleRes); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SmartImageView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SmartImageView(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SmartImageView(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - } 然后在SmartImageView中，添加一个float类型的成员变量ratio作为图片的比例值，并且给它暴露一个setter方法，以便于设置图片比例。\n**[java]** [view plain](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[copy](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/643475)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/643475/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** 图片宽和高的比例 */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; ratio = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;.43f; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setRatio(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; ratio) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.ratio = ratio; - } 然后我们来重写onMeausre方法，如下：\n**[java]** [view plain](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[copy](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/643475)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/643475/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 父容器传过来的宽度方向上的模式\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMode = MeasureSpec.getMode(widthMeasureSpec); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 父容器传过来的高度方向上的模式\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMode = MeasureSpec.getMode(heightMeasureSpec); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 父容器传过来的宽度的值\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width = MeasureSpec.getSize(widthMeasureSpec) \u0026amp;#8211; getPaddingLeft() - \u0026amp;#8211; getPaddingRight(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 父容器传过来的高度的值\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height = MeasureSpec.getSize(heightMeasureSpec) \u0026amp;#8211; getPaddingLeft() - \u0026amp;#8211; getPaddingRight(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (widthMode == MeasureSpec.EXACTLY - \u0026amp;\u0026amp; heightMode != MeasureSpec.EXACTLY \u0026amp;\u0026amp; ratio != \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0f) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 判断条件为，宽度模式为Exactly，也就是填充父窗体或者是指定宽度；\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 且高度模式不是Exaclty，代表设置的既不是fill_parent也不是具体的值，于是需要具体测量\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 且图片的宽高比已经赋值完毕，不再是0.0f\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 表示宽度确定，要测量高度\u0026lt;/span\u0026gt; - height = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (width / ratio + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.5f); - heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, - MeasureSpec.EXACTLY); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (widthMode != MeasureSpec.EXACTLY - \u0026amp;\u0026amp; heightMode == MeasureSpec.EXACTLY \u0026amp;\u0026amp; ratio != \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0f) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 判断条件跟上面的相反，宽度方向和高度方向的条件互换\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 表示高度确定，要测量宽度\u0026lt;/span\u0026gt; - width = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (height * ratio + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.5f); - - widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, - MeasureSpec.EXACTLY); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMeasure(widthMeasureSpec, heightMeasureSpec); - } 对于onMeasure方法，有几点需要注意的：\n1、父容器传过来的两个参数widthMeasureSpec和heightMeasureSpec，通过MeasureSpec.getMode()来获取参数中的模式，与控件的填充方式都是有对应关系的，这在上一篇博文：Android自定义控件系列七：详解onMeasure()方法中如何测量一个控件尺寸(一)中也有提到过\n①xml布局文件中的fill_parent或具体值，或者是直接设置控件的LayoutParams中的width和height的具体值或者LayoutParams.FILL_PARENT填充父容器方式，都会对应让上面通过getMode获取参数中的模式为：MeasureSpect.EXACTLY，代表精确取值，因为除了直接指定值之外，填充父容器，也是精确值\n②xml布局文件中设置wrap_content方式或者是在代码中设置LayoutParams.WRAP_CONTENT方式，都会让getMode变成MeasureSpect.AT_MOST\n2、对于父容器传过来的高度或者宽度的值，不一定就是控件想要的宽度或者高度的值，这是因为模式不一样，这个值代表的意义也不一样，所以才会需要通过测量来改变高度或者宽度的值来达到想要的效果。\n其中，如果是模式是EXACTLY，那么传过来的值就是具体指，也可以说是父容器想要我们的控件变成这个具体的大小。\n但是模式如果是AT_MOST，那么传过来的值，就不会是具体的值，一般会是一个最大值，因为AT_MOST代表，不超过多少，那么这个值就是不超过的上限。\n3、可以看到我们通过拿到父容器传过来的高度，宽度的模式和值，然后经过两种if-else判断来重新测量值的大小，这两种判断的依据就是：\n①当宽度确定时(宽度为EXACTLY)，高度模式不是EXACTLY时(也即高度不确定时)，高度按照ratio的比例来重新测量\n②当高度确定时(高度为EXACTLY)，高度模式不是EXACTLY时(也即高度不确定时)，宽度按照ratio的比例来重新测量\n4、在测量完毕之后，因为已经得到了想要的宽度或者高度的具体的精确的值，我们再通过MeasureSpec.makeMeasureSpec()方法来调用精确的值和精确的模式，来合成一个宽度/高度方向上的合成值，最后将合成好的值传递给super.onMeasure(widthMeasureSpec, heightMeasureSpec);设置控件为我们想要的大小。\n然后我们就可以在XML布局文件中，将之前的ImageView改成：com.example.imageviewdemo.SmartImageView\n然后在代码中将其通过findviewbyid拿到它的对象，然后通过setRatio来设定图片的比例，如下：\n**[html]** [view plain](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[copy](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/643475)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/643475/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.imageviewdemo.SmartImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scaleType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fitXY\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/siv\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/recommend_39\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;描述文字信息\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;.\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; **[java]** [view plain](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[copy](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/643475)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/643475/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.imageviewdemo; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 拿到SmartImageView对象\u0026lt;/span\u0026gt; - SmartImageView siv = (SmartImageView) findViewById(R.id.siv); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置ratio的值\u0026lt;/span\u0026gt; - siv.setRatio(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;.43f); - } - } 经过上面之后，我们会发现，不论在什么屏幕下，不论在横屏还是竖屏，都能以正确的比例显示图片了，\n效果图：\n240*320/2.7寸设备 nexus7 1200*1920设备\nandroidTV(1920*1080)横屏显示设备\n最后再留一个小地方，就是要显示图片的ratio，这个可以有多种方式，一种是从服务器传过来时，服务器指定了，那么我们可以直接拿到，然后设置好即可；然后是自己通过测量BitMap的宽高来确定比例，也是可以的。\n设置ratio的方式可以像上面的调用setRatio()方法，也可以使用自定义属性，在XML文件中直接确定，关于自定义属性，由于不是文本重点，不了解的同学可以去看看专栏的这篇文章：Android自定义控件系列四：自定义开关按钮（三）— 自定义属性，就会明白了。\n之后会带来自定义View的另一个方法:onLayout方法的研究，敬请期待，谢谢！\n","permalink":"https://blog.zdltech.com/posts/%E5%88%A9%E7%94%A8onmeasure%E6%B5%8B%E9%87%8F%E6%9D%A5%E5%AE%9E%E7%8E%B0%E5%9B%BE%E7%89%87%E6%8B%89%E4%BC%B8%E6%B0%B8%E4%B8%8D%E5%8F%98%E5%BD%A2%E8%A7%A3%E5%86%B3%E5%B1%8F%E5%B9%95%E9%80%82/","summary":"\u003ch1 id=\"使用imageview会遇到的问题\"\u003e使用ImageView会遇到的问题\u003c/h1\u003e\n\u003cp\u003e\u003cstrong\u003e转载请注明出处：\u003ca href=\"http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329\"\u003ehttp://blog.csdn.net/cyp331203/article/details/45038329\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在Android应用中，都少不了图片的显示，ImageView，轮播图，ViewPager等等，很多都是来显示图片的，比如一个广告条的轮播效果，参看博客：\u003ca href=\"http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/40707339\"\u003e广告条效果实现—-ViewPager加载大图片(LruCache)以及定时刷新\u003c/a\u003e，很多时候，我们都希望图片能够在宽度上填充父窗体，这样比较符合人的审美观点，但是问题就随之而来了，那就是高度如何定义？？先来看一个普通的ImageView的 Xml布局文件的定义：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n\u003cpre\u003e\u003ccode\u003e    **[html]** [view plain](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[copy](http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/cyp331203/article/details/45038329)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/643475)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/643475/fork)\n  \n\n  \n  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/recommend_39\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;描述文字信息\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;\u0026amp;#8230;.\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e为了方便查看，我在ImageView下面又加上了一句描述的信息的TextView，这时，父控件都是填充父窗体，而ImageView则是：横向填充父窗体，纵向包裹内容；text都是包裹内容；那么来看看显示效果：\u003c/p\u003e","title":"利用onMeasure测量来实现图片拉伸永不变形，解决屏幕适配问题"},{"content":"欢做些开源项目的朋友，相信有不少人都希望能把自己的项目发布到公共的中央仓库，如maven中央仓库，以供别人方便地集成使用。而使用了Android Studio的同学，应该也对gradle和jcenter印象深刻，不少开源库都是发布到这里的。这一篇就主要来介绍一下，如何使用Gradle发布到jcenter。\n转载：http://blog.csdn.net/maosidiaoxian/article/details/43148643\n注册 先到https://bintray.com注册一个账号。 配置账号 我们需要配置一下BINTRAY_USER及BINTRAY_KEY两个属性。BINTRAY_USER即你注册的账号名，BINTRAY_KEY可通过以下方法找到。 如图所示，先点击你的账号名称进入个人页面。 ![](http://img.blog.csdn.net/20150126092456203?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvc2lkaWFveGlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 然后点击Edit，进入编辑页面。 ![](http://img.blog.csdn.net/20150126092541646?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvc2lkaWFveGlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 接着点击API key，再点右边的Show就可以看到API KEY了。 ![](http://img.blog.csdn.net/20150126092533531?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvc2lkaWFveGlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 然后到你的.gradle目录下（如果你没有配置过GRADLE_USER_HOME的环境变量，则是在你的用户目录下），编辑gradle.properties（如果没有则创建），加入配置： **[plain]** [view plain](http://blog.csdn.net/maosidiaoxian/article/details/43148643#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/maosidiaoxian/article/details/43148643#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/589055)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/589055/fork)\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - BINTRAY_USER=xxx - BINTRAY_KEY=xxx 配置项目 下载我的这个项目：https://github.com/msdx/gradle-publish，把gradle.properties拷贝到你的项目中，并配置这些属性。 然后参考这里的build.gradle，在你的build.gradle上面加入： **[java]** [view plain](http://blog.csdn.net/maosidiaoxian/article/details/43148643#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/maosidiaoxian/article/details/43148643#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/589055)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/589055/fork)\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - buildscript { - repositories { - jcenter() - } - dependencies { - classpath \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0\u0026amp;#8217;\u0026lt;/span\u0026gt; - } - } 再加上一句： **[java]** [view plain](http://blog.csdn.net/maosidiaoxian/article/details/43148643#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/maosidiaoxian/article/details/43148643#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/589055)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/589055/fork)\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - apply from: \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;你的bintray.gradle的相对路径\u0026amp;#8217;\u0026lt;/span\u0026gt; 你的bintray.gradle可以参考我这个项目的bintray.gradle 来写一下。我这里的bintray.gradle是用来发布android项目的，发布的文件包括源码，文档以及AAR，如果你也是要发布这些，则可以直接使用。 执行命令进行发布 配置完成后，执行gradle bintray，即会进行编译、打包以及发布。 包含到jcenter中央库 先进入此页面：https://bintray.com/bintray/jcenter。 然后点击Include My Package，如下图： ![](http://img.blog.csdn.net/20150202091406259?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvc2lkaWFveGlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 然后在弹出的对话框中搜索并勾上你的项目。 ![](http://img.blog.csdn.net/20150202091431609?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvc2lkaWFveGlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 然后你可以写一下你的提交请求（貌似也可以不写？），点“Send”，接下来就看管理员审核了。 ![](http://img.blog.csdn.net/20150202091438535?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvc2lkaWFveGlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 审核 等待管理员审核。通常都很快能通过。如果你比较心急，那么在审核通过之前，可以以maven {url http://dl.bintray.com/你的用户名/maven}的方式对你的仓库进行声明。 ## 补充说明 如果添加上这段脚本之后，在android studio中运行项目会出错，请注释apply from那一句。出错原因在于它会找不到我打包aar的那个任务，但是在命令行下是可以的。如果有更好的打包aar的方法，欢迎交流。 ","permalink":"https://blog.zdltech.com/posts/%E4%BD%BF%E7%94%A8gradle%E5%8F%91%E5%B8%83android%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E5%88%B0jcenter/","summary":"\u003cp\u003e欢做些开源项目的朋友，相信有不少人都希望能把自己的项目发布到公共的中央仓库，如maven中央仓库，以供别人方便地集成使用。而使用了Android Studio的同学，应该也对gradle和jcenter印象深刻，不少开源库都是发布到这里的。这一篇就主要来介绍一下，如何使用Gradle发布到jcenter。\u003c/p\u003e\n\u003cp\u003e转载：http://blog.csdn.net/maosidiaoxian/article/details/43148643\u003c/p\u003e\n\u003ch2 id=\"注册\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003e注册\u003c/h2\u003e\n\u003cdiv\u003e\n  先到https://bintray.com注册一个账号。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch2 id=\"配置账号\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e配置账号\u003c/h2\u003e\n\u003cdiv\u003e\n  我们需要配置一下BINTRAY_USER及BINTRAY_KEY两个属性。BINTRAY_USER即你注册的账号名，BINTRAY_KEY可通过以下方法找到。\n\u003c/div\u003e\n\u003cdiv\u003e\n  如图所示，先点击你的账号名称进入个人页面。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20150126092456203?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvc2lkaWFveGlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  然后点击Edit，进入编辑页面。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20150126092541646?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvc2lkaWFveGlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  接着点击API key，再点右边的Show就可以看到API KEY了。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20150126092533531?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvc2lkaWFveGlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n  然后到你的.gradle目录下（如果你没有配置过GRADLE_USER_HOME的环境变量，则是在你的用户目录下），编辑gradle.properties（如果没有则创建），加入配置：\n  \u003cdiv class=\"dp-highlighter bg_plain\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\"\u003e\n\u003cpre\u003e\u003ccode\u003e      **[plain]** [view plain](http://blog.csdn.net/maosidiaoxian/article/details/43148643#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/maosidiaoxian/article/details/43148643#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n    \n\n    \n    \u0026lt;div\u0026gt;\n      \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n      \u0026lt;/embed\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \n\n      \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/589055)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/589055/fork)\u0026lt;/span\u0026gt;\n    \n\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - BINTRAY_USER=xxx\n  \n  - BINTRAY_KEY=xxx\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003ch2 id=\"配置项目\"\u003e\u003ca name=\"t2\"\u003e\u003c/a\u003e配置项目\u003c/h2\u003e\n\u003cdiv\u003e\n  下载我的这个项目：https://github.com/msdx/gradle-publish，把gradle.properties拷贝到你的项目中，并配置这些属性。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  然后参考这里的build.gradle，在你的build.gradle上面加入：\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\"\u003e\n\u003cpre\u003e\u003ccode\u003e      **[java]** [view plain](http://blog.csdn.net/maosidiaoxian/article/details/43148643#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/maosidiaoxian/article/details/43148643#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n    \n\n    \n    \u0026lt;div\u0026gt;\n      \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n      \u0026lt;/embed\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \n\n      \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/589055)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/589055/fork)\u0026lt;/span\u0026gt;\n    \n\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - buildscript {\n  \n  - repositories {\n  \n  - jcenter()\n  \n  - }\n  \n  - dependencies {\n  \n  - classpath \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0\u0026amp;#8217;\u0026lt;/span\u0026gt;\n  \n  - }\n  \n  - }\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e再加上一句：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\"\u003e\n\u003cpre\u003e\u003ccode\u003e      **[java]** [view plain](http://blog.csdn.net/maosidiaoxian/article/details/43148643#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/maosidiaoxian/article/details/43148643#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n    \n\n    \n    \u0026lt;div\u0026gt;\n      \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt;\n      \u0026lt;/embed\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \n\n      \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/589055)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/589055/fork)\u0026lt;/span\u0026gt;\n    \n\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - apply from: \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;你的bintray.gradle的相对路径\u0026amp;#8217;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  你的bintray.gradle可以参考我这个项目的bintray.gradle 来写一下。我这里的bintray.gradle是用来发布android项目的，发布的文件包括源码，文档以及AAR，如果你也是要发布这些，则可以直接使用。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch2 id=\"执行命令进行发布\"\u003e\u003ca name=\"t3\"\u003e\u003c/a\u003e执行命令进行发布\u003c/h2\u003e\n\u003cdiv\u003e\n  配置完成后，执行gradle bintray，即会进行编译、打包以及发布。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch2 id=\"包含到jcenter中央库\"\u003e\u003ca name=\"t4\"\u003e\u003c/a\u003e包含到jcenter中央库\u003c/h2\u003e\n\u003cdiv\u003e\n  先进入此页面：https://bintray.com/bintray/jcenter。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  然后点击Include My Package，如下图：\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20150202091406259?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvc2lkaWFveGlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n  然后在弹出的对话框中搜索并勾上你的项目。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20150202091431609?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvc2lkaWFveGlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  然后你可以写一下你的提交请求（貌似也可以不写？），点“Send”，接下来就看管理员审核了。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20150202091438535?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvc2lkaWFveGlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003ch2 id=\"审核\"\u003e\u003ca name=\"t5\"\u003e\u003c/a\u003e审核\u003c/h2\u003e\n\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e等待管理员审核。通常都很快能通过。如果你比较心急，那么在审核通过之前，可以以maven {url http://dl.bintray.com/你的用户名/maven}的方式对你的仓库进行声明。\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"titlebar-details\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  ## 补充说明\n  \u003cdiv\u003e\n    如果添加上这段脚本之后，在android studio中运行项目会出错，请注释apply from那一句。出错原因在于它会找不到我打包aar的那个任务，但是在命令行下是可以的。如果有更好的打包aar的方法，欢迎交流。\n  \u003c/div\u003e\n\u003c/div\u003e","title":"使用Gradle发布Android开源项目到JCenter"},{"content":" ======================================================== 作者：qiujuer 博客：blog.csdn.net/qiujuer 网站：www.qiujuer.net 开源库：github.com/qiujuer/Genius-Android 转载请注明出处：http://blog.csdn.net/qiujuer/article/details/44195131 ——学之开源，用于开源；初学者的心态，与君共勉！\n======================================================== 有一个好的库想与世界的伙伴分享，于是共享到GitHub上，于是有人看到了，但是要使用却发现配置非常难。但是发现别人的库只需要一行代码却能使用；于是我想知道为什么能这么简单。 在这篇文章中将带你了解如何发布你的库到远程仓库Maven中，又如何使用。\n# \u0026lt;a name=\u0026quot;t0\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;准备 开始之前我们有一定的准备工作，如果准备好了那么后面将会非常顺畅。 - [注册 https://issues.sonatype.org 账户](http://blog.csdn.net/qiujuer/article/details/44195199)，并创建你的 Group Id - 学会GPGTools的使用，并生成你的密钥对；见：[使用GPG对文件进行签名加密](http://blog.csdn.net/qiujuer/article/details/44173611) - 编写你的库，并准备好发布，工具：[Android-Studio](http://blog.csdn.net/qiujuer/article/details/41843095) - 添加发布Maven的Gradle文件 - 添加你的个人信息，如你的发布地址、库版本信息等 - 开发发布快照、以及正式版本，审核 # \u0026lt;a name=\u0026quot;t1\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;开始 前面的两项工作由于篇幅较大，单独开篇了，欢迎大家去看~~，我们从第三的地方开始。 ## \u0026lt;a name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;编写Lib 编写库，这里我采用的是Android-Studio；至于其使用建立过程以及简单使用大家可见：[环境配置之正式版Android Studio 1.0](http://blog.csdn.net/qiujuer/article/details/41843095) 在这里我使用 [Genius-Android](https://github.com/qiujuer/Genius-Android) 开源库进行演示。 在本次项目中我们尝试发布 UI 部分，图中圈起来部分为我们需要的文件。\n## \u0026lt;a name=\u0026quot;t3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;编写发布文件 发布文件就是其中的 **maven_push.gradle** 。由于代码较长就不贴代码了，大家可以去GitHub上查看。 代码已经发布到 BeFoot 开源项目中. 该代码运行在 Gradle 中，作用是按照配置进行打包代码文件，然后签名文件，最后发布你的文件到仓库。\n在该代码中可以看见许多的方法与参数，如： ``` def isReleaseBuild() { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; VERSION_NAME.contains(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;SNAPSHOT\u0026quot;\u0026amp;lt;/span\u0026gt;) == \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt; }\n- 1 - 2 - 3 这个方法的作用是判断版本名称是否含有 **“SNAPSHOT”**字段，也就是判断当前是否发布的是快照版本，以便传输到不同的服务器地址。 但是其中的 **“VERSION_NAME”** 哪里来的呢？往下看~~ ## \u0026lt;a name=\u0026#34;t4\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;gradle.properties 在 **“maven_push”** 文件中所有的字段都是访问的你的 **“gradle.properties”** 文件。 ![这里写图片描述](http://img.blog.csdn.net/20150311174414025) 可以看见我们的项目中有两个这样的文件，两个文件中的内容都可以全部写到一个文件中。之所以写出两个，下面那个代表的是本项目中的全局变量，至于 UILib 中的那个则只局限于 UILib 中使用。 现在我们分别打开看看，首先打开下面那个全局的文件。 ![这里写图片描述](http://img.blog.csdn.net/20150311174954526) 在这里我们需要更改的地方有如下几个地方： ![这里写图片描述](http://img.blog.csdn.net/20150311182302469) 再来看看库中的文件： ![这里写图片描述](http://img.blog.csdn.net/20150311175830185) ** 这里相对简单的多了，无非就是名称，ID，类型，版本等信息。 有必要说明的是，上面的\u0026lt;strong\u0026gt;POM_GROUP_ID+POM_ARTIFACT_ID+VERSION_NAME** 将会得到如下的使用方式： \u0026lt;/blockquote\u0026gt; ``` `dependencies \u0026amp;lt;span class=\u0026#34;hljs-cell\u0026#34;\u0026gt;{ compile \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;com.github.qiujuer:genius-ui:3.0.0-SNAPSHOT\u0026#39;\u0026amp;lt;/span\u0026gt; }\u0026amp;lt;/span\u0026gt;` - 1 - 2 - 3 完了？没~还有一个至关重要的地方，在”Maven_Push”的代码中我们会找到： 以及其中的 signing 部分，但是你会发现你找遍了上面的所有的文件都没有发现这些字段，那么这些字段在哪里呢？\n很简单，在[Android-Studio 缓存文件夹配置](http://blog.csdn.net/qiujuer/article/details/44160127) 中有讲解**“.gradle”**目录对吧？那么现在我们去看看 这个目录中有什么。 可以看见其中也有一个 “gradle.properties”文件，这个文件不在项目中，但是在项目中却可以访问，这是一个全局的文件，任何项目都可以访问该文件，如果你没有，那么可以自己创建一个就OK。\n** 为什么要存储到这里？我们都知道项目中的 \u0026lt;strong\u0026gt;“gradle.properties”** 文件一般来说都是会提交到 Git 上面去的，所以项目中的文件不应该包含私密的东西，比如密钥对，密钥密码，以及你的 Maven 的账户信息。 \u0026lt;/blockquote\u0026gt; 打开该文件我们能看见： - 密钥的相关东西请见：[使用GPG对文件进行签名加密](http://blog.csdn.net/qiujuer/article/details/44173611) - Sonatype 用户名密码详见：[注册 Maven 仓库 sonatype.org 账户](http://blog.csdn.net/qiujuer/article/details/44195199) ## \u0026lt;a name=\u0026quot;t5\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;build.gradle 现在还需要修改你的项目中的 build 文件，需要更改的地方如下： ``` android { \u0026amp;lt;span class=\u0026quot;hljs-built_in\u0026quot;\u0026gt;source\u0026amp;lt;/span\u0026gt;Sets { main { manifest.srcFile \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'src/main/AndroidManifest.xml'\u0026amp;lt;/span\u0026gt; java.srcDirs = [\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'src/main/java'\u0026amp;lt;/span\u0026gt;] res.srcDirs = [\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'src/main/res'\u0026amp;lt;/span\u0026gt;] } } lintOptions { abortOnError \u0026amp;lt;span class=\u0026quot;hljs-literal\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt; } } apply from: \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'https://raw.github.com/qiujuer/BeFoot/master/blog/gradle-mvn-push/gradle-mvn-push.gradle'\u0026amp;lt;/span\u0026gt;\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 # \u0026lt;a name=\u0026#34;t6\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;发布 如果你上面的都做到了，那么现在进入发布的地段了~~ ## \u0026lt;a name=\u0026#34;t7\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;执行发布命令 Android-Studio进入项目中，打开**“Terminal”**窗口，进入你的项目中，执行命令： ``` `\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;$ \u0026amp;lt;/span\u0026gt;gradle clean build uploadArchives` - 1 ![这里写图片描述](http://img.blog.csdn.net/20150311213106249) 第一次操作的时候将会下载一大堆的依赖。 最后出现成功提示则OK。 ## \u0026lt;a name=\u0026quot;t8\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;检查快照版本 在这里我们进入：[https://oss.sonatype.org/content/groups/public/](https://oss.sonatype.org/content/groups/public/) 找到你的项目地址，我本次的是： https://oss.sonatype.org/content/groups/public/com/github/qiujuer/genius-ui/3.0.0-SNAPSHOT/ 可以看出其中有着原始文件以及签名等验证文件。 如果你的没有**“asc”文件，那么发布“Release”**版本时将无法通过审核。\n**也不是说快照版本就无法使用，同样可以，其使用方式为：** ``` dependencies { repositories { maven { url \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;https://oss.sonatype.org/content/repositories/snapshots/\u0026quot;\u0026amp;lt;/span\u0026gt; } } compile \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'com.github.qiujuer:genius-ui:3.0.0-SNAPSHOT'\u0026amp;lt;/span\u0026gt; }\n- 1 - 2 - 3 - 4 - 5 - 6 **如果发布了过个快照版本，那么就为：** ``` `compile \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;com.github.qiujuer:genius-ui:3.0.0-SNAPSHOT-2\u0026#39;\u0026amp;lt;/span\u0026gt; ` - 1 ## \u0026lt;a name=\u0026quot;t9\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;发布“Release” 该发布方法操作命令行的方式与快照版本一样，完全一样；只需要更改你的库中的：**gradle.properties** 文件中的 **VERSION_NAME** ，删除掉后面的 **“”-SNAPSHOT”“** 就OK。 之后执行命令行命令；然后你会发现你在： https://oss.sonatype.org/content/groups/public/ 中无法找到你发布的 “Release”版本；这是正常的；如果现在找到了反而不正常。\n## \u0026lt;a name=\u0026quot;t10\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;操作仓库发布 要完成“Release”版本的发布还需要登陆到后台中进行一些简单的操作。 网站：https://oss.sonatype.org/ 登陆：用户名与密码与https://issues.sonatype.org/中的完全一样。 登陆成功后点击左边导航中的：“Staging Repositories” 在其中根据你的GroupId去找你对应的一行。比如我的Id：“com.github.qiujuer”那么就是： 找到后点击他，如果不是你的或者你没有找到那么看看是不是你上面根本就没有上传成功。 选中后点击上面的**“Close”**按钮，填写描述信息；然后等待一段时间；在这个过程中你可以点击刷新按钮。 在下面可以看见发送了邮件提醒，然后上面的 “Release” 按钮可以点击了，此时点击该按钮，填写描述信息，不必太多。然后等待；当下面同样出现发送了邮件提醒的时候那么恭喜你发布成功了。\n** 如果在上面你上传的文件中没有签名文件那么将无法操作成功；此时你应该重新上传有签名的版本。 \u0026lt;/blockquote\u0026gt; 发布成功后你的使用方式为（你并不能立即就能使用，一般需要10分钟及其以上的时间）： ``` dependencies \u0026amp;lt;span class=\u0026quot;hljs-cell\u0026quot;\u0026gt;{ compile \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'com.github.qiujuer:genius-ui:3.0.0'\u0026amp;lt;/span\u0026gt; }\u0026amp;lt;/span\u0026gt;\n- 1 - 2 - 3 # \u0026lt;a name=\u0026#34;t11\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;附件 本次操作中需要的文件我都上传到 [GitHub](https://github.com/qiujuer/BeFoot) 上了。 地址：[https://github.com/qiujuer/BeFoot/tree/master/blog/gradle-mvn-push](https://github.com/qiujuer/BeFoot/tree/master/blog/gradle-mvn-push) # \u0026lt;a name=\u0026#34;t12\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;一些问题 该地方，暂时就不写了，太长了~~ 说一个简单的吧：如果执行发布命令时出现：\u0026lt;strong\u0026gt;401** 错误，代表你的账户登录失败，也就是你的账户名或者密码错误。 其他问题，大家如果遇到了可以提出来我会一一回答的。 ==============追加=============== ## \u0026lt;a name=\u0026#34;t13\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;仓库唯一 发布项目到Maven 仓库 ，必须要使用sonatype.org么？sonatype.org是一个载体？还有其他选择？ 答案是：有其他的选择~ 如果 Gradle 没有内置你的仓库地址你也可以指定，甚至可以使用自己部署的服务器来发布。比如： ![这里写图片描述](http://img.blog.csdn.net/20150312100018050) 这个就是发布到 快照 仓库，但是快照仓库地址 Gradle 并不知道，所以需要指定。 # \u0026lt;a name=\u0026#34;t14\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;一些题外话 说实话这篇文章，很早以前就想写了；但是大概想了一下感觉篇幅会比较大，所以一直没有写。 这次也是有朋友在问这方面的情况，所以就花了几天时间写了，真的是花了几天时间，不是空闲时间。也许你们看只需要10分钟，或许10分钟都要不到，可我却花了你的100倍甚至更多的时候来写的。 由于是使用的 MarkDown 编辑器（出现BUG意外死掉的情况少）写的，所以没有像以前一样加上高亮等操作，不是不加，而是编辑器还不支持。 ======================================================== 作者：qiujuer 博客：[blog.csdn.net/qiujuer](http://blog.csdn.net/qiujuer) 网站：[www.qiujuer.net](http://www.qiujuer.net/) 开源库：[github.com/qiujuer/Genius-Android](https://github.com/qiujuer/Genius-Android) 转载请注明出处：[http://blog.csdn.net/qiujuer/article/details/44195131](http://blog.csdn.net/qiujuer/article/details/44195131) ——学之开源，用于开源；初学者的心态，与君共勉！ ======================================================== \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;bdsharebuttonbox tracking-ad bdshare-button-style0-16\u0026#34; data-mod=\u0026#34;popu_172\u0026#34; data-bd-bind=\u0026#34;1458097570578\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026#34;digg\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/publish-aar-to-maven-%E4%BD%BF%E7%94%A8-gradle-%E5%8F%91%E5%B8%83-aar-%E5%88%B0-maven-%E4%BB%93%E5%BA%93/","summary":"\u003cdiv id=\"article_content\" class=\"article_content\"\u003e\n  \u003cdiv class=\"markdown_views\"\u003e\n\u003cpre\u003e\u003ccode\u003e  ========================================================\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e作者：qiujuer\n博客：\u003ca href=\"http://blog.csdn.net/qiujuer\"\u003eblog.csdn.net/qiujuer\u003c/a\u003e\n网站：\u003ca href=\"http://www.qiujuer.net/\"\u003ewww.qiujuer.net\u003c/a\u003e\n开源库：\u003ca href=\"https://github.com/qiujuer/Genius-Android\"\u003egithub.com/qiujuer/Genius-Android\u003c/a\u003e\n转载请注明出处：\u003ca href=\"http://blog.csdn.net/qiujuer/article/details/44195131\"\u003ehttp://blog.csdn.net/qiujuer/article/details/44195131\u003c/a\u003e\n——学之开源，用于开源；初学者的心态，与君共勉！\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  ========================================================\n\n\n\n\n\n  有一个好的库想与世界的伙伴分享，于是共享到GitHub上，于是有人看到了，但是要使用却发现配置非常难。但是发现别人的库只需要一行代码却能使用；于是我想知道为什么能这么简单。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在这篇文章中将带你了解如何发布你的库到远程仓库Maven中，又如何使用。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e# \u0026lt;a name=\u0026quot;t0\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;准备\n\n\n\n  开始之前我们有一定的准备工作，如果准备好了那么后面将会非常顺畅。\n\n\n\n\n  - [注册 https://issues.sonatype.org 账户](http://blog.csdn.net/qiujuer/article/details/44195199)，并创建你的 Group Id\n  \n  - 学会GPGTools的使用，并生成你的密钥对；见：[使用GPG对文件进行签名加密](http://blog.csdn.net/qiujuer/article/details/44173611)\n  \n  - 编写你的库，并准备好发布，工具：[Android-Studio](http://blog.csdn.net/qiujuer/article/details/41843095)\n  \n  - 添加发布Maven的Gradle文件\n  \n  - 添加你的个人信息，如你的发布地址、库版本信息等\n  \n  - 开发发布快照、以及正式版本，审核\n  \n\n\n# \u0026lt;a name=\u0026quot;t1\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;开始\n\n\n\n  前面的两项工作由于篇幅较大，单独开篇了，欢迎大家去看~~，我们从第三的地方开始。\n\n\n\n## \u0026lt;a name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;编写Lib\n\n\n\n  编写库，这里我采用的是Android-Studio；至于其使用建立过程以及简单使用大家可见：[环境配置之正式版Android Studio 1.0](http://blog.csdn.net/qiujuer/article/details/41843095)\n\n\n\n\n\n  在这里我使用 [Genius-Android](https://github.com/qiujuer/Genius-Android) 开源库进行演示。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20150311171742276\"\u003e\n在本次项目中我们尝试发布 UI 部分，图中圈起来部分为我们需要的文件。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e## \u0026lt;a name=\u0026quot;t3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;编写发布文件\n\n\n\n  发布文件就是其中的 **maven_push.gradle** 。由于代码较长就不贴代码了，大家可以去GitHub上查看。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20150311211325120\"\u003e\n代码已经发布到 \u003ca href=\"https://github.com/qiujuer/BeFoot\"\u003eBeFoot\u003c/a\u003e 开源项目中.\n该代码运行在 Gradle 中，作用是按照配置进行打包代码文件，然后签名文件，最后发布你的文件到仓库。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  在该代码中可以看见许多的方法与参数，如：\n\n\n\n```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003edef isReleaseBuild() { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; VERSION_NAME.contains(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;SNAPSHOT\u0026quot;\u0026amp;lt;/span\u0026gt;) == \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt; }\u003c/code\u003e\u003c/p\u003e","title":"[Publish AAR To Maven] 使用 Gradle 发布 AAR 到 Maven 仓库"},{"content":"编辑推荐：稀土掘金，这是一个针对技术开发者的一个应用，你可以在掘金上获取最新最优质的技术干货，不仅仅是Android知识、前端、后端以至于产品和设计都有涉猎，想成为全栈工程师的朋友不要错过！\n原文：使用Gradle发布项目到JCenter仓库\n这篇文章介绍通过Gradle把开源项目发布到公共仓库JCenter中，方便你我他的事情，我们都是很懒的嘛。JCenter现在是Android Studio中repositories的默认节点了，之前是Maven的，不过JCenter是兼容Maven的，所以放心使用。步骤基本是按Publishing Gradle Android Library to jCenter Repository这里来的，英文能看的直接看这篇也行。下面我的步骤正式开始，发布到JCenter仓库的是我的项目：BounceProgressBar。\n申请Bintray账号 Bintray的基本功能类似于Maven Central，一样的我们需要一个账号，Bintray传送门，注册完成后第一步算完成了。\n生成项目的JavaDoc和source JARs 简单的说生成的这两样东西就是我们在下一步中上传到远程仓库JCenter上的文件了。这一步需要android-maven-plugin插件，所以我们需要在项目的build.gradle（Top-level build file，项目最外层的build.gradle文件）中添加这个构建依赖，如下：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `buildscript {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``repositories {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``jcenter()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``classpath ``'com.android.tools.build:gradle:1.0.0'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``classpath ``'com.github.dcendents:android-maven-plugin:1.2'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``// NOTE: Do not place your application dependencies here; they belong` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``// in the individual module build.gradle files` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; `allprojects {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``repositories {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``jcenter()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 然后在你需要发布的那个module（我这里的即是library）的build.gradle里配置如下内容：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; 51 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; 52 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; 53 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; 54 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; 55 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; 56 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; 57 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; 58 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; 59 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; 60 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; 61 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; 62 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; 63 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; 64 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; 65 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; 66 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; 67 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; 68 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; 69 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; 70 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; 71 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; 72 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; 73 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; 74 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; 75 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; 76 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; 77 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; 78 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; 79 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; 80 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; 81 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; 82 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; 83 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; 84 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; 85 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; 86 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; 87 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; 88 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; 89 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; 90 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; 91 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt; 92 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `apply plugin: ``'com.android.library'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `apply plugin: ``'com.github.dcendents.android-maven'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `apply plugin: ``'com.jfrog.bintray'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `// This is the library version used when deploying the artifact` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `version = ``\u0026quot;1.0.0\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `android {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``compileSdkVersion 21` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``buildToolsVersion ``\u0026quot;21.1.2\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``resourcePrefix ``\u0026quot;bounceprogressbar__\u0026quot;` `//这个随便填` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``defaultConfig {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``minSdkVersion 9` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``targetSdkVersion 21` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``versionCode 1` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``versionName version` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``buildTypes {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``release {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``minifyEnabled ``false` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``proguardFiles getDefaultProguardFile(``'proguard-android.txt'``), ``'proguard-rules.pro'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; `dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``compile fileTree(dir: ``'libs'``, include: [``'*.jar'``])` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``compile ``'com.nineoldandroids:library:2.4.0+'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; `def siteUrl = ``'\u0026amp;lt;a href=\u0026quot;https://github.com/zhengxiaopeng/BounceProgressBar\u0026quot;\u0026gt;https://github.com/zhengxiaopeng/BounceProgressBar\u0026amp;lt;/a\u0026gt;'` `// 项目的主页` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; `def gitUrl = ``'\u0026amp;lt;a href=\u0026quot;https://github.com/zhengxiaopeng/BounceProgressBar.git\u0026quot;\u0026gt;https://github.com/zhengxiaopeng/BounceProgressBar.git\u0026amp;lt;/a\u0026gt;'` `// Git仓库的url` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; `group = ``\u0026quot;org.rocko.bpb\u0026quot;` `// Maven Group ID for the artifact，一般填你唯一的包名` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; `install {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``repositories.mavenInstaller {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ``// This generates POM.xml with proper parameters` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ``pom {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ``project {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``packaging ``'aar'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; ` ``// Add your description here` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; ` ``name ``'Android BounceProgressBar Widget'` `//项目描述` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; ` ``url siteUrl` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; ` ``// Set your license` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; ` ``licenses {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; ` ``license {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; ` ``name ``'The Apache Software License, Version 2.0'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; ` ``url ``'\u0026amp;lt;a href=\u0026quot;http://www.apache.org/licenses/LICENSE-2.0.txt\u0026quot;\u0026gt;http://www.apache.org/licenses/LICENSE-2.0.txt\u0026amp;lt;/a\u0026gt;'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; ` ``developers {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; ` ``developer {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; ` ``id ``'zhengxiaopeng'` `//填写的一些基本信息` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; ` ``name ``'Rocko'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; ` ``email ``'zhengxiaopeng.china@gmail.com'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; ` ``scm {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; ` ``connection gitUrl` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; ` ``developerConnection gitUrl` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; ` ``url siteUrl` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; `task sourcesJar(type: Jar) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; ` ``from android.sourceSets.main.java.srcDirs` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; ` ``classifier = ``'sources'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; `task javadoc(type: Javadoc) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; ` ``source = android.sourceSets.main.java.srcDirs` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; ` ``classpath += project.files(android.getBootClasspath().join(File.pathSeparator))` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; `task javadocJar(type: Jar, dependsOn: javadoc) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; ` ``classifier = ``'javadoc'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; ` ``from javadoc.destinationDir` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; `artifacts {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; ` ``archives javadocJar` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; ` ``archives sourcesJar` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; `Properties properties = ``new` `Properties()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; `properties.load(project.rootProject.file(``'local.properties'``).newDataInputStream())` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; `bintray {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; ` ``user = properties.getProperty(``\u0026quot;bintray.user\u0026quot;``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; ` ``key = properties.getProperty(``\u0026quot;bintray.apikey\u0026quot;``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; ` ``configurations = [``'archives'``]` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; ` ``pkg {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; ` ``repo = ``\u0026quot;maven\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; ` ``name = ``\u0026quot;BounceProgressBar\u0026quot;` `//发布到JCenter上的项目名字` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; ` ``websiteUrl = siteUrl` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; ` ``vcsUrl = gitUrl` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; ` ``licenses = [``\u0026quot;Apache-2.0\u0026quot;``]` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; ` ``publish = ``true` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 配置好上述后需要在你的项目的根目录上的local.properties文件里（一般这文件需gitignore，防止泄露账户信息）配置你的bintray账号信息，_your_user_name_为你的用户名，_your_apikey_为你的账户的apikey，可以点击进入你的账户信息里再点击Edit即有查看API Key的选项，把他复制下来。\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `bintray.user=your_user_name` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `bintray.apikey=your_apikey` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; Rebuild一下项目，顺利的话，就可以在module里的build文件夹里生成相关文件了。这一步为止，就可以把你项目生成到本地的仓库中了，Android Studio中默认即在Android\\sdk\\extras\\android\\m2repository这里，所以我们可以通过如下命令(Windows中，可能还需要下载一遍Gradle，之后就不需要了)执行生成:\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `gradlew install` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 上传到Bintray 上传到Bintray需要gradle-bintray-plugin的支持，所以在最外层的build.gradle里添加构建依赖：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `buildscript {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``repositories {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``jcenter()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``classpath ``'com.android.tools.build:gradle:1.0.0'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``classpath ``'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``classpath ``'com.github.dcendents:android-maven-plugin:1.2'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``// NOTE: Do not place your application dependencies here; they belong` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``// in the individual module build.gradle files` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; `allprojects {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``repositories {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``jcenter()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; Rebuild一下，然后执行如下命令(Windows中)完成上传：\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `gradlew bintrayUpload` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 上传完成即可在Bintray网站上找到你的Repo，我们需要完成最后一步工作，申请你的Repo添加到JCenter。可以进入这个页面,输入你的项目名字点击匹配到的项目，然后写一写Comments再send即可，然后就等管理员批准了，我是大概等了40分钟，然后网站上会给你一条通过信息，然后就OK了，大功告成。\n成功后就可以在其它项目里方便的使用你发布的项目了：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``compile ``'org.rocko.bpb:library:1.0.0'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; End ","permalink":"https://blog.zdltech.com/posts/%E4%BD%BF%E7%94%A8gradle%E5%8F%91%E5%B8%83%E9%A1%B9%E7%9B%AE%E5%88%B0jcenter%E4%BB%93%E5%BA%93/","summary":"\u003cp\u003e\u003cstrong\u003e编辑推荐：\u003c/strong\u003e\u003ca href=\"http://gold.xitu.io/\"\u003e稀土掘金\u003c/a\u003e，这是一个针对技术开发者的一个应用，你可以在掘金上获取最新最优质的技术干货，不仅仅是Android知识、前端、后端以至于产品和设计都有涉猎，想成为全栈工程师的朋友不要错过！\u003c/p\u003e\n\u003cp\u003e原文：\u003ca href=\"http://zhengxiaopeng.com/2015/02/02/%E4%BD%BF%E7%94%A8Gradle%E5%8F%91%E5%B8%83%E9%A1%B9%E7%9B%AE%E5%88%B0JCenter%E4%BB%93%E5%BA%93/\"\u003e使用Gradle发布项目到JCenter仓库\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这篇文章介绍通过Gradle把开源项目发布到公共仓库JCenter中，方便你我他的事情，我们都是很懒的嘛。JCenter现在是Android Studio中repositories的默认节点了，之前是Maven的，不过JCenter是兼容Maven的，所以放心使用。步骤基本是按\u003ca href=\"https://www.virag.si/2015/01/publishing-gradle-android-library-to-jcenter/\"\u003ePublishing Gradle Android Library to jCenter Repository\u003c/a\u003e这里来的，英文能看的直接看这篇也行。下面我的步骤正式开始，发布到JCenter仓库的是我的项目：\u003ca href=\"https://github.com/zhengxiaopeng/BounceProgressBar\"\u003eBounceProgressBar\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"申请Bintray账号\"\u003e申请Bintray账号\u003c/h2\u003e\n\u003cp\u003eBintray的基本功能类似于Maven Central，一样的我们需要一个账号，\u003ca href=\"https://bintray.com/\"\u003eBintray传送门\u003c/a\u003e，注册完成后第一步算完成了。\u003c/p\u003e\n\u003ch2 id=\"生成项目的JavaDoc和source_JARs\"\u003e生成项目的JavaDoc和source JARs\u003c/h2\u003e\n\u003cp\u003e简单的说生成的这两样东西就是我们在下一步中上传到远程仓库JCenter上的文件了。这一步需要\u003ccode\u003eandroid-maven-plugin\u003c/code\u003e插件，所以我们需要在项目的build.gradle（Top-level build file，项目最外层的build.gradle文件）中添加这个构建依赖，如下：\u003c/p\u003e\n\u003cp\u003e\u003cins class=\"adsbygoogle\" data-ad-client=\"ca-pub-8583773779396897\" data-ad-slot=\"3029555512\" data-adsbygoogle-status=\"done\"\u003e\u003cins id=\"aswift_0_expand\"\u003e\u003cins id=\"aswift_0_anchor\"\u003e\u003c/ins\u003e\u003c/ins\u003e\u003c/ins\u003e\u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_766696\" class=\"syntaxhighlighter  js\"\u003e\n    \u003ctable border=\"0\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n      \u003ctr\u003e\n        \u003ctd class=\"gutter\"\u003e\n          \u003cdiv class=\"line number1 index0 alt2\"\u003e\n            1\n          \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        2\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n        3\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n        4\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n        5\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n        6\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n        7\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n        8\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n        9\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n        10\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n        11\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n        12\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n        13\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n        14\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n        15\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n        16\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `buildscript {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          `    ``repositories {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `        ``jcenter()`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          `    ``dependencies {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n          `        ``classpath ``'com.android.tools.build:gradle:1.0.0'`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n          `        ``classpath ``'com.github.dcendents:android-maven-plugin:1.2'`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n          `        ``// NOTE: Do not place your application dependencies here; they belong`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n          `        ``// in the individual module build.gradle files`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n          `allprojects {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n          `    ``repositories {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n          `        ``jcenter()`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e然后在你需要发布的那个module（我这里的即是library）的build.gradle里配置如下内容：\u003c/p\u003e","title":"使用Gradle发布项目到JCenter仓库"},{"content":"本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据GitHub搜索Java语言选择 (Best Match) 得到的结果, 然后过滤了跟Android不相关的项目, 所以排名并不具备任何官方效力, 仅供参考学习, 方便初学者快速了解当前一些流行的Android开源库.\niOS 版本的在此: https://github.com/Aufree/trip-to-iOS/blob/master/Top-100.md\n感谢 @GitHubDaily 的大力支持, 以及 @stormzhang 的指点\n若有任何疑问可通过邮件或微博联系我\n项目名称 \u0026lt;th\u0026gt; 项目简介 \u0026lt;/th\u0026gt; 1. [react-native](https://github.com/facebook/react-native) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 这个是 Facebook 在 React.js Conf 2015 大会上推出的基于 JavaScript 的开源框架 React Native, 该框架结合了 Web 应用和 Native 应用的优势, 可以使用 JavaScript 来开发 iOS 和 Android 原生应用 \u0026lt;/td\u0026gt; 2.[Android-Universal-Image-Loader](https://github.com/nostra13/Android-Universal-Image-Loader) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; ImageLoader 是最早开源的 Android 图片缓存库, 强大的缓存机制, 早期被广泛 Android 应用使用, 至今仍然有很多 Android 开发者在使用 \u0026lt;/td\u0026gt; 3. [RxJava](https://github.com/ReactiveX/RxJava) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; RxJava 是一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库, 简单来说它就是一个实现异步操作的库, RxJava 的优点在于一个词 \u0026amp;#8220;简洁\u0026amp;#8221;, 使用它就算你程序逻辑有多么复杂, 它依然能够保持简洁易懂 \u0026lt;/td\u0026gt; 4. [retrofit](https://github.com/square/retrofit) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Retrofit 是 Square 公司出品的 HTTP 请求库, 同时是 Square 是最早开源项目之一, Retrofit 是目前 Android 最流行的 Http Client 库之一, 目前版本是 Retrofit2.0 Beta4, 越来越多 Android 开发者开始使用这个请求库了 \u0026lt;/td\u0026gt; 5. [okhttp](https://github.com/square/okhttp) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; OkHttp 是 Square 公司出品的 HTTP 另一个请求库, Google 不推荐人们使用 HttpClient, 可是 HttpURLConnection 实在是太难用了, 因此很多人使用了 OkHttp 来解决这问题, 据说 Android4.4 的源码中可以看到 HttpURLConnection 已经替换成 OkHttp 实现呢 \u0026lt;/td\u0026gt; 6. [SlidingMenu(不建议使用)](https://github.com/jfeinstein10/SlidingMenu) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 一个侧滑菜单开源库, 在 Google 自己原生态的侧滑菜单 NavigationDrawer 没有出现之前, 这个库就已经被广泛使用, 可是到现在这个库已经被放弃了 \u0026lt;/td\u0026gt; 7. [picasso](https://github.com/square/picasso) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Picasso 是 Square 公司出品的一款图片缓存库, 主导者是 JakeWharton 大神 \u0026lt;/td\u0026gt; 8. [android-best-practices](https://github.com/futurice/android-best-practices) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Android 开发最佳实践, 里面所介绍的经验都是来自于 Futurice 公司 Android 开发者, 介绍内容有 Android 开发规范、架构、布局技巧, 以及使用一些有助于快速开发相关工具等等, 非常适合新手去学习 \u0026lt;/td\u0026gt; 9. [EventBus](https://github.com/greenrobot/EventBus) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; EventBus 是 Android 事件管理总线, 使用它可以替带 Android BroadCast, BroadCastReceiver, Handler 在 Activity, Fragment, Service, 线程之间传递消息, 大大简化了事件传递逻辑 \u0026lt;/td\u0026gt; 10. [android-async-http](https://github.com/loopj/android-async-http) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Android-Async-Http 是 Android 一款老牌异步请求库, 专门对 Android 在 Apache 的 HttpClient 基础上构建的异步 http 连接, 该库有很多特征, 例如: 库的 size 小, 支持文件上传不需使用第三方库支持, 内部使用线程池来处理并发, 等等 \u0026lt;/td\u0026gt; 11. [fresco](https://github.com/facebook/fresco) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Fresco 是 FaceBook 公司出品的一款图片缓存库, Fresco 是一个强大的图片加载组件, 支持加载 Gif 图和 WebP 格式, 支持 Android2.3(API level 9) 及其以上系统, Fresco 中设计了 Image pipeline 和 Drawees 两个模块各施其职, 使得图片完美加载出来, 想知道更多 image pipeline 和 Drawees 有关于它的特性, 可以到它[官方平台](http://fresco-cn.org/)看介绍 \u0026lt;/td\u0026gt; 12. [zxing](https://github.com/zxing/zxing) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; ZXing 是二维码领域中名气最大的开源项目, 它提供了多个平台的二维码/条形码扫描解决方案, 拥有扫描快, 识别率高, 使用简单等特点 \u0026lt;/td\u0026gt; 13. [leakcanary](https://github.com/square/leakcanary) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; LeakCanary 是 Square 公司出的一款检测内存泄露工具, 该工具能帮助你在开发阶段方便的检测出内存泄露的问题, 使用起来非常简单方便 \u0026lt;/td\u0026gt; 14. [butterknife](https://github.com/JakeWharton/butterknife) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 由 JakeWharton 大神开发出来的, ButterKnife 是 View 注入框架, 使用它为了简写很多 findViewById 代码, 同时还支持 View 的一些事件处理函数 \u0026lt;/td\u0026gt; 15. [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; MPAndroidChart 是一款强大的 Android 图表库, 支持各种各样图表显示, 能想到的图表样式这里几乎都有, 图表还支持选择, 拖放和缩放动画效果 \u0026lt;/td\u0026gt; 16.[ActionBarSherlock(不建议使用)](https://github.com/JakeWharton/ActionBarSherlock) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; ActionBarSherlock 这个库是 JakeWharton 大神开发出来支持 Android3.0 以下版本的, 后来慢慢的 Google 也提供了 AppCompat 库来支持 Android3.0 以下版本使用 ActionBar, 因此作者不建议我们再使用这个库了 \u0026lt;/td\u0026gt; 17. [androidannotations](https://github.com/excilys/androidannotations) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; AndroidAnnotations 是一个能够让你快速进行 Android 开发的开源框架, 它能让你专注于真正重要的地方, 使代码更加精简, 使项目更加容易维护, 它的目标就是 \u0026amp;#8220;Fast Android Development.Easy maintainance\u0026amp;#8221; \u0026lt;/td\u0026gt; 18. [ViewPagerIndicator](https://github.com/JakeWharton/ViewPagerIndicator) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 由 JakeWharton 大神开发出来的一个 ViewPager 指示器, 使用起来简单方便, 可高度定制, 开发出各种各样动画效果 \u0026lt;/td\u0026gt; 19. [glide](https://github.com/bumptech/glide) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Glide 是 Google 员工的开源项目, 广泛应用于 Google 一些 App 上, 在2014年 Google I/O 大会上被推荐使用, Glide 和 Picasso 被人拿来比较研究过, Glide 与 Picasso 有 90% 的相似度, 但在一些细节上还是有点区别的, 各有各优缺点看君选择 \u0026lt;/td\u0026gt; 20. [HomeMirror](https://github.com/HannahMitt/HomeMirror) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 开发者是由一名程序媛 Hannah Mittelstaedt , HomeMirror 是一款 Android 镜子应用, 目前它能实现日期, 时间, 天气, 生日信息, 事件提醒器, 骑车天气的推荐, 股票信息, XKCD 漫画网站的新帖等等 \u0026lt;/td\u0026gt; 21. [Android-PullToRefresh(不建议使用)](https://github.com/chrisbanes/Android-PullToRefresh) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 一个强大的拉动刷新开源项目，支持各种控件下拉刷新，ListView、ViewPager、WebView、ExpandableListView、GridView、ScrollView、Horizontal ScrollView、Fragment 上下左右拉动刷新, 不过现在这个项目已经停止维护更新了, 推荐使用 Android-Ultra-Pull-to-Refresh \u0026lt;/td\u0026gt; 22. [MaterialDesignLibrary](https://github.com/navasmdc/MaterialDesignLibrary) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 这个库控件都是遵循了 Google Material Design 设计规范开发出来, 例如有: Flat Button, Rectangle Button, CheckBox, Switch, Progress bar circular indeterminate 等等 \u0026lt;/td\u0026gt; 23. [PhotoView](https://github.com/chrisbanes/PhotoView) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; PhotoView 是 ImageView 的子类, 支持所有 ImageView 的源生行为, 例如: 支持 Pinch 手势自由缩放, 支持双击放大/还原, 支持平滑滚动等等, 并且非常方便的与 ImageLoader/Picasso 之类的网络图片读取库集成使用, 还方便的与 ViewPager 等同样支持滑动手势的控件集成 \u0026lt;/td\u0026gt; 24. [RxAndroid](https://github.com/ReactiveX/RxAndroid) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 由 JakeWharton 大神主导开发的项目, RxAndroid 是 RxJava 的一个针对 Android 平台的扩展, 主要用于 Android 开发 \u0026lt;/td\u0026gt; 25. [material-dialogs](https://github.com/afollestad/material-dialogs) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Material Dialogs 是一个可高度定制易用, 符合 Material Design 风格的 Dialogs, 兼容 Android API8 以上版本, 个人使用感觉它完全可替代 Android 原生那个, 比原生那个更加简单易用 \u0026lt;/td\u0026gt; 26.[Android-ObservableScrollView](https://github.com/ksoichiro/Android-ObservableScrollView) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; ObservableScrollView 是一款用于在滚动视图中观测滚动事件的 Android 库, 它能够轻而易举地与 Android 5.0 Lollipop 引进的工具栏 (Toolbar) 进行交互, 还可以帮助开发者实现拥有 Material Design 应用视觉体验的界面外观, 支持ListView, ScrollView, WebView, RecyclerView, GridView组件 \u0026lt;/td\u0026gt; 27. [Android-Bootstrap](https://github.com/Bearded-Hen/Android-Bootstrap) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Android 版的 Bootstrap, 利用这个库能够实现很多 Bootstrap 样式风格, 之前有学过 Html 的人就知道 Bootstrap 是什么玩意啦 \u0026lt;/td\u0026gt; 28. [AndroidSwipeLayout](https://github.com/daimajia/AndroidSwipeLayout) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 开发者是代码家, AndroidSwipeLayout 是一个支持ListView, GridView, ViewGroup等等左右上下滑动出操作菜单, 类似 qq 消息列表向左滑动显示出多某条信息的操作菜单 \u0026lt;/td\u0026gt; 29. [dagger](https://github.com/square/dagger) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Dagger 是 Square 公司出品的一个针对 Android 和 Java 的快速依赖注入器, 能够有效减少你敲代码量 \u0026lt;/td\u0026gt; 30. [ListViewAnimations](https://github.com/nhaarman/ListViewAnimations) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 一个轻轻松松给 Android ListView 添加动画效果的库, 支持的动画有: Alpha, SwingRightIn, SwingLeftIn, SwingBottomIn, SwingRightIn and ScaleIn等等, 使用它能很容易就实现帅爆的效果 \u0026lt;/td\u0026gt; 31. [PagerSlidingTabStrip](https://github.com/astuetz/PagerSlidingTabStrip) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; PagerSlidingTabStrip 是一个给 Android ViewPager添加上 ViewPager 滑动指示器, 从 GitHub 上面看, 这个库似乎没有人在维护了, 请谨慎使用该库 \u0026lt;/td\u0026gt; 32. [AndroidViewAnimations](https://github.com/daimajia/AndroidViewAnimations) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 开发者是代码家, 这个库实现很多很酷炫的 Android 动画, 动画效果是借鉴 Animate.css 来实现的, 非常酷, 而且这个使用起来也是非常简单 \u0026lt;/td\u0026gt; 33. [AndroidSlidingUpPanel](https://github.com/umano/AndroidSlidingUpPanel) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; AndroidSlidingUpPanel 是一个上拉面板, 就是向上滑动的时候往上飞出一个显示面板控件, 该库效果在 Google Music, Google Maps and Rdio等 App 应用到 \u0026lt;/td\u0026gt; 34. [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; MaterialDrawer 是一个类似 Google 官方 NavigationView 侧滑显示控件, 个人认为 NavigationView 并没有 MaterialDrawer 实用, 因为 NavigationView 自由度不是很好, 很多都写死了不可以自由定义布局, 而 MaterialDrawer 能够实现跟 NavigationView 一样的效果, 同时还支持自定义效果, 自由度非常高 \u0026lt;/td\u0026gt; 35. [Material-Animations](https://github.com/lgvalle/Material-Animations) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Material-Animations 是一个很好过渡动画库, 可以应用于 Activity 与 Activity 之间的跳转, Fragment 与 Fragment 之间的跳转, 以及各个 View 变化前后的过渡动画 \u0026lt;/td\u0026gt; 36. [MaterialViewPager](https://github.com/florent37/MaterialViewPager) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 一个简单易用 Material Design 风格的 ViewPager 库 \u0026lt;/td\u0026gt; 37. [ion](https://github.com/koush/ion) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; ion 是一个让 Android 的网络操作变得极其简单, 支持异步获取和处理JSON, 支持 Android 文件下载 (同时支持下载进度条绑定), 支持安全链接和代理 \u0026lt;/td\u0026gt; 38. [stetho](https://github.com/facebook/stetho) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Stetho是 Facebook 出品的一个强大的 Android 调试工具,使用该工具你可以在 Chrome Developer Tools查看App的布局, 网络请求(仅限使用Volley, okhttp的网络请求库), sqlite, preference, 一切都是可视化的操作,无须自己在去使用adb, 也不需要root你的设备 \u0026lt;/td\u0026gt; 39. [fastjson](https://github.com/alibaba/fastjson) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法，把JSON Parse的性能提升到极致，是目前Java语言中最快的JSON库。Fastjson接口简单易用，已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景 \u0026lt;/td\u0026gt; 40. [cardslib](https://github.com/gabrielemariotti/cardslib) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Cardslib 是早期由 Gabriele Mariotti 开发的一个为开发者方便实现各种 Card UI 的 Android 开源代码库, 后来 Google 官方提供自己封装了 CardView 在 v7 包下, 使用 Google 官方的可以完全替代了这个库, 因此这个也被弃用了 \u0026lt;/td\u0026gt; 41. [Android-Ultra-Pull-To-Refresh](https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 开发者是廖祜秋, 这个是一个非常强大的下拉刷新库, 继承 ViewGroup 可以包含任何 View, 功能甚至比 SwipeRefreshLayout 强大, 使用起来也非常容易, 还可以自由定制自己的 UI 样式 \u0026lt;/td\u0026gt; 42. [greenDAO](https://github.com/greenrobot/greenDAO) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; greenDAO 是一个可以帮助 Android 开发者快速将 Java 对象映射到 SQLite 数据库的表单中的 ORM解决方案, 通过使用一个简单的面向对象 API, 开发者可以对 Java 对象进行存储, 更新, 删除和查询, greenDAO 相对 OrmLite, AndrORM 这两个 ORM 开源库, 性能是最高的 \u0026lt;/td\u0026gt; 43. [AndroidStaggeredGrid](https://github.com/etsy/AndroidStaggeredGrid) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; AndroidStaggeredGrid 是一个支持多列并且每一行的 item 大小不一, 交错排列的 GridView, 就是实现瀑布流样式效果, 目前该库已经被弃用了, 开发者建议我们使用 Google 官方控件 RecyleView 中的 StaggeredGridLayoutManager 布局来实现瀑布流效果 \u0026lt;/td\u0026gt; 44. [otto](https://github.com/square/otto) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Otto 是 Square 公司出的一个事件库 (pub/sub 模式), 用来简化应用程序组件之间的通讯, otto 修改自 Google 的 Guava 库, 专门为 Android 平台进行了优化, 与上面介绍的 EventBus 相比, 两个库各有各的优点, 完全取决于我们自己项目的需求来选择它们哪一个 \u0026lt;/td\u0026gt; 45. [xUtils](https://github.com/wyouflf/xUtils) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; xUtils 是一个快速开发框架, 里面包含 DbUtils, ViewUtils, HttpUtils, BitmapUtils 四大模块, 可用于快速开发, 支持大文件上传, 拥有更加灵活的 ORM, 最低兼容 Android 2.2 \u0026lt;/td\u0026gt; 46. [realm-java](https://github.com/realm/realm-java) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Realm 一个轻量的 Android 版本的数据存储库, 比 Android 原生系统的 SQLite 更加简洁快速对数据进行操作 \u0026lt;/td\u0026gt; 47.[Android-CleanArchitecture](https://github.com/android10/Android-CleanArchitecture) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; CleanArchitecture 是一个非常典型使用 MVP 架构的项目, 大家如果还没有理解 MVP 架构的可以看看这个项目 \u0026lt;/td\u0026gt; 48. [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; StickyListHeaders 是一个实现能够固定在屏幕顶部的ListView Section Header库, 就是当前 section 的 header 固定在屏幕顶部, 当滑动到其他 section 时, 其他 section 的 header 会代替之前的 section 的 header, 固定到屏幕顶部, 类似于 Android4.0 的手机通讯录的效果 \u0026lt;/td\u0026gt; 49. [AppIntro](https://github.com/PaoloRotolo/AppIntro) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; AppIntro 是一个让人轻松快速搭建漂亮酷炫的引导页库 \u0026lt;/td\u0026gt; 50. [ActiveAndroid](https://github.com/pardom/ActiveAndroid) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; ActiveAndroid 是采用Rails中的 [Active Record](http://en.wikipedia.org/wiki/Object-relational_mapping)架构模式设计的适用于 Android 平台的轻量级 ORM 架构, 几乎可以不用写任何 SQL 代码实现快速开发 \u0026lt;/td\u0026gt; 51. [android-volley](https://github.com/mcxiaoke/android-volley) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Volley 是谷歌官方开发团队在 2013 年 Google I/O 大会推出的一个新的网络通信框架, 这个框架把 AsyncHttpClient 和 Universal-Image-Loader 的优点集于了一身,既可以像AsyncHttpClient 一样非常简单地进行 HTTP 通信,也可以像 Universal-Image-Loader 一样轻松加载网络上的图片, 这个库并不是官方的, 只是托管同步在 Maven, 官方只提供的 Jar 包 \u0026lt;/td\u0026gt; 52. [twoway-view](https://github.com/lucasr/twoway-view) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; TwoWayView 是简化 RecyclerView 开发的一个库, 可以在其 Base LayoutManager 基础上构建各种各样的布局, 该库内置了几个常用布局 List, Grid, Staggered Grid,Spannable Grid \u0026lt;/td\u0026gt; 53. [ShowcaseView](https://github.com/amlcurran/ShowcaseView) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; ShowcaseView 是一个非常适合用于对用户进行第一次使用进行指导的库,使用起来非常简单还可以自定义样式 \u0026lt;/td\u0026gt; 54. [Calligraphy](https://github.com/chrisjenx/Calligraphy) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Calligraphy 是一个用来简化 Android 应用使用自定义字体的类库, 该类库会自动查找应用中的 TextView 并设置其使用的字体 \u0026lt;/td\u0026gt; 55. [NineOldAndroids](https://github.com/JakeWharton/NineOldAndroids) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; NineOldAndroids 由 JakeWharton 大神开发的一个向下兼容的动画库, 主要是使低于API 11的系统也能够使用 View 的属性动画, 不过现在 JakeWharton 大神已经不推荐使用该库, 而是推荐我们使用官方封装在 Support 库里面的动画 \u0026lt;/td\u0026gt; 56. [android-floating-action-button](https://github.com/futuresimple/android-floating-action-button) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; FloatingActionButton 是一个悬浮操作按钮, 官方在 Support Design 包下也有封装一个类似这个库效果的 FloatingActionButton, 值得说明的是这个库是早在官方封装之前就存在的, 个人感觉这个库比官方那个更加好用 \u0026lt;/td\u0026gt; 57. [CircleImageView](https://github.com/hdodenhof/CircleImageView) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; CircleImageView 是一个轻松帮你实现圆形效果 ImageView 图片库, CircleImageView 是基于 ImageView 扩展出来, 因此它拥有 ImageView 控件所有属性, 简单易用值得你使用的库 \u0026lt;/td\u0026gt; 58. [material](https://github.com/rey5137/material) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Material 是将 Material Design 风格控件封装在该库当中, 目前封装有Progress, Button, Switch, Slider, Spinner, Text Field, TabPageIndicator, SnackBar, Dialog, BottomSheetDialog, Dynamic theme \u0026lt;/td\u0026gt; 59. [ActionBar-PullToRefresh](https://github.com/chrisbanes/ActionBar-PullToRefresh) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; ActionBar-PullToRefresh 是一个下拉刷新, 下拉刷新时在 ActionBar 出现加载中提示的库 \u0026lt;/td\u0026gt; 60. [FloatingActionButton](https://github.com/makovkastar/FloatingActionButton) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 又一个悬浮操作按钮库, 该库添加支持监听滑滚动事件, 当向下滑时按钮隐藏, 向上滑时按钮显示, 还有动画效果, 支持监听 ListView, ScrollView, RecylerView \u0026lt;/td\u0026gt; 61. [AndroidAsync](https://github.com/koush/AndroidAsync) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; AndroidAsync 是一款基于 NIO 的低端 Android 异步 socket, http (client+server), websocket 和 socket.io 网络通信协议类库 \u0026lt;/td\u0026gt; 62. [rebound](https://github.com/facebook/rebound) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Rebound 是 Facebook 推出的一个弹性动画库, 可以让动画看起来真实自然, 像真实世界的物理运动, 带有力的效果, 使用的参数则是 Facebook 的 origami 中使用的 \u0026lt;/td\u0026gt; 63. [android-common](https://github.com/Trinea/android-common) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; android-common-lib 是 Trinea 大神收集的一些开发通用的缓存, 公共 View 以及一些常用工具类 \u0026lt;/td\u0026gt; 64. [RippleEffect](https://github.com/traex/RippleEffect) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; RippleEffect 是一个实现在 Android 任何组件点击出现 Material Design 的波纹效果, 向下兼容到 Android API9 \u0026lt;/td\u0026gt; 65. [SmoothProgressBar](https://github.com/castorflex/SmoothProgressBar) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; SmoothProgressBar 是一个帮你的 App 方便实现可定制, 平滑动画的水平滚动进度条库 \u0026lt;/td\u0026gt; 66. [recyclerview-animators](https://github.com/wasabeef/recyclerview-animators) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; RecyclerView Animators 是一个对 Recycler 控件的 Item 添加以及删除增加动画效果, 动画效果有Scale, Fade, Flip, Slide 里面各种各样效果 \u0026lt;/td\u0026gt; 67. [circular-progress-button](https://github.com/dmytrodanylyk/circular-progress-button) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 一个带进度显示的 Button, 效果和动画做的都非常赞 \u0026lt;/td\u0026gt; 68. [DroidPlugin](https://github.com/Qihoo360/DroidPlugin) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; DroidPlugin 是 360 手机助手在 Android 系统上实现了一种新的插件机制: 它可以在无需安装, 修改的情况下运行APK文件, 此机制对改进大型APP的架构, 实现多团队协作开发具有一定的好处 \u0026lt;/td\u0026gt; 69. [dynamic-load-apk](https://github.com/singwhatiwanna/dynamic-load-apk) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 开发者是singwhatiwanna(任玉刚), 是《Android 开发艺术探索》书籍的作者, 这个是作者联合另两位开发者啸(时之沙)和宋思宇花了几个月时间研究出来的 Apk 动态加载框架, 想了解更多关于这框架可到作者博客看 [这篇文章](http://blog.csdn.net/singwhatiwanna/article/details/39937639) 有详细介绍 \u0026lt;/td\u0026gt; 70. [ExoPlayer](https://github.com/google/ExoPlayer) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; ExoPlayer 是Google 开发团队开源出来的一个媒体播放库, 比 Android 框架原生的 MediaPlayer 拥有更多优点支持动态的自适应流 HTTP(DASH) 和 平滑流, 支持高级的HLS特性, 支持自定义和扩治你的使用场景等等 \u0026lt;/td\u0026gt; 71. [Crouton](https://github.com/keyboardsurfer/Crouton) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Crouton 是一个显示提示信息的显示工具类, 可以用来代替Toast, 默认显示在窗口的顶部, 可以按队列一个接着一个显示, 不过该库已经被弃用, 不推荐使用 \u0026lt;/td\u0026gt; 72. [robospice](https://github.com/stephanenicolas/robospice) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; RoboSpice 是一个使你建立异步的长时间的运行任务异常轻松的一个网络库，在网络请求，缓存支持，和提供开箱即用的rest请求方面尤为强大 \u0026lt;/td\u0026gt; 73. [hugo](https://github.com/JakeWharton/hugo) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Hugo 是 JakeWharton 大神推出的一个用于打印 Log, hugo 是基于注解被调用的, 引入相关依赖后, 在方法上加上 @DebugLog 即可输出 Log, 使用非常简单 \u0026lt;/td\u0026gt; 74. [async-http-client](https://github.com/AsyncHttpClient/async-http-client) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; AsyncHttpClient 是又一款 Android 异步请求库, 该库支持 WebSocket 协议, 使用起来也比较简单易用 \u0026lt;/td\u0026gt; 75. [UltimateRecyclerView](https://github.com/cymcsg/UltimateRecyclerView) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; UltimateRecyclerView 是一个功能强大的 RecyclerView(advanced and flexible version of ListView), 包括了下拉刷新, 加载更多, 多种动画, 空数据提示, 拖动排序, 视差处理, 工具栏渐变, 滑动删除, 自定义floating button, 多种刷新效果, scrollbar, sticky header, 多 layout 支持等等元素, 而且使用起来跟 RecyclerView 一样的方便 \u0026lt;/td\u0026gt; 76. [MaterialEditText](https://github.com/rengwuxian/MaterialEditText) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; MaterialEditText 是就职于 Flipboard 的员工 [扔物线](https://www.zhihu.com/people/rengwuxian) 开发的, 在 AppCompat v21 中也提供了 Material Design 的控件 EditText, 可是由于比较难用, 没有提供设置颜色的 Api, 于是就产生这个第三方库 \u0026lt;/td\u0026gt; 77. [Side-Menu.Android](https://github.com/Yalantis/Side-Menu.Android) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Side Menu 是 [Yalantis](https://yalantis.com/) 组织开源出来, 该组织因开源出一些动画很棒的开源库为大家所熟知该库是其中一个, 该库是提供翻页动画效果的侧边菜单, 动画体验超赞的 \u0026lt;/td\u0026gt; 78. [drag-sort-listview](https://github.com/bauerca/drag-sort-listview) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; DragSortListView 是一个可以实现拖动排序, 滑动删除的 listview 控件, 注意的是作者对该库已经放弃维护更新了, 不过感兴趣的人可以去研究一下 \u0026lt;/td\u0026gt; 79. [android-times-square](https://github.com/square/android-times-square) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; TimesSquare 是 Square 公司出品的一款显示日历选择日期的控件, 可以让用户选择多个日期 \u0026lt;/td\u0026gt; 80. [GreenDroid(不建议使用)](https://github.com/cyrilmottier/GreenDroid) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; GreenDroid 是一个封装好的 Android UI 界面库, 不过该库已经被弃用了，不建议使用 \u0026lt;/td\u0026gt; 81. [logger](https://github.com/orhanobut/logger) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Logger 是一个简单, 漂亮, 强大 Android 打印日志库 \u0026lt;/td\u0026gt; 82. [acra](https://github.com/ACRA/acra) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Acra 是一个能够让 Android 应用自动将崩溃报告以谷歌文档电子表的形式进行发送的库, 旨在当应用发生崩溃或出现错误行为时, 开发者可以获取到相关数据 \u0026lt;/td\u0026gt; 83. [FadingActionBar](https://github.com/ManuelPeinado/FadingActionBar) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; FadingActionBar 是一个支持 ListView, ScrollView, WebView 向下滚动时逐渐显示 ActionBar 库 \u0026lt;/td\u0026gt; 84. [AndroidImageSlider](https://github.com/daimajia/AndroidImageSlider) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; AndroidImageSlider 库开发者是代码家, 该库是为 Banner 图片滑动提供多种动画效果, 还可以轻易为 Banner 加载网络图片 \u0026lt;/td\u0026gt; 85. [SystemBarTint](https://github.com/jgilfelt/SystemBarTint) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; SystemBarTint 是一个实现沉浸式状态栏库, 适用于 Android 系统 4.4 其以上的版本 \u0026lt;/td\u0026gt; 86. [android-menudrawer](https://github.com/SimonVT/android-menudrawer) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; MenuDrawer 是一款滑出式菜单库, 通过拖动屏幕边缘滑出菜单, 支持屏幕上下左右划出, 支持当前 View 处于上下层, 支持 Windows 边缘, ListView 边缘, ViewPager 变化划出菜单等 \u0026lt;/td\u0026gt; 87. [RoundedImageView](https://github.com/vinc3m1/RoundedImageView) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; RoundedImageView 一个快速支持图片圆角显示效果的库, 该库特点是能快速加载, 为了提高加载速度, 该库不用创建原始位图的副本, 不使用clipPath, 不使用 setXfermode 裁剪的位图等方式来实现 ImageView 圆角, 使用也非常简单 \u0026lt;/td\u0026gt; 88. [afinal](https://github.com/yangfuhai/afinal) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Afinal 是一个 android 的 sqlite orm 和 ioc 框架, 同时封装了 android 中的 http 框架, 使其更加简单易用, 使用 finalBitmap, 无需考虑 bitmap 在 android 中加载的时候 oom 的问题和快速滑动的时候图片加载位置错位等问题, Afinal 的宗旨是简洁, 快速, 约定大于配置的方式, 尽量一行代码完成所有事情 \u0026lt;/td\u0026gt; 89. [android-pulltorefresh(不建议使用)](https://github.com/johannilsson/android-pulltorefresh) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 另一个下拉刷新库, 但是该库已经停止维护, 因此不建议使用, 推荐使用 Android-Ultra-Pull-to-Refresh \u0026lt;/td\u0026gt; 90. [Bolts-Android](https://github.com/BoltsFramework/Bolts-Android) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Bolts 是一款底层类库集合, 在后台实现异步操作, 并提供接口反馈当前异步执行的程度 (可以通过接口实现UI进度更新), 最后反馈执行的结果给UI主线程, 与AsyncTask比较: (1)使用的是无大小限制的线程池; (2)任务可组合可级联,防止了代码耦合 \u0026lt;/td\u0026gt; 91. [NumberProgressBar](https://github.com/daimajia/NumberProgressBar) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; NumberProgressBar 开发者是代码家, 这是一个带简约性感数字显示的进度条库, 使用非常简单方便 \u0026lt;/td\u0026gt; 92. [SwipeBackLayout](https://github.com/ikew0ng/SwipeBackLayout) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; SwipeBackLayout 是一个支持屏幕上下左右滑动返回上层 Activity, 关闭当前 Activity, 类似简书 App \u0026lt;/td\u0026gt; 93. [android-gif-drawable](https://github.com/koral--/android-gif-drawable) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 一个支持 gif 显示的 view, 用 jni 实现的, 编译生成 so 库后直接 xml 定义 view 即可, 简单易用 \u0026lt;/td\u0026gt; 94. [VitamioBundle](https://github.com/yixia/VitamioBundle) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Vitamio 是一款 Android 与 iOS 平台上的全能多媒体开发框架, 特点：(1) 全面支持硬件解码与 GPU 渲染, (2) 能够流畅播放 720P 甚至 1080P 高清 MKV, FLV, MP4, MOV, TS, RMVB 等常见格式的视频, (3) 在 Android 与 iOS 上跨平台支持 MMS, RTSP, RTMP, HLS(m3u8)等常见的多种视频流媒体协议, 包括点播与直播 \u0026lt;/td\u0026gt; 95. [SmartTabLayout](https://github.com/ogaclejapan/SmartTabLayout) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; SmartTabLayout 是一个自定义的 Tab title strip, 基于 Google Samples 中的 android-SlidingTabBasic 项目, 滑动时 Indicator 可平滑过渡 \u0026lt;/td\u0026gt; 96. [uCrop](https://github.com/Yalantis/uCrop) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; uCrop 是[Yalantis](https://yalantis.com/) 组织开源的图片裁剪库, 支持缩放, 旋转图片, 支持各种比例的裁剪框, 非常强大的一个图片裁剪库 \u0026lt;/td\u0026gt; 97. [android-crop](https://github.com/jdamcd/android-crop) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; 又一个图片裁剪库, 向下兼容到 Api 10, 个人感觉这个库并没有比上面介绍的 uCrop 强大 \u0026lt;/td\u0026gt; 98. [HoloEveryWhere](https://github.com/Prototik/HoloEverywhere) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; HoloEveryWhere 是一套 Android 开发库, 提供了全套 Holo Style 控件, 它的外观与功能和标准 Holo Style 控件基本相同, 唯一不同的是它可以运行在低于 4.0 版本的 Android 系统上 \u0026lt;/td\u0026gt; 99. [AVLoadingIndicatorView](https://github.com/81813780/AVLoadingIndicatorView) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; AVLoadingIndicatorView 库含有各种各样漂亮的加载动画效果, 使用起来也非常简单, 和平时使用 ProgressBar 一样 \u0026lt;/td\u0026gt; 00. [sweet-alert-dialog](https://github.com/pedant/sweet-alert-dialog) \u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt; Android 版的 SweetAlert, 清新文艺, 快意灵动的甜心弹框, 灵感来源于 JS 版[SweetAlert](http://t4t5.github.io/sweetalert/) \u0026lt;/td\u0026gt; {#user-content-粗计.anchor}粗计 {#user-content-square-公司占有-7-席.anchor}Square 公司占有 7 席 项目名称 \u0026lt;th\u0026gt; 排名 \u0026lt;/th\u0026gt; [Retrofit](https://github.com/square/retrofit) \u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt; 4 \u0026lt;/td\u0026gt; [OkHttp](https://github.com/square/okhttp) \u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt; 5 \u0026lt;/td\u0026gt; [Picasso](https://github.com/square/picasso) \u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt; 7 \u0026lt;/td\u0026gt; [LeakCanary](https://github.com/square/leakcanary) \u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt; 13 \u0026lt;/td\u0026gt; [Dagger](https://github.com/square/dagger) \u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt; 29 \u0026lt;/td\u0026gt; [Otto](https://github.com/square/otto) \u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt; 44 \u0026lt;/td\u0026gt; [TimesSquare](https://github.com/square/android-times-square) \u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt; 79 \u0026lt;/td\u0026gt; {#user-content-facebook-公司占有-4-席.anchor}FaceBook 公司占有 4 席 项目名称 \u0026lt;th\u0026gt; 排名 \u0026lt;/th\u0026gt; [React Native](https://github.com/facebook/react-native) \u0026lt;td width=\u0026quot;124\u0026quot;\u0026gt; 1 \u0026lt;/td\u0026gt; [Fresco](https://github.com/facebook/fresco) \u0026lt;td width=\u0026quot;124\u0026quot;\u0026gt; 11 \u0026lt;/td\u0026gt; [Stetho](https://github.com/facebook/stetho) \u0026lt;td width=\u0026quot;124\u0026quot;\u0026gt; 38 \u0026lt;/td\u0026gt; [Rebound](https://github.com/facebook/rebound) \u0026lt;td width=\u0026quot;124\u0026quot;\u0026gt; 62 \u0026lt;/td\u0026gt; {#user-content-jakewharton-大神占有-5-席.anchor}JakeWharton 大神占有 5 席 项目名称 \u0026lt;th\u0026gt; 排名 \u0026lt;/th\u0026gt; [Butter Knife](https://github.com/JakeWharton/butterknife) \u0026lt;td width=\u0026quot;98\u0026quot;\u0026gt; 14 \u0026lt;/td\u0026gt; [ActionBarSherlock](https://github.com/JakeWharton/ActionBarSherlock) \u0026lt;td width=\u0026quot;98\u0026quot;\u0026gt; 16 \u0026lt;/td\u0026gt; [ViewPagerIndicator](https://github.com/JakeWharton/ViewPagerIndicator) \u0026lt;td width=\u0026quot;98\u0026quot;\u0026gt; 18 \u0026lt;/td\u0026gt; [NineOldAndroids](https://github.com/JakeWharton/NineOldAndroids) \u0026lt;td width=\u0026quot;98\u0026quot;\u0026gt; 55 \u0026lt;/td\u0026gt; [Hugo](https://github.com/JakeWharton/hugo) \u0026lt;td width=\u0026quot;98\u0026quot;\u0026gt; 73 \u0026lt;/td\u0026gt; {#user-content-代码家大神占有-4-席.anchor}代码家大神占有 4 席 项目名称 \u0026lt;th\u0026gt; 排名 \u0026lt;/th\u0026gt; [AndroidSwipeLayout](https://github.com/daimajia/AndroidSwipeLayout) \u0026lt;td width=\u0026quot;89\u0026quot;\u0026gt; 28 \u0026lt;/td\u0026gt; [AndroidViewAnimations](https://github.com/daimajia/AndroidViewAnimations) \u0026lt;td width=\u0026quot;89\u0026quot;\u0026gt; 32 \u0026lt;/td\u0026gt; [AndroidImageSlide](https://github.com/daimajia/AndroidImageSlider) \u0026lt;td width=\u0026quot;89\u0026quot;\u0026gt; 84 \u0026lt;/td\u0026gt; [NumberProgressBar](https://github.com/daimajia/NumberProgressBar) \u0026lt;td width=\u0026quot;89\u0026quot;\u0026gt; 91 \u0026lt;/td\u0026gt; 转自：http://www.lesscode.cn/index.php?s=/view-index-id-299.shtml\n","permalink":"https://blog.zdltech.com/posts/github-%E4%B8%8A%E6%8E%92%E5%90%8D%E5%89%8D-100-%E7%9A%84-android-%E5%BC%80%E6%BA%90%E5%BA%93%E7%AE%80%E4%BB%8B/","summary":"\u003cp\u003e本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据GitHub搜索Java语言选择 (Best Match) 得到的结果, 然后过滤了跟Android不相关的项目, 所以排名并不具备任何官方效力, 仅供参考学习, 方便初学者快速了解当前一些流行的Android开源库.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eiOS 版本的在此: \u003ca href=\"https://github.com/Aufree/trip-to-iOS/blob/master/Top-100.md\"\u003ehttps://github.com/Aufree/trip-to-iOS/blob/master/Top-100.md\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e感谢 \u003ca href=\"http://weibo.com/GitHubDaily\"\u003e@GitHubDaily\u003c/a\u003e 的大力支持, 以及 \u003ca href=\"https://github.com/stormzhang\"\u003e@stormzhang\u003c/a\u003e 的指点\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003e若有任何疑问可通过\u003ca href=\"mailto:huanggaojun13@gmail.com\"\u003e邮件\u003c/a\u003e或\u003ca href=\"http://weibo.com/gaojunhuang\"\u003e微博\u003c/a\u003e联系我\u003c/strong\u003e\u003c/p\u003e\n\u003ctable width=\"568\"\u003e\n  \u003ctr class=\"firstRow\"\u003e\n    \u003cth\u003e\n      项目名称\n    \u003c/th\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;th\u0026gt;\n  项目简介\n\u0026lt;/th\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      1. [react-native](https://github.com/facebook/react-native)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  这个是 Facebook 在 React.js Conf 2015 大会上推出的基于 JavaScript 的开源框架 React Native, 该框架结合了 Web 应用和 Native 应用的优势, 可以使用 JavaScript 来开发 iOS 和 Android 原生应用\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      2.[Android-Universal-Image-Loader](https://github.com/nostra13/Android-Universal-Image-Loader)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  ImageLoader 是最早开源的 Android 图片缓存库, 强大的缓存机制, 早期被广泛 Android 应用使用, 至今仍然有很多 Android 开发者在使用\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      3. [RxJava](https://github.com/ReactiveX/RxJava)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  RxJava 是一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库, 简单来说它就是一个实现异步操作的库, RxJava 的优点在于一个词 \u0026amp;#8220;简洁\u0026amp;#8221;, 使用它就算你程序逻辑有多么复杂, 它依然能够保持简洁易懂\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      4. [retrofit](https://github.com/square/retrofit)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Retrofit 是 Square 公司出品的 HTTP 请求库, 同时是 Square 是最早开源项目之一, Retrofit 是目前 Android 最流行的 Http Client 库之一, 目前版本是 Retrofit2.0 Beta4, 越来越多 Android 开发者开始使用这个请求库了\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      5. [okhttp](https://github.com/square/okhttp)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  OkHttp 是 Square 公司出品的 HTTP 另一个请求库, Google 不推荐人们使用 HttpClient, 可是 HttpURLConnection 实在是太难用了, 因此很多人使用了 OkHttp 来解决这问题, 据说 Android4.4 的源码中可以看到 HttpURLConnection 已经替换成 OkHttp 实现呢\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      6. [SlidingMenu(不建议使用)](https://github.com/jfeinstein10/SlidingMenu)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  一个侧滑菜单开源库, 在 Google 自己原生态的侧滑菜单 NavigationDrawer 没有出现之前, 这个库就已经被广泛使用, 可是到现在这个库已经被放弃了\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      7. [picasso](https://github.com/square/picasso)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Picasso 是 Square 公司出品的一款图片缓存库, 主导者是 JakeWharton 大神\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      8. [android-best-practices](https://github.com/futurice/android-best-practices)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Android 开发最佳实践, 里面所介绍的经验都是来自于 Futurice 公司 Android 开发者, 介绍内容有 Android 开发规范、架构、布局技巧, 以及使用一些有助于快速开发相关工具等等, 非常适合新手去学习\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      9. [EventBus](https://github.com/greenrobot/EventBus)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  EventBus 是 Android 事件管理总线, 使用它可以替带 Android BroadCast, BroadCastReceiver, Handler 在 Activity, Fragment, Service, 线程之间传递消息, 大大简化了事件传递逻辑\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      10. [android-async-http](https://github.com/loopj/android-async-http)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Android-Async-Http 是 Android 一款老牌异步请求库, 专门对 Android 在 Apache 的 HttpClient 基础上构建的异步 http 连接, 该库有很多特征, 例如: 库的 size 小, 支持文件上传不需使用第三方库支持, 内部使用线程池来处理并发, 等等\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      11. [fresco](https://github.com/facebook/fresco)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Fresco 是 FaceBook 公司出品的一款图片缓存库, Fresco 是一个强大的图片加载组件, 支持加载 Gif 图和 WebP 格式, 支持 Android2.3(API level 9) 及其以上系统, Fresco 中设计了 Image pipeline 和 Drawees 两个模块各施其职, 使得图片完美加载出来, 想知道更多 image pipeline 和 Drawees 有关于它的特性, 可以到它[官方平台](http://fresco-cn.org/)看介绍\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      12. [zxing](https://github.com/zxing/zxing)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  ZXing 是二维码领域中名气最大的开源项目, 它提供了多个平台的二维码/条形码扫描解决方案, 拥有扫描快, 识别率高, 使用简单等特点\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      13. [leakcanary](https://github.com/square/leakcanary)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  LeakCanary 是 Square 公司出的一款检测内存泄露工具, 该工具能帮助你在开发阶段方便的检测出内存泄露的问题, 使用起来非常简单方便\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      14. [butterknife](https://github.com/JakeWharton/butterknife)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  由 JakeWharton 大神开发出来的, ButterKnife 是 View 注入框架, 使用它为了简写很多 findViewById 代码, 同时还支持 View 的一些事件处理函数\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      15. [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  MPAndroidChart 是一款强大的 Android 图表库, 支持各种各样图表显示, 能想到的图表样式这里几乎都有, 图表还支持选择, 拖放和缩放动画效果\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      16.[ActionBarSherlock(不建议使用)](https://github.com/JakeWharton/ActionBarSherlock)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  ActionBarSherlock 这个库是 JakeWharton 大神开发出来支持 Android3.0 以下版本的, 后来慢慢的 Google 也提供了 AppCompat 库来支持 Android3.0 以下版本使用 ActionBar, 因此作者不建议我们再使用这个库了\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      17. [androidannotations](https://github.com/excilys/androidannotations)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  AndroidAnnotations 是一个能够让你快速进行 Android 开发的开源框架, 它能让你专注于真正重要的地方, 使代码更加精简, 使项目更加容易维护, 它的目标就是 \u0026amp;#8220;Fast Android Development.Easy maintainance\u0026amp;#8221;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      18. [ViewPagerIndicator](https://github.com/JakeWharton/ViewPagerIndicator)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  由 JakeWharton 大神开发出来的一个 ViewPager 指示器, 使用起来简单方便, 可高度定制, 开发出各种各样动画效果\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      19. [glide](https://github.com/bumptech/glide)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Glide 是 Google 员工的开源项目, 广泛应用于 Google 一些 App 上, 在2014年 Google I/O 大会上被推荐使用, Glide 和 Picasso 被人拿来比较研究过, Glide 与 Picasso 有 90% 的相似度, 但在一些细节上还是有点区别的, 各有各优缺点看君选择\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      20. [HomeMirror](https://github.com/HannahMitt/HomeMirror)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  开发者是由一名程序媛 Hannah Mittelstaedt , HomeMirror 是一款 Android 镜子应用, 目前它能实现日期, 时间, 天气, 生日信息, 事件提醒器, 骑车天气的推荐, 股票信息, XKCD 漫画网站的新帖等等\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      21. [Android-PullToRefresh(不建议使用)](https://github.com/chrisbanes/Android-PullToRefresh)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  一个强大的拉动刷新开源项目，支持各种控件下拉刷新，ListView、ViewPager、WebView、ExpandableListView、GridView、ScrollView、Horizontal ScrollView、Fragment 上下左右拉动刷新, 不过现在这个项目已经停止维护更新了, 推荐使用 Android-Ultra-Pull-to-Refresh\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      22. [MaterialDesignLibrary](https://github.com/navasmdc/MaterialDesignLibrary)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  这个库控件都是遵循了 Google Material Design 设计规范开发出来, 例如有: Flat Button, Rectangle Button, CheckBox, Switch, Progress bar circular indeterminate 等等\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      23. [PhotoView](https://github.com/chrisbanes/PhotoView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  PhotoView 是 ImageView 的子类, 支持所有 ImageView 的源生行为, 例如: 支持 Pinch 手势自由缩放, 支持双击放大/还原, 支持平滑滚动等等, 并且非常方便的与 ImageLoader/Picasso 之类的网络图片读取库集成使用, 还方便的与 ViewPager 等同样支持滑动手势的控件集成\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      24. [RxAndroid](https://github.com/ReactiveX/RxAndroid)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  由 JakeWharton 大神主导开发的项目, RxAndroid 是 RxJava 的一个针对 Android 平台的扩展, 主要用于 Android 开发\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      25. [material-dialogs](https://github.com/afollestad/material-dialogs)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Material Dialogs 是一个可高度定制易用, 符合 Material Design 风格的 Dialogs, 兼容 Android API8 以上版本, 个人使用感觉它完全可替代 Android 原生那个, 比原生那个更加简单易用\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      26.[Android-ObservableScrollView](https://github.com/ksoichiro/Android-ObservableScrollView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  ObservableScrollView 是一款用于在滚动视图中观测滚动事件的 Android 库, 它能够轻而易举地与 Android 5.0 Lollipop 引进的工具栏 (Toolbar) 进行交互, 还可以帮助开发者实现拥有 Material Design 应用视觉体验的界面外观, 支持ListView, ScrollView, WebView, RecyclerView, GridView组件\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      27. [Android-Bootstrap](https://github.com/Bearded-Hen/Android-Bootstrap)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Android 版的 Bootstrap, 利用这个库能够实现很多 Bootstrap 样式风格, 之前有学过 Html 的人就知道 Bootstrap 是什么玩意啦\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      28. [AndroidSwipeLayout](https://github.com/daimajia/AndroidSwipeLayout)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  开发者是代码家, AndroidSwipeLayout 是一个支持ListView, GridView, ViewGroup等等左右上下滑动出操作菜单, 类似 qq 消息列表向左滑动显示出多某条信息的操作菜单\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      29. [dagger](https://github.com/square/dagger)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Dagger 是 Square 公司出品的一个针对 Android 和 Java 的快速依赖注入器, 能够有效减少你敲代码量\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      30. [ListViewAnimations](https://github.com/nhaarman/ListViewAnimations)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  一个轻轻松松给 Android ListView 添加动画效果的库, 支持的动画有: Alpha, SwingRightIn, SwingLeftIn, SwingBottomIn, SwingRightIn and ScaleIn等等, 使用它能很容易就实现帅爆的效果\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      31. [PagerSlidingTabStrip](https://github.com/astuetz/PagerSlidingTabStrip)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  PagerSlidingTabStrip 是一个给 Android ViewPager添加上 ViewPager 滑动指示器, 从 GitHub 上面看, 这个库似乎没有人在维护了, 请谨慎使用该库\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      32. [AndroidViewAnimations](https://github.com/daimajia/AndroidViewAnimations)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  开发者是代码家, 这个库实现很多很酷炫的 Android 动画, 动画效果是借鉴 Animate.css 来实现的, 非常酷, 而且这个使用起来也是非常简单\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      33. [AndroidSlidingUpPanel](https://github.com/umano/AndroidSlidingUpPanel)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  AndroidSlidingUpPanel 是一个上拉面板, 就是向上滑动的时候往上飞出一个显示面板控件, 该库效果在 Google Music, Google Maps and Rdio等 App 应用到\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      34. [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  MaterialDrawer 是一个类似 Google 官方 NavigationView 侧滑显示控件, 个人认为 NavigationView 并没有 MaterialDrawer 实用, 因为 NavigationView 自由度不是很好, 很多都写死了不可以自由定义布局, 而 MaterialDrawer 能够实现跟 NavigationView 一样的效果, 同时还支持自定义效果, 自由度非常高\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      35. [Material-Animations](https://github.com/lgvalle/Material-Animations)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Material-Animations 是一个很好过渡动画库, 可以应用于 Activity 与 Activity 之间的跳转, Fragment 与 Fragment 之间的跳转, 以及各个 View 变化前后的过渡动画\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      36. [MaterialViewPager](https://github.com/florent37/MaterialViewPager)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  一个简单易用 Material Design 风格的 ViewPager 库\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      37. [ion](https://github.com/koush/ion)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  ion 是一个让 Android 的网络操作变得极其简单, 支持异步获取和处理JSON, 支持 Android 文件下载 (同时支持下载进度条绑定), 支持安全链接和代理\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      38. [stetho](https://github.com/facebook/stetho)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Stetho是 Facebook 出品的一个强大的 Android 调试工具,使用该工具你可以在 Chrome Developer Tools查看App的布局, 网络请求(仅限使用Volley, okhttp的网络请求库), sqlite, preference, 一切都是可视化的操作,无须自己在去使用adb, 也不需要root你的设备\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      39. [fastjson](https://github.com/alibaba/fastjson)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法，把JSON Parse的性能提升到极致，是目前Java语言中最快的JSON库。Fastjson接口简单易用，已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      40. [cardslib](https://github.com/gabrielemariotti/cardslib)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Cardslib 是早期由 Gabriele Mariotti 开发的一个为开发者方便实现各种 Card UI 的 Android 开源代码库, 后来 Google 官方提供自己封装了 CardView 在 v7 包下, 使用 Google 官方的可以完全替代了这个库, 因此这个也被弃用了\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      41. [Android-Ultra-Pull-To-Refresh](https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  开发者是廖祜秋, 这个是一个非常强大的下拉刷新库, 继承 ViewGroup 可以包含任何 View, 功能甚至比 SwipeRefreshLayout 强大, 使用起来也非常容易, 还可以自由定制自己的 UI 样式\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      42. [greenDAO](https://github.com/greenrobot/greenDAO)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  greenDAO 是一个可以帮助 Android 开发者快速将 Java 对象映射到 SQLite 数据库的表单中的 ORM解决方案, 通过使用一个简单的面向对象 API, 开发者可以对 Java 对象进行存储, 更新, 删除和查询, greenDAO 相对 OrmLite, AndrORM 这两个 ORM 开源库, 性能是最高的\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      43. [AndroidStaggeredGrid](https://github.com/etsy/AndroidStaggeredGrid)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  AndroidStaggeredGrid 是一个支持多列并且每一行的 item 大小不一, 交错排列的 GridView, 就是实现瀑布流样式效果, 目前该库已经被弃用了, 开发者建议我们使用 Google 官方控件 RecyleView 中的 StaggeredGridLayoutManager 布局来实现瀑布流效果\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      44. [otto](https://github.com/square/otto)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Otto 是 Square 公司出的一个事件库 (pub/sub 模式), 用来简化应用程序组件之间的通讯, otto 修改自 Google 的 Guava 库, 专门为 Android 平台进行了优化, 与上面介绍的 EventBus 相比, 两个库各有各的优点, 完全取决于我们自己项目的需求来选择它们哪一个\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      45. [xUtils](https://github.com/wyouflf/xUtils)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  xUtils 是一个快速开发框架, 里面包含 DbUtils, ViewUtils, HttpUtils, BitmapUtils 四大模块, 可用于快速开发, 支持大文件上传, 拥有更加灵活的 ORM, 最低兼容 Android 2.2\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      46. [realm-java](https://github.com/realm/realm-java)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Realm 一个轻量的 Android 版本的数据存储库, 比 Android 原生系统的 SQLite 更加简洁快速对数据进行操作\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      47.[Android-CleanArchitecture](https://github.com/android10/Android-CleanArchitecture)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  CleanArchitecture 是一个非常典型使用 MVP 架构的项目, 大家如果还没有理解 MVP 架构的可以看看这个项目\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      48. [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  StickyListHeaders 是一个实现能够固定在屏幕顶部的ListView Section Header库, 就是当前 section 的 header 固定在屏幕顶部, 当滑动到其他 section 时, 其他 section 的 header 会代替之前的 section 的 header, 固定到屏幕顶部, 类似于 Android4.0 的手机通讯录的效果\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      49. [AppIntro](https://github.com/PaoloRotolo/AppIntro)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  AppIntro 是一个让人轻松快速搭建漂亮酷炫的引导页库\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      50. [ActiveAndroid](https://github.com/pardom/ActiveAndroid)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  ActiveAndroid 是采用Rails中的 [Active Record](http://en.wikipedia.org/wiki/Object-relational_mapping)架构模式设计的适用于 Android 平台的轻量级 ORM 架构, 几乎可以不用写任何 SQL 代码实现快速开发\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      51. [android-volley](https://github.com/mcxiaoke/android-volley)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Volley 是谷歌官方开发团队在 2013 年 Google I/O 大会推出的一个新的网络通信框架, 这个框架把 AsyncHttpClient 和 Universal-Image-Loader 的优点集于了一身,既可以像AsyncHttpClient 一样非常简单地进行 HTTP 通信,也可以像 Universal-Image-Loader 一样轻松加载网络上的图片, 这个库并不是官方的, 只是托管同步在 Maven, 官方只提供的 Jar 包\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      52. [twoway-view](https://github.com/lucasr/twoway-view)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  TwoWayView 是简化 RecyclerView 开发的一个库, 可以在其 Base LayoutManager 基础上构建各种各样的布局, 该库内置了几个常用布局 List, Grid, Staggered Grid,Spannable Grid\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      53. [ShowcaseView](https://github.com/amlcurran/ShowcaseView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  ShowcaseView 是一个非常适合用于对用户进行第一次使用进行指导的库,使用起来非常简单还可以自定义样式\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      54. [Calligraphy](https://github.com/chrisjenx/Calligraphy)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Calligraphy 是一个用来简化 Android 应用使用自定义字体的类库, 该类库会自动查找应用中的 TextView 并设置其使用的字体\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      55. [NineOldAndroids](https://github.com/JakeWharton/NineOldAndroids)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  NineOldAndroids 由 JakeWharton 大神开发的一个向下兼容的动画库, 主要是使低于API 11的系统也能够使用 View 的属性动画, 不过现在 JakeWharton 大神已经不推荐使用该库, 而是推荐我们使用官方封装在 Support 库里面的动画\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      56. [android-floating-action-button](https://github.com/futuresimple/android-floating-action-button)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  FloatingActionButton 是一个悬浮操作按钮, 官方在 Support Design 包下也有封装一个类似这个库效果的 FloatingActionButton, 值得说明的是这个库是早在官方封装之前就存在的, 个人感觉这个库比官方那个更加好用\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      57. [CircleImageView](https://github.com/hdodenhof/CircleImageView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  CircleImageView 是一个轻松帮你实现圆形效果 ImageView 图片库, CircleImageView 是基于 ImageView 扩展出来, 因此它拥有 ImageView 控件所有属性, 简单易用值得你使用的库\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      58. [material](https://github.com/rey5137/material)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Material 是将 Material Design 风格控件封装在该库当中, 目前封装有Progress, Button, Switch, Slider, Spinner, Text Field, TabPageIndicator, SnackBar, Dialog, BottomSheetDialog, Dynamic theme\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      59. [ActionBar-PullToRefresh](https://github.com/chrisbanes/ActionBar-PullToRefresh)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  ActionBar-PullToRefresh 是一个下拉刷新, 下拉刷新时在 ActionBar 出现加载中提示的库\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      60. [FloatingActionButton](https://github.com/makovkastar/FloatingActionButton)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  又一个悬浮操作按钮库, 该库添加支持监听滑滚动事件, 当向下滑时按钮隐藏, 向上滑时按钮显示, 还有动画效果, 支持监听 ListView, ScrollView, RecylerView\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      61. [AndroidAsync](https://github.com/koush/AndroidAsync)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  AndroidAsync 是一款基于 NIO 的低端 Android 异步 socket, http (client+server), websocket 和 socket.io 网络通信协议类库\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      62. [rebound](https://github.com/facebook/rebound)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Rebound 是 Facebook 推出的一个弹性动画库, 可以让动画看起来真实自然, 像真实世界的物理运动, 带有力的效果, 使用的参数则是 Facebook 的 origami 中使用的\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      63. [android-common](https://github.com/Trinea/android-common)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  android-common-lib 是 Trinea 大神收集的一些开发通用的缓存, 公共 View 以及一些常用工具类\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      64. [RippleEffect](https://github.com/traex/RippleEffect)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  RippleEffect 是一个实现在 Android 任何组件点击出现 Material Design 的波纹效果, 向下兼容到 Android API9\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      65. [SmoothProgressBar](https://github.com/castorflex/SmoothProgressBar)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  SmoothProgressBar 是一个帮你的 App 方便实现可定制, 平滑动画的水平滚动进度条库\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      66. [recyclerview-animators](https://github.com/wasabeef/recyclerview-animators)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  RecyclerView Animators 是一个对 Recycler 控件的 Item 添加以及删除增加动画效果, 动画效果有Scale, Fade, Flip, Slide 里面各种各样效果\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      67. [circular-progress-button](https://github.com/dmytrodanylyk/circular-progress-button)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  一个带进度显示的 Button, 效果和动画做的都非常赞\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      68. [DroidPlugin](https://github.com/Qihoo360/DroidPlugin)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  DroidPlugin 是 360 手机助手在 Android 系统上实现了一种新的插件机制: 它可以在无需安装, 修改的情况下运行APK文件, 此机制对改进大型APP的架构, 实现多团队协作开发具有一定的好处\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      69. [dynamic-load-apk](https://github.com/singwhatiwanna/dynamic-load-apk)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  开发者是singwhatiwanna(任玉刚), 是《Android 开发艺术探索》书籍的作者, 这个是作者联合另两位开发者啸(时之沙)和宋思宇花了几个月时间研究出来的 Apk 动态加载框架, 想了解更多关于这框架可到作者博客看 [这篇文章](http://blog.csdn.net/singwhatiwanna/article/details/39937639) 有详细介绍\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      70. [ExoPlayer](https://github.com/google/ExoPlayer)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  ExoPlayer 是Google 开发团队开源出来的一个媒体播放库, 比 Android 框架原生的 MediaPlayer 拥有更多优点支持动态的自适应流 HTTP(DASH) 和 平滑流, 支持高级的HLS特性, 支持自定义和扩治你的使用场景等等\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      71. [Crouton](https://github.com/keyboardsurfer/Crouton)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Crouton 是一个显示提示信息的显示工具类, 可以用来代替Toast, 默认显示在窗口的顶部, 可以按队列一个接着一个显示, 不过该库已经被弃用, 不推荐使用\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      72. [robospice](https://github.com/stephanenicolas/robospice)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  RoboSpice 是一个使你建立异步的长时间的运行任务异常轻松的一个网络库，在网络请求，缓存支持，和提供开箱即用的rest请求方面尤为强大\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      73. [hugo](https://github.com/JakeWharton/hugo)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Hugo 是 JakeWharton 大神推出的一个用于打印 Log, hugo 是基于注解被调用的, 引入相关依赖后, 在方法上加上 @DebugLog 即可输出 Log, 使用非常简单\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      74. [async-http-client](https://github.com/AsyncHttpClient/async-http-client)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  AsyncHttpClient 是又一款 Android 异步请求库, 该库支持 WebSocket 协议, 使用起来也比较简单易用\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      75. [UltimateRecyclerView](https://github.com/cymcsg/UltimateRecyclerView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  UltimateRecyclerView 是一个功能强大的 RecyclerView(advanced and flexible version of ListView), 包括了下拉刷新, 加载更多, 多种动画, 空数据提示, 拖动排序, 视差处理, 工具栏渐变, 滑动删除, 自定义floating button, 多种刷新效果, scrollbar, sticky header, 多 layout 支持等等元素, 而且使用起来跟 RecyclerView 一样的方便\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      76. [MaterialEditText](https://github.com/rengwuxian/MaterialEditText)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  MaterialEditText 是就职于 Flipboard 的员工 [扔物线](https://www.zhihu.com/people/rengwuxian) 开发的, 在 AppCompat v21 中也提供了 Material Design 的控件 EditText, 可是由于比较难用, 没有提供设置颜色的 Api, 于是就产生这个第三方库\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      77. [Side-Menu.Android](https://github.com/Yalantis/Side-Menu.Android)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Side Menu 是 [Yalantis](https://yalantis.com/) 组织开源出来, 该组织因开源出一些动画很棒的开源库为大家所熟知该库是其中一个, 该库是提供翻页动画效果的侧边菜单, 动画体验超赞的\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      78. [drag-sort-listview](https://github.com/bauerca/drag-sort-listview)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  DragSortListView 是一个可以实现拖动排序, 滑动删除的 listview 控件, 注意的是作者对该库已经放弃维护更新了, 不过感兴趣的人可以去研究一下\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      79. [android-times-square](https://github.com/square/android-times-square)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  TimesSquare 是 Square 公司出品的一款显示日历选择日期的控件, 可以让用户选择多个日期\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      80. [GreenDroid(不建议使用)](https://github.com/cyrilmottier/GreenDroid)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  GreenDroid 是一个封装好的 Android UI 界面库, 不过该库已经被弃用了，不建议使用\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      81. [logger](https://github.com/orhanobut/logger)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Logger 是一个简单, 漂亮, 强大 Android 打印日志库\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      82. [acra](https://github.com/ACRA/acra)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Acra 是一个能够让 Android 应用自动将崩溃报告以谷歌文档电子表的形式进行发送的库, 旨在当应用发生崩溃或出现错误行为时, 开发者可以获取到相关数据\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      83. [FadingActionBar](https://github.com/ManuelPeinado/FadingActionBar)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  FadingActionBar 是一个支持 ListView, ScrollView, WebView 向下滚动时逐渐显示 ActionBar 库\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      84. [AndroidImageSlider](https://github.com/daimajia/AndroidImageSlider)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  AndroidImageSlider 库开发者是代码家, 该库是为 Banner 图片滑动提供多种动画效果, 还可以轻易为 Banner 加载网络图片\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      85. [SystemBarTint](https://github.com/jgilfelt/SystemBarTint)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  SystemBarTint 是一个实现沉浸式状态栏库, 适用于 Android 系统 4.4 其以上的版本\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      86. [android-menudrawer](https://github.com/SimonVT/android-menudrawer)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  MenuDrawer 是一款滑出式菜单库, 通过拖动屏幕边缘滑出菜单, 支持屏幕上下左右划出, 支持当前 View 处于上下层, 支持 Windows 边缘, ListView 边缘, ViewPager 变化划出菜单等\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      87. [RoundedImageView](https://github.com/vinc3m1/RoundedImageView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  RoundedImageView 一个快速支持图片圆角显示效果的库, 该库特点是能快速加载, 为了提高加载速度, 该库不用创建原始位图的副本, 不使用clipPath, 不使用 setXfermode 裁剪的位图等方式来实现 ImageView 圆角, 使用也非常简单\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      88. [afinal](https://github.com/yangfuhai/afinal)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Afinal 是一个 android 的 sqlite orm 和 ioc 框架, 同时封装了 android 中的 http 框架, 使其更加简单易用, 使用 finalBitmap, 无需考虑 bitmap 在 android 中加载的时候 oom 的问题和快速滑动的时候图片加载位置错位等问题, Afinal 的宗旨是简洁, 快速, 约定大于配置的方式, 尽量一行代码完成所有事情\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      89. [android-pulltorefresh(不建议使用)](https://github.com/johannilsson/android-pulltorefresh)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  另一个下拉刷新库, 但是该库已经停止维护, 因此不建议使用, 推荐使用 Android-Ultra-Pull-to-Refresh\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      90. [Bolts-Android](https://github.com/BoltsFramework/Bolts-Android)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Bolts 是一款底层类库集合, 在后台实现异步操作, 并提供接口反馈当前异步执行的程度 (可以通过接口实现UI进度更新), 最后反馈执行的结果给UI主线程, 与AsyncTask比较: (1)使用的是无大小限制的线程池; (2)任务可组合可级联,防止了代码耦合\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      91. [NumberProgressBar](https://github.com/daimajia/NumberProgressBar)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  NumberProgressBar 开发者是代码家, 这是一个带简约性感数字显示的进度条库, 使用非常简单方便\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      92. [SwipeBackLayout](https://github.com/ikew0ng/SwipeBackLayout)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  SwipeBackLayout 是一个支持屏幕上下左右滑动返回上层 Activity, 关闭当前 Activity, 类似简书 App\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      93. [android-gif-drawable](https://github.com/koral--/android-gif-drawable)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  一个支持 gif 显示的 view, 用 jni 实现的, 编译生成 so 库后直接 xml 定义 view 即可, 简单易用\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      94. [VitamioBundle](https://github.com/yixia/VitamioBundle)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Vitamio 是一款 Android 与 iOS 平台上的全能多媒体开发框架, 特点：(1) 全面支持硬件解码与 GPU 渲染, (2) 能够流畅播放 720P 甚至 1080P 高清 MKV, FLV, MP4, MOV, TS, RMVB 等常见格式的视频, (3) 在 Android 与 iOS 上跨平台支持 MMS, RTSP, RTMP, HLS(m3u8)等常见的多种视频流媒体协议, 包括点播与直播\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      95. [SmartTabLayout](https://github.com/ogaclejapan/SmartTabLayout)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  SmartTabLayout 是一个自定义的 Tab title strip, 基于 Google Samples 中的 android-SlidingTabBasic 项目, 滑动时 Indicator 可平滑过渡\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      96. [uCrop](https://github.com/Yalantis/uCrop)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  uCrop 是[Yalantis](https://yalantis.com/) 组织开源的图片裁剪库, 支持缩放, 旋转图片, 支持各种比例的裁剪框, 非常强大的一个图片裁剪库\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      97. [android-crop](https://github.com/jdamcd/android-crop)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  又一个图片裁剪库, 向下兼容到 Api 10, 个人感觉这个库并没有比上面介绍的 uCrop 强大\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      98. [HoloEveryWhere](https://github.com/Prototik/HoloEverywhere)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  HoloEveryWhere 是一套 Android 开发库, 提供了全套 Holo Style 控件, 它的外观与功能和标准 Holo Style 控件基本相同, 唯一不同的是它可以运行在低于 4.0 版本的 Android 系统上\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      99. [AVLoadingIndicatorView](https://github.com/81813780/AVLoadingIndicatorView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  AVLoadingIndicatorView 库含有各种各样漂亮的加载动画效果, 使用起来也非常简单, 和平时使用 ProgressBar 一样\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"103\"\u003e\n      00. [sweet-alert-dialog](https://github.com/pedant/sweet-alert-dialog)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;275\u0026quot;\u0026gt;\n  Android 版的 SweetAlert, 清新文艺, 快意灵动的甜心弹框, 灵感来源于 JS 版[SweetAlert](http://t4t5.github.io/sweetalert/)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003ch2 id=\"user-content-粗计anchor粗计\"\u003e\u003ca href=\"https://github.com/Freelander/Android_Data/blob/master/Android-Librarys-Top-100.md?hmsr=toutiao.io\u0026amp;utm_medium=toutiao.io\u0026amp;utm_source=toutiao.io#%E7%B2%97%E8%AE%A1\"\u003e\u003c/a\u003e{#user-content-粗计.anchor}粗计\u003c/h2\u003e\n\u003ch4 id=\"user-content-square-公司占有-7-席anchorsquare-公司占有-7-席\"\u003e\u003ca href=\"https://github.com/Freelander/Android_Data/blob/master/Android-Librarys-Top-100.md?hmsr=toutiao.io\u0026amp;utm_medium=toutiao.io\u0026amp;utm_source=toutiao.io#square-%E5%85%AC%E5%8F%B8%E5%8D%A0%E6%9C%89-7-%E5%B8%AD\"\u003e\u003c/a\u003e{#user-content-square-公司占有-7-席.anchor}Square 公司占有 7 席\u003c/h4\u003e\n\u003ctable width=\"568\"\u003e\n  \u003ctr class=\"firstRow\"\u003e\n    \u003cth\u003e\n      项目名称\n    \u003c/th\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;th\u0026gt;\n  排名\n\u0026lt;/th\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"248\"\u003e\n      [Retrofit](https://github.com/square/retrofit)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt;\n  4\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"248\"\u003e\n      [OkHttp](https://github.com/square/okhttp)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt;\n  5\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"248\"\u003e\n      [Picasso](https://github.com/square/picasso)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt;\n  7\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"248\"\u003e\n      [LeakCanary](https://github.com/square/leakcanary)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt;\n  13\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"248\"\u003e\n      [Dagger](https://github.com/square/dagger)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt;\n  29\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"248\"\u003e\n      [Otto](https://github.com/square/otto)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt;\n  44\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"248\"\u003e\n      [TimesSquare](https://github.com/square/android-times-square)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;130\u0026quot;\u0026gt;\n  79\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003ch4 id=\"user-content-facebook-公司占有-4-席anchorfacebook-公司占有-4-席\"\u003e\u003ca href=\"https://github.com/Freelander/Android_Data/blob/master/Android-Librarys-Top-100.md?hmsr=toutiao.io\u0026amp;utm_medium=toutiao.io\u0026amp;utm_source=toutiao.io#facebook-%E5%85%AC%E5%8F%B8%E5%8D%A0%E6%9C%89-4-%E5%B8%AD\"\u003e\u003c/a\u003e{#user-content-facebook-公司占有-4-席.anchor}FaceBook 公司占有 4 席\u003c/h4\u003e\n\u003ctable width=\"568\"\u003e\n  \u003ctr class=\"firstRow\"\u003e\n    \u003cth\u003e\n      项目名称\n    \u003c/th\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;th\u0026gt;\n  排名\n\u0026lt;/th\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"254\"\u003e\n      [React Native](https://github.com/facebook/react-native)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;124\u0026quot;\u0026gt;\n  1\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"254\"\u003e\n      [Fresco](https://github.com/facebook/fresco)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;124\u0026quot;\u0026gt;\n  11\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"254\"\u003e\n      [Stetho](https://github.com/facebook/stetho)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;124\u0026quot;\u0026gt;\n  38\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"254\"\u003e\n      [Rebound](https://github.com/facebook/rebound)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;124\u0026quot;\u0026gt;\n  62\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003ch4 id=\"user-content-jakewharton-大神占有-5-席anchorjakewharton-大神占有-5-席\"\u003e\u003ca href=\"https://github.com/Freelander/Android_Data/blob/master/Android-Librarys-Top-100.md?hmsr=toutiao.io\u0026amp;utm_medium=toutiao.io\u0026amp;utm_source=toutiao.io#jakewharton-%E5%A4%A7%E7%A5%9E%E5%8D%A0%E6%9C%89-5-%E5%B8%AD\"\u003e\u003c/a\u003e{#user-content-jakewharton-大神占有-5-席.anchor}JakeWharton 大神占有 5 席\u003c/h4\u003e\n\u003ctable width=\"568\"\u003e\n  \u003ctr class=\"firstRow\"\u003e\n    \u003cth\u003e\n      项目名称\n    \u003c/th\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;th\u0026gt;\n  排名\n\u0026lt;/th\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"280\"\u003e\n      [Butter Knife](https://github.com/JakeWharton/butterknife)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;98\u0026quot;\u0026gt;\n  14\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"280\"\u003e\n      [ActionBarSherlock](https://github.com/JakeWharton/ActionBarSherlock)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;98\u0026quot;\u0026gt;\n  16\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"280\"\u003e\n      [ViewPagerIndicator](https://github.com/JakeWharton/ViewPagerIndicator)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;98\u0026quot;\u0026gt;\n  18\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"280\"\u003e\n      [NineOldAndroids](https://github.com/JakeWharton/NineOldAndroids)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;98\u0026quot;\u0026gt;\n  55\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"280\"\u003e\n      [Hugo](https://github.com/JakeWharton/hugo)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;98\u0026quot;\u0026gt;\n  73\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003ch4 id=\"user-content-代码家大神占有-4-席anchor代码家大神占有-4-席\"\u003e\u003ca href=\"https://github.com/Freelander/Android_Data/blob/master/Android-Librarys-Top-100.md?hmsr=toutiao.io\u0026amp;utm_medium=toutiao.io\u0026amp;utm_source=toutiao.io#%E4%BB%A3%E7%A0%81%E5%AE%B6%E5%A4%A7%E7%A5%9E%E5%8D%A0%E6%9C%89-4-%E5%B8%AD\"\u003e\u003c/a\u003e{#user-content-代码家大神占有-4-席.anchor}代码家大神占有 4 席\u003c/h4\u003e\n\u003ctable width=\"568\"\u003e\n  \u003ctr class=\"firstRow\"\u003e\n    \u003cth\u003e\n      项目名称\n    \u003c/th\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;th\u0026gt;\n  排名\n\u0026lt;/th\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"289\"\u003e\n      [AndroidSwipeLayout](https://github.com/daimajia/AndroidSwipeLayout)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;89\u0026quot;\u0026gt;\n  28\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"289\"\u003e\n      [AndroidViewAnimations](https://github.com/daimajia/AndroidViewAnimations)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;89\u0026quot;\u0026gt;\n  32\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"289\"\u003e\n      [AndroidImageSlide](https://github.com/daimajia/AndroidImageSlider)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;89\u0026quot;\u0026gt;\n  84\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"289\"\u003e\n      [NumberProgressBar](https://github.com/daimajia/NumberProgressBar)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;89\u0026quot;\u0026gt;\n  91\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003cp\u003e转自：http://www.lesscode.cn/index.php?s=/view-index-id-299.shtml\u003c/p\u003e","title":"GitHub 上排名前 100 的 Android 开源库简介"},{"content":"CentOS7的yum源中默认好像是没有mysql的。为了解决这个问题，我们要先下载mysql的repo源。\n1. 下载mysql的repo源\n$ wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 2. 安装mysql-community-release-el7-5.noarch.rpm包\n$ sudo rpm -ivh mysql-community-release-el7-5.noarch.rpm 安装这个包后，会获得两个mysql的yum repo源：/etc/yum.repos.d/mysql-community.repo，/etc/yum.repos.d/mysql-community-source.repo。\n3. 安装mysql\n$ sudo yum install mysql-server 根据步骤安装就可以了，不过安装完成后，没有密码，需要重置密码。\n4. 重置密码\n重置密码前，首先要登录\n$ mysql -u root 登录时有可能报这样的错：ERROR 2002 (HY000): Can‘t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock‘ (2)，原因是/var/lib/mysql的访问权限问题。下面的命令把/var/lib/mysql的拥有者改为当前用户：\n$ sudo chown -R openscanner:openscanner /var/lib/mysql 然后，重启服务：\n$ service mysqld restart 接下来登录重置密码：\n$ mysql -u root mysql \u0026amp;gt; use mysql; mysql \u0026amp;gt; update user set password=password(‘123456‘) where user=‘root‘; mysql \u0026amp;gt; exit; 5. 开放3306端口\n$ sudo vim /etc/sysconfig/iptables 添加以下内容：\n-A INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT 保存后重启防火墙：\n$ sudo service iptables restart 这样从其它客户机也可以连接上mysql服务了。\n安装最新mysql出现 用户名密码问题；\n新安装的MySQL5.7，登录时提示密码错误，安装的时候并没有更改密码，后来通过免密码登录的方式更改密码，输入update mysql.user set password=password(‘root’) where user=’root’时提示ERROR 1054 (42S22): Unknown column ‘password’ in ‘field list’，原来是mysql数据库下已经没有password这个字段了，password字段改成了\nauthentication_string update mysql.user set authentication_string=password(\u0026#39;root\u0026#39;) where user=\u0026#39;root\u0026#39; http://blog.csdn.net/u010603691/article/details/50379282\n","permalink":"https://blog.zdltech.com/posts/centos7%E4%B8%8B%E4%BD%BF%E7%94%A8yum%E5%AE%89%E8%A3%85mysql/","summary":"\u003cp\u003eCentOS7的yum源中默认好像是没有mysql的。为了解决这个问题，我们要先下载mysql的repo源。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. 下载mysql的repo源\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e2. 安装mysql-community-release-el7-5.noarch.rpm包\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ sudo rpm -ivh mysql-community-release-el7-5.noarch.rpm\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e安装这个包后，会获得两个mysql的yum repo源：/etc/yum.repos.d/mysql-community.repo，/etc/yum.repos.d/mysql-community-source.repo。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. 安装mysql\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ sudo yum install mysql-server\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e根据步骤安装就可以了，不过安装完成后，没有密码，需要重置密码。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4. 重置密码\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e重置密码前，首先要登录\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ mysql -u root\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e登录时有可能报这样的错：ERROR 2002 (HY000): Can‘t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock‘ (2)，原因是/var/lib/mysql的访问权限问题。下面的命令把/var/lib/mysql的拥有者改为当前用户：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e$\u003c/span\u003e sudo chown \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eR openscanner:openscanner \u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003evar\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003elib\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003emysql\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后，重启服务：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ service mysqld restart\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e接下来登录重置密码：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ mysql -u root\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emysql \u0026amp;gt; use mysql;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emysql \u0026amp;gt; update user set password=password(‘123456‘) where user=‘root‘;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emysql \u0026amp;gt; exit;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e5. 开放3306端口\u003c/strong\u003e\u003c/p\u003e","title":"centos7下使用yum安装mysql"},{"content":"安卓开发过程中一旦开始和硬件打交道，以及涉及到一定的native代码之后，各种闪退就开始浮出水面了，声音录制和播放当然不例外。本文总结了YOLO安卓客户端大半年来的安卓音频实践，整理出一套系统API的封装，命名为RxAndroidAudio。\n概览 安卓平台和声音录制与播放相关的主要是4个类：MediaRecorder，MediaPlayer，AudioRecord和AudioTrack。\nMediaRecorder可以录制视频和音频到文件，MediaPlayer可以播放视频和音频文件，AudioRecord可以提供接口读取音频流数据（byte数组或者short数组），AudioTrack提供接口用于播放音频流数据。\n小结一下，其中MediaRecorder和AudioRecord用于声音录制，MediaPlayer和AudioTrack用于声音播放。AudioRecord和AudioTrack用于操作音频流数据，操作对象是byte数组（或者short数组），而MediaRecorder和MediaPlayer提供了经过更高层抽象和封装接口，直接对文件进行操作，而且他俩功能更丰富，同时支持音频和视频。\n本文会涉及到部分关于声音录制和播放更底层的实现，详细的分析并不是本文的内容范围了，此外本文主要目标并不是声音录制和播放的使用教程，本文主要关注的是上述4个类的使用过程中需要注意的地方。\n基于文件的操作 使用MediaRecorder录制声音到文件：\nmRecorder.prepare()调用需要捕获IOException和RuntimeException，注意需要捕获RuntimeException而不是IllegalStateException，尽管Java doc中只声明了会抛出IllegalStateException，但是查看jni层代码可以看到，prepare的调用也是可能会触发RuntimeException的；\nmRecorder.start()，mRecorder.stop()，mRecorder.reset()调用也需要捕获RuntimeException，理由同上；\n无论是prepare还是start，抛出异常之后都需要reset和release；\n需要保证不会对jni层进行多线程的调用，以免出现下面这样的“静默闪退”（参考资料），RxAndroidAudio通过单例和synchronized方法来保证这一点： A/libc: Fatal signal 11 (SIGSEGV) at 0x00000010 (code=1), thread 9302 (RxComputationTh)\n当用户录完声音，需要停止录音，调用stop的时候，需要sleep一段时间，以免最后几百毫秒录不上，这有可能是安卓系统音频编码器的bug，参考资料； 当prepare返回后，有些低端的设备需要再延迟一段时间开始说话，以免开头几百毫秒录不上，可以在prepare返回后延迟几百毫秒（例如300ms）再显示初始化完毕的UI，原因还需要继续寻找； 使用MediaPlayer播放声音文件：\n和MediaRecorder一样，prepare，start，stop，reset，release函数的调用都需要捕获异常； 和MediaRecorder一样，需要保证不会对jni层进行多线程的调用； MediaPlayer提供了两种音频文件播放方式：通过文件绝对路径指定播放文件，或者使用资源文件id指定；绝对路径的方式需要调用mPlayer.prepare()，而资源文件id方式不需要； 在MediaPlayer.OnCompletionListener的onCompletion回调中，需要延迟一定时间再释放MediaPlayer，否则可能导致下次紧接着的播放无法成功（静默失败，不会抛出异常），原因还需要继续寻找； 基于数据流的操作 使用AudioRecord录制音频流数据：\n和MediaRecorder一样，startRecording需要捕获异常； 和MediaRecorder一样，需要保证不会对jni层进行多线程的调用； mAudioRecord.read的返回值需要进行错误检查； mAudioRecord.read传入的参数类型需要进行区分，ENCODING_PCM_16BIT格式的录音需要传入short数组，ENCODING_PCM_8BIT格式的录音需要传入byte数组，尽管在jni层的实现都是一样的，但是[Java doc][18]明确说明了这一注意事项，理应遵循； RxAndroidAudio使用ExecutorService来执行异步任务（从AudioRecord中循环读取数据）； [使用AudioTrack播放音频流数据][19]：\n和MediaRecorder一样，write需要捕获异常； 和MediaRecorder一样，需要保证不会对jni层进行多线程的调用； Bonus Part Reactive!\nRxAndroidAudio之所以叫Rx，就是因为它尽可能的提供了Reactive的API。\nRxAudioPlayer播放声音文件：\n当然RxAudioPlayer也提供了传统的API：\nRxAmplitude获取当前说话音量等级：\n当然RxAmplitude使用的是AudioRecorder的传统API：\n[18]: http://developer.android.com/reference/android/media/AudioRecord.html#read(byte[], int, int) [19]: https://github.com/Piasy/RxAndroidAudio/blob/master/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FStreamAudioPlayer.java\n","permalink":"https://blog.zdltech.com/posts/%E8%BF%99%E5%8F%AF%E8%83%BD%E6%98%AF%E7%9B%AE%E5%89%8D%E6%9C%80%E9%B2%81%E6%A3%92%E7%9A%84android%E5%A3%B0%E9%9F%B3%E5%BD%95%E5%88%B6%E5%92%8C%E6%92%AD%E6%94%BE%E5%B0%81%E8%A3%85%E5%BA%93%E4%BA%86/","summary":"\u003cp\u003e安卓开发过程中一旦开始和硬件打交道，以及涉及到一定的native代码之后，各种闪退就开始浮出水面了，声音录制和播放当然不例外。本文总结了YOLO安卓客户端大半年来的安卓音频实践，整理出一套系统API的封装，命名为\u003ca href=\"https://github.com/Piasy/RxAndroidAudio\"\u003eRxAndroidAudio\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"section\"\u003e概览\u003c/h2\u003e\n\u003cp\u003e安卓平台和声音录制与播放相关的主要是4个类：MediaRecorder，MediaPlayer，AudioRecord和AudioTrack。\u003c/p\u003e\n\u003cp\u003eMediaRecorder可以录制视频和音频到文件，MediaPlayer可以播放视频和音频文件，AudioRecord可以提供接口读取音频流数据（byte数组或者short数组），AudioTrack提供接口用于播放音频流数据。\u003c/p\u003e\n\u003cp\u003e小结一下，其中MediaRecorder和AudioRecord用于声音录制，MediaPlayer和AudioTrack用于声音播放。AudioRecord和AudioTrack用于操作音频流数据，操作对象是byte数组（或者short数组），而MediaRecorder和MediaPlayer提供了经过更高层抽象和封装接口，直接对文件进行操作，而且他俩功能更丰富，同时支持音频和视频。\u003c/p\u003e\n\u003cp\u003e本文会涉及到部分关于声音录制和播放更底层的实现，详细的分析并不是本文的内容范围了，此外本文主要目标并不是声音录制和播放的使用教程，本文主要关注的是上述4个类的使用过程中需要注意的地方。\u003c/p\u003e\n\u003ch2 id=\"section-1\"\u003e基于文件的操作\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://github.com/Piasy/RxAndroidAudio/blob/master/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FAudioRecorder.java\"\u003e使用MediaRecorder录制声音到文件\u003c/a\u003e：\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003emRecorder.prepare()\u003c/code\u003e调用需要\u003ca href=\"https://github.com/Piasy/RxAndroidAudio/blob/f9c840e3aaf0a4512aee433d250c570cb441e4d8/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FAudioRecorder.java#L131\"\u003e捕获\u003ccode\u003eIOException\u003c/code\u003e和\u003ccode\u003eRuntimeException\u003c/code\u003e\u003c/a\u003e，注意需要捕获\u003ccode\u003eRuntimeException\u003c/code\u003e而不是\u003ccode\u003eIllegalStateException\u003c/code\u003e，尽管Java doc中只声明了会抛出IllegalStateException，但是查看\u003ca href=\"http://androidxref.com/6.0.1_r10/xref/frameworks/base/media/jni/android_media_MediaRecorder.cpp#330\"\u003ejni层代码\u003c/a\u003e可以看到，prepare的调用也是可能会触发RuntimeException的；\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003emRecorder.start()\u003c/code\u003e，\u003ccode\u003emRecorder.stop()\u003c/code\u003e，\u003ccode\u003emRecorder.reset()\u003c/code\u003e调用也需要捕获\u003ccode\u003eRuntimeException\u003c/code\u003e，理由同上；\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e无论是prepare还是start，抛出异常之后\u003ca href=\"https://github.com/Piasy/RxAndroidAudio/blob/f9c840e3aaf0a4512aee433d250c570cb441e4d8/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FAudioRecorder.java#L145\"\u003e都需要reset和release\u003c/a\u003e；\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e需要保证不会对jni层进行多线程的调用，以免出现下面这样的“静默闪退”（\u003ca href=\"http://stackoverflow.com/questions/14023291/fatal-signal-11-sigsegv-at-0x00000000-code-1-phonegap\"\u003e参考资料\u003c/a\u003e），RxAndroidAudio通过\u003ca href=\"https://github.com/Piasy/RxAndroidAudio/blob/f9c840e3aaf0a4512aee433d250c570cb441e4d8/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FAudioRecorder.java#L61\"\u003e单例\u003c/a\u003e和\u003ca href=\"https://github.com/Piasy/RxAndroidAudio/blob/f9c840e3aaf0a4512aee433d250c570cb441e4d8/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FAudioRecorder.java#L116\"\u003esynchronized方法\u003c/a\u003e来保证这一点：\n\u003ccode\u003eA/libc: Fatal signal 11 (SIGSEGV) at 0x00000010 (code=1), thread 9302 (RxComputationTh)\u003c/code\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e当用户录完声音，需要停止录音，调用stop的时候，\u003ca href=\"https://github.com/Piasy/RxAndroidAudio/blob/f9c840e3aaf0a4512aee433d250c570cb441e4d8/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FAudioRecorder.java#L239\"\u003e需要sleep一段时间\u003c/a\u003e，以免最后几百毫秒录不上，这有可能是安卓系统音频编码器的bug，\u003ca href=\"http://stackoverflow.com/a/24092524/3077508\"\u003e参考资料\u003c/a\u003e；\u003c/li\u003e\n\u003cli\u003e当prepare返回后，有些低端的设备需要再延迟一段时间开始说话，以免开头几百毫秒录不上，可以\u003ca href=\"https://github.com/Piasy/RxAndroidAudio/blob/f9c840e3aaf0a4512aee433d250c570cb441e4d8/app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2Fexample%2FFileActivity.java#L210\"\u003e在prepare返回后延迟几百毫秒（例如300ms）再显示初始化完毕的UI\u003c/a\u003e，原因还需要继续寻找；\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://github.com/Piasy/RxAndroidAudio/blob/master/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FRxAudioPlayer.java\"\u003e使用MediaPlayer播放声音文件\u003c/a\u003e：\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e和MediaRecorder一样，prepare，start，stop，reset，release函数的调用都需要捕获异常；\u003c/li\u003e\n\u003cli\u003e和MediaRecorder一样，需要保证不会对jni层进行多线程的调用；\u003c/li\u003e\n\u003cli\u003eMediaPlayer提供了两种音频文件播放方式：通过文件绝对路径指定播放文件，或者使用资源文件id指定；绝对路径的方式\u003ca href=\"https://github.com/Piasy/RxAndroidAudio/blob/f9c840e3aaf0a4512aee433d250c570cb441e4d8/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FRxAudioPlayer.java#L167\"\u003e需要调用\u003ccode\u003emPlayer.prepare()\u003c/code\u003e\u003c/a\u003e，而资源文件id方式不需要；\u003c/li\u003e\n\u003cli\u003e在\u003ccode\u003eMediaPlayer.OnCompletionListener\u003c/code\u003e的\u003ccode\u003eonCompletion\u003c/code\u003e回调中，需要\u003ca href=\"https://github.com/Piasy/RxAndroidAudio/blob/f9c840e3aaf0a4512aee433d250c570cb441e4d8/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FRxAudioPlayer.java#L199\"\u003e延迟一定时间再释放MediaPlayer\u003c/a\u003e，否则可能导致下次紧接着的播放无法成功（静默失败，不会抛出异常），原因还需要继续寻找；\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"section-2\"\u003e基于数据流的操作\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://github.com/Piasy/RxAndroidAudio/blob/master/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FStreamAudioRecorder.java\"\u003e使用AudioRecord录制音频流数据\u003c/a\u003e：\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e和MediaRecorder一样，startRecording需要捕获异常；\u003c/li\u003e\n\u003cli\u003e和MediaRecorder一样，需要保证不会对jni层进行多线程的调用；\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emAudioRecord.read\u003c/code\u003e的返回值需要进行错误检查；\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/Piasy/RxAndroidAudio/blob/f9c840e3aaf0a4512aee433d250c570cb441e4d8/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FStreamAudioRecorder.java#L129\"\u003e\u003ccode\u003emAudioRecord.read\u003c/code\u003e传入的参数类型需要进行区分\u003c/a\u003e，\u003ccode\u003eENCODING_PCM_16BIT\u003c/code\u003e格式的录音需要传入short数组，\u003ccode\u003eENCODING_PCM_8BIT\u003c/code\u003e格式的录音需要传入byte数组，尽管在\u003ca href=\"http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/jni/android_media_AudioRecord.cpp#android_media_AudioRecord_readInArray\"\u003ejni层的实现\u003c/a\u003e都是一样的，但是[Java doc][18]明确说明了这一注意事项，理应遵循；\u003c/li\u003e\n\u003cli\u003eRxAndroidAudio使用\u003ccode\u003eExecutorService\u003c/code\u003e来执行异步任务（从AudioRecord中循环读取数据）；\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e[使用AudioTrack播放音频流数据][19]：\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e和MediaRecorder一样，write需要捕获异常；\u003c/li\u003e\n\u003cli\u003e和MediaRecorder一样，需要保证不会对jni层进行多线程的调用；\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"bonus-part\"\u003eBonus Part\u003c/h2\u003e\n\u003cp\u003eReactive!\u003c/p\u003e\n\u003cp\u003eRxAndroidAudio之所以叫Rx，就是因为它尽可能的提供了Reactive的API。\u003c/p\u003e\n\u003cp\u003eRxAudioPlayer播放声音文件：\u003c/p\u003e\n\u003cp\u003e当然RxAudioPlayer也提供了传统的API：\u003c/p\u003e\n\u003cp\u003eRxAmplitude获取当前说话音量等级：\u003c/p\u003e\n\u003cp\u003e当然RxAmplitude使用的是AudioRecorder的传统API：\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e[18]: \u003ca href=\"http://developer.android.com/reference/android/media/AudioRecord.html#read(byte%5B%5D\"\u003ehttp://developer.android.com/reference/android/media/AudioRecord.html#read(byte[]\u003c/a\u003e, int, int)\n[19]: \u003ca href=\"https://github.com/Piasy/RxAndroidAudio/blob/master/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FStreamAudioPlayer.java\"\u003ehttps://github.com/Piasy/RxAndroidAudio/blob/master/rxandroidaudio%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgithub%2Fpiasy%2Frxandroidaudio%2FStreamAudioPlayer.java\u003c/a\u003e\u003c/p\u003e","title":"这可能是目前最鲁棒的Android声音录制和播放封装库了"},{"content":" 转发：http://www.tuicool.com/articles/nmy26nv 清华大学镜像 无论是Ubuntu源更新还是Android源码下砸，都是使用清华大学镜像。\nUbuntu源使用方法 不多说了，不会的自行Google。\nAndroid源码清华镜像使用方法 官方介绍使用方法 ==== 点击浏览 ====\n我来介绍 1.下载修改好的 repo ， ==== 下载地址 ====，密码： rb5t ；\n2.打开终端，输入：\n``` mkdir ~/bin PATH=~/bin:$PATH \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 3.将 **repo** 放入 `~/bin` 目录下； 4.赋予执行权限，终端输入： \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; ``` chmod a+x ~\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/bin/repo\u0026lt;/span\u0026gt; 5.建立android源码存放目录：\n``` mkdir android_source cd android_source \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 6.查看想要下载的源码的Tag和Builds，网址： [==== **点击查看，需要翻蔷** ====](https://source.android.com/source/build-numbers.html#source-code-tags-and-builds)，这里 @安卓猴 给你们截下图，自己放大查看： ![](http://img1.tuicool.com/bMBn2eu.jpg!web) 7.例如我要下载android-5.1.1_r3，就在终端输入： \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; ``` repo init -u \u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;git:\u0026lt;/span\u0026gt;/\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/aosp.tuna.tsinghua.edu.cn/android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/platform/manifest\u0026lt;/span\u0026gt; -b android-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;5.1\u0026lt;/span\u0026gt;.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1_\u0026lt;/span\u0026gt;r3 8.终端输入下面命令使用 repo 开始源代码下载同步， -j4 表示并发数为4，清华镜像只支持最大并发数4：\n``` repo sync -j4 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 9.漫长的等待后，源码下载完毕。速度在200～800KB/s不等。 ## 结束 Android源码终于下载完毕，历程才刚刚开始，接下来的 **编译** 工作，才最考验耐心。 \u0026amp;nbsp; 清华大学TUNA镜像：https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/ ","permalink":"https://blog.zdltech.com/posts/%E5%9B%BD%E5%86%85%E9%95%9C%E5%83%8F%E5%8A%A0%E9%80%9Fandroid%E6%BA%90%E7%A0%81%E4%B8%8B%E8%BD%BD/","summary":"\u003cdiv\u003e\n  \u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e  转发：http://www.tuicool.com/articles/nmy26nv\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch2 id=\"清华大学镜像\"\u003e清华大学镜像\u003c/h2\u003e\n\u003cp\u003e无论是Ubuntu源更新还是Android源码下砸，都是使用清华大学镜像。\u003c/p\u003e\n\u003ch3 id=\"ubuntu源使用方法\"\u003eUbuntu源使用方法\u003c/h3\u003e\n\u003cp\u003e不多说了，不会的自行Google。\u003c/p\u003e\n\u003ch2 id=\"android源码清华镜像使用方法\"\u003eAndroid源码清华镜像使用方法\u003c/h2\u003e\n\u003ch3 id=\"官方介绍使用方法\"\u003e官方介绍使用方法\u003c/h3\u003e\n\u003cp\u003e\u003ca href=\"https://wiki.tuna.tsinghua.edu.cn/MirrorUsage/android\"\u003e==== \u003cstrong\u003e点击浏览\u003c/strong\u003e ====\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"我来介绍\"\u003e我来介绍\u003c/h3\u003e\n\u003cp\u003e1.下载修改好的 \u003cstrong\u003erepo\u003c/strong\u003e ， \u003ca href=\"http://pan.baidu.com/s/1dDpqsmd\"\u003e==== \u003cstrong\u003e下载地址\u003c/strong\u003e ====\u003c/a\u003e，密码： \u003ccode\u003erb5t\u003c/code\u003e ；\u003c/p\u003e\n\u003cp\u003e2.打开终端，输入：\u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv\u003e\n    ```\n\u003cspan class=\"keyword\"\u003emkdir\u003c/span\u003e ~\u003cspan class=\"regexp\"\u003e/bin\u003c/span\u003e\u003cspan class=\"regexp\"\u003e\nPATH=~/bin\u003c/span\u003e:\u003cspan class=\"variable\"\u003e$PATH\u003c/span\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e3.将 **repo** 放入 `~/bin` 目录下；\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e4.赋予执行权限，终端输入：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003echmod a+x ~\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/bin/repo\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e5.建立android源码存放目录：\u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv\u003e\n    ```\n\u003cspan class=\"keyword\"\u003emkdir\u003c/span\u003e android_source\ncd android_source\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e6.查看想要下载的源码的Tag和Builds，网址： [==== **点击查看，需要翻蔷** ====](https://source.android.com/source/build-numbers.html#source-code-tags-and-builds)，这里 @安卓猴 给你们截下图，自己放大查看：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e![](http://img1.tuicool.com/bMBn2eu.jpg!web) \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e7.例如我要下载android-5.1.1_r3，就在终端输入：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003erepo init -u \u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;git:\u0026lt;/span\u0026gt;/\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/aosp.tuna.tsinghua.edu.cn/android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/platform/manifest\u0026lt;/span\u0026gt; -b android-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;5.1\u0026lt;/span\u0026gt;.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1_\u0026lt;/span\u0026gt;r3\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e8.终端输入下面命令使用 \u003cstrong\u003erepo\u003c/strong\u003e 开始源代码下载同步， \u003ccode\u003e-j4\u003c/code\u003e 表示并发数为4，清华镜像只支持最大并发数4：\u003c/p\u003e","title":"国内镜像加速Android源码下载"},{"content":"该控件由另一篇文章：Android 图片拖拽、放大缩小的自定义控件 扩展而来 http://www.linuxidc.com/Linux/2014-12/110763.htm\n如图：\n思路：在一个自定义View上绘制一张图片（参照前面提到的另一篇文章），在该自定义View上绘制一个自定义的FloatDrawable，也就是图中的浮层。绘制图片和FloatDrawable的交集的补集部分灰色阴影（这个其实很简单，就一句话）。在自定义View的touch中去处理具体的拖动事件和FloatDrawable的变换。图片的绘制和FloatDrawable的绘制以及变换最终其实就是在操作各自的Rect而已，Rect就是一个有矩形，有四个坐标，图片和FloatDrawable就是按照坐标去绘制的。\nCropImageView.java\n该类继承View\n功能：在onDraw方法中画图片、浮层，处理touch事件，最后根据坐标对图片进行剪裁。\npublic class CropImageView extends View {\n// 在touch重要用到的点，\nprivate float mX_1 = 0;\nprivate float mY_1 = 0;\n// 触摸事件判断\nprivate final int STATUS_SINGLE = 1;\nprivate final int STATUS_MULTI_START = 2;\nprivate final int STATUS_MULTI_TOUCHING = 3;\n// 当前状态\nprivate int mStatus = STATUS_SINGLE;\n// 默认裁剪的宽高\nprivate int cropWidth;\nprivate int cropHeight;\n// 浮层Drawable的四个点\nprivate final int EDGE_LT = 1;\nprivate final int EDGE_RT = 2;\nprivate final int EDGE_LB = 3;\nprivate final int EDGE_RB = 4;\nprivate final int EDGE_MOVE_IN = 5;\nprivate final int EDGE_MOVE_OUT = 6;\nprivate final int EDGE_NONE = 7;\npublic int currentEdge = EDGE_NONE;\nprotected float oriRationWH = 0;\nprotected final float maxZoomOut = 5.0f;\nprotected final float minZoomIn = 0.333333f;\nprotected Drawable mDrawable;\nprotected FloatDrawable mFloatDrawable;\nprotected Rect mDrawableSrc = new Rect();// 图片Rect变换时的Rect\nprotected Rect mDrawableDst = new Rect();// 图片Rect\nprotected Rect mDrawableFloat = new Rect();// 浮层的Rect\nprotected boolean isFrist = true;\nprivate boolean isTouchInSquare = true;\nprotected Context mContext;\npublic CropImageView(Context context) {\nsuper(context);\ninit(context);\n}\npublic CropImageView(Context context, AttributeSet attrs) {\nsuper(context, attrs);\ninit(context);\n}\npublic CropImageView(Context context, AttributeSet attrs, int defStyle) {\nsuper(context, attrs, defStyle);\ninit(context);\n}\n@SuppressLint(“NewApi”)\nprivate void init(Context context) {\nthis.mContext = context;\ntry {\nif (android.os.Build.VERSION.SDK_INT \u0026gt;= 11) {\nthis.setLayerType(LAYER_TYPE_SOFTWARE, null);\n}\n} catch (Exception e) {\ne.printStackTrace();\n}\nmFloatDrawable = new FloatDrawable(context);\n}\npublic void setDrawable(Drawable mDrawable, int cropWidth, int cropHeight) {\nthis.mDrawable = mDrawable;\nthis.cropWidth = cropWidth;\nthis.cropHeight = cropHeight;\nthis.isFrist = true;\ninvalidate();\n}\n@SuppressLint(“ClickableViewAccessibility”)\n@Override\npublic boolean onTouchEvent(MotionEvent event) {\nif (event.getPointerCount() \u0026gt; 1) {\nif (mStatus == STATUS_SINGLE) {\nmStatus = STATUS_MULTI_START;\n} else if (mStatus == STATUS_MULTI_START) {\nmStatus = STATUS_MULTI_TOUCHING;\n}\n} else {\nif (mStatus == STATUS_MULTI_START\n|| mStatus == STATUS_MULTI_TOUCHING) {\nmX_1 = event.getX();\nmY_1 = event.getY();\n}\nmStatus = STATUS_SINGLE;\n}\nswitch (event.getAction()) {\ncase MotionEvent.ACTION_DOWN:\nmX_1 = event.getX();\nmY_1 = event.getY();\ncurrentEdge = getTouch((int) mX_1, (int) mY_1);\nisTouchInSquare = mDrawableFloat.contains((int) event.getX(),\n(int) event.getY());\nbreak;\ncase MotionEvent.ACTION_UP:\ncheckBounds();\nbreak;\ncase MotionEvent.ACTION_POINTER_UP:\ncurrentEdge = EDGE_NONE;\nbreak;\ncase MotionEvent.ACTION_MOVE:\nif (mStatus == STATUS_MULTI_TOUCHING) {\n} else if (mStatus == STATUS_SINGLE) {\nint dx = (int) (event.getX() – mX_1);\nint dy = (int) (event.getY() – mY_1);\nmX_1 = event.getX();\nmY_1 = event.getY();\n// 根據得到的那一个角，并且变换Rect\nif (!(dx == 0 \u0026amp;\u0026amp; dy == 0)) {\nswitch (currentEdge) {\ncase EDGE_LT:\nmDrawableFloat.set(mDrawableFloat.left + dx,\nmDrawableFloat.top + dy, mDrawableFloat.right,\nmDrawableFloat.bottom);\nbreak;\ncase EDGE_RT:\nmDrawableFloat.set(mDrawableFloat.left,\nmDrawableFloat.top + dy, mDrawableFloat.right\ndx, mDrawableFloat.bottom);\nbreak; case EDGE_LB:\nmDrawableFloat.set(mDrawableFloat.left + dx,\nmDrawableFloat.top, mDrawableFloat.right,\nmDrawableFloat.bottom + dy);\nbreak;\ncase EDGE_RB:\nmDrawableFloat.set(mDrawableFloat.left,\nmDrawableFloat.top, mDrawableFloat.right + dx,\nmDrawableFloat.bottom + dy);\nbreak;\ncase EDGE_MOVE_IN:\nif (isTouchInSquare) {\nmDrawableFloat.offset((int) dx, (int) dy);\n}\nbreak;\ncase EDGE_MOVE_OUT:\nbreak;\n}\nmDrawableFloat.sort();\ninvalidate();\n}\n}\nbreak;\n}\nreturn true;\n}\n// 根据初触摸点判断是触摸的Rect哪一个角\npublic int getTouch(int eventX, int eventY) {\nif (mFloatDrawable.getBounds().left \u0026lt;= eventX\n\u0026amp;\u0026amp; eventX \u0026lt; (mFloatDrawable.getBounds().left + mFloatDrawable\n.getBorderWidth())\n\u0026amp;\u0026amp; mFloatDrawable.getBounds().top \u0026lt;= eventY\n\u0026amp;\u0026amp; eventY \u0026lt; (mFloatDrawable.getBounds().top + mFloatDrawable\n.getBorderHeight())) {\nreturn EDGE_LT;\n} else if ((mFloatDrawable.getBounds().right – mFloatDrawable\n.getBorderWidth()) \u0026lt;= eventX\n\u0026amp;\u0026amp; eventX \u0026lt; mFloatDrawable.getBounds().right\n\u0026amp;\u0026amp; mFloatDrawable.getBounds().top \u0026lt;= eventY\n\u0026amp;\u0026amp; eventY \u0026lt; (mFloatDrawable.getBounds().top + mFloatDrawable\n.getBorderHeight())) {\nreturn EDGE_RT;\n} else if (mFloatDrawable.getBounds().left \u0026lt;= eventX\n\u0026amp;\u0026amp; eventX \u0026lt; (mFloatDrawable.getBounds().left + mFloatDrawable\n.getBorderWidth())\n\u0026amp;\u0026amp; (mFloatDrawable.getBounds().bottom – mFloatDrawable\n.getBorderHeight()) \u0026lt;= eventY\n\u0026amp;\u0026amp; eventY \u0026lt; mFloatDrawable.getBounds().bottom) {\nreturn EDGE_LB;\n} else if ((mFloatDrawable.getBounds().right – mFloatDrawable\n.getBorderWidth()) \u0026lt;= eventX\n\u0026amp;\u0026amp; eventX \u0026lt; mFloatDrawable.getBounds().right\n\u0026amp;\u0026amp; (mFloatDrawable.getBounds().bottom – mFloatDrawable\n.getBorderHeight()) \u0026lt;= eventY\n\u0026amp;\u0026amp; eventY \u0026lt; mFloatDrawable.getBounds().bottom) {\nreturn EDGE_RB;\n} else if (mFloatDrawable.getBounds().contains(eventX, eventY)) {\nreturn EDGE_MOVE_IN;\n}\nreturn EDGE_MOVE_OUT;\n}\n@Override\nprotected void onDraw(Canvas canvas) {\nif (mDrawable == null) {\nreturn;\n}\nif (mDrawable.getIntrinsicWidth() == 0\n|| mDrawable.getIntrinsicHeight() == 0) {\nreturn;\n}\nconfigureBounds();\n// 在画布上花图片\nmDrawable.draw(canvas);\ncanvas.save();\n// 在画布上画浮层FloatDrawable,Region.Op.DIFFERENCE是表示Rect交集的补集\ncanvas.clipRect(mDrawableFloat, Region.Op.DIFFERENCE);\n// 在交集的补集上画上灰色用来区分\ncanvas.drawColor(Color.parseColor(“#a0000000″));\ncanvas.restore();\n// 画浮层\nmFloatDrawable.draw(canvas);\n}\nprotected void configureBounds() {\n// configureBounds在onDraw方法中调用\n// isFirst的目的是下面对mDrawableSrc和mDrawableFloat只初始化一次，\n// 之后的变化是根据touch事件来变化的，而不是每次执行重新对mDrawableSrc和mDrawableFloat进行设置\nif (isFrist) {\noriRationWH = ((float) mDrawable.getIntrinsicWidth())\n/ ((float) mDrawable.getIntrinsicHeight());\nfinal float scale = mContext.getResources().getDisplayMetrics().density;\nint w = Math.min(getWidth(), (int) (mDrawable.getIntrinsicWidth()\nscale + 0.5f));\nint h = (int) (w / oriRationWH); int left = (getWidth() – w) / 2;\nint top = (getHeight() – h) / 2;\nint right = left + w;\nint bottom = top + h;\nmDrawableSrc.set(left, top, right, bottom);\nmDrawableDst.set(mDrawableSrc);\nint floatWidth = dipTopx(mContext, cropWidth);\nint floatHeight = dipTopx(mContext, cropHeight);\nif (floatWidth \u0026gt; getWidth()) {\nfloatWidth = getWidth();\nfloatHeight = cropHeight * floatWidth / cropWidth;\n}\nif (floatHeight \u0026gt; getHeight()) {\nfloatHeight = getHeight();\nfloatWidth = cropWidth * floatHeight / cropHeight;\n}\nint floatLeft = (getWidth() – floatWidth) / 2;\nint floatTop = (getHeight() – floatHeight) / 2;\nmDrawableFloat.set(floatLeft, floatTop, floatLeft + floatWidth,\nfloatTop + floatHeight);\nisFrist = false;\n}\nmDrawable.setBounds(mDrawableDst);\nmFloatDrawable.setBounds(mDrawableFloat);\n}\n// 在up事件中调用了该方法，目的是检查是否把浮层拖出了屏幕\nprotected void checkBounds() {\nint newLeft = mDrawableFloat.left;\nint newTop = mDrawableFloat.top;\nboolean isChange = false;\nif (mDrawableFloat.left \u0026lt; getLeft()) {\nnewLeft = getLeft();\nisChange = true;\n}\nif (mDrawableFloat.top \u0026lt; getTop()) {\nnewTop = getTop();\nisChange = true;\n}\nif (mDrawableFloat.right \u0026gt; getRight()) {\nnewLeft = getRight() – mDrawableFloat.width();\nisChange = true;\n}\nif (mDrawableFloat.bottom \u0026gt; getBottom()) {\nnewTop = getBottom() – mDrawableFloat.height();\nisChange = true;\n}\nmDrawableFloat.offsetTo(newLeft, newTop);\nif (isChange) {\ninvalidate();\n}\n}\n// 进行图片的裁剪，所谓的裁剪就是根据Drawable的新的坐标在画布上创建一张新的图片\npublic Bitmap getCropImage() {\nBitmap tmpBitmap = Bitmap.createBitmap(getWidth(), getHeight(),\nConfig.RGB_565);\nCanvas canvas = new Canvas(tmpBitmap);\nmDrawable.draw(canvas);\nMatrix matrix = new Matrix();\nfloat scale = (float) (mDrawableSrc.width())\n/ (float) (mDrawableDst.width());\nmatrix.postScale(scale, scale);\nBitmap ret = Bitmap.createBitmap(tmpBitmap, mDrawableFloat.left,\nmDrawableFloat.top, mDrawableFloat.width(),\nmDrawableFloat.height(), matrix, true);\ntmpBitmap.recycle();\ntmpBitmap = null;\nreturn ret;\n}\npublic int dipTopx(Context context, float dpValue) {\nfinal float scale = context.getResources().getDisplayMetrics().density;\nreturn (int) (dpValue * scale + 0.5f);\n}\n}\nFloatDrawable.java\n继承自Drawable\n功能：图片上面的浮动框，通过拖动确定位置\npublic class FloatDrawable extends Drawable {\nprivate Context mContext;\nprivate int offset = 50;\nprivate Paint mLinePaint = new Paint();\nprivate Paint mLinePaint2 = new Paint();\n{\nmLinePaint.setARGB(200, 50, 50, 50);\nmLinePaint.setStrokeWidth(1F);\nmLinePaint.setStyle(Paint.Style.STROKE);\nmLinePaint.setAntiAlias(true);\nmLinePaint.setColor(Color.WHITE);\n//\nmLinePaint2.setARGB(200, 50, 50, 50);\nmLinePaint2.setStrokeWidth(7F);\nmLinePaint2.setStyle(Paint.Style.STROKE);\nmLinePaint2.setAntiAlias(true);\nmLinePaint2.setColor(Color.WHITE);\n}\npublic FloatDrawable(Context context) {\nsuper();\nthis.mContext = context;\n}\npublic int getBorderWidth() {\nreturn dipTopx(mContext, offset);//根据dip计算的像素值，做适配用的\n}\npublic int getBorderHeight() {\nreturn dipTopx(mContext, offset);\n}\n@Override\npublic void draw(Canvas canvas) {\nint left = getBounds().left;\nint top = getBounds().top;\nint right = getBounds().right;\nint bottom = getBounds().bottom;\nRect mRect = new Rect(left + dipTopx(mContext, offset) / 2, top\ndipTopx(mContext, offset) / 2, right\n– dipTopx(mContext, offset) / 2, bottom\n– dipTopx(mContext, offset) / 2);\n//画默认的选择框\ncanvas.drawRect(mRect, mLinePaint);\n//画四个角的四个粗拐角、也就是八条粗线\ncanvas.drawLine((left + dipTopx(mContext, offset) / 2 – 3.5f), top dipTopx(mContext, offset) / 2,\nleft + dipTopx(mContext, offset) – 8f,\ntop + dipTopx(mContext, offset) / 2, mLinePaint2);\ncanvas.drawLine(left + dipTopx(mContext, offset) / 2,\ntop + dipTopx(mContext, offset) / 2,\nleft + dipTopx(mContext, offset) / 2,\ntop + dipTopx(mContext, offset) / 2 + 30, mLinePaint2);\ncanvas.drawLine(right – dipTopx(mContext, offset) + 8f,\ntop + dipTopx(mContext, offset) / 2,\nright – dipTopx(mContext, offset) / 2,\ntop + dipTopx(mContext, offset) / 2, mLinePaint2);\ncanvas.drawLine(right – dipTopx(mContext, offset) / 2,\ntop + dipTopx(mContext, offset) / 2 – 3.5f,\nright – dipTopx(mContext, offset) / 2,\ntop + dipTopx(mContext, offset) / 2 + 30, mLinePaint2);\ncanvas.drawLine((left + dipTopx(mContext, offset) / 2 – 3.5f), bottom\n– dipTopx(mContext, offset) / 2,\nleft + dipTopx(mContext, offset) – 8f,\nbottom – dipTopx(mContext, offset) / 2, mLinePaint2);\ncanvas.drawLine((left + dipTopx(mContext, offset) / 2), bottom\n– dipTopx(mContext, offset) / 2,\n(left + dipTopx(mContext, offset) / 2),\nbottom – dipTopx(mContext, offset) / 2 – 30f, mLinePaint2);\ncanvas.drawLine((right – dipTopx(mContext, offset) + 8f), bottom\n– dipTopx(mContext, offset) / 2,\nright – dipTopx(mContext, offset) / 2,\nbottom – dipTopx(mContext, offset) / 2, mLinePaint2);\ncanvas.drawLine((right – dipTopx(mContext, offset) / 2), bottom\n– dipTopx(mContext, offset) / 2 – 30f,\nright – dipTopx(mContext, offset) / 2,\nbottom – dipTopx(mContext, offset) / 2 + 3.5f, mLinePaint2); }\n@Override\npublic void setBounds(Rect bounds) {\nsuper.setBounds(new Rect(bounds.left – dipTopx(mContext, offset) / 2,\nbounds.top – dipTopx(mContext, offset) / 2, bounds.right\ndipTopx(mContext, offset) / 2, bounds.bottom dipTopx(mContext, offset) / 2));\n} @Override\npublic void setAlpha(int alpha) {\n}\n@Override\npublic void setColorFilter(ColorFilter cf) {\n}\n@Override\npublic int getOpacity() {\nreturn 0;\n}\npublic int dipTopx(Context context, float dpValue) {\nfinal float scale = context.getResources().getDisplayMetrics().density;\nreturn (int) (dpValue * scale + 0.5f);\n}\n}\n使用\n布局中：\n\u0026lt;RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android”\nxmlns:tools=”http://schemas.android.com/tools”\nandroid:layout_width=”match_parent”\nandroid:layout_height=”match_parent” \u0026gt;\n\u0026lt;com.onehead.cropimage.CropImageView\nandroid:id=”@+id/cropimage”\nandroid:layout_width=”match_parent”\nandroid:layout_height=”match_parent” /\u0026gt;\nActivity中：\npublic class MainActivity extends ActionBarActivity {\nprivate CropImageView mView;\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\nsuper.onCreate(savedInstanceState);\nsetContentView(R.layout.activity_main);\nmView = (CropImageView) findViewById(R.id.cropimage);\n//设置资源和默认长宽\nmView.setDrawable(getResources().getDrawable(R.drawable.test2), 300,\n300);\n//调用该方法得到剪裁好的图片\nBitmap mBitmap= mView.getCropImage();\n}\n}\n","permalink":"https://blog.zdltech.com/posts/android-%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6-%E5%9B%BE%E7%89%87%E5%89%AA%E8%A3%81/","summary":"\u003cp\u003e该控件由另一篇文章：Android 图片拖拽、放大缩小的自定义控件 扩展而来 \u003ca href=\"http://www.linuxidc.com/Linux/2014-12/110763.htm\"\u003ehttp://www.linuxidc.com/Linux/2014-12/110763.htm\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e如图：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Android 自定义控件——图片剪裁\" loading=\"lazy\" src=\"http://www.linuxidc.com/upload/2014_12/14122308339067.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://www.linuxidc.com/upload/2014_12/141223083662301.png\"\u003e\u003c/p\u003e\n\u003cp\u003e思路：在一个自定义View上绘制一张图片（参照前面提到的另一篇\u003ca href=\"http://www.linuxidc.com/Linux/2014-12/110763.htm\"\u003e文章\u003c/a\u003e），在该自定义View上绘制一个自定义的FloatDrawable，也就是图中的浮层。绘制图片和FloatDrawable的交集的补集部分灰色阴影（这个其实很简单，就一句话）。在自定义View的touch中去处理具体的拖动事件和FloatDrawable的变换。图片的绘制和FloatDrawable的绘制以及变换最终其实就是在操作各自的Rect而已，Rect就是一个有矩形，有四个坐标，图片和FloatDrawable就是按照坐标去绘制的。\u003c/p\u003e\n\u003cp\u003eCropImageView.java\u003c/p\u003e\n\u003cp\u003e该类继承View\u003c/p\u003e\n\u003cp\u003e功能：在onDraw方法中画图片、浮层，处理touch事件，最后根据坐标对图片进行剪裁。\u003c/p\u003e\n\u003cp\u003epublic class CropImageView extends View {\u003cbr\u003e\n// 在touch重要用到的点，\u003cbr\u003e\nprivate float mX_1 = 0;\u003cbr\u003e\nprivate float mY_1 = 0;\u003cbr\u003e\n// 触摸事件判断\u003cbr\u003e\nprivate final int STATUS_SINGLE = 1;\u003cbr\u003e\nprivate final int STATUS_MULTI_START = 2;\u003cbr\u003e\nprivate final int STATUS_MULTI_TOUCHING = 3;\u003cbr\u003e\n// 当前状态\u003cbr\u003e\nprivate int mStatus = STATUS_SINGLE;\u003cbr\u003e\n// 默认裁剪的宽高\u003cbr\u003e\nprivate int cropWidth;\u003cbr\u003e\nprivate int cropHeight;\u003cbr\u003e\n// 浮层Drawable的四个点\u003cbr\u003e\nprivate final int EDGE_LT = 1;\u003cbr\u003e\nprivate final int EDGE_RT = 2;\u003cbr\u003e\nprivate final int EDGE_LB = 3;\u003cbr\u003e\nprivate final int EDGE_RB = 4;\u003cbr\u003e\nprivate final int EDGE_MOVE_IN = 5;\u003cbr\u003e\nprivate final int EDGE_MOVE_OUT = 6;\u003cbr\u003e\nprivate final int EDGE_NONE = 7;\u003c/p\u003e","title":"Android 自定义控件——图片剪裁"},{"content":"支持圆形裁剪框，裁剪后生成圆形图案。\n代码基于开源项目修改，github上项目链接：https://github.com/shengge/android-crop\n还是贴下效果图：\n说一下圆形裁剪实现部分：\n1.UI方面，自定义CircleHighlightView继承至HighlightView（原有的矩形裁剪框实现），直接看draw方法实现 **[java]** [view plain](http://blog.csdn.net/jiantao_yang/article/details/43635581#) [copy](http://blog.csdn.net/jiantao_yang/article/details/43635581#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/600342)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/600342/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; draw(Canvas canvas) { - canvas.save(); - Path path = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Path(); - outlinePaint.setStrokeWidth( outlineWidth); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!hasFocus()) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//没焦点是，直接画一个黑色的矩形框\u0026lt;/span\u0026gt; - outlinePaint.setColor( Color.BLACK); - canvas.drawRect( drawRect, outlinePaint); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - Rect viewDrawingRect = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect(); - viewContext.getDrawingRect( viewDrawingRect); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//已裁剪框drawRect，算出圆的半径\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//添加一个圆形\u0026lt;/span\u0026gt; - path.addCircle( drawRect.left + radius, drawRect.top + radius, radius, Direction.CW); - outlinePaint.setColor( highlightColor); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//裁剪画布，path之外的区域，以outsidePaint填充\u0026lt;/span\u0026gt; - canvas.clipPath( path, Region.Op.DIFFERENCE); - canvas.drawRect( viewDrawingRect, outsidePaint); - - canvas.restore(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//绘制圆上高亮线，这里outlinePaint定义的Paint.Style.STROKE：表示只绘制几何图形的轮廓。\u0026lt;/span\u0026gt; - canvas.drawPath( path, outlinePaint); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//当modifyMode为grow时，绘制handles,也就是那四个小圆\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(handleMode == HandleMode.Always || (handleMode == HandleMode.Changing \u0026amp;\u0026amp; modifyMode == ModifyMode.Grow)) { - drawHandles( canvas); - } - } - } \u0026lt;/div\u0026gt; 这里就实现了画圆形裁剪框的操作。 ### \u0026lt;a name=\u0026quot;t1\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;2. 响应和处理用户触摸事件 #### \u0026lt;a name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;1). 判断触摸点坐标与圆的位置 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/600342)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/600342/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 根据x,y坐标，计算其与圆的关系（圆上、圆内、圆外）\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param x\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param y\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getHitOnCircle(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y) { - Rect r = computeLayout(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; retval = GROW_NONE; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; hysteresis = 20F; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; centerX = r.left + radius; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; centerY = r.top + radius; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//判断触摸位置是否在圆上\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;double\u0026lt;/span\u0026gt; rRadius = Math.sqrt( ret); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(gap \u0026lt;= hysteresis) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 圆上。这里由于是继承至HighlightView（绘制矩形框的）来处理，所以模拟返回了左右上下，而非纯圆上，亲测可用。你也可以自定义。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(x \u0026lt; centerX) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// left\u0026lt;/span\u0026gt; - retval |= GROW_LEFT_EDGE; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - retval |= GROW_RIGHT_EDGE; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(y \u0026lt; centerY) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// up\u0026lt;/span\u0026gt; - retval |= GROW_TOP_EDGE; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - retval |= GROW_BOTTOM_EDGE; - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(rRadius \u0026gt; radius) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// outside\u0026lt;/span\u0026gt; - retval = GROW_NONE; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(rRadius \u0026lt; radius) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// inside，圆内就执行move\u0026lt;/span\u0026gt; - retval = MOVE; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; retval; - } \u0026lt;/div\u0026gt; 由于是继承至HighLightView(矩形框)来实现的，如果点（x,y）位置圆上，还需判断其它那个象限，对应矩形的上下左右位置。 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; #### \u0026lt;a name=\u0026quot;t3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;2). 移动裁剪框 \u0026lt;div\u0026gt; 若上一步判断，触摸点在圆内，就会返回MOVE，并处理移动过程。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/600342)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/600342/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Grows the cropping rectangle by (dx, dy) in image space\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; moveBy(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; dy) { - Rect invalRect = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect(drawRect); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//移动\u0026lt;/span\u0026gt; - cropRect.offset(dx, dy); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Put the cropping rectangle inside image rectangle\u0026lt;/span\u0026gt; - cropRect.offset( - - cropRect.offset( - - drawRect = computeLayout(); - invalRect.union(drawRect); - invalRect.inset(-(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) handleRadius, -(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) handleRadius); - viewContext.invalidate(invalRect); - } \u0026lt;/div\u0026gt; 移动裁剪框并保证其它image图片显示范围内。 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; #### \u0026lt;a name=\u0026quot;t4\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;3). 缩放裁剪框 \u0026lt;div\u0026gt; 此过程和上一步类似，将cropRect矩阵进行等比缩放即可，这里就细说了，详见代码：HighLightView.growBy(float dx, float dy) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t5\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;3.将裁剪图片保存为圆形 \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/600342)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/600342/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param bitmap src图片\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; Bitmap getCircleBitmap(Bitmap bitmap) { - Bitmap output = Bitmap.createBitmap( bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); - Canvas canvas = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Canvas( output); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; color = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xff424242\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Paint paint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Rect rect = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect( \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, bitmap.getWidth(), bitmap.getHeight()); - - paint.setAntiAlias( \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - paint.setFilterBitmap( \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - paint.setDither( \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - canvas.drawARGB( \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - paint.setColor( color); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//在画布上绘制一个圆\u0026lt;/span\u0026gt; - canvas.drawCircle( bitmap.getWidth() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, bitmap.getHeight() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, bitmap.getWidth() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, paint); - paint.setXfermode( \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PorterDuffXfermode( Mode.SRC_IN)); - canvas.drawBitmap( bitmap, rect, rect, paint); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; output; - } \u0026lt;/div\u0026gt; 注意：将bitmap保存为file时，格式请选择png，不然会出现黑色背景。 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 鉴于水平有限，从小语文就没学好，描述比较凌乱，需要深入理解的请阅读[源代码](http://download.csdn.net/detail/jiantao_yang/8433015)。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 附：另外一个很好开源项目 https://github.com/edmodo/cropper \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-imagecropper-%E7%9F%A9%E5%BD%A2-%E5%9C%86%E5%BD%A2-%E8%A3%81%E5%89%AA%E6%A1%86/","summary":"\u003cp\u003e\u003cstrong\u003e支持圆形裁剪框，裁剪后生成圆形图案。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e代码基于开源项目修改，github上项目链接：https://github.com/shengge/android-crop\u003c/p\u003e\n\u003cp\u003e还是贴下效果图：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20150208105748862?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmlhblRhb19ZYW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e   \u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20150208105811420?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmlhblRhb19ZYW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e说一下圆形裁剪实现部分：\u003c/p\u003e\n\u003ch3 id=\"1ui方面自定义circlehighlightview继承至highlightview原有的矩形裁剪框实现直接看draw方法实现\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003e\u003cstrong\u003e1.UI方面\u003c/strong\u003e，自定义CircleHighlightView继承至HighlightView（原有的矩形裁剪框实现），直接看draw方法实现\u003c/h3\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u003cspan class=\"tracking-ad\" data-mod=\"popu_168\"\u003e\u003cspan class=\"tracking-ad\" data-mod=\"popu_168\"\u003e [copy](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u003c/span\u003e\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n\n    \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/600342)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/600342/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \n    \n    \n      - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; draw(Canvas canvas) {\n      \n      - canvas.save();\n      \n      - Path path = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Path();\n      \n      - outlinePaint.setStrokeWidth( outlineWidth);\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!hasFocus()) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//没焦点是，直接画一个黑色的矩形框\u0026lt;/span\u0026gt;\n      \n      - outlinePaint.setColor( Color.BLACK);\n      \n      - canvas.drawRect( drawRect, outlinePaint);\n      \n      - }\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n      \n      - Rect viewDrawingRect = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect();\n      \n      - viewContext.getDrawingRect( viewDrawingRect);\n      \n      - \n      - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//已裁剪框drawRect，算出圆的半径\u0026lt;/span\u0026gt;\n      \n      \n      - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//添加一个圆形\u0026lt;/span\u0026gt;\n      \n      - path.addCircle( drawRect.left + radius, drawRect.top + radius, radius, Direction.CW);\n      \n      - outlinePaint.setColor( highlightColor);\n      \n      - \n      - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//裁剪画布，path之外的区域，以outsidePaint填充\u0026lt;/span\u0026gt;\n      \n      - canvas.clipPath( path, Region.Op.DIFFERENCE);\n      \n      - canvas.drawRect( viewDrawingRect, outsidePaint);\n      \n      - \n      - canvas.restore();\n      \n      - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//绘制圆上高亮线，这里outlinePaint定义的Paint.Style.STROKE：表示只绘制几何图形的轮廓。\u0026lt;/span\u0026gt;\n      \n      - canvas.drawPath( path, outlinePaint);\n      \n      - \n      - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//当modifyMode为grow时，绘制handles,也就是那四个小圆\u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(handleMode == HandleMode.Always || (handleMode == HandleMode.Changing \u0026amp;\u0026amp; modifyMode == ModifyMode.Grow)) {\n      \n      - drawHandles( canvas);\n      \n      - }\n      \n      - }\n      \n      - }\n      \n    \u0026lt;/div\u0026gt; \n    \n    \n\n      这里就实现了画圆形裁剪框的操作。\n    \n\n    \n    ### \u0026lt;a name=\u0026quot;t1\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;2. 响应和处理用户触摸事件\n    \n    #### \u0026lt;a name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;1). 判断触摸点坐标与圆的位置\n    \n    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n          \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n            **[java]** [view plain](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n            \n            \u0026lt;div\u0026gt;\n              \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n              \u0026lt;/embed\u0026gt;\n            \u0026lt;/div\u0026gt;\n            \n            \n\n              \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/600342)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/600342/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \n              \n              \n                - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n                \n                - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 根据x,y坐标，计算其与圆的关系（圆上、圆内、圆外）\u0026lt;/span\u0026gt;\n                \n                - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param x\u0026lt;/span\u0026gt;\n                \n                - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param y\u0026lt;/span\u0026gt;\n                \n                - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return\u0026lt;/span\u0026gt;\n                \n                - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n                \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getHitOnCircle(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y) {\n                \n                - Rect r = computeLayout();\n                \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; retval = GROW_NONE;\n                \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; hysteresis = 20F;\n                \n                \n                - \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; centerX = r.left + radius;\n                \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; centerY = r.top + radius;\n                \n                - \n                - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//判断触摸位置是否在圆上\u0026lt;/span\u0026gt;\n                \n                \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;double\u0026lt;/span\u0026gt; rRadius = Math.sqrt( ret);\n                \n                \n                - \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(gap \u0026lt;= hysteresis) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 圆上。这里由于是继承至HighlightView（绘制矩形框的）来处理，所以模拟返回了左右上下，而非纯圆上，亲测可用。你也可以自定义。\u0026lt;/span\u0026gt;\n                \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(x \u0026lt; centerX) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// left\u0026lt;/span\u0026gt;\n                \n                - retval |= GROW_LEFT_EDGE;\n                \n                - }\n                \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n                \n                - retval |= GROW_RIGHT_EDGE;\n                \n                - }\n                \n                - \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(y \u0026lt; centerY) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// up\u0026lt;/span\u0026gt;\n                \n                - retval |= GROW_TOP_EDGE;\n                \n                - }\n                \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n                \n                - retval |= GROW_BOTTOM_EDGE;\n                \n                - }\n                \n                - }\n                \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(rRadius \u0026gt; radius) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// outside\u0026lt;/span\u0026gt;\n                \n                - retval = GROW_NONE;\n                \n                - }\n                \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(rRadius \u0026lt; radius) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// inside，圆内就执行move\u0026lt;/span\u0026gt;\n                \n                - retval = MOVE;\n                \n                - }\n                \n                - \n                - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; retval;\n                \n                - }\n                \n              \u0026lt;/div\u0026gt; \n              \n              \n\n                由于是继承至HighLightView(矩形框)来实现的，如果点（x,y）位置圆上，还需判断其它那个象限，对应矩形的上下左右位置。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e \n\u003cpre\u003e\u003ccode\u003e              \u0026lt;div\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              #### \u0026lt;a name=\u0026quot;t3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;2).  移动裁剪框\n              \n              \u0026lt;div\u0026gt;\n                若上一步判断，触摸点在圆内，就会返回MOVE，并处理移动过程。\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div\u0026gt;\n                \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n                  \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n                    \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n                      **[java]** [view plain](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n                      \n                      \u0026lt;div\u0026gt;\n                        \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt;\n                        \u0026lt;/embed\u0026gt;\n                      \u0026lt;/div\u0026gt;\n                      \n                      \n\n                        \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/600342)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/600342/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \n                        \n                        \n                          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Grows the cropping rectangle by (dx, dy) in image space\u0026lt;/span\u0026gt;\n                          \n                          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; moveBy(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; dy) {\n                          \n                          - Rect invalRect = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect(drawRect);\n                          \n                          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//移动\u0026lt;/span\u0026gt;\n                          \n                          - cropRect.offset(dx, dy);\n                          \n                          - \n                          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Put the cropping rectangle inside image rectangle\u0026lt;/span\u0026gt;\n                          \n                          - cropRect.offset(\n                          \n                          \n                          \n                          - \n                          - cropRect.offset(\n                          \n                          \n                          \n                          - \n                          - drawRect = computeLayout();\n                          \n                          - invalRect.union(drawRect);\n                          \n                          - invalRect.inset(-(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) handleRadius, -(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) handleRadius);\n                          \n                          - viewContext.invalidate(invalRect);\n                          \n                          - }\n                          \n                        \u0026lt;/div\u0026gt; \n                        \n                        \n\n                          移动裁剪框并保证其它image图片显示范围内。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e \n\u003cpre\u003e\u003ccode\u003e                        \u0026lt;div\u0026gt;\n                        \u0026lt;/div\u0026gt;\n                        \n                        #### \u0026lt;a name=\u0026quot;t4\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;3). 缩放裁剪框\n                        \n                        \u0026lt;div\u0026gt;\n                          此过程和上一步类似，将cropRect矩阵进行等比缩放即可，这里就细说了，详见代码：HighLightView.growBy(float dx, float dy)\n                        \u0026lt;/div\u0026gt;\n                        \n                        \u0026lt;div\u0026gt;\n                        \u0026lt;/div\u0026gt;\n                        \n                        ### \u0026lt;a name=\u0026quot;t5\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;3.将裁剪图片保存为圆形\n                        \n                        \u0026lt;div\u0026gt;\n                          \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n                            \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n                              \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n                                **[java]** [view plain](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_168\u0026quot;\u0026gt; [copy](http://blog.csdn.net/jiantao_yang/article/details/43635581#)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n                                \n                                \u0026lt;div\u0026gt;\n                                  \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt;\n                                  \u0026lt;/embed\u0026gt;\n                                \u0026lt;/div\u0026gt;\n                                \n                                \n\n                                  \u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_167\u0026quot;\u0026gt;[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/600342)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tracking-ad\u0026quot; data-mod=\u0026quot;popu_170\u0026quot;\u0026gt;[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/600342/fork)\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \n                                  \n                                  \n                                    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n                                    \n                                    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param bitmap src图片\u0026lt;/span\u0026gt;\n                                    \n                                    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return\u0026lt;/span\u0026gt;\n                                    \n                                    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n                                    \n                                    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; Bitmap getCircleBitmap(Bitmap bitmap) {\n                                    \n                                    - Bitmap output = Bitmap.createBitmap( bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);\n                                    \n                                    - Canvas canvas = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Canvas( output);\n                                    \n                                    - \n                                    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; color = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xff424242\u0026lt;/span\u0026gt;;\n                                    \n                                    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Paint paint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint();\n                                    \n                                    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Rect rect = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect( \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, bitmap.getWidth(), bitmap.getHeight());\n                                    \n                                    - \n                                    - paint.setAntiAlias( \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n                                    \n                                    - paint.setFilterBitmap( \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n                                    \n                                    - paint.setDither( \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n                                    \n                                    - canvas.drawARGB( \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n                                    \n                                    - paint.setColor( color);\n                                    \n                                    - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//在画布上绘制一个圆\u0026lt;/span\u0026gt;\n                                    \n                                    - canvas.drawCircle( bitmap.getWidth() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, bitmap.getHeight() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, bitmap.getWidth() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, paint);\n                                    \n                                    - paint.setXfermode( \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PorterDuffXfermode( Mode.SRC_IN));\n                                    \n                                    - canvas.drawBitmap( bitmap, rect, rect, paint);\n                                    \n                                    - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; output;\n                                    \n                                    - }\n                                    \n                                  \u0026lt;/div\u0026gt; \n                                  \n                                  \n\n                                    注意：将bitmap保存为file时，格式请选择png，不然会出现黑色背景。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e \n\u003cpre\u003e\u003ccode\u003e                                  \u0026lt;div\u0026gt;\n                                  \u0026lt;/div\u0026gt;\n                                  \n                                  \u0026lt;div\u0026gt;\n                                    鉴于水平有限，从小语文就没学好，描述比较凌乱，需要深入理解的请阅读[源代码](http://download.csdn.net/detail/jiantao_yang/8433015)。\n                                  \u0026lt;/div\u0026gt;\n                                  \n                                  \u0026lt;div\u0026gt;\n                                  \u0026lt;/div\u0026gt;\n                                  \n                                  \u0026lt;div\u0026gt;\n                                    附：另外一个很好开源项目 https://github.com/edmodo/cropper\n                                  \u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e","title":"Android ImageCropper 矩形 圆形 裁剪框"},{"content":"最近项目里面又要加一个拍照搜题的功能，也就是用户对着不会做的题目拍一张照片，将照片的文字使用ocr识别出来，再调用题库搜索接口搜索出来展示给用户，类似于小猿搜题、学霸君等app。\n其实Android提供Intent让我们打开系统的相机，但是系统相机跟自己app风格不搭，而且用起来体验不好。所以我使用了SDK提供的camera API自定义了一个相机，并且在相机界面上面添加了参考线，有助于用户将题目拍正，提高ocr的识别率。\n1、绘制参考线的代码\n![复制代码](http://common.cnblogs.com/images/copycode.gif) 1 public class ReferenceLine extends View { 2 3 private Paint mLinePaint; 4 5 public ReferenceLine(Context context) { 6 super(context); 7 init(); 8 } 9 10 public ReferenceLine(Context context, AttributeSet attrs) { 11 super(context, attrs); 12 init(); 13 } 14 15 public ReferenceLine(Context context, AttributeSet attrs, int defStyleAttr) { 16 super(context, attrs, defStyleAttr); 17 init(); 18 } 19 20 private void init() { 21 mLinePaint = new Paint(); 22 mLinePaint.setAntiAlias(true); 23 mLinePaint.setColor(Color.parseColor(\u0026#34;#45e0e0e0\u0026#34;)); 24 mLinePaint.setStrokeWidth(1); 25 } 26 27 28 29 @Override 30 protected void onDraw(Canvas canvas) { 31 int screenWidth = Utils.getScreenWH(getContext()).widthPixels; 32 int screenHeight = Utils.getScreenWH(getContext()).heightPixels; 33 34 int width = screenWidth/3; 35 int height = screenHeight/3; 36 37 for (int i = width, j = 0;i \u0026amp;lt; screenWidth \u0026amp;\u0026amp; j\u0026amp;lt;2;i += width, j++) { 38 canvas.drawLine(i, 0, i, screenHeight, mLinePaint); 39 } 40 for (int j = height,i = 0;j \u0026amp;lt; screenHeight \u0026amp;\u0026amp; i \u0026amp;lt; 2;j += height,i++) { 41 canvas.drawLine(0, j, screenWidth, j, mLinePaint); 42 } 43 } 44 45 46 } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 2、自定义相机代码\n这里主要是要创建一个SurfaceView，将摄像头的预览界面放到SurfaceView中显示。\n![复制代码](http://common.cnblogs.com/images/copycode.gif) 1 package com.bbk.lling.camerademo.camare; 2 3 import android.content.Context; 4 import android.content.res.Configuration; 5 import android.graphics.PixelFormat; 6 import android.graphics.Rect; 7 import android.hardware.Camera; 8 import android.hardware.Camera.AutoFocusCallback; 9 import android.hardware.Camera.PictureCallback; 10 import android.util.AttributeSet; 11 import android.util.Log; 12 import android.view.MotionEvent; 13 import android.view.SurfaceHolder; 14 import android.view.SurfaceView; 15 import android.view.View; 16 import android.widget.RelativeLayout; 17 import android.widget.Toast; 18 19 import com.bbk.lling.camerademo.utils.Utils; 20 21 import java.io.IOException; 22 import java.util.ArrayList; 23 import java.util.Date; 24 import java.util.List; 25 26 /** 27 * @Class: CameraPreview 28 * @Description: 自定义相机 29 * @author: lling(www.cnblogs.com/liuling) 30 * @Date: 2015/10/25 31 */ 32 public class CameraPreview extends SurfaceView implements 33 SurfaceHolder.Callback, AutoFocusCallback { 34 private static final String TAG = \u0026#34;CameraPreview\u0026#34;; 35 36 private int viewWidth = 0; 37 private int viewHeight = 0; 38 39 /** 监听接口 */ 40 private OnCameraStatusListener listener; 41 42 private SurfaceHolder holder; 43 private Camera camera; 44 private FocusView mFocusView; 45 46 //创建一个PictureCallback对象，并实现其中的onPictureTaken方法 47 private PictureCallback pictureCallback = new PictureCallback() { 48 49 // 该方法用于处理拍摄后的照片数据 50 @Override 51 public void onPictureTaken(byte[] data, Camera camera) { 52 // 停止照片拍摄 53 try { 54 camera.stopPreview(); 55 } catch (Exception e) { 56 } 57 // 调用结束事件 58 if (null != listener) { 59 listener.onCameraStopped(data); 60 } 61 } 62 }; 63 64 // Preview类的构造方法 65 public CameraPreview(Context context, AttributeSet attrs) { 66 super(context, attrs); 67 // 获得SurfaceHolder对象 68 holder = getHolder(); 69 // 指定用于捕捉拍照事件的SurfaceHolder.Callback对象 70 holder.addCallback(this); 71 // 设置SurfaceHolder对象的类型 72 holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 73 setOnTouchListener(onTouchListener); 74 } 75 76 // 在surface创建时激发 77 public void surfaceCreated(SurfaceHolder holder) { 78 Log.e(TAG, \u0026#34;==surfaceCreated==\u0026#34;); 79 if(!Utils.checkCameraHardware(getContext())) { 80 Toast.makeText(getContext(), \u0026#34;摄像头打开失败！\u0026#34;, Toast.LENGTH_SHORT).show(); 81 return; 82 } 83 // 获得Camera对象 84 camera = getCameraInstance(); 85 try { 86 // 设置用于显示拍照摄像的SurfaceHolder对象 87 camera.setPreviewDisplay(holder); 88 } catch (IOException e) { 89 e.printStackTrace(); 90 // 释放手机摄像头 91 camera.release(); 92 camera = null; 93 } 94 updateCameraParameters(); 95 if (camera != null) { 96 camera.startPreview(); 97 } 98 setFocus(); 99 } 100 101 // 在surface销毁时激发 102 public void surfaceDestroyed(SurfaceHolder holder) { 103 Log.e(TAG, \u0026#34;==surfaceDestroyed==\u0026#34;); 104 // 释放手机摄像头 105 camera.release(); 106 camera = null; 107 } 108 109 // 在surface的大小发生改变时激发 110 public void surfaceChanged(final SurfaceHolder holder, int format, int w, 111 int h) { 112 // stop preview before making changes 113 try { 114 camera.stopPreview(); 115 } catch (Exception e){ 116 // ignore: tried to stop a non-existent preview 117 } 118 // set preview size and make any resize, rotate or 119 // reformatting changes here 120 updateCameraParameters(); 121 // start preview with new settings 122 try { 123 camera.setPreviewDisplay(holder); 124 camera.startPreview(); 125 126 } catch (Exception e){ 127 Log.d(TAG, \u0026#34;Error starting camera preview: \u0026#34; + e.getMessage()); 128 } 129 setFocus(); 130 } 131 132 /** 133 * 点击显示焦点区域 134 */ 135 OnTouchListener onTouchListener = new OnTouchListener() { 136 @SuppressWarnings(\u0026#34;deprecation\u0026#34;) 137 @Override 138 public boolean onTouch(View v, MotionEvent event) { 139 if (event.getAction() == MotionEvent.ACTION_DOWN) { 140 int width = mFocusView.getWidth(); 141 int height = mFocusView.getHeight(); 142 mFocusView.setX(event.getX() - (width / 2)); 143 mFocusView.setY(event.getY() - (height / 2)); 144 mFocusView.beginFocus(); 145 } else if (event.getAction() == MotionEvent.ACTION_UP) { 146 focusOnTouch(event); 147 } 148 return true; 149 } 150 }; 151 152 /** 153 * 获取摄像头实例 154 * @return 155 */ 156 private Camera getCameraInstance() { 157 Camera c = null; 158 try { 159 int cameraCount = 0; 160 Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); 161 cameraCount = Camera.getNumberOfCameras(); // get cameras number 162 163 for (int camIdx = 0; camIdx \u0026amp;lt; cameraCount; camIdx++) { 164 Camera.getCameraInfo(camIdx, cameraInfo); // get camerainfo 165 // 代表摄像头的方位，目前有定义值两个分别为CAMERA_FACING_FRONT前置和CAMERA_FACING_BACK后置 166 if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { 167 try { 168 c = Camera.open(camIdx); //打开后置摄像头 169 } catch (RuntimeException e) { 170 Toast.makeText(getContext(), \u0026#34;摄像头打开失败！\u0026#34;, Toast.LENGTH_SHORT).show(); 171 } 172 } 173 } 174 if (c == null) { 175 c = Camera.open(0); // attempt to get a Camera instance 176 } 177 } catch (Exception e) { 178 Toast.makeText(getContext(), \u0026#34;摄像头打开失败！\u0026#34;, Toast.LENGTH_SHORT).show(); 179 } 180 return c; 181 } 182 183 private void updateCameraParameters() { 184 if (camera != null) { 185 Camera.Parameters p = camera.getParameters(); 186 187 setParameters(p); 188 189 try { 190 camera.setParameters(p); 191 } catch (Exception e) { 192 Camera.Size previewSize = findBestPreviewSize(p); 193 p.setPreviewSize(previewSize.width, previewSize.height); 194 p.setPictureSize(previewSize.width, previewSize.height); 195 camera.setParameters(p); 196 } 197 } 198 } 199 200 /** 201 * @param p 202 */ 203 private void setParameters(Camera.Parameters p) { 204 List\u0026amp;lt;String\u0026amp;gt; focusModes = p.getSupportedFocusModes(); 205 if (focusModes 206 .contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { 207 p.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); 208 } 209 210 long time = new Date().getTime(); 211 p.setGpsTimestamp(time); 212 // 设置照片格式 213 p.setPictureFormat(PixelFormat.JPEG); 214 Camera.Size previewSize = findPreviewSizeByScreen(p); 215 p.setPreviewSize(previewSize.width, previewSize.height); 216 p.setPictureSize(previewSize.width, previewSize.height); 217 p.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); 218 if (getContext().getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) { 219 camera.setDisplayOrientation(90); 220 p.setRotation(90); 221 } 222 } 223 224 // 进行拍照，并将拍摄的照片传入PictureCallback接口的onPictureTaken方法 225 public void takePicture() { 226 if (camera != null) { 227 try { 228 camera.takePicture(null, null, pictureCallback); 229 } catch (Exception e) { 230 e.printStackTrace(); 231 } 232 } 233 } 234 235 // 设置监听事件 236 public void setOnCameraStatusListener(OnCameraStatusListener listener) { 237 this.listener = listener; 238 } 239 240 @Override 241 public void onAutoFocus(boolean success, Camera camera) { 242 243 } 244 245 public void start() { 246 if (camera != null) { 247 camera.startPreview(); 248 } 249 } 250 251 public void stop() { 252 if (camera != null) { 253 camera.stopPreview(); 254 } 255 } 256 257 /** 258 * 相机拍照监听接口 259 */ 260 public interface OnCameraStatusListener { 261 // 相机拍照结束事件 262 void onCameraStopped(byte[] data); 263 } 264 265 @Override 266 protected void onMeasure(int widthSpec, int heightSpec) { 267 viewWidth = MeasureSpec.getSize(widthSpec); 268 viewHeight = MeasureSpec.getSize(heightSpec); 269 super.onMeasure( 270 MeasureSpec.makeMeasureSpec(viewWidth, MeasureSpec.EXACTLY), 271 MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY)); 272 } 273 274 /** 275 * 将预览大小设置为屏幕大小 276 * @param parameters 277 * @return 278 */ 279 private Camera.Size findPreviewSizeByScreen(Camera.Parameters parameters) { 280 if (viewWidth != 0 \u0026amp;\u0026amp; viewHeight != 0) { 281 return camera.new Size(Math.max(viewWidth, viewHeight), 282 Math.min(viewWidth, viewHeight)); 283 } else { 284 return camera.new Size(Utils.getScreenWH(getContext()).heightPixels, 285 Utils.getScreenWH(getContext()).widthPixels); 286 } 287 } 288 289 /** 290 * 找到最合适的显示分辨率 （防止预览图像变形） 291 * @param parameters 292 * @return 293 */ 294 private Camera.Size findBestPreviewSize(Camera.Parameters parameters) { 295 296 // 系统支持的所有预览分辨率 297 String previewSizeValueString = null; 298 previewSizeValueString = parameters.get(\u0026#34;preview-size-values\u0026#34;); 299 300 if (previewSizeValueString == null) { 301 previewSizeValueString = parameters.get(\u0026#34;preview-size-value\u0026#34;); 302 } 303 304 if (previewSizeValueString == null) { // 有些手机例如m9获取不到支持的预览大小 就直接返回屏幕大小 305 return camera.new Size(Utils.getScreenWH(getContext()).widthPixels, 306 Utils.getScreenWH(getContext()).heightPixels); 307 } 308 float bestX = 0; 309 float bestY = 0; 310 311 float tmpRadio = 0; 312 float viewRadio = 0; 313 314 if (viewWidth != 0 \u0026amp;\u0026amp; viewHeight != 0) { 315 viewRadio = Math.min((float) viewWidth, (float) viewHeight) 316 / Math.max((float) viewWidth, (float) viewHeight); 317 } 318 319 String[] COMMA_PATTERN = previewSizeValueString.split(\u0026#34;,\u0026#34;); 320 for (String prewsizeString : COMMA_PATTERN) { 321 prewsizeString = prewsizeString.trim(); 322 323 int dimPosition = prewsizeString.indexOf(\u0026#39;x\u0026#39;); 324 if (dimPosition == -1) { 325 continue; 326 } 327 328 float newX = 0; 329 float newY = 0; 330 331 try { 332 newX = Float.parseFloat(prewsizeString.substring(0, dimPosition)); 333 newY = Float.parseFloat(prewsizeString.substring(dimPosition + 1)); 334 } catch (NumberFormatException e) { 335 continue; 336 } 337 338 float radio = Math.min(newX, newY) / Math.max(newX, newY); 339 if (tmpRadio == 0) { 340 tmpRadio = radio; 341 bestX = newX; 342 bestY = newY; 343 } else if (tmpRadio != 0 \u0026amp;\u0026amp; (Math.abs(radio - viewRadio)) \u0026amp;lt; (Math.abs(tmpRadio - viewRadio))) { 344 tmpRadio = radio; 345 bestX = newX; 346 bestY = newY; 347 } 348 } 349 350 if (bestX \u0026amp;gt; 0 \u0026amp;\u0026amp; bestY \u0026amp;gt; 0) { 351 return camera.new Size((int) bestX, (int) bestY); 352 } 353 return null; 354 } 355 356 /** 357 * 设置焦点和测光区域 358 * 359 * @param event 360 */ 361 public void focusOnTouch(MotionEvent event) { 362 363 int[] location = new int[2]; 364 RelativeLayout relativeLayout = (RelativeLayout)getParent(); 365 relativeLayout.getLocationOnScreen(location); 366 367 Rect focusRect = Utils.calculateTapArea(mFocusView.getWidth(), 368 mFocusView.getHeight(), 1f, event.getRawX(), event.getRawY(), 369 location[0], location[0] + relativeLayout.getWidth(), location[1], 370 location[1] + relativeLayout.getHeight()); 371 Rect meteringRect = Utils.calculateTapArea(mFocusView.getWidth(), 372 mFocusView.getHeight(), 1.5f, event.getRawX(), event.getRawY(), 373 location[0], location[0] + relativeLayout.getWidth(), location[1], 374 location[1] + relativeLayout.getHeight()); 375 376 Camera.Parameters parameters = camera.getParameters(); 377 parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); 378 379 if (parameters.getMaxNumFocusAreas() \u0026amp;gt; 0) { 380 List\u0026amp;lt;Camera.Area\u0026amp;gt; focusAreas = new ArrayList\u0026amp;lt;Camera.Area\u0026amp;gt;(); 381 focusAreas.add(new Camera.Area(focusRect, 1000)); 382 383 parameters.setFocusAreas(focusAreas); 384 } 385 386 if (parameters.getMaxNumMeteringAreas() \u0026amp;gt; 0) { 387 List\u0026amp;lt;Camera.Area\u0026amp;gt; meteringAreas = new ArrayList\u0026amp;lt;Camera.Area\u0026amp;gt;(); 388 meteringAreas.add(new Camera.Area(meteringRect, 1000)); 389 390 parameters.setMeteringAreas(meteringAreas); 391 } 392 393 try { 394 camera.setParameters(parameters); 395 } catch (Exception e) { 396 } 397 camera.autoFocus(this); 398 } 399 400 /** 401 * 设置聚焦的图片 402 * @param focusView 403 */ 404 public void setFocusView(FocusView focusView) { 405 this.mFocusView = focusView; 406 } 407 408 /** 409 * 设置自动聚焦，并且聚焦的圈圈显示在屏幕中间位置 410 */ 411 public void setFocus() { 412 if(!mFocusView.isFocusing()) { 413 try { 414 camera.autoFocus(this); 415 mFocusView.setX((Utils.getWidthInPx(getContext())-mFocusView.getWidth()) / 2); 416 mFocusView.setY((Utils.getHeightInPx(getContext())-mFocusView.getHeight()) / 2); 417 mFocusView.beginFocus(); 418 } catch (Exception e) { 419 } 420 } 421 } 422 423 } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 3、Activity中使用自定义相机\n![复制代码](http://common.cnblogs.com/images/copycode.gif) 1 public class TakePhoteActivity extends Activity implements CameraPreview.OnCameraStatusListener, 2 SensorEventListener { 3 private static final String TAG = \u0026#34;TakePhoteActivity\u0026#34;; 4 public static final Uri IMAGE_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 5 public static final String PATH = Environment.getExternalStorageDirectory() 6 .toString() + \u0026#34;/AndroidMedia/\u0026#34;; 7 CameraPreview mCameraPreview; 8 CropImageView mCropImageView; 9 RelativeLayout mTakePhotoLayout; 10 LinearLayout mCropperLayout; 11 @Override 12 protected void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 // 设置横屏 15 // setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 16 // 设置全屏 17 requestWindowFeature(Window.FEATURE_NO_TITLE); 18 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 19 WindowManager.LayoutParams.FLAG_FULLSCREEN); 20 setContentView(R.layout.activity_take_phote); 21 // Initialize components of the app 22 mCropImageView = (CropImageView) findViewById(R.id.CropImageView); 23 mCameraPreview = (CameraPreview) findViewById(R.id.cameraPreview); 24 FocusView focusView = (FocusView) findViewById(R.id.view_focus); 25 mTakePhotoLayout = (RelativeLayout) findViewById(R.id.take_photo_layout); 26 mCropperLayout = (LinearLayout) findViewById(R.id.cropper_layout); 27 28 mCameraPreview.setFocusView(focusView); 29 mCameraPreview.setOnCameraStatusListener(this); 30 mCropImageView.setGuidelines(2); 31 32 mSensorManager = (SensorManager) getSystemService(Context. 33 SENSOR_SERVICE); 34 mAccel = mSensorManager.getDefaultSensor(Sensor. 35 TYPE_ACCELEROMETER); 36 37 } 38 39 boolean isRotated = false; 40 41 @Override 42 protected void onResume() { 43 super.onResume(); 44 if(!isRotated) { 45 TextView hint_tv = (TextView) findViewById(R.id.hint); 46 ObjectAnimator animator = ObjectAnimator.ofFloat(hint_tv, \u0026#34;rotation\u0026#34;, 0f, 90f); 47 animator.setStartDelay(800); 48 animator.setDuration(1000); 49 animator.setInterpolator(new LinearInterpolator()); 50 animator.start(); 51 View view = findViewById(R.id.crop_hint); 52 AnimatorSet animSet = new AnimatorSet(); 53 ObjectAnimator animator1 = ObjectAnimator.ofFloat(view, \u0026#34;rotation\u0026#34;, 0f, 90f); 54 ObjectAnimator moveIn = ObjectAnimator.ofFloat(view, \u0026#34;translationX\u0026#34;, 0f, -50f); 55 animSet.play(animator1).before(moveIn); 56 animSet.setDuration(10); 57 animSet.start(); 58 isRotated = true; 59 } 60 mSensorManager.registerListener(this, mAccel, SensorManager.SENSOR_DELAY_UI); 61 } 62 63 @Override 64 protected void onPause() { 65 super.onPause(); 66 mSensorManager.unregisterListener(this); 67 } 68 69 @Override 70 public void onConfigurationChanged(Configuration newConfig) { 71 Log.e(TAG, \u0026#34;onConfigurationChanged\u0026#34;); 72 super.onConfigurationChanged(newConfig); 73 } 74 75 public void takePhoto(View view) { 76 if(mCameraPreview != null) { 77 mCameraPreview.takePicture(); 78 } 79 } 80 81 public void close(View view) { 82 finish(); 83 } 84 85 /** 86 * 关闭截图界面 87 * @param view 88 */ 89 public void closeCropper(View view) { 90 showTakePhotoLayout(); 91 } 92 93 /** 94 * 开始截图，并保存图片 95 * @param view 96 */ 97 public void startCropper(View view) { 98 //获取截图并旋转90度 99 CropperImage cropperImage = mCropImageView.getCroppedImage(); 100 Log.e(TAG, cropperImage.getX() + \u0026#34;,\u0026#34; + cropperImage.getY()); 101 Log.e(TAG, cropperImage.getWidth() + \u0026#34;,\u0026#34; + cropperImage.getHeight()); 102 Bitmap bitmap = Utils.rotate(cropperImage.getBitmap(), -90); 103 // Bitmap bitmap = mCropImageView.getCroppedImage(); 104 // 系统时间 105 long dateTaken = System.currentTimeMillis(); 106 // 图像名称 107 String filename = DateFormat.format(\u0026#34;yyyy-MM-dd kk.mm.ss\u0026#34;, dateTaken) 108 .toString() + \u0026#34;.jpg\u0026#34;; 109 Uri uri = insertImage(getContentResolver(), filename, dateTaken, PATH, 110 filename, bitmap, null); 111 cropperImage.getBitmap().recycle(); 112 cropperImage.setBitmap(null); 113 Intent intent = new Intent(this, ShowCropperedActivity.class); 114 intent.setData(uri); 115 intent.putExtra(\u0026#34;path\u0026#34;, PATH + filename); 116 intent.putExtra(\u0026#34;width\u0026#34;, bitmap.getWidth()); 117 intent.putExtra(\u0026#34;height\u0026#34;, bitmap.getHeight()); 118 intent.putExtra(\u0026#34;cropperImage\u0026#34;, cropperImage); 119 startActivity(intent); 120 bitmap.recycle(); 121 finish(); 122 super.overridePendingTransition(R.anim.fade_in, 123 R.anim.fade_out); 124 // doAnimation(cropperImage); 125 } 126 127 private void doAnimation(CropperImage cropperImage) { 128 ImageView imageView = new ImageView(this); 129 View view = LayoutInflater.from(this).inflate( 130 R.layout.image_view_layout, null); 131 ((RelativeLayout) view.findViewById(R.id.root_layout)).addView(imageView); 132 RelativeLayout relativeLayout = ((RelativeLayout) findViewById(R.id.root_layout)); 133 // relativeLayout.addView(imageView); 134 imageView.setX(cropperImage.getX()); 135 imageView.setY(cropperImage.getY()); 136 ViewGroup.LayoutParams lp = imageView.getLayoutParams(); 137 lp.width = (int)cropperImage.getWidth(); 138 lp.height = (int) cropperImage.getHeight(); 139 imageView.setLayoutParams(lp); 140 imageView.setImageBitmap(cropperImage.getBitmap()); 141 try { 142 getWindow().addContentView(view, lp); 143 } catch (Exception e) { 144 e.printStackTrace(); 145 } 146 /*AnimatorSet animSet = new AnimatorSet(); 147 ObjectAnimator translationX = ObjectAnimator.ofFloat(this, \u0026#34;translationX\u0026#34;, cropperImage.getX(), 0); 148 ObjectAnimator translationY = ObjectAnimator.ofFloat(this, \u0026#34;translationY\u0026#34;, cropperImage.getY(), 0);*/ 149 150 TranslateAnimation translateAnimation = new TranslateAnimation( 151 0, -cropperImage.getX(), 0, -(Math.abs(cropperImage.getHeight() - cropperImage.getY())));// 当前位置移动到指定位置 152 RotateAnimation rotateAnimation = new RotateAnimation(0, -90, 153 Animation.ABSOLUTE, cropperImage.getX() ,Animation.ABSOLUTE, cropperImage.getY()); 154 AnimationSet animationSet = new AnimationSet(true); 155 animationSet.addAnimation(translateAnimation); 156 animationSet.addAnimation(rotateAnimation); 157 animationSet.setFillAfter(true); 158 animationSet.setDuration(2000L); 159 imageView.startAnimation(animationSet); 160 // finish(); 161 } 162 163 /** 164 * 拍照成功后回调 165 * 存储图片并显示截图界面 166 * @param data 167 */ 168 @Override 169 public void onCameraStopped(byte[] data) { 170 Log.i(\u0026#34;TAG\u0026#34;, \u0026#34;==onCameraStopped==\u0026#34;); 171 // 创建图像 172 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 173 // 系统时间 174 long dateTaken = System.currentTimeMillis(); 175 // 图像名称 176 String filename = DateFormat.format(\u0026#34;yyyy-MM-dd kk.mm.ss\u0026#34;, dateTaken) 177 .toString() + \u0026#34;.jpg\u0026#34;; 178 // 存储图像（PATH目录） 179 Uri source = insertImage(getContentResolver(), filename, dateTaken, PATH, 180 filename, bitmap, data); 181 //准备截图 182 try { 183 mCropImageView.setImageBitmap(MediaStore.Images.Media.getBitmap(this.getContentResolver(), source)); 184 // mCropImageView.rotateImage(90); 185 } catch (IOException e) { 186 Log.e(TAG, e.getMessage()); 187 } 188 showCropperLayout(); 189 } 190 191 /** 192 * 存储图像并将信息添加入媒体数据库 193 */ 194 private Uri insertImage(ContentResolver cr, String name, long dateTaken, 195 String directory, String filename, Bitmap source, byte[] jpegData) { 196 OutputStream outputStream = null; 197 String filePath = directory + filename; 198 try { 199 File dir = new File(directory); 200 if (!dir.exists()) { 201 dir.mkdirs(); 202 } 203 File file = new File(directory, filename); 204 if (file.createNewFile()) { 205 outputStream = new FileOutputStream(file); 206 if (source != null) { 207 source.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); 208 } else { 209 outputStream.write(jpegData); 210 } 211 } 212 } catch (FileNotFoundException e) { 213 Log.e(TAG, e.getMessage()); 214 return null; 215 } catch (IOException e) { 216 Log.e(TAG, e.getMessage()); 217 return null; 218 } finally { 219 if (outputStream != null) { 220 try { 221 outputStream.close(); 222 } catch (Throwable t) { 223 } 224 } 225 } 226 ContentValues values = new ContentValues(7); 227 values.put(MediaStore.Images.Media.TITLE, name); 228 values.put(MediaStore.Images.Media.DISPLAY_NAME, filename); 229 values.put(MediaStore.Images.Media.DATE_TAKEN, dateTaken); 230 values.put(MediaStore.Images.Media.MIME_TYPE, \u0026#34;image/jpeg\u0026#34;); 231 values.put(MediaStore.Images.Media.DATA, filePath); 232 return cr.insert(IMAGE_URI, values); 233 } 234 235 private void showTakePhotoLayout() { 236 mTakePhotoLayout.setVisibility(View.VISIBLE); 237 mCropperLayout.setVisibility(View.GONE); 238 } 239 240 private void showCropperLayout() { 241 mTakePhotoLayout.setVisibility(View.GONE); 242 mCropperLayout.setVisibility(View.VISIBLE); 243 mCameraPreview.start(); //继续启动摄像头 244 } 245 246 247 private float mLastX = 0; 248 private float mLastY = 0; 249 private float mLastZ = 0; 250 private boolean mInitialized = false; 251 private SensorManager mSensorManager; 252 private Sensor mAccel; 253 @Override 254 public void onSensorChanged(SensorEvent event) { 255 256 float x = event.values[0]; 257 float y = event.values[1]; 258 float z = event.values[2]; 259 if (!mInitialized){ 260 mLastX = x; 261 mLastY = y; 262 mLastZ = z; 263 mInitialized = true; 264 } 265 float deltaX = Math.abs(mLastX - x); 266 float deltaY = Math.abs(mLastY - y); 267 float deltaZ = Math.abs(mLastZ - z); 268 269 if(deltaX \u0026amp;gt; 0.8 || deltaY \u0026amp;gt; 0.8 || deltaZ \u0026amp;gt; 0.8){ 270 mCameraPreview.setFocus(); 271 } 272 mLastX = x; 273 mLastY = y; 274 mLastZ = z; 275 } 276 277 @Override 278 public void onAccuracyChanged(Sensor sensor, int accuracy) { 279 } 280 } ![复制代码](http://common.cnblogs.com/images/copycode.gif) actiity中注册了SensorEventListener，也就是使用传感器监听用户手机的移动，如果有一定距离的移动，则自动聚焦，这样体验好一点。\n我对比了一下小猿搜题和学霸君两款app的拍照功能，个人感觉小猿搜题的体验要好一些，因为从主界面进入拍照界面，连个界面没有一个旋转的过渡，而学霸君就有一个过渡，有一丝丝的影响体验。也就是说学霸君的拍照界面是横屏的，在activity的onCreate方法里面调用了setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)来设置全屏，而切换界面的时候又从竖屏切换为横屏，就会有个过渡的效果，影响了体验。\n个人猜测小猿搜题是将拍照界面的activity设置为竖屏，而将摄像头直接旋转90度，这样就强制用户横屏拍摄，当然，拍完之后还要将图片旋转回来。所以我参考小猿搜题来实现的，毕竟体验为王嘛。\n如上图（其实是竖屏），红色圈起来的其实是放到底部，然后将屏幕中间的文字旋转90度（带有动画，起了提示用户横屏拍照的作用），就给人的感觉是横屏的。了。\n还有一点就是小猿搜题拍完照到截图过渡的很自然，感觉很流畅，估计是拍照和截图放在同一个activity中的，如果是两个activty，涉及到界面切换，肯定不会那么自然。所以我也将拍照和截图放在一个界面，拍照完就将自定义相机隐藏，将截图界面显示出来，这样切换就很流畅了。\n项目中截图的功能我是从github上面找的一个开源库cropper：https://github.com/edmodo/cropper\n因为ocr图片识别的代码是公司的，所以识别的功能没有添加到demo里面去。\nDemo源码下载：https://github.com/liuling07/CustomCameraDemo\n","permalink":"https://blog.zdltech.com/posts/android%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9B%B8%E6%9C%BA%E6%8B%8D%E7%85%A7%E5%9B%BE%E7%89%87%E8%A3%81%E5%89%AA%E7%9A%84%E5%AE%9E%E7%8E%B0/","summary":"\u003cp\u003e最近项目里面又要加一个拍照搜题的功能，也就是用户对着不会做的题目拍一张照片，将照片的文字使用ocr识别出来，再调用题库搜索接口搜索出来展示给用户，类似于小猿搜题、学霸君等app。\u003c/p\u003e\n\u003cp\u003e其实Android提供Intent让我们打开系统的相机，但是系统相机跟自己app风格不搭，而且用起来体验不好。所以我使用了SDK提供的camera API自定义了一个相机，并且在相机界面上面添加了参考线，有助于用户将题目拍正，提高ocr的识别率。\u003c/p\u003e\n\u003cp\u003e1、绘制参考线的代码\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e public \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e ReferenceLine \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e View {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e     private Paint mLinePaint;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e4\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e5\u003c/span\u003e     public ReferenceLine(Context context) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e6\u003c/span\u003e         super(context);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e7\u003c/span\u003e         init();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e8\u003c/span\u003e     }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e9\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e10\u003c/span\u003e     public ReferenceLine(Context context, AttributeSet attrs) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e11\u003c/span\u003e         super(context, attrs);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e12\u003c/span\u003e         init();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e13\u003c/span\u003e     }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e14\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e15\u003c/span\u003e     public ReferenceLine(Context context, AttributeSet attrs, int defStyleAttr) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e16\u003c/span\u003e         super(context, attrs, defStyleAttr);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e17\u003c/span\u003e         init();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e18\u003c/span\u003e     }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e19\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e     private void init() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e21\u003c/span\u003e         mLinePaint \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new Paint();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e22\u003c/span\u003e         mLinePaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetAntiAlias(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e23\u003c/span\u003e         mLinePaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetColor(Color\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eparseColor(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;#45e0e0e0\u0026#34;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e24\u003c/span\u003e         mLinePaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetStrokeWidth(\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e25\u003c/span\u003e     }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e26\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e27\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e28\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e29\u003c/span\u003e     @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e30\u003c/span\u003e     protected void onDraw(Canvas canvas) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e31\u003c/span\u003e         int screenWidth \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Utils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetScreenWH(getContext())\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidthPixels;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e32\u003c/span\u003e         int screenHeight \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Utils\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetScreenWH(getContext())\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eheightPixels;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e33\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e34\u003c/span\u003e         int width \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e screenWidth\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e35\u003c/span\u003e         int height \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e screenHeight\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e36\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e37\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e (int i \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e width, j \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e;i \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt; screenWidth \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e j\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e;i \u003cspan style=\"color:#ff79c6\"\u003e+=\u003c/span\u003e width, j\u003cspan style=\"color:#ff79c6\"\u003e++\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e38\u003c/span\u003e             canvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawLine(i, \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e, i, screenHeight, mLinePaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e39\u003c/span\u003e         }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e40\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e (int j \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e height,i \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e;j \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt; screenHeight \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e i \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt; \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e;j \u003cspan style=\"color:#ff79c6\"\u003e+=\u003c/span\u003e height,i\u003cspan style=\"color:#ff79c6\"\u003e++\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e41\u003c/span\u003e             canvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawLine(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e, j, screenWidth, j, mLinePaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e42\u003c/span\u003e         }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e43\u003c/span\u003e     }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e44\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e45\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#bd93f9\"\u003e46\u003c/span\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android自定义相机拍照、图片裁剪的实现"},{"content":"Frozen UI 自述：简单易用，轻量快捷，为移动端服务的前端框架。\n主页：http://frozenui.github.io/\n开发团队：QQVIP FD Team\nGithub：https://github.com/frozenui/frozenui\nDemo：http://frozenui.github.io/frozenui/demo/index.html\nWeUI 自述：WeUI是一套同微信原生视觉体验一致的基础样式库，为微信 Web 开发量身设计，可以令用户的使用感知更加统一。\n开发团队：Wechat Official Design Team\nGithub：https://github.com/weui/weui\nDemo：http://weui.github.io/weui/\nSUI Mobile 主页：http://m.sui.taobao.org/\n自述：轻量、小巧、精美的UI库，方便迅速搭建手机H5应用，也非常适合开发跨平台Web App。\n开发团队：阿里巴巴共享业务事业部UED团队\nGithub：https://github.com/sdc-alibaba/SUI-Mobile\nDemo：http://m.sui.taobao.org/demos/\n兼容：兼容到 iOS 6+ 以及 Android 4.0+\n基于 Framework7 进行开发，并参考 Ratchet、Fastclick 开源库\nMUI\n主页：http://dev.dcloud.net.cn/mui/\n自述：最接近原生APP体验的高性能前端框架\nGithub：https://github.com/dcloudio/mui/\nAPICloud\n主页：http://www.apicloud.com/\n自述：混合APP开发平台 助力创业七十二变\nWeUI 主页：https://github.com/weui/weui\n","permalink":"https://blog.zdltech.com/posts/%E7%A7%BB%E5%8A%A8%E7%AB%AF%E5%89%8D%E7%AB%AFui%E5%BA%93-frozen-uiweuisui-mobile/","summary":"\u003ch4 id=\"frozen-ui\"\u003eFrozen UI\u003c/h4\u003e\n\u003cblockquote\u003e\n\u003cp\u003e自述：简单易用，轻量快捷，为移动端服务的前端框架。\u003c/p\u003e\n\u003cp\u003e主页：http://frozenui.github.io/\u003c/p\u003e\n\u003cp\u003e开发团队：QQVIP FD Team\u003c/p\u003e\n\u003cp\u003eGithub：https://github.com/frozenui/frozenui\u003c/p\u003e\n\u003cp\u003eDemo：http://frozenui.github.io/frozenui/demo/index.html\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch4 id=\"weui\"\u003eWeUI\u003c/h4\u003e\n\u003cblockquote\u003e\n\u003cp\u003e自述：WeUI是一套同微信原生视觉体验一致的基础样式库，为微信 Web 开发量身设计，可以令用户的使用感知更加统一。\u003c/p\u003e\n\u003cp\u003e开发团队：Wechat Official Design Team\u003c/p\u003e\n\u003cp\u003eGithub：https://github.com/weui/weui\u003c/p\u003e\n\u003cp\u003eDemo：http://weui.github.io/weui/\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch4 id=\"sui-mobile\"\u003eSUI Mobile\u003c/h4\u003e\n\u003cblockquote\u003e\n\u003cp\u003e主页：http://m.sui.taobao.org/\u003c/p\u003e\n\u003cp\u003e自述：轻量、小巧、精美的UI库，方便迅速搭建手机H5应用，也非常适合开发跨平台Web App。\u003c/p\u003e\n\u003cp\u003e开发团队：阿里巴巴共享业务事业部UED团队\u003c/p\u003e\n\u003cp\u003eGithub：https://github.com/sdc-alibaba/SUI-Mobile\u003c/p\u003e\n\u003cp\u003eDemo：http://m.sui.taobao.org/demos/\u003c/p\u003e\n\u003cp\u003e兼容：兼容到 iOS 6+ 以及 Android 4.0+\u003c/p\u003e\n\u003cp\u003e基于 \u003ca href=\"http://framework7.taobao.org/\"\u003eFramework7\u003c/a\u003e 进行开发，并参考 \u003ca href=\"http://goratchet.com/\"\u003eRatchet\u003c/a\u003e、\u003ca href=\"https://github.com/ftlabs/fastclick\"\u003eFastclick\u003c/a\u003e 开源库\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eMUI\u003c/p\u003e\n\u003cp\u003e主页：http://dev.dcloud.net.cn/mui/\u003c/p\u003e\n\u003cp\u003e自述：最接近原生APP体验的高性能前端框架\u003c/p\u003e\n\u003cp\u003eGithub：https://github.com/dcloudio/mui/\u003c/p\u003e\n\u003cp\u003eAPICloud\u003c/p\u003e\n\u003cp\u003e主页：http://www.apicloud.com/\u003c/p\u003e\n\u003cp\u003e自述：混合APP开发平台 助力创业七十二变\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 id=\"weui-1\"\u003eWeUI\u003c/h1\u003e\n\u003cp\u003e主页：https://github.com/weui/weui\u003c/p\u003e","title":"移动端前端UI库—Frozen UI、WeUI、SUI Mobile"},{"content":"前言 我从去年开始使用 RxJava ，到现在一年多了。今年加入了 Flipboard 后，看到 Flipboard 的 Android 项目也在使用 RxJava ，并且使用的场景越来越多 。而最近这几个月，我也发现国内越来越多的人开始提及 RxJava 。有人说『RxJava 真是太好用了』，有人说『RxJava 真是太难用了』，另外更多的人表示：我真的百度了也谷歌了，但我还是想问： RxJava 到底是什么？\n鉴于 RxJava 目前这种既火爆又神秘的现状，而我又在一年的使用过程中对 RxJava 有了一些理解，我决定写下这篇文章来对 RxJava 做一个相对详细的、针对 Android 开发者的介绍。\n这篇文章的目的有两个：\n给对 RxJava 感兴趣的人一些入门的指引 给正在使用 RxJava 但仍然心存疑惑的人一些更深入的解析 - [RxJava 到底是什么](http://gank.io/post/560e15be2dca930e00da1083#toc_1) - [RxJava 好在哪](http://gank.io/post/560e15be2dca930e00da1083#toc_2) - [API 介绍和原理简析](http://gank.io/post/560e15be2dca930e00da1083#toc_3) - [1. 概念：扩展的观察者模式](http://gank.io/post/560e15be2dca930e00da1083#toc_4) - [观察者模式](http://gank.io/post/560e15be2dca930e00da1083#toc_5) - [RxJava 的观察者模式](http://gank.io/post/560e15be2dca930e00da1083#toc_6) - [2. 基本实现](http://gank.io/post/560e15be2dca930e00da1083#toc_7) - [1) 创建 Observer](http://gank.io/post/560e15be2dca930e00da1083#toc_8) - [2) 创建 Observable](http://gank.io/post/560e15be2dca930e00da1083#toc_9) - [3) Subscribe (订阅)](http://gank.io/post/560e15be2dca930e00da1083#toc_10) - [4) 场景示例](http://gank.io/post/560e15be2dca930e00da1083#toc_11) - [a. 打印字符串数组](http://gank.io/post/560e15be2dca930e00da1083#toc_12) - [b. 由 id 取得图片并显示](http://gank.io/post/560e15be2dca930e00da1083#toc_13) - [3. 线程控制 —— Scheduler (一)](http://gank.io/post/560e15be2dca930e00da1083#toc_14) - [1) Scheduler 的 API (一)](http://gank.io/post/560e15be2dca930e00da1083#toc_15) - [2) Scheduler 的原理 (一)](http://gank.io/post/560e15be2dca930e00da1083#toc_16) - [4. 变换](http://gank.io/post/560e15be2dca930e00da1083#toc_17) - [1) API](http://gank.io/post/560e15be2dca930e00da1083#toc_18) - [2) 变换的原理：lift()](http://gank.io/post/560e15be2dca930e00da1083#toc_19) - [3) compose: 对 Observable 整体的变换](http://gank.io/post/560e15be2dca930e00da1083#toc_20) - [5. 线程控制：Scheduler (二)](http://gank.io/post/560e15be2dca930e00da1083#toc_21) - [1) Scheduler 的 API (二)](http://gank.io/post/560e15be2dca930e00da1083#toc_22) - [2) Scheduler 的原理（二）](http://gank.io/post/560e15be2dca930e00da1083#toc_23) - [3) 延伸：doOnSubscribe()](http://gank.io/post/560e15be2dca930e00da1083#toc_24) - [RxJava 的适用场景和使用方式](http://gank.io/post/560e15be2dca930e00da1083#toc_25) - [1. 与 Retrofit 的结合](http://gank.io/post/560e15be2dca930e00da1083#toc_26) - [2. RxBinding](http://gank.io/post/560e15be2dca930e00da1083#toc_27) - [3. 各种异步操作](http://gank.io/post/560e15be2dca930e00da1083#toc_28) - [4. RxBus](http://gank.io/post/560e15be2dca930e00da1083#toc_29) - [最后](http://gank.io/post/560e15be2dca930e00da1083#toc_30) - [关于作者：](http://gank.io/post/560e15be2dca930e00da1083#toc_31) - [为什么写这个？](http://gank.io/post/560e15be2dca930e00da1083#toc_32) 在正文开始之前的最后，放上 GitHub 链接和引入依赖的 gradle 代码： Github：\nhttps://github.com/ReactiveX/RxJava\nhttps://github.com/ReactiveX/RxAndroid\n引入依赖：\ncompile 'io.reactivex:rxjava:1.0.14'\ncompile 'io.reactivex:rxandroid:1.0.1'\n（版本号是文章发布时的最新稳定版）\n另外，感谢 RxJava 核心成员流火枫林的技术支持和内测读者代码家、鲍永章、drakeet、马琳、有时放纵、程序亦非猿、大头鬼、XZoomEye、席德雨、TCahead、Tiiime、Ailurus、宅学长、妖孽、大大大大大臣哥、NicodeLee的帮助，以及周伯通招聘的赞助。\nRxJava 到底是什么 一个词：异步。\nRxJava 在 GitHub 主页上的自我介绍是 “a library for composing asynchronous and event-based programs using observable sequences for the Java VM”（一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库）。这就是 RxJava ，概括得非常精准。\n然而，对于初学者来说，这太难看懂了。因为它是一个『总结』，而初学者更需要一个『引言』。\n其实， RxJava 的本质可以压缩为异步这一个词。说到根上，它就是一个实现异步操作的库，而别的定语都是基于这之上的。\nRxJava 好在哪 换句话说，『同样是做异步，为什么人们用它，而不用现成的 AsyncTask / Handler / XXX / … ？』\n一个词：简洁。\n异步操作很关键的一点是程序的简洁性，因为在调度过程比较复杂的情况下，异步代码经常会既难写也难被读懂。 Android 创造的AsyncTask 和Handler ，其实都是为了让异步代码更加简洁。RxJava 的优势也是简洁，但它的简洁的与众不同之处在于，随着程序逻辑变得越来越复杂，它依然能够保持简洁。\n假设有这样一个需求：界面上有一个自定义的视图 imageCollectorView ，它的作用是显示多张图片，并能使用 addImage(Bitmap) 方法来任意增加显示的图片。现在需要程序将一个给出的目录数组 File[] folders 中每个目录下的 png 图片都加载出来并显示在imageCollectorView 中。需要注意的是，由于读取图片的这一过程较为耗时，需要放在后台执行，而图片的显示则必须在 UI 线程执行。常用的实现方式有多种，我这里贴出其中一种：\n`\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Thread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; run\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;run\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; folder \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; folders\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;[]\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; files \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; folder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;listFiles\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; file \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; files\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;().\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;endsWith\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;.png\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;))\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; bitmap \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getBitmapFromFile\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getActivity\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;().\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;runOnUiThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Runnable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; run\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; imageCollectorView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;addImage\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;start\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt;` 而如果使用 RxJava ，实现方式是这样的：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;folders\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;flatMap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Func1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; file\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;listFiles\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;filter\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Func1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Boolean\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Boolean\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; file\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; file\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;().\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;endsWith\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;.png\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;map\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Func1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; file\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getBitmapFromFile\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Schedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;io\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;AndroidSchedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;mainThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; imageCollectorView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;addImage\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 那位说话了：『你这代码明明变多了啊！简洁个毛啊！』大兄弟你消消气，我说的是逻辑的简洁，不是单纯的代码量少（逻辑简洁才是提升读写代码速度的必杀技对不？）。观察一下你会发现， RxJava 的这个实现，是一条从上到下的链式调用，没有任何嵌套，这在逻辑的简洁性上是具有优势的。当需求变得复杂时，这种优势将更加明显（试想如果还要求只选取前 10 张图片，常规方式要怎么办？如果有更多这样那样的要求呢？再试想，在这一大堆需求实现完两个月之后需要改功能，当你翻回这里看到自己当初写下的那一片迷之缩进，你能保证自己将迅速看懂，而不是对着代码重新捋一遍思路？）。\n另外，如果你的 IDE 是 Android Studio ，其实每次打开某个 Java 文件的时候，你会看到被自动 Lambda 化的预览，这将让你更加清晰地看到程序逻辑：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;folders\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;flatMap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;((\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Func1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;folder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;-\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;listFiles\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;filter\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;((\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Func1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;-\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; file\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;().\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;endsWith\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;.png\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;map\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;((\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Func1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;-\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getBitmapFromFile\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Schedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;io\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;AndroidSchedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;mainThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;((\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;-\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; imageCollectorView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;addImage\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 如果你习惯使用 Retrolambda ，你也可以直接把代码写成上面这种简洁的形式。而如果你看到这里还不知道什么是 Retrolambda ，我不建议你现在就去学习它。原因有两点：1. Lambda 是把双刃剑，它让你的代码简洁的同时，降低了代码的可读性，因此同时学习 RxJava 和 Retrolambda 可能会让你忽略 RxJava 的一些技术细节；2. Retrolambda 是 Java 6/7 对 Lambda 表达式的非官方兼容方案，它的向后兼容性和稳定性是无法保障的，因此对于企业项目，使用 Retrolambda 是有风险的。所以，与很多 RxJava 的推广者不同，我并不推荐在学习 RxJava 的同时一起学习 Retrolambda。事实上，我个人虽然很欣赏 Retrolambda，但我从来不用它。\n在Flipboard 的 Android 代码中，有一段逻辑非常复杂，包含了多次内存操作、本地文件操作和网络操作，对象分分合合，线程间相互配合相互等待，一会儿排成人字，一会儿排成一字。如果使用常规的方法来实现，肯定是要写得欲仙欲死，然而在使用 RxJava 的情况下，依然只是一条链式调用就完成了。它很长，但很清晰。\n所以， RxJava 好在哪？就好在简洁，好在那把什么复杂逻辑都能穿成一条线的简洁。\nAPI 介绍和原理简析 这个我就做不到一个词说明了……因为这一节的主要内容就是一步步地说明 RxJava 到底怎样做到了异步，怎样做到了简洁。\n1. 概念：扩展的观察者模式 RxJava 的异步实现，是通过一种扩展的观察者模式来实现的。\n观察者模式 先简述一下观察者模式，已经熟悉的可以跳过这一段。\n观察者模式面向的需求是：A 对象（观察者）对 B 对象（被观察者）的某种变化高度敏感，需要在 B 变化的一瞬间做出反应。举个例子，新闻里喜闻乐见的警察抓小偷，警察需要在小偷伸手作案的时候实施抓捕。在这个例子里，警察是观察者，小偷是被观察者，警察需要时刻盯着小偷的一举一动，才能保证不会漏过任何瞬间。程序的观察者模式和这种真正的『观察』略有不同，观察者不需要时刻盯着被观察者（例如 A 不需要每过 2ms 就检查一次 B 的状态），而是采用注册(Register)或者称为订阅**(Subscribe)**的方式，告诉被观察者：我需要你的某某状态，你要在它变化的时候通知我。 Android 开发中一个比较典型的例子是点击监听器 OnClickListener 。对设置 OnClickListener 来说， View 是被观察者， OnClickListener 是观察者，二者通过 setOnClickListener() 方法达成订阅关系。订阅之后用户点击按钮的瞬间，Android Framework 就会将点击事件发送给已经注册的 OnClickListener 。采取这样被动的观察方式，既省去了反复检索状态的资源消耗，也能够得到最高的反馈速度。当然，这也得益于我们可以随意定制自己程序中的观察者和被观察者，而警察叔叔明显无法要求小偷『你在作案的时候务必通知我』。\nOnClickListener 的模式大致如下图：\n如图所示，通过 setOnClickListener() 方法，Button 持有 OnClickListener 的引用（这一过程没有在图上画出）；当用户点击时，Button 自动调用 OnClickListener 的 onClick() 方法。另外，如果把这张图中的概念抽象出来（Button -\u0026gt; 被观察者、OnClickListener -\u0026gt; 观察者、setOnClickListener() -\u0026gt; 订阅，onClick() -\u0026gt; 事件），就由专用的观察者模式（例如只用于监听控件点击）转变成了通用的观察者模式。如下图：\n而 RxJava 作为一个工具库，使用的就是通用形式的观察者模式。\nRxJava 的观察者模式 RxJava 有四个基本概念：Observable (可观察者，即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和Observer 通过 subscribe() 方法实现订阅关系，从而 Observable 可以在需要的时候发出事件来通知 Observer。\n与传统观察者模式不同， RxJava 的事件回调方法除了普通事件 onNext() （相当于 onClick() / onEvent()）之外，还定义了两个特殊的事件：onCompleted() 和 onError()。\nonCompleted(): 事件队列完结。RxJava 不仅把每个事件单独处理，还会把它们看做一个队列。RxJava 规定，当不会再有新的onNext() 发出时，需要触发 onCompleted() 方法作为标志。 onError(): 事件队列异常。在事件处理过程中出异常时，onError() 会被触发，同时队列自动终止，不允许再有事件发出。 在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个，并且是事件序列中的最后一个。需要注意的是，onCompleted() 和 onError() 二者也是互斥的，即在队列中调用了其中一个，就不应该再调用另一个。 RxJava 的观察者模式大致如下图：\n2. 基本实现 基于以上的概念， RxJava 的基本实现主要有三点：\n1) 创建 Observer Observer 即观察者，它决定事件触发的时候将有怎样的行为。 RxJava 中的 Observer 接口的实现方式：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observer \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; s\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;d\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tag\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Item: \u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;+\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; s\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onCompleted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;d\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tag\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Completed!\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Throwable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;d\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tag\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Error!\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt;` 除了 Observer 接口之外，RxJava 还内置了一个实现了 Observer 的抽象类：Subscriber。 Subscriber 对 Observer 接口进行了一些扩展，但他们的基本使用方式是完全一样的：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; s\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;d\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tag\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Item: \u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;+\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; s\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onCompleted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;d\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tag\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Completed!\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Throwable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;d\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tag\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Error!\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt;` 不仅基本使用方式一样，实质上，在 RxJava 的 subscribe 过程中，Observer 也总是会先被转换成一个 Subscriber 再使用。所以如果你只想使用基本功能，选择 Observer 和 Subscriber 是完全一样的。它们的区别对于使用者来说主要有两点：\nonStart(): 这是 Subscriber 增加的方法。它会在 subscribe 刚开始，而事件还未发送之前被调用，可以用于做一些准备工作，例如数据的清零或重置。这是一个可选方法，默认情况下它的实现为空。需要注意的是，如果对准备工作的线程有要求（例如弹出一个显示进度的对话框，这必须在主线程执行）， onStart() 就不适用了，因为它总是在 subscribe 所发生的线程被调用，而不能指定线程。要在指定的线程来做准备工作，可以使用 doOnSubscribe() 方法，具体可以在后面的文中看到。 unsubscribe(): 这是 Subscriber 所实现的另一个接口 Subscription 的方法，用于取消订阅。在这个方法被调用后，Subscriber 将不再接收事件。一般在这个方法调用前，可以使用 isUnsubscribed() 先判断一下状态。 unsubscribe() 这个方法很重要，因为在 subscribe() 之后， Observable 会持有 Subscriber 的引用，这个引用如果不能及时被释放，将有内存泄露的风险。所以最好保持一个原则：要在不再使用的时候尽快在合适的地方（例如 onPause() onStop() 等方法中）调用unsubscribe() 来解除引用关系，以避免内存泄露的发生。 2) 创建 Observable Observable 即被观察者，它决定什么时候触发事件以及触发怎样的事件。 RxJava 使用 create() 方法来创建一个 Observable ，并为它定义事件触发规则：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;create\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;OnSubscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;?\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Hello\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Hi\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Aloha\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onCompleted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 可以看到，这里传入了一个 OnSubscribe 对象作为参数。OnSubscribe 会被存储在返回的 Observable 对象中，它的作用相当于一个计划表，当 Observable 被订阅的时候，OnSubscribe 的 call() 方法会自动被调用，事件序列就会依照设定依次触发（对于上面的代码，就是观察者Subscriber 将会被调用三次 onNext() 和一次 onCompleted()）。这样，由被观察者调用了观察者的回调方法，就实现了由被观察者向观察者的事件传递，即观察者模式。\n这个例子很简单：事件的内容是字符串，而不是一些复杂的对象；事件的内容是已经定好了的，而不像有的观察者模式一样是待确定的（例如网络请求的结果在请求返回之前是未知的）；所有事件在一瞬间被全部发送出去，而不是夹杂一些确定或不确定的时间间隔或者经过某种触发器来触发的。总之，这个例子看起来毫无实用价值。但这是为了便于说明，实质上只要你想，各种各样的事件发送规则你都可以自己来写。至于具体怎么做，后面都会讲到，但现在不行。只有把基础原理先说明白了，上层的运用才能更容易说清楚。\ncreate() 方法是 RxJava 最基本的创造事件序列的方法。基于这个方法， RxJava 还提供了一些方法用来快捷创建事件队列，例如：\njust(T...): 将传入的参数依次发送出来。 `\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;just\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Hello\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Hi\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Aloha\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 将会依次调用：\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// onNext(\u0026#34;Hello\u0026#34;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// onNext(\u0026#34;Hi\u0026#34;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// onNext(\u0026#34;Aloha\u0026#34;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// onCompleted();\u0026amp;lt;/span\u0026gt;` from(T[]) / from(Iterable\u0026lt;? extends T\u0026gt;) : 将传入的数组或 Iterable 拆分成具体对象后，依次发送出来。 `\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;[]\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; words \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Hello\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Hi\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Aloha\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;words\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 将会依次调用：\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// onNext(\u0026#34;Hello\u0026#34;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// onNext(\u0026#34;Hi\u0026#34;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// onNext(\u0026#34;Aloha\u0026#34;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// onCompleted();\u0026amp;lt;/span\u0026gt;` 上面 just(T...) 的例子和 from(T[]) 的例子，都和之前的 create(OnSubscribe) 的例子是等价的。\n3) Subscribe (订阅) 创建了 Observable 和 Observer 之后，再用 subscribe() 方法将它们联结起来，整条链子就可以工作了。代码形式很简单：\n`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 或者：\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 有人可能会注意到， subscribe() 这个方法有点怪：它看起来是『observalbe 订阅了 observer / subscriber』而不是『observer / subscriber 订阅了 observalbe』，这看起来就像『杂志订阅了读者』一样颠倒了对象关系。这让人读起来有点别扭，不过如果把 API 设计成 observer.subscribe(observable) / subscriber.subscribe(observable) ，虽然更加符合思维逻辑，但对流式 API 的设计就造成影响了，比较起来明显是得不偿失的。\nObservable.subscribe(Subscriber) 的内部实现是这样的（仅核心代码）：\n`\u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 注意：这不是 subscribe() 的源码，而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 如果需要看源码，可以去 RxJava 的 GitHub 仓库下载。\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onStart\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onSubscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt;` 可以看到，subscriber() 做了3件事：\n调用 Subscriber.onStart() 。这个方法在前面已经介绍过，是一个可选的准备方法。 调用 Observable 中的 OnSubscribe.call(Subscriber) 。在这里，事件发送的逻辑开始运行。从这也可以看出，在 RxJava 中，Observable 并不是在创建的时候就立即开始发送事件，而是在它被订阅的时候，即当 subscribe() 方法执行的时候。 将传入的 Subscriber 作为 Subscription 返回。这是为了方便 unsubscribe(). 整个过程中对象间的关系如下图：\n或者可以看动图：\n除了 subscribe(Observer) 和 subscribe(Subscriber) ，subscribe() 还支持不完整定义的回调，RxJava 会自动根据定义创建出Subscriber 。形式如下：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onNextAction \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// onNext()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; s\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;d\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tag\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; s\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Throwable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onErrorAction \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Throwable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// onError()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Throwable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; throwable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// Error handling\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onCompletedAction \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// onCompleted()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;d\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tag\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;completed\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 自动创建 Subscriber ，并使用 onNextAction 来定义 onNext()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onNextAction\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 自动创建 Subscriber ，并使用 onNextAction 和 onErrorAction 来定义 onNext() 和 onError()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onNextAction\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onErrorAction\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 自动创建 Subscriber ，并使用 onNextAction、 onErrorAction 和 onCompletedAction 来定义 onNext()、 onError() 和 onCompleted()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onNextAction\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onErrorAction\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onCompletedAction\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 简单解释一下这段代码中出现的 Action1 和 Action0。 Action0 是 RxJava 的一个接口，它只有一个方法 call()，这个方法是无参无返回值的；由于 onCompleted() 方法也是无参无返回值的，因此 Action0 可以被当成一个包装对象，将 onCompleted() 的内容打包起来将自己作为一个参数传入 subscribe() 以实现不完整定义的回调。这样其实也可以看做将 onCompleted() 方法作为参数传进了subscribe()，相当于其他某些语言中的『闭包』。 Action1 也是一个接口，它同样只有一个方法 call(T param)，这个方法也无返回值，但有一个参数；与 Action0 同理，由于 onNext(T obj) 和 onError(Throwable error) 也是单参数无返回值的，因此 Action1可以将 onNext(obj) 和 onError(error) 打包起来传入 subscribe() 以实现不完整定义的回调。事实上，虽然 Action0 和 Action1在 API 中使用最广泛，但 RxJava 是提供了多个 ActionX 形式的接口 (例如 Action2, Action3) 的，它们可以被用以包装不同的无返回值的方法。\n注：正如前面所提到的，Observer 和 Subscriber 具有相同的角色，而且 Observer 在 subscribe() 过程中最终会被转换成 Subscriber 对象，因此，从这里开始，后面的描述我将用 Subscriber 来代替 Observer ，这样更加严谨。\n4) 场景示例 下面举两个例子：\n为了把原理用更清晰的方式表述出来，本文中挑选的都是功能尽可能简单的例子，以至于有些示例代码看起来会有『画蛇添足』『明明不用 RxJava 可以更简便地解决问题』的感觉。当你看到这种情况，不要觉得是因为 RxJava 太啰嗦，而是因为在过早的时候举出真实场景的例子并不利于原理的解析，因此我刻意挑选了简单的情景。\na. 打印字符串数组 将字符串数组 names 中的所有字符串依次打印出来：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;[]\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; names \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;names\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; name\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;d\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tag\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; name\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` b. 由 id 取得图片并显示 由指定的一个 drawable 文件 id drawableRes 取得图片，并显示在 ImageView 中，并在出现异常的时候打印 Toast 报错：\n`\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; drawableRes \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;ImageView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; imageView \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;create\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;OnSubscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;?\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; drawable \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getTheme\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;().\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getDrawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;drawableRes\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;));\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onCompleted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}).\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; imageView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;setImageDrawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onCompleted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Throwable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Toast\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;makeText\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;activity\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Error!\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Toast\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;LENGTH_SHORT\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;).\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;show\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 正如上面两个例子这样，创建出 Observable 和 Subscriber ，再用 subscribe() 将它们串起来，一次 RxJava 的基本使用就完成了。非常简单。\n然而，\n在 RxJava 的默认规则中，事件的发出和消费都是在同一个线程的。也就是说，如果只用上面的方法，实现出来的只是一个同步的观察者模式。观察者模式本身的目的就是『后台处理，前台回调』的异步机制，因此异步对于 RxJava 是至关重要的。而要实现异步，则需要用到 RxJava 的另一个概念： Scheduler 。\n3. 线程控制 —— Scheduler (一) 在不指定线程的情况下， RxJava 遵循的是线程不变的原则，即：在哪个线程调用 subscribe()，就在哪个线程生产事件；在哪个线程生产事件，就在哪个线程消费事件。如果需要切换线程，就需要用到 Scheduler （调度器）。\n1) Scheduler 的 API (一) 在RxJava 中，Scheduler ——调度器，相当于线程控制器，RxJava 通过它来指定每一段代码应该运行在什么样的线程。RxJava 已经内置了几个 Scheduler ，它们已经适合大多数的使用场景：\nSchedulers.immediate(): 直接在当前线程运行，相当于不指定线程。这是默认的 Scheduler。 Schedulers.newThread(): 总是启用新线程，并在新线程执行操作。 Schedulers.io(): I/O 操作（读写文件、读写数据库、网络信息交互等）所使用的 Scheduler。行为模式和 newThread() 差不多，区别在于 io() 的内部实现是是用一个无数量上限的线程池，可以重用空闲的线程，因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中，可以避免创建不必要的线程。 Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算，即不会被 I/O 等操作限制性能的操作，例如图形的计算。这个 Scheduler 使用的固定的线程池，大小为 CPU 核数。不要把 I/O 操作放在 computation() 中，否则 I/O 操作的等待时间会浪费 CPU。 另外， Android 还有一个专用的 AndroidSchedulers.mainThread()，它指定的操作将在 Android 主线程运行。 有了这几个 Scheduler ，就可以使用 subscribeOn() 和 observeOn() 两个方法来对线程进行控制了。\nsubscribeOn(): 指定 subscribe() 所发生的线程，即 Observable.OnSubscribe 被激活时所处的线程。或者叫做事件产生的线程。 observeOn(): 指定 Subscriber 所运行在的线程。或者叫做事件消费的线程。 文字叙述总归难理解，上代码：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;just\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;3\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Schedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;io\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 指定 subscribe() 发生在 IO 线程\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;AndroidSchedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;mainThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 指定 Subscriber 的回调发生在主线程\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Integer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Integer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; number\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;d\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tag\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;number:\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;+\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; number\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 上面这段代码中，由于 subscribeOn(Schedulers.io()) 的指定，被创建的事件的内容 1、2、3、4 将会在 IO 线程发出；而由于observeOn(AndroidScheculers.mainThread()) 的指定，因此 subscriber 数字的打印将发生在主线程 。事实上，这种在subscribe() 之前写上两句 subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式非常常见，它适用于多数的 『后台线程取数据，主线程显示』的程序策略。\n而前面提到的由图片 id 取得图片并显示的例子，如果也加上这两句：\n`\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; drawableRes \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;ImageView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; imageView \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;create\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;OnSubscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;?\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; drawable \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getTheme\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;().\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getDrawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;drawableRes\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;));\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onCompleted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Schedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;io\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 指定 subscribe() 发生在 IO 线程\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;AndroidSchedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;mainThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 指定 Subscriber 的回调发生在主线程\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; imageView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;setImageDrawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;drawable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onCompleted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Throwable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Toast\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;makeText\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;activity\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;Error!\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Toast\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;LENGTH_SHORT\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;).\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;show\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 那么，加载图片将会发生在 IO 线程，而设置图片则被设定在了主线程。这就意味着，即使加载图片耗费了几十甚至几百毫秒的时间，也不会造成丝毫界面的卡顿。\n2) Scheduler 的原理 (一) RxJava 的 Scheduler API 很方便，也很神奇（加了一句话就把线程切换了，怎么做到的？而且 subscribe() 不是最外层直接调用的方法吗，它竟然也能被指定线程？）。然而 Scheduler 的原理需要放在后面讲，因为它的原理是以下一节《变换》的原理作为基础的。\n好吧这一节其实我屁也没说，只是为了让你安心，让你知道我不是忘了讲原理，而是把它放在了更合适的地方。\n4. 变换 终于要到牛逼的地方了，不管你激动不激动，反正我是激动了。\nRxJava 提供了对事件序列进行变换的支持，这是它的核心功能之一，也是大多数人说『RxJava 真是太好用了』的最大原因。**所谓变换，就是将事件序列中的对象或整个序列进行加工处理，转换成不同的事件或事件序列。**概念说着总是模糊难懂的，来看 API。\n1) API 首先看一个 map() 的例子：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;just\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;images/logo.png\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 输入类型 String\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;map\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Func1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; filePath\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 参数类型 String\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getBitmapFromPath\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;filePath\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 返回类型 Bitmap\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 参数类型 Bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; showBitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;bitmap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 这里出现了一个叫做 Func1 的类。它和 Action1 非常相似，也是 RxJava 的一个接口，用于包装含有一个参数的方法。 Func1 和Action 的区别在于， Func1 包装的是有返回值的方法。另外，和 ActionX 一样， FuncX 也有多个，用于不同参数个数的方法。FuncX和 ActionX 的区别在 FuncX 包装的是有返回值的方法。\n可以看到，map() 方法将参数中的 String 对象转换成一个 Bitmap 对象后返回，而在经过 map() 方法后，事件的参数类型也由 String转为了 Bitmap。这种直接变换对象并返回的，是最常见的也最容易理解的变换。不过 RxJava 的变换远不止这样，它不仅可以针对事件对象，还可以针对整个事件队列，这使得 RxJava 变得非常灵活。我列举几个常用的变换：\nmap(): 事件对象的直接变换，具体功能上面已经介绍过。它是 RxJava 最常用的变换。 map() 的示意图： flatMap(): 这是一个很有用但非常难理解的变换，因此我决定花多些篇幅来介绍它。 首先假设这么一种需求：假设有一个数据结构『学生』，现在需要打印出一组学生的名字。实现方式很简单： `\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;[]\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; students \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; name\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;d\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tag\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; name\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;students\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;map\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Func1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 很简单。那么再假设：如果要打印出每个学生所需要修的所有课程的名称呢？（需求的区别在于，每个学生只有一个名字，但却有多个课程。）首先可以这样实现：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;[]\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; students \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;List\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Course\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; courses \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getCourses\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; i \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; i \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; courses\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;size\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; i\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;++)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Course\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; course \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; courses\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;get\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;i\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;d\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tag\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; course\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;students\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 依然很简单。那么如果我不想在 Subscriber 中使用 for 循环，而是希望 Subscriber 中直接传入单个的 Course 对象呢（这对于代码复用很重要）？用 map() 显然是不行的，因为 map() 是一对一的转化，而我现在的要求是一对多的转化。那怎么才能把一个 Student 转化成多个 Course 呢？\n这个时候，就需要用 flatMap() 了：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;[]\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; students \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Course\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Course\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Course\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; course\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Log\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;d\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;tag\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; course\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;students\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;flatMap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Func1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Course\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Course\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;student\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getCourses\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 从上面的代码可以看出， flatMap() 和 map() 有一个相同点：它也是把传入的参数转化之后返回另一个对象。但需要注意，和 map()不同的是， flatMap() 中返回的是个 Observable 对象，并且这个 Observable 对象并不是被直接发送到了 Subscriber 的回调方法中。 flatMap() 的原理是这样的：1. 使用传入的事件对象创建一个 Observable 对象；2. 并不发送这个 Observable, 而是将它激活，于是它开始发送事件；3. 每一个创建出来的 Observable 发送的事件，都被汇入同一个 Observable ，而这个 Observable 负责将这些事件统一交给 Subscriber 的回调方法。这三个步骤，把事件拆成了两级，通过一组新创建的 Observable 将初始的对象『铺平』之后通过统一路径分发了下去。而这个『铺平』就是 flatMap() 所谓的 flat。\nflatMap() 示意图：\n扩展：由于可以在嵌套的 Observable 中添加异步代码， flatMap() 也常用于嵌套的异步操作，例如嵌套的网络请求。示例代码（Retrofit + RxJava）：\n`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;networkClient\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;token\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 返回 Observable\u0026amp;lt;String\u0026amp;gt;，在订阅时请求 token，并在响应后发送 token\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;flatMap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Func1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Messages\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Messages\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; token\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 返回 Observable\u0026amp;lt;Messages\u0026amp;gt;，在订阅时请求消息列表，并在响应后发送请求到的消息列表\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; networkClient\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;messages\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Messages\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Messages\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; messages\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 处理显示消息列表\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; showMessages\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;messages\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 传统的嵌套请求需要使用嵌套的 Callback 来实现。而通过 flatMap() ，可以把嵌套的请求写在一条链中，从而保持程序逻辑的清晰。\nthrottleFirst(): 在每次事件触发后的一定时间间隔内丢弃新的事件。常用作去抖动过滤，例如按钮的点击监听器： `\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;RxView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;clickEvents\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;button\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// RxBinding 代码，后面的文章有解释\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;throttleFirst\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;500\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;TimeUnit\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;MILLISECONDS\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 设置防抖间隔为 500ms\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` `\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;妈妈再也不怕我的用户手抖点开两个重复的界面啦。\u0026amp;lt;/span\u0026gt;` 此外， RxJava 还提供很多便捷的方法来实现事件序列的变换，这里就不一一举例了。\n2) 变换的原理：lift() 这些变换虽然功能各有不同，但实质上都是针对事件序列的处理和再发送。而在 RxJava 的内部，它们是基于同一个基础的变换方法：lift(Operator)。首先看一下 lift() 的内部实现（仅核心代码）：\n`\u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 注意：这不是 lift() 的源码，而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 如果需要看源码，可以去 RxJava 的 GitHub 仓库下载。\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; lift\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Operator\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;?\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;?\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; T\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;operator\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;create\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;OnSubscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; newSubscriber \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;operator\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; newSubscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onStart\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onSubscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;newSubscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt;` 这段代码很有意思：它生成了一个新的 Observable 并返回，而且创建新 Observable 所用的参数 OnSubscribe 的回调方法 call() 中的实现竟然看起来和前面讲过的 Observable.subscribe() 一样！然而它们并不一样哟~不一样的地方关键就在于第二行onSubscribe.call(subscriber) 中的 onSubscribe 所指代的对象不同（高能预警：接下来的几句话可能会导致身体的严重不适）——\nsubscribe() 中这句话的 onSubscribe 指的是 Observable 中的 onSubscribe 对象，这个没有问题，但是 lift() 之后的情况就复杂了点。 当含有 lift() 时：\n1.lift() 创建了一个 Observable 后，加上之前的原始 Observable，已经有两个 Observable 了；\n2.而同样地，新 Observable 里的新 OnSubscribe 加上之前的原始 Observable 中的原始 OnSubscribe，也就有了两个OnSubscribe；\n3.当用户调用经过 lift() 后的 Observable 的 subscribe() 的时候，使用的是 lift() 所返回的新的 Observable ，于是它所触发的 onSubscribe.call(subscriber)，也是用的新 Observable 中的新 OnSubscribe，即在 lift() 中生成的那个 OnSubscribe；\n4.而这个新 OnSubscribe 的 call() 方法中的 onSubscribe ，就是指的原始 Observable 中的原始 OnSubscribe ，在这个 call()方法里，新 OnSubscribe 利用 operator.call(subscriber) 生成了一个新的 Subscriber（Operator 就是在这里，通过自己的call() 方法将新 Subscriber 和原始 Subscriber 进行关联，并插入自己的『变换』代码以实现变换），然后利用这个新Subscriber 向原始 Observable 进行订阅。\n这样就实现了 lift() 过程，有点像一种代理机制，通过事件拦截和处理实现事件序列的变换。 精简掉细节的话，也可以这么说：在 Observable 执行了 lift(Operator) 方法之后，会返回一个新的 Observable，这个新的Observable 会像一个代理一样，负责接收原始的 Observable 发出的事件，并在处理后发送给 Subscriber。\n如果你更喜欢具象思维，可以看图：\n或者可以看动图：\n两次和多次的 lift() 同理，如下图：\n举一个具体的 Operator 的实现。下面这是一个将事件中的 Integer 对象转换成 String 的例子，仅供参考：\n`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Operator\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Integer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;?\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Integer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;?\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 将事件序列中的 Integer 对象转换为 String 对象\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Integer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Integer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; integer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;+\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; integer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onCompleted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onCompleted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Throwable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 讲述 lift() 的原理只是为了让你更好地了解 RxJava ，从而可以更好地使用它。然而不管你是否理解了 lift() 的原理，RxJava 都不建议开发者自定义 Operator 来直接使用 lift()，而是建议尽量使用已有的 lift() 包装方法（如map() flatMap() 等）进行组合来实现需求，因为直接使用 lift() 非常容易发生一些难以发现的错误。\n3) compose: 对 Observable 整体的变换 除了 lift() 之外， Observable 还有一个变换方法叫做 compose(Transformer)。它和 lift() 的区别在于， **lift() 是针对事件项和事件序列的，而 compose() 是针对 Observable 自身进行变换。**举个例子，假设在程序中有多个 Observable ，并且他们都需要应用一组相同的 lift() 变换。你可以这么写：\n`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observable1 \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift3\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift4\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable2 \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift3\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift4\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable3 \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift3\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift4\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber3\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable4 \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift3\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift4\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 你觉得这样太不软件工程了，于是你改成了这样：\n`\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; liftAll\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift3\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift4\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; liftAll\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observable1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;).\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; liftAll\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observable2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;).\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; liftAll\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observable3\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;).\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber3\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; liftAll\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observable4\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;).\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber4\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 可读性、可维护性都提高了。可是 Observable 被一个方法包起来，这种方式对于 Observale 的灵活性似乎还是增添了那么点限制。怎么办？这个时候，就应该用 compose() 来解决了：\n`\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;LiftAllTransformer\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;implements\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Transformer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Integer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Integer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift3\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;lift4\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Transformer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; liftAll \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;LiftAllTransformer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;compose\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;liftAll\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;).\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;compose\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;liftAll\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;).\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable3\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;compose\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;liftAll\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;).\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber3\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; observable4\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;compose\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;liftAll\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;).\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber4\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 像上面这样，使用 compose() 方法，Observable 可以利用传入的 Transformer 对象的 call 方法直接对自身进行处理，也就不必被包在方法的里面了。\ncompose() 的原理比较简单，不附图喽。\n5. 线程控制：Scheduler (二) 除了灵活的变换，RxJava 另一个牛逼的地方，就是线程的自由控制。\n1) Scheduler 的 API (二) 前面讲到了，可以利用 subscribeOn() 结合 observeOn() 来实现线程控制，让事件的产生和消费发生在不同的线程。可是在了解了map() flatMap() 等变换方法后，有些好事的（其实就是当初刚接触 RxJava 时的我）就问了：能不能多切换几次线程？\n答案是：能。因为 observeOn() 指定的是 Subscriber 的线程，而这个 Subscriber 并不是（严格说应该为『不一定是』，但这里不妨理解为『不是』）subscribe() 参数中的 Subscriber ，而是 observeOn() 执行时的当前 Observable 所对应的 Subscriber ，即它的直接下级 Subscriber 。换句话说，observeOn() 指定的是它之后的操作所在的线程。因此如果有多次切换线程的需求，只要在每个想要切换线程的位置调用一次 observeOn() 即可。上代码：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;just\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;3\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// IO 线程，由 subscribeOn() 指定\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Schedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;io\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Schedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;newThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;map\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;mapOperator\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 新线程，由 observeOn() 指定\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Schedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;io\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;map\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;mapOperator2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// IO 线程，由 observeOn() 指定\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;AndroidSchedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;mainThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// Android 主线程，由 observeOn() 指定\u0026amp;lt;/span\u0026gt;` 如上，通过 observeOn() 的多次调用，程序实现了线程的多次切换。\n不过，不同于 observeOn() ， subscribeOn() 的位置放在哪里都可以，但它是只能调用一次的。\n又有好事的（其实还是当初的我）问了：如果我非要调用多次 subscribeOn() 呢？会有什么效果？\n这个问题先放着，我们还是从 RxJava 线程控制的原理说起吧。\n2) Scheduler 的原理（二） 其实， subscribeOn() 和 observeOn() 的内部实现，也是用的 lift()。具体看图（不同颜色的箭头表示不同的线程）：\nsubscribeOn() 原理图：\nobserveOn() 原理图：\n从图中可以看出，subscribeOn() 和 observeOn() 都做了线程切换的工作（图中的 “schedule…” 部位）。不同的是， subscribeOn()的线程切换发生在 OnSubscribe 中，即在它通知上一级 OnSubscribe 时，这时事件还没有开始发送，因此 subscribeOn() 的线程控制可以从事件发出的开端就造成影响；而 observeOn() 的线程切换则发生在它内建的 Subscriber 中，即发生在它即将给下一级Subscriber 发送事件时，因此 observeOn() 控制的是它后面的线程。\n最后，我用一张图来解释当多个 subscribeOn() 和 observeOn() 混合使用时，线程调度是怎么发生的（由于图中对象较多，相对于上面的图对结构做了一些简化调整）：\n图中共有 5 处含有对事件的操作。由图中可以看出，①和②两处受第一个 subscribeOn() 影响，运行在红色线程；③和④处受第一个observeOn() 的影响，运行在绿色线程；⑤处受第二个 onserveOn() 影响，运行在紫色线程；而第二个 subscribeOn() ，由于在通知过程中线程就被第一个 subscribeOn() 截断，因此对整个流程并没有任何影响。这里也就回答了前面的问题：当使用了多个subscribeOn() 的时候，只有第一个 subscribeOn() 起作用。\n3) 延伸：doOnSubscribe() 然而，虽然超过一个的 subscribeOn() 对事件处理的流程没有影响，但在流程之前却是可以利用的。\n在前面讲 Subscriber 的时候，提到过 Subscriber 的 onStart() 可以用作流程开始前的初始化。然而 onStart() 由于在subscribe() 发生时就被调用了，因此不能指定线程，而是只能执行在 subscribe() 被调用时的线程。这就导致如果 onStart() 中含有对线程有要求的代码（例如在界面上显示一个 ProgressBar，这必须在主线程执行），将会有线程非法的风险，因为有时你无法预测subscribe() 将会在什么线程执行。\n而与 Subscriber.onStart() 相对应的，有一个方法 Observable.doOnSubscribe() 。它和 Subscriber.onStart() 同样是在subscribe() 调用后而且在事件发送前执行，但区别在于它可以指定线程。默认情况下， doOnSubscribe() 执行在 subscribe() 发生的线程；而如果在 doOnSubscribe() 之后有 subscribeOn() 的话，它将执行在离它最近的 subscribeOn() 所指定的线程。\n示例代码：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;create\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;onSubscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Schedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;io\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;doOnSubscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; progressBar\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;setVisibility\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;View\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;VISIBLE\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 需要在主线程执行\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;AndroidSchedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;mainThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 指定主线程\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;AndroidSchedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;mainThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 如上，在 doOnSubscribe()的后面跟一个 subscribeOn() ，就能指定准备工作的线程了。\nRxJava 的适用场景和使用方式 1. 与 Retrofit 的结合 Retrofit 是 Square 的一个著名的网络请求库。没有用过 Retrofit 的可以选择跳过这一小节也没关系，我举的每种场景都只是个例子，而且例子之间并无前后关联，只是个抛砖引玉的作用，所以你跳过这里看别的场景也可以的。\nRetrofit 除了提供了传统的 Callback 形式的 API，还有 RxJava 版本的 Observable 形式 API。下面我用对比的方式来介绍 Retrofit 的 RxJava 版 API 和传统版本的区别。\n以获取一个 User 对象的接口作为例子。使用Retrofit 的传统 API，你可以用这样的方式来定义请求：\n`\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@GET\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;/user\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Query\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;userId\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; userId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Callback\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; callback\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 在程序的构建过程中， Retrofit 会把自动把方法实现并生成代码，然后开发者就可以利用下面的方法来获取特定用户并处理响应：\n`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;userId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Callback\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; success\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; userView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;setUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; failure\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;RetrofitError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; error\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// Error handling\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt;` 而使用 RxJava 形式的 API，定义同样的请求是这样的：\n`\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@GET\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;/user\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Query\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;userId\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; userId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 使用的时候是这样的：\n`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;userId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;AndroidSchedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;mainThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; userView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;setUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onCompleted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Throwable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; error\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// Error handling\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 看到区别了吗？\n当 RxJava 形式的时候，Retrofit 把请求封装进 Observable ，在请求结束后调用 onNext() 或在请求失败后调用 onError()。\n对比来看， Callback 形式和 Observable 形式长得不太一样，但本质都差不多，而且在细节上 Observable 形式似乎还比 Callback形式要差点。那 Retrofit 为什么还要提供 RxJava 的支持呢？\n因为它好用啊！从这个例子看不出来是因为这只是最简单的情况。而一旦情景复杂起来， Callback 形式马上就会开始让人头疼。比如：\n假设这么一种情况：你的程序取到的 User 并不应该直接显示，而是需要先与数据库中的数据进行比对和修正后再显示。使用 Callback方式大概可以这么写：\n`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;userId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Callback\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; success\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; processUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 尝试修正 User 数据\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; userView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;setUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; failure\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;RetrofitError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; error\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// Error handling\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt;` 有问题吗？\n很简便，但不要这样做。为什么？因为这样做会影响性能。数据库的操作很重，一次读写操作花费 10~20ms 是很常见的，这样的耗时很容易造成界面的卡顿。所以通常情况下，如果可以的话一定要避免在主线程中处理数据库。所以为了提升性能，这段代码可以优化一下：\n`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;userId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Callback\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; success\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Thread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; run\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; processUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 尝试修正 User 数据\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; runOnUiThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Runnable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 切回 UI 线程\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; run\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; userView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;setUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}).\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;start\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; failure\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;RetrofitError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; error\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// Error handling\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt;` 性能问题解决，但……这代码实在是太乱了，迷之缩进啊！杂乱的代码往往不仅仅是美观问题，因为代码越乱往往就越难读懂，而如果项目中充斥着杂乱的代码，无疑会降低代码的可读性，造成团队开发效率的降低和出错率的升高。\n这时候，如果用 RxJava 的形式，就好办多了。 RxJava 形式的代码是这样的：\n`\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;getUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;userId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;doOnNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; processUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;AndroidSchedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;mainThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; userView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;setUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onCompleted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Throwable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; error\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// Error handling\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 后台代码和前台代码全都写在一条链中，明显清晰了很多。\n再举一个例子：假设 /user 接口并不能直接访问，而需要填入一个在线获取的 token ，代码应该怎么写？\nCallback 方式，可以使用嵌套的 Callback：\n`\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@GET\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;/token\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getToken\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Callback\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; callback\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@GET\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;/user\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Query\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;token\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; token\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Query\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;userId\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; userId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Callback\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; callback\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getToken\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Callback\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; success\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; token\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;userId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Callback\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; success\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; userView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;setUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; failure\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;RetrofitError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; error\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// Error handling\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; failure\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;RetrofitError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; error\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// Error handling\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 倒是没有什么性能问题，可是迷之缩进毁一生，你懂我也懂，做过大项目的人应该更懂。\n而使用 RxJava 的话，代码是这样的：\n`\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@GET\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;/token\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getToken\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@GET\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;/user\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Query\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;token\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; token\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Query\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;str\u0026#34;\u0026gt;\u0026#34;userId\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; userId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getToken\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;flatMap\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Func1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; token\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; getUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;token\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; userId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;})\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;observeOn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;AndroidSchedulers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;mainThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Observer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onNext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;User\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; userView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;setUser\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;user\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onCompleted\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; onError\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Throwable\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; error\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// Error handling\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 用一个 flatMap() 就搞定了逻辑，依然是一条链。看着就很爽，是吧？\n好，Retrofit 部分就到这里。\n2. RxBinding RxBinding 是 Jake Wharton 的一个开源库，它提供了一套在 Android 平台上的基于 RxJava 的 Binding API。所谓 Binding，就是类似设置 OnClickListener 、设置 TextWatcher 这样的注册绑定对象的 API。\n举个设置点击监听的例子。使用 RxBinding ，可以把事件监听用这样的方法来设置：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Button\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; button \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;...;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;RxView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;clickEvents\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;button\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// 以 Observable 形式来反馈点击事件\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;Action1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;ViewClickEvent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;\u0026amp;gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kwd\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; call\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;ViewClickEvent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt; event\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;com\u0026#34;\u0026gt;// Click handling\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt;` 看起来除了形式变了没什么区别，实质上也是这样。甚至如果你看一下它的源码，你会发现它连实现都没什么惊喜：它的内部是直接用一个包裹着的 setOnClickListener() 来实现的。然而，仅仅这一个形式的改变，却恰好就是 RxBinding 的目的：扩展性。通过RxBinding 把点击监听转换成 Observable 之后，就有了对它进行扩展的可能。扩展的方式有很多，根据需求而定。一个例子是前面提到过的 throttleFirst() ，用于去抖动，也就是消除手抖导致的快速连环点击：\n`\u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;RxView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;clickEvents\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;button\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;throttleFirst\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;lit\u0026#34;\u0026gt;500\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;typ\u0026#34;\u0026gt;TimeUnit\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;MILLISECONDS\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pln\u0026#34;\u0026gt;clickAction\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;pun\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt;` 如果想对 RxBinding 有更多了解，可以去它的 GitHub 项目 下面看看。\n3. 各种异步操作 前面举的 Retrofit 和 RxBinding 的例子，是两个可以提供现成的 Observable 的库。而如果你有某些异步操作无法用这些库来自动生成 Observable，也完全可以自己写。例如数据库的读写、大图片的载入、文件压缩/解压等各种需要放在后台工作的耗时操作，都可以用 RxJava 来实现，有了之前几章的例子，这里应该不用再举例了。\n4. RxBus RxBus 名字看起来像一个库，但它并不是一个库，而是一种模式，它的思想是使用 RxJava 来实现了 EventBus ，而让你不再需要使用Otto 或者 GreenRobot 的 EventBus。至于什么是 RxBus，可以看这篇文章。顺便说一句，Flipboard 已经用 RxBus 替换掉了 Otto，目前为止没有不良反应。\n最后 对于 Android 开发者来说， RxJava 是一个很难上手的库，因为它对于 Android 开发者来说有太多陌生的概念了。可是它真的很牛逼。因此，我写了这篇《给 Android 开发者的 RxJava 详解》，希望能给始终搞不明白什么是 RxJava 的人一些入门的指引，或者能让正在使用 RxJava 但仍然心存疑惑的人看到一些更深入的解析。无论如何，只要能给各位同为 Android 工程师的你们提供一些帮助，这篇文章的目的就达到了。\n","permalink":"https://blog.zdltech.com/posts/%E7%BB%99-android-%E5%BC%80%E5%8F%91%E8%80%85%E7%9A%84-rxjava-%E8%AF%A6%E8%A7%A3/","summary":"\u003ch3 id=\"\"\u003e前言\u003c/h3\u003e\n\u003cp\u003e我从去年开始使用 RxJava ，到现在一年多了。今年加入了 Flipboard 后，看到 Flipboard 的 Android 项目也在使用 RxJava ，并且使用的场景越来越多 。而最近这几个月，我也发现国内越来越多的人开始提及 RxJava 。有人说『RxJava 真是太好用了』，有人说『RxJava 真是太难用了』，另外更多的人表示：我真的百度了也谷歌了，但我还是想问： RxJava 到底是什么？\u003c/p\u003e\n\u003cp\u003e鉴于 RxJava 目前这种既火爆又神秘的现状，而我又在一年的使用过程中对 RxJava 有了一些理解，我决定写下这篇文章来对 RxJava 做一个相对详细的、针对 Android 开发者的介绍。\u003c/p\u003e\n\u003cp\u003e这篇文章的目的有两个：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e给对 RxJava 感兴趣的人一些入门的指引\u003c/li\u003e\n\u003cli\u003e给正在使用 RxJava 但仍然心存疑惑的人一些更深入的解析\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"toc\"\u003e\n\u003cpre\u003e\u003ccode\u003e- [RxJava 到底是什么](http://gank.io/post/560e15be2dca930e00da1083#toc_1)\n\n- [RxJava 好在哪](http://gank.io/post/560e15be2dca930e00da1083#toc_2)\n\n- [API 介绍和原理简析](http://gank.io/post/560e15be2dca930e00da1083#toc_3) \n    - [1. 概念：扩展的观察者模式](http://gank.io/post/560e15be2dca930e00da1083#toc_4) \n        - [观察者模式](http://gank.io/post/560e15be2dca930e00da1083#toc_5)\n        \n        - [RxJava 的观察者模式](http://gank.io/post/560e15be2dca930e00da1083#toc_6)\n        \n      \n    \n    \n    - [2. 基本实现](http://gank.io/post/560e15be2dca930e00da1083#toc_7) \n        - [1) 创建 Observer](http://gank.io/post/560e15be2dca930e00da1083#toc_8)\n        \n        - [2) 创建 Observable](http://gank.io/post/560e15be2dca930e00da1083#toc_9)\n        \n        - [3) Subscribe (订阅)](http://gank.io/post/560e15be2dca930e00da1083#toc_10)\n        \n        - [4) 场景示例](http://gank.io/post/560e15be2dca930e00da1083#toc_11) \n            - [a. 打印字符串数组](http://gank.io/post/560e15be2dca930e00da1083#toc_12)\n            \n            - [b. 由 id 取得图片并显示](http://gank.io/post/560e15be2dca930e00da1083#toc_13)\n            \n          \n        \n      \n    \n    \n    - [3. 线程控制 —— Scheduler (一)](http://gank.io/post/560e15be2dca930e00da1083#toc_14) \n        - [1) Scheduler 的 API (一)](http://gank.io/post/560e15be2dca930e00da1083#toc_15)\n        \n        - [2) Scheduler 的原理 (一)](http://gank.io/post/560e15be2dca930e00da1083#toc_16)\n        \n      \n    \n    \n    - [4. 变换](http://gank.io/post/560e15be2dca930e00da1083#toc_17) \n        - [1) API](http://gank.io/post/560e15be2dca930e00da1083#toc_18)\n        \n        - [2) 变换的原理：lift()](http://gank.io/post/560e15be2dca930e00da1083#toc_19)\n        \n        - [3) compose: 对 Observable 整体的变换](http://gank.io/post/560e15be2dca930e00da1083#toc_20)\n        \n      \n    \n    \n    - [5. 线程控制：Scheduler (二)](http://gank.io/post/560e15be2dca930e00da1083#toc_21) \n        - [1) Scheduler 的 API (二)](http://gank.io/post/560e15be2dca930e00da1083#toc_22)\n        \n        - [2) Scheduler 的原理（二）](http://gank.io/post/560e15be2dca930e00da1083#toc_23)\n        \n        - [3) 延伸：doOnSubscribe()](http://gank.io/post/560e15be2dca930e00da1083#toc_24)\n        \n      \n    \n  \n\n\n- [RxJava 的适用场景和使用方式](http://gank.io/post/560e15be2dca930e00da1083#toc_25) \n    - [1. 与 Retrofit 的结合](http://gank.io/post/560e15be2dca930e00da1083#toc_26)\n    \n    - [2. RxBinding](http://gank.io/post/560e15be2dca930e00da1083#toc_27)\n    \n    - [3. 各种异步操作](http://gank.io/post/560e15be2dca930e00da1083#toc_28)\n    \n    - [4. RxBus](http://gank.io/post/560e15be2dca930e00da1083#toc_29)\n    \n  \n\n\n- [最后](http://gank.io/post/560e15be2dca930e00da1083#toc_30) \n    - [关于作者：](http://gank.io/post/560e15be2dca930e00da1083#toc_31)\n    \n    - [为什么写这个？](http://gank.io/post/560e15be2dca930e00da1083#toc_32)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e在正文开始之前的最后，放上 \u003ccode\u003eGitHub\u003c/code\u003e 链接和引入依赖的 \u003ccode\u003egradle\u003c/code\u003e 代码： Github：\u003cbr\u003e\n\u003ca href=\"https://github.com/ReactiveX/RxJava\"\u003ehttps://github.com/ReactiveX/RxJava\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"https://github.com/ReactiveX/RxAndroid\"\u003ehttps://github.com/ReactiveX/RxAndroid\u003c/a\u003e\u003cbr\u003e\n引入依赖：\u003cbr\u003e\n\u003ccode\u003ecompile 'io.reactivex:rxjava:1.0.14'\u003c/code\u003e\u003cbr\u003e\n\u003ccode\u003ecompile 'io.reactivex:rxandroid:1.0.1'\u003c/code\u003e\u003cbr\u003e\n（版本号是文章发布时的最新稳定版）\u003c/p\u003e","title":"给 Android 开发者的 RxJava 详解"},{"content":"Android性能优化典范第4季的课程学习笔记终于在2015年的最后一天完成了，文章共17个段落，包含的内容大致有：优化网络请求的行为，优化安装包的资源文件，优化数据传输的效率，性能优化的几大基础原理等等。因为学习认知水平有限，肯定存在不少理解偏差甚至错误的地方，请多多交流指正！\n1)Cachematters for networking 想要使得Android系统上的网络访问操作更加的高效就必须做好网络数据的缓存。这是提高网络访问性能最基础的步骤之一。从手机的缓存中直接读取数据肯定比从网络上获取数据要更加的便捷高效，特别是对于那些会被频繁访问到的数据，需要把这些数据缓存到设备上，以便更加快速的进行访问。\nAndroid系统上关于网络请求的Http Response Cache是默认关闭的，这样会导致每次即使请求的数据内容是一样的也会需要重复被调用执行，效率低下。我们可以通过下面的代码示例开启HttpResponseCache。\n开启Http Response Cache之后，Http操作相关的返回数据就会缓存到文件系统上，不仅仅是主程序自己编写的网络请求相关的数据会被缓存，另外引入的library库中的网络相关的请求数据也会被缓存到这个Cache中。\n网络请求的场景有可以是普通的http请求，也可以打开某个URL去获取数据，如下图所示：\n我们有两种方式来清除HttpResponseCache的缓存数据：第一种方式是缓存溢出的时候删除最旧最老的文件，第二种方式是通过Http返回Header中的Cache-Control字段来进行控制的。如下图所示：\n通常来说，HttpResponseCache会缓存所有的返回信息，包括实际的数据与Header的部分.一般情况下，这个Cache会自动根据协议返回Cache-Control的内容与当前缓存的数据量来决定哪些数据应该继续保留，哪些数据应该删除。但是在一些极端的情况下，例如服务器返回的数据没有设置Cache废弃的时间，或者是本地的Cache文件系统与返回的缓存数据有冲突，或者是某些特殊的网络环境导致HttpResponseCache工作异常，在这些情况下就需要我们自己来实现Http的缓存Cache。\n实现自定义的http缓存，需要解决两个问题：第一个是实现一个DiskCacheManager，另外一个是制定Cache的缓存策略。关于DiskCacheManager，我们可以扩展Android系统提供的DiskLruCache来实现。而Cache的缓存策略，相对来说复杂一些，我们可能需要把部分JSON数据设计成不能缓存的，另外一些JSON数据设计成可以缓存几天的，把缩略图设计成缓存一两天的等等，为不同的数据类型根据他们的使用特点制定不同的缓存策略。\n想要比较好的实现这两件事情，如果全部自己从头开始写会比较繁琐复杂，所幸的是，有不少著名的开源框架帮助我们快速的解决了那些问题。我们可以使用Volly，okHTTP，Picasso来实现网络缓存。\n实现好网络缓存之后，我们可以使用Android Studio里面的Network Traffic Tools来查看网络数据的请求与返回情况，另外我们还可以使用AT\u0026amp;T ARO工具来抓取网络数据包进行分析查看。\n2)Optimizing Network Request Frequencies 应用程序的一个基础功能是能够保持确保界面上呈现的信息是即时最新的，例如呈现最新的新闻，天气，信息流等等信息。但是，过于频繁的促使手机客户端应用去同步最新的服务器数据会对性能产生很大的负面影响，不仅仅使得CPU不停的在工作，内存，网络流量，电量等等都会持续的被消耗，所以在进行网络请求操作的时候一定要避免多度同步操作。\n退到后台的应用为了能够在切换回前台的时候呈现最新的数据，会偷偷在后台不停的做同步的操作。这种行为会带来很严重的问题，首先因为网络请求的行为异常的耗电，其次不停的进行网络同步会耗费很多带宽流量。\n为了能够尽量的减少不必要的同步操作，我们需要遵守下面的一些规则：\n首先我们要对网络行为进行分类，区分需要立即更新数据的行为和其他可以进行延迟的更新行为，为不同的场景进行差异化处理。 其次要避免客户端对服务器的轮询操作，这样会浪费很多的电量与带宽流量。解决这个问题，我们可以使用Google Cloud Message来对更新的数据进行推送。 然后在某些必须做同步的场景下，需要避免使用固定的间隔频率来进行更新操作，我们应该在返回的数据无更新的时候，使用双倍的间隔时间来进行下一次同步。 最后更进一步，我们还可以通过判断当前设备的状态来决定同步的频率，例如判断设备处于休眠，运动等不同的状态设计各自不同时间间隔的同步频率。 另外，我们还可以通过判断设备是否连接上WiFi，是否正在充电来决定更新的频率。为了能够方便的实现这个功能，Android为我们提供了GCMNetworkManager来判断设备当下的状态，从而设计更加高效的网络同步操作，如下图所示：\n3)Effective Prefetching 关于提升网络操作的性能，除了避免频繁的网络同步操作之外，还可以使用捆绑批量访问的方式来减少访问的频率，为了达到这个目的，我们就需要了解Prefetching。\n举个例子，在某个场景下，一开始发出了网络请求得到了某张图片，隔了10s之后，发出第二次请求想要拿到另外一张图片，再隔了6s发出第三张图片的网络请求。这会导致设备的无线蜂窝一直处于高消耗的状态。Prefetching就是预先判定那些可能马上就会使用到的网络资源，捆绑一起集中进行网络请求。这样能够极大的减少电量的消耗，提升设备的续航时间。\n使用Prefetching的难点在于如何判断事先获取的数据量到底是多少，如果预取的数据量偏少，那么就起不到什么效果，但是如果预取过多，又可能导致访问的时间过长。\n那么问题来了，到底预取多少才比较合适呢？一个比较普适的规则是，在3G网络下可以预取1-5Mb的数据量，或者是按照提前预期后续1-2分钟的数据作为基线标准。在实际的操作当中，我们还需要考虑当前的网络速度来决定预取的数据量，例如在同样的时间下，4G网络可以获取到12张图片的数据，而2G网络则只能拿到3张图片的数据。所以，我们还需要把当前的网络环境情况添加到设计预取数据量的策略当中去。判断当前设备的状态与网络情况，可以使用前面提到过的GCMNetworkManager。\n4)Adapting to Latency 网络延迟通常来说很容易被用户察觉到，严重的网络延迟会对用户体验造成很大的影响，用户很容易抱怨应用程序写的不好。\n一个典型的网络操作行为，通常包含以下几个步骤：首先手机端发起网络请求，到达网络服务运营商的基站，再转移到服务提供者的服务器上，经过解码之后，接着访问本地的存储数据库，获取到数据之后，进行编码，最后按照原来传递的路径逐层返回。如下图所示：\n在上面的网络请求链路当中的任何一个环节都有可能导致严重的延迟，成为性能瓶颈，但是这些环节可能出现的问题，客户端应用是无法进行调节控制的，应用能够做的就只是根据当前的网络环境选择当下最佳的策略来降低出现网络延迟的概率。主要的实施步骤有两步：第1步检测收集当前的网络环境信息，第2步根据当前收集到的信息进行网络请求行为的调整。\n关于第1步检测当前的网络环境，我们可以使用系统提供的API来获取到相关的信息，如下图所示：\n通过上面的示例，我们可以获取到移动网络的详细子类型，例如4G(LTE),3G等等，详细分类见下图，获取到详细的移动网络类型之后，我们可以根据当前网络的速率来调整网络请求的行为：\n关于第2步根据收集到的信息进行策略的调整，通常来说，我们可以把网络请求延迟划分为三档：例如把网络延迟小于60ms的划分为GOOD，大于220ms的划分为BAD，介于两者之间的划分为OK（这里的60ms，220ms会需要根据不同的场景提前进行预算推测）。如果网络延迟属于GOOD的范畴，我们就可以做更多比较激进的预取数据的操作，如果网络延迟属于BAD的范畴，我们就应该考虑把当下的网络请求操作Hold住等待网络状况恢复到GOOD的状态再进行处理。\n前面提到说60ms，220ms是需要提前自己预测的，可是预测的工作相当复杂。首先针对不同的机器与网络环境，网络延迟的三档阈值都不太一样，出现的概率也不尽相同，我们会需要针对这些不同的用户与设备选择不同的阈值进行差异化处理：\nAndroid官方为了帮助我们设计自己的网络请求策略，为我们提供了模拟器的网络流量控制功能来对实际环境进行模拟测量，或者还可以使用AT\u0026amp;T提供的AT\u0026amp;T Network Attenuator来帮助预估网络延迟。\n5)Minimizing Asset Payload 为了能够减小网络传输的数据量，我们需要对传输的数据做压缩的处理，这样能够提高网络操作的性能。首先不同的网络环境，下载速度以及网络延迟是存在差异的，如下图所示：\n如果我们选择在网速更低的网络环境下进行数据传输，这就意味着需要执行更长的时间，而更长的网络操作行为，会导致电量消耗更加严重。另外传输的数据如果不做压缩处理，也同样会增加网络传输的时间，消耗更多的电量。不仅如此，未经过压缩的数据，也会消耗更多的流量，使得用户需要付出更多的流量费。\n通常来说，网络传输数据量的大小主要由两部分组成：图片与序列化的数据，那么我们需要做的就是减少这两部分的数据传输大小，分下面两个方面来讨论。\nA)首先需要做的是减少图片的大小，选择合适的图片保存格式是第一步。下图展示了PNG,JPEG,WEBP三种主流格式在占用空间与图片质量之间的对比： 对于JPEG与WEBP格式的图片，不同的清晰度对占用空间的大小也会产生很大的影响，适当的减少JPG Quality，可以大大的缩小图片占用的空间大小。\n另外，我们需要为不同的使用场景提供当前场景下最合适的图片大小，例如针对全屏显示的情况我们会需要一张清晰度比较高的图片，而如果只是显示为缩略图的形式，就只需要服务器提供一个相对清晰度低很多的图片即可。服务器应该支持到为不同的使用场景分别准备多套清晰度不一样的图片，以便在对应的场景下能够获取到最适合自己的图片。这虽然会增加服务端的工作量，可是这个付出却十分值得！\nB)其次需要做的是减少序列化数据的大小。JSON与XML为了提高可读性，在文件中加入了大量的符号，空格等等字符，而这些字符对于程序来说是没有任何意义的。我们应该使用Protocal Buffers，Nano-Proto-Buffers，FlatBuffer来减小序列化的数据的大小。 Android系统为我们提供了工具来查看网络传输的数据情况，打开Android Studio的Monitor，里面有网络访问的模块。或者是打开AT\u0026amp;T提供的ARO工具来查看网络请求状态。\n6)Service Performance Patterns Service是Android程序里面最常用的基础组件之一，但是使用Service很容易引起电量的过度消耗以及系统资源的未及时释放。学会在何时启用Service以及使用何种方式杀掉Service就显得十分有必要了。\n简要过一下Service的特性：Service和UI没有关联，Service的创建，执行，销毁Service都是需要占用系统时间和内存的。另外Service是默认运行在UI线程的，这意味着Service可能会影响到系统的流畅度。\n使用Service应该遵循下面的一些规则：\n避免错误的使用Service，例如我们不应该使用Service来监听某些事件的变化，不应该搞一个Service在后台对服务器不断的进行轮询(应该使用Google Cloud Messaging) 如果已经事先知道Service里面的任务应该执行在后台线程(非默认的主线程)的时候，我们应该使用IntentService或者结合HanderThread，AsycnTask Loader实现的Service。 Android系统为我们提供了以下的一些异步相关的工具类\nGCM BroadcastReciever LocalBroadcastReciever WakefulBroadcastReciver HandlerThreads AsyncTaskLoaders IntentService 如果使用上面的诸多方案还是无法替代普通的Service，那么需要注意的就是如何正确的关闭Service。\n普通的Started Service，需要通过stopSelf()来停止Service 另外一种Bound Service，会在其他组件都unBind之后自动关闭自己 把上面两种Service进行合并之后，我们可以得到如下图所示的Service(相关知识，还可以参考http://hukai.me/android-notes-services/,http://hukai.me/android-notes-bound-services/)\n7)Removing unused code 使用第三方库(library)可以在不用自己编写大量代码的前提下帮助我们解决一些难题，节约大量的时间，但是这些引入的第三方库很可能会导致主程序代码臃肿冗余。\n如果我们处在人力，财力都相对匮乏的情况下，通常会倾向大量使用第三方库来帮助编写应用程序。这其实是无可厚非的，那些著名的第三方库的可行性早就被很多应用所采用并实践证明过。但是这里面存在的问题是，如果我们因为只需要某个library的一小部分功能而把整个library都导入自己的项目，这就会引起代码臃肿。一旦发生代码臃肿，用户就会下载到安装包偏大的应用程序，另外因为代码臃肿，还很有可能会超过单个编译文件只能有65536个方法的上限。解决这个问题的办法是使用MultiDex的方案，可是这实在是无奈之举，原则上，我们还是应该尽量避免出现这种情况。\nAndroid为我们提供了Proguard的工具来帮助应用程序对代码进行瘦身，优化，混淆的处理。它会帮助移除那些没有使用到的代码，还可以对类名，方法名进行混淆处理以避免程序被反编译。举个例子，Google I/O 2015这个应用使用了大量的library，没有经过Proguard处理之前编译出来的包是8.4Mb大小，经过处理之后的包仅仅是4.1Mb大小。\n使用Proguard相当的简单，只需要在build.gradle文件中配置minifEnable为true即可，如下图所示：\n但是Proguard还是不足够聪明到能够判断哪些类，哪些方法是不能够被混淆的，针对这些情况，我们需要手动的把这些需要保留的类名与方法名添加到Proguard的配置文件中，如下图所示：\n在使用library的时候，需要特别注意这些library在proguard配置上的说明文档，我们需要把这些配置信息添加到自己的主项目中。关于Proguard的详细说明，请看官方文档http://developer.android.com/tools/help/proguard.html\n8)Removing unused resources 减少APK安装包的大小也是Android程序优化中很重要的一个方面，我们不应该给用户下载到一个臃肿的安装包。假设这样一个场景，我们引入了Google Play Service的library，是想要使用里面的Maps的功能，但是里面的登入等等其他功能是不需要的，可是这些功能相关的代码与图片资源，布局资源如果也被引入我们的项目，这样就会导致我们的程序安装包臃肿。\n所幸的是，我们可以使用Gradle来帮助我们分析代码，分析引用的资源，对于那些没有被引用到的资源，会在编译阶段被排除在APK安装包之外，要实现这个功能，对我们来说仅仅只需要在build.gradle文件中配置shrinkResource为true就好了，如下图所示：\n为了辅助gradle对资源进行瘦身，或者是某些时候的特殊需要，我们可以通过tools:keep或者是tools:discard标签来实现对特定资源的保留与废弃，如下图所示：\nGradle目前无法对values，drawable等根据运行时来决定使用的资源进行优化，对于这些资源，需要我们自己来确保资源不会有冗余。\n9)Perf Theory: Caching 当我们讨论性能优化的时候，缓存是最常见最有效的策略之一。无论是为了提高CPU的计算速度还是提高数据的访问速度，在绝大多数的场景下，我们都会使用到缓存。关于缓存是如何提高效率的，这里就不赘述了。\n那么在什么地方，在何时应该利用好缓存来提高效率呢？请看下面的例子，很明显的演示了在某些细节上是如何利用缓存的原理来提高代码的执行效率的：\n类似上面的例子采用缓存原理的地方还有很多，例如缓存到内存里面的图片资源，网络请求返回数据的缓存等等。总之，使用缓存就是为了减少不必要的操作，尽量复用已有的对象来提高效率。\n10)Perf Theory: Approximation(近似法) 很多时候，我们都需要学会在性能更优与体验更好之间做一定的权衡取舍。为了获取更好的表现性能，我们可能会需要牺牲一些用户体验，例如把某些细节做删除或者是降级处理以便有更好的性能。例如，导航类的应用，如果在导航期间是不停的执行定位的操作，这样能够很及时的获取到最新的位置信息以及当下位置相关的其他提示信息，但是这样会导致网络流量以及手机电量的过度消耗。所以我们可以做一定的降级处理，每隔固定的一段时间才去获取一次位置信息，损失一点及时性来换取更长的续航时间。\n还有很多地方都会用到近似法则来优化程序的性能，例如使用一张比较接近实际大小的图片来替代原图，换取更快的加载速度。所以对于那些对计算结果要求不需要十分精确的场景，我们可以使用近似法则来提高程序的性能。\n11)Perf Theory: Culling(遴选，挑选) 在以前的性能优化课程里面，我们知道可以通过减少Overdraw来提高程序的渲染性能（主要手段有移除非必须的background，减少重叠的布局，使用clipRect来提高自定义View的绘制性能），今天在这里要介绍的另外一个提高性能的方法是逐步对数据进行过滤筛选，减小搜索的数据集，以此提高程序的执行性能。例如我们需要搜索到居住在某个地方，年龄是多少，符合某些特定条件的候选人，就可以通过逐层过滤筛选的方式来提高后续搜索的执行效率。\n12)Perf Theory: Threading 使用多线程并发处理任务，从某种程度上可以快速提高程序的执行性能。对于Android程序来说，主线程通常也成为UI线程，需要处理UI的渲染，响应用户的操作等等。对于那些可能影响到UI线程的任务都需要特别留意是否有必要放到其他的线程来进行处理。如果处理不当，很有可能引起程序ANR。关于多线程的使用建议，可以参考官方的培训课程http://developer.android.com/training/best-background.html\n13)Perf Theory: Batching 关于Batching，在前几季的性能优化课程里面也不止一次提到，下面使用一张图演示下Batching的原理：\n网络请求的批量执行是另外一个比较适合说明batching使用场景的例子，因为每次发起网络请求都相对来说比较耗时耗电，如果能够做到批量一起执行，可以大大的减少电量的消耗。\n14)Serialization performance 数据的序列化是程序代码里面必不可少的组成部分，当我们讨论到数据序列化的性能的时候，需要了解有哪些候选的方案，他们各自的优缺点是什么。首先什么是序列化？用下面的图来解释一下：\n数据序列化的行为可能发生在数据传递过程中的任何阶段，例如网络传输，不同进程间数据传递，不同类之间的参数传递，把数据存储到磁盘上等等。通常情况下，我们会把那些需要序列化的类实现Serializable接口(如下图所示)，但是这种传统的做法效率不高，实施的过程会消耗更多的内存。\n但是我们如果使用GSON库来处理这个序列化的问题，不仅仅执行速度更快，内存的使用效率也更高。Android的XML布局文件会在编译的阶段被转换成更加复杂的格式，具备更加高效的执行性能与更高的内存使用效率。\n下面介绍三个数据序列化的候选方案：\nProtocal Buffers：强大，灵活，但是对内存的消耗会比较大，并不是移动终端上的最佳选择。 Nano-Proto-Buffers：基于Protocal，为移动终端做了特殊的优化，代码执行效率更高，内存使用效率更佳。 FlatBuffers：这个开源库最开始是由Google研发的，专注于提供更优秀的性能。 上面这些方案在性能方面的数据对比如下图所示：\n为了避免序列化带来的性能问题，我们其实可以考虑使用SharedPreference或者SQLite来存储那些数据，避免需要先把那些复杂的数据进行序列化的操作。\n15)Smaller Serialized Data 数据呈现的顺序以及结构会对序列化之后的空间产生不小的影响。通常来说，一般的数据序列化的过程如下图所示：\n上面的过程，存在两个弊端，第一个是重复的属性名称：\n另外一个是GZIP没有办法对上面的数据进行更加有效的压缩，假如相似数据间隔了32k的数据量，这样GZIP就无法进行更加有效的压缩：\n但是我们稍微改变下数据的记录方式，就可以得到占用空间更小的数据，如下图所示：\n通过优化，至少有三方面的性能提升，如下图所示：\n1）减少了重复的属性名：\n2）使得GZIP的压缩效率更高：\n3）同样的数据类型可以批量优化：\n16)Caching UI data 如今绝大多数的应用界面上呈现的数据都依赖于网络请求返回的结果，如何做到在网络数据返回之前避免呈现一个空白的等待页面呢（当然这里说的是非首次冷启动的情况）？这就会涉及到如何缓存UI界面上的数据。\n缓存UI界面上的数据，可以采用方案有存储到文件系统，Preference，SQLite等等，做了缓存之后，这样就可以在请求数据返回结果之前，呈现给用户旧的数据，而不是使用正在加载的方式让用户什么数据都看不到，当然在请求网络最新数据的过程中，需要有正在刷新的提示。至于到底选择哪个方案来对数据进行缓存，就需要根据具体情况来做选择了。\n17)CPU Frequency Scaling 调节CPU的频率会执行的性能产生较大的影响，为了最大化的延长设备的续航时间，系统会动态调整CPU的频率，频率越高执行代码的速度自然就越快。\nAndroid系统会在电量消耗与表现性能之间不断的做权衡，当有需要的时候会迅速调整CPU的频率到一个比较高负荷的状态，当程序不需要高性能的时候就会降低频率来确保更长的续航时间。\nAndroid系统检测到需要调整CPU的频率到CPU频率真的达到对应频率会需要花费大概20ms的时间，在此期间很有可能会因为CPU频率不够而导致代码执行偏慢。\n我们可以使用Systrace工具来导出CPU的执行情况，以便帮助定位性能问题。\n","permalink":"https://blog.zdltech.com/posts/android%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E5%85%B8%E8%8C%83-%E7%AC%AC4%E5%AD%A3/","summary":"\u003cp\u003e\u003ca href=\"https://www.youtube.com/playlist?list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE\"\u003eAndroid性能优化典范\u003c/a\u003e第4季的课程学习笔记终于在2015年的最后一天完成了，文章共17个段落，包含的内容大致有：优化网络请求的行为，优化安装包的资源文件，优化数据传输的效率，性能优化的几大基础原理等等。因为学习认知水平有限，肯定存在不少理解偏差甚至错误的地方，请多多交流指正！\u003c/p\u003e\n\u003ch2 id=\"1cachematters-for-networking\"\u003e1)Cachematters for networking\u003c/h2\u003e\n\u003cp\u003e想要使得Android系统上的网络访问操作更加的高效就必须做好网络数据的缓存。这是提高网络访问性能最基础的步骤之一。从手机的缓存中直接读取数据肯定比从网络上获取数据要更加的便捷高效，特别是对于那些会被频繁访问到的数据，需要把这些数据缓存到设备上，以便更加快速的进行访问。\u003c/p\u003e\n\u003cp\u003eAndroid系统上关于网络请求的Http Response Cache是默认关闭的，这样会导致每次即使请求的数据内容是一样的也会需要重复被调用执行，效率低下。我们可以通过下面的代码示例开启\u003ca href=\"http://developer.android.com/reference/android/net/http/HttpResponseCache.html\"\u003eHttpResponseCache\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"android_perf_4_network_cache_enable\" loading=\"lazy\" src=\"http://hukai.me/images/android_perf_4_network_cache_enable.png\"\u003e\u003c/p\u003e\n\u003cp\u003e开启Http Response Cache之后，Http操作相关的返回数据就会缓存到文件系统上，不仅仅是主程序自己编写的网络请求相关的数据会被缓存，另外引入的library库中的网络相关的请求数据也会被缓存到这个Cache中。\u003c/p\u003e\n\u003cp\u003e网络请求的场景有可以是普通的http请求，也可以打开某个URL去获取数据，如下图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"android_perf_4_network_cache_code\" loading=\"lazy\" src=\"http://hukai.me/images/android_perf_4_network_cache_code.png\"\u003e\u003c/p\u003e\n\u003cp\u003e我们有两种方式来清除\u003ccode\u003eHttpResponseCache\u003c/code\u003e的缓存数据：第一种方式是缓存溢出的时候删除最旧最老的文件，第二种方式是通过Http返回Header中的\u003ccode\u003eCache-Control\u003c/code\u003e字段来进行控制的。如下图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"android_perf_4_network_cache_control\" loading=\"lazy\" src=\"http://hukai.me/images/android_perf_4_network_cache_control.png\"\u003e\u003c/p\u003e\n\u003cp\u003e通常来说，\u003ccode\u003eHttpResponseCache\u003c/code\u003e会缓存所有的返回信息，包括实际的数据与Header的部分.一般情况下，这个Cache会自动根据协议返回\u003ccode\u003eCache-Control\u003c/code\u003e的内容与当前缓存的数据量来决定哪些数据应该继续保留，哪些数据应该删除。但是在一些极端的情况下，例如服务器返回的数据没有设置Cache废弃的时间，或者是本地的Cache文件系统与返回的缓存数据有冲突，或者是某些特殊的网络环境导致HttpResponseCache工作异常，在这些情况下就需要我们自己来实现Http的缓存Cache。\u003c/p\u003e\n\u003cp\u003e实现自定义的http缓存，需要解决两个问题：第一个是实现一个DiskCacheManager，另外一个是制定Cache的缓存策略。关于DiskCacheManager，我们可以扩展Android系统提供的\u003ca href=\"https://developer.android.com/intl/zh-cn/samples/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/DiskLruCache.html\"\u003eDiskLruCache\u003c/a\u003e来实现。而Cache的缓存策略，相对来说复杂一些，我们可能需要把部分JSON数据设计成不能缓存的，另外一些JSON数据设计成可以缓存几天的，把缩略图设计成缓存一两天的等等，为不同的数据类型根据他们的使用特点制定不同的缓存策略。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"android_perf_4_network_cache_diff\" loading=\"lazy\" src=\"http://hukai.me/images/android_perf_4_network_cache_diff.png\"\u003e\u003c/p\u003e\n\u003cp\u003e想要比较好的实现这两件事情，如果全部自己从头开始写会比较繁琐复杂，所幸的是，有不少著名的开源框架帮助我们快速的解决了那些问题。我们可以使用\u003ca href=\"https://developer.android.com/training/volley/index.html\"\u003eVolly\u003c/a\u003e，\u003ca href=\"http://square.github.io/okhttp/\"\u003eokHTTP\u003c/a\u003e，\u003ca href=\"http://square.github.io/picasso/\"\u003ePicasso\u003c/a\u003e来实现网络缓存。\u003c/p\u003e\n\u003cp\u003e实现好网络缓存之后，我们可以使用Android Studio里面的\u003ccode\u003eNetwork Traffic Tools\u003c/code\u003e来查看网络数据的请求与返回情况，另外我们还可以使用\u003ca href=\"https://developer.att.com/application-resource-optimizer\"\u003eAT\u0026amp;T ARO\u003c/a\u003e工具来抓取网络数据包进行分析查看。\u003c/p\u003e\n\u003ch2 id=\"2optimizing-network-request-frequencies\"\u003e2)Optimizing Network Request Frequencies\u003c/h2\u003e\n\u003cp\u003e应用程序的一个基础功能是能够保持确保界面上呈现的信息是即时最新的，例如呈现最新的新闻，天气，信息流等等信息。但是，过于频繁的促使手机客户端应用去同步最新的服务器数据会对性能产生很大的负面影响，不仅仅使得CPU不停的在工作，内存，网络流量，电量等等都会持续的被消耗，所以在进行网络请求操作的时候一定要避免多度同步操作。\u003c/p\u003e\n\u003cp\u003e退到后台的应用为了能够在切换回前台的时候呈现最新的数据，会偷偷在后台不停的做同步的操作。这种行为会带来很严重的问题，首先因为网络请求的行为异常的耗电，其次不停的进行网络同步会耗费很多带宽流量。\u003c/p\u003e\n\u003cp\u003e为了能够尽量的减少不必要的同步操作，我们需要遵守下面的一些规则：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e首先我们要对网络行为进行分类，区分需要立即更新数据的行为和其他可以进行延迟的更新行为，为不同的场景进行差异化处理。\u003c/li\u003e\n\u003cli\u003e其次要避免客户端对服务器的轮询操作，这样会浪费很多的电量与带宽流量。解决这个问题，我们可以使用Google Cloud Message来对更新的数据进行推送。\u003c/li\u003e\n\u003cli\u003e然后在某些必须做同步的场景下，需要避免使用固定的间隔频率来进行更新操作，我们应该在返回的数据无更新的时候，使用双倍的间隔时间来进行下一次同步。\u003c/li\u003e\n\u003cli\u003e最后更进一步，我们还可以通过判断当前设备的状态来决定同步的频率，例如判断设备处于休眠，运动等不同的状态设计各自不同时间间隔的同步频率。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg alt=\"android_perf_4_network_frequencies_backoff\" loading=\"lazy\" src=\"http://hukai.me/images/android_perf_4_network_frequencies_backoff.png\"\u003e\u003c/p\u003e\n\u003cp\u003e另外，我们还可以通过判断设备是否连接上WiFi，是否正在充电来决定更新的频率。为了能够方便的实现这个功能，Android为我们提供了\u003ca href=\"https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager\"\u003eGCMNetworkManager\u003c/a\u003e来判断设备当下的状态，从而设计更加高效的网络同步操作，如下图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"android_perf_4_network_frequencies_gcm\" loading=\"lazy\" src=\"http://hukai.me/images/android_perf_4_network_frequencies_gcm.png\"\u003e\u003c/p\u003e\n\u003ch2 id=\"3effective-prefetching\"\u003e3)Effective Prefetching\u003c/h2\u003e\n\u003cp\u003e关于提升网络操作的性能，除了避免频繁的网络同步操作之外，还可以使用捆绑批量访问的方式来减少访问的频率，为了达到这个目的，我们就需要了解Prefetching。\u003c/p\u003e\n\u003cp\u003e举个例子，在某个场景下，一开始发出了网络请求得到了某张图片，隔了10s之后，发出第二次请求想要拿到另外一张图片，再隔了6s发出第三张图片的网络请求。这会导致设备的无线蜂窝一直处于高消耗的状态。Prefetching就是预先判定那些可能马上就会使用到的网络资源，捆绑一起集中进行网络请求。这样能够极大的减少电量的消耗，提升设备的续航时间。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"android_perf_4_prefetching_bundle\" loading=\"lazy\" src=\"http://hukai.me/images/android_perf_4_prefetching_bundle.png\"\u003e\u003c/p\u003e\n\u003cp\u003e使用Prefetching的难点在于如何判断事先获取的数据量到底是多少，如果预取的数据量偏少，那么就起不到什么效果，但是如果预取过多，又可能导致访问的时间过长。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"android_perf_4_prefetching_tricky\" loading=\"lazy\" src=\"http://hukai.me/images/android_perf_4_prefetching_tricky.png\"\u003e\u003c/p\u003e\n\u003cp\u003e那么问题来了，到底预取多少才比较合适呢？一个比较普适的规则是，在3G网络下可以预取1-5Mb的数据量，或者是按照提前预期后续1-2分钟的数据作为基线标准。在实际的操作当中，我们还需要考虑当前的网络速度来决定预取的数据量，例如在同样的时间下，4G网络可以获取到12张图片的数据，而2G网络则只能拿到3张图片的数据。所以，我们还需要把当前的网络环境情况添加到设计预取数据量的策略当中去。判断当前设备的状态与网络情况，可以使用前面提到过的\u003ca href=\"https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager\"\u003eGCMNetworkManager\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"4adapting-to-latency\"\u003e4)Adapting to Latency\u003c/h2\u003e\n\u003cp\u003e网络延迟通常来说很容易被用户察觉到，严重的网络延迟会对用户体验造成很大的影响，用户很容易抱怨应用程序写的不好。\u003c/p\u003e\n\u003cp\u003e一个典型的网络操作行为，通常包含以下几个步骤：首先手机端发起网络请求，到达网络服务运营商的基站，再转移到服务提供者的服务器上，经过解码之后，接着访问本地的存储数据库，获取到数据之后，进行编码，最后按照原来传递的路径逐层返回。如下图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"android_perf_4_network_latency\" loading=\"lazy\" src=\"http://hukai.me/images/android_perf_4_network_latency.png\"\u003e\u003c/p\u003e\n\u003cp\u003e在上面的网络请求链路当中的任何一个环节都有可能导致严重的延迟，成为性能瓶颈，但是这些环节可能出现的问题，客户端应用是无法进行调节控制的，应用能够做的就只是根据当前的网络环境选择当下最佳的策略来降低出现网络延迟的概率。主要的实施步骤有两步：第1步检测收集当前的网络环境信息，第2步根据当前收集到的信息进行网络请求行为的调整。\u003c/p\u003e\n\u003cp\u003e关于第1步检测当前的网络环境，我们可以使用系统提供的API来获取到相关的信息，如下图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"android_perf_4_network_latency_detect\" loading=\"lazy\" src=\"http://hukai.me/images/android_perf_4_network_latency_detect.png\"\u003e\u003c/p\u003e\n\u003cp\u003e通过上面的示例，我们可以获取到移动网络的详细子类型，例如4G(LTE),3G等等，详细分类见下图，获取到详细的移动网络类型之后，我们可以根据当前网络的速率来调整网络请求的行为：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"android_perf_4_network_latency_subtype\" loading=\"lazy\" src=\"http://hukai.me/images/android_perf_4_network_latency_subtype.png\"\u003e\u003c/p\u003e\n\u003cp\u003e关于第2步根据收集到的信息进行策略的调整，通常来说，我们可以把网络请求延迟划分为三档：例如把网络延迟小于60ms的划分为GOOD，大于220ms的划分为BAD，介于两者之间的划分为OK（这里的60ms，220ms会需要根据不同的场景提前进行预算推测）。如果网络延迟属于GOOD的范畴，我们就可以做更多比较激进的预取数据的操作，如果网络延迟属于BAD的范畴，我们就应该考虑把当下的网络请求操作Hold住等待网络状况恢复到GOOD的状态再进行处理。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"android_perf_4_network_latency_three_category\" loading=\"lazy\" src=\"http://hukai.me/images/android_perf_4_network_latency_three_category.png\"\u003e\u003c/p\u003e\n\u003cp\u003e前面提到说60ms，220ms是需要提前自己预测的，可是预测的工作相当复杂。首先针对不同的机器与网络环境，网络延迟的三档阈值都不太一样，出现的概率也不尽相同，我们会需要针对这些不同的用户与设备选择不同的阈值进行差异化处理：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"android_perf_4_network_latency_three_level\" loading=\"lazy\" src=\"http://hukai.me/images/android_perf_4_network_latency_three_level.png\"\u003e\u003c/p\u003e\n\u003cp\u003eAndroid官方为了帮助我们设计自己的网络请求策略，为我们提供了模拟器的网络流量控制功能来对实际环境进行模拟测量，或者还可以使用AT\u0026amp;T提供的\u003ca href=\"http://developer.att.com/developer/legalAgreementPage.jsp?passedItemId=14500040\"\u003eAT\u0026amp;T Network Attenuator\u003c/a\u003e来帮助预估网络延迟。\u003c/p\u003e\n\u003ch2 id=\"5minimizing-asset-payload\"\u003e5)Minimizing Asset Payload\u003c/h2\u003e\n\u003cp\u003e为了能够减小网络传输的数据量，我们需要对传输的数据做压缩的处理，这样能够提高网络操作的性能。首先不同的网络环境，下载速度以及网络延迟是存在差异的，如下图所示：\u003c/p\u003e","title":"Android性能优化典范 – 第4季"},{"content":" 现阶段做企业级项目开发一般都采用Java语言。开发的项目需要放在服务器上运行测试，若以CentOS系统为服务器系统，首先要解决就是CentOS系统上的Java环境搭建。 下面由小河给大家分享：如何使用yum方式在CentOS上安装Java环境，系统以CentOS6.4为例。 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ## 工具/原料 - \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt; Java JDK \u0026lt;/div\u0026gt; - \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt; yum库 \u0026lt;/div\u0026gt; - \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt; CentOS6.4 \u0026lt;/div\u0026gt; ## 方法/步骤 - \u0026lt;div class=\u0026quot;list-icon\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt; 查看CentOS自带JDK是否已安装。 ◆输入：yum list installed |grep java。 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;content-list-media\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt; [![在CentOS上安装Java环境：[1]使用yum安装java](http://c.hiphotos.baidu.com/exp/w=500/sign=5b030433b01bb0518f24b328067bda77/a1ec08fa513d2697ab9a004c56fbb2fb4316d852.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=1) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;div class=\u0026quot;list-icon\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt; 若有自带安装的JDK，如何卸载CentOS系统自带Java环境？ ◆卸载JDK相关文件输入：yum -y remove java-1.7.0-openjdk*。 ◆卸载tzdata-java输入：yum -y remove tzdata-java.noarch。 当结果显示为Complete！即卸载完毕。 *注：“*”表示卸载掉java 1.7.0的所有openjdk相关文件。* \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;content-list-media\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt; [![在CentOS上安装Java环境：[1]使用yum安装java](http://d.hiphotos.baidu.com/exp/w=500/sign=047d15191c30e924cfa49c317c096e66/0df3d7ca7bcb0a46f16a83286863f6246b60af52.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=2) \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt; [![在CentOS上安装Java环境：[1]使用yum安装java](http://g.hiphotos.baidu.com/exp/w=500/sign=5596d6e5b44543a9f51bfacc2e168a7b/7af40ad162d9f2d3b1a32cfeaaec8a136327cc75.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=3) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;div class=\u0026quot;list-icon\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt; 检查CentOS系统网络连接是否正常。 ◆使用yum方式安装需要连接网络下载Java相应安装文件，故此需要使用ping命令测试网络；如：ping 百度URL即可。 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;content-list-media\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt; [![在CentOS上安装Java环境：[1]使用yum安装java](http://f.hiphotos.baidu.com/exp/w=500/sign=e95f1515379b033b2c88fcda25cf3620/8c1001e93901213f857b46cd57e736d12f2e9552.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=4) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;div class=\u0026quot;list-icon\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt; 查看yum库中的Java安装包。 ◆输入：yum -y list java* 。 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;content-list-media\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt; [![在CentOS上安装Java环境：[1]使用yum安装java](http://e.hiphotos.baidu.com/exp/w=500/sign=1958e90b2b34349b74066e85f9eb1521/7dd98d1001e939011d4a852f78ec54e736d19652.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=5) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;div class=\u0026quot;list-icon\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt; 使用yum安装Java环境。 ◆输入：yum -y install java-1.7.0-openjdk* ，以yum库中java-1.7.0为例。 当结果显示为Complete！即安装完毕。 *注：“*”表示将java-1.7.0的所有相关Java程序都安装上。* \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;content-list-media\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt; [![在CentOS上安装Java环境：[1]使用yum安装java](http://h.hiphotos.baidu.com/exp/w=500/sign=0bee3e1a58b5c9ea62f303e3e538b622/3801213fb80e7bec6b920bf02c2eb9389b506b52.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=6) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;div class=\u0026quot;list-icon\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt; 查看刚安装的Java版本信息。 ◆输入：java -version 可查看Java版本； ◆输入：javac 可查看Java的编译器命令用法（可略）。 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;content-list-media\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt; [![在CentOS上安装Java环境：[1]使用yum安装java](http://h.hiphotos.baidu.com/exp/w=500/sign=fd64ae32b37eca80120539e7a1229712/a6efce1b9d16fdfae024ceffb78f8c5494ee7b52.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=7) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;last-item\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;last-item-end\u0026quot;\u0026gt;END\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 转自：http://jingyan.baidu.com/article/4853e1e51d0c101909f72607.html ","permalink":"https://blog.zdltech.com/posts/%E5%9C%A8centos%E4%B8%8A%E5%AE%89%E8%A3%85java%E7%8E%AF%E5%A2%831%E4%BD%BF%E7%94%A8yum%E5%AE%89%E8%A3%85java/","summary":"\u003cdiv class=\"exp-content-block\"\u003e\n  \u003cdiv class=\"exp-content-body exp-brief-step\"\u003e\n    \u003cdiv class=\"exp-content-listblock\"\u003e\n      \u003cdiv class=\"content-listblock-text\"\u003e\n\u003cpre\u003e\u003ccode\u003e      现阶段做企业级项目开发一般都采用Java语言。开发的项目需要放在服务器上运行测试，若以CentOS系统为服务器系统，首先要解决就是CentOS系统上的Java环境搭建。\n    \n\n    \n    \n\n      下面由小河给大家分享：如何使用yum方式在CentOS上安装Java环境，系统以CentOS6.4为例。\n    \n\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"exp-content-block\"\u003e\n  ## \u003ca name=\"section-2\"\u003e\u003c/a\u003e工具/原料\n  \u003cdiv class=\"exp-content-body\"\u003e\n\u003cpre\u003e\u003ccode\u003e  - \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt;\n      Java JDK\n    \u0026lt;/div\u0026gt;\n  \n  \n  - \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt;\n      yum库\n    \u0026lt;/div\u0026gt;\n  \n  \n  - \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt;\n      CentOS6.4\n    \u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"exp-content-block\"\u003e\n  ## \u003ca name=\"section-3\"\u003e\u003c/a\u003e方法/步骤\n  \u003cdiv class=\"exp-content-body\"\u003e\n\u003cpre\u003e\u003ccode\u003e  - \u0026lt;div class=\u0026quot;list-icon\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt;\n      \n\n        查看CentOS自带JDK是否已安装。\n      \n\n      \n      \n\n        ◆输入：yum list installed |grep java。\n      \n\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;content-list-media\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt;\n        [![在CentOS上安装Java环境：[1]使用yum安装java](http://c.hiphotos.baidu.com/exp/w=500/sign=5b030433b01bb0518f24b328067bda77/a1ec08fa513d2697ab9a004c56fbb2fb4316d852.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=1)\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \n  \n  - \u0026lt;div class=\u0026quot;list-icon\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt;\n      \n\n        若有自带安装的JDK，如何卸载CentOS系统自带Java环境？\n      \n\n      \n      \n\n        ◆卸载JDK相关文件输入：yum -y remove java-1.7.0-openjdk*。\n      \n\n      \n      \n\n        ◆卸载tzdata-java输入：yum -y remove tzdata-java.noarch。\n      \n\n      \n      \n\n        当结果显示为Complete！即卸载完毕。\n      \n\n      \n      \n\n        *注：“*”表示卸载掉java 1.7.0的所有openjdk相关文件。*\n      \n\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;content-list-media\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt;\n        [![在CentOS上安装Java环境：[1]使用yum安装java](http://d.hiphotos.baidu.com/exp/w=500/sign=047d15191c30e924cfa49c317c096e66/0df3d7ca7bcb0a46f16a83286863f6246b60af52.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=2)\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt;\n        [![在CentOS上安装Java环境：[1]使用yum安装java](http://g.hiphotos.baidu.com/exp/w=500/sign=5596d6e5b44543a9f51bfacc2e168a7b/7af40ad162d9f2d3b1a32cfeaaec8a136327cc75.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=3)\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \n  \n  - \u0026lt;div class=\u0026quot;list-icon\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt;\n      \n\n        检查CentOS系统网络连接是否正常。\n      \n\n      \n      \n\n        ◆使用yum方式安装需要连接网络下载Java相应安装文件，故此需要使用ping命令测试网络；如：ping 百度URL即可。\n      \n\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;content-list-media\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt;\n        [![在CentOS上安装Java环境：[1]使用yum安装java](http://f.hiphotos.baidu.com/exp/w=500/sign=e95f1515379b033b2c88fcda25cf3620/8c1001e93901213f857b46cd57e736d12f2e9552.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=4)\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \n  \n  - \u0026lt;div class=\u0026quot;list-icon\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt;\n      \n\n        查看yum库中的Java安装包。\n      \n\n      \n      \n\n        ◆输入：yum -y list java* 。\n      \n\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;content-list-media\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt;\n        [![在CentOS上安装Java环境：[1]使用yum安装java](http://e.hiphotos.baidu.com/exp/w=500/sign=1958e90b2b34349b74066e85f9eb1521/7dd98d1001e939011d4a852f78ec54e736d19652.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=5)\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \n  \n  - \u0026lt;div class=\u0026quot;list-icon\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt;\n      \n\n        使用yum安装Java环境。\n      \n\n      \n      \n\n        ◆输入：yum -y install java-1.7.0-openjdk* ，以yum库中java-1.7.0为例。\n      \n\n      \n      \n\n        当结果显示为Complete！即安装完毕。\n      \n\n      \n      \n\n        *注：“*”表示将java-1.7.0的所有相关Java程序都安装上。*\n      \n\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;content-list-media\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt;\n        [![在CentOS上安装Java环境：[1]使用yum安装java](http://h.hiphotos.baidu.com/exp/w=500/sign=0bee3e1a58b5c9ea62f303e3e538b622/3801213fb80e7bec6b920bf02c2eb9389b506b52.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=6)\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \n  \n  - \u0026lt;div class=\u0026quot;list-icon\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;content-list-text\u0026quot;\u0026gt;\n      \n\n        查看刚安装的Java版本信息。\n      \n\n      \n      \n\n        ◆输入：java -version 可查看Java版本；\n      \n\n      \n      \n\n        ◆输入：javac 可查看Java的编译器命令用法（可略）。\n      \n\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;content-list-media\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;content-list-image clearfix\u0026quot;\u0026gt;\n        [![在CentOS上安装Java环境：[1]使用yum安装java](http://h.hiphotos.baidu.com/exp/w=500/sign=fd64ae32b37eca80120539e7a1229712/a6efce1b9d16fdfae024ceffb78f8c5494ee7b52.jpg)](http://jingyan.baidu.com/album/4853e1e51d0c101909f72607.html?picindex=7)\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;last-item\u0026quot;\u0026gt;\n      \u0026lt;span class=\u0026quot;last-item-end\u0026quot;\u0026gt;END\u0026lt;/span\u0026gt;\n    \u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"exp-content-block\"\u003e\n   转自：http://jingyan.baidu.com/article/4853e1e51d0c101909f72607.html\n\u003c/div\u003e","title":"在CentOS上安装Java环境：[1]使用yum安装java"},{"content":"获取手机底部虚拟键盘的高度 魅族手机底部SmartBar高度 import android.content.Context; import android.content.res.Resources; import android.graphics.Point; import android.os.Build; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.View; import android.view.Menu; import android.view.MenuItem; import android.view.ViewConfiguration; import android.view.WindowManager; import java.lang.reflect.Field; import java.lang.reflect.Method; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, \u0026#34;Replace with your own action\u0026#34;, Snackbar.LENGTH_LONG) .setAction(\u0026#34;Action\u0026#34;, null).show(); Log.e(MainActivity.class.getName(), \u0026#34;hasNavBar1 = \u0026#34; + hasNavBar(MainActivity.this)); } }); Log.e(MainActivity.class.getName(),\u0026#34;ScreenHeight = \u0026#34;+getScreenHight()); Log.e(MainActivity.class.getName(),\u0026#34;SmartBarHeight = \u0026#34;+getSmartBarHeight(this)); Log.e(MainActivity.class.getName(),\u0026#34;hasNavBar = \u0026#34;+hasNavBar(this)); Log.e(MainActivity.class.getName(),\u0026#34;getNavigationBarHeight = \u0026#34;+getNavigationBarHeight(this)); } private int getScreenHight(){ // 获取屏幕高 Point point = new Point(); getWindowManager().getDefaultDisplay().getSize(point); int screenHeight = point.y + (isMeizu() ? 0 : getNavigationBarHeight(this)); return screenHeight; } /** * 获取虚拟按键栏高度 * @param context * @return */ public static int getNavigationBarHeight(Context context) { int result = 0; if (hasNavBar(context)){ Resources res = context.getResources(); int resourceId = res.getIdentifier(\u0026#34;navigation_bar_height\u0026#34;, \u0026#34;dimen\u0026#34;, \u0026#34;android\u0026#34;); if (resourceId \u0026amp;gt; 0) { result = res.getDimensionPixelSize(resourceId); } } return result; } /** * 检查是否存在虚拟按键栏 * @param context * @return */ private static boolean hasNavBar(Context context) { Resources res = context.getResources(); int resourceId = res.getIdentifier(\u0026#34;config_showNavigationBar\u0026#34;, \u0026#34;bool\u0026#34;, \u0026#34;android\u0026#34;); if (resourceId != 0) { boolean hasNav = res.getBoolean(resourceId); // check override flag String sNavBarOverride = getNavBarOverride(); if (\u0026#34;1\u0026#34;.equals(sNavBarOverride)) { hasNav = false; } else if (\u0026#34;0\u0026#34;.equals(sNavBarOverride)) { hasNav = true; } return hasNav; } else { // fallback return !ViewConfiguration.get(context).hasPermanentMenuKey(); } } /** * 判断虚拟按键栏是否重写 * @return */ private static String getNavBarOverride() { String sNavBarOverride = null; if (Build.VERSION.SDK_INT \u0026amp;gt;= Build.VERSION_CODES.KITKAT) { try { Class c = Class.forName(\u0026#34;android.os.SystemProperties\u0026#34;); Method m = c.getDeclaredMethod(\u0026#34;get\u0026#34;, String.class); m.setAccessible(true); sNavBarOverride = (String) m.invoke(null, \u0026#34;qemu.hw.mainkeys\u0026#34;); } catch (Throwable e) { } } return sNavBarOverride; } /** * 判断是否meizu手机 * @return */ public static boolean isMeizu() { return Build.BRAND.equals(\u0026#34;Meizu\u0026#34;); } /** * 获取魅族手机底部虚拟键盘高度 * @param context * @return */ public static int getSmartBarHeight(Context context) { try { Class c = Class.forName(\u0026#34;com.android.internal.R$dimen\u0026#34;); Object obj = c.newInstance(); Field field = c.getField(\u0026#34;mz_action_button_min_height\u0026#34;); int height = Integer.parseInt(field.get(obj).toString()); return context.getResources().getDimensionPixelSize(height); } catch (Exception e) { e.printStackTrace(); } return 0; } } import java.lang.reflect.Field; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC4\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;java.lang.reflect.InvocationTargetException\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC5\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;java.lang.reflect.Method\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC6\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC7\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.app.ActionBar\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC8\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.content.Context\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC9\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.content.res.Configuration\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC10\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.os.Build\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC11\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.support.v4.app.FragmentActivity\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC12\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.view.View\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC13\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.view.Window\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC14\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.view.WindowManager\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC15\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC16\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;SmartBarUtils\u0026lt;/span\u0026gt; { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC17\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC18\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;SMART_BAR_HEIGH\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;96\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC19\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC20\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC21\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 调用 ActionBar.setTabsShowAtBottom(boolean) 方法。 如果\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC22\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * android:uiOptions=\u0026amp;#8221;splitActionBarWhenNarrow\u0026amp;#8221;，则可设置ActionBar Tabs显示在底栏。\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC23\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC24\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 示例： public class MyActivity extends Activity implements\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC25\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * ActionBar.TabListener { protected void onCreate(Bundle\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC26\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * savedInstanceState) { super.onCreate(savedInstanceState); \u0026amp;#8230;\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC27\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC28\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * final ActionBar bar = getActionBar();\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC29\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC30\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * SmartBarUtils.setActionBarTabsShowAtBottom(bar, true);\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC31\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC32\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * bar.addTab(bar.newTab().setText(\u0026amp;quot;tab1\u0026amp;quot;).setTabListener(this));\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC33\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026amp;#8230; } }\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC34\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC35\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC36\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;setActionBarTabsShowAtBottom\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBar\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;actionbar\u0026lt;/span\u0026gt;, \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC37\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;showAtBottom\u0026lt;/span\u0026gt;) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC38\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC39\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Method\u0026lt;/span\u0026gt; method \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;forName(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;android.app.ActionBar\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;)\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMethod( \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC40\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;setTabsShowAtBottom\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;[] { \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;class }); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC41\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC42\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; method\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;invoke(actionbar, showAtBottom); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC43\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalArgumentException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC44\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC45\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalAccessException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC46\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC47\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;InvocationTargetException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC48\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC49\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC50\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;SecurityException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC51\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC52\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;NoSuchMethodException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC53\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC54\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ClassNotFoundException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC55\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC56\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC57\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC58\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC59\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC60\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 调用 ActionBar.setActionBarViewCollapsable(boolean) 方法。\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC61\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 设置ActionBar顶栏无显示内容时是否隐藏。\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC62\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC63\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 示例：\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC64\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC65\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * public class MyActivity extends Activity {\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC66\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC67\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * protected void onCreate(Bundle savedInstanceState) {\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC68\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * super.onCreate(savedInstanceState); \u0026amp;#8230;\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC69\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC70\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * final ActionBar bar = getActionBar();\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC71\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC72\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * // 调用setActionBarViewCollapsable，并设置ActionBar没有显示内容，则ActionBar顶栏不显示\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC73\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * SmartBarUtils.setActionBarViewCollapsable(bar, true);\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC74\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * bar.setDisplayOptions(0); } }\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC75\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC76\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;setActionBarViewCollapsable\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBar\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;actionbar\u0026lt;/span\u0026gt;, \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC77\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;collapsable\u0026lt;/span\u0026gt;) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC78\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC79\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Method\u0026lt;/span\u0026gt; method \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;forName(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;android.app.ActionBar\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;)\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMethod( \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC80\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;setActionBarViewCollapsable\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC81\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;[] { \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;class }); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC82\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC83\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; method\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;invoke(actionbar, collapsable); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC84\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalArgumentException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC85\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC86\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalAccessException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC87\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC88\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;InvocationTargetException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC89\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC90\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC91\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;SecurityException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC92\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC93\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;NoSuchMethodException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC94\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC95\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ClassNotFoundException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC96\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC97\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC98\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC99\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC100\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC101\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 调用 ActionBar.setActionModeHeaderHidden(boolean) 方法。 设置ActionMode顶栏是否隐藏。\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC102\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC103\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * public class MyActivity extends Activity {\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC104\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC105\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * protected void onCreate(Bundle savedInstanceState) {\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC106\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * super.onCreate(savedInstanceState); \u0026amp;#8230;\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC107\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC108\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * final ActionBar bar = getActionBar();\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC109\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC110\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * // ActionBar转为ActionMode时，不显示ActionMode顶栏\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC111\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * SmartBarUtils.setActionModeHeaderHidden(bar, true); } }\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC112\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC113\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;setActionModeHeaderHidden\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBar\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;actionbar\u0026lt;/span\u0026gt;, \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC114\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;hidden\u0026lt;/span\u0026gt;) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC115\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC116\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Method\u0026lt;/span\u0026gt; method \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;forName(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;android.app.ActionBar\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;)\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMethod( \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC117\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;setActionModeHeaderHidden\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;[] { \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;class }); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC118\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC119\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; method\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;invoke(actionbar, hidden); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC120\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalArgumentException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC121\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC122\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalAccessException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC123\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC124\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;InvocationTargetException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC125\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC126\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC127\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;SecurityException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC128\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC129\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;NoSuchMethodException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC130\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC131\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ClassNotFoundException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC132\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC133\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC134\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC135\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC136\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC137\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 原隐藏SmartBar的方法\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC138\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 此方法已从Flyme2.4.1开始失效 示例：\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC139\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC140\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * final ActionBar actionBar = getActionBar(); SmartBarUtils.hide(this);\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC141\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC142\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC143\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;@Deprecated\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC144\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;hide\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;FragmentActivity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC145\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBar\u0026lt;/span\u0026gt; actionBar \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; activity\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getActionBar(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC146\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (actionBar \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC147\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC148\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC149\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;Class\u0026lt;? extends \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBar\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBarClass\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; actionBar\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getClass(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC150\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Method\u0026lt;/span\u0026gt; setTabsShowAtBottom; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC151\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC152\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; setTabsShowAtBottom \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBarClass\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMethod( \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC153\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;setTabsShowAtBottom\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Boolean\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;TYPE\u0026lt;/span\u0026gt;); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC154\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; setTabsShowAtBottom\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;invoke(activity\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getActionBar(), \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC155\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;NoSuchMethodException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC156\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC157\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalArgumentException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC158\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC159\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalAccessException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC160\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC161\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;InvocationTargetException\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC162\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC163\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC164\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC165\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC166\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC167\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 以下三个方法原作者为c跳跳(http://weibo.com/u/1698085875),\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC168\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 由Shawn(http://weibo.com/linshen2011)在其基础上改进了一种判断SmartBar是否存在的方法,\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC169\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 注意该方法反射的接口只存在于2013年6月之后魅族的flyme固件中\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC170\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC171\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC172\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC173\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 方法一:uc等在使用的方法(新旧版flyme均有效)，\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC174\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 此方法需要配合requestWindowFeature(Window.FEATURE_NO_TITLE\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC175\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * )使用,缺点是程序无法使用系统actionbar\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC176\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC177\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @param decorView\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC178\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * window.getDecorView\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC179\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC180\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;hide\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;decorView\u0026lt;/span\u0026gt;) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC181\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;!\u0026lt;/span\u0026gt;hasSmartBar()) \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC182\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC183\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC184\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC185\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; @SuppressWarnings(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;rawtypes\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;) \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC186\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;[] arrayOfClass \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC187\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; arrayOfClass[\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Integer\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;TYPE\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC188\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Method\u0026lt;/span\u0026gt; localMethod \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;class\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMethod(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;setSystemUiVisibility\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC189\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; arrayOfClass); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC190\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Field\u0026lt;/span\u0026gt; localField \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;class \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC191\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; .getField(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;SYSTEM_UI_FLAG_HIDE_NAVIGATION\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC192\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;Object\u0026lt;/span\u0026gt;[] arrayOfObject \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Object\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC193\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC194\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; arrayOfObject[\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; localField\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;get(\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC195\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Exception\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC196\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC197\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC198\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; localMethod\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;invoke(decorView, arrayOfObject); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC199\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC200\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Exception\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC201\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC202\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC203\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC204\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC205\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC206\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 方法二：此方法需要配合requestWindowFeature(Window.FEATURE_NO_TITLE)使用\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC207\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * ，缺点是程序无法使用系统actionbar\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC208\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC209\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC210\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @param window\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC211\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC212\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;hide\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Context\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;context\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Window\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;window\u0026lt;/span\u0026gt;) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC213\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; hide(context, window, \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC214\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC215\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC216\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;getStatusBarHeight\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Context\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;context\u0026lt;/span\u0026gt;) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC217\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; result \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC218\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; resourceId \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; context\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getResources()\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getIdentifier( \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC219\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;status_bar_height\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;dimen\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;android\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC220\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (resourceId \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC221\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; result \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; context\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getResources()\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getDimensionPixelSize(resourceId); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC222\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC223\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; result; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC224\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC225\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC226\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC227\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 方法三：需要使用顶部actionbar的应用请使用此方法\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC228\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC229\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC230\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @param window\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC231\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @param smartBarHeight\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC232\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * set SmartBarUtils.SMART_BAR_HEIGHT_PIXEL\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC233\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC234\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;hide\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Context\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;context\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Window\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;window\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;smartBarHeight\u0026lt;/span\u0026gt;) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC235\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;!\u0026lt;/span\u0026gt;hasSmartBar()) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC236\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC237\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC238\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (context\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getResources()\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getConfiguration()\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;orientation \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Configuration\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;ORIENTATION_LANDSCAPE\u0026lt;/span\u0026gt;) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC239\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC240\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC241\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC242\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; window\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;setFlags(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;WindowManager\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;LayoutParams\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;FLAG_FULLSCREEN\u0026lt;/span\u0026gt;, \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC243\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;WindowManager\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;LayoutParams\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;FLAG_FULLSCREEN\u0026lt;/span\u0026gt;); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC244\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; window\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;addFlags(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;WindowManager\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;LayoutParams\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;FLAG_FORCE_NOT_FULLSCREEN\u0026lt;/span\u0026gt;); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC245\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; statusBarHeight \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; getStatusBarHeight(context); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC246\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC247\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; window\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getDecorView() \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC248\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; .setPadding(\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, statusBarHeight, \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;#8211;\u0026lt;/span\u0026gt;smartBarHeight); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC249\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC250\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC251\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC252\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 新型号可用反射调用Build.hasSmartBar()来判断有无SmartBar\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC253\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC254\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC255\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;hasSmartBar\u0026lt;/span\u0026gt;() { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC256\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC257\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Method\u0026lt;/span\u0026gt; method \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;forName(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;android.os.Build\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;)\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMethod( \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC258\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;hasSmartBar\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC259\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; ((\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Boolean\u0026lt;/span\u0026gt;) method\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;invoke(\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;))\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;booleanValue(); \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC260\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Exception\u0026lt;/span\u0026gt; e) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC261\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC262\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC263\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Build\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;DEVICE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;equals(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;mx2\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;)) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC264\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC265\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Build\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;DEVICE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;equals(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;mx\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;) \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;||\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Build\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;DEVICE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;equals(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;m9\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;)) { \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC266\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC267\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC268\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC269\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC270\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td id=\u0026quot;file-smartbarutils-java-LC271\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt; } \u0026lt;/td\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android%E8%8E%B7%E5%8F%96%E6%89%8B%E6%9C%BA%E5%BA%95%E9%83%A8%E8%99%9A%E6%8B%9F%E6%8C%89%E9%94%AE%E9%AB%98%E5%BA%A6/","summary":"\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e获取手机底部虚拟键盘的高度\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e魅族手机底部SmartBar高度\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003econtent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eContext;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003econtent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eres\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eResources;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ePoint;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eos\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBuild;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eos\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBundle;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edesign\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eFloatingActionButton;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edesign\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eSnackbar;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAppCompatActivity;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eToolbar;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eutil\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLog;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMenu;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMenuItem;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eViewConfiguration;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eWindowManager;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elang\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ereflect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eField;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport java\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elang\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ereflect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMethod;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e MainActivity \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e AppCompatActivity {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    protected void onCreate(Bundle savedInstanceState) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonCreate(savedInstanceState);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        getWindow()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetFlags(WindowManager\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLayoutParams\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eFLAG_FULLSCREEN, WindowManager\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLayoutParams\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eFLAG_FULLSCREEN);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        setContentView(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elayout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eactivity_main);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Toolbar toolbar \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (Toolbar) findViewById(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etoolbar);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        setSupportActionBar(toolbar);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        FloatingActionButton fab \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (FloatingActionButton) findViewById(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003efab);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        fab\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetOnClickListener(new View\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eOnClickListener() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            public void onClick(View view) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                Snackbar\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emake(view, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Replace with your own action\u0026#34;\u003c/span\u003e, Snackbar\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLENGTH_LONG)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetAction(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Action\u0026#34;\u003c/span\u003e, null)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eshow();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                Log\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ee(MainActivity\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetName(), \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hasNavBar1 = \u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e hasNavBar(MainActivity\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ethis));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        });\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Log\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ee(MainActivity\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetName(),\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;ScreenHeight = \u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003egetScreenHight());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Log\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ee(MainActivity\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetName(),\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;SmartBarHeight = \u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003egetSmartBarHeight(this));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Log\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ee(MainActivity\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetName(),\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hasNavBar = \u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003ehasNavBar(this));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Log\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ee(MainActivity\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetName(),\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;getNavigationBarHeight = \u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003egetNavigationBarHeight(this));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private int getScreenHight(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 获取屏幕高\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Point point \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new Point();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        getWindowManager()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetDefaultDisplay()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetSize(point);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        int screenHeight \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e point\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ey \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e (isMeizu() ? \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e : getNavigationBarHeight(this));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e screenHeight;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 获取虚拟按键栏高度\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @param context\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e int getNavigationBarHeight(Context context) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        int result \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (hasNavBar(context)){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            Resources res \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e context\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetResources();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            int resourceId \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetIdentifier(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;navigation_bar_height\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;dimen\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;android\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (resourceId \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt; \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                result \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetDimensionPixelSize(resourceId);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e result;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 检查是否存在虚拟按键栏\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @param context\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e boolean hasNavBar(Context context) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Resources res \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e context\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetResources();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        int resourceId \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetIdentifier(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;config_showNavigationBar\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;bool\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;android\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (resourceId \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            boolean hasNav \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e res\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetBoolean(resourceId);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e check override flag\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            String sNavBarOverride \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e getNavBarOverride();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;1\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eequals(sNavBarOverride)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                hasNav \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            } \u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;0\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eequals(sNavBarOverride)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                hasNav \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e hasNav;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } \u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e { \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e fallback\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003eViewConfiguration\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(context)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ehasPermanentMenuKey();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 判断虚拟按键栏是否重写\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e String getNavBarOverride() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String sNavBarOverride \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (Build\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eVERSION\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eSDK_INT \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Build\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eVERSION_CODES\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eKITKAT) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            try {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                Class c \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Class\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eforName(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;android.os.SystemProperties\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                Method m \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e c\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetDeclaredMethod(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;get\u0026#34;\u003c/span\u003e, String\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                m\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetAccessible(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                sNavBarOverride \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (String) m\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003einvoke(null, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;qemu.hw.mainkeys\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            } catch (Throwable e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e sNavBarOverride;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 判断是否meizu手机\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e boolean isMeizu() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e Build\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBRAND\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eequals(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Meizu\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e/**\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 获取魅族手机底部虚拟键盘高度\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @param context\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e int getSmartBarHeight(Context context)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        try {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            Class c \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Class\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eforName(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;com.android.internal.R$dimen\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            Object obj \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e c\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003enewInstance();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            Field field \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e c\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetField(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;mz_action_button_min_height\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            int height \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Integer\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eparseInt(field\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(obj)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etoString());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e context\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetResources()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetDimensionPixelSize(height);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } catch (Exception e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintStackTrace();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ctable class=\"highlight tab-size js-file-line-container\" data-tab-size=\"8\"\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-LC3\" class=\"blob-code blob-code-inner js-file-line\"\u003e\n      \u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003ejava.lang.reflect.Field\u003c/span\u003e;\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L4\" class=\"blob-num js-line-number\" data-line-number=\"4\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC4\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;java.lang.reflect.InvocationTargetException\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L5\" class=\"blob-num js-line-number\" data-line-number=\"5\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC5\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;java.lang.reflect.Method\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L6\" class=\"blob-num js-line-number\" data-line-number=\"6\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC6\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L7\" class=\"blob-num js-line-number\" data-line-number=\"7\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC7\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.app.ActionBar\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L8\" class=\"blob-num js-line-number\" data-line-number=\"8\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC8\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.content.Context\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L9\" class=\"blob-num js-line-number\" data-line-number=\"9\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC9\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.content.res.Configuration\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L10\" class=\"blob-num js-line-number\" data-line-number=\"10\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC10\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.os.Build\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L11\" class=\"blob-num js-line-number\" data-line-number=\"11\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC11\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.support.v4.app.FragmentActivity\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L12\" class=\"blob-num js-line-number\" data-line-number=\"12\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC12\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.view.View\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L13\" class=\"blob-num js-line-number\" data-line-number=\"13\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC13\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.view.Window\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L14\" class=\"blob-num js-line-number\" data-line-number=\"14\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC14\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;android.view.WindowManager\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L15\" class=\"blob-num js-line-number\" data-line-number=\"15\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC15\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L16\" class=\"blob-num js-line-number\" data-line-number=\"16\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC16\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;SmartBarUtils\u0026lt;/span\u0026gt; {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L17\" class=\"blob-num js-line-number\" data-line-number=\"17\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC17\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L18\" class=\"blob-num js-line-number\" data-line-number=\"18\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC18\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;SMART_BAR_HEIGH\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;96\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L19\" class=\"blob-num js-line-number\" data-line-number=\"19\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC19\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L20\" class=\"blob-num js-line-number\" data-line-number=\"20\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC20\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L21\" class=\"blob-num js-line-number\" data-line-number=\"21\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC21\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 调用 ActionBar.setTabsShowAtBottom(boolean) 方法。 如果\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L22\" class=\"blob-num js-line-number\" data-line-number=\"22\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC22\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * android:uiOptions=\u0026amp;#8221;splitActionBarWhenNarrow\u0026amp;#8221;，则可设置ActionBar Tabs显示在底栏。\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L23\" class=\"blob-num js-line-number\" data-line-number=\"23\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC23\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L24\" class=\"blob-num js-line-number\" data-line-number=\"24\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC24\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 示例： public class MyActivity extends Activity implements\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L25\" class=\"blob-num js-line-number\" data-line-number=\"25\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC25\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * ActionBar.TabListener { protected void onCreate(Bundle\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L26\" class=\"blob-num js-line-number\" data-line-number=\"26\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC26\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * savedInstanceState) { super.onCreate(savedInstanceState); \u0026amp;#8230;\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L27\" class=\"blob-num js-line-number\" data-line-number=\"27\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC27\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L28\" class=\"blob-num js-line-number\" data-line-number=\"28\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC28\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * final ActionBar bar = getActionBar();\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L29\" class=\"blob-num js-line-number\" data-line-number=\"29\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC29\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L30\" class=\"blob-num js-line-number\" data-line-number=\"30\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC30\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * SmartBarUtils.setActionBarTabsShowAtBottom(bar, true);\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L31\" class=\"blob-num js-line-number\" data-line-number=\"31\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC31\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L32\" class=\"blob-num js-line-number\" data-line-number=\"32\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC32\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * bar.addTab(bar.newTab().setText(\u0026amp;quot;tab1\u0026amp;quot;).setTabListener(this));\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L33\" class=\"blob-num js-line-number\" data-line-number=\"33\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC33\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026amp;#8230; } }\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L34\" class=\"blob-num js-line-number\" data-line-number=\"34\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC34\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L35\" class=\"blob-num js-line-number\" data-line-number=\"35\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC35\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L36\" class=\"blob-num js-line-number\" data-line-number=\"36\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC36\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;setActionBarTabsShowAtBottom\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBar\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;actionbar\u0026lt;/span\u0026gt;,\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L37\" class=\"blob-num js-line-number\" data-line-number=\"37\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC37\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;showAtBottom\u0026lt;/span\u0026gt;) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L38\" class=\"blob-num js-line-number\" data-line-number=\"38\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC38\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L39\" class=\"blob-num js-line-number\" data-line-number=\"39\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC39\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Method\u0026lt;/span\u0026gt; method \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;forName(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;android.app.ActionBar\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;)\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMethod(\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L40\" class=\"blob-num js-line-number\" data-line-number=\"40\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC40\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;setTabsShowAtBottom\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;[] { \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;class });\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L41\" class=\"blob-num js-line-number\" data-line-number=\"41\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC41\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L42\" class=\"blob-num js-line-number\" data-line-number=\"42\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC42\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  method\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;invoke(actionbar, showAtBottom);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L43\" class=\"blob-num js-line-number\" data-line-number=\"43\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC43\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalArgumentException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L44\" class=\"blob-num js-line-number\" data-line-number=\"44\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC44\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L45\" class=\"blob-num js-line-number\" data-line-number=\"45\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC45\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalAccessException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L46\" class=\"blob-num js-line-number\" data-line-number=\"46\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC46\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L47\" class=\"blob-num js-line-number\" data-line-number=\"47\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC47\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;InvocationTargetException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L48\" class=\"blob-num js-line-number\" data-line-number=\"48\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC48\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L49\" class=\"blob-num js-line-number\" data-line-number=\"49\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC49\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L50\" class=\"blob-num js-line-number\" data-line-number=\"50\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC50\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;SecurityException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L51\" class=\"blob-num js-line-number\" data-line-number=\"51\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC51\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L52\" class=\"blob-num js-line-number\" data-line-number=\"52\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC52\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;NoSuchMethodException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L53\" class=\"blob-num js-line-number\" data-line-number=\"53\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC53\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L54\" class=\"blob-num js-line-number\" data-line-number=\"54\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC54\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ClassNotFoundException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L55\" class=\"blob-num js-line-number\" data-line-number=\"55\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC55\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L56\" class=\"blob-num js-line-number\" data-line-number=\"56\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC56\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L57\" class=\"blob-num js-line-number\" data-line-number=\"57\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC57\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L58\" class=\"blob-num js-line-number\" data-line-number=\"58\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC58\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L59\" class=\"blob-num js-line-number\" data-line-number=\"59\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC59\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L60\" class=\"blob-num js-line-number\" data-line-number=\"60\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC60\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 调用 ActionBar.setActionBarViewCollapsable(boolean) 方法。\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L61\" class=\"blob-num js-line-number\" data-line-number=\"61\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC61\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 设置ActionBar顶栏无显示内容时是否隐藏。\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L62\" class=\"blob-num js-line-number\" data-line-number=\"62\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC62\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L63\" class=\"blob-num js-line-number\" data-line-number=\"63\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC63\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 示例：\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L64\" class=\"blob-num js-line-number\" data-line-number=\"64\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC64\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L65\" class=\"blob-num js-line-number\" data-line-number=\"65\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC65\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * public class MyActivity extends Activity {\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L66\" class=\"blob-num js-line-number\" data-line-number=\"66\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC66\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L67\" class=\"blob-num js-line-number\" data-line-number=\"67\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC67\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * protected void onCreate(Bundle savedInstanceState) {\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L68\" class=\"blob-num js-line-number\" data-line-number=\"68\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC68\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * super.onCreate(savedInstanceState); \u0026amp;#8230;\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L69\" class=\"blob-num js-line-number\" data-line-number=\"69\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC69\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L70\" class=\"blob-num js-line-number\" data-line-number=\"70\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC70\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * final ActionBar bar = getActionBar();\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L71\" class=\"blob-num js-line-number\" data-line-number=\"71\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC71\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L72\" class=\"blob-num js-line-number\" data-line-number=\"72\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC72\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * // 调用setActionBarViewCollapsable，并设置ActionBar没有显示内容，则ActionBar顶栏不显示\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L73\" class=\"blob-num js-line-number\" data-line-number=\"73\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC73\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * SmartBarUtils.setActionBarViewCollapsable(bar, true);\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L74\" class=\"blob-num js-line-number\" data-line-number=\"74\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC74\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * bar.setDisplayOptions(0); } }\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L75\" class=\"blob-num js-line-number\" data-line-number=\"75\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC75\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L76\" class=\"blob-num js-line-number\" data-line-number=\"76\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC76\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;setActionBarViewCollapsable\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBar\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;actionbar\u0026lt;/span\u0026gt;,\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L77\" class=\"blob-num js-line-number\" data-line-number=\"77\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC77\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;collapsable\u0026lt;/span\u0026gt;) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L78\" class=\"blob-num js-line-number\" data-line-number=\"78\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC78\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L79\" class=\"blob-num js-line-number\" data-line-number=\"79\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC79\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Method\u0026lt;/span\u0026gt; method \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;forName(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;android.app.ActionBar\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;)\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMethod(\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L80\" class=\"blob-num js-line-number\" data-line-number=\"80\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC80\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;setActionBarViewCollapsable\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;,\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L81\" class=\"blob-num js-line-number\" data-line-number=\"81\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC81\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;[] { \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;class });\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L82\" class=\"blob-num js-line-number\" data-line-number=\"82\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC82\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L83\" class=\"blob-num js-line-number\" data-line-number=\"83\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC83\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  method\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;invoke(actionbar, collapsable);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L84\" class=\"blob-num js-line-number\" data-line-number=\"84\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC84\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalArgumentException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L85\" class=\"blob-num js-line-number\" data-line-number=\"85\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC85\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L86\" class=\"blob-num js-line-number\" data-line-number=\"86\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC86\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalAccessException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L87\" class=\"blob-num js-line-number\" data-line-number=\"87\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC87\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L88\" class=\"blob-num js-line-number\" data-line-number=\"88\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC88\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;InvocationTargetException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L89\" class=\"blob-num js-line-number\" data-line-number=\"89\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC89\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L90\" class=\"blob-num js-line-number\" data-line-number=\"90\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC90\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L91\" class=\"blob-num js-line-number\" data-line-number=\"91\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC91\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;SecurityException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L92\" class=\"blob-num js-line-number\" data-line-number=\"92\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC92\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L93\" class=\"blob-num js-line-number\" data-line-number=\"93\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC93\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;NoSuchMethodException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L94\" class=\"blob-num js-line-number\" data-line-number=\"94\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC94\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L95\" class=\"blob-num js-line-number\" data-line-number=\"95\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC95\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ClassNotFoundException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L96\" class=\"blob-num js-line-number\" data-line-number=\"96\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC96\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L97\" class=\"blob-num js-line-number\" data-line-number=\"97\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC97\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L98\" class=\"blob-num js-line-number\" data-line-number=\"98\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC98\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L99\" class=\"blob-num js-line-number\" data-line-number=\"99\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC99\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L100\" class=\"blob-num js-line-number\" data-line-number=\"100\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC100\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L101\" class=\"blob-num js-line-number\" data-line-number=\"101\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC101\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 调用 ActionBar.setActionModeHeaderHidden(boolean) 方法。 设置ActionMode顶栏是否隐藏。\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L102\" class=\"blob-num js-line-number\" data-line-number=\"102\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC102\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L103\" class=\"blob-num js-line-number\" data-line-number=\"103\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC103\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * public class MyActivity extends Activity {\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L104\" class=\"blob-num js-line-number\" data-line-number=\"104\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC104\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L105\" class=\"blob-num js-line-number\" data-line-number=\"105\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC105\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * protected void onCreate(Bundle savedInstanceState) {\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L106\" class=\"blob-num js-line-number\" data-line-number=\"106\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC106\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * super.onCreate(savedInstanceState); \u0026amp;#8230;\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L107\" class=\"blob-num js-line-number\" data-line-number=\"107\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC107\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L108\" class=\"blob-num js-line-number\" data-line-number=\"108\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC108\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * final ActionBar bar = getActionBar();\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L109\" class=\"blob-num js-line-number\" data-line-number=\"109\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC109\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L110\" class=\"blob-num js-line-number\" data-line-number=\"110\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC110\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * // ActionBar转为ActionMode时，不显示ActionMode顶栏\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L111\" class=\"blob-num js-line-number\" data-line-number=\"111\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC111\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * SmartBarUtils.setActionModeHeaderHidden(bar, true); } }\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L112\" class=\"blob-num js-line-number\" data-line-number=\"112\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC112\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L113\" class=\"blob-num js-line-number\" data-line-number=\"113\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC113\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;setActionModeHeaderHidden\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBar\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;actionbar\u0026lt;/span\u0026gt;,\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L114\" class=\"blob-num js-line-number\" data-line-number=\"114\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC114\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;hidden\u0026lt;/span\u0026gt;) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L115\" class=\"blob-num js-line-number\" data-line-number=\"115\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC115\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L116\" class=\"blob-num js-line-number\" data-line-number=\"116\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC116\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Method\u0026lt;/span\u0026gt; method \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;forName(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;android.app.ActionBar\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;)\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMethod(\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L117\" class=\"blob-num js-line-number\" data-line-number=\"117\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC117\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;setActionModeHeaderHidden\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;[] { \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;class });\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L118\" class=\"blob-num js-line-number\" data-line-number=\"118\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC118\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L119\" class=\"blob-num js-line-number\" data-line-number=\"119\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC119\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  method\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;invoke(actionbar, hidden);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L120\" class=\"blob-num js-line-number\" data-line-number=\"120\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC120\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalArgumentException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L121\" class=\"blob-num js-line-number\" data-line-number=\"121\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC121\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L122\" class=\"blob-num js-line-number\" data-line-number=\"122\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC122\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalAccessException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L123\" class=\"blob-num js-line-number\" data-line-number=\"123\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC123\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L124\" class=\"blob-num js-line-number\" data-line-number=\"124\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC124\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;InvocationTargetException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L125\" class=\"blob-num js-line-number\" data-line-number=\"125\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC125\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L126\" class=\"blob-num js-line-number\" data-line-number=\"126\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC126\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L127\" class=\"blob-num js-line-number\" data-line-number=\"127\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC127\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;SecurityException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L128\" class=\"blob-num js-line-number\" data-line-number=\"128\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC128\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L129\" class=\"blob-num js-line-number\" data-line-number=\"129\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC129\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;NoSuchMethodException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L130\" class=\"blob-num js-line-number\" data-line-number=\"130\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC130\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L131\" class=\"blob-num js-line-number\" data-line-number=\"131\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC131\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ClassNotFoundException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L132\" class=\"blob-num js-line-number\" data-line-number=\"132\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC132\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L133\" class=\"blob-num js-line-number\" data-line-number=\"133\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC133\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L134\" class=\"blob-num js-line-number\" data-line-number=\"134\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC134\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L135\" class=\"blob-num js-line-number\" data-line-number=\"135\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC135\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L136\" class=\"blob-num js-line-number\" data-line-number=\"136\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC136\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L137\" class=\"blob-num js-line-number\" data-line-number=\"137\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC137\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 原隐藏SmartBar的方法\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L138\" class=\"blob-num js-line-number\" data-line-number=\"138\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC138\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 此方法已从Flyme2.4.1开始失效 示例：\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L139\" class=\"blob-num js-line-number\" data-line-number=\"139\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC139\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L140\" class=\"blob-num js-line-number\" data-line-number=\"140\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC140\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * final ActionBar actionBar = getActionBar(); SmartBarUtils.hide(this);\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L141\" class=\"blob-num js-line-number\" data-line-number=\"141\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC141\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L142\" class=\"blob-num js-line-number\" data-line-number=\"142\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC142\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L143\" class=\"blob-num js-line-number\" data-line-number=\"143\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC143\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;@Deprecated\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L144\" class=\"blob-num js-line-number\" data-line-number=\"144\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC144\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;hide\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;FragmentActivity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L145\" class=\"blob-num js-line-number\" data-line-number=\"145\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC145\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBar\u0026lt;/span\u0026gt; actionBar \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; activity\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getActionBar();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L146\" class=\"blob-num js-line-number\" data-line-number=\"146\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC146\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (actionBar \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L147\" class=\"blob-num js-line-number\" data-line-number=\"147\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC147\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L148\" class=\"blob-num js-line-number\" data-line-number=\"148\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC148\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L149\" class=\"blob-num js-line-number\" data-line-number=\"149\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC149\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;Class\u0026lt;? extends \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBar\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBarClass\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; actionBar\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getClass();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L150\" class=\"blob-num js-line-number\" data-line-number=\"150\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC150\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Method\u0026lt;/span\u0026gt; setTabsShowAtBottom;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L151\" class=\"blob-num js-line-number\" data-line-number=\"151\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC151\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L152\" class=\"blob-num js-line-number\" data-line-number=\"152\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC152\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  setTabsShowAtBottom \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ActionBarClass\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMethod(\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L153\" class=\"blob-num js-line-number\" data-line-number=\"153\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC153\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;setTabsShowAtBottom\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Boolean\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;TYPE\u0026lt;/span\u0026gt;);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L154\" class=\"blob-num js-line-number\" data-line-number=\"154\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC154\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  setTabsShowAtBottom\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;invoke(activity\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getActionBar(), \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L155\" class=\"blob-num js-line-number\" data-line-number=\"155\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC155\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;NoSuchMethodException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L156\" class=\"blob-num js-line-number\" data-line-number=\"156\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC156\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L157\" class=\"blob-num js-line-number\" data-line-number=\"157\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC157\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalArgumentException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L158\" class=\"blob-num js-line-number\" data-line-number=\"158\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC158\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L159\" class=\"blob-num js-line-number\" data-line-number=\"159\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC159\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;IllegalAccessException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L160\" class=\"blob-num js-line-number\" data-line-number=\"160\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC160\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L161\" class=\"blob-num js-line-number\" data-line-number=\"161\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC161\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;InvocationTargetException\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L162\" class=\"blob-num js-line-number\" data-line-number=\"162\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC162\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L163\" class=\"blob-num js-line-number\" data-line-number=\"163\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC163\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L164\" class=\"blob-num js-line-number\" data-line-number=\"164\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC164\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L165\" class=\"blob-num js-line-number\" data-line-number=\"165\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC165\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L166\" class=\"blob-num js-line-number\" data-line-number=\"166\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC166\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L167\" class=\"blob-num js-line-number\" data-line-number=\"167\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC167\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 以下三个方法原作者为c跳跳(http://weibo.com/u/1698085875),\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L168\" class=\"blob-num js-line-number\" data-line-number=\"168\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC168\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 由Shawn(http://weibo.com/linshen2011)在其基础上改进了一种判断SmartBar是否存在的方法,\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L169\" class=\"blob-num js-line-number\" data-line-number=\"169\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC169\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 注意该方法反射的接口只存在于2013年6月之后魅族的flyme固件中\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L170\" class=\"blob-num js-line-number\" data-line-number=\"170\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC170\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L171\" class=\"blob-num js-line-number\" data-line-number=\"171\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC171\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L172\" class=\"blob-num js-line-number\" data-line-number=\"172\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC172\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L173\" class=\"blob-num js-line-number\" data-line-number=\"173\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC173\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 方法一:uc等在使用的方法(新旧版flyme均有效)，\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L174\" class=\"blob-num js-line-number\" data-line-number=\"174\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC174\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 此方法需要配合requestWindowFeature(Window.FEATURE_NO_TITLE\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L175\" class=\"blob-num js-line-number\" data-line-number=\"175\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC175\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * )使用,缺点是程序无法使用系统actionbar\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L176\" class=\"blob-num js-line-number\" data-line-number=\"176\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC176\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L177\" class=\"blob-num js-line-number\" data-line-number=\"177\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC177\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @param decorView\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L178\" class=\"blob-num js-line-number\" data-line-number=\"178\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC178\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * window.getDecorView\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L179\" class=\"blob-num js-line-number\" data-line-number=\"179\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC179\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L180\" class=\"blob-num js-line-number\" data-line-number=\"180\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC180\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;hide\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;decorView\u0026lt;/span\u0026gt;) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L181\" class=\"blob-num js-line-number\" data-line-number=\"181\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC181\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;!\u0026lt;/span\u0026gt;hasSmartBar())\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L182\" class=\"blob-num js-line-number\" data-line-number=\"182\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC182\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L183\" class=\"blob-num js-line-number\" data-line-number=\"183\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC183\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L184\" class=\"blob-num js-line-number\" data-line-number=\"184\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC184\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L185\" class=\"blob-num js-line-number\" data-line-number=\"185\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC185\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  @SuppressWarnings(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;rawtypes\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L186\" class=\"blob-num js-line-number\" data-line-number=\"186\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC186\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;[] arrayOfClass \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L187\" class=\"blob-num js-line-number\" data-line-number=\"187\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC187\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  arrayOfClass[\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Integer\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;TYPE\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L188\" class=\"blob-num js-line-number\" data-line-number=\"188\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC188\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Method\u0026lt;/span\u0026gt; localMethod \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;class\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMethod(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;setSystemUiVisibility\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;,\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L189\" class=\"blob-num js-line-number\" data-line-number=\"189\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC189\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  arrayOfClass);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L190\" class=\"blob-num js-line-number\" data-line-number=\"190\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC190\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Field\u0026lt;/span\u0026gt; localField \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;class\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L191\" class=\"blob-num js-line-number\" data-line-number=\"191\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC191\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  .getField(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;SYSTEM_UI_FLAG_HIDE_NAVIGATION\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L192\" class=\"blob-num js-line-number\" data-line-number=\"192\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC192\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;Object\u0026lt;/span\u0026gt;[] arrayOfObject \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Object\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L193\" class=\"blob-num js-line-number\" data-line-number=\"193\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC193\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L194\" class=\"blob-num js-line-number\" data-line-number=\"194\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC194\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  arrayOfObject[\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; localField\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;get(\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L195\" class=\"blob-num js-line-number\" data-line-number=\"195\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC195\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Exception\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L196\" class=\"blob-num js-line-number\" data-line-number=\"196\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC196\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L197\" class=\"blob-num js-line-number\" data-line-number=\"197\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC197\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L198\" class=\"blob-num js-line-number\" data-line-number=\"198\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC198\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  localMethod\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;invoke(decorView, arrayOfObject);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L199\" class=\"blob-num js-line-number\" data-line-number=\"199\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC199\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L200\" class=\"blob-num js-line-number\" data-line-number=\"200\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC200\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Exception\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L201\" class=\"blob-num js-line-number\" data-line-number=\"201\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC201\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L202\" class=\"blob-num js-line-number\" data-line-number=\"202\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC202\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L203\" class=\"blob-num js-line-number\" data-line-number=\"203\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC203\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L204\" class=\"blob-num js-line-number\" data-line-number=\"204\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC204\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L205\" class=\"blob-num js-line-number\" data-line-number=\"205\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC205\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L206\" class=\"blob-num js-line-number\" data-line-number=\"206\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC206\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 方法二：此方法需要配合requestWindowFeature(Window.FEATURE_NO_TITLE)使用\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L207\" class=\"blob-num js-line-number\" data-line-number=\"207\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC207\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * ，缺点是程序无法使用系统actionbar\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L208\" class=\"blob-num js-line-number\" data-line-number=\"208\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC208\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L209\" class=\"blob-num js-line-number\" data-line-number=\"209\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC209\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L210\" class=\"blob-num js-line-number\" data-line-number=\"210\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC210\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @param window\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L211\" class=\"blob-num js-line-number\" data-line-number=\"211\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC211\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L212\" class=\"blob-num js-line-number\" data-line-number=\"212\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC212\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;hide\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Context\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;context\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Window\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;window\u0026lt;/span\u0026gt;) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L213\" class=\"blob-num js-line-number\" data-line-number=\"213\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC213\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  hide(context, window, \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L214\" class=\"blob-num js-line-number\" data-line-number=\"214\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC214\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L215\" class=\"blob-num js-line-number\" data-line-number=\"215\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC215\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L216\" class=\"blob-num js-line-number\" data-line-number=\"216\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC216\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;getStatusBarHeight\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Context\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;context\u0026lt;/span\u0026gt;) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L217\" class=\"blob-num js-line-number\" data-line-number=\"217\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC217\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; result \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L218\" class=\"blob-num js-line-number\" data-line-number=\"218\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC218\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; resourceId \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; context\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getResources()\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getIdentifier(\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L219\" class=\"blob-num js-line-number\" data-line-number=\"219\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC219\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;status_bar_height\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;dimen\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;android\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L220\" class=\"blob-num js-line-number\" data-line-number=\"220\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC220\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (resourceId \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L221\" class=\"blob-num js-line-number\" data-line-number=\"221\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC221\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  result \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; context\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getResources()\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getDimensionPixelSize(resourceId);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L222\" class=\"blob-num js-line-number\" data-line-number=\"222\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC222\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L223\" class=\"blob-num js-line-number\" data-line-number=\"223\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC223\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; result;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L224\" class=\"blob-num js-line-number\" data-line-number=\"224\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC224\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L225\" class=\"blob-num js-line-number\" data-line-number=\"225\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC225\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L226\" class=\"blob-num js-line-number\" data-line-number=\"226\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC226\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L227\" class=\"blob-num js-line-number\" data-line-number=\"227\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC227\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 方法三：需要使用顶部actionbar的应用请使用此方法\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L228\" class=\"blob-num js-line-number\" data-line-number=\"228\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC228\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L229\" class=\"blob-num js-line-number\" data-line-number=\"229\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC229\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L230\" class=\"blob-num js-line-number\" data-line-number=\"230\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC230\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @param window\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L231\" class=\"blob-num js-line-number\" data-line-number=\"231\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC231\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @param smartBarHeight\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L232\" class=\"blob-num js-line-number\" data-line-number=\"232\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC232\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * set SmartBarUtils.SMART_BAR_HEIGHT_PIXEL\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L233\" class=\"blob-num js-line-number\" data-line-number=\"233\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC233\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L234\" class=\"blob-num js-line-number\" data-line-number=\"234\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC234\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;hide\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Context\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;context\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Window\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;window\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;smartBarHeight\u0026lt;/span\u0026gt;) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L235\" class=\"blob-num js-line-number\" data-line-number=\"235\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC235\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;!\u0026lt;/span\u0026gt;hasSmartBar()) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L236\" class=\"blob-num js-line-number\" data-line-number=\"236\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC236\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L237\" class=\"blob-num js-line-number\" data-line-number=\"237\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC237\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L238\" class=\"blob-num js-line-number\" data-line-number=\"238\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC238\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (context\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getResources()\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getConfiguration()\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;orientation \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Configuration\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;ORIENTATION_LANDSCAPE\u0026lt;/span\u0026gt;) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L239\" class=\"blob-num js-line-number\" data-line-number=\"239\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC239\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L240\" class=\"blob-num js-line-number\" data-line-number=\"240\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC240\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L241\" class=\"blob-num js-line-number\" data-line-number=\"241\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC241\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L242\" class=\"blob-num js-line-number\" data-line-number=\"242\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC242\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  window\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;setFlags(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;WindowManager\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;LayoutParams\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;FLAG_FULLSCREEN\u0026lt;/span\u0026gt;,\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L243\" class=\"blob-num js-line-number\" data-line-number=\"243\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC243\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;WindowManager\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;LayoutParams\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;FLAG_FULLSCREEN\u0026lt;/span\u0026gt;);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L244\" class=\"blob-num js-line-number\" data-line-number=\"244\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC244\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  window\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;addFlags(\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;WindowManager\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;LayoutParams\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;FLAG_FORCE_NOT_FULLSCREEN\u0026lt;/span\u0026gt;);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L245\" class=\"blob-num js-line-number\" data-line-number=\"245\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC245\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; statusBarHeight \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; getStatusBarHeight(context);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L246\" class=\"blob-num js-line-number\" data-line-number=\"246\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC246\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L247\" class=\"blob-num js-line-number\" data-line-number=\"247\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC247\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  window\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getDecorView()\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L248\" class=\"blob-num js-line-number\" data-line-number=\"248\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC248\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  .setPadding(\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, statusBarHeight, \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;#8211;\u0026lt;/span\u0026gt;smartBarHeight);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L249\" class=\"blob-num js-line-number\" data-line-number=\"249\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC249\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L250\" class=\"blob-num js-line-number\" data-line-number=\"250\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC250\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L251\" class=\"blob-num js-line-number\" data-line-number=\"251\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC251\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L252\" class=\"blob-num js-line-number\" data-line-number=\"252\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC252\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * 新型号可用反射调用Build.hasSmartBar()来判断有无SmartBar\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L253\" class=\"blob-num js-line-number\" data-line-number=\"253\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC253\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L254\" class=\"blob-num js-line-number\" data-line-number=\"254\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC254\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L255\" class=\"blob-num js-line-number\" data-line-number=\"255\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC255\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;hasSmartBar\u0026lt;/span\u0026gt;() {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L256\" class=\"blob-num js-line-number\" data-line-number=\"256\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC256\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L257\" class=\"blob-num js-line-number\" data-line-number=\"257\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC257\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Method\u0026lt;/span\u0026gt; method \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;forName(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;android.os.Build\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;)\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMethod(\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L258\" class=\"blob-num js-line-number\" data-line-number=\"258\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC258\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;hasSmartBar\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;);\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L259\" class=\"blob-num js-line-number\" data-line-number=\"259\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC259\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; ((\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Boolean\u0026lt;/span\u0026gt;) method\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;invoke(\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;))\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;booleanValue();\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L260\" class=\"blob-num js-line-number\" data-line-number=\"260\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC260\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Exception\u0026lt;/span\u0026gt; e) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L261\" class=\"blob-num js-line-number\" data-line-number=\"261\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC261\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L262\" class=\"blob-num js-line-number\" data-line-number=\"262\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC262\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L263\" class=\"blob-num js-line-number\" data-line-number=\"263\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC263\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Build\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;DEVICE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;equals(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;mx2\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;)) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L264\" class=\"blob-num js-line-number\" data-line-number=\"264\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC264\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L265\" class=\"blob-num js-line-number\" data-line-number=\"265\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC265\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Build\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;DEVICE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;equals(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;mx\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;) \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;||\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Build\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;DEVICE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;equals(\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;m9\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;)) {\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L266\" class=\"blob-num js-line-number\" data-line-number=\"266\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC266\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L267\" class=\"blob-num js-line-number\" data-line-number=\"267\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC267\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L268\" class=\"blob-num js-line-number\" data-line-number=\"268\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC268\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L269\" class=\"blob-num js-line-number\" data-line-number=\"269\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC269\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L270\" class=\"blob-num js-line-number\" data-line-number=\"270\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC270\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"file-smartbarutils-java-L271\" class=\"blob-num js-line-number\" data-line-number=\"271\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td id=\u0026quot;file-smartbarutils-java-LC271\u0026quot; class=\u0026quot;blob-code blob-code-inner js-file-line\u0026quot;\u0026gt;\n  }\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e","title":"Android获取手机底部虚拟按键高度"},{"content":"Material Design真的很好看，动画效果真的很实用。前面也写了一些文章介绍如何编写Material风格的程序，但是很多都是一些新的api，低版本上面没有这些api，我们没办法使用。但是不用气馁，google官方，以及一些大牛，给我们提供了一些程序，让我们在低版本上面可以实现Material风格的程序，这里就给大家介绍一下。\n妹子图截屏\n使用support library 使用support library最新的版本，appcomt21，可以在较低版本上面实现部分风格，在之前的文章我已经说过了，这里在系统的说一下。\n应用主题 这部分的话之前的文章说过，链接在这里: http://blog.isming.me/2014/10/18/creating-android-app-with-material-design-one-theme/\n使用gralde进行构建的话，在依赖中添加v7包：\n[?](http://www.open-open.com/lib/view/open1416277425289.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `compile ``'com.android.support:appcompat-v7:21.0.+'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `compile ``'com.android.support:cardview-v7:21.0.+'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `compile ``'com.android.support:recyclerview-v7:21.0.+'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 使用eclipse构建的话，加入最新的appcompat包即可。\n另外在style文件中加入：\n[?](http://www.open-open.com/lib/view/open1416277425289.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;!-- extend one of the Theme.AppCompat themes --\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `\u0026amp;lt;``style` `name``=``\u0026quot;Theme.MyTheme\u0026quot;` `parent``=``\u0026quot;Theme.AppCompat.Light\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `\u0026amp;lt;!-- customize the color palette --\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `\u0026amp;lt;``item` `name``=``\u0026quot;colorPrimary\u0026quot;``\u0026amp;gt;@color/material_blue_500\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `\u0026amp;lt;``item` `name``=``\u0026quot;colorPrimaryDark\u0026quot;``\u0026amp;gt;@color/material_blue_700\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `\u0026amp;lt;``item` `name``=``\u0026quot;colorAccent\u0026quot;``\u0026amp;gt;@color/material_green_A200\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `\u0026amp;lt;/``style``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 在appliaction中使用我们的这个Theme.MyTheme，上一次的文章中有个错误，这种情况下不需要在valus-v21中创建一个同名的继承自Material的theme,否则会报错。这样我们就可以使用Material风格了。不过低版本上面还是有很多地方不可以实现这种效果的。\n使用Toolbar代替ActionBar。 android 5.0增加了ToolBar,可以用其代替ActionBar,在更低版本中，推荐使用，这样，动画特效更方便实现。\n在布局文件中增加Toolbar：\n[?](http://www.open-open.com/lib/view/open1416277425289.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;``android.support.v7.widget.Toolbar` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``xmlns:android``=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/toolbar\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``android:background``=``\u0026quot;?attr/colorPrimaryDark\u0026quot;``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 在代码中，使用Toolbar代替ActionBar（Activity必须是继承自ActionBarActivity的）：\n[?](http://www.open-open.com/lib/view/open1416277425289.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``protected` `void` `onCreate(Bundle savedInstanceState) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``super``.onCreate(savedInstanceState);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``setContentView(getLayoutResource());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``if` `(toolbar != ``null``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``setSupportActionBar(toolbar);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 使用CardView 不详说了，参看我之前的博客吧http://blog.isming.me/2014/10/21/creating-app-with-material-design-two-list/。\n使用动画 对于低版本，在support v7包中，提供了一些兼容，可以使用activity过渡动画(不过效果没有5.0的好)。\n首先声明主题的时候，创建一个AppTheme.Base用来声明主题，在其上增加动画属性:\n以下放在values/themes.xml中，用于适配低版本：\n[?](http://www.open-open.com/lib/view/open1416277425289.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;?``xml` `version``=``\u0026quot;1.0\u0026quot;` `encoding``=``\u0026quot;utf-8\u0026quot;``?\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `\u0026amp;lt;``resources``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``style` `name``=``\u0026quot;AppTheme\u0026quot;` `parent``=``\u0026quot;AppTheme.Base\u0026quot;``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``style` `name``=``\u0026quot;AppTheme.Base\u0026quot;` `parent``=``\u0026quot;Theme.AppCompat\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;colorPrimary\u0026quot;``\u0026amp;gt;@color/colorPrimary\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;colorPrimaryDark\u0026quot;``\u0026amp;gt;@color/colorPrimary\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:windowNoTitle\u0026quot;``\u0026amp;gt;true\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;windowActionBar\u0026quot;``\u0026amp;gt;false\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``style``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; `\u0026amp;lt;/``resources``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 以下放在values-v21/themes.xml中\n[?](http://www.open-open.com/lib/view/open1416277425289.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;?``xml` `version``=``\u0026quot;1.0\u0026quot;` `encoding``=``\u0026quot;utf-8\u0026quot;``?\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `\u0026amp;lt;``resources``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `\u0026amp;lt;``style` `name``=``\u0026quot;AppTheme\u0026quot;` `parent``=``\u0026quot;AppTheme.Base\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:windowContentTransitions\u0026quot;``\u0026amp;gt;true\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:windowAllowEnterTransitionOverlap\u0026quot;``\u0026amp;gt;true\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:windowAllowReturnTransitionOverlap\u0026quot;``\u0026amp;gt;true\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:windowSharedElementEnterTransition\u0026quot;``\u0026amp;gt;@android:transition/move\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:windowSharedElementExitTransition\u0026quot;``\u0026amp;gt;@android:transition/move\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; `\u0026amp;lt;/``style``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; `\u0026amp;lt;/``resources``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 在代码中启动新Activity的时候，使用v7包中的方法,具体过渡方法跟5.0一样，可以看我之前的博客：\n[?](http://www.open-open.com/lib/view/open1416277425289.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``activity, transitionView, DetailActivity.EXTRA_IMAGE);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `ActivityCompat.startActivity(activity, ``new` `Intent(activity, DetailActivity.``class``),` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `options.toBundle());` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 使用开源控件 对于很多的控件样式，动画，对话框等，使用兼容包无法完成，我们可以使用一些大神开发的第三方包来实现.\n组件: https://github.com/navasmdc/MaterialDesignLibrary\nhttps://github.com/keithellis/MaterialWidget\n上面两个主要是一些实现了Material的组件\nMaterial Design的对话框: https://github.com/afollestad/material-dialogs\n这个github仓库收集了很多的开源实现，大家可以过来看看。https://github.com/lightSky/MaterialDesignCenter\n其他 根据提供的规范，自己来实现相应的ui界面以及动画效果等等。\n这里提供一下谷歌的规范地址:\n谷歌设计规范：http://www.google.com/design/spec/material-design/introduction.html需要翻墙、http://design.1sters.com(中文)\n图标素材：https://github.com/google/material-design-icons、https://github.com/Templarian/MaterialDesign\n谷歌IO2014，Material Design的诠释:https://github.com/google/iosched\n其他人写的应用:https://github.com/afollestad/cabinet\n我写的一个应用，从之前的版本改过来，还没完成，大家随便看看就行了,也是Material Design：https://github.com/sangmingming/Meizitu 原文地址：http://blog.isming.me/2014/11/17/material-design-for-pre-lollipop-android/，转载请注明出处。\n","permalink":"https://blog.zdltech.com/posts/%E5%9C%A8%E4%BD%8E%E7%89%88%E6%9C%ACandroid%E7%B3%BB%E7%BB%9F%E4%B8%8A%E5%AE%9E%E7%8E%B0material-design%E5%BA%94%E7%94%A8/","summary":"\u003cp\u003eMaterial Design真的很好看，动画效果真的很实用。前面也写了一些文章介绍如何编写Material风格的程序，但是很多都是一些新的api，低版本上面没有这些api，我们没办法使用。但是不用气馁，google官方，以及一些大牛，给我们提供了一些程序，让我们在低版本上面可以实现Material风格的程序，这里就给大家介绍一下。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"screenmeizitu.png\" loading=\"lazy\" src=\"http://static.open-open.com/lib/uploadImg/20141118/20141118102423_677.png\"\u003e\u003c/p\u003e\n\u003cp\u003e妹子图截屏\u003c/p\u003e\n\u003ch3 id=\"使用support-library\"\u003e使用support library\u003c/h3\u003e\n\u003cp\u003e使用support library最新的版本，appcomt21，可以在较低版本上面实现部分风格，在之前的文章我已经说过了，这里在系统的说一下。\u003c/p\u003e\n\u003ch4 id=\"应用主题\"\u003e应用主题\u003c/h4\u003e\n\u003cp\u003e这部分的话之前的文章说过，链接在这里: \u003ca href=\"http://blog.isming.me/2014/10/18/creating-android-app-with-material-design-one-theme/\"\u003ehttp://blog.isming.me/2014/10/18/creating-android-app-with-material-design-one-theme/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e使用gralde进行构建的话，在依赖中添加v7包：\u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_332205\" class=\"syntaxhighlighter  java\"\u003e\n    \u003cdiv class=\"toolbar\"\u003e\n      [?](http://www.open-open.com/lib/view/open1416277425289.html#)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n  \u0026lt;tr\u0026gt;\n    \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n        1\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        2\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n        3\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n        4\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n        5\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `dependencies {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          `compile ``'com.android.support:appcompat-v7:21.0.+'`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `compile ``'com.android.support:cardview-v7:21.0.+'`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          `compile ``'com.android.support:recyclerview-v7:21.0.+'`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e使用eclipse构建的话，加入最新的appcompat包即可。\u003c/p\u003e","title":"在低版本android系统上实现Material design应用"},{"content":"Material Designer\n宗旨：让不同大小不同用途的设备上拥有同一种设计风格\n1.纸张\n这种设计模式大量参考了纸墨的模式，将空间变得像纸张一样，而用户的手指就是毛笔。用户按到控件上就会产生墨晕效果。这样的好处是明确的告诉用户是否点击了控件，而且还能让用户一下子明白控件的布局思路。毕竟一张一张的纸叠加起来的控件是很容易让人接受的。这里还有一个词“引喻”，虽然控件像纸张，但是它具有变大变小，改变颜色等能力，所以完全可以不用拘泥于现实纸张。\n2.深度\n新的设计中希望所有的控件都是现实世界中的隐喻，比如你按下按钮，按钮就应该有被按下的状态，这里就要用到了涟漪（Ripple）效果了。其实涟漪效果是来表示你手指按上去后墨晕扩散的效果的，下面的图能很明白的说明这点。\n3.动画\n动画贯穿于Material Designer之中，官方文档中用了很大的篇幅来讲解动画效果，希望让设计的动画效果很美观。但我个人认为为了动画而动画是完全不可取的，比如下面的例子\n这里的动画看起来十分自然和美观，但是在实际中用户切换activity是很常见的，如果经常出现这个动画用户会觉得“很腻”，十分不友好。动画其实是一个画龙点睛的东西，万不可变为画蛇添足。那么，上图的这个动画应该在什么时候使用呢？用在第一次用户进入一个新的界面的时候，我们为了凸显这个界面的某种特定功能，就可以让这个功能的图标动起来，表现出一个点我试试的效果。\n4.排版\n新的设计里面很在意排版，里面列出了很多详细的数据来支持我们的设计。对于留白也有了详细的说明。优秀的排班会让你的应用看起来干净，优雅，这点十分重要。在之后的文章中我也会多少说到这方面的知识。\n设计文档（不用FQ）\nhttp://design.1sters.com/\nhttp://www.ui.cn/Material/\n目录\nMaterial Designer的低版本兼容实现（二）—— Theme{#cb_post_title_url.postTitle2} Material Designer的低版本兼容实现（三）——Color{#cb_post_title_url.postTitle2} Material Designer的低版本兼容实现（四）—— ToolBar{#cb_post_title_url.postTitle2} Material Designer的低版本兼容实现（五）—— ActivityOptionsCompat{#cb_post_title_url.postTitle2} Material Designer的低版本兼容实现（六）—— Ripple Layout{#cb_post_title_url.postTitle2} Material Designer的低版本兼容实现（七）—— Rectange Button{#cb_post_title_url.postTitle2} Material Designer的低版本兼容实现（八）—— Flat Button{#cb_post_title_url.postTitle2} Material Designer的低版本兼容实现（九）—— Float Button \u0026amp; Small Float Button{#cb_post_title_url.postTitle2} Material Designer的低版本兼容实现（十）—— CheckBox \u0026amp; RadioButton{#cb_post_title_url.postTitle2} Material Designer的低版本兼容实现（十一）—— Switch{#cb_post_title_url.postTitle2} Material Designer的低版本兼容实现（十二）—— Slider or SeekBar{#cb_post_title_url.postTitle2} Material Designer的低版本兼容实现（十三）—— ProgressBar{#cb_post_title_url.postTitle2} Material Designer的低版本兼容实现（十四）—— CardView{#cb_post_title_url.postTitle2} 留着以后真正用到了再写的东东\n没写真的不是因为我懒，主要是东西太多了，还是请大家参考下面的项目MaterailCenter来看开源库吧。自己真正用到的时候就可以拿来用了。\nMaterial Designer的低版本兼容实现（XX）—— EditText \u0026amp; Typography\nMaterialEditText：https://github.com/rengwuxian/MaterialEditText（一中国大神做的，感觉很棒）\nAndroid 5.0更新了Roboto样式，不论多大的text，展示起来都会美观和简洁。\n添加了一种新的中等高度属性(android:fontFamily=”sans-serif-medium”) 和新的AppAppearance样式为了平衡内容密度和阅读的舒适感,实现了推荐的打印式缩放的。比如你可以简单的通过 android:textAppearance=”@android:style/TextAppearance.Material.Title” 设置 “Title”风格。在旧的版本中可以使用AppCompat support library的样式： “@style/TextAppearance.AppCompat.Title”.\nMaterial Designer的低版本兼容实现（XX）—— Dialog\nMaterialDialog：https://github.com/drakeet/MaterialDialog（国人做的）\nL—Dialog：https://github.com/lewisjdeane/L-Dialogs\nMaterial Designer的低版本兼容实现（XX）—— Drawer\nL-Drawer：https://github.com/ikimuhendis/LDrawer\nMaterialNavigationDrawer：https://github.com/neokree/MaterialNavigationDrawer\nMaterial Designer的低版本兼容实现（XX）—— Animation\nTransitions-Everywhere：https://github.com/andkulikov/transitions-everywhere\nAndroid-UI：https://github.com/markushi/android-ui\nCircularReveal：https://github.com/ozodrukh/CircularReveal\n参考项目：https://github.com/lightSky/MaterialDesignCenter（这个项目就是下面文章作者做的）\n参考文章：http://blog.csdn.net/xushuaic/article/details/40627389\nhttp://blog.csdn.net/xushuaic/article/details/40627389\n","permalink":"https://blog.zdltech.com/posts/material-designer%E7%9A%84%E4%BD%8E%E7%89%88%E6%9C%AC%E5%85%BC%E5%AE%B9%E5%AE%9E%E7%8E%B0-view-animation/","summary":"\u003cp\u003e\u003cstrong\u003eMaterial Designer\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e宗旨：让不同大小不同用途的设备上拥有同一种设计风格\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201411/071155051599008.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1.纸张\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201411/071155348625400.gif\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e这种设计模式大量参考了纸墨的模式，将空间变得像纸张一样，而用户的手指就是毛笔。用户按到控件上就会产生墨晕效果。这样的好处是明确的告诉用户是否点击了控件，而且还能让用户一下子明白控件的布局思路。毕竟一张一张的纸叠加起来的控件是很容易让人接受的。这里还有一个词“引喻”，虽然控件像纸张，但是它具有变大变小，改变颜色等能力，所以完全可以不用拘泥于现实纸张。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2.深度\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e新的设计中希望所有的控件都是现实世界中的隐喻，比如你按下按钮，按钮就应该有被按下的状态，这里就要用到了涟漪（Ripple）效果了。其实涟漪效果是来表示你手指按上去后墨晕扩散的效果的，下面的图能很明白的说明这点。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201411/071159412687690.gif\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3.动画\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e动画贯穿于Material Designer之中，官方文档中用了很大的篇幅来讲解动画效果，希望让设计的动画效果很美观。但我个人认为为了动画而动画是完全不可取的，比如下面的例子\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201411/071203521591274.gif\"\u003e\u003c/p\u003e\n\u003cp\u003e这里的动画看起来十分自然和美观，但是在实际中用户切换activity是很常见的，如果经常出现这个动画用户会觉得“很腻”，十分不友好。动画其实是一个画龙点睛的东西，万不可变为画蛇添足。那么，上图的这个动画应该在什么时候使用呢？用在第一次用户进入一个新的界面的时候，我们为了凸显这个界面的某种特定功能，就可以让这个功能的图标动起来，表现出一个点我试试的效果。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4.排版\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e新的设计里面很在意排版，里面列出了很多详细的数据来支持我们的设计。对于留白也有了详细的说明。优秀的排班会让你的应用看起来干净，优雅，这点十分重要。在之后的文章中我也会多少说到这方面的知识。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201411/071549184094928.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e设计文档（不用FQ）\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://design.1sters.com/\"\u003ehttp://design.1sters.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.ui.cn/Material/\"\u003ehttp://www.ui.cn/Material/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e目录\u003c/strong\u003e\u003c/p\u003e\n\u003ch1 class=\"postTitle\" id=\"material-designer的低版本兼容实现二-themecb_post_title_urlposttitle2\"\u003e\u003ca href=\"http://www.cnblogs.com/tianzhijiexian/p/4081562.html\"\u003eMaterial Designer的低版本兼容实现（二）—— Theme\u003c/a\u003e{#cb_post_title_url.postTitle2}\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201412/061357065147014.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 class=\"postTitle\" id=\"material-designer的低版本兼容实现三colorcb_post_title_urlposttitle2\"\u003e\u003ca href=\"http://www.cnblogs.com/tianzhijiexian/p/4081888.html\"\u003eMaterial Designer的低版本兼容实现（三）——Color\u003c/a\u003e{#cb_post_title_url.postTitle2}\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201412/061359590616301.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 class=\"postTitle\" id=\"material-designer的低版本兼容实现四-toolbarcb_post_title_urlposttitle2\"\u003e\u003ca href=\"http://www.cnblogs.com/tianzhijiexian/p/4082892.html\"\u003eMaterial Designer的低版本兼容实现（四）—— ToolBar\u003c/a\u003e{#cb_post_title_url.postTitle2}\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201412/061422199832676.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 class=\"postTitle\" id=\"material-designer的低版本兼容实现五-activityoptionscompatcb_post_title_urlposttitle2\"\u003e\u003ca href=\"http://www.cnblogs.com/tianzhijiexian/p/4087917.html\"\u003eMaterial Designer的低版本兼容实现（五）—— ActivityOptionsCompat\u003c/a\u003e{#cb_post_title_url.postTitle2}\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201412/061405013894504.gif\"\u003e     \u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201412/061431241554728.gif\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 class=\"postTitle\" id=\"material-designer的低版本兼容实现六-ripple-layoutcb_post_title_urlposttitle2\"\u003e\u003ca href=\"http://www.cnblogs.com/tianzhijiexian/p/4133672.html\"\u003eMaterial Designer的低版本兼容实现（六）—— Ripple Layout\u003c/a\u003e{#cb_post_title_url.postTitle2}\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201412/061413510149067.gif\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 class=\"postTitle\" id=\"material-designer的低版本兼容实现七-rectange-buttoncb_post_title_urlposttitle2\"\u003e\u003ca href=\"http://www.cnblogs.com/tianzhijiexian/p/4135993.html\"\u003eMaterial Designer的低版本兼容实现（七）—— Rectange Button\u003c/a\u003e{#cb_post_title_url.postTitle2}\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201412/061415283113810.png\"\u003e   \u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201412/061415455458110.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 class=\"postTitle\" id=\"material-designer的低版本兼容实现八-flat-buttoncb_post_title_urlposttitle2\"\u003e\u003ca href=\"http://www.cnblogs.com/tianzhijiexian/p/4143709.html\"\u003eMaterial Designer的低版本兼容实现（八）—— Flat Button\u003c/a\u003e{#cb_post_title_url.postTitle2}\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201412/061417116707032.png\"\u003e   \u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201412/061417035767139.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 class=\"postTitle\" id=\"material-designer的低版本兼容实现九-float-button--small-float-buttoncb_post_title_urlposttitle2\"\u003e\u003ca href=\"http://www.cnblogs.com/tianzhijiexian/p/4146924.html\"\u003eMaterial Designer的低版本兼容实现（九）—— Float Button \u0026amp; Small Float Button\u003c/a\u003e{#cb_post_title_url.postTitle2}\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201412/061419557487240.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 class=\"postTitle\" id=\"material-designer的低版本兼容实现十-checkbox--radiobuttoncb_post_title_urlposttitle2\"\u003e\u003ca href=\"http://www.cnblogs.com/tianzhijiexian/p/4147982.html\"\u003eMaterial Designer的低版本兼容实现（十）—— CheckBox \u0026amp; RadioButton\u003c/a\u003e{#cb_post_title_url.postTitle2}\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201412/061423270451653.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 class=\"postTitle\" id=\"material-designer的低版本兼容实现十一-switchcb_post_title_urlposttitle2\"\u003e\u003ca href=\"http://www.cnblogs.com/tianzhijiexian/p/4148131.html\"\u003eMaterial Designer的低版本兼容实现（十一）—— Switch\u003c/a\u003e{#cb_post_title_url.postTitle2}\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/651487/201412/061426227176151.png\"\u003e\u003c/p\u003e","title":"Material Designer的低版本兼容实现——View \u0026 Animation"},{"content":"一 概述 上周一我们发布了[Android 百分比布局库(percent-support-lib) 解析与扩展][1]中对percent-support这个库进行了解析和添加了PercentLinearLayout的支持。\n那么为什么本篇博客的存在的意义是什么呢？\n首先我们回顾下百分比布局库的用法，提供了PercentRelativeLayout、PercentFrameLayout供大家在编写的时候，对于以下属性：\nlayout_widthPercent、layout_heightPercent、\nlayout_marginPercent、layout_marginLeftPercent、\nlayout_marginTopPercent、layout_marginRightPercent、\nlayout_marginBottomPercent、layout_marginStartPercent、layout_marginEndPercent。\n可以使用百分比进行设置宽、高、边距，的确给我们在适配上提供了极大的便利，但是在使用过程中，觉得存在一些场景无法得到满足。什么场景呢？下面我举几个例子。\n当使用图片时，无法设置宽高的比例 比如我们的图片宽高是200*100的，我们在使用过程中我们设置宽高为20%、10%，这样会造成图片的比例失调。为什么呢？因为20%参考的是屏幕的宽度，而10%参考的是屏幕的高度。\n很难使用百分比定义一个正方形的控件 比如，我现在界面的右下角有一个FloatingActionButton，我希望其宽度和高度都为屏幕宽度的10%，很难做到。\n一个控件的margin四个方向值一致 有些时候，我设置margin，我希望四边的边距一致的，但是如果目前设置5%，会造成，上下为高度的5%，左右边距为宽度的5%。\n综合上述这些问题，可以发现目前的percent-support-lib并不能完全满足我们的需求，所以我们考虑对其进行扩展。说白了，我们就希望在布局的时候可以自己设定参考看度还是高度，比如上述2，我们对于宽高可以写成10%w，10%w。也就是在不改变原库的用法的前提下，添加一些额外的支持。\n二 扩展的功能 目前我初步对该库进行了改写，github地址：[android-percent-support-extend][2]，对于官方库，做了如下的改变：\n不改变原有库的用法\n添加了PercentLinearLayout\n支持百分比指定特定的参考值，比如宽度或者高度。 例如：app:layout_heightPercent=\u0026quot;50%w\u0026quot;, app:layout_marginPercent=\u0026quot;15%w\u0026quot;,\napp:layout_marginBottomPercent=\u0026quot;20%h\u0026quot;.\n支持通过app:layout_textSizePercent设置textView的textSize 对于外层套ScrollView的问题，目前可以在PercentLinearLayout的外层使用ScrollView，不过对于宽度的百分比参考的就是android.R.id.content的高度(因为，无法参考父控件的高度，父控件的高度理论上依赖于子View高度，且模式为UNSPECIFIED)。 对于如何导入，也是相当的简单，android studio的用户，直接： ``` dependencies { //... compile 'com.zhy:percent-support-extends:1.0.1' } - 1 - 2 - 3 - 4 - 5 不需要导入官方的percent-support-lib了。 对于的三个类分别为： ``` `com.zhy.android.percent.support.PercentLinearLayout com.zhy.android.percent.support.PercentRelativeLayout com.zhy.android.percent.support.PercentFrameLayout` - 1 - 2 - 3 对于eclipse的用户：github上自行下载源码，就几个类和一个attrs.xml，也可以在[bintray.com/percent-support-extends][3] 下载相关文件。 下面看几个具体的示例。 * * * ### \u0026lt;a name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;三 具体的示例 {#三-具体的示例} #### \u0026lt;a name=\u0026quot;t3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;Demo 1 {#demo-1} xml: ``` `\u0026lt;span class=\u0026ldquo;hljs-pi\u0026rdquo;\u0026gt;\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;utf-8\u0026rdquo;?\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;com.zhy.android.percent.support.PercentFrameLayout \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;xmlns:app\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;http://schemas.android.com/apk/res-auto\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;vertical\u0026rdquo;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;com.zhy.android.percent.support.PercentFrameLayout \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;center\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ff44aacc\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_heightPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;50%w\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_widthPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;50%w\u0026rdquo;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;com.zhy.android.percent.support.PercentFrameLayout \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;center\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ffcc5ec7\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_heightPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;50%w\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_widthPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;50%w\u0026rdquo;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;TextView \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;center\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ff7ecc16\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;center\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;margin 15% of w\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_marginPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;15%w\u0026rdquo;\u0026lt;/span\u0026gt; /\u0026gt;\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;com.zhy.android.percent.support.PercentFrameLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;com.zhy.android.percent.support.PercentFrameLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;TextView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;0dp\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;0dp\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;android:layout_gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;bottom|right\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;#44ff0000\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;android:gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;center\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;android:text\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;15%w,15%w\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;app:layout_heightPercent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;15%w\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;app:layout_marginPercent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;5%w\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-attribute\u0026quot;\u0026gt;app:layout_widthPercent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026quot;hljs-value\u0026quot;\u0026gt;\u0026quot;15%w\u0026quot;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;com.zhy.android.percent.support.PercentFrameLayout\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; `\n- 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 #### \u0026lt;a name=\u0026#34;t4\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;Demo 2 {#demo-2} ![](http://img.blog.csdn.net/20150706001401256) xml: ``` `\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;com.zhy.android.percent.support.PercentRelativeLayout \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:app\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res-auto\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:clickable\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;true\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;TextView \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/row_one_item_one\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_alignParentTop\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;true\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#7700ff00\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:text\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;w:70%,h:20%\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;center\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:layout_heightPercent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;20%\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:layout_widthPercent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;70%\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;TextView \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/row_one_item_two\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_toRightOf\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/row_one_item_one\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#396190\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:text\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;w:30%,h:20%\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:layout_heightPercent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;20%\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;center\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:layout_widthPercent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;30%\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ImageView \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/row_two_item_one\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:src\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@drawable/tangyan\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:scaleType\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;centerCrop\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_below\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/row_one_item_one\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#d89695\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:layout_heightPercent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;70%\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;TextView \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_below\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@id/row_two_item_one\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#770000ff\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;center\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:text\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;width:100%,height:10%\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:layout_heightPercent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;10%\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;app:layout_widthPercent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;100%\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;com.zhy.android.percent.support.PercentRelativeLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; ` - 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 ok，例子都比较简单，主要就一个布局文件，可以看出上述我们可以给宽度、高度，边距等指定参考值为宽度或者高度。这样的话，在保证图片宽、高比例、控件设置为正方形等需求就没问题了。 * * * 接下来还有个例子，功能主要是设置TextView对于textSize的百分比设置；以及对于ScrollView的支持。当然了，对于ScrollView的支持，这个理论上是不支持的，因为大家都清楚，如果`PercentLinearLayout`在ScrollView中，那么高度的模式肯定是`UNSPECIFIED`，那么理论上来说高度是无限制的，也就是依赖于子View的高度，而百分比布局的高度是依赖于父View的高度的，所有是互斥的。而我们支持是：考虑到编写代码的时候，大多参考的是屏幕高度（android.R.id.content）的高度，所以如果在ScrollView中，编写10%h，这个百分比是依赖于屏幕高度的（不包括ActionBar的高度）。 #### \u0026lt;a name=\u0026quot;t5\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;Demo 3 {#demo-3} xml: ``` `\u0026lt;span class=\u0026ldquo;hljs-pi\u0026rdquo;\u0026gt;\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;utf-8\u0026rdquo;?\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;ScrollView \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;xmlns:app\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;http://schemas.android.com/apk/res-auto\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;com.zhy.android.percent.support.PercentLinearLayout \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;xmlns:app\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;http://schemas.android.com/apk/res-auto\u0026quot;\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;wrap_content\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;vertical\u0026rdquo;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;TextView \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ff44aacc\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;center\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;width:60%,height:5%,ts:3%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ffffff\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_heightPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;5%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_marginBottomPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;5%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_textSizePercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;3%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_widthPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;60%\u0026quot;\u0026lt;/span\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;TextView \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ff4400cc\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;center\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;width:70%,height:10%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ffffff\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_heightPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;10%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_marginBottomPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;5%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_widthPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;70%\u0026quot;\u0026lt;/span\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;TextView \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ff44aacc\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;center\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;w:80%,h:15%,textSize:5%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ffffff\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_heightPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;15%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_marginBottomPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;5%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_textSizePercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;5%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_widthPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;80%\u0026quot;\u0026lt;/span\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;TextView \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ff4400cc\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;center\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;width:90%,height:5%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ffffff\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_heightPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;20%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_marginBottomPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;5%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_widthPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;90%\u0026quot;\u0026lt;/span\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;TextView \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ff44aacc\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;center\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;width:100%,height:25%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ffffff\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_heightPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;25%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_marginBottomPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;5%\u0026quot;\u0026lt;/span\u0026gt; /\u0026gt;\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;TextView \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;match_parent\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;0dp\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ff44aacc\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;center\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;width:100%,height:30%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026quot;#ffffff\u0026rdquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_heightPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;30%\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-attribute\u0026rdquo;\u0026gt;app:layout_marginBottomPercent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026ldquo;hljs-value\u0026rdquo;\u0026gt;\u0026ldquo;5%\u0026quot;\u0026lt;/span\u0026gt; /\u0026gt;\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;hljs-tag\u0026quot;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;com.zhy.android.percent.support.PercentLinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-tag\u0026rdquo;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;ScrollView\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n`\n- 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 上面的第三个TextView的字体设置的就是5%（默认参考容器高度）。整个PercentLinearLayout在ScrollView中。ok~ 姑且这样，由于源码比较简单，大家可以根据自己的实际需求去修改，前提尽可能不要改变原有的功能。 * * * ### \u0026lt;a name=\u0026#34;t6\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;四 扩展的相关源码 {#四-扩展的相关源码} #### \u0026lt;a name=\u0026#34;t7\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;(一) 关于attrs.xml {#一-关于attrsxml} 原库中所有的属性的format为fraction，但是由于我期望的写法有10%w，10%h，10%，没有找到合适的format，就直接定义为string了~string我可以自己去解析~ ``` `\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;declare-styleable\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;PercentLayout_Layout\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;attr\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout_widthPercent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;format\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;string\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;attr\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout_heightPercent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;format\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;string\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;attr\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout_marginPercent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;format\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;string\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;attr\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout_marginLeftPercent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;format\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;string\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;attr\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout_marginTopPercent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;format\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;string\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;attr\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout_marginRightPercent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;format\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;string\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;attr\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout_marginBottomPercent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;format\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;string\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;attr\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout_marginStartPercent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;format\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;string\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;attr\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout_marginEndPercent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;format\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;string\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;attr\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout_textSizePercent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;format\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;string\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;declare-styleable\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; ` - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 #### \u0026lt;a name=\u0026quot;t8\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;（二） 获取自定义属性的值及使用 {#二-获取自定义属性的值及使用} 如果看了上篇博文的话，应该清楚，对于自定义属性的值是在`PercentLayoutHelper.getPercentLayoutInfo(c, attrs)`中获取的。 简单看下修改后的代码： ``` ` \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;static\u0026lt;/span\u0026gt; PercentLayoutInfo \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;getPercentLayoutInfo\u0026lt;/span\u0026gt;(Context context, AttributeSet attrs) { PercentLayoutInfo info = \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;null\u0026lt;/span\u0026gt;; TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PercentLayout_Layout);\nString sizeStr = array.getString(R.styleable.PercentLayout_Layout_layout_widthPercent); PercentLayoutInfo.PercentVal percentVal = getPercentVal(sizeStr, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;true\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt; (percentVal != \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt; (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;percent width: \u0026quot;\u0026amp;lt;/span\u0026gt; + percentVal.percent); } info = info != \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt; ? info : \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; PercentLayoutInfo(); info.widthPercent = percentVal; } \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//省略了获取其他的类似属性\u0026amp;lt;/span\u0026gt; array.recycle(); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; info; } \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;final\u0026amp;lt;/span\u0026gt; String REGEX_PERCENT = \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;^(([0-9]+)([.]([0-9]+))?|([.]([0-9]+))?)%([wh]?)$\u0026quot;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/** * widthStr to PercentVal * \u0026amp;lt;br/\u0026amp;gt; * eg: 35%w =\u0026amp;gt; new PercentVal(35, true) * *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @param\u0026amp;lt;/span\u0026gt; percentStr *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @param\u0026amp;lt;/span\u0026gt; isOnWidth *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @return\u0026amp;lt;/span\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;static\u0026amp;lt;/span\u0026gt; PercentLayoutInfo.PercentVal \u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;getPercentVal\u0026amp;lt;/span\u0026gt;(String percentStr, \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; isOnWidth) { \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//valid param\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt; (percentStr == \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;; } Pattern p = Pattern.compile(REGEX_PERCENT); Matcher matcher = p.matcher(percentStr); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!matcher.matches()) { \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;throw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; RuntimeException(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;the value of layout_xxxPercent invalid! ==\u0026amp;gt;\u0026quot;\u0026amp;lt;/span\u0026gt; + percentStr); } \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt; len = percentStr.length(); \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//extract the float value\u0026amp;lt;/span\u0026gt; String floatVal = matcher.group(\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1\u0026amp;lt;/span\u0026gt;); String lastAlpha = percentStr.substring(len - \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026amp;lt;/span\u0026gt; percent = Float.parseFloat(floatVal) / \u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;100\u0026amp;lt;/span\u0026gt;f; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; isBasedWidth = (isOnWidth \u0026amp;\u0026amp; !lastAlpha.equals(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;h\u0026quot;\u0026amp;lt;/span\u0026gt;)) || lastAlpha.equals(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;w\u0026quot;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; PercentLayoutInfo.PercentVal(percent, isBasedWidth); } `\n- 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 首先我们获取自定义属性的填写的值，通过getPercentVal方法，在该方法内部通过正则校验其合法性，如果合法，则将其拆解封装成PercentVal对象，该对象中记录百分比值，已经知否参考宽度的布尔值（如果参考宽度则为true，否则为false）。对于没有后缀w|h的，和原库的解析方式相同。 PercentVal对象如下: ``` `public static class PercentVal { public float percent = -1; public boolean isBaseWidth; public PercentVal(float percent, boolean isBaseWidth) { this.percent = percent; this.isBaseWidth = isBaseWidth; } } ` - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 对于定义的自定义属性获取完成之后，剩下的无非是测量时候对于原本的LayoutParams中的宽度和高度的赋值做简单的修改。参考上一篇的源码，我们直接看 `PercentLayoutInfo.fillLayoutParams(params, widthHint, heightHint);`方法： ``` ` \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;fillLayoutParams\u0026lt;/span\u0026gt;(ViewGroup.LayoutParams params, \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; widthHint, \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; heightHint) { \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;// Preserve the original layout params, so we can restore them after the measure step.\u0026lt;/span\u0026gt; mPreservedParams.width = params.width; mPreservedParams.height = params.height; \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;/* if (widthPercent \u0026gt;= 0) { params.width = (int) (widthHint * widthPercent); } if (heightPercent \u0026gt;= 0) { params.height = (int) (heightHint * heightPercent); }*/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt; (widthPercent != \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; base = widthPercent.isBaseWidth ? widthHint : heightHint; params.width = (\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt;) (base * widthPercent.percent); } \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt; (heightPercent != \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt; base = heightPercent.isBaseWidth ? widthHint : heightHint; params.height = (\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt;) (base * heightPercent.percent); }\n\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt; (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;after fillLayoutParams: (\u0026quot;\u0026amp;lt;/span\u0026gt; + params.width + \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;, \u0026quot;\u0026amp;lt;/span\u0026gt; + params.height + \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;)\u0026quot;\u0026amp;lt;/span\u0026gt;); } } `\n- 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 原本的源码比较简单，只需要将widthHint/heightHint乘以百分比即可（见上代码注释），而我们修改的也比较容易，首先判断参考宽度还是高度，然后乘以百分比（根据我们的对象PercentVal的属性）。 ok，大概的源码修改就是上述的内容，有兴趣的可以直接查看源码。 当然了，上述库中肯定还存在或多或少的问题，大家可以fork完善下，或者直接留言提意见都可以。 * * * github地址：[android-percent-support-extend][2] ，用法参考上文，或者README。欢迎star and fork 。 ~~have a nice day ~~ ok~ [1]: http://blog.csdn.net/lmj623565791/article/details/46695347 [2]: https://github.com/hongyangAndroid/android-percent-support-extend [3]: https://bintray.com/hongyangandroid/maven/android-screen-support-ext/view#files ","permalink":"https://blog.zdltech.com/posts/android-%E5%A2%9E%E5%BC%BA%E7%89%88%E7%99%BE%E5%88%86%E6%AF%94%E5%B8%83%E5%B1%80%E5%BA%93-%E4%B8%BA%E4%BA%86%E9%80%82%E9%85%8D%E8%80%8C%E6%89%A9%E5%B1%95/","summary":"\u003ch3 id=\"一-概述\"\u003e一 概述\u003c/h3\u003e\n\u003cp\u003e上周一我们发布了[Android 百分比布局库(percent-support-lib) 解析与扩展][1]中对percent-support这个库进行了解析和添加了\u003ccode\u003ePercentLinearLayout\u003c/code\u003e的支持。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e那么为什么本篇博客的存在的意义是什么呢？\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e首先我们回顾下百分比布局库的用法，提供了\u003ccode\u003ePercentRelativeLayout\u003c/code\u003e、\u003ccode\u003ePercentFrameLayout\u003c/code\u003e供大家在编写的时候，对于以下属性：\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003elayout_widthPercent\u003c/code\u003e、\u003ccode\u003elayout_heightPercent\u003c/code\u003e、\u003cbr\u003e\n\u003ccode\u003elayout_marginPercent\u003c/code\u003e、\u003ccode\u003elayout_marginLeftPercent\u003c/code\u003e、\u003cbr\u003e\n\u003ccode\u003elayout_marginTopPercent\u003c/code\u003e、\u003ccode\u003elayout_marginRightPercent\u003c/code\u003e、\u003cbr\u003e\n\u003ccode\u003elayout_marginBottomPercent\u003c/code\u003e、\u003ccode\u003elayout_marginStartPercent\u003c/code\u003e、\u003ccode\u003elayout_marginEndPercent\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e可以使用百分比进行设置宽、高、边距，的确给我们在适配上提供了极大的便利，但是在使用过程中，觉得存在一些场景无法得到满足。什么场景呢？下面我举几个例子。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e当使用图片时，无法设置宽高的比例\n比如我们的图片宽高是200*100的，我们在使用过程中我们设置宽高为20%、10%，这样会造成图片的比例失调。为什么呢？因为20%参考的是屏幕的宽度，而10%参考的是屏幕的高度。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e很难使用百分比定义一个正方形的控件\n比如，我现在界面的右下角有一个\u003ccode\u003eFloatingActionButton\u003c/code\u003e，我希望其宽度和高度都为屏幕宽度的10%，很难做到。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e一个控件的margin四个方向值一致\n有些时候，我设置margin，我希望四边的边距一致的，但是如果目前设置5%，会造成，上下为高度的5%，左右边距为宽度的5%。\u003c/p\u003e\n\u003cp\u003e综合上述这些问题，可以发现目前的percent-support-lib并不能完全满足我们的需求，所以我们考虑对其进行扩展。说白了，我们就希望在布局的时候可以自己设定参考看度还是高度，比如上述2，我们对于宽高可以写成10%w，10%w。也就是在不改变原库的用法的前提下，添加一些额外的支持。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"二-扩展的功能\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e二 扩展的功能\u003c/h3\u003e\n\u003cp\u003e目前我初步对该库进行了改写，github地址：[android-percent-support-extend][2]，对于官方库，做了如下的改变：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e不改变原有库的用法\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e添加了\u003ccode\u003ePercentLinearLayout\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e支持百分比指定特定的参考值，比如宽度或者高度。\n例如：\u003ccode\u003eapp:layout_heightPercent=\u0026quot;50%w\u0026quot;\u003c/code\u003e, \u003ccode\u003eapp:layout_marginPercent=\u0026quot;15%w\u0026quot;\u003c/code\u003e,\u003cbr\u003e\n\u003ccode\u003eapp:layout_marginBottomPercent=\u0026quot;20%h\u0026quot;\u003c/code\u003e.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e支持通过app:layout_textSizePercent设置textView的textSize\u003c/li\u003e\n\u003cli\u003e对于外层套ScrollView的问题，目前可以在\u003ccode\u003ePercentLinearLayout\u003c/code\u003e的外层使用ScrollView，不过对于宽度的百分比参考的就是android.R.id.content的高度(因为，无法参考父控件的高度，父控件的高度理论上依赖于子View高度，且模式为UNSPECIFIED)。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e对于如何导入，也是相当的简单，android studio的用户，直接：\n\n```\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003ccode\u003edependencies { //... compile 'com.zhy:percent-support-extends:1.0.1' } \u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - 1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - 2\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - 3\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - 4\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  - 5\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                不需要导入官方的percent-support-lib了。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                对于的三个类分别为：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`com.zhy.android.percent.support.PercentLinearLayout\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecom.zhy.android.percent.support.PercentRelativeLayout\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecom.zhy.android.percent.support.PercentFrameLayout`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e              - 1\n              \n              - 2\n              \n              - 3\n              \n            \n            \n            对于eclipse的用户：github上自行下载源码，就几个类和一个attrs.xml，也可以在[bintray.com/percent-support-extends][3] 下载相关文件。\n            \n            下面看几个具体的示例。\n            \n            * * *\n            \n            ### \u0026lt;a name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;三 具体的示例 {#三-具体的示例}\n            \n            #### \u0026lt;a name=\u0026quot;t3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;Demo 1 {#demo-1}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20150706001314859\"\u003e\u003c/p\u003e","title":"Android 增强版百分比布局库 为了适配而扩展"},{"content":"StrictMode类是Android 2.3 （API 9）引入的一个工具类，可以用来帮助开发者发现代码中的一些不规范的问题。比如，如果你在UI线程中进行了网络或者磁盘操作，StrictMode就会通过Log（logcat ）或者对话框的方式把信息提示给你，因为让你的UI线程处理这里操作会被认为是不规范的做法，可能会让你的应用变得比较卡顿。\n官网文档：http://developer.android.com/reference/android/os/StrictMode.html\n如何启用 StrictMode 我们通常在 Activity 或者自定义的Application类中启动 StrictMode，代码如下：\n``` ` \u0026lt;span class=\"kd\"\u003epublic\u0026lt;/span\u003e \u0026lt;span class=\"kt\"\u003evoid\u0026lt;/span\u003e \u0026lt;span class=\"nf\"\u003eonCreate\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e{\u0026lt;/span\u003e \u0026lt;span class=\"k\"\u003eif\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e(\u0026lt;/span\u003e\u0026lt;span class=\"n\"\u003eDEVELOPER_MODE\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e)\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e{\u0026lt;/span\u003e \u0026lt;span class=\"n\"\u003eStrictMode\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003esetThreadPolicy\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e(\u0026lt;/span\u003e\u0026lt;span class=\"k\"\u003enew\u0026lt;/span\u003e \u0026lt;span class=\"n\"\u003eStrictMode\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003eThreadPolicy\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003eBuilder\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003edetectDiskReads\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003edetectDiskWrites\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003edetectNetwork\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e \u0026lt;span class=\"c1\"\u003e// or .detectAll() for all detectable problems\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003epenaltyLog\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003ebuild\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e());\u0026lt;/span\u003e \u0026lt;span class=\"n\"\u003eStrictMode\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003esetVmPolicy\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e(\u0026lt;/span\u003e\u0026lt;span class=\"k\"\u003enew\u0026lt;/span\u003e \u0026lt;span class=\"n\"\u003eStrictMode\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003eVmPolicy\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003eBuilder\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003edetectLeakedSqlLiteObjects\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003edetectLeakedClosableObjects\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003epenaltyLog\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003epenaltyDeath\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003ebuild\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e());\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e}\u0026lt;/span\u003e \u0026lt;span class=\"kd\"\u003esuper\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003eonCreate\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e();\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e}\u0026lt;/span\u003e ` ``` **注意：**我们只需要在app的开发版本下使用 StrictMode，线上版本避免使用 StrictMode，随意需要通过 诸如 DEVELOPER_MODE 这样的配置变量来进行控制。\n下面我们举几个例子来说明 StrictMode 是如何发挥作用的。\n代码1：\n``` `\u0026lt;span class=\"kd\"\u003epublic\u0026lt;/span\u003e \u0026lt;span class=\"kd\"\u003eclass\u0026lt;/span\u003e \u0026lt;span class=\"nc\"\u003eActivitySimple\u0026lt;/span\u003e \u0026lt;span class=\"kd\"\u003eextends\u0026lt;/span\u003e \u0026lt;span class=\"n\"\u003eActivity\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e{\u0026lt;/span\u003e \u0026amp;lt;span class=\u0026quot;nd\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Bundle\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;setContentView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;layout\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;activity_main\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;StrictMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;setThreadPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;ThreadPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;Builder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;detectAll\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;penaltyDialog\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;//弹出违规提示对话框\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;penaltyLog\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;//在Logcat 中打印违规异常信息\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;build\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;testNetwork\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;testNetwork\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;try\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;URL\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;url\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;URL\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;http://www.baidu.com\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;HttpURLConnection\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;conn\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;HttpURLConnection\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;url\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;openConnection\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;conn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;connect\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;BufferedReader\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;reader\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;BufferedReader\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;InputStreamReader\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;conn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getInputStream\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()));\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;String\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;lines\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;StringBuffer\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;sb\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;StringBuffer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;while\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;((\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;lines\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;reader\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;readLine\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;!=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;sb\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;append\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;lines\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;catch\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Exception\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;printStackTrace\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt; `\n\u0026lt;/div\u0026gt; 在这里例子中，我们在主线程（UI线程）中执行了网络请求，ThreadPolicy 策略中的 `detectAll()`方法 包含而来对这类违规操作的检查，同时我们通过`penaltyDialog()` 和 `penaltyLog()` 两个方法将违规信息提示给开发者。 在运行这段代码是，我们会看到下图中的对话框提示： ![](http://android-performance.com/images/android-strict-mode/dialog.png) 在LogCat 中我们会看到这样的日志信息： \u0026hellip; D/StrictMode(26365): StrictMode policy violation; ~duration=58 ms: android.os.StrictMode$StrictModeNetworkViolation: policy=63 violation=4 \u0026hellip; D/StrictMode(26365): at android.os.StrictModeAndroidBlockGuardPolicy.onNetwork(StrictMode.java:1134) \u0026hellip; D/StrictMode(26365): at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:163) \u0026hellip; D/StrictMode(26365): at libcore.io.IoBridge.recvfrom(IoBridge.java:557) \u0026hellip; D/StrictMode(26365): at java.net.PlainSocketImpl.read(PlainSocketImpl.java:490) \u0026hellip; D/StrictMode(26365): at java.net.PlainSocketImpl.access000(PlainSocketImpl.java:46) \u0026hellip; （后面的部分省略）\n# StrictMode 详解 {#tocAnchor-1-2} StrictMode 通过策略方式来让你自定义需要检查哪方面的问题。 主要有两中策略，一个时线程方策略（[ThreadPolicy][1]），一个是VM方面的策略（[VmPolicy][2]）。 * ThreadPolicy 主要用于发现在UI线程中是否有读写磁盘的操作，是否有网络操作，以及检查UI线程中调用的自定义代码是否执行得比较慢。 * VmPolicy，主要用于发现内存问题，比如 Activity内存泄露， SQL 对象内存泄露， 资源未释放，能够限定某个类的最大对象数。 ## ThreadPolicy 详解 {#tocAnchor-1-2-1} [StrictMode.ThreadPolicy.Builder][3] 主要方法如下： * detectNetwork() 用于检查UI线程中是否有网络请求操作，上面的代码的就是网络请求违规的问题。 * detectDiskReads() 和 detectDiskReads() 是磁盘读写检查，触发时会打印出如下日志（以 detectDiskReads() 为例）： ``` ... D/StrictMode(27429): StrictMode policy violation; ~duration=33 ms: android.os.StrictMode\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;StrictModeDiskReadViolation: policy=31 violation=2 ... D/StrictMode(27429): at android.os.StrictMode\u0026lt;/span\u0026gt;AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1118) ... D/StrictMode(27429): at libcore.io.BlockGuardOs.open(BlockGuardOs.java:106) ... D/StrictMode(27429): at java.io.File.createNewFile(File.java:941) ... D/StrictMode(27429): at com.ap.teststrictmode.ActivityTestDisk.testWriteDisk(ActivityTestDisk.java:51) ... D/StrictMode(27429): at com.ap.teststrictmode.ActivityTestDisk.onCreate(ActivityTestDisk.java:40) ... D/StrictMode(27429): at android.app.Activity.performCreate(Activity.java:5122) ... D/StrictMode(27429): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1081) ... D/StrictMode(27429): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2270) ... （后面的部分省略） detectCustomSlowCalls() 主要用于帮助开发者发现UI线程调用的那些方法执行得比较慢，要和 StrictMode.noteSlowCall 配合使用，StrictMode.noteSlowCall 只有通过 StrictMode.noteSlowCall用来标记“可能会”执行比较慢的方法，只有标记过的方法才能被检测到，日志中会记录方法的执行时间（比如 ~duration=2019 ms）。看下面的例子：\n代码2： ``` `\u0026lt;span class=\"kd\"\u003epublic\u0026lt;/span\u003e \u0026lt;span class=\"kd\"\u003eclass\u0026lt;/span\u003e \u0026lt;span class=\"nc\"\u003eActivityTestDetectCustomSlowCalls\u0026lt;/span\u003e \u0026lt;span class=\"kd\"\u003eextends\u0026lt;/span\u003e \u0026lt;span class=\"n\"\u003eActivity\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e{\u0026lt;/span\u003e` ``` \u0026lt;span class=\u0026quot;kd\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;textView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kc\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kd\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kd\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kt\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;isStrictMode\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kc\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nd\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kd\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kt\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nf\u0026quot;\u0026gt;onCreate\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;Bundle\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;savedInstanceState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kd\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;onCreate\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;savedInstanceState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;setContentView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;layout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;activity*main*\u0026lt;/span\u0026gt;*\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;textView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;findViewById\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;text\u0026lt;/span\u0026gt;*view\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;textView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;setText\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026amp;#8220;In ActivityTestDetectCustomSlowCalls\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;(!\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;isStrictMode\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;){\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;StrictMode\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;setThreadPolicy\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;ThreadPolicy\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;Builder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;detectCustomSlowCalls\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;penaltyLog\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;build\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;isStrictMode\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kc\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;slowCall*1*\u0026lt;/span\u0026gt;*\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;k\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;slowCall\u0026lt;/span\u0026gt;*2\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;cm\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt;* \u0026lt;span class=\u0026quot;cm\u0026quot;\u0026gt; * 没有标记的方法\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;cm\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kd\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kt\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nf\u0026quot;\u0026gt;slowCall_1\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;(){\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;c1\u0026quot;\u0026gt;//用来标记潜在执行比较慢的方法\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;n\u0026quot;\u0026gt;SystemClock\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;sleep\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;mi\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt; * \u0026lt;span class=\u0026quot;mi\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; `\u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;/\u0026amp;lt;/span\u0026gt;\u0026amp;lt;strong\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt; * 标记过的方法\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt; \u0026amp;lt;em\u0026gt;/\u0026amp;lt;/em\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;em\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;slowCall_2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(){\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;//用来标记潜在执行比较慢的方法\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;StrictMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;noteSlowCall\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;slowCall 2\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;SystemClock\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;sleep\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;mi\u0026quot;\u0026gt;1000\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/em\u0026gt; \u0026amp;lt;span class=\u0026quot;mi\u0026quot;\u0026gt;2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/strong\u0026gt;` \u0026lt;/div\u0026gt; ** 在logcat 中我们只能看到和方法 `slowCall_2()`（因为通过`StrictMode.noteSlowCall()`标记过）相关的日志： **\n``` **\u0026hellip;: D/StrictMode(1349): StrictMode policy violation; ~duration=2019 ms: android.os.StrictModeStrictModeCustomViolation: policy=24 violation=8 msg=slowCall 2 \u0026hellip;: D/StrictMode(1349): at android.os.StrictModeAndroidBlockGuardPolicy.onCustomSlowCall(StrictMode.java:1105) \u0026hellip;: D/StrictMode(1349): at android.os.StrictMode.noteSlowCall(StrictMode.java:1903) \u0026hellip;: D/StrictMode(1349): at com.ap.teststrictmode.ActivityTestDetectCustomSlowCalls.slowCall_2(ActivityTestDetectCustomSlowCalls.java:52) \u0026hellip;: D/StrictMode(1349): at com.ap.teststrictmode.ActivityTestDetectCustomSlowCalls.onCreate(ActivityTestDetectCustomSlowCalls.java:35) \u0026hellip;: D/StrictMode(1349): at android.app.Activity.performCreate(Activity.java:5122) \u0026hellip;: D/StrictMode(1349): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1081) \u0026hellip;: D/StrictMode(1349): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2270) \u0026hellip;: D/StrictMode(1349): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2358) \u0026hellip;: D/StrictMode(1349): at android.app.ActivityThread.access600(ActivityThread.java:156) \u0026hellip;: D/StrictMode(1349): at android.app.ActivityThreadH.handleMessage(ActivityThread.java:1340) \u0026hellip;: D/StrictMode(1349): at android.os.Handler.dispatchMessage(Handler.java:99) \u0026hellip;: D/StrictMode(1349): at android.os.Looper.loop(Looper.java:153) \u0026hellip; （后面的部分省略）\n当然你也可以在其他线程中使用 detectCustomSlowCalls()，但是没有什么实际意义，也看不到方法执行时间，比如： \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nc\u0026#34;\u0026gt;ActivityTestDetectCustomSlowCalls\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Activity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;TextView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;textView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kc\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nd\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Bundle\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;setContentView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;layout\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;activity_main\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;textView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;TextView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;findViewById\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;id\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;text_view\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;textView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;setText\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;In ActivityTestDetectCustomSlowCalls\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34;\u0026gt;Thread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(){\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34;\u0026gt;run\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;StrictMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;setThreadPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;ThreadPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;Builder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;detectCustomSlowCalls\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;penaltyLog\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;build\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;slowCallInCustomThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;};\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34;\u0026gt;slowCallInCustomThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(){\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;c1\u0026#34;\u0026gt;//用来标记潜在执行比较慢的方法\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;StrictMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;noteSlowCall\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;slowCallInCustomThread\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;SystemClock\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;sleep\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;1000\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;*\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;start\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;();;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; ` \u0026lt;/div\u0026gt; 日志输出如下： ``` \u0026hellip;: D/StrictMode(2418): StrictMode policy violation: android.os.StrictModeStrictModeCustomViolation: policy=24 violation=8 msg=slowCallInCustomThread \u0026hellip;: D/StrictMode(2418): at android.os.StrictModeAndroidBlockGuardPolicy.onCustomSlowCall(StrictMode.java:1105) \u0026hellip;: D/StrictMode(2418): at android.os.StrictMode.noteSlowCall(StrictMode.java:1903) \u0026hellip;: D/StrictMode(2418): at com.ap.teststrictmode.ActivityTestDetectCustomSlowCalls1.slowCallInCustomThread(ActivityTestDetectCustomSlowCalls.java:35) \u0026hellip;: D/StrictMode(2418): at com.ap.teststrictmode.ActivityTestDetectCustomSlowCalls1.run(ActivityTestDetectCustomSlowCalls.java:30) \u0026hellip; （后面的部分省略）\n* penaltyDeath()，当触发违规条件时，直接Crash掉当前应用程序。 * penaltyDeathOnNetwork()，当触发网络违规时，Crash掉当前应用程序。 * penaltyDialog()，触发违规时，显示对违规信息对话框。 * penaltyFlashScreen()，会造成屏幕闪烁，不过一般的设备可能没有这个功能。 * penaltyDropBox()，将违规信息记录到 dropbox 系统日志目录中（/data/system/dropbox），你可以通过如下命令进行插件： ``` *adb shell dumpsys dropbox data*app*strictmode --print* 会得到如下的信息： ``` 2014-05-04 14:56:32 dataappstrictmode (text, 2627 bytes) Process: com.ap.teststrictmode Flags: 0x40a8be46 Package: com.ap.teststrictmode v1 (1.0) Build: Xiaomi/pisces/pisces:4.2.1/JOP40D/JXCCNBA13.0:user/release-keys System-App: false Uptime-Millis: 66679049 Loop-Violation-Number: 10 Duration-Millis: 24 android.os.StrictModeStrictModeNetworkViolation: policy=191 violation=4 at android.os.StrictModeAndroidBlockGuardPolicy.onNetwork(StrictMode.java:1136) at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:163) at libcore.io.IoBridge.recvfrom(IoBridge.java:513) at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488) at java.net.PlainSocketImpl.access000(PlainSocketImpl.java:46) at java.net.PlainSocketImplPlainSocketInputStream.read(PlainSocketImpl.java:240) at java.io.InputStream.read(InputStream.java:163) at java.io.BufferedInputStream.fillbuf(BufferedInputStream.java:142) at java.io.BufferedInputStream.read(BufferedInputStream.java:227) at libcore.io.Streams.readAsciiLine(Streams.java:201) at libcore.net.http.ChunkedInputStream.readChunkSize(ChunkedInputStream.java:77) at libcore.net.http.ChunkedInputStream.read(ChunkedInputStream.java:68) at java.io.InputStream.read(InputStream.java:163) at java.util.zip.InflaterInputStream.fill(InflaterInputStream.java:200) at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:154) at java.util.zip.GZIPInputStream.read(GZIPInputStream.java:167) \u0026hellip;\n* permitCustomSlowCalls()、permitDiskReads ()、permitDiskWrites()、permitNetwork： 如果你想关闭某一项检测，可以使用对应的permit*方法。 ## VMPolicy 详解 {#tocAnchor-1-2-2} * detectActivityLeaks() 用户检查 Activity 的内存泄露情况，比如下面的代码： \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nc\u0026#34;\u0026gt;ActivityTestActivityLeaks\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Activity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;isStrictMode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kc\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nd\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Bundle\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;setContentView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;layout\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;activity_main\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(!\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;isStrictMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;){\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;StrictMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;setVmPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;VmPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;Builder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;detectActivityLeaks\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;penaltyLog\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;build\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;isStrictMode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kc\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34;\u0026gt;Thread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nd\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34;\u0026gt;run\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;while\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kc\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;SystemClock\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;sleep\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;1000\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;start\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; ` \u0026lt;/div\u0026gt; 我们反复旋转屏幕就会输出如下信息（重点在 instances=4; limit=1 这一行）： ``` \u0026hellip;: E/StrictMode(4784): class com.ap.teststrictmode.ActivityTestActivityLeaks; instances=4; limit=1 \u0026hellip;: E/StrictMode(4784): android.os.StrictMode$InstanceCountViolation: class com.ap.teststrictmode.ActivityTestActivityLeaks; instances=4; limit=1 \u0026hellip;: E/StrictMode(4784): at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)\n这时因为，我们在Activity中创建了一个Thread匿名内部类，而匿名内部类隐式持有外部类的引用。而每次旋转屏幕是，Android会新创建一个Activity，而原来的Activity实例又被我们启动的匿名内部类线程持有，所以不会释放，从日志上看，当先系统中该Activty有4个实例，而限制是只能创建1各实例。我们不断翻转屏幕，instances 的个数还会持续增加。 * detectLeakedClosableObjects() 和 detectLeakedSqlLiteObjects()，资源没有正确关闭时回触发，比如下面的代码： \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; ``` ` \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nc\u0026#34;\u0026gt;MainActivityTestDetectLeakedClosableObjects\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Activity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;isStrictMode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kc\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nd\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Bundle\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;setContentView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;layout\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;activity_main\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(!\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;isStrictMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;){\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;StrictMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;setVmPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;VmPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;Builder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;detectLeakedClosableObjects\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;penaltyLog\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;build\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;isStrictMode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kc\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;newxmlfile\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Environment\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;getExternalStorageDirectory\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(),\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;aaa.txt\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;newxmlfile\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;createNewFile\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;FileWriter\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;fw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;FileWriter\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;newxmlfile\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;fw\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;write\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;aaaaaaaaaaa\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;c1\u0026#34;\u0026gt;//fw.close(); 我们在这里故意没有关闭 fw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;IOException\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;printStackTrace\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; ` \u0026lt;/div\u0026gt; 会产生如下异常信息： ``` \u0026hellip; E/StrictMode(22056): A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. \u0026hellip; E/StrictMode(22056): java.lang.Throwable: Explicit termination method \u0026lsquo;close\u0026rsquo; not called \u0026hellip; E/StrictMode(22056): at dalvik.system.CloseGuard.open(CloseGuard.java:184) \u0026hellip; E/StrictMode(22056): at java.io.FileOutputStream.(FileOutputStream.java:90) \u0026hellip; E/StrictMode(22056): at java.io.FileOutputStream.(FileOutputStream.java:73) \u0026hellip; E/StrictMode(22056): at java.io.FileWriter.(FileWriter.java:42) \u0026hellip; E/StrictMode(22056): at com.ap.teststrictmode.MainActivityTestDetectLeakedClosableObjects.onCreate(MainActivityTestDetectLeakedClosableObjects.java:44) \u0026hellip; E/StrictMode(22056): at android.app.Activity.performCreate(Activity.java:5122) \u0026hellip; E/StrictMode(22056): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1081) \u0026hellip; E/StrictMode(22056): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2270) \u0026hellip; E/StrictMode(22056): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2358) \u0026hellip; E/StrictMode(22056): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3865) （后面的省略）\ndetectLeakedSqlLiteObjects() 和 detectLeakedClosableObjects()的用法类似，只不过是用来检查 SQLiteCursor 或者 其他 SQLite 对象是否被正确关闭。 * detectLeakedRegistrationObjects() 用来检查 BroadcastReceiver 或者 ServiceConnection 注册类对象是否被正确释放，看下面的代码 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nc\u0026#34;\u0026gt;ActivityTestLeakedRegistrationObjects\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Activity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;TextView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;textView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kc\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;isStrictMode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kc\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;MyReceiver\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;receiver\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kc\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nd\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Bundle\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;setContentView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;layout\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;activity_main\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;textView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;TextView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;findViewById\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;id\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;text_view\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;textView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;setText\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;In ActivityTestLeakedRegistrationObjects\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(!\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;isStrictMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;){\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;StrictMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;setVmPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;VmPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;Builder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;detectLeakedRegistrationObjects\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;penaltyLog\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;build\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;isStrictMode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kc\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;receiver\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;MyReceiver\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;IntentFilter\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;filter\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;IntentFilter\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;filter\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;addAction\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;android.intent.action.MY_BROADCAST\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;registerReceiver\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;receiver\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;filter\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nd\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34;\u0026gt;onDestroy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;onDestroy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; ` \u0026lt;/div\u0026gt; 输入信息如下： ``` \u0026hellip;: E/ActivityThread(24442): Activity com.ap.teststrictmode.ActivityTestLeakedRegistrationObjects has leaked IntentReceiver com.ap.teststrictmode.MyReceiver@41f1f128 that was originally registered here. Are you missing a call to unregisterReceiver()? \u0026hellip;: E/ActivityThread(24442): android.app.IntentReceiverLeaked: Activity com.ap.teststrictmode.ActivityTestLeakedRegistrationObjects has leaked IntentReceiver com.ap.teststrictmode.MyReceiver@41f1f128 that was originally registered here. Are you missing a call to unregisterReceiver()? \u0026hellip;: E/ActivityThread(24442): at android.app.LoadedApk$ReceiverDispatcher.(LoadedApk.java:825) \u0026hellip;: E/ActivityThread(24442): at android.app.LoadedApk.getReceiverDispatcher(LoadedApk.java:596) \u0026hellip;: E/ActivityThread(24442): at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1388) \u0026hellip;: E/ActivityThread(24442): at android.app.ContextImpl.registerReceiver(ContextImpl.java:1368) \u0026hellip;\n正确做法应该是在 onDestroy() 方法中将 receiver 释放掉： \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; ``` ` \u0026amp;lt;span class=\u0026#34;nd\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34;\u0026gt;onDestroy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;unregisterReceiver\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;receiver\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;onDestroy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; ` \u0026lt;/div\u0026gt; * setClassInstanceLimit()，设置某个类的同时处于内存中的实例上限，可以协助检查内存泄露。比如下面的代码： \u0026lt;div class=\u0026quot;highlight\u0026quot;\u0026gt; ``` `\u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;nc\u0026rdquo;\u0026gt;ActivityTestObjectLimit\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Activity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;nc\u0026rdquo;\u0026gt;MyClass\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{}\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;isStrictMode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;false\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;List\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;MyClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;classList\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;ArrayList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;ActivityTestObjectLimit\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;MyClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nd\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Bundle\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;setContentView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;layout\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;activity_main\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(!\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;isStrictMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;){\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;StrictMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;setVmPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;VmPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;Builder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;setClassInstanceLimit\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;MyClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;class\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;mi\u0026quot;\u0026gt;2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;penaltyLog\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;build\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;isStrictMode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;true\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;classList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;add\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;MyClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;classList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;add\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;MyClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;classList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;add\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;MyClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;classList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;add\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;MyClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;classList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;add\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;MyClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;classList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;add\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;MyClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;classList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;add\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;MyClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;classList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;add\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;MyClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt; `\n\u0026lt;/div\u0026gt; 日志信息如下： ``` ...: E/StrictMode(27681): class com.ap.teststrictmode.ActivityTestObjectLimit\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;MyClass; instances=72; limit=2 ...: E/StrictMode(27681): android.os.StrictMode\u0026lt;/span\u0026gt;InstanceCountViolation: class com.ap.teststrictmode.ActivityTestObjectLimit$MyClass; instances=8; limit=2 ...: E/StrictMode(27681): at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1) 注意：上面的异常一般都在GC之后抛出，如果测试的时候没有现象，可以多翻转几次屏幕，或者通过DDMS工具手动触发一下。 ","permalink":"https://blog.zdltech.com/posts/strictmode-%E8%AF%A6%E8%A7%A3/","summary":"\u003cp\u003eStrictMode类是Android 2.3 （API 9）引入的一个工具类，可以用来帮助开发者发现代码中的一些不规范的问题。比如，如果你在UI线程中进行了网络或者磁盘操作，StrictMode就会通过Log（logcat ）或者对话框的方式把信息提示给你，因为让你的UI线程处理这里操作会被认为是不规范的做法，可能会让你的应用变得比较卡顿。\u003c/p\u003e\n\u003cp\u003e官网文档：\u003ca href=\"http://developer.android.com/reference/android/os/StrictMode.html\"\u003ehttp://developer.android.com/reference/android/os/StrictMode.html\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"tocAnchor-1-1\"\u003e如何启用 StrictMode\u003c/h1\u003e\n\u003cp\u003e我们通常在 Activity 或者自定义的Application类中启动 StrictMode，代码如下：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\n  ```\n` \u0026lt;span class=\"kd\"\u003epublic\u0026lt;/span\u003e \u0026lt;span class=\"kt\"\u003evoid\u0026lt;/span\u003e \u0026lt;span class=\"nf\"\u003eonCreate\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e{\u0026lt;/span\u003e\n     \u0026lt;span class=\"k\"\u003eif\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e(\u0026lt;/span\u003e\u0026lt;span class=\"n\"\u003eDEVELOPER_MODE\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e)\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e{\u0026lt;/span\u003e\n         \u0026lt;span class=\"n\"\u003eStrictMode\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003esetThreadPolicy\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e(\u0026lt;/span\u003e\u0026lt;span class=\"k\"\u003enew\u0026lt;/span\u003e \u0026lt;span class=\"n\"\u003eStrictMode\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003eThreadPolicy\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003eBuilder\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e\n                 \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003edetectDiskReads\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e\n                 \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003edetectDiskWrites\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e\n                 \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003edetectNetwork\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e   \u0026lt;span class=\"c1\"\u003e// or .detectAll() for all detectable problems\u0026lt;/span\u003e\n                 \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003epenaltyLog\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e\n                 \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003ebuild\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e());\u0026lt;/span\u003e\n         \u0026lt;span class=\"n\"\u003eStrictMode\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003esetVmPolicy\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e(\u0026lt;/span\u003e\u0026lt;span class=\"k\"\u003enew\u0026lt;/span\u003e \u0026lt;span class=\"n\"\u003eStrictMode\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003eVmPolicy\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003eBuilder\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e\n                 \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003edetectLeakedSqlLiteObjects\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e\n                 \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003edetectLeakedClosableObjects\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e\n                 \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003epenaltyLog\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e\n                 \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003epenaltyDeath\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e()\u0026lt;/span\u003e\n                 \u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003ebuild\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e());\u0026lt;/span\u003e\n     \u0026lt;span class=\"o\"\u003e}\u0026lt;/span\u003e\n     \u0026lt;span class=\"kd\"\u003esuper\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003eonCreate\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e();\u0026lt;/span\u003e\n \u0026lt;span class=\"o\"\u003e}\u0026lt;/span\u003e\n`\n```\n\u003c/div\u003e\n\u003cp\u003e**注意：**我们只需要在app的开发版本下使用 StrictMode，线上版本避免使用 StrictMode，随意需要通过 诸如 DEVELOPER_MODE 这样的配置变量来进行控制。\u003c/p\u003e\n\u003cp\u003e下面我们举几个例子来说明 StrictMode 是如何发挥作用的。\u003c/p\u003e\n\u003cp\u003e代码1：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\n  ```\n`\u0026lt;span class=\"kd\"\u003epublic\u0026lt;/span\u003e \u0026lt;span class=\"kd\"\u003eclass\u0026lt;/span\u003e \u0026lt;span class=\"nc\"\u003eActivitySimple\u0026lt;/span\u003e \u0026lt;span class=\"kd\"\u003eextends\u0026lt;/span\u003e \u0026lt;span class=\"n\"\u003eActivity\u0026lt;/span\u003e \u0026lt;span class=\"o\"\u003e{\u0026lt;/span\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026amp;lt;span class=\u0026quot;nd\u0026quot;\u0026gt;@Override\u0026amp;lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Bundle\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt;\n    \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt;\n    \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;setContentView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;layout\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;activity_main\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt;\n\n    \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;StrictMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;setThreadPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;ThreadPolicy\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;Builder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt;\n            \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;detectAll\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt;\n            \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;penaltyDialog\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;//弹出违规提示对话框\u0026amp;lt;/span\u0026gt;\n            \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;penaltyLog\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;//在Logcat 中打印违规异常信息\u0026amp;lt;/span\u0026gt;\n            \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;build\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt;\n    \n    \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;testNetwork\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n\n\n\u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;testNetwork\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt;\n    \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;try\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt;\n        \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;URL\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;url\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;URL\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;http://www.baidu.com\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt;\n        \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;HttpURLConnection\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;conn\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;HttpURLConnection\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;url\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;openConnection\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt;\n        \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;conn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;connect\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt;\n        \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;BufferedReader\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;reader\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;BufferedReader\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;InputStreamReader\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\n                \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;conn\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getInputStream\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()));\u0026amp;lt;/span\u0026gt;\n        \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;String\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;lines\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n        \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;StringBuffer\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;sb\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;StringBuffer\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt;\n        \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;while\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;((\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;lines\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;reader\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;readLine\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;())\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;!=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt;\n            \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;sb\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;append\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;lines\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt;\n        \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n    \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;catch\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Exception\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt;\n        \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;printStackTrace\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt;\n    \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt;\n`\u003c/p\u003e","title":"StrictMode 详解"},{"content":"摘要 转载：http://kymjs.com/code/2015/12/12/01\n本文总共分三部分，从源码角度分析了 EventBus 库。以及介绍了其内部实现注册、发送、响应、取消注册的原理。\nEventBus 是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent, Handler, BroadCast 在 Fragment，Activity，Service，线程之间传递消息.优点是开销小，使用方便,可以很大程度上降低它们之间的耦合，使得我们的代码更加简洁，耦合性更低，提升我们的代码质量。\n类似的库还有 Otto ,今天就带大家一起研读 EventBus 的源码.\n在写这篇文章之前，我已经将本文相关的中文注释代码上传到了GitHub：https://github.com/kymjs/EventBus\n基础用法 在读代码之前,首先你得了解它的基本用法.如果你已经能够很熟练的使用EventBus等事件总线库了,那么你可以跳过本节.\n首先引入依赖包,查看GitHub主页的说明: https://github.com/greenrobot/EventBus\n在Gradle文件加入\ncompile 'de.greenrobot:eventbus:2.4.0'\n用法与广播相同,且比广播更简单:\n注册订阅者 首先你需要注册一个事件订阅者,为了方便理解你可以把他当成广播的广播接收者 你可以在任何一个类中使用如下代码注册以及解除注册\n``` `\u0026lt;span class=\"c1\"\u003e\u0026lt;span class=\"hljs-comment\"\u003e//把当前类注册为订阅者(接收者)\u0026lt;/span\u003e\u0026lt;/span\u003e \u0026lt;span class=\"n\"\u003eEventBus\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003egetDefault\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e().\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003eregister\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e(\u0026lt;/span\u003e\u0026lt;span class=\"k\"\u003e\u0026lt;span class=\"hljs-keyword\"\u003ethis\u0026lt;/span\u003e\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e);\u0026lt;/span\u003e \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//解除注册当前类(同广播一样,一定要调用,否则会内存泄露)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;EventBus\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;getDefault\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;().\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;unregister\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt;`\n\u0026lt;/div\u0026gt; 注册了订阅者以后,我们需要创建一个回调方法`onEvent`,当我们订阅的事件发送的时候就会回调它 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//其实命名不一定必须是onEvent(),但那属于高级用法了,这里我们只说最简单的\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onEvent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;Object\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{}\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; #### 事件发送 {#section-2} 当有了订阅者以后,我们的代码已经可以工作了.但是此时的代码是没有意义的,我们订阅的事件还没有发生. 就像广播需要一个`sendBroadcast()`，EventBus需要`post(event)` 你可以在任何一个类中使用如下代码发送事件： \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; * 这里的event类型必须和上面我们onEvent()方法的参数类型一致\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; * (子父类关系也不行,必须是相同类型，原因我们下面看源码)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; */\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;EventBus\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getDefault\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;().\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;post\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; 至此,EventBus就可以正常工作了. ## 进入源码世界 {#section-3} #### 入口类EventBus类 {#eventbus} 我们从使用的流程来,首先看`EventBus#getDefault()` \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;static\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;EventBus\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;getDefault\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;defaultInstance\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;==\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;synchronized\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;EventBus\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;class\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;defaultInstance\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;==\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;defaultInstance\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;EventBus\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;defaultInstance\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; 只是简单的维护单例,调用构造方法,再看构造方法,调用重载的构造方法,重载的构造方法又需要一个`EventBusBuilder`对象 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; `\u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;nf\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;EventBus\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;()\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;DEFAULT_BUILDER\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;EventBus\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;EventBusBuilder\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;builder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt;`\n\u0026lt;/div\u0026gt; #### EventBusBuilder类 {#eventbusbuilder} 看名字就知道,这个类是用来创建`EventBus`对象的. ![开源实验室：图1](http://kymjs.com/images/blog_image/20151211_1.png) Builder类提供了这么多个可选的配置属性,这里变量含义大家直接看我的注释,就不多作解释了 我们主要来看最终的建造方法 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; `\u0026lt;span class=\u0026ldquo;cm\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-javadoc\u0026rdquo;\u0026gt;/**\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;cm\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-javadoc\u0026rdquo;\u0026gt; * 根据参数创建对象,并赋值给EventBus.defaultInstance, 必须在默认的eventbus对象使用以前调用\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;cm\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-javadoc\u0026rdquo;\u0026gt; *\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;cm\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-javadoc\u0026rdquo;\u0026gt; *\u0026lt;span class=\u0026ldquo;hljs-javadoctag\u0026rdquo;\u0026gt; @throws\u0026lt;/span\u0026gt; EventBusException if there\u0026rsquo;s already a default EventBus instance in place\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;cm\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-javadoc\u0026rdquo;\u0026gt; */\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;EventBus\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;nf\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;installDefaultEventBus\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;()\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;synchronized\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;EventBus\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;EventBus\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;defaultInstance\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;!=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kc\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;throw\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;nf\u0026rdquo;\u0026gt;EventBusException\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;s\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;Default instance already exists.\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;+\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;s\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rdquo; It may be only set once before it\u0026rsquo;s used the first time to ensure \u0026ldquo;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;+\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;s\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;consistent behavior.\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;EventBus\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;defaultInstance\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;build\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;return\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;EventBus\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;defaultInstance\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;cm\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-javadoc\u0026rdquo;\u0026gt;/**\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;cm\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-javadoc\u0026rdquo;\u0026gt; * 根据参数创建对象\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;cm\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-javadoc\u0026rdquo;\u0026gt; */\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;EventBus\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;nf\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;build\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;()\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;return\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;nf\u0026rdquo;\u0026gt;EventBus\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt;`\n\u0026lt;/div\u0026gt; EventBusBuilder类提供了两种建造方法,还记得之前的getDefault()方法吗,维护了一个单例对象,`installDefaultEventBus()` 方法建造的EventBus对象最终会赋值给那个单例对象,但是有一个前提就是我们之前并没有创建过那个单例对象. 这里大家思考一下，为什么如果`EventBus.defaultInstance`不为`null`以后程序要抛出异常？咱们之后说答案。 第二个方法就是默认的建造者方法了. 再回到我们的`EventBus`构造方法,根据提供的建造者初始化了一大堆属性 ![图3](http://kymjs.com/images/blog_image/20151211_3.png) 我们继续看这些初始化的字段. #### 三个Poster类 {#poster} 先是一大堆Map,看不懂,跳过去,我们先来看这三个Poster，需要说明的一点就是：Poster只负责处理粘滞事件，原因我们之后看代码。 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;final\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;HandlerPoster\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;mainThreadPoster\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//前台发送者\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;final\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;BackgroundPoster\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;backgroundPoster\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//后台发送者\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;final\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;AsyncPoster\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;asyncPoster\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//后台发送者(只让队列第一个待订阅者去响应)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; 其实从类名我们就能看出个大概了,就是三个发送事件的方法。 我们来看看他们的内部实现. 这几个Poster的设计可以说是整个EventBus的一个经典部分,越看越想继续多看几遍. 每个Poster中都有一个发送任务队列,`PendingPostQueue queue;` 进到队列里面再看 定义了两个节点,从字面上理解就是队列的头节点和尾节点 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;PendingPost\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;head\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//待发送对象队列头节点\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;PendingPost\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;tail\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//待发送对象队列尾节点\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; 再看这个PendingPost类的实现: \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; `\u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//单例池,复用对象\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;static\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;PendingPost\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;pendingPostPool\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;ArrayList\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;PendingPost\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026gt;();\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Object\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;event\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//事件类型\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Subscription\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscription\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//订阅者\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;PendingPost\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;next\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//队列下一个待发送对象\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;`\n\u0026lt;/div\u0026gt; 首先是提供了一个`池`的设计，类似于我们的线程池，目的是为了减少对象创建的开销，当一个对象不用了，我们可以留着它，下次再需要的时候返回这个保留的而不是再去创建。 再看最后的变量，`PendingPost next` 非常典型的队列设计，队列中每个节点都有一个指向下一个节点的指针(sorry，数据结构用C学的)。 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; * 首先检查复用池中是否有可用,如果有则返回复用,否则返回一个新的\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; *\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @param\u0026amp;lt;/span\u0026gt; subscription 订阅者\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @param\u0026amp;lt;/span\u0026gt; event 订阅事件\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @return\u0026amp;lt;/span\u0026gt; 待发送对象\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; */\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;static\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;PendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;obtainPendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;Subscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;subscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;Object\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;synchronized\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPostPool\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;size\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPostPool\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;size\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;size\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;mi\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;PendingPost\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPostPool\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;remove\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;size\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;-\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;mi\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;subscription\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;next\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;PendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; * 回收一个待发送对象,并加入复用池\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; *\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @param\u0026amp;lt;/span\u0026gt; pendingPost 待回收的待发送对象\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; */\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;static\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;releasePendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;PendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;subscription\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;next\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;synchronized\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPostPool\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 防止池无限增长\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPostPool\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;size\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;mi\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;10000\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPostPool\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;add\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; `obtainPendingPost()`,对池复用的实现，每次新创建的节点尾指针都为 null 。 `releasePendingPost()`，回收pendingPost对象，既然有从池中取，当然需要有存。这里，原作非常细心的加了一次判断，`if (pendingPostPool.size() \u0026lt; 10000)` 其实我觉得10000都很大了，1000就够了，我们一次只可能创建一个pendingPost，如果`ArrayList`里面存了上千条都没有取走，那么肯定是使用出错了。 PendingPost的代码我们就看完了，再回到上一级，队列的设计： 接着是`PendingPostQueue`的入队方法 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;synchronized\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;enqueue\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;PendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;tail\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;!=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;tail\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;next\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;tail\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;head\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;==\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;head\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;tail\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; 首先将当前节点的上一个节点(入队前整个队列的最后一个节点)的尾指针指向当期正在入队的节点(传入的参数pendingPost)，并将队列的尾指针指向自己(自己变成队列的最后一个节点)，这样就完成了入队。 如果是队列的第一个元素(队列之前是空的),那么直接将队列的头尾两个指针都指向自身就行了。 出队也是类似的队列指针操作 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;synchronized\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;PendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;poll\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;PendingPost\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;head\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;head\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;!=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;head\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;head\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;next\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;head\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;==\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;tail\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; 首先将出队前的头节点保留一个临时变量(它就是要出队的节点),拿到这个将要出队的临时变量的下一个节点指针，将出队前的第二个元素(出队后的第一个元素)的赋值为现在队列的头节点，出队完成。 值得提一点的就是，`PendingPostQueue`的所有方法都声明了`synchronized`，这意味着在多线程下它依旧可以正常工作，细想想这也是必须的，对吗？ 再回到上一级，接着是`HandlerPoster`的入队方法`enqueue()`, \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @param\u0026amp;lt;/span\u0026gt; subscription 订阅者\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @param\u0026amp;lt;/span\u0026gt; event 订阅事件\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; */\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;enqueue\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;Subscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;subscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;Object\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;PendingPost\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;PendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;obtainPendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;synchronized\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;queue\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;enqueue\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;pendingPost\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(!\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;handlerActive\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;handlerActive\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;true\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(!\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;sendMessage\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;obtainMessage\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()))\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;throw\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;EventBusException\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;Could not send handler message\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; 入队方法会根据参数创建 待发送对象 pendingPost 并加入队列,如果此时 handleMessage() 没有在运行中,则发送一条空消息让 handleMessage 响应 接着是`handleMessage()`方法 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; `\u0026lt;span class=\u0026ldquo;nd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-annotation\u0026rdquo;\u0026gt;@Override\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kt\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;void\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;nf\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;handleMessage\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;Message\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;msg\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kt\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;boolean\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;rescheduled\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kc\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;false\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;try\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kt\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;long\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;started\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;SystemClock\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;uptimeMillis\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;while\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;kc\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;true\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;PendingPost\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;pendingPost\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;queue\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;poll\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;pendingPost\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kc\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;synchronized\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;// 双重校验,类似单例中的实现\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;pendingPost\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;queue\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;poll\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;pendingPost\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kc\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;handlerActive\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kc\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;false\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;return\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//如果订阅者没有取消注册,则分发消息\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;eventBus\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;invokeSubscriber\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;pendingPost\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt;\n\u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//如果在一定时间内仍然没有发完队列中所有的待发送者,则退出\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;long\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;timeInMethod\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;SystemClock\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;uptimeMillis\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;-\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;started\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;timeInMethod\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;maxMillisInsideHandleMessage\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(!\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;sendMessage\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;obtainMessage\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()))\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;throw\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;EventBusException\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;Could not send handler message\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;rescheduled\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;true\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;finally\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;handlerActive\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;rescheduled\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt;`\n\u0026lt;/div\u0026gt; `handleMessage()`不停的在待发送队列queue中去取消息。 需要说明的是在循环之外有个临时`boolean`变量`rescheduled`,最后是通过这个值去修改了`handlerActive`。而 handlerActive 是用来判断当前queue中是否有正在发送对象的任务，看到上面的入队方法`enqueue()`,如果已经有任务在跑着了，就不需要再去sendMessage()唤起我们的`handleMessage()` 最终通过`eventBus`对象的`invokeSubscriber()`最终发送出去，并回收这个`pendingPost`，让注册了的订阅者去响应(相当于回调),至于这个发送方法,我们之后再看。 看完了HandlePoster类,另外两个异步的发送者实现代码也差不多,唯一的区别就是另外两个是工作在异步,实现的Runnable接口,大家自己类比,这里就不帖代码了. ## Poster工作原理 {#poster-1} 最后我们再来回顾一下`Poster`、`PendingPostQueue`、`PendingPost`这三个类，再看看下面这张图，是不是有种似曾相识的感觉。 ![开源实验室：图4](http://kymjs.com/images/blog_image/20151211_4.png) 啊哈，那是`Handle`、`Message`、`Looper`的工作原理，再看看Poster的 ![开源实验室：图5](http://kymjs.com/images/blog_image/20151211_5.png) 至此，整个EventBus源码的发送接收核心部分已经分析完了。 还记得上面我们留下的那几个问题吗： 1、为什么如果EventBus.defaultInstance不为null以后程序要抛出异常？ 2、Poster只对粘滞事件有效的说明代码在哪。 3、`invokeSubscriber()`最终的发送怎么实现的。 接下来我们继续分析它的注册流程以及粘滞事件的设计(那又是一个经典的地方)。 \u0026amp;nbsp; ## Subscribe流程 {#subscribe} 我们继续来看`EventBus`类，分析完了包含的属性，接下来我们看入口方法`register()` 通过查看源码我们发现，所有的register()方法，最后都会直接或者间接的调用register()方法 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @param\u0026amp;lt;/span\u0026gt; subscriber 订阅者对象\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @param\u0026amp;lt;/span\u0026gt; sticky 是否粘滞\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; *\u0026amp;lt;span class=\u0026quot;hljs-javadoctag\u0026quot;\u0026gt; @param\u0026amp;lt;/span\u0026gt; priority 优先级\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;cm\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt; */\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;synchronized\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;register\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;Object\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;sticky\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;priority\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;List\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;SubscriberMethod\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscriberMethods\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscriberMethodFinder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;findSubscriberMethods\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getClass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;for\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;SubscriberMethod\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscriberMethod\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscriberMethods\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscribe\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscriberMethod\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;sticky\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;priority\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; #### SubscriberMethod类 {#subscribermethod} 出现了一个`SubscriberMethod`类，看看它是干嘛的： 看字面意思是订阅者方法,看看类中的内容，除了复写的equals()和hashCode()就只有这些了。 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; `\u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Method\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;method\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//方法名\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;ThreadMode\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;threadMode\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//工作在哪个线程\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;?\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;eventType\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//参数类型\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;cm\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-javadoc\u0026rdquo;\u0026gt;/** Used for efficient comparison */\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;String\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;methodString\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;synchronized\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kt\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;void\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;nf\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-title\u0026rdquo;\u0026gt;checkMethodString\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-function\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-params\u0026rdquo;\u0026gt;()\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;methodString\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kc\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;// Method.toString has more overhead, just take relevant parts of the method\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;StringBuilder\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;builder\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;nf\u0026rdquo;\u0026gt;StringBuilder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;mi\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;64\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;builder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;append\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;method\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;getDeclaringClass\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;().\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;getName\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;());\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;builder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;append\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;sc\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;#\u0026rsquo;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;).\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;append\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;method\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;getName\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;());\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;builder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;append\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;sc\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;(\u0026rsquo;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;).\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;append\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;eventType\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;getName\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;());\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;methodString\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;builder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;toString\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt;`\n\u0026lt;/div\u0026gt; `ThreadMode`是一个枚举类，是不是应该换成 int 更好呢。 `checkMethodString()`方法就是为了设置变量 methodString 的值，这里new了一个`StringBuilder`，然后又调用了`toString()`返回，是不是应该改成直接`new String(format...)`更好呢？ OK，不管那些细节，看到这里就知道，其实这个类也就是一个封装了的方法名而已。 回到`EventBus#register()`咱们继续. 噢，又遇到了`SubscriberMethodFinder`这又是啥，继续去看。 #### SubscriberMethodFinder类 {#subscribermethodfinder} 从字面理解，就是订阅者方法发现者。 回想一下，我们之前用 EventBus 的时候，需要在注册方法传的那个 this 对象里面写一个 `onEvent()` 方法。没错，`SubscriberMethodFinder`类就是查看传进去的那个 this 对象里面有没有`onEvent()`方法的。怎么做到的？当然是反射。而且这个类用了大量的反射去查找类中方法名。 先看他的变量声明 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; `\u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;static\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;String\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;ON_EVENT_METHOD_NAME\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;s\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;onEvent\u0026rdquo;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;cm\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-javadoc\u0026rdquo;\u0026gt;/**\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;cm\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-javadoc\u0026rdquo;\u0026gt; * 在较新的类文件，编译器可能会添加方法。那些被称为BRIDGE或SYNTHETIC方法。\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;cm\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-javadoc\u0026rdquo;\u0026gt; * EventBus必须忽略两者。有修饰符没有公开，但在Java类文件中有格式定义\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;cm\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-javadoc\u0026rdquo;\u0026gt; */\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;static\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kt\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;BRIDGE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;mh\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;0x40\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;static\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kt\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;SYNTHETIC\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;mh\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;0x1000\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//需要忽略的修饰符\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;static\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kt\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;MODIFIERS_IGNORE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Modifier\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;ABSTRACT\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;|\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Modifier\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;STATIC\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;|\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;BRIDGE\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;|\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;SYNTHETIC\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//key:类名,value:该类中需要相应的方法集合\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;static\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Map\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;SubscriberMethod\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;methodCache\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;HashMap\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;SubscriberMethod\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026gt;\u0026gt;();\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//跳过校验方法的类(即通过构造函数传入的集合)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Map\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;?\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;?\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;skipMethodVerificationForClasses\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt;`\n\u0026lt;/div\u0026gt; 有一句注释 \u0026gt; In newer class files, compilers may add methods. Those are called bridge or synthetic methods. EventBus must ignore both. There modifiers are not public but defined in the Java class file format: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1 翻译过来大概就是说java编译器在编译的时候，会额外添加一些修饰符，然后这些修饰符为了效率应该是被忽略的。 还有一个`skipMethodVerificationForClasses`，看到注释是需要跳过被校验方法的类，校验方法是什么？看看他是干什么的。`findSubscriberMethods()`方法有点长，咱们抽一点看。 跳过上面的那些临时变量，从while循环里开始看： \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Method\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;[]\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methods\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;clazz\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getDeclaredMethods\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;for\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Method\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;method\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methods\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;String\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methodName\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;method\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methodName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;startsWith\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;ON_EVENT_METHOD_NAME\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;))\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;modifiers\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;method\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getModifiers\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//方法的修饰符\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//如果是public,且 不是之前定义要忽略的类型\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;((\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;modifiers\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Modifier\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;PUBLIC\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;!=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;mi\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;\u0026amp;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;modifiers\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;MODIFIERS_IGNORE\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;==\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;mi\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//。。。先不看\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;clazz\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;clazz\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getSuperclass\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; 首先是反射获取到 clazz 的全部方法 methods。 通过对全部的方法遍历，为了效率首先做一次筛选，只关注我们的以 “onEvent” 开头的方法。(现在知道之前在基础用法中我说：其实命名不一定必须是onEvent()的原因了吧，因为只要是onEvent开头的就可以了。) 忽略private类型的，最后如果是公有，并且不是 java编译器 生成的方法名，那么就是我们要的了。 再来看拿到要的方法后是怎么处理的 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Class\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;?\u0026amp;gt;[]\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;parameterTypes\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;method\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getParameterTypes\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//如果只有一个参数\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;parameterTypes\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;length\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;==\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;mi\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;String\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;modifierString\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methodName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;substring\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;ON_EVENT_METHOD_NAME\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;length\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;ThreadMode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;threadMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;modifierString\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;length\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;==\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;mi\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;threadMode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;ThreadMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;PostThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;modifierString\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;equals\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;MainThread\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;threadMode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;ThreadMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;MainThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;modifierString\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;equals\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;BackgroundThread\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;threadMode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;ThreadMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;BackgroundThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;modifierString\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;equals\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;Async\u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;threadMode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;ThreadMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;Async\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;skipMethodVerificationForClasses\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;containsKey\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;clazz\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;))\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;continue\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;throw\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;EventBusException\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;Illegal onEvent method, check \u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;+\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;for typos: \u0026quot;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;+\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;method\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Class\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;eventType\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;parameterTypes\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;[\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;mi\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;];\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methodKeyBuilder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;setLength\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;mi\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methodKeyBuilder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;append\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methodName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methodKeyBuilder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;append\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;sc\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'\u0026amp;gt;'\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;).\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;append\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;eventType\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getName\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;String\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methodKey\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methodKeyBuilder\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;toString\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;eventTypesFound\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;add\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methodKey\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;))\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 方法名,工作在哪个线程,事件类型\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscriberMethods\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;add\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;SubscriberMethod\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;method\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;threadMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;eventType\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;));\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; 还是反射，拿到这个方法的全部参数集合，如果是只有一个参数，再去根据不同的方法名赋予不同的线程模式(其实也就是最后响应的方法是工作在哪个线程)。 这里我们看到，其实`EventBus`不仅仅支持`onEvent()`的回调，它还支持`onEventMainThread()`、`onEventBackgroundThread()`、`onEventAsync()`这三个方法的回调。 一直到最后，我们看到这个方法把所有的方法名集合作为value，类名作为key存入了 methodCache 这个全局静态变量中。意味着，整个库在运行期间所有遍历的方法都会存在这个 map 中，而不必每次都去做耗时的反射取方法了。 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;synchronized\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methodCache\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;methodCache\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;put\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;key\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscriberMethods\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscriberMethods\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; 看了这么久，我们再回到 `EventBus#register()` 方法。这回可以看懂了，就是拿到指定类名的全部订阅方法(以 onEvent 开头的方法)，并对每一个方法调用`subscribe()`。那么再看`subscribe()`方法。 ## 事件的处理与发送subscribe() {#subscribe-1} subscribe()方法接受四个参数，分别为：订阅者封装的对象、响应方法名封装的对象、是否为粘滞事件(可理解为广播)、这条事件的优先级。 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; `\u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//根据传入的响应方法名获取到响应事件(参数类型)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;?\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;eventType\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscriberMethod\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;eventType\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Subscription\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;newSubscription\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;nf\u0026rdquo;\u0026gt;Subscription\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscriber\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscriberMethod\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;priority\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//通过响应事件作为key,并取得这个事件类型将会响应的全部订阅者\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//没个订阅者至少会订阅一个事件,多个订阅者可能订阅同一个事件(多对多)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//key:订阅的事件,value:订阅这个事件的所有订阅者集合\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;CopyOnWriteArrayList\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Subscription\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscriptions\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscriptionsByEventType\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;get\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;eventType\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//根据优先级插入到订阅者集合中\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kt\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;size\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscriptions\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;size\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;for\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;kt\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;i\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;mi\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;0\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;i\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;size\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;i\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;++)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;i\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;size\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;||\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;newSubscription\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;priority\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscriptions\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;get\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;i\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;).\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;priority\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscriptions\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;add\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;i\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;newSubscription\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;break\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//当前订阅者订阅了哪些事件\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;?\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscribedEvents\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;typesBySubscriber\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;get\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscriber\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscribedEvents\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kc\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscribedEvents\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;ArrayList\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Class\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;?\u0026gt;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;typesBySubscriber\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;put\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscriber\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscribedEvents\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//key:订阅者对象,value:这个订阅者订阅的事件集合\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;subscribedEvents\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;add\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;eventType\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt;`\n\u0026lt;/div\u0026gt; 跳过一些初始化的局部变量(逻辑看注释就够了) 如果传入的事件是有优先级之分的，则会根据优先级，将事件插入所有订阅了事件`eventType`的类的集合`subscriptions`中去。看逻辑我们发现，这里并没有对优先级的大小做限制，默认的优先级是0，priority越大，优先级越高。 每个订阅者是可以有多个重载的`onEvent()`方法的，所以这里多做了一步，将所有订阅者的响应方法保存到`subscribedEvents`中。 至此，我们就知道了 EventBus 中那几个map的全部含义。同时也回答了上一篇中问的为什么如果EventBus.defaultInstance不为null以后程序要抛出异常，就是因为这几个 map 不同了。 map 变了以后，订阅的事件就全部变为另一个 EventBus 对象的了，就没办法响应之前那个 EventBus 对象的订阅方法了。 最后又是一个感叹：子事件也可以让响应父事件的 onEvent() 。这个有点绕，举个例子，订阅者的onEvent(CharSequence),如果传一个String类型的值进去，默认情况下是不会响应的，但如果我们在构建的时候设置了 `eventInheritance` 为 true ,那么它就会响应了。 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;sticky\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;eventInheritance\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Set\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Map\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;Entry\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Class\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;?\u0026amp;gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Object\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;entries\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;stickyEvents\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;entrySet\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;for\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Map\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;Entry\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Class\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;?\u0026amp;gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Object\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;entry\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;entries\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Class\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;candidateEventType\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;entry\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getKey\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//如果eventtype是candidateEventType同一个类或是其子类\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;eventType\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;isAssignableFrom\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;candidateEventType\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;))\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Object\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;stickyEvent\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;entry\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getValue\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;checkPostStickyEventToSubscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;newSubscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;stickyEvent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;Object\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;stickyEvent\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;stickyEvents\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;get\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;eventType\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;checkPostStickyEventToSubscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;newSubscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;stickyEvent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; 最后是调用`checkPostStickyEventToSubscription()`做一次安全判断，就调用`postToSubscription()`发送事件了。 这里就关联到了我们之前讲的Poster类的作用了。 回答之前的问题：Poster只负责粘滞事件的代码。这里可以回答一部分：如果不是 sticky 事件都直接不执行了，还怎么响应。 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;postToSubscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(...)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;switch\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;threadMode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nl\u0026quot;\u0026gt;PostThread:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//直接调用响应方法\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;invokeSubscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nl\u0026quot;\u0026gt;MainThread:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//如果是主线程则直接调用响应事件,否则使用handle去在主线程响应事件\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;isMainThread\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;invokeSubscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;mainThreadPoster\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;enqueue\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;k\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//。。。\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;}\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; 最后，还记得我们之前没有讲的那个`invokeSubscriber(subscription, event);`方法吗？ 之前我们不知道`subscriberMethod`是什么，现在我们能看懂了，就是通过反射调用订阅者类`subscriber`的订阅方法`onEventXXX()`，并将`event`作为参数传递进去 \u0026lt;div class=\u0026#34;highlight\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;subscriberMethod\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;method\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;invoke\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;subscription\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;subscriber\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;);\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; ## Register与Poster工作图 {#registerposter} #### 原理图 {#section} ![开源实验室：图6](http://www.kymjs.com/images/blog_image/20151211_6.png) #### 流程图 {#section-1} 完整的注册流程 ![开源实验室：图7](http://www.kymjs.com/images/blog_image/20151211_7.png) 至此，整个EventBus从注册订阅到事件的处理到响应的过程我们都分析完了，最后就只剩下发送流程和取消注册了。 ","permalink":"https://blog.zdltech.com/posts/eventbus%E6%BA%90%E7%A0%81%E7%A0%94%E8%AF%BB/","summary":"\u003ch3 id=\"摘要\"\u003e摘要\u003c/h3\u003e\n\u003cp\u003e转载：\u003ca href=\"http://kymjs.com/code/2015/12/12/01\"\u003ehttp://kymjs.com/code/2015/12/12/01\u003c/a\u003e\u003cbr\u003e\n本文总共分三部分，从源码角度分析了 EventBus 库。以及介绍了其内部实现注册、发送、响应、取消注册的原理。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/greenrobot/EventBus\"\u003eEventBus\u003c/a\u003e 是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent, Handler, BroadCast 在 Fragment，Activity，Service，线程之间传递消息.优点是开销小，使用方便,可以很大程度上降低它们之间的耦合，使得我们的代码更加简洁，耦合性更低，提升我们的代码质量。\u003cbr\u003e\n类似的库还有 \u003ca href=\"https://github.com/square/otto\"\u003eOtto\u003c/a\u003e ,今天就带大家一起研读 EventBus 的源码.\u003c/p\u003e\n\u003cp\u003e在写这篇文章之前，我已经将本文相关的中文注释代码上传到了GitHub：\u003ca href=\"https://github.com/kymjs/EventBus\"\u003ehttps://github.com/kymjs/EventBus\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"section\"\u003e基础用法\u003c/h2\u003e\n\u003cp\u003e在读代码之前,首先你得了解它的基本用法.如果你已经能够很熟练的使用EventBus等事件总线库了,那么你可以跳过本节.\u003cbr\u003e\n首先引入依赖包,查看GitHub主页的说明: \u003ca href=\"https://github.com/greenrobot/EventBus\"\u003ehttps://github.com/greenrobot/EventBus\u003c/a\u003e\u003cbr\u003e\n在Gradle文件加入\u003cbr\u003e\n\u003ccode\u003ecompile 'de.greenrobot:eventbus:2.4.0'\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e用法与广播相同,且比广播更简单:\u003c/p\u003e\n\u003ch4 id=\"section-1\"\u003e注册订阅者\u003c/h4\u003e\n\u003cp\u003e首先你需要注册一个\u003ccode\u003e事件订阅者\u003c/code\u003e,为了方便理解你可以把他当成广播的\u003ccode\u003e广播接收者\u003c/code\u003e 你可以在任何一个类中使用如下代码注册以及解除注册\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\n  ```\n`\u0026lt;span class=\"c1\"\u003e\u0026lt;span class=\"hljs-comment\"\u003e//把当前类注册为订阅者(接收者)\u0026lt;/span\u003e\u0026lt;/span\u003e\n\u0026lt;span class=\"n\"\u003eEventBus\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e.\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003egetDefault\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e().\u0026lt;/span\u003e\u0026lt;span class=\"na\"\u003eregister\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e(\u0026lt;/span\u003e\u0026lt;span class=\"k\"\u003e\u0026lt;span class=\"hljs-keyword\"\u003ethis\u0026lt;/span\u003e\u0026lt;/span\u003e\u0026lt;span class=\"o\"\u003e);\u0026lt;/span\u003e\n\u003cp\u003e\u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//解除注册当前类(同广播一样,一定要调用,否则会内存泄露)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;EventBus\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;getDefault\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;().\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;unregister\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt;`\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-mysql\" data-lang=\"mysql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ediv\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e注册了订阅者以后,我们需要创建一个回调方法\u003cspan style=\"color:#ff79c6\"\u003e`\u003c/span\u003eonEvent\u003cspan style=\"color:#ff79c6\"\u003e`\u003c/span\u003e,当我们订阅的事件发送的时候就会回调它\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ediv\u003c/span\u003e class\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;highlight\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003e\u0026amp;lt;span class=\u0026quot;c1\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//其实命名不一定必须是onEvent(),但那属于高级用法了,这里我们只说最简单的\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kd\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;kt\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;nf\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onEvent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;Object\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;event\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-function\u0026quot;\u0026gt;\u0026amp;lt;span class=\u0026quot;hljs-params\u0026quot;\u0026gt;)\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;{}\u0026amp;lt;/span\u0026gt;\u003c/code\u003e\u003c/p\u003e","title":"EventBus源码研读"},{"content":"写一个listview容易，写一个adapter容易，自己new一个线程过滤数据也容易，但是如何将过滤的效率发挥到最大化，不得不提一下android自带的filter类。\n有同学肯定要问，过滤数据自己写一个完全没问题，为什么要用android自带的filter类？我原来也是自己写线程过滤，然而最近项目中遇到一个低配机，双核0.8GCPU，过滤效果实在是卡顿厉害，优化起见，使用了android内部filter试一下效果，结果真是比自己写的好用，于是认真学习了下源码，从头至尾备忘如下：\n![](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif) ![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` private static final String LOG_TAG = \u0026ldquo;Filter\u0026rdquo;;\nprivate static final String THREAD_NAME = \u0026quot;Filter\u0026quot;; private static final int FILTER_TOKEN = 0xD0D0F00D; private static final int FINISH_TOKEN = 0xDEADBEEF; private Handler mThreadHandler; private Handler mResultHandler; private Delayer mDelayer; private final Object mLock = new Object(); \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 其实用到的全局变量只有8个，并且有一半是常量：两个handler，一个delayer，一个对象锁。google开发大牛用这几个变量加上为数不多的几个局部变量就做出来了一个拓展性极佳的过滤器，不得不让人钦佩。 首先看构造方法： \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; ![](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif) \u0026lt;div id=\u0026#34;cnblogs_code_open_c440c2da-b7c0-476f-bacb-a745b6a72f88\u0026#34; class=\u0026#34;cnblogs_code_hide\u0026#34;\u0026gt; ``` public Filter() { mResultHandler = new ResultsHandler(); } 构造方法中二小强之一——ResultsHandler已经被创建了，顾名思义处理过滤操作结果。我们看看这个类的定义：\n![](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif) ![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` private class ResultsHandler extends Handler { /** * \u0026lt;p\u0026gt;Messages received from the request handler are processed in the * UI thread. The processing involves calling * {@link Filter#publishResults(CharSequence, * android.widget.Filter.FilterResults)} * to post the results back in the UI and then notifying the listener, * if any.\u0026lt;/p\u0026gt; * * @param msg the filtering results */ @Override public void handleMessage(Message msg) { RequestArguments args = (RequestArguments) msg.obj;\npublishResults(args.constraint, args.results); if (args.listener != null) { int count = args.results != null ? args.results.count : -1; args.listener.onFilterComplete(count); } } } /** * \u0026amp;lt;p\u0026amp;gt;Holds the arguments of a filtering request as well as the results * of the request.\u0026amp;lt;/p\u0026amp;gt; */ private static class RequestArguments { /** * \u0026amp;lt;p\u0026amp;gt;The constraint used to filter the data.\u0026amp;lt;/p\u0026amp;gt; */ CharSequence constraint; /** * \u0026amp;lt;p\u0026amp;gt;The listener to notify upon completion. Can be null.\u0026amp;lt;/p\u0026amp;gt; */ FilterListener listener; /** * \u0026amp;lt;p\u0026amp;gt;The results of the filtering operation.\u0026amp;lt;/p\u0026amp;gt; */ FilterResults results; } /** * @hide */ public interface Delayer { /** * @param constraint The constraint passed to {@link Filter#filter(CharSequence)} * @return The delay that should be used for * {@link Handler#sendMessageDelayed(android.os.Message, long)} */ long getPostingDelay(CharSequence constraint); } \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 注意到主要的操作就是：ResultsHandler接收到消息以后，调用抽象的publishResults()方法供UI线程更新画面。 接下来直接看主力的filter方法： \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; ![](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif) \u0026lt;div id=\u0026#34;cnblogs_code_open_ee9d504d-96e2-4682-a87a-17ce3e453f0a\u0026#34; class=\u0026#34;cnblogs_code_hide\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ``` public final void filter(CharSequence constraint, FilterListener listener) { synchronized (mLock) { if (mThreadHandler == null) { HandlerThread thread = new HandlerThread( THREAD_NAME, android.os.Process.THREAD_PRIORITY_BACKGROUND); thread.start(); mThreadHandler = new RequestHandler(thread.getLooper()); } final long delay = (mDelayer == null) ? 0 : mDelayer.getPostingDelay(constraint); Message message = mThreadHandler.obtainMessage(FILTER_TOKEN); RequestArguments args = new RequestArguments(); // make sure we use an immutable copy of the constraint, so that // it doesn\u0026#39;t change while the filter operation is in progress args.constraint = constraint != null ? constraint.toString() : null; args.listener = listener; message.obj = args; mThreadHandler.removeMessages(FILTER_TOKEN); mThreadHandler.removeMessages(FINISH_TOKEN); mThreadHandler.sendMessageDelayed(message, delay); } } \u0026lt;div class=\u0026quot;cnblogs_code_toolbar\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_copy\u0026quot;\u0026gt;\u0026lt;a title=\u0026quot;复制代码\u0026quot;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 官方文档介绍这个每次调用这个方法将会开启一个异步的过滤操作，调用这个方法会取消之前没有执行的过滤操作，让我们分析一下他们是如何来做的。\n首先整个方法都在同步块synchronized (mLock){}中，意图很直接：其他的方法我不管，排队队，吃果果，你一个，我一个，你下一个filter方法调用必须等我这次filter方法调用结束。接着呢，创建了一个HandlerThread，这个HandlerThread大家可以自行查看源码，实际上就是自备一个Handler的维他命——Looper，有了Looper，可以初始化我们的filter二小强之二（处理请求操作）：mThreadHandler = new RequestHandler(thread.getLooper());然后获得一个Message message = mThreadHandler.obtainMessage(FILTER_TOKEN);最后移除掉之前带有FILTER_TOKEN和FINISH_TOKEN的标记（因为后面的操作很有耗时的，你不晓得到底是执行到什么状态了），这样保证了这个方法执行以后，所有执行过滤的操作肯定只有一个message在传递了\n这个方法的妙处在，方法本身很简单，几乎不耗时，即使你不断地调用filter（）方法，程序始终能保证只有一个message在做过滤操作。\n接下来看看这个RequestHandler类;\n![](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif) ![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` private class RequestHandler extends Handler { public RequestHandler(Looper looper) { super(looper); }\n/** * \u0026amp;lt;p\u0026amp;gt;Handles filtering requests by calling * {@link Filter#performFiltering} and then sending a message * with the results to the results handler.\u0026amp;lt;/p\u0026amp;gt; * * @param msg the filtering request */ public void handleMessage(Message msg) { int what = msg.what; Message message; switch (what) { case FILTER_TOKEN: RequestArguments args = (RequestArguments) msg.obj; try { args.results = performFiltering(args.constraint); } catch (Exception e) { args.results = new FilterResults(); Log.w(LOG_TAG, \u0026quot;An exception occured during performFiltering()!\u0026quot;, e); } finally { message = mResultHandler.obtainMessage(what); message.obj = args; message.sendToTarget(); } synchronized (mLock) { if (mThreadHandler != null) { Message finishMessage = mThreadHandler.obtainMessage(FINISH_TOKEN); mThreadHandler.sendMessageDelayed(finishMessage, 3000); } } break; case FINISH_TOKEN: synchronized (mLock) { if (mThreadHandler != null) { mThreadHandler.getLooper().quit(); mThreadHandler = null; } } break; } } } \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 其实除了filter方法，主要的高端逻辑都在这里，试想一个场景，如果我连续调用了五次filter，这5个msg的第1个已经被remove掉了，但是由它调用的performFiltering()耗时任务还在进行，2，3，4肯定排队过程中就被第5个msg干掉了，然后第1个msg过滤操作完成，给ResultsHandler发送消息更新UI，然后给RequestHandler发一个三秒延时消息， 接着执行msg5，这时候再调用一次filter，msg1和msg5就被干掉了，然后同样是执行完由msg5调用的performFiltering()再执行msg6，然后是msg5和msg6最终都生成一个延时消息，msg5生成的延时消息把mThreadHandler销毁了，msg6生成的延时消息到的时候，不做任何操作。 前面我们在filter（）中看到过一次synchronized (mLock){}，而在这个handler中有两个同步代码块，case FINISH\\_TOKEN中的同步代码块保证了，如果刚刚在filter中创建了mThreadHandler（这是UI线程的操作），会立刻移除所有之前的延迟消息，从而不会在此处去销毁掉mThreadHandler导致空指针异常。 case FILTER\\_TOKEN中的同步代码块的作用，目前还是想不出来到底有什么用，因为case FILTER\\_TOKEN和case FINISH\\_TOKEN本来就是队列执行，不存在争用锁的情况，所以不会存在线程间的时空差导致的空指针，有高手能看出作用还望不吝赐教。 好了，来总结一下吧，其实作者就是利用了looper中messageQueue排队队的特性，又有两处对象同步锁的妙用，保证了UI线程和HandlerThread不冲突，而过滤过程中的一些冗余msg都被新msg创建时候给干掉了，一个线程有序进行，大哉大牛！ \u0026amp;nbsp; \u0026amp;nbsp; _Demo原文_ [http://blog.csdn.net/lfdfhl/article/details/18897401][1]{.cut.cut70} MainActivity如下: package cc.testfilterable;\nimport java.util.ArrayList; import java.util.HashMap; import android.os.Bundle; import android.widget.ListView; import android.app.Activity; import android.content.Context; /**\nDemo描述: 利用Filter过滤数据 可用于AutoCompleteTextView筛选数据等功能 备注说明: 该Demo只表述原理,代码逻辑较简单,有一些小的bug. 完整的应用请参见以下资料. 参考资料: 1 http://gundumw100.iteye.com/blog/1446507 2 http://blog.csdn.net/ssstudio/article/details/7579089 3 http://blog.csdn.net/jiahui524/article/details/7802033 */ public class MainActivity extends Activity { private Context mContext; private ListView mListView; private ListViewAdapter mListViewAdapter; private ArrayList\u0026lt;String\u0026gt; mArrayList; private HashMap\u0026lt;String, String\u0026gt; mHashMap; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); init(); }\nprivate void init(){ mContext=this; mListView=(ListView) findViewById(R.id.listView); mArrayList=new ArrayList\u0026lt;String\u0026gt;(); mArrayList.add(\u0026ldquo;张三1\u0026rdquo;); mArrayList.add(\u0026ldquo;李四1\u0026rdquo;); mArrayList.add(\u0026ldquo;王五1\u0026rdquo;); mArrayList.add(\u0026ldquo;张三2\u0026rdquo;); mArrayList.add(\u0026ldquo;李四2\u0026rdquo;); mArrayList.add(\u0026ldquo;王五2\u0026rdquo;); mArrayList.add(\u0026ldquo;张三3\u0026rdquo;); mArrayList.add(\u0026ldquo;李四3\u0026rdquo;); mArrayList.add(\u0026ldquo;王五3\u0026rdquo;); mArrayList.add(\u0026ldquo;张三4\u0026rdquo;); mArrayList.add(\u0026ldquo;李四4\u0026rdquo;); mArrayList.add(\u0026ldquo;王五4\u0026rdquo;); mListViewAdapter=new ListViewAdapter(mContext, mArrayList); //过滤数据 //过滤出姓名里面包含\u0026quot;张\u0026quot;的数据 mListViewAdapter.getFilter().filter(\u0026ldquo;张\u0026rdquo;); mListView.setAdapter(mListViewAdapter); }\n}\nListViewAdapter如下: \u0026lt;div id=\u0026#34;nei\u0026#34; class=\u0026#34;article_body\u0026#34;\u0026gt; \u0026lt;div\u0026gt; ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;package\u0026lt;/span\u0026gt; cc.testfilterable; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Iterator; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.BaseAdapter; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Filter; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;ListViewAdapter\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;BaseAdapter\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; NameFilter mNameFilter; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; mArrayList; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; mFilteredArrayList; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; LayoutInflater mLayoutInflater; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; ListViewAdapter(Context context,List\u0026amp;lt;String\u0026amp;gt; arrayList) { mArrayList = arrayList; mLayoutInflater=LayoutInflater.from(context); mFilteredArrayList=\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026amp;lt;String\u0026amp;gt;(); } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getCount() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (mArrayList == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; (mArrayList.size()); } } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; Object getItem(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (mArrayList == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; mArrayList.get(position); } } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;long\u0026lt;/span\u0026gt; getItemId(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; position; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; Filter getFilter() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (mNameFilter == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { mNameFilter = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; NameFilter(); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; mNameFilter; } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; View getView(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) { View itemView = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; itemView = convertView; ViewHolder viewHolder = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (itemView == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { itemView = mLayoutInflater.inflate(R.layout.listviewitem, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;); viewHolder = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; ViewHolder(); viewHolder.textView = (TextView) itemView.findViewById(R.id.textView); itemView.setTag(viewHolder); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { viewHolder = (ViewHolder) itemView.getTag(); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (mArrayList != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (viewHolder.textView != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { viewHolder.textView.setText((mArrayList.get(position))); } } convertView = itemView; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; convertView; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;ViewHolder\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; TextView textView; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//过滤数据\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;NameFilter\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Filter\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//执行筛选\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; FilterResults performFiltering(CharSequence charSequence) { FilterResults filterResults = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; FilterResults(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;for\u0026lt;/span\u0026gt; (Iterator\u0026amp;lt;String\u0026amp;gt; iterator = mArrayList.iterator(); iterator.hasNext();) { String name = iterator.next(); System.out.println(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;---\u0026amp;gt; name=\u0026#34;\u0026lt;/span\u0026gt; + name); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (name.contains(charSequence)) { mFilteredArrayList.add(name); } } filterResults.values = mFilteredArrayList; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; filterResults; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//筛选结果\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; publishResults(CharSequence arg0, FilterResults results) { mArrayList = (List\u0026amp;lt;String\u0026amp;gt;) results.values; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (results.count \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { notifyDataSetChanged(); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { notifyDataSetInvalidated(); } }} } ``` \u0026lt;RelativeLayout xmlns:android=\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot; xmlns:tools=\u0026ldquo;http://schemas.android.com/tools\u0026quot; android:layout_width=\u0026ldquo;match_parent\u0026rdquo; android:layout_height=\u0026ldquo;match_parent\u0026rdquo; \u0026gt;\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;ListView android:id=\u0026rdquo;@+id/listView\u0026rdquo; android:layout_width=\u0026ldquo;fill_parent\u0026rdquo; android:layout_height=\u0026ldquo;fill_parent\u0026rdquo; /\u0026gt;\n\u0026lt;/RelativeLayout\u0026gt;\n``` \u0026lt;span class=\u0026#34;pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026lt;/span\u0026gt; \u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;@+id/textView\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;50dip\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;center\u0026#34;\u0026lt;/span\u0026gt; /\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-%E6%BA%90%E7%A0%81%E8%A7%92%E5%BA%A6%E5%85%A8%E6%96%B9%E4%BD%8D%E7%90%86%E8%A7%A3filter-%E5%8F%8A%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8/","summary":"\u003cp\u003e写一个listview容易，写一个adapter容易，自己new一个线程过滤数据也容易，但是如何将过滤的效率发挥到最大化，不得不提一下android自带的filter类。\u003c/p\u003e\n\u003cp\u003e有同学肯定要问，过滤数据自己写一个完全没问题，为什么要用android自带的filter类？我原来也是自己写线程过滤，然而最近项目中遇到一个低配机，双核0.8GCPU，过滤效果实在是卡顿厉害，优化起见，使用了android内部filter试一下效果，结果真是比自己写的好用，于是认真学习了下源码，从头至尾备忘如下：\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n\u003cpre\u003e\u003ccode\u003e![](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv id=\"cnblogs_code_open_e8d21bec-e48c-481e-a83c-0bc06ada4024\" class=\"cnblogs_code_hide\"\u003e\n    \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n      \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eprivate static final String LOG_TAG = \u0026ldquo;Filter\u0026rdquo;;\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eprivate static final String THREAD_NAME = \u0026quot;Filter\u0026quot;;\nprivate static final int FILTER_TOKEN = 0xD0D0F00D;\nprivate static final int FINISH_TOKEN = 0xDEADBEEF;\n\nprivate Handler mThreadHandler;\nprivate Handler mResultHandler;\n\nprivate Delayer mDelayer;\n\nprivate final Object mLock = new Object();\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003ediv \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cnblogs_code_toolbar\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cnblogs_code_copy\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003ea title\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;复制代码\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;!\u003c/span\u003e[复制代码](http:\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003ecommon\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecnblogs\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecom\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eimages\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003ecopycode\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egif)\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ea\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ediv\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ediv\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ediv\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e其实用到的全局变量只有\u003cspan style=\"color:#bd93f9\"\u003e8\u003c/span\u003e个，并且有一半是常量：两个handler，一个delayer，一个对象锁。google开发大牛用这几个变量加上为数不多的几个局部变量就做出来了一个拓展性极佳的过滤器，不得不让人钦佩。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e首先看构造方法：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003ediv \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cnblogs_code\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003e[](http:\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003eimages\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecnblogs\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecom\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eOutliningIndicators\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eExpandedBlockStart\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egif)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003ediv id\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cnblogs_code_open_c440c2da-b7c0-476f-bacb-a745b6a72f88\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;cnblogs_code_hide\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public Filter() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mResultHandler \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new ResultsHandler();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e构造方法中二小强之一——ResultsHandler已经被创建了，顾名思义处理过滤操作结果。我们看看这个类的定义：\u003c/p\u003e","title":"android 源码角度全方位理解filter 及简单使用"},{"content":" 2015.10.22 腾讯Bugly [微信分享](http://bugly.qq.com/blog/?p=781#) 背景 当一个App发布之后，突然发现了一个严重bug需要进行紧急修复，这时候公司各方就会忙得焦头烂额：重新打包App、测试、向各个应用市场和渠道换包、提示用户升级、用户下载、覆盖安装。有时候仅仅是为了修改了一行代码，也要付出巨大的成本进行换包和重新发布。 这时候就提出一个问题：**有没有办法以补丁的方式动态修复紧急Bug，不再需要重新发布App，不再需要用户重新下载，覆盖安装？** 虽然Android系统并没有提供这个技术，但是很幸运的告诉大家，答案是：可以。 解决方案 该方案基于的是android dex分包方案的，关于dex分包方案，网上有几篇解释了，所以这里就不再赘述，具体可以看这里：https://m.oschina.net/blog/308583（请复制链接到浏览器打开）。 简单的概括一下，就是把多个dex文件塞入到app的classloader之中，但是android dex拆包方案中的类是没有重复的，如果classes.dex和classes1.dex中有重复的类，当用到这个重复的类的时候，系统会选择哪个类进行加载呢？ 让我们来看看类加载的代码： `\u0026amp;lt;strong\u0026gt;public\u0026amp;lt;/strong\u0026gt; Class findClass(String name, List\u0026amp;lt;Throwable\u0026amp;gt; suppressed) { \u0026amp;lt;strong\u0026gt;for\u0026amp;lt;/strong\u0026gt; (Element element : dexElements) { //每个Element就是一个dex文件 DexFile dex = element.dexFile; \u0026amp;lt;strong\u0026gt;if\u0026amp;lt;/strong\u0026gt; (dex != \u0026amp;lt;strong\u0026gt;null\u0026amp;lt;/strong\u0026gt;) { Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed); \u0026amp;lt;strong\u0026gt;if \u0026amp;lt;/strong\u0026gt;(clazz != \u0026amp;lt;strong\u0026gt;null\u0026amp;lt;/strong\u0026gt;) { \u0026amp;lt;strong\u0026gt; return \u0026amp;lt;/strong\u0026gt;clazz; } } } \u0026amp;lt;strong\u0026gt; if \u0026amp;lt;/strong\u0026gt;(dexElementsSuppressedExceptions != \u0026amp;lt;strong\u0026gt;null\u0026amp;lt;/strong\u0026gt;) { suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions)); } \u0026amp;lt;strong\u0026gt; return null\u0026amp;lt;/strong\u0026gt;; } ` 一个ClassLoader可以包含多个dex文件，每个dex文件是一个Element，多个dex文件排列成一个有序的数组dexElements，当找类的时候，会按顺序遍历dex文件，然后从当前遍历的dex文件中找类，如果找类则返回，如果找不到从下一个dex文件继续查找。 理论上，如果在不同的dex中有相同的类存在，那么会优先选择排在前面的dex文件的类，如下图： ![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4de39gh3QXrLudkAtkVzFOtDJoCpVwNq85HU9Lpw9tuCHLibDzQHjNicYnWNET0wvCWNVdZc6XUFI4yw/0?wx_fmt=jpeg) 在此基础上，我们构想了热补丁的方案，把有问题的类打包到一个dex（patch.dex）中去，然后把这个dex插入到Elements的最前面，如下图 ![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4de39gh3QXrLudkAtkVzFOtD4icmchNG1Z6HgDD20mzQBs11XyUyxlAL6OZBqO2Pnicf8t4vjnA01N8Q/0?wx_fmt=jpeg) 好，该方案基于第二个拆分dex的方案，方案实现如果懂拆分dex的原理的话，大家应该很快就会实现该方案，如果没有拆分dex的项目的话，可以参考一下谷歌的multidex方案实现。然后在插入数组的时候，把补丁包插入到最前面去。 好，看似问题很简单，轻松的搞定了，让我们来试验一下，修改某个类，然后打包成dex，插入到classloader，当加载类的时候出现了（本例中是ActivityManager要被替换）： ![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4deljxecuyiaGnrNtAnOS3WkIicoAnyViaKrpmWcAwO3kebB20AbpkqbCVP0zlXkGQe5XpjZUiaYMw1NVw/0?wx_fmt=jpeg) **为什么会出现以上问题呢？** **从log的意思上来讲，ModuleManager引用了ActivityManager，但是发现这这两个类所在的dex不在一起，其中：** **1. ModuleManager在classes.dex中** **2. ActivityManager在patch.dex中** **结果发生了错误。** **这里有个问题,拆分dex的很多类都不是在同一个dex内的,怎么没有问题?** **让我们搜索一下抛出错误的代码所在，嘿咻嘿咻，找到了一下代码：** ![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4deljxecuyiaGnrNtAnOS3WkIiavUvrYI3Via0BrrMfBAXcicwZV2pejc56PVH1IwmruNmvibcbw8boCnVg/0?wx_fmt=png) 从代码上来看，如果两个相关联的类在不同的dex中就会报错，但是拆分dex没有报错这是为什么，原来这个校验的前提是： ![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4de39gh3QXrLudkAtkVzFOtDVqPD8yt3X72ETcJDG4icZyeDt3Sic6CLNAXAmicN3yZzQEu6ODr9CHWBw/0?wx_fmt=png) 如果引用者（也就是ModuleManager）这个类被打上了**CLASS_ISPREVERIFIED标志**，**那么就会进行dex的校验。那么这个标志是什么时候被打上去的？** **让我们在继续搜索一下代码，嘿咻嘿咻~~，在DexPrepare.cpp找到了一下代码：** **\n![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4de39gh3QXrLudkAtkVzFOtDXQSZeR7Ta4WBPC2oxTLdUkR7RVE2sD5ovUwM8a5ibWwZtwLhELQicvXw/0?wx_fmt=png) 这段代码是dex转化成odex(dexopt)的代码中的一段，我们知道当一个apk在安装的时候，apk中的classes.dex会被虚拟机(dexopt)优化成odex文件，然后才会拿去执行. 虚拟机在启动的时候，会有许多的启动参数，其中一项就是verify选项，当verify选项被打开的时候，上面doVerify变量为true，那么就会执行dvmVerifyClass进行类的校验，如果dvmVerifyClass校验类成功，那么这个类会被打上CLASS_ISPREVERIFIED的标志，那么具体的校验过程是什么样子的呢？ 此代码在DexVerify.cpp中，如下： ![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4de39gh3QXrLudkAtkVzFOtDfySocVU3mydF5aZVsmpnibMrUHTnpmS3Xp2K9PzSoia8qHlib8wbmwTEw/0?wx_fmt=png) 1. 验证clazz-\u0026gt;directMethods方法，directMethods包含了以下方法： 1. static方法 2. private方法 3. 构造函数 2. clazz-\u0026gt;virtualMethods 1. 虚函数=override方法? 概括一下就是如果以上方法中直接引用到的类（第一层级关系，不会进行递归搜索）和clazz都在同一个dex中的话，那么这个类就会被打上\u0026lt;strong\u0026gt;CLASS_ISPREVERIFIED标志** ![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4de39gh3QXrLudkAtkVzFOtDz3mTBsCH1k0awWSQWricLSGysWAMWQGpLtia06sibTgRxo1S49KuAfI4g/0?wx_fmt=jpeg) **所以为了实现补丁方案，所以必须从这些方法中入手，防止类被打上CLASS_ISPREVERIFIED标志。** **最终空间的方案是往所有类的构造函数里面插入了一段代码，代码如下：** if (ClassVerifier.PREVENT_VERIFY) { System.out.println(AntilazyLoad.class); } ![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4de39gh3QXrLudkAtkVzFOtDfkwsyYxKMP4ckOcSurNzRfd4jD5Dl7hx54yst5Ot40qjglq2ZctMcg/0?wx_fmt=jpeg) **其中AntilazyLoad类会被打包成单独的hack.dex，这样当安装apk的时候，classes.dex内的类都会引用一个在不相同dex中的AntilazyLoad类，这样就防止了类被打上CLASS_ISPREVERIFIED的标志了。只要没被打上这个标志的类都可以进行打补丁操作。** **然后在应用启动的时候加载进来.AntilazyLoad类所在的dex包必须被先加载进来,不然AntilazyLoad类会被标记为不存在,即使后续加载了hack.dex包,那么他也是不存在的,这样屏幕就会出现茫茫多的类AntilazyLoad找不到的log。** **所以Application作为应用的入口不能插入这段代码。（因为载入hack.dex的代码是在Application中onCreate中执行的，如果在Application的构造函数里面插入了这段代码，那么就是在hack.dex加载之前就使用该类，该类一次找不到，会被永远的打上找不到的标志)。** 其中: class ClassVerifier { public static boolean PREVENT_VERIFY = false;//false防止代码被执行,提高性能 } 之所以选择构造函数是因为他不增加方法数，一个类即使没有显式的构造函数，也会有一个隐式的默认构造函数。 空间使用的是在字节码插入代码,而不是源代码插入，使用的是javaassist库来进行字节码插入的。 隐患 虚拟机在安装期间为类打上**CLASS_ISPREVERIFIED标志**是为了提高性能的，我们强制防止类被打上标志是否会影响性能？这里我们会做一下更加详细的性能测试。 但是在大项目中拆分dex的问题已经比较严重，很多类都没有被打上这个标志。 **如何打包补丁包：** １．空间在正式版本发布的时候，会生成一份缓存文件，里面记录了所有class文件的md5。还有一份mapping混淆文件。 ２．在后续的版本中使用-applymapping选项，应用正式版本的mapping文件，然后计算编译完成后的class文件的md5和正式版本进行比较，把不相同的class文件打包成补丁包。 备注：该方案现在也应用到我们的编译过程当中，编译不需要重新打包dex，只需要把修改过的类的class文件打包成patch dex，然后放到sdcard下，那么就会让改变的代码生效。 ","permalink":"https://blog.zdltech.com/posts/%E6%96%B0%E6%8A%80%E8%83%BDget%E8%AE%A9app%E5%83%8Fweb%E4%B8%80%E6%A0%B7%E5%8F%91%E5%B8%83%E6%96%B0%E7%89%88%E6%9C%AC/","summary":"\u003cdiv class=\"blog-title-info\"\u003e\n  \u003cspan class=\"time\"\u003e2015.10.22\u003c/span\u003e \u003cspan class=\"author\"\u003e腾讯Bugly\u003c/span\u003e \u003cspan class=\"share\"\u003e[微信分享](http://bugly.qq.com/blog/?p=781#)\u003c/span\u003e\n\u003c/div\u003e\n\u003cdiv class=\"blog-con\"\u003e\n  \u003csection class=\"wxqq-borderTopColor\"\u003e \u003csection class=\"wxqq-borderTopColor\"\u003e \u003csection class=\"wxqq-bg\"\u003e \n\u003ch3 id=\"背景\"\u003e背景\u003c/section\u003e \u003c/section\u003e \u003c/section\u003e\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003e当一个App发布之后，突然发现了一个严重bug需要进行紧急修复，这时候公司各方就会忙得焦头烂额：重新打包App、测试、向各个应用市场和渠道换包、提示用户升级、用户下载、覆盖安装。有时候仅仅是为了修改了一行代码，也要付出巨大的成本进行换包和重新发布。\n\n\n\n\n\n这时候就提出一个问题：**有没有办法以补丁的方式动态修复紧急Bug，不再需要重新发布App，不再需要用户重新下载，覆盖安装？**\n\n\n\n\n\n虽然Android系统并没有提供这个技术，但是很幸运的告诉大家，答案是：可以。\n\u003c/code\u003e\u003c/pre\u003e\n\u003csection class=\"wxqq-borderTopColor\"\u003e \u003csection class=\"wxqq-borderTopColor\"\u003e \u003csection class=\"wxqq-bg\"\u003e \n\u003ch3 id=\"解决方案\"\u003e解决方案\u003c/section\u003e \u003c/section\u003e \u003c/section\u003e\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003e该方案基于的是android dex分包方案的，关于dex分包方案，网上有几篇解释了，所以这里就不再赘述，具体可以看这里：https://m.oschina.net/blog/308583（请复制链接到浏览器打开）。\n\n\n\n\n\n简单的概括一下，就是把多个dex文件塞入到app的classloader之中，但是android dex拆包方案中的类是没有重复的，如果classes.dex和classes1.dex中有重复的类，当用到这个重复的类的时候，系统会选择哪个类进行加载呢？\n\n\n\n\n\n让我们来看看类加载的代码：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;strong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003estrong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e Class findClass(String name, List\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;Throwable\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt; suppressed) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;strong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003estrong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (Element element : dexElements) {  \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e每个Element就是一个dex文件\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       DexFile dex \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e element\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edexFile; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;strong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003estrong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (dex \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;strong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enull\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003estrong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e) { \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           Class clazz \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e dex\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eloadClassBinaryName(name, definingContext, suppressed); \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;strong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003estrong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(clazz \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;strong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enull\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003estrong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e) { \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;strong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003estrong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eclazz;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  } \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;strong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003estrong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(dexElementsSuppressedExceptions \u003cspan style=\"color:#ff79c6\"\u003e!=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;strong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enull\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003estrong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       suppressed\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddAll(Arrays\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003easList(dexElementsSuppressedExceptions));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   } \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;strong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e null\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003estrong\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}                 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e一个ClassLoader可以包含多个dex文件，每个dex文件是一个Element，多个dex文件排列成一个有序的数组dexElements，当找类的时候，会按顺序遍历dex文件，然后从当前遍历的dex文件中找类，如果找类则返回，如果找不到从下一个dex文件继续查找。\n\n\n\n\n\n理论上，如果在不同的dex中有相同的类存在，那么会优先选择排在前面的dex文件的类，如下图：\n\n\n\n\n\n![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4de39gh3QXrLudkAtkVzFOtDJoCpVwNq85HU9Lpw9tuCHLibDzQHjNicYnWNET0wvCWNVdZc6XUFI4yw/0?wx_fmt=jpeg)\n\n\n\n\n\n在此基础上，我们构想了热补丁的方案，把有问题的类打包到一个dex（patch.dex）中去，然后把这个dex插入到Elements的最前面，如下图\n\n\n\n\n\n![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4de39gh3QXrLudkAtkVzFOtD4icmchNG1Z6HgDD20mzQBs11XyUyxlAL6OZBqO2Pnicf8t4vjnA01N8Q/0?wx_fmt=jpeg)\n\n\n\n\n\n好，该方案基于第二个拆分dex的方案，方案实现如果懂拆分dex的原理的话，大家应该很快就会实现该方案，如果没有拆分dex的项目的话，可以参考一下谷歌的multidex方案实现。然后在插入数组的时候，把补丁包插入到最前面去。\n\n\n\n\n\n好，看似问题很简单，轻松的搞定了，让我们来试验一下，修改某个类，然后打包成dex，插入到classloader，当加载类的时候出现了（本例中是ActivityManager要被替换）：\n\n\n\n\n\n![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4deljxecuyiaGnrNtAnOS3WkIicoAnyViaKrpmWcAwO3kebB20AbpkqbCVP0zlXkGQe5XpjZUiaYMw1NVw/0?wx_fmt=jpeg)\n\n\n\n\n\n**为什么会出现以上问题呢？**\n\n\n\n\n\n**从log的意思上来讲，ModuleManager引用了ActivityManager，但是发现这这两个类所在的dex不在一起，其中：**\n\n\n\n\n\n**1. ModuleManager在classes.dex中**\n\n\n\n\n\n**2. ActivityManager在patch.dex中**\n\n\n\n\n\n**结果发生了错误。**\n\n\n\n\n\n**这里有个问题,拆分dex的很多类都不是在同一个dex内的,怎么没有问题?**\n\n\n\n\n\n**让我们搜索一下抛出错误的代码所在，嘿咻嘿咻，找到了一下代码：**\n\n\n\n\n\n![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4deljxecuyiaGnrNtAnOS3WkIiavUvrYI3Via0BrrMfBAXcicwZV2pejc56PVH1IwmruNmvibcbw8boCnVg/0?wx_fmt=png)\n\n\n\n\n\n从代码上来看，如果两个相关联的类在不同的dex中就会报错，但是拆分dex没有报错这是为什么，原来这个校验的前提是：\n\n\n\n\n\n![](https://mmbiz.qlogo.cn/mmbiz/tnZGrhTk4de39gh3QXrLudkAtkVzFOtDVqPD8yt3X72ETcJDG4icZyeDt3Sic6CLNAXAmicN3yZzQEu6ODr9CHWBw/0?wx_fmt=png)\n\n\n\n\n\n如果引用者（也就是ModuleManager）这个类被打上了**CLASS_ISPREVERIFIED标志**，**那么就会进行dex的校验。那么这个标志是什么时候被打上去的？**\n\n\n\n\n\n**让我们在继续搜索一下代码，嘿咻嘿咻~~，在DexPrepare.cpp找到了一下代码：**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e**\u003c/p\u003e","title":"【新技能get】让App像Web一样发布新版本"},{"content":"原创 2015-11-26 李金涛 腾讯Bugly\n一、背景\n就在项目灰度测试前不久，爆出了在 Android 3.0以下手机上安装时出现 INSTALL _ FAILED_DEXOPT，导致安装失败。这一问题意味着项目将不能在 Android 3.0以下的手机上安装使用，对项目的发布有比较大的影响，所以必须尽快解决。\nINSTAL L_FAILED_DEXOPT导致无法安装的问题，从根本上来说，可能是两个原因造成的：\n（1） 单个 dex 文件方法总数65K 的限制。\n（2） Dexopt 的 LinearAlloc 限制。\n当 Android 系统安装一个应用的时候，有一步是对 Dex 进行优化，这个过程有一个专门的工具来处理，叫 DexOpt。DexOpt 是在第一次加载 Dex 文件的时候执行的。这个过程会生成一个 ODEX 文件，即 Optimised Dex。执行 ODEX 的效率会比直接执行 Dex 文件的效率要高很多。\n但是在早期的 Android 系统中，DexOpt 有两个问题。（一）：DexOpt 会把每一个类的方法 id 检索起来，存在一个链表结构里面，但是这个链表的长度是用一个 short 类型来保存的，导致了方法 id 的数目不能够超过65536个。当一个项目足够大的时候，显然这个方法数的上限是不够的。（二）：Dexopt 使用 LinearAlloc 来存储应用的方法信息。Dalvik LinearAlloc 是一个固定大小的缓冲区。在Android 版本的历史上，LinearAlloc 分别经历了4M/5M/8M/16M限制。Android 2.2和2.3的缓冲区只有5MB，Android 4.x提高到了8MB 或16MB。当方法数量过多导致超出缓冲区大小时，也会造成dexopt崩溃。\n尽管在新版本的 Android 系统中，DexOpt 修复了方法数65K的限制问题，并且扩大了 LinearAlloc 限制，但是我们仍然需要对低版本的 Android 系统做兼容。\n回头说项目。由于项目新版本新增功能点和代码较多，在方法数减无可减的时候，仍然不能解决INSTALL FAILED DEXOPT的问题。所以，最终我们采用了 dex 分包的方案，来避开了 Android 3.0以下平台的方法数和 LinearAlloc 限制。\n简单的说，分包就是在打包时将应用的代码分成多个 dex，使得主 dex 的方法数和所需的 LinearAlloc 不超过系统限制。在应用启动或运行过程中，首先是主 dex 启动运行后，再加载从 dex，这样就绕开了这两个限制。\n这样，我们的分包方案就要解决两个问题：一是如何对 dex 进行拆分，二是如何加载从 dex。\n二、Google 官方方案 1．Dex 拆分\n首先，我们需要解决如何对dex进行拆分？\n通过学习资料，我们知道，对于方法数超过65K 的问题，Google 官方从 Android Build tools 21.1就开始着手解决了。\n先看官方网站提供的配置。Google MultiDex 官方文档是针对 Gradle 进行配置的，如下：\nandroid { compileSdkVersion 21 buildToolsVersion \u0026quot;21.1.0\u0026quot; defaultConfig { ... minSdkVersion 14 targetSdkVersion 21 ... // Enabling multidex support. multiDexEnabled true } ... } dependencies { compile 'com.android.support:multidex:1.0.0' } 那么，是不是按 Google 官方文档配置一下就 OK 了呢？不管怎样，这是官方提供的方案，而且是最直接的做法，所以我们应该先试一试。\n因为我们项目的 RDM 构建环境采用的是 ant 脚本编译，所以首先要想办法把 Google 官方编译配置改造成 ant 脚本。\n官方文档上只提供了如何使用 MultiDex，没有说明构建时如何打包出多个 dex。其实是因为如果用了这种 Gradle来构建，当应用构建时，构建工具会自动分析哪些类必须放在第一个 DEX 文件（主 dex），哪些类可以放在附加的 DEX 文件（从 dex）中，并将分析结果输出到 dx 进行后续打包。当它创建了主 dex 文件（classes.dex）后，如果有必要会继续创建从 DEX 文件，如 classes2.dex, classes3.dex。这种方法优点是配置比较简单，但是最大的缺点是不能指定哪些类必须包含在主 dex 中，容易导致应用启动时某些类找不到，出现 Class Not Found Exception。\n我们把上述 Gradle 的配置改成 ant 脚本时，就不能简单套用了。通过查看 dx 工具的用法：\n参数说明：\n—multi-dex：多 dex 打包的开关。\n—main-dex-list=：参数是一个类列表的文件，在该文件中的类会被打包在第一个 dex 中。\n—minimal-main-dex：只有在—main-dex-list 文件中指定的类被打包在第一个 dex，其余的都在第二个 dex 文件中。\n因为后两个参数是 optional 参数，所以理论上只需给 dx 加上“—multi-dex”参数即可生成出 classes.dex、classes2.dex、classes3.dex、…。\n在 Gradle 中可以做如下的配置：\nafterEvaluate { tasks.matching { it.name.startsWith('dex') }.each { dx -\u0026gt; if (dx.additionalParameters == null) { dx.additionalParameters = ['--multi-dex'] } else { dx.additionalParameters += '--multi-dex' } } } 好了，这样我们就可以改造我们的 ant 脚本了。\n改造的方法是在项目打包的 ant 脚本中引入 Android build Tools 21.1.2，并把用 dx 生成 dex 的部分改造成下面的样子：\n编译、打包，并没有像预期那样生成多个 dex，而是只生成了一个 classes.dex：\n生成的 apk 包跟 dex 分包前一样。为什么会这样？\n再看 dx 的参数，main-dex-list 和 minimal-main-dex 只会影响到主 dex 中包含的文件，不会影响到从 dex 是否生成，所以应该是其他原因造成的。\n查不到资料，分析源代码就是解决问题的不二法门。于是我把 dx.jar 反编译了一下，通过分析，找到了下面的几行关键代码：\n显然，dx 进行多 dex 打包时，默认每个 dex 中方法数最大为65536。而查看当前应用 dex 的方法数，一共只有51392（方法数没超标，主要是 LinearAlloc 超标），没有达到65536，所以打包的时候只有一个 dex。\n再继续分析代码，发现下面一段关键代码：\n这说明 dx 有一个隐藏的参数：—set-max-idx-number，这个参数可以用于设置 dx 打包时每个 dex 最大的方法数，但是此参数并未在 dx 的 Usage 中列出（坑爹啊！）。\n我们在 ant 脚本中把这个参数设置上，暂时设置每个 dex 的方法数最大为48000：\n重新打包，结果如下：\n果然，第二个 dex 出现了！\n可是，观察一下 res 目录，这里出现了一个新的问题，drawable 密度后缀的资源目录都多了一个 v4：\n为什么这几个目录会带 v4后缀呢？原来这是 R6以上的 Android SDK Tools 自动打包工具新加的一个处理，即为这些在 Android 1.0 时不存在的密度后缀命名的资源路径名称后面自动添加一个适合的版本后缀，以确保老版本不使用这些资源（只有 API level 4以及更高版本支持后缀），v4 就表示使用在 Android 1.6 或更高版本。\n上述的 Dex 拆分过程采用的就是 Google 官方的方案。Dex 拆分已经完成，如何加载呢？\n2．Dex加载\n因为 Android 系统在启动应用时只加载了主 dex（Classes.dex），其他的 dex 需要我们在应用启动后进行动态加载安装。\nGoogle 官方方案是如何加载的呢？\nGoogle 官方支持 Multidex 的 jar 包是 android-support-multidex.jar，该 jar 包从 build tools 21.1 开始支持。这个 jar 加载 apk 中的从 dex 流程如下：\n此处主要的工作就是从 apk 中提取出所有的从 dex（classes2.dex，classes3.dex，…），然后通过反射依次安装加载从 dex 并合并 DexPathList 的 Element 数组。\n如果引用这个 jar 包，MultiDexApplication 的 Java Doc 提供了三种方式来加载从 dex：\n1）在 AndroidManifest.xml 中，把 application 定义为 android.support.multidex.MultiDexApplication。\n2）用自定义的 Application 类继承 android.support.multidex.MultiDexApplication，再配置 application 为自定义的类。\n3）如果之前自定义的 Application 类已经继承了其他 Application 类，而且不想改变，那么可以重写自定义 Application 类的 attachBaseContext() 或者 onCreate() 方法，并添加语句 MultiDex.install(this)。\n为了使改动最小，我们采用上述3）中的调用方式：\n到此为止，用 Google 官方方案进行 dex 拆分和加载就已经完成了。安装运行一下试试！\n3．安装运行\n我们把分包后的 apk 在 Android 4.3的手机上进行安装。没有问题，顺利安装上了！\n没想到的是，启动时没出现任何页面，直接 crash。Crash 的 log 如下：\n从 log 上看，项目在启动闪屏页面时无法实例化 com.example.AppService.AstApp，因为找不到 com.example.AppService.AstApp 这个类。既然 Application 类都找不到，那么我们在 Application 中加载从 dex 更加没有执行到了。\n反编译一下 classes.dex 和 classes2.dex，果然 com.example.AppService.AstApp 是在classes2.dex，所以刚启动时在主 dex（classes.dex） 中找不到 com.example.AppService.AstApp（Application 类）。\n理论上，启动必需的代码应该放在主 dex 中，这些代码包括 Application、BaseActivity 等代码以及继承自它们的代码的一个依赖集。但是我们看到，单纯依赖于构建工具自动进行 dex 拆分时，我们无法决定或干预哪些类应该放在主 dex，哪些类应该放在从 dex，这就可能导致启动时往往会有类库找不到。\n接下来，我们就得想办法来自主定制主、从 dex 包含的文件，使它们完全可控。\n4．Google 官方方案的小结\n采用 Google 官方的拆包方案走到现在，我们需要再梳理一下思路了。\n到现在为止，已经解决的问题是：\n1）能正常打出多个 dex；\n2）可以指定每个 dex 的大小；\n3）可以加载多个 dex。\n尚未解决的问题是：如何指定哪些类应该放到主 dex，哪些类应该放到从 dex？\n关于这个问题，从前面 dx 工具的用法中可得知，我们可以在 dx 的参数中加入—main-dex-list，指定哪些类应该放在主 dex 中（也可同时配合使用参数—minimal-main-dex，指定主 dex 中只包含在—main-dex-list 文件中指定的类）。\n可是问题又来了，怎么得到 main-dex-list 文件？在大的工程开发中，手动添加文件列表显然不现实。\n同时，在前面研究和验证 Google 官方方案的过程中，也有几个不得不提的问题：\n1）需要高版本的 build Tools、SDK Tools 编译打包；\n2）编译打包 apk 后生成的 drawable 密度后缀目录被添加了 v4 后缀；\n3）Google 的 MultiDex 方案在运行中需要比较大的 LinearAlloc，但是由于 Android 4.0 (API level 14) 以下的机器上 Dalvik LinearAlloc 的一个缺陷 (Issue 22586) 和限制 (Issue 78035)，可能导致运行时无法满足 LinearAlloc 的需求而造成 DexOpt 失败或者 Dalvik 虚拟机崩溃；\n4）从 dex 不能太大，否则在运行时安装加载从 dex 的过程比较复杂和耗时，可能会导致应用程序无响应 （ANR） 的错误。\n由于项目是首次做分包，安装包改动已经比较大了，如果再将一直使用且没有问题的 build Tools、SDK Tools 冒然升级以及 drawable 密度后缀目录改变，那么无论怎样，它们所带来的风险和挑战都是比较大的，也会带来后期测试和维护的工作量。所以，我们的方案一定要做到尽量减少这些改变。而对于后面两点，我们就应该考虑对 dex 的拆分进行干预，使每个 dex 的大小在一定的合理范围内，消除或减少触发 Dalvik LinearAlloc 缺陷和限制的概率以及分包引起的 ANR。\n综合以上几点，我们就需要在对官方方案透彻研究的基础上，自己实现工具脚本来进行 dex 的自主拆分、加载，便于灵活的适应低版本 Android SDK tools 以及 Android 平台。\n三、DEX 自动拆包和动态加载方案 1．Dex 拆分\n根据前面对官方方案的研究总结，我们可以很快梳理出下面几个dex拆分步骤：\n1）自动扫描整个工程代码得到 main-dex-list；\n2）根据 main-dex-list 对整个工程编译后的所有 class 进行拆分，将主、从 dex 的 class 文件分开；\n3）用 dx 工具对主、从 dex 的 class 文件分别打包成 .dex 文件，并放在 apk 的合适目录。\n怎么自动生成 main-dex-list？\nAndroid SDK 从 build tools 21 开始提供了 mainDexClasses 脚本来生成主 dex 的文件列表。查看这个脚本的源码，可以看到它主要做了下面两件事情：\n1）调用 proguard 的 shrink 操作来生成一个临时 jar 包；\n2）将生成的临时 jar 包和输入的文件集合作为参数，然后调用com.android.multidex.MainDexListBuilder 来生成主 dex 文件列表。\nProguard的官网执行步骤如下：\n在 shrink 这一步，proguard 会根据 keep 规则保留需要的类和类成员，并丢弃不需要的类和类成员。也就是说，上面 shrink 步骤生成的临时 jar 包里面保留了符合 keep 规则的类，这些类是需要放在主 dex 中的入口类。\n但是仅有这些入口类放在主 dex 还不够，还要找出入口类引用的其他类，不然仍然会在启动时出现 NoClassDefFoundError。而找出这些引用类，就是调用的 com.android.multidex.MainDexListBuilder，它的部分核心代码如下：\n在调用 com.android.multidex.MainDexListBuilder 之后，符合 keep 规则的主 dex 文件列表就生成了。\n既然 Android SDK 已经提供了这样一种比较方便的工具，我们就不再重复发明轮子了。所以我们首先把 mainDexClasses 脚本进行了一些适当的改造，然后移植到 RDM 构建环境下，然后根据项目代码的实际情况将主要的基础类、common 类、wakeup 类做为补充规则加入扫描规则中，再加上基本规则 Application、Activity、Service、Provider、Receiver 等类，就组成了项目的主 dex 扫描规则。\n这时，新的问题是，由于项目编译打包时有代码混淆的步骤，那我们扫描主 dex 文件列表时到底是在代码混淆之前还是之后？理论上，混淆前后都可以扫描，但是混淆之后扫描时主要的问题是：在制定 keep 规则时，最合理的方式是采用包路径来制定规则，而混淆后的代码中大部分包路径被混淆了，我们无法根据混淆后的包路径来制定 keep 规则，也就无法完全指定哪些文件应该放在主 dex 中。所以，结论就是，我们必须在代码混淆之前扫描生成主 dex 文件列表。\n再往下做时，问题又出现了，我们是在扫描生成主 dex 文件列表后就立刻将主、从 dex 的 class 文件拆分到不同目录，然后各自进行代码混淆呢还是统一混淆后再进行 class 文件的拆分呢？答案是，我们需要统一混淆后再做拆分。因为如果拆分后各自混淆，则必然会造成混淆后主、从 dex 引用类名的不一致，从而导致应用无法正常运行。\n但是，这样又有了新的问题，我们是在代码混淆之前扫描生成的主 dex 文件列表，当代码混淆之后，大部分类名称和路径都改变了，我们又如何根据主 dex 文件列表做拆分呢？答案是，因为 proguard 做代码混淆时生成了一个混淆前后代码之间的 mapping 关系文件，我们只需要根据这个 mapping 文件进行映射，即可得到混淆后的主 dex 文件列表。\n到此为止，思路已经梳理得比较清楚了。\n按照这个思路，很快就实现了工具脚本，完成了对主、从 dex 的拆分。这样就实现了主、从 dex 的灵活的生成和定制，不仅解决了前面 Google 官方方案存在的问题，而且也为将来从 dex 的异步加载、按需加载提供了比较好的基础。\n最后，项目的从 dex 是打成 jar 包放在 assets 目录，如下图所示：\n2．Dex加载\nGoogle 官方提供的 android-support-multidex.jar 可以用来加载官方方案打包的 dex，也完全可以用于加载我们自己的方案打包的 dex，但是这种方式有下面几个不利的地方：\n1）灵活性不够，需要所有的从 dex 跟主 dex 在同一级目录，即都在 apk 的根目录，而且从 dex 的命名要符合 classes2.dex、classes3.dex、…、classes(N).dex。\n2）该 jar 包提供的是同步加载方式，而且是启动时一次性加载所有的从 dex，但是从项目分包的需求以及其他产品的经验来看，加载接口提供异步加载和按需加载的能力是很有必要的。\n因此，我们的加载方案需要有比较好的灵活性以及提供同步加载、异步加载、按需加载的能力。根据这些要求，我们研究了网上一些开源的代码（也包括 Google 官方 android-support-multidex.jar 的代码），然后经过改造和验证，实现了一种比较灵活的加载方案。\n跟 Google 官方加载方案一样，这个方案采用的也是运行时动态加载的方式，利用了 Dalvik 虚拟机的类加载器。\n我们知道，在 Java 虚拟机里动态加载用的是 ClassLoader。但是在 Dalvik 虚拟机里，却不是 ClassLoader，Android 为我们从 ClassLoader 派生出了两个类：DexClassLoader 和 PathClassLoader。这两者的区别就是 PathClassLoader 不能主动从 zip 包中释放出 dex，因此只支持直接操作 dex 格式文件，或者已经安装的 apk（因为已经安装的 apk 在 cache 中存在缓存的 dex 文件）；而 DexClassLoader 可以支持 .apk、.jar 和 .dex文件，并且会在指定的 outpath 路径释放出 dex 文件。\n由于前面说了，在安装包里有多个 dex 时，应用安装时不会主动释放从 dex，所以我们需要用 DexClassLoader 来释放加载从 dex。当需要加载从 dex 时，加载逻辑会先从 apk 相应的目录释放出所需加载的从 dex，然后执行加载。\n加载过程的部分核心代码如下：\n上述代码是通过反射获取 PathClassLoader 中的 DexPathList 中的 Element 数组（加载主 dex 后的 Element 数组）和 DexClassLoader 中的 DexPathList 中的 Element 数组（加载从 dex 后的 Element 数组），然后将两个 Element 数组合并之后，再将其赋值给 PathClassLoader 的 Element 数组。这样就将主、从 dex 中类的访问方式进行了统一，所以也称为 dex 的注入。\n那么什么时候加载从 dex 呢？这个问题也就是从 dex 的加载时机。\n如果是启动时同步加载，一般可以在 Application 的 onCreate 或 attachBaseContext 中执行加载，两者区别不大。不过，由于 Application 的 onCreate 调用是在 ContentProvider 的 OnCreate 调用之后，而 attachBaseContext 的调用是在 ContentProvider 的 OnCreate 调用之前，所以当 app 有注册 ContentProvider 的时候，就必须在 attachBaseContext 中加载从 dex。\n如果是按需加载，则在代码充分解耦后，只要在从 dex 中的代码调用之前执行加载，都是可以的。\n3．安装运行\nDex 拆分脚本和加载代码都完成了，打一个包，然后在 Android 2.3 系统的手机上安装运行试试吧。一切顺利，终于出现了久违的闪屏页！\n4．小结\n上面就是项目 dex 分包方案的研究经过，主要是把 Google 的方案研究清楚以后，又参考了网上的一些开源代码，从而实现了自己的 DEX 自动拆包和动态加载方案。在我们的方案中，可以通过脚本工具来完全定制拆分过程和主、从 dex 文件内容，在运行时也能比较自由、灵活的动态加载从 dex。\n四、性能影响 Dex 分包后，如果是启动时同步加载，对应用的启动速度会有一定的影响，但是主要影响的是安装后首次启动。这是因为安装后首次启动时，Android 系统会对加载的从 dex 做 Dexopt 并生成 ODEX，而 Dexopt 是比较耗时的操作，所以对安装后首次启动速度影响较大。在非安装后首次启动时，应用只需加载 ODEX，这个过程速度很快，对启动速度影响不大。同时，从 dex 的大小也直接影响启动速度，即从dex 越小则启动越快。\n目前项目的从 dex 的原始大小在 1M 左右。经过测试，安装后首次启动时，在 GT-I8160(Android 2.3) 上加载耗时大约 1200ms，在 N i9250(Android 4.3) 上加载耗时大约 1000ms；非安装后首次启动时，在这两台测试手机上的加载速度分别为约 10ms 和 4ms。\n五、后续 分包方案落地后，我们又解决了覆盖安装和 MD5 校验的问题。不过后续还有不少可优化的点如下：\n（1） 应用启动性能的优化。如添加启动页、提前做 DexOpt 等；\n（2） 编译脚本性能优化。由于分包是一个比较复杂和耗时的过程，开始时分包脚本的性能并不理想，后来经过我们两次优化，将打包过程中的分包时间从7分多钟优化到10秒以内；\n（3） 研究未来可能的按需加载或异步加载从 dex 的问题。\n","permalink":"https://blog.zdltech.com/posts/dex%E5%88%86%E5%8C%85%E5%8F%98%E5%BD%A2%E8%AE%B0/","summary":"\u003cp\u003e\u003cspan id=\"copyright_logo\" class=\"rich_media_meta meta_original_tag\"\u003e原创\u003c/span\u003e \u003cem\u003e2015-11-26\u003c/em\u003e \u003cem\u003e李金涛\u003c/em\u003e \u003ca id=\"post-user\" class=\"rich_media_meta rich_media_meta_link rich_media_meta_nickname\"\u003e\u003c/a\u003e腾讯Bugly\u003c/p\u003e\n\u003cp\u003e一、背景\u003c/p\u003e\n\u003cp\u003e就在项目灰度测试前不久，爆出了在 Android 3.0以下手机上安装时出现 INSTALL _ FAILED_DEXOPT，导致安装失败。这一问题意味着项目将不能在 Android 3.0以下的手机上安装使用，对项目的发布有比较大的影响，所以必须尽快解决。\u003c/p\u003e\n\u003cp\u003eINSTAL L_FAILED_DEXOPT导致无法安装的问题，从根本上来说，可能是两个原因造成的：\u003c/p\u003e\n\u003cp\u003e（1） 单个 dex 文件方法总数65K 的限制。\u003c/p\u003e\n\u003cp\u003e（2） Dexopt 的 LinearAlloc 限制。\u003c/p\u003e\n\u003cp\u003e当 Android 系统安装一个应用的时候，有一步是对 Dex 进行优化，这个过程有一个专门的工具来处理，叫 DexOpt。DexOpt 是在第一次加载 Dex 文件的时候执行的。这个过程会生成一个 ODEX 文件，即 Optimised Dex。执行 ODEX 的效率会比直接执行 Dex 文件的效率要高很多。\u003c/p\u003e\n\u003cp\u003e但是在早期的 Android 系统中，DexOpt 有两个问题。（一）：DexOpt 会把每一个类的方法 id 检索起来，存在一个链表结构里面，但是这个链表的长度是用一个 short 类型来保存的，导致了方法 id 的数目不能够超过65536个。当一个项目足够大的时候，显然这个方法数的上限是不够的。（二）：Dexopt 使用 LinearAlloc 来存储应用的方法信息。Dalvik LinearAlloc 是一个固定大小的缓冲区。在Android 版本的历史上，LinearAlloc 分别经历了4M/5M/8M/16M限制。Android 2.2和2.3的缓冲区只有5MB，Android 4.x提高到了8MB 或16MB。当方法数量过多导致超出缓冲区大小时，也会造成dexopt崩溃。\u003c/p\u003e\n\u003cp\u003e尽管在新版本的 Android 系统中，DexOpt 修复了方法数65K的限制问题，并且扩大了 LinearAlloc 限制，但是我们仍然需要对低版本的 Android 系统做兼容。\u003c/p\u003e","title":"Dex分包变形记"},{"content":"Android开发又将带来新一轮热潮，很多开发者都投入到这个浪潮中去了，创造了许许多多相当优秀的应用。其中也有许许多多的开发者提供了应用开源项 目，贡献出他们的智慧和创造力。学习开源代码是掌握技术的一个最佳方式。下面推荐几个应用开源项目，这些项目不仅提供了优秀的创意，也可以直接掌握 Android内核的接口使用：\n1.Android团队提供的示例项目\n如果不是从学习Android SDK中提供的那些样例代码开始，可能没有更好的方法来掌握在Android这个框架上开发。由Android的核心开发团队提供了15个优秀的示例项 目，包含了游戏、图像处理、时间显示、开始菜单快捷方式等。\n地址：http://code.google.com/p/apps-for-android/\n2.Remote Droid\nRemoteDroid是一个Android应用，能够让用户使用自己的无线网络使用无线键盘、触摸屏操作手机。这个项目为开发者提供了如网络连接、触 摸屏手指运动等很好的样例。\n地址：http://code.google.com/p/remotedroid/\n3.TorProxy和Shadow\nTorProxy应用实现了Android手机无线电电传通讯(TOR)，和Shadow应用一起使用，可以使用手机匿名上网。从该项目源代码中，可以 掌握socket连接、管理cookie等方法。\n地址：http://www.cl.cam.ac.uk/research/dtg/code/svn/android-tor/\nhttp://www.cl.cam.ac.uk/research/dtg/android/tor/\n4、 Android SMSPopup\nSMSPopup可以截获短信内容显示在一个泡泡形状的窗口中。从这个项目中可以掌握到如何使用内置的短信SMS接口。\n地址：http://code.google.com/p/android-smspopup/\n5、 Standup Timer\nStandup Timer应用用于控制站立会议时间，类似秒表倒计时，可以提醒每个人的讲话时间已到，从而保证每个与会者使用时间一样。从该项目的代码中，可以学会如何 使用时间函数。另外，这个项目的代码是采用视图view、模型model严格分离的设计思路。\n地址：http://github.com/jwood/standup-timer\n6、 Foursquare\n是Foursquare.com的一个客户端应用，该应用主要分为两个模块：API(com.joelapenna.foursquare)和界面前端 (com.joelapenna.foursquared)两部分。从该项目代码中，可以学会如何同步、多线程、HTTP连接等技术。\n地址：http://code.google.com/p/foursquared/\n7、 Pedometer\nPedometer应用用于记录你每天走路步数的。尽管记录不一定精准，但是从这个项目中，可以学习几个不同的技术：加速器交互、语音更新、后台运行服 务等。\n地址：http://code.google.com/p/pedometer/\n8、 OpenSudoku-android\nOpenSudoku是一个简单的九宫格数独游戏。从代码中可以学习到如何在视图中显示表格数据，以及如何和一个网站交互等技术。\n地址：http://code.google.com/p/opensudoku-android/\n9、 ConnectBot\nConnectBot是Android平台的一个客户端安全壳应用。从该项目代码中，可以学习到很多Android安全方面的内容，这些是你在开发应用 时经常需要考虑的安全问题。\n地址：http://code.google.com/p/connectbot/\n10、 WordPress的Android应用\n当然在最后不能不提WordPress的Android应用了，这是WordPress官方开发团队提供的一个项目。从代码中可以学习到XMLRPC调 用（当然还有更多的优秀内容）。\n地址：http://android.svn.wordpress.org/trunk/\n","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E5%8F%91%E8%80%85%E5%BF%85%E9%A1%BB%E6%B7%B1%E5%85%A5%E5%AD%A6%E4%B9%A0%E7%9A%8410%E4%B8%AA%E5%BA%94%E7%94%A8%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/","summary":"\u003cp\u003eAndroid开发又将带来新一轮热潮，很多开发者都投入到这个浪潮中去了，创造了许许多多相当优秀的应用。其中也有许许多多的开发者提供了应用开源项 目，贡献出他们的智慧和创造力。学习开源代码是掌握技术的一个最佳方式。下面推荐几个应用开源项目，这些项目不仅提供了优秀的创意，也可以直接掌握 Android内核的接口使用：\u003cbr\u003e\n1.Android团队提供的示例项目\u003cbr\u003e\n如果不是从学习Android SDK中提供的那些样例代码开始，可能没有更好的方法来掌握在Android这个框架上开发。由Android的核心开发团队提供了15个优秀的示例项 目，包含了游戏、图像处理、时间显示、开始菜单快捷方式等。\u003cbr\u003e\n地址：\u003ca href=\"http://code.google.com/p/apps-for-android/\"\u003ehttp://code.google.com/p/apps-for-android/\u003c/a\u003e\u003cbr\u003e\n2.Remote Droid\u003cbr\u003e\nRemoteDroid是一个Android应用，能够让用户使用自己的无线网络使用无线键盘、触摸屏操作手机。这个项目为开发者提供了如网络连接、触 摸屏手指运动等很好的样例。\u003cbr\u003e\n地址：\u003ca href=\"http://code.google.com/p/remotedroid/\"\u003ehttp://code.google.com/p/remotedroid/\u003c/a\u003e\u003cbr\u003e\n3.TorProxy和Shadow\u003cbr\u003e\nTorProxy应用实现了Android手机无线电电传通讯(TOR)，和Shadow应用一起使用，可以使用手机匿名上网。从该项目源代码中，可以 掌握socket连接、管理cookie等方法。\u003cbr\u003e\n地址：\u003ca href=\"http://www.cl.cam.ac.uk/research/dtg/code/svn/android-tor/\"\u003ehttp://www.cl.cam.ac.uk/research/dtg/code/svn/android-tor/\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"http://www.cl.cam.ac.uk/research/dtg/android/tor/\"\u003ehttp://www.cl.cam.ac.uk/research/dtg/android/tor/\u003c/a\u003e\u003cbr\u003e\n4、 Android SMSPopup\u003cbr\u003e\nSMSPopup可以截获短信内容显示在一个泡泡形状的窗口中。从这个项目中可以掌握到如何使用内置的短信SMS接口。\u003cbr\u003e\n地址：\u003ca href=\"http://code.google.com/p/android-smspopup/\"\u003ehttp://code.google.com/p/android-smspopup/\u003c/a\u003e\u003cbr\u003e\n5、 Standup Timer\u003cbr\u003e\nStandup Timer应用用于控制站立会议时间，类似秒表倒计时，可以提醒每个人的讲话时间已到，从而保证每个与会者使用时间一样。从该项目的代码中，可以学会如何 使用时间函数。另外，这个项目的代码是采用视图view、模型model严格分离的设计思路。\u003cbr\u003e\n地址：\u003ca href=\"http://github.com/jwood/standup-timer\"\u003ehttp://github.com/jwood/standup-timer\u003c/a\u003e\u003cbr\u003e\n6、 Foursquare\u003cbr\u003e\n是Foursquare.com的一个客户端应用，该应用主要分为两个模块：API(com.joelapenna.foursquare)和界面前端 (com.joelapenna.foursquared)两部分。从该项目代码中，可以学会如何同步、多线程、HTTP连接等技术。\u003cbr\u003e\n地址：\u003ca href=\"http://code.google.com/p/foursquared/\"\u003ehttp://code.google.com/p/foursquared/\u003c/a\u003e\u003cbr\u003e\n7、 Pedometer\u003cbr\u003e\nPedometer应用用于记录你每天走路步数的。尽管记录不一定精准，但是从这个项目中，可以学习几个不同的技术：加速器交互、语音更新、后台运行服 务等。\u003cbr\u003e\n地址：\u003ca href=\"http://code.google.com/p/pedometer/\"\u003ehttp://code.google.com/p/pedometer/\u003c/a\u003e\u003cbr\u003e\n8、 OpenSudoku-android\u003cbr\u003e\nOpenSudoku是一个简单的九宫格数独游戏。从代码中可以学习到如何在视图中显示表格数据，以及如何和一个网站交互等技术。\u003cbr\u003e\n地址：\u003ca href=\"http://code.google.com/p/opensudoku-android/\"\u003ehttp://code.google.com/p/opensudoku-android/\u003c/a\u003e\u003cbr\u003e\n9、 ConnectBot\u003cbr\u003e\nConnectBot是Android平台的一个客户端安全壳应用。从该项目代码中，可以学习到很多Android安全方面的内容，这些是你在开发应用 时经常需要考虑的安全问题。\u003cbr\u003e\n地址：\u003ca href=\"http://code.google.com/p/connectbot/\"\u003ehttp://code.google.com/p/connectbot/\u003c/a\u003e\u003cbr\u003e\n10、 WordPress的Android应用\u003cbr\u003e\n当然在最后不能不提WordPress的Android应用了，这是WordPress官方开发团队提供的一个项目。从代码中可以学习到XMLRPC调 用（当然还有更多的优秀内容）。\u003cbr\u003e\n地址：\u003ca href=\"http://android.svn.wordpress.org/trunk/\"\u003ehttp://android.svn.wordpress.org/trunk/\u003c/a\u003e\u003c/p\u003e","title":"Android开发者必须深入学习的10个应用开源项目"},{"content":" 每个人都知道一个 App 的成功，与这个 App 的性能体验有着很密切的关系。但是如何让你的 App 拥有极致性能体验呢？在 DroidCon NYC 2015 的这个分享里，Boris Farber 带来了他关于 Android Api 以及如何避免一些常见坑的经验。带你了解如何缩短启动时间，优化滑动效果，创建更加顺滑的用户体验。 \u0026lt;div class=\u0026quot;company-info\u0026quot;\u0026gt; Transcription below provided by Realm: a replacement for SQLite that you can use in Java or Kotlin. [Check out the docs!](https://realm.io/docs/java/latest/) \u0026lt;/div\u0026gt; [Sign up to be notified of new videos](http://eepurl.com/2mbQX) — we won’t email you for any other reason, ever. \u0026lt;hr /\u0026gt; \u0026lt;div class=\u0026quot;author-info\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;author-info-name\u0026quot;\u0026gt; About the Speaker: Boris Farber \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;author-info-bio\u0026quot;\u0026gt; 每个人都知道一个 App 的成功，更这个 App 的性能体验有着很密切的关系。但是如何让你的 App 拥有极致性能体验呢？在 DroidCon NYC 2015 的这个分享里，Boris Farber 带来了他关于 Android Api 以及如何避免一些常见的坑的经验。了解如何缩短启动时间，优化滑动效果，创建更加顺滑的用户体验。 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;author-info-links\u0026quot;\u0026gt; [**@borisfarber](https://twitter.com/borisfarber) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;hr /\u0026gt; *Save the date for [Droidcon SF](http://sf.droidcon.com/) in March — a conference with best-in-class presentations from leaders in all parts of the Android ecosystem.* \u0026lt;hr /\u0026gt; ### 简介 \u0026lt;a\u0026gt;(0:00)\u0026lt;/a\u0026gt; 大家好，我是 Boris，现在是 Google 的一枚员工，目前专注于需要高性能的 App。这个分享是我长期以来从错误中，以及在给合作伙伴做咨询的时候攒下的最佳实践。如果你有一个小型的 App，读过之后，会在你的 App 成长阶段起到帮助。 我常常会见到那些启动时间很长，滑动不流畅，甚至出现没有反应的 App。我们通常要花很多时间去改善这些问题，毕竟我们都希望自己的 App 能够成功。 ### Activity 泄漏 \u0026lt;a\u0026gt;(1:17)\u0026lt;/a\u0026gt; 我们第一个需要修复的问题就是 Activity 泄漏，我们先来看看内存泄漏是怎么发生的。 Activity 泄漏通常是内存泄漏的一种。为什么会泄漏呢？如果你持有一个未使用的 Activity 的引用，其实也就持有了 Activity 的布局，自然也就包含了所有的 View。最棘手的是持有静态引用。别忘了，Activity 和 Fragment 都有自己的生命周期。一旦我们持有了静态引用，Activity 和 Fragment 就不会被垃圾回收器清理掉了。这就是为什么静态引用很危险。 \u0026lt;div class=\u0026quot;highlighter-rouge\u0026quot;\u0026gt; ``` \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;m_staticActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;staticFragment\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getActivity\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt;\n\u0026lt;/div\u0026gt; 我看过太多次这样的代码了。 另外，泄漏 Listener 也是经常会发生的事情。比如说，我有下面的代码。`LeakActivity`继承自`Activity`，我们有一个单例：`NastyManager`，当我们通过 `addListener(this)` 将 Activity 作为 Listener 和 NastyManager 绑定起来的时候，不好的事情就发生了。 \u0026lt;div class=\u0026#34;highlighter-rouge\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nc\u0026#34;\u0026gt;LeakActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Activity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nd\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Bundle\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;NastyManager\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;getInstance\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;().\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;addListener\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt;` \u0026lt;/div\u0026gt; 想要修复这样的 Bug，其实相当简单，就是在你的 Acitivity 被销毁的时候，将他和`NastyManager` 取消掉绑定就好了。 \u0026lt;div class=\u0026quot;highlighter-rouge\u0026quot;\u0026gt; ``` `\u0026lt;span class=\u0026ldquo;nd\u0026rdquo;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kt\u0026rdquo;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;nf\u0026rdquo;\u0026gt;onDestroy\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;p\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;super\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;onDestroy\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;();\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;NastyManager\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;getInstance\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;().\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;na\u0026rdquo;\u0026gt;removeListener\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt;`\n\u0026lt;/div\u0026gt; 相对上面的解决方案，我们自然还有更好的。比如我们真的需要用到单例吗？通常，并不需要。不过某些时候可能真的很需要。我们得权衡和设计。不过无论如何，记住，**当 Activity 销毁的时候，在单例中移除掉对 Activity 的引用**。下面我们讨论下： **如果是内部类，会发生什么**？比如说，我们有一个在 Activity 里有一个很简短的非静态 Handler。 尽管它看起来很短，但是只要它还存活着，那么包含它的 Activity 就会存活着。如果你不信我，在 VM 里试试看。这就是另一个内存泄漏的案例：**Activity 内部的 Handler**。 \u0026lt;div class=\u0026#34;highlighter-rouge\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nc\u0026#34;\u0026gt;MainActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Activity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;c1\u0026#34;\u0026gt;//...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Handler\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;handler\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nd\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Bundle\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;savedInstanceState\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;c1\u0026#34;\u0026gt;//...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;handler\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Handler\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nd\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;handleMessage\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Message\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;msg\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt;` \u0026lt;/div\u0026gt; Handler 是个很常用也很有用的类，异步，线程安全等等。如果有下面这样的代码，会发生什么呢？`handler.postDeslayed` ，假设 delay 时间是几个小时… 这意味着什么？意味着只要 handler 的消息还没有被处理结束，它就一直存活着，包含它的 Activity 就跟着活着。我们来想办法修复它，修复的方案是`WeakReference`，也就是所谓的弱引用。垃圾回收器在回收的时候，是会忽视掉弱引用的，所以包含它的 Activity 会被正常清理掉。大概代码如下： \u0026lt;div class=\u0026quot;highlighter-rouge\u0026quot;\u0026gt; ``` `\u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;nc\u0026rdquo;\u0026gt;MyHandler\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Handler\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;WeakReference\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;MainActivity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;mActivity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;// \u0026hellip;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;MyHandler\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;MainActivity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;mActivity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;k\u0026rdquo;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;WeakReference\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;MainActivity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;//\u0026hellip; \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;nd\u0026rdquo;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kd\u0026rdquo;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;kt\u0026rdquo;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;handleMessage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;Message\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;n\u0026rdquo;\u0026gt;msg\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;c1\u0026rdquo;\u0026gt;//\u0026hellip;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;o\u0026rdquo;\u0026gt;}\u0026lt;/span\u0026gt;`\n\u0026lt;/div\u0026gt; 概括来说：我们有个内部类，就像 Handler，内部非静态类是不能脱离所属类而单独存活的，Android 里通常是 Activity。所以，看看你的代码里的内部类，确保他们没有出现内存泄漏。 相比非静态内部类，最好使用静态内部类。区别就是静态内部类不依赖所属类，他们拥有不同的生命周期。我经常见到类似的原因引起的内存泄露。 #### 如何避免 Activity 泄漏? \u0026lt;a\u0026gt;(8:37)\u0026lt;/a\u0026gt; - 移除掉所有的静态引用。 - 考虑用 EventBus 来解耦 Listener。 - 记着在不需要的时候，解除 Listener 的绑定。 - 尽量用静态内部类。 - 做 Code Review。个人经验：Code Review 能很早的发现内存泄漏。 - 了解你程序的结构。 - 用类似 MAT，Eclipse Analyzer，LeakCanary 这样的工具分析内存。 - 在 Callback 里打印 Log。​ ### 滑动 \u0026lt;a\u0026gt;(10:05)\u0026lt;/a\u0026gt; 实现流畅滑动的技巧：UI 线程只用作 UI 渲染。这一条真谛能够解决 99% 的滑动卡顿问题。不要在 UI 线程做下面的事情： - 载入图片 - 网络请求 - 解析 JSON - 读取数据库 做这些操作是很慢的，像图片，网络，JSON考虑用现成的库，有很多社区提供的解决方案，数据库考虑下用 Loader，支持批量更新和载入。 #### 图片 \u0026lt;a\u0026gt;(11:26)\u0026lt;/a\u0026gt; 图片相关的库有很多，比如 [Glide](https://github.com/bumptech/glide), [Picasso](https://github.com/square/picasso), [Fresco](https://github.com/facebook/fresco)。你可以自己去了解下他们之间的区别，以帮助自己在特定场景下做出取舍。 #### 内存\u0026lt;a\u0026gt;(12:13)\u0026lt;/a\u0026gt; Bitmap 操作是很需要技巧的，图片一般比较大，而且系统对最大内存又有限制和要求。在我面对 4.0 之前的系统的时候，我简直要崩溃了。内存管理也很需要技巧。有的时候需要放到文件里，有的时候需要放到内存里，别忘了，我们还有一个很有用的工具：LRUCache。 #### 网络\u0026lt;a\u0026gt;(12:54)\u0026lt;/a\u0026gt; 首先，Java 的网络请求确实是 Android 的一个阻碍。很多 Java.net 的 API 都是阻断执行的，切记不可在 UI 线程执行网络请求。在线程里执行或者直接使用第三方库吧。 异步 HTTP 其实也挺麻烦的，4.4 起 OkHttp 就成了 Android 代码的一部分了，然而… 如果你需要最新版本的 OkHttp ，可以考虑自己引入。另外有个不错的库叫： [Volley](https://android.googlesource.com/platform/frameworks/volley)，也可以试试 Square 的[Retrofit](https://github.com/square/retrofit)。这些都能让你的网络请求变得更友好。 #### 大 JSON \u0026lt;a\u0026gt;(14:35)\u0026lt;/a\u0026gt; 在 UI 线程，也不做解析 Json 的事情，因为这是一个很耗时的事情。试着用 Google 的 [GSON](https://github.com/google/gson) 来做反序列化的操作。 对于巨大的 JSON 解析，建议用更快的 [Jackson](https://github.com/FasterXML/jackson) 以及 [ig-json-parser](https://github.com/Instagram/ig-json-parser)，这两个工具在 JSON 的解析上做的非常漂亮。从公司的反馈结果来看 ig-json-parser 的效率是最高的。 `Looper.myLooper() == Looper.getMainLooper()` 是可以帮助你确定你是否在主线程的代码。 #### 如何优化滑动速度? \u0026lt;a\u0026gt;(16:56)\u0026lt;/a\u0026gt; - UI 线程只做 UI 更新。 - 理解并发 API。 - 开始使用优秀的第三方库。 - 使用 Loader 加载数据库数据 之所以要用第三方库，是因为你自己去完善一个复杂功能是需要花时间的。如果你打算专注在自己的功能性的 App 上，那么用库吧。 ### 并发 APIs \u0026lt;a\u0026gt;(18:00)\u0026lt;/a\u0026gt; 如何让 App 快速响应请求是个很重要。开发者们，甚至包括我，经常忘记 Service 的方法是在 UI 线程执行的。请考虑使用 `IntentService`，`AsyncTask`，`Executors`，`Handler` 和 `Loopers`。 我们来盘点下这些的区别： #### IntentService \u0026lt;a\u0026gt;(19:07)\u0026lt;/a\u0026gt; 我在之前的公司，我用 IntentService 来执行上传功能。IntentService 是一个单线程，一次一个任务的工作流。我们没有很复杂的任务系统。如果你有大型复杂的任务，而且这个任务不需要跟 UI 打交道，那么考虑用 IntentService 吧。 #### AsyncTask \u0026lt;a\u0026gt;(19:56)\u0026lt;/a\u0026gt; 如果你的任务需要更新 UI，那么考虑用 AsyncTask 吧，AsyncTask 虽然相对容易，但是有些坑得留意。当你旋转手机的时候，Activity 会被关闭，然后重启。不然可能造成内存泄露。 #### Executor Framework \u0026lt;a\u0026gt;(21:11)\u0026lt;/a\u0026gt; 这是 Java 6 自带的并发方案。默认是存在一个由系统管理的线程池，你可以通过 callback，future 来控制和管理。这根 MapRedues 发难有点像，面对复杂的任务，你希望能够把他们拆分交给多个线程来处理。Executor 的框架就很能胜任这种场景。 #### 如何适应并发APIs? \u0026lt;a\u0026gt;(22:07)\u0026lt;/a\u0026gt; - 学会和理解 API，懂得权衡 - 确保找到了问题的正确解决方案 - 了解问题真实所在 - 重构代码​ ### Deprecation \u0026lt;a\u0026gt;(22:42)\u0026lt;/a\u0026gt; 我们肯定都知道，最好能够避免使用废弃的 API。比如以下的例子： - 不要通过反射来调用私有 API。 - 不要再 NDK 和 C 语言层调用私有 Native 方法。 - 不要轻易调用 Runtime.exec 指令完成进程通讯功能。 - `adb shell am` 做进程通讯并不好。 废弃的意思是这些 API 将会被移除，通常在正式版发布 1，2天左右，你的 App 就不会工作了。更糟糕的情况是，如果你的 App 依赖了一些库，而这些库哟改了废弃的 Api 或者工具。那可就惨了，如果一旦作者没有更新…你懂得。 不要用废弃 Api 的另一个原因是性能问题和安全问题。 如何避免废弃 Api： - 使用正确的 API。 - 重构依赖。 - 不要滥用系统。 - 更新依赖和工具。 - 越新的通常越好。 用 Toolbar 而非 ActionBar，在需要动画的时候用 RecyclerView，因为它专门为动画做过优化。同时 Android M 里移除了 Apache Http Connection。请使用 HttpURLConnection，它拥有更简单的 API，更小的体积，默认的压缩功能，更好的 Response 缓存，等等其他很赞的功能。 ### 架构 \u0026lt;a\u0026gt;(27:03)\u0026lt;/a\u0026gt; 架构中的 Bug 总是最为烦人。想要避免这种问题，学习下 App 组件的生命周期。比如什么是 Activity 的 Flag？什么是 Fragment？什么事 stated fragment？什么是 task？读读文档，尝试下用回调的 log 搞清楚这些概念。 时常有人问我：“Picasso 和 Glide 哪个更好？我改用 Volley 还是 OkHttp？”，这种问题根本没有 100% 正确的答案。不过，当我在选择一个库的时候，我会用下面的 Checklist 来决策： - 确保它能够解决你的问题。 - 确保它和当前所有的依赖能正常工作。 - 检查依赖 - 留意一下依赖的版本冲突 - 了解维护情况和成本 总的来说，提及架构和设计，最好的\b方法就是让你的程序最快响应。确保用户能够快速理解你的 App，并且拥有良好体验。 转自：https://realm.io/cn/news/droidcon-farber-improving-android-app-performance/ \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/10-%E6%9D%A1%E6%8F%90%E5%8D%87-android-%E6%80%A7%E8%83%BD%E7%9A%84%E5%BB%BA%E8%AE%AE/","summary":"\u003cdiv class=\"row\"\u003e\n  \u003cdiv class=\"col-md-8 col-md-offset-2\"\u003e\n\u003cpre\u003e\u003ccode\u003e  每个人都知道一个 App 的成功，与这个 App 的性能体验有着很密切的关系。但是如何让你的 App 拥有极致性能体验呢？在 DroidCon NYC 2015 的这个分享里，Boris Farber 带来了他关于 Android Api 以及如何避免一些常见坑的经验。带你了解如何缩短启动时间，优化滑动效果，创建更加顺滑的用户体验。\n\n\n\n\u0026lt;div class=\u0026quot;company-info\u0026quot;\u0026gt;\n  Transcription below provided by Realm: a replacement for SQLite that you can use in Java or Kotlin. [Check out the docs!](https://realm.io/docs/java/latest/)\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"row video-row\"\u003e\n  \u003cdiv class=\"col-md-6 video-col\"\u003e\n    \u003cdiv id=\"video-player\" class=\"flex-video widescreen\"\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"col-md-6 video-col\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"row\"\u003e\n  \u003cdiv class=\"col-md-8 col-md-offset-2\"\u003e\n    \u003csection class=\"newsletter-meetup\"\u003e[Sign up to be notified of new videos](http://eepurl.com/2mbQX) \u003csmall\u003e— we won’t email you for any other reason, ever.\u003c/small\u003e\u003c/section\u003e \n\u003cpre\u003e\u003ccode\u003e\u0026lt;hr /\u0026gt;\n\n\u0026lt;div class=\u0026quot;author-info\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;author-info-name\u0026quot;\u0026gt;\n    About the Speaker: Boris Farber\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div class=\u0026quot;author-info-bio\u0026quot;\u0026gt;\n    \n\n      每个人都知道一个 App 的成功，更这个 App 的性能体验有着很密切的关系。但是如何让你的 App 拥有极致性能体验呢？在 DroidCon NYC 2015 的这个分享里，Boris Farber 带来了他关于 Android Api 以及如何避免一些常见的坑的经验。了解如何缩短启动时间，优化滑动效果，创建更加顺滑的用户体验。\n    \n\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div class=\u0026quot;author-info-links\u0026quot;\u0026gt;\n    [**@borisfarber](https://twitter.com/borisfarber)\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;hr /\u0026gt;\n\n\n\n  *Save the date for [Droidcon SF](http://sf.droidcon.com/) in March — a conference with best-in-class presentations from leaders in all parts of the Android ecosystem.*\n\n\n\n\u0026lt;hr /\u0026gt;\n\n### 简介 \u0026lt;a\u0026gt;(0:00)\u0026lt;/a\u0026gt;\n\n\n\n  大家好，我是 Boris，现在是 Google 的一枚员工，目前专注于需要高性能的 App。这个分享是我长期以来从错误中，以及在给合作伙伴做咨询的时候攒下的最佳实践。如果你有一个小型的 App，读过之后，会在你的 App 成长阶段起到帮助。\n\n\n\n\n\n  我常常会见到那些启动时间很长，滑动不流畅，甚至出现没有反应的 App。我们通常要花很多时间去改善这些问题，毕竟我们都希望自己的 App 能够成功。\n\n\n\n### Activity 泄漏 \u0026lt;a\u0026gt;(1:17)\u0026lt;/a\u0026gt;\n\n\n\n  我们第一个需要修复的问题就是 Activity 泄漏，我们先来看看内存泄漏是怎么发生的。 Activity 泄漏通常是内存泄漏的一种。为什么会泄漏呢？如果你持有一个未使用的 Activity 的引用，其实也就持有了 Activity 的布局，自然也就包含了所有的 View。最棘手的是持有静态引用。别忘了，Activity 和 Fragment 都有自己的生命周期。一旦我们持有了静态引用，Activity 和 Fragment 就不会被垃圾回收器清理掉了。这就是为什么静态引用很危险。\n\n\n\n\u0026lt;div class=\u0026quot;highlighter-rouge\u0026quot;\u0026gt;\n  ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003e\u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;m_staticActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;n\u0026quot;\u0026gt;staticFragment\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;na\u0026quot;\u0026gt;getActivity\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026quot;o\u0026quot;\u0026gt;()\u0026amp;lt;/span\u0026gt;\u003c/code\u003e\u003c/p\u003e","title":"10 条提升 Android 性能的建议"},{"content":" **【工匠若水 [http://blog.csdn.net/yanbober](http://blog.csdn.net/yanbober) 转载请注明出处。[点我开始Android技术交流](https://github.com/yanbober/AndroidCommunication)】** # \u0026lt;a name=\u0026quot;t0\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**1 背景** 在开始Gradle之前请务必保证自己已经初步了解了Groovy脚本，特别是闭包规则，如果还不了解Groovy则可以先看[《Groovy脚本基础全攻略》](http://blog.csdn.net/yanbober/article/details/49047515)这一篇博客速成一下Groovy基础，然后再看此文即可。关于Gradle速成干货基础详情也请参考[Geadle官方网站](https://www.gradle.org/)，不好意思我太Low了。 ![这里写图片描述](http://img.blog.csdn.net/20151025165437078) Gradle核心是基于Groovy的领域特定语言(DSL，具体概念参见[《Groovy脚本基础全攻略》](http://blog.csdn.net/yanbober/article/details/49047515))，具有非常好的扩展性，所以不管是简单的独立项目还是大型的多项目构建它都能高效的提高构建任务，尤其对多项目支持是非常牛逼的；Gradle还提供了局部构建功能，譬如构建一个单独子项目时它会构建这个子项目依赖的所有子项目；当然了他对远程仓库和本地库的支持也很到位；哎呀，总之后面你就明白他的牛逼之处了。 既然Gradle核心是Groovy，Groovy本质又是Java，所以很明显可以发现Gradle环境必须依赖JDK与Groovy库，具体如下： - JDK版本必须是JDK6以上； - 因为Gradle自带Groovy库, 所以已安装的Groovy会被Gradle忽略； 具体Gradle环境配置好了以后如下图： ![这里写图片描述](http://img.blog.csdn.net/20151022113143209) **【工匠若水 [http://blog.csdn.net/yanbober](http://blog.csdn.net/yanbober) 转载请注明出处。[点我开始Android技术交流](https://github.com/yanbober/AndroidCommunication)】** # \u0026lt;a name=\u0026quot;t1\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**2 Gradle DSL基础** Gradle的实质是配置脚本，执行一种类型的配置脚本时就会创建一个关联的对象，譬如执行Build script脚本就会创建一个Project对象，这个对象其实就是Gradle的代理对象。下面给出来各种类型Gradle对应的对象类型： \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;th\u0026gt; 脚本类型 \u0026lt;/th\u0026gt; \u0026lt;th\u0026gt; 关联对象类型 \u0026lt;/th\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; Build script \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; Project \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; Init script \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; Gradle \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; Settings script \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; Settings \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; Gradle的三种主要对象解释如下： - Project对象：每个build.gradle会转换成一个Project对象。 - Gradle对象：构建初始化时创建，整个构建执行过程中只有这么一个对象，一般很少去修改这个默认配置脚本。 - Settings对象：每个settings.gradle会转换成一个Settings对象。 可以看见，当我们编写指定类型Gradle脚本时我们可以直接使用关联对象的属性和方法；当然了，每个脚本也都实现了Script接口，也就是说我们也可以直接使用Script接口的属性与方法。 ## \u0026lt;a name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**2-1 构建脚本Build script（Project）** 在Gradle中每个待编译的工程都是一个Project（每个工程的build.gradle对应一个Project对象），每个Project在构建的时候都包含一系列Task，这些Task中很多又是Gradle的插件默认支持的。 PS：所谓的我们编写Gradle脚本，实质大多数时候都是在编写构建脚本Build script，所以说Project和Script对象的属性和方法等API非常重要。 每一个Project对象和build.gradle一一对应，一个项目在构建时都具备如下流程： - 为当前项目创建一个Settings类型的实例。 - 如果当前项目存在settings.gradle文件，则通过该文件配置刚才创建的Settings实例。 - 通过Settings实例的配置创建项目层级结构的Project对象实例。 - 最后通过上面创建的项目层级结构Project对象实例去执行每个Project对应的build.gradle脚本。 ## \u0026lt;a name=\u0026quot;t3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**2-2 初始化脚本Init script（Gradle）和设置脚本Settings script（Settings）** **Gradle对象：** 初始化脚本Init script（Gradle）类似于Gradle的其他类型脚本，这种脚本在构建开始之前运行，主要的用途是为接下来的Build script做一些准备工作。我们如果需要编写初始化脚本Init script，则可以把它按规则放置在USER_HOME/.gradle/相关目录下。譬如： ![这里写图片描述](http://img.blog.csdn.net/20151025171346780) 初始化脚本的Gradle对象代表了Gradle的调运，我们可以通过调用Project对象的getGradle()方法获得Gradle实例对象。 **Settings对象：** 在对工程进行配置（譬如多项目树构建）时Settings实例与settings.gradle文件一一对应，它用来进行一些项目设置的配置。这个文件一般放置在工程的根目录。譬如： ![这里写图片描述](http://img.blog.csdn.net/20151025171558864) ## \u0026lt;a name=\u0026quot;t4\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**2-3 Build生命周期** Gradle的构建脚本生命周期具备三大步，如下： ![这里写图片描述](http://img.blog.csdn.net/20151025173643212) 可以看见，生命周期其实和上面构建脚本Build script的执行流程是可以关联上的。有了这个流程图我们接下里详细看下每个过程。 **settings.gradle文件：** 除了构建脚本文件，Gradle还定义了一个约定名称的设置文件（默认为settings.gradle）。该文件在初始化阶段被执行，对于多项目构建必须保证在根目录下有settings.gradle文件，对于单项目构建设置文件是可选的，不过建议还是写上。 如下是单项目构建的一个例子： ``` \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//settings.gradle\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-built_in\u0026quot;\u0026gt;println\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'This is executed during the initialization phase.'\u0026amp;lt;/span\u0026gt;\n- 1 - 2 ``` `\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//build.gradle\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;println\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;This is executed during the configuration phase.\u0026#39;\u0026amp;lt;/span\u0026gt; task configured { \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;println\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;This is also executed during the configuration phase.\u0026#39;\u0026amp;lt;/span\u0026gt; } task test \u0026amp;lt;\u0026amp;lt; { \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;println\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;This is executed during the execution phase.\u0026#39;\u0026amp;lt;/span\u0026gt; } task testBoth { doFirst { \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;println\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;This is executed first during the execution phase.\u0026#39;\u0026amp;lt;/span\u0026gt; } doLast { \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;println\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;This is executed last during the execution phase.\u0026#39;\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;println\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;This is executed during the configuration phase as well.\u0026#39;\u0026amp;lt;/span\u0026gt; }` - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 运行构建结果： ``` `\u0026gt; gradle test testBoth This \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;is\u0026lt;/span\u0026gt; executed during \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;the\u0026lt;/span\u0026gt; initialization phase. This \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;is\u0026lt;/span\u0026gt; executed during \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;the\u0026lt;/span\u0026gt; configuration phase. This \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;is\u0026lt;/span\u0026gt; also executed during \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;the\u0026lt;/span\u0026gt; configuration phase. This \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;is\u0026lt;/span\u0026gt; executed during \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;the\u0026lt;/span\u0026gt; configuration phase \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;as\u0026lt;/span\u0026gt; well. :test This \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;is\u0026lt;/span\u0026gt; executed during \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;the\u0026lt;/span\u0026gt; execution phase. :testBoth This \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;is\u0026lt;/span\u0026gt; executed \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;first\u0026lt;/span\u0026gt; during \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;the\u0026lt;/span\u0026gt; execution phase. This \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;is\u0026lt;/span\u0026gt; executed \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;last\u0026lt;/span\u0026gt; during \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;the\u0026lt;/span\u0026gt; execution phase.\nBUILD SUCCESSFUL\nTotal \u0026lt;span class=\u0026ldquo;hljs-property\u0026rdquo;\u0026gt;time\u0026lt;/span\u0026gt;: \u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;1\u0026lt;/span\u0026gt; secs`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 **Gradle多项目构建：** 多项目构建总是需要指定一个树根，树中的每一个节点代表一个项目，每一个Project对象都指定有一个表示在树中位置的路径；在设置文件中我们还可以使用一套方法来自定义构建项目树。 ``` `\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//分层布局的多项目构建settings.gradle文件\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;include\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;project1\u0026#39;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;project2:child\u0026#39;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;project3:child1\u0026#39;\u0026amp;lt;/span\u0026gt;` - 1 - 2 上面例子中把project的路径作为了include方法的参数，譬如上面的’project3:child1’参数就指定了物理路径的project3/child1（project3/child1是相对于多项目根路径的相对路径），这也同时意味着会创建’project3’和’project3:child1’两个project。 ``` \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//平面布局的多项目构建settings.gradle文件\u0026amp;lt;/span\u0026gt; includeFlat \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'project3'\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'project4'\u0026amp;lt;/span\u0026gt;\n- 1 - 2 上面例子中includeFlat方法接受目录名作为参数，但是特别注意，这些项目目录必须是根目录的兄弟目录。 当然了，设置文件中创建的多项目树其实是由项目描述符来描述的，我们可以在设置文件中随时修改这些描述符。如下： ``` `\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//settings.gradle\u0026amp;lt;/span\u0026gt; rootProject.name = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;main\u0026#39;\u0026amp;lt;/span\u0026gt; project(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;:projectA\u0026#39;\u0026amp;lt;/span\u0026gt;).projectDir = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File(settingsDir, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;../my-project-a\u0026#39;\u0026amp;lt;/span\u0026gt;) project(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;:projectA\u0026#39;\u0026amp;lt;/span\u0026gt;).buildFileName = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;projectA.gradle\u0026#39;\u0026amp;lt;/span\u0026gt;` - 1 - 2 - 3 - 4 可以看见，如上例子通过描述符更改名称和项目目录，并且建立了一个项目的文件。 **Gradle构建初始化Initialization：** 在初始化阶段如果我们在根路径下直接指明settings.gradle文件和相关配置则构建初始化就会直接按照我们的设置去构建项目，如果我们没指明settings.gradle文件则Gradle会以一定的规则去寻找settings.gradle文件，然后依据寻找结果的不同去决定如何构建项目。 **【工匠若水 [http://blog.csdn.net/yanbober](http://blog.csdn.net/yanbober) 转载请注明出处。[点我开始Android技术交流](https://github.com/yanbober/AndroidCommunication)】** # \u0026lt;a name=\u0026quot;t5\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**3 Gradle构建基础** 通过上一章可以知道，每一个Gradle构建都是由一个或多个project构成，每一个project都是由一个或多个tasks构成，每个task的实质其实是一些更加细化的构建（譬如编译class、创建jar文件等）。 **任务task基础：** 如下例子我们先来直观感受一下task的概念，具体细节后面会探讨： ``` `\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//创建一个名为build.gradle的文件\u0026lt;/span\u0026gt; task hello { doLast { \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;println\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;Hello world!\u0026rsquo;\u0026lt;/span\u0026gt; } }\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//这是快捷写法，用\u0026lt;\u0026lt;替换doLast，后面解释\u0026lt;/span\u0026gt; task hl \u0026lt;\u0026lt; { \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;println\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;Hello world!\u0026rsquo;\u0026lt;/span\u0026gt; }\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//创建upper的task，使用Groovy语言编写\u0026lt;/span\u0026gt; task upper \u0026lt;\u0026lt; { String someString = \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;mY_nAmE\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;println\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;Original: \u0026ldquo;\u0026lt;/span\u0026gt; + someString \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;println\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;Upper case: \u0026ldquo;\u0026lt;/span\u0026gt; + someString.toUpperCase() }`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 通过如下命令运行构建上面名为hello的task，具体如下： ``` `xxx\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;@XXX\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-symbol\u0026#34;\u0026gt;:~/\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;$ \u0026amp;lt;/span\u0026gt;gradle hello \u0026amp;lt;span class=\u0026#34;hljs-symbol\u0026#34;\u0026gt;:hello\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-constant\u0026#34;\u0026gt;Hello\u0026amp;lt;/span\u0026gt; world! \u0026amp;lt;span class=\u0026#34;hljs-constant\u0026#34;\u0026gt;BUILD\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-constant\u0026#34;\u0026gt;SUCCESSFUL\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-constant\u0026#34;\u0026gt;Total\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-symbol\u0026#34;\u0026gt;time:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1.037\u0026amp;lt;/span\u0026gt; secs` - 1 - 2 - 3 - 4 - 5 - 6 - 7 可以看见，gradle命令会在当前目录中查找一个叫build.gradle的构建脚本文件，这个构建脚本定义了一个叫做hello的独立task，并且添加了一个action，我们执行了这个task就得到了想要的结果。 在这里再多嘴一句，我们看下task有无action的区别，如下： ``` \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//有Action的task\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;task\u0026amp;lt;/span\u0026gt; actionTask \u0026amp;lt;\u0026amp;lt; { println \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'I am actionTask'\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//无Action的task\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;task\u0026amp;lt;/span\u0026gt; noActionTask { println \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'I am noActionTask'\u0026amp;lt;/span\u0026gt; } - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 一定要记住，在上面这个例子中如果task没有加\u0026lt;\u0026lt;则这个任务在脚本初始化initialization阶段（即无论执行啥task都被执行，具体参见上一章的第一个例子）被执行，如果加了\u0026lt;\u0026lt;则在gradle actionTask后才执行。因为没有加\u0026lt;\u0026lt;则闭包在task函数返回前会执行，而加了\u0026lt;\u0026lt;则变成调用actionTask.doLast()，所以会等到gradle actionTask时执行。 **任务task依赖：** 我们通过上面task基础感受的例子可以发现，一个build.gradle文件中定义多个task互相没有关系，决定执行的是我们gradle命令后面跟的task名字；那我们要是让他们之间有依赖关系咋办呢？如下： ``` `\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;task\u0026amp;lt;/span\u0026gt; taskX(dependsOn: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;taskY\u0026#39;\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;\u0026amp;lt; { println \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;taskX\u0026#39;\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;task\u0026amp;lt;/span\u0026gt; taskY \u0026amp;lt;\u0026amp;lt; { println \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;taskY\u0026#39;\u0026amp;lt;/span\u0026gt; }` - 1 - 2 - 3 - 4 - 5 - 6 运行结果如下： ``` `xxx\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;@XXX\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:~/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;$ \u0026lt;/span\u0026gt;gradle taskX \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:taskY\u0026lt;/span\u0026gt; taskY \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:taskX\u0026lt;/span\u0026gt; taskX\n\u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;BUILD\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;SUCCESSFUL\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Total\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;time:\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;1.039\u0026lt;/span\u0026gt; secs`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 **动态任务task：** 我们还可以在Gradle中使用Groovy来创建动态task，如下： ``` `\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;times\u0026amp;lt;/span\u0026gt; { counter -\u0026amp;gt; task \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;task\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;$counter\u0026amp;lt;/span\u0026gt;\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;\u0026amp;lt; { println \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;I\u0026#39;m task number \u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;$counter\u0026amp;lt;/span\u0026gt;\u0026#34;\u0026amp;lt;/span\u0026gt; } }` - 1 - 2 - 3 - 4 - 5 运行结果如下： ``` `xxx\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;@XXX\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:~/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;$ \u0026lt;/span\u0026gt;gradle task1 \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:task1\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;I\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;m task number 1\nBUILD SUCCESSFUL\nTotal time: 1.397 secs\u0026lt;/span\u0026gt;`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 **使用已存在任务task：** 我们除过在上面定义任务task时指明依赖以外还可以通过API为任务加入一个依赖，如下： ``` `\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;times\u0026amp;lt;/span\u0026gt; { counter -\u0026amp;gt; task \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;task\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;$counter\u0026amp;lt;/span\u0026gt;\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;\u0026amp;lt; { println \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;I\u0026#39;m task number \u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;$counter\u0026amp;lt;/span\u0026gt;\u0026#34;\u0026amp;lt;/span\u0026gt; } } task\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;.dependsOn task2, task3` - 1 - 2 - 3 - 4 - 5 - 6 运行结果如下： ``` `xxx\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;@XXX\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:~/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;$ \u0026lt;/span\u0026gt;gradle task\u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;0\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:task0\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;I\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;m task number 2 I\u0026rsquo;\u0026lt;/span\u0026gt;m task number \u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;3\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;I\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;m task number 0\nBUILD SUCCESSFUL\nTotal time: 1.397 secs\u0026lt;/span\u0026gt;`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 或者我们还可以通过API为任务加入一些新行为，如下： ``` `task hello \u0026amp;lt;\u0026amp;lt; \u0026amp;lt;span class=\u0026#34;hljs-cell\u0026#34;\u0026gt;{ println \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Hello Earth\u0026#39;\u0026amp;lt;/span\u0026gt; }\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-transposed_variable\u0026#34;\u0026gt;hello.\u0026amp;lt;/span\u0026gt;doFirst \u0026amp;lt;span class=\u0026#34;hljs-cell\u0026#34;\u0026gt;{ println \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Hello Venus\u0026#39;\u0026amp;lt;/span\u0026gt; }\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-transposed_variable\u0026#34;\u0026gt;hello.\u0026amp;lt;/span\u0026gt;doLast \u0026amp;lt;span class=\u0026#34;hljs-cell\u0026#34;\u0026gt;{ println \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Hello Mars\u0026#39;\u0026amp;lt;/span\u0026gt; }\u0026amp;lt;/span\u0026gt; hello \u0026amp;lt;\u0026amp;lt; \u0026amp;lt;span class=\u0026#34;hljs-cell\u0026#34;\u0026gt;{ println \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Hello Jupiter\u0026#39;\u0026amp;lt;/span\u0026gt; }\u0026amp;lt;/span\u0026gt;` - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 运行结果如下： ``` `xxx\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;@XXX\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:~/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;$ \u0026lt;/span\u0026gt;gradle hello \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:hello\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Hello\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Venus\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Hello\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Earth\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Hello\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Mars\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Hello\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Jupiter\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;BUILD\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;SUCCESSFUL\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Total\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;time:\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;1.397\u0026lt;/span\u0026gt; secs`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 可以发现，doFirst和doLast可以被执行多次，\u0026lt;\u0026lt;操作符实质就是doLast。 **任务task短标记：** 我们可以通过美元符将一个task作为另一个task的属性，如下： ``` `task hello \u0026amp;lt;\u0026amp;lt; { \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;println\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Hello world!\u0026#39;\u0026amp;lt;/span\u0026gt; } hello.doLast { \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;println\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Greetings from the $hello.name task.\u0026#34;\u0026amp;lt;/span\u0026gt; }` - 1 - 2 - 3 - 4 - 5 - 6 执行结果如下： ``` `xxx\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;@XXX\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:~/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;$ \u0026lt;/span\u0026gt;gradle hello \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:hello\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Hello\u0026lt;/span\u0026gt; world! \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Greetings\u0026lt;/span\u0026gt; from the hello task.\n\u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;BUILD\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;SUCCESSFUL\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Total\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;time:\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;1.397\u0026lt;/span\u0026gt; secs`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 可以看见，上面脚本中使用的name其实是任务的默认属性, 代表当前任务的名称。 **自定义任务task属性：** 我们还可以给任务task加入自定义的属性，如下例子： ``` `\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;task\u0026amp;lt;/span\u0026gt; myTask { ext.myProperty = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;myValue\u0026#34;\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;task\u0026amp;lt;/span\u0026gt; printTaskProperties \u0026amp;lt;\u0026amp;lt; { println myTask.myProperty }` - 1 - 2 - 3 - 4 - 5 - 6 - 7 执行结果如下： ``` `xxx\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;@XXX\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:~/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;$ \u0026lt;/span\u0026gt;gradle printTaskProperties \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:printTaskProperties\u0026lt;/span\u0026gt; myValue\n\u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;BUILD\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;SUCCESSFUL\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Total\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;time:\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;1.397\u0026lt;/span\u0026gt; secs`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 **定义默认任务task：** Gradle允许在脚本中定义一个或多个默认任务，如下： ``` `defaultTasks \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;clean\u0026#39;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;run\u0026#39;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;task\u0026amp;lt;/span\u0026gt; clean \u0026amp;lt;\u0026amp;lt; { println \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Default Cleaning!\u0026#39;\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;task\u0026amp;lt;/span\u0026gt; run \u0026amp;lt;\u0026amp;lt; { println \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Default Running!\u0026#39;\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;task\u0026amp;lt;/span\u0026gt; other \u0026amp;lt;\u0026amp;lt; { println \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;I\u0026#39;m not a default task!\u0026#34;\u0026amp;lt;/span\u0026gt; }` - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 执行结果如下： ``` `xxx\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;@XXX\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:~/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;$ \u0026lt;/span\u0026gt;gradle \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:clean\u0026lt;/span\u0026gt;,run \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Default\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Cleaning\u0026lt;/span\u0026gt;! \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Default\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Running\u0026lt;/span\u0026gt;!\n\u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;BUILD\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;SUCCESSFUL\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Total\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;time:\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;1.397\u0026lt;/span\u0026gt; secs`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 **【工匠若水 [http://blog.csdn.net/yanbober](http://blog.csdn.net/yanbober) 转载请注明出处。[点我开始Android技术交流](https://github.com/yanbober/AndroidCommunication)】** # \u0026lt;a name=\u0026#34;t6\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;**4 Gradle依赖管理基础** 大多数项目都不是完全独立的，它们需要依赖其他项目进行编译等，Gradle允许你告诉它你项目的依赖关系,以便找到这些依赖关系,并在你的构建中维护这些依赖关系，依赖关系可能需要从远程的Maven等仓库中下载，也可能是在本地文件系统中，或者是通过多项目构建另一个构建，我们称这个过程为依赖解析。 **Gradle依赖声明：** 关于依赖声明不解释，直接给个例子，如下： ``` `apply plugin: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;java\u0026#39;\u0026amp;lt;/span\u0026gt; repositories { mavenCentral() } dependencies { compile \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;group\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;org.hibernate\u0026#39;\u0026amp;lt;/span\u0026gt;, name: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;hibernate-core\u0026#39;\u0026amp;lt;/span\u0026gt;, version: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;3.6.7.Final\u0026#39;\u0026amp;lt;/span\u0026gt; testCompile \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;group\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;junit\u0026#39;\u0026amp;lt;/span\u0026gt;, name: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;junit\u0026#39;\u0026amp;lt;/span\u0026gt;, version: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;4.+\u0026#39;\u0026amp;lt;/span\u0026gt; }` - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 **Gradle依赖配置：** 在Gradle中依赖可以组合成configurations（配置），一个配置简单地说就是一系列的依赖，通俗说也就是依赖配置；我们可以使用它们声明项目的外部依赖，也可以被用来声明项目的发布。下面我们给出几种Java插件中常见的配置，如下： - compile 用来编译项目源代码的依赖；\n- runtime 在运行时被生成的类需要的依赖，默认项，包含编译时的依赖；\n- testCompile 编译测试代码依赖，默认项，包含生成的类运行所需的依赖和编译源代码的依赖； - testRuntime 运行测试所需要的依赖，默认项，包含上面三个依赖； 各种各样的插件支持许多标准的配置，我们还可以定义自己的配置。 **Gradle外部依赖：** 我们可以用Gradle声明许多种依赖，其中有一种是外部依赖（external dependency），它是在当前构建之外的一种依赖，一般存放在远程（譬如Maven）或本地的仓库里。如下是一个外部依赖的例子： ``` dependencies { compile \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;group\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'org.hibernate'\u0026amp;lt;/span\u0026gt;, name: \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'hibernate-core'\u0026amp;lt;/span\u0026gt;, version: \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'3.6.7.Final'\u0026amp;lt;/span\u0026gt; }\n- 1 - 2 - 3 可以看见，引用一个外部依赖需要用到group、name、version属性。上面的写法还有一种简写，如下规则： ``` `\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;group\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-pseudo\u0026#34;\u0026gt;:name\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-pseudo\u0026#34;\u0026gt;:version\u0026amp;lt;/span\u0026gt;` - 1 这是一个简写的例子： ``` dependencies \u0026amp;lt;span class=\u0026quot;hljs-cell\u0026quot;\u0026gt;{ compile \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'org.hibernate:hibernate-core:3.6.7.Final'\u0026amp;lt;/span\u0026gt; }\u0026amp;lt;/span\u0026gt;\n- 1 - 2 - 3 **Gradle仓库：** 有了上面的外部依赖，你指定会想Gradle是咋找到那些外部依赖文件的。其实Gradle会在一个仓库（repository）里找这些依赖文件，仓库其实就是很多依赖文件的集合服务器, 他们通过group、name、version进行归类存储，好在Gradle可以解析好几种不同的仓库形式（譬如Maven等），但是Gradle默认不提前定义任何仓库，我们必须手动在使用外部依赖之前定义自己的仓库。 下面是一个使用MavenCentral仓库的例子： ``` `repositories \u0026amp;lt;span class=\u0026#34;hljs-list\u0026#34;\u0026gt;{ mavenCentral() }\u0026amp;lt;/span\u0026gt;` - 1 - 2 - 3 这是一个使用远程Maven仓库的例子： ``` repositories { maven { url \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;http://repo.mycompany.com/maven2\u0026quot;\u0026amp;lt;/span\u0026gt; } }\n- 1 - 2 - 3 - 4 - 5 这是一个使用本地文件系统里库的例子： ``` `repositories { ivy { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// URL can refer to a local directory\u0026amp;lt;/span\u0026gt; url \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;../local-repo\u0026#34;\u0026amp;lt;/span\u0026gt; } }` - 1 - 2 - 3 - 4 - 5 - 6 当然了，一个项目可以有好几个库，Gradle会根据依赖定义的顺序在各个库里寻找它们，在第一个库里找到了就不会再在第二个库里找它了，否则在第二个库找。 **Gradle发布artifacts：** 依赖配置也可以用来发布文件，我们可以通过在uploadArchives任务里加入仓库来完成。下面是一个发布到Maven 库的例子，Gradle将生成和上传pom.xml，如下： ``` `apply plugin: \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;maven\u0026rsquo;\u0026lt;/span\u0026gt;\nuploadArchives { repositories { mavenDeployer { repository(url: \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;file://localhost/tmp/myRepo/\u0026quot;\u0026lt;/span\u0026gt;) } } }`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 **【工匠若水 [http://blog.csdn.net/yanbober](http://blog.csdn.net/yanbober) 转载请注明出处。[点我开始Android技术交流](https://github.com/yanbober/AndroidCommunication)】** # \u0026lt;a name=\u0026#34;t7\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;**5 Gradle命令** **多任务调用命令：** ``` `gradle task1 task2 [\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;...\u0026amp;lt;/span\u0026gt;]` - 1 **排除任务命令：** ``` gradle -x task1 task2 [\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;...\u0026amp;lt;/span\u0026gt;]\n- 1 **失败后继续执行构建命令：** 只要有任务调用失败Gradle默认就会中断执行，我们可以使用–continue选项在一次调用中不中断执行，然后发现所有失败原因。 **简化任务名命令：** 当我们调用某个任务时如果名字太长我们可以采用简化操作，但是必须保证可以唯一区分出该任务的字符，譬如： ``` `\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//简写\u0026amp;lt;/span\u0026gt; gradle \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;-x\u0026amp;lt;/span\u0026gt; t1 \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//替换\u0026amp;lt;/span\u0026gt; gradle \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;-x\u0026amp;lt;/span\u0026gt; task1` - 1 - 2 - 3 - 4 **选择执行构建命令：** 调用gradle命令默认会构建当前目录下的build.gradle文件，我们可以使用-b参数选择其他目录的构建文件且当使用此参数时settings.gradle将不会生效。如下： ``` //选择文件构建subdir/myproject.gradle task hello \u0026amp;lt;\u0026amp;lt; { println \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;using build file '\u0026amp;lt;span class=\u0026quot;hljs-variable\u0026quot;\u0026gt;$buildFile\u0026amp;lt;/span\u0026gt;.name' in '\u0026amp;lt;span class=\u0026quot;hljs-variable\u0026quot;\u0026gt;$buildFile\u0026amp;lt;/span\u0026gt;.parentFile.name'.\u0026quot;\u0026amp;lt;/span\u0026gt; }\n- 1 - 2 - 3 - 4 执行过程： ``` `xxx\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;@XXX\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-symbol\u0026#34;\u0026gt;:~/\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;$ \u0026amp;lt;/span\u0026gt;gradle -b subdir/myproject.gradle hello \u0026amp;lt;span class=\u0026#34;hljs-symbol\u0026#34;\u0026gt;:hello\u0026amp;lt;/span\u0026gt; using build file \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;myproject.gradle\u0026#39;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;in\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;subdir\u0026#39;\u0026amp;lt;/span\u0026gt;. \u0026amp;lt;span class=\u0026#34;hljs-constant\u0026#34;\u0026gt;BUILD\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-constant\u0026#34;\u0026gt;SUCCESSFUL\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-constant\u0026#34;\u0026gt;Total\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-symbol\u0026#34;\u0026gt;time:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1.397\u0026amp;lt;/span\u0026gt; secs` - 1 - 2 - 3 - 4 - 5 - 6 - 7 此外我们还可以使用-p参数来指定构建的目录，譬如在多项目构建中可以用-p替代-b参数。如下执行过程： ``` `xxx\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;@XXX\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:~/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026ldquo;hljs-variable\u0026rdquo;\u0026gt;$ \u0026lt;/span\u0026gt;gradle -p subdir hello \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;:hello\u0026lt;/span\u0026gt; using build file \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;build.gradle\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;in\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;subdir\u0026rsquo;\u0026lt;/span\u0026gt;.\n\u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;BUILD\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;SUCCESSFUL\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026ldquo;hljs-constant\u0026rdquo;\u0026gt;Total\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-symbol\u0026rdquo;\u0026gt;time:\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-number\u0026rdquo;\u0026gt;1.397\u0026lt;/span\u0026gt; secs`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 **获取构建信息：** - gradle projects命令：列出子项目名称列表。 - gradle tasks命令：列出项目中所有任务。 - gradle help –task someTask命令：可以显示指定任务的详细信息。 - gradle dependencies命令：列出项目的依赖列表，所有依赖会根据任务区分，以树型结构展示。 **【工匠若水 [http://blog.csdn.net/yanbober](http://blog.csdn.net/yanbober) 转载请注明出处。[点我开始Android技术交流](https://github.com/yanbober/AndroidCommunication)】** # \u0026lt;a name=\u0026#34;t8\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;**6 编写Gradle脚本** Gradle是以Groovy语言为基础，基于DSL语法的自动化构建工具，一个构建脚本能够包含任何Groovy语言元素，每个脚本都是UTF-8编码的文件。 ## \u0026lt;a name=\u0026#34;t9\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;**6-1 Project对象API** 前面我们说过，Gradle在构建脚本中定义了一个project，对于构建脚本中每个project其实Gradle都创建了一个 Project类型的对象来关联，当构建脚本执行时它会去配置所关联的Project对象；构建脚本中每个被调用的方法和属性都委托给了当前Project对象。 如下我们看一个使用Project属性的例子： ``` `println \u0026amp;lt;span class=\u0026#34;hljs-property\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt; println project.\u0026amp;lt;span class=\u0026#34;hljs-property\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;` - 1 - 2 上面两个println语句的输出是一样的；由于name属性没有在当前脚本中定义，所以可以像第一个那样使用自动委托 ，通常我们使用第二中写法。 Project对象提供了一些标准的属性，我们可以在构建脚本中很方便的使用他们，如下： \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;th\u0026gt; Name \u0026lt;/th\u0026gt; \u0026lt;th\u0026gt; Type \u0026lt;/th\u0026gt; \u0026lt;th\u0026gt; Default Value \u0026lt;/th\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; project \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; Project \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; Project实例对象 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; name \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; String \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 项目目录的名称 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; path \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; String \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 项目的绝对路径 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; description \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; String \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 项目描述 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; projectDir \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; File \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 包含构建脚本的目录 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; build \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; File \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; projectDir/build \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; group \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; Object \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 未具体说明 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; version \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; Object \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 未具体说明 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; ant \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; AntBuilder \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; Ant实例对象 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 具体关于Project的方法详情参阅Project的API文档。这里我们给出Project的apply方法的一个例子，如下： ``` \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//加载一个gradle文件\u0026amp;lt;/span\u0026gt; apply \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;from\u0026amp;lt;/span\u0026gt;: rootProject.getRootDir().getAbsolutePath() + \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;/common.gradle\u0026quot;\u0026amp;lt;/span\u0026gt; - 1 - 2 ## \u0026lt;a name=\u0026#34;t10\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;**6-2 Script对象API** 当Gradle执行一个脚本时它会将这个脚本编译为实现了Script的类（在上篇博客[《Groovy脚本基础全攻略》](http://blog.csdn.net/yanbober/article/details/49047515)Groovy的本质编译class代码那块有介绍），也就是说所有的属性和方法都是在Script的接口中声明。 ## \u0026lt;a name=\u0026#34;t11\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;**6-3 Gradle对象API** 关于Gradle对象的详细属性和API介绍[点我即可](https://docs.gradle.org/current/dsl/org.gradle.api.invocation.Gradle.html)。这里直接给出一个使用Gradle对象的例子，如下： ![这里写图片描述](http://img.blog.csdn.net/20151025224143998) ## \u0026lt;a name=\u0026#34;t12\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;**6-4 Gradle变量声明** 在Gradle脚本中有两种类型的变量可以声明，如下： - 局部变量 - 扩展变量 局部变量使用关键字def声明，它只在声明的地方可见，如下： ``` ` def dest = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;dest\u0026#34;\u0026amp;lt;/span\u0026gt; task copy(\u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;type\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Copy\u0026amp;lt;/span\u0026gt;) {\u0026amp;lt;/span\u0026gt; form \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;source\u0026#34;\u0026amp;lt;/span\u0026gt; into dest }` - 1 - 2 - 3 - 4 - 5 - 6 - 7 在Gradle中所有被增强的对象可以拥有自定义属性（譬如projects、tasks、source sets等），使用ext扩展块可以一次添加多个属性。如下： ``` `apply plugin: \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;java\u0026rdquo;\u0026lt;/span\u0026gt;\next { springVersion = \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;3.1.0.RELEASE\u0026rdquo;\u0026lt;/span\u0026gt; emailNotification = \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;build@master.org\u0026rdquo;\u0026lt;/span\u0026gt; }\nsourceSets\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.all\u0026lt;/span\u0026gt; { ext\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.purpose\u0026lt;/span\u0026gt; = null }\nsourceSets { main { purpose = \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;production\u0026rdquo;\u0026lt;/span\u0026gt; } test { purpose = \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;test\u0026rdquo;\u0026lt;/span\u0026gt; } plugin { purpose = \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;production\u0026rdquo;\u0026lt;/span\u0026gt; } }\ntask printProperties \u0026lt;\u0026lt; { println springVersion println emailNotification sourceSets\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.matching\u0026lt;/span\u0026gt; { it\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.purpose\u0026lt;/span\u0026gt; == \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026ldquo;production\u0026rdquo;\u0026lt;/span\u0026gt; }\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.each\u0026lt;/span\u0026gt; { println it\u0026lt;span class=\u0026ldquo;hljs-preprocessor\u0026rdquo;\u0026gt;.name\u0026lt;/span\u0026gt;} } `\n- 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 上面我们用一个ext扩展块向Project对象添加两个扩展属性，当这些扩展属性被添加后，它们就像预定义的属性一样可以被读写。 ## \u0026lt;a name=\u0026#34;t13\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;**6-5 Gradle中Groovy使用** 这个没啥说的，具体可以参考[《Groovy脚本基础全攻略》](http://blog.csdn.net/yanbober/article/details/49047515)这篇博客，里面有详细介绍。我们这里粗略总结回忆一下即可： - Groovy会自动将一个属性的引用转换为相应的getter/setter方法。 - Groovy调用方法时圆括号可有可无。 - Groovy为List和Map集合提供了一些操作捷径，譬如apply plugin:’java’中的plugin:’java’其实就是Groovy中的Map，apply是一个方法，省略了括弧而已。 哎呀，详细的还是去看前一篇博客吧。 **【工匠若水 [http://blog.csdn.net/yanbober](http://blog.csdn.net/yanbober) 转载请注明出处。[点我开始Android技术交流](https://github.com/yanbober/AndroidCommunication)】** # \u0026lt;a name=\u0026#34;t14\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;**7 Gradle文件操作基础** 实际使用Gradle过程中大多数时候需要操作文件，好在Gradle给我们提供了一些API来快捷处理。 **定位文件：** 我们可以使用Project.file()方法来定位一个文件获取File对象（详情参考Project的API），如下： ``` `\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//相对路径\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt; configFile = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src/config.xml\u0026#39;\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//绝对路径\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt; configFile = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;(configFile.absolutePath) \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//项目路径的文件对象 \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt; configFile = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;(new \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;File\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src/config.xml\u0026#39;\u0026amp;lt;/span\u0026gt;))` - 1 - 2 - 3 - 4 - 5 - 6 可以从Project的API发现file()方法能够接收任何形式的对象参数，它会将参数值转换为一个绝对文件对象，通常我们可以传一个String或File实例；如果传的路径是绝对路径，则会被直接构造为一个文件实例，否则会被构造为项目目录加上传递目录的文件对象；当然了，file()方法还能识别URL（譬如file:/some/path.xml等）。 **文件集合：** 文件集合其实是一组文件，Gradle使用FileCollection接口表示文件集合，Gradle API中许多类都实现了这个接口，譬如dependency configurations等。获取FileCollection实例的一种方法是Project.files()，我们可以传递任何数量的对象参数。如下： ``` FileCollection collection = \u0026amp;lt;span class=\u0026quot;hljs-built_in\u0026quot;\u0026gt;files\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'src/file1.txt'\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-built_in\u0026quot;\u0026gt;new\u0026amp;lt;/span\u0026gt; File(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'src/file2.txt'\u0026amp;lt;/span\u0026gt;), [\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'src/file3.txt'\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'src/file4.txt'\u0026amp;lt;/span\u0026gt;])\n- 1 - 2 - 3 使用迭代操作还能将其转换为其他的一些类型，同时我们还可以使用+操作将两个文件集合合并，使用-操作对一个文件集合做减法。如下例子： ``` `// 对文件集合进行迭代 collection.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;each\u0026amp;lt;/span\u0026gt; {File \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt; -\u0026amp;gt; println \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;.name } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt; // 转换文件集合为其他类型\u0026amp;lt;/span\u0026gt; Set \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt; = collection.\u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;files\u0026amp;lt;/span\u0026gt; Set set2 = collection \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;as\u0026amp;lt;/span\u0026gt; Set List list = collection \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;as\u0026amp;lt;/span\u0026gt; List String path = collection.asPath File \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt; = collection.singleFile File file2 = collection \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;as\u0026amp;lt;/span\u0026gt; File \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt; // 增加和减少文件集合\u0026amp;lt;/span\u0026gt; def \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;union\u0026amp;lt;/span\u0026gt; = collection + \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;files\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src/file3.txt\u0026#39;\u0026amp;lt;/span\u0026gt;) def different = collection - \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;files\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src/file3.txt\u0026#39;\u0026amp;lt;/span\u0026gt;)` - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 我们也可以向files()方法传递闭包或者可回调的实例参数，当查询集合的内容时就会调用它，然后将返回值转换为一些文件实例，返回值可以是files()方法支持的任何类型的对象。如下例子： ``` `task list \u0026lt;\u0026lt; { File srcDir\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt; // 使用闭合创建一个文件集合\u0026lt;/span\u0026gt; collection = \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;files\u0026lt;/span\u0026gt; { srcDir.listFiles() }\nsrcDir = \u0026amp;lt;span class=\u0026quot;hljs-built_in\u0026quot;\u0026gt;file\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'src'\u0026amp;lt;/span\u0026gt;) println \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;Contents of $srcDir.name\u0026quot;\u0026amp;lt;/span\u0026gt; collection.collect { relativePath(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;it\u0026amp;lt;/span\u0026gt;) }.\u0026amp;lt;span class=\u0026quot;hljs-built_in\u0026quot;\u0026gt;sort\u0026amp;lt;/span\u0026gt;().\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;each\u0026amp;lt;/span\u0026gt; { println \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;it\u0026amp;lt;/span\u0026gt; } srcDir = \u0026amp;lt;span class=\u0026quot;hljs-built_in\u0026quot;\u0026gt;file\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'src2'\u0026amp;lt;/span\u0026gt;) println \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;\u0026quot;Contents of $srcDir.name\u0026quot;\u0026amp;lt;/span\u0026gt; collection.collect { relativePath(\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;it\u0026amp;lt;/span\u0026gt;) }.\u0026amp;lt;span class=\u0026quot;hljs-built_in\u0026quot;\u0026gt;sort\u0026amp;lt;/span\u0026gt;().\u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;each\u0026amp;lt;/span\u0026gt; { println \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;it\u0026amp;lt;/span\u0026gt; } }`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 **文件树：** 文件树可以代表一个目录树结构或一个ZIP压缩文件的内容，FileTree继承自FileCollection，所以我们可以像处理文件集合一样处理文件树，使用Project.fileTree()方法可以得到FileTree实例，它会创建一个基于基准目录的对象。如下： ``` `/以一个基准目录创建一个文件树 FileTree tree = fileTree(dir: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src/main\u0026#39;\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt; // 添加包含和排除规则\u0026amp;lt;/span\u0026gt; tree.\u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;include\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;**/*.java\u0026#39;\u0026amp;lt;/span\u0026gt; tree.exclude \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;**/Abstract*\u0026#39;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt; // 使用路径创建一个树\u0026amp;lt;/span\u0026gt; tree = fileTree(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src\u0026#39;\u0026amp;lt;/span\u0026gt;).\u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;include\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;**/*.java\u0026#39;\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt; // 使用闭合创建一个数\u0026amp;lt;/span\u0026gt; tree = fileTree(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src\u0026#39;\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;include\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;**/*.java\u0026#39;\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt; // 使用map创建一个树\u0026amp;lt;/span\u0026gt; tree = fileTree(dir: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src\u0026#39;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;include\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;**/*.java\u0026#39;\u0026amp;lt;/span\u0026gt;) tree = fileTree(dir: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src\u0026#39;\u0026amp;lt;/span\u0026gt;, includes: [\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;**/*.java\u0026#39;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;**/*.xml\u0026#39;\u0026amp;lt;/span\u0026gt;]) tree = fileTree(dir: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src\u0026#39;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;include\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;**/*.java\u0026#39;\u0026amp;lt;/span\u0026gt;, exclude: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;**/*test*/**\u0026#39;\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt; // 遍历文件树\u0026amp;lt;/span\u0026gt; tree.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;each\u0026amp;lt;/span\u0026gt; {File \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt; -\u0026amp;gt; println \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt; // 过滤文件树\u0026amp;lt;/span\u0026gt; FileTree filtered = tree.matching { \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;include\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;org/gradle/api/**\u0026#39;\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt; // 合并文件树A\u0026amp;lt;/span\u0026gt; FileTree \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;sum\u0026amp;lt;/span\u0026gt; = tree + fileTree(dir: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src/test\u0026#39;\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt; // 访问文件数的元素\u0026amp;lt;/span\u0026gt; tree.visit {\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;element\u0026amp;lt;/span\u0026gt; -\u0026amp;gt; println \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026amp;lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;element.relativePath =\u0026amp;gt;\u0026amp;lt;/span\u0026gt;element.file\u0026#34;\u0026amp;lt;/span\u0026gt; }` - 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 我们还可以使用ZIP或TAR等压缩文件的内容作为文件树，Project.zipTree()和Project.tarTree()方法可以返回一个FileTree实例。如下： ``` `\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;// 使用路径创建一个ZIP文件\u0026lt;/span\u0026gt; FileTree zip = zipTree(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;someFile.zip\u0026rsquo;\u0026lt;/span\u0026gt;)\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;// 使用路径创建一个TAR文件\u0026lt;/span\u0026gt; FileTree tar = tarTree(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;someFile.tar\u0026rsquo;\u0026lt;/span\u0026gt;)\n\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//TarTree可以根据文件扩展名得到压缩方式，如果我们想明确的指定压缩方式则可以如下操作\u0026lt;/span\u0026gt; FileTree someTar = tarTree(resources.gzip(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;someTar.ext\u0026rsquo;\u0026lt;/span\u0026gt;))`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 **指定输入文件：** Gradle中有些对象的属性可以接收一组输入文件，譬如JavaComplile任务的source属性（定义编译的源文件）。如下： ``` `\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//使用一个File对象设置源目录\u0026amp;lt;/span\u0026gt; compile { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;source\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src/main/java\u0026#39;\u0026amp;lt;/span\u0026gt;) } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//使用一个字符路径设置源目录\u0026amp;lt;/span\u0026gt; compile { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;source\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src/main/java\u0026#39;\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//使用一个集合设置多个源目录\u0026amp;lt;/span\u0026gt; compile { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;source\u0026amp;lt;/span\u0026gt; = [\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src/main/java\u0026#39;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;../shared/java\u0026#39;\u0026amp;lt;/span\u0026gt;] } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//使用FileCollection或者FileTree设置源目录\u0026amp;lt;/span\u0026gt; compile { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;source\u0026amp;lt;/span\u0026gt; = fileTree(dir: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src/main/java\u0026#39;\u0026amp;lt;/span\u0026gt;).matching {include \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;org/gradle/api/**\u0026#39;\u0026amp;lt;/span\u0026gt;} } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//使用闭包设置源目录\u0026amp;lt;/span\u0026gt; compile { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;source\u0026amp;lt;/span\u0026gt; = { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Use the contents of each zip file in the src dir\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src\u0026#39;\u0026amp;lt;/span\u0026gt;).listFiles().findAll {it.name.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;endsWith\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;.zip\u0026#39;\u0026amp;lt;/span\u0026gt;)}.collect { zipTree(it) } } } compile { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//使用字符路径添加源目录\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;source\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src/main/java\u0026#39;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src/main/groovy\u0026#39;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//使用File对象添加源目录\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;source\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;../shared/java\u0026#39;\u0026amp;lt;/span\u0026gt;) \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//使用闭包添加源目录\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;source\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;file\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;src/test/\u0026#39;\u0026amp;lt;/span\u0026gt;).listFiles() } }` - 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 **复制文件：** 我们可以使用复制任务（Copy）进行文件复制操作，复制任务扩展性很强，它可以过滤复制文件的内容，使用复制任务要提供想要复制的源文件和一个目标目录，如果要指定文件被复制时的转换方式则可以使用复制规则，复制规则是一个CopySpec接口的实现，我们使用CopySpec.from()方法指定源文件，CopySpec.into()方法指定目标目录即可。如下： ``` `task copyTask(type: Copy) { \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;from\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;src/main/webapp\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;into\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;build/explodedWar\u0026rsquo;\u0026lt;/span\u0026gt; }\ntask anotherCopyTask(type: Copy) { \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt; //复制src/main/webapp目录下的所有文件\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;from\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;src/main/webapp\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt; //复制一个单独文件\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;from\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;src/staging/index.html\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt; //复制一个任务输出的文件\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;from\u0026lt;/span\u0026gt; copyTask \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt; //显式使用任务的outputs属性复制任务的输出文件\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;from\u0026lt;/span\u0026gt; copyTaskWithPatterns.outputs \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt; //复制一个ZIP压缩文件的内容\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;from\u0026lt;/span\u0026gt; zipTree(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;src/main/assets.zip\u0026rsquo;\u0026lt;/span\u0026gt;) \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt; //指定目标目录\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;into\u0026lt;/span\u0026gt; { getDestDir() } }\ntask copyTaskWithPatterns(type: Copy) { \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;from\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;src/main/webapp\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;into\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;build/explodedWar\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;include\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;/*.html\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;include\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;/*.jsp\u0026rsquo;\u0026lt;/span\u0026gt; exclude { details -\u0026gt; details.\u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;file\u0026lt;/span\u0026gt;.name.endsWith(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;.html\u0026rsquo;\u0026lt;/span\u0026gt;) \u0026amp;\u0026amp; details.\u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;file\u0026lt;/span\u0026gt;.\u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;text\u0026lt;/span\u0026gt;.\u0026lt;span class=\u0026ldquo;hljs-operator\u0026rdquo;\u0026gt;contains\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;staging\u0026rsquo;\u0026lt;/span\u0026gt;) } }\ntask copyMethod \u0026lt;\u0026lt; { copy { \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;from\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;src/main/webapp\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;into\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;build/explodedWar\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;include\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;/*.html\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;include\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;/*.jsp\u0026rsquo;\u0026lt;/span\u0026gt; } } \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt; //在复制时重命名文件\u0026lt;/span\u0026gt; task \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;rename\u0026lt;/span\u0026gt;(type: Copy) { \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;from\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;src/main/webapp\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;into\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;build/explodedWar\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt; //使用闭包映射文件名\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;rename\u0026lt;/span\u0026gt; { String fileName -\u0026gt; fileName.\u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;replace\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;-staging-\u0026rsquo;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;\u0026rsquo;\u0026lt;/span\u0026gt;) } \u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt; // 使用正则表达式映射文件名\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;rename\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;(.+)-staging-(.+)\u0026rsquo;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;\u0026lt;span class=\u0026ldquo;katex math inline\u0026rdquo;\u0026gt;1\u0026lt;/span\u0026gt;2\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-built_in\u0026rdquo;\u0026gt;rename\u0026lt;/span\u0026gt;(/(.+)-staging-(.+)/, \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026rsquo;\u0026lt;span class=\u0026ldquo;katex math inline\u0026rdquo;\u0026gt;1\u0026lt;/span\u0026gt;2\u0026rsquo;\u0026lt;/span\u0026gt;) }`\n- 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 **文件同步任务：** 同步任务（Sync）继承自复制任务（Copy），当执行时会复制源文件到目标目录，然后从目标目录删除所有非复制文件。如下： ``` `task libs(\u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;type\u0026amp;lt;/span\u0026gt;: Sync) { from configurations.runtime into \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026amp;lt;span class=\u0026#34;hljs-variable\u0026#34;\u0026gt;$buildDir\u0026amp;lt;/span\u0026gt;/libs\u0026#34;\u0026amp;lt;/span\u0026gt; }` - 1 - 2 - 3 - 4 **创建归档文件：** 使用归档任务可以创建Zip、Tar、Jar、War、Ear等归档文件，如下： ``` `apply plugin: \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;java\u0026rsquo;\u0026lt;/span\u0026gt;\ntask zip(type: Zip) { \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;from\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;src/dist\u0026rsquo;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;into\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;libs\u0026rsquo;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026ldquo;hljs-keyword\u0026rdquo;\u0026gt;from\u0026lt;/span\u0026gt; configurations.runtime } }`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 关于文件操作的其他请参考API文档。 **【工匠若水 [http://blog.csdn.net/yanbober](http://blog.csdn.net/yanbober) 转载请注明出处。[点我开始Android技术交流](https://github.com/yanbober/AndroidCommunication)】** # \u0026lt;a name=\u0026#34;t15\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;**8 Gradle插件** ## \u0026lt;a name=\u0026#34;t16\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;**8-1 Gradle插件概述** **插件基础：** 关于Gradle支持的插件可以[点我搜索](https://plugins.gradle.org/)。其实Gradle的核心只是一个空空的框架，所谓的Gradle构建便捷脚本其实都是由插件提供支持的，插件添加了新的任务。在Gradle中一般有两种类型的插件，如下： - 脚本插件 是额外的构建脚本，它会进一步配置构建，通常会在构建内部使用。脚本插件可以从本地文件系统或远程获取，如果从文件系统获取则是相对于项目目录，如果是远程获取则是由HTTP URL指定。 - 二进制插件 是实现了Plugin接口的类，并且采用编程的方式来操纵构建。 插件需要通过Project.apply()方法完成声明应用，相同的插件可以应用多次。如下例子： ``` `\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//脚本插件\u0026amp;lt;/span\u0026gt; apply \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;other.gradle\u0026#39;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//二进制插件\u0026amp;lt;/span\u0026gt; apply plugin: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;java\u0026#39;\u0026amp;lt;/span\u0026gt;` - 1 - 2 - 3 - 4 - 5 插件还可以使用插件ID，插件的id作为给定插件的唯一标识符，我们可以给插件注册一个缩写字符的id。譬如下面例子： ``` \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//通过Java插件的id进行引用\u0026amp;lt;/span\u0026gt; apply plugin: JavaPlugin\n- 1 - 2 **使用构建脚本块应用插件：** 我们可以向构建脚本中加入插件的类路径然后再应用插件和使用插件的任务，如下： ``` `buildscript { repositories { jcenter() } dependencies { classpath \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;com.jfrog.bintray.gradle:gradle-bintray-plugin:0.4.1\u0026#34;\u0026amp;lt;/span\u0026gt; } } apply plugin: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;com.jfrog.bintray\u0026#34;\u0026amp;lt;/span\u0026gt;` - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 **Gradle插件拓展：** 可以看见，Gradle其实是依托于各种插件壮大的，譬如Java插件用来构建Java工程，Android插件用来构建打包Android工程，我们只需要选择合适的插件即可，插件会为我们提供丰富的任务用来快捷处理构建，具体详情参考各插件API即可。 ## \u0026lt;a name=\u0026quot;t17\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**8-2 Gradle的Java插件构建实例** 上面说了，插件是Gradle的扩展，它会通过某种方式配置我们的项目（譬如加入一些task）；Gradle自带许多插件，我们也可以编写自己的插件然后开源.，Java 插件就是这样的一个插件，该插件已经给项目定义了默认的参数（譬如Java源文件位置），所以通常我们不需要在脚本中加入太多东西。 **单个基础Java项目构建：** ``` \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//把Java插件加入到项目中，也就是许多预定制的任务被自动加入到了项目里\u0026amp;lt;/span\u0026gt; apply plugin: \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'java'\u0026amp;lt;/span\u0026gt;\n- 1 - 2 加入上面插件以后Gradle默认希望能在src/main/java路径下找到源代码，在 src/test/java路径下找到测试代码，任何src/main/resources路径的文件都会被包含在JAR文件里，任何src/test/resources路径的文件都会被加入到classpath中以运行测试代码，所有的输出文件将会被创建在构建目录里，JAR文件存放在 build/libs文件夹里。 加入Java插件后我们可以通过gradle tasks命令来列出项目的所有任务，这样就可以知道Java插件添加了哪些task。常用的task如下： - build task 当运行gradle build命令时Gradle将会编译和测试你的代码，并且创建一个包含类和资源的JAR文件。 - clean task 当运行gradle clean命令时Gradle将会删除build生成的目录和所有生成的文件。 - assemble task 当运行gradle assemble命令时Gradle将会编译并打包代码，但是并不运行单元测试。 - check task 当运行gradle check命令时Gradle将会编译并测试你的代码，其他的插件会加入更多的检查步骤。 **单个具有外部依赖的Java项目构建：** 当然了，一个Java项目可能会有许多外部依赖（即调用第三方JAR），为了在项目里引用这些 JAR包，我们需要告诉Gradle去哪里找他们，好在Gradle支持许多仓库，这些仓库可以被用来提取或者放置依赖，我们可以很方便的从这些仓库中取得第三方Jar包。如下： ``` `\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//加入Maven仓库\u0026amp;lt;/span\u0026gt; repositories { \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;mavenCentral()\u0026amp;lt;/span\u0026gt; }` - 1 - 2 - 3 - 4 接着加入一些编译阶段来自于mavenCentral仓库的依赖，如下： ``` dependencies { \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//编译阶段\u0026amp;lt;/span\u0026gt; compile \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;group\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'commons-collections'\u0026amp;lt;/span\u0026gt;, name: \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'commons-collections'\u0026amp;lt;/span\u0026gt;, version: \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'3.2'\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//测试编译阶段\u0026amp;lt;/span\u0026gt; testCompile \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;group\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'junit'\u0026amp;lt;/span\u0026gt;, name: \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'junit'\u0026amp;lt;/span\u0026gt;, version: \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'4.+'\u0026amp;lt;/span\u0026gt; }\n- 1 - 2 - 3 - 4 - 5 - 6 **定制构建项目：** Java插件给项目加入了一些属性，这些属性已经被赋予了默认的值且已经够我们日常使用了，如果我们觉得这些默认属性不好也可以自己修改。如下： ``` `//定制 MANIFEST.MF 文件 sourceCompatibility = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1.5\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;version\u0026amp;lt;/span\u0026gt; = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;1.0\u0026#39;\u0026amp;lt;/span\u0026gt; jar { manifest { attributes \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Implementation-Title\u0026#39;\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Gradle Quickstart\u0026#39;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;Implementation-Version\u0026#39;\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;version\u0026amp;lt;/span\u0026gt; } }` - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 默认Java插件加入的任务是常规性的任务，但是我们可以定制任务，譬如我们可以设置一个任务的属性、在任务中加入行为、改变任务的依赖、完全重写一个任务等。如下： ``` \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//测试阶段加入一个系统属性\u0026amp;lt;/span\u0026gt; test { systemProperties \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'property'\u0026amp;lt;/span\u0026gt;: \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'value'\u0026amp;lt;/span\u0026gt; }\n- 1 - 2 - 3 - 4 关于哪些属性是可用的问题，我们可以使用gradle properties命令列出项目的所有属性。 **发布JAR文件：** 通常JAR文件需要在某个地方发布，我们可以通过Gradle方便的进行发布，譬如下面例子将发布到一个本地的目录，如下： ``` `//uploadArchives task uploadArchives { repositories { flatDir { \u0026amp;lt;span class=\u0026#34;hljs-built_in\u0026#34;\u0026gt;dirs\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;repos\u0026#39;\u0026amp;lt;/span\u0026gt; } } }` - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 **多Java项目构建：** 在Gradle中为了定义一个多项目构建我们需要创建一个设置文件（settings.gradle），设置文件放在源代码的根目录，它用来指定要包含哪个项目且名字必须叫做settings.gradle。如下例子： ``` \u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//多项目工程结构树：\u0026amp;lt;/span\u0026gt; multiproject/ api/ services/webservice/ \u0026amp;lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;shared\u0026amp;lt;/span\u0026gt;/\n- 1 - 2 - 3 - 4 - 5 ``` `\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//多项目构建settings.gradle文件\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;include\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;shared\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;api\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;services:webservice\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;services:shared\u0026#34;\u0026amp;lt;/span\u0026gt;` - 1 - 2 对于大多数多项目构建有一些配置对所有项目都是通用的，所以我们将在根项目里定义一个这样的通用配置（配置注入技术 configuration injection）。 根项目就像一个容器，subprojects方法遍历这个容器的所有元素并且注入指定的配置。如下： ``` `\u0026lt;span class=\u0026ldquo;hljs-comment\u0026rdquo;\u0026gt;//多项目构建通用配置\u0026lt;/span\u0026gt; subprojects { apply plugin: \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;java\u0026rsquo;\u0026lt;/span\u0026gt; apply plugin: \u0026lt;span class=\u0026ldquo;hljs-string\u0026rdquo;\u0026gt;\u0026lsquo;eclipse-wtp\u0026rsquo;\u0026lt;/span\u0026gt;\nrepositories { mavenCentral() } dependencies { testCompile \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'junit:junit:4.11'\u0026amp;lt;/span\u0026gt; } version = \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'1.0'\u0026amp;lt;/span\u0026gt; jar { manifest.attributes provider: \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'gradle'\u0026amp;lt;/span\u0026gt; } }`\n- 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 可以看见，上面通用配置把Java插件应用到了每一个子项目中。 我们还可以在同一个构建里加入项目之间的依赖，这样可以保证他们的先后关系。如下： ``` `\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//api/build.gradle\u0026amp;lt;/span\u0026gt; dependencies { compile \u0026amp;lt;span class=\u0026#34;hljs-function\u0026#34;\u0026gt;project(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;:shared\u0026#39;\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;/span\u0026gt; }` - 1 - 2 - 3 - 4 至此基础的Java插件使用就OK了，深入的请自行查看API。 **【工匠若水 [http://blog.csdn.net/yanbober](http://blog.csdn.net/yanbober) 转载请注明出处。[点我开始Android技术交流](https://github.com/yanbober/AndroidCommunication)】** # \u0026lt;a name=\u0026quot;t18\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**4 Gradle基础总结** 到此Gradle的基础知识就完全介绍完了，我们对Gradle的框架也有了一个直观的认识。其实编写Gradle无非也就是对类的属性和方法进行调运操作，至于如何调运操作依据具体插件而异，核心的生命周期和几个对象实例搞明白基本上就能驾驭Gradle脚本了，其他的无非就是熟练度和API查找。 ![这里写图片描述](http://img.blog.csdn.net/20151117140731595) \u0026lt;div class=\u0026quot;bdsharebuttonbox bdshare-button-style0-16\u0026quot; data-bd-bind=\u0026quot;1449017718688\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; \u0026amp;nbsp; ","permalink":"https://blog.zdltech.com/posts/gradle%E8%84%9A%E6%9C%AC%E5%9F%BA%E7%A1%80%E5%85%A8%E6%94%BB%E7%95%A5/","summary":"\u003cdiv id=\"article_content\" class=\"article_content\"\u003e\n  \u003cdiv class=\"markdown_views\"\u003e\n\u003cpre\u003e\u003ccode\u003e  **【工匠若水 [http://blog.csdn.net/yanbober](http://blog.csdn.net/yanbober) 转载请注明出处。[点我开始Android技术交流](https://github.com/yanbober/AndroidCommunication)】**\n\n\n\n# \u0026lt;a name=\u0026quot;t0\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**1 背景**\n\n\n\n  在开始Gradle之前请务必保证自己已经初步了解了Groovy脚本，特别是闭包规则，如果还不了解Groovy则可以先看[《Groovy脚本基础全攻略》](http://blog.csdn.net/yanbober/article/details/49047515)这一篇博客速成一下Groovy基础，然后再看此文即可。关于Gradle速成干货基础详情也请参考[Geadle官方网站](https://www.gradle.org/)，不好意思我太Low了。\n\n\n\n\n\n  ![这里写图片描述](http://img.blog.csdn.net/20151025165437078)\n\n\n\n\n\n  Gradle核心是基于Groovy的领域特定语言(DSL，具体概念参见[《Groovy脚本基础全攻略》](http://blog.csdn.net/yanbober/article/details/49047515))，具有非常好的扩展性，所以不管是简单的独立项目还是大型的多项目构建它都能高效的提高构建任务，尤其对多项目支持是非常牛逼的；Gradle还提供了局部构建功能，譬如构建一个单独子项目时它会构建这个子项目依赖的所有子项目；当然了他对远程仓库和本地库的支持也很到位；哎呀，总之后面你就明白他的牛逼之处了。\n\n\n\n\n\n  既然Gradle核心是Groovy，Groovy本质又是Java，所以很明显可以发现Gradle环境必须依赖JDK与Groovy库，具体如下：\n\n\n\n\n  - JDK版本必须是JDK6以上；\n  \n  - 因为Gradle自带Groovy库, 所以已安装的Groovy会被Gradle忽略；\n  \n\n\n\n\n  具体Gradle环境配置好了以后如下图：\n\n\n\n\n\n  ![这里写图片描述](http://img.blog.csdn.net/20151022113143209)\n\n\n\n\n\n  **【工匠若水 [http://blog.csdn.net/yanbober](http://blog.csdn.net/yanbober) 转载请注明出处。[点我开始Android技术交流](https://github.com/yanbober/AndroidCommunication)】**\n\n\n\n# \u0026lt;a name=\u0026quot;t1\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**2 Gradle DSL基础**\n\n\n\n  Gradle的实质是配置脚本，执行一种类型的配置脚本时就会创建一个关联的对象，譬如执行Build script脚本就会创建一个Project对象，这个对象其实就是Gradle的代理对象。下面给出来各种类型Gradle对应的对象类型：\n\n\n\n\u0026lt;table\u0026gt;\n  \u0026lt;tr\u0026gt;\n    \u0026lt;th\u0026gt;\n      脚本类型\n    \u0026lt;/th\u0026gt;\n    \n    \u0026lt;th\u0026gt;\n      关联对象类型\n    \u0026lt;/th\u0026gt;\n  \u0026lt;/tr\u0026gt;\n  \n  \u0026lt;tr\u0026gt;\n    \u0026lt;td\u0026gt;\n      Build script\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td\u0026gt;\n      Project\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n  \n  \u0026lt;tr\u0026gt;\n    \u0026lt;td\u0026gt;\n      Init script\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td\u0026gt;\n      Gradle\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n  \n  \u0026lt;tr\u0026gt;\n    \u0026lt;td\u0026gt;\n      Settings script\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td\u0026gt;\n      Settings\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\n\n\n  Gradle的三种主要对象解释如下：\n\n\n\n\n  - Project对象：每个build.gradle会转换成一个Project对象。\n  \n  - Gradle对象：构建初始化时创建，整个构建执行过程中只有这么一个对象，一般很少去修改这个默认配置脚本。\n  \n  - Settings对象：每个settings.gradle会转换成一个Settings对象。\n  \n\n\n\n\n  可以看见，当我们编写指定类型Gradle脚本时我们可以直接使用关联对象的属性和方法；当然了，每个脚本也都实现了Script接口，也就是说我们也可以直接使用Script接口的属性与方法。\n\n\n\n## \u0026lt;a name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**2-1 构建脚本Build script（Project）**\n\n\n\n  在Gradle中每个待编译的工程都是一个Project（每个工程的build.gradle对应一个Project对象），每个Project在构建的时候都包含一系列Task，这些Task中很多又是Gradle的插件默认支持的。\n\n\n\n\n\n  PS：所谓的我们编写Gradle脚本，实质大多数时候都是在编写构建脚本Build script，所以说Project和Script对象的属性和方法等API非常重要。\n\n\n\n\n\n  每一个Project对象和build.gradle一一对应，一个项目在构建时都具备如下流程：\n\n\n\n\n  - 为当前项目创建一个Settings类型的实例。\n  \n  - 如果当前项目存在settings.gradle文件，则通过该文件配置刚才创建的Settings实例。\n  \n  - 通过Settings实例的配置创建项目层级结构的Project对象实例。\n  \n  - 最后通过上面创建的项目层级结构Project对象实例去执行每个Project对应的build.gradle脚本。\n  \n\n\n## \u0026lt;a name=\u0026quot;t3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**2-2 初始化脚本Init script（Gradle）和设置脚本Settings script（Settings）**\n\n\n\n  **Gradle对象：**\n\n\n\n\n\n  初始化脚本Init script（Gradle）类似于Gradle的其他类型脚本，这种脚本在构建开始之前运行，主要的用途是为接下来的Build script做一些准备工作。我们如果需要编写初始化脚本Init script，则可以把它按规则放置在USER_HOME/.gradle/相关目录下。譬如：\n\n\n\n\n\n  ![这里写图片描述](http://img.blog.csdn.net/20151025171346780)\n\n\n\n\n\n  初始化脚本的Gradle对象代表了Gradle的调运，我们可以通过调用Project对象的getGradle()方法获得Gradle实例对象。\n\n\n\n\n\n  **Settings对象：**\n\n\n\n\n\n  在对工程进行配置（譬如多项目树构建）时Settings实例与settings.gradle文件一一对应，它用来进行一些项目设置的配置。这个文件一般放置在工程的根目录。譬如：\n\n\n\n\n\n  ![这里写图片描述](http://img.blog.csdn.net/20151025171558864)\n\n\n\n## \u0026lt;a name=\u0026quot;t4\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;**2-3 Build生命周期**\n\n\n\n  Gradle的构建脚本生命周期具备三大步，如下：\n\n\n\n\n\n  ![这里写图片描述](http://img.blog.csdn.net/20151025173643212)\n\n\n\n\n\n  可以看见，生命周期其实和上面构建脚本Build script的执行流程是可以关联上的。有了这个流程图我们接下里详细看下每个过程。\n\n\n\n\n\n  **settings.gradle文件：**\n\n\n\n\n\n  除了构建脚本文件，Gradle还定义了一个约定名称的设置文件（默认为settings.gradle）。该文件在初始化阶段被执行，对于多项目构建必须保证在根目录下有settings.gradle文件，对于单项目构建设置文件是可选的，不过建议还是写上。\n\n\n\n\n\n  如下是单项目构建的一个例子：\n\n\n\n```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003e\u0026amp;lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;//settings.gradle\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-built_in\u0026quot;\u0026gt;println\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026quot;hljs-string\u0026quot;\u0026gt;'This is executed during the initialization phase.'\u0026amp;lt;/span\u0026gt;\u003c/code\u003e\u003c/p\u003e","title":"Gradle脚本基础全攻略"},{"content":" {.title} 忘掉那些在学校或者课堂上学习反而收获甚微的方式吧。这些网站或者APP涵盖科学、艺术和技术。它们会教你一些特别的东东，像用node.js构建APP, 而且大部分是免费的。这不会强制你掌握一个新技能，却能扩展你的知识，甚至促进你的职业。你可以在你喜欢的地方学习或者是你自己的舒服的家里。真的不能再简单了。你还等什么呢？ 1、在线课程 2、学习编程 [Codecademy](http://www.codecademy.com/)-交互式学习编码，免费 Stuk.io-零基础学习编程 Udacity-获取可被业界承认的技能 Platzi-在线学习设计、市场推广、编码 Learnable-最好的方式学习web开发 Code Scool-亲自动手学习编程 Thinkful-一对一的辅导 Code.org-根据指南现在就开始学习 BaseRails-掌握Ruby on Rails和其他web技术 Treehouse-学习HTML,CSS ,iPhone apps和更多 One Month-一个月内学习编程并构建web应用 Dash-学习制作酷炫的网站\n3、和数据打交道 [DataCamp](https://www.datacamp.com/)-R语言的指南和数据课程 DataQuest-浏览器里学习数据科学 DataMonkey-简单有趣的方式开发你的分析技能\n4、学习新的语言 [Duolingo](https://www.duolingo.com/)-免费学习新语言 Lingvist-200小时内学习一门新的语言 Busuu-免费的语言学习社区 Memrise-用识字卡来学习词汇\n5、扩展你的知识 [TED-Ed](http://ed.ted.com/)-找到辅助的教育视频 Khan Academy-可交互的非常全面的图书馆 Guides.co-最大的在线指南的搜索 Squareknot-漂亮的指引，一步步的指南 Learnist-学习更专业的内容通过web、纸质、视频 Prismatic-学习社会推荐的一些有趣的内容\n6、其它红利 [Chesscademy](http://www.chesscademy.com/)-免费学习国际象棋 Pianu-新的方式学习钢琴，可交互 Yousician-数字时代下你的个人吉他教程\n[阅读原文](https://medium.com/life-learning/the-37-best-websites-to-learn-something-new-895e2cb0cad4#.fdh3dqi1q) ","permalink":"https://blog.zdltech.com/posts/37%E4%B8%AA%E6%9C%80%E5%A5%BD%E7%9A%84%E5%AD%A6%E4%B9%A0%E6%96%B0%E4%B8%9C%E8%A5%BF%E7%9A%84%E7%BD%91%E7%AB%99%E8%AF%91/","summary":"\u003cheader\u003e \n\u003ch1 id=\"title\"\u003e\u003ca href=\"https://cdn-images-1.medium.com/max/800/1*7uSLM1qBgX2mS8Ivvbo8Lg.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://cdn-images-1.medium.com/max/800/1*7uSLM1qBgX2mS8Ivvbo8Lg.png\"\u003e\u003c/a\u003e {.title}\u003c/header\u003e\u003c/h1\u003e\n\u003cdiv class=\"entry\"\u003e\n\u003cpre\u003e\u003ccode\u003e忘掉那些在学校或者课堂上学习反而收获甚微的方式吧。这些网站或者APP涵盖科学、艺术和技术。它们会教你一些特别的东东，像用node.js构建APP, 而且大部分是免费的。这不会强制你掌握一个新技能，却能扩展你的知识，甚至促进你的职业。你可以在你喜欢的地方学习或者是你自己的舒服的家里。真的不能再简单了。你还等什么呢？\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"1在线课程\"\u003e1、在线课程\u003c/h2\u003e\n\u003cp\u003e\u003ca id=\"more\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"2学习编程\"\u003e2、学习编程\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e[Codecademy](http://www.codecademy.com/)-交互式学习编码，免费\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"https://stuk.io/\"\u003eStuk.io\u003c/a\u003e-零基础学习编程\n\u003ca href=\"https://www.udacity.com/\"\u003eUdacity\u003c/a\u003e-获取可被业界承认的技能\n\u003ca href=\"https://courses.platzi.com/\"\u003ePlatzi\u003c/a\u003e-在线学习设计、市场推广、编码\n\u003ca href=\"https://learnable.com/\"\u003eLearnable\u003c/a\u003e-最好的方式学习web开发\n\u003ca href=\"https://www.codeschool.com/\"\u003eCode Scool\u003c/a\u003e-亲自动手学习编程\n\u003ca href=\"https://www.thinkful.com/\"\u003eThinkful\u003c/a\u003e-一对一的辅导\n\u003ca href=\"https://code.org/\"\u003eCode.org\u003c/a\u003e-根据指南现在就开始学习\n\u003ca href=\"https://www.baserails.com/\"\u003eBaseRails\u003c/a\u003e-掌握Ruby on Rails和其他web技术\n\u003ca href=\"https://teamtreehouse.com/\"\u003eTreehouse\u003c/a\u003e-学习HTML,CSS ,iPhone apps和更多\n\u003ca href=\"https://onemonth.com/\"\u003eOne Month\u003c/a\u003e-一个月内学习编程并构建web应用\n\u003ca href=\"https://dash.generalassemb.ly/\"\u003eDash\u003c/a\u003e-学习制作酷炫的网站\u003c/p\u003e\n\u003ch2 id=\"3和数据打交道\"\u003e3、和数据打交道\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e[DataCamp](https://www.datacamp.com/)-R语言的指南和数据课程\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"https://dataquest.io/\"\u003eDataQuest\u003c/a\u003e-浏览器里学习数据科学\n\u003ca href=\"http://datamonkey.pro/\"\u003eDataMonkey\u003c/a\u003e-简单有趣的方式开发你的分析技能\u003c/p\u003e\n\u003ch2 id=\"4学习新的语言\"\u003e4、学习新的语言\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e[Duolingo](https://www.duolingo.com/)-免费学习新语言\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"https://www.lingvist.io/\"\u003eLingvist\u003c/a\u003e-200小时内学习一门新的语言\n\u003ca href=\"https://www.busuu.com/\"\u003eBusuu\u003c/a\u003e-免费的语言学习社区\n\u003ca href=\"http://www.memrise.com/\"\u003eMemrise\u003c/a\u003e-用识字卡来学习词汇\u003c/p\u003e\n\u003ch2 id=\"5扩展你的知识\"\u003e5、扩展你的知识\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e[TED-Ed](http://ed.ted.com/)-找到辅助的教育视频\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"https://www.khanacademy.org/\"\u003eKhan Academy\u003c/a\u003e-可交互的非常全面的图书馆\n\u003ca href=\"http://guides.co/\"\u003eGuides.co\u003c/a\u003e-最大的在线指南的搜索\n\u003ca href=\"https://squareknot.com/search/projects/\"\u003eSquareknot\u003c/a\u003e-漂亮的指引，一步步的指南\n\u003ca href=\"http://learni.st/\"\u003eLearnist\u003c/a\u003e-学习更专业的内容通过web、纸质、视频\n\u003ca href=\"http://getprismatic.com/news/\"\u003ePrismatic\u003c/a\u003e-学习社会推荐的一些有趣的内容\u003c/p\u003e\n\u003ch2 id=\"6其它红利\"\u003e6、其它红利\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e[Chesscademy](http://www.chesscademy.com/)-免费学习国际象棋\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"https://pianu.com/\"\u003ePianu\u003c/a\u003e-新的方式学习钢琴，可交互\n\u003ca href=\"http://get.yousician.com/\"\u003eYousician\u003c/a\u003e-数字时代下你的个人吉他教程\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e[阅读原文](https://medium.com/life-learning/the-37-best-websites-to-learn-something-new-895e2cb0cad4#.fdh3dqi1q)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"37个最好的学习新东西的网站(译)"},{"content":"转载请标明出处：http://blog.csdn.net/lmj623565791/article/details/39480503，本文出自：【张鸿洋的博客】\n上一篇已经带大家实现了自由的放大缩小图片，简单介绍了下Matrix；具体请参考：Android 手势检测实战 打造支持缩放平移的图片预览效果（上）；本篇继续完善我们的ImageView~~\n首先加入放大后的移动~~\n1、自由的进行移动 我们在onTouchEvent里面，加上移动的代码，当然了，必须长或宽大于屏幕才可以移动~~~\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39480503#)[copy](http://blog.csdn.net/lmj623565791/article/details/39480503#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) - { - mScaleGestureDetector.onTouchEvent(event); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, y = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 拿到触摸点的个数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; pointerCount = event.getPointerCount(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 得到多个触摸点的x与y均值\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; pointerCount; i++) - { - x += event.getX(i); - y += event.getY(i); - } - x = x / pointerCount; - y = y / pointerCount; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 每当触摸点发生变化时，重置mLasX , mLastY \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pointerCount != lastPointerCount) - { - isCanDrag = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - mLastX = x; - mLastY = y; - } - - - lastPointerCount = pointerCount; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (event.getAction()) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - Log.e(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;ACTION_MOVE\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; dx = x \u0026amp;#8211; mLastX; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; dy = y \u0026amp;#8211; mLastY; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isCanDrag) - { - isCanDrag = isCanDrag(dx, dy); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isCanDrag) - { - RectF rectF = getMatrixRectF(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getDrawable() != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - isCheckLeftAndRight = isCheckTopAndBottom = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果宽度小于屏幕宽度，则禁止左右移动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (rectF.width() \u0026lt; getWidth()) - { - dx = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - isCheckLeftAndRight = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果高度小雨屏幕高度，则禁止上下移动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (rectF.height() \u0026lt; getHeight()) - { - dy = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - isCheckTopAndBottom = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - mScaleMatrix.postTranslate(dx, dy); - checkMatrixBounds(); - setImageMatrix(mScaleMatrix); - } - } - mLastX = x; - mLastY = y; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_CANCEL: - Log.e(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;ACTION_UP\u0026amp;#8221;\u0026lt;/span\u0026gt;); - lastPointerCount = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } 首先我们拿到触摸点的数量，然后求出多个触摸点的平均值，设置给我们的mLastX , mLastY ， 然后在移动的时候，得到dx ,dy 进行范围检查以后，调用mScaleMatrix.postTranslate进行设置偏移量，当然了，设置完成以后，还需要再次校验一下，不能把图片移动的与屏幕边界出现白边，校验完成后，调用setImageMatrix.\n这里：需要注意一下，我们没有复写ACTION_DOWM，是因为，ACTION_DOWN在多点触控的情况下，只要有一个手指按下状态，其他手指按下不会再次触发ACTION_DOWN，但是多个手指以后，触摸点的平均值会发生很大变化，所以我们没有用到ACTION_DOWN。每当触摸点的数量变化，我们就会跟新当前的mLastX,mLastY.\n下面是上面用到的两个私有方法，一个用于检查边界，一个用于判断是否是拖动的操作：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39480503#)[copy](http://blog.csdn.net/lmj623565791/article/details/39480503#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 移动时，进行边界判断，主要判断宽或高大于屏幕的\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; checkMatrixBounds() - { - RectF rect = getMatrixRectF(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; deltaX = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, deltaY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; viewWidth = getWidth(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; viewHeight = getHeight(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 判断移动或缩放后，图片显示是否超出屏幕边界\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (rect.top \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; isCheckTopAndBottom) - { - deltaY = -rect.top; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (rect.bottom \u0026lt; viewHeight \u0026amp;\u0026amp; isCheckTopAndBottom) - { - deltaY = viewHeight \u0026amp;#8211; rect.bottom; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (rect.left \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; isCheckLeftAndRight) - { - deltaX = -rect.left; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (rect.right \u0026lt; viewWidth \u0026amp;\u0026amp; isCheckLeftAndRight) - { - deltaX = viewWidth \u0026amp;#8211; rect.right; - } - mScaleMatrix.postTranslate(deltaX, deltaY); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 是否是推动行为\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param dx\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param dy\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isCanDrag(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; dy) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; Math.sqrt((dx * dx) + (dy * dy)) \u0026gt;= mTouchSlop; - } 这样，我们就可以快乐的放大、缩小加移动了~~~\n效果图：这次换个男人的图片，我们越狱的主角之一，TBug~\n我们的缩放+移动搞定~~\n2、双击放大与缩小 谈到双击事件，我们的GestureDetector终于要登场了，这哥们可以捕获双击事件~~\n1、GestureDetector的使用 因为GestureDetector设置监听器的话，方法一大串，而我们只需要onDoubleTap这个回调，所以我们准备使用它的一个内部类SimpleOnGestureListener，对接口的其他方法实现了空实现。\n不过还有几个问题需要讨论下，才能开始我们的代码：\n1、我们双击尺寸如何变化？\n我是这样的，根据当前的缩放值，如果是小于2的，我们双击直接到变为原图的2倍；如果是2,4之间的，我们双击直接为原图的4倍；其他状态也就是4倍，双击后还原到最初的尺寸。\n如果你觉得这样不合适，可以根据自己的爱好调整。\n2、我们双击变化，需要一个动画~~比如我们上例的演示图，图片很大，全屏显示的时候initScale=0.5左后，如果双击后变为2，也就是瞬间大了四倍，没有一个过渡的效果的话，给用户的感觉会特别差。所以，我们准备使用postDelay执行一个Runnable，Runnable中再次根据的当然的缩放值继续执行。\n首先我们在构造方法中，完成对GestureDetector的初始化，以及设置onDoubleTap监听\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39480503#)[copy](http://blog.csdn.net/lmj623565791/article/details/39480503#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ZoomImageView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - mScaleGestureDetector = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ScaleGestureDetector(context, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - mGestureDetector = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(context, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SimpleOnGestureListener() - { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDoubleTap(MotionEvent e) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isAutoScale == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x = e.getX(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y = e.getY(); - Log.e(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;DoubleTap\u0026amp;#8221;\u0026lt;/span\u0026gt;, getScale() + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; , \u0026amp;#8220;\u0026lt;/span\u0026gt; + initScale); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScale() \u0026lt; SCALE_MID) - { - ZoomImageView.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.postDelayed( - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AutoScaleRunnable(SCALE_MID, x, y), \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;); - isAutoScale = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScale() \u0026gt;= SCALE_MID - \u0026amp;\u0026amp; getScale() \u0026lt; SCALE_MAX) - { - ZoomImageView.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.postDelayed( - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AutoScaleRunnable(SCALE_MAX, x, y), \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;); - isAutoScale = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - { - ZoomImageView.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.postDelayed( - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AutoScaleRunnable(initScale, x, y), \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;); - isAutoScale = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - }); - mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.setScaleType(ScaleType.MATRIX); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.setOnTouchListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - } 1、当双击的时候，首先判断是否正在自动缩放，如果在，直接retrun ;\n2、然后就进入了我们的if，如果当然是scale小于2，则通过view.发送一个Runnable进行执行；其他类似；\n下面看我们的Runnable的代码：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39480503#)[copy](http://blog.csdn.net/lmj623565791/article/details/39480503#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 自动缩放的任务\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author zhy\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; AutoScaleRunnable \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Runnable - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; BIGGER = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.07f; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; SMALLER = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.93f; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mTargetScale; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; tmpScale; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 缩放的中心\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 传入目标缩放值，根据目标值与当前值，判断应该放大还是缩小\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param targetScale\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; AutoScaleRunnable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; targetScale, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mTargetScale = targetScale; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.x = x; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.y = y; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScale() \u0026lt; mTargetScale) - { - tmpScale = BIGGER; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - { - tmpScale = SMALLER; - } - - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 进行缩放\u0026lt;/span\u0026gt; - mScaleMatrix.postScale(tmpScale, tmpScale, x, y); - checkBorderAndCenterWhenScale(); - setImageMatrix(mScaleMatrix); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; currentScale = getScale(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//如果值在合法范围内，继续缩放\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (((tmpScale \u0026gt; 1f) \u0026amp;\u0026amp; (currentScale \u0026lt; mTargetScale)) - || ((tmpScale \u0026lt; 1f) \u0026amp;\u0026amp; (mTargetScale \u0026lt; currentScale))) - { - ZoomImageView.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.postDelayed(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置为目标的缩放比例\u0026lt;/span\u0026gt; - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; deltaScale = mTargetScale / currentScale; - mScaleMatrix.postScale(deltaScale, deltaScale, x, y); - checkBorderAndCenterWhenScale(); - setImageMatrix(mScaleMatrix); - isAutoScale = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - } - } 代码写完了，我们依然需要把我们的event传给它，依然是在onTouch方法：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39480503#)[copy](http://blog.csdn.net/lmj623565791/article/details/39480503#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mGestureDetector.onTouchEvent(event)) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; 好了，双击放大与缩小的功能就搞定了，下面测试下~~~\n效果图，终于可以用模拟器了~~：\n3、处理与ViewPager的冲突 直接把我们的图片作为ViewPager的Item，可想而知，肯定有冲突~~\n1、布局文件 **[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39480503#)[copy](http://blog.csdn.net/lmj623565791/article/details/39480503#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;RelativeLayout xmlns:android=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - xmlns:tools=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; - - \u0026lt;android.support.v4.view.ViewPager - android:id=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@+id/id_viewpager\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; - \u0026lt;/android.support.v4.view.ViewPager\u0026gt; - - \u0026lt;/RelativeLayout\u0026gt; 2、Activity代码\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39480503#)[copy](http://blog.csdn.net/lmj623565791/article/details/39480503#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.zhy_scalegesturedetector02; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v4.view.PagerAdapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v4.view.ViewPager; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.view.ZoomImageView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ViewPager mViewPager; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] mImgs = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] { R.drawable.tbug, R.drawable.a, - R.drawable.xx }; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageView[] mImageViews = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageView[mImgs.length]; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.vp); - - mViewPager = (ViewPager) findViewById(R.id.id_viewpager); - mViewPager.setAdapter(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PagerAdapter() - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object instantiateItem(ViewGroup container, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) - { - ZoomImageView imageView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ZoomImageView( - getApplicationContext()); - imageView.setImageResource(mImgs[position]); - container.addView(imageView); - mImageViews[position] = imageView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; imageView; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; destroyItem(ViewGroup container, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, - Object object) - { - container.removeView(mImageViews[position]); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isViewFromObject(View arg0, Object arg1) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; arg0 == arg1; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mImgs.length; - } - }); - - } - } 现在直接运行，发现ViewPager好着呢，但是我们的图片放大以后，移动和ViewPager冲突了，又不能移动了~。。。擦擦擦。。。\n3、处理冲突 现在我们迅速的想一想，记得之前学习过事件分发机制，我们的ZoomImageView在ViewPager中，如果我们不想被拦截，那么如何做呢？\n首先不想被拦截的条件是：我们的宽或高大于屏幕宽或高时，因为此时可以移动，我们不想被拦截。接下来，不想被拦截：\ngetParent().requestDisallowInterceptTouchEvent(true);\n一行代码足以，如果你对事件分发中，不被拦截不清晰，可以参考：如何不被拦截 。\n放在一起我们的代码就是：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39480503#)[copy](http://blog.csdn.net/lmj623565791/article/details/39480503#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (event.getAction()) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (rectF.width() \u0026gt; getWidth() || rectF.height() \u0026gt; getHeight()) - { - getParent().requestDisallowInterceptTouchEvent(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (rectF.width() \u0026gt; getWidth() || rectF.height() \u0026gt; getHeight()) - { - getParent().requestDisallowInterceptTouchEvent(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - } ~当宽或高大于屏幕宽或高时，拖动效果认为是移动图片，反之则让ViewPager去处理\n此时的效果：\nok，现在已经解决了和ViewPager的冲突，ps：尼玛不应该双击还能放大两次到4倍，，，，，好恶心。。。\n4、到达边界事件交给ViewPager处理 可能有些用户还希望，当图片到达边界时，不能再拖动的时候，能够把事件给ViewPager\n那就在ACTION_MOVE中，判断当前已经到达边界，且还在拉的时候，事件交给ViewPager\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39480503#)[copy](http://blog.csdn.net/lmj623565791/article/details/39480503#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isCanDrag) - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getDrawable() != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getMatrixRectF().left == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; dx \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - getParent().requestDisallowInterceptTouchEvent(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getMatrixRectF().right == getWidth() \u0026amp;\u0026amp; dx \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - getParent().requestDisallowInterceptTouchEvent(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); - } 此时的效果：\n好了，其实添加了这个之后，体验一般哈~~~\n终于写完了，代码中可能存在BUG，发现问题，或者解决了发现的BUG时，希望可以直接在博客下面留言，也能够方便他人~~\n到此，我们的Android 手势检测实战 打造支持缩放平移的图片预览效果 结束~~！\n建议把双击放大到4倍的地方，注释掉一个If\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39480503#)[copy](http://blog.csdn.net/lmj623565791/article/details/39480503#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_10\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_10\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// else if (getScale() \u0026gt;= SCALE_MID\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// \u0026amp;\u0026amp; getScale() \u0026lt; SCALE_MAX)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// {\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// ZoomImageView.this.postDelayed(\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// new AutoScaleRunnable(SCALE_MAX, x, y), 16);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// isAutoScale = true;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// } \u0026lt;/span\u0026gt; 连续双击放大，感觉不爽，代码已经上传，我就不重传了，如果你也觉得不爽，可以自行注释。\n单图版源码点击下载\nViewPager版源码下载\n———————————————————————————————————-\n博主部分视频已经上线，如果你不喜欢枯燥的文本，请猛戳（初录，期待您的支持）：\n1、高仿微信5.2.1主界面及消息提醒\n2、高仿QQ5.0侧滑\n","permalink":"https://blog.zdltech.com/posts/android-%E6%89%8B%E5%8A%BF%E6%A3%80%E6%B5%8B%E5%AE%9E%E6%88%98-%E6%89%93%E9%80%A0%E6%94%AF%E6%8C%81%E7%BC%A9%E6%94%BE%E5%B9%B3%E7%A7%BB%E7%9A%84%E5%9B%BE%E7%89%87%E9%A2%84%E8%A7%88%E6%95%88%E6%9E%9C/","summary":"\u003cp\u003e转载请标明出处：\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/39480503\"\u003ehttp://blog.csdn.net/lmj623565791/article/details/39480503\u003c/a\u003e，本文出自：\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/39480503\"\u003e【张鸿洋的博客】\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e上一篇已经带大家实现了自由的放大缩小图片，简单介绍了下Matrix；具体请参考：\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/39474553\"\u003eAndroid 手势检测实战 打造支持缩放平移的图片预览效果（上）\u003c/a\u003e；本篇继续完善我们的ImageView~~\u003c/p\u003e\n\u003cp\u003e首先加入放大后的移动~~\u003c/p\u003e\n\u003ch1 id=\"1自由的进行移动\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003e1、自由的进行移动\u003c/h1\u003e\n\u003cp\u003e我们在onTouchEvent里面，加上移动的代码，当然了，必须长或宽大于屏幕才可以移动~~~\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39480503#)[copy](http://blog.csdn.net/lmj623565791/article/details/39480503#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event)\n\n- {\n\n- mScaleGestureDetector.onTouchEvent(event);\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, y = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 拿到触摸点的个数\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; pointerCount = event.getPointerCount();\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 得到多个触摸点的x与y均值\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; pointerCount; i++)\n\n- {\n\n- x += event.getX(i);\n\n- y += event.getY(i);\n\n- }\n\n- x = x / pointerCount;\n\n- y = y / pointerCount;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         * 每当触摸点发生变化时，重置mLasX , mLastY \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pointerCount != lastPointerCount)\n\n- {\n\n- isCanDrag = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- mLastX = x;\n\n- mLastY = y;\n\n- }\n\n- \n- \n- lastPointerCount = pointerCount;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (event.getAction())\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE:\n\n- Log.e(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;ACTION_MOVE\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; dx = x \u0026amp;#8211; mLastX;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; dy = y \u0026amp;#8211; mLastY;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isCanDrag)\n\n- {\n\n- isCanDrag = isCanDrag(dx, dy);\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isCanDrag)\n\n- {\n\n- RectF rectF = getMatrixRectF();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getDrawable() != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)\n\n- {\n\n- isCheckLeftAndRight = isCheckTopAndBottom = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果宽度小于屏幕宽度，则禁止左右移动\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (rectF.width() \u0026lt; getWidth())\n\n- {\n\n- dx = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- isCheckLeftAndRight = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果高度小雨屏幕高度，则禁止上下移动\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (rectF.height() \u0026lt; getHeight())\n\n- {\n\n- dy = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- isCheckTopAndBottom = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- mScaleMatrix.postTranslate(dx, dy);\n\n- checkMatrixBounds();\n\n- setImageMatrix(mScaleMatrix);\n\n- }\n\n- }\n\n- mLastX = x;\n\n- mLastY = y;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP:\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_CANCEL:\n\n- Log.e(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;ACTION_UP\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- lastPointerCount = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e首先我们拿到触摸点的数量，然后求出多个触摸点的平均值，设置给我们的mLastX , mLastY ， 然后在移动的时候，得到dx ,dy 进行范围检查以后，调用mScaleMatrix.postTranslate进行设置偏移量，当然了，设置完成以后，还需要再次校验一下，不能把图片移动的与屏幕边界出现白边，校验完成后，调用setImageMatrix.\u003c/p\u003e","title":"Android 手势检测实战 打造支持缩放平移的图片预览效果（下）"},{"content":"运行时权限介绍 Android 6.0在我们原有的AndroidManifest.xml声明权限的基础上，又新增了运行时权限动态检测，以下权限都需要在运行时判断：\n身体传感器 日历 摄像头 通讯录 地理位置 麦克风 电话 短信 存储空间 运行时权限处理 Android6.0系统默认为targetSdkVersion小于23的应用默认授予了所申请的所有权限，所以如果你以前的APP设置的targetSdkVersion低于23，在运行时也不会崩溃，但这也只是一个临时的救急策略，用户还是可以在设置中取消授予的权限。\n声明目标SDK版本 我们需要在build.gradle中声明targetSdkVersion为23 android { compileSdkVersion 23 buildToolsVersion \u0026#34;23.0.1\u0026#34; defaultConfig { applicationId \u0026#34;com.yourcomany.app minSdkVersion 18 targetSdkVersion 23 versionCode 1 versionName \u0026#34;1.0\u0026#34; } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile(\u0026#39;proguard-android.txt\u0026#39;), \u0026#39;proguard-rules.pro\u0026#39; } } } 检查并申请权限 我们需要在用到权限的地方，每次都检查是否APP已经拥有权限，比如我们有一个下载功能，需要写SD卡的权限，我们在写入之前检查是否有WRITE_EXTERNAL_STORAGE权限，没有则申请权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { //申请WRITE_EXTERNAL_STORAGE权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_REQUEST_CODE); } 请求权限后，系统会弹出请求权限的Dialog 用户选择允许或需要后，会回调onRequestPermissionsResult方法, 该方法类似于onActivityResult ``` @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); doNext(requestCode,grantResults); } - 我们接着需要根据requestCode和grantResults(授权结果)做相应的后续处理 ``` private void doNext(int requestCode, int[] grantResults) { if (requestCode == WRITE_EXTERNAL_STORAGE_REQUEST_CODE) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission Granted } else { // Permission Denied } } } Fragment中运行时权限的特殊处理 在Fragment中申请权限，不要使用ActivityCompat.requestPermissions, 直接使用Fragment的requestPermissions方法，否则会回调到Activity的 onRequestPermissionsResult\n如果在Fragment中嵌套Fragment，在子Fragment中使用requestPermissions方 法，onRequestPermissionsResult不会回调回来，建议使用 getParentFragment().requestPermissions方法，这个方法会回调到父Fragment中的onRequestPermissionsResult，加入以下代码可以把回调透传到子Fragment ``` @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); List fragments = getChildFragmentManager().getFragments(); if (fragments != null) { for (Fragment fragment : fragments) { if (fragment != null) { fragment.onRequestPermissionsResult(requestCode,permissions,grantResults); } } } }\n## 相关开源项目 **PermissionsDispatcher** 使用标注的方式，动态生成类处理运行时权限，目前还不支持嵌套Fragment。 **RxPermissions** 基于RxJava的运行时权限检测框架 **Grant** 简化运行时权限的处理，比较灵活 **android-RuntimePermissions** Google官方的例子 ## 附录 以下权限只需要在AndroidManifest.xml中声明即可使用 android.permission.ACCESS_LOCATION_EXTRA_COMMANDS android.permission.ACCESS_NETWORK_STATE android.permission.ACCESS_NOTIFICATION_POLICY android.permission.ACCESS_WIFI_STATE android.permission.ACCESS_WIMAX_STATE android.permission.BLUETOOTH android.permission.BLUETOOTH_ADMIN android.permission.BROADCAST_STICKY android.permission.CHANGE_NETWORK_STATE android.permission.CHANGE_WIFI_MULTICAST_STATE android.permission.CHANGE_WIFI_STATE android.permission.CHANGE_WIMAX_STATE android.permission.DISABLE_KEYGUARD android.permission.EXPAND_STATUS_BAR android.permission.FLASHLIGHT android.permission.GET_ACCOUNTS android.permission.GET_PACKAGE_SIZE android.permission.INTERNET android.permission.KILL_BACKGROUND_PROCESSES android.permission.MODIFY_AUDIO_SETTINGS android.permission.NFC android.permission.READ_SYNC_SETTINGS android.permission.READ_SYNC_STATS android.permission.RECEIVE_BOOT_COMPLETED android.permission.REORDER_TASKS android.permission.REQUEST_INSTALL_PACKAGES android.permission.SET_TIME_ZONE android.permission.SET_WALLPAPER android.permission.SET_WALLPAPER_HINTS android.permission.SUBSCRIBED_FEEDS_READ android.permission.TRANSMIT_IR android.permission.USE_FINGERPRINT android.permission.VIBRATE android.permission.WAKE_LOCK android.permission.WRITE_SYNC_SETTINGS com.android.alarm.permission.SET_ALARM com.android.launcher.permission.INSTALL_SHORTCUT com.android.launcher.permission.UNINSTALL_SHORTCUT\n","permalink":"https://blog.zdltech.com/posts/android-6-0-%E8%BF%90%E8%A1%8C%E6%97%B6%E6%9D%83%E9%99%90%E5%A4%84%E7%90%86/","summary":"\u003ch2 id=\"运行时权限介绍\"\u003e运行时权限介绍\u003c/h2\u003e\n\u003cp\u003eAndroid 6.0在我们原有的AndroidManifest.xml声明权限的基础上，又新增了运行时权限动态检测，以下权限都需要在运行时判断：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e身体传感器\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e日历\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e摄像头\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e通讯录\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e地理位置\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e麦克风\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e电话\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e短信\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e存储空间\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"运行时权限处理\"\u003e运行时权限处理\u003c/h2\u003e\n\u003cp\u003eAndroid6.0系统默认为targetSdkVersion小于23的应用默认授予了所申请的所有权限，所以如果你以前的APP设置的targetSdkVersion低于23，在运行时也不会崩溃，但这也只是一个临时的救急策略，用户还是可以在设置中取消授予的权限。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e声明目标SDK版本\n我们需要在build.gradle中声明targetSdkVersion为23\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eandroid {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e compileSdkVersion 23\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e buildToolsVersion \u0026#34;23.0.1\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e defaultConfig {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     applicationId \u0026#34;com.yourcomany.app\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     minSdkVersion 18\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     targetSdkVersion 23\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     versionCode 1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     versionName \u0026#34;1.0\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile(\u0026#39;proguard-android.txt\u0026#39;), \u0026#39;proguard-rules.pro\u0026#39; } } }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e检查并申请权限\n我们需要在用到权限的地方，每次都检查是否APP已经拥有权限，比如我们有一个下载功能，需要写SD卡的权限，我们在写入之前检查是否有WRITE_EXTERNAL_STORAGE权限，没有则申请权限\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              != PackageManager.PERMISSION_GRANTED) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          //申请WRITE_EXTERNAL_STORAGE权限\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  WRITE_EXTERNAL_STORAGE_REQUEST_CODE);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e请求权限后，系统会弹出请求权限的Dialog\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg alt=\"11.png\" loading=\"lazy\" src=\"http://looip.cn//uploads/soho/UEimage/20151112/1447316107189330.png\"\u003e\u003c/p\u003e","title":"Android 6.0 运行时权限处理"},{"content":"引言\n在本教程中，我已经收集了10个给 Linux 用户的有用工具，其中包括各种网络监控，系统审计和一些其它实用的命令，它可以帮助用户提高工作效率。我希望你会喜欢他们。 1. w\n显示谁登录了系统并执行了哪些程序。\n$ w 不显示头部信息（LCTT译注：原文此处有误）\nw -h 显示指定用户的信息 w 2. nmon\nNmon（nigel’s monitor 的简写）是一个显示系统性能信息的工具。\nsudo apt-get install nmon nmon nmon 可以显示与 netwrok，cpu, memory 和磁盘使用情况的信息。 nmon 显示 cpu 信息 (按 c) nmon 显示 network 信息 (按 n) nman 显示 disk 信息 (按 d) 3. ncdu\n是一个支持光标的du程序，这个命令是用来分析各种目录占用的磁盘空间。\napt-get install ncdu ncdu / 最终的输出: 按 n 则通过文件名来排序，按 s 则按文件大小来排序（默认的）。\n4. slurm\n一个基于网络接口的带宽监控命令行程序，它会用字符来显示文本图形。\napt-get install slurm 例如: slurm -i $ slurm -i eth1 选项 按 l 显示 lx/tx 指示灯.\n按 c 切换到经典模式.\n按 r 刷新屏幕.\n按 q 退出.\n**5.findmnt** Findmnt 命令用于查找挂载的文件系统。它用来列出安装设备，当需要时也可以挂载或卸载设备，它是 util-linux 软件包的一部分。 例子:\n$ findmnt 以列表格式输出。\n$ findmnt -l 列出在 fstab 中挂载的文件系统。\n$ findmnt -s 按文件类型列出已挂载的文件系统。\n$ findmnt -t ext4 **6. dstat** 一种灵活的组合工具，它可用于监控内存，进程，网络和磁盘性能，它可以用来取代 ifstat, iostat, dmstat 等。 \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;apt-get install dstat 例如: 查看有关 cpu，硬盘和网络的详细信息。 dstat -c cpu\n$ dstat -c -d 磁盘\n$ dstat -d 显示 cpu、磁盘等的详细信息。\n$ dstat -cdl -D sda1 **7. saidar** 另一种基于命令行的系统统计数据[监控工具](http://www.codeceo.com/article/7-monitor-tools.html)，提供了有关磁盘使用，网络，内存，交换分区等信息。 \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;sudo apt-get install saidar 例如: saidar 启用彩色输出\n$ saider -c **8. ss** ss（socket statistics）是一个很好的替代 netstat 的选择，它从内核空间收集信息，比 netstat 的性能更好。 例如: 列出所有的连接\n$ ss |less 列出 tcp 流量\n$ ss -A tcp 列出进程名和 pid\n$ ss -ltp **9. ccze** 一个美化日志显示的工具![](http://www.codeceo.com/wp-content/themes/d-simple/img/smilies/icon_smile.gif). \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;apt-get install ccze 例如: tailf /var/log/syslog | ccze 列出 ccze 模块:\n$ ccze -l 将日志保存为 html 文件。\ntailf /var/log/syslog | ccze -h \u0026gt; /home/tux/Desktop/rajneesh.html **10. ranwhen.py** 一种基于 Python 的终端工具，它可以用来以图形方式显示系统活动状态。详细信息以一个丰富多彩的柱状图来展示。 安装 python（LCTT 译注：一般来说，你应该已经有了 python，不需要此步）：\n\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;sudo apt-add-repository ppa:fkrull/deadsnakes 更新系统: sudo apt-get update 下载 python:\n$ sudo apt-get install python3.2 点此下载 ranwhen.py\n\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;unzip ranwhen-master.zip \u0026amp;\u0026amp; cd ranwhen-master 运行工具。 python3.2 ranwhen.py **结论** 这都是些不常见但重要的 Linux 管理工具。他们可以在日常生活中帮助用户。在我们即将发表的文章中，我们会尽量多带来些管理员/用户工具。 玩得愉快！\n原文：[http://www.unixmen.com/10-useful-utilities-linux-users/](http://www.unixmen.com/10-useful-utilities-linux-users/) 译文：LCTT [https://linux.cn/article-6467-1.html](https://linux.cn/article-6467-1.html) \u0026lt;/span\u0026gt; ","permalink":"https://blog.zdltech.com/posts/%E5%88%86%E4%BA%AB%E7%BB%99linux%E7%94%A8%E6%88%B7%E7%9A%8410%E4%B8%AA%E6%9C%89%E7%94%A8%E5%B7%A5%E5%85%B7/","summary":"\u003cp\u003e\u003cspan style=\"font-size: medium;\"\u003e\u003cstrong\u003e引言\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在本教程中，我已经收集了10个给 Linux 用户的有用工具，其中包括各种网络监控，系统审计和一些其它实用的命令，它可以帮助用户提高工作效率。我希望你会喜欢他们。\n\u003cimg loading=\"lazy\" src=\"http://static.codeceo.com/images/2015/10/213053smh9raz1crdcxhxn.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. w\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e显示谁登录了系统并执行了哪些程序。\u003c/p\u003e\n\u003cp\u003e$ w\n\u003cimg loading=\"lazy\" src=\"http://static.codeceo.com/images/2015/10/213054zxz7ymhb0hqp27im.png\"\u003e\n不显示头部信息（LCTT译注：原文此处有误）\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"katex math inline\"\u003ew -h\n显示指定用户的信息\u003c/span\u003e w \u003cusername\u003e\n\u003cimg loading=\"lazy\" src=\"http://static.codeceo.com/images/2015/10/213055w0ci5sj4w66jzvvx.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. nmon\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eNmon（nigel’s monitor 的简写）是一个显示系统性能信息的工具。\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"katex math inline\"\u003esudo apt-get install nmon\u003c/span\u003e nmon\n\u003cimg loading=\"lazy\" src=\"http://static.codeceo.com/images/2015/10/213058ceu5qhx85kkui83q.png\"\u003e\nnmon 可以显示与 netwrok，cpu, memory 和磁盘使用情况的信息。\n\u003cstrong\u003enmon 显示 cpu 信息 (按 c)\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"http://static.codeceo.com/images/2015/10/213100w2zlbbqjlrkjbja8.png\"\u003e\n\u003cstrong\u003enmon 显示 network 信息 (按 n)\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"http://static.codeceo.com/images/2015/10/213103e6z0pl7m6mzr6xlx.png\"\u003e\n\u003cstrong\u003enman 显示 disk 信息 (按 d)\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"http://static.codeceo.com/images/2015/10/213107wlzt138x0cff03sw.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. ncdu\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e是一个支持光标的du程序，这个命令是用来分析各种目录占用的磁盘空间。\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"katex math inline\"\u003eapt-get install ncdu\u003c/span\u003e ncdu /\n\u003cimg loading=\"lazy\" src=\"http://static.codeceo.com/images/2015/10/213110i7oowmiwuowmxrns.png\"\u003e\n最终的输出:\n\u003cimg loading=\"lazy\" src=\"http://static.codeceo.com/images/2015/10/213112vx0kh36dzldwd49l.png\"\u003e\n按 n 则通过文件名来排序，按 s 则按文件大小来排序（默认的）。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4. slurm\u003c/strong\u003e\u003c/p\u003e","title":"分享给Linux用户的10个有用工具"},{"content":"概述 作为一个android开发者，在开发应用时，随着业务规模发展到一定程度，不断地加入新功能、添加新的类库，代码在急剧的膨胀，相应的apk包的大小也急剧增加， 那么终有一天，你会不幸遇到这个错误：\n生成的apk在android 2.3或之前的机器上无法安装，提示INSTALL_FAILED_DEXOPT 方法数量过多，编译时出错，提示： Conversion to Dalvik format failed:Unable to execute dex: method ID not in [0, 0xffff]: 65536 而问题产生的具体原因如下：\n无法安装（Android 2.3 INSTALL_FAILED_DEXOPT）问题，是由dexopt的LinearAlloc限制引起的，在Android版本不同分别经历了4M/5M/8M/16M限制，目前主流4.2.x系统上可能都已到16M， 在Gingerbread或者以下系统LinearAllocHdr分配空间只有5M大小的， 高于Gingerbread的系统提升到了8M。Dalvik linearAlloc是一个固定大小的缓冲区。在应用的安装过程中，系统会运行一个名为dexopt的程序为该应用在当前机型中运行做准备。dexopt使用LinearAlloc来存储应用的方法信息。Android 2.2和2.3的缓冲区只有5MB，Android 4.x提高到了8MB或16MB。当方法数量过多导致超出缓冲区大小时，会造成dexopt崩溃。 超过最大方法数限制的问题，是由于DEX文件格式限制，一个DEX文件中method个数采用使用原生类型short来索引文件中的方法，也就是4个字节共计最多表达65536个method，field/class的个数也均有此限制。对于DEX文件，则是将工程所需全部class文件合并且压缩到一个DEX文件期间，也就是Android打包的DEX过程中， 单个DEX文件可被引用的方法总数（自己开发的代码以及所引用的Android框架、类库的代码）被限制为65536； 插件化？ MultiDex？ 解决这个问题，一般有下面几种方案，一种方案是加大Proguard的力度来减小DEX的大小和方法数，但这是治标不治本的方案，随着业务代码的添加，方法数终究会到达这个限制，一种比较流行的方案是插件化方案，另外一种是采用google提供的MultiDex方案，以及google在推出MultiDex之前Android Developers博客介绍的通过自定义类加载过程， 再就是Facebook推出的为Android应用开发的Dalvik补丁， 但facebook博客里写的不是很详细；我们在插件化方案上也做了探索和尝试，发现部署插件化方案，首先需要梳理和修改各个业务线的代码，使之解耦，改动的面和量比较巨大，通过一定的探讨和分析，我们认为对我们目前来说采用MultiDex方案更靠谱一些，这样我们可以快速和简洁的对代码进行拆分，同时代码改动也在可以接受的范围内； 这样我们采用了google提供的MultiDex方式进行了开发。\n插件化方案在业内有不同的实现原理，这里不再一一列举，这里只列举下Google为构建超过65K方法数的应用提供官方支持的方案：MultiDex。\n首先使用Android SDK Manager升级到最新的Android SDK Build Tools和Android Support Library。然后进行以下两步操作：\n1.修改Gradle配置文件，启用MultiDex并包含MultiDex支持：\nandroid { compileSdkVersion 21 buildToolsVersion \u0026quot;21.1.0\u0026quot; defaultConfig { ... minSdkVersion 14 targetSdkVersion 21 ... // Enabling MultiDex support. MultiDexEnabled true } ... } dependencies { compile 'com.android.support:MultiDex:1.0.0' } 2.让应用支持多DEX文件。在官方文档中描述了三种可选方法：\n在AndroidManifest.xml的application中声明android.support.MultiDex.MultiDexApplication；\n如果你已经有自己的Application类，让其继承MultiDexApplication；\n如果你的Application类已经继承自其它类，你不想/能修改它，那么可以重写attachBaseContext()方法：\n@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } 并在Manifest中添加以下声明：\n\u0026lt;?xml version=\u0026quot;1.0\u0026quot; encoding=\u0026quot;utf-8\u0026quot;?\u0026gt; \u0026lt;manifest xmlns:android=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot; package=\u0026quot;com.example.android.MultiDex.myapplication\u0026quot;\u0026gt; \u0026lt;application ... android:name=\u0026quot;android.support.MultiDex.MultiDexApplication\u0026quot;\u0026gt; ... \u0026lt;/application\u0026gt; \u0026lt;/manifest\u0026gt; 如果已经有自己的Application，则让其继承MultiDexApplication即可.\nDex自动拆包及动态加载 MultiDex带来的问题 在第一版本采用MultiDex方案上线后，在Dalvik下MultiDex带来了下列几个问题：\n在冷启动时因为需要安装DEX文件，如果DEX文件过大时，处理时间过长，很容易引发ANR（Application Not Responding）； 采用MultiDex方案的应用可能不能在低于Android 4.0 (API level 14) 机器上启动，这个主要是因为Dalvik linearAlloc的一个bug (Issue 22586); 采用MultiDex方案的应用因为需要申请一个很大的内存，在运行时可能导致程序的崩溃，这个主要是因为Dalvik linearAlloc 的一个限制(Issue 78035). 这个限制在 Android 4.0 (API level 14)已经增加了, 应用也有可能在低于 Android 5.0 (API level 21)版本的机器上触发这个限制； 而在ART下MultiDex是不存在这个问题的，这主要是因为ART下采用Ahead-of-time (AOT) compilation技术，系统在APK的安装过程中会使用自带的dex2oat工具对APK中可用的DEX文件进行编译并生成一个可在本地机器上运行的文件，这样能提高应用的启动速度，因为是在安装过程中进行了处理这样会影响应用的安装速度，对ART感兴趣的可以参考一下ART和Dalvik的区别.\nMultiDex的基本原理是把通过DexFile来加载Secondary DEX，并存放在BaseDexClassLoader的DexPathList中。\n下面代码片段是BaseDexClassLoader findClass的过程:\nprotected Class\u0026lt;?\u0026gt; findClass(String name) throws ClassNotFoundException { List\u0026lt;Throwable\u0026gt; suppressedExceptions = new ArrayList\u0026lt;Throwable\u0026gt;(); Class c = pathList.findClass(name, suppressedExceptions); if (c == null) { ClassNotFoundException cnfe = new ClassNotFoundException(\u0026quot;Didn't find class \\\u0026quot;\u0026quot; + name + \u0026quot;\\\u0026quot; on path: \u0026quot; + pathList); for (Throwable t : suppressedExceptions) { cnfe.addSuppressed(t); } throw cnfe; } return c; } 下面代码片段为怎么通过DexFile来加载Secondary DEX并放到BaseDexClassLoader的DexPathList中:\nprivate static void install(ClassLoader loader, List\u0026lt;File\u0026gt; additionalClassPathEntries, File optimizedDirectory) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException { /* The patched class loader is expected to be a descendant of * dalvik.system.BaseDexClassLoader. We modify its * dalvik.system.DexPathList pathList field to append additional DEX * file entries. */ Field pathListField = findField(loader, \u0026quot;pathList\u0026quot;); Object dexPathList = pathListField.get(loader); ArrayList\u0026lt;IOException\u0026gt; suppressedExceptions = new ArrayList\u0026lt;IOException\u0026gt;(); expandFieldArray(dexPathList, \u0026quot;dexElements\u0026quot;, makeDexElements(dexPathList, new ArrayList\u0026lt;File\u0026gt;(additionalClassPathEntries), optimizedDirectory, suppressedExceptions)); try { if (suppressedExceptions.size() \u0026gt; 0) { for (IOException e : suppressedExceptions) { //Log.w(TAG, \u0026quot;Exception in makeDexElement\u0026quot;, e); } Field suppressedExceptionsField = findField(loader, \u0026quot;dexElementsSuppressedExceptions\u0026quot;); IOException[] dexElementsSuppressedExceptions = (IOException[]) suppressedExceptionsField.get(loader); if (dexElementsSuppressedExceptions == null) { dexElementsSuppressedExceptions = suppressedExceptions.toArray( new IOException[suppressedExceptions.size()]); } else { IOException[] combined = new IOException[suppressedExceptions.size() + dexElementsSuppressedExceptions.length]; suppressedExceptions.toArray(combined); System.arraycopy(dexElementsSuppressedExceptions, 0, combined, suppressedExceptions.size(), dexElementsSuppressedExceptions.length); dexElementsSuppressedExceptions = combined; } suppressedExceptionsField.set(loader, dexElementsSuppressedExceptions); } } catch(Exception e) { } } Dex自动拆包及动态加载方案简介 通过查看MultiDex的源码，我们发现MultiDex在冷启动时容易导致ANR的瓶颈， 在2.1版本之前的Dalvik的VM版本中， MultiDex的安装大概分为几步，第一步打开apk这个zip包，第二步把MultiDex的dex解压出来（除去Classes.dex之外的其他DEX，例如：classes2.dex， classes3.dex等等)，因为android系统在启动app时只加载了第一个Classes.dex，其他的DEX需要我们人工进行安装，第三步通过反射进行安装，这三步其实都比较耗时， 为了解决这个问题我们考虑是否可以把DEX的加载放到一个异步线程中，这样冷启动速度能提高不少，同时能够减少冷启动过程中的ANR，对于Dalvik linearAlloc的一个缺陷(Issue 22586)和限制(Issue 78035)，我们考虑是否可以人工对DEX的拆分进行干预，使每个DEX的大小在一定的合理范围内，这样就减少触发Dalvik linearAlloc的缺陷和限制； 为了实现这几个目的，我们需要解决下面三个问题：\n在打包过程中如何产生多个的DEX包？ 如果做到动态加载，怎么决定哪些DEX动态加载呢？ 如果启动后在工作线程中做动态加载，如果没有加载完而用户进行页面操作需要使用到动态加载DEX中的class怎么办？ 我们首先来分析如何解决第一个问题，在使用MultiDex方案时，我们知道BuildTool会自动把代码进行拆成多个DEX包，并且可以通过配置文件来控制哪些代码放到第一个DEX包中， 下图是Android的打包流程示意图：\n为了实现产生多个DEX包，我们可以在生成DEX文件的这一步中， 在Ant或gradle中自定义一个Task来干预DEX产生的过程，从而产生多个DEX，下图是在ant和gradle中干预产生DEX的自定task的截图:\ntasks.whenTaskAdded { task -\u0026gt; if (task.name.startsWith('proguard') \u0026amp;\u0026amp; (task.name.endsWith('Debug') || task.name.endsWith('Release'))) { task.doLast { makeDexFileAfterProguardJar(); } task.doFirst { delete \u0026quot;${project.buildDir}/intermediates/classes-proguard\u0026quot;; String flavor = task.name.substring('proguard'.length(), task.name.lastIndexOf(task.name.endsWith('Debug') ? \u0026quot;Debug\u0026quot; : \u0026quot;Release\u0026quot;)); generateMainIndexKeepList(flavor.toLowerCase()); } } else if (task.name.startsWith('zipalign') \u0026amp;\u0026amp; (task.name.endsWith('Debug') || task.name.endsWith('Release'))) { task.doFirst { ensureMultiDexInApk(); } } } 上一步解决了如何打包出多个DEX的问题了，那我们该怎么该根据什么来决定哪些class放到Main DEX，哪些放到Secondary DEX呢（这里的Main DEX是指在2.1版本的Dalvik VM之前由android系统在启动apk时自己主动加载的Classes.dex，而Secondary DEX是指需要我们自己安装进去的DEX，例如：Classes2.dex, Classes3.dex等）， 这个需要分析出放到Main DEX中的class依赖，需要确保把Main DEX中class所有的依赖都要放进来，否则在启动时会发生ClassNotFoundException, 这里我们的方案是把Service、Receiver、Provider涉及到的代码都放到Main DEX中，而把Activity涉及到的代码进行了一定的拆分，把首页Activity、Laucher Activity、欢迎页的Activity、城市列表页Activity等所依赖的class放到了Main DEX中，把二级、三级页面的Activity以及业务频道的代码放到了Secondary DEX中，为了减少人工分析class的依赖所带了的不可维护性和高风险性，我们编写了一个能够自动分析Class依赖的脚本， 从而能够保证Main DEX包含class以及他们所依赖的所有class都在其内，这样这个脚本就会在打包之前自动分析出启动到Main DEX所涉及的所有代码，保证Main DEX运行正常。\n随着第二个问题的迎刃而解，我们来到了比较棘手的第三问题，如果我们在后台加载Secondary DEX过程中，用户点击界面将要跳转到使用了在Secondary DEX中class的界面， 那此时必然发生ClassNotFoundException, 那怎么解决这个问题呢，在所有的Activity跳转代码处添加判断Secondary DEX是否加载完成？这个方法可行，但工作量非常大； 那有没有更好的解决方案呢？我们通过分析Activity的启动过程，发现Activity是由ActivityThread 通过Instrumentation来启动的，我们是否可以在Instrumentation中做一定的手脚呢？通过分析代码ActivityThread和Instrumentation发现，Instrumentation有关Activity启动相关的方法大概有：execStartActivity、newActivity等等，这样我们就可以在这些方法中添加代码逻辑进行判断这个Class是否加载了，如果加载则直接启动这个Activity，如果没有加载完成则启动一个等待的Activity显示给用户，然后在这个Activity中等待后台Secondary DEX加载完成，完成后自动跳转到用户实际要跳转的Activity；这样在代码充分解耦合，以及每个业务代码能够做到颗粒化的前提下，我们就做到Secondary DEX的按需加载了， 下面是Instrumentation添加的部分关键代码：\npublic ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) { ActivityResult activityResult = null; String className; if (intent.getComponent() != null) { className = intent.getComponent().getClassName(); } else { ResolveInfo resolveActivity = who.getPackageManager().resolveActivity(intent, 0); if (resolveActivity != null \u0026amp;\u0026amp; resolveActivity.activityInfo != null) { className = resolveActivity.activityInfo.name; } else { className = null; } } if (!TextUtils.isEmpty(className)) { boolean shouldInterrupted = !MeituanApplication.isDexAvailable(); if (MeituanApplication.sIsDexAvailable.get() || mByPassActivityClassNameList.contains(className)) { shouldInterrupted = false; } if (shouldInterrupted) { Intent interruptedIntent = new Intent(mContext, WaitingActivity.class); activityResult = execStartActivity(who, contextThread, token, target, interruptedIntent, requestCode); } else { activityResult = execStartActivity(who, contextThread, token, target, intent, requestCode); } } else { activityResult = execStartActivity(who, contextThread, token, target, intent, requestCode); } return activityResult; } public Activity newActivity(Class\u0026lt;?\u0026gt; clazz, Context context, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance) throws InstantiationException, IllegalAccessException { String className = \u0026quot;\u0026quot;; Activity newActivity = null; if (intent.getComponent() != null) { className = intent.getComponent().getClassName(); } boolean shouldInterrupted = !MeituanApplication.isDexAvailable(); if (MeituanApplication.sIsDexAvailable.get() || mByPassActivityClassNameList.contains(className)) { shouldInterrupted = false; } if (shouldInterrupted) { intent = new Intent(mContext, WaitingActivity.class); newActivity = mBase.newActivity(clazz, context, token, application, intent, info, title, parent, id, lastNonConfigurationInstance); } else { newActivity = mBase.newActivity(clazz, context, token, application, intent, info, title, parent, id, lastNonConfigurationInstance); } return newActivity; } 实际应用中我们还遇到另外一个比较棘手的问题， 就是Field的过多的问题，Field过多是由我们目前采用的代码组织结构引入的，我们为了方便多业务线、多团队并发协作的情况下开发，我们采用的aar的方式进行开发，并同时在aar依赖链的最底层引入了一个通用业务aar，而这个通用业务aar中包含了很多资源，而ADT14以及更高的版本中对Library资源处理时，Library的R资源不再是static final的了，详情请查看google官方说明，这样在最终打包时Library中的R没法做到内联，这样带来了R field过多的情况，导致需要拆分多个Secondary DEX，为了解决这个问题我们采用的是在打包过程中利用脚本把Libray中R field（例如ID、Layout、Drawable等）的引用替换成常量，然后删去Library中R.class中的相应Field。\n总结 上面就是我们在使用MultiDex过程中进化而来的DEX自动化拆包的方案， 这样我们就可以通过脚本控制来进行自动化的拆分DEX，然后在运行时自由的加载Secondary DEX，既能保证冷启动速度，又能减少运行时的内存占用。\n转自：http://tech.meituan.com/mt-android-auto-split-dex.html\n","permalink":"https://blog.zdltech.com/posts/%E7%BE%8E%E5%9B%A2android-dex%E8%87%AA%E5%8A%A8%E6%8B%86%E5%8C%85%E5%8F%8A%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E7%AE%80%E4%BB%8B-2/","summary":"\u003ch2 id=\"-\"\u003e概述\u003c/h2\u003e\n\u003cp\u003e作为一个android开发者，在开发应用时，随着业务规模发展到一定程度，不断地加入新功能、添加新的类库，代码在急剧的膨胀，相应的apk包的大小也急剧增加， 那么终有一天，你会不幸遇到这个错误：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e生成的apk在android 2.3或之前的机器上无法安装，提示INSTALL_FAILED_DEXOPT\u003c/li\u003e\n\u003cli\u003e方法数量过多，编译时出错，提示：\nConversion to Dalvik format failed:Unable to execute dex: method ID not in [0, 0xffff]: 65536\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e而问题产生的具体原因如下：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e无法安装（Android 2.3 INSTALL_FAILED_DEXOPT）问题，是由dexopt的LinearAlloc限制引起的，在Android版本不同分别经历了4M/5M/8M/16M限制，目前主流4.2.x系统上可能都已到16M， 在Gingerbread或者以下系统LinearAllocHdr分配空间只有5M大小的， 高于Gingerbread的系统提升到了8M。Dalvik linearAlloc是一个固定大小的缓冲区。在应用的安装过程中，系统会运行一个名为dexopt的程序为该应用在当前机型中运行做准备。dexopt使用LinearAlloc来存储应用的方法信息。Android 2.2和2.3的缓冲区只有5MB，Android 4.x提高到了8MB或16MB。当方法数量过多导致超出缓冲区大小时，会造成dexopt崩溃。\u003c/li\u003e\n\u003cli\u003e超过最大方法数限制的问题，是由于DEX文件格式限制，一个DEX文件中method个数采用使用原生类型short来索引文件中的方法，也就是4个字节共计最多表达65536个method，field/class的个数也均有此限制。对于DEX文件，则是将工程所需全部class文件合并且压缩到一个DEX文件期间，也就是Android打包的DEX过程中， 单个DEX文件可被引用的方法总数（自己开发的代码以及所引用的Android框架、类库的代码）被限制为65536；\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"-multidex-\"\u003e插件化？ MultiDex？\u003c/h2\u003e\n\u003cp\u003e解决这个问题，一般有下面几种方案，一种方案是加大Proguard的力度来减小DEX的大小和方法数，但这是治标不治本的方案，随着业务代码的添加，方法数终究会到达这个限制，一种比较流行的方案是插件化方案，另外一种是采用google提供的MultiDex方案，以及google在推出MultiDex之前Android Developers博客介绍的通过\u003ca href=\"http://android-developers.blogspot.hk/2011/07/custom-class-loading-in-dalvik.html\"\u003e自定义类加载过程\u003c/a\u003e， 再就是Facebook推出的为Android应用开发的\u003ca href=\"https://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920\"\u003eDalvik补丁\u003c/a\u003e， 但facebook博客里写的不是很详细；我们在插件化方案上也做了探索和尝试，发现部署插件化方案，首先需要梳理和修改各个业务线的代码，使之解耦，改动的面和量比较巨大，通过一定的探讨和分析，我们认为对我们目前来说采用MultiDex方案更靠谱一些，这样我们可以快速和简洁的对代码进行拆分，同时代码改动也在可以接受的范围内； 这样我们采用了google提供的MultiDex方式进行了开发。\u003c/p\u003e\n\u003cp\u003e插件化方案在业内有不同的实现原理，这里不再一一列举，这里只列举下Google为构建超过65K方法数的应用提供官方支持的方案：\u003ca href=\"https://developer.android.com/tools/building/MultiDex.html\"\u003eMultiDex\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e首先使用Android SDK Manager升级到最新的Android SDK Build Tools和Android Support Library。然后进行以下两步操作：\u003c/p\u003e\n\u003cp\u003e1.修改Gradle配置文件，启用MultiDex并包含MultiDex支持：\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  android {\n    compileSdkVersion 21 buildToolsVersion \u0026quot;21.1.0\u0026quot;\n\n    defaultConfig {\n        ...\n        minSdkVersion 14\n        targetSdkVersion 21\n        ...\n\n        // Enabling MultiDex support.\n        MultiDexEnabled true\n        }\n        ...\n    }\n    dependencies { compile 'com.android.support:MultiDex:1.0.0'\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e2.让应用支持多DEX文件。在官方文档中描述了三种可选方法：\u003c/p\u003e","title":"美团Android DEX自动拆包及动态加载简介"},{"content":"前言 Android应用中的APK安全性一直遭人诟病，市面上充斥着各种被破解或者汉化的应用，破解者可以非常简单的通过破解工具就能对一个APK进行反编译、破解、汉化等等，这样就可以修改原有代码的逻辑、添加新代码、添加或修改资源、或者更有甚者植入病毒等等，从而破坏原有APK的安全和用户体验，最终伤害到用户和原有的开发者。\n而事物都是有两方面的，有矛就有盾，针对Android应用安全的各种方案应运而生，大家比较熟悉一般是各类加壳加固的工具，我们可以使用这些工具来保护我们的APK，加壳加固是另外一个话题了，我们这里不对加壳加固进行介绍，后续如果有机会会单独开一个话题讨论，我们在开发过程中可以通过ProGuard或者DexGuard来保护我们的代码，从而实现相对的代码安全，但我们的资源呢？我们往往忽略对资源文件的保护，那这里将要分享的是如果采用常规方式对APK中的资源文件进行保护。\n资源安全 资源安全这个话题目前大家关注度不算太高，相比较而言大家更关注代码安全，目前市面上各类APP基本都使用了ProGuard来保护代码的安全，但对资源文件的保护力度都不大，其实资源文件是存在比较大的安全隐患，那资源会有哪些安全隐患呢？下面我们通过一个比较简单的例子来说明下保护资源文件的重要性。\n我们先用最常见的apktool工具来反编译一个应用来看看，通过运行下面命令就能进行反编译；\napktool d -s xxx.apk 反编译成功后我们来看下反编译得到的文件结构（见下图）；\n通过上图中的目录结构，我们可以看到这个应用的资源文件大概有：anim、drawable、layout、menu、values等等，我们可以通过修改这些文件夹下的资源文件，并通过apktool进行回编译（apktool b 命令）就能创建一个经过修改过的APK应用，例如我们修改下图中红色横线所标示的layout文件，就能往原有APK的支付信息（根据资源名称猜测这个layout的意图）中添加一些我们自己的东西；\n这个问题主要是因为我们在开发过程中倡导命名的规范性，一般都要求在命名时做到见名知意，这样能够方便我们自己的理解和维护，但同时这也方便了破解者，破解者可以轻松的根据文件名称来猜测这个文件的意图和作用，从而做破坏性的修改。\n通过这个例子我们可以看出目前资源安全的重要性，那如何做到资源安全呢？安全都是相对的，没有绝对的安全，我们接下来要讨论的是类似Proguard方式的对我们的资源进行保护。我们主要是通过修改AAPT工具来对资源进行保护，为了方便理解，下面先讲一下Android应用是怎么查找资源的。\nAndroid查找资源的流程 在Android系统中，每一个应用程序一般都会配置很多资源，用来适配不同密度、大小和方向的屏幕，以及适配不同的国家、地区和语言等等。这些资源是在应用程序运行时自动根据设备的当前配置信息进行适配的。这也就是说，给定一个相同的资源ID，在不同的设备配置之下，查找到的可能是不同的资源。\n这个查找过程对应用程序来说，是完全透明的，这个过程主要是靠Android资源管理框架来完成的，而Android资源管理框架实际是由AssetManager和Resources两个类来实现的。其中，Resources类可以根据ID来查找资源，而AssetManager类根据文件名来查找资源。事实上，如果一个资源ID对应的是一个文件，那么Resources类是先根据ID来找到资源文件名称，然后再将该文件名称交给AssetManager类来打开对应的文件的。基本流程如下图：\n通过上图我们可以看到Resources是通过resources.arsc把Resource的ID转化成资源文件的名称，然后交由AssetManager来加载的。\n而Resources.arsc这个文件是存放在APK包中的，他是由AAPT工具在打包过程中生成的，他本身是一个资源的索引表，里面维护者资源ID、Name、Path或者Value的对应关系，AssetManager通过这个索引表，就可以通过资源的ID找到这个资源对应的文件或者数据。\nAAPT介绍 AAPT是Android Asset Packaging Tool的缩写，它存放在SDK的tools/目录下，AAPT的功能很强大，可以通过它查看查看、创建、更新压缩文件(如 .zip文件，.jar文件, .apk文件), 它也可以把资源编译为二进制文件，并生成resources.arsc, AAPT这个工具在APK打包过程中起到了非常重要作用，在打包过程中使用AAPT对APK中用到的资源进行打包，这里不对AAPT这个工具做过多的讨论，只看一下AAPT这个工具在打包过程中起到的作用，下图是AAPT打包的流程：\nAAPT这个工具在打包过程中主要做了下列工作：\n把”assets”和”res/raw”目录下的所有资源进行打包（会根据不同的文件后缀选择压缩或不压缩），而”res/”目录下的其他资源进行编译或者其他处理（具体处理方式视文件后缀不同而不同，例如：”.xml”会编译成二进制文件，”.png”文件会进行优化等等）后才进行打包； 会对除了assets资源之外所有的资源赋予一个资源ID常量，并且会生成一个资源索引表resources.arsc； 编译AndroidManifest.xml成二进制的XML文件； 把上面3个步骤中生成结果保存在一个*.ap_文件，并把各个资源ID常量定义在一个R.java中； .ap_这个文件会在生成APK时放入APK包中, .ap _这个文件本身是一个ZIP包，他里面包含resources.arsc、AndroidManifest.xml、assets以及所有的资源文件，下图是UNZIP后的截图：\n可以看出*.ap_这个文件中包含的内容，这个文件存放在build/intermediates/res的目录下，下图是这个文件存放的路径截图：\n资源保护 我们这里参考Proguard Obfuscator方式，对APK中资源文件名使用简短无意义名称进行替换，给破解者制造困难，从而做到资源的相对安全；通过上面分析，我们可以看出通过修改AAPT在生成resources.arsc和*.ap_时把资源文件的名称进行替换，从而保护资源。\n通过阅读AAPT编译资源的代码，我们发现修改AAPT在处理资源文件相关的源码是能够做到资源文件名的替换，下面是Resource.cpp中makeFileResources()的修改的代码片段：\nstatic status_t makeFileResources(Bundle* bundle, const sp\u0026lt;AaptAssets\u0026gt;\u0026amp; assets, ResourceTable* table, const sp\u0026lt;ResourceTypeSet\u0026gt;\u0026amp; set, const char* resType) { String8 type8(resType); String16 type16(resType); bool hasErrors = false; ResourceDirIterator it(set, String8(resType)); ssize_t res; while ((res=it.next()) == NO_ERROR) { if (bundle-\u0026gt;getVerbose()) { printf(\u0026quot; (new resource id %s from %s)\\n\u0026quot;, it.getBaseName().string(), it.getFile()-\u0026gt;getPrintableSource().string()); } String16 baseName(it.getBaseName()); const char16_t* str = baseName.string(); const char16_t* const end = str + baseName.size(); while (str \u0026lt; end) { if (!((*str \u0026gt;= 'a' \u0026amp;\u0026amp; *str \u0026lt;= 'z') || (*str \u0026gt;= '0' \u0026amp;\u0026amp; *str \u0026lt;= '9') || *str == '_' || *str == '.')) { fprintf(stderr, \u0026quot;%s: Invalid file name: must contain only [a-z0-9_.]\\n\u0026quot;, it.getPath().string()); hasErrors = true; } str++; } String8 resPath = it.getPath(); resPath.convertToResPath(); String8 obfuscationName; String8 obfuscationPath = getObfuscationName(resPath, obfuscationName); table-\u0026gt;addEntry(SourcePos(it.getPath(), 0), String16(assets-\u0026gt;getPackage()), type16, baseName, // String16(obfuscationName), String16(obfuscationPath), // resPath NULL, \u0026amp;it.getParams()); assets-\u0026gt;addResource(it.getLeafName(), obfuscationPath/*resPath*/, it.getFile(), type8); } return hasErrors ? UNKNOWN_ERROR : NO_ERROR; } 上述代码是在ResourceTable和Assets中添加资源文件时， 对资源文件名称进行修改，这就能够做到资源文件名称的替换，这样通过使用修改过的AAPT编译资源并进行打包，我们再用上面讲到的apktool这个工具进行反编译，下图是反编译后的截图：\n发现什么变化了吗？在res目录下熟悉的layout、drawable、anim、menu等文件夹不见了，那他们去哪了呢？因为apktool工具把它们放到了unknown文件夹下了，见下图：\n让我们来看一下unknown文件夹，你会发现资源文件名已经被简短无意义名称进行替换了，这样会给反编译者制造理解上的困难，反编译者需要消耗一定的时间来搞清楚这些资源文件的作用，资源混淆带来的另外一个好处是能明显减小APK的大小，资源混淆既能保护资源文件的安全又能减小安装包的大小，那我们何乐而不为呢？\n这样通过修改AAPT，我们可以在代码零修改的基础下就能做到相对的资源安全，当然安全是相对的，没有绝对的安全。\n转自：http://tech.meituan.com/mt-android-resource-obfuscation.html\n","permalink":"https://blog.zdltech.com/posts/%E7%BE%8E%E5%9B%A2android%E8%B5%84%E6%BA%90%E6%B7%B7%E6%B7%86%E4%BF%9D%E6%8A%A4%E5%AE%9E%E8%B7%B5/","summary":"\u003ch2 id=\"-\"\u003e前言\u003c/h2\u003e\n\u003cp\u003eAndroid应用中的APK安全性一直遭人诟病，市面上充斥着各种被破解或者汉化的应用，破解者可以非常简单的通过破解工具就能对一个APK进行反编译、破解、汉化等等，这样就可以修改原有代码的逻辑、添加新代码、添加或修改资源、或者更有甚者植入病毒等等，从而破坏原有APK的安全和用户体验，最终伤害到用户和原有的开发者。\u003cbr\u003e\n而事物都是有两方面的，有矛就有盾，针对Android应用安全的各种方案应运而生，大家比较熟悉一般是各类加壳加固的工具，我们可以使用这些工具来保护我们的APK，加壳加固是另外一个话题了，我们这里不对加壳加固进行介绍，后续如果有机会会单独开一个话题讨论，我们在开发过程中可以通过ProGuard或者DexGuard来保护我们的代码，从而实现相对的代码安全，但我们的资源呢？我们往往忽略对资源文件的保护，那这里将要分享的是如果采用常规方式对APK中的资源文件进行保护。\u003c/p\u003e\n\u003ch2 id=\"-\"\u003e资源安全\u003c/h2\u003e\n\u003cp\u003e资源安全这个话题目前大家关注度不算太高，相比较而言大家更关注代码安全，目前市面上各类APP基本都使用了ProGuard来保护代码的安全，但对资源文件的保护力度都不大，其实资源文件是存在比较大的安全隐患，那资源会有哪些安全隐患呢？下面我们通过一个比较简单的例子来说明下保护资源文件的重要性。\u003c/p\u003e\n\u003cp\u003e我们先用最常见的apktool工具来反编译一个应用来看看，通过运行下面命令就能进行反编译；\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    apktool d -s xxx.apk\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e反编译成功后我们来看下反编译得到的文件结构（见下图）；\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://tech.meituan.com/img/mt-android-resource-obfuscation/decompile_folder_struct.png\"\u003e\u003c/p\u003e\n\u003cp\u003e通过上图中的目录结构，我们可以看到这个应用的资源文件大概有：anim、drawable、layout、menu、values等等，我们可以通过修改这些文件夹下的资源文件，并通过apktool进行回编译（apktool b 命令）就能创建一个经过修改过的APK应用，例如我们修改下图中红色横线所标示的layout文件，就能往原有APK的支付信息（根据资源名称猜测这个layout的意图）中添加一些我们自己的东西；\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://tech.meituan.com/img/mt-android-resource-obfuscation/decompile_folder_struct2.png\"\u003e\u003c/p\u003e\n\u003cp\u003e这个问题主要是因为我们在开发过程中倡导命名的规范性，一般都要求在命名时做到见名知意，这样能够方便我们自己的理解和维护，但同时这也方便了破解者，破解者可以轻松的根据文件名称来猜测这个文件的意图和作用，从而做破坏性的修改。\u003c/p\u003e\n\u003cp\u003e通过这个例子我们可以看出目前资源安全的重要性，那如何做到资源安全呢？安全都是相对的，没有绝对的安全，我们接下来要讨论的是类似Proguard方式的对我们的资源进行保护。我们主要是通过修改AAPT工具来对资源进行保护，为了方便理解，下面先讲一下Android应用是怎么查找资源的。\u003c/p\u003e\n\u003ch2 id=\"android-\"\u003eAndroid查找资源的流程\u003c/h2\u003e\n\u003cp\u003e在Android系统中，每一个应用程序一般都会配置很多资源，用来适配不同密度、大小和方向的屏幕，以及适配不同的国家、地区和语言等等。这些资源是在应用程序运行时自动根据设备的当前配置信息进行适配的。这也就是说，给定一个相同的资源ID，在不同的设备配置之下，查找到的可能是不同的资源。\u003cbr\u003e\n这个查找过程对应用程序来说，是完全透明的，这个过程主要是靠Android资源管理框架来完成的，而Android资源管理框架实际是由AssetManager和Resources两个类来实现的。其中，Resources类可以根据ID来查找资源，而AssetManager类根据文件名来查找资源。事实上，如果一个资源ID对应的是一个文件，那么Resources类是先根据ID来找到资源文件名称，然后再将该文件名称交给AssetManager类来打开对应的文件的。基本流程如下图：\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://tech.meituan.com/img/mt-android-resource-obfuscation/android_resource_resolved_flow.png\"\u003e\u003c/p\u003e\n\u003cp\u003e通过上图我们可以看到Resources是通过resources.arsc把Resource的ID转化成资源文件的名称，然后交由AssetManager来加载的。\u003cbr\u003e\n而Resources.arsc这个文件是存放在APK包中的，他是由AAPT工具在打包过程中生成的，他本身是一个资源的索引表，里面维护者资源ID、Name、Path或者Value的对应关系，AssetManager通过这个索引表，就可以通过资源的ID找到这个资源对应的文件或者数据。\u003c/p\u003e\n\u003ch2 id=\"aapt-\"\u003eAAPT介绍\u003c/h2\u003e\n\u003cp\u003eAAPT是Android Asset Packaging Tool的缩写，它存放在SDK的tools/目录下，AAPT的功能很强大，可以通过它查看查看、创建、更新压缩文件(如 .zip文件，.jar文件, .apk文件), 它也可以把资源编译为二进制文件，并生成resources.arsc, AAPT这个工具在APK打包过程中起到了非常重要作用，在打包过程中使用AAPT对APK中用到的资源进行打包，这里不对AAPT这个工具做过多的讨论，只看一下AAPT这个工具在打包过程中起到的作用，下图是AAPT打包的流程：\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://tech.meituan.com/img/mt-android-resource-obfuscation/aapt_packaging_flow.png\"\u003e\u003c/p\u003e\n\u003cp\u003eAAPT这个工具在打包过程中主要做了下列工作：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e把”assets”和”res/raw”目录下的所有资源进行打包（会根据不同的文件后缀选择压缩或不压缩），而”res/”目录下的其他资源进行编译或者其他处理（具体处理方式视文件后缀不同而不同，例如：”.xml”会编译成二进制文件，”.png”文件会进行优化等等）后才进行打包；\u003c/li\u003e\n\u003cli\u003e会对除了assets资源之外所有的资源赋予一个资源ID常量，并且会生成一个资源索引表resources.arsc；\u003c/li\u003e\n\u003cli\u003e编译AndroidManifest.xml成二进制的XML文件；\u003c/li\u003e\n\u003cli\u003e把上面3个步骤中生成结果保存在一个*.ap_文件，并把各个资源ID常量定义在一个R.java中；\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cem\u003e.ap_这个文件会在生成APK时放入APK包中,\u003c/em\u003e .ap _这个文件本身是一个ZIP包，他里面包含resources.arsc、AndroidManifest.xml、assets以及所有的资源文件，下图是UNZIP后的截图：\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://tech.meituan.com/img/mt-android-resource-obfuscation/ap_file_unzip.png\"\u003e\u003cbr\u003e\n可以看出*.ap_这个文件中包含的内容，这个文件存放在build/intermediates/res的目录下，下图是这个文件存放的路径截图：\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://tech.meituan.com/img/mt-android-resource-obfuscation/ap_file_unzip2.png\"\u003e\u003c/p\u003e\n\u003ch2 id=\"-\"\u003e资源保护\u003c/h2\u003e\n\u003cp\u003e我们这里参考Proguard Obfuscator方式，对APK中资源文件名使用简短无意义名称进行替换，给破解者制造困难，从而做到资源的相对安全；通过上面分析，我们可以看出通过修改AAPT在生成resources.arsc和*.ap_时把资源文件的名称进行替换，从而保护资源。\u003cbr\u003e\n通过阅读AAPT编译资源的代码，我们发现修改AAPT在处理资源文件相关的源码是能够做到资源文件名的替换，下面是Resource.cpp中makeFileResources()的修改的代码片段：\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    static status_t makeFileResources(Bundle* bundle, const sp\u0026lt;AaptAssets\u0026gt;\u0026amp; assets,\n                                      ResourceTable* table,\n                                      const sp\u0026lt;ResourceTypeSet\u0026gt;\u0026amp; set,\n                                      const char* resType)\n    {\n        String8 type8(resType);\n        String16 type16(resType);\n\n        bool hasErrors = false;\n\n        ResourceDirIterator it(set, String8(resType));\n        ssize_t res;\n        while ((res=it.next()) == NO_ERROR) {\n            if (bundle-\u0026gt;getVerbose()) {\n                printf(\u0026quot;    (new resource id %s from %s)\\n\u0026quot;,\n                       it.getBaseName().string(), it.getFile()-\u0026gt;getPrintableSource().string());\n            }\n            String16 baseName(it.getBaseName());\n            const char16_t* str = baseName.string();\n            const char16_t* const end = str + baseName.size();\n            while (str \u0026lt; end) {\n                if (!((*str \u0026gt;= 'a' \u0026amp;\u0026amp; *str \u0026lt;= 'z')\n                        || (*str \u0026gt;= '0' \u0026amp;\u0026amp; *str \u0026lt;= '9')\n                        || *str == '_' || *str == '.')) {\n                    fprintf(stderr, \u0026quot;%s: Invalid file name: must contain only [a-z0-9_.]\\n\u0026quot;,\n                            it.getPath().string());\n                    hasErrors = true;\n                }\n                str++;\n            }\n            String8 resPath = it.getPath();\n            resPath.convertToResPath();\n\n            String8 obfuscationName;\n            String8 obfuscationPath = getObfuscationName(resPath, obfuscationName);\n\n            table-\u0026gt;addEntry(SourcePos(it.getPath(), 0), String16(assets-\u0026gt;getPackage()),\n                            type16,\n                            baseName, // String16(obfuscationName),\n                            String16(obfuscationPath), // resPath\n                            NULL,\n                            \u0026amp;it.getParams());\n            assets-\u0026gt;addResource(it.getLeafName(), obfuscationPath/*resPath*/, it.getFile(), type8);\n        }\n\n        return hasErrors ? UNKNOWN_ERROR : NO_ERROR;\n    }\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上述代码是在ResourceTable和Assets中添加资源文件时， 对资源文件名称进行修改，这就能够做到资源文件名称的替换，这样通过使用修改过的AAPT编译资源并进行打包，我们再用上面讲到的apktool这个工具进行反编译，下图是反编译后的截图：\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://tech.meituan.com/img/mt-android-resource-obfuscation/decompile_folder_struct_with_modified_aapt.png\"\u003e\u003c/p\u003e","title":"美团Android资源混淆保护实践"},{"content":"概述 前一篇文章(美团Android自动化之旅—生成渠道包)介绍了Android中几种生成渠道包的方式，基本解决了打包慢的问题。\n但是，随着渠道越来越多，不同渠道对应用的要求也不尽相同。例如，有的渠道要求美团客户端的应用名为美团，有的渠道要求应用名为美团团购。又比如，有些渠道要求应用不能使用第三方统计工具（如flurry）。总之，每次打包都需要对这些渠道进行适配。\n之前的做法是为每个需要适配的渠道创建一个Git分支，发版时再切换到相应的分支，并合并主分支的代码。适配的渠道比较少的话这种方式还可以接受，如果分支比较多，对开发人员来说简直就是噩梦。还好，自从有了Gradle flavor，一切都变得简单了。本文假定读者使用过Gradle，如果还不了解建议先阅读相关文档。\nFlavor 先来看build.gradle文件中的一段代码：\nandroid { .... productFlavors { flavor1 { minSdkVersion 14 } } } 上例定义了一个flavor：flavor1，并指定了应用的minSdkVersion为14（当然还可以配置更多的属性，具体可参考相关文档）。与此同时，Gradle还会为该flavor关联对应的sourceSet，默认位置为src/\u0026lt;flavorName\u0026gt;目录，对应到本例就是src/flavor1。\n接下来，要做的就是根据具体的需求在build.gradle文件中配置flavor，并添加必要的代码和资源文件。以flavor1为例，运行gradle assembleFlavor1命令既可生成所需的适配包。下面主要介绍美团团购Android客户端的一些适配案例。\n案例 使用不同的包名 美团团购Android客户端之前有两个版本：手机版(com.meituan.group)和hd版(com.meituan.group.hd)，两个版本使用了不同的代码。目前hd版对应的代码已不再维护，希望能直接使用手机版的代码。解决该问题可以有多种方法，不过使用flavor相对比较简单，示例如下：\nproductFlavors { hd { applicationId \u0026quot;com.meituan.group.hd\u0026quot; } } 上面的代码添加了一个名为hd的flavor，并指定了应用的包名为com.meituan.group.hd，运行gradle assembleHd命令即可生成hd适配包。\n控制是否自动更新 美团团购Android客户端在启动时会默认检查客户端是否有更新，如果有更新就会提示用户下载。但是有些渠道和应用市场不允许这种默认行为，所以在适配这些渠道时需要禁止自动更新功能。\n解决的思路是提供一个配置字段，应用启动的时候检查该字段的值以决定是否开启自动更新功能。使用flavor可以完美的解决这类问题。\nGradle会在generateSources阶段为flavor生成一个BuildConfig.java文件。BuildConfig类默认提供了一些常量字段，比如应用的版本名（VERSION_NAME），应用的包名（PACKAGE_NAME）等。更强大的是，开发者还可以添加自定义的一些字段。下面的示例假设wandoujia市场默认禁止自动更新功能：\nandroid { defaultConfig { buildConfigField \u0026quot;boolean\u0026quot;, \u0026quot;AUTO_UPDATES\u0026quot;, \u0026quot;true\u0026quot; } productFlavors { wandoujia { buildConfigField \u0026quot;boolean\u0026quot;, \u0026quot;AUTO_UPDATES\u0026quot;, \u0026quot;false\u0026quot; } } } 上面的代码会在BuildConfig类中生成AUTO_UPDATES布尔常量，默认值为true，在使用wandoujia flavor时，该值会被设置成false。接下来就可以在代码中使用AUTO_UPDATES常量来判断是否开启自动更新功能了。最后，运行gradle assembleWandoujia命令即可生成默认不开启自动升级功能的渠道包，是不是很简单。\n使用不同的应用名 最常见的一类适配是修改应用的资源。例如，美团团购Android客户端的应用名是美团，但有的渠道需要把应用名修改为美团团购；还有，客户端经常会和一些应用分发市场合作，需要在应用的启动界面中加上第三方市场的Logo，类似这类适配形式还有很多。\nGradle在构建应用时，会优先使用flavor所属dataSet中的同名资源。所以，解决思路就是在flavor的dataSet中添加同名的字符串资源，以覆盖默认的资源。下面以适配wandoujia渠道的应用名为美团团购为例进行介绍。\n首先，在build.gradle配置文件中添加如下flavor：\nandroid { productFlavors { wandoujia { } } } 上面的配置会默认src/wandoujia目录为wandoujia flavor的dataSet。\n接下来，在src目录内创建wandoujia目录，并添加如下应用名字符串资源（src/wandoujia/res/values/appname.xml）：\n\u0026lt;resources\u0026gt; \u0026lt;string name=\u0026quot;app_name\u0026quot;\u0026gt;美团团购\u0026lt;/string\u0026gt; \u0026lt;/resources\u0026gt; 默认的应用名字符串资源如下（src/main/res/values/strings.xml）:\n\u0026lt;resources\u0026gt; \u0026lt;string name=\u0026quot;app_name\u0026quot;\u0026gt;美团\u0026lt;/string\u0026gt; \u0026lt;/resources\u0026gt; 最后，运行gradle assembleWandoujia命令即可生成应用名为美团团购的应用了。\n使用第三方SDK 某些渠道会要求客户端嵌入第三方SDK来满足特定的适配需求。比如360应用市场要求美团团购Android客户端的精品应用模块使用他们提供的SDK。问题的难点在于如何只为特定的渠道添加SDK，其他渠道不引入该SDK。使用flavor可以很好的解决这个问题，下面以为qihu360 flavor引入com.qihoo360.union.sdk:union:1.0SDK为例进行说明：\nandroid { productFlavors { qihu360 { } } } ... dependencies { provided 'com.qihoo360.union.sdk:union:1.0' qihu360Compile 'com.qihoo360.union.sdk:union:1.0' } 上例添加了名为qihu360的flavor，并且指定编译和运行时都依赖com.qihoo360.union.sdk:union:1.0。而其他渠道只是在构建的时候依赖该SDK，打包的时候并不会添加它。\n接下来，需要在代码中使用反射技术判断应用程序是否添加了该SDK，从而决定是否要显示360 SDK提供的精品应用。部分代码如下：\nclass MyActivity extends Activity { private boolean useQihuSdk; @override public void onCreate(Bundle savedInstanceState) { try { Class.forName(\u0026quot;com.qihoo360.union.sdk.UnionManager\u0026quot;); useQihuSdk = true; } catch (ClassNotFoundException ignored) { } } } 最后，运行gradle assembleQihu360命令即可生成包含360精品应用模块的渠道包了。\n总结 适配是一项dirty工作，尤其是适配的渠道比较多的时候。上面介绍了几种使用Gradle flavor进行适配的例子，基本解决了繁杂的适配工作。\n参考资料 http://www.gradle.org/ Product flavors http://pkaq.github.io/gradledoc/docs/userguide/userguide.html\n","permalink":"https://blog.zdltech.com/posts/%E7%BE%8E%E5%9B%A2android%E8%87%AA%E5%8A%A8%E5%8C%96%E4%B9%8B%E6%97%85-%E9%80%82%E9%85%8D%E6%B8%A0%E9%81%93%E5%8C%85/","summary":"\u003ch2 id=\"-\"\u003e概述\u003c/h2\u003e\n\u003cp\u003e前一篇文章(\u003ca href=\"http://tech.meituan.com/mt-apk-packaging.html\"\u003e美团Android自动化之旅—生成渠道包\u003c/a\u003e)介绍了Android中几种生成渠道包的方式，基本解决了打包慢的问题。\u003c/p\u003e\n\u003cp\u003e但是，随着渠道越来越多，不同渠道对应用的要求也不尽相同。例如，有的渠道要求美团客户端的应用名为\u003ccode\u003e美团\u003c/code\u003e，有的渠道要求应用名为\u003ccode\u003e美团团购\u003c/code\u003e。又比如，有些渠道要求应用不能使用第三方统计工具（如flurry）。总之，每次打包都需要对这些渠道进行适配。\u003c/p\u003e\n\u003cp\u003e之前的做法是为每个需要适配的渠道创建一个Git分支，发版时再切换到相应的分支，并合并主分支的代码。适配的渠道比较少的话这种方式还可以接受，如果分支比较多，对开发人员来说简直就是噩梦。还好，自从有了Gradle flavor，一切都变得简单了。本文假定读者使用过Gradle，如果还不了解建议先阅读相关文档。\u003c/p\u003e\n\u003ch2 id=\"flavor\"\u003eFlavor\u003c/h2\u003e\n\u003cp\u003e先来看\u003ccode\u003ebuild.gradle\u003c/code\u003e文件中的一段代码：\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eandroid {\n    ....\n\n    productFlavors {\n        flavor1 {\n            minSdkVersion 14\n        }\n    }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上例定义了一个flavor：\u003ccode\u003eflavor1\u003c/code\u003e，并指定了应用的\u003ccode\u003eminSdkVersion\u003c/code\u003e为14（当然还可以配置更多的属性，具体可参考相关文档）。与此同时，Gradle还会为该flavor关联对应的\u003ccode\u003esourceSet\u003c/code\u003e，默认位置为\u003ccode\u003esrc/\u0026lt;flavorName\u0026gt;\u003c/code\u003e目录，对应到本例就是\u003ccode\u003esrc/flavor1\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e接下来，要做的就是根据具体的需求在\u003ccode\u003ebuild.gradle\u003c/code\u003e文件中配置flavor，并添加必要的代码和资源文件。以\u003ccode\u003eflavor1\u003c/code\u003e为例，运行\u003ccode\u003egradle assembleFlavor1\u003c/code\u003e命令既可生成所需的适配包。下面主要介绍美团团购Android客户端的一些适配案例。\u003c/p\u003e\n\u003ch2 id=\"-\"\u003e案例\u003c/h2\u003e\n\u003ch3 id=\"-\"\u003e使用不同的包名\u003c/h3\u003e\n\u003cp\u003e美团团购Android客户端之前有两个版本：手机版(\u003ccode\u003ecom.meituan.group\u003c/code\u003e)和hd版(\u003ccode\u003ecom.meituan.group.hd\u003c/code\u003e)，两个版本使用了不同的代码。目前hd版对应的代码已不再维护，希望能直接使用手机版的代码。解决该问题可以有多种方法，不过使用flavor相对比较简单，示例如下：\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eproductFlavors {\n    hd {\n        applicationId \u0026quot;com.meituan.group.hd\u0026quot;\n    }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上面的代码添加了一个名为\u003ccode\u003ehd\u003c/code\u003e的flavor，并指定了应用的包名为\u003ccode\u003ecom.meituan.group.hd\u003c/code\u003e，运行\u003ccode\u003egradle assembleHd\u003c/code\u003e命令即可生成hd适配包。\u003c/p\u003e\n\u003ch3 id=\"-\"\u003e控制是否自动更新\u003c/h3\u003e\n\u003cp\u003e美团团购Android客户端在启动时会默认检查客户端是否有更新，如果有更新就会提示用户下载。但是有些渠道和应用市场不允许这种默认行为，所以在适配这些渠道时需要禁止自动更新功能。\u003c/p\u003e\n\u003cp\u003e解决的思路是提供一个配置字段，应用启动的时候检查该字段的值以决定是否开启自动更新功能。使用flavor可以完美的解决这类问题。\u003c/p\u003e\n\u003cp\u003eGradle会在\u003ccode\u003egenerateSources\u003c/code\u003e阶段为flavor生成一个\u003ccode\u003eBuildConfig.java\u003c/code\u003e文件。\u003ccode\u003eBuildConfig\u003c/code\u003e类默认提供了一些常量字段，比如应用的版本名（\u003ccode\u003eVERSION_NAME\u003c/code\u003e），应用的包名（\u003ccode\u003ePACKAGE_NAME\u003c/code\u003e）等。更强大的是，开发者还可以添加自定义的一些字段。下面的示例假设\u003ccode\u003ewandoujia\u003c/code\u003e市场默认禁止自动更新功能：\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eandroid {\n    defaultConfig {\n        buildConfigField \u0026quot;boolean\u0026quot;, \u0026quot;AUTO_UPDATES\u0026quot;, \u0026quot;true\u0026quot;\n    }\n\n    productFlavors {\n        wandoujia {\n            buildConfigField \u0026quot;boolean\u0026quot;, \u0026quot;AUTO_UPDATES\u0026quot;, \u0026quot;false\u0026quot;\n        }        \n    }\n\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上面的代码会在\u003ccode\u003eBuildConfig\u003c/code\u003e类中生成\u003ccode\u003eAUTO_UPDATES\u003c/code\u003e布尔常量，默认值为\u003ccode\u003etrue\u003c/code\u003e，在使用\u003ccode\u003ewandoujia\u003c/code\u003e flavor时，该值会被设置成\u003ccode\u003efalse\u003c/code\u003e。接下来就可以在代码中使用\u003ccode\u003eAUTO_UPDATES\u003c/code\u003e常量来判断是否开启自动更新功能了。最后，运行\u003ccode\u003egradle assembleWandoujia\u003c/code\u003e命令即可生成默认不开启自动升级功能的渠道包，是不是很简单。\u003c/p\u003e\n\u003ch3 id=\"-\"\u003e使用不同的应用名\u003c/h3\u003e\n\u003cp\u003e最常见的一类适配是修改应用的资源。例如，美团团购Android客户端的应用名是\u003ccode\u003e美团\u003c/code\u003e，但有的渠道需要把应用名修改为\u003ccode\u003e美团团购\u003c/code\u003e；还有，客户端经常会和一些应用分发市场合作，需要在应用的启动界面中加上第三方市场的Logo，类似这类适配形式还有很多。\u003cbr\u003e\nGradle在构建应用时，会优先使用flavor所属\u003ccode\u003edataSet\u003c/code\u003e中的同名资源。所以，解决思路就是在flavor的\u003ccode\u003edataSet\u003c/code\u003e中添加同名的字符串资源，以覆盖默认的资源。下面以适配\u003ccode\u003ewandoujia\u003c/code\u003e渠道的应用名为\u003ccode\u003e美团团购\u003c/code\u003e为例进行介绍。\u003c/p\u003e\n\u003cp\u003e首先，在\u003ccode\u003ebuild.gradle\u003c/code\u003e配置文件中添加如下flavor：\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eandroid {\n    productFlavors {\n        wandoujia { \n        }\n    }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上面的配置会默认\u003ccode\u003esrc/wandoujia\u003c/code\u003e目录为\u003ccode\u003ewandoujia\u003c/code\u003e flavor的\u003ccode\u003edataSet\u003c/code\u003e。\u003c/p\u003e","title":"美团Android自动化之旅—适配渠道包"},{"content":"In the passed Google Developer Summit Thailand, Google introduced us an Image Loader Library for Android developed by bumptech named Glide as a library that recommended by Google. It has been used in many Google open source projects till now including Google I/O 2014 official application.\nIt succeeded in making me interested. I spent a whole night playing with it and decided to share my experience in this blog post. As a begining, I must say that it looks 90% similar to Picasso. To be more precise, I think it is something like a Picasso-clone.\nAnyway it is quite different in details. You will learn how.\nImport to project\nBoth Picasso and Glide are on jcenter. You can simply import it to your project with dependency like this:\n**Picasso **\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``compile 'com.squareup.picasso:picasso:2.5.1'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; Glide\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``compile 'com.github.bumptech.glide:glide:3.5.2'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``compile 'com.android.support:support-v4:22.0.0'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; Anyway Glide also needs Android Support Library v4, please don’t forget to import support-v4 to your project like above as well. But it is not kind of a problem since Android Support Library v4 is basically needed in every single new-age Android project.\nBasic\nAs I said, it is very similar to Picasso. The way to load an image to ImageView with Glide is quite the same as Picasso.\nPicasso\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `Picasso.with(context)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``.load(``\u0026quot;http://inthecheesefactory.com/uploads/source/glidepicasso/cover.jpg\u0026quot;``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``.into(ivImg);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; Glide\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `Glide.with(context)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``.load(``\u0026quot;http://inthecheesefactory.com/uploads/source/glidepicasso/cover.jpg\u0026quot;``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``.into(ivImg);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; Although it looks quite the same but in details Glide is designed far better since with doesn’t accept only Context but also Activity and Fragment. Context will be automatically extracted from those things you throw in.\nAnd the brilliant benefit from passing Activity/Fragment to Glide is: image loading would be integrated with Activity/Fragment’s lifecycle for example, pause loading in Paused state and automatically resume on Resumed state. So I encourage you to pass the Activity or Fragment to Glide not just a Context if possible.\nDefault Bitmap Format is RGB_565\nHere is the result of image loading comparing to Picasso. (1920×1080 pixels image is loaded into 768×432 pixels ImageView)\nYou can notice that image loaded by Glide has the worse quality compared to Picasso. Why? This is because Glide default Bitmap Format is set to RGB_565 since it consumed just 50% memory footprint compared to ARGB_8888.\nHere is the memory consumption graphs between Picasso at ARGB8888 and Glide at RGB565. (Base application consumes around 8MB)\nYou don’t have to do anything if you are ok with the image’s quality already. But if think it is unacceptable or just not good enough for you, you can switch Bitmap Format to ARGB_8888 by creating a new class which extended from GlideModule like this:\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `GlideConfiguration ``implements` `GlideModule {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``public` `void` `applyOptions(Context context, GlideBuilder builder) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``// Apply options to the builder here.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``public` `void` `registerComponents(Context context, Glide glide) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``// register ModelLoaders here.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; And then define it as meta-data inside AndroidManifest.xml\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;``meta-data` `android:name``=``\u0026quot;com.inthecheesefactory.lab.glidepicasso.GlideConfiguration\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:value``=``\u0026quot;GlideModule\u0026quot;``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; It looks far better now!\nLet’s take a look at memory consumption graphs once again. It appears that although Glide consumes almost 2 times than previous but Picasso still consumes a lot memory footprint more than Glide.\nThe reason is Picasso loads the full-size image (1920×1080 pixels) into the memory and let GPU does the real-time resizing when drawn. While Glide loads the exact ImageView-size (768×432 pixels) into the memory which is a best practice. Anyway you can change the behavior of Picasso to do the same with resize() command:\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `Picasso.with(``this``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``.load(``\u0026quot;http://nuuneoi.com/uploads/source/playstore/cover.jpg\u0026quot;``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``.resize(``768``, ``432``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``.into(ivImgPicasso);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; But the problem is you need to manually calculate the ImageView’s size. Or if your ImageView has the exact size (not set to wrap_content), you can simply do like this.\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `Picasso.with(``this``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``.load(``\u0026quot;http://nuuneoi.com/uploads/source/playstore/cover.jpg\u0026quot;``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``.fit()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``.centerCrop()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``.into(ivImgPicasso);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; Memory consumption graphs are now finally almost the same !\nAlthough memory consumption are quite the same but I must say that Glide beats Picasso in term of functionality of this part since it could calculate the ImageView size automatically in every single case.\nImage’s quality in details\nHere is the result when I tried to zoom an ImageView to the actual size.\nIt is noticeable that image loaded by Glide has some hard pixels and is not as smooth as the Picasso one. And till now, I still couldn’t find the straight way to change image resizing algorithm.\nBut if you ask me is it bad? I would say that it is not that noticeable in real use. Quality is acceptable but you just need to set Bitmap Format to ARGB_8888, that’s all.\nDisk Caching Default disk caching concept of Picasso and Glide are quite different. From the experiment, the same Full HD image is loaded into ImageView with Picasso and Glide. When I checked the cache folder, it appears that Glide cached the ImageView-size (768×432 pixels) while Picasso cached the full-size one (1920×1080 pixels).\nAnd yes, hard pixels described above is also there. In addition, if image is loaded in RGB565 mode, the cached image will be also in RGB565.\nWhen I tried to adjust ImageView to the different sizes. The result is whatever the size is, Picasso will cache only single size of image, the full-size one. Glide acts differently, caches separate file for each size of ImageView. Although an image has already been loaded once but if you need to load another size the same image, it needs to be downloaded once again before be resized to the right resolution and then be cached.\nTo be more clear, if there is an ImageView in the first page with 200×200 pixels dimension and there is the another one in the second page with 100×100 pixels that are needed to show the same image. You have to download the same image twice.\nAnyway you could adjust its behavior by let Glide cache both the full-size image and the resized onewith this command.\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `Glide.with(``this``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``.load(``\u0026quot;http://nuuneoi.com/uploads/source/playstore/cover.jpg\u0026quot;``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``.diskCacheStrategy(DiskCacheStrategy.ALL)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``.into(ivImgGlide);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; The next time image is requested to show on any ImageView, the full-size image would be loaded from cache, resized and then cached.\nAn advantage of the way Glide was designed is image could be loaded and showed very fast. While the Picasso way causes some delay on loading since it needs to be resized first before is set to an ImageView even you add this command to make it showed immediately.\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `//Picasso` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `.noFade();` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; There is some trade off between Picasso’s and Glide’s way of disk caching. You can choose the way fit your app’s requirement best.\nFor me, I prefer Glide to Picasso since it is far faster although it needs more space to cache the image.\nFeatures You can do almost all the same things just like Picasso can do with the same style of coding for example, Image Resizing\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `// Picasso` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `.resize(``300``, ``200``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `// Glide` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `.override(``300``, ``200``);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; Center Cropping\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `// Picasso` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `.centerCrop();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `// Glide` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `.centerCrop();` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; Transforming\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `// Picasso` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `.transform(``new` `CircleTransform())` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `// Glide` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `.transform(``new` `CircleTransform(context))` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; Setting the Placeholder and **Error **image\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `// Picasso` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `.placeholder(R.drawable.placeholder)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `.error(R.drawable.imagenotfound)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `// Glide` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `.placeholder(R.drawable.placeholder)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `.error(R.drawable.imagenotfound)` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; As I said, if you are familiar with Picasso, moving to Glide would be just like chewing a candy for you. =)\nWhat that Glide has but Picasso doesn’t\nAn ability to load **GIF Animation **to a simple ImageView might be the most interesting feature of Glide. And yes, you can’t do that with Picasso.\nAnd since Glide is designed to work perfectly with Activity/Fragment’s lifecycle so the animation would be automatically paused and resumed along with Activity/Fragment’s state.\nThe way Glide caches is still be the same, resized first and then cached.\nAnyway from an measurement I found that GIF Animation consumes quite a lot of memory. Please use it wisely.\nBesides GIF Animation loading, Glide is also able to decode any local video file to a still image.\nAnother feature that might be useful is you can configure the way image appears with an Animator (R.animator) while Picasso could do only one animation, fading in.\nThe last one if you could generate a thumbnail file of an image you loaded with thumbnail().\nActually there are some other features you can play with but most of them are not that important for general use for example, transcode an image into Byte Array, etc.\nConfigurations\nYou can adjust so many configurations for example, size and location of disk caching, maximum limit of memory caching, Bitmap Format and many more. You can read more about this at Configuration page.\nLibrary’s size\nPicasso (v2.5.1)’s size is around 118KB while Glide (v3.5.2)’s is around 430KB.\nAnyway 312KB difference might not be that significant.\nMethod count of Picasso and Glide are at 840 and 2678 respectively.\nI must say 2678 is quite a lot for 65535 methods limit of Android DEX file. ProGuard is recommended to turn on if you choose Glide. (And you should turn it on anyway for production release).\nConclusion Neither Glide nor Picasso is perfect. The way Glide loads an image to memory and do the caching is better than Picasso which let an image loaded far faster. In addition, it also helps preventing an app from popular OutOfMemoryError. GIF Animation loading is a killing feature provided by Glide. Anyway Picasso decodes an image with better quality than Glide.\nWhich one do I prefer? Although I use Picasso for such a very long time, I must admit that I now prefer Glide. But I would recommend you to change Bitmap Format to ARGB_8888 and let Glide cache both full-size image and resized one first. The rest would do your job great!\nResources There are not so many online resources related to Glide. But here are what I found. Please take a look on links below.\n– Glide 3.0: a media management library for Android\n– Glide Wiki\n– Android Picasso vs Glide\n– Android: Image loading libraries Picasso vs Glide\n转自：http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en\n中文翻译：http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0327/2650.html\n","permalink":"https://blog.zdltech.com/posts/introduction-to-glide-image-loader-library-for-android-recommended-by-google/","summary":"\u003cp\u003eIn the passed Google Developer Summit Thailand, Google introduced us an Image Loader Library for Android developed by bumptech named \u003ca href=\"https://github.com/bumptech/glide\"\u003eGlide\u003c/a\u003e as a library that recommended by Google. It has been used in many Google open source projects till now including Google I/O 2014 official application.\u003c/p\u003e\n\u003cp\u003eIt succeeded in making me interested. I spent a whole night playing with it and decided to share  my experience in this blog post. As a begining, I must say that it looks 90% similar to Picasso. To be more precise, I think it is something like a Picasso-clone.\u003c/p\u003e","title":"Introduction to Glide, Image Loader Library for Android, recommended by Google"},{"content":"英文原文：https://guides.codepath.com/android/Handling-Scrolls-with-CoordinatorLayout\n这篇文章专门讲解和CoordinatorLayout相关的知识点，这也是Design Support Library中最重要与最难的部分。\n概览 CoordinatorLayout 实现了多种Material Design中提到的滚动效果。目前这个框架提供了几种不用写动画代码就能工作的方法，这些效果包括：\n让浮动操作按钮上下滑动，为Snackbar留出空间。 扩展或者缩小Toolbar或者头部，让主内容区域有更多的空间。 控制哪个view应该扩展还是收缩，以及其显示大小比例，包括视差滚动效果动画。 设置 首先确保遵循了Design Support Library的使用说明。\n浮动操作按钮与Snackbar CoordinatorLayout可以用来配合浮动操作按钮的 layout_anchor 和 layout_gravity属性创造出浮动效果，详情请参见浮动操作按钮指南。\n当Snackbar在显示的时候，往往出现在屏幕的底部。为了给Snackbar留出空间，浮动操作按钮需要向上移动。\n只要使用CoordinatorLayout作为基本布局，将自动产生向上移动的动画。浮动操作按钮有一个 默认的 behavior来检测Snackbar的添加并让按钮在Snackbar之上呈现上移与Snackbar等高的动画。\n[?](http://my.oschina.net/kooeasy/blog/484593#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``android.support.design.widget.CoordinatorLayout` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/main_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``xmlns:android``=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``xmlns:app``=``\u0026quot;http://schemas.android.com/apk/res-auto\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;match_parent\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``android.support.v7.widget.RecyclerView` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/rvToDoList\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;match_parent\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``android.support.v7.widget.RecyclerView``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``android.support.design.widget.FloatingActionButton` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``android:layout_gravity``=``\u0026quot;bottom|right\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``android:layout_margin``=``\u0026quot;16dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``android:src``=``\u0026quot;@mipmap/ic_launcher\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``app:layout_anchor``=``\u0026quot;@id/rvToDoList\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``app:layout_anchorGravity``=``\u0026quot;bottom|right|end\u0026quot;``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``android.support.design.widget.CoordinatorLayout``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; Toolbar的扩展与收缩 首先需要确保你不是使用已经过时的ActionBar。务必遵循 使用ToolBar作为actionbar这篇文章的指南。同样，这里也需要CoordinatorLayout作为主布局容器。\n[?](http://my.oschina.net/kooeasy/blog/484593#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;``android.support.design.widget.CoordinatorLayout` `xmlns:android``=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``xmlns:app``=``\u0026quot;http://schemas.android.com/apk/res-auto\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/main_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``android:fitsSystemWindows``=``\u0026quot;true\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``android.support.v7.widget.Toolbar` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/toolbar\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;?attr/actionBarSize\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``app:popupTheme``=``\u0026quot;@style/ThemeOverlay.AppCompat.Light\u0026quot;` `/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; `\u0026amp;lt;/``android.support.design.widget.CoordinatorLayout``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 接下来，我们必须使用一个容器布局： [AppBarLayout](http://developer.android.com/reference/android/support/design/widget/AppBarLayout.html) 来让Toolbar响应滚动事件。响应滚动事件\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_994531\u0026quot; class=\u0026quot;syntaxhighlighter xml\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://my.oschina.net/kooeasy/blog/484593#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;``android.support.design.widget.AppBarLayout` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/appbar\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;@dimen/detail_backdrop_height\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``android:theme``=``\u0026quot;@style/ThemeOverlay.AppCompat.Dark.ActionBar\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``android:fitsSystemWindows``=``\u0026quot;true\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``android.support.v7.widget.Toolbar` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/toolbar\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;?attr/actionBarSize\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``app:popupTheme``=``\u0026quot;@style/ThemeOverlay.AppCompat.Light\u0026quot;` `/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``android.support.design.widget.AppBarLayout``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 然后，我们需要定义AppBarLayout与滚动视图之间的联系。在RecyclerView或者任意支持嵌套滚动的view比如[NestedScrollView](http://stackoverflow.com/questions/25136481/what-are-the-new-nested-scrolling-apis-for-android-l)上添加app:layout_behavior。support library包含了一个特殊的字符串资源@string/appbar_scrolling_view_behavior，它和[AppBarLayout.ScrollingViewBehavior](https://developer.android.com/reference/android/support/design/widget/AppBarLayout.ScrollingViewBehavior.html)相匹配，用来通知AppBarLayout 这个特殊的view何时发生了滚动事件，这个behavior需要设置在触发事件（滚动）的view之上。注意：根据官方的[谷歌文档](http://developer.android.com/reference/android/support/design/widget/AppBarLayout.html)，AppBarLayout目前必须是第一个嵌套在CoordinatorLayout里面的子view。 \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_295670\u0026quot; class=\u0026quot;syntaxhighlighter xml\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://my.oschina.net/kooeasy/blog/484593#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;``android.support.v7.widget.RecyclerView` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/rvToDoList\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``app:layout_behavior``=``\u0026quot;@string/appbar_scrolling_view_behavior\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; AppBarLayout里面定义的view只要设置了app:layout_scrollFlags属性，就可以在RecyclerView滚动事件发生的时候被触发：当CoordinatorLayout发现RecyclerView中定义了这个属性，它会搜索自己所包含的其他view，看看是否有view与这个behavior相关联。AppBarLayout.ScrollingViewBehavior描述了RecyclerView与AppBarLayout之间的依赖关系。RecyclerView的任意滚动事件都将触发AppBarLayout或者AppBarLayout里面view的改变。 \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_195708\u0026quot; class=\u0026quot;syntaxhighlighter xml\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://my.oschina.net/kooeasy/blog/484593#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;``android.support.design.widget.AppBarLayout` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:fitsSystemWindows``=``\u0026quot;true\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``android:theme``=``\u0026quot;@style/ThemeOverlay.AppCompat.Dark.ActionBar\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``android.support.v7.widget.Toolbar` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/toolbar\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;?attr/actionBarSize\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``app:layout_scrollFlags``=``\u0026quot;scroll|enterAlways\u0026quot;``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``android.support.design.widget.AppBarLayout``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; enterAlways: 一旦向上滚动这个view就可见。app:layout_scrollFlags属性里面必须至少启用scroll这个flag，这样这个view才会滚动出屏幕，否则它将一直固定在顶部。可以使用的其他flag有： \u0026lt;/div\u0026gt; - enterAlwaysCollapsed: 顾名思义，这个flag定义的是何时进入（已经消失之后何时再次显示）。假设你定义了一个最小高度（minHeight）同时enterAlways也定义了，那么view将在到达这个最小高度的时候开始显示，并且从这个时候开始慢慢展开，当滚动到顶部的时候展开完。 - exitUntilCollapsed: 同样顾名思义，这个flag时定义何时退出，当你定义了一个minHeight，这个view将在滚动到达这个最小高度的时候消失。 记住，要把带有scroll flag的view放在前面，这样收回的view才能让正常退出，而固定的view继续留在顶部。 此时，你应该注意到我们的Toolbar能够响应滚动事件了。 [![CoordinatorLayout与滚动的处理](http://static.oschina.net/uploads/img/201507/28112431_mOxz.gif)](http://static.oschina.net/uploads/img/201507/28112431_mOxz.gif) \u0026lt;a rel=\u0026quot;nofollow\u0026quot;\u0026gt;回到顶部\u0026lt;/a\u0026gt; ### 制造折叠效果 如果想制造toolbar的折叠效果，我们必须把Toolbar放在CollapsingToolbarLayout中： \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_443633\u0026quot; class=\u0026quot;syntaxhighlighter xml\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://my.oschina.net/kooeasy/blog/484593#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;``android.support.design.widget.CollapsingToolbarLayout` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/collapsing_toolbar\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``android:fitsSystemWindows``=``\u0026quot;true\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``app:contentScrim``=``\u0026quot;?attr/colorPrimary\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``app:expandedTitleMarginEnd``=``\u0026quot;64dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``app:expandedTitleMarginStart``=``\u0026quot;48dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``app:layout_scrollFlags``=``\u0026quot;scroll|exitUntilCollapsed\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``android.support.v7.widget.Toolbar` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/toolbar\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;?attr/actionBarSize\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``app:layout_scrollFlags``=``\u0026quot;scroll|enterAlways\u0026quot;``\u0026amp;gt;\u0026amp;lt;/``android.support.v7.widget.Toolbar``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``android.support.design.widget.CollapsingToolbarLayout``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; [![CoordinatorLayout与滚动的处理](http://static.oschina.net/uploads/img/201507/28112431_oNXC.gif)](http://static.oschina.net/uploads/img/201507/28112431_oNXC.gif) 现在效果就成了： \u0026lt;/div\u0026gt; 通常，我们我们都是设置Toolbar的title，而现在，我们需要把title设置在CollapsingToolBarLayout上，而不是Toolbar。 \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_500348\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://my.oschina.net/kooeasy/blog/484593#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `CollapsingToolbarLayout collapsingToolbar =(CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `collapsingToolbar.setTitle(``\u0026quot;Title\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;a rel=\u0026quot;nofollow\u0026quot;\u0026gt;制造视差效果\u0026lt;/a\u0026gt; \u0026lt;a rel=\u0026quot;nofollow\u0026quot;\u0026gt;回到顶部\u0026lt;/a\u0026gt; CollapsingToolbarLayout还能让我们做出更高级的动画，比如在里面放一个ImageView，然后在它折叠的时候渐渐淡出。同时在用户滚动的时候title的高度也会随着改变。 [![CoordinatorLayout与滚动的处理](http://static.oschina.net/uploads/img/201507/28112432_qzXu.gif)](http://static.oschina.net/uploads/img/201507/28112432_qzXu.gif) 为了制造出这种效果，我们添加一个定义了app:layout_collapseMode=\u0026amp;#8221;parallax\u0026amp;#8221; 属性的ImageView。 ## \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_174592\u0026quot; class=\u0026quot;syntaxhighlighter xml\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://my.oschina.net/kooeasy/blog/484593#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``android.support.design.widget.CollapsingToolbarLayout` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/collapsing_toolbar\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``android:fitsSystemWindows``=``\u0026quot;true\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``app:contentScrim``=``\u0026quot;?attr/colorPrimary\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``app:expandedTitleMarginEnd``=``\u0026quot;64dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``app:expandedTitleMarginStart``=``\u0026quot;48dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``app:layout_scrollFlags``=``\u0026quot;scroll|exitUntilCollapsed\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``android.support.v7.widget.Toolbar` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/toolbar\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;?attr/actionBarSize\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``app:layout_scrollFlags``=``\u0026quot;scroll|enterAlways\u0026quot;``\u0026amp;gt;\u0026amp;lt;/``android.support.v7.widget.Toolbar``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``ImageView` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``android:src``=``\u0026quot;@drawable/cheese_1\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``app:layout_scrollFlags``=``\u0026quot;scroll|enterAlways|enterAlwaysCollapsed\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``android:scaleType``=``\u0026quot;centerCrop\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``app:layout_collapseMode``=``\u0026quot;parallax\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``android:minHeight``=``\u0026quot;100dp\u0026quot;``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``android.support.design.widget.CollapsingToolbarLayout``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ## 在[CoordinatorLayout 与浮动操作按钮](http://guides.codepath.com/android/Floating-Action-Buttons#using-coordinatorlayout)中我们讨论了一个自定义behavior的例子。注： 译文[http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0718/3197.html](http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0718/3197.html) 。 ## 自定义Behavior CoordinatorLayout的工作原理是搜索定义了[CoordinatorLayout Behavior](http://developer.android.com/reference/android/support/design/widget/CoordinatorLayout.Behavior.html) 的子view，不管是通过在xml中使用app:layout_behavior标签还是通过在代码中对view类使用@DefaultBehavior修饰符来添加注解。当滚动发生的时候，CoordinatorLayout会尝试触发那些声明了依赖的子view。 要自己定义CoordinatorLayout Behavior，你需要实现layoutDependsOn() 和onDependentViewChanged()两个方法。比如AppBarLayout.Behavior 就定义了这两个关键方法。这个behavior用于当滚动发生的时候让AppBarLayout发生改变。 \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_14552\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://my.oschina.net/kooeasy/blog/484593#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `boolean` `layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``return` `dependency ``instanceof` `AppBarLayout;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `public` `boolean` `onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``// check the behavior triggered` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``android.support.design.widget.CoordinatorLayout.Behavior behavior = ((android.support.design.widget.CoordinatorLayout.LayoutParams) dependency.getLayoutParams()).getBehavior();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``if` `(behavior ``instanceof` `AppBarLayout.Behavior) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``// do stuff here` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 理解如何实现这些自定义behavior的最好途径是研究AppBarLayout.Behavior 和 FloatingActionButtion.Behavior。虽然这些源代码还没有放出来，但是你可以使用Android Studio 1.2集成的反编译器来查看。 参考：[Android的材料设计兼容库（Design Support Library）](http://www.jcodecraeer.com/a/anzhuokaifa/developer/2015/0531/2958.html) ","permalink":"https://blog.zdltech.com/posts/android5-0coordinatorlayout/","summary":"\u003cp\u003e英文原文：\u003ca href=\"https://guides.codepath.com/android/Handling-Scrolls-with-CoordinatorLayout\"\u003ehttps://guides.codepath.com/android/Handling-Scrolls-with-CoordinatorLayout\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这篇文章专门讲解和CoordinatorLayout相关的知识点，这也是Design Support Library中最重要与最难的部分。\u003c/p\u003e\n\u003ch2 id=\"概览\"\u003e概览\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout.html\"\u003eCoordinatorLayout\u003c/a\u003e 实现了多种Material Design中提到的\u003ca href=\"http://www.google.com/design/spec/patterns/scrolling-techniques.html\"\u003e滚动效果\u003c/a\u003e。目前这个框架提供了几种不用写动画代码就能工作的方法，这些效果包括：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e让浮动操作按钮上下滑动，为Snackbar留出空间。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201507/28112430_EWt9.gif\"\u003e\u003cimg alt=\"CoordinatorLayout与滚动的处理\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201507/28112430_EWt9.gif\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e扩展或者缩小Toolbar或者头部，让主内容区域有更多的空间。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201507/28112430_6C1A.gif\"\u003e\u003cimg alt=\"CoordinatorLayout与滚动的处理\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201507/28112430_6C1A.gif\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e控制哪个view应该扩展还是收缩，以及其显示大小比例，包括\u003ca href=\"https://ihatetomatoes.net/demos/parallax-scroll-effect/\"\u003e视差滚动效果\u003c/a\u003e动画。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201507/28112430_0o21.gif\"\u003e\u003cimg alt=\"CoordinatorLayout与滚动的处理\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201507/28112430_0o21.gif\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"设置\"\u003e设置\u003c/h2\u003e\n\u003cp\u003e首先确保遵循了\u003ca href=\"https://guides.codepath.com/android/Design-Support-Library\"\u003eDesign Support Library\u003c/a\u003e的使用说明。\u003c/p\u003e\n\u003ch2 id=\"浮动操作按钮与snackbar\"\u003e浮动操作按钮与Snackbar\u003c/h2\u003e\n\u003cp\u003eCoordinatorLayout可以用来配合浮动操作按钮的 layout_anchor 和 layout_gravity属性创造出浮动效果，详情请参见\u003ca href=\"https://guides.codepath.com/android/Floating-Action-Buttons\"\u003e浮动操作按钮\u003c/a\u003e指南。\u003c/p\u003e\n\u003cp\u003e当\u003ca href=\"https://guides.codepath.com/android/Displaying-the-Snackbar\"\u003eSnackbar\u003c/a\u003e在显示的时候，往往出现在屏幕的底部。为了给Snackbar留出空间，浮动操作按钮需要向上移动。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201507/28112431_bPf3.gif\"\u003e\u003cimg alt=\"CoordinatorLayout与滚动的处理\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201507/28112431_bPf3.gif\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e只要使用CoordinatorLayout作为基本布局，将自动产生向上移动的动画。浮动操作按钮有一个 \u003ca href=\"https://developer.android.com/reference/android/support/design/widget/FloatingActionButton.Behavior.html\"\u003e默认的 behavior\u003c/a\u003e来检测Snackbar的添加并让按钮在Snackbar之上呈现上移与Snackbar等高的动画。\u003c/p\u003e\n\u003cdiv class=\"line number1 index0 alt2\"\u003e\n  \u003cdiv\u003e\n    \u003cdiv id=\"highlighter_629240\" class=\"syntaxhighlighter  xml\"\u003e\n      \u003cdiv class=\"toolbar\"\u003e\n        [?](http://my.oschina.net/kooeasy/blog/484593#)\n      \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          1\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          2\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          3\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          4\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          5\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n          6\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n          7\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n          8\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n          9\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n          10\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n          11\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n          12\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n          13\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n          14\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n          15\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n          16\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n          17\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n          18\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n          19\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n          20\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n          21\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n          22\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n          \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n            ` ``\u0026amp;lt;``android.support.design.widget.CoordinatorLayout`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n            `        ``android:id``=``\u0026quot;@+id/main_content\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n            `        ``xmlns:android``=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n            `        ``xmlns:app``=``\u0026quot;http://schemas.android.com/apk/res-auto\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n            `        ``android:layout_width``=``\u0026quot;match_parent\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n            `        ``android:layout_height``=``\u0026quot;match_parent\u0026quot;``\u0026amp;gt;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n            ` `\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n            `   ``\u0026amp;lt;``android.support.v7.widget.RecyclerView`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n            `         ``android:id``=``\u0026quot;@+id/rvToDoList\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n            `         ``android:layout_width``=``\u0026quot;match_parent\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n            `         ``android:layout_height``=``\u0026quot;match_parent\u0026quot;``\u0026amp;gt;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n            `   ``\u0026amp;lt;/``android.support.v7.widget.RecyclerView``\u0026amp;gt;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n            ` `\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n            `   ``\u0026amp;lt;``android.support.design.widget.FloatingActionButton`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n            `        ``android:layout_width``=``\u0026quot;wrap_content\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n            `        ``android:layout_height``=``\u0026quot;wrap_content\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n            `        ``android:layout_gravity``=``\u0026quot;bottom|right\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n            `        ``android:layout_margin``=``\u0026quot;16dp\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n            `        ``android:src``=``\u0026quot;@mipmap/ic_launcher\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n            `        ``app:layout_anchor``=``\u0026quot;@id/rvToDoList\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n            `        ``app:layout_anchorGravity``=``\u0026quot;bottom|right|end\u0026quot;``/\u0026amp;gt;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n            ` ``\u0026amp;lt;/``android.support.design.widget.CoordinatorLayout``\u0026amp;gt;`\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003ch2 id=\"coordinatorlayout与滚动的处理\"\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201507/28112431_hMNx.gif\"\u003e\u003cimg alt=\"CoordinatorLayout与滚动的处理\" loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201507/28112431_hMNx.gif\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003ch2 id=\"toolbar的扩展与收缩\"\u003eToolbar的扩展与收缩\u003c/h2\u003e\n\u003cp\u003e首先需要确保你不是使用已经过时的ActionBar。务必遵循 \u003ca href=\"http://guides.codepath.com/android/Defining-The-ActionBar#using-toolbar-as-actionbar\"\u003e使用ToolBar作为actionbar\u003c/a\u003e这篇文章的指南。同样，这里也需要CoordinatorLayout作为主布局容器。\u003c/p\u003e","title":"Android5.0+(CoordinatorLayout)"},{"content":"在android中的加载网络图片是一件十分令人头疼的事情，在网上有着许多关于加载网络图片的开源库，可以让我们十分方便的加载网络图片。在这里我主要介绍一下我自己在使用Volley, Picasso, Universal-Imageloader的一些使用的感悟。以及最基本的用法介绍。\n1.android-Volley\n给ImageView设置图片源\n- \u0026gt; // imageView是一个ImageView实例 - \u0026gt; // ImageLoader.getImageListener的第二个参数是默认的图片resource id - \u0026gt; // 第三个参数是请求失败时候的资源id，可以指定为0 - \u0026gt; ImageListener listener = ImageLoader.getImageListener(imageView, android.R.drawable.ic_menu_rotate, android.R.drawable.ic_delete); - \u0026gt; mImageLoader.get(url, listener); 复制代码 使用NetworkImageView Volley提供了一个新的控件NetworkImageView来代替传统的ImageView，这个控件的图片属性可以通过\n- \u0026gt; mImageView.setImageUrl(url, imageLoader) 复制代码 来设定。而且，这个控件在被从父控件detach的时候，会自动取消网络请求的，即完全不用我们担心相关网络请求的生命周期问题。\n- \u0026gt; mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache()); - \u0026gt; \u0026amp;#8230;. \u0026amp;#8230; - \u0026gt; - \u0026gt; if(holder.imageRequest != null) { - \u0026gt; holder.imageRequest.cancel(); - \u0026gt; } - \u0026gt; holder.imageRequest = mImageLoader.get(BASE_UR + item.image_url, holder.imageView, R.drawable.loading, R.drawable.error); - \u0026gt; 复制代码 总结：如果你的工程项目，是一个比较小的项目，或者要求不是很高的项目，处理比较简单的可以使用这个库，这个库是Google 2013 I/O 发布的一个开源库。使用这个库在图片的处理上，没有提供任何的图片处理的操作，个人感觉这个库主要在网络数据连接上比较好，在图片处理上还是不够完善，强大。\n2.Picasso\nPicasso加载网络图片的使用很简单，只需要一行代码就可以搞定。\n- \u0026gt; Picasso.with(context) .load(url).resize(50, 50).centerCrop().into(imageView) - \u0026gt; 复制代码 Picasso有如下特性：\n处理Adapter中的 ImageView 回收和取消已经回收ImageView的下载进程 使用最少的内存完成复杂的图片转换，比如把下载的图片转换为圆角等 自动添加磁盘和内存缓存 总结：如果你的项目里面，对于图片有一些具体的要求的话，建议使用这个库，但是这个库当你需要对图片作一些具体的操作比如加载圆角矩形图片、裁剪图片为圆形时，需要你自己写一些操作，如果基础不够好的会感觉很困难。还有就是这个库我们只能看到结果，无法关心图片的下载过程。\n3.Universal-ImageLoader\n先要配置ImageLoaderConfiguration这个类实现全局ImageLoader的实现情况。可以选择在Application中初始化设置该类。 使用ImageLoader进行图片加载的时候，先要实例化ImageLoader 总结：这个库有着对加载网络图片的吵详细配置。可以根据个人的喜欢，进行一些配置等等。并且可以实现图片下载过程的监听。且可以支持图片下载完成后，显示圆形或者圆角矩形的图片。\n4.Fresco # \u003e 关于 Fresco Facebook最近推出了一款用于Android应用中展示图片的强大图片库Fresco，它能够从网络、本地存储和本地资源中加载图片。而且，为了节省数据和CPU，它拥有三级缓存。 Fresco 是一个强大的图片加载组件。 Fresco 中设计有一个叫做 image pipeline 的模块。它负责从网络，从本地文件系统，本地资源加载图片。为了最大限度节省空间和CPU时间，它含有3级缓存设计（2级内存，1级文件）。 Fresco 中设计有一个叫做 Drawees 模块，方便地显示loading图，当图片不再显示在屏幕上时，及时地释放内存和空间占用。 Fresco 支持 Android2.3(API level 9) 及其以上系统。 \u0026gt; 特性 \u0026gt; 内存管理 解压后的图片，即Android中的`Bitmap`，占用大量的内存。大的内存占用势必引发更加频繁的GC。在5.0以下，GC将会显著地引发界面卡顿。 在5.0以下系统，Fresco将图片放到一个特别的内存区域。当然，在图片不显示的时候，占用的内存会自动被释放。这会使得APP更加流畅，减少因图片内存占用而引发的OOM。 Fresco 在低端机器上表现一样出色，你再也不用因图片内存占用而思前想后。 \u0026gt; 图片的渐进式呈现 渐进式的JPEG图片格式已经流行数年了，渐进式图片格式先呈现大致的图片轮廓，然后随着图片下载的继续，呈现逐渐清晰的图片，这对于移动设备，尤其是慢网络有极大的利好，可带来更好的用户体验。 Android 本身的图片库不支持此格式，但是Fresco支持。使用时，和往常一样，仅仅需要提供一个图片的URI即可，剩下的事情，Fresco会处理。 \u0026gt; Gif图和WebP格式 是的，支持加载Gif图，支持WebP格式。 \u0026gt; 图像的呈现 Fresco 的 Drawees 设计，带来一些有用的特性： - \u0026gt; 自定义居中焦点(对人脸等图片显示非常有帮助) - \u0026gt; 圆角图，当然圆圈也行。 - \u0026gt; 下载失败之后，点击重现下载 - \u0026gt; 自定义占位图，自定义overlay, 或者进度条 - \u0026gt; 指定用户按压时的overlay \u0026gt; 图像的加载 Fresco 的 image pipeline 设计，允许用户在多方面控制图片的加载： - \u0026gt; 为同一个图片指定不同的远程路径，或者使用已经存在本地缓存中的图片 - \u0026gt; 先显示一个低解析度的图片，等高清图下载完之后再显示高清图 - \u0026gt; 加载完成回调通知 - \u0026gt; 对于本地图，如有EXIF缩略图，在大图加载完成之前，可先显示缩略图 - \u0026gt; 缩放或者旋转图片 - \u0026gt; 处理已下载的图片 - \u0026gt; WebP 支持 \u0026gt; PS:还有一个glide的框架 [Glide](https://github.com/bumptech/glide) 是一个高效、开源、 Android设备上的媒体管理框架，它遵循BSD、MIT以及Apache 2.0协议发布。Glide具有获取、解码和展示视频剧照、图片、动画等功能，它还有灵活的API，这些API使开发者能够将Glide应用在几乎任何网络协议栈里。创建Glide的主要目的有两个，一个是实现平滑的图片列表滚动效果，另一个是支持远程图片的获取、大小调整和展示。近日，Glide 3.0发布，现已提供 [jar包下载](https://github.com/bumptech/glide/releases) ，同时还支持使用Gradle以及Maven进行构建。该版本包括很多值得关注的新功能，如支持Gif 动画和视频剧照解码、智能的暂停和重新开始请求、支持缩略图等，具体新增功能如下如下： - \u0026gt; **GIF 动画的解码** ：通过调用Glide.with(context).load(“图片路径“)方法，GIF动画图片可以自动显示为动画效果。如果想有更多的控制，还可以使用Glide.with(context).load(“图片路径“).asBitmap()方法加载静态图片，使用Glide.with(context).load(“图片路径“).asGif()方法加载动画图片 - \u0026gt; **本地视频剧照的解码：** 通过调用Glide.with(context).load(“图片路径“)方法，Glide能够支持Android设备中的所有视频剧照的加载和展示 - \u0026gt; **缩略图的支持：** 为了减少在同一个view组件里同时加载多张图片的时间，可以调用Glide.with(context).load(“图片路径“).thumbnail(“缩略比例“).into(“view组件“)方法加载一个缩略图，还可以控制thumbnail()中的参数的大小，以控制显示不同比例大小的缩略图 - \u0026gt; **Activity 生命周期的集成：** 当Activity暂停和重启时，Glide能够做到智能的暂停和重新开始请求，并且当Android设备的连接状态变化时，所有失败的请求能够自动重新请求 - \u0026gt; **转码的支持：** Glide的toBytes() 和transcode() 两个方法可以用来获取、解码和变换背景图片，并且transcode() 方法还能够改变图片的样式 - \u0026gt; **动画的支持：** 新增支持图片的淡入淡出动画效果（调用crossFade()方法）和查看动画的属性的功能 - \u0026gt; **OkHttp 和Volley 的支持：** 默认选择HttpUrlConnection作为网络协议栈，还可以选择OkHttp和Volley作为网络协议栈 - \u0026gt; **其他功能：** 如在图片加载过程中，使用Drawables对象作为占位符、图片请求的优化、图片的宽度和高度可重新设定、缩略图和原图的缓存等功能 另外，请大家注意，除了以上新引入的功能外，还具有Glide 2.x系列版本的所有功能，如背景图片的加载、内存和磁盘间的高效缓存、使用位图和资源池提高加载性能， 更多Glide3.0相关信息请登陆GitHub上的 [Wiki页面](https://github.com/bumptech/glide/wiki) 查看。 2015年10月14日16:26:20 引用网友 [倾城_之泪](http://www.jianshu.com/users/36b23cb5edb5)的理解： **Universal Image Loader**：一个强大的图片加载库，包含各种各样的配置，最老牌，使用也最广泛。 **Picasso**: Square出品，必属精品。和OkHttp搭配起来更配呦！ **Volley ImageLoader**：Google官方出品，可惜不能加载本地图片~ **Fresco**：Facebook出的，天生骄傲！不是一般的强大。 **Glide**：Google推荐的图片加载库，专注于流畅的滚动。 还有就是转载下泡在网上的日子文章总结： \u0026gt; 总结 \u003e \u003e \u003e Glide和Picasso都是非常完美的库。Glide加载图像以及磁盘缓存的方式都要优于Picasso，速度更快，并且Glide更有利于减少OutOfMemoryError的发生，GIF动画是Glide的杀手锏。不过Picasso的图片质量更高。你更喜欢哪个呢？ 虽然我使用了很长时间的Picasso，但是我得承认现在我更喜欢Glide。我的建议是使用Glide，但是将Bitmap格式换成 ARGB_8888、让Glide缓存同时缓存全尺寸和改变尺寸两种。 比较：http://stackoverflow.com/questions/29363321/picasso-v-s-imageloader-v-s-fresco-vs-glide\n","permalink":"https://blog.zdltech.com/posts/universal-image-loaderandroid-volleypicassofresco%E5%92%8Cglide%E4%BA%94%E5%A4%A7android%E5%BC%80%E6%BA%90%E7%BB%84%E4%BB%B6%E5%8A%A0%E8%BD%BD%E7%BD%91%E7%BB%9C%E5%9B%BE/","summary":"\u003cp\u003e在android中的加载网络图片是一件十分令人头疼的事情，在网上有着许多关于加载网络图片的开源库，可以让我们十分方便的加载网络图片。在这里我主要介绍一下我自己在使用Volley, Picasso, Universal-Imageloader的一些使用的感悟。以及最基本的用法介绍。\u003cbr\u003e\n1.android-Volley\u003c/p\u003e\n\u003cp\u003e给ImageView设置图片源\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cdiv class=\"blockcode\"\u003e\n  \u003cdiv id=\"code_e3V\"\u003e\n\u003cpre\u003e\u003ccode\u003e  - \u0026gt;         // imageView是一个ImageView实例\n  \n  - \u0026gt;         // ImageLoader.getImageListener的第二个参数是默认的图片resource id\n  \n  - \u0026gt;         // 第三个参数是请求失败时候的资源id，可以指定为0\n  \n  - \u0026gt;         ImageListener listener = ImageLoader.getImageListener(imageView, android.R.drawable.ic_menu_rotate, android.R.drawable.ic_delete);\n  \n  - \u0026gt;         mImageLoader.get(url, listener);\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003e复制代码\n\u003c/code\u003e\u003c/pre\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e使用NetworkImageView\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eVolley提供了一个新的控件NetworkImageView来代替传统的ImageView，这个控件的图片属性可以通过\u003c/p\u003e\n\u003cdiv class=\"blockcode\"\u003e\n  \u003cdiv id=\"code_r59\"\u003e\n\u003cpre\u003e\u003ccode\u003e  - \u0026gt;         mImageView.setImageUrl(url, imageLoader)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003e复制代码\n\u003c/code\u003e\u003c/pre\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/div\u003e\n\u003cp\u003e来设定。而且，这个控件在被从父控件detach的时候，会自动取消网络请求的，即完全不用我们担心相关网络请求的生命周期问题。\u003c/p\u003e\n\u003cdiv class=\"blockcode\"\u003e\n  \u003cdiv id=\"code_q11\"\u003e\n\u003cpre\u003e\u003ccode\u003e  - \u0026gt;         mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache());\n  \n  - \u0026gt;         \u0026amp;#8230;. \u0026amp;#8230;\n  \n  - \u0026gt;\n  \n  - \u0026gt;         if(holder.imageRequest != null) {\n  \n  - \u0026gt;            holder.imageRequest.cancel();\n  \n  - \u0026gt;         }\n  \n  - \u0026gt;         holder.imageRequest = mImageLoader.get(BASE_UR + item.image_url, holder.imageView, R.drawable.loading, R.drawable.error);\n  \n  - \u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cpre\u003e\u003ccode\u003e复制代码\n\u003c/code\u003e\u003c/pre\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/div\u003e\n\u003cp\u003e总结：如果你的工程项目，是一个比较小的项目，或者要求不是很高的项目，处理比较简单的可以使用这个库，这个库是Google 2013 I/O 发布的一个开源库。使用这个库在图片的处理上，没有提供任何的图片处理的操作，个人感觉这个库主要在网络数据连接上比较好，在图片处理上还是不够完善，强大。\u003c/p\u003e","title":"Universal-Image-Loader，android-Volley，Picasso、Fresco和Glide五大Android开源组件加载网络图片的优缺点比较"},{"content":"Android Volley 是Google开发的一个网络lib，可以让你更加简单并且快速的访问网络数据。Volley库的网络请求都是异步的，你不必担心异步处理问题。\nVolley的优点：\n请求队列和请求优先级 请求Cache和内存管理 扩展性性强 可以取消请求 ##下载和编译volley.jar\n需要安装git，ant，android sdk clone代码：\ngit clone https://android.googlesource.com/platform/frameworks/volley\n编译jar：\nandroid update project -p . ant jar\n添加volley.jar到你的项目中 不过已经有人将volley的代码放到github上了：\nhttps://github.com/mcxiaoke/android-volley，你可以使用更加简单的方式来使用volley：\n###Maven\nformat: jar\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;dependency\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;groupId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;com.mcxiaoke.volley\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;groupId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;artifactId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;library\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;artifactId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;1.0.6\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;dependency\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; ###Gradle\nformat: jar\ncompile 'com.mcxiaoke.volley:library:1.0.6'\n##Volley工作原理图\n{.fancybox}\n##创建Volley 单例\n使用volley时，必须要创建一个请求队列RequestQueue，使用请求队列的最佳方式就是将它做成一个单例，整个app使用这么一个请求队列。\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;AppController\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;Application\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = AppController.class .getSimpleName(); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; RequestQueue mRequestQueue; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageLoader mImageLoader; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; AppController mInstance; \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onCreate\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(); mInstance = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; AppController \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getInstance\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mInstance; } \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; RequestQueue \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getRequestQueue\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mRequestQueue == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { mRequestQueue = Volley.newRequestQueue(getApplicationContext()); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mRequestQueue; } \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ImageLoader \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getImageLoader\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ getRequestQueue(); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mImageLoader == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { mImageLoader = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageLoader(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mRequestQueue, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LruBitmapCache()); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mImageLoader; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;T\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;addToRequestQueue\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Request\u0026lt;T\u0026gt; req, String tag)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// set the default tag if tag is empty\u0026lt;/span\u0026gt; req.setTag(TextUtils.isEmpty(tag) ? TAG : tag); getRequestQueue().add(req); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;T\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;addToRequestQueue\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Request\u0026lt;T\u0026gt; req)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ req.setTag(TAG); getRequestQueue().add(req); } \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;cancelPendingRequests\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Object tag)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mRequestQueue != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { mRequestQueue.cancelAll(tag); } } } 另外，你还需要一个Cache来存放请求的图片：\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;LruBitmapCache\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;LruCache\u0026lt;/span\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;Bitmap\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;implement\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;ImageCache\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getDefaultLruCacheSize\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; maxMemory = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (Runtime.getRuntime().maxMemory() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1024\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cacheSize = maxMemory / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; cacheSize; } \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;LruBitmapCache\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(getDefaultLruCacheSize()); } \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;LruBitmapCache\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; sizeInKiloBytes)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(sizeInKiloBytes); } \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;sizeOf\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(String key, Bitmap value)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; value.getRowBytes() * value.getHeight() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1024\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;Bitmap \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getBitmap\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(String url)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;get\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(url)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;putBitmap\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(String url, Bitmap bitmap)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ put(url, bitmap); } } 别忘记在AndroidManifest.xml文件中添加android.permission.INTERNET权限。\n##创建Json请求\nvolley自带了JsonObjectRequest和JsonArrayRequest分别来处理Json对象请求和Json数据请求（但是voley没有使用gson库写一个GsonRequest，发送一个request，volley直接返回一个java对象，不过我们可以自己写）。\n###创建json object请求\n发送一个请求只要这么简单，创建一个JsonRequest对象，写好response回调接口，并把这个请求放到请求队列中就可以了。JsonArrayRequest也类似。\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Tag used to cancel the request\u0026lt;/span\u0026gt; String tag_json_obj = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;json_obj_req\u0026quot;\u0026lt;/span\u0026gt;; String url = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;http://api.androidhive.info/volley/person_object.json\u0026quot;\u0026lt;/span\u0026gt;; JsonObjectRequest jsonObjReq = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; JsonObjectRequest(Method.GET,url, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.Listener\u0026lt;JSONObject\u0026gt;() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onResponse\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(JSONObject response)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ Log.d(TAG, response.toString()); } }, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.ErrorListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onErrorResponse\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(VolleyError \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;error\u0026lt;/span\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ VolleyLog.d(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Error: \u0026quot;\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;error\u0026lt;/span\u0026gt;.getMessage()); } }); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Adding request to request queue\u0026lt;/span\u0026gt; AppController.getInstance().addToRequestQueue(jsonObjReq, tag_json_obj); 创建String请求 StringRequest可以用来请求任何string类型的数据：json，xml，文本等等。\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Tag used to cancel the request\u0026lt;/span\u0026gt; String tag_string_req = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;string_req\u0026quot;\u0026lt;/span\u0026gt;; String url = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;http://api.androidhive.info/volley/string_response.html\u0026quot;\u0026lt;/span\u0026gt;; ProgressDialog pDialog = new ProgressDialog\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(this)\u0026lt;/span\u0026gt;; pDialog.setMessage\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Loading...\u0026quot;\u0026lt;/span\u0026gt;)\u0026lt;/span\u0026gt;; pDialog.show\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;; StringRequest strReq = new StringRequest\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Method.GET, url, new Response.Listener\u0026lt;String\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; { @Override public void onResponse\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(String response)\u0026lt;/span\u0026gt; { Log.d\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(TAG, response.toString\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;)\u0026lt;/span\u0026gt;; pDialog.hide\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;; } }, new Response.ErrorListener\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; { @Override public void onErrorResponse\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(VolleyError error)\u0026lt;/span\u0026gt; { VolleyLog.d\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Error: \u0026quot;\u0026lt;/span\u0026gt; + error.getMessage\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;)\u0026lt;/span\u0026gt;; pDialog.hide\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;; } })\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Adding request to request queue\u0026lt;/span\u0026gt; AppController.getInstance\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;.addToRequestQueue\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(strReq, tag_string_req)\u0026lt;/span\u0026gt;; 创建POST请求 上面说的都是GET请求，下面来说一下POST请求，与GET请求不同的是，只要在创建请求的时候将请求类型改为POST请求，并且override Request的getParams方法即可。\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Tag used to cancel the request\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt; tag_json_obj = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;json_obj_req\u0026quot;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt; url = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;http://api.androidhive.info/volley/person_object.json\u0026quot;\u0026lt;/span\u0026gt;; ProgressDialog pDialog = \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ProgressDialog(this); pDialog\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;setMessage(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Loading...\u0026quot;\u0026lt;/span\u0026gt;); pDialog\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;show(); JsonObjectRequest jsonObjReq = \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; JsonObjectRequest(Method\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;POST, url, \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;Listener\u0026lt;JSONObject\u0026gt;() { @Override \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onResponse(JSONObject response) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;Log\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;d(\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;TAG\u0026lt;/span\u0026gt;, response\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;toString()); pDialog\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;hide(); } }, \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;ErrorListener() { @Override \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onErrorResponse(VolleyErr\u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;or\u0026lt;/span\u0026gt; err\u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;or\u0026lt;/span\u0026gt;) { VolleyLog\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;d(\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;TAG\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Error: \u0026quot;\u0026lt;/span\u0026gt; + err\u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;or\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMessage()); pDialog\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;hide(); } }) { @Override \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;Map\u0026lt;/span\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026gt; getParams() { \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;Map\u0026lt;/span\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;params\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026gt;(); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;params\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;name\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Androidhive\u0026quot;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;params\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;email\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;abc@androidhive.info\u0026quot;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;params\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;password\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;password123\u0026quot;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;params\u0026lt;/span\u0026gt;; } }; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Adding request to request queue\u0026lt;/span\u0026gt; AppController\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getInstance()\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;addToRequestQueue(jsonObjReq, tag_json_obj); ##添加请求头部信息\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Tag used to cancel the request\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt; tag_json_obj = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;json_obj_req\u0026quot;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt; url = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;http://api.androidhive.info/volley/person_object.json\u0026quot;\u0026lt;/span\u0026gt;; ProgressDialog pDialog = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ProgressDialog(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); pDialog.setMessage(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Loading...\u0026quot;\u0026lt;/span\u0026gt;); pDialog.show(); JsonObjectRequest jsonObjReq = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; JsonObjectRequest(Method.POST,url, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.Listener\u0026lt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;JSONObject\u0026lt;/span\u0026gt;\u0026gt;() { @Override \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onResponse(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;JSONObject\u0026lt;/span\u0026gt; response) { Log.d(TAG, response.toString()); pDialog.hide(); } }, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.ErrorListener() { @Override \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onErrorResponse(VolleyError error) { VolleyLog.d(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Error: \u0026quot;\u0026lt;/span\u0026gt; + error.getMessage()); pDialog.hide(); } }) { \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** * Passing some request headers * */\u0026lt;/span\u0026gt; @Override \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Map\u0026lt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026gt; getHeaders() \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; AuthFailureError { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;HashMap\u0026lt;/span\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026gt; headers = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;HashMap\u0026lt;/span\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026gt;(); headers.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Content-Type\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;application/json\u0026quot;\u0026lt;/span\u0026gt;); headers.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;apiKey\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;xxxxxxxxxxxxxxx\u0026quot;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; headers; } }; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Adding request to request queue\u0026lt;/span\u0026gt; AppController.getInstance().addToRequestQueue(jsonObjReq, tag_json_obj); ##创建Image请求\nVolley库中自带了NetworkImageView类，这个ImageView可以自动使用volley下载图片\n###用NetworkImageView加载图片\n首先，说明一下，加载图片的原理：\nNetworkImageView加载图片需要一个ImageLoader和一个图片URL，这个ImageLoader对象需要一个请求队列对象和ImageCahe对象。调用NetworkImageView的setUrl方法后，首先会判断当前ImageView的URL和新传入的URL是否一致，如果相同，就不用再发送http请求了，如果不同，那么就使用ImageLoader对象来发送http请求获取图片。\nImageLoader imageLoader = AppController.getInstance\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;.getImageLoader\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// If you are using NetworkImageView\u0026lt;/span\u0026gt; imgNetWorkView.setImageUrl\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Const.URL_IMAGE, imageLoader)\u0026lt;/span\u0026gt;; 加载一个图片只要这么简单~~~\n###用ImageView来加载图片\n这个过程和NetworkImageView类似\nImageLoader imageLoader = AppController.getInstance().getImageLoader(); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// If you are using normal ImageView\u0026lt;/span\u0026gt; imageLoader.get(Const.URL_IMAGE, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onErrorResponse\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(VolleyError \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;error\u0026lt;/span\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ Log.e(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Image Load Error: \u0026quot;\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;error\u0026lt;/span\u0026gt;.getMessage()); } \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onResponse\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(ImageContainer response, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; arg1)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (response.getBitmap() != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// load image into imageview\u0026lt;/span\u0026gt; imageView.setImageBitmap(response.getBitmap()); } } }); 可以再简单一点：\n// Loading image \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;with\u0026lt;/span\u0026gt; placeholder \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;and\u0026lt;/span\u0026gt; error image imageLoader.get(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;Const\u0026lt;/span\u0026gt;.URL_IMAGE, ImageLoader.getImageListener(imageView, R.drawable.ico_loading, R.drawable.ico_error))\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; ImageLoader.getImageListener方法中已经写了一个默认的ImageListener了\n##Volley Cache\nvolley中自带了强大的cache机制来管理请求cache，这会减少网络请求次数和用户等待时间。\n###从请求Cache中加载请求\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;Cache\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;cache\u0026lt;/span\u0026gt; = AppController\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getInstance()\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getRequestQueue()\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getCache(); Entry entry = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;cache\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;get(url); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(entry != \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ try { \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;(entry\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;UTF-8\u0026quot;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// handle data, like converting it to xml, json, bitmap etc.,\u0026lt;/span\u0026gt; } catch (UnsupportedEncodingException e) { e\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); } } }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Cached response doesn't exists. Make network call here\u0026lt;/span\u0026gt; } ###使请求缓存失效\n失效并不意味这删除，Volley还会继续使用缓存的对象直到从服务器上获取到了新的数据，新的数据会覆盖旧的数据。\nAppController.getInstance\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;.getRequestQueue\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;.getCache\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;.invalidate\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(url, \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;)\u0026lt;/span\u0026gt;; ###关闭Cache\n如果你想将某一个请求的Cache功能关闭，直接调用Request的setShouldCache()方法就可以：\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// String request\u0026lt;/span\u0026gt; StringRequest stringReq = \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringRequest(\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;...\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// disable cache\u0026lt;/span\u0026gt; stringReq\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;setShouldCache(\u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); ###将某一URL的Cache删除\n调用Cache的remove方法可以删除这个URL的cache:\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;AppController\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;.getInstance\u0026lt;/span\u0026gt;()\u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;.getRequestQueue\u0026lt;/span\u0026gt;()\u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;.getCache\u0026lt;/span\u0026gt;()\u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;.remove\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;url\u0026lt;/span\u0026gt;); ###删除所有的Cache\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;AppController\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;.getInstance\u0026lt;/span\u0026gt;()\u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;.getRequestQueue\u0026lt;/span\u0026gt;()\u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;.getCache\u0026lt;/span\u0026gt;()\u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;.clear\u0026lt;/span\u0026gt;(); ##取消请求\n在你添加一个请求到请求队列中的时候，你可以发现，addToRequestQueue(request, tag)方法还接受一个tag参数，这个tag就是用来标记某一类请求的，这样就可以取消这个tag的所有请求了：\nString tag_json_arry = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;json_req\u0026quot;\u0026lt;/span\u0026gt;; ApplicationController.getInstance\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;.getRequestQueue\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt;.cancelAll\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;feed_request\u0026quot;\u0026lt;/span\u0026gt;)\u0026lt;/span\u0026gt;; ##请求优先级\n在创建一个request的时候可以Override Request方法的getPriority方法返回一个优先级，优先级分为：Normal, Low, Immediate, High\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Priority priority = Priority.HIGH; StringRequest strReq = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringRequest(Method.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;GET\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;Const\u0026lt;/span\u0026gt;.URL_STRING_REQ, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;Response\u0026lt;/span\u0026gt;.Listener\u0026lt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026gt;() { @Override \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; void onResponse(\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;response\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;Log\u0026lt;/span\u0026gt;.d(TAG, \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;response\u0026lt;/span\u0026gt;.toString()); msgResponse.setText(\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;response\u0026lt;/span\u0026gt;.toString()); hideProgressDialog(); } }, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;Response\u0026lt;/span\u0026gt;.ErrorListener() { @Override \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; void onErrorResponse(VolleyError \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;error\u0026lt;/span\u0026gt;) { VolleyLog.d(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Error: \u0026quot;\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;error\u0026lt;/span\u0026gt;.getMessage()); hideProgressDialog(); } }) { @Override \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Priority getPriority() { return priority; } }; ##Missing! 创建xml请求\n就像创建Gson请求一样，你可以自定义一个XMLRequest类来请求xml数据\n","permalink":"https://blog.zdltech.com/posts/android%E5%BA%93volley%E7%9A%84%E4%BD%BF%E7%94%A8%E4%BB%8B%E7%BB%8D-2/","summary":"\u003cp\u003e\u003ca href=\"http://developer.android.com/training/volley/index.html\"\u003eAndroid Volley\u003c/a\u003e 是Google开发的一个网络lib，可以让你更加简单并且快速的访问网络数据。Volley库的网络请求都是异步的，你不必担心异步处理问题。\u003c/p\u003e\n\u003cp\u003eVolley的优点：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e请求队列和请求优先级\u003c/li\u003e\n\u003cli\u003e请求Cache和内存管理\u003c/li\u003e\n\u003cli\u003e扩展性性强\u003c/li\u003e\n\u003cli\u003e可以取消请求\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e##下载和编译volley.jar\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e需要安装git，ant，android sdk\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eclone代码：\u003cbr\u003e\n\u003ccode\u003egit clone https://android.googlesource.com/platform/frameworks/volley\u003c/code\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e编译jar：\u003cbr\u003e\n\u003ccode\u003eandroid update project -p . ant jar\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e添加volley.jar到你的项目中\n\u003cstrong\u003e\u003cem\u003e不过已经有人将volley的代码放到github上了：\u003c/em\u003e\u003c/strong\u003e\u003cbr\u003e\n\u003ca href=\"https://github.com/mcxiaoke/android-volley\"\u003ehttps://github.com/mcxiaoke/android-volley\u003c/a\u003e，你可以使用更加简单的方式来使用volley：\u003c/p\u003e\n\u003cp\u003e###Maven\u003c/p\u003e\n\u003cp\u003eformat: jar\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;dependency\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;groupId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;com.mcxiaoke.volley\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;groupId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;artifactId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;library\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;artifactId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;1.0.6\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;dependency\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003chr\u003e\n\u003cp\u003e###Gradle\u003c/p\u003e\n\u003cp\u003eformat: jar\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecompile 'com.mcxiaoke.volley:library:1.0.6'\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e##Volley工作原理图\u003cbr\u003e\n\u003ca href=\"http://bxbxbai.github.io/img/volley.png\"\u003e\u003cimg alt=\"Volley\" loading=\"lazy\" src=\"http://bxbxbai.github.io/img/volley.png\"\u003e\u003c/a\u003e{.fancybox}\u003c/p\u003e\n\u003cp\u003e##创建Volley 单例\u003cbr\u003e\n使用volley时，必须要创建一个请求队列\u003ccode\u003eRequestQueue\u003c/code\u003e，使用请求队列的最佳方式就是将它做成一个单例，整个app使用这么一个请求队列。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;AppController\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;Application\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = AppController.class\n        .getSimpleName();\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; RequestQueue mRequestQueue;\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageLoader mImageLoader;\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; AppController mInstance;\n\n\u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onCreate\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate();\n    mInstance = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;;\n}\n\n\u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; AppController \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getInstance\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mInstance;\n}\n\n\u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; RequestQueue \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getRequestQueue\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mRequestQueue == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n        mRequestQueue = Volley.newRequestQueue(getApplicationContext());\n    }\n\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mRequestQueue;\n}\n\n\u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ImageLoader \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getImageLoader\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n    getRequestQueue();\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mImageLoader == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n        mImageLoader = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageLoader(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mRequestQueue,\n                \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LruBitmapCache());\n    }\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mImageLoader;\n}\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;T\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;addToRequestQueue\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Request\u0026lt;T\u0026gt; req, String tag)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n    \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// set the default tag if tag is empty\u0026lt;/span\u0026gt;\n    req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);\n    getRequestQueue().add(req);\n}\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;T\u0026gt; \u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;addToRequestQueue\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Request\u0026lt;T\u0026gt; req)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n    req.setTag(TAG);\n    getRequestQueue().add(req);\n}\n\n\u0026lt;span class=\u0026quot;function\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;cancelPendingRequests\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;params\u0026quot;\u0026gt;(Object tag)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mRequestQueue != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n        mRequestQueue.cancelAll(tag);\n    }\n}\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e另外，你还需要一个Cache来存放请求的图片：\u003c/p\u003e","title":"Android库Volley的使用介绍"},{"content":"原文：How to distribute your own Android library through jCenter and Maven Central from Android Studio\n如果你想在Android Studio中引入一个library到你的项目，你只需添加如下的一行代码到模块的build.gradle文件中。\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``compile ``'com.inthecheesefactory.thecheeselibrary:fb-like:0.9.3'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 就是如此简单的一行代码，你就可以使用这个library了。\n酷呆了。不过你可能很好奇Android Studio是从哪里得到这个library的。这篇文章将详细讲解这是怎么回事，包括如何把你的库发布出去分享给世界各地的其他开发者，这样不仅可以让世界更美好，还可以耍一次酷。\nAndroid studio 是从哪里得到库的？ 先从这个简单的问题开始，我相信不是每个人都完全明白Android studio 是从哪里得到这些library的。莫非就是Android studio 从google搜索然后下载了一个合适的给我们？\n呵呵，没那么复杂。Android Studio是从build.gradle里面定义的Maven 仓库服务器上下载library的。Apache Maven是Apache开发的一个工具，提供了用于贡献library的文件服务器。总的来说，只有两个标准的Android library文件服务器：jcenter 和 Maven Central。\n[回到顶部](http://www.open-open.com/lib/view/open1435109824278.html#_labelTop) jcenter jcenter是一个由 bintray.com维护的Maven仓库 。你可以在这里看到整个仓库的内容。\n我们在项目的build.gradle 文件中如下定义仓库，就能使用jcenter了：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `allprojects {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``repositories {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``jcenter()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; [回到顶部](http://www.open-open.com/lib/view/open1435109824278.html#_labelTop) Maven Central Maven Central 则是由sonatype.org维护的Maven仓库。你可以在这里看到整个仓库。\n注：不管是jcenter还是Maven Central ，两者都是Maven仓库\n我们在项目的build.gradle 文件中如下定义仓库，就能使用Maven Central了：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `allprojects {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``repositories {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``mavenCentral()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 注意，虽然jcenter和Maven Central 都是标准的 android library仓库，但是它们维护在完全不同的服务器上，由不同的人提供内容，两者之间毫无关系。在jcenter上有的可能 Maven Central 上没有，反之亦然。\n除了两个标准的服务器之外，如果我们使用的library的作者是把该library放在自己的服务器上，我们还可以自己定义特有的Maven仓库服务器。Twitter的Fabric.io 就是这种情况，它们在https://maven.fabric.io/public上维护了一个自己的Maven仓库。如果你想使用Fabric.io的library，你必须自己如下定义仓库的url。\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `repositories {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``maven { url ``'\u0026amp;lt;a href=\u0026quot;https://maven.fabric.io/public\u0026quot;\u0026gt;https://maven.fabric.io/public\u0026amp;lt;/a\u0026gt;'` `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 然后在里面使用相同的方法获取一个library。\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``compile ``'com.crashlytics.sdk.android:crashlytics:2.2.4@aar'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 但是将library上传到标准的服务器与自建服务器，哪种方法更好呢？当然是前者。如果将我们的library公开，其他开发者除了一行定义依赖名的代码之外不需要定义任何东西。因此这篇文章中，我们将只关注对开发者更友好的jcenter 和 Maven Central 。\n实际上可以在Android Studio上使用的除了Maven 仓库之外还有另外一种仓库：Ivy 仓库 。但是根据我的经验来看，我还没看到任何人用过它，包括我，因此本文就直接忽略了。\n[回到顶部](http://www.open-open.com/lib/view/open1435109824278.html#_labelTop) 理解jcenter和Maven Central 为何有两个标准的仓库？\n事实上两个仓库都具有相同的使命：提供Java或者Android library服务。上传到哪个（或者都上传）取决于开发者。\n起初，Android Studio 选择Maven Central作为默认仓库。如果你使用老版本的Android Studio创建一个新项目，mavenCentral()会自动的定义在build.gradle中。\n但是Maven Central的最大问题是对开发者不够友好。上传library异常困难。上传上去的开发者都是某种程度的极客。同时还因为诸如安全方面的其他原因，Android Studio团队决定把默认的仓库替换成jcenter。正如你看到的，一旦使用最新版本的Android Studio创建一个项目，jcenter()自动被定义，而不是mavenCentral()。\n有许多将Maven Central替换成jcenter的理由，下面是几个主要的原因。\n– jcenter通过CDN发送library，开发者可以享受到更快的下载体验。\n– jcenter是全世界最大的Java仓库，因此在Maven Central 上有的，在jcenter上也极有可能有。换句话说jcenter是Maven Central的超集。\n– 上传library到仓库很简单，不需要像在 Maven Central上做很多复杂的事情。\n– 友好的用户界面\n– 如果你想把library上传到 Maven Central ，你可以在bintray网站上直接点击一个按钮就能实现。\n基于上面的原因以及我自己的经验，可以说替换到jcenter是明智之举。\n所以我们这篇文章将把重心放在jcenter，反正如果你能成功把library放在jcenter，转到 Maven Central 是非常容易的事情。\n[回到顶部](http://www.open-open.com/lib/view/open1435109824278.html#_labelTop) gradle是如何从仓库上获取一个library的？ 在讨论如何上传library到jcenter之前，我们先看看gradle是如何从仓库获取library的。比如我们在 build.gradle输入如下代码的时候，这些库是如果奇迹般下载到我们的项目中的。\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `compile ``'com.inthecheesefactory.thecheeselibrary:fb-like:0.9.3'` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 一般来说，我们需要知道library的字符串形式，包含3部分\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `GROUP_ID:ARTIFACT_ID:VERSION` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 上面的例子中，GROUP_ID是com.inthecheesefactory.thecheeselibrary ，ARTIFACT_ID是fb-like，VERSION是0.9.3。\nGROUP_ID定义了library的group。有可能在同样的上下文中存在多个不同功能的library。如果library具有相同的group，那么它们将共享一个GROUP_ID。通常我们以开发者包名紧跟着library的group名称来命名，比如com.squareup.picasso。然后ARTIFACT_ID中是library的真实名称。至于VERSION，就是版本号而已，虽然可以是任意文字，但是我建议设置为x.y.z的形式，如果喜欢还可以加上beta这样的后缀。\n下面是Square library的一个例子。你可以看到每个都可以很容易的分辨出library和开发者的名称。\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``compile ``'com.squareup:otto:1.3.7'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``compile ``'com.squareup.picasso:picasso:2.5.2'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``compile ``'com.squareup.okhttp:okhttp:2.4.0'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``compile ``'com.squareup.retrofit:retrofit:1.9.0'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 那么在添加了上面的依赖之后会发生什么呢？简单。Gradle会询问Maven仓库服务器这个library是否存在，如果是，gradle会获得请求library的路径，一般这个路径都是这样的形式：GROUP_ID/ARTIFACT_ID/VERSION_ID。比如可以在http://jcenter.bintray.com/com/squareup/otto/1.3.7 和 https://oss.sonatype.org/content/repositories/releases/com/squareup/otto/1.3.7/\n下获得com.squareup:otto:1.3.7的library文件。\n然后Android Studio 将下载这些文件到我们的电脑上，与我们的项目一起编译。整个过程就是这么简单，一点都不复杂。\n我相信你应该清楚的知道从仓库上下载的library只是存储在仓库服务器上的jar 或者aar文件而已。有点类似于自己去下载这些文件，拷贝然后和项目一起编译。但是使用gradle依赖管理的最大好处是你除了添加几行文字之外啥也不做。library一下子就可以在项目中使用了。\n[回到顶部](http://www.open-open.com/lib/view/open1435109824278.html#_labelTop) 了解aar文件 等等，我刚才说了仓库中存储的有两种类型的library：jar 和 aar。jar文件大家都知道，但是什么是aar文件呢？\naar文件时在jar文件之上开发的。之所以有它是因为有些Android Library需要植入一些安卓特有的文件，比如AndroidManifest.xml，资源文件，Assets或者JNI。这些都不是jar文件的标准。\n因此aar文件就时发明出来包含所有这些东西的。总的来说它和jar一样只是普通的zip文件，不过具有不同的文件结构。jar文件以classes.jar的名字被嵌入到aar文件中。其余的文件罗列如下：\n– /AndroidManifest.xml (mandatory)\n– /classes.jar (mandatory)\n– /res/ (mandatory)\n– /R.txt (mandatory)\n– /assets/ (optional)\n– /libs/.jar (optional)\n– /jni//.so (optional)\n– /proguard.txt (optional)\n– /lint.jar (optional)\n可以看到.aar文件是专门为安卓设计的。因此这篇文章将教你如何创建与上传一个aar形式的library。\n[回到顶部](http://www.open-open.com/lib/view/open1435109824278.html#_labelTop) 如何上传library到jcenter 我相信你已经知道了仓库系统的大体工作原理。现在我们来开始最重要的部分：上传。这个任务和如何上传library文件到http://jcenter.bintray.com一样简单。如果做到，这个library就算发布了。好吧，有两个需要考虑：如何创建aar文件以及如何上传构建的文件到仓库。\n虽然需要若干步骤，但是我还是想强调这事并不复杂，因为已经准备好了所有事情。整个过程如下图：\n因为细节比较多，我分为7部分，一步一步的详细解释清楚。\n[回到顶部](http://www.open-open.com/lib/view/open1435109824278.html#_labelTop) 第一部分：在bintray上创建package 首先，你需要在bintray上创建一个package。为此，你需要一个bintray账号，并在网站上创建一个package。\n第一步：在bintray.com上注册一个账号。（注册过程很简单，自己完成）\n第二步：完成注册之后，登录网站，然后点击maven。\n第三步：点击Add New Package，为我们的library创建一个新的package。\n第四步：输入所有需要的信息\n虽然如何命名包名没有什么限定，但是也有一定规范。所有字母应该为小写，单词之间用－分割，比如，fb-like。\n当每项都填完之后，点击Create Package。\n第五步：网页将引导你到 Package编辑页面。点击 Edit Package文字下的Package名字，进入Package详情界面。\n完工！现在你有了自己在Bintray上的Maven仓库，可以准备上传library到上面了。\nBintray账户的注册就完成了。下一步是Sonatype，Maven Central 的提供者。\n[回到顶部](http://www.open-open.com/lib/view/open1435109824278.html#_labelTop) 第二部分：为Maven Central创建个Sonatype帐号 注：如果你不打算把library上传到Maven Central，可以跳过第二和第三部分。不过我建议你不要跳过，因为仍然有许多开发者在使用这个仓库。\n和jcenter一样，如果你想通过Maven Central,贡献自己的library，你需要在提供者的网站Sonatype上注册一个帐号。\n你需要知道的就是这个帐号，你需要在Sonatype网站上创建一个IRA Issue Tracker 帐号。请到Sonatype Dashboard 注册这个帐号。\n完成之后。你需要请求得到贡献library到Maven Central的权限。不过这个过程对我来说有点无厘头，因为你需要做的就是在JIRA中创建一个issue，让它们允许你上传匹配Maven Central提供的GROUP_ID的library。\n要创建上述所讲到的issue，访问Sonatype Dashboard，用创建的帐号登录。然后点击顶部菜单的Create。\n填写如下信息：\nProject: Community Support – Open Source Project Repository Hosting\nIssue Type: New Project\nSummary: 你的 library名称的概要，比如The Cheese Library。\nGroup Id: 输入根GROUP_ID，比如，com.inthecheeselibrary 。一旦批准之后，每个以com.inthecheeselibrary开始的library都允许被上传到仓库，比如com.inthecheeselibrary.somelib。\nProject URL: 输入任意一个你想贡献的library的URL，比如， https://github.com/nuuneoi/FBLikeAndroid。\nSCM URL: 版本控制的URL，比如 https://github.com/nuuneoi/FBLikeAndroid.git。\n其余的不用管，然后点击Create。现在是最难的部分…耐心等待…平均大概1周左右，你会获准把自己的library分享到 Maven Central。\n最后一件事是在Bintray Profile的帐户选项中填写自己的Sonatype OSS用户名。\n点击Update，完成。\n[回到顶部](http://www.open-open.com/lib/view/open1435109824278.html#_labelTop) 第三部分：启用bintray里的自动注册 就如我上面提到的，我们可以通过jcenter上传library到Maven Central ，不过我们需要先注册这个library。bintray提供了通过用户界面让library一旦上传后自动注册的机制。\n第一步是使用下面的命令行产生一个key。（如果你用的是windows，请在cygwin下做这件事情）\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `gpg --gen-key` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 有几个必填项。部分可以采用默认值，但是某些项需要你自己输入恰当的内容，比如，你的真实名字，密码 等等。\n创建了key之后，调用如下的命令查看被创建key的信息。\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `gpg --list-keys` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 如果没没问题的话，可以看到下面的信息：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `pub 2048R/01ABCDEF 2015-03-07` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `uid Sittiphol Phanvilai \u0026amp;lt;yourmail@email.com\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `sub 2048R/98765432 2015-03-07` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 现在你需要把key上传到keyserver让它发挥作用。为此，请调用如下的命令并且将其中的PUBLIC_KEY_ID替换成上面pub一行中2048R/ 后面的 8位16进制值，譬如本例是01ABCDEF。\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `gpg --keyserver hkp:``//pool.sks-keyservers.net --send-keys PUBLIC_KEY_ID` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 然后，使用如下的命令以ASCII形式导出公共和私有的key，请将yourmail@email.com替换成你前面用于创建key的email。\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `gpg -a --export yourmail@email.com \u0026amp;gt; public_key_sender.asc` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `gpg -a --export-secret-key yourmail@email.com \u0026amp;gt; private_key_sender.asc` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 打开Bintray的Edit Profile页面点击GPG 注册。分别在Public Key和 Private Key中填入上一步导出的public_key_sender.asc和 private_key_sender.asc文件中的内容。\n点击Update保存这些key。\n最后一步就是启用自动注册。到Bintray的主页点击maven。\n点击编辑\n勾选中GPG Sign uploaed files automatically以启用自动注册。\n点击Update保存这些步骤。完成。现在只需点击一下，每个上传到我们Maven仓库的东西都会自动注册并做好转向Maven Central 。\n请注意这是一次性的操作，以后创建的每一个library都要应用此操作。\nBintray和Maven Central 已经准备好了。现在转到Android Studio部分。\n[回到顶部](http://www.open-open.com/lib/view/open1435109824278.html#_labelTop) 第四部分：准备一个Android Studio项目 很多情况下，我们需要同时上传一个以上的library到仓库，也可能不需要上传东西。因此我建议最好将每部分分成一个Module。最好分成两个module，一个Application Module一个Library Module。Application Module用于展示库的用法，Library Module是library的源代码。如果你的项目有一个以上的library，尽管创建另外的module：1个 module对应1 个library。\n__****__\n我相信大家知道如何创建一个新的module，因此就不会深入讲解这个问题了。其实很简单，基本就是选择creating an Android Library module ，然后就完了。\n下一步是把bintray插件应用在项目中。我们需要修改项目的build.gradle文件中的依赖部分，如下：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``classpath ``'com.android.tools.build:gradle:1.2.3'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``classpath ``'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``classpath ``'com.github.dcendents:android-maven-plugin:1.2'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 有一点非常重要，那就是gradle build tools的版本设置成1.1.2以上，因为以前的版本有严重的bug，我们将使用的是最新的版本1.2.3。\n接下来我们将修改local.properties。在里面定义api key的用户名以及被创建key的密码，用于bintray的认证。之所以要把这些东西放在这个文件是因为这些信息时比较敏感的，不应该到处分享，包括版本控制里面。幸运的是在创建项目的时候local.properties文件就已经被添加到.gitignore了。因此这些敏感数据不会被误传到git服务器。\n下面是要添加的三行代码：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `bintray.user=YOUR_BINTRAY_USERNAME` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `bintray.apikey=YOUR_BINTRAY_API_KEY` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `bintray.gpg.password=YOUR_GPG_PASSWORD` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; bintray username 放在第一行， API Key放在第二行， API Key可以在Edit Profile页面的API Key 选项卡中找到。\n最后一行是创建 GPG key的密码。保存并关闭这个文件。\n最后要修改的是module的build.gradle文件。注意前面修改的是项目的build.gradle文件。打开它，在apply plugin: ‘com.android.library’之后添加这几行，如下：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `apply plugin: ``'com.android.library'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `ext {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``bintrayRepo = ``'maven'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``bintrayName = ``'fb-like'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``publishedGroupId = ``'com.inthecheesefactory.thecheeselibrary'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``libraryName = ``'FBLike'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``artifact = ``'fb-like'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``libraryDescription = ``'A wrapper for Facebook Native Like Button (LikeView) on Android'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``siteUrl = ``'\u0026amp;lt;a href=\u0026quot;https://github.com/nuuneoi/FBLikeAndroid\u0026quot;\u0026gt;https://github.com/nuuneoi/FBLikeAndroid\u0026amp;lt;/a\u0026gt;'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``gitUrl = ``'\u0026amp;lt;a href=\u0026quot;https://github.com/nuuneoi/FBLikeAndroid.git\u0026quot;\u0026gt;https://github.com/nuuneoi/FBLikeAndroid.git\u0026amp;lt;/a\u0026gt;'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``libraryVersion = ``'0.9.3'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``developerId = ``'nuuneoi'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``developerName = ``'Sittiphol Phanvilai'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``developerEmail = ``'sittiphol@gmail.com'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``licenseName = ``'The Apache Software License, Version 2.0'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``licenseUrl = ``'\u0026amp;lt;a href=\u0026quot;http://www.apache.org/licenses/LICENSE-2.0.txt\u0026quot;\u0026gt;http://www.apache.org/licenses/LICENSE-2.0.txt\u0026amp;lt;/a\u0026gt;'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``allLicenses = [``\u0026quot;Apache-2.0\u0026quot;``]` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; bintrayRepo使用默认的，即maven。bintrayName修改成你上面创建的 package name。其余的项也修改成和你library信息相匹配的值。有了上面的脚本，每个人都能通过下面的一行gradle脚本使用这个library。\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `compile ``'com.inthecheesefactory.thecheeselibrary:fb-like:0.9.3'` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 最后在文件的后面追加两行如下的代码来应用两个脚本，用于构建library文件和上传文件到bintray（为了方便，我直接使用了github上连接到相关文件的链接）：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `apply from: ``'\u0026amp;lt;a href=\u0026quot;https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle\u0026quot;\u0026gt;https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle\u0026amp;lt;/a\u0026gt;'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `apply from: ``'\u0026amp;lt;a href=\u0026quot;https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle\u0026quot;\u0026gt;https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle\u0026amp;lt;/a\u0026gt;'` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 完成！你的项目现在设置好了，准备上传到bintray吧！\n[回到顶部](http://www.open-open.com/lib/view/open1435109824278.html#_labelTop) 第五部分：把library上传到你的bintray空间 现在是上传library到你自己的bintray仓库上的时候了。请到Android Studio的终端（Terminal）选项卡。\n第一步是检查代码的正确性，以及编译library文件（aar，pom等等），输入下面的命令：\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;gt; gradlew install` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 如果没有什么问题，会显示：\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `BUILD SUCCESSFUL` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 现在我们已经成功一半了。下一步是上传编译的文件到bintray，使用如下的命令：\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `gradlew bintrayUpload` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 如果显示如下你就大喊一声eureka吧！\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `SUCCESSFUL` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 在bintray的网页上检查一下你的package。你会发现在版本区域的变化。\n点击进去，进入Files选项卡，你会看见那里有我们所上传的library文件。\n恭喜，你的library终于放在了互联网上，任何人都可以使用了！\n不过也别高兴过头，library现在仍然只是在你自己的Maven仓库，而不是在jcenter上。如果有人想使用你的library，他必须定义仓库的url，如下：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `repositories {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``maven {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``url ``'\u0026amp;lt;a href=\u0026quot;https://dl.bintray.com/nuuneoi/maven/\u0026quot;\u0026gt;https://dl.bintray.com/nuuneoi/maven/\u0026amp;lt;/a\u0026gt;'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `...` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; `dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``compile ``'com.inthecheesefactory.thecheeselibrary:fb-like:0.9.3'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 译者注：前面都没怎么看懂，看到上面的代码之后一下子全懂了，呵呵。\n你可以在bintray的web界面找到自己Maven仓库的url，或者直接吧nuuneoi替换成你的bintray用户名（因为前面部分其实都是一样的）。我还建议你直接访问那个链接，看看里面到底是什么。\n但是，就如我们前面所讲的那样，让开发者去定义url这种复杂的事情并不是分享library的最佳方式。想象一下，使用10个library不得添加10个url？所以为了更好的体验，我们把library从自己的仓库传到jcenter上。\n[回到顶部](http://www.open-open.com/lib/view/open1435109824278.html#_labelTop) 第六部分：同步bintray用户仓库到jcenter 把library同步到jcenter非常容易。只需访问网页并点击Add to JCenter\n什么也不做直接点击Send。\n现在我们所能做的就是等待bintray团队审核我们的请求，大概2-3个小时。一旦同步的请求审核通过，你会收到一封确认此更改的邮件。现在我们去网页上确认，你会在 Linked To 部分看到一些变化。\n从此之后，任何开发者都可以使用jcenter() repository 外加一行gradle脚本来使用我们的library了\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `compile ``'com.inthecheesefactory.thecheeselibrary:fb-like:0.9.3'` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 想检查一下自己的library在jcenter上是否存在？你可以直接访问http://jcenter.bintray.com，然后进入和你library的group id 以及artifact id匹配的目录。在本例中就是com -\u0026gt; inthecheesefactory -\u0026gt; thecheeselibrary -\u0026gt; fb-like -\u0026gt; 0.9.3。\n请注意链接到jcenter是一个只需做一次的操作。如果你对你的package做了任何修改，比如上传了一个新版本的binary，删除了旧版本的binary等等，这些改变也会影响到jcenter。不过毕竟你自己的仓库和jcenter在不同的地方，所以需要等待2－3分钟让jcenter同步这些修改。\n同时注意，如果你决定删除整个package，放在jcenter仓库上的library不会被删除。它们会像僵尸一样的存在，没有人再能删除它了。因此我建议，如果你想删除整个package，请在移除package之前先在网页上删除每一个版本。\n[回到顶部](http://www.open-open.com/lib/view/open1435109824278.html#_labelTop) 第七部分：上传library到Maven Central 并不是每个安卓开发者都使用jcenter。仍然有部分开发者还在使用mavenCentral() ，因此让我们也把library上传到Maven Central 吧。\n要从jcenter到Maven Central，首先需要完成两个任务：\nBintray package 已经连接到jcenter。\nMaven Central上的仓库已经认证通过\n如果你已经通过了这些授权，上传library package到Maven Central就异常简单了，只需在package的详情页面点击Maven Central 的链接。\n输入你的Sonatype用户名和密码并点击Sync。\n如果成功，在Last Sync Status中会显示Successfully synced and closed repo（见图），但是如果遇到任何问题，则会在Last Sync Errors显示出来。你需要根据情况修复问题，能上传到Maven Central 的library的条件是相当严格的，比如+ 号是不能在ibrary版本的依赖定义中使用的。\n完成之后，你可以在 Maven Central Repository 上找到你的library。在那些匹配你ibrary的group id以及artifact id的目录中。比如本例中就是com -\u0026gt; inthecheesefactory -\u0026gt; thecheeselibrary -\u0026gt; fb-like -\u0026gt; 0.9.3。\n恭喜！虽然需要许多步骤，但是每一步都很简单。而且大部分操作都是一劳永逸的。\n如此长篇的文章！希望对你有所帮助。我的英语也许有点晦涩，不过希望至少内容是可以理解的。\n期待能在上面看到你的library大作！\n来自：http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0623/3097.html\n","permalink":"https://blog.zdltech.com/posts/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8android-studio%E6%8A%8A%E8%87%AA%E5%B7%B1%E7%9A%84android-library%E5%88%86%E4%BA%AB%E5%88%B0jcenter%E5%92%8Cmaven-central/","summary":"\u003cp\u003e原文：\u003ca href=\"http://inthecheesefactory.com/blog/how-to-upload-library-to-jcenter-maven-central-as-dependency/en\"\u003eHow to distribute your own Android library through jCenter and Maven Central from Android Studio\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e如果你想在Android Studio中引入一个library到你的项目，你只需添加如下的一行代码到模块的build.gradle文件中。\u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_448375\" class=\"syntaxhighlighter  js\"\u003e\n    \u003ctable border=\"0\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n      \u003ctr\u003e\n        \u003ctd class=\"gutter\"\u003e\n          \u003cdiv class=\"line number1 index0 alt2\"\u003e\n            1\n          \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        2\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n        3\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `dependencies {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          `    ``compile ``'com.inthecheesefactory.thecheeselibrary:fb-like:0.9.3'`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e就是如此简单的一行代码，你就可以使用这个library了。\u003c/p\u003e","title":"如何使用Android Studio把自己的Android library分享到jCenter和Maven Central"},{"content":"JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition – December 1999的一个子集。 JSON采用完全独立于语言的文本格式，这些特性使JSON成为理想的数据交换语言。\n下面介绍四款处理json的java类库：Json-lib、Gson、Jackson、Fastjson\n一、Json-lib JSON-lib is a java library for transforming beans, maps, collections, java arrays and XML to JSON and back again to beans and DynaBeans. 官网：http://json-lib.sourceforge.net/\nmaven依赖配置：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) \u0026amp;lt;dependency\u0026amp;gt; \u0026amp;lt;groupId\u0026amp;gt;net.sf.json-lib\u0026amp;lt;/groupId\u0026amp;gt; \u0026amp;lt;artifactId\u0026amp;gt;json-lib\u0026amp;lt;/artifactId\u0026amp;gt; \u0026amp;lt;version\u0026amp;gt;2.4\u0026amp;lt;/version\u0026amp;gt; \u0026amp;lt;classifier\u0026amp;gt;jdk15\u0026amp;lt;/classifier\u0026amp;gt; \u0026amp;lt;/dependency\u0026amp;gt; ![复制代码](http://common.cnblogs.com/images/copycode.gif) 示例：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) /** * 将对象序列化成json字符串 * @param obj * @return */ public static String bean2Json(Object obj){ JSONObject jsonObject=JSONObject.fromObject(obj); return jsonObject.toString(); } /** * 将json字符串反序列化为对象 * @param jsonStr * @param objClass 反序列化为该类的对象 * @return */ @SuppressWarnings(\u0026#34;unchecked\u0026#34;) public static \u0026amp;lt;T\u0026amp;gt; T json2Bean(String jsonStr,Class\u0026amp;lt;T\u0026amp;gt; objClass){ return (T)JSONObject.toBean(JSONObject.fromObject(jsonStr), objClass); } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 二、Gson Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.\n官网：https://code.google.com/p/google-gson/\nmaven依赖：\n``` \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.google.code.gson\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;gson\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.2.4\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; ``` 示例：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) public static String bean2Json(Object obj){ Gson gson = new GsonBuilder().create(); return gson.toJson(obj); } public static \u0026amp;lt;T\u0026amp;gt; T json2Bean(String jsonStr,Class\u0026amp;lt;T\u0026amp;gt; objClass){ Gson gson = new GsonBuilder().create(); return gson.fromJson(jsonStr, objClass); } /** * 把混乱的json字符串整理成缩进的json字符串 * @param uglyJsonStr * @return */ public static String jsonFormatter(String uglyJsonStr){ Gson gson = new GsonBuilder().setPrettyPrinting().create(); JsonParser jp = new JsonParser(); JsonElement je = jp.parse(uglyJsonStr); String prettyJsonString = gson.toJson(je); return prettyJsonString; } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 三、Jackson Jackson is a high-performance JSON processor (parser, generator)。官网：http://jackson.codehaus.org/Home\nmaven依赖：\n``` \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.codehaus.jackson\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;jackson-mapper-asl\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;1.9.13\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; ``` 示例：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) public static String bean2Json(Object obj) throws IOException { ObjectMapper mapper = new ObjectMapper(); StringWriter sw = new StringWriter(); JsonGenerator gen = new JsonFactory().createJsonGenerator(sw); mapper.writeValue(gen, obj); gen.close(); return sw.toString(); } public static \u0026amp;lt;T\u0026amp;gt; T json2Bean(String jsonStr, Class\u0026amp;lt;T\u0026amp;gt; objClass) throws JsonParseException, JsonMappingException, IOException { ObjectMapper mapper = new ObjectMapper(); return mapper.readValue(jsonStr, objClass); } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 四、FastJson Fastjson是一个Java语言编写的JSON处理器,由阿里巴巴公司开发。网址：https://github.com/alibaba/fastjson\nmaven依赖配置：\n``` \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.alibaba\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;fastjson\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;1.1.35\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; ``` 示例：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) public static String bean2Json(Object obj){ return JSON.toJSONString(obj); } public static \u0026amp;lt;T\u0026amp;gt; T json2Bean(String jsonStr,Class\u0026amp;lt;T\u0026amp;gt; objClass){ return JSON.parseObject(jsonStr, objClass); } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 五、性能测试 1、Java对象序列化为Json字符串：\n执行100 0000次转换，各个类库的耗时如下：（以秒为单位）\nGson \u0026lt;td\u0026gt; 48.891s \u0026lt;/td\u0026gt; Json-lib \u0026lt;td\u0026gt; 311.446s \u0026lt;/td\u0026gt; Jackson \u0026lt;td\u0026gt; 19.439s \u0026lt;/td\u0026gt; FastJson \u0026lt;td\u0026gt; 21.706 \u0026lt;/td\u0026gt; 2、Json字符串 反序列化为Java对象\n执行100 0000次转换，各个类库的耗时如下：（以秒为单位）\nGson \u0026lt;td\u0026gt; 39.280s \u0026lt;/td\u0026gt; Json-lib \u0026lt;td\u0026gt; 使用该类库的方法进行转换时（测试代码见下面），抛出异常。其原因是Person类的属性：List\u0026lt;Person\u0026gt; friends，其List中的对象不是Person类型的对象，而是net.sf.ezmorph.bean.MorphDynaBean类型的对象。说明，Json-lib对嵌套的自定义类支持的很差，或许是我写的方法有问题。 \u0026lt;/td\u0026gt; Jackson \u0026lt;td\u0026gt; 26.427s \u0026lt;/td\u0026gt; FastJson \u0026lt;td\u0026gt; 40.556 \u0026lt;/td\u0026gt; 3、总结：\nJava Bean序列化为Json，性能：Jackson \u0026gt; FastJson \u0026gt; Gson \u0026gt; Json-lib。这4中类库的序列化结构都正确。\nJson字符串反序列化为Java Bean时，性能：Jackson \u0026gt; Gson \u0026gt; FastJson \u0026gt;Json-lib。并且Jackson、Gson、FastJson可以很好的支持复杂的嵌套结构定义的类，而Json-lib对于复制的反序列化会出错。\nJackson、FastJson、Gson类库各有优点，各有自己的专长，都具有很高的可用性。\n4、测试用例\n1）Java Bean\n![复制代码](http://common.cnblogs.com/images/copycode.gif) public class Person { private String name; private FullName fullName; private int age; private Date birthday; private List\u0026amp;lt;String\u0026amp;gt; hobbies; private Map\u0026amp;lt;String, String\u0026amp;gt; clothes; private List\u0026amp;lt;Person\u0026amp;gt; friends; **//getter setter 方法。略** @Override public String toString() { String str= \u0026#34;Person [name=\u0026#34; + name + \u0026#34;, fullName=\u0026#34; + fullName + \u0026#34;, age=\u0026#34; + age + \u0026#34;, birthday=\u0026#34; + birthday + \u0026#34;, hobbies=\u0026#34; + hobbies + \u0026#34;, clothes=\u0026#34; + clothes + \u0026#34;]\\n\u0026#34;; if(friends!=null){ str+=\u0026#34;Friends:\\n\u0026#34;; for (Person f : friends) { str+=\u0026#34;\\t\u0026#34;+f; } } return str; } } class FullName { private String firstName; private String middleName; private String lastName; //构造方法、getter setter 方法，略 @Override public String toString() { return \u0026#34;[firstName=\u0026#34; + firstName + \u0026#34;, middleName=\u0026#34; + middleName + \u0026#34;, lastName=\u0026#34; + lastName + \u0026#34;]\u0026#34;; } } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 2）Json-lib、Gson、Jackson、FastJson类库：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) import net.sf.json.JSONObject; public class JsonObjectUtil { public static String bean2Json(Object obj){ JSONObject jsonObject=JSONObject.fromObject(obj); return jsonObject.toString(); } @SuppressWarnings(\u0026#34;unchecked\u0026#34;) public static \u0026amp;lt;T\u0026amp;gt; T json2Bean(String jsonStr,Class\u0026amp;lt;T\u0026amp;gt; objClass){ return (T)JSONObject.toBean(JSONObject.fromObject(jsonStr), objClass); } } ![复制代码](http://common.cnblogs.com/images/copycode.gif) ![复制代码](http://common.cnblogs.com/images/copycode.gif) import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonParser; public class GsonUtil { private static Gson gson = new GsonBuilder().create(); public static String bean2Json(Object obj){ return gson.toJson(obj); } public static \u0026amp;lt;T\u0026amp;gt; T json2Bean(String jsonStr,Class\u0026amp;lt;T\u0026amp;gt; objClass){ return gson.fromJson(jsonStr, objClass); } public static String jsonFormatter(String uglyJsonStr){ Gson gson = new GsonBuilder().setPrettyPrinting().create(); JsonParser jp = new JsonParser(); JsonElement je = jp.parse(uglyJsonStr); String prettyJsonString = gson.toJson(je); return prettyJsonString; } } ![复制代码](http://common.cnblogs.com/images/copycode.gif) ![复制代码](http://common.cnblogs.com/images/copycode.gif) import java.io.IOException; import java.io.StringWriter; import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; public class JacksonUtil { private static ObjectMapper mapper = new ObjectMapper(); public static String bean2Json(Object obj) throws IOException { StringWriter sw = new StringWriter(); JsonGenerator gen = new JsonFactory().createJsonGenerator(sw); mapper.writeValue(gen, obj); gen.close(); return sw.toString(); } public static \u0026amp;lt;T\u0026amp;gt; T json2Bean(String jsonStr, Class\u0026amp;lt;T\u0026amp;gt; objClass) throws JsonParseException, JsonMappingException, IOException { return mapper.readValue(jsonStr, objClass); } } ![复制代码](http://common.cnblogs.com/images/copycode.gif) ![复制代码](http://common.cnblogs.com/images/copycode.gif) public class FastJsonUtil { public static String bean2Json(Object obj){ return JSON.toJSONString(obj); } public static \u0026amp;lt;T\u0026amp;gt; T json2Bean(String jsonStr,Class\u0026amp;lt;T\u0026amp;gt; objClass){ return JSON.parseObject(jsonStr, objClass); } } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 3）Java对象序列化为Json字符串 测试类：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) public class TestBean2Json { private Person p; private Person createAPerson(String name,List\u0026amp;lt;Person\u0026amp;gt; friends) { Person newPerson=new Person(); newPerson.setName(name); newPerson.setFullName(new FullName(\u0026#34;xxx_first\u0026#34;, \u0026#34;xxx_middle\u0026#34;, \u0026#34;xxx_last\u0026#34;)); newPerson.setAge(24); List\u0026amp;lt;String\u0026amp;gt; hobbies=new ArrayList\u0026amp;lt;String\u0026amp;gt;(); hobbies.add(\u0026#34;篮球\u0026#34;); hobbies.add(\u0026#34;游泳\u0026#34;); hobbies.add(\u0026#34;coding\u0026#34;); newPerson.setHobbies(hobbies); Map\u0026amp;lt;String,String\u0026amp;gt; clothes=new HashMap\u0026amp;lt;String, String\u0026amp;gt;(); clothes.put(\u0026#34;coat\u0026#34;, \u0026#34;Nike\u0026#34;); clothes.put(\u0026#34;trousers\u0026#34;, \u0026#34;adidas\u0026#34;); clothes.put(\u0026#34;shoes\u0026#34;, \u0026#34;安踏\u0026#34;); newPerson.setClothes(clothes); newPerson.setFriends(friends); return newPerson; } @Before public void init(){ List\u0026amp;lt;Person\u0026amp;gt; friends=new ArrayList\u0026amp;lt;Person\u0026amp;gt;(); friends.add(createAPerson(\u0026#34;小明\u0026#34;,null)); friends.add(createAPerson(\u0026#34;Tony\u0026#34;,null)); friends.add(createAPerson(\u0026#34;陈小二\u0026#34;,null)); p=createAPerson(\u0026#34;邵同学\u0026#34;,friends); } // @Test public void testGsonBean2Json(){ System.out.println(GsonUtil.bean2Json(p)); for (int i = 0; i \u0026amp;lt; 1000000; i++) { GsonUtil.bean2Json(p); } } //@Test public void testJsonObjectBean2Json(){ System.out.println(JsonlibUtil.bean2Json(p)); for (int i = 0; i \u0026amp;lt; 1000000; i++) { JsonlibUtil.bean2Json(p); } } // @Test public void testJacksonBean2Json() throws Exception{ System.out.println(JacksonUtil.bean2Json(p)); for (int i = 0; i \u0026amp;lt; 1000000; i++) { JacksonUtil.bean2Json(p); } } @Test public void testFastJsonBean2Json() throws Exception{ System.out.println(FastJsonUtil.bean2Json(p)); for (int i = 0; i \u0026amp;lt; 1000000; i++) { FastJsonUtil.bean2Json(p); } } } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 4）Json字符串 反序列化为Java对象 测试类：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) public class TestJson2Bean { private String jsonStr; @Before public void init(){ jsonStr=\u0026#34;{\\\u0026#34;name\\\u0026#34;:\\\u0026#34;邵同学\\\u0026#34;,\\\u0026#34;fullName\\\u0026#34;:{\\\u0026#34;firstName\\\u0026#34;:\\\u0026#34;xxx_first\\\u0026#34;,\\\u0026#34;middleName\\\u0026#34;:\\\u0026#34;xxx_middle\\\u0026#34;,\\\u0026#34;lastName\\\u0026#34;:\\\u0026#34;xxx_last\\\u0026#34;},\\\u0026#34;age\\\u0026#34;:24,\\\u0026#34;birthday\\\u0026#34;:null,\\\u0026#34;hobbies\\\u0026#34;:[\\\u0026#34;篮球\\\u0026#34;,\\\u0026#34;游泳\\\u0026#34;,\\\u0026#34;coding\\\u0026#34;],\\\u0026#34;clothes\\\u0026#34;:{\\\u0026#34;shoes\\\u0026#34;:\\\u0026#34;安踏\\\u0026#34;,\\\u0026#34;trousers\\\u0026#34;:\\\u0026#34;adidas\\\u0026#34;,\\\u0026#34;coat\\\u0026#34;:\\\u0026#34;Nike\\\u0026#34;},\\\u0026#34;friends\\\u0026#34;:[{\\\u0026#34;name\\\u0026#34;:\\\u0026#34;小明\\\u0026#34;,\\\u0026#34;fullName\\\u0026#34;:{\\\u0026#34;firstName\\\u0026#34;:\\\u0026#34;xxx_first\\\u0026#34;,\\\u0026#34;middleName\\\u0026#34;:\\\u0026#34;xxx_middle\\\u0026#34;,\\\u0026#34;lastName\\\u0026#34;:\\\u0026#34;xxx_last\\\u0026#34;},\\\u0026#34;age\\\u0026#34;:24,\\\u0026#34;birthday\\\u0026#34;:null,\\\u0026#34;hobbies\\\u0026#34;:[\\\u0026#34;篮球\\\u0026#34;,\\\u0026#34;游泳\\\u0026#34;,\\\u0026#34;coding\\\u0026#34;],\\\u0026#34;clothes\\\u0026#34;:{\\\u0026#34;shoes\\\u0026#34;:\\\u0026#34;安踏\\\u0026#34;,\\\u0026#34;trousers\\\u0026#34;:\\\u0026#34;adidas\\\u0026#34;,\\\u0026#34;coat\\\u0026#34;:\\\u0026#34;Nike\\\u0026#34;},\\\u0026#34;friends\\\u0026#34;:null},{\\\u0026#34;name\\\u0026#34;:\\\u0026#34;Tony\\\u0026#34;,\\\u0026#34;fullName\\\u0026#34;:{\\\u0026#34;firstName\\\u0026#34;:\\\u0026#34;xxx_first\\\u0026#34;,\\\u0026#34;middleName\\\u0026#34;:\\\u0026#34;xxx_middle\\\u0026#34;,\\\u0026#34;lastName\\\u0026#34;:\\\u0026#34;xxx_last\\\u0026#34;},\\\u0026#34;age\\\u0026#34;:24,\\\u0026#34;birthday\\\u0026#34;:null,\\\u0026#34;hobbies\\\u0026#34;:[\\\u0026#34;篮球\\\u0026#34;,\\\u0026#34;游泳\\\u0026#34;,\\\u0026#34;coding\\\u0026#34;],\\\u0026#34;clothes\\\u0026#34;:{\\\u0026#34;shoes\\\u0026#34;:\\\u0026#34;安踏\\\u0026#34;,\\\u0026#34;trousers\\\u0026#34;:\\\u0026#34;adidas\\\u0026#34;,\\\u0026#34;coat\\\u0026#34;:\\\u0026#34;Nike\\\u0026#34;},\\\u0026#34;friends\\\u0026#34;:null},{\\\u0026#34;name\\\u0026#34;:\\\u0026#34;陈小二\\\u0026#34;,\\\u0026#34;fullName\\\u0026#34;:{\\\u0026#34;firstName\\\u0026#34;:\\\u0026#34;xxx_first\\\u0026#34;,\\\u0026#34;middleName\\\u0026#34;:\\\u0026#34;xxx_middle\\\u0026#34;,\\\u0026#34;lastName\\\u0026#34;:\\\u0026#34;xxx_last\\\u0026#34;},\\\u0026#34;age\\\u0026#34;:24,\\\u0026#34;birthday\\\u0026#34;:null,\\\u0026#34;hobbies\\\u0026#34;:[\\\u0026#34;篮球\\\u0026#34;,\\\u0026#34;游泳\\\u0026#34;,\\\u0026#34;coding\\\u0026#34;],\\\u0026#34;clothes\\\u0026#34;:{\\\u0026#34;shoes\\\u0026#34;:\\\u0026#34;安踏\\\u0026#34;,\\\u0026#34;trousers\\\u0026#34;:\\\u0026#34;adidas\\\u0026#34;,\\\u0026#34;coat\\\u0026#34;:\\\u0026#34;Nike\\\u0026#34;},\\\u0026#34;friends\\\u0026#34;:null}]}\u0026#34;; } // @Test public void testGsonjson2Bean() throws Exception{ Person pp=GsonUtil.json2Bean(jsonStr, Person.class); System.out.println(pp); for (int i = 0; i \u0026amp;lt; 1000000; i++) { GsonUtil.json2Bean(jsonStr, Person.class); } } // @Test public void testJsonlibJson2Bean() throws Exception{ Person pp=JsonlibUtil.json2Bean(jsonStr, Person.class); System.out.println(pp); for (int i = 0; i \u0026amp;lt; 1000000; i++) { JsonlibUtil.json2Bean(jsonStr, Person.class); } } // @Test public void testJacksonJson2Bean() throws Exception{ Person pp=JacksonUtil.json2Bean(jsonStr, Person.class); System.out.println(pp); for (int i = 0; i \u0026amp;lt; 1000000; i++) { JacksonUtil.json2Bean(jsonStr, Person.class); } } @Test public void testFastJsonJson2Bean() throws Exception{ Person pp=FastJsonUtil.json2Bean(jsonStr, Person.class); System.out.println(pp); for (int i = 0; i \u0026amp;lt; 1000000; i++) { FastJsonUtil.json2Bean(jsonStr, Person.class); } } } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 参考：http://www.json.org/json-zh.html\n","permalink":"https://blog.zdltech.com/posts/%E4%BB%8B%E7%BB%8D4%E6%AC%BEjson%E7%9A%84java%E7%B1%BB%E5%BA%93-%E5%8F%8A-%E5%85%B6%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/","summary":"\u003cp\u003e\u003cstrong\u003eJSON\u003c/strong\u003e(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于\u003ca href=\"http://www.crockford.com/javascript\"\u003eJavaScript Programming Language\u003c/a\u003e, \u003ca href=\"http://www.ecma-international.org/publications/files/ecma-st/ECMA-262.pdf\"\u003eStandard ECMA-262 3rd Edition – December 1999\u003c/a\u003e的一个子集。 JSON采用完全独立于语言的文本格式，这些特性使JSON成为理想的数据交换语言。\u003c/p\u003e\n\u003cp\u003e下面介绍四款处理json的java类库：Json-lib、Gson、Jackson、Fastjson\u003c/p\u003e\n\u003ch2 id=\"一json-lib\"\u003e一、Json-lib\u003c/h2\u003e\n\u003cp\u003eJSON-lib is a java library for transforming beans, maps, collections, java arrays and XML to JSON and back again to beans and DynaBeans. 官网：\u003ca href=\"http://json-lib.sourceforge.net/\"\u003ehttp://json-lib.sourceforge.net/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003emaven依赖配置：\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       \u0026amp;lt;dependency\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u0026amp;lt;groupId\u0026amp;gt;net.sf.json-lib\u0026amp;lt;/groupId\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u0026amp;lt;artifactId\u0026amp;gt;json-lib\u0026amp;lt;/artifactId\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u0026amp;lt;version\u0026amp;gt;2.4\u0026amp;lt;/version\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u0026amp;lt;classifier\u0026amp;gt;jdk15\u0026amp;lt;/classifier\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026amp;lt;/dependency\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e示例：\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * 将对象序列化成json字符串\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * @param obj\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * @return\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  public static String bean2Json(Object obj){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      JSONObject jsonObject=JSONObject.fromObject(obj);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      return jsonObject.toString();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  /**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * 将json字符串反序列化为对象\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * @param jsonStr\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * @param objClass 反序列化为该类的对象\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * @return\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  @SuppressWarnings(\u0026#34;unchecked\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  public static \u0026amp;lt;T\u0026amp;gt; T json2Bean(String jsonStr,Class\u0026amp;lt;T\u0026amp;gt; objClass){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      return (T)JSONObject.toBean(JSONObject.fromObject(jsonStr), objClass);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"介绍4款json的java类库 及 其性能测试"},{"content":"在摸索过程中，GitHub上搜集了很多很棒的Android第三方库，推荐给在苦苦寻找的开发者，而且我会不定期的更新这篇文章。\nAndroid下的优秀开发库数不胜数，在本文中，我列举的多是开发流程中最常用的一些。如果你还想了解更多的Android开源库，可以查看我的GitHub Star，过滤Java选项，每一个库都是我认真查看或者编译运行的，希望对你产生帮助。\n一、兼容类库 ActionBarSherlock : Action Bar是Android 3.0后才开始支持的，ActionBarSherlock是让Action Bar功能支持2.X后的所有平台，而且他会自动的判断是调用原生Action Bar还是使用扩展ActionBar。在我的小熊词典里有用到这个库，而且很多非常知名的App也在使用这个库。GitHub Official ActionBar科普 最新消息（2013年7月）：Android官方发布的的Support Library Revision 18 开始支持ActionBar的兼容。所以可以不用再使用ActionBarSherlock了。 Android-ViewPagerIndicator : 这是与ViewPager兼容的一个分页指示器库。分页指示器（Friends 和 Suggested就是分页，而下面蓝色的小条就是指示器，ViewPagerIndicator支持多种样式的指示器。）：GitHub NineOldAndroids : NineOldAndroids 将 Honeycomb (Android 3.0) 的动画 API扩展到了Android 1.0以上。这个库的作者即是ActionBarSherlock的作者，也是Android-ViewPagerIndicator的作者，Jake Wharton， 非常厉害的一个人，Github关注量超过1.6K，如果你也做Android开发或者即将开始学习Android开发，一定要去Follow他，而且留意一下他每次的star和follow信息，经常会有很惊奇的发现。 HoloEverywhere：在Android 4.0时，Google引入了新的主题风格—Holo，多数厂商都想统一界面设计UI，因此更加具有兼容性的Holo主题库HoloEveryWhere便成为很多开发者的选择。在Android的官方Blog中也对HoloEveryWhere这个库有所推荐，点此查看官方博客对HoloEveryWhere的介绍。HoloEveryWhere的Github。 Android-Datepicker: 兼容Android 4.0的datepicker至Android 2.2。 GitHub **二、**扩展功能库 SlidingMenu : SlidingMenu 能非常容易的让开发者实现程序的抽屉效果，所谓的抽屉效果如下图所示，通常被用作呼出菜单。而且SlidingMenu能很方便的与ActionBarSherlock融合，在官方GitHub上有关于如何融合的说明。 GitHub 同时，想要达到相同功能也可以看另一个Drawer设计：Android-Undergarment\nAppMsg : 优雅的弹出类似Toast的消息提示，支持3种状态Alert,Confirm以及Info。GitHub\nDrag-Sort-ListView : 很多人都用过在一个ListView中通过拖拽对已有的数据进行排序操作。Drag-Sort-Listview就是实现这一功能的开源库。GitHub\nAndroid-Flip : 轻松实现类似FlipBoard的翻页功能。 GitHub\nAndroid-PullToRefresh : Android下拉刷新组件。 GitHub 此外，该作者还有另外一个实用度和关注量极高的项目–另一种Android ActionBar的实现：GitHub 另：GitHub上另一个Android-PullToRefresh的实现。GitHub\nActionBar-PullToRefresh： 基于ActionBar的下拉刷新组件，在下拉的时候会替换掉ActionBar，显示更新中… GitHub Demo下载\npicasso: 程序中经常面临加载网络图片的情况，成熟做法：异步下载-\u0026gt;缓存-\u0026gt;显示，Picasso一行代码就可这三步轻松完成。GitHub GitHubPage ，GitHub上图片异步加载缓存类库很多，你也可尝试使用Android-Universal-Image-Loader 或者 LazyList 后面将介绍到的afinal(国人项目)也具有此功能。\nCard-UI: Google很早之前开始在自家的App内使用卡片式布局，CardUI极其美观大方，想要在自己的App中集成卡片UI布局，那么就轻松地用这个项目吧。GitHub 或者你也可以使用这个库来完成卡片布局。CardLib 另一个卡片式布局: GitHub\nAndroid-DragArea：Android拖拽排序，拖拽移动 库。GitHub (Opera Android浏览器的拖拽排序就是用的这个库)\nAndroid-StaggeredGrid: Android 下类pinterest布局。GitHub Android 类 Pinterest 布局\n\u0026lt;/div\u0026gt; FlipImageView: 通过扩展ImageView，实现了ImageView的各种翻转效果。GitHub 体验地址\naChartEngine: Android绘制K线图，以及各种丰富功能的图表。Official Site SmoothProgressBar：平滑的ProgressBar，各种效果。GitHub 体验地址 各式各样的ProgressBar\n\u0026lt;/div\u0026gt; SuperToasts: 一个愤青对Toast的超强扩展，支持Toast中显示Progressbar，显示图片，显示文等等效果，快去感受下吧！Play GitHub\nAndroidFloatLabel：Android Textview 浮动提示，效果是类似下图的。GitHub 浮动提示\n\u0026lt;/div\u0026gt; cropper:Android截图和旋转库，轻松实现头像和一些场景下的图片操作。GitHub Android Cropper\n\u0026lt;/div\u0026gt; StickyGridHeaders:给GridView加上Header。GitHub GridHeader\n\u0026lt;/div\u0026gt; avatar-android: 一个用来展示头像的库，支持多种展示方式（圆形，方形）。GitHub 下载感受 Background-ViewPage:支持背景图同时滑动的ViewPager。感受地址 GitHub pinned-section-listview: 类似Google联系人里的分类列表效果，通过关键字设置不同的分类。GitHub 感受地址 DraggablePanel：实现类似Youtube的拖拽缩小，滑动删除效果。GitHub 另一个 原文地址 查看效果图（图片较大） Progress-Button: 支持Progress-bar的Button。GitHub 体验地址 GoogleStyle-Datatime-Picker：做的很精致的Google风格的时间选择器。 Play GitHub Caldroid：另一个很棒的Android-Calendar。GitHub 有一个很棒的Date Time Number Picker。 GitHub Android-CircleButton：Android圆形按钮。 GitHub FreeFlow: 支持多种展示方式的布局方法。GitHub AsymmetricGridView： 另一个类似FreeFlow的很酷的布局库。GitHub Apk Demo JazzViewPager：提供多种ViewPager的过场动画。 GitHub Photo-Process：Android下给照片加各种滤镜。GitHub Apk Demo\nAndroid-UndoBar: 类似Google Gmail中的Undo bar实现。GitHub 另一个 ScrollBarPanelWithClock：类Path侧边滚动条时钟效果。 感受地址 activity-animation:一个库，收集Activity animation 动画 GitHub Apk体验 shake-detector: android晃动检测。GitHub parallaxlistview：这种视差效果最早是由Path引入的，优美的效果一下抓住了用户的眼球，无聊的时候就会拽啊拽的，Android下也有一个仿Path的第三方库： GitHub Apk体验 poppyview: 提供类似Google Plus和Chrome上的下滑浮出View效果。GitHub APK体验地址\n** 三、工具类库：** ** **首先，就我个人开发经验，总结一下平常用到的一些最常用的功能： 必不可少的调试功能 下载，比如图片，文件。 将下载的文件进行解压。 请求服务器，比如说上传登陆信息，更新某些数据，又或者上传头像文件。 从文件系统中选择要操作的文件（图片，拍照，视频，拍摄视频）。 有时候也需要爬取某些网页数据。 存储一些配置信息 播放视频 再有一个特殊需求就是关乎Android程序UI设计，图标是个很麻烦的问题。每次都难以找到合适的Android 设计UI。 随后，我将很有针对性的推荐一些功能库，来简化上面的问题。\nDebugLog：更加机智的调试功能，能够友好的显示调试信息所在类和函数。GitHub afinal： afinal是一个很方便的工具库。GitHub 作者博客（注：国人项目哟） 一行代码就可以对数据库进行增删改查。 完全注解方式就可以进行UI绑定和事件绑定。无需findViewById和setClickListener等。 轻松实现Android上传文件，POST数据，下载文件（支持断点续传，随时停止下载任务 或者 开始任务）。 一行代码加载网络图片。 android-async-http: Android下的异步HTTP库。GitHub 文档 PS：作者的GitHub值得关注。 发送异步http请求，并且可在回调函数中处理返回响应Response。 http请求在thread线程，不会阻塞UI线程。 请求使用线程池（ThreadPool）实现，优化了并发的资源使用。 支持Multipart 文件上传。 如果Request请求失败，会自动请求。 支持Json解码。 支持存储Cookies到Preference中。 支持gzip处理Request以及Response。 整个库只有19KB。 http-requests: Java http请求库，设计的很优雅的一个库，推荐。 GitHub async-http-client: Android下的异步 Http 和 WebSocket 库。 GitHub 支持代理设置 支持分片儿处理请求返回内容 支持WebSocket zt-zip: 压缩和解压库。 GitHub 压缩和解压 单独操作文件压缩和解压。 替换zip文件中的某个文件 jarchivelib: 另一个zip的压缩解压库。 GitHub aFileChooser：文件选择器,用于选择需要操作的文件 GitHub image-chooser-library: 图片和视频的选择库。 GitHub Demo jsoup: HTML解析，并且能很好理解DOM，CSS，以及JQuery。GitHub 官方 PS：这是java库。做网页爬虫（Crawler,Robot）必备。 toml:这是个跨语言的配置信息存取方案。GitHub Androiton-Action-Bar-Icons:一个针对Android 优化过的ICON图标集。 GitHub Demo 推荐一个Android整体框架：ThinkAndroid 集成了ioc，orm，下载，缓存等模块，能让开发更加快速和高效，同时还是国人项目。GitHub 如果你想要更快的网络传输和加载速度可以试试OKHTTP，他实现了Google开发的SPDY协议，通过复用一个Socket，缩短网络加载时间。关于SPDY看这里 OKHTTP Android-ProgressFragment:等待数据的时候，支持显示等待符号的Fragment控件。GitHub 关于播放视频，不要再去研究什么FFMPEG了，too slow，国人有个非常非常出色的开源项目叫Vitamio，让你播放视频简单如abc。GitHub 官方网站 AndroidCommon:Android常用的一些库和功能，如缓存，下拉列表，下载管理，静默安装等。感谢Trinea GitHub ion: 让Android的网络操作变得极其简单，支持异步获取和处理JSON，支持Android文件下载（同时支持下载进度条绑定），支持安全链接和代理。超级推荐！ GitHub IcePick: onSaveInstance的辅助类，用于快速恢复Activity状态。GitHub 四、图标资源： - [http://iconsparadise.com/](http://iconsparadise.com/) 质量一般，但也是一种选择 - [http://iconbench.com/](http://iconbench.com/) 在线产生一些小图标 - [http://www.androidicons.com/](http://www.androidicons.com/) 图标质量很不错，但是要付费($25刀)，如果有想合买的可以联系我~ - [https://code.google.com/p/android-ui-utils/](http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html) 用来在线生成符合Android Design风格的设计图标。 [项目地址](https://code.google.com/p/android-ui-utils/) - [http://www.flaticon.com/](http://www.flaticon.com/) 高质量矢量图，推荐之~ - [http://subtlepatterns.com/](http://subtlepatterns.com/) 背景素材集合 - [Android-Iconify](https://github.com/JoanZapata/android-iconify):一个将AweomeICON和Android结合起来的项目，推荐。 - [IonIconView](https://github.com/MarsVard/IonIconView)：Android下的一个基于AwesomeICON的图标组件，力荐~ ![](http://daimajia-wordpress.b0.upaiyun.com/image/2014/02/33d8963a58c739a73f7104efc9f182cf.jpg) 五、一些手册 - [Android图形界面设计手册](http://petrnohejl.github.io/Android-Cheatsheet-For-Graphic-Designers/#google-play-asset-dimensions)，可以用来快速查看图标的大小、ActionBar的Height等琐碎的[Android Design](http://developer.android.com/design/index.html)要求。[GitHub](https://github.com/petrnohejl/Android-Cheatsheet-For-Graphic-Designers) - Android 官方UI设计手册：[下载](http://s.yunio.com/Ea8jMb) 另：中文翻译版本 [源地址](http://adchs.sourceforge.net/index.html) （需要梯子） [镜像1](http://www.apkbus.com/design/)、[镜像2](http://www.freemindworld.com/adchs/)、[镜像3](http://www.topfun.us/adchs/)[离线版本打包](http://s.yunio.com/d6_LFg) 项目发起人：[SunJW](http://www.sunjw.us/) （需要梯子） ## 七、一些视频（以下均为Google 2013 I/O大会的现场视频，视频较多持续更新中…） - [Android Studio](http://developer.android.com/sdk/installing/studio.html) 的新特性官方讲解视频，我在官方技术博客上下载下来，上传到网盘，希望对大家有帮助。[下载地址](http://s.yunio.com/HpQzSd) - Android引入Gradle的官方讲解视频 [下载地址](http://s.yunio.com/vAm6Xr)。 - Google 2013 IO大会上抽出40多分钟时间讲解了Android Custom View的底层原理和书写方法。非常值得一看！[下载地址](http://s.yunio.com/RNbsMr)。 - IO大会上还讲解了高性能Android RenderScript的原理和使用方法，搞图形图像必备良品。[下载地址](http://s.yunio.com/soOFec) - 大会上还向开发者讲解了如何实现简洁、快速的网络请求。包括常用的JSON、AsyncTask，还提出了一种网络负荷较重情况下的解决方案RequestQueue（请求队列），提升自己技术必备视频。[下载地址](http://s.yunio.com/4peski) - Android 蓝牙 操作最佳实践。[下载地址](http://s.yunio.com/c433jq) - Android ui 设计官方指南 [下载地址](http://s.yunio.com/j0xgSn) - Android游戏开发 官方讲解视频 [下载地址](http://s.yunio.com/v6xk0z) ## 八、高价值链接 - [Android官方博客](http://officialandroid.blogspot.com/) 提供一些跟Android相关的即时咨询。（需要梯子） - [Android官方技术博客](http://android-developers.blogspot.com/) 主要提供一些新工具（如Android Studio），新技术（如每次更新带来新特性）的演示和讲解。（需要梯子） - [23code.com](http://www.23code.com/): 超强烈推荐，里面收集了非常多漂亮的Android开源项目。 - [StylingAndroid](http://www.stylingandroid.com/): 时常介绍Android的新特性。 - [AndroidViews](http://www.androidviews.net/) Android View组件收集站点。 - [那两年炼就的Android内功修养](http://blog.csdn.net/luoshengyang/article/details/8923485) (这是一篇Android入门到提高的文章，内容很全面，而且由浅入深，强烈推荐，来自老罗的Android之旅) - [Android-er](http://android-er.blogspot.com/) :专注Android好多年的一个老外的Blog。（需要梯子） - [Android-Pattern](http://www.androidpatterns.com/):Android的一些设计模式。 - [Android-Nicetices](http://androidniceties.tumblr.com/):博客收录了很多优秀的Android设计样式。 - [Android-Newbie](http://xjaphx.wordpress.com/learning/tutorials/): 收录了Android图像处理相关的教程。 - [MooDroid](http://moodroid.com/): 我创办的另一个关于Android 开源库的分享站点。 - [Chris Banes](http://chris.banes.me/): 很酷！ ## 九、集成其他开发特性(懒人专用) - ORM： Object-relationship mapping，如果你不知道什么是ORM设计，[Google](https://www.google.com.hk/search?q=ORM\u0026amp;oq=ORM\u0026amp;aqs=chrome.0.57j60l4j62.386j0\u0026amp;sourceid=chrome\u0026amp;ie=UTF-8)。 目前Android上主要有三个ORM开源库。[greenDAO](http://greendao-orm.com/)、[OrmLite](http://ormlite.com/)、[AndrORM](http://androrm.the-pixelpla.net/)。排序基本代表性能。[greenDao和Ormlite性能测试](http://greendao-orm.com/features/)[Ormlite和Androrm性能对比](http://www.cnblogs.com/youxilua/archive/2012/02/02/2336102.html)，主要是原理实现决定的性能差异（GreenDao采用生成数据表类文件，其他的则采用了反射…）。如果对数据库性能要求很高，那么采用greenDao，如果想图方便采用OrmLite或者AndrORM。 - ORM2: ActiveAndroid，另一个Android ORM组件，做的非常棒，推荐。[GitHub](https://github.com/pardom/ActiveAndroid) - sprinkles: 有一个ORM组件。 [GitHub](https://github.com/emilsjolander/sprinkles) - android-priority-jobqueue：Android Job队列。轻松实现后台task管理，保证代码更清晰，低耦合。[GitHub](https://github.com/path/android-priority-jobqueue) - androidquery: 简单的Android框架，让写代码变得更简单。[Google Code](https://code.google.com/p/android-query/) - Android-Templates-And-Utilities: 集合了Android开发中一些常用的工具类和模板以及一些代码片段。[GitHub](https://github.com/petrnohejl/Android-Templates-And-Utilities) - Android key value 引擎： [MooDroid](http://moodroid.com/2014/04/android-key-value-database/) ### 十、专注Android的Blog - [http://www.trinea.cn/](http://www.trinea.cn/) 关注Android性能还有一些小细节的，感谢[VilenEera](http://weibo.com/vileneera)推荐。 - [http://blog.csdn.net/jj120522](http://blog.csdn.net/jj120522) 解决很多关于Android生产环节的开发细节，感谢star的推荐。 - [https://github.com/Trinea/android-open-project](https://github.com/Trinea/android-open-project) 由Trinea收集的很多关于Android第三方特征库的Repo。 - [http://linkyan.com/](http://linkyan.com/) 就职于花瓣，专注于Android。 ## 十一、有用的Android Studio 和 Eclipse插件 - android-parcelable-intellij-plugin: 快速为类实现Parcelable接口。 [GitHub](https://github.com/mcharmas/android-parcelable-intellij-plugin) - sdk-manager-plugin: 自动下载和安装缺失的SDK和依赖库，建议所有开源项目集成，使得第三方更加容易编译。[GitHub](https://github.com/JakeWharton/sdk-manager-plugin) - android_dbinspector：开发过程中经常要看数据库的结构和数据库内容，这个第三方工具就能快速帮助你完成所有数据库校验工作。[GitHub](https://github.com/infinum/android_dbinspector) - AndroidStudioTemplate：开发过程中，帮助你快速创建一些开发模板。[GitHub](https://github.com/gabrielemariotti/AndroidStudioTemplate) ## 十二、从这些项目中学习组件的用法 - [repay-android](https://github.com/matt-allen/repay-android) : 一个和朋友之间管理账务的App，做的很精致。 - Android-GitHub: GitHub官方Android客户端（感谢[Liu Chong](https://plus.google.com/104187829302882941869)推荐），用到了以下几个项目： - [ActionBarSherlock](https://github.com/JakeWharton/ActionBarSherlock) - [ViewPagerIndicator](https://github.com/JakeWharton/Android-ViewPagerIndicator) - [RoboGuice](https://github.com/roboguice/roboguice) - [android-maven-plugin](https://github.com/jayway/maven-android-plugin) - [CodeMirror](https://github.com/marijnh/CodeMirror) 转自：http://blog.daimajia.com/android-library-collection/ ","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E6%BA%90%E5%BA%93/","summary":"\u003cp\u003e在摸索过程中，GitHub上搜集了很多很棒的Android第三方库，推荐给在苦苦寻找的开发者，而且我会\u003cstrong\u003e不定期的更新\u003c/strong\u003e这篇文章。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eAndroid下的优秀开发库数不胜数，在本文中，我列举的多是开发流程中最常用的一些。如果你还想了解更多的Android开源库，可以查看\u003ca href=\"https://github.com/daimajia\"\u003e我的GitHub\u003c/a\u003e Star，过滤Java选项，每一个库都是我认真查看或者编译运行的，希望对你产生帮助。\u003c/p\u003e\n\u003ch1 id=\"一兼容类库\"\u003e一、兼容类库\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003eActionBarSherlock : Action Bar是Android 3.0后才开始支持的，ActionBarSherlock是让Action Bar功能支持2.X后的所有平台，而且他会自动的判断是调用原生Action Bar还是使用扩展ActionBar。在我的小熊词典里有用到这个库，而且很多非常知名的App也在使用这个库。\u003ca href=\"https://github.com/JakeWharton/ActionBarSherlock\"\u003eGitHub\u003c/a\u003e \u003ca href=\"http://actionbarsherlock.com/\"\u003eOfficial\u003c/a\u003e \u003ca href=\"http://developer.android.com/guide/topics/ui/actionbar.html\"\u003eActionBar科普\u003c/a\u003e 最新消息（2013年7月）：Android官方发布的的Support \u003ca href=\"http://developer.android.com/tools/support-library/index.html\"\u003eLibrary Revision 18\u003c/a\u003e 开始支持\u003ca href=\"http://developer.android.com/guide/topics/ui/actionbar.html\"\u003eActionBar\u003c/a\u003e的兼容。所以可以不用再使用ActionBarSherlock了。\u003c/li\u003e\n\u003cli\u003eAndroid-ViewPagerIndicator : 这是与ViewPager兼容的一个分页指示器库。分页指示器（Friends 和 Suggested就是分页，而下面蓝色的小条就是指示器，ViewPagerIndicator支持多种样式的指示器。）：\u003ca href=\"https://github.com/JakeWharton/Android-ViewPagerIndicator\"\u003eGitHub\u003cimg loading=\"lazy\" src=\"http://daimajia-wordpress.b0.upaiyun.com/image/2014/02/a187a8d1e48539c0fa9c32a2fa889c9a.jpg\"\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eNineOldAndroids  : NineOldAndroids 将 \u003ca href=\"http://developer.android.com/about/versions/android-3.0.html\"\u003eHoneycomb (Android 3.0) 的动画 API\u003c/a\u003e扩展到了Android 1.0以上。这个库的作者即是ActionBarSherlock的作者，也是Android-ViewPagerIndicator的作者，\u003cem\u003e\u003cstrong\u003e\u003ca href=\"https://github.com/JakeWharton\"\u003eJake Wharton\u003c/a\u003e，\u003c/strong\u003e 非常厉害的一个人，Github关注量超过\u003cstrong\u003e1.6K\u003c/strong\u003e，如果你也做Android开发或者即将开始学习Android开发，一定要去Follow他，而且留意一下他每次的star和follow信息，经常会有很惊奇的发现。\u003ca href=\"https://github.com/JakeWharton\"\u003e\u003cimg alt=\"Jake Wharton\" loading=\"lazy\" src=\"https://gravatar1.233.wiki/avatar/e68309f117985270285ade8082f4877d?s=420\u0026d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png\"\u003e\u003c/a\u003e\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003eHoloEverywhere：在Android 4.0时，Google引入了新的主题风格—\u003ca href=\"http://developer.android.com/design/style/themes.html\"\u003eHolo\u003c/a\u003e，多数厂商都想统一界面设计UI，因此更加具有兼容性的Holo主题库HoloEveryWhere便成为很多开发者的选择。在Android的官方Blog中也对HoloEveryWhere这个库有所推荐，\u003ca href=\"http://android-developers.blogspot.com/2012/01/holo-everywhere.html\"\u003e点此查看\u003c/a\u003e官方博客对HoloEveryWhere的介绍。HoloEveryWhere的\u003ca href=\"https://github.com/Prototik/HoloEverywhere\"\u003eGithub\u003c/a\u003e。\u003c/li\u003e\n\u003cli\u003eAndroid-Datepicker: 兼容Android 4.0的\u003ca href=\"http://developer.android.com/guide/topics/ui/controls/pickers.html\"\u003edatepicker\u003c/a\u003e至Android 2.2。 \u003ca href=\"https://github.com/SimonVT/android-datepicker\"\u003eGitHub\u003c/a\u003e\u003cimg loading=\"lazy\" src=\"http://daimajia-wordpress.b0.upaiyun.com/image/2014/02/3582e7c62b8b04f7f04a991e41ff20e2.jpg\"\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch1 id=\"二扩展功能库\"\u003e**二、**\u003cstrong\u003e扩展功能库\u003c/strong\u003e\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eSlidingMenu : SlidingMenu 能非常容易的让开发者实现程序的抽屉效果，所谓的抽屉效果如下图所示，通常被用作呼出菜单。而且SlidingMenu能很方便的与ActionBarSherlock融合，在官方GitHub上有关于如何融合的说明。 \u003ca href=\"https://github.com/jfeinstein10/SlidingMenu\"\u003eGitHub\u003c/a\u003e  同时，想要达到相同功能也可以看另一个Drawer设计：\u003ca href=\"https://github.com/eddieringle/android-undergarment\"\u003eAndroid-Undergarment\u003c/a\u003e\u003cbr\u003e\n\u003cimg alt=\"滑动效果演示\" loading=\"lazy\" src=\"http://daimajia-wordpress.b0.upaiyun.com/image/2014/02/46d909d579eb5e721a9af8363d130e65.gif\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eAppMsg : 优雅的弹出类似Toast的消息提示，支持3种状态Alert,Confirm以及Info。\u003ca href=\"https://github.com/johnkil/Android-AppMsg\"\u003eGitHub\u003c/a\u003e\u003cimg loading=\"lazy\" src=\"http://daimajia-wordpress.b0.upaiyun.com/image/2014/02/071c3c8185f64bd41257815a0f8faa23.jpg\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eDrag-Sort-ListView : 很多人都用过在一个ListView中通过拖拽对已有的数据进行排序操作。Drag-Sort-Listview就是实现这一功能的开源库。\u003ca href=\"https://github.com/bauerca/drag-sort-listview\"\u003eGitHub\u003c/a\u003e\u003cimg loading=\"lazy\" src=\"http://daimajia-wordpress.b0.upaiyun.com/image/2014/02/d06bd800111000a3f484c72862972e94.jpg\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eAndroid-Flip : 轻松实现类似FlipBoard的翻页功能。 \u003ca href=\"https://github.com/openaphid/android-flip\"\u003eGitHub\u003c/a\u003e\u003cimg loading=\"lazy\" src=\"http://daimajia-wordpress.b0.upaiyun.com/image/2014/02/e2bb6b90fd267b206dbd6987cf310d95.jpg\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eAndroid-PullToRefresh : Android下拉刷新组件。 \u003ca href=\"https://github.com/johannilsson/android-pulltorefresh\"\u003eGitHub\u003c/a\u003e    此外，该作者还有另外一个实用度和关注量极高的项目–另一种Android ActionBar的实现：\u003ca href=\"https://github.com/johannilsson/android-actionbar\"\u003eGitHub\u003c/a\u003e  另：GitHub上另一个Android-PullToRefresh的实现。\u003ca href=\"https://github.com/chrisbanes/Android-PullToRefresh\"\u003eGitHub\u003c/a\u003e\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://daimajia-wordpress.b0.upaiyun.com/image/2014/02/0d3925aab4f83ecee6cf7ac137de608f.jpg\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eActionBar-PullToRefresh： 基于ActionBar的下拉刷新组件，在下拉的时候会替换掉ActionBar，显示更新中… \u003ca href=\"https://github.com/chrisbanes/ActionBar-PullToRefresh\"\u003eGitHub\u003c/a\u003e \u003ca href=\"http://d.pr/f/xU5c\"\u003eDemo下载\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003epicasso:  程序中经常面临加载网络图片的情况，成熟做法：异步下载-\u0026gt;缓存-\u0026gt;显示，Picasso一行代码就可这三步轻松完成。\u003ca href=\"https://github.com/square/picasso\"\u003eGitHub\u003c/a\u003e \u003ca href=\"http://square.github.io/picasso/\"\u003eGitHubPage\u003c/a\u003e ，GitHub上图片异步加载缓存类库很多，你也可尝试使用\u003ca href=\"https://github.com/nostra13/Android-Universal-Image-Loader\"\u003eAndroid-Universal-Image-Loader\u003c/a\u003e 或者 \u003ca href=\"https://github.com/thest1/LazyList\"\u003eLazyList\u003c/a\u003e 后面将介绍到的afinal(国人项目)也具有此功能。\u003cimg loading=\"lazy\" src=\"http://daimajia-wordpress.b0.upaiyun.com/image/2014/02/d73a611aae657fc21a7d1e42947a90df.jpg\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eCard-UI: Google很早之前开始在自家的App内使用卡片式布局，CardUI极其美观大方，想要在自己的App中集成卡片UI布局，那么就轻松地用这个项目吧。\u003ca href=\"https://github.com/afollestad/Cards-UI\"\u003eGitHub\u003c/a\u003e 或者你也可以使用这个库来完成卡片布局。\u003ca href=\"https://github.com/gabrielemariotti/cardslib\"\u003eCardLib\u003c/a\u003e 另一个卡片式布局: \u003ca href=\"https://github.com/nadavfima/cardsui-for-android\"\u003eGitHub\u003c/a\u003e\u003cimg loading=\"lazy\" src=\"http://daimajia-wordpress.b0.upaiyun.com/image/2014/02/534c360905c4aa0ec71e528d55628ca0.jpg\"\u003e\u003c/p\u003e","title":"Android开源库"},{"content":" **adb** shell /system/bin/screencap -p /sdcard/screenshot.png（保存到SDCard） **adb** pull /sdcard/screenshot.png d:/screenshot.png（保存到电脑） \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; `$ adb shell screencap -p /sdcard/screen.png\u0026amp;lt;br /\u0026gt; $ adb pull /sdcard/screen.png\u0026lt;br /\u0026gt; $ adb shell rm /sdcard/screen.png` \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ## [](https://github.com/bxiaopeng/wirelessqa/blob/master/Android/AndroidTest/Android%E6%88%AA%E5%9B%BE%E5%91%BD%E4%BB%A4screencap.md#%E6%88%AA%E5%9B%BE%E7%9B%B4%E6%8E%A5%E4%BF%9D%E5%AD%98%E5%88%B0%E7%94%B5%E8%84%91)截图直接保存到电脑 \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; `$ adb shell screencap -p | sed 's/\\r$//' \u0026amp;gt; screen.png` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 上一个命令没有成功（mac下） \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 下面这个命令成功了 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; `adb shell screencap -p | perl -pe 's/\\x0D\\x0A/\\x0A/g' \u0026amp;gt; screen.png` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 执行adb shell 将\\n转换\\r\\n, 因此需要用sed删除多余的\\r \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ## [](https://github.com/bxiaopeng/wirelessqa/blob/master/Android/AndroidTest/Android%E6%88%AA%E5%9B%BE%E5%91%BD%E4%BB%A4screencap.md#%E5%A6%82%E6%9E%9C%E7%9B%B4%E6%8E%A5%E5%BD%93%E5%91%BD%E4%BB%A4%E7%94%A8%E8%BF%98%E5%8F%AF%E4%BB%A5%E7%94%A8-alias-%E5%8C%85%E8%A3%9D%E8%A3%85%E8%B5%B7%E4%BE%86)如果直接当命令用还可以用 alias 包裝装起來： ``` $ alias and-screencap=\u0026quot;adb shell screencap -p | sed 's/\\r$//'\u0026quot; $ and-screencap \u0026amp;gt; screen.png \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; 以后就可以方便的用and-screencap \u0026gt; 直接将截图保存到电脑上了 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 在android代码中使用adb命令来截屏 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 直接在PC上cmd下可调用adb shell screencap -p /sdcard/screenshot.png来截屏，截取到的内容将包括在线视频等原本需要单独处理的内容。 使用过在ondraw()里面获取cache或者view来截取屏幕，但那样无法获取在线视频内容，但是通过在PC上调用adb命令，可以截取屏幕，因此想到在android代码中运行cmd里面的命令行，将图片保存起来即可。 下面的只是初步代码，适用于有root权限的机器（暂时没有时间尝试在没有root权限的情况调用，有兴趣的可以自己尝试） \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; 这段代码的缺陷在于无法获知什么时候截取完毕屏幕的内容、什么时候保存，因此，我的做法是延时2s去读取指定文件夹下的这个文件。如果有知道解决的，请在后面回复中贴出，让大家一起进步 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; public static void savecreen(Activity ac, String name) { \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; String cmd=\u0026amp;#8221;screencap -p /sdcard/\u0026amp;#8221;+name+\u0026amp;#8221;.png\u0026amp;#8221;; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; try { \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; // 权限设置 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; Process p = Runtime.getRuntime().exec(\u0026amp;#8220;su\u0026amp;#8221;); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; // 获取输出流 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; OutputStream outputStream = p.getOutputStream(); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; DataOutputStream dataOutputStream = new DataOutputStream( \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; outputStream); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; // 将命令写入 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; dataOutputStream.writeBytes(cmd); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; // 提交命令 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; dataOutputStream.flush(); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; // 关闭流操作 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; dataOutputStream.close(); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; outputStream.close(); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; } catch (Throwable t) { \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; t.printStackTrace(); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; } \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android%E4%BB%A3%E7%A0%81%E8%BF%90%E8%A1%8Ccmd%E5%91%BD%E4%BB%A4%E6%88%AA%E5%B1%8F/","summary":"\u003cdiv\u003e\n  \u003cdiv\u003e\n    \u003cdiv\u003e\n      \u003cdiv\u003e\n        **adb** shell /system/bin/screencap -p /sdcard/screenshot.png（保存到SDCard）\n **adb** pull /sdcard/screenshot.png d:/screenshot.png（保存到电脑）\n      \u003c/div\u003e\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  \u0026lt;div\u0026gt;\n    `$ adb shell screencap -p /sdcard/screen.png\u0026amp;lt;br /\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e$ adb pull /sdcard/screen.png\u0026lt;br /\u0026gt;\n$ adb shell rm /sdcard/screen.png`\n\u003c/div\u003e\n\u003c/div\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  ## [](https://github.com/bxiaopeng/wirelessqa/blob/master/Android/AndroidTest/Android%E6%88%AA%E5%9B%BE%E5%91%BD%E4%BB%A4screencap.md#%E6%88%AA%E5%9B%BE%E7%9B%B4%E6%8E%A5%E4%BF%9D%E5%AD%98%E5%88%B0%E7%94%B5%E8%84%91)截图直接保存到电脑\n  \n  \u0026lt;div\u0026gt;\n    \u0026lt;div\u0026gt;\n      `$ adb shell screencap -p | sed 's/\\r$//' \u0026amp;gt; screen.png`\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  上一个命令没有成功（mac下）\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  下面这个命令成功了\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  \u0026lt;div\u0026gt;\n    `adb shell screencap -p | perl -pe 's/\\x0D\\x0A/\\x0A/g' \u0026amp;gt; screen.png`\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  执行adb shell 将\\n转换\\r\\n, 因此需要用sed删除多余的\\r\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  ## [](https://github.com/bxiaopeng/wirelessqa/blob/master/Android/AndroidTest/Android%E6%88%AA%E5%9B%BE%E5%91%BD%E4%BB%A4screencap.md#%E5%A6%82%E6%9E%9C%E7%9B%B4%E6%8E%A5%E5%BD%93%E5%91%BD%E4%BB%A4%E7%94%A8%E8%BF%98%E5%8F%AF%E4%BB%A5%E7%94%A8-alias-%E5%8C%85%E8%A3%9D%E8%A3%85%E8%B5%B7%E4%BE%86)如果直接当命令用还可以用 alias 包裝装起來：\n  \n  ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003e$ alias and-screencap=\u0026quot;adb shell screencap -p | sed 's/\\r$//'\u0026quot; $ and-screencap \u0026amp;gt; screen.png  \u003c/code\u003e\u003c/p\u003e","title":"android代码运行cmd命令截屏"},{"content":" # 高斯模糊 - 高斯模糊就是将指定像素变换为其与周边像素加权平均后的值，权重就是高斯分布函数计算出来的值。 一种实现 [点击打开链接](http://my.oschina.net/tonywolf/blog/64896)\u0026lt;-这里是一片关于高斯模糊算法的介绍，我们需要首先根据高斯分布函数计算权重值，为了提高效率我们采用一维高斯分布函数，然后处理图像的时候在横向和纵向进行两次计算得到结果。下面是一种实现 \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/xu_fu/article/details/23131241#)[copy](http://blog.csdn.net/xu_fu/article/details/23131241#)[print](http://blog.csdn.net/xu_fu/article/details/23131241#)[?](http://blog.csdn.net/xu_fu/article/details/23131241#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; gaussBlur(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] data, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; radius, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; sigma) { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; pa = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; / (Math.sqrt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; * Math.PI) * sigma)); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; pb = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f / (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; * sigma * sigma); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// generate the Gauss Matrix\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] gaussMatrix = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[radius * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; gaussSum = 0f; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, x = -radius; x \u0026lt;= radius; ++x, ++i) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; g = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) (pa * Math.exp(pb * x * x)); - gaussMatrix[i] = g; - gaussSum += g; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, length = gaussMatrix.length; i \u0026lt; length; ++i) { - gaussMatrix[i] /= gaussSum; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// x direction\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; y \u0026lt; height; ++y) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; x \u0026lt; width; ++x) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; r = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, g = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, b = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - gaussSum = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; j = -radius; j \u0026lt;= radius; ++j) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; k = x + j; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (k \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; k \u0026lt; width) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; index = y * width + k; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; color = data[index]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cr = (color \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x00ff0000\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cg = (color \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x0000ff00\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cb = (color \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x000000ff\u0026lt;/span\u0026gt;); - - r += cr * gaussMatrix[j + radius]; - g += cg * gaussMatrix[j + radius]; - b += cb * gaussMatrix[j + radius]; - - gaussSum += gaussMatrix[j + radius]; - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; index = y * width + x; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cr = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (r / gaussSum); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cg = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (g / gaussSum); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cb = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (b / gaussSum); - - data[index] = cr \u0026lt;\u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt; | cg \u0026lt;\u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; | cb | \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xff000000\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// y direction\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; x \u0026lt; width; ++x) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; y \u0026lt; height; ++y) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; r = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, g = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, b = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - gaussSum = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; j = -radius; j \u0026lt;= radius; ++j) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; k = y + j; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (k \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; k \u0026lt; height) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; index = k * width + x; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; color = data[index]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cr = (color \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x00ff0000\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cg = (color \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x0000ff00\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cb = (color \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x000000ff\u0026lt;/span\u0026gt;); - - r += cr * gaussMatrix[j + radius]; - g += cg * gaussMatrix[j + radius]; - b += cb * gaussMatrix[j + radius]; - - gaussSum += gaussMatrix[j + radius]; - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; index = y * width + x; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cr = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (r / gaussSum); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cg = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (g / gaussSum); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cb = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (b / gaussSum); - data[index] = cr \u0026lt;\u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt; | cg \u0026lt;\u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; | cb | \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xff000000\u0026lt;/span\u0026gt;; - } - } - } \u0026lt;/div\u0026gt; 实际测试会发现这种计算方式是很耗时间的，而且模糊半径越大，从原理也可以看到计算量是平方增长的，所以计算时间也越长。 ## \u0026lt;a name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;RenderScript RenderScript是Android在API 11之后加入的，用于高效的图片处理，包括模糊、混合、矩阵卷积计算等，代码示例如下 \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/xu_fu/article/details/23131241#)[copy](http://blog.csdn.net/xu_fu/article/details/23131241#)[print](http://blog.csdn.net/xu_fu/article/details/23131241#)[?](http://blog.csdn.net/xu_fu/article/details/23131241#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Bitmap blurBitmap(Bitmap bitmap){ - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Let\u0026amp;#8217;s create an empty bitmap with the same size of the bitmap we want to blur\u0026lt;/span\u0026gt; - Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Instantiate a new Renderscript\u0026lt;/span\u0026gt; - RenderScript rs = RenderScript.create(getApplicationContext()); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Create an Intrinsic Blur Script using the Renderscript\u0026lt;/span\u0026gt; - ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Create the Allocations (in/out) with the Renderscript and the in/out bitmaps\u0026lt;/span\u0026gt; - Allocation allIn = Allocation.createFromBitmap(rs, bitmap); - Allocation allOut = Allocation.createFromBitmap(rs, outBitmap); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Set the radius of the blur\u0026lt;/span\u0026gt; - blurScript.setRadius(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;25\u0026lt;/span\u0026gt;.f); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Perform the Renderscript\u0026lt;/span\u0026gt; - blurScript.setInput(allIn); - blurScript.forEach(allOut); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Copy the final bitmap created by the out Allocation to the outBitmap\u0026lt;/span\u0026gt; - allOut.copyTo(outBitmap); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//recycle the original bitmap\u0026lt;/span\u0026gt; - bitmap.recycle(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//After finishing everything, we destroy the Renderscript.\u0026lt;/span\u0026gt; - rs.destroy(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; outBitmap; - - - } \u0026lt;/div\u0026gt; （示例来源 [https://gist.github.com/Mariuxtheone/903c35b4927c0df18cf8](https://gist.github.com/Mariuxtheone/903c35b4927c0df18cf8)） ## \u0026lt;a name=\u0026quot;t3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;FastBlur \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/xu_fu/article/details/23131241#)[copy](http://blog.csdn.net/xu_fu/article/details/23131241#)[print](http://blog.csdn.net/xu_fu/article/details/23131241#)[?](http://blog.csdn.net/xu_fu/article/details/23131241#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; FastBlur { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; Bitmap doBlur(Bitmap sentBitmap, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; radius, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canReuseInBitmap) { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Stack Blur v1.0 from\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Java Author: Mario Klingemann \u0026lt;mario at quasimondo.com\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// http://incubator.quasimondo.com\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// created Feburary 29, 2004\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Android port : Yahel Bouaziz \u0026lt;yahel at kayenko.com\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// http://www.kayenko.com\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// ported april 5th, 2012\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// This is a compromise between Gaussian Blur and Box blur\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// It creates much better looking blurs than Box Blur, but is\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 7x faster than my Gaussian Blur implementation.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// I called it Stack Blur because this describes best how this\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// filter works internally: it creates a kind of moving stack\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// of colors whilst scanning through the image. Thereby it\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// just has to add one new block of color to the right side\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// of the stack and remove the leftmost color. The remaining\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// colors on the topmost layer of the stack are either added on\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// or reduced by one, depending on if they are on the right or\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// on the left side of the stack.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// If you are using this algorithm in your code please add\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// the following line:\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Stack Blur Algorithm by Mario Klingemann \u0026lt;mario@quasimondo.com\u0026gt;\u0026lt;/span\u0026gt; - - Bitmap bitmap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (canReuseInBitmap) { - bitmap = sentBitmap; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - bitmap = sentBitmap.copy(sentBitmap.getConfig(), \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (radius \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; w = bitmap.getWidth(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; h = bitmap.getHeight(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] pix = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[w * h]; - bitmap.getPixels(pix, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, w, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, w, h); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; wm = w \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; hm = h \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; wh = w * h; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; div = radius + radius + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r[] = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[wh]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; g[] = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[wh]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b[] = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[wh]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; rsum, gsum, bsum, x, y, i, p, yp, yi, yw; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; vmin[] = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[Math.max(w, h)]; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; divsum = (div + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - divsum *= divsum; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dv[] = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;256\u0026lt;/span\u0026gt; * divsum]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;256\u0026lt;/span\u0026gt; * divsum; i++) { - dv[i] = (i / divsum); - } - - yw = yi = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[][] stack = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[div][\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; stackpointer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; stackstart; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] sir; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; rbs; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r1 = radius + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; routsum, goutsum, boutsum; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; rinsum, ginsum, binsum; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (y = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; y \u0026lt; h; y++) { - rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (i = -radius; i \u0026lt;= radius; i++) { - p = pix[yi + Math.min(wm, Math.max(i, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;))]; - sir = stack[i + radius]; - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] = (p \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xff0000\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;; - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;] = (p \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x00ff00\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;] = (p \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x0000ff\u0026lt;/span\u0026gt;); - rbs = r1 \u0026amp;#8211; Math.abs(i); - rsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] * rbs; - gsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;] * rbs; - bsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;] * rbs; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (i \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - rinsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - ginsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - binsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;]; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - routsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - goutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - boutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;]; - } - } - stackpointer = radius; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (x = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; x \u0026lt; w; x++) { - - r[yi] = dv[rsum]; - g[yi] = dv[gsum]; - b[yi] = dv[bsum]; - - rsum -= routsum; - gsum -= goutsum; - bsum -= boutsum; - - stackstart = stackpointer \u0026amp;#8211; radius + div; - sir = stack[stackstart % div]; - - routsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - goutsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - boutsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;]; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (y == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - vmin[x] = Math.min(x + radius + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, wm); - } - p = pix[yw + vmin[x]]; - - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] = (p \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xff0000\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;; - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;] = (p \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x00ff00\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;] = (p \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x0000ff\u0026lt;/span\u0026gt;); - - rinsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - ginsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - binsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;]; - - rsum += rinsum; - gsum += ginsum; - bsum += binsum; - - stackpointer = (stackpointer + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) % div; - sir = stack[(stackpointer) % div]; - - routsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - goutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - boutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;]; - - rinsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - ginsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - binsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;]; - - yi++; - } - yw += w; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (x = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; x \u0026lt; w; x++) { - rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - yp = -radius * w; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (i = -radius; i \u0026lt;= radius; i++) { - yi = Math.max(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, yp) + x; - - sir = stack[i + radius]; - - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] = r[yi]; - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;] = g[yi]; - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;] = b[yi]; - - rbs = r1 \u0026amp;#8211; Math.abs(i); - - rsum += r[yi] * rbs; - gsum += g[yi] * rbs; - bsum += b[yi] * rbs; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (i \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - rinsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - ginsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - binsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;]; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - routsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - goutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - boutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;]; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (i \u0026lt; hm) { - yp += w; - } - } - yi = x; - stackpointer = radius; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (y = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; y \u0026lt; h; y++) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Preserve alpha channel: ( 0xff000000 \u0026amp; pix[yi] )\u0026lt;/span\u0026gt; - pix[yi] = (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xff000000\u0026lt;/span\u0026gt; \u0026amp; pix[yi]) | (dv[rsum] \u0026lt;\u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;) | (dv[gsum] \u0026lt;\u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;) | dv[bsum]; - - rsum -= routsum; - gsum -= goutsum; - bsum -= boutsum; - - stackstart = stackpointer \u0026amp;#8211; radius + div; - sir = stack[stackstart % div]; - - routsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - goutsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - boutsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;]; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (x == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - vmin[y] = Math.min(y + r1, hm) * w; - } - p = x + vmin[y]; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] = r[p]; - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;] = g[p]; - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;] = b[p]; - - rinsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - ginsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - binsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;]; - - rsum += rinsum; - gsum += ginsum; - bsum += binsum; - - stackpointer = (stackpointer + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) % div; - sir = stack[stackpointer]; - - routsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - goutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - boutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;]; - - rinsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - ginsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - binsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;]; - - yi += w; - } - } - - bitmap.setPixels(pix, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, w, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, w, h); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (bitmap); - } 这里的方法也可以实现高斯模糊的效果，但使用了特殊的算法，比第一种可以快很多，但比起RenderScript还是慢一些 （示例来源 [Android高级模糊技术](http://blog.jobbole.com/63894/)） 实现YAHOO天气的动态模糊效果 YAHOO天气中的背景会随着手指上滑模糊程度加深，实际使用中发现怎么都达不到那样流畅的效果，因为手势刷新的速度很快，每一帧都去重新模糊计算一遍，还是会有延迟，造成页面卡顿。后来在一次偶然的开发中发现其实不需要每一帧都重新去模糊一遍，而是将图片最大程度模糊一次，之后和原图叠加，通过改变叠加的模糊图片的alpha值来达到不同程度的模糊效果。下面是一个例子，可以看到随着模糊图片alpha值的变化，叠加后产生不同程度的模糊效果。\n随滑动变换alpha值的代码如下\n**[java]** [view plain](http://blog.csdn.net/xu_fu/article/details/23131241#)[copy](http://blog.csdn.net/xu_fu/article/details/23131241#)[print](http://blog.csdn.net/xu_fu/article/details/23131241#)[?](http://blog.csdn.net/xu_fu/article/details/23131241#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - mBlurImage.setOnTouchListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnTouchListener() { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mLastY; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (event.getAction()) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: - mLastY = event.getY(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y = event.getY(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; alphaDelt = (y \u0026amp;#8211; mLastY) / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; alpha = mBlurImage.getAlpha() + alphaDelt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (alpha \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1.0\u0026lt;/span\u0026gt;) { - alpha = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (alpha \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0.0\u0026lt;/span\u0026gt;) { - alpha = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0f; - } - mTextView.setText(String.valueOf(alpha)); - mBlurImage.setAlpha(alpha); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - }); 示例代码下载 http://download.csdn.net/detail/xu_fu/7628139\n图： 效果图： 核心自然是高斯算法，这里没有深究其中的算法实现，只是项目实现而已。 引用代码： /** 水平方向模糊度 */ private static float hRadius = 10; /** 竖直方向模糊度 / private static float vRadius = 10; /* 模糊迭代度 */ private static int iterations = 7;\n\u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_304250\u0026quot; class=\u0026quot;syntaxhighlighter nogutter java\u0026quot;\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``* 高斯模糊` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``public` `static` `Drawable BoxBlurFilter(Bitmap bmp) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``int` `width = bmp.getWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``int` `height = bmp.getHeight();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``int``[] inPixels = ``new` `int``[width * height];` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``int``[] outPixels = ``new` `int``[width * height];` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``Bitmap bitmap = Bitmap.createBitmap(width, height,Bitmap.Config.ARGB_8888);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``bmp.getPixels(inPixels, ````, width, ````, ````, width, height);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``for` `(``int` `i = ````; i \u0026amp;lt; iterations; i++) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``blur(inPixels, outPixels, width, height, hRadius);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``blur(outPixels, inPixels, height, width, vRadius);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``blurFractional(inPixels, outPixels, width, height, hRadius);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``blurFractional(outPixels, inPixels, height, width, vRadius);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``bitmap.setPixels(inPixels, ````, width, ````, ````, width, height);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``Drawable drawable = ``new` `BitmapDrawable(bitmap);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``return` `drawable;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 核心算法： `public` `static` `void` `blur(``int``[] in, ``int``[] out, ``int` `width, ``int` `height,` \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``float` `radius) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``int` `widthMinus1 = width - ``1``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``int` `r = (``int``) radius;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``int` `tableSize = ``2` `* r + ``1``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``int` `divide[] = ``new` `int``[``256` `* tableSize];` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``for` `(``int` `i = ````; i \u0026amp;lt; ``256` `* tableSize; i++)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``divide[i] = i / tableSize;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``int` `inIndex = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``for` `(``int` `y = ````; y \u0026amp;lt; height; y++) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``int` `outIndex = y;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``int` `ta = ````, tr = ````, tg = ````, tb = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``for` `(``int` `i = -r; i \u0026amp;lt;= r; i++) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``int` `rgb = in[inIndex + clamp(i, ````, width - ``1``)];` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``ta += (rgb \u0026amp;gt;\u0026amp;gt; ``24``) \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``tr += (rgb \u0026amp;gt;\u0026amp;gt; ``16``) \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``tg += (rgb \u0026amp;gt;\u0026amp;gt; ``8``) \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``tb += rgb \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``for` `(``int` `x = ````; x \u0026amp;lt; width; x++) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``out[outIndex] = (divide[ta] \u0026amp;lt;\u0026amp;lt; ``24``) | (divide[tr] \u0026amp;lt;\u0026amp;lt; ``16``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``| (divide[tg] \u0026amp;lt;\u0026amp;lt; ``8``) | divide[tb];` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``int` `i1 = x + r + ``1``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ``if` `(i1 \u0026amp;gt; widthMinus1)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``i1 = widthMinus1;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ``int` `i2 = x - r;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ``if` `(i2 \u0026amp;lt; ````)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ``i2 = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``int` `rgb1 = in[inIndex + i1];` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; ` ``int` `rgb2 = in[inIndex + i2];` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; ` ``ta += ((rgb1 \u0026amp;gt;\u0026amp;gt; ``24``) \u0026amp; ``0xff``) - ((rgb2 \u0026amp;gt;\u0026amp;gt; ``24``) \u0026amp; ``0xff``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; ` ``tr += ((rgb1 \u0026amp; ``0xff0000``) - (rgb2 \u0026amp; ``0xff0000``)) \u0026amp;gt;\u0026amp;gt; ``16``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; ` ``tg += ((rgb1 \u0026amp; ``0xff00``) - (rgb2 \u0026amp; ``0xff00``)) \u0026amp;gt;\u0026amp;gt; ``8``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; ` ``tb += (rgb1 \u0026amp; ``0xff``) - (rgb2 \u0026amp; ``0xff``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; ` ``outIndex += height;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; ` ``inIndex += width;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; ` ``public` `static` `void` `blurFractional(``int``[] in, ``int``[] out, ``int` `width,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; ` ``int` `height, ``float` `radius) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; ` ``radius -= (``int``) radius;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; ` ``float` `f = ``1``.0f / (``1` `+ ``2` `* radius);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; ` ``int` `inIndex = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; ` ``for` `(``int` `y = ````; y \u0026amp;lt; height; y++) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; ` ``int` `outIndex = y;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; ` ``out[outIndex] = in[````];` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; ` ``outIndex += height;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; ` ``for` `(``int` `x = ``1``; x \u0026amp;lt; width - ``1``; x++) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; ` ``int` `i = inIndex + x;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; ` ``int` `rgb1 = in[i - ``1``];` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; ` ``int` `rgb2 = in[i];` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; ` ``int` `rgb3 = in[i + ``1``];` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; ` ``int` `a1 = (rgb1 \u0026amp;gt;\u0026amp;gt; ``24``) \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; ` ``int` `r1 = (rgb1 \u0026amp;gt;\u0026amp;gt; ``16``) \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; ` ``int` `g1 = (rgb1 \u0026amp;gt;\u0026amp;gt; ``8``) \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; ` ``int` `b1 = rgb1 \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; ` ``int` `a2 = (rgb2 \u0026amp;gt;\u0026amp;gt; ``24``) \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; ` ``int` `r2 = (rgb2 \u0026amp;gt;\u0026amp;gt; ``16``) \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; ` ``int` `g2 = (rgb2 \u0026amp;gt;\u0026amp;gt; ``8``) \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; ` ``int` `b2 = rgb2 \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; ` ``int` `a3 = (rgb3 \u0026amp;gt;\u0026amp;gt; ``24``) \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; ` ``int` `r3 = (rgb3 \u0026amp;gt;\u0026amp;gt; ``16``) \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; ` ``int` `g3 = (rgb3 \u0026amp;gt;\u0026amp;gt; ``8``) \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; ` ``int` `b3 = rgb3 \u0026amp; ``0xff``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; ` ``a1 = a2 + (``int``) ((a1 + a3) * radius);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; ` ``r1 = r2 + (``int``) ((r1 + r3) * radius);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; ` ``g1 = g2 + (``int``) ((g1 + g3) * radius);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; ` ``b1 = b2 + (``int``) ((b1 + b3) * radius);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; ` ``a1 *= f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; ` ``r1 *= f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; ` ``g1 *= f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; ` ``b1 *= f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; ` ``out[outIndex] = (a1 \u0026amp;lt;\u0026amp;lt; ``24``) | (r1 \u0026amp;lt;\u0026amp;lt; ``16``) | (g1 \u0026amp;lt;\u0026amp;lt; ``8``) | b1;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; ` ``outIndex += height;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; ` ``out[outIndex] = in[width - ``1``];` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; ` ``inIndex += width;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt; ` ``public` `static` `int` `clamp(``int` `x, ``int` `a, ``int` `b) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt; ` ``return` `(x \u0026amp;lt; a) ? a : (x \u0026amp;gt; b) ? b : x;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android%E5%9B%BE%E7%89%87%E9%AB%98%E6%96%AF%E6%A8%A1%E7%B3%8A%E7%9A%84%E4%B8%80%E4%BA%9B%E6%96%B9%E6%B3%95/","summary":"\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    # 高斯模糊\n\u003cpre\u003e\u003ccode\u003e  - 高斯模糊就是将指定像素变换为其与周边像素加权平均后的值，权重就是高斯分布函数计算出来的值。\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"一种实现\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e一种实现\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e      [点击打开链接](http://my.oschina.net/tonywolf/blog/64896)\u0026lt;-这里是一片关于高斯模糊算法的介绍，我们需要首先根据高斯分布函数计算权重值，为了提高效率我们采用一维高斯分布函数，然后处理图像的时候在横向和纵向进行两次计算得到结果。下面是一种实现\n    \n\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n          \n\n            **[java]** [view plain](http://blog.csdn.net/xu_fu/article/details/23131241#)[copy](http://blog.csdn.net/xu_fu/article/details/23131241#)[print](http://blog.csdn.net/xu_fu/article/details/23131241#)[?](http://blog.csdn.net/xu_fu/article/details/23131241#)\n          \n\n          \n          \u0026lt;div\u0026gt;\n            \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n            \u0026lt;/embed\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; gaussBlur(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] data, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; radius,\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; sigma) {\n        \n        - \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; pa = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; / (Math.sqrt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; * Math.PI) * sigma));\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; pb = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f / (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; * sigma * sigma);\n        \n        - \n        - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// generate the Gauss Matrix\u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] gaussMatrix = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[radius * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; gaussSum = 0f;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, x = -radius; x \u0026lt;= radius; ++x, ++i) {\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; g = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) (pa * Math.exp(pb * x * x));\n        \n        - gaussMatrix[i] = g;\n        \n        - gaussSum += g;\n        \n        - }\n        \n        - \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, length = gaussMatrix.length; i \u0026lt; length; ++i) {\n        \n        - gaussMatrix[i] /= gaussSum;\n        \n        - }\n        \n        - \n        - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// x direction\u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; y \u0026lt; height; ++y) {\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; x \u0026lt; width; ++x) {\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; r = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, g = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, b = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n        \n        - gaussSum = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; j = -radius; j \u0026lt;= radius; ++j) {\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; k = x + j;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (k \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; k \u0026lt; width) {\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; index = y * width + k;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; color = data[index];\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cr = (color \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x00ff0000\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cg = (color \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x0000ff00\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cb = (color \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x000000ff\u0026lt;/span\u0026gt;);\n        \n        - \n        - r += cr * gaussMatrix[j + radius];\n        \n        - g += cg * gaussMatrix[j + radius];\n        \n        - b += cb * gaussMatrix[j + radius];\n        \n        - \n        - gaussSum += gaussMatrix[j + radius];\n        \n        - }\n        \n        - }\n        \n        - \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; index = y * width + x;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cr = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (r / gaussSum);\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cg = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (g / gaussSum);\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cb = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (b / gaussSum);\n        \n        - \n        - data[index] = cr \u0026lt;\u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt; | cg \u0026lt;\u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; | cb | \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xff000000\u0026lt;/span\u0026gt;;\n        \n        - }\n        \n        - }\n        \n        - \n        - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// y direction\u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; x \u0026lt; width; ++x) {\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; y \u0026lt; height; ++y) {\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; r = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, g = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, b = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n        \n        - gaussSum = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; j = -radius; j \u0026lt;= radius; ++j) {\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; k = y + j;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (k \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; k \u0026lt; height) {\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; index = k * width + x;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; color = data[index];\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cr = (color \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x00ff0000\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cg = (color \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x0000ff00\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cb = (color \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x000000ff\u0026lt;/span\u0026gt;);\n        \n        - \n        - r += cr * gaussMatrix[j + radius];\n        \n        - g += cg * gaussMatrix[j + radius];\n        \n        - b += cb * gaussMatrix[j + radius];\n        \n        - \n        - gaussSum += gaussMatrix[j + radius];\n        \n        - }\n        \n        - }\n        \n        - \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; index = y * width + x;\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cr = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (r / gaussSum);\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cg = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (g / gaussSum);\n        \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cb = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (b / gaussSum);\n        \n        - data[index] = cr \u0026lt;\u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt; | cg \u0026lt;\u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; | cb | \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xff000000\u0026lt;/span\u0026gt;;\n        \n        - }\n        \n        - }\n        \n        - }\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \n\n      实际测试会发现这种计算方式是很耗时间的，而且模糊半径越大，从原理也可以看到计算量是平方增长的，所以计算时间也越长。\n    \n\n    \n    ## \u0026lt;a name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;RenderScript\n    \n    \n\n      RenderScript是Android在API 11之后加入的，用于高效的图片处理，包括模糊、混合、矩阵卷积计算等，代码示例如下\n    \n\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n          \n\n            **[java]** [view plain](http://blog.csdn.net/xu_fu/article/details/23131241#)[copy](http://blog.csdn.net/xu_fu/article/details/23131241#)[print](http://blog.csdn.net/xu_fu/article/details/23131241#)[?](http://blog.csdn.net/xu_fu/article/details/23131241#)\n          \n\n          \n          \u0026lt;div\u0026gt;\n            \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n            \u0026lt;/embed\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Bitmap blurBitmap(Bitmap bitmap){\n        \n        - \n        - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Let\u0026amp;#8217;s create an empty bitmap with the same size of the bitmap we want to blur\u0026lt;/span\u0026gt;\n        \n        - Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);\n        \n        - \n        - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Instantiate a new Renderscript\u0026lt;/span\u0026gt;\n        \n        - RenderScript rs = RenderScript.create(getApplicationContext());\n        \n        - \n        - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Create an Intrinsic Blur Script using the Renderscript\u0026lt;/span\u0026gt;\n        \n        - ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));\n        \n        - \n        - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Create the Allocations (in/out) with the Renderscript and the in/out bitmaps\u0026lt;/span\u0026gt;\n        \n        - Allocation allIn = Allocation.createFromBitmap(rs, bitmap);\n        \n        - Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);\n        \n        - \n        - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Set the radius of the blur\u0026lt;/span\u0026gt;\n        \n        - blurScript.setRadius(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;25\u0026lt;/span\u0026gt;.f);\n        \n        - \n        - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Perform the Renderscript\u0026lt;/span\u0026gt;\n        \n        - blurScript.setInput(allIn);\n        \n        - blurScript.forEach(allOut);\n        \n        - \n        - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Copy the final bitmap created by the out Allocation to the outBitmap\u0026lt;/span\u0026gt;\n        \n        - allOut.copyTo(outBitmap);\n        \n        - \n        - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//recycle the original bitmap\u0026lt;/span\u0026gt;\n        \n        - bitmap.recycle();\n        \n        - \n        - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//After finishing everything, we destroy the Renderscript.\u0026lt;/span\u0026gt;\n        \n        - rs.destroy();\n        \n        - \n        - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; outBitmap;\n        \n        - \n        - \n        - }\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \n\n      （示例来源 [https://gist.github.com/Mariuxtheone/903c35b4927c0df18cf8](https://gist.github.com/Mariuxtheone/903c35b4927c0df18cf8)）\n    \n\n    \n    ## \u0026lt;a name=\u0026quot;t3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;FastBlur\n    \n    \u0026lt;div\u0026gt;\n      \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n          \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt;\n            \n\n              **[java]** [view plain](http://blog.csdn.net/xu_fu/article/details/23131241#)[copy](http://blog.csdn.net/xu_fu/article/details/23131241#)[print](http://blog.csdn.net/xu_fu/article/details/23131241#)[?](http://blog.csdn.net/xu_fu/article/details/23131241#)\n            \n\n            \n            \u0026lt;div\u0026gt;\n              \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt;\n              \u0026lt;/embed\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; FastBlur {\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; Bitmap doBlur(Bitmap sentBitmap, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; radius, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canReuseInBitmap) {\n          \n          - \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Stack Blur v1.0 from\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Java Author: Mario Klingemann \u0026lt;mario at quasimondo.com\u0026gt;\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// http://incubator.quasimondo.com\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// created Feburary 29, 2004\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Android port : Yahel Bouaziz \u0026lt;yahel at kayenko.com\u0026gt;\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// http://www.kayenko.com\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// ported april 5th, 2012\u0026lt;/span\u0026gt;\n          \n          - \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// This is a compromise between Gaussian Blur and Box blur\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// It creates much better looking blurs than Box Blur, but is\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 7x faster than my Gaussian Blur implementation.\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// I called it Stack Blur because this describes best how this\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// filter works internally: it creates a kind of moving stack\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// of colors whilst scanning through the image. Thereby it\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// just has to add one new block of color to the right side\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// of the stack and remove the leftmost color. The remaining\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// colors on the topmost layer of the stack are either added on\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// or reduced by one, depending on if they are on the right or\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// on the left side of the stack.\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// If you are using this algorithm in your code please add\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// the following line:\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Stack Blur Algorithm by Mario Klingemann \u0026lt;mario@quasimondo.com\u0026gt;\u0026lt;/span\u0026gt;\n          \n          - \n          - Bitmap bitmap;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (canReuseInBitmap) {\n          \n          - bitmap = sentBitmap;\n          \n          - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n          \n          - bitmap = sentBitmap.copy(sentBitmap.getConfig(), \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n          \n          - }\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (radius \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) {\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;);\n          \n          - }\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; w = bitmap.getWidth();\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; h = bitmap.getHeight();\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] pix = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[w * h];\n          \n          - bitmap.getPixels(pix, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, w, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, w, h);\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; wm = w \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; hm = h \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; wh = w * h;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; div = radius + radius + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r[] = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[wh];\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; g[] = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[wh];\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b[] = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[wh];\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; rsum, gsum, bsum, x, y, i, p, yp, yi, yw;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; vmin[] = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[Math.max(w, h)];\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; divsum = (div + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n          \n          - divsum *= divsum;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dv[] = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;256\u0026lt;/span\u0026gt; * divsum];\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;256\u0026lt;/span\u0026gt; * divsum; i++) {\n          \n          - dv[i] = (i / divsum);\n          \n          - }\n          \n          - \n          - yw = yi = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[][] stack = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[div][\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;];\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; stackpointer;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; stackstart;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] sir;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; rbs;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r1 = radius + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; routsum, goutsum, boutsum;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; rinsum, ginsum, binsum;\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (y = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; y \u0026lt; h; y++) {\n          \n          - rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (i = -radius; i \u0026lt;= radius; i++) {\n          \n          - p = pix[yi + Math.min(wm, Math.max(i, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;))];\n          \n          - sir = stack[i + radius];\n          \n          - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] = (p \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xff0000\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;;\n          \n          - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;] = (p \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x00ff00\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;;\n          \n          - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;] = (p \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x0000ff\u0026lt;/span\u0026gt;);\n          \n          - rbs = r1 \u0026amp;#8211; Math.abs(i);\n          \n          - rsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] * rbs;\n          \n          - gsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;] * rbs;\n          \n          - bsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;] * rbs;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (i \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {\n          \n          - rinsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];\n          \n          - ginsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n          \n          - binsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;];\n          \n          - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n          \n          - routsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];\n          \n          - goutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n          \n          - boutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;];\n          \n          - }\n          \n          - }\n          \n          - stackpointer = radius;\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (x = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; x \u0026lt; w; x++) {\n          \n          - \n          - r[yi] = dv[rsum];\n          \n          - g[yi] = dv[gsum];\n          \n          - b[yi] = dv[bsum];\n          \n          - \n          - rsum -= routsum;\n          \n          - gsum -= goutsum;\n          \n          - bsum -= boutsum;\n          \n          - \n          - stackstart = stackpointer \u0026amp;#8211; radius + div;\n          \n          - sir = stack[stackstart % div];\n          \n          - \n          - routsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];\n          \n          - goutsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n          \n          - boutsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;];\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (y == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {\n          \n          - vmin[x] = Math.min(x + radius + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, wm);\n          \n          - }\n          \n          - p = pix[yw + vmin[x]];\n          \n          - \n          - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] = (p \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xff0000\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;;\n          \n          - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;] = (p \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x00ff00\u0026lt;/span\u0026gt;) \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;;\n          \n          - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;] = (p \u0026amp; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x0000ff\u0026lt;/span\u0026gt;);\n          \n          - \n          - rinsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];\n          \n          - ginsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n          \n          - binsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;];\n          \n          - \n          - rsum += rinsum;\n          \n          - gsum += ginsum;\n          \n          - bsum += binsum;\n          \n          - \n          - stackpointer = (stackpointer + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) % div;\n          \n          - sir = stack[(stackpointer) % div];\n          \n          - \n          - routsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];\n          \n          - goutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n          \n          - boutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;];\n          \n          - \n          - rinsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];\n          \n          - ginsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n          \n          - binsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;];\n          \n          - \n          - yi++;\n          \n          - }\n          \n          - yw += w;\n          \n          - }\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (x = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; x \u0026lt; w; x++) {\n          \n          - rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n          \n          - yp = -radius * w;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (i = -radius; i \u0026lt;= radius; i++) {\n          \n          - yi = Math.max(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, yp) + x;\n          \n          - \n          - sir = stack[i + radius];\n          \n          - \n          - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] = r[yi];\n          \n          - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;] = g[yi];\n          \n          - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;] = b[yi];\n          \n          - \n          - rbs = r1 \u0026amp;#8211; Math.abs(i);\n          \n          - \n          - rsum += r[yi] * rbs;\n          \n          - gsum += g[yi] * rbs;\n          \n          - bsum += b[yi] * rbs;\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (i \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {\n          \n          - rinsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];\n          \n          - ginsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n          \n          - binsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;];\n          \n          - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n          \n          - routsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];\n          \n          - goutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n          \n          - boutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;];\n          \n          - }\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (i \u0026lt; hm) {\n          \n          - yp += w;\n          \n          - }\n          \n          - }\n          \n          - yi = x;\n          \n          - stackpointer = radius;\n          \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (y = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; y \u0026lt; h; y++) {\n          \n          - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Preserve alpha channel: ( 0xff000000 \u0026amp; pix[yi] )\u0026lt;/span\u0026gt;\n          \n          - pix[yi] = (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xff000000\u0026lt;/span\u0026gt; \u0026amp; pix[yi]) | (dv[rsum] \u0026lt;\u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;) | (dv[gsum] \u0026lt;\u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;) | dv[bsum];\n          \n          - \n          - rsum -= routsum;\n          \n          - gsum -= goutsum;\n          \n          - bsum -= boutsum;\n          \n          - \n          - stackstart = stackpointer \u0026amp;#8211; radius + div;\n          \n          - sir = stack[stackstart % div];\n          \n          - \n          - routsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];\n          \n          - goutsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n          \n          - boutsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;];\n          \n          - \n          - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (x == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {\n          \n          - vmin[y] = Math.min(y + r1, hm) * w;\n          \n          - }\n          \n          - p = x + vmin[y];\n          \n        \n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \n  \n  - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] = r[p];\n  \n  - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;] = g[p];\n  \n  - sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;] = b[p];\n  \n  - \n  - rinsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];\n  \n  - ginsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n  \n  - binsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;];\n  \n  - \n  - rsum += rinsum;\n  \n  - gsum += ginsum;\n  \n  - bsum += binsum;\n  \n  - \n  - stackpointer = (stackpointer + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) % div;\n  \n  - sir = stack[stackpointer];\n  \n  - \n  - routsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];\n  \n  - goutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n  \n  - boutsum += sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;];\n  \n  - \n  - rinsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];\n  \n  - ginsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n  \n  - binsum -= sir[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;];\n  \n  - \n  - yi += w;\n  \n  - }\n  \n  - }\n  \n  - \n  - bitmap.setPixels(pix, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, w, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, w, h);\n  \n  - \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (bitmap);\n  \n  - }\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e这里的方法也可以实现高斯模糊的效果，但使用了特殊的算法，比第一种可以快很多，但比起RenderScript还是慢一些\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  （示例来源 [Android高级模糊技术](http://blog.jobbole.com/63894/)）\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch2 id=\"实现yahoo天气的动态模糊效果\"\u003e\u003ca name=\"t4\"\u003e\u003c/a\u003e实现YAHOO天气的动态模糊效果\u003c/h2\u003e\n\u003cp\u003eYAHOO天气中的背景会随着手指上滑模糊程度加深，实际使用中发现怎么都达不到那样流畅的效果，因为手势刷新的速度很快，每一帧都去重新模糊计算一遍，还是会有延迟，造成页面卡顿。后来在一次偶然的开发中发现其实不需要每一帧都重新去模糊一遍，而是将图片最大程度模糊一次，之后和原图叠加，通过改变叠加的模糊图片的alpha值来达到不同程度的模糊效果。下面是一个例子，可以看到随着模糊图片alpha值的变化，叠加后产生不同程度的模糊效果。\u003c/p\u003e","title":"Android图片高斯模糊的一些方法"},{"content":"live555是一个处理流媒体传输对c++库，再Mplayer与vlc中都有用到。我们计划将其加入到自己编写对Android上的播放器中作为流媒体模块，首先就需要将这个库移植到Android上。\n1. 首先在官网下载live555对源码并解压。 2. 新建一个Android工程，将源码文件放到一个该工程的jni目录下，如：jni/live。 3. 新建jni/Android.mk文件作为Makefile。将需要编译对源文件加入到LOCAL_SRC_FILES变量，将需要引用对头文件加入到LOCAL_C_INCLUDES，编译过程中会提示需要参数：-fexceptions，于是加入参数LOCAL_CPPFLAGS += -fexceptions。\n内容如下：\n4. 新建jni/Application.mk文件。由于live555需要引用stl，所以加入： APP_STL := gnustl_shared\n5. 运行ndk-build就可以得到live555.so文件啦。\n","permalink":"https://blog.zdltech.com/posts/%E5%9F%BA%E4%BA%8E%E7%A7%BB%E5%8A%A8%E5%B9%B3%E5%8F%B0%E7%9A%84%E5%A4%9A%E5%AA%92%E4%BD%93%E6%A1%86%E6%9E%B6-%E7%A7%BB%E6%A4%8Dlive555%E5%88%B0android%E4%B8%8A/","summary":"\u003cp\u003e\u003cspan class=\"s1\"\u003elive555是一个处理流媒体传输对c++库，再Mplayer与vlc中都有用到。我们计划将其加入到自己编写对Android上的播放器中作为流媒体模块，首先就需要将这个库移植到Android上。\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e1. 首先在官网下载live555对源码并解压。\u003c/span\u003e\u003cspan class=\"s2\"\u003e\n\u003c/span\u003e\u003cspan class=\"s1\"\u003e2. 新建一个Android工程，将源码文件放到一个该工程的jni目录下，如：jni/live。\u003c/span\u003e\u003cspan class=\"s2\"\u003e\n\u003c/span\u003e\u003cspan class=\"s1\"\u003e3. 新建jni/Android.mk文件作为Makefile。将需要编译对源文件加入到LOCAL_SRC_FILES变量，将需要引用对头文件加入到LOCAL_C_INCLUDES，编译过程中会提示需要参数：-fexceptions，于是加入参数LOCAL_CPPFLAGS += -fexceptions。\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e内容如下：\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e4. 新建jni/Application.mk文件。由于live555需要引用stl，所以加入：\u003c/span\u003e\u003cspan class=\"s2\"\u003e\n\u003c/span\u003e\u003cspan class=\"s1\"\u003eAPP_STL := gnustl_shared\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e5. 运行ndk-build就可以得到live555.so文件啦。\u003c/span\u003e\u003c/p\u003e","title":"基于移动平台的多媒体框架——移植Live555到Android上"},{"content":" Android开源项目第一篇——个性化控件(View)篇 * 包括ListView、ActionBar、Menu、ViewPager、Gallery、GridView、ImageView、ProgressBar、TextView、其他* Android开源项目第二篇——工具库篇 * 包括依赖注入、图片缓存、网络相关、数据库ORM工具包、Android公共库、高版本向低版本兼容库、多媒体、事件总线、传感器、安全、其他* Android开源项目第三篇——优秀项目篇 * 比较有意思的完整的Android项目* Android开源项目第四篇——开发及测试工具篇 * 包括开发效率工具、开发自测相关、测试工具、开发及编译环境、其他* 第一部分 个性化控件(View)\n主要介绍那些不错个性化的View，包括ListView、ActionBar、Menu、ViewPager、Gallery、GridView、ImageView、ProgressBar及其他如Dialog、Toast、EditText、TableView、Activity Animation等等。\n一、ListView\nandroid-pulltorefresh\n一个强大的拉动刷新开源项目，支持各种控件下拉刷新，ListView、ViewPager、WevView、ExpandableListView、GridView、ScrollView、Horizontal ScrollView、Fragment上下左右拉动刷新，比下面johannilsson那个只支持ListView的强大的多。并且他实现的下拉刷新ListView在item不足一屏情况下也不会显示刷新提示，体验更好。\n项目地址：https://github.com/chrisbanes/Android-PullToRefresh\nDemo地址：https://github.com/Trinea/TrineaDownload/blob/master/pull-to-refreshview-demo.apk?raw=true\nAPP示例：新浪微博各个页面 android-pulltorefresh-listview\n下拉刷新ListView\n项目地址：https://github.com/johannilsson/android-pulltorefresh\nDemo地址：https://github.com/Trinea/TrineaDownload/blob/master/pull-to-refresh-listview-demo.apk?raw=true\nPS：这个被很多人使用的项目实际有不少bug，推荐使用上面的android-pulltorefresh DropDownListView\n下拉刷新及滑动到底部加载更多ListView\n项目地址：https://github.com/Trinea/AndroidCommon\nDemo地址：https://play.google.com/store/apps/details?id=cn.trinea.android.demo\n文档介绍：http://www.trinea.cn/android/dropdown-to-refresh-and-bottom-load-more-listview/ DragSortListView\n拖动排序的ListView，同时支持ListView滑动item删除，各个Item高度不一、单选、复选、CursorAdapter做为适配器、拖动背景变化等\n项目地址：https://github.com/bauerca/drag-sort-listview\nDemo地址：https://play.google.com/store/apps/details?id=com.mobeta.android.demodslv\nAPP示例：Wordpress Android SwipeListView\n支持定义ListView左右滑动事件，支持左右滑动位移，支持定义动画时间\n项目地址：https://github.com/47deg/android-swipelistview\nDemo地址：https://play.google.com/store/apps/details?id=com.fortysevendeg.android.swipelistview\nAPP示例：微信 Android-SwipeToDismiss\n滑动Item消失ListView\n项目地址：https://github.com/romannurik/Android-SwipeToDismiss\n支持3.0以下版本见：https://github.com/JakeWharton/SwipeToDismissNOA\nDemo地址：https://github.com/JakeWharton/SwipeToDismissNOA/SwipeToDismissNOA.apk/qr_code StickyListHeaders\nGroupName滑动到顶端时会固定不动直到另外一个GroupName到达顶端的ExpandListView，支持快速滑动，支持Android2.3及以上\n项目地址：https://github.com/emilsjolander/StickyListHeaders\nAPP示例：Android 4.0联系人\n效果图： pinned-section-listview\nGroupName滑动到顶端时会固定不动直到另外一个GroupName到达顶端的ExpandListView\n项目地址：https://github.com/beworker/pinned-section-listview\n效果图： PinnedHeaderListView\nGroupName滑动到顶端时会固定不动直到另外一个GroupName到达顶端的ExpandListView\n项目地址：https://github.com/JimiSmith/PinnedHeaderListView 2. QuickReturnHeader\nListView/ScrollView的header或footer，当向下滚动时消失，向上滚动时出现\n项目地址：https://github.com/ManuelPeinado/QuickReturnHeader\nDemo地址：https://github.com/Trinea/TrineaDownload/blob/master/quick-return-header-demo.apk?raw=true\nAPP示例：google plus 3. IndexableListView\nListView右侧会显示item首字母快捷索引，点击可快速滑动到某个item\n项目地址：https://github.com/woozzu/IndexableListView\nDemo地址：https://github.com/Trinea/TrineaDownload/blob/master/indexable-listview.apk?raw=true\nAPP示例：微信通讯录、小米联系人 4. CustomFastScrollView\nListView快速滑动，同时屏幕中间PopupWindows显示滑动到的item内容或首字母\n项目地址：https://github.com/nolanlawson/CustomFastScrollViewDemo\n效果图： 5. Android-ScrollBarPanel\nListView滑动时固定的Panel指示显示在scrollbar旁边\n项目地址：https://github.com/rno/Android-ScrollBarPanel\n效果展示：https://github.com/rno/Android-ScrollBarPanel/raw/master/demo_capture.png 6. SlideExpandableListView\n用户点击listView item滑出固定区域，其他item的区域收缩\n项目地址：https://github.com/tjerkw/Android-SlideExpandableListView\nDemo地址：https://github.com/Trinea/TrineaDownload/blob/master/slide-expandable-listView-demo.apk?raw=true 7. JazzyListView\nListView及GridView item以特殊动画效果进入屏幕，效果包括grow、cards、curl、wave、flip、fly等等\n项目地址：https://github.com/twotoasters/JazzyListView\nDemo地址：https://play.google.com/store/apps/details?id=com.twotoasters.jazzylistview.sample\n效果展示：http://lab.hakim.se/scroll-effects/ 8. ListViewAnimations\n带Item显示动画的ListView，动画包括底部飞入、其他方向斜飞入、下层飞入、渐变消失、滑动删除等\n项目地址：https://github.com/nhaarman/ListViewAnimations\nDemo地址：https://play.google.com/store/apps/details?id=com.haarman.listviewanimations\nAPP示例：Google plus、Google Now卡片式进入、小米系统中应用商店、联系人、游戏中心、音乐、文件管理器的ListView、Ultimate、Light Flow Lite、TreinVerkeer、Running Coach、Pearl Jam Lyrics、Calorie Chart、Car Hire、Super BART、DK FlashCards、Counter Plus、Voorlees Verhaaltjes 2.0 9. DevsmartLib-Android\n横向ListView\n项目地址：https://github.com/dinocore1/DevsmartLib-Android\nDemo地址：https://github.com/Trinea/TrineaDownload/blob/master/horizontal-listview-demo.apk?raw=true 10. HorizontalVariableListView\n支持Item宽度不一致的ListView\n项目地址：https://github.com/sephiroth74/HorizontalVariableListView 11. LinearListView\n用LinearLayout实现的ListView，可解决多个ListView并且等问题。目前自己也有需要，等亲自尝试过后会再具体介绍\n项目地址：https://github.com/frankiesardo/LinearListView 12. MultiChoiceAdapter\n支持多选的ListView Adapter\n项目地址：https://github.com/ManuelPeinado/MultiChoiceAdapter\nDemo地址：https://play.google.com/store/apps/details?id=com.manuelpeinado.multichoiceadapter.demo 13. EnhancedListView\n支持横向滑动滑动删除列表项以及撤销删除的ListView，该项目的前身是SwipeToDismissUndoList\n项目地址：https://github.com/timroes/EnhancedListView\nDemo地址：https://play.google.com/store/apps/details?id=de.timroes.android.listviewdemo\u0026amp;rdid=de.timroes.android.listviewdemo 14. ListBuddies\n自动滚动的双列ListView ，两个ListView滚动速度不一致，有视差效果\n项目地址：https://github.com/jpardogo/ListBuddies\nDemo地址：https://play.google.com/store/apps/details?id=com.jpardogo.android.listbuddies\n效果展示：\n\u0026lt;a name=\u0026quot;user-content-%E4%BA%8Cactionbar\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;二、ActionBar 1. ActionBarSherlock 为Android所有版本提供统一的ActionBar，解决4.0以下ActionBar的适配问题 项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/ActionBarSherlock\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.demos\u0026lt;/a\u0026gt; APP示例：太多了。。现在连google都在用 2. ActionBar-PullToRefresh 下拉刷新，ActionBar出现加载中提示 项目地址：\u0026lt;a\u0026gt;https://github.com/chrisbanes/ActionBar-PullToRefresh\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=uk.co.senab.actionbarpulltorefresh.samples.stock\u0026lt;/a\u0026gt; APP示例：Gmail，Google plus，知乎等 3. FadingActionBar ListView向下滚动逐渐显现的ActionBar 项目地址：\u0026lt;a\u0026gt;https://github.com/ManuelPeinado/FadingActionBar\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.manuelpeinado.fadingactionbar.demo\u0026lt;/a\u0026gt; APP示例：google music，知乎 4. NotBoringActionBar google music下拉收缩的ActionBar 项目地址：\u0026lt;a\u0026gt;https://github.com/flavienlaurent/NotBoringActionBar\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;http://flavienlaurent.com/blog/2013/11/20/making-your-action-bar-not-boring/\u0026lt;/a\u0026gt; APP示例：Google音乐 5. RefreshActionItem 带进度显示和刷新按钮的ActionBar 项目地址：\u0026lt;a\u0026gt;https://github.com/ManuelPeinado/RefreshActionItem\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.manuelpeinado.refreshactionitem.demo\u0026lt;/a\u0026gt; APP示例：The New York Times，DevAppsDirect. 6. GlassActionBar 类似玻璃的有一定透明度的ActionBar 项目地址：\u0026lt;a\u0026gt;https://github.com/ManuelPeinado/GlassActionBar\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.manuelpeinado.glassactionbardemo\u0026lt;/a\u0026gt; APP示例：google music \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%B8%89menu\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;三、Menu 1. MenuDrawer 滑出式菜单，通过拖动屏幕边缘滑出菜单，支持屏幕上下左右划出，支持当前View处于上下层，支持Windows边缘、ListView边缘、ViewPager变化划出菜单等。 项目地址：\u0026lt;a\u0026gt;https://github.com/SimonVT/android-menudrawer\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;http://simonvt.github.io/android-menudrawer/\u0026lt;/a\u0026gt; APP示例：Gmail、Google Music等大部分google app 2. SlidingMenu 滑出式菜单，通过拖动屏幕边缘滑出菜单，支持屏幕左右划出，支持菜单zoom、scale、slide up三种动画样式出现。 项目地址：\u0026lt;a\u0026gt;https://github.com/jfeinstein10/SlidingMenu\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.slidingmenu.example\u0026lt;/a\u0026gt; APP示例：Foursquare, LinkedIn, Zappos, Rdio, Evernote Food, Plume, VLC for Android, ESPN ScoreCenter, MLS MatchDay, 9GAG, Wunderlist 2, The Verge, MTG Familiar, Mantano Reader, Falcon Pro (BETA), MW3 Barracks MenuDrawer和SlidingMenu比较：SlidingMenu支持菜单动画样式出现，MenuDrawer支持菜单view处于内容的上下层 3. ArcMenu 支持类似Path的左下角动画旋转菜单及横向划出菜单、圆心弹出菜单 项目地址：\u0026lt;a\u0026gt;https://github.com/daCapricorn/ArcMenu\u0026lt;/a\u0026gt; APP示例：Path 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/503830c53d4a8aaec4666ed8ad12d0f08e882f81/68747470733a2f2f646c2e64726f70626f7875736572636f6e74656e742e636f6d2f752f31313336393638372f70726576696577302e706e67)\u0026lt;/a\u0026gt; \u0026lt;a\u0026gt;https://dl.dropboxusercontent.com/u/11369687/preview1.png\u0026lt;/a\u0026gt; \u0026lt;a\u0026gt;https://dl.dropboxusercontent.com/u/11369687/raymenu.png\u0026lt;/a\u0026gt; 4. android-satellite-menu 类似Path的左下角动画旋转菜单 项目地址：\u0026lt;a\u0026gt;https://github.com/siyamed/android-satellite-menu\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/satellite-menu-demo.apk?raw=true\u0026lt;/a\u0026gt; APP示例：Path 5. radial-menu-widget 圆形菜单，支持二级菜单 项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/radial-menu-widget/\u0026lt;/a\u0026gt; 效果图：\u0026lt;a\u0026gt;http://farm8.staticflickr.com/7377/11621125154_d1773c2dcc_o.jpg\u0026lt;/a\u0026gt; 6. Android Wheel Menu 圆形旋转选取菜单 项目地址：\u0026lt;a\u0026gt;https://github.com/anupcowkur/Android-Wheel-Menu\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/anupcowkur/Android-Wheel-Menu/master/graphics/wheel.gif)\u0026lt;/a\u0026gt; 7. FoldingNavigationDrawer 滑动并以折叠方式打开菜单 项目地址：\u0026lt;a\u0026gt;https://github.com/tibi1712/FoldingNavigationDrawer-Android\u0026lt;/a\u0026gt; 使用介绍：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.ptr.folding.sample\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/e556bb96a96e4a3991de0ce8a0ca81b51e909370/68747470733a2f2f6c68362e67677068742e636f6d2f566e4b555a656e416f7a51304b46416d35626c465447714d614b466a76582d424b324a482d6a725831734958565471636941437152687146483438686334706d32513d683331302d7277)\u0026lt;/a\u0026gt; 8. AndroidResideMenu 仿 Dribbble 的边栏菜单 项目地址：\u0026lt;a\u0026gt;https://github.com/SpecialCyCi/AndroidResideMenu\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github.com/SpecialCyCi/AndroidResideMenu/raw/master/2.gif)\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E5%9B%9Bviewpager-gallery\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;四、ViewPager 、Gallery 1. Android-ViewPagerIndicator 配合ViewPager使用的Indicator，支持各种位置和样式 项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/Android-ViewPagerIndicator\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.viewpagerindicator.sample\u0026lt;/a\u0026gt; APP示例：太多了。。 2. JazzyViewPager 支持Fragment切换动画的ViewPager，动画包括转盘、淡入淡出、翻页、层叠、旋转、方块、翻转、放大缩小等 项目地址：\u0026lt;a\u0026gt;https://github.com/jfeinstein10/JazzyViewPager\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/jfeinstein10/JazzyViewPager/blob/master/JazzyViewPager.apk?raw=true\u0026lt;/a\u0026gt; 效果类似桌面左右切换的各种效果，不过桌面并非用ViewPager实现而已 3. Android-DirectionalViewPager 支持横向和纵向(垂直)的ViewPager 项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/Android-DirectionalViewPager\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://market.android.com/details?id=com.directionalviewpager.sample\u0026lt;/a\u0026gt; 4. android-pulltorefresh 支持下拉刷新的ViewPager 项目地址：\u0026lt;a\u0026gt;https://github.com/chrisbanes/Android-PullToRefresh\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/pull-to-refreshview-demo.apk?raw=true\u0026lt;/a\u0026gt; APP示例：新浪微博各个页面 5. FancyCoverFlow 支持Item切换动画效果的类似Gallery View 项目地址：\u0026lt;a\u0026gt;https://github.com/davidschreiber/FancyCoverFlow\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=at.technikum.mti.fancycoverflow.samples\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github-camo.global.ssl.fastly.net/ef5ced52b7b54652b50499521ed797c0188c7a6b/687474703a2f2f64617669647363687265696265722e6769746875622e696f2f46616e6379436f766572466c6f772f73637265656e73686f74322e706e67)\u0026lt;/a\u0026gt; 6. AndroidTouchGallery 支持双击或双指缩放的Gallery(用ViewPager实现)，相比下面的PhotoView，在被放大后依然能滑到下一个item，并且支持直接从url和文件中获取图片， 项目地址：\u0026lt;a\u0026gt;https://github.com/Dreddik/AndroidTouchGallery\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/touch-gallery-demo.apk?raw=true\u0026lt;/a\u0026gt; APP示例：类似微信中查看聊天记录图片时可双击放大，并且放大情况下能正常左右滑动到前后图片 7. Android Auto Scroll ViewPager Android自动滚动 轮播循环的ViewPager 项目地址：\u0026lt;a\u0026gt;https://github.com/Trinea/android-auto-scroll-view-pager\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=cn.trinea.android.demo\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://www.trinea.cn/android/auto-scroll-view-pager/\u0026lt;/a\u0026gt; 8. Salvage view 带View缓存的Viewpager PagerAdapter，很方便使用 项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/salvage\u0026lt;/a\u0026gt; 9. Android PagerSlidingTabStrip 配合ViewPager使用的Indicator，支持ViewPager Scroll时Indicator联动 项目地址：\u0026lt;a\u0026gt;https://github.com/astuetz/PagerSlidingTabStrip\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.astuetz.viewpager.extensions.sample\u0026lt;/a\u0026gt; 10. ViewPager3D ViewPager3D效果 项目地址：\u0026lt;a\u0026gt;https://github.com/inovex/ViewPager3D\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%BA%94gridview\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;五、GridView 1. StaggeredGridView 允许非对齐行的GridView，类似Pinterest的瀑布流，并且跟ListView一样自带View缓存，继承自ViewGroup 项目地址：\u0026lt;a\u0026gt;https://github.com/maurycyw/StaggeredGridView\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/staggered-gridview-demo.apk?raw=true\u0026lt;/a\u0026gt; APP示例：Pinterest等 2. AndroidStaggeredGrid 允许非对齐行的GridView，类似Pinterest的瀑布流，继承自AbsListView 项目地址：\u0026lt;a\u0026gt;https://github.com/etsy/AndroidStaggeredGrid\u0026lt;/a\u0026gt; APP示例：Pinterest等 3. PinterestLikeAdapterView 允许非对齐行的GridView，类似Pinterest的瀑布流，允许下拉刷新 项目地址：\u0026lt;a\u0026gt;https://github.com/GDG-Korea/PinterestLikeAdapterView\u0026lt;/a\u0026gt; APP示例：Pinterest等 4. DraggableGridView Item可拖动交换位置的GridView，实际是自己继承ViewGroup实现，类似桌面的单屏效果，可屏幕自动上下滚动进行Item移动交换，多屏效果见下面PagedDragDropGrid 项目地址：\u0026lt;a\u0026gt;https://github.com/thquinn/DraggableGridView\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/thquinn/DraggableGridView/blob/master/bin/DraggableGridViewSample.apk?raw=true\u0026lt;/a\u0026gt; 5. StickyGridHeaders GroupName滑动到顶端时会固定不动直到另外一个GroupName到达顶端的GridView 项目地址：\u0026lt;a\u0026gt;https://github.com/TonicArtos/StickyGridHeaders\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github-camo.global.ssl.fastly.net/90b57e9383704c400706545225d439e057c6fcc0/687474703a2f2f342e62702e626c6f6773706f742e636f6d2f2d535f4262685758367754592f55517057306377554745492f41414141414141414776552f7a7a4a586a2d50635662592f73313630302f73637265656e2d6c616e6473636170652d736d616c6c65722e706e67)\u0026lt;/a\u0026gt; 6. PagedDragDropGrid Item可拖动交换位置、拖动删除的自定义控件，实际是自己继承ViewGroup实现，类似桌面的多屏效果，可拖动到屏幕边缘，屏幕自动左右滚动进行Item移动交换，可拖动进行删除，单屏效果见上面DraggableGridView 项目地址：\u0026lt;a\u0026gt;https://github.com/mrKlar/PagedDragDropGrid\u0026lt;/a\u0026gt; Demo视频：\u0026lt;a\u0026gt;http://youtu.be/FYTSRfthSuQ\u0026lt;/a\u0026gt; 7. Android-DraggableGridViewPager Item可拖动交换位置的GridView，实际是自己继承ViewGroup实现，类似桌面的多屏效果，可屏幕自动左右滚动进行Item移动交换，单屏效果见上面DraggableGridView 项目地址：\u0026lt;a\u0026gt;https://github.com/zzhouj/Android-DraggableGridViewPager\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/trinea-download/blob/master/draggable-grid-viewpager-demo.apk?raw=true\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E5%85%ADimageview\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;六、ImageView 1. PhotoView 支持双击或双指缩放的ImageView，在ViewPager等Scrolling view中正常使用，相比上面的AndroidTouchGallery，不仅支持ViewPager，同时支持单个ImageView 项目地址：\u0026lt;a\u0026gt;https://github.com/chrisbanes/PhotoView\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=uk.co.senab.photoview.sample\u0026lt;/a\u0026gt; APP示例：photup 2. android-gif-drawable 支持gif显示的view，用jni实现的，编译生成so库后直接xml定义view即可，而且本身不依赖于其他开源项目所以相对下面的ImageViewEx简单的多 项目地址：\u0026lt;a\u0026gt;https://github.com/koral\u0026amp;#8211;/android-gif-drawable\u0026lt;/a\u0026gt; 3. ImageViewEx 支持Gif显示的ImageView 项目地址：\u0026lt;a\u0026gt;https://github.com/frapontillo/ImageViewEx\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/imageviewex-demo.apk?raw=true\u0026lt;/a\u0026gt; 依赖很多，编译过程很繁琐!|_|! 4. RoundedImageView 带圆角的ImageView 项目地址：\u0026lt;a\u0026gt;https://github.com/vinc3m1/RoundedImageView\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/makeramen/RoundedImageView/master/screenshot.png)\u0026lt;/a\u0026gt; 5. ColorArt 根据图片的均色设置背景色显示文字和图片，类似itune11中效果 项目地址：\u0026lt;a\u0026gt;https://github.com/MichaelEvans/ColorArt\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/color-art-demo.apk?raw=true\u0026lt;/a\u0026gt; 6. CircleImageView 圆形的ImageView 项目地址：\u0026lt;a\u0026gt;https://github.com/hdodenhof/CircleImageView\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/hdodenhof/CircleImageView/master/screenshot.png)\u0026lt;/a\u0026gt; 7. ImageViewZoom 支持放大和平移的ImageView 项目地址：\u0026lt;a\u0026gt;https://github.com/sephiroth74/ImageViewZoom\u0026lt;/a\u0026gt; APP示例：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.aviary.android.feather\u0026lt;/a\u0026gt; 8. KenBurnsView 实现Ken Burns effect效果，达到身临其境效果的ImageView 项目地址：\u0026lt;a\u0026gt;https://github.com/flavioarfaria/KenBurnsView\u0026lt;/a\u0026gt; 9. CustomShapeImageView 各种形状的ImageView, 相比上面的圆形ImageView，多了更多形状 项目地址：\u0026lt;a\u0026gt;https://github.com/MostafaGazar/CustomShapeImageView\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/MostafaGazar/CustomShapeImageView/master/Screenshot_2013-11-05-23-08-12.png)\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%B8%83progressbar\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;七、ProgressBar 1. SmoothProgressBar 水平进度条 项目地址：\u0026lt;a\u0026gt;https://github.com/castorflex/SmoothProgressBar\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=fr.castorflex.android.smoothprogressbar.sample\u0026lt;/a\u0026gt; 2. ProgressWheel 支持进度显示的圆形ProgressBar 项目地址：\u0026lt;a\u0026gt;https://github.com/Todd-Davies/ProgressWheel\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/progress-wheel-demo.apk?raw=true\u0026lt;/a\u0026gt; 3. android-square-progressbar 在图片周围显示进度 项目地址：\u0026lt;a\u0026gt;https://github.com/mrwonderman/android-square-progressbar\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=net.yscs.android.square_progressbar_example\u0026lt;/a\u0026gt; APP示例：square 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/6cb902f23ff22f1acc42b54182c2a27f53c379c2/68747470733a2f2f676f6f676c6564726976652e636f6d2f686f73742f30427745537750437558747737654578775346564c516b52325454672f6e657773637265656e312e706e67)\u0026lt;/a\u0026gt; 4. HoloCircularProgressBar Android4.1 时钟App样式 项目地址：\u0026lt;a\u0026gt;https://github.com/passsy/android-HoloCircularProgressBar\u0026lt;/a\u0026gt; APP示例：Android4.1时钟App 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/passsy/android-HoloCircularProgressBar/master/raw/screenshot1.png)\u0026lt;/a\u0026gt; 5. ProgressButton 通过图钉的不同状态显示进度 项目地址：\u0026lt;a\u0026gt;https://github.com/f2prateek/progressbutton\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://f2prateek.com/progressbutton/\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/a5eb0cefeef3c5a9047feacd154f82549b6fadc4/687474703a2f2f66327072617465656b2e636f6d2f70726f6772657373627574746f6e2f7374617469632f7374617465732e706e67)\u0026lt;/a\u0026gt; 6. GoogleProgressBar 类似google 多个圆形卡片翻转的progressBar 项目地址：\u0026lt;a\u0026gt;https://github.com/jpardogo/GoogleProgressBar\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.githubusercontent.com/jpardogo/GoogleProgressBar/master/art/GoogleProgressBar.gif)\u0026lt;/a\u0026gt; 7. TH-ProgressButton 带圆形进度显示的按钮 项目地址；\u0026lt;a\u0026gt;https://github.com/torryharris/TH-ProgressButton\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/Vyshakh-K/TH-ProgressButton/master/screenshots/progressshot1.png)\u0026lt;/a\u0026gt;\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/Vyshakh-K/TH-ProgressButton/master/screenshots/progressshot2.png)\u0026lt;/a\u0026gt;\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/Vyshakh-K/TH-ProgressButton/master/screenshots/progressshot3.png)\u0026lt;/a\u0026gt;\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/Vyshakh-K/TH-ProgressButton/master/screenshots/progressshot4.png)\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E5%85%ABtextview\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;八、TextView包括TextView及所有继承自TextView控件，如EditText、Button、RadioButton 1. android-flowtextview 文字自动环绕其他View的Layout 项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/android-flowtextview/\u0026lt;/a\u0026gt; 效果图：\u0026lt;a\u0026gt;http://i949.photobucket.com/albums/ad332/vostroman1500/1.png\u0026lt;/a\u0026gt; 2. Android Form EditText 验证输入合法性的编辑框，支持输入、英文、ip、url等多种正则验证 项目地址：\u0026lt;a\u0026gt;https://github.com/vekexasia/android-edittext-validator\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.andreabaccega.edittextformexample\u0026lt;/a\u0026gt; 3. Emojicon 支持emojis的TextView和EditText 项目地址：\u0026lt;a\u0026gt;https://github.com/rockerhieu/emojicon\u0026lt;/a\u0026gt; 文档地址：\u0026lt;a\u0026gt;http://rockerhieu.com/emojicon/\u0026lt;/a\u0026gt; 4. android-circlebutton Android圆形按钮，实际实现是继承自ImageView 项目地址：\u0026lt;a\u0026gt;https://github.com/markushi/android-circlebutton\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/markushi/android-circlebutton/blob/master/example/example.apk\u0026lt;/a\u0026gt; 5. Segmented Radio Buttons for Android iOS’s segmented controls的实现 项目地址：\u0026lt;a\u0026gt;https://github.com/vinc3m1/android-segmentedradiobutton\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/thquinn/DraggableGridView/blob/master/bin/DraggableGridViewSample.apk?raw=true\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/vinc3m1/android-segmentedradiobutton/master/screens/segmentedradio.png)\u0026lt;/a\u0026gt; 6. Chips EditText Library 支持国家名字联想从而选择显示该国国旗的EditText，实际就是通过SpannableStringBuilder实现 项目地址：\u0026lt;a\u0026gt;https://github.com/kpbird/chips-edittext-library\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/kpbird/chips-edittext-library/tree/master/ChipsEditTextDemo/bin\u0026lt;/a\u0026gt; 7. AutoFitTextView 可固定边界内容字体大小自适应的TextView 项目地址：\u0026lt;a\u0026gt;https://github.com/grantland/android-autofittextview\u0026lt;/a\u0026gt; 8. Shimmer for Android 文字发淡光的TextView 项目地址：\u0026lt;a\u0026gt;https://github.com/RomainPiel/Shimmer-android\u0026lt;/a\u0026gt; 9. Titanic 可以显示水位上升下降(不知道该怎么描述 囧)的TextView 项目地址：\u0026lt;a\u0026gt;https://github.com/RomainPiel/Titanic\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github.com/RomainPiel/Titanic/raw/master/titanic.gif)\u0026lt;/a\u0026gt; 10. android-iconify 提供带Icon的TextView,Menu,Button等 项目地址：\u0026lt;a\u0026gt;https://github.com/JoanZapata/android-iconify\u0026lt;/a\u0026gt; 11. Calligraphy 让我们在[Android开发](http://www.eoeandroid.com/)中使用自定义字体变得更加简单 项目地址 ：\u0026lt;a\u0026gt;https://github.com/chrisjenx/Calligraphy\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github.com/chrisjenx/Calligraphy/raw/master/screenshot.png)\u0026lt;/a\u0026gt; 12. CreditsRoll 类似星球大战字幕效果的TextView 项目地址：\u0026lt;a\u0026gt;https://github.com/frakbot/CreditsRoll\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%B9%9D%E5%85%B6%E4%BB%96\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;九、其他 1. achartengine 强大的图表绘制工具，支持折线图、面积图、散点图、时间图、柱状图、条图、饼图、气泡图、圆环图、范围（高至低）条形图、拨号图/表、立方线图及各种图的结合 项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/achartengine/\u0026lt;/a\u0026gt; 官方网站：\u0026lt;a\u0026gt;http://www.achartengine.org/\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/d3a4fa07ace8e6aca2f1e4c5131009de2e897a3e/687474703a2f2f7777772e616368617274656e67696e652e6f72672f64696d616765732f617665726167655f74656d70657261747572652e706e67)\u0026lt;/a\u0026gt; \u0026lt;a\u0026gt;http://www.achartengine.org/dimages/sales_line_and_area_chart.png\u0026lt;/a\u0026gt; \u0026lt;a\u0026gt;http://www.achartengine.org/dimages/temperature_range_chart.png\u0026lt;/a\u0026gt; \u0026lt;a\u0026gt;http://www.achartengine.org/dimages/combined_chart.png\u0026lt;/a\u0026gt; \u0026lt;a\u0026gt;http://www.achartengine.org/dimages/budget_chart.png\u0026lt;/a\u0026gt; APP示例：Wordpress Android，Google Analytics 2. GraphView 绘制图表和曲线图的View，可用于Android上的曲形图、柱状图、波浪图展示 项目地址：\u0026lt;a\u0026gt;https://github.com/jjoe64/GraphView\u0026lt;/a\u0026gt; Demo工程：\u0026lt;a\u0026gt;https://github.com/jjoe64/GraphView-Demos\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.sothree.umano\u0026lt;/a\u0026gt; APP示例：Wordpress Android，Google Analytics 3. android-flip 类似Flipboard翻转动画的实现 项目地址：\u0026lt;a\u0026gt;https://github.com/openaphid/android-flip\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/openaphid/android-flip/blob/master/FlipView/Demo/APK/Aphid-FlipView-Demo.apk?raw=true\u0026lt;/a\u0026gt; APP示例：flipboard 4. FlipImageView 支持x、y、z及动画选择的翻转动画的实现 项目地址：\u0026lt;a\u0026gt;https://github.com/castorflex/FlipImageView\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=fr.castorflex.android.flipimageview\u0026lt;/a\u0026gt; 5. SwipeBackLayout 左右或向上滑动返回的Activity 项目地址：\u0026lt;a\u0026gt;https://github.com/Issacw0ng/SwipeBackLayout\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=me.imid.swipebacklayout.demo\u0026lt;/a\u0026gt; APP示例：知乎 6. Cards-UI 卡片式View，支持单个卡片，item为卡片的ListView 项目地址：\u0026lt;a\u0026gt;https://github.com/afollestad/Cards-UI\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/cards-ui-demo.apk?raw=true\u0026lt;/a\u0026gt; 7. cardslib 卡片式View，支持单个卡片，item为卡片的ListView和GridView 项目地址：\u0026lt;a\u0026gt;https://github.com/gabrielemariotti/cardslib\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=it.gmariotti.cardslib.demo\u0026lt;/a\u0026gt; 8. android-styled-dialogs 可自定义样式的dialog，默认与Holo主题样式一致，在Android2.2以上同一样式 项目地址：\u0026lt;a\u0026gt;https://github.com/inmite/android-styled-dialogs\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/styled-dialogs-demo.apk?raw=true\u0026lt;/a\u0026gt; 9. Crouton 丰富样式的Toast，允许alert、comfirm、info样式及点击消失样式，允许设置Toast显示时间，允许自定义View。 本文32. SuperToasts为其扩展版 项目地址：\u0026lt;a\u0026gt;https://github.com/keyboardsurfer/Crouton\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;http://play.google.com/store/apps/details?id=de.keyboardsurfer.app.demo.crouton\u0026lt;/a\u0026gt; 10. supertooltips 带动画效果的Tips显示 项目地址：\u0026lt;a\u0026gt;https://github.com/nhaarman/supertooltips\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.haarman.supertooltips\u0026lt;/a\u0026gt; 11. Android ViewBadger 为其他View添加角标等 项目地址：\u0026lt;a\u0026gt;https://github.com/jgilfelt/android-viewbadger\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/android-viewbadger.apk?raw=true\u0026lt;/a\u0026gt; 效果图：\u0026lt;a\u0026gt;https://github-camo.global.ssl.fastly.net/a705a3e88c75ae2394943bd7c56f725697616ea8/687474703a2f2f7777772e6a65666667696c66656c742e636f6d2f766965776261646765722f76622d31612e706e67\u0026lt;/a\u0026gt; 12. Android Sliding Up Panel 可拖动的View，能在当前Activity上扶起一个可拖动的Panel 项目地址：\u0026lt;a\u0026gt;https://github.com/umano/AndroidSlidingUpPanel\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.sothree.umano\u0026lt;/a\u0026gt; APP示例：Google Music精简播放栏 13. android-times-square Android日历时间部件，支持选取单个日期，多个日期，及日期区间段和对话框形式显示 项目地址：\u0026lt;a\u0026gt;https://github.com/square/android-times-square\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/times-square-demo.apk?raw=true\u0026lt;/a\u0026gt; 14. android-calendar-card 日历 项目地址：\u0026lt;a\u0026gt;https://github.com/kenumir/android-calendar-card\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.wt.calendarcardsample\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/kenumir/android-calendar-card/master/calendar-card-sample/_work/device-2013-10-12-151801.png)\u0026lt;/a\u0026gt; 15. ColorPickerView 颜色选择器，支持PopupWindows或新的Activity中打开 项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/color-picker-view/\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/c1b120db21965381e28349dcb019a8ec5525c326/687474703a2f2f6f6934312e74696e797069632e636f6d2f333363366d6d382e6a7067)\u0026lt;/a\u0026gt; 16. HoloColorPicker 颜色选择器 项目地址：\u0026lt;a\u0026gt;https://github.com/LarsWerkman/HoloColorPicker\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://docs.google.com/file/d/0BwclyDTlLrdXRzVnTGJvTlRfU2s/edit\u0026lt;/a\u0026gt; 17. AndroidWheel Android Wheel支持城市、多种日期时间、密码、图片 项目地址：\u0026lt;a\u0026gt;https://github.com/sephiroth74/AndroidWheel\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/e9a9430ac807dcfcde5ebc407684a8b7459bb9bd/687474703a2f2f6661726d362e737461746963666c69636b722e636f6d2f353533322f31313632313532383738365f323230633034306261355f6f2e6a7067)\u0026lt;/a\u0026gt; 18. TableFixHeaders 第一列固定的Table 项目地址：\u0026lt;a\u0026gt;https://github.com/InQBarna/TableFixHeaders\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;http://bit.ly/13buAIq\u0026lt;/a\u0026gt; 19. UITableView ios风格控件，包括Button、ListView、TableView 项目地址：\u0026lt;a\u0026gt;https://github.com/thiagolocatelli/android-uitableview\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/ui-tableview-demo.apk?raw=true\u0026lt;/a\u0026gt; 20. ATableView ios风格控件 项目地址：\u0026lt;a\u0026gt;https://github.com/dmacosta/ATableView\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.nakardo.atableview.demo\u0026lt;/a\u0026gt; 21. UndoBar 屏幕底部显示取消或是确认的PopupWindows 项目地址：\u0026lt;a\u0026gt;https://github.com/soarcn/UndoBar\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github.com/soarcn/UndoBar/blob/master/art/redo.png?raw=true)\u0026lt;/a\u0026gt; 22. Inscription 可用于展示应用change和new feature信息 项目地址：\u0026lt;a\u0026gt;https://github.com/MartinvanZ/Inscription\u0026lt;/a\u0026gt; 23. ActivityTransition Activity切换动画，包括渐变、flip、某个位置进入等等 项目地址：\u0026lt;a\u0026gt;https://github.com/ophilbert/ActivityTransition\u0026lt;/a\u0026gt; 使用介绍：\u0026lt;a\u0026gt;https://github.com/jfeinstein10/JazzyViewPager/blob/master/JazzyViewPager.apk?raw=true\u0026lt;/a\u0026gt; 效果图：类似桌面左右切换的各种效果，不过桌面并非用ViewPager实现而已 24. GlowPadBackport 将Android4.2的锁屏界面解锁扩展到Android1.6及1.6+ 项目地址：\u0026lt;a\u0026gt;https://github.com/rock3r/GlowPadBackport\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=net.sebastianopoggi.samples.ui.GlowPadSample\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/1f0f4dc520a157e4e81113b6362ff2e120c04d8b/68747470733a2f2f6c68362e67677068742e636f6d2f5530373062364c6836635673567778346a4e2d356e7130787169423150427a7259414250654a49456532685a513555574f78632d464455473737774144656c546f48413d683331302d7277)\u0026lt;/a\u0026gt; 25. GlowPadView Android4锁屏界面解锁 项目地址：\u0026lt;a\u0026gt;https://github.com/nadavfima/GlowPadView\u0026lt;/a\u0026gt; 效果图：\u0026lt;a\u0026gt;https://raw.github.com/nadavfima/GlowPadView/master/example.png\u0026lt;/a\u0026gt; 26. android-lockpattern Android的图案密码解锁 项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/android-lockpattern/\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=group.pals.android.lib.ui.lockpattern.demo\u0026lt;/a\u0026gt; 使用介绍：\u0026lt;a\u0026gt;https://code.google.com/p/android-lockpattern/wiki/QuickUse\u0026lt;/a\u0026gt; 示例APP：Android开机的图案密码解锁，支付宝的密码解锁 27. RangeBar 类似于SeekBar，不同的是可以选择一个范围内的值而不是单个值 项目地址：\u0026lt;a\u0026gt;https://github.com/edmodo/range-bar\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/range-bar-demo.apk?raw=true\u0026lt;/a\u0026gt; 效果图: \u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/0ff8267b4b90dc0ef973e612dd9a5eb2232735cb/687474703a2f2f692e696d6775722e636f6d2f7138354768526a6c2e706e67)\u0026lt;/a\u0026gt; 28. SuperToasts 更丰富样式的toast，支持Button、Progress、Horizontal Progress样式、支持进入动画、支持撤销及其动画设置 项目地址：\u0026lt;a\u0026gt;https://github.com/JohnPersano/SuperToasts\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.supertoastsdemo\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![SuperButtonToast](https://camo.githubusercontent.com/2c780a4dfb06cb4cc108a283ed6c091b7906df53/687474703a2f2f69313333312e70686f746f6275636b65742e636f6d2f616c62756d732f773539372f4a6f686e50657273616e6f2f7375706572746f617374735f676974687562696d6167655f7a707338613563656237632e706e67)\u0026lt;/a\u0026gt; 29. GoogleDateTimePickers 时间选择部件 项目地址：\u0026lt;a\u0026gt;https://github.com/Mirkoddd/GoogleDateTimePickers\u0026lt;/a\u0026gt; 文档地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.mirko.sample\u0026amp;hl=it\u0026lt;/a\u0026gt; 30. UndoBar 屏幕底部显示取消或是确认某操作 项目地址：\u0026lt;a\u0026gt;https://github.com/jenzz/Android-UndoBar\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/jenzz/Android-UndoBar/master/assets/Screenshot2.png)\u0026lt;/a\u0026gt; 31. ColorPickerPreference 颜色选择器 项目地址：\u0026lt;a\u0026gt;https://github.com/attenzione/android-ColorPickerPreference\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github.com/attenzione/android-ColorPickerPreference/raw/master/screen_2.png)\u0026lt;/a\u0026gt; 32. HoloGraphLibrary 绘制现状图、柱状图、饼状图 项目地址：\u0026lt;a\u0026gt;https://bitbucket.org/danielnadeau/holographlibrary/src\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://bitbucket.org/danielnadeau/holographlibrary/wiki/Home\u0026lt;/a\u0026gt; 33. ChromeView 利用Chromium实现的WebView，解决各个Android版本WebView不同的问题，同时利用最新Chrome代码 项目地址：\u0026lt;a\u0026gt;https://github.com/pwnall/chromeview\u0026lt;/a\u0026gt; 34. Discrollview 支持滚动时Item淡入淡出，平移，缩放效果的ScrollView 项目地址：\u0026lt;a\u0026gt;https://github.com/flavienlaurent/discrollview\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/flavienlaurent/discrollview/raw/master/sample.apk\u0026lt;/a\u0026gt; 35. Android Slider Preference Library 可添加到设置中的基于对话框的RankBar小部件 项目地址：\u0026lt;a\u0026gt;https://github.com/jayschwa/AndroidSliderPreference\u0026lt;/a\u0026gt; 36. ShowcaseView library 用于高亮显示应用程序的特定部分，从而突出突出重点 项目地址：\u0026lt;a\u0026gt;https://github.com/amlcurran/ShowcaseView\u0026lt;/a\u0026gt; 37. android-segmented-control Android上的Segmented Controls，相当于RadioButton组 项目地址：\u0026lt;a\u0026gt;https://github.com/hoang8f/android-segmented-control\u0026lt;/a\u0026gt; 38. PullScrollView 仿照新浪微博Android客户端个人中心的ScrollView，下拉背景伸缩回弹效果。 项目地址：\u0026lt;a\u0026gt;https://github.com/MarkMjw/PullScrollView\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/MarkMjw/PullScrollView/master/Screenshots/1.png)\u0026lt;/a\u0026gt; 39. ParallaxScrollView 支持视差滚动的ScrollView ，背景图片的滚动速度小于ScrollView中子控件的滚动速度 项目地址：\u0026lt;a\u0026gt;https://github.com/chrisjenx/ParallaxScrollView\u0026lt;/a\u0026gt; 示例APK地址：\u0026lt;a\u0026gt;https://github.com/chrisjenx/ParallaxScrollView/downloads\u0026lt;/a\u0026gt; 40. Android-Bootstrap Bootstrap 风格的按钮 项目地址： \u0026lt;a\u0026gt;https://github.com/Bearded-Hen/Android-Bootstrap\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/Bearded-Hen/Android-Bootstrap/master/images/device_image.png)\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E7%AC%AC%E4%BA%8C%E9%83%A8%E5%88%86-%E5%B7%A5%E5%85%B7%E5%BA%93\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;第二部分 工具库主要包括那些不错的开发库，包括依赖注入框架、图片缓存、网络相关、数据库ORM建模、Android公共库、Android 高版本向低版本兼容、多媒体相关及其他。\u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%B8%80%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5di\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;一、依赖注入DI通过依赖注入减少View、服务、资源简化初始化，事件绑定等重复繁琐工作 1. AndroidAnnotations(Code Diet) android快速开发框架 项目地址：\u0026lt;a\u0026gt;https://github.com/excilys/androidannotations\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/excilys/androidannotations/wiki\u0026lt;/a\u0026gt; 官方网站：\u0026lt;a\u0026gt;http://androidannotations.org/\u0026lt;/a\u0026gt; 特点：(1) 依赖注入：包括view，extras，系统服务，资源等等 (2) 简单的线程模型，通过annotation表示方法运行在ui线程还是后台线程 (3) 事件绑定：通过annotation表示view的响应事件，不用在写内部类 (4) REST客户端：定义客户端接口，自动生成REST请求的实现 (5) 没有你想象的复杂：AndroidAnnotations只是在在编译时生成相应子类 (6) 不影响应用性能：仅50kb，在编译时完成，不会对运行时有性能影响。 PS：与roboguice的比较：roboguice通过运行时读取annotations进行反射，所以可能影响应用性能，而AndroidAnnotations在编译时生成子类，所以对性能没有影响 2. roboguice 帮你处理了很多代码异常，利用annotation使得更少的代码完成项目 项目地址：\u0026lt;a\u0026gt;https://github.com/roboguice/roboguice\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/roboguice/roboguice/wiki\u0026lt;/a\u0026gt; 3. butterknife 利用annotation帮你快速完成View的初始化，减少代码 项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/butterknife\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://jakewharton.github.io/butterknife/\u0026lt;/a\u0026gt; 4. Dagger 依赖注入，适用于Android和Java 项目地址：\u0026lt;a\u0026gt;https://github.com/square/dagger\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://square.github.io/dagger/\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%BA%8C%E5%9B%BE%E7%89%87%E7%BC%93%E5%AD%98\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;二、图片缓存 1. Android-Universal-Image-Loader 图片缓存，目前使用最广泛的图片缓存，支持主流图片缓存的绝大多数特性。 项目地址：\u0026lt;a\u0026gt;https://github.com/nostra13/Android-Universal-Image-Loader\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/universal-imageloader-demo.apk?raw=true\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://www.intexsoft.com/blog/item/74-universal-image-loader-part-3.html\u0026lt;/a\u0026gt; 2. picasso square开源的图片缓存 项目地址：\u0026lt;a\u0026gt;https://github.com/square/picasso\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://square.github.io/picasso/\u0026lt;/a\u0026gt; 特点：(1)可以自动检测adapter的重用并取消之前的下载 (2)图片变换 (3)可以加载本地资源 (4)可以设置占位资源 (5)支持debug模式 3. ImageCache 图片缓存，包含内存和Sdcard缓存 项目地址：\u0026lt;a\u0026gt;https://github.com/Trinea/AndroidCommon\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=cn.trinea.android.demo\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://www.trinea.cn/android/android-imagecache/\u0026lt;/a\u0026gt; 特点：(1)支持预取新图片，支持等待队列 (2)包含二级缓存，可自定义文件名保存规则 (3)可选择多种缓存算法(FIFO、LIFO、LRU、MRU、LFU、MFU等13种)或自定义缓存算法 (4)可方便的保存及初始化恢复数据 (5)支持不同类型网络处理 (6)可根据系统配置初始化缓存等 \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%B8%89%E7%BD%91%E7%BB%9C%E7%9B%B8%E5%85%B3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;三、网络相关 1. Asynchronous Http Client for Android Android异步Http请求 项目地址：\u0026lt;a\u0026gt;https://github.com/loopj/android-async-http\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://loopj.com/android-async-http/\u0026lt;/a\u0026gt; 特点：(1) 在匿名回调中处理请求结果 (2) 在UI线程外进行http请求 (3) 文件断点上传 (4) 智能重试 (5) 默认gzip压缩 (6) 支持解析成Json格式 (7) 可将Cookies持久化到SharedPreferences 2. android-query 异步加载，更少代码完成Android加载 项目地址：\u0026lt;a\u0026gt;https://github.com/androidquery/androidquery\u0026lt;/a\u0026gt; 或 \u0026lt;a\u0026gt;https://code.google.com/p/android-query/\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://code.google.com/p/android-query/#Why_AQuery\u0026lt;/a\u0026gt;? Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.androidquery\u0026lt;/a\u0026gt; 特点：\u0026lt;a\u0026gt;https://code.google.com/p/android-query/#Why_AQuery\u0026lt;/a\u0026gt;? 3. Async Http Client Java异步Http请求 项目地址：\u0026lt;a\u0026gt;https://github.com/AsyncHttpClient/async-http-client\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://sonatype.github.io/async-http-client/\u0026lt;/a\u0026gt; 4. Ion 支持图片、json、http post等异步请求 项目地址：\u0026lt;a\u0026gt;https://github.com/koush/ion\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/koush/ion#more-examples\u0026lt;/a\u0026gt; 5. HttpCache Http缓存 项目地址：\u0026lt;a\u0026gt;https://github.com/Trinea/AndroidCommon\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=cn.trinea.android.demo\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://www.trinea.cn/android/android-http-cache\u0026lt;/a\u0026gt; 特点是：(1) 根据cache-control、expires缓存http请求 (2) 支持同步、异步Http请求 (3) 在匿名回调中处理请求结果 (4) 在UI线程外进行http请求 (5) 默认gzip压缩 6. Http Request 项目地址：\u0026lt;a\u0026gt;https://github.com/kevinsawicki/http-request\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/kevinsawicki/http-request#examples\u0026lt;/a\u0026gt; 7. okhttp square开源的http工具类 项目地址：\u0026lt;a\u0026gt;https://github.com/square/okhttp\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://square.github.io/okhttp/\u0026lt;/a\u0026gt; 特点：(1) 支持SPDY( \u0026lt;a\u0026gt;http://zh.wikipedia.org/wiki/SPDY\u0026lt;/a\u0026gt; )协议。SPDY协议是Google开发的基于传输控制协议的应用层协议，通过压缩，多路复用(一个TCP链接传送网页和图片等资源)和优先级来缩短加载时间。 (2) 如果SPDY不可用，利用连接池减少请求延迟 (3) Gzip压缩 (4) Response缓存减少不必要的请求 8. Retrofit RESTFUL API设计 项目地址：\u0026lt;a\u0026gt;https://github.com/square/retrofit\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://square.github.io/retrofit/\u0026lt;/a\u0026gt; 9. RoboSpice Android异步网络请求工具，支持缓存、REST等等 项目地址：\u0026lt;a\u0026gt;https://github.com/stephanenicolas/robospice\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/stephanenicolas/RoboDemo/downloads\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E5%9B%9B%E6%95%B0%E6%8D%AE%E5%BA%93-orm%E5%B7%A5%E5%85%B7%E5%8C%85\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;四、数据库 orm工具包orm的db工具类，简化建表、查询、更新、插入、事务、索引的操作 1. greenDAO Android Sqlite orm的db工具类 项目地址：\u0026lt;a\u0026gt;https://github.com/greenrobot/greenDAO\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://greendao-orm.com/documentation/\u0026lt;/a\u0026gt; 官方网站：\u0026lt;a\u0026gt;http://greendao-orm.com/\u0026lt;/a\u0026gt; 特点：(1) 性能佳 (2) 简单易用的API (3) 内存小好小 (4) 库大小小 2. ActiveAndroid Android Sqlite orm的db工具类 项目地址：\u0026lt;a\u0026gt;https://github.com/pardom/ActiveAndroid\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/pardom/ActiveAndroid/wiki/_pages\u0026lt;/a\u0026gt; 3. Sprinkles Android Sqlite orm的db工具类 项目地址：\u0026lt;a\u0026gt;https://github.com/emilsjolander/sprinkles\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://emilsjolander.github.io/blog/2013/12/18/android-with-sprinkles/\u0026lt;/a\u0026gt; 特点：比较显著的特点就是配合\u0026lt;a\u0026gt;https://github.com/square/retrofit\u0026lt;/a\u0026gt; 能保存从服务器获取的数据 4. ormlite-android 项目地址：\u0026lt;a\u0026gt;https://github.com/j256/ormlite-android\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://ormlite.com/sqlite_java_android_orm.shtml\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%BA%94android%E5%85%AC%E5%85%B1%E5%BA%93\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;五、Android公共库 1. Guava Google的基于java1.6的类库集合的扩展项目，包括collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O等等. 这些高质量的API可以使你的JAVa代码更加优雅，更加简洁 项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/guava-libraries/\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://code.google.com/p/guava-libraries/wiki/GuavaExplained\u0026lt;/a\u0026gt; 2. Volley Google提供的网络通信库，使得网络请求更简单、更快速 项目地址：\u0026lt;a\u0026gt;https://android.googlesource.com/platform/frameworks/volley\u0026lt;/a\u0026gt; Github地址：\u0026lt;a\u0026gt;https://github.com/mcxiaoke/android-volley\u0026lt;/a\u0026gt; 文档地址：\u0026lt;a\u0026gt;http://commondatastorage.googleapis.com/io-2013/presentations/110%20-%20Volley-%20Easy,%20Fast%20Networking%20for%20Android.pdf\u0026lt;/a\u0026gt; 3. AndroidCommon Android公共库 项目地址：\u0026lt;a\u0026gt;https://github.com/Trinea/AndroidCommon\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=cn.trinea.android.demo\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://www.trinea.cn/android/android-common-lib/\u0026lt;/a\u0026gt; 包括：(1)缓存(图片缓存、预取缓存、网络缓存) (2) 公共View(下拉及底部加载更多ListView、底部加载更多ScrollView、滑动一页Gallery) (3) Android常用工具类(网络、下载、Android资源操作、shell、文件、Json、随机数、Collection等等) 4. shipfaster 整合了Dagger Otto Retrofit Robolectric Picasso OkHttp，方便快速开发 项目地址：\u0026lt;a\u0026gt;https://github.com/pyricau/shipfaster\u0026lt;/a\u0026gt; 5. CleanAndroidCode 整合了Dagger Otto AndroidAnnotations，方便快速开发 项目地址：\u0026lt;a\u0026gt;https://github.com/pyricau/CleanAndroidCode\u0026lt;/a\u0026gt; 我目前也在做框架选型方面的工作，不出意外后面也会出个跟4、5类似的项目 \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E5%85%ADandroid-%E9%AB%98%E7%89%88%E6%9C%AC%E5%90%91%E4%BD%8E%E7%89%88%E6%9C%AC%E5%85%BC%E5%AE%B9\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;六、Android 高版本向低版本兼容 1. ActionBarSherlock 为Android所有版本提供统一的ActionBar，解决4.0以下ActionBar的适配问题 项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/ActionBarSherlock\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.demos\u0026lt;/a\u0026gt; APP示例：太多了。。现在连google都在用 2. Nine Old Androids 将Android 3.0(Honeycomb)所有动画API(ObjectAnimator ValueAnimator等)兼容到Android1.0 项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/NineOldAndroids\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.jakewharton.nineoldandroids.sample\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://nineoldandroids.com/\u0026lt;/a\u0026gt; 3. HoloEverywhere 将Android 3.0的Holo主题兼容到Android2.1++ 项目地址：\u0026lt;a\u0026gt;https://github.com/Prototik/HoloEverywhere\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://raw.github.com/Prototik/HoloEverywhere/repo/org/holoeverywhere/demo/2.1.0/demo-2.1.0.apk\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://android-developers.blogspot.com/2012/01/holo-everywhere.html\u0026lt;/a\u0026gt; 4. SherlockNavigationDrawer 将Android NavigationDrawer和ActionbarSherlock结合，解决4.0以下NavigationDrawer的适配问题 项目地址：\u0026lt;a\u0026gt;https://github.com/tobykurien/SherlockNavigationDrawer\u0026lt;/a\u0026gt; 5. Notifications4EveryWhere 将Android 4.1的兼容到Android2.2++ 项目地址：\u0026lt;a\u0026gt;https://github.com/youxiachai/Notifications4EveryWhere\u0026lt;/a\u0026gt; NavigationDrawer文档地址：\u0026lt;a\u0026gt;http://developer.android.com/training/implementing-navigation/nav-drawer.html\u0026lt;/a\u0026gt; 6. Android Switch Widget Backport 将Android Switch和SwitchPreference的兼容到Android2.1++ 项目地址：\u0026lt;a\u0026gt;https://github.com/BoD/android-switch-backport\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=org.jraf.android.backport.switchwidget.sample\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/BoD/android-switch-backport#using-the-switch\u0026lt;/a\u0026gt; 7. android-datepicker 将Android 4.0的datepicker兼容到Android2.2++ 项目地址：\u0026lt;a\u0026gt;https://github.com/SimonVT/android-datepicker\u0026lt;/a\u0026gt; 8. GlowPadBackport Android 4.2的GlowPadView向后适配到API4以上 项目地址：\u0026lt;a\u0026gt;https://github.com/frakbot/GlowPadBackport\u0026lt;/a\u0026gt;\u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%B8%83%E5%A4%9A%E5%AA%92%E4%BD%93%E7%9B%B8%E5%85%B3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;七、多媒体相关 1. cocos2d-x 跨平台的2d游戏框架，支持Android、IOS、Linux、Windows等众多平台 项目地址：\u0026lt;a\u0026gt;https://github.com/cocos2d/cocos2d-x\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://www.cocos2d-x.org/wiki\u0026lt;/a\u0026gt; 官方网站：\u0026lt;a\u0026gt;http://www.cocos2d-x.org/\u0026lt;/a\u0026gt; 2. Vitamio 是一款Android与iOS平台上的全能多媒体开发框架 项目地址：\u0026lt;a\u0026gt;https://github.com/yixia/VitamioBundle\u0026lt;/a\u0026gt; 网站介绍：\u0026lt;a\u0026gt;http://www.vitamio.org/docs/\u0026lt;/a\u0026gt; 特点：(1) 全面支持硬件解码与GPU渲染 (2) 能够流畅播放720P甚至1080P高清MKV，FLV，MP4，MOV，TS，RMVB等常见格式的视频 (3) 在Android与iOS上跨平台支持 MMS, RTSP, RTMP, HLS(m3u8)等常见的多种视频流媒体协议，包括点播与直播。 3. PhotoProcessing 利用ndk处理图片库，支持Instafix、Ansel、Testino、XPro、Retro、BW、Sepia、Cyano、Georgia、Sahara、HDR、Rotate(旋转)、Flip(翻转)等各种特效 项目地址：\u0026lt;a\u0026gt;https://github.com/lightbox/PhotoProcessing\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/photo-processing.apk?raw=true\u0026lt;/a\u0026gt; 4. Android StackBlur 图片模糊效果工具类 项目地址：\u0026lt;a\u0026gt;https://github.com/kikoso/android-stackblur\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/kikoso/android-stackblur/blob/master/StackBlurDemo/bin/StackBlurDemo.apk?raw=true\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/kikoso/android-stackblur#usage\u0026lt;/a\u0026gt; 5. Bitmap Smart Clipping using OpenCV 图片智能裁剪保留重要部分显示 项目地址：\u0026lt;a\u0026gt;https://github.com/beartung/tclip-android\u0026lt;/a\u0026gt; 利用淘宝的 \u0026lt;a\u0026gt;http://code.taobao.org/p/tclip/\u0026lt;/a\u0026gt; 库完成 一淘玩客正在使用的图片裁剪，自动识别图片中的重要区域，并且在图片裁剪时保留重要区域 特点：(1). 能进行人脸识别。图片中有人脸，将自动视为人脸区域为重要区域，将不会被裁剪掉 (2).自动其它重要区域。如果图片中未识别出人脸，则会根据特征分布计算出重区域 6. Cropper 图片局部剪切工具，可触摸控制选择区域或旋转 项目地址：\u0026lt;a\u0026gt;https://github.com/edmodo/cropper\u0026lt;/a\u0026gt; 使用介绍：\u0026lt;a\u0026gt;https://github.com/edmodo/cropper/wiki\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github-camo.global.ssl.fastly.net/e4fde77bf41d4a60b234b4e268e5cfa8c17d9b6f/687474703a2f2f692e696d6775722e636f6d2f334668735467666c2e6a7067)\u0026lt;/a\u0026gt; 7. android-crop 图片裁剪Activity 项目地址：\u0026lt;a\u0026gt;https://github.com/jdamcd/android-crop\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github.com/jdamcd/android-crop/raw/master/screenshot.png)\u0026lt;/a\u0026gt; 8. TileView 可分块显示大图，支持2D拖动、双击、双指放大、双指捏合 项目地址：\u0026lt;a\u0026gt;https://github.com/moagrius/TileView\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;http://moagrius.github.io/TileView/TileViewDemo.apk\u0026lt;/a\u0026gt; 9. BlurEffectForAndroidDesign 图片模糊效果 项目地址：\u0026lt;a\u0026gt;https://github.com/PomepuyN/BlurEffectForAndroidDesign\u0026lt;/a\u0026gt; 10. android-eye PC端网页查看同一局域网内的手机摄像头内容，可以用来监控哦 项目地址：\u0026lt;a\u0026gt;https://github.com/Teaonly/android-eye\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=teaonly.droideye\u0026lt;/a\u0026gt; 11. libpng for Android PNG图片的jni库，支持几乎png的所有特性 项目地址：\u0026lt;a\u0026gt;https://github.com/julienr/libpng-android\u0026lt;/a\u0026gt; 文档地址：\u0026lt;a\u0026gt;http://www.libpng.org/pub/png/libpng.html\u0026lt;/a\u0026gt; 12. android-gpuimage 基于GPU的图片滤镜 项目地址：\u0026lt;a\u0026gt;https://github.com/CyberAgent/android-gpuimage\u0026lt;/a\u0026gt; 13. AndroidFaceCropper 图片脸部自动识别，将识别后的局部图片返回 项目地址：\u0026lt;a\u0026gt;https://github.com/lafosca/AndroidFaceCropper\u0026lt;/a\u0026gt; 14. Android Video Crop 利用TextureView播放和剪切视频，类似ImageView.setScaleType 项目地址：\u0026lt;a\u0026gt;https://github.com/dmytrodanylyk/android-video-crop\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/lafosca/AndroidFaceCropper/releases/download/1.0/FaceCropper-sample-debug-unaligned.apk\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E5%85%AB%E4%BA%8B%E4%BB%B6%E6%80%BB%E7%BA%BF%E8%AE%A2%E9%98%85%E8%80%85%E6%A8%A1%E5%BC%8F\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;八、事件总线(订阅者模式)通过发布/订阅事件解耦事件发送和接受，从而简化应用程序组件(Activities, Fragments及后台线程)之间的通信 1. EventBus greenrobot的开源项目 项目地址：\u0026lt;a\u0026gt;https://github.com/greenrobot/EventBus\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/greenrobot/EventBus#general-usage-and-api\u0026lt;/a\u0026gt; 特点：(1) 支持在不同类型的线程中处理订阅，包括发布所在线程，UI线程、单一后台线程、异步线程 (2) 支持事件优先级定义，支持优先级高的订阅者取消事件继续传递，支持粘性事件，是不是跟系统的有序广播、粘性广播很像啊 (3) 不是基于annotations (4) 性能更优 (5) 体积小 (6) 支持单例创建或创建多个对象 (7) 支持根据事件类型订阅 2. Otto Square的开源项目，基于Guava的Android优化 项目地址：\u0026lt;a\u0026gt;https://github.com/square/otto\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://square.github.io/otto/\u0026lt;/a\u0026gt; \u0026lt;a\u0026gt;EventBus与Otto的功能及性能对比文档\u0026lt;/a\u0026gt; \u0026lt;a\u0026gt;EventBus与Otto性能对比Demo Apk\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%B9%9D%E4%BC%A0%E6%84%9F%E5%99%A8\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;九、传感器 1. Great Android Sensing Toolkit Android感应器工具包，包含示例及使用过程中可能需要的算法 项目地址：\u0026lt;a\u0026gt;https://github.com/gast-lib/gast-lib\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=root.gast.playground\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/gast-lib/gast-lib#documentation\u0026lt;/a\u0026gt; 2. SensorManager Android传感器管理 项目地址：\u0026lt;a\u0026gt;https://github.com/nlathia/SensorManager\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://docs.google.com/document/d/1TqThJULb-4e6TGb1gdkAaPCfyuXStjJpbnt7a0OZ9OE/edit\u0026lt;/a\u0026gt; 3. GPSLogger 记录GPS信息 项目地址：\u0026lt;a\u0026gt;https://github.com/mendhak/gpslogger\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.mendhak.gpslogger\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://code.mendhak.com/gpslogger/\u0026lt;/a\u0026gt; 4. Pedometer 计步器，使用硬件计步感应器 项目地址：\u0026lt;a\u0026gt;https://github.com/j4velin/Pedometer\u0026lt;/a\u0026gt; 5. leapcast ChromeCast模拟器的App 项目地址：\u0026lt;a\u0026gt;https://github.com/dz0ny/leapcast\u0026lt;/a\u0026gt; 6. Arduino-Communicator 与Arduino通信的App 项目地址：\u0026lt;a\u0026gt;https://github.com/jeppsson/Arduino-Communicator\u0026lt;/a\u0026gt; 7. android-pedometer Android计步器 项目地址：\u0026lt;a\u0026gt;https://github.com/bagilevi/android-pedometer\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;http://pedometer.googlecode.com/files/Pedometer-1.4.apk\u0026lt;/a\u0026gt; 8. OwnTracks for Android 自己的轨迹记录 项目地址：\u0026lt;a\u0026gt;https://github.com/owntracks/android\u0026lt;/a\u0026gt; 9. Shake Detector library for Android Android手机震动摇晃检测库，提供供UI线程调用的回调接口 项目地址：\u0026lt;a\u0026gt;https://github.com/tbouron/ShakeDetector\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.github.tbouron.shakedetector.example\u0026lt;/a\u0026gt; 10. Android heart rate monitor Android心跳检测 项目地址：\u0026lt;a\u0026gt;https://github.com/phishman3579/android-heart-rate-monitor\u0026lt;/a\u0026gt; 11. Bluetooth LE Library for Android 蓝牙源信息，包括宝库Mac、更新时间、RSSI、UUID、信号源距离、影响范围等信息 项目地址：\u0026lt;a\u0026gt;https://github.com/alt236/Bluetooth-LE-Library\u0026amp;#8212;Android\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=uk.co.alt236.btlescan\u0026lt;/a\u0026gt; 12. farebot 通过NFC 从公交卡中读取数据的一个应用 项目地址：\u0026lt;a\u0026gt;https://github.com/codebutler/farebot\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E5%8D%81%E5%AE%89%E5%85%A8\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;十、安全 1. SQLCipher Sqlite加密工具 项目地址：\u0026lt;a\u0026gt;https://github.com/sqlcipher/sqlcipher\u0026lt;/a\u0026gt; 帮助文档：\u0026lt;a\u0026gt;http://sqlcipher.net/sqlcipher-for-android/\u0026lt;/a\u0026gt; 2. Conceal 快速高效的进行文件加密解密 项目地址：\u0026lt;a\u0026gt;https://github.com/facebook/conceal\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/facebook/conceal#usage\u0026lt;/a\u0026gt; 3. Android-PasscodeLock 应用锁，每次启动或从任何Activity启动应用都需要输入四位数字的密码方可进入 项目地址：\u0026lt;a\u0026gt;https://github.com/wordpress-mobile/Android-PasscodeLock\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.sothree.umano\u0026lt;/a\u0026gt; APP示例：Wordpress Android，支付宝，挖财 4. GlowPadBackport 将Android4.2的锁屏界面解锁扩展到Android1.6及1.6+ 项目地址：\u0026lt;a\u0026gt;https://github.com/rock3r/GlowPadBackport\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=net.sebastianopoggi.samples.ui.GlowPadSample\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/1f0f4dc520a157e4e81113b6362ff2e120c04d8b/68747470733a2f2f6c68362e67677068742e636f6d2f5530373062364c6836635673567778346a4e2d356e7130787169423150427a7259414250654a49456532685a513555574f78632d464455473737774144656c546f48413d683331302d7277)\u0026lt;/a\u0026gt; 5. GlowPadView Android 4锁屏界面解锁 项目地址：\u0026lt;a\u0026gt;https://github.com/nadavfima/GlowPadView\u0026lt;/a\u0026gt; 效果图：\u0026lt;a\u0026gt;https://raw.github.com/nadavfima/GlowPadView/master/example.png\u0026lt;/a\u0026gt; 6. android-lockpattern Android的图案密码解锁 项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/android-lockpattern/\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=group.pals.android.lib.ui.lockpattern.demo\u0026lt;/a\u0026gt; 使用介绍：\u0026lt;a\u0026gt;https://code.google.com/p/android-lockpattern/wiki/QuickUse\u0026lt;/a\u0026gt; 示例APP：Android开机的图案密码解锁，支付宝的密码解锁 \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E5%8D%81%E4%B8%80%E5%85%B6%E4%BB%96\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;十一、其他 1. Salvage view 带View缓存的Viewpager PagerAdapter，很方便使用 项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/salvage\u0026lt;/a\u0026gt; 2. Android Priority Job Queue Android后台任务队列 项目地址：\u0026lt;a\u0026gt;https://github.com/path/android-priority-jobqueue\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/path/android-priority-jobqueue#getting-started\u0026lt;/a\u0026gt; 3. jsoup 一个解析html的java库，可方便的提取和操作数据 项目地址：\u0026lt;a\u0026gt;https://github.com/jhy/jsoup\u0026lt;/a\u0026gt; 官方网站：\u0026lt;a\u0026gt;http://jsoup.org/\u0026lt;/a\u0026gt; 作用：(1) 从一个url、文件或string获得html并解析 (2) 利用dom遍历或css选择器查找、提取数据 (3) 操作html元素 (4) 根据白名单去除用于提交的非法数据防止xss攻击 (5) 输出整齐的html 4. ZIP java压缩和解压库 项目地址：\u0026lt;a\u0026gt;https://github.com/zeroturnaround/zt-zip\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/zeroturnaround/zt-zip#examples\u0026lt;/a\u0026gt; 作用：(1) 解压和压缩，并支持文件夹内递归操作 (2) 支持包含和排除某些元素 (3) 支持重命名元素 (4) 支持遍历zip包内容 (5) 比较两个zip包等功能 5. Cobub Razor 开源的mobile行为分析系统，包括web端、android端，支持ios和window phone 项目地址：\u0026lt;a\u0026gt;https://github.com/cobub/razor\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;http://demo.cobub.com/razor\u0026lt;/a\u0026gt; 网站介绍：\u0026lt;a\u0026gt;http://dev.cobub.com/\u0026lt;/a\u0026gt; 6. aFileChooser 文件选择器，可内嵌到程序中，而无需使用系统或三方文件选择器。 项目地址：\u0026lt;a\u0026gt;https://github.com/iPaulPro/aFileChooser\u0026lt;/a\u0026gt; 7. androidpn 基于xmpp协议的消息推送解决方案，包括服务器端和android端。 项目地址：\u0026lt;a\u0026gt;https://github.com/dannytiehui/androidpn\u0026lt;/a\u0026gt; 8. Android Plugin Framework Android插件式开发 项目地址：\u0026lt;a\u0026gt;https://github.com/umeng/apf\u0026lt;/a\u0026gt; 9. purePDF 允许从任何运行的SWF文件读取和创建PDF文档 项目地址：\u0026lt;a\u0026gt;https://github.com/sephiroth74/purePDF\u0026lt;/a\u0026gt; 10. Bolts Android的异步编程模式 项目地址：\u0026lt;a\u0026gt;https://github.com/BoltsFramework/Bolts-Android/\u0026lt;/a\u0026gt; 与AsyncTask比较：(1) 使用的是无大小限制的线程池 (2) 任务可组合可级联，防止了代码耦合 11. CastCompanionLibrary-android 使Android程序中更快的接入Google Cast 项目地址：\u0026lt;a\u0026gt;https://github.com/googlecast/CastCompanionLibrary-android\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://developers.google.com/cast/\u0026lt;/a\u0026gt; 12. CastVideos-android 从Android设备分享Video通过Google Cast 项目地址：\u0026lt;a\u0026gt;https://github.com/googlecast/CastVideos-android\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://developers.google.com/cast/\u0026lt;/a\u0026gt; 13. Uninstall_Statics Android应用自身被卸载监听及打开浏览器等反馈功能实现 项目地址：\u0026lt;a\u0026gt;https://github.com/sevenler/Uninstall_Statics\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://www.cnblogs.com/zealotrouge/p/3157126.html\u0026lt;/a\u0026gt; \u0026lt;a\u0026gt;http://www.cnblogs.com/zealotrouge/p/3159772.html\u0026lt;/a\u0026gt; 14. xCombine Android App插件式插件开发 项目地址：\u0026lt;a\u0026gt;https://github.com/wyouflf/xCombine\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://my.oschina.net/u/1171837/blog/155377\u0026lt;/a\u0026gt; 15. Memento 保证在系统配置改变时，Activity中的某些数据可以简单安全的保持不变 项目地址：\u0026lt;a\u0026gt;https://github.com/mttkay/memento\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/mttkay/memento#usage\u0026lt;/a\u0026gt; 16. svg-android Android Svg矢量图形支持 项目地址：\u0026lt;a\u0026gt;https://github.com/japgolly/svg-android\u0026lt;/a\u0026gt; \u0026lt;a\u0026gt;https://github.com/japgolly/svg-android\u0026lt;/a\u0026gt; 17. Office 365 SDK for Android Preview 可支持Microsoft SharePoint Lists, Microsoft SharePoint Files, Microsoft Exchange Calendar, Microsoft Exchange Contacts, Microsoft Exchange Mail 项目地址：\u0026lt;a\u0026gt;https://github.com/OfficeDev/Office-365-SDK-for-Android\u0026lt;/a\u0026gt; 18. OpenSpritz-Android Epub阅读器 项目地址：\u0026lt;a\u0026gt;https://github.com/OnlyInAmerica/OpenSpritz-Android\u0026lt;/a\u0026gt; 19. FreeFlow 布局引擎，更简单的创建自定义布局，并且当数据和布局改变时更美观的过渡动画 项目地址：\u0026lt;a\u0026gt;https://github.com/Comcast/FreeFlow\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/Comcast/FreeFlow/releases\u0026lt;/a\u0026gt; 20. Android Gesture Detectors Framework Android手势框架，支持双指旋转、移动、平移、缩放等 项目地址：\u0026lt;a\u0026gt;https://github.com/Almeros/android-gesture-detectors\u0026lt;/a\u0026gt; 21. Mapbox Android SDK Android Map的替代版 项目地址：\u0026lt;a\u0026gt;https://github.com/mapbox/mapbox-android-sdk\u0026lt;/a\u0026gt; 22. Activity animation Activity跳转动画，支持各个方向波浪的效果 项目地址：\u0026lt;a\u0026gt;https://github.com/flavienlaurent/activityanimation\u0026lt;/a\u0026gt; 在线演示：\u0026lt;a\u0026gt;https://www.youtube.com/watch?v=-E0sc6w_Jck\u0026lt;/a\u0026gt; 23. dynamic-load-apk Android动态加载Apk，热部署 项目地址：\u0026lt;a\u0026gt;https://github.com/singwhatiwanna/dynamic-load-apk\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://blog.csdn.net/singwhatiwanna/article/details/22597587\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E7%AC%AC%E4%B8%89%E9%83%A8%E5%88%86-%E4%BC%98%E7%A7%80%E9%A1%B9%E7%9B%AE\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;第三部分 优秀项目主要介绍那些Android还不错的完整项目，目前包含的项目主要依据是项目有意思或项目分层规范比较好。 Linux 项目地址：\u0026lt;a\u0026gt;https://github.com/torvalds/linux\u0026lt;/a\u0026gt; Android 项目地址：\u0026lt;a\u0026gt;https://android.googlesource.com/\u0026lt;/a\u0026gt; 或 \u0026lt;a\u0026gt;https://github.com/android\u0026lt;/a\u0026gt; 以上两个项目，不解释 (1) ZXing 二维码扫描工具 项目地址：\u0026lt;a\u0026gt;https://github.com/zxing/zxing\u0026lt;/a\u0026gt; 或 \u0026lt;a\u0026gt;https://code.google.com/p/zxing/\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.google.zxing.client.android\u0026lt;/a\u0026gt; PS：现在市面上很多应用的二维码扫描功能都是从这个修改而来 (2) photup 编辑机批量上传照片到facebook上 项目地址：\u0026lt;a\u0026gt;https://github.com/chrisbanes/photup\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=uk.co.senab.photup\u0026lt;/a\u0026gt; PS：代码分包合理，很棒。不过这个项目依赖的开源项目比较多，比较难编译 (3) github-android Github的Android客户端项目 项目地址：\u0026lt;a\u0026gt;https://github.com/github/android\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.github.mobile\u0026lt;/a\u0026gt; (4) Notes MIUI便签 项目地址：\u0026lt;a\u0026gt;https://github.com/MiCode/Notes\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/miui-note-demo.apk?raw=true\u0026lt;/a\u0026gt; PS：项目分包比较合理，相比较miui的文件管理器\u0026lt;a\u0026gt;https://github.com/MiCode/FileExplorer\u0026lt;/a\u0026gt; 代码规范较好得多 (5) weicuiyuan 四次元-新浪微博客户端 项目地址：\u0026lt;a\u0026gt;https://github.com/qii/weiciyuan\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=org.qii.weiciyuan\u0026lt;/a\u0026gt; (6) gnucash-android 一个记账理财软件 项目地址：\u0026lt;a\u0026gt;https://github.com/codinguser/gnucash-android\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;http://play.google.com/store/apps/details?id=org.gnucash.android\u0026lt;/a\u0026gt; (7) AntennaPod 支持rss订阅、音乐订阅 项目地址：\u0026lt;a\u0026gt;https://github.com/danieloeh/AntennaPod\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=de.danoeh.antennapod\u0026lt;/a\u0026gt; (8) ChaseWhisplyProject 打鬼游戏 项目地址：\u0026lt;a\u0026gt;https://github.com/tvbarthel/ChaseWhisplyProject\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=fr.tvbarthel.games.chasewhisply\u0026lt;/a\u0026gt; (9) Tweet Lanes 功能完整的Twitter客户端 项目地址：\u0026lt;a\u0026gt;https://github.com/chrislacy/TweetLanes\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.tweetlanes.android\u0026lt;/a\u0026gt; (10) Financius 简单易用的记账程序 项目地址：\u0026lt;a\u0026gt;https://github.com/mvarnagiris/Financius\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.code44.finance\u0026lt;/a\u0026gt; (11) todo.txt-android todo.txt的官方Android应用 项目地址：\u0026lt;a\u0026gt;https://github.com/ginatrapani/todo.txt-android\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.todotxt.todotxttouch\u0026lt;/a\u0026gt; (12) simpletask 基于todo.txt官方应用的另一个客户端 项目地址：\u0026lt;a\u0026gt;https://github.com/mpcjanssen/simpletask-android\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=nl.mpcjanssen.todotxtholo\u0026lt;/a\u0026gt; (13) Muzei Live Wallpaper 定时更换桌面精美壁纸 项目地址：\u0026lt;a\u0026gt;https://github.com/romannurik/muzei\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=net.nurik.roman.muzei\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E7%AC%AC%E5%9B%9B%E9%83%A8%E5%88%86-%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7%E5%8F%8A%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;第四部分 开发工具及测试工具主要介绍和[Android开发](http://www.eoeandroid.com/)工具和测试工具相关的开源项目。\u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%B8%80%E5%BC%80%E5%8F%91%E6%95%88%E7%8E%87%E5%B7%A5%E5%85%B7\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;一、开发效率工具 1. Json2Java 根据JSon数据自动生成对应的Java实体类，还支持Parcel、Gson Annotations对应代码自动生成。期待后续的提取父类以及多url构建整个工程的功能 项目地址：\u0026lt;a\u0026gt;https://github.com/jonfhancock/JsonToJava\u0026lt;/a\u0026gt; 在线演示：\u0026lt;a\u0026gt;http://jsontojava.appspot.com/\u0026lt;/a\u0026gt; 2. IntelliJ Plugin for Android Parcelable boilerplate code generation Android studio插件，生成Parcelable代码 项目地址：\u0026lt;a\u0026gt;https://github.com/mcharmas/android-parcelable-intellij-plugin\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Holo Colors Idea](https://github.com/mcharmas/android-parcelable-intellij-plugin/raw/master/screenshot.png)\u0026lt;/a\u0026gt; 3. Android Holo Colors IntelliJ Plugin Android studio插件，生成holo样式9 patch图片 项目地址：\u0026lt;a\u0026gt;https://github.com/jeromevdl/android-holo-colors-idea-plugin\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Holo Colors Idea](https://raw.github.com/jeromevdl/android-holo-colors-idea-plugin/master/other/holocolorsidea.png)\u0026lt;/a\u0026gt; 4. Android Drawable Factory 用于生成各个分辨率的图片 项目地址：\u0026lt;a\u0026gt;https://github.com/tizionario/AndroidDrawableFactory\u0026lt;/a\u0026gt; 效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Android Drawable Factory](https://github-camo.global.ssl.fastly.net/5c3844b345a9779296f996490070dab0bfc9dbf5/68747470733a2f2f646c2e64726f70626f7875736572636f6e74656e742e636f6d2f752f32363636343637352f416e64726f69644472617761626c65466163746f72792f312e706e67)\u0026lt;/a\u0026gt; 5. SelectorChapek for Android Android Studio插件，可根据固定文件名格式资源自动生成drawable selectors xml文件。 项目地址：\u0026lt;a\u0026gt;https://github.com/inmite/android-selector-chapek\u0026lt;/a\u0026gt; 6. Android Action Bar Style Generator Android ActionBar样式生成器，可在线选择ActionBar样式自动生成所需要的图片资源及xml文件 项目地址：\u0026lt;a\u0026gt;https://github.com/jgilfelt/android-actionbarstylegenerator\u0026lt;/a\u0026gt; 在线演示：\u0026lt;a\u0026gt;http://jgilfelt.github.io/android-actionbarstylegenerator/\u0026lt;/a\u0026gt; 7. ButterKnifeZelezny 用于快速生成\u0026lt;a\u0026gt;ButterKnife\u0026lt;/a\u0026gt;View注入代码的Android Studio/IDEA插件 项目地址：\u0026lt;a\u0026gt;https://github.com/inmite/android-butterknife-zelezny\u0026lt;/a\u0026gt; 8. RoboCoP 利用Gradle task根据固定格式的json文件生成ContentProvider 项目地址：\u0026lt;a\u0026gt;https://github.com/mediarain/RoboCoP\u0026lt;/a\u0026gt; 9. appiconsizes 用于生成各个分辨率的图片 项目地址：\u0026lt;a\u0026gt;http://www.appiconsizes.com/\u0026lt;/a\u0026gt; 10. Gradle Retrolambda Plugin \u0026lt;a\u0026gt;Retrolambda\u0026lt;/a\u0026gt;是将Java8的Lambdas应用于Java7的工具，本项目是Gradle插件，通过Retrolambda从而使Java或Android项目用Java8的Lambdas编写，将编译后的字节码转换为Java6和7的字节码从而正常运行 项目地址：\u0026lt;a\u0026gt;https://github.com/evant/gradle-retrolambda\u0026lt;/a\u0026gt; 11. Dagger IntelliJ Plugin dagger的intellij插件 项目地址：\u0026lt;a\u0026gt;https://github.com/square/dagger-intellij-plugin\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%BA%8C%E5%BC%80%E5%8F%91%E8%87%AA%E6%B5%8B%E7%9B%B8%E5%85%B3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;二、开发自测相关 1. Quality Tools for Android Android测试及自测工具集合和示例 项目地址：\u0026lt;a\u0026gt;https://github.com/stephanenicolas/Quality-Tools-for-Android\u0026lt;/a\u0026gt; 2. android-test-kit Google的Android测试工具 包括GoogleInstrumentationTestRunner(增强版的InstrumentationTestRunner)和Espresso(用于快速写出可靠测试用例的API) 项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/android-test-kit/\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://code.google.com/p/android-test-kit/w/list\u0026lt;/a\u0026gt; 3. robolectric 测试用例编写框架 项目地址：\u0026lt;a\u0026gt;https://github.com/robolectric/robolectric\u0026lt;/a\u0026gt; Demo地址：\u0026lt;a\u0026gt;https://github.com/robolectric/robolectricsample\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;http://robolectric.org/\u0026lt;/a\u0026gt; 特点：(1). 不需要模拟器在一般JVM就可以运行测试用例 (2). 能完成在真机上的大部分测试包括感应器 其他的测试用例及相关模块Mock可见：\u0026lt;a\u0026gt;android-mock\u0026lt;/a\u0026gt;, \u0026lt;a\u0026gt;mockito\u0026lt;/a\u0026gt;, \u0026lt;a\u0026gt;easy-mock\u0026lt;/a\u0026gt; 4. Android FEST 提供一些列方便的断言，可用于提高编写Android自测代码效率 项目地址：\u0026lt;a\u0026gt;https://github.com/square/fest-android\u0026lt;/a\u0026gt; 5. BoundBox 可用于测试类各种访问权限的属性、方法。实际是通过BoundBox这个annotation生成一个属性和方法都是public权限的中间类并对此类进行测试完成的 项目地址：\u0026lt;a\u0026gt;https://github.com/stephanenicolas/boundbox\u0026lt;/a\u0026gt; 6. Hugo 用于打印函数信息及执行时间的工具，仅在debug模式生效 项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/hugo\u0026lt;/a\u0026gt; 7. scalpel 在应用下面添加一层用于界面调试，待详细补充 // TODO 项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/scalpel\u0026lt;/a\u0026gt; 8. Android Screenshot library Android截图工具类，用于在持续集成时截图 项目地址：\u0026lt;a\u0026gt;https://github.com/rtyley/android-screenshot-lib\u0026lt;/a\u0026gt; 9. sonar-android-lint-plugin 将android lint的错误在sonar中展现 项目地址：\u0026lt;a\u0026gt;https://github.com/SonarCommunity/sonar-android\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%B8%89%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;三、测试工具 1. Spoon 可用于android不同机型设备自动化测试，能将应用apk和测试apk运行在不同机器上并生成相应测试报告。 项目地址：\u0026lt;a\u0026gt;https://github.com/square/spoon\u0026lt;/a\u0026gt; 2. Tencent APT APT是腾讯开源的一个Android平台高效性能测试组件，提供丰富实用的功能，适用于开发自测、定位性能瓶颈；测试人员完成性能基准测试、竞品对比测试 项目地址：\u0026lt;a\u0026gt;https://github.com/stormzhang/APT\u0026lt;/a\u0026gt; 3. Emmagee 网易开源的性能测试工具，包括CPU、内存、网络流量、启动时间、电池状态等 项目地址：\u0026lt;a\u0026gt;https://github.com/NetEase/Emmagee\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E5%9B%9B%E5%BC%80%E5%8F%91%E5%8F%8A%E7%BC%96%E8%AF%91%E7%8E%AF%E5%A2%83\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;四、开发及编译环境 1. Buck facebook开源的Android编译工具，效率是ant的两倍。主要优点在于： (1) 加快编译速度，通过并行利用多核cpu和跟踪不变资源减少增量编译时间实现 (2) 可以在编译系统中生成编译规则而无须另外的系统生成编译规则文件 (3) 编译同时可生成单元测试结果 (4) 既可用于IDE编译也可用于持续集成编译 (5) facebook持续优化中 项目地址：\u0026lt;a\u0026gt;https://github.com/facebook/buck\u0026lt;/a\u0026gt; 2. Android Maven Plugin Android Maven插件，可用于对android三方依赖进行管理。在J2EE开发中，maven是非常成熟的依赖库管理工具，可统一管理依赖库。 项目地址：\u0026lt;a\u0026gt;https://github.com/jayway/maven-android-plugin\u0026lt;/a\u0026gt; 3. umeng-muti-channel-build-tool 渠道打包工具 项目地址：\u0026lt;a\u0026gt;https://github.com/umeng/umeng-muti-channel-build-tool\u0026lt;/a\u0026gt; 另可参见Google的构建系统Gradle：\u0026lt;a\u0026gt;http://tools.android.com/tech-docs/new-build-system/user-guide\u0026lt;/a\u0026gt; 4. Genymotion 目前最好用最快的android模拟器 项目地址：\u0026lt;a\u0026gt;http://www.genymotion.com/\u0026lt;/a\u0026gt; Android studio集成控件： \u0026lt;a\u0026gt;http://plugins.jetbrains.com/plugin/7269?pr=idea\u0026lt;/a\u0026gt; Cyril Mottier推荐：\u0026lt;a\u0026gt;http://cyrilmottier.com/2013/06/27/a-productive-android-development-environment/\u0026lt;/a\u0026gt; 5. gradle-mvn-push 方便的将Gradle的Artifacts上传到Maven仓库 项目地址：\u0026lt;a\u0026gt;https://github.com/chrisbanes/gradle-mvn-push\u0026lt;/a\u0026gt; 文档介绍：\u0026lt;a\u0026gt;https://github.com/chrisbanes/gradle-mvn-push#usage\u0026lt;/a\u0026gt; 6. Android Emulator Plugin for Jenkins Android模拟器 jenkins插件，用于Jenkins做持续集成时跑模拟器测试 项目地址：\u0026lt;a\u0026gt;https://github.com/jenkinsci/android-emulator-plugin\u0026lt;/a\u0026gt; 7. Android Maven Plugin 管理应用所需要的依赖库。包括的构建工具有Maven、Gradle、ant、sbt 项目地址：\u0026lt;a\u0026gt;https://github.com/mosabua/maven-android-sdk-deployer\u0026lt;/a\u0026gt; 8. SDK Manager Plugin 下载和管理Android SDK的Gradle插件 项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/sdk-manager-plugin\u0026lt;/a\u0026gt; \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt; \u0026lt;a name=\u0026quot;user-content-%E4%BA%94%E5%85%B6%E4%BB%96\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;五、其他 1. ViewServer 允许app运行在任何手机上都可以用HierarchyViewer查看 项目地址：\u0026lt;a\u0026gt;https://github.com/romainguy/ViewServer\u0026lt;/a\u0026gt; 2. GridWichterle for Android 在整个系统上显示一个grid，用来帮助查看应用布局及使得布局更美观，可设置grid网格大小和颜色，android推荐48dp和8dp，可见 Android Design Guidelines – Metrics and Grids 项目地址：\u0026lt;a\u0026gt;https://github.com/inmite/android-grid-wichterle\u0026lt;/a\u0026gt; APK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=eu.inmite.android.gridwichterle\u0026lt;/a\u0026gt; PS：比起hierarchyviewer相差甚远，不过偶尔可用来作为布局查看工具。 3. Catlog 手机端log查看工具，支持不同颜色显示、关键字过滤、级别过滤、进程id过滤、录制功能等 项目地址：\u0026lt;a\u0026gt;https://github.com/nolanlawson/Catlog\u0026lt;/a\u0026gt; 在线演示：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.nolanlawson.logcat\u0026lt;/a\u0026gt; 4. PID Cat 根据package查看logcat日志 项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/pidcat\u0026lt;/a\u0026gt; 5. ACRA 应用崩溃信息上报到GoogleDoc工具，网页版展现结果三方开源地址\u0026lt;a\u0026gt;https://github.com/BenoitDuffez/crashreportsviewer\u0026lt;/a\u0026gt; 项目地址：\u0026lt;a\u0026gt;https://github.com/ACRA/acra\u0026lt;/a\u0026gt; 文档地址：\u0026lt;a\u0026gt;https://github.com/ACRA/acra/wiki/BasicSetup\u0026lt;/a\u0026gt; 6. Crashlytics 提供丰富的应用崩溃信息收集 轻量级，丰富，可自定义应用崩溃信息收集器，附有邮件通知 项目地址：\u0026lt;a\u0026gt;http://www.crashlytics.com/\u0026lt;/a\u0026gt; 集成插件：\u0026lt;a\u0026gt;Android Studio, Eclipse and IntelliJ\u0026lt;/a\u0026gt; 7. Android Resource Navigator chrome插件，可以方便的查看github上android源码工程的styles.xml和themes.xml。主要功能： (1) 快速打开android styles.xml themes.xml (2) 方便在资源间跳转。styles.xml themes.xml文件中资源链接跳转，可以方便跳转到某个资源 (3) 方便查找某个style和theme。chrome地址栏输入arn+tab+搜索内容回车即可 (4) 自动下载不同分辨率下的drawable (5) 通过映射查找那些不是按照固定命名规则命名的style和theme 项目地址：\u0026lt;a\u0026gt;https://github.com/jgilfelt/android-resource-navigator\u0026lt;/a\u0026gt; 示例：\u0026lt;a\u0026gt;https://chrome.google.com/webstore/detail/android-resource-navigato/agoomkionjjbejegcejiefodgbckeebo?hl=en\u0026amp;gl=GB\u0026lt;/a\u0026gt; 8. android-resource-remover 根据lint的提示删除项目中无用的资源，减少包的大小 项目地址：\u0026lt;a\u0026gt;https://github.com/KeepSafe/android-resource-remover\u0026lt;/a\u0026gt;(转自https://github.com/Trinea/android-open-project#%E7%9B%AE%E5%89%8D%E5%8C%85%E6%8B%AC) ","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E6%B1%87%E6%80%BB-%E5%A4%87%E7%94%A8/","summary":"\u003cdiv\u003e\n  \u003ca\u003eAndroid开源项目第一篇——个性化控件(View)篇\u003c/a\u003e\n *  包括\u003ca\u003eListView\u003c/a\u003e、\u003ca\u003eActionBar\u003c/a\u003e、\u003ca\u003eMenu\u003c/a\u003e、\u003ca\u003eViewPager\u003c/a\u003e、\u003ca\u003eGallery\u003c/a\u003e、\u003ca\u003eGridView\u003c/a\u003e、\u003ca\u003eImageView\u003c/a\u003e、\u003ca\u003eProgressBar\u003c/a\u003e、\u003ca\u003eTextView\u003c/a\u003e、\u003ca\u003e其他\u003c/a\u003e*\n \u003ca\u003eAndroid开源项目第二篇——工具库篇\u003c/a\u003e\n *  包括\u003ca\u003e依赖注入\u003c/a\u003e、\u003ca\u003e图片缓存\u003c/a\u003e、\u003ca\u003e网络相关\u003c/a\u003e、\u003ca\u003e数据库ORM工具包\u003c/a\u003e、\u003ca\u003eAndroid公共库\u003c/a\u003e、\u003ca\u003e高版本向低版本兼容库\u003c/a\u003e、\u003ca\u003e多媒体\u003c/a\u003e、\u003ca\u003e事件总线\u003c/a\u003e、\u003ca\u003e传感器\u003c/a\u003e、\u003ca\u003e安全\u003c/a\u003e、\u003ca\u003e其他\u003c/a\u003e*\n \u003ca\u003eAndroid开源项目第三篇——优秀项目篇\u003c/a\u003e\n *  比较有意思的完整的Android项目*\n \u003ca\u003eAndroid开源项目第四篇——开发及测试工具篇\u003c/a\u003e\n *  包括\u003ca\u003e开发效率工具\u003c/a\u003e、\u003ca\u003e开发自测相关\u003c/a\u003e、\u003ca\u003e测试工具\u003c/a\u003e、\u003ca\u003e开发及编译环境\u003c/a\u003e、\u003ca\u003e其他\u003c/a\u003e*\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cp\u003e第一部分 个性化控件(View)\u003c/p\u003e\n\u003cp\u003e主要介绍那些不错个性化的View，包括ListView、ActionBar、Menu、ViewPager、Gallery、GridView、ImageView、ProgressBar及其他如Dialog、Toast、EditText、TableView、Activity Animation等等。\u003c/p\u003e\n\u003cp\u003e\u003ca name=\"user-content-%E4%B8%80listview\"\u003e\u003c/a\u003e一、ListView\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eandroid-pulltorefresh\u003cbr\u003e\n一个强大的拉动刷新开源项目，支持各种控件下拉刷新，ListView、ViewPager、WevView、ExpandableListView、GridView、ScrollView、Horizontal ScrollView、Fragment上下左右拉动刷新，比下面johannilsson那个只支持ListView的强大的多。并且他实现的下拉刷新ListView在item不足一屏情况下也不会显示刷新提示，体验更好。\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/chrisbanes/Android-PullToRefresh\"\u003ehttps://github.com/chrisbanes/Android-PullToRefresh\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://github.com/Trinea/TrineaDownload/blob/master/pull-to-refreshview-demo.apk?raw=true\"\u003ehttps://github.com/Trinea/TrineaDownload/blob/master/pull-to-refreshview-demo.apk?raw=true\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nAPP示例：新浪微博各个页面\u003c/li\u003e\n\u003cli\u003eandroid-pulltorefresh-listview\u003cbr\u003e\n下拉刷新ListView\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/johannilsson/android-pulltorefresh\"\u003ehttps://github.com/johannilsson/android-pulltorefresh\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://github.com/Trinea/TrineaDownload/blob/master/pull-to-refresh-listview-demo.apk?raw=true\"\u003ehttps://github.com/Trinea/TrineaDownload/blob/master/pull-to-refresh-listview-demo.apk?raw=true\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nPS：这个被很多人使用的项目实际有不少bug，推荐使用上面的android-pulltorefresh\u003c/li\u003e\n\u003cli\u003eDropDownListView\u003cbr\u003e\n下拉刷新及滑动到底部加载更多ListView\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/Trinea/AndroidCommon\"\u003ehttps://github.com/Trinea/AndroidCommon\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://play.google.com/store/apps/details?id=cn.trinea.android.demo\"\u003ehttps://play.google.com/store/apps/details?id=cn.trinea.android.demo\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\n文档介绍：\u003ca\u003e\u003ca href=\"http://www.trinea.cn/android/dropdown-to-refresh-and-bottom-load-more-listview/\"\u003ehttp://www.trinea.cn/android/dropdown-to-refresh-and-bottom-load-more-listview/\u003c/a\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eDragSortListView\u003cbr\u003e\n拖动排序的ListView，同时支持ListView滑动item删除，各个Item高度不一、单选、复选、CursorAdapter做为适配器、拖动背景变化等\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/bauerca/drag-sort-listview\"\u003ehttps://github.com/bauerca/drag-sort-listview\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://play.google.com/store/apps/details?id=com.mobeta.android.demodslv\"\u003ehttps://play.google.com/store/apps/details?id=com.mobeta.android.demodslv\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nAPP示例：Wordpress Android\u003c/li\u003e\n\u003cli\u003eSwipeListView\u003cbr\u003e\n支持定义ListView左右滑动事件，支持左右滑动位移，支持定义动画时间\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/47deg/android-swipelistview\"\u003ehttps://github.com/47deg/android-swipelistview\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://play.google.com/store/apps/details?id=com.fortysevendeg.android.swipelistview\"\u003ehttps://play.google.com/store/apps/details?id=com.fortysevendeg.android.swipelistview\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nAPP示例：微信\u003c/li\u003e\n\u003cli\u003eAndroid-SwipeToDismiss\u003cbr\u003e\n滑动Item消失ListView\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/romannurik/Android-SwipeToDismiss\"\u003ehttps://github.com/romannurik/Android-SwipeToDismiss\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\n支持3.0以下版本见：\u003ca\u003e\u003ca href=\"https://github.com/JakeWharton/SwipeToDismissNOA\"\u003ehttps://github.com/JakeWharton/SwipeToDismissNOA\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://github.com/JakeWharton/SwipeToDismissNOA/SwipeToDismissNOA.apk/qr_code\"\u003ehttps://github.com/JakeWharton/SwipeToDismissNOA/SwipeToDismissNOA.apk/qr_code\u003c/a\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eStickyListHeaders\u003cbr\u003e\nGroupName滑动到顶端时会固定不动直到另外一个GroupName到达顶端的ExpandListView，支持快速滑动，支持Android2.3及以上\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/emilsjolander/StickyListHeaders\"\u003ehttps://github.com/emilsjolander/StickyListHeaders\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nAPP示例：Android 4.0联系人\u003cbr\u003e\n效果图：\u003ca target=\"_blank\"\u003e\u003cimg alt=\"Renderings\" loading=\"lazy\" src=\"https://raw.github.com/emilsjolander/StickyListHeaders/master/demo.gif\"\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003epinned-section-listview\u003cbr\u003e\nGroupName滑动到顶端时会固定不动直到另外一个GroupName到达顶端的ExpandListView\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/beworker/pinned-section-listview\"\u003ehttps://github.com/beworker/pinned-section-listview\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\n效果图：\u003ca target=\"_blank\"\u003e\u003cimg alt=\"Renderings\" loading=\"lazy\" src=\"https://raw.github.com/beworker/pinned-section-listview/master/screen1.png\"\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003col\u003e\n\u003cli\u003ePinnedHeaderListView\u003cbr\u003e\nGroupName滑动到顶端时会固定不动直到另外一个GroupName到达顶端的ExpandListView\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/JimiSmith/PinnedHeaderListView\"\u003ehttps://github.com/JimiSmith/PinnedHeaderListView\u003c/a\u003e\u003c/a\u003e\n2. QuickReturnHeader\u003cbr\u003e\nListView/ScrollView的header或footer，当向下滚动时消失，向上滚动时出现\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/ManuelPeinado/QuickReturnHeader\"\u003ehttps://github.com/ManuelPeinado/QuickReturnHeader\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://github.com/Trinea/TrineaDownload/blob/master/quick-return-header-demo.apk?raw=true\"\u003ehttps://github.com/Trinea/TrineaDownload/blob/master/quick-return-header-demo.apk?raw=true\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nAPP示例：google plus\n3. IndexableListView\u003cbr\u003e\nListView右侧会显示item首字母快捷索引，点击可快速滑动到某个item\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/woozzu/IndexableListView\"\u003ehttps://github.com/woozzu/IndexableListView\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://github.com/Trinea/TrineaDownload/blob/master/indexable-listview.apk?raw=true\"\u003ehttps://github.com/Trinea/TrineaDownload/blob/master/indexable-listview.apk?raw=true\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nAPP示例：微信通讯录、小米联系人\n4. CustomFastScrollView\u003cbr\u003e\nListView快速滑动，同时屏幕中间PopupWindows显示滑动到的item内容或首字母\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/nolanlawson/CustomFastScrollViewDemo\"\u003ehttps://github.com/nolanlawson/CustomFastScrollViewDemo\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\n效果图：\u003ca target=\"_blank\"\u003e\u003cimg alt=\"Renderings\" loading=\"lazy\" src=\"https://raw.github.com/nolanlawson/CustomFastScrollViewDemo/master/example.png\"\u003e\u003c/a\u003e\n5. Android-ScrollBarPanel\u003cbr\u003e\nListView滑动时固定的Panel指示显示在scrollbar旁边\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/rno/Android-ScrollBarPanel\"\u003ehttps://github.com/rno/Android-ScrollBarPanel\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\n效果展示：\u003ca\u003e\u003ca href=\"https://github.com/rno/Android-ScrollBarPanel/raw/master/demo_capture.png\"\u003ehttps://github.com/rno/Android-ScrollBarPanel/raw/master/demo_capture.png\u003c/a\u003e\u003c/a\u003e\n6. SlideExpandableListView\u003cbr\u003e\n用户点击listView item滑出固定区域，其他item的区域收缩\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/tjerkw/Android-SlideExpandableListView\"\u003ehttps://github.com/tjerkw/Android-SlideExpandableListView\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://github.com/Trinea/TrineaDownload/blob/master/slide-expandable-listView-demo.apk?raw=true\"\u003ehttps://github.com/Trinea/TrineaDownload/blob/master/slide-expandable-listView-demo.apk?raw=true\u003c/a\u003e\u003c/a\u003e\n7. JazzyListView\u003cbr\u003e\nListView及GridView item以特殊动画效果进入屏幕，效果包括grow、cards、curl、wave、flip、fly等等\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/twotoasters/JazzyListView\"\u003ehttps://github.com/twotoasters/JazzyListView\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://play.google.com/store/apps/details?id=com.twotoasters.jazzylistview.sample\"\u003ehttps://play.google.com/store/apps/details?id=com.twotoasters.jazzylistview.sample\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\n效果展示：\u003ca\u003e\u003ca href=\"http://lab.hakim.se/scroll-effects/\"\u003ehttp://lab.hakim.se/scroll-effects/\u003c/a\u003e\u003c/a\u003e\n8. ListViewAnimations\u003cbr\u003e\n带Item显示动画的ListView，动画包括底部飞入、其他方向斜飞入、下层飞入、渐变消失、滑动删除等\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/nhaarman/ListViewAnimations\"\u003ehttps://github.com/nhaarman/ListViewAnimations\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://play.google.com/store/apps/details?id=com.haarman.listviewanimations\"\u003ehttps://play.google.com/store/apps/details?id=com.haarman.listviewanimations\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nAPP示例：Google plus、Google Now卡片式进入、小米系统中应用商店、联系人、游戏中心、音乐、文件管理器的ListView、Ultimate、Light Flow Lite、TreinVerkeer、Running Coach、Pearl Jam Lyrics、Calorie Chart、Car Hire、Super BART、DK FlashCards、Counter Plus、Voorlees Verhaaltjes 2.0\n9. DevsmartLib-Android\u003cbr\u003e\n横向ListView\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/dinocore1/DevsmartLib-Android\"\u003ehttps://github.com/dinocore1/DevsmartLib-Android\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://github.com/Trinea/TrineaDownload/blob/master/horizontal-listview-demo.apk?raw=true\"\u003ehttps://github.com/Trinea/TrineaDownload/blob/master/horizontal-listview-demo.apk?raw=true\u003c/a\u003e\u003c/a\u003e\n10. HorizontalVariableListView\u003cbr\u003e\n支持Item宽度不一致的ListView\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/sephiroth74/HorizontalVariableListView\"\u003ehttps://github.com/sephiroth74/HorizontalVariableListView\u003c/a\u003e\u003c/a\u003e\n11. LinearListView\u003cbr\u003e\n用LinearLayout实现的ListView，可解决多个ListView并且等问题。目前自己也有需要，等亲自尝试过后会再具体介绍\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/frankiesardo/LinearListView\"\u003ehttps://github.com/frankiesardo/LinearListView\u003c/a\u003e\u003c/a\u003e\n12. MultiChoiceAdapter\u003cbr\u003e\n支持多选的ListView Adapter\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/ManuelPeinado/MultiChoiceAdapter\"\u003ehttps://github.com/ManuelPeinado/MultiChoiceAdapter\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://play.google.com/store/apps/details?id=com.manuelpeinado.multichoiceadapter.demo\"\u003ehttps://play.google.com/store/apps/details?id=com.manuelpeinado.multichoiceadapter.demo\u003c/a\u003e\u003c/a\u003e\n13. EnhancedListView\u003cbr\u003e\n支持横向滑动滑动删除列表项以及撤销删除的ListView，该项目的前身是\u003ca\u003eSwipeToDismissUndoList\u003c/a\u003e\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/timroes/EnhancedListView\"\u003ehttps://github.com/timroes/EnhancedListView\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://play.google.com/store/apps/details?id=de.timroes.android.listviewdemo\u0026amp;rdid=de.timroes.android.listviewdemo\"\u003ehttps://play.google.com/store/apps/details?id=de.timroes.android.listviewdemo\u0026amp;rdid=de.timroes.android.listviewdemo\u003c/a\u003e\u003c/a\u003e\n14. ListBuddies\u003cbr\u003e\n自动滚动的双列ListView ，两个ListView滚动速度不一致，有视差效果\u003cbr\u003e\n项目地址：\u003ca\u003e\u003ca href=\"https://github.com/jpardogo/ListBuddies\"\u003ehttps://github.com/jpardogo/ListBuddies\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\nDemo地址：\u003ca\u003e\u003ca href=\"https://play.google.com/store/apps/details?id=com.jpardogo.android.listbuddies\"\u003ehttps://play.google.com/store/apps/details?id=com.jpardogo.android.listbuddies\u003c/a\u003e\u003c/a\u003e\u003cbr\u003e\n效果展示：\u003ca target=\"_blank\"\u003e\u003cimg alt=\"Renderings\" loading=\"lazy\" src=\"https://raw.github.com/jpardogo/ListBuddies/master/art/screenshot_listbuddies_2.png\"\u003e\u003c/a\u003e\u003cbr\u003e\n\u003ca title=\"返回目录\"\u003e\u003cimg loading=\"lazy\" src=\"https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67\"\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;a name=\u0026quot;user-content-%E4%BA%8Cactionbar\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;二、ActionBar\n\n  1. ActionBarSherlock  \n    为Android所有版本提供统一的ActionBar，解决4.0以下ActionBar的适配问题  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/ActionBarSherlock\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.demos\u0026lt;/a\u0026gt;  \n    APP示例：太多了。。现在连google都在用\n  2. ActionBar-PullToRefresh  \n    下拉刷新，ActionBar出现加载中提示  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/chrisbanes/ActionBar-PullToRefresh\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=uk.co.senab.actionbarpulltorefresh.samples.stock\u0026lt;/a\u0026gt;  \n    APP示例：Gmail，Google plus，知乎等\n  3. FadingActionBar  \n    ListView向下滚动逐渐显现的ActionBar  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/ManuelPeinado/FadingActionBar\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.manuelpeinado.fadingactionbar.demo\u0026lt;/a\u0026gt;  \n    APP示例：google music，知乎\n  4. NotBoringActionBar  \n    google music下拉收缩的ActionBar  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/flavienlaurent/NotBoringActionBar\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;http://flavienlaurent.com/blog/2013/11/20/making-your-action-bar-not-boring/\u0026lt;/a\u0026gt;  \n    APP示例：Google音乐\n  5. RefreshActionItem  \n    带进度显示和刷新按钮的ActionBar  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/ManuelPeinado/RefreshActionItem\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.manuelpeinado.refreshactionitem.demo\u0026lt;/a\u0026gt;  \n    APP示例：The New York Times，DevAppsDirect.\n  6. GlassActionBar  \n    类似玻璃的有一定透明度的ActionBar  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/ManuelPeinado/GlassActionBar\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.manuelpeinado.glassactionbardemo\u0026lt;/a\u0026gt;  \n    APP示例：google music  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%B8%89menu\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;三、Menu\n\n  1. MenuDrawer  \n    滑出式菜单，通过拖动屏幕边缘滑出菜单，支持屏幕上下左右划出，支持当前View处于上下层，支持Windows边缘、ListView边缘、ViewPager变化划出菜单等。  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/SimonVT/android-menudrawer\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;http://simonvt.github.io/android-menudrawer/\u0026lt;/a\u0026gt;  \n    APP示例：Gmail、Google Music等大部分google app\n  2. SlidingMenu  \n    滑出式菜单，通过拖动屏幕边缘滑出菜单，支持屏幕左右划出，支持菜单zoom、scale、slide up三种动画样式出现。  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jfeinstein10/SlidingMenu\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.slidingmenu.example\u0026lt;/a\u0026gt;  \n    APP示例：Foursquare, LinkedIn, Zappos, Rdio, Evernote Food, Plume, VLC for Android, ESPN ScoreCenter, MLS MatchDay, 9GAG, Wunderlist 2, The Verge, MTG Familiar, Mantano Reader, Falcon Pro (BETA), MW3 Barracks  \n    MenuDrawer和SlidingMenu比较：SlidingMenu支持菜单动画样式出现，MenuDrawer支持菜单view处于内容的上下层\n  3. ArcMenu  \n    支持类似Path的左下角动画旋转菜单及横向划出菜单、圆心弹出菜单  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/daCapricorn/ArcMenu\u0026lt;/a\u0026gt;  \n    APP示例：Path  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/503830c53d4a8aaec4666ed8ad12d0f08e882f81/68747470733a2f2f646c2e64726f70626f7875736572636f6e74656e742e636f6d2f752f31313336393638372f70726576696577302e706e67)\u0026lt;/a\u0026gt;  \n    \u0026lt;a\u0026gt;https://dl.dropboxusercontent.com/u/11369687/preview1.png\u0026lt;/a\u0026gt;  \n    \u0026lt;a\u0026gt;https://dl.dropboxusercontent.com/u/11369687/raymenu.png\u0026lt;/a\u0026gt;\n  4. android-satellite-menu  \n    类似Path的左下角动画旋转菜单  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/siyamed/android-satellite-menu\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/satellite-menu-demo.apk?raw=true\u0026lt;/a\u0026gt;  \n    APP示例：Path\n  5. radial-menu-widget  \n    圆形菜单，支持二级菜单  \n    项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/radial-menu-widget/\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a\u0026gt;http://farm8.staticflickr.com/7377/11621125154_d1773c2dcc_o.jpg\u0026lt;/a\u0026gt;\n  6. Android Wheel Menu  \n    圆形旋转选取菜单  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/anupcowkur/Android-Wheel-Menu\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/anupcowkur/Android-Wheel-Menu/master/graphics/wheel.gif)\u0026lt;/a\u0026gt;\n  7. FoldingNavigationDrawer  \n    滑动并以折叠方式打开菜单  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/tibi1712/FoldingNavigationDrawer-Android\u0026lt;/a\u0026gt;  \n    使用介绍：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.ptr.folding.sample\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/e556bb96a96e4a3991de0ce8a0ca81b51e909370/68747470733a2f2f6c68362e67677068742e636f6d2f566e4b555a656e416f7a51304b46416d35626c465447714d614b466a76582d424b324a482d6a725831734958565471636941437152687146483438686334706d32513d683331302d7277)\u0026lt;/a\u0026gt;\n  8. AndroidResideMenu  \n    仿 Dribbble 的边栏菜单  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/SpecialCyCi/AndroidResideMenu\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github.com/SpecialCyCi/AndroidResideMenu/raw/master/2.gif)\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E5%9B%9Bviewpager-gallery\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;四、ViewPager 、Gallery\n\n  1. Android-ViewPagerIndicator  \n    配合ViewPager使用的Indicator，支持各种位置和样式  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/Android-ViewPagerIndicator\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.viewpagerindicator.sample\u0026lt;/a\u0026gt;  \n    APP示例：太多了。。\n  2. JazzyViewPager  \n    支持Fragment切换动画的ViewPager，动画包括转盘、淡入淡出、翻页、层叠、旋转、方块、翻转、放大缩小等  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jfeinstein10/JazzyViewPager\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/jfeinstein10/JazzyViewPager/blob/master/JazzyViewPager.apk?raw=true\u0026lt;/a\u0026gt;  \n    效果类似桌面左右切换的各种效果，不过桌面并非用ViewPager实现而已\n  3. Android-DirectionalViewPager  \n    支持横向和纵向(垂直)的ViewPager  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/Android-DirectionalViewPager\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://market.android.com/details?id=com.directionalviewpager.sample\u0026lt;/a\u0026gt;\n  4. android-pulltorefresh  \n    支持下拉刷新的ViewPager  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/chrisbanes/Android-PullToRefresh\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/pull-to-refreshview-demo.apk?raw=true\u0026lt;/a\u0026gt;  \n    APP示例：新浪微博各个页面\n  5. FancyCoverFlow  \n    支持Item切换动画效果的类似Gallery View  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/davidschreiber/FancyCoverFlow\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=at.technikum.mti.fancycoverflow.samples\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github-camo.global.ssl.fastly.net/ef5ced52b7b54652b50499521ed797c0188c7a6b/687474703a2f2f64617669647363687265696265722e6769746875622e696f2f46616e6379436f766572466c6f772f73637265656e73686f74322e706e67)\u0026lt;/a\u0026gt;\n  6. AndroidTouchGallery  \n    支持双击或双指缩放的Gallery(用ViewPager实现)，相比下面的PhotoView，在被放大后依然能滑到下一个item，并且支持直接从url和文件中获取图片，  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/Dreddik/AndroidTouchGallery\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/touch-gallery-demo.apk?raw=true\u0026lt;/a\u0026gt;  \n    APP示例：类似微信中查看聊天记录图片时可双击放大，并且放大情况下能正常左右滑动到前后图片\n  7. Android Auto Scroll ViewPager  \n    Android自动滚动 轮播循环的ViewPager  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/Trinea/android-auto-scroll-view-pager\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=cn.trinea.android.demo\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://www.trinea.cn/android/auto-scroll-view-pager/\u0026lt;/a\u0026gt;\n  8. Salvage view  \n    带View缓存的Viewpager PagerAdapter，很方便使用  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/salvage\u0026lt;/a\u0026gt;\n  9. Android PagerSlidingTabStrip  \n    配合ViewPager使用的Indicator，支持ViewPager Scroll时Indicator联动  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/astuetz/PagerSlidingTabStrip\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.astuetz.viewpager.extensions.sample\u0026lt;/a\u0026gt;\n 10. ViewPager3D  \n    ViewPager3D效果  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/inovex/ViewPager3D\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%BA%94gridview\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;五、GridView\n\n  1. StaggeredGridView  \n    允许非对齐行的GridView，类似Pinterest的瀑布流，并且跟ListView一样自带View缓存，继承自ViewGroup  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/maurycyw/StaggeredGridView\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/staggered-gridview-demo.apk?raw=true\u0026lt;/a\u0026gt;  \n    APP示例：Pinterest等\n  2. AndroidStaggeredGrid  \n    允许非对齐行的GridView，类似Pinterest的瀑布流，继承自AbsListView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/etsy/AndroidStaggeredGrid\u0026lt;/a\u0026gt;  \n    APP示例：Pinterest等\n  3. PinterestLikeAdapterView  \n    允许非对齐行的GridView，类似Pinterest的瀑布流，允许下拉刷新  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/GDG-Korea/PinterestLikeAdapterView\u0026lt;/a\u0026gt;  \n    APP示例：Pinterest等\n  4. DraggableGridView  \n    Item可拖动交换位置的GridView，实际是自己继承ViewGroup实现，类似桌面的单屏效果，可屏幕自动上下滚动进行Item移动交换，多屏效果见下面PagedDragDropGrid  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/thquinn/DraggableGridView\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/thquinn/DraggableGridView/blob/master/bin/DraggableGridViewSample.apk?raw=true\u0026lt;/a\u0026gt;\n  5. StickyGridHeaders  \n    GroupName滑动到顶端时会固定不动直到另外一个GroupName到达顶端的GridView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/TonicArtos/StickyGridHeaders\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github-camo.global.ssl.fastly.net/90b57e9383704c400706545225d439e057c6fcc0/687474703a2f2f342e62702e626c6f6773706f742e636f6d2f2d535f4262685758367754592f55517057306377554745492f41414141414141414776552f7a7a4a586a2d50635662592f73313630302f73637265656e2d6c616e6473636170652d736d616c6c65722e706e67)\u0026lt;/a\u0026gt;\n  6. PagedDragDropGrid  \n    Item可拖动交换位置、拖动删除的自定义控件，实际是自己继承ViewGroup实现，类似桌面的多屏效果，可拖动到屏幕边缘，屏幕自动左右滚动进行Item移动交换，可拖动进行删除，单屏效果见上面DraggableGridView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/mrKlar/PagedDragDropGrid\u0026lt;/a\u0026gt;  \n    Demo视频：\u0026lt;a\u0026gt;http://youtu.be/FYTSRfthSuQ\u0026lt;/a\u0026gt;\n  7. Android-DraggableGridViewPager  \n    Item可拖动交换位置的GridView，实际是自己继承ViewGroup实现，类似桌面的多屏效果，可屏幕自动左右滚动进行Item移动交换，单屏效果见上面DraggableGridView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/zzhouj/Android-DraggableGridViewPager\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/trinea-download/blob/master/draggable-grid-viewpager-demo.apk?raw=true\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E5%85%ADimageview\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;六、ImageView\n\n  1. PhotoView  \n    支持双击或双指缩放的ImageView，在ViewPager等Scrolling view中正常使用，相比上面的AndroidTouchGallery，不仅支持ViewPager，同时支持单个ImageView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/chrisbanes/PhotoView\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=uk.co.senab.photoview.sample\u0026lt;/a\u0026gt;  \n    APP示例：photup\n  2. android-gif-drawable  \n    支持gif显示的view，用jni实现的，编译生成so库后直接xml定义view即可，而且本身不依赖于其他开源项目所以相对下面的ImageViewEx简单的多  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/koral\u0026amp;#8211;/android-gif-drawable\u0026lt;/a\u0026gt;\n  3. ImageViewEx  \n    支持Gif显示的ImageView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/frapontillo/ImageViewEx\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/imageviewex-demo.apk?raw=true\u0026lt;/a\u0026gt;  \n    依赖很多，编译过程很繁琐!|_|!\n  4. RoundedImageView  \n    带圆角的ImageView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/vinc3m1/RoundedImageView\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/makeramen/RoundedImageView/master/screenshot.png)\u0026lt;/a\u0026gt;\n  5. ColorArt  \n    根据图片的均色设置背景色显示文字和图片，类似itune11中效果  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/MichaelEvans/ColorArt\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/color-art-demo.apk?raw=true\u0026lt;/a\u0026gt;\n  6. CircleImageView  \n    圆形的ImageView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/hdodenhof/CircleImageView\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/hdodenhof/CircleImageView/master/screenshot.png)\u0026lt;/a\u0026gt;\n  7. ImageViewZoom  \n    支持放大和平移的ImageView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/sephiroth74/ImageViewZoom\u0026lt;/a\u0026gt;  \n    APP示例：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.aviary.android.feather\u0026lt;/a\u0026gt;\n  8. KenBurnsView  \n    实现Ken Burns effect效果，达到身临其境效果的ImageView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/flavioarfaria/KenBurnsView\u0026lt;/a\u0026gt;\n  9. CustomShapeImageView  \n    各种形状的ImageView, 相比上面的圆形ImageView，多了更多形状  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/MostafaGazar/CustomShapeImageView\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/MostafaGazar/CustomShapeImageView/master/Screenshot_2013-11-05-23-08-12.png)\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%B8%83progressbar\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;七、ProgressBar\n\n  1. SmoothProgressBar  \n    水平进度条  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/castorflex/SmoothProgressBar\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=fr.castorflex.android.smoothprogressbar.sample\u0026lt;/a\u0026gt;\n  2. ProgressWheel  \n    支持进度显示的圆形ProgressBar  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/Todd-Davies/ProgressWheel\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/progress-wheel-demo.apk?raw=true\u0026lt;/a\u0026gt;\n  3. android-square-progressbar  \n    在图片周围显示进度  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/mrwonderman/android-square-progressbar\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=net.yscs.android.square_progressbar_example\u0026lt;/a\u0026gt;  \n    APP示例：square  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/6cb902f23ff22f1acc42b54182c2a27f53c379c2/68747470733a2f2f676f6f676c6564726976652e636f6d2f686f73742f30427745537750437558747737654578775346564c516b52325454672f6e657773637265656e312e706e67)\u0026lt;/a\u0026gt;\n  4. HoloCircularProgressBar  \n    Android4.1 时钟App样式  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/passsy/android-HoloCircularProgressBar\u0026lt;/a\u0026gt;  \n    APP示例：Android4.1时钟App  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/passsy/android-HoloCircularProgressBar/master/raw/screenshot1.png)\u0026lt;/a\u0026gt;\n  5. ProgressButton  \n    通过图钉的不同状态显示进度  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/f2prateek/progressbutton\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://f2prateek.com/progressbutton/\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/a5eb0cefeef3c5a9047feacd154f82549b6fadc4/687474703a2f2f66327072617465656b2e636f6d2f70726f6772657373627574746f6e2f7374617469632f7374617465732e706e67)\u0026lt;/a\u0026gt;\n  6. GoogleProgressBar  \n    类似google 多个圆形卡片翻转的progressBar  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jpardogo/GoogleProgressBar\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.githubusercontent.com/jpardogo/GoogleProgressBar/master/art/GoogleProgressBar.gif)\u0026lt;/a\u0026gt;\n  7. TH-ProgressButton  \n    带圆形进度显示的按钮  \n    项目地址；\u0026lt;a\u0026gt;https://github.com/torryharris/TH-ProgressButton\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/Vyshakh-K/TH-ProgressButton/master/screenshots/progressshot1.png)\u0026lt;/a\u0026gt;\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/Vyshakh-K/TH-ProgressButton/master/screenshots/progressshot2.png)\u0026lt;/a\u0026gt;\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/Vyshakh-K/TH-ProgressButton/master/screenshots/progressshot3.png)\u0026lt;/a\u0026gt;\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/Vyshakh-K/TH-ProgressButton/master/screenshots/progressshot4.png)\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E5%85%ABtextview\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;八、TextView包括TextView及所有继承自TextView控件，如EditText、Button、RadioButton\n\n  1. android-flowtextview  \n    文字自动环绕其他View的Layout  \n    项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/android-flowtextview/\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a\u0026gt;http://i949.photobucket.com/albums/ad332/vostroman1500/1.png\u0026lt;/a\u0026gt;\n  2. Android Form EditText  \n    验证输入合法性的编辑框，支持输入、英文、ip、url等多种正则验证  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/vekexasia/android-edittext-validator\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.andreabaccega.edittextformexample\u0026lt;/a\u0026gt;\n  3. Emojicon  \n    支持emojis的TextView和EditText  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/rockerhieu/emojicon\u0026lt;/a\u0026gt;  \n    文档地址：\u0026lt;a\u0026gt;http://rockerhieu.com/emojicon/\u0026lt;/a\u0026gt;\n  4. android-circlebutton  \n    Android圆形按钮，实际实现是继承自ImageView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/markushi/android-circlebutton\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/markushi/android-circlebutton/blob/master/example/example.apk\u0026lt;/a\u0026gt;\n  5. Segmented Radio Buttons for Android  \n    iOS’s segmented controls的实现  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/vinc3m1/android-segmentedradiobutton\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/thquinn/DraggableGridView/blob/master/bin/DraggableGridViewSample.apk?raw=true\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/vinc3m1/android-segmentedradiobutton/master/screens/segmentedradio.png)\u0026lt;/a\u0026gt;\n  6. Chips EditText Library  \n    支持国家名字联想从而选择显示该国国旗的EditText，实际就是通过SpannableStringBuilder实现  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/kpbird/chips-edittext-library\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/kpbird/chips-edittext-library/tree/master/ChipsEditTextDemo/bin\u0026lt;/a\u0026gt;\n  7. AutoFitTextView  \n    可固定边界内容字体大小自适应的TextView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/grantland/android-autofittextview\u0026lt;/a\u0026gt;\n  8. Shimmer for Android  \n    文字发淡光的TextView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/RomainPiel/Shimmer-android\u0026lt;/a\u0026gt;\n  9. Titanic  \n    可以显示水位上升下降(不知道该怎么描述 囧)的TextView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/RomainPiel/Titanic\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github.com/RomainPiel/Titanic/raw/master/titanic.gif)\u0026lt;/a\u0026gt;\n 10. android-iconify  \n    提供带Icon的TextView,Menu,Button等  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JoanZapata/android-iconify\u0026lt;/a\u0026gt;\n 11. Calligraphy  \n    让我们在[Android开发](http://www.eoeandroid.com/)中使用自定义字体变得更加简单  \n    项目地址 ：\u0026lt;a\u0026gt;https://github.com/chrisjenx/Calligraphy\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github.com/chrisjenx/Calligraphy/raw/master/screenshot.png)\u0026lt;/a\u0026gt;\n 12. CreditsRoll  \n    类似星球大战字幕效果的TextView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/frakbot/CreditsRoll\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%B9%9D%E5%85%B6%E4%BB%96\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;九、其他\n\n  1. achartengine  \n    强大的图表绘制工具，支持折线图、面积图、散点图、时间图、柱状图、条图、饼图、气泡图、圆环图、范围（高至低）条形图、拨号图/表、立方线图及各种图的结合  \n    项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/achartengine/\u0026lt;/a\u0026gt;  \n    官方网站：\u0026lt;a\u0026gt;http://www.achartengine.org/\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/d3a4fa07ace8e6aca2f1e4c5131009de2e897a3e/687474703a2f2f7777772e616368617274656e67696e652e6f72672f64696d616765732f617665726167655f74656d70657261747572652e706e67)\u0026lt;/a\u0026gt;  \n    \u0026lt;a\u0026gt;http://www.achartengine.org/dimages/sales_line_and_area_chart.png\u0026lt;/a\u0026gt;  \n    \u0026lt;a\u0026gt;http://www.achartengine.org/dimages/temperature_range_chart.png\u0026lt;/a\u0026gt;  \n    \u0026lt;a\u0026gt;http://www.achartengine.org/dimages/combined_chart.png\u0026lt;/a\u0026gt;  \n    \u0026lt;a\u0026gt;http://www.achartengine.org/dimages/budget_chart.png\u0026lt;/a\u0026gt;  \n    APP示例：Wordpress Android，Google Analytics\n  2. GraphView  \n    绘制图表和曲线图的View，可用于Android上的曲形图、柱状图、波浪图展示  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jjoe64/GraphView\u0026lt;/a\u0026gt;  \n    Demo工程：\u0026lt;a\u0026gt;https://github.com/jjoe64/GraphView-Demos\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.sothree.umano\u0026lt;/a\u0026gt;  \n    APP示例：Wordpress Android，Google Analytics\n  3. android-flip  \n    类似Flipboard翻转动画的实现  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/openaphid/android-flip\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/openaphid/android-flip/blob/master/FlipView/Demo/APK/Aphid-FlipView-Demo.apk?raw=true\u0026lt;/a\u0026gt;  \n    APP示例：flipboard\n  4. FlipImageView  \n    支持x、y、z及动画选择的翻转动画的实现  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/castorflex/FlipImageView\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=fr.castorflex.android.flipimageview\u0026lt;/a\u0026gt;\n  5. SwipeBackLayout  \n    左右或向上滑动返回的Activity  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/Issacw0ng/SwipeBackLayout\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=me.imid.swipebacklayout.demo\u0026lt;/a\u0026gt;  \n    APP示例：知乎\n  6. Cards-UI  \n    卡片式View，支持单个卡片，item为卡片的ListView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/afollestad/Cards-UI\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/cards-ui-demo.apk?raw=true\u0026lt;/a\u0026gt;\n  7. cardslib  \n    卡片式View，支持单个卡片，item为卡片的ListView和GridView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/gabrielemariotti/cardslib\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=it.gmariotti.cardslib.demo\u0026lt;/a\u0026gt;\n  8. android-styled-dialogs  \n    可自定义样式的dialog，默认与Holo主题样式一致，在Android2.2以上同一样式  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/inmite/android-styled-dialogs\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/styled-dialogs-demo.apk?raw=true\u0026lt;/a\u0026gt;\n  9. Crouton  \n    丰富样式的Toast，允许alert、comfirm、info样式及点击消失样式，允许设置Toast显示时间，允许自定义View。 本文32. SuperToasts为其扩展版  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/keyboardsurfer/Crouton\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;http://play.google.com/store/apps/details?id=de.keyboardsurfer.app.demo.crouton\u0026lt;/a\u0026gt;\n 10. supertooltips  \n    带动画效果的Tips显示  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/nhaarman/supertooltips\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.haarman.supertooltips\u0026lt;/a\u0026gt;\n 11. Android ViewBadger  \n    为其他View添加角标等  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jgilfelt/android-viewbadger\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/android-viewbadger.apk?raw=true\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a\u0026gt;https://github-camo.global.ssl.fastly.net/a705a3e88c75ae2394943bd7c56f725697616ea8/687474703a2f2f7777772e6a65666667696c66656c742e636f6d2f766965776261646765722f76622d31612e706e67\u0026lt;/a\u0026gt;\n 12. Android Sliding Up Panel  \n    可拖动的View，能在当前Activity上扶起一个可拖动的Panel  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/umano/AndroidSlidingUpPanel\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.sothree.umano\u0026lt;/a\u0026gt;  \n    APP示例：Google Music精简播放栏\n 13. android-times-square  \n    Android日历时间部件，支持选取单个日期，多个日期，及日期区间段和对话框形式显示  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/square/android-times-square\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/times-square-demo.apk?raw=true\u0026lt;/a\u0026gt;\n 14. android-calendar-card  \n    日历  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/kenumir/android-calendar-card\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.wt.calendarcardsample\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/kenumir/android-calendar-card/master/calendar-card-sample/_work/device-2013-10-12-151801.png)\u0026lt;/a\u0026gt;\n 15. ColorPickerView  \n    颜色选择器，支持PopupWindows或新的Activity中打开  \n    项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/color-picker-view/\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/c1b120db21965381e28349dcb019a8ec5525c326/687474703a2f2f6f6934312e74696e797069632e636f6d2f333363366d6d382e6a7067)\u0026lt;/a\u0026gt;\n 16. HoloColorPicker  \n    颜色选择器  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/LarsWerkman/HoloColorPicker\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://docs.google.com/file/d/0BwclyDTlLrdXRzVnTGJvTlRfU2s/edit\u0026lt;/a\u0026gt;\n 17. AndroidWheel  \n    Android Wheel支持城市、多种日期时间、密码、图片  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/sephiroth74/AndroidWheel\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/e9a9430ac807dcfcde5ebc407684a8b7459bb9bd/687474703a2f2f6661726d362e737461746963666c69636b722e636f6d2f353533322f31313632313532383738365f323230633034306261355f6f2e6a7067)\u0026lt;/a\u0026gt;\n 18. TableFixHeaders  \n    第一列固定的Table  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/InQBarna/TableFixHeaders\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;http://bit.ly/13buAIq\u0026lt;/a\u0026gt;\n 19. UITableView  \n    ios风格控件，包括Button、ListView、TableView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/thiagolocatelli/android-uitableview\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/ui-tableview-demo.apk?raw=true\u0026lt;/a\u0026gt;\n 20. ATableView  \n    ios风格控件  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/dmacosta/ATableView\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.nakardo.atableview.demo\u0026lt;/a\u0026gt;\n 21. UndoBar  \n    屏幕底部显示取消或是确认的PopupWindows  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/soarcn/UndoBar\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github.com/soarcn/UndoBar/blob/master/art/redo.png?raw=true)\u0026lt;/a\u0026gt;\n 22. Inscription  \n    可用于展示应用change和new feature信息  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/MartinvanZ/Inscription\u0026lt;/a\u0026gt;\n 23. ActivityTransition  \n    Activity切换动画，包括渐变、flip、某个位置进入等等  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/ophilbert/ActivityTransition\u0026lt;/a\u0026gt;  \n    使用介绍：\u0026lt;a\u0026gt;https://github.com/jfeinstein10/JazzyViewPager/blob/master/JazzyViewPager.apk?raw=true\u0026lt;/a\u0026gt;  \n    效果图：类似桌面左右切换的各种效果，不过桌面并非用ViewPager实现而已\n 24. GlowPadBackport  \n    将Android4.2的锁屏界面解锁扩展到Android1.6及1.6+  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/rock3r/GlowPadBackport\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=net.sebastianopoggi.samples.ui.GlowPadSample\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/1f0f4dc520a157e4e81113b6362ff2e120c04d8b/68747470733a2f2f6c68362e67677068742e636f6d2f5530373062364c6836635673567778346a4e2d356e7130787169423150427a7259414250654a49456532685a513555574f78632d464455473737774144656c546f48413d683331302d7277)\u0026lt;/a\u0026gt;\n 25. GlowPadView  \n    Android4锁屏界面解锁  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/nadavfima/GlowPadView\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a\u0026gt;https://raw.github.com/nadavfima/GlowPadView/master/example.png\u0026lt;/a\u0026gt;\n 26. android-lockpattern  \n    Android的图案密码解锁  \n    项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/android-lockpattern/\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=group.pals.android.lib.ui.lockpattern.demo\u0026lt;/a\u0026gt;  \n    使用介绍：\u0026lt;a\u0026gt;https://code.google.com/p/android-lockpattern/wiki/QuickUse\u0026lt;/a\u0026gt;  \n    示例APP：Android开机的图案密码解锁，支付宝的密码解锁\n 27. RangeBar  \n    类似于SeekBar，不同的是可以选择一个范围内的值而不是单个值  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/edmodo/range-bar\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/range-bar-demo.apk?raw=true\u0026lt;/a\u0026gt;  \n    效果图: \u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/0ff8267b4b90dc0ef973e612dd9a5eb2232735cb/687474703a2f2f692e696d6775722e636f6d2f7138354768526a6c2e706e67)\u0026lt;/a\u0026gt;\n 28. SuperToasts  \n    更丰富样式的toast，支持Button、Progress、Horizontal Progress样式、支持进入动画、支持撤销及其动画设置  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JohnPersano/SuperToasts\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.supertoastsdemo\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![SuperButtonToast](https://camo.githubusercontent.com/2c780a4dfb06cb4cc108a283ed6c091b7906df53/687474703a2f2f69313333312e70686f746f6275636b65742e636f6d2f616c62756d732f773539372f4a6f686e50657273616e6f2f7375706572746f617374735f676974687562696d6167655f7a707338613563656237632e706e67)\u0026lt;/a\u0026gt;\n 29. GoogleDateTimePickers  \n    时间选择部件  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/Mirkoddd/GoogleDateTimePickers\u0026lt;/a\u0026gt;  \n    文档地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.mirko.sample\u0026amp;hl=it\u0026lt;/a\u0026gt;\n 30. UndoBar  \n    屏幕底部显示取消或是确认某操作  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jenzz/Android-UndoBar\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/jenzz/Android-UndoBar/master/assets/Screenshot2.png)\u0026lt;/a\u0026gt;\n 31. ColorPickerPreference  \n    颜色选择器  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/attenzione/android-ColorPickerPreference\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github.com/attenzione/android-ColorPickerPreference/raw/master/screen_2.png)\u0026lt;/a\u0026gt;\n 32. HoloGraphLibrary  \n    绘制现状图、柱状图、饼状图  \n    项目地址：\u0026lt;a\u0026gt;https://bitbucket.org/danielnadeau/holographlibrary/src\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://bitbucket.org/danielnadeau/holographlibrary/wiki/Home\u0026lt;/a\u0026gt;\n 33. ChromeView  \n    利用Chromium实现的WebView，解决各个Android版本WebView不同的问题，同时利用最新Chrome代码  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/pwnall/chromeview\u0026lt;/a\u0026gt;\n 34. Discrollview  \n    支持滚动时Item淡入淡出，平移，缩放效果的ScrollView  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/flavienlaurent/discrollview\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/flavienlaurent/discrollview/raw/master/sample.apk\u0026lt;/a\u0026gt;\n 35. Android Slider Preference Library  \n    可添加到设置中的基于对话框的RankBar小部件  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jayschwa/AndroidSliderPreference\u0026lt;/a\u0026gt;\n 36. ShowcaseView library  \n    用于高亮显示应用程序的特定部分，从而突出突出重点  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/amlcurran/ShowcaseView\u0026lt;/a\u0026gt;\n 37. android-segmented-control  \n    Android上的Segmented Controls，相当于RadioButton组  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/hoang8f/android-segmented-control\u0026lt;/a\u0026gt;\n 38. PullScrollView  \n    仿照新浪微博Android客户端个人中心的ScrollView，下拉背景伸缩回弹效果。  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/MarkMjw/PullScrollView\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/MarkMjw/PullScrollView/master/Screenshots/1.png)\u0026lt;/a\u0026gt;\n 39. ParallaxScrollView  \n    支持视差滚动的ScrollView ，背景图片的滚动速度小于ScrollView中子控件的滚动速度  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/chrisjenx/ParallaxScrollView\u0026lt;/a\u0026gt;  \n    示例APK地址：\u0026lt;a\u0026gt;https://github.com/chrisjenx/ParallaxScrollView/downloads\u0026lt;/a\u0026gt;\n 40. Android-Bootstrap  \n    Bootstrap 风格的按钮  \n    项目地址： \u0026lt;a\u0026gt;https://github.com/Bearded-Hen/Android-Bootstrap\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://raw.github.com/Bearded-Hen/Android-Bootstrap/master/images/device_image.png)\u0026lt;/a\u0026gt;\n\n\u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E7%AC%AC%E4%BA%8C%E9%83%A8%E5%88%86-%E5%B7%A5%E5%85%B7%E5%BA%93\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;第二部分 工具库主要包括那些不错的开发库，包括依赖注入框架、图片缓存、网络相关、数据库ORM建模、Android公共库、Android 高版本向低版本兼容、多媒体相关及其他。\u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%B8%80%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5di\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;一、依赖注入DI通过依赖注入减少View、服务、资源简化初始化，事件绑定等重复繁琐工作\n\n  1. AndroidAnnotations(Code Diet)  \n    android快速开发框架  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/excilys/androidannotations\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/excilys/androidannotations/wiki\u0026lt;/a\u0026gt;  \n    官方网站：\u0026lt;a\u0026gt;http://androidannotations.org/\u0026lt;/a\u0026gt;  \n    特点：(1) 依赖注入：包括view，extras，系统服务，资源等等  \n    (2) 简单的线程模型，通过annotation表示方法运行在ui线程还是后台线程  \n    (3) 事件绑定：通过annotation表示view的响应事件，不用在写内部类  \n    (4) REST客户端：定义客户端接口，自动生成REST请求的实现  \n    (5) 没有你想象的复杂：AndroidAnnotations只是在在编译时生成相应子类  \n    (6) 不影响应用性能：仅50kb，在编译时完成，不会对运行时有性能影响。  \n    PS：与roboguice的比较：roboguice通过运行时读取annotations进行反射，所以可能影响应用性能，而AndroidAnnotations在编译时生成子类，所以对性能没有影响\n  2. roboguice  \n    帮你处理了很多代码异常，利用annotation使得更少的代码完成项目  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/roboguice/roboguice\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/roboguice/roboguice/wiki\u0026lt;/a\u0026gt;\n  3. butterknife  \n    利用annotation帮你快速完成View的初始化，减少代码  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/butterknife\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://jakewharton.github.io/butterknife/\u0026lt;/a\u0026gt;\n  4. Dagger  \n    依赖注入，适用于Android和Java  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/square/dagger\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://square.github.io/dagger/\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%BA%8C%E5%9B%BE%E7%89%87%E7%BC%93%E5%AD%98\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;二、图片缓存\n\n  1. Android-Universal-Image-Loader  \n    图片缓存，目前使用最广泛的图片缓存，支持主流图片缓存的绝大多数特性。  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/nostra13/Android-Universal-Image-Loader\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/universal-imageloader-demo.apk?raw=true\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://www.intexsoft.com/blog/item/74-universal-image-loader-part-3.html\u0026lt;/a\u0026gt;\n  2. picasso  \n    square开源的图片缓存  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/square/picasso\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://square.github.io/picasso/\u0026lt;/a\u0026gt;  \n    特点：(1)可以自动检测adapter的重用并取消之前的下载  \n    (2)图片变换  \n    (3)可以加载本地资源  \n    (4)可以设置占位资源  \n    (5)支持debug模式\n  3. ImageCache  \n    图片缓存，包含内存和Sdcard缓存  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/Trinea/AndroidCommon\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=cn.trinea.android.demo\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://www.trinea.cn/android/android-imagecache/\u0026lt;/a\u0026gt;  \n    特点：(1)支持预取新图片，支持等待队列  \n    (2)包含二级缓存，可自定义文件名保存规则  \n    (3)可选择多种缓存算法(FIFO、LIFO、LRU、MRU、LFU、MFU等13种)或自定义缓存算法  \n    (4)可方便的保存及初始化恢复数据  \n    (5)支持不同类型网络处理  \n    (6)可根据系统配置初始化缓存等  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%B8%89%E7%BD%91%E7%BB%9C%E7%9B%B8%E5%85%B3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;三、网络相关\n\n  1. Asynchronous Http Client for Android  \n    Android异步Http请求  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/loopj/android-async-http\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://loopj.com/android-async-http/\u0026lt;/a\u0026gt;  \n    特点：(1) 在匿名回调中处理请求结果  \n    (2) 在UI线程外进行http请求  \n    (3) 文件断点上传  \n    (4) 智能重试  \n    (5) 默认gzip压缩  \n    (6) 支持解析成Json格式  \n    (7) 可将Cookies持久化到SharedPreferences\n  2. android-query  \n    异步加载，更少代码完成Android加载  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/androidquery/androidquery\u0026lt;/a\u0026gt; 或 \u0026lt;a\u0026gt;https://code.google.com/p/android-query/\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://code.google.com/p/android-query/#Why_AQuery\u0026lt;/a\u0026gt;?  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.androidquery\u0026lt;/a\u0026gt;  \n    特点：\u0026lt;a\u0026gt;https://code.google.com/p/android-query/#Why_AQuery\u0026lt;/a\u0026gt;?\n  3. Async Http Client  \n    Java异步Http请求  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/AsyncHttpClient/async-http-client\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://sonatype.github.io/async-http-client/\u0026lt;/a\u0026gt;\n  4. Ion  \n    支持图片、json、http post等异步请求  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/koush/ion\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/koush/ion#more-examples\u0026lt;/a\u0026gt;\n  5. HttpCache  \n    Http缓存  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/Trinea/AndroidCommon\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=cn.trinea.android.demo\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://www.trinea.cn/android/android-http-cache\u0026lt;/a\u0026gt;  \n    特点是：(1) 根据cache-control、expires缓存http请求  \n    (2) 支持同步、异步Http请求  \n    (3) 在匿名回调中处理请求结果  \n    (4) 在UI线程外进行http请求  \n    (5) 默认gzip压缩\n  6. Http Request  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/kevinsawicki/http-request\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/kevinsawicki/http-request#examples\u0026lt;/a\u0026gt;\n  7. okhttp  \n    square开源的http工具类  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/square/okhttp\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://square.github.io/okhttp/\u0026lt;/a\u0026gt;  \n    特点：(1) 支持SPDY( \u0026lt;a\u0026gt;http://zh.wikipedia.org/wiki/SPDY\u0026lt;/a\u0026gt; )协议。SPDY协议是Google开发的基于传输控制协议的应用层协议，通过压缩，多路复用(一个TCP链接传送网页和图片等资源)和优先级来缩短加载时间。  \n    (2) 如果SPDY不可用，利用连接池减少请求延迟  \n    (3) Gzip压缩  \n    (4) Response缓存减少不必要的请求\n  8. Retrofit  \n    RESTFUL API设计  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/square/retrofit\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://square.github.io/retrofit/\u0026lt;/a\u0026gt;\n  9. RoboSpice  \n    Android异步网络请求工具，支持缓存、REST等等  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/stephanenicolas/robospice\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/stephanenicolas/RoboDemo/downloads\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E5%9B%9B%E6%95%B0%E6%8D%AE%E5%BA%93-orm%E5%B7%A5%E5%85%B7%E5%8C%85\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;四、数据库 orm工具包orm的db工具类，简化建表、查询、更新、插入、事务、索引的操作\n\n  1. greenDAO  \n    Android Sqlite orm的db工具类  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/greenrobot/greenDAO\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://greendao-orm.com/documentation/\u0026lt;/a\u0026gt;  \n    官方网站：\u0026lt;a\u0026gt;http://greendao-orm.com/\u0026lt;/a\u0026gt;  \n    特点：(1) 性能佳  \n    (2) 简单易用的API  \n    (3) 内存小好小  \n    (4) 库大小小\n  2. ActiveAndroid  \n    Android Sqlite orm的db工具类  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/pardom/ActiveAndroid\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/pardom/ActiveAndroid/wiki/_pages\u0026lt;/a\u0026gt;\n  3. Sprinkles  \n    Android Sqlite orm的db工具类  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/emilsjolander/sprinkles\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://emilsjolander.github.io/blog/2013/12/18/android-with-sprinkles/\u0026lt;/a\u0026gt;  \n    特点：比较显著的特点就是配合\u0026lt;a\u0026gt;https://github.com/square/retrofit\u0026lt;/a\u0026gt; 能保存从服务器获取的数据\n  4. ormlite-android  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/j256/ormlite-android\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://ormlite.com/sqlite_java_android_orm.shtml\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%BA%94android%E5%85%AC%E5%85%B1%E5%BA%93\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;五、Android公共库\n\n  1. Guava  \n    Google的基于java1.6的类库集合的扩展项目，包括collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O等等. 这些高质量的API可以使你的JAVa代码更加优雅，更加简洁  \n    项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/guava-libraries/\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://code.google.com/p/guava-libraries/wiki/GuavaExplained\u0026lt;/a\u0026gt;\n  2. Volley  \n    Google提供的网络通信库，使得网络请求更简单、更快速  \n    项目地址：\u0026lt;a\u0026gt;https://android.googlesource.com/platform/frameworks/volley\u0026lt;/a\u0026gt;  \n    Github地址：\u0026lt;a\u0026gt;https://github.com/mcxiaoke/android-volley\u0026lt;/a\u0026gt;  \n    文档地址：\u0026lt;a\u0026gt;http://commondatastorage.googleapis.com/io-2013/presentations/110%20-%20Volley-%20Easy,%20Fast%20Networking%20for%20Android.pdf\u0026lt;/a\u0026gt;\n  3. AndroidCommon  \n    Android公共库  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/Trinea/AndroidCommon\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=cn.trinea.android.demo\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://www.trinea.cn/android/android-common-lib/\u0026lt;/a\u0026gt;  \n    包括：(1)缓存(图片缓存、预取缓存、网络缓存)  \n    (2) 公共View(下拉及底部加载更多ListView、底部加载更多ScrollView、滑动一页Gallery)  \n    (3) Android常用工具类(网络、下载、Android资源操作、shell、文件、Json、随机数、Collection等等)\n  4. shipfaster  \n    整合了Dagger Otto Retrofit Robolectric Picasso OkHttp，方便快速开发  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/pyricau/shipfaster\u0026lt;/a\u0026gt;\n  5. CleanAndroidCode  \n    整合了Dagger Otto AndroidAnnotations，方便快速开发  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/pyricau/CleanAndroidCode\u0026lt;/a\u0026gt;  \n    我目前也在做框架选型方面的工作，不出意外后面也会出个跟4、5类似的项目  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E5%85%ADandroid-%E9%AB%98%E7%89%88%E6%9C%AC%E5%90%91%E4%BD%8E%E7%89%88%E6%9C%AC%E5%85%BC%E5%AE%B9\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;六、Android 高版本向低版本兼容\n\n  1. ActionBarSherlock  \n    为Android所有版本提供统一的ActionBar，解决4.0以下ActionBar的适配问题  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/ActionBarSherlock\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.demos\u0026lt;/a\u0026gt;  \n    APP示例：太多了。。现在连google都在用\n  2. Nine Old Androids  \n    将Android 3.0(Honeycomb)所有动画API(ObjectAnimator ValueAnimator等)兼容到Android1.0  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/NineOldAndroids\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.jakewharton.nineoldandroids.sample\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://nineoldandroids.com/\u0026lt;/a\u0026gt;\n  3. HoloEverywhere  \n    将Android 3.0的Holo主题兼容到Android2.1++  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/Prototik/HoloEverywhere\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://raw.github.com/Prototik/HoloEverywhere/repo/org/holoeverywhere/demo/2.1.0/demo-2.1.0.apk\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://android-developers.blogspot.com/2012/01/holo-everywhere.html\u0026lt;/a\u0026gt;\n  4. SherlockNavigationDrawer  \n    将Android NavigationDrawer和ActionbarSherlock结合，解决4.0以下NavigationDrawer的适配问题  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/tobykurien/SherlockNavigationDrawer\u0026lt;/a\u0026gt;\n  5. Notifications4EveryWhere  \n    将Android 4.1的兼容到Android2.2++  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/youxiachai/Notifications4EveryWhere\u0026lt;/a\u0026gt;  \n    NavigationDrawer文档地址：\u0026lt;a\u0026gt;http://developer.android.com/training/implementing-navigation/nav-drawer.html\u0026lt;/a\u0026gt;\n  6. Android Switch Widget Backport  \n    将Android Switch和SwitchPreference的兼容到Android2.1++  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/BoD/android-switch-backport\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=org.jraf.android.backport.switchwidget.sample\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/BoD/android-switch-backport#using-the-switch\u0026lt;/a\u0026gt;\n  7. android-datepicker  \n    将Android 4.0的datepicker兼容到Android2.2++  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/SimonVT/android-datepicker\u0026lt;/a\u0026gt;\n  8. GlowPadBackport  \n    Android 4.2的GlowPadView向后适配到API4以上  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/frakbot/GlowPadBackport\u0026lt;/a\u0026gt;\u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%B8%83%E5%A4%9A%E5%AA%92%E4%BD%93%E7%9B%B8%E5%85%B3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;七、多媒体相关\n\n  1. cocos2d-x  \n    跨平台的2d游戏框架，支持Android、IOS、Linux、Windows等众多平台  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/cocos2d/cocos2d-x\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://www.cocos2d-x.org/wiki\u0026lt;/a\u0026gt;  \n    官方网站：\u0026lt;a\u0026gt;http://www.cocos2d-x.org/\u0026lt;/a\u0026gt;\n  2. Vitamio  \n    是一款Android与iOS平台上的全能多媒体开发框架  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/yixia/VitamioBundle\u0026lt;/a\u0026gt;  \n    网站介绍：\u0026lt;a\u0026gt;http://www.vitamio.org/docs/\u0026lt;/a\u0026gt;  \n    特点：(1) 全面支持硬件解码与GPU渲染  \n    (2) 能够流畅播放720P甚至1080P高清MKV，FLV，MP4，MOV，TS，RMVB等常见格式的视频  \n    (3) 在Android与iOS上跨平台支持 MMS, RTSP, RTMP, HLS(m3u8)等常见的多种视频流媒体协议，包括点播与直播。\n  3. PhotoProcessing  \n    利用ndk处理图片库，支持Instafix、Ansel、Testino、XPro、Retro、BW、Sepia、Cyano、Georgia、Sahara、HDR、Rotate(旋转)、Flip(翻转)等各种特效  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/lightbox/PhotoProcessing\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/photo-processing.apk?raw=true\u0026lt;/a\u0026gt;\n  4. Android StackBlur  \n    图片模糊效果工具类  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/kikoso/android-stackblur\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/kikoso/android-stackblur/blob/master/StackBlurDemo/bin/StackBlurDemo.apk?raw=true\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/kikoso/android-stackblur#usage\u0026lt;/a\u0026gt;\n  5. Bitmap Smart Clipping using OpenCV  \n    图片智能裁剪保留重要部分显示  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/beartung/tclip-android\u0026lt;/a\u0026gt;  \n    利用淘宝的 \u0026lt;a\u0026gt;http://code.taobao.org/p/tclip/\u0026lt;/a\u0026gt; 库完成  \n    一淘玩客正在使用的图片裁剪，自动识别图片中的重要区域，并且在图片裁剪时保留重要区域  \n    特点：(1). 能进行人脸识别。图片中有人脸，将自动视为人脸区域为重要区域，将不会被裁剪掉  \n    (2).自动其它重要区域。如果图片中未识别出人脸，则会根据特征分布计算出重区域\n  6. Cropper  \n    图片局部剪切工具，可触摸控制选择区域或旋转  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/edmodo/cropper\u0026lt;/a\u0026gt;  \n    使用介绍：\u0026lt;a\u0026gt;https://github.com/edmodo/cropper/wiki\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github-camo.global.ssl.fastly.net/e4fde77bf41d4a60b234b4e268e5cfa8c17d9b6f/687474703a2f2f692e696d6775722e636f6d2f334668735467666c2e6a7067)\u0026lt;/a\u0026gt;\n  7. android-crop  \n    图片裁剪Activity  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jdamcd/android-crop\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://github.com/jdamcd/android-crop/raw/master/screenshot.png)\u0026lt;/a\u0026gt;\n  8. TileView  \n    可分块显示大图，支持2D拖动、双击、双指放大、双指捏合  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/moagrius/TileView\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;http://moagrius.github.io/TileView/TileViewDemo.apk\u0026lt;/a\u0026gt;\n  9. BlurEffectForAndroidDesign  \n    图片模糊效果  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/PomepuyN/BlurEffectForAndroidDesign\u0026lt;/a\u0026gt;\n 10. android-eye  \n    PC端网页查看同一局域网内的手机摄像头内容，可以用来监控哦  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/Teaonly/android-eye\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=teaonly.droideye\u0026lt;/a\u0026gt;\n 11. libpng for Android  \n    PNG图片的jni库，支持几乎png的所有特性  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/julienr/libpng-android\u0026lt;/a\u0026gt;  \n    文档地址：\u0026lt;a\u0026gt;http://www.libpng.org/pub/png/libpng.html\u0026lt;/a\u0026gt;\n 12. android-gpuimage  \n    基于GPU的图片滤镜  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/CyberAgent/android-gpuimage\u0026lt;/a\u0026gt;\n 13. AndroidFaceCropper  \n    图片脸部自动识别，将识别后的局部图片返回  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/lafosca/AndroidFaceCropper\u0026lt;/a\u0026gt;\n 14. Android Video Crop  \n    利用TextureView播放和剪切视频，类似ImageView.setScaleType  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/dmytrodanylyk/android-video-crop\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/lafosca/AndroidFaceCropper/releases/download/1.0/FaceCropper-sample-debug-unaligned.apk\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E5%85%AB%E4%BA%8B%E4%BB%B6%E6%80%BB%E7%BA%BF%E8%AE%A2%E9%98%85%E8%80%85%E6%A8%A1%E5%BC%8F\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;八、事件总线(订阅者模式)通过发布/订阅事件解耦事件发送和接受，从而简化应用程序组件(Activities, Fragments及后台线程)之间的通信\n\n  1. EventBus  \n    greenrobot的开源项目  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/greenrobot/EventBus\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/greenrobot/EventBus#general-usage-and-api\u0026lt;/a\u0026gt;  \n    特点：(1) 支持在不同类型的线程中处理订阅，包括发布所在线程，UI线程、单一后台线程、异步线程  \n    (2) 支持事件优先级定义，支持优先级高的订阅者取消事件继续传递，支持粘性事件，是不是跟系统的有序广播、粘性广播很像啊  \n    (3) 不是基于annotations  \n    (4) 性能更优  \n    (5) 体积小  \n    (6) 支持单例创建或创建多个对象  \n    (7) 支持根据事件类型订阅\n  2. Otto  \n    Square的开源项目，基于Guava的Android优化  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/square/otto\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://square.github.io/otto/\u0026lt;/a\u0026gt;  \n    \u0026lt;a\u0026gt;EventBus与Otto的功能及性能对比文档\u0026lt;/a\u0026gt;  \n    \u0026lt;a\u0026gt;EventBus与Otto性能对比Demo Apk\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%B9%9D%E4%BC%A0%E6%84%9F%E5%99%A8\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;九、传感器\n\n  1. Great Android Sensing Toolkit  \n    Android感应器工具包，包含示例及使用过程中可能需要的算法  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/gast-lib/gast-lib\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=root.gast.playground\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/gast-lib/gast-lib#documentation\u0026lt;/a\u0026gt;\n  2. SensorManager  \n    Android传感器管理  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/nlathia/SensorManager\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://docs.google.com/document/d/1TqThJULb-4e6TGb1gdkAaPCfyuXStjJpbnt7a0OZ9OE/edit\u0026lt;/a\u0026gt;\n  3. GPSLogger  \n    记录GPS信息  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/mendhak/gpslogger\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.mendhak.gpslogger\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://code.mendhak.com/gpslogger/\u0026lt;/a\u0026gt;\n  4. Pedometer  \n    计步器，使用硬件计步感应器  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/j4velin/Pedometer\u0026lt;/a\u0026gt;\n  5. leapcast  \n    ChromeCast模拟器的App  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/dz0ny/leapcast\u0026lt;/a\u0026gt;\n  6. Arduino-Communicator  \n    与Arduino通信的App  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jeppsson/Arduino-Communicator\u0026lt;/a\u0026gt;\n  7. android-pedometer  \n    Android计步器  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/bagilevi/android-pedometer\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;http://pedometer.googlecode.com/files/Pedometer-1.4.apk\u0026lt;/a\u0026gt;\n  8. OwnTracks for Android  \n    自己的轨迹记录  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/owntracks/android\u0026lt;/a\u0026gt;\n  9. Shake Detector library for Android  \n    Android手机震动摇晃检测库，提供供UI线程调用的回调接口  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/tbouron/ShakeDetector\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.github.tbouron.shakedetector.example\u0026lt;/a\u0026gt;\n 10. Android heart rate monitor  \n    Android心跳检测  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/phishman3579/android-heart-rate-monitor\u0026lt;/a\u0026gt;\n 11. Bluetooth LE Library for Android  \n    蓝牙源信息，包括宝库Mac、更新时间、RSSI、UUID、信号源距离、影响范围等信息  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/alt236/Bluetooth-LE-Library\u0026amp;#8212;Android\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=uk.co.alt236.btlescan\u0026lt;/a\u0026gt;\n 12. farebot  \n    通过NFC 从公交卡中读取数据的一个应用  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/codebutler/farebot\u0026lt;/a\u0026gt;\n\n\u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E5%8D%81%E5%AE%89%E5%85%A8\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;十、安全\n\n  1. SQLCipher  \n    Sqlite加密工具  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/sqlcipher/sqlcipher\u0026lt;/a\u0026gt;  \n    帮助文档：\u0026lt;a\u0026gt;http://sqlcipher.net/sqlcipher-for-android/\u0026lt;/a\u0026gt;\n  2. Conceal  \n    快速高效的进行文件加密解密  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/facebook/conceal\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/facebook/conceal#usage\u0026lt;/a\u0026gt;\n  3. Android-PasscodeLock  \n    应用锁，每次启动或从任何Activity启动应用都需要输入四位数字的密码方可进入  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/wordpress-mobile/Android-PasscodeLock\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.sothree.umano\u0026lt;/a\u0026gt;  \n    APP示例：Wordpress Android，支付宝，挖财\n  4. GlowPadBackport  \n    将Android4.2的锁屏界面解锁扩展到Android1.6及1.6+  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/rock3r/GlowPadBackport\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=net.sebastianopoggi.samples.ui.GlowPadSample\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Renderings](https://camo.githubusercontent.com/1f0f4dc520a157e4e81113b6362ff2e120c04d8b/68747470733a2f2f6c68362e67677068742e636f6d2f5530373062364c6836635673567778346a4e2d356e7130787169423150427a7259414250654a49456532685a513555574f78632d464455473737774144656c546f48413d683331302d7277)\u0026lt;/a\u0026gt;\n  5. GlowPadView  \n    Android 4锁屏界面解锁  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/nadavfima/GlowPadView\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a\u0026gt;https://raw.github.com/nadavfima/GlowPadView/master/example.png\u0026lt;/a\u0026gt;\n  6. android-lockpattern  \n    Android的图案密码解锁  \n    项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/android-lockpattern/\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=group.pals.android.lib.ui.lockpattern.demo\u0026lt;/a\u0026gt;  \n    使用介绍：\u0026lt;a\u0026gt;https://code.google.com/p/android-lockpattern/wiki/QuickUse\u0026lt;/a\u0026gt;  \n    示例APP：Android开机的图案密码解锁，支付宝的密码解锁  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E5%8D%81%E4%B8%80%E5%85%B6%E4%BB%96\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;十一、其他\n\n  1. Salvage view  \n    带View缓存的Viewpager PagerAdapter，很方便使用  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/salvage\u0026lt;/a\u0026gt;\n  2. Android Priority Job Queue  \n    Android后台任务队列  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/path/android-priority-jobqueue\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/path/android-priority-jobqueue#getting-started\u0026lt;/a\u0026gt;\n  3. jsoup  \n    一个解析html的java库，可方便的提取和操作数据  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jhy/jsoup\u0026lt;/a\u0026gt;  \n    官方网站：\u0026lt;a\u0026gt;http://jsoup.org/\u0026lt;/a\u0026gt;  \n    作用：(1) 从一个url、文件或string获得html并解析  \n    (2) 利用dom遍历或css选择器查找、提取数据  \n    (3) 操作html元素  \n    (4) 根据白名单去除用于提交的非法数据防止xss攻击  \n    (5) 输出整齐的html\n  4. ZIP  \n    java压缩和解压库  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/zeroturnaround/zt-zip\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/zeroturnaround/zt-zip#examples\u0026lt;/a\u0026gt;  \n    作用：(1) 解压和压缩，并支持文件夹内递归操作  \n    (2) 支持包含和排除某些元素  \n    (3) 支持重命名元素  \n    (4) 支持遍历zip包内容  \n    (5) 比较两个zip包等功能\n  5. Cobub Razor  \n    开源的mobile行为分析系统，包括web端、android端，支持ios和window phone  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/cobub/razor\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;http://demo.cobub.com/razor\u0026lt;/a\u0026gt;  \n    网站介绍：\u0026lt;a\u0026gt;http://dev.cobub.com/\u0026lt;/a\u0026gt;\n  6. aFileChooser  \n    文件选择器，可内嵌到程序中，而无需使用系统或三方文件选择器。  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/iPaulPro/aFileChooser\u0026lt;/a\u0026gt;\n  7. androidpn  \n    基于xmpp协议的消息推送解决方案，包括服务器端和android端。  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/dannytiehui/androidpn\u0026lt;/a\u0026gt;\n  8. Android Plugin Framework  \n    Android插件式开发  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/umeng/apf\u0026lt;/a\u0026gt;\n  9. purePDF  \n    允许从任何运行的SWF文件读取和创建PDF文档  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/sephiroth74/purePDF\u0026lt;/a\u0026gt;\n 10. Bolts  \n    Android的异步编程模式  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/BoltsFramework/Bolts-Android/\u0026lt;/a\u0026gt;  \n    与AsyncTask比较：(1) 使用的是无大小限制的线程池  \n    (2) 任务可组合可级联，防止了代码耦合\n 11. CastCompanionLibrary-android  \n    使Android程序中更快的接入Google Cast  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/googlecast/CastCompanionLibrary-android\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://developers.google.com/cast/\u0026lt;/a\u0026gt;\n 12. CastVideos-android  \n    从Android设备分享Video通过Google Cast  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/googlecast/CastVideos-android\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://developers.google.com/cast/\u0026lt;/a\u0026gt;\n 13. Uninstall_Statics  \n    Android应用自身被卸载监听及打开浏览器等反馈功能实现  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/sevenler/Uninstall_Statics\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://www.cnblogs.com/zealotrouge/p/3157126.html\u0026lt;/a\u0026gt;  \n    \u0026lt;a\u0026gt;http://www.cnblogs.com/zealotrouge/p/3159772.html\u0026lt;/a\u0026gt;\n 14. xCombine  \n    Android App插件式插件开发  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/wyouflf/xCombine\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://my.oschina.net/u/1171837/blog/155377\u0026lt;/a\u0026gt;\n 15. Memento  \n    保证在系统配置改变时，Activity中的某些数据可以简单安全的保持不变  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/mttkay/memento\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/mttkay/memento#usage\u0026lt;/a\u0026gt;\n 16. svg-android  \n    Android Svg矢量图形支持  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/japgolly/svg-android\u0026lt;/a\u0026gt; \u0026lt;a\u0026gt;https://github.com/japgolly/svg-android\u0026lt;/a\u0026gt;\n 17. Office 365 SDK for Android Preview  \n    可支持Microsoft SharePoint Lists, Microsoft SharePoint Files, Microsoft Exchange Calendar, Microsoft Exchange Contacts, Microsoft Exchange Mail  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/OfficeDev/Office-365-SDK-for-Android\u0026lt;/a\u0026gt;\n 18. OpenSpritz-Android  \n    Epub阅读器  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/OnlyInAmerica/OpenSpritz-Android\u0026lt;/a\u0026gt;\n 19. FreeFlow  \n    布局引擎，更简单的创建自定义布局，并且当数据和布局改变时更美观的过渡动画  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/Comcast/FreeFlow\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/Comcast/FreeFlow/releases\u0026lt;/a\u0026gt;\n 20. Android Gesture Detectors Framework  \n    Android手势框架，支持双指旋转、移动、平移、缩放等  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/Almeros/android-gesture-detectors\u0026lt;/a\u0026gt;\n 21. Mapbox Android SDK  \n    Android Map的替代版  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/mapbox/mapbox-android-sdk\u0026lt;/a\u0026gt;\n 22. Activity animation  \n    Activity跳转动画，支持各个方向波浪的效果  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/flavienlaurent/activityanimation\u0026lt;/a\u0026gt;  \n    在线演示：\u0026lt;a\u0026gt;https://www.youtube.com/watch?v=-E0sc6w_Jck\u0026lt;/a\u0026gt;\n 23. dynamic-load-apk  \n    Android动态加载Apk，热部署  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/singwhatiwanna/dynamic-load-apk\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://blog.csdn.net/singwhatiwanna/article/details/22597587\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E7%AC%AC%E4%B8%89%E9%83%A8%E5%88%86-%E4%BC%98%E7%A7%80%E9%A1%B9%E7%9B%AE\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;第三部分 优秀项目主要介绍那些Android还不错的完整项目，目前包含的项目主要依据是项目有意思或项目分层规范比较好。  \nLinux  \n项目地址：\u0026lt;a\u0026gt;https://github.com/torvalds/linux\u0026lt;/a\u0026gt;  \nAndroid  \n项目地址：\u0026lt;a\u0026gt;https://android.googlesource.com/\u0026lt;/a\u0026gt; 或 \u0026lt;a\u0026gt;https://github.com/android\u0026lt;/a\u0026gt;  \n以上两个项目，不解释\n\n(1) ZXing  \n二维码扫描工具  \n项目地址：\u0026lt;a\u0026gt;https://github.com/zxing/zxing\u0026lt;/a\u0026gt; 或 \u0026lt;a\u0026gt;https://code.google.com/p/zxing/\u0026lt;/a\u0026gt;  \nAPK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.google.zxing.client.android\u0026lt;/a\u0026gt;  \nPS：现在市面上很多应用的二维码扫描功能都是从这个修改而来\n\n(2) photup  \n编辑机批量上传照片到facebook上  \n项目地址：\u0026lt;a\u0026gt;https://github.com/chrisbanes/photup\u0026lt;/a\u0026gt;  \nAPK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=uk.co.senab.photup\u0026lt;/a\u0026gt;  \nPS：代码分包合理，很棒。不过这个项目依赖的开源项目比较多，比较难编译\n\n(3) github-android Github的Android客户端项目  \n项目地址：\u0026lt;a\u0026gt;https://github.com/github/android\u0026lt;/a\u0026gt;  \nAPK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.github.mobile\u0026lt;/a\u0026gt;\n\n(4) Notes  \nMIUI便签  \n项目地址：\u0026lt;a\u0026gt;https://github.com/MiCode/Notes\u0026lt;/a\u0026gt;  \nAPK地址：\u0026lt;a\u0026gt;https://github.com/Trinea/TrineaDownload/blob/master/miui-note-demo.apk?raw=true\u0026lt;/a\u0026gt;  \nPS：项目分包比较合理，相比较miui的文件管理器\u0026lt;a\u0026gt;https://github.com/MiCode/FileExplorer\u0026lt;/a\u0026gt; 代码规范较好得多\n\n(5) weicuiyuan  \n四次元-新浪微博客户端  \n项目地址：\u0026lt;a\u0026gt;https://github.com/qii/weiciyuan\u0026lt;/a\u0026gt;  \nAPK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=org.qii.weiciyuan\u0026lt;/a\u0026gt;\n\n(6) gnucash-android  \n一个记账理财软件  \n项目地址：\u0026lt;a\u0026gt;https://github.com/codinguser/gnucash-android\u0026lt;/a\u0026gt;  \nAPK地址：\u0026lt;a\u0026gt;http://play.google.com/store/apps/details?id=org.gnucash.android\u0026lt;/a\u0026gt;\n\n(7) AntennaPod  \n支持rss订阅、音乐订阅  \n项目地址：\u0026lt;a\u0026gt;https://github.com/danieloeh/AntennaPod\u0026lt;/a\u0026gt;  \nAPK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=de.danoeh.antennapod\u0026lt;/a\u0026gt;\n\n(8) ChaseWhisplyProject  \n打鬼游戏  \n项目地址：\u0026lt;a\u0026gt;https://github.com/tvbarthel/ChaseWhisplyProject\u0026lt;/a\u0026gt;  \nAPK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=fr.tvbarthel.games.chasewhisply\u0026lt;/a\u0026gt;\n\n(9) Tweet Lanes  \n功能完整的Twitter客户端  \n项目地址：\u0026lt;a\u0026gt;https://github.com/chrislacy/TweetLanes\u0026lt;/a\u0026gt;  \nAPK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.tweetlanes.android\u0026lt;/a\u0026gt;\n\n(10) Financius  \n简单易用的记账程序  \n项目地址：\u0026lt;a\u0026gt;https://github.com/mvarnagiris/Financius\u0026lt;/a\u0026gt;  \nAPK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.code44.finance\u0026lt;/a\u0026gt;\n\n(11) todo.txt-android  \ntodo.txt的官方Android应用  \n项目地址：\u0026lt;a\u0026gt;https://github.com/ginatrapani/todo.txt-android\u0026lt;/a\u0026gt;  \nAPK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.todotxt.todotxttouch\u0026lt;/a\u0026gt;\n\n(12) simpletask  \n基于todo.txt官方应用的另一个客户端  \n项目地址：\u0026lt;a\u0026gt;https://github.com/mpcjanssen/simpletask-android\u0026lt;/a\u0026gt;  \nAPK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=nl.mpcjanssen.todotxtholo\u0026lt;/a\u0026gt;\n\n(13) Muzei Live Wallpaper  \n定时更换桌面精美壁纸  \n项目地址：\u0026lt;a\u0026gt;https://github.com/romannurik/muzei\u0026lt;/a\u0026gt;  \nAPK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=net.nurik.roman.muzei\u0026lt;/a\u0026gt;  \n\u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E7%AC%AC%E5%9B%9B%E9%83%A8%E5%88%86-%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7%E5%8F%8A%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;第四部分 开发工具及测试工具主要介绍和[Android开发](http://www.eoeandroid.com/)工具和测试工具相关的开源项目。\u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%B8%80%E5%BC%80%E5%8F%91%E6%95%88%E7%8E%87%E5%B7%A5%E5%85%B7\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;一、开发效率工具\n\n  1. Json2Java  \n    根据JSon数据自动生成对应的Java实体类，还支持Parcel、Gson Annotations对应代码自动生成。期待后续的提取父类以及多url构建整个工程的功能  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jonfhancock/JsonToJava\u0026lt;/a\u0026gt;  \n    在线演示：\u0026lt;a\u0026gt;http://jsontojava.appspot.com/\u0026lt;/a\u0026gt;\n  2. IntelliJ Plugin for Android Parcelable boilerplate code generation  \n    Android studio插件，生成Parcelable代码  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/mcharmas/android-parcelable-intellij-plugin\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Holo Colors Idea](https://github.com/mcharmas/android-parcelable-intellij-plugin/raw/master/screenshot.png)\u0026lt;/a\u0026gt;\n  3. Android Holo Colors IntelliJ Plugin  \n    Android studio插件，生成holo样式9 patch图片  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jeromevdl/android-holo-colors-idea-plugin\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Holo Colors Idea](https://raw.github.com/jeromevdl/android-holo-colors-idea-plugin/master/other/holocolorsidea.png)\u0026lt;/a\u0026gt;\n  4. Android Drawable Factory  \n    用于生成各个分辨率的图片  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/tizionario/AndroidDrawableFactory\u0026lt;/a\u0026gt;  \n    效果图：\u0026lt;a target=\u0026quot;_blank\u0026quot;\u0026gt;![Android Drawable Factory](https://github-camo.global.ssl.fastly.net/5c3844b345a9779296f996490070dab0bfc9dbf5/68747470733a2f2f646c2e64726f70626f7875736572636f6e74656e742e636f6d2f752f32363636343637352f416e64726f69644472617761626c65466163746f72792f312e706e67)\u0026lt;/a\u0026gt;\n  5. SelectorChapek for Android  \n    Android Studio插件，可根据固定文件名格式资源自动生成drawable selectors xml文件。  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/inmite/android-selector-chapek\u0026lt;/a\u0026gt;\n  6. Android Action Bar Style Generator  \n    Android ActionBar样式生成器，可在线选择ActionBar样式自动生成所需要的图片资源及xml文件  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jgilfelt/android-actionbarstylegenerator\u0026lt;/a\u0026gt;  \n    在线演示：\u0026lt;a\u0026gt;http://jgilfelt.github.io/android-actionbarstylegenerator/\u0026lt;/a\u0026gt;\n  7. ButterKnifeZelezny  \n    用于快速生成\u0026lt;a\u0026gt;ButterKnife\u0026lt;/a\u0026gt;View注入代码的Android Studio/IDEA插件  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/inmite/android-butterknife-zelezny\u0026lt;/a\u0026gt;\n  8. RoboCoP  \n    利用Gradle task根据固定格式的json文件生成ContentProvider  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/mediarain/RoboCoP\u0026lt;/a\u0026gt;\n  9. appiconsizes  \n    用于生成各个分辨率的图片  \n    项目地址：\u0026lt;a\u0026gt;http://www.appiconsizes.com/\u0026lt;/a\u0026gt;\n 10. Gradle Retrolambda Plugin  \n    \u0026lt;a\u0026gt;Retrolambda\u0026lt;/a\u0026gt;是将Java8的Lambdas应用于Java7的工具，本项目是Gradle插件，通过Retrolambda从而使Java或Android项目用Java8的Lambdas编写，将编译后的字节码转换为Java6和7的字节码从而正常运行  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/evant/gradle-retrolambda\u0026lt;/a\u0026gt;\n 11. Dagger IntelliJ Plugin  \n    dagger的intellij插件  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/square/dagger-intellij-plugin\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%BA%8C%E5%BC%80%E5%8F%91%E8%87%AA%E6%B5%8B%E7%9B%B8%E5%85%B3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;二、开发自测相关\n\n  1. Quality Tools for Android  \n    Android测试及自测工具集合和示例  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/stephanenicolas/Quality-Tools-for-Android\u0026lt;/a\u0026gt;\n  2. android-test-kit  \n    Google的Android测试工具  \n    包括GoogleInstrumentationTestRunner(增强版的InstrumentationTestRunner)和Espresso(用于快速写出可靠测试用例的API)  \n    项目地址：\u0026lt;a\u0026gt;https://code.google.com/p/android-test-kit/\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://code.google.com/p/android-test-kit/w/list\u0026lt;/a\u0026gt;\n  3. robolectric  \n    测试用例编写框架  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/robolectric/robolectric\u0026lt;/a\u0026gt;  \n    Demo地址：\u0026lt;a\u0026gt;https://github.com/robolectric/robolectricsample\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;http://robolectric.org/\u0026lt;/a\u0026gt;  \n    特点：(1). 不需要模拟器在一般JVM就可以运行测试用例  \n    (2). 能完成在真机上的大部分测试包括感应器  \n    其他的测试用例及相关模块Mock可见：\u0026lt;a\u0026gt;android-mock\u0026lt;/a\u0026gt;, \u0026lt;a\u0026gt;mockito\u0026lt;/a\u0026gt;, \u0026lt;a\u0026gt;easy-mock\u0026lt;/a\u0026gt;\n  4. Android FEST  \n    提供一些列方便的断言，可用于提高编写Android自测代码效率  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/square/fest-android\u0026lt;/a\u0026gt;\n  5. BoundBox  \n    可用于测试类各种访问权限的属性、方法。实际是通过BoundBox这个annotation生成一个属性和方法都是public权限的中间类并对此类进行测试完成的  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/stephanenicolas/boundbox\u0026lt;/a\u0026gt;\n  6. Hugo  \n    用于打印函数信息及执行时间的工具，仅在debug模式生效  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/hugo\u0026lt;/a\u0026gt;\n  7. scalpel  \n    在应用下面添加一层用于界面调试，待详细补充 // TODO  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/scalpel\u0026lt;/a\u0026gt;\n  8. Android Screenshot library  \n    Android截图工具类，用于在持续集成时截图  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/rtyley/android-screenshot-lib\u0026lt;/a\u0026gt;\n  9. sonar-android-lint-plugin  \n    将android lint的错误在sonar中展现  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/SonarCommunity/sonar-android\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%B8%89%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;三、测试工具\n\n  1. Spoon  \n    可用于android不同机型设备自动化测试，能将应用apk和测试apk运行在不同机器上并生成相应测试报告。  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/square/spoon\u0026lt;/a\u0026gt;\n  2. Tencent APT  \n    APT是腾讯开源的一个Android平台高效性能测试组件，提供丰富实用的功能，适用于开发自测、定位性能瓶颈；测试人员完成性能基准测试、竞品对比测试  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/stormzhang/APT\u0026lt;/a\u0026gt;\n  3. Emmagee  \n    网易开源的性能测试工具，包括CPU、内存、网络流量、启动时间、电池状态等  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/NetEase/Emmagee\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E5%9B%9B%E5%BC%80%E5%8F%91%E5%8F%8A%E7%BC%96%E8%AF%91%E7%8E%AF%E5%A2%83\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;四、开发及编译环境\n\n  1. Buck  \n    facebook开源的Android编译工具，效率是ant的两倍。主要优点在于：  \n    (1) 加快编译速度，通过并行利用多核cpu和跟踪不变资源减少增量编译时间实现  \n    (2) 可以在编译系统中生成编译规则而无须另外的系统生成编译规则文件  \n    (3) 编译同时可生成单元测试结果  \n    (4) 既可用于IDE编译也可用于持续集成编译  \n    (5) facebook持续优化中  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/facebook/buck\u0026lt;/a\u0026gt;\n  2. Android Maven Plugin  \n    Android Maven插件，可用于对android三方依赖进行管理。在J2EE开发中，maven是非常成熟的依赖库管理工具，可统一管理依赖库。  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jayway/maven-android-plugin\u0026lt;/a\u0026gt;\n  3. umeng-muti-channel-build-tool  \n    渠道打包工具  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/umeng/umeng-muti-channel-build-tool\u0026lt;/a\u0026gt;  \n    另可参见Google的构建系统Gradle：\u0026lt;a\u0026gt;http://tools.android.com/tech-docs/new-build-system/user-guide\u0026lt;/a\u0026gt;\n  4. Genymotion  \n    目前最好用最快的android模拟器  \n    项目地址：\u0026lt;a\u0026gt;http://www.genymotion.com/\u0026lt;/a\u0026gt;  \n    Android studio集成控件： \u0026lt;a\u0026gt;http://plugins.jetbrains.com/plugin/7269?pr=idea\u0026lt;/a\u0026gt;  \n    Cyril Mottier推荐：\u0026lt;a\u0026gt;http://cyrilmottier.com/2013/06/27/a-productive-android-development-environment/\u0026lt;/a\u0026gt;\n  5. gradle-mvn-push  \n    方便的将Gradle的Artifacts上传到Maven仓库  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/chrisbanes/gradle-mvn-push\u0026lt;/a\u0026gt;  \n    文档介绍：\u0026lt;a\u0026gt;https://github.com/chrisbanes/gradle-mvn-push#usage\u0026lt;/a\u0026gt;\n  6. Android Emulator Plugin for Jenkins  \n    Android模拟器 jenkins插件，用于Jenkins做持续集成时跑模拟器测试  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jenkinsci/android-emulator-plugin\u0026lt;/a\u0026gt;\n  7. Android Maven Plugin  \n    管理应用所需要的依赖库。包括的构建工具有Maven、Gradle、ant、sbt  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/mosabua/maven-android-sdk-deployer\u0026lt;/a\u0026gt;\n  8. SDK Manager Plugin  \n    下载和管理Android SDK的Gradle插件  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/sdk-manager-plugin\u0026lt;/a\u0026gt;  \n    \u0026lt;a title=\u0026quot;返回目录\u0026quot;\u0026gt;![](https://camo.githubusercontent.com/01a7b0f6a5751ece650a2658c342f5b4bd84db1e/687474703a2f2f6661726d342e737461746963666c69636b722e636f6d2f333733372f31323136373431333133345f656463666636386532325f6f2e706e67)\u0026lt;/a\u0026gt;\n\n\u0026lt;a name=\u0026quot;user-content-%E4%BA%94%E5%85%B6%E4%BB%96\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;五、其他\n\n  1. ViewServer  \n    允许app运行在任何手机上都可以用HierarchyViewer查看  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/romainguy/ViewServer\u0026lt;/a\u0026gt;\n  2. GridWichterle for Android  \n    在整个系统上显示一个grid，用来帮助查看应用布局及使得布局更美观，可设置grid网格大小和颜色，android推荐48dp和8dp，可见 Android Design Guidelines – Metrics and Grids  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/inmite/android-grid-wichterle\u0026lt;/a\u0026gt;  \n    APK地址：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=eu.inmite.android.gridwichterle\u0026lt;/a\u0026gt;  \n    PS：比起hierarchyviewer相差甚远，不过偶尔可用来作为布局查看工具。\n  3. Catlog  \n    手机端log查看工具，支持不同颜色显示、关键字过滤、级别过滤、进程id过滤、录制功能等  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/nolanlawson/Catlog\u0026lt;/a\u0026gt;  \n    在线演示：\u0026lt;a\u0026gt;https://play.google.com/store/apps/details?id=com.nolanlawson.logcat\u0026lt;/a\u0026gt;\n  4. PID Cat  \n    根据package查看logcat日志  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/JakeWharton/pidcat\u0026lt;/a\u0026gt;\n  5. ACRA  \n    应用崩溃信息上报到GoogleDoc工具，网页版展现结果三方开源地址\u0026lt;a\u0026gt;https://github.com/BenoitDuffez/crashreportsviewer\u0026lt;/a\u0026gt;  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/ACRA/acra\u0026lt;/a\u0026gt;  \n    文档地址：\u0026lt;a\u0026gt;https://github.com/ACRA/acra/wiki/BasicSetup\u0026lt;/a\u0026gt;\n  6. Crashlytics  \n    提供丰富的应用崩溃信息收集  \n    轻量级，丰富，可自定义应用崩溃信息收集器，附有邮件通知  \n    项目地址：\u0026lt;a\u0026gt;http://www.crashlytics.com/\u0026lt;/a\u0026gt;  \n    集成插件：\u0026lt;a\u0026gt;Android Studio, Eclipse and IntelliJ\u0026lt;/a\u0026gt;\n  7. Android Resource Navigator  \n    chrome插件，可以方便的查看github上android源码工程的styles.xml和themes.xml。主要功能：  \n    (1) 快速打开android styles.xml themes.xml  \n    (2) 方便在资源间跳转。styles.xml themes.xml文件中资源链接跳转，可以方便跳转到某个资源  \n    (3) 方便查找某个style和theme。chrome地址栏输入arn+tab+搜索内容回车即可  \n    (4) 自动下载不同分辨率下的drawable  \n    (5) 通过映射查找那些不是按照固定命名规则命名的style和theme  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/jgilfelt/android-resource-navigator\u0026lt;/a\u0026gt;  \n    示例：\u0026lt;a\u0026gt;https://chrome.google.com/webstore/detail/android-resource-navigato/agoomkionjjbejegcejiefodgbckeebo?hl=en\u0026amp;gl=GB\u0026lt;/a\u0026gt;\n  8. android-resource-remover  \n    根据lint的提示删除项目中无用的资源，减少包的大小  \n    项目地址：\u0026lt;a\u0026gt;https://github.com/KeepSafe/android-resource-remover\u0026lt;/a\u0026gt;(转自https://github.com/Trinea/android-open-project#%E7%9B%AE%E5%89%8D%E5%8C%85%E6%8B%AC)\n\u003c/code\u003e\u003c/pre\u003e","title":"【Android】开源项目汇总-备用"},{"content":"启动Activity\nadb调用Activity Manager\nadb shell am start [options] option\n-D debug调试\n-W 等待启动完成\nINTENT\n-a :设置 intent的action\n-d\u0026lt;Data_URL\u0026gt; 设置intent的uri\n-t\u0026lt;MIME_TYPE\u0026gt;设置intent的mime类型\n-c设置intent的类别\n-n设置intent的component\n-f设置intent的flag\n命令监听crash和ANR\nadb shell am monitor\nctrl +c 结束监听\n强制停止应用\nadb shell am force-stop 包名\n清理进程\nam kill 进程名称（-all ）\nam startservice -n 包名/服务的名称\nam broadcast -n 包名/广播的名称 启动广播\nadb调用PackageManger -获取应用列表\n命令\nadb shell pm list package [options] [filter]\noption\n-s 表示过滤出系统应用\n-3 表示过滤出第三方应用\n-f 表示列出包名，apk名称和存放位置\n-u 表示列出包含卸载的应用\n-d 表示过滤出系统禁用的应用\n-e表示过滤出系统正常使用的应用\n-i 列出应用包名及其安装来源\nfilter\n包名 表示过滤包名\n列出应用包名对应的apk的位置\nadb shell pm path dump应用信息\nadb shell pm dump 安装应用\nadb shell pm install [options] (apk文件在手机上使用该命令，在电脑上使用adb install)\noptions\n-r 覆盖安装\n-s 安装到sdcard中\n-f 安装到手机内部存储中\n-d 降价安装（低版本应用）\n卸载应用\nadb shell pm uninstall\n清空数据\nadb shell am clear 获取应用安装位置设置信息\nadb shell pm get-install-location adb shell pm set-install-location 0/1/2\n0是自动\n1是内部存储\n2是外部存储\n获取系统中的所有功能\nadb shell pm list features\n启用一个应用或者组件\nadb shell pm enabled 禁用一个应用或者组件\nadb shell pm disabled 持续更新中。。。\n转载说明出处：http://www.etongwl.com/archives/977.html\n","permalink":"https://blog.zdltech.com/posts/adb%E5%91%BD%E4%BB%A4%E4%BD%BF%E7%94%A8/","summary":"\u003cp\u003e\u003cspan class=\"s1\"\u003e启动\u003c/span\u003eActivity\u003c/p\u003e\n\u003cp\u003eadb调用Activity Manager\u003c/p\u003e\n\u003cp\u003eadb shell am start [options] \u003cINTENT\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"Apple-converted-space\"\u003e   \u003c/span\u003eoption\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"Apple-converted-space\"\u003e       \u003c/span\u003e-D debug\u003cspan class=\"s1\"\u003e调试\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"Apple-converted-space\"\u003e       \u003c/span\u003e-W \u003cspan class=\"s1\"\u003e等待启动完成\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"Apple-converted-space\"\u003e   \u003c/span\u003eINTENT\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"Apple-converted-space\"\u003e       \u003c/span\u003e-a \u003cACTION\u003e:\u003cspan class=\"s1\"\u003e设置\u003c/span\u003e intent\u003cspan class=\"s1\"\u003e的\u003c/span\u003eaction\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"Apple-converted-space\"\u003e       \u003c/span\u003e-d\u0026lt;Data_URL\u0026gt; \u003cspan class=\"s1\"\u003e设置\u003c/span\u003eintent\u003cspan class=\"s1\"\u003e的\u003c/span\u003euri\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e\u003cspan class=\"Apple-converted-space\"\u003e       \u003c/span\u003e-t\u003c/span\u003e\u0026lt;MIME_TYPE\u0026gt;设置intent的mime类型\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"Apple-converted-space\"\u003e        \u003c/span\u003e-c\u003cCATEGORY\u003e设置intent的类别\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"Apple-converted-space\"\u003e        \u003c/span\u003e-n\u003cCOMPONENT\u003e设置intent的component\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"Apple-converted-space\"\u003e        \u003c/span\u003e-f\u003cFLAG\u003e设置intent的flag\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e命令监听\u003c/span\u003ecrash\u003cspan class=\"s1\"\u003e和\u003c/span\u003eANR\u003c/p\u003e\n\u003cp\u003eadb shell am monitor\u003c/p\u003e\n\u003cp\u003ectrl +c \u003cspan class=\"s1\"\u003e结束监听\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e强制停止应用\u003c/p\u003e\n\u003cp\u003eadb shell am force-stop \u003cspan class=\"s1\"\u003e包名\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e清理进程\u003c/p\u003e\n\u003cp\u003eam kill 进程名称（-all ）\u003c/p\u003e\n\u003cp\u003eam startservice -n 包名/服务的名称\u003c/p\u003e\n\u003cp\u003eam broadcast -n\u003cspan class=\"Apple-converted-space\"\u003e  \u003c/span\u003e包名/广播的名称 \u003cspan class=\"Apple-converted-space\"\u003e    \u003c/span\u003e启动广播\u003c/p\u003e\n\u003cp\u003eadb调用PackageManger -获取应用列表\u003c/p\u003e\n\u003cp\u003e命令\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"Apple-converted-space\"\u003e   \u003c/span\u003eadb shell pm list package [options] [filter]\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"Apple-converted-space\"\u003e   \u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"Apple-converted-space\"\u003e    \u003c/span\u003eoption\u003c/p\u003e","title":"adb命令使用"},{"content":"下面我将一下mac环境下的配置步骤：\n1.启动Terminal终端工具\n2.输入cd ~/ 进入当前用户的home目录\n3. 创建： touch .bash_profile 4.打开并编辑： open .bash_profile 5、在文件中写入以下内容：export PATH=${PATH}:/Users/sxpmg/Application/android-sdk-mac_x86/tools:/Users/sxpmg/Application/android-sdk-mac_x86/platform-tools\n其中：/Users/sxpmg/Application/android-sdk-mac_x86/tools不是固定的，它指向android SDK的tools目录，/Users/sxpmg/Application/android-sdk-mac_x86/platform-tools指向android SDK的platform-tools目录，也是根据具体情况而定。这只是我配置的时候所用的路径而已。\n6、执行如下命令：source .bash_profile\n7、验证：输入adb回车。如果未显示command not found，说明此命令有效，环境便亮设置完成。\n","permalink":"https://blog.zdltech.com/posts/mac%E4%B8%8Bandroid_sdk%E9%85%8D%E7%BD%AE%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F/","summary":"\u003cp\u003e下面我将一下mac环境下的配置步骤：\u003c/p\u003e\n\u003cp\u003e1.启动Terminal终端工具\u003cbr\u003e\n2.输入cd ~/ 进入当前用户的home目录\u003c/p\u003e\n\u003cdiv\u003e\n  3. 创建：\n\u003c/div\u003e\n\u003cdiv\u003e\n  touch .bash_profile\n\u003c/div\u003e\n\u003cdiv\u003e\n  4.打开并编辑：\n\u003c/div\u003e\n\u003cdiv\u003e\n  open .bash_profile\n\u003c/div\u003e\n\u003cp\u003e5、在文件中写入以下内容：export PATH=${PATH}:/Users/sxpmg/Application/android-sdk-mac_x86/tools:/Users/sxpmg/Application/android-sdk-mac_x86/platform-tools\u003cbr\u003e\n其中：/Users/sxpmg/Application/android-sdk-mac_x86/tools不是固定的，它指向android SDK的tools目录，/Users/sxpmg/Application/android-sdk-mac_x86/platform-tools指向android SDK的platform-tools目录，也是根据具体情况而定。这只是我配置的时候所用的路径而已。\u003cbr\u003e\n6、执行如下命令：source .bash_profile\u003cbr\u003e\n7、验证：输入adb回车。如果未显示command not found，说明此命令有效，环境便亮设置完成。\u003c/p\u003e","title":"Mac下android_sdk配置环境变量"},{"content":"Android系统中的Activity可以说一件很赞的设计，它在内存管理上良好的设计，使得多任务管理在Android系统中运行游刃有余。但是Activity绝非启动展示在屏幕而已，其启动方式也大有学问，本文讲具体介绍Activity的启动模式的诸多细节，纠正一些开发中可能错误的观点，帮助大家深入理解Activity。\n行文之前 在正式行文之前，先介绍一些文章提到的概念\n文章后续会提到Task，这里的Task指的是与用户交互的Activity实例的集合。 Task中的Activity实例以栈的形式存放，这个栈就是Activity的回退栈。 本文图片较多，在看图时，请注意观察Activity顶部的title，来区分具体Activity。\n为何有启动模式 应用中的每一个Activity都是进行不同的事物处理。以邮件客户端为例，InboxActivity目的就是为了展示收件箱，这个Activity不建议创建成多个实例。而ComposeMailActivity则是用来撰写邮件，可以实例化多个此Activity对象。合理地设计Activity对象是否使用已有的实例还是多次创建，会使得交互设计更加良好，也能避免很多问题。至于想要达到前面的目标，就需要使用今天的Activity启动模式。\n如何使用 使用很简单，只需要在manifest中对应的Activity元素加入android:launchMode属性即可。如下述代码\n``` 1 2 3 4 5 \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34;\u0026gt;\u0026amp;lt;activity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:name=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;.SingleTaskActivity\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:label=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;singleTask launchMode\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:launchMode=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;singleTask\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34;\u0026gt;\u0026amp;lt;/activity\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 接下来就是介绍launchMode的四个值的时刻了。\nstandard 这是launchMode的默认值，Activity不包含android:launchMode或者显示设置为standard的Activity就会使用这种模式。\n一旦设置成这个值，每当有一次Intent请求，就会创建一个新的Activity实例。举个例子，如果有10个撰写邮件的Intent，那么就会创建10个ComposeMailActivity的实例来处理这些Intent。结果很明显，这种模式会创建某个Activity的多个实例。\nAndroid 5.0之前的表现 这种Activity新生成的实例会放入发送Intent的Task的栈的顶部。下图为启动同一程序内的Activity。\n下面的图片展示跨程序之间调用，新生成的Activity实例会放入发送Intent的Task的栈的顶部，尽管它们属于不同的程序。\n但是当我们打开任务管理器，则会有一点奇怪，应为显示的任务是Gallery，展示的界面确实另一个程序的Activity（因为其位于Task的栈顶）。\n这时候如果我们从Gallery应用切换到拨号应用，再返回到Gallery，看到的还是这个非Gallery的Activity，如果我们想要对Gallery进行操作，必须按Back键返回到Gallery界面才可以。确实有点不太合理。\nAndroid 5.0及之后表现 对于同一应用内部Activity启动和5.0之前表现一样，变化的就是不同应用之间Activity启动变得合理了。\n跨应用之间启动Activity，会创建一个新的Task，新生成的Activity就会放入刚创建的Task中。如下图\n同时任务管理器查看任务也显得更加合理了。\n假设之前存在我们的测试程序，然后从Gallery又分享文件到我们的测试程序，则对应的任务管理器展示效果如下。\n使用场景：standard这种启动模式适合于撰写邮件Activity或者社交网络消息发布Activity。如果你想为每一个intent创建一个Activity处理，那么就是用standard这种模式。\nsingleTop singleTop其实和standard几乎一样，使用singleTop的Activity也可以创建很多个实例。唯一不同的就是，如果调用的目标Activity已经位于调用者的Task的栈顶，则不创建新实例，而是使用当前的这个Activity实例，并调用这个实例的onNewIntent方法。 在singleTop这种模式下，我们需要处理应用这个模式的Activity的onCreate和onNewIntent两个方法，确保逻辑正常。\n使用场景 关于singleTop一个典型的使用场景就是搜索功能。假设有一个搜索框，每次搜索查询都会将我们引导至SearchActivity查看结果，为了更好的交互体验，我们在结果页顶部也放置这样的搜索框。\n假设一下，SearchActivity启动模式为standard，那么每一个搜索都会创建一个新的SearchActivity实例，10次查询就是10个Activity。当我们想要退回到非SearchActivity，我们需要按返回键10次，这显然太不合理了。\n但是如果我们使用singleTop的话，如果SearchActivity在栈顶，当有了新的查询时，不再重新创建SearchAc实例，而是使用当前的SearchActivity来更新结果。当我们需要返回到非SearchActivity只需要按一次返回键即可。使用了singleTop显然比之前要合理。\n总结 只有在调用者和目标Activity在同一Task中，并且目标Activity位于栈顶，才使用现有目标Activity实例，否则创建新的目标Activity实例。 如果是外部程序启动singleTop的Activity，在Android 5.0之前新创建的Activity会位于调用者的Task中，5.0及以后会放入新的Task中。 singleTask singleTask这个模式和前面提到的standard和singleTop截然不同。使用singleTask启动模式的Activity在系统中只会存在一个实例。如果这个实例已经存在，intent就会通过onNewIntent传递到这个Activity。否则新的Activity实例被创建。\n同一程序内 如果系统中不存在singleTask Activity的实例，那么就需要创建这个Activity的实例，并且将这个实例放入和调用者相同的Task中并位于栈顶。\n如果singleTask Activity实例已然存在，那么在Activity回退栈中，所有位于该Activity上面的Activity实例都将被销毁掉（销毁过程会调用Activity生命周期回调），这样使得singleTask Activity实例位于栈顶。与此同时，Intent会通过onNewIntent传递到这个SingleTask Activity实例。\n然而在Google关于singleTask的文档有这样一段描述\nThe system creates a new task and instantiates the activity at the root of the new task.\n意思为 系统会创建一个新的Task，并创建Activity实例放入这个新的Task的底部。\n然而实际并非如此，在我的例子中，singleTask Activity并创建并放入了调用者所在的Task，而不是放入新的Task，使用adb shell dumpsys activity便可以进行验证。\n``` 1 2 3 4 5 6 7 8 9 \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Task\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;id\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;err\u0026#34;\u0026gt;#\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;239\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;TaskRecord\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;428\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;efe30\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;err\u0026#34;\u0026gt;#\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;239\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;A\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;com\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;thecheesefactory\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;lab\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;launchmode\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;U\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;sz\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Intent\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;act\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;action\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;MAIN\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;cat\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=[\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;category\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;LAUNCHER\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;]\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;flg\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mh\u0026#34;\u0026gt;0x10000000\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;cmp\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;com\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;thecheesefactory\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;lab\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;launchmode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;/.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;StandardActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Hist\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;err\u0026#34;\u0026gt;#\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;ActivityRecord\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;429\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;a88d0\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;u0\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;com\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;thecheesefactory\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;lab\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;launchmode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;/.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;SingleTaskActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;t239\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Intent\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;cmp\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;com\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;thecheesefactory\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;lab\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;launchmode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;/.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;SingleTaskActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;ProcessRecord\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;42243130\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;18965\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;com\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;thecheesefactory\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;lab\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;launchmode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;/\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;u0a123\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Hist\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;err\u0026#34;\u0026gt;#\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;ActivityRecord\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;425\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;fec98\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;u0\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;com\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;thecheesefactory\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;lab\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;launchmode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;/.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;StandardActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;t239\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Intent\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;act\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;action\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;MAIN\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;cat\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=[\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;category\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;LAUNCHER\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;]\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;flg\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mh\u0026#34;\u0026gt;0x10000000\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;cmp\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;com\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;thecheesefactory\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;lab\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;launchmode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;/.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;StandardActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;ProcessRecord\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;42243130\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;mi\u0026#34;\u0026gt;18965\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;:\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;com\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;thecheesefactory\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;lab\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;launchmode\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;/\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;u0a123\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 然而想要实现文档的描述也并非不可能，我们需要在设置launchMode为singleTask的同时，再加上taskAffinity属性即可。\n``` 1 2 3 4 5 6 \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34;\u0026gt;\u0026amp;lt;activity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:name=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;.SingleTaskActivity\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:label=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;singleTask launchMode\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:launchMode=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;singleTask\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:taskAffinity=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34;\u0026gt;\u0026amp;lt;/activity\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 完成上面的修改，我们看一下效果，Task的变化如下图\n同时，系统中的任务管理器效果也会相应变化\n跨应用之间 在跨应用Intent传递时，如果系统中不存在singleTask Activity的实例，那么讲创建一个新的Task，然后创建SingleTask Activity的实例，将其放入新的Task中。Task变化如下。\n系统的任务管理器也会如下变化\n如果singleTask Activity所在的应用进程存在，但是singleTask Activity实例不存在，那么从别的应用启动这个Activity，新的Activity实例会被创建，并放入到所属进程所在的Task中，并位于栈顶位置。\n更复杂的一种情况，如果singleTask Activity实例存在，从其他程序被启动，那么这个Activity所在的Task会被移到顶部，并且在这个Task中，位于singleTask Activity实例之上的所有Activity将会被正常销毁掉。如果我们按返回键，那么我们首先会回退到这个Task中的其他Activity，直到当前Task的Activity回退栈为空时，才会返回到调用者的Task。\n在上图中，当Task2中的相册启动分享调用Task1中的singleTask Activity，而该Activity实例存在，并位于Task1中回退栈中的第三个位置（从上到下顺序），那么位于该Activity上面的两个Activity实例将会被销毁掉，使得该Activity实例位于栈顶。此时Task1中的回退栈只剩两个Activity，如果点击返回，那么会退到的不是相册应用，而是singleTask Activity栈位置下面的Activity，再次点击返回方可返回相册应用。\n使用场景 该模式的使用场景多类似于邮件客户端的收件箱或者社交应用的时间线Activity。上述两种场景需要对应的Activity只保持一个实例即可，但是也要谨慎使用这种模式，因为它可以在用户未感知的情况下销毁掉其他Activity。\nsingleInstance 这个模式和singleTask差不多，因为他们在系统中都只有一份实例。唯一不同的就是存放singleInstance Activity实例的Task只能存放一个该模式的Activity实例。如果从singleInstance Activity实例启动另一个Activity，那么这个Activity实例会放入其他的Task中。同理，如果singleInstance Activity被别的Activity启动，它也会放入不同于调用者的Task中。\n虽然是两个task，但是在系统的任务管理器中，却始终显示一个，即位于顶部的Task中。\n另外当我们从任务管理器进入这个应用，是无法通过返回键会退到Task1的。\n好在有办法解决这个问题，就是之前提到的taskAffinity=\u0026quot;\u0026quot;，为launchMode为singleInstance的Activity加入这个属性即可。\n``` 1 2 3 4 5 6 \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34;\u0026gt;\u0026amp;lt;activity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:name=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;.SingleInstanceActivity\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:label=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;singleInstance launchMode\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:launchMode=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;singleInstance\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:taskAffinity=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34;\u0026gt;\u0026amp;lt;/activity\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 再次运行修改的代码，查看任务管理器，这样的结果就合理了。\n使用情况 这种模式的使用情况比较罕见，在Launcher中可能使用。或者你确定你需要使Activity只有一个实例。建议谨慎使用。\nIntent Flags 除了在manifest文件中设置launchMode之外，还可以在Intnet中设置flag达到同样的效果。如下述代码就可以让StandardActivity已singleTop模式启动。\n``` 1 2 3 \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Intent\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;intent\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;StandardActivity\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;StandardActivity\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;addFlags\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;Intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;FLAG_ACTIVITY_SINGLE_TOP\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;startActivity\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34;\u0026gt;intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 关于Intent Flags这里暂不做重点介绍，具体可以参考官方文档\n原文信息 Understand Android Activity’s launchMode: standard, singleTop, singleTask and singleInstance ","permalink":"https://blog.zdltech.com/posts/%E6%B7%B1%E5%85%A5%E8%AE%B2%E8%A7%A3android%E4%B8%ADactivity-launchmode/","summary":"\u003cp\u003eAndroid系统中的Activity可以说一件很赞的设计，它在内存管理上良好的设计，使得多任务管理在Android系统中运行游刃有余。但是Activity绝非启动展示在屏幕而已，其启动方式也大有学问，本文讲具体介绍Activity的启动模式的诸多细节，纠正一些开发中可能错误的观点，帮助大家深入理解Activity。\u003c/p\u003e\n\u003ch2 id=\"行文之前\"\u003e行文之前\u003c/h2\u003e\n\u003cp\u003e在正式行文之前，先介绍一些文章提到的概念\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e文章后续会提到Task，这里的Task指的是与用户交互的Activity实例的集合。\u003c/li\u003e\n\u003cli\u003eTask中的Activity实例以栈的形式存放，这个栈就是Activity的回退栈。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e本文图片较多，在看图时，请注意观察Activity顶部的title，来区分具体Activity。\u003c/strong\u003e\u003c/p\u003e\n\u003ch2 id=\"为何有启动模式\"\u003e为何有启动模式\u003c/h2\u003e\n\u003cp\u003e应用中的每一个Activity都是进行不同的事物处理。以邮件客户端为例，InboxActivity目的就是为了展示收件箱，这个Activity不建议创建成多个实例。而ComposeMailActivity则是用来撰写邮件，可以实例化多个此Activity对象。合理地设计Activity对象是否使用已有的实例还是多次创建，会使得交互设计更加良好，也能避免很多问题。至于想要达到前面的目标，就需要使用今天的Activity启动模式。\u003c/p\u003e\n\u003ch2 id=\"如何使用\"\u003e如何使用\u003c/h2\u003e\n\u003cp\u003e使用很简单，只需要在manifest中对应的Activity元素加入\u003cstrong\u003eandroid:launchMode\u003c/strong\u003e属性即可。如下述代码\u003cfigure class=\"code\"\u003e\u003cfigcaption\u003e\u003c/figcaption\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\n  \u003ctable\u003e\n    \u003ctr\u003e\n      \u003ctd class=\"gutter\"\u003e\n        ```\n\u003cspan class=\"line-number\"\u003e1\u003c/span\u003e\n\u003cspan class=\"line-number\"\u003e2\u003c/span\u003e\n\u003cspan class=\"line-number\"\u003e3\u003c/span\u003e\n\u003cspan class=\"line-number\"\u003e4\u003c/span\u003e\n\u003cspan class=\"line-number\"\u003e5\u003c/span\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;td class=\u0026#34;code\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34;\u0026gt;\u0026amp;lt;activity\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;    \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:name=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;.SingleTaskActivity\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;    \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:label=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;singleTask launchMode\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;    \u0026amp;lt;span class=\u0026#34;na\u0026#34;\u0026gt;android:launchMode=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34;\u0026gt;\u0026#34;singleTask\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34;\u0026gt;\u0026amp;lt;/activity\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/span\u0026gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e  \u0026lt;/td\u0026gt;\n\u0026lt;/tr\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/table\u003e\n\u003c/div\u003e\u003c/figure\u003e \n\u003cp\u003e接下来就是介绍launchMode的四个值的时刻了。\u003c/p\u003e\n\u003ch2 id=\"standard\"\u003estandard\u003c/h2\u003e\n\u003cp\u003e这是launchMode的默认值，Activity不包含android:launchMode或者显示设置为standard的Activity就会使用这种模式。\u003c/p\u003e\n\u003cp\u003e一旦设置成这个值，\u003cstrong\u003e每当有一次Intent请求，就会创建一个新的Activity实例\u003c/strong\u003e。举个例子，如果有10个撰写邮件的Intent，那么就会创建10个ComposeMailActivity的实例来处理这些Intent。结果很明显，这种模式会创建某个Activity的多个实例。\u003c/p\u003e\n\u003ch3 id=\"android-50之前的表现\"\u003eAndroid 5.0之前的表现\u003c/h3\u003e\n\u003cp\u003e这种Activity新生成的实例会放入发送Intent的Task的栈的顶部。下图为启动同一程序内的Activity。\u003cimg loading=\"lazy\" src=\"http://7jpolu.com1.z0.glb.clouddn.com/pre_lollipop_standard_activity_in_same_app.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e下面的图片展示跨程序之间调用，新生成的Activity实例会放入发送Intent的Task的栈的顶部，尽管它们属于不同的程序。\u003cimg loading=\"lazy\" src=\"http://7jpolu.com1.z0.glb.clouddn.com/pre_lollipop_standard_activity_across_app.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e但是当我们打开任务管理器，则会有一点奇怪，应为显示的任务是Gallery，展示的界面确实另一个程序的Activity（因为其位于Task的栈顶）。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://7jpolu.com1.z0.glb.clouddn.com/pre_lollipop_task_manager_across_app.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e这时候如果我们从Gallery应用切换到拨号应用，再返回到Gallery，看到的还是这个非Gallery的Activity，如果我们想要对Gallery进行操作，必须按Back键返回到Gallery界面才可以。确实有点不太合理。\u003c/p\u003e\n\u003ch3 id=\"android-50及之后表现\"\u003eAndroid 5.0及之后表现\u003c/h3\u003e\n\u003cp\u003e对于同一应用内部Activity启动和5.0之前表现一样，变化的就是不同应用之间Activity启动变得合理了。\u003c/p\u003e\n\u003cp\u003e跨应用之间启动Activity，会创建一个新的Task，新生成的Activity就会放入刚创建的Task中。如下图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://7jpolu.com1.z0.glb.clouddn.com/lollipop_across_app_new_task.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e同时任务管理器查看任务也显得更加合理了。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://7jpolu.com1.z0.glb.clouddn.com/lollipop_task_manager_standard.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e假设之前存在我们的测试程序，然后从Gallery又分享文件到我们的测试程序，则对应的任务管理器展示效果如下。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://7jpolu.com1.z0.glb.clouddn.com/lollipop_standard_across_app_alread_exists.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e使用场景：standard这种启动模式适合于撰写邮件Activity或者社交网络消息发布Activity。如果你想为每一个intent创建一个Activity处理，那么就是用standard这种模式。\u003c/p\u003e\n\u003ch2 id=\"singletop\"\u003esingleTop\u003c/h2\u003e\n\u003cp\u003esingleTop其实和standard几乎一样，使用singleTop的Activity也可以创建很多个实例。唯一不同的就是，\u003cstrong\u003e如果调用的目标Activity已经位于调用者的Task的栈顶，则不创建新实例，而是使用当前的这个Activity实例，并调用这个实例的onNewIntent方法\u003c/strong\u003e。\u003cimg loading=\"lazy\" src=\"http://7jpolu.com1.z0.glb.clouddn.com/singletop.jpg\"\u003e 在singleTop这种模式下，我们需要处理应用这个模式的Activity的onCreate和onNewIntent两个方法，确保逻辑正常。\u003c/p\u003e","title":"深入讲解Android中Activity launchMode"},{"content":" 如果你执行了从module列表中移除module的操作，但是没有执行delete module文件夹的操作，那如何恢复被移除掉的module呢。 关于如何移除请戳这：[Android Studio如何删除module](http://www.cnblogs.com/0616--ataozhijia/p/3865379.html) 这种场景还是很多见的，比如我 移除了module app，但是后面我又想用这个module了，要恢复的话，很简单，看下图，编辑settings.gradle即可，当然里面的module名称必须得 和你移除的module名称要一致，编辑完了记得点sycn gradle按钮。 ![](http://img.blog.csdn.net/20140707170254562?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHlyODM5NjA5NDQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) ","permalink":"https://blog.zdltech.com/posts/android-studio-android-studio%E7%A7%BB%E9%99%A4%E7%9A%84module%E5%A6%82%E4%BD%95%E6%81%A2%E5%A4%8D/","summary":"\u003cdiv id=\"cnblogs_post_body\"\u003e\n\u003cpre\u003e\u003ccode\u003e如果你执行了从module列表中移除module的操作，但是没有执行delete module文件夹的操作，那如何恢复被移除掉的module呢。\n\n\n\n\n\n关于如何移除请戳这：[Android Studio如何删除module](http://www.cnblogs.com/0616--ataozhijia/p/3865379.html)\n\n\n\n\n\n这种场景还是很多见的，比如我 移除了module app，但是后面我又想用这个module了，要恢复的话，很简单，看下图，编辑settings.gradle即可，当然里面的module名称必须得 和你移除的module名称要一致，编辑完了记得点sycn gradle按钮。\n\n\n\n\n\n![](http://img.blog.csdn.net/20140707170254562?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHlyODM5NjA5NDQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv class=\"clear\"\u003e\n\u003c/div\u003e\n\u003cdiv id=\"blog_post_info_block\"\u003e\n  \u003cdiv id=\"BlogPostCategory\"\u003e\n  \u003c/div\u003e\n\u003c/div\u003e","title":"[Android Studio] Android Studio移除的Module如何恢复"},{"content":"当前有很大的趋势是转向移动应用平台，Android 是最广泛使用的移动操作系统，2014 年大约占 80% 以上的市场。在开发 Android 应用的时候要进行测试，现在市场上有大量的测试工具。\n本文主要是展示一系列的开源 Android 测试工具。每个工具都会有相应的简短介绍，还有一些相关的资源。Android 测试工具列表是按照字母来排序的，最后还会介绍几个不是特别活跃的 Android 测试相关的开源项目。\n本文提到的开源 Android 软件测试工具包括：Android Test Kit, AndroidJUnit4, Appium, calabash-android, Monkey, MonkeyTalk, NativeDriver, Robolectric, RoboSpock, Robotium, UIAutomator, Selendroid。\nAndroid Test Kit\nAndroid Test Kit 是一组 Google 开源测试工具，用于 Android 平台，包含 Espresso API 可用于编写简洁可靠的 Android UI 测试。\nOSChina URL: http://www.oschina.net/p/android-test-kit\n相关资源\nAndroid application testing with the Android test framework – Tutorial Espresso for Android is here! AndroidJUnit4\nAndroidJUnit4 是一个让 JUnit 4 可以直接运行在 Android 设备上的开源命令行工具。\nOSChina URL: http://www.oschina.net/p/androidjunit4\nAppium\nAppium 是一个开源、跨平台的自动化测试工具，用于测试原生和轻量移动应用，支持 iOS, Android 和 FirefoxOS 平台。Appium 驱动苹果的 UIAutomation 库和 Android 的 UiAutomator 框架，使用 Selenium 的 WebDriver JSON 协议。Appinm 的 iOS 支持是基于 Dan Cuellar’s 的 iOS Auto. Appium 同时绑定了 Selendroid 用于老的 Android 平台测试。\nOSChina URL: http://www.oschina.net/p/appium\n相关资源\nAppium Tutorial Android UI testing with Appium Calabash-android\ncalabash-android 是一个基于 Cucumber 的 Android 的功能自动化测试框架。Calabash 允许你写和执行，是开源的自动化移动应用测试工具，支持 Android 和 iOS 原生应用。Calabash 的库允许原生和混合应用的交互测试，交互包括大量的终端用户活动。Calabash 可以媲美 Selenium WebDriver。但是， 需要注意的是 web 应用和桌面环境的交互跟触摸屏应用的交互是不同的。Calabash 专为触摸屏设备的原生应用提供 APIs。\nOSChina URL: http://www.oschina.net/p/calabash-android\n相关资源\nA better way to test Android applications using Calabash Calabash Android: query language basics Monkey\nMonkey 是 Google 开发的 UI/应用测试工具，也是命令行工具，主要针对压力测试。你可以在任意的模拟器示例或者设备上运行。Monkey 发送一个用户事件的 pseudo-random 流给系统，作为你开发应用的压力测试。\nOSChina URL: http://developer.android.com/tools/help/monkey.html\nMonkeyTalk\nMonkeyTalk 是世界上最强大的移动应用测试工具。MonkeyTalk 自动为 iOS 和 Android 应用进行真实的，功能性交互测试。MonkeyTalk 提供简单的 “smoke tests”，复杂数据驱动的测试套件。MonkeyTalk 支持原生，移动和混合应用，真实设备或者模拟器。MonkeyTalk 使得场景捕获非常容易，可以记录高级别，可读的测试脚本。同样的命令可以用在 iOS 和 Android 应用上。你可以记录一个平台的一个测试，并且可以在另外一个平台回放。MonkeyTalk 支持移动触摸和基于手势交互为主的移动体验。点击，拖拽，移动，甚至是手指绘制也可以被记录和回放。\nOSChina URL: http://www.oschina.net/p/monkeytalk\n相关资源\nUsing MonkeyTalk in AndroidStudio NativeDriver\nNativeDriver 是 WebDriver API 的实现，是原生应用 UI 驱动，而不是 web 应用。\nOSChina URL: http://www.oschina.net/p/nativedriver\nRobolectric\nRobolectric 是一款Android单元测试框架，使用 Android SDK jar，所以你可以使用测试驱动开发 Android 应用。测试只需几秒就可以在工作站的 JVM 运行。Robolectric 处理视图缩放，资源加载和大量 Android 设备原生的 C 代码实现。Robolectric 允许你做大部分真实设备上可以做的事情，可以在工作站中运行，也可以在常规的 JVM 持续集成环境运行，不需要通过模拟器。\nOSChina URL: http://www.oschina.net/p/robolectric\nAdditional resources\nBetter Android Testing with Robolectric 2.0\nUsing Robolectric for Android testing – Tutorial RoboSpock\nRoboSpock 是一个开源的 Android 测试框架。提供简单的编写 BDD 行为驱动开发规范的方法，使用Groovy 语音，支持 Google Guice 库。RoboSpock 合并了 Robolectric 和 Spock 的功能。\nOSChina URL: http://www.oschina.net/p/robospock\n相关资源\nRoboSpock – Behavior Driven Development (BDD) for Android Robotium\nRobotium 是一款国外的Android自动化测试框架，主要针对Android平台的应用进行黑盒自动化测试，它提供了模拟各种手势操作（点击、长 按、滑动等）、查找和断言机制的API，能够对各种控件进行操作。Robotium结合Android官方提供的测试框架达到对应用程序进行自动化的测 试。另外，Robotium 4.0版本已经支持对WebView的操作。Robotium 对Activity，Dialog，Toast，Menu 都是支持的。\nOSChina URL: http://www.oschina.net/p/robotium\n相关资源\nRobotium – Testing Android User Interface Android user interface testing with Robotium – Tutorial UIAutomator\nuiautomator 测试框架提高用户界面（UI）的测试效率，通过自动创建功能 UI 测试示例，可以在一个或者多个设备上运行你的应用。\nOSChina URL: http://www.oschina.net/p/uiautomator\n相关资源\nAutomatic Android Testing with UiAutomator Selendroid\nSelendroid 是一个 Android 原生应用的 UI 自动化测试框架。测试使用 Selenium 2 客户端 API 编写。Selendroid 可以在模拟器和实际设备上使用，也可以集成网格节点作为缩放和并行测试。\nOSChina URL: http://www.oschina.net/p/selendroid\n相关资源\nMobile Test Automation with Selendroid Road to setup Selendroid and create first test script of android application Up and running with: Selendroid 一些停止维护的 Android 测试工具\n一些几乎没有继续维护的开源 Android 测试工具项目（至少是最近几个月都没有更新的项目）。\nEmmagee\nEmmagee 是监控指定被测应用在使用过程中占用机器的CPU、内存、流量资源的性能测试小工具。Emmagee 同时还提供非常酷的一些特性，比如定制间隔来收集数据，使用浮动窗口呈现实时进程状态等。\nOSChina URL: http://www.oschina.net/p/emmagee\nSirocco\nScirocco（scirocco-webdriver） 是开源的应用自动化测试工具，可以从 Eclipse 访问必要的测试设备。Scirocco 提供自动化的 Android 应用测试功能，代替手工测试。Scirocco 支持谷歌的 NativeDriver，把 AndroidDriver 作为主要的测试库。Scirocco 包括三个部分：NativeDriver，AndroidDriver，scirocco 插件（一个 Eclipse 插件；可以自动执行 scenario 测试和制作测试报告截图）。\nOSChina URL: http://www.oschina.net/p/scirocco\nvia softwaretestingmagazine\n","permalink":"https://blog.zdltech.com/posts/2014-%E9%9D%9E%E5%B8%B8%E5%A5%BD%E7%94%A8%E7%9A%84%E5%BC%80%E6%BA%90-android-%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/","summary":"\u003cp\u003e当前有很大的趋势是转向移动应用平台，Android 是最广泛使用的移动操作系统，2014 年大约占 80% 以上的市场。在开发 Android 应用的时候要进行测试，现在市场上有大量的测试工具。\u003c/p\u003e\n\u003cp\u003e本文主要是展示一系列的开源 Android 测试工具。每个工具都会有相应的简短介绍，还有一些相关的资源。Android 测试工具列表是按照字母来排序的，最后还会介绍几个不是特别活跃的 Android 测试相关的开源项目。\u003c/p\u003e\n\u003cp\u003e本文提到的开源 Android 软件测试工具包括：Android Test Kit, AndroidJUnit4, Appium, calabash-android, Monkey, MonkeyTalk, NativeDriver, Robolectric, RoboSpock, Robotium, UIAutomator, Selendroid。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAndroid Test Kit\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eAndroid Test Kit 是一组 Google 开源测试工具，用于 Android 平台，包含 Espresso API 可用于编写简洁可靠的 Android UI 测试。\u003c/p\u003e\n\u003cp\u003eOSChina URL: \u003ca href=\"http://www.oschina.net/p/android-test-kit\"\u003ehttp://www.oschina.net/p/android-test-kit\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e相关资源\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.vogella.com/tutorials/AndroidTesting/article.html\"\u003eAndroid application testing with the Android test framework – Tutorial\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://googletesting.blogspot.ch/2013/10/espresso-for-android-is-here.html\"\u003eEspresso for Android is here!\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eAndroidJUnit4\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eAndroidJUnit4 是一个让 \u003ca href=\"http://www.oschina.net/p/junit\"\u003eJUnit\u003c/a\u003e 4 可以直接运行在 Android 设备上的开源命令行工具。\u003c/p\u003e","title":"2014 非常好用的开源 Android 测试工具"},{"content":"由于看了IOS上面很多开发者开发的APP的视图界面切换动画体验非常好，这些都是IOS自带的，但是Android的Activity等视图切换动画并没有提供原生的，所以特此写了一个可以媲美IOS视图切换动画的Android视图切换动画特效库！SwitchLayout！可以说是目前Android上第一个，也是唯一的一个强大的视图切换动画库引擎！\n作者：谭东\nQQ：852041173\n项目开源！推荐使用jar包形式！\n没有经过作者允许，不可修改项目库源码自行发布。\n如果你的项目中使用了SwtichLayout，建议你在您的APP关于页面注明SwitchLayout库提供支持！非常感谢！如果您觉得SwitchLayout强大，欢迎推荐给你们的朋友。\n如果有什么建议，也可以反馈给我，会及时升级SwitchLayout库。\nSwitchLayout 的1.0jar包下载地址和Demo下载地址：http://pan.baidu.com/s/1dD6baLV\n源码和demo在github地址：https://github.com/jaychou2012/SwitchLayout\n好了，先看下主要的界面支持的视图切换特效吧！（此为Demo截图）\n、\n效果引擎足够媲美IOS了。\n里面的列表中，每个特效暴露的自定义扩展特效引擎接口大概可以扩充8个特效。所以一共大概可以扩充105种特效！足够强大！\n好了，下面说下大致的用法：\n1.导入SwitchLayout1.0.jar或者下载开源库。\n2.每个Activity实现接口implements SwichLayoutInterFace。推荐这种用法；接口里分别实现2个方法：setEnterSwichLayout();和setExitSwichLayout();这两个方法分别是设置进入Activity动画和离开Activity的动画的。\n在onCreate()里调用setEnterSwichLayout(); 在关闭Activity操作里调用setExitSwichLayout(); 如果需要的话在onKeyDown里拦截返回按键，调用setExitSwichLayout();\n3.具体特效调用（举一个例子）： SwitchLayout.getSlideFromBottom(this, false,BaseEffects.getMoreSlowEffect());\n// 三个参数分别为（Activity/View，是否关闭Activity，特效（可为空））；每个特效支持8种扩种，也可以不填特效。\n4.注意，在项目注册清单里，每个Activity要设置主题为透明主题。 android:theme=”@android:style/Theme.Translucent”，API在11以上即可。\n下面贴下SwitchLayoutDemo里的代码：\n**[java]** [view plain](http://blog.csdn.net/jay100500/article/details/42227365#)[copy](http://blog.csdn.net/jay100500/article/details/42227365#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/565636)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/565636/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.tandong.swichlayoutdemo; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Button; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.tandong.swichlayout.BaseEffects; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.tandong.swichlayout.SwitchLayout; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * SwitchLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * QQ 852041173\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 为Android提供IOS平台自有的界面视图切换动画而开发此库，工作量也不小，感谢支持SwitchLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 如果想自定义特效动画时长的话，请在此四个变量对应设置 SwitchLayout.animDuration = 1000;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * SwitchLayout.longAnimDuration = 2000; BaseAnimViewS.animDuration = 1000;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * BaseAnimViewS.longAnimDuration = 2000;即可。单位毫秒。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 以后SwitchLayout将会划分入我的SmartUI库下面\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author Tan Dong（谭东） 2014.12.28\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Button btn_ok, btn_1, btn_2, btn_3, btn_4, btn_5, btn_6, btn_7, - btn_8, btn_9, btn_10, btn_11, btn_12, btn_13, btn_14; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - requestWindowFeature(Window.FEATURE_NO_TITLE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - initView(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置进入Activity的Activity特效动画，同理可拓展为布局动画\u0026lt;/span\u0026gt; - SwitchLayout.getSlideFromBottom(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, - BaseEffects.getQuickToSlowEffect()); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 三个参数分别为（Activity/View，是否关闭Activity，特效（可为空））\u0026lt;/span\u0026gt; - initListener(); - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initListener() { - btn_ok.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - - btn_1.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - btn_2.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - btn_3.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - btn_4.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - btn_5.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - btn_6.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;6\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - - btn_7.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;7\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - btn_8.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - btn_9.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;9\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - btn_10.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - btn_11.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;11\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - btn_12.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;12\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - btn_13.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;13\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - btn_14.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;); - MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in); - } - }); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() { - btn_ok = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_ok); - btn_1 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_1); - btn_2 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_2); - btn_3 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_3); - btn_4 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_4); - btn_5 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_5); - btn_6 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_6); - btn_7 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_7); - btn_8 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_8); - btn_9 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_9); - btn_10 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_10); - btn_11 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_11); - btn_12 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_12); - btn_13 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_13); - btn_14 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_14); - - } - } **[java]** [view plain](http://blog.csdn.net/jay100500/article/details/42227365#)[copy](http://blog.csdn.net/jay100500/article/details/42227365#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/565636)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/565636/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.tandong.swichlayoutdemo; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.KeyEvent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.tandong.swichlayout.BaseEffects; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.tandong.swichlayout.SwichLayoutInterFace; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.tandong.swichlayout.SwitchLayout; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.tandong.swichlayoutdemo.R; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * SwitchLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * QQ 852041173\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 为Android提供IOS平台自有的界面视图切换动画而开发此库，工作量也不小，感谢支持SwitchLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author Tan Dong（谭东） 2014.12.28\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SecondActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; SwichLayoutInterFace { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Intent intent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageView iv_back; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; key = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - requestWindowFeature(Window.FEATURE_NO_TITLE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_second); - initIntent(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置进入Activity的Activity特效动画，同理可拓展为布局动画\u0026lt;/span\u0026gt; - setEnterSwichLayout(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initIntent() { - intent = getIntent(); - key = intent.getExtras().getInt(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;); - iv_back = (ImageView) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.iv_back); - iv_back.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - setExitSwichLayout(); - } - }); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onKeyDown(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; keyCode, KeyEvent event) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 按返回键时退出Activity的Activity特效动画\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (keyCode == KeyEvent.KEYCODE_BACK \u0026amp;\u0026amp; event.getRepeatCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - setExitSwichLayout(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onKeyDown(keyCode, event); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setEnterSwichLayout() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (key) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;: - SwitchLayout.get3DRotateFromLeft(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 三个参数分别为（Activity/View，是否关闭Activity，特效（可为空））\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;: - SwitchLayout.getSlideFromBottom(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, - BaseEffects.getMoreSlowEffect()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;: - SwitchLayout.getSlideFromTop(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, - BaseEffects.getReScrollEffect()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;: - SwitchLayout.getSlideFromLeft(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, - BaseEffects.getLinearInterEffect()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;: - SwitchLayout.getSlideFromRight(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;: - SwitchLayout.getFadingIn(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;6\u0026lt;/span\u0026gt;: - SwitchLayout.ScaleBig(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;7\u0026lt;/span\u0026gt;: - SwitchLayout.FlipUpDown(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, - BaseEffects.getQuickToSlowEffect()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;: - SwitchLayout.ScaleBigLeftTop(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;9\u0026lt;/span\u0026gt;: - SwitchLayout.getShakeMode(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;: - SwitchLayout.RotateLeftCenterIn(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;11\u0026lt;/span\u0026gt;: - SwitchLayout.RotateLeftTopIn(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;12\u0026lt;/span\u0026gt;: - SwitchLayout.RotateCenterIn(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;13\u0026lt;/span\u0026gt;: - SwitchLayout.ScaleToBigHorizontalIn(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;: - SwitchLayout.ScaleToBigVerticalIn(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setExitSwichLayout() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (key) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;: - SwitchLayout.get3DRotateFromRight(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;: - SwitchLayout.getSlideToBottom(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, - BaseEffects.getMoreSlowEffect()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;: - SwitchLayout.getSlideToTop(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, - BaseEffects.getReScrollEffect()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;: - SwitchLayout.getSlideToLeft(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, - BaseEffects.getLinearInterEffect()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;: - SwitchLayout.getSlideToRight(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;: - SwitchLayout.getFadingOut(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;6\u0026lt;/span\u0026gt;: - SwitchLayout.ScaleSmall(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;7\u0026lt;/span\u0026gt;: - SwitchLayout.FlipUpDown(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, - BaseEffects.getQuickToSlowEffect()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;: - SwitchLayout.ScaleSmallLeftTop(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;9\u0026lt;/span\u0026gt;: - SwitchLayout.getShakeMode(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;: - SwitchLayout.RotateLeftCenterOut(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;11\u0026lt;/span\u0026gt;: - SwitchLayout.RotateLeftTopOut(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;12\u0026lt;/span\u0026gt;: - SwitchLayout.RotateCenterOut(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;13\u0026lt;/span\u0026gt;: - SwitchLayout.ScaleToBigHorizontalOut(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;: - SwitchLayout.ScaleToBigVerticalOut(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - - } - - } **[java]** [view plain](http://blog.csdn.net/jay100500/article/details/42227365#)[copy](http://blog.csdn.net/jay100500/article/details/42227365#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/565636)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/565636/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;?xml version=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; encoding=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;?\u0026gt; - \u0026lt;manifest xmlns:android=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.tandong.swichlayoutdemo\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:versionCode=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:versionName=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; - - \u0026lt;uses-sdk - android:minSdkVersion=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;11\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:targetSdkVersion=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;19\u0026amp;#8221;\u0026lt;/span\u0026gt; /\u0026gt; - - \u0026lt;application - android:allowBackup=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:icon=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_launcher\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:label=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@string/app_name\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:theme=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@style/AppTheme\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; - \u0026lt;activity - android:name=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.tandong.swichlayoutdemo.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:label=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@string/app_name\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:theme=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Theme.Translucent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; - \u0026lt;intent-filter\u0026gt; - \u0026lt;action android:name=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.action.MAIN\u0026amp;#8221;\u0026lt;/span\u0026gt; /\u0026gt; - - \u0026lt;category android:name=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.category.LAUNCHER\u0026amp;#8221;\u0026lt;/span\u0026gt; /\u0026gt; - \u0026lt;/intent-filter\u0026gt; - \u0026lt;/activity\u0026gt; - \u0026lt;activity - android:name=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.tandong.swichlayoutdemo.SecondActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:launchMode=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;singleTask\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:theme=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Theme.Translucent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; - \u0026lt;/activity\u0026gt; - \u0026lt;/application\u0026gt; - - \u0026lt;/manifest\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android%E7%9A%84activity%E5%88%87%E6%8D%A2%E5%8A%A8%E7%94%BB%E7%89%B9%E6%95%88%E5%BA%93switchlayout%E8%A7%86%E5%9B%BE%E5%88%87%E6%8D%A2%E5%8A%A8%E7%94%BB%E5%BA%93%E5%AA%B2%E7%BE%8Eio/","summary":"\u003cp\u003e由于看了IOS上面很多开发者开发的APP的视图界面切换动画体验非常好，这些都是IOS自带的，但是Android的Activity等视图切换动画并没有提供原生的，所以特此写了一个可以媲美IOS视图切换动画的Android视图切换动画特效库！SwitchLayout！可以说是目前Android上第一个，也是唯一的一个强大的视图切换动画库引擎！\u003c/p\u003e\n\u003cp\u003e作者：谭东\u003c/p\u003e\n\u003cp\u003eQQ：852041173\u003c/p\u003e\n\u003cp\u003e项目开源！推荐使用jar包形式！\u003c/p\u003e\n\u003cp\u003e没有经过作者允许，不可修改项目库源码自行发布。\u003c/p\u003e\n\u003cp\u003e如果你的项目中使用了SwtichLayout，建议你在您的APP关于页面注明SwitchLayout库提供支持！非常感谢！如果您觉得SwitchLayout强大，欢迎推荐给你们的朋友。\u003c/p\u003e\n\u003cp\u003e如果有什么建议，也可以反馈给我，会及时升级SwitchLayout库。\u003c/p\u003e\n\u003cp\u003eSwitchLayout 的1.0jar包下载地址和Demo下载地址：\u003ca href=\"http://pan.baidu.com/s/1dD6baLV\"\u003ehttp://pan.baidu.com/s/1dD6baLV\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e源码和demo在github地址：\u003ca href=\"https://github.com/jaychou2012/SwitchLayout\"\u003ehttps://github.com/jaychou2012/SwitchLayout\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e好了，先看下主要的界面支持的视图切换特效吧！（此为Demo截图）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20141229010619196?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamF5MTAwNTAw/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e 、\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20141229010634515?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamF5MTAwNTAw/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e效果引擎足够媲美IOS了。\u003c/p\u003e\n\u003cp\u003e里面的列表中，每个特效暴露的自定义扩展特效引擎接口大概可以扩充8个特效。所以一共大概可以扩充105种特效！足够强大！\u003c/p\u003e\n\u003cp\u003e好了，下面说下大致的用法：\u003c/p\u003e\n\u003cp\u003e1.导入SwitchLayout1.0.jar或者下载开源库。\u003c/p\u003e\n\u003cp\u003e2.每个Activity实现接口implements SwichLayoutInterFace。推荐这种用法；接口里分别实现2个方法：setEnterSwichLayout();和setExitSwichLayout();这两个方法分别是设置进入Activity动画和离开Activity的动画的。\u003c/p\u003e\n\u003cp\u003e在onCreate()里调用setEnterSwichLayout();  在关闭Activity操作里调用setExitSwichLayout(); 如果需要的话在onKeyDown里拦截返回按键，调用setExitSwichLayout();\u003c/p\u003e\n\u003cp\u003e3.具体特效调用（举一个例子）： SwitchLayout.getSlideFromBottom(this, false,BaseEffects.getMoreSlowEffect());\u003c/p\u003e\n\u003cp\u003e// 三个参数分别为（Activity/View，是否关闭Activity，特效（可为空））；每个特效支持8种扩种，也可以不填特效。\u003c/p\u003e\n\u003cp\u003e4.注意，在项目注册清单里，每个Activity要设置主题为透明主题。 android:theme=”@android:style/Theme.Translucent”，API在11以上即可。\u003c/p\u003e\n\u003cp\u003e下面贴下SwitchLayoutDemo里的代码：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/jay100500/article/details/42227365#)[copy](http://blog.csdn.net/jay100500/article/details/42227365#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/565636)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/565636/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.tandong.swichlayoutdemo;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Button;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.tandong.swichlayout.BaseEffects;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.tandong.swichlayout.SwitchLayout;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * SwitchLayout\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * QQ 852041173\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 为Android提供IOS平台自有的界面视图切换动画而开发此库，工作量也不小，感谢支持SwitchLayout\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 如果想自定义特效动画时长的话，请在此四个变量对应设置 SwitchLayout.animDuration = 1000;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * SwitchLayout.longAnimDuration = 2000; BaseAnimViewS.animDuration = 1000;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * BaseAnimViewS.longAnimDuration = 2000;即可。单位毫秒。\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 以后SwitchLayout将会划分入我的SmartUI库下面\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author Tan Dong（谭东） 2014.12.28\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Button btn_ok, btn_1, btn_2, btn_3, btn_4, btn_5, btn_6, btn_7,\n\n- btn_8, btn_9, btn_10, btn_11, btn_12, btn_13, btn_14;\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) {\n\n- requestWindowFeature(Window.FEATURE_NO_TITLE);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);\n\n- setContentView(R.layout.activity_main);\n\n- initView();\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置进入Activity的Activity特效动画，同理可拓展为布局动画\u0026lt;/span\u0026gt;\n\n- SwitchLayout.getSlideFromBottom(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;,\n\n- BaseEffects.getQuickToSlowEffect());\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 三个参数分别为（Activity/View，是否关闭Activity，特效（可为空））\u0026lt;/span\u0026gt;\n\n- initListener();\n\n- \n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initListener() {\n\n- btn_ok.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- \n- btn_1.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- btn_2.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- btn_3.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- btn_4.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- btn_5.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- btn_6.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;6\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- \n- btn_7.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;7\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- btn_8.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- btn_9.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;9\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- btn_10.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- btn_11.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;11\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- btn_12.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;12\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- btn_13.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;13\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- btn_14.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Intent in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SecondActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- in.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;key\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;);\n\n- MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.startActivity(in);\n\n- }\n\n- });\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() {\n\n- btn_ok = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_ok);\n\n- btn_1 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_1);\n\n- btn_2 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_2);\n\n- btn_3 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_3);\n\n- btn_4 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_4);\n\n- btn_5 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_5);\n\n- btn_6 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_6);\n\n- btn_7 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_7);\n\n- btn_8 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_8);\n\n- btn_9 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_9);\n\n- btn_10 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_10);\n\n- btn_11 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_11);\n\n- btn_12 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_12);\n\n- btn_13 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_13);\n\n- btn_14 = (Button) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.findViewById(R.id.btn_14);\n\n- \n- }\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android的Activity切换动画特效库SwitchLayout，视图切换动画库，媲美IOS"},{"content":"1 背景 不能只分析源码呀，分析的同时也要整理归纳基础知识，刚好有人微博私信让全面说说Android的动画，所以今天来一发Android应用的各种Animation大集合。英文厉害的请直接移步参考Android Developer。\nAndroid系统提供了很多丰富的API去实现UI的2D与3D动画，最主要的划分可以分为如下几类：\nView Animation： 视图动画在古老的Android版本系统中就已经提供了，只能被用来设置View的动画。 Drawable Animation： 这种动画（也叫Frame动画、帧动画）其实可以划分到视图动画的类别，专门用来一个一个的显示Drawable的resources，就像放幻灯片一样。 Property Animation： 属性动画只对Android 3.0（API 11）以上版本的Android系统才有效，这种动画可以设置给任何Object，包括那些还没有渲染到屏幕上的对象。这种动画是可扩展的，可以让你自定义任何类型和属性的动画。 可以看见，当前应用程序开发涉及的主要动画也就这三大类，我们接下来以类别为基础来慢慢展开说明。\n【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流】\n2 View Animation（视图动画）使用详解 2-1 视图动画概述 视图动画，也叫Tween（补间）动画可以在一个视图容器内执行一系列简单变换（位置、大小、旋转、透明度）。譬如，如果你有一个TextView对象，您可以移动、旋转、缩放、透明度设置其文本，当然，如果它有一个背景图像，背景图像会随着文本变化。\n补间动画通过XML或Android代码定义，建议使用XML文件定义，因为它更具可读性、可重用性。\n如下是视图动画相关的类继承关系：\njava类名 xml关键字 描述信息 AlphaAnimation \u0026lt;alpha\u0026gt; 放置在res/anim/目录下 渐变透明度动画效果 RotateAnimation \u0026lt;rotate\u0026gt; 放置在res/anim/目录下 画面转移旋转动画效果 ScaleAnimation \u0026lt;scale\u0026gt; 放置在res/anim/目录下 渐变尺寸伸缩动画效果 TranslateAnimation \u0026lt;translate\u0026gt; 放置在res/anim/目录下 画面转换位置移动动画效果 AnimationSet \u0026lt;set\u0026gt; 放置在res/anim/目录下 一个持有其它动画元素alpha、scale、translate、rotate或者其它set元素的容器 通过上图和上表可以直观的看出来补间动画的关系及种类了吧，接下来我们就详细一个一个的介绍一下各种补间动画。\n2-2 视图动画详细说明 可以看出来Animation抽象类是所有补间动画类的基类，所以基类会提供一些通用的动画属性方法，如下我们就来详细看看这些属性，关于这些属性详细官方解释翻墙点击我或者翻墙点击我。\n2-2-1 Animation属性详解 xml属性 java方法 解释 android:detachWallpaper setDetachWallpaper(boolean) 是否在壁纸上运行 android:duration setDuration(long) 动画持续时间，毫秒为单位 android:fillAfter setFillAfter(boolean) 控件动画结束时是否保持动画最后的状态 android:fillBefore setFillBefore(boolean) 控件动画结束时是否还原到开始动画前的状态 android:fillEnabled setFillEnabled(boolean) 与android:fillBefore效果相同 android:interpolator setInterpolator(Interpolator) 设定插值器（指定的动画效果，譬如回弹等） android:repeatCount setRepeatCount(int) 重复次数 android:repeatMode setRepeatMode(int) 重复类型有两个值，reverse表示倒序回放，restart表示从头播放 android:startOffset setStartOffset(long) 调用start函数之后等待开始运行的时间，单位为毫秒 android:zAdjustment setZAdjustment(int) 表示被设置动画的内容运行时在Z轴上的位置（top/bottom/normal），默认为normal 也就是说，无论我们补间动画的哪一种都已经具备了这种属性，也都可以设置使用这些属性中的一个或多个。\n那接下来我们就看看每种补间动画特有的一些属性说明吧。\n2-2-2 Alpha属性详解 xml属性 java方法 解释 android:fromAlpha AlphaAnimation(float fromAlpha, …) 动画开始的透明度（0.0到1.0，0.0是全透明，1.0是不透明） android:toAlpha AlphaAnimation(…, float toAlpha) 动画结束的透明度，同上 2-2-3 Rotate属性详解 xml属性 java方法 解释 android:fromDegrees RotateAnimation(float fromDegrees, …) 旋转开始角度，正代表顺时针度数，负代表逆时针度数 android:toDegrees RotateAnimation(…, float toDegrees, …) 旋转结束角度，正代表顺时针度数，负代表逆时针度数 android:pivotX RotateAnimation(…, float pivotX, …) 缩放起点X坐标（数值、百分数、百分数p，譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点） android:pivotY RotateAnimation(…, float pivotY) 缩放起点Y坐标，同上规律 2-2-4 Scale属性详解 xml属性 java方法 解释 android:fromXScale ScaleAnimation(float fromX, …) 初始X轴缩放比例，1.0表示无变化 android:toXScale ScaleAnimation(…, float toX, …) 结束X轴缩放比例 android:fromYScale ScaleAnimation(…, float fromY, …) 初始Y轴缩放比例 android:toYScale ScaleAnimation(…, float toY, …) 结束Y轴缩放比例 android:pivotX ScaleAnimation(…, float pivotX, …) 缩放起点X轴坐标（数值、百分数、百分数p，譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点） android:pivotY ScaleAnimation(…, float pivotY) 缩放起点Y轴坐标，同上规律 2-2-5 Translate属性详解 xml属性 java方法 解释 android:fromXDelta TranslateAnimation(float fromXDelta, …) 起始点X轴坐标（数值、百分数、百分数p，譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点） android:fromYDelta TranslateAnimation(…, float fromYDelta, …) 起始点Y轴从标，同上规律 android:toXDelta TranslateAnimation(…, float toXDelta, …) 结束点X轴坐标，同上规律 android:toYDelta TranslateAnimation(…, float toYDelta) 结束点Y轴坐标，同上规律 2-2-6 AnimationSet详解 AnimationSet继承自Animation，是上面四种的组合容器管理类，没有自己特有的属性，他的属性继承自Animation，所以特别注意，当我们对set标签使用Animation的属性时会对该标签下的所有子控件都产生影响。\n2-3 视图动画使用方法 通过上面对于动画的属性介绍之后我们来看看在Android中这些动画如何使用（PS：这里直接演示xml方式，至于java方式太简单了就不说了），如下：\n`\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:interpolator\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@[package:]anim/interpolator_resource\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:shareInterpolator\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;[\u0026#34;true\u0026#34;\u0026amp;lt;/span\u0026gt; | \u0026#34;\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;\u0026#34;] \u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;alpha \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:fromAlpha\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:toAlpha\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;scale \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:fromXScale\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:toXScale\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:fromYScale\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:toYScale\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:pivotX\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:pivotY\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;translate \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:fromXDelta\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:toXDelta\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:fromYDelta\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:toYDelta\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;rotate \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:fromDegrees\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:toDegrees\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:pivotX\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:pivotY\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; ... \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` `ImageView spaceshipImage = (ImageView) findViewById(R.id.spaceshipImage); Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, R.anim.hyperspace_jump); spaceshipImage.startAnimation(hyperspaceJumpAnimation);` 上面就是一个标准的使用我们定义的补间动画的模板。至于补间动画的使用，Animation还有如下一些比较实用的方法介绍：\nAnimation类的方法 解释 reset() 重置Animation的初始化 cancel() 取消Animation动画 start() 开始Animation动画 setAnimationListener(AnimationListener listener) 给当前Animation设置动画监听 hasStarted() 判断当前Animation是否开始 hasEnded() 判断当前Animation是否结束 既然补间动画只能给View使用，那就来看看View中和动画相关的几个常用方法吧，如下：\nView类的常用动画操作方法 解释 startAnimation(Animation animation) 对当前View开始设置的Animation动画 clearAnimation() 取消当View在执行的Animation动画 到此整个Android的补间动画常用详细属性及方法全部介绍完毕，如有特殊的属性需求可以访问Android Developer查阅即可。如下我们就来个综合大演练。\n2-4 视图动画注意事项 关于视图动画（补间动画）的例子我就不介绍了，网上简直多的都泛滥了。只是强调在使用补间动画时注意如下一点即可：\n特别特别注意：补间动画执行之后并未改变View的真实布局属性值。切记这一点，譬如我们在Activity中有一个Button在屏幕上方，我们设置了平移动画移动到屏幕下方然后保持动画最后执行状态呆在屏幕下方，这时如果点击屏幕下方动画执行之后的Button是没有任何反应的，而点击原来屏幕上方没有Button的地方却响应的是点击Button的事件。\n2-5 视图动画Interpolator插值器详解 2-5-1 插值器简介 介绍补间动画插值器之前我们先来看一幅图，如下：\n可以看见其实各种插值器都是实现了Interpolator接口而已，同时可以看见系统提供了许多已经实现OK的插值器，具体如下：\njava类 xml id值 描述 AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator 动画始末速率较慢，中间加速 AccelerateInterpolator @android:anim/accelerate_interpolator 动画开始速率较慢，之后慢慢加速 AnticipateInterpolator @android:anim/anticipate_interpolator 开始的时候从后向前甩 AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_interpolator 类似上面AnticipateInterpolator BounceInterpolator @android:anim/bounce_interpolator 动画结束时弹起 CycleInterpolator @android:anim/cycle_interpolator 循环播放速率改变为正弦曲线 DecelerateInterpolator @android:anim/decelerate_interpolator 动画开始快然后慢 LinearInterpolator @android:anim/linear_interpolator 动画匀速改变 OvershootInterpolator @android:anim/overshoot_interpolator 向前弹出一定值之后回到原来位置 如上就是系统提供的一些插值器，下面我们来看看怎么使用他们。\n2-5-2 插值器使用方法 插值器的使用比较简答，如下：\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:interpolator\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@android:anim/accelerate_interpolator\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; ... \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 2-5-3 插值器的自定义 有时候你会发现系统提供的插值器不够用，可能就像View一样需要自定义。所以接下来我们来看看插值器的自定义，关于插值器的自定义分为两种实现方式，xml自定义实现（其实就是对现有的插值器的一些属性修改）或者java代码实现方式。如下我们来说说。\n先看看XML自定义插值器的步骤：\n在res/anim/目录下创建filename.xml文件。 修改你准备自定义的插值器如下： `\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;InterpolatorName\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:attribute_name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;value\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 在你的补间动画文件中引用该文件即可。 可以看见上面第二步修改的是现有插值器的一些属性，但是有些插值器却不具备修改属性，具体如下：\n\u0026lt;accelerateDecelerateInterpolator\u0026gt;\n无可自定义的attribute。\n\u0026lt;accelerateInterpolator\u0026gt;\nandroid:factor 浮点值，加速速率（默认值为1）。\n\u0026lt;anticipateInterploator\u0026gt;\nandroid:tension 浮点值，起始点后拉的张力数（默认值为2）。\n\u0026lt;anticipateOvershootInterpolator\u0026gt;\nandroid:tension 浮点值，起始点后拉的张力数（默认值为2）。\nandroid:extraTension 浮点值，拉力的倍数（默认值为1.5）。\n\u0026lt;bounceInterpolator\u0026gt;\n无可自定义的attribute。\n\u0026lt;cycleInterplolator\u0026gt;\nandroid:cycles 整形，循环的个数（默认为1）。\n\u0026lt;decelerateInterpolator\u0026gt;\nandroid:factor 浮点值，减速的速率（默认为1）。\n- 无可自定义的attribute。\n\u0026lt;overshootInterpolator\u0026gt;\nandroid:tension 浮点值，超出终点后的张力（默认为2）。\n再来看看Java自定义插值器的（Java自定义插值器其实是xml自定义的升级，也就是说如果我们修改xml的属性还不能满足需求，那就可以选择通过Java来实现）方式。\n可以看见上面所有的Interpolator都实现了Interpolator接口，而Interpolator接口又继承自TimeInterpolator，TimeInterpolator接口定义了一个float getInterpolation(float input);方法，这个方法是由系统调用的，其中的参数input代表动画的时间，在0和1之间，也就是开始和结束之间。\n如下就是一个动画始末速率较慢、中间加速的AccelerateDecelerateInterpolator插值器：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AccelerateDecelerateInterpolator\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;BaseInterpolator\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;implements\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;NativeInterpolatorFactory\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getInterpolation\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; input) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;)(Math.cos((input + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) * Math.PI) / \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2.0\u0026amp;lt;/span\u0026gt;f) + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0.5\u0026amp;lt;/span\u0026gt;f; } ...... }` 到此整个补间动画与补间动画的插值器都分析完毕了，接下来看下别的动画。\n【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流】\n3 Drawable Animation（Drawable动画）使用详解 3-1 Drawable动画概述 Drawable动画其实就是Frame动画（帧动画），它允许你实现像播放幻灯片一样的效果，这种动画的实质其实是Drawable，所以这种动画的XML定义方式文件一般放在res/drawable/目录下。具体关于帧动画的xml使用方式翻墙点击我查看，java方式翻墙点击我查看。\n如下图就是帧动画的源码文件：\n可以看见实际的真实父类就是Drawable。\n3-2 Drawable动画详细说明 我们依旧可以使用xml或者java方式实现帧动画。但是依旧推荐使用xml，具体如下：\n\u0026lt;animation-list\u0026gt; 必须是根节点，包含一个或者多个\u0026lt;item\u0026gt;元素，属性有：\nandroid:oneshot true代表只执行一次，false循环执行。 \u0026lt;item\u0026gt; 类似一帧的动画资源。 \u0026lt;item\u0026gt; animation-list的子项，包含属性如下：\nandroid:drawable 一个frame的Drawable资源。 android:duration 一个frame显示多长时间。 3-3 Drawable动画实例演示 关于帧动画相对来说比较简单，这里给出一个常规使用框架，如下：\n`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;\u0026amp;lt;!-- 注意：rocket.xml文件位于res/drawable/目录下 --\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;animation-list\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:oneshot\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;[\u0026#34;true\u0026#34;\u0026amp;lt;/span\u0026gt; | \u0026#34;\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;\u0026#34;] \u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:drawable\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@[package:]drawable/drawable_resource_name\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:duration\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;integer\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;animation-list\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` `ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image); rocketImage.setBackgroundResource(R.drawable.rocket_thrust); rocketAnimation = (AnimationDrawable) rocketImage.getBackground(); rocketAnimation.start();` 特别注意，AnimationDrawable的start()方法不能在Activity的onCreate方法中调运，因为AnimationDrawable还未完全附着到window上，所以最好的调运时机是onWindowFocusChanged()方法中。\n至此帧动画也就说明完成了。让我们接下来进入Android更牛叉的动画类型。\n【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流】\n4 Property Animation（属性动画）使用详解 在使用属性动画之前先来看几个常用的View属性成员：\ntranslationX，translationY：控制View的位置，值是相对于View容器左上角坐标的偏移。 rotationX，rotationY：控制相对于轴心旋转。 x，y：控制View在容器中的位置，即左上角坐标加上translationX和translationY的值。 alpha：控制View对象的alpha透明度值。 这几个常用的属性相信大家都很熟悉，接下来的属性动画我们就从这里展开。\n4-1 属性动画概述 Android 3.0以后引入了属性动画，属性动画可以轻而易举的实现许多View动画做不到的事，上面也看见了，View动画无非也就做那几种事情，别的也搞不定，而属性动画就可以的，譬如3D旋转一张图片。其实说白了，你记住一点就行，属性动画实现原理就是修改控件的属性值实现的动画。\n具体先看下类关系：\n`\u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * This is the superclass for classes which provide basic support for animations which can be * started, ended, and have \u0026amp;lt;code\u0026amp;gt;AnimatorListeners\u0026amp;lt;/code\u0026amp;gt; added to them. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;abstract\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Animator\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;implements\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Cloneable\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; ...... }` 所有的属性动画的抽象基类就是他。我们看下他的实现子类：\n其实可以看见，属性动画的实现有7个类（PS，之所以类继承关系列表会出来那么多是因为我下载了所有版本的SDK，你只用关注我红点标注的就行，妹的，ubuntu下图片处理工具怎么都这么难用），进去粗略分析可以发现，好几个是hide的类，而其他可用的类继承关系又如下：\njava类名 xml关键字 描述信息 ValueAnimator \u0026lt;animator\u0026gt; 放置在res/animator/目录下 在一个特定的时间里执行一个动画 TimeAnimator 不支持/点我查看原因 时序监听回调工具 ObjectAnimator \u0026lt;objectAnimator\u0026gt; 放置在res/animator/目录下 一个对象的一个属性动画 AnimatorSet \u0026lt;set\u0026gt; 放置在res/animator/目录下 动画集合 所以可以看见，我们平时使用属性动画的重点就在于AnimatorSet、ObjectAnimator、TimeAnimator、ValueAnimator。所以接下来我们就来依次说说如何使用。\n4-2 属性动画详细说明 4-2-1 属性动画计算原理 参看Android官方文档，英文原版详情点我查看！\nAndroid属性动画（注意最低兼容版本，不过可以使用开源项目来替代低版本问题）提供了以下属性：\nDuration：动画的持续时间； TimeInterpolation：定义动画变化速率的接口，所有插值器都必须实现此接口，如线性、非线性插值器； TypeEvaluator：用于定义属性值计算方式的接口，有int、float、color类型，根据属性的起始、结束值和插值一起计算出当前时间的属性值； Animation sets：动画集合，即可以同时对一个对象应用多个动画，这些动画可以同时播放也可以对不同动画设置不同的延迟； Frame refreash delay：多少时间刷新一次，即每隔多少时间计算一次属性值，默认为10ms，最终刷新时间还受系统进程调度与硬件的影响； Repeat Country and behavoir：重复次数与方式，如播放3次、5次、无限循环，可以让此动画一直重复，或播放完时向反向播放； 接下来先来看官方为了解释原理给出的两幅图（其实就是初中物理题，不解释）：\n上面就是一个线性匀速动画，描述了一个Object的X属性运动动画，该对象的X坐标在40ms内从0移动到40，每10ms刷新一次，移动4次，每次移动为40/4=10pixel。\n上面是一个非匀速动画，描述了一个Object的X属性运动动画，该对象的X坐标在40ms内从0移动到40，每10ms刷新一次，移动4次，但是速率不同，开始和结束的速度要比中间部分慢，即先加速后减速。\n接下来我们来详细的看一下，属性动画系统的重要组成部分是如何计算动画值的，下图描述了如上面所示动画的实现作用过程。\n其中的ValueAnimator是动画的执行类，跟踪了当前动画的执行时间和当前时间下的属性值；ValueAnimator封装了动画的TimeInterpolator时间插值器和一个TypeEvaluator类型估值，用于设置动画属性的值，就像上面图2非线性动画里，TimeInterpolator使用了AccelerateDecelerateInterpolator、TypeEvaluator使用了IntEvaluator。\n为了执行一个动画，你需要创建一个ValueAnimator，并且指定目标对象属性的开始、结束值和持续时间。在调用start后，整个动画过程中， ValueAnimator会根据已经完成的动画时间计算得到一个0到1之间的分数，代表该动画的已完成动画百分比。0表示0%，1表示100%，譬如上面图一线性匀速动画中总时间 t = 40 ms，t = 10 ms的时候是 0.25。\n当ValueAnimator计算完已完成动画分数后，它会调用当前设置的TimeInterpolator，去计算得到一个interpolated（插值）分数，在计算过程中，已完成动画百分比会被加入到新的插值计算中。如上图2非线性动画中，因为动画的运动是缓慢加速的，它的插值分数大约是 0.15，小于t = 10ms时的已完成动画分数0.25。而在上图1中，这个插值分数一直和已完成动画分数是相同的。\n当插值分数计算完成后，ValueAnimator会根据插值分数调用合适的 TypeEvaluator去计算运动中的属性值。\n好了，现在我们来看下代码就明白这段话了，上面图2非线性动画里，TimeInterpolator使用了AccelerateDecelerateInterpolator、TypeEvaluator使用了IntEvaluator。所以这些类都是标准的API，我们来看下标准API就能类比自己写了，如下：\n首先计算已完成动画时间分数（以10ms为例）：t=10ms/40ms=0.25。\n接着看如下源码如何实现计算差值分数的：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AccelerateDecelerateInterpolator\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;BaseInterpolator\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;implements\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;NativeInterpolatorFactory\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AccelerateDecelerateInterpolator\u0026amp;lt;/span\u0026gt;() { } ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//这是我们关注重点，可以发现如下计算公式计算后（input即为时间因子）插值大约为0.15。\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getInterpolation\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; input) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;)(Math.cos((input + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) * Math.PI) / \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2.0\u0026amp;lt;/span\u0026gt;f) + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0.5\u0026amp;lt;/span\u0026gt;f; } ...... }` 其实AccelerateDecelerateInterpolator的基类接口就是TimeInterpolator，如下，他只有getInterpolation方法，也就是上面我们关注的方法。\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;interface\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;TimeInterpolator\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; getInterpolation(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; input); }` 接着ValueAnimator会根据插值分数调用合适的TypeEvaluator（IntEvaluator）去计算运动中的属性值，如下，因为startValue = 0，所以属性值：0+0.15*（40-0）= 6。\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;IntEvaluator\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;implements\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;TypeEvaluator\u0026amp;lt;/span\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Integer\u0026amp;lt;/span\u0026gt;\u0026amp;gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; Integer \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;evaluate\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; fraction, Integer startValue, Integer endValue) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; startInt = startValue; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;)(startInt + fraction * (endValue - startInt)); } }` 这就是官方给的一个关于属性动画实现的过程及基本原理解释，相信你看到这里是会有些迷糊的，没关系，你先有个大致概念就行，接下来我们会慢慢进入实战，因为Android的属性动画相对于其他动画来说涉及的知识点本来就比较复杂，所以我们慢慢来。\n4-2-2 XML方式属性动画 在xml中可直接用的属性动画节点有ValueAnimator、ObjectAnimator、AnimatorSet。如下是官方的一个例子和解释（详情点我）：\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;set \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:ordering\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;[\u0026#34;together\u0026#34;\u0026amp;lt;/span\u0026gt; | \u0026#34;\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;sequentially\u0026amp;lt;/span\u0026gt;\u0026#34;]\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;objectAnimator \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:propertyName\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;string\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:duration\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;int\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:valueFrom\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float | int | color\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:valueTo\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float | int | color\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:startOffset\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;int\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:repeatCount\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;int\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:repeatMode\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;[\u0026#34;repeat\u0026#34;\u0026amp;lt;/span\u0026gt; | \u0026#34;\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;reverse\u0026amp;lt;/span\u0026gt;\u0026#34;] \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:valueType\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;[\u0026#34;intType\u0026#34;\u0026amp;lt;/span\u0026gt; | \u0026#34;\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;floatType\u0026amp;lt;/span\u0026gt;\u0026#34;]/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;animator \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:duration\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;int\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:valueFrom\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float | int | color\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:valueTo\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;float | int | color\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:startOffset\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;int\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:repeatCount\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;int\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:repeatMode\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;[\u0026#34;repeat\u0026#34;\u0026amp;lt;/span\u0026gt; | \u0026#34;\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;reverse\u0026amp;lt;/span\u0026gt;\u0026#34;] \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:valueType\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;[\u0026#34;intType\u0026#34;\u0026amp;lt;/span\u0026gt; | \u0026#34;\u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;floatType\u0026amp;lt;/span\u0026gt;\u0026#34;]/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; ... \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` \u0026lt;set\u0026gt;属性解释：\nxml属性 解释 android:ordering 控制子动画启动方式是先后有序的还是同时进行。sequentially:动画按照先后顺序；together(默认):动画同时启动； \u0026lt;objectAnimator\u0026gt;属性解释：\nxml属性 解释 android:propertyName String类型，必须要设置的节点属性，代表要执行动画的属性（通过名字引用），辟如你可以指定了一个View的”alpha” 或者 “backgroundColor” ，这个objectAnimator元素没有对外说明target属性，所以你不能在XML中设置执行这个动画，必须通过调用loadAnimator()方法加载你的XML动画资源，然后调用setTarget()应用到具备这个属性的目标对象上（譬如TextView）。 android:valueTo float、int或者color类型，必须要设置的节点属性，表明动画结束的点；如果是颜色的话，由6位十六进制的数字表示。 android:valueFrom 相对应valueTo，动画的起始点，如果没有指定，系统会通过属性的get方法获取，颜色也是6位十六进制的数字表示。 android:duration 动画的时长，int类型，以毫秒为单位，默认为300毫秒。 android:startOffset 动画延迟的时间，从调用start方法后开始计算，int型，毫秒为单位。 android:repeatCount 一个动画的重复次数，int型，”-1“表示无限循环，”1“表示动画在第一次执行完成后重复执行一次，也就是两次，默认为0，不重复执行。 android:repeatMode 重复模式：int型，当一个动画执行完的时候应该如何处理。该值必须是正数或者是-1，“reverse”会使得按照动画向相反的方向执行，可实现类似钟摆效果。“repeat”会使得动画每次都从头开始循环。 android:valueType 关键参数，如果该value是一个颜色，那么就不需要指定，因为动画框架会自动的处理颜色值。有intType和floatType（默认）两种：分别说明动画值为int和float型。 \u0026lt;objectAnimator\u0026gt;属性解释：\n同上\u0026lt;objectAnimator\u0026gt;属性，不多介绍。\nXML属性动画使用方法：\n`AnimatorSet \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt; = (AnimatorSet) AnimatorInflater\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.loadAnimator\u0026amp;lt;/span\u0026gt;(myContext, R\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.animtor\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.property\u0026amp;lt;/span\u0026gt;_animator)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.setTarget\u0026amp;lt;/span\u0026gt;(myObject)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;set\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.start\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt;` 4-2-3 Java方式属性动画 1、**ObjectAnimator：**继承自ValueAnimator，允许你指定要进行动画的对象以及该对象的一个属性。该类会根据计算得到的新值自动更新属性。大多数的情况使用ObjectAnimator就足够了，因为它使得目标对象动画值的处理过程变得足够简单，不用像ValueAnimator那样自己写动画更新的逻辑，但是ObjectAnimator有一定的限制，比如它需要目标对象的属性提供指定的处理方法（譬如提供getXXX，setXXX方法），这时候你就需要根据自己的需求在ObjectAnimator和ValueAnimator中看哪种实现更方便了。\nObjectAnimator类提供了ofInt、ofFloat、ofObject这个三个常用的方法，这些方法都是设置动画作用的元素、属性、开始、结束等任意属性值。当属性值（上面方法的参数）只设置一个时就把通过getXXX反射获取的值作为起点，设置的值作为终点；如果设置两个（参数），那么一个是开始、另一个是结束。 特别注意：ObjectAnimator的动画原理是不停的调用setXXX方法更新属性值，所有使用ObjectAnimator更新属性时的前提是Object必须声明有getXXX和setXXX方法。 我们通常使用ObjectAnimator设置View已知的属性来生成动画，而一般View已知属性变化时都会主动触发重绘图操作，所以动画会自动实现；但是也有特殊情况，譬如作用Object不是View，或者作用的属性没有触发重绘，或者我们在重绘时需要做自己的操作，那都可以通过如下方法手动设置：\n`ObjectAnimator mObjectAnimator= ObjectAnimator.ofInt(view, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;customerDefineAnyThingName\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;).setDuration(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2000\u0026amp;lt;/span\u0026gt;); mObjectAnimator.addUpdateListener(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; AnimatorUpdateListener() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onAnimationUpdate\u0026amp;lt;/span\u0026gt;(ValueAnimator animation) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//int value = animation.getAnimatedValue(); 可以获取当前属性值\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//view.postInvalidate(); 可以主动刷新\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//view.setXXX(value);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//view.setXXX(value);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//......可以批量修改属性\u0026amp;lt;/span\u0026gt; } });` 如下是一个我在项目中的Y轴3D旋转动画实现实例：\n`ObjectAnimator.ofFloat(view, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;rotationY\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0.0\u0026amp;lt;/span\u0026gt;f, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;360.0\u0026amp;lt;/span\u0026gt;f).setDuration(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1000\u0026amp;lt;/span\u0026gt;).start();` 2、**PropertyValuesHolder：**多属性动画同时工作管理类。有时候我们需要同时修改多个属性，那就可以用到此类，具体如下：\n`PropertyValuesHolder a1 = PropertyValuesHolder.ofFloat(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;alpha\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;f, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;f); PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;translationY\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, viewWidth); ...... ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1000\u0026amp;lt;/span\u0026gt;).start();` 如上代码就可以实现同时修改多个属性的动画啦。\n3、**ValueAnimator：**属性动画中的时间驱动，管理着动画时间的开始、结束属性值，相应时间属性值计算方法等。包含所有计算动画值的核心函数以及每一个动画时间节点上的信息、一个动画是否重复、是否监听更新事件等，并且还可以设置自定义的计算类型。\n特别注意：ValueAnimator只是动画计算管理驱动，设置了作用目标，但没有设置属性，需要通过updateListener里设置属性才会生效。 `ValueAnimator animator = ValueAnimator.ofFloat(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mContentHeight); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//定义动画\u0026amp;lt;/span\u0026gt; animator.setTarget(view); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置作用目标\u0026amp;lt;/span\u0026gt; animator.setDuration(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5000\u0026amp;lt;/span\u0026gt;).start(); animator.addUpdateListener(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; AnimatorUpdateListener() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onAnimationUpdate\u0026amp;lt;/span\u0026gt;(ValueAnimator animation){ \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; value = (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;) animation.getAnimatedValue(); view.setXXX(value); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//必须通过这里设置属性值才有效\u0026amp;lt;/span\u0026gt; view.mXXX = value; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//不需要setXXX属性方法\u0026amp;lt;/span\u0026gt; } });` 大眼看上去可以发现和ObjectAnimator没啥区别，实际上正是由于ValueAnimator不直接操作属性值，所以要操作对象的属性可以不需要setXXX与getXXX方法，你完全可以通过当前动画的计算去修改任何属性。\n4、**AnimationSet：**动画集合，提供把多个动画组合成一个组合的机制，并可设置动画的时序关系，如同时播放、顺序播放或延迟播放。具体使用方法比较简单，如下：\n`ObjectAnimator a1 = ObjectAnimator.ofFloat(view, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;alpha\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1.0\u0026amp;lt;/span\u0026gt;f, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;f); ObjectAnimator a2 = ObjectAnimator.ofFloat(view, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;translationY\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;f, viewWidth); ...... AnimatorSet animSet = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; AnimatorSet(); animSet.setDuration(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5000\u0026amp;lt;/span\u0026gt;); animSet.setInterpolator(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; LinearInterpolator()); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//animSet.playTogether(a1, a2, ...); //两个动画同时执行 \u0026amp;lt;/span\u0026gt; animSet.play(a1).after(a2); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//先后执行\u0026amp;lt;/span\u0026gt; ......\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//其他组合方式\u0026amp;lt;/span\u0026gt; animSet.start(); ` 5、Evaluators相关类解释： Evaluators就是属性动画系统如何去计算一个属性值。它们通过Animator提供的动画的起始和结束值去计算一个动画的属性值。\n**IntEvaluator：**整数属性值。 **FloatEvaluator：**浮点数属性值。 **ArgbEvaluator：**十六进制color属性值。 **TypeEvaluator：**用户自定义属性值接口，譬如对象属性值类型不是int、float、color类型，你必须实现这个接口去定义自己的数据类型。 既然说到这了，那就来个例子吧，譬如我们需要实现一个自定义属性类型和计算规则的属性动画，如下类型float[]：\n`ValueAnimator valueAnimator = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ValueAnimator(); valueAnimator.setDuration(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5000\u0026amp;lt;/span\u0026gt;); valueAnimator.setObjectValues(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;]); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置属性值类型\u0026amp;lt;/span\u0026gt; valueAnimator.setInterpolator(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; LinearInterpolator()); valueAnimator.setEvaluator(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; TypeEvaluator\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;[]\u0026amp;gt;() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;[] \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;evaluate\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; fraction, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;[] startValue, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;[] endValue) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//实现自定义规则计算的float[]类型的属性值\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;[] temp = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;]; temp[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] = fraction * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;; temp[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] = (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;)Math.random() * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;10\u0026amp;lt;/span\u0026gt; * fraction; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; temp; } }); valueAnimator.start(); valueAnimator.addUpdateListener(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ValueAnimator.AnimatorUpdateListener() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onAnimationUpdate\u0026amp;lt;/span\u0026gt;(ValueAnimator animation) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;[] xyPos = (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;[]) animation.getAnimatedValue(); view.setHeight(xyPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;]); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//通过属性值设置View属性动画\u0026amp;lt;/span\u0026gt; view.setWidth(xyPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;]); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//通过属性值设置View属性动画\u0026amp;lt;/span\u0026gt; } });` 6、Interpolators相关类解释：\n**AccelerateDecelerateInterolator：**先加速后减速。 **AccelerateInterpolator：**加速。 **DecelerateInterpolator：**减速。 **AnticipateInterpolator：**先向相反方向改变一段再加速播放。 **AnticipateOvershootInterpolator：**先向相反方向改变，再加速播放，会超出目标值然后缓慢移动至目标值，类似于弹簧回弹。 **BounceInterpolator：**快到目标值时值会跳跃。 **CycleIinterpolator：**动画循环一定次数，值的改变为一正弦函数：Math.sin(2 * mCycles * Math.PI * input)。 **LinearInterpolator：**线性均匀改变。 **OvershottInterpolator：**最后超出目标值然后缓慢改变到目标值。 **TimeInterpolator：**一个允许自定义Interpolator的接口，以上都实现了该接口。 举个例子，就像系统提供的标准API一样，如下就是加速插值器的实现代码，我们自定义时也可以类似实现：\n`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//开始很慢然后不断加速的插值器。\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AccelerateInterpolator\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;implements\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Interpolator\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; mFactor; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;double\u0026amp;lt;/span\u0026gt; mDoubleFactor; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AccelerateInterpolator\u0026amp;lt;/span\u0026gt;() { mFactor = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1.0\u0026amp;lt;/span\u0026gt;f; mDoubleFactor = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2.0\u0026amp;lt;/span\u0026gt;; } ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//input 0到1.0。表示动画当前点的值，0表示开头，1表示结尾。\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//return 插值。值可以大于1超出目标值，也可以小于0突破低值。\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getInterpolation\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; input) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//实现核心代码块\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mFactor == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1.0\u0026amp;lt;/span\u0026gt;f) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; input * input; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt;)Math.pow(input, mDoubleFactor); } } }` 综上可以发现，我们可以使用现有系统提供标准的东东实现属性动画，也可以通过自定义继承相关接口实现自己的动画，只要实现上面提到的那些主要方法即可。\n4-2-4 Java属性动画拓展之ViewPropertyAnimator动画 在Android API 12时，View中添加了animate方法，具体如下：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;View\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;implements\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Drawable\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Callback\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;KeyEvent\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Callback\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AccessibilityEventSource\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; ...... \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * This method returns a ViewPropertyAnimator object, which can be used to animate * specific properties on this View. * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; ViewPropertyAnimator The ViewPropertyAnimator associated with this View. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ViewPropertyAnimator \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;animate\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mAnimator == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { mAnimator = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ViewPropertyAnimator(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mAnimator; } ...... }` 可以看见通过View的animate()方法可以得到一个ViewPropertyAnimator的属性动画（有人说他没有继承Animator类，是的，他是成员关系，不是之前那种继承关系）。\nViewPropertyAnimator提供了一种非常方便的方法为View的部分属性设置动画（切记，是部分属性），它可以直接使用一个Animator对象设置多个属性的动画；在多属性设置动画时，它比 上面的ObjectAnimator更加牛逼、高效，因为他会管理多个属性的invalidate方法统一调运触发，而不像上面分别调用，所以还会有一些性能优化。如下就是一个例子：\n`myView.animate().x(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;f).y(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;100\u0026amp;lt;/span\u0026gt;f).start(); ` 1 4-2-5 Java属性动画拓展之LayoutAnimator容器布局动画 Property动画系统还提供了对ViewGroup中View添加时的动画功能，我们可以用LayoutTransition对ViewGroup中的View进行动画设置显示。LayoutTransition的动画效果都是设置给ViewGroup，然后当被设置动画的ViewGroup中添加删除View时体现出来。该类用于当前布局容器中有View添加、删除、隐藏、显示等时候定义布局容器自身的动画和View的动画，也就是说当在一个LinerLayout中隐藏一个View的时候，我们可以自定义 整个由于LinerLayout隐藏View而改变的动画，同时还可以自定义被隐藏的View自己消失时候的动画等。\n我们可以发现LayoutTransition类中主要有五种容器转换动画类型，具体如下：\nLayoutTransition.APPEARING：当View出现或者添加的时候View出现的动画。 LayoutTransition.CHANGE_APPEARING：当添加View导致布局容器改变的时候整个布局容器的动画。 LayoutTransition.DISAPPEARING：当View消失或者隐藏的时候View消失的动画。 LayoutTransition.CHANGE_DISAPPEARING：当删除或者隐藏View导致布局容器改变的时候整个布局容器的动画。 LayoutTransition.CHANGE：当不是由于View出现或消失造成对其他View位置造成改变的时候整个布局容器的动画。 XML方式使用系统提供的默认LayoutTransition动画：\n我们可以通过如下方式使用系统提供的默认ViewGroup的LayoutTransition动画：\n`android:animateLayoutChanges=”true”` 1 在ViewGroup添加如上xml属性默认是没有任何动画效果的，因为前面说了，该动画针对于ViewGroup内部东东发生改变时才有效，所以当我们设置如上属性然后调运ViewGroup的addView、removeView方法时就能看见系统默认的动画效果了。\n还有一种就是通过如下方式设置：\n`android:layoutAnimation=”@anim/customer_anim”` 1 通过这种方式就能实现很多吊炸天的动画。\nJava方式使用系统提供的默认LayoutTransition动画：\n在使用LayoutTransition时，你可以自定义这几种事件类型的动画，也可以使用默认的动画，总之最终都是通过setLayoutTransition(LayoutTransition lt)方法把这些动画以一个LayoutTransition对象设置给一个ViewGroup。\n譬如实现如上Xml方式的默认系统LayoutTransition动画如下：\n`mTransitioner = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; LayoutTransition(); mViewGroup.setLayoutTransition(mTransitioner);` 1\n2\n稍微再高端一点吧，我们来自定义这几类事件的动画，分别实现他们，那么你可以像下面这么处理：\n`mTransitioner = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; LayoutTransition(); ...... ObjectAnimator anim = ObjectAnimator.ofFloat(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;scaleX\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;); ......\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置更多动画\u0026amp;lt;/span\u0026gt; mTransition.setAnimator(LayoutTransition.APPEARING, anim); ......\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置更多类型的动画 mViewGroup.setLayoutTransition(mTransitioner);\u0026amp;lt;/span\u0026gt;` 到此通过LayoutTransition你就能实现类似小米手机计算器切换普通型和科学型的炫酷动画了。\n【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流】\n5 Android动画总结 到此Android动画基本已经描述OK了，也就这么三大类，尤其是属性动画更加一筹。但是特别说一句，上面基本都没有提及到各种动画的Listener接口，原因是这个玩意太简单，所以不提了，相信你会监听View的onClickListener就一定会触类旁通动画的Listener方法的。有了这些基础相信无论是自定义控件时还是自定义动画时都会起到直接的指导参考作用。其实对于Android的动画实现远远不止现在提到的这些，但是这些又是基础，所以后面还会写文章说说Android提供的其他动画参考工具类的。\n现在我们继续沿用官方的对比，翻译一下这些动画的区别，具体如下（点我参看原文How Property Animation Differs from View Animation）：\nView动画：\nView动画只能够为View添加动画，如果想为非View对象添加动画须自己实现；且View动画支持的种类很少；尤其是他改变的是View的绘制效果，View的属性没有改变，其位置与大小都不变； View动画代码量少，使用简单方便。\nProperty动画：\n弥补了View动画的缺陷，你可以为一个对象的任意属性添加动画，对象自己的属性会被真的改变；当对象的属性变化的时候，属性动画会自动刷新屏幕；属性动画改变的是对象的真实属性，而且属性动画不止用于View，还可以用于任何对象。\n好了，太不容易了！这一篇文章差点难产了，断断续续各种事，终于追求完美OK了，接下来博客恢复正常更新。\n** 转自：http://blog.csdn.net/yanbober **\n","permalink":"https://blog.zdltech.com/posts/android%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E4%B9%8B%E6%89%80%E6%9C%89%E5%8A%A8%E7%94%BB%E4%BD%BF%E7%94%A8%E8%AF%A6%E8%A7%A3/","summary":"\u003ch2 id=\"1-背景\"\u003e\u003cstrong\u003e1 背景\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e不能只分析源码呀，分析的同时也要整理归纳基础知识，刚好有人微博私信让全面说说Android的动画，所以今天来一发Android应用的各种Animation大集合。英文厉害的请直接移步参考\u003ca href=\"http://developer.android.com/guide/topics/graphics/overview.html\"\u003eAndroid Developer\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003eAndroid系统提供了很多丰富的API去实现UI的2D与3D动画，最主要的划分可以分为如下几类：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eView Animation：\u003c/strong\u003e 视图动画在古老的Android版本系统中就已经提供了，只能被用来设置View的动画。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDrawable Animation：\u003c/strong\u003e 这种动画（也叫Frame动画、帧动画）其实可以划分到视图动画的类别，专门用来一个一个的显示Drawable的resources，就像放幻灯片一样。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eProperty Animation：\u003c/strong\u003e 属性动画只对Android 3.0（API 11）以上版本的Android系统才有效，这种动画可以设置给任何Object，包括那些还没有渲染到屏幕上的对象。这种动画是可扩展的，可以让你自定义任何类型和属性的动画。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e可以看见，当前应用程序开发涉及的主要动画也就这三大类，我们接下来以类别为基础来慢慢展开说明。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e【工匠若水 \u003ca href=\"http://blog.csdn.net/yanbober\"\u003ehttp://blog.csdn.net/yanbober\u003c/a\u003e 转载请注明出处。\u003ca href=\"https://github.com/yanbober/AndroidCommunication\"\u003e点我开始Android技术交流\u003c/a\u003e】\u003c/strong\u003e\u003c/p\u003e\n\u003ch2 id=\"2-view-animation视图动画使用详解\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e\u003cstrong\u003e2 View Animation（视图动画）使用详解\u003c/strong\u003e\u003c/h2\u003e\n\u003ch3 id=\"2-1-视图动画概述\"\u003e\u003ca name=\"t2\"\u003e\u003c/a\u003e\u003cstrong\u003e2-1 视图动画概述\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e视图动画，也叫Tween（补间）动画可以在一个视图容器内执行一系列简单变换（位置、大小、旋转、透明度）。譬如，如果你有一个TextView对象，您可以移动、旋转、缩放、透明度设置其文本，当然，如果它有一个背景图像，背景图像会随着文本变化。\u003c/p\u003e\n\u003cp\u003e补间动画通过XML或Android代码定义，建议使用XML文件定义，因为它更具可读性、可重用性。\u003c/p\u003e\n\u003cp\u003e如下是视图动画相关的类继承关系：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20150613182703583\"\u003e\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003ejava类名\u003c/th\u003e\n          \u003cth\u003exml关键字\u003c/th\u003e\n          \u003cth\u003e描述信息\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eAlphaAnimation\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e\u0026lt;alpha\u0026gt;\u003c/code\u003e 放置在res/anim/目录下\u003c/td\u003e\n          \u003ctd\u003e渐变透明度动画效果\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eRotateAnimation\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e\u0026lt;rotate\u0026gt;\u003c/code\u003e 放置在res/anim/目录下\u003c/td\u003e\n          \u003ctd\u003e画面转移旋转动画效果\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eScaleAnimation\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e\u0026lt;scale\u0026gt;\u003c/code\u003e 放置在res/anim/目录下\u003c/td\u003e\n          \u003ctd\u003e渐变尺寸伸缩动画效果\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTranslateAnimation\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e\u0026lt;translate\u0026gt;\u003c/code\u003e 放置在res/anim/目录下\u003c/td\u003e\n          \u003ctd\u003e画面转换位置移动动画效果\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eAnimationSet\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e\u0026lt;set\u0026gt;\u003c/code\u003e 放置在res/anim/目录下\u003c/td\u003e\n          \u003ctd\u003e一个持有其它动画元素alpha、scale、translate、rotate或者其它set元素的容器\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e通过上图和上表可以直观的看出来补间动画的关系及种类了吧，接下来我们就详细一个一个的介绍一下各种补间动画。\u003c/p\u003e\n\u003ch3 id=\"2-2-视图动画详细说明\"\u003e\u003ca name=\"t3\"\u003e\u003c/a\u003e\u003cstrong\u003e2-2 视图动画详细说明\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e可以看出来Animation抽象类是所有补间动画类的基类，所以基类会提供一些通用的动画属性方法，如下我们就来详细看看这些属性，关于这些属性详细官方解释\u003ca href=\"http://www.androidcommunitydocs.com/reference/android/view/animation/package-summary.html\"\u003e翻墙点击我\u003c/a\u003e或者\u003ca href=\"http://www.androidcommunitydocs.com/guide/topics/resources/animation-resource.html\"\u003e翻墙点击我\u003c/a\u003e。\u003c/p\u003e\n\u003ch4 id=\"2-2-1-animation属性详解\"\u003e\u003ca name=\"t4\"\u003e\u003c/a\u003e\u003cstrong\u003e2-2-1 Animation属性详解\u003c/strong\u003e\u003c/h4\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003exml属性\u003c/th\u003e\n          \u003cth\u003ejava方法\u003c/th\u003e\n          \u003cth\u003e解释\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eandroid:detachWallpaper\u003c/td\u003e\n          \u003ctd\u003esetDetachWallpaper(boolean)\u003c/td\u003e\n          \u003ctd\u003e是否在壁纸上运行\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eandroid:duration\u003c/td\u003e\n          \u003ctd\u003esetDuration(long)\u003c/td\u003e\n          \u003ctd\u003e动画持续时间，毫秒为单位\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eandroid:fillAfter\u003c/td\u003e\n          \u003ctd\u003esetFillAfter(boolean)\u003c/td\u003e\n          \u003ctd\u003e控件动画结束时是否保持动画最后的状态\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eandroid:fillBefore\u003c/td\u003e\n          \u003ctd\u003esetFillBefore(boolean)\u003c/td\u003e\n          \u003ctd\u003e控件动画结束时是否还原到开始动画前的状态\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eandroid:fillEnabled\u003c/td\u003e\n          \u003ctd\u003esetFillEnabled(boolean)\u003c/td\u003e\n          \u003ctd\u003e与android:fillBefore效果相同\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eandroid:interpolator\u003c/td\u003e\n          \u003ctd\u003esetInterpolator(Interpolator)\u003c/td\u003e\n          \u003ctd\u003e设定插值器（指定的动画效果，譬如回弹等）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eandroid:repeatCount\u003c/td\u003e\n          \u003ctd\u003esetRepeatCount(int)\u003c/td\u003e\n          \u003ctd\u003e重复次数\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eandroid:repeatMode\u003c/td\u003e\n          \u003ctd\u003esetRepeatMode(int)\u003c/td\u003e\n          \u003ctd\u003e重复类型有两个值，reverse表示倒序回放，restart表示从头播放\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eandroid:startOffset\u003c/td\u003e\n          \u003ctd\u003esetStartOffset(long)\u003c/td\u003e\n          \u003ctd\u003e调用start函数之后等待开始运行的时间，单位为毫秒\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eandroid:zAdjustment\u003c/td\u003e\n          \u003ctd\u003esetZAdjustment(int)\u003c/td\u003e\n          \u003ctd\u003e表示被设置动画的内容运行时在Z轴上的位置（top/bottom/normal），默认为normal\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e也就是说，无论我们补间动画的哪一种都已经具备了这种属性，也都可以设置使用这些属性中的一个或多个。\u003c/p\u003e","title":"Android应用开发之所有动画使用详解"},{"content":"Ctrl+G / Ctrl+Alt+Shift+G：查询变量或者函数或者类在哪里被使用或被调用，后者是前者的复杂表现，可以选择查询范围等。\nAlt+H：查找功能，全局查找\nF4：查看类继承关系\nF2：查看文档说明（函数使用说明）\nCtrl+E：查看最近打开过的文件\nCtrl+Shift+E：查看最近编辑过的文件\ndouble Shift：全局查找，这个查看和Alt+H稍稍有些不同，这个是全局文件查找，到文件名称层面。\nCtrl+Shift+R：快速定位到你所想打开的文件。\nAlt+↑：光标所在位置那行代码往上移动\nAlt+↓：光标所在位置那行代码往下移动\nCtrl+D：删除光标所在位置那行代码\nCtrl+X：剪切光标所在位置那行代码\nAlt+Shift+↓/Ctrl+C：复制光标所在行代码到下一行\nCtrl+O:快捷查找当前类中的函数，变量\nCtrl+Shift+R：修改名称\nAlt+Enter：导入包\nAlt+←：后退，定位到上个查看或者编辑的地方\nAlt+→：往前定位，比如你定位到上个点后，想回去，就可以用这个快捷键\nCtrl+/：当行注释，反注释再按一次即可\nCtrl+Shift+/：模块注释，反注释再按一次即可,注意这边的”/“不能用小键盘的\nCtrl+Shift+小键盘/：折叠代码（Ctrl+Shift+小键盘*这个不灵了，今天没空了，后面会针对这个问题做解决，并更新上来），当然笔记本没小键盘，你可以自己改快捷键\nCtrl+Alt+S：打开settings界面\nCtrl+Alt+Shift+S：打开Project Structure界面\nAlt+Shift+X：运行（Run）\nAlt+Shift+D：调试运行（Debug）\nCtrl+F9：编译工程\nCtrl+Shift+K：push文件到Server（git）\nDebug类快捷键\nF5：但不调试进入函数内部。\nF6：但不调试不进入函数内部。\nF7：由函数内部返回调用处。\nF8：执行到下一个断点，没断点则执行完成。\nAction Mac OSX Win/Linux 注释代码(//) Cmd + / Ctrl + / 注释代码(/**/) Cmd + Option + / Ctrl + Shift + / 格式化代码 Cmd + Option + L Ctrl + Alt + L 清除无效包引用 Option + Control + O Alt + Ctrl + O 查找 Cmd + F Ctrl + F 查找+替换 Cmd + R Ctrl + R 上下移动代码 Option + Shift + Up/Down Alt + Shift + Up/Down 删除行 Cmd + Delete Ctrl + Y 扩大缩小选中范围 Option + Up/Down Ctrl + W/Ctrl + Shift + W 快捷生成结构体 Cmd + Option + T Ctrl + Alt + T 快捷覆写方法 Ctrl + O Ctrl + O 快捷定位到行首/尾 Cmd + Left/Right Ctrl + Left/Right 折叠展开代码块 Cmd + Plus,Minus Ctrl + Plus/Minus 折叠展开全部代码块 Cmd + Shift + Plus,Minus Ctrl + Shift + Plus,Minus 文件方法结构 Cmd + F12 Ctrl + F12 查找调用的位置 Ctrl + Option + H Ctrl + Alt + H 大小写转换 Cmd + Shift + U Ctrl + Shift + U Mac下快捷键的符号所对应的按键\n⌥—\u0026gt; option|alt\n⇧—\u0026gt;shift\n⌃—\u0026gt;control\n⌘—\u0026gt;command\n⎋—\u0026gt;esc\n注: 与F6/F7/F12等F功能键开头的组合的快捷键需要按住fn开启功能键 如：快捷键⌘F12的按键组合为：fn + command + F12\nAndroid Studio 常用快捷键 for mac\n查找／查看相关\n⌘O: 全局查找class类名\u0026laquo;/span\u0026gt;使用率非常高\u0026gt;\n⌘F: 在当前编辑文件中查找\u0026laquo;/span\u0026gt;使用率非常高\u0026gt; ｜ 对应window中的Ctrl + F\n⌘F12：当前编辑的文件中结构快速导航 | 对应window中的 Ctrl + F12\n⌘E: 打开最近访问的文件列表 | 对应window中的Ctrl + E\n⌥⌘O: 输入类名／方法名／字段名来查找任何匹配的类／方法／字段\u0026laquo;/span\u0026gt;使用率非常高\u0026gt;\n⇧⌘O: 全局项目查找文件（类／资源文件／布局文件都通过该快捷键查找）\u0026laquo;/span\u0026gt;使用率非常高\u0026gt;\n⌃H: 查看当前编辑class类的hierarchy结构 | 对应window中的Ctrl + H\n⌥F7: 列出全局项目中该类／方法 被引用／调用的情况\u0026laquo;/span\u0026gt;使用率非常高\u0026gt;[比⌥⌘F7显示效果好] | 对应window中的Alt + F7\n⌥⌘F7: 列出全局项目中该类／方法 被引用／调用的情况 | 对应window中的Ctrl + Alt + F7\n⌃⌥H: 方法被调用结构［method’s Call Hierarchy］| 对应window中的ctrl + alt + h\n⌘P: 列出函数方法一系列的有效参数，如果光标是一个方法调用的括号之间 | 对应window中的Ctrl + P\n⇧⌘F7: 快速，高亮显示变量在当前文件中的引用情况,使用⌘G和⇧⌘G快捷键 可以前往跳到下一个/上一个高亮的变量，按⎋移除高亮显示 | 对应window中的Ctrl + Shift + F7\nF1: 查看类／方法的注释文档\n控制操作相关\n⌘/: 注释与取消注释，注释效果 //… | 对应window中的Ctrl + /\n⌥⌘/: 注释与取消注释，注释效果 /…/ | 对应window中的Ctrl+Shift+/\n⇧⌥up/down: 移动行上下移动 | 对应window中的alt + shift + up/down\n⌘delete: 删除行 ｜ 对应window中的ctrl + y\n⌘d: 复制行 ｜ 对应window中的 ctrl + d\n⌘J: 快速生成模版代码块，如if,while,return等\u0026laquo;/span\u0026gt;使用频率非常高，高效率编写代码\u0026gt; | 对应window中的Ctrl + J\n⌘N: 快速生成getter／setter方法，构造方法，toString()方法等 \u0026laquo;/span\u0026gt;使用率非常高\u0026gt; | 对应window中的Alt + Insert\n⌥⌘T: Surround with快速调出if,for,try…catch,while等环绕代码 ｜ 对应window中的ctrl + alt + t\n⌃O: 引入重写父类的方法［Override Methods］\u0026laquo;/span\u0026gt;使用率非常高\u0026gt;\n⌃I: 引入实现接口或抽象类方法［Implement Methods］\u0026laquo;/span\u0026gt;使用率非常高\u0026gt;\n⌃Space: 当申明一个变量时，根据变量类型提示给出建议的变量名称，等还有其他很多智能提示作用\u0026laquo;/span\u0026gt;使用率非常高\u0026gt;\n⌥⌘L: 代码格式化 \u0026laquo;/span\u0026gt;使用率非常高\u0026gt; | 对应window中的Ctrl+Alt+L\n代码重构相关\n⇧F6:代码重构时，类名／方法名／变量名 重命名操作 | 对应window中的Shift + F6\n⌘R: 代码重构时，可以用来批量重命名变量\n⌥⌘M: 方法重构，方法抽离 ｜对应window中的Ctrl+Alt+M\n⌥⌘P: 参数重构，将方法内变量抽离成方法参数 ｜对应window中的Ctrl+Alt+P\n⌥⌘V: 变量抽离，\u0026laquo;/span\u0026gt;使用率非常高\u0026gt; | 对应window中的Ctrl+Alt+V\nnew StringBuffer()\n使用快捷键后效果如下：\nStringBuffer stringBuffer = new StringBuffer();\n⌥⌘F: 字段抽离，将方法内的变量抽离成类字段申明,简单说就是把变量的申明从方法内重构抽离到方法外 ｜ 对应window中的Ctrl+Alt+F\n其他\n⇧⌘A: 你可以调用任何菜单或动作的名称在Android studio中 ｜ 对应window中的ctrl + shift + a\n","permalink":"https://blog.zdltech.com/posts/androidstudio%E5%BF%AB%E6%8D%B7%E9%94%AE/","summary":"\u003cp\u003eCtrl+G / Ctrl+Alt+Shift+G：查询变量或者函数或者类在哪里被使用或被调用，后者是前者的复杂表现，可以选择查询范围等。\u003c/p\u003e\n\u003cp\u003eAlt+H：查找功能，全局查找\u003c/p\u003e\n\u003cp\u003eF4：查看类继承关系\u003c/p\u003e\n\u003cp\u003eF2：查看文档说明（函数使用说明）\u003c/p\u003e\n\u003cp\u003eCtrl+E：查看最近打开过的文件\u003c/p\u003e\n\u003cp\u003eCtrl+Shift+E：查看最近编辑过的文件\u003c/p\u003e\n\u003cp\u003edouble Shift：全局查找，这个查看和Alt+H稍稍有些不同，这个是全局文件查找，到文件名称层面。\u003c/p\u003e\n\u003cp\u003eCtrl+Shift+R：快速定位到你所想打开的文件。\u003c/p\u003e\n\u003cp\u003eAlt+↑：光标所在位置那行代码往上移动\u003c/p\u003e\n\u003cp\u003eAlt+↓：光标所在位置那行代码往下移动\u003c/p\u003e\n\u003cp\u003eCtrl+D：删除光标所在位置那行代码\u003c/p\u003e\n\u003cp\u003eCtrl+X：剪切光标所在位置那行代码\u003c/p\u003e\n\u003cp\u003eAlt+Shift+↓/Ctrl+C：复制光标所在行代码到下一行\u003c/p\u003e\n\u003cp\u003eCtrl+O:快捷查找当前类中的函数，变量\u003c/p\u003e\n\u003cp\u003eCtrl+Shift+R：修改名称\u003c/p\u003e\n\u003cp\u003eAlt+Enter：导入包\u003c/p\u003e\n\u003cp\u003eAlt+←：后退，定位到上个查看或者编辑的地方\u003c/p\u003e\n\u003cp\u003eAlt+→：往前定位，比如你定位到上个点后，想回去，就可以用这个快捷键\u003c/p\u003e\n\u003cp\u003eCtrl+/：当行注释，反注释再按一次即可\u003c/p\u003e\n\u003cp\u003eCtrl+Shift+/：模块注释，反注释再按一次即可,注意这边的”/“不能用小键盘的\u003c/p\u003e\n\u003cp\u003eCtrl+Shift+小键盘/：折叠代码（Ctrl+Shift+小键盘*这个不灵了，今天没空了，后面会针对这个问题做解决，并更新上来），当然笔记本没小键盘，你可以自己改快捷键\u003c/p\u003e\n\u003cp\u003eCtrl+Alt+S：打开settings界面\u003c/p\u003e\n\u003cp\u003eCtrl+Alt+Shift+S：打开Project Structure界面\u003c/p\u003e\n\u003cp\u003eAlt+Shift+X：运行（Run）\u003c/p\u003e\n\u003cp\u003eAlt+Shift+D：调试运行（Debug）\u003c/p\u003e\n\u003cp\u003eCtrl+F9：编译工程\u003c/p\u003e\n\u003cp\u003eCtrl+Shift+K：push文件到Server（git）\u003c/p\u003e\n\u003cp\u003eDebug类快捷键\u003c/p\u003e\n\u003cp\u003eF5：但不调试进入函数内部。\u003c/p\u003e\n\u003cp\u003eF6：但不调试不进入函数内部。\u003c/p\u003e\n\u003cp\u003eF7：由函数内部返回调用处。\u003c/p\u003e\n\u003cp\u003eF8：执行到下一个断点，没断点则执行完成。\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eAction\u003c/th\u003e\n          \u003cth\u003eMac OSX\u003c/th\u003e\n          \u003cth\u003eWin/Linux\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e注释代码(//)\u003c/td\u003e\n          \u003ctd\u003eCmd + /\u003c/td\u003e\n          \u003ctd\u003eCtrl + /\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e注释代码(/**/)\u003c/td\u003e\n          \u003ctd\u003eCmd + Option + /\u003c/td\u003e\n          \u003ctd\u003eCtrl + Shift + /\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e格式化代码\u003c/td\u003e\n          \u003ctd\u003eCmd + Option + L\u003c/td\u003e\n          \u003ctd\u003eCtrl + Alt + L\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e清除无效包引用\u003c/td\u003e\n          \u003ctd\u003eOption + Control + O\u003c/td\u003e\n          \u003ctd\u003eAlt + Ctrl + O\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e查找\u003c/td\u003e\n          \u003ctd\u003eCmd + F\u003c/td\u003e\n          \u003ctd\u003eCtrl + F\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e查找+替换\u003c/td\u003e\n          \u003ctd\u003eCmd + R\u003c/td\u003e\n          \u003ctd\u003eCtrl + R\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e上下移动代码\u003c/td\u003e\n          \u003ctd\u003eOption + Shift + Up/Down\u003c/td\u003e\n          \u003ctd\u003eAlt + Shift + Up/Down\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e删除行\u003c/td\u003e\n          \u003ctd\u003eCmd + Delete\u003c/td\u003e\n          \u003ctd\u003eCtrl + Y\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e扩大缩小选中范围\u003c/td\u003e\n          \u003ctd\u003eOption + Up/Down\u003c/td\u003e\n          \u003ctd\u003eCtrl + W/Ctrl + Shift + W\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e快捷生成结构体\u003c/td\u003e\n          \u003ctd\u003eCmd + Option + T\u003c/td\u003e\n          \u003ctd\u003eCtrl + Alt + T\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e快捷覆写方法\u003c/td\u003e\n          \u003ctd\u003eCtrl + O\u003c/td\u003e\n          \u003ctd\u003eCtrl + O\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e快捷定位到行首/尾\u003c/td\u003e\n          \u003ctd\u003eCmd + Left/Right\u003c/td\u003e\n          \u003ctd\u003eCtrl + Left/Right\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e折叠展开代码块\u003c/td\u003e\n          \u003ctd\u003eCmd + Plus,Minus\u003c/td\u003e\n          \u003ctd\u003eCtrl + Plus/Minus\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e折叠展开全部代码块\u003c/td\u003e\n          \u003ctd\u003eCmd + Shift + Plus,Minus\u003c/td\u003e\n          \u003ctd\u003eCtrl + Shift + Plus,Minus\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e文件方法结构\u003c/td\u003e\n          \u003ctd\u003eCmd + F12\u003c/td\u003e\n          \u003ctd\u003eCtrl + F12\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e查找调用的位置\u003c/td\u003e\n          \u003ctd\u003eCtrl + Option + H\u003c/td\u003e\n          \u003ctd\u003eCtrl + Alt + H\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e大小写转换\u003c/td\u003e\n          \u003ctd\u003eCmd + Shift + U\u003c/td\u003e\n          \u003ctd\u003eCtrl + Shift + U\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e \u003c/p\u003e","title":"AndroidStudio快捷键"},{"content":"当我们在使用SQLiteOpenHelper时，经常使用db.execSQL(String sql)方法写入对应语句实现创建表的操作，这样的确可以实现业务逻辑。与此同时还有一种更灵活的方法，从assets文件夹下读取对应的.sql文件，然后创建表。\n1.首先在工程的assets文件夹下，添加对应的.sql文件\n2.配置一个Configuration类，用于保存固定路径变量\n**[java]** [view plain](http://blog.csdn.net/yangqicong11/article/details/21396437#)[copy](http://blog.csdn.net/yangqicong11/article/details/21396437#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/240525)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/240525/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; Configuration { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String DB_PATH = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;schema\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String DB_NAME = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;test.db\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; DB_VERSION = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - - } 3.逻辑实现类，executeAssetsSQL方法用于向Assets文件夹对应的路径读取SQL语句然后执行创建操作\n**[java]** [view plain](http://blog.csdn.net/yangqicong11/article/details/21396437#)[copy](http://blog.csdn.net/yangqicong11/article/details/21396437#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/240525)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/240525/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; DBHelper \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; SQLiteOpenHelper { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context mContext; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; DBHelper(Context context, String databaseName, - CursorFactory factory, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; version) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, databaseName, factory, version); - mContext = context; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 数据库第一次创建时调用\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(SQLiteDatabase db) { - executeAssetsSQL(db, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;schema.sql\u0026amp;#8221;\u0026lt;/span\u0026gt;); - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;创建表\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 数据库升级时调用\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onUpgrade(SQLiteDatabase db, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldVersion, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; newVersion) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//数据库不升级\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (newVersion \u0026lt;= oldVersion) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - } - Configuration.oldVersion = oldVersion; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; changeCnt; i++) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 依次执行updatei_i+1文件 由1更新到2 [1-2]，2更新到3 [2-3]\u0026lt;/span\u0026gt; - String schemaName = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;update\u0026amp;#8221;\u0026lt;/span\u0026gt; + (oldVersion + i) + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;_\u0026amp;#8221;\u0026lt;/span\u0026gt; - + (oldVersion + i + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;.sql\u0026amp;#8221;\u0026lt;/span\u0026gt;; - executeAssetsSQL(db, schemaName); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 读取数据库文件（.sql），并执行sql语句\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; executeAssetsSQL(SQLiteDatabase db, String schemaName) { - BufferedReader in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - in = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BufferedReader(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; InputStreamReader(mContext.getAssets() - .open(Configuration.DB_PATH + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;/\u0026amp;#8221;\u0026lt;/span\u0026gt; + schemaName))); - - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;路径:\u0026amp;#8221;\u0026lt;/span\u0026gt;+Configuration.DB_PATH + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;/\u0026amp;#8221;\u0026lt;/span\u0026gt; + schemaName); - String line; - String buffer = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt; ((line = in.readLine()) != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - buffer += line; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (line.trim().endsWith(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;;\u0026amp;#8221;\u0026lt;/span\u0026gt;)) { - db.execSQL(buffer.replace(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;;\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - buffer = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;; - } - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) { - Log.e(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;db-error\u0026amp;#8221;\u0026lt;/span\u0026gt;, e.toString()); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;finally\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (in != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - in.close(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) { - Log.e(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;db-error\u0026amp;#8221;\u0026lt;/span\u0026gt;, e.toString()); - } - } - } - - } ","permalink":"https://blog.zdltech.com/posts/android%E7%BC%96%E7%A8%8B%E5%BF%83%E5%BE%97-%E5%9C%A8assets%E6%96%87%E4%BB%B6%E5%A4%B9%E4%B8%AD%E6%94%BE%E5%85%A5-sql%E6%96%87%E4%BB%B6%E5%AE%9E%E7%8E%B0%E5%88%9B%E5%BB%BAsqlite%E8%A1%A8%E7%9A%84/","summary":"\u003cp\u003e当我们在使用SQLiteOpenHelper时，经常使用db.execSQL(String sql)方法写入对应语句实现创建表的操作，这样的确可以实现业务逻辑。与此同时还有一种更灵活的方法，从assets文件夹下读取对应的.sql文件，然后创建表。\u003c/p\u003e\n\u003cp\u003e1.首先在工程的assets文件夹下，添加对应的.sql文件\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140317163759015?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuZ3FpY29uZzEx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e2.配置一个Configuration类，用于保存固定路径变量\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/yangqicong11/article/details/21396437#)[copy](http://blog.csdn.net/yangqicong11/article/details/21396437#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/240525)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/240525/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; Configuration {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String DB_PATH = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;schema\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String DB_NAME = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;test.db\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; DB_VERSION = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n\n\n- \n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android编程心得-在Assets文件夹中放入.sql文件实现创建SQlite表的操作"},{"content":"Android Volley 是Google开发的一个网络lib，可以让你更加简单并且快速的访问网络数据。Volley库的网络请求都是异步的，你不必担心异步处理问题。\nVolley的优点：\n请求队列和请求优先级 请求Cache和内存管理 扩展性性强 可以取消请求 下载和编译volley.jar 需要安装git，ant，android sdk clone代码：\ngit clone https://android.googlesource.com/platform/frameworks/volley\n编译jar：\nandroid update project -p . ant jar\n添加volley.jar到你的项目中 不过已经有人将volley的代码放到github上了：\nhttps://github.com/mcxiaoke/android-volley，你可以使用更加简单的方式来使用volley：\nMaven format: jar\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;dependency\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;groupId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;com.mcxiaoke.volley\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;groupId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;artifactId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;library\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;artifactId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;1.0.6\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;dependency\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; Gradle format: jar\ncompile 'com.mcxiaoke.volley:library:1.0.6'\nVolley工作原理图 {.fancybox}\n创建Volley 单例 使用volley时，必须要创建一个请求队列RequestQueue，使用请求队列的最佳方式就是将它做成一个单例，整个app使用这么一个请求队列。\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;AppController\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;Application\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = AppController.class .getSimpleName(); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; RequestQueue mRequestQueue; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageLoader mImageLoader; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; AppController mInstance; \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onCreate\u0026lt;/span\u0026gt;() { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(); mInstance = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; AppController \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getInstance\u0026lt;/span\u0026gt;() { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mInstance; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; RequestQueue \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getRequestQueue\u0026lt;/span\u0026gt;() { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mRequestQueue == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { mRequestQueue = Volley.newRequestQueue(getApplicationContext()); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mRequestQueue; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ImageLoader \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getImageLoader\u0026lt;/span\u0026gt;() { getRequestQueue(); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mImageLoader == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { mImageLoader = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageLoader(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mRequestQueue, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LruBitmapCache()); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mImageLoader; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;T\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;addToRequestQueue\u0026lt;/span\u0026gt;(Request\u0026lt;T\u0026gt; req, String tag) { \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// set the default tag if tag is empty\u0026lt;/span\u0026gt; req.setTag(TextUtils.isEmpty(tag) ? TAG : tag); getRequestQueue().add(req); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;T\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;addToRequestQueue\u0026lt;/span\u0026gt;(Request\u0026lt;T\u0026gt; req) { req.setTag(TAG); getRequestQueue().add(req); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;cancelPendingRequests\u0026lt;/span\u0026gt;(Object tag) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mRequestQueue != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { mRequestQueue.cancelAll(tag); } } } 另外，你还需要一个Cache来存放请求的图片：\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;LruBitmapCache\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;LruCache\u0026lt;/span\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;Bitmap\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;implement\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;ImageCache\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getDefaultLruCacheSize\u0026lt;/span\u0026gt;() { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; maxMemory = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (Runtime.getRuntime().maxMemory() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1024\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cacheSize = maxMemory / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; cacheSize; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;LruBitmapCache\u0026lt;/span\u0026gt;() { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(getDefaultLruCacheSize()); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;LruBitmapCache\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; sizeInKiloBytes) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(sizeInKiloBytes); } \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;sizeOf\u0026lt;/span\u0026gt;(String key, Bitmap value) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; value.getRowBytes() * value.getHeight() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1024\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Bitmap \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getBitmap\u0026lt;/span\u0026gt;(String url) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; get(url); } \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;putBitmap\u0026lt;/span\u0026gt;(String url, Bitmap bitmap) { put(url, bitmap); } } 别忘记在AndroidManifest.xml文件中添加android.permission.INTERNET权限。\n创建Json请求 volley自带了JsonObjectRequest和JsonArrayRequest分别来处理Json对象请求和Json数据请求（但是voley没有使用gson库写一个GsonRequest，发送一个request，volley直接返回一个java对象，不过我们可以自己写）。\n创建json object请求 发送一个请求只要这么简单，创建一个JsonRequest对象，写好response回调接口，并把这个请求放到请求队列中就可以了。JsonArrayRequest也类似。\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Tag used to cancel the request\u0026lt;/span\u0026gt; String tag_json_obj = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;json_obj_req\u0026quot;\u0026lt;/span\u0026gt;; String url = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;http://api.androidhive.info/volley/person_object.json\u0026quot;\u0026lt;/span\u0026gt;; JsonObjectRequest jsonObjReq = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; JsonObjectRequest(Method.GET,url, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.Listener\u0026lt;JSONObject\u0026gt;() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onResponse\u0026lt;/span\u0026gt;(JSONObject response) { Log.d(TAG, response.toString()); } }, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.ErrorListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onErrorResponse\u0026lt;/span\u0026gt;(VolleyError error) { VolleyLog.d(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Error: \u0026quot;\u0026lt;/span\u0026gt; + error.getMessage()); } }); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Adding request to request queue\u0026lt;/span\u0026gt; AppController.getInstance().addToRequestQueue(jsonObjReq, tag_json_obj); 创建String请求 StringRequest可以用来请求任何string类型的数据：json，xml，文本等等。\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Tag used to cancel the request\u0026lt;/span\u0026gt; String tag_string_req = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;string_req\u0026quot;\u0026lt;/span\u0026gt;; String url = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;http://api.androidhive.info/volley/string_response.html\u0026quot;\u0026lt;/span\u0026gt;; ProgressDialog pDialog = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ProgressDialog(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); pDialog.setMessage(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Loading...\u0026quot;\u0026lt;/span\u0026gt;); pDialog.show(); StringRequest strReq = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringRequest(Method.GET, url, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.Listener\u0026lt;String\u0026gt;() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onResponse\u0026lt;/span\u0026gt;(String response) { Log.d(TAG, response.toString()); pDialog.hide(); } }, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.ErrorListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onErrorResponse\u0026lt;/span\u0026gt;(VolleyError error) { VolleyLog.d(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Error: \u0026quot;\u0026lt;/span\u0026gt; + error.getMessage()); pDialog.hide(); } }); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Adding request to request queue\u0026lt;/span\u0026gt; AppController.getInstance().addToRequestQueue(strReq, tag_string_req); 创建POST请求 上面说的都是GET请求，下面来说一下POST请求，与GET请求不同的是，只要在创建请求的时候将请求类型改为POST请求，并且override Request的getParams方法即可。\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Tag used to cancel the request\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt; tag_json_obj \u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;json_obj_req\u0026quot;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt; url \u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;http://api.androidhive.info/volley/person_object.json\u0026quot;\u0026lt;/span\u0026gt;; ProgressDialog pDialog \u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ProgressDialog(this); pDialog\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;setMessage(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Loading...\u0026quot;\u0026lt;/span\u0026gt;); pDialog\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;show(); JsonObjectRequest jsonObjReq \u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; JsonObjectRequest(Method\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;POST, url, \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;Listener\u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;JSONObject\u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;() { @Override \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onResponse(JSONObject response) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;Log\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;d(\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;TAG\u0026lt;/span\u0026gt;, response\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;toString()); pDialog\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;hide(); } }, \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;ErrorListener() { @Override \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onErrorResponse(VolleyError error) { VolleyLog\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;d(\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;TAG\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Error: \u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; error\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMessage()); pDialog\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;hide(); } }) { @Override \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;Map\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; getParams() { \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;Map\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;params\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;(); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;params\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;name\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Androidhive\u0026quot;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;params\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;email\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;abc@androidhive.info\u0026quot;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;params\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;password\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;password123\u0026quot;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;params\u0026lt;/span\u0026gt;; } }; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Adding request to request queue\u0026lt;/span\u0026gt; AppController\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getInstance()\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;addToRequestQueue(jsonObjReq, tag_json_obj); 添加请求头部信息 \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Tag used to cancel the request\u0026lt;/span\u0026gt; String tag_json_obj = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;json_obj_req\u0026quot;\u0026lt;/span\u0026gt;; String url = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;http://api.androidhive.info/volley/person_object.json\u0026quot;\u0026lt;/span\u0026gt;; ProgressDialog pDialog = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ProgressDialog(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); pDialog.setMessage(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Loading...\u0026quot;\u0026lt;/span\u0026gt;); pDialog.show(); JsonObjectRequest jsonObjReq = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; JsonObjectRequest(Method.POST,url, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.Listener\u0026lt;JSONObject\u0026gt;() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onResponse\u0026lt;/span\u0026gt;(JSONObject response) { Log.d(TAG, response.toString()); pDialog.hide(); } }, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.ErrorListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onErrorResponse\u0026lt;/span\u0026gt;(VolleyError error) { VolleyLog.d(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Error: \u0026quot;\u0026lt;/span\u0026gt; + error.getMessage()); pDialog.hide(); } }) { \u0026lt;span class=\u0026quot;javadoc\u0026quot;\u0026gt;/** * Passing some request headers * */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Map\u0026lt;String, String\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getHeaders\u0026lt;/span\u0026gt;() \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; AuthFailureError { HashMap\u0026lt;String, String\u0026gt; headers = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;String, String\u0026gt;(); headers.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Content-Type\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;application/json\u0026quot;\u0026lt;/span\u0026gt;); headers.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;apiKey\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;xxxxxxxxxxxxxxx\u0026quot;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; headers; } }; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Adding request to request queue\u0026lt;/span\u0026gt; AppController.getInstance().addToRequestQueue(jsonObjReq, tag_json_obj); 创建Image请求 Volley库中自带了NetworkImageView类，这个ImageView可以自动使用volley下载图片\n用NetworkImageView加载图片 首先，说明一下，加载图片的原理：\nNetworkImageView加载图片需要一个ImageLoader和一个图片URL，这个ImageLoader对象需要一个请求队列对象和ImageCahe对象。调用NetworkImageView的setUrl方法后，首先会判断当前ImageView的URL和新传入的URL是否一致，如果相同，就不用再发送http请求了，如果不同，那么就使用ImageLoader对象来发送http请求获取图片。\n\u0026lt;span class=\u0026quot;constant\u0026quot;\u0026gt;ImageLoader imageLoader\u0026lt;/span\u0026gt; = AppController.getInstance().getImageLoader(); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// If you are using NetworkImageView\u0026lt;/span\u0026gt; imgNetWorkView.setImageUrl(Const.URL_IMAGE, imageLoader); 加载一个图片只要这么简单~~~\n用ImageView来加载图片 这个过程和NetworkImageView类似\nImageLoader imageLoader = AppController.getInstance().getImageLoader(); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// If you are using normal ImageView\u0026lt;/span\u0026gt; imageLoader.get(Const.URL_IMAGE, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onErrorResponse\u0026lt;/span\u0026gt;(VolleyError error) { Log.e(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Image Load Error: \u0026quot;\u0026lt;/span\u0026gt; + error.getMessage()); } \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onResponse\u0026lt;/span\u0026gt;(ImageContainer response, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; arg1) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (response.getBitmap() != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// load image into imageview\u0026lt;/span\u0026gt; imageView.setImageBitmap(response.getBitmap()); } } }); 可以再简单一点：\n// Loading image with placeholder \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;and\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;error\u0026lt;/span\u0026gt; image imageLoader.get(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;Const\u0026lt;/span\u0026gt;.URL_IMAGE, ImageLoader.getImageListener(imageView, R.drawable.ico_loading, R.drawable.ico_error)); ImageLoader.getImageListener方法中已经写了一个默认的ImageListener了\nVolley Cache volley中自带了强大的cache机制来管理请求cache，这会减少网络请求次数和用户等待时间。\n从请求Cache中加载请求 \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;Cache\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;cache\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; AppController\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getInstance()\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getRequestQueue()\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getCache(); Entry entry \u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;cache\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;get(url); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(entry \u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;!=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ try { \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;(entry\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;UTF-8\u0026quot;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// handle data, like converting it to xml, json, bitmap etc.,\u0026lt;/span\u0026gt; } catch (UnsupportedEncodingException e) { e\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;printStackTrace(); } } }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Cached response doesn't exists. Make network call here\u0026lt;/span\u0026gt; } 使请求缓存失效 失效并不意味这删除，Volley还会继续使用缓存的对象直到从服务器上获取到了新的数据，新的数据会覆盖旧的数据。\nAppController.getInstance().getRequestQueue().getCache().invalidate(url, \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); 关闭Cache 如果你想将某一个请求的Cache功能关闭，直接调用Request的setShouldCache()方法就可以：\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// String request\u0026lt;/span\u0026gt; StringRequest stringReq \u0026lt;span class=\u0026quot;subst\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringRequest(\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;...\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// disable cache\u0026lt;/span\u0026gt; stringReq\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;setShouldCache(\u0026lt;span class=\u0026quot;literal\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); 将某一URL的Cache删除 调用Cache的remove方法可以删除这个URL的cache:\nAppController.getInstance().getRequestQueue().getCache().\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;remove\u0026lt;/span\u0026gt;(url); 删除所有的Cache AppController.getInstance().getRequestQueue().getCache().\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;clear\u0026lt;/span\u0026gt;(); 取消请求 在你添加一个请求到请求队列中的时候，你可以发现，addToRequestQueue(request, tag)方法还接受一个tag参数，这个tag就是用来标记某一类请求的，这样就可以取消这个tag的所有请求了：\n\u0026lt;span class=\u0026quot;built_in\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt; tag_json_arry = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;json_req\u0026quot;\u0026lt;/span\u0026gt;; ApplicationController.getInstance().getRequestQueue().cancelAll(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;feed_request\u0026quot;\u0026lt;/span\u0026gt;); 请求优先级 在创建一个request的时候可以Override Request方法的getPriority方法返回一个优先级，优先级分为：Normal, Low, Immediate, High\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Priority priority = Priority.HIGH; StringRequest strReq = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringRequest(Method.GET, Const.URL_STRING_REQ, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.Listener\u0026lt;String\u0026gt;() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onResponse\u0026lt;/span\u0026gt;(String response) { Log.d(TAG, response.toString()); msgResponse.setText(response.toString()); hideProgressDialog(); } }, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.ErrorListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onErrorResponse\u0026lt;/span\u0026gt;(VolleyError error) { VolleyLog.d(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;Error: \u0026quot;\u0026lt;/span\u0026gt; + error.getMessage()); hideProgressDialog(); } }) { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Priority \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getPriority\u0026lt;/span\u0026gt;() { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; priority; } }; Missing! 创建xml请求 {#Missing!_创建xml请求} 就像创建Gson请求一样，你可以自定义一个XMLRequest类来请求xml数据\n","permalink":"https://blog.zdltech.com/posts/android%E5%BA%93volley%E7%9A%84%E4%BD%BF%E7%94%A8%E4%BB%8B%E7%BB%8D/","summary":"\u003cp\u003e\u003ca href=\"http://developer.android.com/training/volley/index.html\"\u003eAndroid Volley\u003c/a\u003e 是Google开发的一个网络lib，可以让你更加简单并且快速的访问网络数据。Volley库的网络请求都是异步的，你不必担心异步处理问题。\u003c/p\u003e\n\u003cp\u003eVolley的优点：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e请求队列和请求优先级\u003c/li\u003e\n\u003cli\u003e请求Cache和内存管理\u003c/li\u003e\n\u003cli\u003e扩展性性强\u003c/li\u003e\n\u003cli\u003e可以取消请求\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"下载和编译volley-jar\"\u003e下载和编译volley.jar\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e需要安装git，ant，android sdk\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eclone代码：\u003cbr\u003e\n\u003ccode\u003egit clone https://android.googlesource.com/platform/frameworks/volley\u003c/code\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e编译jar：\u003cbr\u003e\n\u003ccode\u003eandroid update project -p . ant jar\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e添加volley.jar到你的项目中\n\u003cstrong\u003e\u003cem\u003e不过已经有人将volley的代码放到github上了：\u003c/em\u003e\u003c/strong\u003e\u003cbr\u003e\n\u003ca href=\"https://github.com/mcxiaoke/android-volley\"\u003ehttps://github.com/mcxiaoke/android-volley\u003c/a\u003e，你可以使用更加简单的方式来使用volley：\u003c/p\u003e\n\u003ch3 id=\"Maven\"\u003eMaven\u003c/h3\u003e\n\u003cp\u003eformat: jar\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;dependency\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;groupId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;com.mcxiaoke.volley\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;groupId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;artifactId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;library\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;artifactId\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;1.0.6\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;dependency\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003chr\u003e\n\u003ch3 id=\"Gradle\"\u003eGradle\u003c/h3\u003e\n\u003cp\u003eformat: jar\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecompile 'com.mcxiaoke.volley:library:1.0.6'\u003c/code\u003e\u003c/p\u003e\n\u003ch2 id=\"Volley工作原理图\"\u003eVolley工作原理图\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://bxbxbai.github.io/img/volley.png\"\u003e\u003cimg alt=\"Volley\" loading=\"lazy\" src=\"http://bxbxbai.github.io/img/volley.png\"\u003e\u003c/a\u003e{.fancybox}\u003c/p\u003e\n\u003ch2 id=\"创建Volley_单例\"\u003e创建Volley 单例\u003c/h2\u003e\n\u003cp\u003e使用volley时，必须要创建一个请求队列\u003ccode\u003eRequestQueue\u003c/code\u003e，使用请求队列的最佳方式就是将它做成一个单例，整个app使用这么一个请求队列。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;AppController\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;Application\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = AppController.class\n        .getSimpleName();\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; RequestQueue mRequestQueue;\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageLoader mImageLoader;\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; AppController mInstance;\n\n\u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;onCreate\u0026lt;/span\u0026gt;() {\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate();\n    mInstance = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;;\n}\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; AppController \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getInstance\u0026lt;/span\u0026gt;() {\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mInstance;\n}\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; RequestQueue \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getRequestQueue\u0026lt;/span\u0026gt;() {\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mRequestQueue == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n        mRequestQueue = Volley.newRequestQueue(getApplicationContext());\n    }\n\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mRequestQueue;\n}\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ImageLoader \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;getImageLoader\u0026lt;/span\u0026gt;() {\n    getRequestQueue();\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mImageLoader == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n        mImageLoader = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageLoader(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mRequestQueue,\n                \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LruBitmapCache());\n    }\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mImageLoader;\n}\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;T\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;addToRequestQueue\u0026lt;/span\u0026gt;(Request\u0026lt;T\u0026gt; req, String tag) {\n    \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// set the default tag if tag is empty\u0026lt;/span\u0026gt;\n    req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);\n    getRequestQueue().add(req);\n}\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;T\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;addToRequestQueue\u0026lt;/span\u0026gt;(Request\u0026lt;T\u0026gt; req) {\n    req.setTag(TAG);\n    getRequestQueue().add(req);\n}\n\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;cancelPendingRequests\u0026lt;/span\u0026gt;(Object tag) {\n    \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mRequestQueue != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n        mRequestQueue.cancelAll(tag);\n    }\n}\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e另外，你还需要一个Cache来存放请求的图片：\u003c/p\u003e","title":"Android库Volley的使用介绍"},{"content":"转载来自： http://blog.csdn.net/tianjian4592\n前面关于paint的方法讲解里，讲到 setXfermode 就截止了，原因有两个：\n那篇文章已经太长了，我自己都看不下去了； 2. setXfermode 在paint 里占有至关重要的地位；\n基于以上两个原因，我们一起来看看这个方法有何妙用。\n首先我们还是来看看关于这个方法的说明：\n/** * Set or clear the xfermode object. - 设置或清除xfermode对象; * Pass null to clear any previous xfermode. - 传递null以清除任何以前的xfermode。 * As a convenience, the parameter passed is also returned. - 为方便起见，也返回传递的参数。 * * @return xfermode */ public Xfermode setXfermode(Xfermode xfermode) { int xfermodeNative = 0; if (xfermode != null) xfermodeNative = xfermode.native_instance; native_setXfermode(mNativePaint, xfermodeNative); mXfermode = xfermode; return xfermode; } 这个方法传进一个 Xfermode 对象，而打开 Xfermode 发现里面没有提供任何可用的构造函数或方法，ctrl ＋T 看到它有三个子类：\n前两个子类 AvoidXfermode 和 PixelXorXfermode 大家可以看到都已经被划上了斜线，下面就简单提及一下，咱们的重点在 PorterDuffXfermode :\n1. AvoidXfermode:\n/** This xfermode draws, or doesn\u0026#39;t draw, based on the destination\u0026#39;s * distance from an op-color. * * There are two modes, and each mode interprets a tolerance value. * * Avoid: In this mode, drawing is allowed only on destination pixels that * are different from the op-color. * Tolerance near 0: avoid any colors even remotely similar to the op-color * Tolerance near 255: avoid only colors nearly identical to the op-color * Tolerance near 0: draw only on colors that are nearly identical to the op-color * Tolerance near 255: draw on any colors even remotely similar to the op-color */ public AvoidXfermode(int opColor, int tolerance, Mode mode) { if (tolerance \u0026amp;lt; 0 || tolerance \u0026amp;gt; 255) { throw new IllegalArgumentException(\u0026#34;tolerance must be 0..255\u0026#34;); } native_instance = nativeCreate(opColor, tolerance, mode.nativeInt); } 咱们把它上面的说明看下就很清楚了：\nxfermode 是否绘制，基于目标色和参数 op-color 的差距；\n其中有两种模式，分别为 Avoid 和 TARGET：\nAvoid模式：只会在目标像素值和 op-color “不一样” 的地方进行绘制；\nTarget模式：只会在目标像素值和 op-color “一样” 的地方进行绘制；\n上面的”一样” 和 “不一样” 我都打上了引号，并不是指严格意义上的一样，而是只要在可容忍范围内就代表一样，这个可容忍范围，就是容差值（tolerance），0 代表最小容差，即得和 op-color 真正意义上一样才 ok ，255 则代表最大容差，只要有一点相近，则ok；\n咱们一起来看个小例子：\n先在网上找个图案，用PS去掉周围部分，主体改为纯色；\n当我们使用PS里的魔棒创立选区的时候，发现一次只选取了其中最相近的一部分，这时候可以看到容差为5，但我们的目的是想把图形周围近似的蓝灰色都选中该怎么办呢？容差这时候就起作用了，改大容差，就相当于调大近似度，这个概念和我们里面的容差值是一样的，希望这样说便于理解，我们看下对比图，调到50 一下就可以选中外层所有蓝灰色：\n好，我们现在有了一个纯色的图标，假定我们现在有一个需求，需要在某种操作下将图标变色，类似微信底部的tab图标，未选中时时白色，选中时是绿色，这个时候我们就可以用\nAvoidXfermode 进行实现，我们一起看看要怎么做：\n给paint 设置要变换的颜色和图层混合模式为 AvoidXfermode;\n绘制图标；\n再绘制对应色块；\n由于是对对应颜色进行替换，所以也就形成了图标变色的效果，一起来看看代码：\npublic class AvoidXfermodeView extends View { private Paint mBitmapPaint, mAvoidPaint; private int mTotalWidth, mTotalHeight; private Bitmap mBitmap; private int mBitWidth, mBitHeight; private Rect mOriginSrcRect, mOriginDestRect; private Rect mAvoidSrcRect, mAvoidDestRect; private AvoidXfermode mAvoidXfermode; public AvoidXfermodeView(Context context) { super(context); initPaint(); initBitmap(); // 对蓝色相近的颜色进行替换 mAvoidXfermode = new AvoidXfermode(Color.BLUE, 150, Mode.TARGET); } private void initBitmap() { mBitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.bluelogo)).getBitmap(); mBitWidth = mBitmap.getWidth(); mBitHeight = mBitmap.getHeight(); } private void initPaint() { mBitmapPaint = new Paint(); // 去锯齿 mBitmapPaint.setAntiAlias(true); // 防抖动 mBitmapPaint.setDither(true); // 图像过滤 mBitmapPaint.setFilterBitmap(true); // 使用上面属性创建一个新paint mAvoidPaint = new Paint(mBitmapPaint); // 颜色设置为红色 mAvoidPaint.setColor(Color.RED); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制原图 canvas.drawBitmap(mBitmap, mOriginSrcRect, mOriginDestRect, mBitmapPaint); // 绘制用于变色图 canvas.drawBitmap(mBitmap, mAvoidSrcRect, mAvoidDestRect, mAvoidPaint); // 设置图层混合模式 mAvoidPaint.setXfermode(mAvoidXfermode); // 绘制色块进行混合，得到最终效果 canvas.drawRect(mAvoidDestRect, mAvoidPaint); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mTotalWidth = w; mTotalHeight = h; mOriginSrcRect = new Rect(0, 0, mBitWidth, mBitHeight); // 为了让图水平居中 int left = (mTotalWidth - mBitWidth) / 2; mOriginDestRect = new Rect(left, 0, left + mBitWidth, mBitHeight); mAvoidSrcRect = new Rect(mOriginSrcRect); // 两张图得间距 int distance = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()); mAvoidDestRect = new Rect(left, mBitHeight + distance, left + mBitWidth, mBitHeight * 2 + distance); } } 一起来看看效果：\n我擦，什么情况，逗我玩儿呢？这时候大家别忘了，前面说过这方法已经在API 16过时了，要在高版本用的话需要关掉硬件加速，什么？硬件加速怎么关…\n硬件加速分全局（Application）、Activity、Window、View 四个层级，也简单提及一下：\n1.在AndroidManifest.xml文件为application标签添加如下的属性即可为整个应用程序开启硬件加速：\n\u0026amp;lt;application android:hardwareAccelerated=\u0026#34;true\u0026#34; ...\u0026amp;gt; 2.在Activity 标签下使用 hardwareAccelerated 属性开启或关闭硬件加速：\n\u0026amp;lt;activity android:hardwareAccelerated=\u0026#34;false\u0026#34; /\u0026amp;gt; 在Window 层级使用如下代码开启硬件加速： getWindow().setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); 4.View 级别如下关闭硬件加速，view 层级上没法单独开启硬件加速：\nsetLayerType(View.LAYER_TYPE_SOFTWARE, null); 好了，原来如此，咱们直接在全局application 关闭硬件加速：\n\u0026amp;lt;application android:allowBackup=\u0026#34;true\u0026#34; android:hardwareAccelerated=\u0026#34;false\u0026#34;－－－ 再看下效果：\n我们可以看到，现在蓝花已经变成红花了，已经实现了前面说的图标变色小需求，这时候有人可能会说了，这东西还有点用，如果我要在进行某些操作的时候让图标进行颜色的平滑过渡，该怎么办呢？比如viewPager从一页滑到另一页的时候，图标颜色渐变过渡，其实这样的需求只需要在上面的基础上稍加改动即可，提供下思路：\neg：view层级对外提供个接口，传入渐变比例，view里根据比例计算出当前色值，然后实时的把paint的色值更新，重新绘制即可！\n好了，AvoidXfermode 就讲这些！\n2. PixelXorXfermode\n/** * PixelXorXfermode implements a simple pixel xor (op ^ src ^ dst). * This transformation does not follow premultiplied conventions, therefore * this mode *always* returns an opaque color (alpha == 255). Thus it is * not really usefull for operating on blended colors. */ @Deprecated public class PixelXorXfermode extends Xfermode { public PixelXorXfermode(int opColor) { native_instance = nativeCreate(opColor); } private static native int nativeCreate(int opColor); } 从上面的介绍上讲，这只是一个简单异或运算，这种变换不满足预乘公约，因此会总是返回一个不透明的颜色，所以对操作颜色混合不是特别的有效；\n基于以上说明和这个类已经过时，讲解到此结束；\n3. PorterDuffXfermode\n这个类是setXfermode 方法的核心，也是图层混合模式里的核武器，通过它再加上我们的想象力，就能解决图形图像绘制里的很多问题，首先，还是看下方法说明：\n/** * Create an xfermode that uses the specified porter-duff mode. * * @param mode The porter-duff mode that is applied */ public PorterDuffXfermode(PorterDuff.Mode mode) { this.mode = mode; native_instance = nativeCreateXfermode(mode.nativeInt); } 使用 PorterDuff 模式创建一个图层混合模式，如此说来，我们的重心就转移到了 PorterDuff 身上；\nPorterDuff 是啥，居然没法翻译，我靠，百思不得其姐，如果对图形图像学有所了解，肯定会知道，PorterDuff 实则是两个人名的的组合Thomas Porter 和 Tom Duff ，PorterDuff则是用于描述数字图像合成的基本手法，通过组合使用 Porter-Duff 操作，可完成任意 2D图像的合成；\n听起来好像很屌炸天的样子，接下来我们一起来逐个看下这些模式：\npublic class PorterDuff { // these value must match their native equivalents. See SkPorterDuff.h public enum Mode { /** [0, 0] */ CLEAR (0), /** [Sa, Sc] */ SRC (1), /** [Da, Dc] */ DST (2), /** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */ SRC_OVER (3), /** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */ DST_OVER (4), /** [Sa * Da, Sc * Da] */ SRC_IN (5), /** [Sa * Da, Sa * Dc] */ DST_IN (6), /** [Sa * (1 - Da), Sc * (1 - Da)] */ SRC_OUT (7), /** [Da * (1 - Sa), Dc * (1 - Sa)] */ DST_OUT (8), /** [Da, Sc * Da + (1 - Sa) * Dc] */ SRC_ATOP (9), /** [Sa, Sa * Dc + Sc * (1 - Da)] */ DST_ATOP (10), /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */ XOR (11), /** [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */ DARKEN (12), /** [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */ LIGHTEN (13), /** [Sa * Da, Sc * Dc] */ MULTIPLY (14), /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */ SCREEN (15), /** Saturate(S + D) */ ADD (16), OVERLAY (17); Mode(int nativeInt) { this.nativeInt = nativeInt; } /** * @hide */ public final int nativeInt; } 可以看到里面通过枚举enum定义了18种混合模式，并且每种模式都写出了对应的计算方法：\n其中 Sa 代表source alpha ，即源 alpha 值 ，Da 代表 Destination alpha ，即 目标alpha值 ，Sc 代表 source color ，即源色值 ，Dc 代表 Destination color ，即目标色值，并且这所有的计算都以像素为单位，在某一种混合模式下，对每一个像素的alpha 和 color 通过对应算法进行运算，得出新的像素值，进行展示；\n接下来写个view 逐个对以上模式进行测试：\npublic class PorterDuffXfermodeView extends View { private Paint mPaint; private Bitmap mBottomBitmap, mTopBitmap; private Rect mBottomSrcRect, mBottomDestRect; private Rect mTopSrcRect, mTopDestRect; private Xfermode mPorterDuffXfermode; // 图层混合模式 private PorterDuff.Mode mPorterDuffMode; // 总宽高 private int mTotalWidth, mTotalHeight; private Resources mResources; public PorterDuffXfermodeView(Context context) { super(context); mResources = getResources(); initBitmap(); initPaint(); initXfermode(); } // 初始化bitmap private void initBitmap() { mBottomBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.blue)).getBitmap(); mTopBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.red)).getBitmap(); } // 初始化混合模式 private void initXfermode() { mPorterDuffMode = PorterDuff.Mode.DST; mPorterDuffXfermode = new PorterDuffXfermode(mPorterDuffMode); } private void initPaint() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 背景铺白 canvas.drawColor(Color.WHITE); // 保存为单独的层 int saveCount = canvas.saveLayer(0, 0, mTotalWidth, mTotalHeight, mPaint, Canvas.ALL_SAVE_FLAG); // 绘制目标图 canvas.drawBitmap(mBottomBitmap, mBottomSrcRect, mBottomDestRect, mPaint); // 设置混合模式 mPaint.setXfermode(mPorterDuffXfermode); // 绘制源图 canvas.drawBitmap(mTopBitmap, mTopSrcRect, mTopDestRect, mPaint); mPaint.setXfermode(null); canvas.restoreToCount(saveCount); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mTotalWidth = w; mTotalHeight = h; int halfHeight = h / 2; mBottomSrcRect = new Rect(0, 0, mBottomBitmap.getWidth(), mBottomBitmap.getHeight()); // 矩形只画屏幕一半 mBottomDestRect = new Rect(0, 0, mTotalWidth, halfHeight); mTopSrcRect = new Rect(0, 0, mTopBitmap.getWidth(), mTopBitmap.getHeight()); mTopDestRect = new Rect(0, 0, mTotalWidth, mTotalHeight); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } 原图如下：\n蓝色上下分别为完全不透明和半透区，红色左右为半透和完全不透明区，这样绘制时可以让所有的情况进行交叉，便于分析，先看下默认绘制效果：\n(1). CLEAR\n清除模式［0，0］，即最终所有点的像素的alpha 和color 都为 0，所以画出来的效果只有白色背景：\n(2). SRC －［Sa , Sc］\n只保留源图像的 alpha 和 color ，所以绘制出来只有源图，有时候会感觉分不清先绘制的是源图还是后绘制的是源图，这个时候可以这么记，先绘制的是目标图，不管任何时候，一定要做一个有目标的人，目标在前！\n这个时候绘制的情形是只有屏幕上的红色圆；\n(3). DST －[ Da, Dc ]\n同上类比，只保留目标图像的 alpha 和 color，所以绘制出来的只有目标图，也就是屏幕上的的蓝色图；\n(4).SRC_OVER － [ Sa +(1-Sa) * Da , Rc = Sc +( 1- Sa ) * Dc]\n在目标图片顶部绘制源图像,从命名上也可以看出来就是把源图像绘制在上方；\n可以和 SRC_OVER 进行类比，将目标图像绘制在上方,这时候就会看到先绘制的蓝色盖在了红色圆的上面；\n(6). SRC_IN － [ Sa * Da , Sc * Da ]\n在两者相交的地方绘制源图像，并且绘制的效果会受到目标图像对应地方透明度的影响；\n(7). DST_IN － [ Sa * Da , Sa * Dc ]\n可以和SRC_IN 进行类比，在两者相交的地方绘制目标图像，并且绘制的效果会受到源图像对应地方透明度的影响；\n从字面上可以理解为 在不相交的地方绘制 源图像，那么我们来看看效果是不是这样；\n所以该模式总结一下应该是：在不相交的地方绘制源图像，相交处根据目标alpha进行过滤，目标色完全不透明时则完全过滤，完全透明则不过滤；\n同样，可以类比SRC_OUT , 在不相交的地方绘制目标图像，相交处根据源图像alpha进行过滤，完全不透明处则完全过滤，完全透明则不过滤；\n源图像和目标图像相交处绘制源图像，不相交的地方绘制目标图像，并且相交处的效果会受到源图像和目标图像alpha的影响；\n源图像和目标图像相交处绘制目标图像，不相交的地方绘制源图像，并且相交处的效果会受到源图像和目标图像alpha的影响；\n在不相交的地方按原样绘制源图像和目标图像，相交的地方受到对应alpha和色值影响，按上面公式进行计算，如果都完全不透明则相交处完全不绘制；\n该模式处理过后，会感觉效果变暗，即进行对应像素的比较，取较暗值，如果色值相同则进行混合；\n从算法上看，alpha值变大，色值上如果都不透明则取较暗值，非完全不透明情况下使用上面算法进行计算，受到源图和目标图对应色值和alpha值影响；\n同样的，这样的混合效果可以直接在PS里进行简单模拟，创建三个一样的图层，选择对应的混合模式，对于效果表示是一致的：\n可以和 DARKEN 对比起来看，DARKEN 的目的是变暗，LIGHTEN 的目的则是变亮，如果在均完全不透明的情况下 ，色值取源色值和目标色值中的较大值，否则按上面算法进行计算；\n(15). MULTIPLY － [ Sa * Da , Sc * Dc ]\n正片叠底，即查看每个通道中的颜色信息，并将基色与混合色复合。结果色总是较暗的颜色。任何颜色与黑色复合产生黑色。任何颜色与白色复合保持不变。当用黑色或白色以外的颜色绘画时，绘画工具绘制的连续描边产生逐渐变暗的颜色。\n滤色，滤色模式与我们所用的显示屏原理相同，所以也有版本把它翻译成“屏幕”；\n简单的说就是保留两个图层中较白的部分，较暗的部分被遮盖；\n当一层使用了滤色（屏幕）模式时，图层中纯黑的部分变成完全透明，纯白部分完全不透明，其他的颜色根据颜色级别产生半透明的效果;\n(17). ADD － [ Saturate( S+ D ) ]\n饱和度叠加\n像素是进行 Multiply （正片叠底）混合还是 Screen （屏幕）混合，取决于底层颜色，但底层颜色的高光与阴影部分的亮度细节会被保留；\n以上就是android 提供的所有的混合模式，有了这，只要是图像与图像任何形式混合能创造的效果，我们就都能够进行实现，这时候我们再看看混合模式的示意图：\n前面我们用AvoidXfermode实现的图标变色小栗子也同样可以使用PorterDuffXfermode进行实现，大家可以自己尝试；\n最后，我们利用混合模式完成两个小栗子：\n一、还算比较流行的一种 loading 形式：\n先看下效果：\n这个效果如果不知道图像的混合模式，做的话可能会采用2张图，对上面的图进行裁切，但自从有了混合模式，这一切都将变的简单；\n我们只需要如下几步：\n1.绘制目标图；\n2.设置混合模式；\n3.绘制带颜色的Rect；\n4.不断改变Rect的区域；\n代码如下：\npublic class PoterDuffLoadingView extends View { private Resources mResources; private Paint mBitPaint; private Bitmap mBitmap; private int mTotalWidth, mTotalHeight; private int mBitWidth, mBitHeight; private Rect mSrcRect, mDestRect; private PorterDuffXfermode mXfermode; private Rect mDynamicRect; private int mCurrentTop; private int mStart, mEnd; public PoterDuffLoadingView(Context context) { super(context); mResources = getResources(); initBitmap(); initPaint(); initXfermode(); } private void initXfermode() { // 叠加处绘制源图 mXfermode = new PorterDuffXfermode(Mode.SRC_IN); } private void initPaint() { // 初始化paint mBitPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBitPaint.setFilterBitmap(true); mBitPaint.setDither(true); mBitPaint.setColor(Color.RED); } private void initBitmap() { // 初始化bitmap mBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.ga_studio)) .getBitmap(); mBitWidth = mBitmap.getWidth(); mBitHeight = mBitmap.getHeight(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 存为新图层 int saveLayerCount = canvas.saveLayer(0, 0, mTotalWidth, mTotalHeight, mBitPaint, Canvas.ALL_SAVE_FLAG); // 绘制目标图 canvas.drawBitmap(mBitmap, mSrcRect, mDestRect, mBitPaint); // 设置混合模式 mBitPaint.setXfermode(mXfermode); // 绘制源图形 canvas.drawRect(mDynamicRect, mBitPaint); // 清除混合模式 mBitPaint.setXfermode(null); // 恢复保存的图层； canvas.restoreToCount(saveLayerCount); // 改变Rect区域，真实情况下时提供接口传入进度，计算高度 mCurrentTop -= 8; if (mCurrentTop \u0026amp;lt;= mEnd) { mCurrentTop = mStart; } mDynamicRect.top = mCurrentTop; postInvalidate(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mTotalWidth = w; mTotalHeight = h; mSrcRect = new Rect(0, 0, mBitWidth, mBitHeight); // 让左边和上边有些距离 int left = (int) TypedValue.complexToDimension(20, mResources.getDisplayMetrics()); mDestRect = new Rect(left, left, left + mBitWidth, left + mBitHeight); mStart = left + mBitHeight; mCurrentTop = mStart; mEnd = left; mDynamicRect = new Rect(left, mStart, left + mBitWidth, left + mBitHeight); } } 二、采用混合模式过滤形状，实现水波纹：\n文章链接 －自定义view实现水波纹效果\nCSDN 源码下载地址：http://download.csdn.net/detail/tianjian4592/8571355\n","permalink":"https://blog.zdltech.com/posts/android-paint%E4%B9%8B-setxfermode-porterduffxfermode-%E8%AE%B2%E8%A7%A3androidsetxfermode/","summary":"\u003cp\u003e转载来自： \u003ca href=\"http://blog.csdn.net/tianjian4592\"\u003ehttp://blog.csdn.net/tianjian4592\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e前面关于paint的方法讲解里，讲到 setXfermode 就截止了，原因有两个：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e那篇文章已经太长了，我自己都看不下去了；\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e2. setXfermode 在paint 里占有至关重要的地位；\u003c/p\u003e\n\u003cp\u003e基于以上两个原因，我们一起来看看这个方法有何妙用。\u003c/p\u003e\n\u003cp\u003e首先我们还是来看看关于这个方法的说明：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * Set or clear the xfermode object. - 设置或清除xfermode对象;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * Pass null to clear any previous xfermode. - 传递null以清除任何以前的xfermode。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * As a convenience, the parameter passed is also returned. - 为方便起见，也返回传递的参数。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * @return         xfermode\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public Xfermode setXfermode(Xfermode xfermode) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        int xfermodeNative = 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        if (xfermode != null)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            xfermodeNative = xfermode.native_instance;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        native_setXfermode(mNativePaint, xfermodeNative);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mXfermode = xfermode;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return xfermode;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这个方法传进一个 Xfermode 对象，而打开 Xfermode 发现里面没有提供任何可用的构造函数或方法，ctrl ＋T 看到它有三个子类：\u003c/p\u003e","title":"Android Paint之 setXfermode PorterDuffXfermode 讲解，androidsetxfermode"},{"content":"转载请标明出处：http://blog.csdn.net/lmj623565791/article/details/39122981，本文出自【张鸿洋的博客】\n上一篇已经对ORMLite框架做了简单的介绍：Android ORMLite 框架的入门用法~~本篇将介绍项目可能会使用到的一些用法，也为我们的使用ORMLite框架总结出一个较合理的用法。\n通过上一篇的了解，我们使用ORMLite，需要自己写一个DatabaseHelper去继承OrmLiteSqliteOpenHelper，下面我们首先给出一个我认为比较靠谱的Helper的写法：\n1、DatabaseHelper **[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.db; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.sql.SQLException; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.HashMap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Map; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.database.sqlite.SQLiteDatabase; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.dao.Dao; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.support.ConnectionSource; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.table.TableUtils; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.bean.Article; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.bean.Student; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.bean.User; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; DatabaseHelper \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; OrmLiteSqliteOpenHelper - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TABLE_NAME = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sqlite-test.db\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Map\u0026lt;String, Dao\u0026gt; daos = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;String, Dao\u0026gt;(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; DatabaseHelper(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, TABLE_NAME, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(SQLiteDatabase database, - ConnectionSource connectionSource) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; - { - TableUtils.createTable(connectionSource, User.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - TableUtils.createTable(connectionSource, Article.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - TableUtils.createTable(connectionSource, Student.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SQLException e) - { - e.printStackTrace(); - } - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onUpgrade(SQLiteDatabase database, - ConnectionSource connectionSource, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldVersion, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; newVersion) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; - { - TableUtils.dropTable(connectionSource, User.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - TableUtils.dropTable(connectionSource, Article.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - TableUtils.dropTable(connectionSource, Student.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - onCreate(database, connectionSource); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SQLException e) - { - e.printStackTrace(); - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; DatabaseHelper instance; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 单例获取该Helper\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; DatabaseHelper getHelper(Context context) - { - context = context.getApplicationContext(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (instance == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; (DatabaseHelper.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (instance == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - instance = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DatabaseHelper(context); - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; instance; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; Dao getDao(Class clazz) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; SQLException - { - Dao dao = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - String className = clazz.getSimpleName(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (daos.containsKey(className)) - { - dao = daos.get(className); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (dao == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - dao = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.getDao(clazz); - daos.put(className, dao); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; dao; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 释放资源\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; close() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.close(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (String key : daos.keySet()) - { - Dao dao = daos.get(key); - dao = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - } - - } 1、整个DatabaseHelper使用单例只对外公布出一个对象，保证app中只存在一个SQLite Connection ， 参考文章：http://www.touchlab.co/2011/10/single-sqlite-connection/\n2、我们对每个Bean创建一个XXXDao来处理当前Bean的数据库操作，当然真正去和数据库打交道的对象，通过上面代码中的getDao（T t）进行获取\ngetDao为一个泛型方法，会根据传入Class对象进行创建Dao，并且使用一个Map来保持所有的Dao对象，只有第一次调用时才会去调用底层的getDao()。\n2、Bean的Dao **[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.db; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.sql.SQLException; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.dao.Dao; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.bean.User; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; UserDao - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Dao\u0026lt;User, Integer\u0026gt; userDaoOpe; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; DatabaseHelper helper; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; UserDao(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.context = context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; - { - helper = DatabaseHelper.getHelper(context); - userDaoOpe = helper.getDao(User.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SQLException e) - { - e.printStackTrace(); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 增加一个用户\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param user\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; add(User user) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; - { - userDaoOpe.create(user); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SQLException e) - { - e.printStackTrace(); - } - - }\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026amp;#8230;other operations\u0026lt;/span\u0026gt; - - - } 我们的所有的XXXDao遵循以上的风格~\n好了，基本了解了我们的代码的结构~~ps:如果觉得不合理可以留言指出，如果觉得不能接收，直接忽略。。。\n3、ORMLite外键引用 现在我们有两张表一张User，一张Article；\nArticle中当然需要存储User的主键，作为关联~~那么在ORMLite中如何做到呢？\n可能有人会直接在Article中声明一个int类型userId属性，当作普通属性处理搞定，这种做法并没有做，但是没有体现出面向对象的思想。\n面向对象是这样的：Article属于某个User\n类这么定义：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.bean; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.field.DatabaseField; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.table.DatabaseTable; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@DatabaseTable\u0026lt;/span\u0026gt;(tableName = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;tb_article\u0026amp;#8221;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; Article - { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@DatabaseField\u0026lt;/span\u0026gt;(generatedId = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@DatabaseField\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String title; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@DatabaseField\u0026lt;/span\u0026gt;(canBeNull = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, foreign = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, columnName = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;user_id\u0026amp;#8221;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; User user; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getId() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; id; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.id = id; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getTitle() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; title; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setTitle(String title) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.title = title; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; User getUser() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; user; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setUser(User user) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.user = user; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String toString() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Article [id=\u0026amp;#8221;\u0026lt;/span\u0026gt; + id + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;, title=\u0026amp;#8221;\u0026lt;/span\u0026gt; + title + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;, user=\u0026amp;#8221;\u0026lt;/span\u0026gt; + user - + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;]\u0026amp;#8221;\u0026lt;/span\u0026gt;; - } - - } 不会去定义一个int类型的userId，而是直接定义一个User成员变量，表示本Article属于该User;\n然后在User user属性上添加： @DatabaseField(canBeNull = true, foreign = true, columnName = “user_id”)\ncanBeNull -表示不能为null；foreign=true表示是一个外键;columnName 列名\nUser类暂且就两个属性：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.bean; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.field.DatabaseField; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.table.DatabaseTable; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@DatabaseTable\u0026lt;/span\u0026gt;(tableName = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;tb_user\u0026amp;#8221;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; User - { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@DatabaseField\u0026lt;/span\u0026gt;(generatedId = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@DatabaseField\u0026lt;/span\u0026gt;(columnName = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;name\u0026amp;#8221;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String name; - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; User() - { - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getId() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; id; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.id = id; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getName() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; name; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setName(String name) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.name = name; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String toString() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;User [id=\u0026amp;#8221;\u0026lt;/span\u0026gt; + id + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;, name=\u0026amp;#8221;\u0026lt;/span\u0026gt; + name - + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;]\u0026amp;#8221;\u0026lt;/span\u0026gt;; - } - - - - - - } 现在看我们的ArticleDao\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.db; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.sql.SQLException; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.dao.Dao; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.bean.Article; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.bean.User; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ArticleDao - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Dao\u0026lt;Article, Integer\u0026gt; articleDaoOpe; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; DatabaseHelper helper; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@SuppressWarnings\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;unchecked\u0026amp;#8221;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ArticleDao(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; - { - helper = DatabaseHelper.getHelper(context); - articleDaoOpe = helper.getDao(Article.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SQLException e) - { - e.printStackTrace(); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 添加一个Article\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param article\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; add(Article article) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; - { - articleDaoOpe.create(article); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SQLException e) - { - e.printStackTrace(); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 通过Id得到一个Article\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param id\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@SuppressWarnings\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;unchecked\u0026amp;#8221;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Article getArticleWithUser(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id) - { - Article article = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; - { - article = articleDaoOpe.queryForId(id); - helper.getDao(User.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;).refresh(article.getUser()); - - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SQLException e) - { - e.printStackTrace(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; article; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 通过Id得到一篇文章\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param id\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Article get(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id) - { - Article article = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; - { - article = articleDaoOpe.queryForId(id); - - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SQLException e) - { - e.printStackTrace(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; article; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 通过UserId获取所有的文章\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param userId\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; List\u0026lt;Article\u0026gt; listByUserId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; userId) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; articleDaoOpe.queryBuilder().where().eq(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;user_id\u0026amp;#8221;\u0026lt;/span\u0026gt;, userId) - .query(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SQLException e) - { - e.printStackTrace(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - - } 接下来看我们的测试类：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; OrmLiteDbTest \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; AndroidTestCase - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; testAddArticle() - { - User u = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; User(); - u.setName(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;张鸿洋\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; UserDao(getContext()).add(u); - Article article = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Article(); - article.setTitle(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;ORMLite的使用\u0026amp;#8221;\u0026lt;/span\u0026gt;); - article.setUser(u); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArticleDao(getContext()).add(article); - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; testGetArticleById() - { - Article article = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArticleDao(getContext()).get(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - L.e(article.getUser() + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; , \u0026amp;#8220;\u0026lt;/span\u0026gt; + article.getTitle()); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; testGetArticleWithUser() - { - - Article article = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArticleDao(getContext()).getArticleWithUser(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - L.e(article.getUser() + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; , \u0026amp;#8220;\u0026lt;/span\u0026gt; + article.getTitle()); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; testListArticlesByUserId() - { - - List\u0026lt;Article\u0026gt; articles = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArticleDao(getContext()).listByUserId(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - L.e(articles.toString()); - } 分别测试，添加一个Article；通过Id获取一个Article；通过Id获取一个Article且携带User；通过userId获取所有的Article；\n主要看第三个：通过Id获取一个Article且携带User，testGetArticleWithUser（id）\n如何值传一个Article的Id，然后能够拿到Article对象，且内部的user属性直接赋值呢？\n两种方式：\n1、即上述写法\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - article = articleDaoOpe.queryForId(id); - helper.getDao(User.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;).refresh(article.getUser()); 2、在user属性的注解上：@DatabaseField(canBeNull = true, foreign = true, columnName = “user_id”, foreignAutoRefresh = true)\n添加foreignAutoRefresh =true，这样；当调用queryForId时，拿到Article对象则直接携带了user；\n4、关联一个集合 每个User关联一个或多个Article，如果我在User中声明一个Collection articles，我能否在查询User的时候，一并能够获取到articles的值呢？\n答案是可以的。在User中添加如下属性，且注解如下：\n@ForeignCollectionField\nprivate Collection articles;\n我们在UserDao中书写查询User的代码：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; User get(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; userDaoOpe.queryForId(id); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SQLException e) - { - e.printStackTrace(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; ; - } 测试代码：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; testGetUserById() - { - User user = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; UserDao(getContext()).get(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - L.e(user.getName()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (user.getArticles() != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (Article article : user.getArticles()) - { - L.e(article.toString()); - } - } 输出：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_10\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_10\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 可以看到，我们通过一个queryForId，成功的获取了User，以及User关联的所有的Articles；\n5、条件查询QueryBuilder的使用 上述代码其实已经用到了简单的条件查询了：\n1、简单的where等于\narticleDaoOpe.queryBuilder().where().eq(“user_id”, userId).query();直接返回Article的列表\n2、where and\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_11\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_11\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - QueryBuilder\u0026lt;Article, Integer\u0026gt; queryBuilder = articleDaoOpe - .queryBuilder(); - Where\u0026lt;Article, Integer\u0026gt; where = queryBuilder.where(); - where.eq(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;user_id\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - where.and(); - where.eq(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;name\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;xxx\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//或者\u0026lt;/span\u0026gt; - articleDaoOpe.queryBuilder().\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt; - where().\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt; - eq(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;user_id\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;).and().\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt; - eq(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;name\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;xxx\u0026amp;#8221;\u0026lt;/span\u0026gt;); 上述两种都相当与：select * from tb_article where user_id = 1 and name = ‘xxx’ ;\n3、更复杂的查询\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_12\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_12\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - where.or( - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt; - where.and(\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt; - where.eq(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;user_id\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;), where.eq(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;name\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;xxx\u0026amp;#8221;\u0026lt;/span\u0026gt;)), - where.and(\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt; - where.eq(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;user_id\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;), where.eq(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;name\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;yyy\u0026amp;#8221;\u0026lt;/span\u0026gt;))); select * from tb_article where ( user_id = 1 and name = ‘xxx’ ) or ( user_id = 2 and name = ‘yyy’ ) ;\n好了，再复杂的查询估计也能够凑出来了~~\n6、updateBuilder、deleteBuilder 使用queryBuilder是因为我们希望执行完成查询直接返回List集合；\n对于Update我们并不关注返回值，直接使用\narticleDaoOpe.updateRaw(statement, arguments);传入sql和参数即可~~\n何必在那articleDaoOpe.updateBuilder().updateColumnValue(“name”,”zzz”).where().eq(“user_id”, 1);这样的痛苦呢~~~\n同理还有deleteBuilder还是建议直接拼写sql，当然很简单的除外，直接使用它的API~\n7、事务操作 在我们的Dao中直接写如下代码：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_13\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_13\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//事务操作\u0026lt;/span\u0026gt; - TransactionManager.callInTransaction(helper.getConnectionSource(), - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Callable\u0026lt;Void\u0026gt;() - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Void call() \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; Exception - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - }); 8、其他操作 1、当Bean继承BaseDaoEnabled时，可以使用bean.create(bean)；bean.update(bean)一类操作\n例如：\nStudent extends BaseDaoEnabled\u0026lt;Student, Integer\u0026gt;\nDao dao = DatabaseHelper.getHelper(getContext()).getDao(Student.class);\nStudent student = new Student();\nstudent.setDao(dao);\nstudent.setName(“张鸿洋”);\nstudent.create();\n前提dao需要手动设置，如果dao为null会报错，尼玛，我觉得一点用没有。。。\n2、Join\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_14\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_14\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - QueryBuilder\u0026lt;Article, Integer\u0026gt; articleBuilder = articleDaoOpe - .queryBuilder(); - QueryBuilder userBuilder = helper.getDao(User.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;).queryBuilder(); - articleBuilder.join(userBuilder); Article与User做Join操作；\n本篇主要想介绍在项目中如何写DataBaseHelper已经如何写BeanDao，以及列出了在项目中可能会用到的ORMLite的功能，如果需要详细了解，还请看ORMLite官方文档，源码中也会提供~~\n源码点击下载\n","permalink":"https://blog.zdltech.com/posts/android-%E5%BF%AB%E9%80%9F%E5%BC%80%E5%8F%91%E7%B3%BB%E5%88%97-ormlite-%E6%A1%86%E6%9E%B6%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/","summary":"\u003cp\u003e转载请标明出处：\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/39122981\"\u003ehttp://blog.csdn.net/lmj623565791/article/details/39122981\u003c/a\u003e，本文出自【张鸿洋的博客】\u003c/p\u003e\n\u003cp\u003e上一篇已经对ORMLite框架做了简单的介绍：\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/39121377\"\u003eAndroid ORMLite 框架的入门用法\u003c/a\u003e~~本篇将介绍项目可能会使用到的一些用法，也为我们的使用ORMLite框架总结出一个较合理的用法。\u003c/p\u003e\n\u003cp\u003e通过上一篇的了解，我们使用ORMLite，需要自己写一个DatabaseHelper去继承OrmLiteSqliteOpenHelper，下面我们首先给出一个我认为比较靠谱的Helper的写法：\u003c/p\u003e\n\u003ch1 id=\"1databasehelper\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003e1、DatabaseHelper\u003c/h1\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39122981#)[copy](http://blog.csdn.net/lmj623565791/article/details/39122981#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/465469)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/465469/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.db;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.sql.SQLException;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.HashMap;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Map;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.database.sqlite.SQLiteDatabase;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.dao.Dao;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.support.ConnectionSource;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.j256.ormlite.table.TableUtils;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.bean.Article;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.bean.Student;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.zhy_ormlite.bean.User;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; DatabaseHelper \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; OrmLiteSqliteOpenHelper\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TABLE_NAME = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sqlite-test.db\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Map\u0026lt;String, Dao\u0026gt; daos = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;String, Dao\u0026gt;();\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; DatabaseHelper(Context context)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, TABLE_NAME, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(SQLiteDatabase database,\n\n- ConnectionSource connectionSource)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt;\n\n- {\n\n- TableUtils.createTable(connectionSource, User.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- TableUtils.createTable(connectionSource, Article.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- TableUtils.createTable(connectionSource, Student.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SQLException e)\n\n- {\n\n- e.printStackTrace();\n\n- }\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onUpgrade(SQLiteDatabase database,\n\n- ConnectionSource connectionSource, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldVersion, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; newVersion)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt;\n\n- {\n\n- TableUtils.dropTable(connectionSource, User.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n\n- TableUtils.dropTable(connectionSource, Article.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n\n- TableUtils.dropTable(connectionSource, Student.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n\n- onCreate(database, connectionSource);\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (SQLException e)\n\n- {\n\n- e.printStackTrace();\n\n- }\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; DatabaseHelper instance;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 单例获取该Helper\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param context\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; DatabaseHelper getHelper(Context context)\n\n- {\n\n- context = context.getApplicationContext();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (instance == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; (DatabaseHelper.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (instance == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)\n\n- instance = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DatabaseHelper(context);\n\n- }\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; instance;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; Dao getDao(Class clazz) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; SQLException\n\n- {\n\n- Dao dao = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n- String className = clazz.getSimpleName();\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (daos.containsKey(className))\n\n- {\n\n- dao = daos.get(className);\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (dao == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)\n\n- {\n\n- dao = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.getDao(clazz);\n\n- daos.put(className, dao);\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; dao;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 释放资源\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; close()\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.close();\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (String key : daos.keySet())\n\n- {\n\n- Dao dao = daos.get(key);\n\n- dao = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n- }\n\n- }\n\n- \n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e1、整个DatabaseHelper使用单例只对外公布出一个对象，保证app中只存在一个SQLite Connection ， 参考文章：http://www.touchlab.co/2011/10/single-sqlite-connection/\u003c/p\u003e","title":"Android 快速开发系列 ORMLite 框架最佳实践"},{"content":"Android系统的“程序异常退出”，给应用的用户体验造成不良影响。为了捕获应用运行时异常并给出友好提示，便可继承UncaughtExceptionHandler类来处理。通过Thread.setDefaultUncaughtExceptionHandler()方法将异常处理类设置到线程上即可。\n1、异常处理类，代码如下：\n**[java]** [view plain](http://blog.csdn.net/hehe9737/article/details/7662123#)[copy](http://blog.csdn.net/hehe9737/article/details/7662123#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; CrashHandler \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; UncaughtExceptionHandler { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;CrashHandler\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; CrashHandler INSTANCE = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; CrashHandler(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context mContext; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Thread.UncaughtExceptionHandler mDefaultHandler; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; CrashHandler() { - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; CrashHandler getInstance() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; INSTANCE; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; init(Context ctx) { - mContext = ctx; - mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); - Thread.setDefaultUncaughtExceptionHandler(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; uncaughtException(Thread thread, Throwable ex) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// if (!handleException(ex) \u0026amp;\u0026amp; mDefaultHandler != null) {\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// mDefaultHandler.uncaughtException(thread, ex);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// } else {\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// android.os.Process.killProcess(android.os.Process.myPid());\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// System.exit(10);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// }\u0026lt;/span\u0026gt; - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;uncaughtException\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Thread() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - Looper.prepare(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AlertDialog.Builder(mContext).setTitle(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;提示\u0026amp;#8221;\u0026lt;/span\u0026gt;).setCancelable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;) - .setMessage(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;程序崩溃了\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;).setNeutralButton(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;我知道了\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(DialogInterface dialog, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; which) { - System.exit(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - } - }) - .create().show(); - Looper.loop(); - } - }.start(); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. 开发者可以根据自己的情况来自定义异常处理逻辑\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param ex\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return true:如果处理了该异常信息;否则返回false\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; handleException(Throwable ex) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (ex == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// new Handler(Looper.getMainLooper()).post(new Runnable() {\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// @Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// public void run() {\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// new AlertDialog.Builder(mContext).setTitle(\u0026amp;#8220;提示\u0026amp;#8221;)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// .setMessage(\u0026amp;#8220;程序崩溃了\u0026amp;#8230;\u0026amp;#8221;).setNeutralButton(\u0026amp;#8220;我知道了\u0026amp;#8221;, null)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// .create().show();\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// }\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// });\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - } 2、线程绑定异常处理类\n**[java]** [view plain](http://blog.csdn.net/hehe9737/article/details/7662123#)[copy](http://blog.csdn.net/hehe9737/article/details/7662123#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; CrashHandlerActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** Called when the activity is first created. */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.main); - CrashHandler crashHandler = CrashHandler.getInstance(); - crashHandler.init(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//传入参数必须为Activity，否则AlertDialog将不显示。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 创建错误\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throw\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; NullPointerException(); - } - } **Demo下载地址：**http://code.google.com/p/android-custom-view/downloads/list\n转载地址: http://orgcent.com/android-uncaughtexceptionhandler-exception/ | 萝卜白菜的博客\n","permalink":"https://blog.zdltech.com/posts/android%E4%BD%BF%E7%94%A8uncaughtexceptionhandler%E6%8D%95%E8%8E%B7%E5%85%A8%E5%B1%80%E5%BC%82%E5%B8%B8/","summary":"\u003cp\u003eAndroid系统的“程序异常退出”，给应用的用户体验造成不良影响。为了捕获应用运行时异常并给出友好提示，便可继承\u003ca href=\"http://orgcent.com/tag/UncaughtExceptionHandler/\"\u003eUncaughtExceptionHandler\u003c/a\u003e类来处理。通过Thread.setDefaultUncaughtExceptionHandler()方法将异常处理类设置到线程上即可。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1、异常处理类，代码如下：\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/hehe9737/article/details/7662123#)[copy](http://blog.csdn.net/hehe9737/article/details/7662123#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; CrashHandler \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; UncaughtExceptionHandler {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;CrashHandler\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; CrashHandler INSTANCE = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; CrashHandler();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context mContext;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Thread.UncaughtExceptionHandler mDefaultHandler;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; CrashHandler() {\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; CrashHandler getInstance() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; INSTANCE;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; init(Context ctx) {\n\n- mContext = ctx;\n\n- mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();\n\n- Thread.setDefaultUncaughtExceptionHandler(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; uncaughtException(Thread thread, Throwable ex) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// if (!handleException(ex) \u0026amp;\u0026amp; mDefaultHandler != null) {\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// mDefaultHandler.uncaughtException(thread, ex);\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// } else {\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// android.os.Process.killProcess(android.os.Process.myPid());\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// System.exit(10);\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// }\u0026lt;/span\u0026gt;\n\n- System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;uncaughtException\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Thread() {\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() {\n\n- Looper.prepare();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AlertDialog.Builder(mContext).setTitle(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;提示\u0026amp;#8221;\u0026lt;/span\u0026gt;).setCancelable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;)\n\n- .setMessage(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;程序崩溃了\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;).setNeutralButton(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;我知道了\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(DialogInterface dialog, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; which) {\n\n- System.exit(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- }\n\n- })\n\n- .create().show();\n\n- Looper.loop();\n\n- }\n\n- }.start();\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. 开发者可以根据自己的情况来自定义异常处理逻辑\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     *\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param ex\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return true:如果处理了该异常信息;否则返回false\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; handleException(Throwable ex) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (ex == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// new Handler(Looper.getMainLooper()).post(new Runnable() {\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// @Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// public void run() {\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// new AlertDialog.Builder(mContext).setTitle(\u0026amp;#8220;提示\u0026amp;#8221;)\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// .setMessage(\u0026amp;#8220;程序崩溃了\u0026amp;#8230;\u0026amp;#8221;).setNeutralButton(\u0026amp;#8220;我知道了\u0026amp;#8221;, null)\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// .create().show();\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// }\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// });\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003e2、线程绑定异常处理类\u003c/strong\u003e\u003c/p\u003e","title":"Android使用UncaughtExceptionHandler捕获全局异常"},{"content":"大标题 大标题一般显示工程名,类似html的\u0026lt;h1\u0026gt;\n你只要在标题下面跟上=====即可\n中标题\n———————————–\n中标题一般显示重点项,类似html的\u0026lt;h2\u0026gt;\n你只要在标题下面输入——即可\n### 小标题\n小标题类似html的\u0026lt;h3\u0026gt;\n小标题的格式如下 ### 小标题\n注意#和标题字符中间要有空格\n### 注意!!!下面所有语法的提示我都先用小标题提醒了!!!\n### 单行文本框\n这是一个单行的文本框,只要两个Tab再输入文字即可\n### 多行文本框\n这是一个有多行的文本框\n你可以写入代码等,每行文字只要输入两个Tab再输入文字即可\n这里你可以输入一段代码\n### 比如我们可以在多行文本框里输入一段代码,来一个Java版本的HelloWorld吧\npublic class HelloWorld {\n/**\n@param args\n*/\npublic static void main(String[] args) {\nSystem.out.println(“HelloWorld!”); }\n}\n### 链接\n1.[点击这里你可以链接到www.google.com](http://www.google.com)\n2.[点击这里我你可以链接到我的博客](http://guoyunsky.iteye.com)\n###只是显示图片\n![github](http://github.com/unicorn.png “github”)\n###想点击某个图片进入一个网页,比如我想点击github的icorn然后再进入www.github.com\n[![image]](http://www.github.com/)\n[image]: http://github.com/github.png “github”\n### 文字被些字符包围\n文字被些字符包围\n只要再文字前面加上\u0026gt;空格即可\n如果你要换行的话,新起一行,输入\u0026gt;空格即可,后面不接文字\n但\u0026gt; 只能放在行首才有效\n### 文字被些字符包围,多重包围\n文字被些字符包围开始\n只要再文字前面加上\u0026gt;空格即可\n如果你要换行的话,新起一行,输入\u0026gt;空格即可,后面不接文字\n但\u0026gt; 只能放在行首才有效\n### 特殊字符处理\n有一些特殊字符如\u0026lt;,#等,只要在特殊字符前面加上转义字符\\即可\n你想换行的话其实可以直接用html标签\u0026lt;br /\u0026gt;\n以下转自:http://www.tuicool.com/articles/zIJrEjn\n自从开始玩GitHub以来，就 越来越 感觉它有爱。最近对它的 README.md 文件颇为感兴趣。便写下这贴，帮助更多的还不会编写README文件的同学们。\nREADME文件后缀名为md。md是markdown的缩写，markdown是一种编辑博客的语言。用惯了可视化的博客编辑器（比如CSDN博客，囧），这种编程式的博客编辑方案着实让人眼前一亮。不过貌似并不支持全部的markdown语法。本文内容大部分是我自己摸索，可能有些叙述不准确，还望大家批评指正。\n————————————————————————————\n我在GitHub上为本文建的一个项目，供大家查看代码即具体效果：https://github.com/guodongxiaren/test\n首先强烈建议一条，不要用360或搜狗浏览器访问GitHub网站，你会发现此时网站上很多按钮都不可用。。建议使用火狐或谷歌浏览器访问GitHub\n————————————————————————————\n开始编辑README 打开你的GitHub的某个项目，我们可以直接在线编辑你的README文件，如果你已经有了这个文件，则在文件目录中直接点击它，如果你还没有这个文件那么点击项目名称右边的一个按钮，来添加新文件：\n然后你就打开了编辑页面，编辑区的左上角有填写文件名的区域，注意加上后缀**.md**\n如果你本来就有这个文件要重新编辑它的话，那么在点击了文件目录中的该文件后，在上方有工具栏，选择 Edit\n然后滚动屏幕到下面， 如果是新文件 会有一个 Commit new file 的按钮，若没有内容是不能点击的。如果是旧文件重修编辑，那么这个按钮显示的是 Commit changes\n**\n**\n//顺便吐槽一句如果是360或搜狗浏览器的话，这个按钮是永远都无法点击的，囧。。\n先随便写的东西把这个新文件提交，然后再点击 Edit 重新打开它。你会发现编辑区左上角有了变化。\n默认选中Code，即我们的编辑模式。若点击 Preview（预览）就能实时显示当前的显示效果了。\n好了，下面正式开始编辑这个文件\n关于标题 规范的README文件开头都写上一个标题，这被称为大标题 。\n大标题 ==== 在文本下面加上 等于号 = ，那么上方的文本就变成了大标题。等于号的个数无限制，但一定要大于0个哦。。\n比大标题低一级的是中标题，也就是显示出来比大标题小点。\n中标题 \u0026lt;span class=\u0026#34;header\u0026#34;\u0026gt;-------\u0026lt;/span\u0026gt; 在文本下面加上 下划线 – ，那么上方的文本就变成了中标题，同样的 下划线个数无限制。\n除此以外，关于标题还有等级表示法，分为六个等级，显示的文本大小依次减小。不同等级之间是以井号 # 的个数来标识的。一级标题有一个 #，二级标题有两个# ，以此类推。\n\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;#一级标题\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;##二级标题\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;###三级标题\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;####四级标题\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;#####五级标题\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;######六级标题\u0026lt;/span\u0026gt; 注意井号#和标题名称要并排写作一行，显示效果如图：\n实际上，前文所述的大标题和中标题是分别和一级标题和二级标题对应的。即大标题大小和一级标题相同，中标题大小和二级标题相同。\n显示文本 普通文本 直接输入的文字就是普通文本。需要注意的是要换行的时候不能直接通过回车来换行，需要使用 。也就是html里面的标签 。\n这是一段普通的文本， 直接回车不能换行，\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;br\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; 要使用\\\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;br\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; 注意第三行的 前加了反斜杠 \\ 。目的就是像其他语言那样实现转义，也就是 \u0026lt; 的转义。\n效果如图：\n此外，要显示一个 超链接 的话，就直接输入这个链接的URL就好了。显示出来会自动变成可链接的形式的。\n单行文本 使用两个Tab符实现单行文本。\n\u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;Hello,大家好，我是果冻虾仁。\u0026lt;/span\u0026gt; 注意前面有两个Tab。在GitHub上单行文本显示效果如图：\n多行文本 多行文本和单行文本异曲同工，只要在每行行首加两个Tab\n欢迎到访 很高兴见到您 祝您，早上好，中午好，下午好，晚安 部分文字的高亮 如果你想使一段话中部分文字高亮显示，来起到突出强调的作用，那么可以把它用 ` ` 包围起来。注意这不是单引号，而是Tab上方，数字1左边的按键（注意使用英文输入法）。\nThank `You` . Please `Call` Me `Coder`\n文字超链接 给一段文字加入超链接的格式是这样的 [ 要显示的文字 ]( 链接的地址 )。比如：\n[我的博客](http:\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//blog.csdn.net/guodongxiaren)\u0026lt;/span\u0026gt; 显示效果：\n你还可以给他加上一个鼠标悬停显示的文本。\n[我的博客](http:\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//blog.csdn.net/guodongxiaren \u0026#34;悬停显示\u0026#34;)\u0026lt;/span\u0026gt; 即在URL之后 用双引号括起来一个字符串。同样要注意这里是英文双引号。\n插入符号 圆点符 这是一个圆点符 这也是一个圆点符 上面这段的圆点是CSDN博客编辑器里面的符号列表。写文章在列出条目时经常用到。在GitHub的markdown语法里也支持使用圆点符。编辑的时候使用的是星号 *\n* 昵称：果冻虾仁 * 别名：隔壁老王 * 英文名：Jelly 要注意的是星号* 后面要有一个空格。否则显示为普通星号。上文的显示效果如图：\n此外还有二级圆点和三级圆点。就是多加一个Tab。\n* 编程语言 * 脚本语言 * Python 第二行一个Tab，第三行两个Tab。这样用来表示层级结构就更清晰了吧，看效果：\n如果你觉得三级的结构还不够表达清楚的话，我们可以试着换一种形式，请看 字符包围\n字符包围 我不知道称之为“字符包围”是否贴切。我也是看的网上有一篇博文是这样称呼的，我就姑且也这样称呼吧。囧。。\n\u0026amp;gt;数据结构 \u0026amp;gt;\u0026amp;gt;树 \u0026amp;gt;\u0026amp;gt;\u0026amp;gt;二叉树 \u0026amp;gt;\u0026amp;gt;\u0026amp;gt;\u0026amp;gt;平衡二叉树 \u0026amp;gt;\u0026amp;gt;\u0026amp;gt;\u0026amp;gt;\u0026amp;gt;满二叉树 显示效果：\n具体这个“字符包围”的用法可能还有其他用法。大家自己摸索吧。\n插入图片 来源于网络的图片 网上有很多README插入图片的教程了，经我自己多次测试呢，发现可以使用的最简单，最基本的语法是：\n![](\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;http:\u0026lt;/span\u0026gt;/\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/www.baidu.com/img\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/bdlogo.gif)\u0026lt;/span\u0026gt; 即 叹号! + 方括号[ ] + 括号( ) 其中叹号里是图片的URL。\n如果不加叹号! ,就会变成普通文本baidu了。\n在方括号里可以加入一些 标识性的信息，比如\n![baidu](\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;http:\u0026lt;/span\u0026gt;/\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/www.baidu.com/img\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/bdlogo.gif)\u0026lt;/span\u0026gt; 这个方括号里的baidu并不会对图像显示造成任何改动，如果你想达到 鼠标悬停 显示提示信息，那么可以仿照前面介绍的文本中的方法，就是这样：\n![baidu](\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;http:\u0026lt;/span\u0026gt;/\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/www.baidu.com/img\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/bdlogo.gif \u0026#34;百度logo\u0026#34;)\u0026lt;/span\u0026gt; 在URL后面，加一个双引号包围的字符串，显示效果如图：\nGitHub仓库里的图片 有时候我们想显示一个GitHub仓库(或者说项目)里的图片而不是一张其他来源网络图片，因为其他来源的URL很可能会失效。那么如何显示一个GitHub项目里的图片呢？\n其实与上面的格式基本一致的，所不同的就是括号里的URL该怎么写。\n** https://github.com** / 你的用户名 / 你的项目名 / raw / 分支名 / 存放图片的文件夹**/** 该文件夹下的图片\n这样一目了然了吧。比如：\n![](\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;https:\u0026lt;/span\u0026gt;/\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/github.com/guodongxiaren\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/ImageCache/raw\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;/master/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;Logo\u0026lt;/span\u0026gt;/foryou.gif) 我在GitHub上的用户名guodongxiaren；有一个项目ImageCache；raw表示原数据的意思吧，不用管它；主分支master；项目里有一个文件夹Logo；Logo文件夹下有一张图片foryou.gif\n给图片加上超链接 如果你想使图片带有超链接的功能，即点击一个图片进入一个指定的网页。那么可以这样写：\n[![baidu]](http:\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//baidu.com)\u0026lt;/span\u0026gt; [baidu]:http:\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//www.baidu.com/img/bdlogo.gif \u0026#34;百度Logo\u0026#34;\u0026lt;/span\u0026gt; 这两句和前面的写法差异较大，但是也极易模仿着写出，就不过多介绍了。只需注意上下文中的 baidu 是你自己起的标识的名称，可以随意，但是一定要保证上下两行的 标识 是一致的。\n这样就能实现 点击图片进入网页的功能了。\n插入代码片段 我们需要在代码的上一行和下一行用` “ 标记。“` 不是三个单引号，而是数字1左边，Tab键上面的键。要实现语法高亮那么只要在 “` 之后加上你的编程语言即可（忽略大小写）。c++语言可以写成c++也可以是cpp。看代码：\n实际显示效果\n[题外话]在GitHub上用Gist写日记吧 看了这么多markdown的语法，你一定不满足于仅仅写一个README文件了，开始跃跃欲试想实际用markdown语法来编写博客或文章了吧。的确，网上也有依托或者支持markdown语法的博客。但是呢，更方便的是，你可以借助GitHub本身就有的一个功能——Gist。\nGist是以文件为单位的，不是以项目为单位的。而且与普通的GitHub上建的仓库不同，Gist是private的哦。普通的项目默认都是public的，要想弄成private貌似还要交钱的样子。既然是private那么用来写写日记，是极好的。\nGitHub网页的顶部有 ：\n点进去:\n这就是你可以编辑的私有文件，它不仅支持Text文本，还支持各种编程语言呢！当然也包括markdown。输入文件名：\n最后保存，选中 Create Secret Gist 就是私有的喽。\n","permalink":"https://blog.zdltech.com/posts/github%E4%B8%8Areadme-md%E4%BB%8B%E7%BB%8D/","summary":"\u003ch1 id=\"大标题\"\u003e大标题\u003c/h1\u003e\n\u003cp\u003e大标题一般显示工程名,类似html的\u0026lt;h1\u0026gt;\u003c/p\u003e\n\u003cp\u003e你只要在标题下面跟上=====即可\u003cbr\u003e\n中标题\u003cbr\u003e\n———————————–\u003cbr\u003e\n中标题一般显示重点项,类似html的\u0026lt;h2\u0026gt;\u003c/p\u003e\n\u003cp\u003e你只要在标题下面输入——即可\u003c/p\u003e\n\u003cp\u003e### 小标题\u003cbr\u003e\n小标题类似html的\u0026lt;h3\u0026gt;\u003c/p\u003e\n\u003cp\u003e小标题的格式如下 ### 小标题\u003c/p\u003e\n\u003cp\u003e注意#和标题字符中间要有空格\u003c/p\u003e\n\u003cp\u003e### 注意!!!下面所有语法的提示我都先用小标题提醒了!!!\u003c/p\u003e\n\u003cp\u003e### 单行文本框\u003cbr\u003e\n这是一个单行的文本框,只要两个Tab再输入文字即可\u003c/p\u003e\n\u003cp\u003e### 多行文本框\u003cbr\u003e\n这是一个有多行的文本框\u003cbr\u003e\n你可以写入代码等,每行文字只要输入两个Tab再输入文字即可\u003cbr\u003e\n这里你可以输入一段代码\u003c/p\u003e\n\u003cp\u003e### 比如我们可以在多行文本框里输入一段代码,来一个Java版本的HelloWorld吧\u003cbr\u003e\npublic class HelloWorld {\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e@param args\u003cbr\u003e\n*/\u003cbr\u003e\npublic static void main(String[] args) {\u003cbr\u003e\nSystem.out.println(“HelloWorld!”);\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e}\u003cbr\u003e\n### 链接\u003cbr\u003e\n1.[点击这里你可以链接到www.google.com](\u003ca href=\"http://www.google.com\"\u003ehttp://www.google.com\u003c/a\u003e)\u003c/p\u003e\n\u003cp\u003e2.[点击这里我你可以链接到我的博客](\u003ca href=\"http://guoyunsky.iteye.com\"\u003ehttp://guoyunsky.iteye.com\u003c/a\u003e)\u003c/p\u003e\n\u003cp\u003e###只是显示图片\u003cbr\u003e\n![github](\u003ca href=\"http://github.com/unicorn.png\"\u003ehttp://github.com/unicorn.png\u003c/a\u003e “github”)\u003c/p\u003e\n\u003cp\u003e###想点击某个图片进入一个网页,比如我想点击github的icorn然后再进入www.github.com\u003cbr\u003e\n[![image]](\u003ca href=\"http://www.github.com/\"\u003ehttp://www.github.com/\u003c/a\u003e)\u003cbr\u003e\n[image]: \u003ca href=\"http://github.com/github.png\"\u003ehttp://github.com/github.png\u003c/a\u003e “github”\u003c/p\u003e\n\u003cp\u003e### 文字被些字符包围\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e文字被些字符包围\u003c/p\u003e\n\u003cp\u003e只要再文字前面加上\u0026gt;空格即可\u003c/p\u003e\n\u003cp\u003e如果你要换行的话,新起一行,输入\u0026gt;空格即可,后面不接文字\u003cbr\u003e\n但\u0026gt; 只能放在行首才有效\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e### 文字被些字符包围,多重包围\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e文字被些字符包围开始\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e只要再文字前面加上\u0026gt;空格即可\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e如果你要换行的话,新起一行,输入\u0026gt;空格即可,后面不接文字\u003c/p\u003e\u003c/blockquote\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cblockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e但\u0026gt; 只能放在行首才有效\u003c/p\u003e\u003c/blockquote\u003e\u003c/blockquote\u003e\u003c/blockquote\u003e\u003c/blockquote\u003e\n\u003cp\u003e### 特殊字符处理\u003cbr\u003e\n有一些特殊字符如\u0026lt;,#等,只要在特殊字符前面加上转义字符\\即可\u003c/p\u003e","title":"Github上README.md介绍"},{"content":"首页创建Android studio项目\n在项目的build.gradle中添加如下代码（如此简单）\nbuildscript {\nrepositories {\nmavenCentral()\n}\ndependencies {\n// replace with the current version of the Android plugin\nclasspath ‘com.android.tools.build:gradle:1.2.3’\n// the latest version of the android-apt plugin\nclasspath ‘com.neenbedankt.gradle.plugins:android-apt:1.4’\n}\n}\nrepositories {\nmavenCentral()\nmavenLocal()\n}\napply plugin: ‘com.android.application’\napply plugin: ‘android-apt’\ndef AAVersion = ‘3.3.2’//这个是Annotations的版本号，这个可以去Annotations官网查看，也可以在Android studio中Jcenter或者mavenCentral中查找最新版本号\ndependencies {\ncompile fileTree(include: [‘*.jar’], dir: ‘libs’)\ncompile ‘com.android.support:appcompat-v7:22.2.0’\napt “org.androidannotations:androidannotations:AAVersion” compile “org.androidannotations:androidannotations-api:AAVersion”\n}\napt {\narguments {\nandroidManifestFile variant.outputs[0].processResources.manifestFile\n// if you have multiple outputs (when using splits), you may want to have other index than 0\n// you should set your package name here if you are using different application IDs\n// resourcePackageName “your.package.name”\n// You can set optional annotation processing options here, like these commented options:\n// logLevel ‘INFO’\n// logFile ‘/var/log/aa.log’\n}\n}\n到此配置完成，android studio就可以使用Annotations框架了。\n这要注意：所有的方法和变量在使用注解时不能声明为 private，在Android minfaset文件中配置Activity、service等名称的后面添加上“_”（下划线，这个是框架编译时使用）\n接下来就是使用注解了。\n这里给列出支持的注解\nEnhanced components @EActivity{.internal.present} @EApplication{.internal.present} @EBean{.internal.present} @EFragment{.internal.present} @EProvider{.internal.present} @EReceiver{.internal.present} @EIntentService{.internal.present} @EService{.internal.present} @EView{.internal.present} @EViewGroup{.internal.present} {#user-content-injection.anchor}Injection @AfterExtras{.internal.present} @AfterInject{.internal.present} @AfterViews{.internal.present} @App{.internal.present} @Bean{.internal.present} @Extra{.internal.present} @FragmentArg{.internal.present} @FragmentById{.internal.present} @FragmentByTag{.internal.present} @FromHtml{.internal.present} @HttpsClient{.internal.present} @NonConfigurationInstance{.internal.present} @RootContext{.internal.present} @SystemService{.internal.present} @ViewById{.internal.present} @ViewsById{.internal.present} {#user-content-event-binding.anchor}Event binding @TextChange{.internal.present} @AfterTextChange{.internal.present} @BeforeTextChange{.internal.present} @EditorAction{.internal.present} @FocusChange{.internal.present} @CheckedChange{.internal.present} @Touch{.internal.present} @Click{.internal.present} @LongClick{.internal.present} @ItemClick{.internal.present} @ItemLongClick{.internal.present} @ItemSelect{.internal.present} @OptionsItem{.internal.present} @SeekBarProgressChange{.internal.present} @SeekBarTouchStart{.internal.present} @SeekBarTouchStop{.internal.present} {#user-content-threading.anchor}Threading @Background{.internal.present} @UiThread{.internal.present} @SupposeBackground{.internal.present} @SupposeUiThread{.internal.present} {#user-content-misc.anchor}Misc @InstanceState{.internal.present} @WindowFeature{.internal.present} @Fullscreen{.internal.present} @CustomTitle{.internal.present} @InjectMenu{.internal.present} @OptionsMenu{.internal.present} @OptionsMenuItem{.internal.present} @OrmLiteDao{.internal.present} @RoboGuice{.internal.present} @Trace{.internal.present} @Transactional{.internal.present} @OnActivityResult{.internal.present} @OnActivityResult.Extra{.internal.present} @HierarchyViewerSupport{.internal.present} @ServiceAction{.internal.present} @Receiver{.internal.present} @Receiver.Extra{.internal.present} @ReceiverAction{.internal.present} @ReceiverAction.Extra{.internal.present} @IgnoredWhenDetached{.internal.present} @WakeLock{.internal.present} {#user-content-resource-injection.anchor}Resource injection @StringRes{.internal.present} @AnimationRes{.internal.present} @ColorRes{.internal.present} @DimensionPixelOffsetRes{.internal.present} @DimensionPixelSizeRes{.internal.present} @DimensionRes{.internal.present} @BooleanRes{.internal.present} @ColorStateListRes{.internal.present} @DrawableRes{.internal.present} @IntArrayRes{.internal.present} @IntegerRes{.internal.present} @LayoutRes{.internal.present} @MovieRes{.internal.present} @StringArrayRes{.internal.present} @TextArrayRes{.internal.present} @TextRes{.internal.present} @HtmlRes{.internal.present} {#user-content-rest-api.anchor}Rest API @Rest{.internal.present} @RestService{.internal.present} @Get{.internal.present} @Post{.internal.present} @Put{.internal.present} @Delete{.internal.present} @Options{.internal.present} @Head{.internal.present} @Accept{.internal.present} @RequiresHeader{.internal.present} @RequiresCookie{.internal.present} @RequiresCookieInUrl{.internal.present} @RequiresAuthentication{.internal.present} @SetsCookie{.internal.present} @RequiresCookieInUrl{.internal.present} {#user-content-typesafe-sharedpreferences.anchor}Typesafe SharedPreferences @DefaultBoolean{.internal.present} @DefaultFloat{.internal.present} @DefaultInt{.internal.present} @DefaultLong{.internal.present} @DefaultString{.internal.present} @DefaultStringSet{.internal.present} @DefaultRes{.internal.present} @Pref{.internal.present} @SharedPref{.internal.present} {#user-content-preference-api-helpers.anchor}Preference API helpers @PreferenceScreen{.internal.present} @PreferenceHeaders{.internal.present} @PreferenceByKey{.internal.present} @PreferenceChange{.internal.present} @PreferenceClick{.internal.present} @AfterPreferences{.internal.present} 框架官网网站：https://github.com/excilys/androidannotations/wiki/AvailableAnnotations\n转自请注明：http://www.etongwl.com/archives/956.html\n","permalink":"https://blog.zdltech.com/posts/android-studio%E4%BD%BF%E7%94%A8annotations%E6%A1%86%E6%9E%B6/","summary":"\u003cp\u003e首页创建Android studio项目\u003c/p\u003e\n\u003cp\u003e在项目的build.gradle中添加如下代码（如此简单）\u003cbr\u003e\nbuildscript {\u003cbr\u003e\nrepositories {\u003cbr\u003e\nmavenCentral()\u003cbr\u003e\n}\u003cbr\u003e\ndependencies {\u003cbr\u003e\n// replace with the current version of the Android plugin\u003cbr\u003e\nclasspath ‘com.android.tools.build:gradle:1.2.3’\u003cbr\u003e\n// the latest version of the android-apt plugin\u003cbr\u003e\nclasspath ‘com.neenbedankt.gradle.plugins:android-apt:1.4’\u003cbr\u003e\n}\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003erepositories {\u003cbr\u003e\nmavenCentral()\u003cbr\u003e\nmavenLocal()\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003eapply plugin: ‘com.android.application’\u003cbr\u003e\napply plugin: ‘android-apt’\u003cbr\u003e\ndef AAVersion = ‘3.3.2’//这个是Annotations的版本号，这个可以去Annotations官网查看，也可以在Android studio中Jcenter或者mavenCentral中查找最新版本号\u003c/p\u003e\n\u003cp\u003edependencies {\u003cbr\u003e\ncompile fileTree(include: [‘*.jar’], dir: ‘libs’)\u003cbr\u003e\ncompile ‘com.android.support:appcompat-v7:22.2.0’\u003cbr\u003e\napt “org.androidannotations:androidannotations:\u003cspan class=\"katex math inline\"\u003eAAVersion”\ncompile “org.androidannotations:androidannotations-api:\u003c/span\u003eAAVersion”\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003eapt {\u003cbr\u003e\narguments {\u003cbr\u003e\nandroidManifestFile variant.outputs[0].processResources.manifestFile\u003cbr\u003e\n// if you have multiple outputs (when using splits), you may want to have other index than 0\u003c/p\u003e","title":"Android studio使用Annotations框架"},{"content":"**　本文介绍在Android中实现推送方式的基础知识及相关解决方案。推送功能在手机开发中应用的场景是越来起来了，不说别的，就我们手机上的新闻客户端就时不j时的推送过来新的消息，很方便的阅读最新的新闻信息。这种推送功能是好的一面，但是也会经常看到很多推送过来的垃圾信息，这就让我们感到厌烦了，关于这个我们就不能多说什么了，毕竟很多商家要做广告。本文就是来探讨下Android中实现推送功能的一些解决方案，也希望能够起到抛砖引玉的作用。^_^**\n**　1.推送方式基础知识： **\n在移动互联网时代以前的手机，如果有事情发生需要通知用户，则会有一个窗口弹出，将告诉用户正在发生什么事情。可能是未接电话的提示，日历的提醒，或是一封新的彩信。推送功能最早是被用于Email中，用来提示我们新的信息。由于时代的发展和移动互联网的热潮，推送功能更加地普及，已经不再仅仅用在推送邮件了，更多地用在我们的APP中了。\n当我们开发需要和服务器交互的应用程序时，基本上都需要获取服务器端的数据，比如《地震应急通》就需要及时获取服务器上最新的地震信息。要获取服务器上不定时更新的信息，一般来说有两种方法：第一种是客户端使用Pull（拉）的方式，就是隔一段时间就去服务器上获取一下信息，看是否有更新的信息出现。第二种就是 服务器使用Push（推送）的方式，当服务器端有新信息了，则把最新的信息Push到客户端上。这样，客户端就能自动的接收到消息。\n虽然Pull和Push两种方式都能实现获取服务器端更新信息的功能，但是明显来说Push方式比Pull方式更优越。因为Pull方式更费客户端的网络流量，更主要的是费电量，还需要我们的程序不停地去监测服务端的变化。\n在开发Android和iPhone应用程序时，我们往往需要从服务器不定的向手机客户端即时推送各种通知消息。我们只需要在Android或IPhone的通知栏处向下一拉，就展开了Notification Panel，可以集中一览各种各样通知消息。目前IOS平台上已经有了比较简单的和完美的推送通知解决方案，我会在以后详细介绍IPhone中的解决方案，可是Android平台上实现起来却相对比较麻烦。\n最近利用几天的时间对Android的推送通知服务进行初步的研究，也希望能和大家共同探讨一下。\n**　2. 几种常见的解决方案实现原理：**\n1）轮询(Pull)方式：应用程序应当阶段性的与服务器进行连接并查询是否有新的消息到达，你必须自己实现与服务器之间的通信，例如消息排队等。而且你还要考虑轮询的频率，如果太慢可能导致某些消息的延迟，如果太快，则会大量消耗网络带宽和电池。\n2）SMS(Push)方式：在Android平台上，你可以通过拦截SMS消息并且解析消息内容来了解服务器的意图，并获取其显示内容进行处理。这是一个不错的想法，我就见过采用这个方案的应用程序。这个方案的好处是，可以实现完全的实时操作。但是问题是这个方案的成本相对比较高，我们需要向移动公司缴纳相应的费用。我们目前很难找到免费的短消息发送网关来实现这种方案。\n3）持久连接(Push)方式：这个方案可以解决由轮询带来的性能问题，但是还是会消耗手机的电池。IOS平台的推送服务之所以工作的很好，是因为每一台手机仅仅保持一个与服务器之间的连接，事实上C2DM也是这么工作的。不过刚才也讲了，这个方案存在着很多的不足之处，就是我们很难在手机上实现一个可靠的服务，目前也无法与IOS平台的推送功能相比。\nAndroid操作系统允许在低内存情况下杀死系统服务，所以我们的推送通知服务很有可能就被操作系统Kill掉了。 轮询(Pull)方式和SMS(Push)方式这两个方案也存在明显的不足。至于持久连接(Push)方案也有不足，不过我们可以通过良好的设计来弥补，以便于让该方案可以有效的工作。毕竟，我们要知道GMail，GTalk以及GoogleVoice都可以实现实时更新的。\n3.第一种解决方案：C2DM云端推送功能。\n在Android手机平台上，Google提供了C2DM（Cloudto Device Messaging）服务，起初我就是准备采用这个服务来实现自己手机上的推送功能，并将其带入自己的项目中。\nAndroid Cloud to Device Messaging (C2DM)是一个用来帮助开发者从服务器向Android应用程序发送数据的服务。该服务提供了一个简单的、轻量级的机制，允许服务器可以通知移动应用程序直接与服务器进行通信，以便于从服务器获取应用程序更新和用户数据。C2DM服务负责处理诸如消息排队等事务并向运行于目标设备上的应用程序分发这些消息。关于C2DM具体使用过程，大家可以去查阅相关的资料，在这里先让我们了解下大致方案情况。\n下面是C2DM操作过程示例图:\n但是经过一番研究发现，这个服务存在很大的问题：\n1）C2DM内置于Android的2.2系统上，无法兼容老的1.6到2.1系统;\n2）C2DM需要依赖于Google官方提供的C2DM服务器，由于国内的网络环境，这个服务经常不可用，如果想要很好的使用，我们的App Server必须也在国外，这个恐怕不是每个开发者都能够实现的;\n3) 不像在iPhone中，他们把硬件系统集成在一块了。所以对于我们开发者来说，如果要在我们的应用程序中使用C2DM的推送功能，因为对于不同的这种硬件厂商平台，比如摩托罗拉、华为、中兴做一个手机，他们可能会把Google的这种服务去掉，尤其像在国内就很多这种，把Google这种原生的服务去掉。买了一些像什么山寨机或者是华为这种国产机，可能Google的服务就没有了。而像在国外出的那些可能会内置。\n有了上述几个方面的制约，导致我最终放弃了这个方案，不过我想利用另外一篇文章来详细的介绍C2DM的框架以及客户端和App Server的相应设置方法，可以作为学习资源让我们有个参考的资料。 即然C2DM无法满足我们的要求，那么我们就需要自己来实现Android手机客户端与App Server之间的通信协议，保证在App Server想向指定的Android设备发送消息时，Android设备能够及时的收到。\n**　4. **第二种解决方案：MQTT协议实现Android推送功能。\n采用MQTT协议实现Android推送功能也是一种解决方案。MQTT是一个轻量级的消息发布/订阅协议，它是实现基于手机客户端的消息推送服务器的理想解决方案。\nwmqtt.jar 是IBM提供的MQTT协议的实现。我们可以从这里（https://github.com/tokudu/AndroidPushNotificationsDemo）下载该项目的实例代码，并且可以找到一个采用PHP书写的服务器端实现（https://github.com/tokudu/PhpMQTTClient）。\n架构如下图所示：\n**　wmqtt.jar** 是IBM提供的MQTT协议的实现。我们可以从如下站点下载（http://www-01.ibm.com/support/docview.wss?rs=171\u0026amp;uid=swg24006006）它。我们可以将该jar包加入自己的Android应用程序中。\n**　5.**第三种解决方案：RSMB实现推送功能。\nReally Small Message Broker (RSMB) ，他是一个简单的MQTT代理，同样由IBM提供，其查看地址是：http://www.alphaworks.ibm.com/tech/rsmb。缺省打开1883端口，应用程序当中，它负责接收来自服务器的消息并将其转发给指定的移动设备。\nSAM是一个针对MQTT写的[PHP库](http://pecl.php.net/package/sam/download/0.2.0)。我们可以从这个[http://pecl.php.net/package/sam/download/0.2.](http://pecl.php.net/package/sam/download/0.2.)[](http://pecl.php.net/package/sam/download/0.2.0)地址下载它. send_mqtt.php是一个通过POST接收消息并且通过SAM将消息发送给RSMB的PHP脚本。\n**　6. **第四种解决方案：XMPP协议实现Android推送功能。\n这是我希望在项目中采用的方案，因为目前它是开源的，对于其简单的推送功能它还是能够实现的。我们可以修改其源代码来适应我们的应用程序。\n事实上Google官方的C2DM服务器底层也是采用XMPP协议进行的封装。XMPP(可扩展通讯和表示协议)是基于可扩展标记语言（XML）的协议，它用于即时消息（IM）以及在线探测。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息。关于XMPP协议我在上篇博文中已经介绍，大家可以参考下文章：http://www.cnblogs.com/hanyonglu/archive/2012/03/04/2378956.html\nandroidpn是一个基于XMPP协议的java开源Android push notification实现，我会在以后的博文中详细介绍androidpn。它包含了完整的客户端和服务器端。经过源代码研究我发现，该服务器端基本是在另外一个开源工程openfire基础上修改实现的，不过比较郁闷的是androidpn的文档是由韩语写的，所以整个研究过程基本都是读源码。\n这是androidpn的项目主页：http://sourceforge.net/projects/androidpn/\nandroidpn实现意图如下图所示：\nandroidpn 客户端需要用到一个基于java的开源XMPP协议包asmack，这个包同样也是基于openfire下的另外一个开源项目smack，不过我们不需要自己编译，可以直接把androidpn客户端里面的asmack.jar拿来使用。客户端利用asmack中提供的XMPPConnection类与服 务器建立持久连接，并通过该连接进行用户注册和登录认证，同样也是通过这条连接，接收服务器发送的通知。\nandroidpn服务器端也是java语言实现的，基于openfire开源工程，不过它的Web部分采用的是spring框架，这一点与 openfire是不同的。Androidpn服务器包含两个部分，一个是侦听在5222端口上的XMPP服务，负责与客户端的 XMPPConnection类进行通信，作用是用户注册和身份认证，并发送推送通知消息。另外一部分是Web服务器，采用一个轻量级的HTTP服务器， 负责接收用户的Web请求。服务器架构如下：\n最上层包含四个组成部分，分别是SessionManager，Auth Manager，PresenceManager以及Notification Manager。SessionManager负责管理客户端与服务器之间的会话，Auth Manager负责客户端用户认证管理，Presence Manager负责管理客户端用户的登录状态，NotificationManager负责实现服务器向客户端推送消息功能。\n这个解决方案的最大优势就是简单，我们不需要象C2DM那样依赖操作系统版本，也不会担心某一天Google服务器不可用。利用XMPP协议我们还可以进一步的对协议进行扩展，实现更为完善的功能。 采用这个方案，我们目前只能发送文字消息，不过对于推送来说一般足够了，因为我们不能指望通过推送得到所有的数据，一般情况下，利用推送只是告诉手机端服务器发生了某些改变，当客户端收到通知以后，应该主动到服务器获取最新的数据，这样才是推送服务的完整实现。 XMPP协议书相对来说还是比较简单的，值得我们进一步研究。\n但是在经过一段时间的测试，我发现关于androidpn也存在一些不足之处：\n1. 比如时间过长时，就再也收不到推送的信息了。\n2. 性能上也不够稳定。\n如果将消息从服务器上推送出去，就不再管理了，不管消息是否成功到达客户端手机上。 等等，总之，androidpn也有很多的缺点。如果我们要使用androidpn，则还需要做大量的工作。\n至于详细使用过程，我们会在下个博文中再给大家介绍。\n7.第五种解决方案：使用第三方平台。\n**　第三方平台有商用的也有免费的，我们可以根据实现情况使用。关于国内的第三方平台，我感觉目前比较不错的就是极光推送。关于极光推送目前**是免费的，我们可以直接使用。关于详细情况，**大家可以查看它的主页：http://www.jpush.cn/index.jsp，这里不再详细描述。\n**\n关于国外的第三方平台我也见过几个：http://www.push-notification.org/。有兴趣的朋友可以查阅相关信息。使用第三方平台就需要使用别人的服务器，关于这点，你懂的。\n8.第六种解决方案：自己搭建一个推送平台。\n这不是一件轻松的工作，当然可以根据各自的需要采取合适的方案。\n好了，以上是关于在Android中实现推送方式的基础知识及相关解决方案。\n最后，希望转载的朋友能够尊重作者的劳动成果，加上转载地址：http://www.cnblogs.com/hanyonglu/archive/2012/03/04/2378971.html 谢谢。\n完毕。 ^_^\n","permalink":"https://blog.zdltech.com/posts/android%E5%AE%9E%E7%8E%B0%E6%8E%A8%E9%80%81%E6%96%B9%E5%BC%8F%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/","summary":"\u003cp\u003e**　本文介绍在Android中实现推送方式的基础知识及相关解决方案。推送功能在手机开发中应用的场景是越来起来了，不说别的，就我们手机上的新闻客户端就时不j时的推送过来新的消息，很方便的阅读最新的新闻信息。这种推送功能是好的一面，但是也会经常看到很多推送过来的垃圾信息，这就让我们感到厌烦了，关于这个我们就不能多说什么了，毕竟很多商家要做广告。本文就是来探讨下Android中实现推送功能的一些解决方案，也希望能够起到抛砖引玉的作用。^_^**\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e**　　1.推送方式基础知识： **\u003c/p\u003e\n\u003cp\u003e在移动互联网时代以前的手机，如果有事情发生需要通知用户，则会有一个窗口弹出，将告诉用户正在发生什么事情。可能是未接电话的提示，日历的提醒，或是一封新的彩信。推送功能最早是被用于Email中，用来提示我们新的信息。由于时代的发展和移动互联网的热潮，推送功能更加地普及，已经不再仅仅用在推送邮件了，更多地用在我们的APP中了。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e当我们开发需要和服务器交互的应用程序时，基本上都需要获取服务器端的数据，比如《地震应急通》就需要及时获取服务器上最新的地震信息。要获取服务器上不定时更新的信息，一般来说有两种方法：第一种是客户端使用Pull（拉）的方式，就是隔一段时间就去服务器上获取一下信息，看是否有更新的信息出现。第二种就是 服务器使用Push（推送）的方式，当服务器端有新信息了，则把最新的信息Push到客户端上。这样，客户端就能自动的接收到消息。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e虽然Pull和Push两种方式都能实现获取服务器端更新信息的功能，但是明显来说Push方式比Pull方式更优越。因为Pull方式更费客户端的网络流量，更主要的是费电量，还需要我们的程序不停地去监测服务端的变化。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e在开发Android和iPhone应用程序时，我们往往需要从服务器不定的向手机客户端即时推送各种通知消息。我们只需要在Android或IPhone的通知栏处向下一拉，就展开了Notification Panel，可以集中一览各种各样通知消息。目前IOS平台上已经有了比较简单的和完美的推送通知解决方案，我会在以后详细介绍IPhone中的解决方案，可是Android平台上实现起来却相对比较麻烦。\u003c/p\u003e\n\u003cp\u003e最近利用几天的时间对Android的推送通知服务进行初步的研究，也希望能和大家共同探讨一下。\u003c/p\u003e\n\u003cp\u003e**　　2. 几种常见的解决方案实现原理：**\u003c/p\u003e\n\u003cp\u003e1）轮询(Pull)方式：应用程序应当阶段性的与服务器进行连接并查询是否有新的消息到达，你必须自己实现与服务器之间的通信，例如消息排队等。而且你还要考虑轮询的频率，如果太慢可能导致某些消息的延迟，如果太快，则会大量消耗网络带宽和电池。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e2）SMS(Push)方式：在Android平台上，你可以通过拦截SMS消息并且解析消息内容来了解服务器的意图，并获取其显示内容进行处理。这是一个不错的想法，我就见过采用这个方案的应用程序。这个方案的好处是，可以实现完全的实时操作。但是问题是这个方案的成本相对比较高，我们需要向移动公司缴纳相应的费用。我们目前很难找到免费的短消息发送网关来实现这种方案。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e3）持久连接(Push)方式：这个方案可以解决由轮询带来的性能问题，但是还是会消耗手机的电池。IOS平台的推送服务之所以工作的很好，是因为每一台手机仅仅保持一个与服务器之间的连接，事实上C2DM也是这么工作的。不过刚才也讲了，这个方案存在着很多的不足之处，就是我们很难在手机上实现一个可靠的服务，目前也无法与IOS平台的推送功能相比。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eAndroid操作系统允许在低内存情况下杀死系统服务，所以我们的推送通知服务很有可能就被操作系统Kill掉了。 轮询(Pull)方式和SMS(Push)方式这两个方案也存在明显的不足。至于持久连接(Push)方案也有不足，不过我们可以通过良好的设计来弥补，以便于让该方案可以有效的工作。毕竟，我们要知道GMail，GTalk以及GoogleVoice都可以实现实时更新的。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3.第一种解决方案：C2DM云端推送功能。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在Android手机平台上，Google提供了C2DM（Cloudto Device Messaging）服务，起初我就是准备采用这个服务来实现自己手机上的推送功能，并将其带入自己的项目中。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eAndroid Cloud to Device Messaging (C2DM)是一个用来帮助开发者从服务器向Android应用程序发送数据的服务。该服务提供了一个简单的、轻量级的机制，允许服务器可以通知移动应用程序直接与服务器进行通信，以便于从服务器获取应用程序更新和用户数据。C2DM服务负责处理诸如消息排队等事务并向运行于目标设备上的应用程序分发这些消息。关于C2DM具体使用过程，大家可以去查阅相关的资料，在这里先让我们了解下大致方案情况。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e下面是C2DM操作过程示例图:\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/image001.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e但是经过一番研究发现，这个服务存在很大的问题：\u003c/p\u003e\n\u003cp\u003e1）C2DM内置于Android的2.2系统上，无法兼容老的1.6到2.1系统;\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e2）C2DM需要依赖于Google官方提供的C2DM服务器，由于国内的网络环境，这个服务经常不可用，如果想要很好的使用，我们的App Server必须也在国外，这个恐怕不是每个开发者都能够实现的;\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e3) 不像在iPhone中，他们把硬件系统集成在一块了。所以对于我们开发者来说，如果要在我们的应用程序中使用C2DM的推送功能，因为对于不同的这种硬件厂商平台，比如摩托罗拉、华为、中兴做一个手机，他们可能会把Google的这种服务去掉，尤其像在国内就很多这种，把Google这种原生的服务去掉。买了一些像什么山寨机或者是华为这种国产机，可能Google的服务就没有了。而像在国外出的那些可能会内置。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e有了上述几个方面的制约，导致我最终放弃了这个方案，不过我想利用另外一篇文章来详细的介绍C2DM的框架以及客户端和App Server的相应设置方法，可以作为学习资源让我们有个参考的资料。 即然C2DM无法满足我们的要求，那么我们就需要自己来实现Android手机客户端与App Server之间的通信协议，保证在App Server想向指定的Android设备发送消息时，Android设备能够及时的收到。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e**　　4. **第二种解决方案：\u003cstrong\u003eMQTT协议实现Android推送功能。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e采用MQTT协议实现Android推送功能也是一种解决方案。MQTT是一个轻量级的消息发布/订阅协议，它是实现基于手机客户端的消息推送服务器的理想解决方案。\u003c/p\u003e\n\u003cp\u003ewmqtt.jar 是IBM提供的MQTT协议的实现。我们可以从\u003ca href=\"http://github.com/tokudu/AndroidPushNotificationsDemo\"\u003e这里\u003c/a\u003e（\u003ca href=\"https://github.com/tokudu/AndroidPushNotificationsDemo\"\u003ehttps://github.com/tokudu/AndroidPushNotificationsDemo\u003c/a\u003e）下载该项目的实例代码，并且可以找到一个采用PHP书写的\u003ca href=\"http://github.com/tokudu/PhpMQTTClient\"\u003e服务器端实现\u003c/a\u003e（\u003ca href=\"https://github.com/tokudu/PhpMQTTClient\"\u003ehttps://github.com/tokudu/PhpMQTTClient\u003c/a\u003e）。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e架构如下图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/0_130881365599DT.gif\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e**　　wmqtt.jar** 是IBM提供的MQTT协议的实现。我们可以从如下站点\u003ca href=\"http://www-01.ibm.com/support/docview.wss?rs=171\u0026amp;uid=swg24006006\"\u003e下载\u003c/a\u003e（\u003ca href=\"http://www-01.ibm.com/support/docview.wss?rs=171\u0026amp;uid=swg24006006\"\u003ehttp://www-01.ibm.com/support/docview.wss?rs=171\u0026amp;uid=swg24006006\u003c/a\u003e）它。我们可以将该jar包加入自己的Android应用程序中。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e**　　5.**第三种解决方案：\u003cstrong\u003eRSMB实现推送功能。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eReally Small Message Broker (RSMB) ，他是一个简单的MQTT代理，同样由IBM提供，其查看地址是：\u003ca href=\"http://www.alphaworks.ibm.com/tech/rsmb\"\u003ehttp://www.alphaworks.ibm.com/tech/rsmb\u003c/a\u003e。缺省打开1883端口，应用程序当中，它负责接收来自服务器的消息并将其转发给指定的移动设备。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e　　SAM是一个针对MQTT写的[PHP库](http://pecl.php.net/package/sam/download/0.2.0)。我们可以从这个[http://pecl.php.net/package/sam/download/0.2.](http://pecl.php.net/package/sam/download/0.2.)[](http://pecl.php.net/package/sam/download/0.2.0)地址下载它.\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003esend_mqtt.php是一个通过POST接收消息并且通过SAM将消息发送给RSMB的PHP脚本。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e**　　6. **第四种解决方案：\u003cstrong\u003eXMPP协议实现Android推送功能。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e这是我希望在项目中采用的方案，因为目前它是开源的，对于其简单的推送功能它还是能够实现的。我们可以修改其源代码来适应我们的应用程序。\u003c/p\u003e","title":"Android实现推送方式解决方案"},{"content":"** **本文详细介绍了十个Material Design开源项目，从示例、FAB、菜单、动画、Ripple到Dialog，看被誉为“Google第一次在设计语言和规范上超越了Apple”的Material Design是如何逐渐成为App的一种全新设计标准。\n介于拟物和扁平之间的Material Design自面世以来，便引起了很多人的关注与思考，就此产生的讨论也不绝于耳。本文详细介绍了在Android开发者圈子里颇受青睐的十个Material Design开源项目，从示例、FAB、菜单、动画、Ripple到Dialog，看被称为“Google第一次在设计语言和规范上超越了Apple”的Material Design是如何逐渐成为App的一种全新设计标准。\n1. MaterialDesignLibrary\n在众多新晋库中，MaterialDesignLibrary可以说是颇受开发者瞩目的一个控件效果库，能够让开发者在Android 2.2系统上使用Android 5.0才支持的控件效果，比如扁平、矩形、浮动按钮，复选框以及各式各样的进度指示器等。\n![](http://dl2.iteye.com/upload/attachment/0103/5584/80416adf-b40f-31f9-b2e0-3986c8ab7790.jpg) 除上述之外，MaterialDesignLibrary还拥有SnackBar、Dialog、Color selector组件，可非常便捷地对应用界面进行设置。\n进度指示器样式效果设置：\nXml代码 \u0026lt;embed src=\u0026quot;http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.gc.materialdesign.views.ProgressBarCircularIndetermininate\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/progressBarCircularIndetermininate\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;32dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;32dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#1E88E5\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; Dialog：\nJava代码 \u0026lt;embed src=\u0026quot;http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; - Dialog dialog = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Dialog(Context context,String title, String message); - dialog.show(); 2. RippleEffect\n由来自法兰西的Robin Chutaux开发的RippleEffect基于MIT许可协议开源，能够在Android API 9+上实现Material Design，为开发者提供了一种极为简易的方式来创建带有可扩展视图的header视图，并且允许最大程度上的自定制。\n![](http://dl2.iteye.com/upload/attachment/0103/5586/f48bad92-5fd0-3a3a-8864-72c2581337d1.jpg) Xml代码 \u0026lt;embed src=\u0026quot;http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.andexert.library.RippleView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/more\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;?android:actionBarSize\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;?android:actionBarSize\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_toLeftOf\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/more2\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_margin\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;ripple:rv_centered\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;?android:actionBarSize\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;?android:actionBarSize\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:drawable/ic_menu_edit\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerInParent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:padding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/holo_blue_dark\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.andexert.library.RippleView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 3. MaterialEditText\n随着Material Design的到来，AppCompat v21也为开发者提供了Material Design的控件外观支持，其中就包括EditText，但却并不好用，没有设置颜色的API，也没有任何Google Material Design Spec中提到的特性。于是，来自国内的开发者“扔物线”开发了MaterialEditText库，直接继承EditText，无需修改Java文件即能实现自定义控件颜色。\n![](http://dl2.iteye.com/upload/attachment/0103/5588/36b38f8f-bb26-3601-a5f0-1f0d539aeae5.jpg) 自定义Base Color：\nXml代码 \u0026lt;embed src=\u0026quot;http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;app:baseColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#0056d3\u0026amp;#8221;\u0026lt;/span\u0026gt; 自定义Error Color：\nXml代码 \u0026lt;embed src=\u0026quot;http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;app:maxCharacters\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;app:errorColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#ddaa00\u0026amp;#8221;\u0026lt;/span\u0026gt; ![](http://dl2.iteye.com/upload/attachment/0103/5590/19b8efe3-976d-33e0-ad92-ac5d3ed97ade.jpg) 4. Android-LollipopShowcase\nAndroid-LollipopShowcase是由来自奥地利的移动、后端及Web开发者Mike Penz所开发的演示应用，集中演示了新Material Design中所有的UI效果，以及Android Lollipop中其他非常酷炫的特性元素，比如Toolbar、RecyclerView、ActionBarDrawerToggle、Floating Action Button（FAB）、Android Compat Theme等。\n![](http://dl2.iteye.com/upload/attachment/0103/5594/9a803370-9135-31a6-8a35-300b8c467ccb.jpg) 5. MaterialList\nMaterialList是一个能够帮助所有Android开发者获取谷歌UI设计规范中新增的CardView（卡片视图）的开源库，支持Android 2.3+系统。作为ListView的扩展，MaterialList可以接收、存储卡片列表，并根据它们的Android风格和设计模式进行展示。此外，开发者还可以创建专属于自己的卡片布局，并轻松将其添加到CardList中。\n![](http://dl2.iteye.com/upload/attachment/0103/5596/b878adaf-ce4a-393c-871e-9a2961036f92.jpg) 使用过程代码，在布局中声明MaterialListView：\nXml代码 \u0026lt;embed src=\u0026quot;http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_horizontal_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_horizontal_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_vertical_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_vertical_margin\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.dexafree.materiallistviewexample.view.MaterialListView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/material_listview\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 6. android-floating-action-button\nFloating Action Button（FAB）是众多专家大牛针对Material Design讨论比较细化的一个点，通过圆形元素与分割线、卡片、各种Bar的直线形成鲜明对比，并使用色彩设定中鲜艳的辅色，带来更具突破性的视觉效果。也正因如此，在Github上，有着许多与FAB相关的开源项目，基于Material Design规范的开源Android浮动Action Button控件android-floating-action-button便是其中之一。\n![](http://dl2.iteye.com/upload/attachment/0103/5598/8e27c078-651c-3144-ae17-d1f4d50189b8.jpg) 其主要特性如下：\n支持常规56dp和最小40dp的按钮； 支持自定义正常、Press状态以及可拖拽图标的按钮背景颜色； AddFloatingActionButton类能够让开发者非常方便地直接在代码中写入加号图标； FloatingActionsMenu类支持展开/折叠显示动作。 7. android-ui\nandroid-ui是Android UI组件类库，支持Android API 14+，包含了ActionView、RevealColorView等UI组件。其中，ActionView可使Action动作显示动画效果，而RevealColorView则带来了Android 5.0中的圆形显示/隐藏动画体验。\n![](http://dl2.iteye.com/upload/attachment/0103/5600/2f4e3b74-0df7-3495-802d-1217ef3c76f9.jpg) 8. Material Menu\nMaterial Menu为开发者带来了非常酷炫的Android菜单、返回、删除以及检查按钮变形，完全控制动画，并为开发者提供了两种MaterialMenuDrawable包装。\n![](http://dl2.iteye.com/upload/attachment/0103/5602/d17b8ee9-7c50-313d-af88-40f327255f96.jpg) 自定义颜色等操作：\nJava代码 \u0026lt;embed src=\u0026quot;http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// change color \u0026lt;/span\u0026gt; - MaterialMenu.setColor(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; color) - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// change transformation animation duration \u0026lt;/span\u0026gt; - MaterialMenu.setTransformationDuration(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; duration) - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// change pressed animation duration \u0026lt;/span\u0026gt; - MaterialMenu.setPressedDuration(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; duration) - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// change transformation interpolator \u0026lt;/span\u0026gt; - MaterialMenu.setInterpolator(Interpolator interpolator) - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// set RTL layout support \u0026lt;/span\u0026gt; - MaterialMenu.setRTLEnabled(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; enabled) 9. Android-ObservableScrollView\nAndroid-ObservableScrollView是一款用于在滚动视图中观测滚动事件的Android库。它能够轻而易举地与Android 5.0 Lollipop引进的工具栏（Toolbar）进行交互，还可以帮助开发者实现拥有Material Design应用视觉体验的界面外观，支持ListView、ScrollView、WebView、RecyclerView、GridView组件。\n![](http://dl2.iteye.com/upload/attachment/0103/5604/5b551bd0-86ce-35dd-a5e8-f82e67495008.jpg) 交互代码回调：\nJava代码 \u0026lt;embed src=\u0026quot;http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onUpOrCancelMotionEvent(ScrollState scrollState) { - ActionBar ab = getSupportActionBar(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (scrollState == ScrollState.UP) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (ab.isShowing()) { - ab.hide(); - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (scrollState == ScrollState.DOWN) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!ab.isShowing()) { - ab.show(); - } - } - } 10. Material Design Icons\n最后，再来介绍一下Google Material Design规范的官方开源图标集Material Design Icons。良心Google开源了包括Material Design系统图标包在内的750个字形，涵盖动作、音视频、通信、内容、编辑器、文件、硬件、图像、地图、导航、通知、社交等各个方面，适用于Web、Android和iOS应用开发，绝对是开发者及设计师必备的资源。\n![](http://dl2.iteye.com/upload/attachment/0103/5608/934b7436-05e3-3a42-9887-ce96b150c472.jpg) 图标格式主要包括：\nSVG格式，24px和48px； SVG和CSS Sprites； 适用于Web平台的1x、2x PNG格式图标； 适用于iOS的1x、2x、3x PNG图标； 所有图标的Hi-dpi版本（hdpi、mdpi、xhdpi、xxhdpi、xxxhdpi）。 ","permalink":"https://blog.zdltech.com/posts/%E7%9B%B4%E6%8E%A5%E6%8B%BF%E6%9D%A5%E7%94%A8%E5%8D%81%E5%A4%A7material-design%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/","summary":"\u003cp\u003e**       **本文详细介绍了十个Material Design开源项目，从示例、FAB、菜单、动画、Ripple到Dialog，看被誉为“Google第一次在设计语言和规范上超越了Apple”的Material Design是如何逐渐成为App的一种全新设计标准。\u003cbr\u003e\n介于拟物和扁平之间的Material Design自面世以来，便引起了很多人的关注与思考，就此产生的讨论也不绝于耳。本文详细介绍了在Android开发者圈子里颇受青睐的十个Material Design开源项目，从示例、FAB、菜单、动画、Ripple到Dialog，看被称为“Google第一次在设计语言和规范上超越了Apple”的Material Design是如何逐渐成为App的一种全新设计标准。\u003cbr\u003e\n\u003cstrong\u003e1. \u003ca href=\"https://github.com/navasmdc/MaterialDesignLibrary\"\u003eMaterialDesignLibrary\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在众多新晋库中，MaterialDesignLibrary可以说是颇受开发者瞩目的一个控件效果库，能够让开发者在Android 2.2系统上使用Android 5.0才支持的控件效果，比如扁平、矩形、浮动按钮，复选框以及各式各样的进度指示器等。\u003c/p\u003e\n\u003cdiv\u003e\n  ![](http://dl2.iteye.com/upload/attachment/0103/5584/80416adf-b40f-31f9-b2e0-3986c8ab7790.jpg)\n\u003c/div\u003e\n\u003cp\u003e除上述之外，MaterialDesignLibrary还拥有SnackBar、Dialog、Color selector组件，可非常便捷地对应用界面进行设置。\u003c/p\u003e\n\u003cp\u003e进度指示器样式效果设置：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      Xml代码 \n\u003cpre\u003e\u003ccode\u003e  \u0026lt;embed src=\u0026quot;http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt;\n  \u0026lt;/embed\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.gc.materialdesign.views.ProgressBarCircularIndetermininate\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/progressBarCircularIndetermininate\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;32dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;32dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#1E88E5\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003eDialog：\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      Java代码 \n\u003cpre\u003e\u003ccode\u003e  \u0026lt;embed src=\u0026quot;http://www.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt;\n  \u0026lt;/embed\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- Dialog dialog = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Dialog(Context context,String title, String message);\n\n- dialog.show();\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003e2. \u003ca href=\"https://github.com/traex/RippleEffect\"\u003eRippleEffect\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e","title":"直接拿来用！十大Material Design开源项目"},{"content":"开发自定义控件的步骤:\n1、了解View的工作原理\n2、 编写继承自View的子类\n3、 为自定义View类增加属性\n4、 绘制控件\n5、 响应用户消息\n6 、自定义回调函数\n一、View结构原理\nAndroid系统的视图结构的设计也采用了组合模式，即View作为所有图形的基类，Viewgroup对View继承扩展为视图容器类。\nView定义了绘图的基本操作\n基本操作由三个函数完成：measure()、layout()、draw()，其内部又分别包含了onMeasure()、onLayout()、onDraw()三个子方法。具体操作如下：\n1、measure操作\nmeasure操作主要用于计算视图的大小，即视图的宽度和长度。在view中定义为final类型，要求子类不能修改。measure()函数中又会调用下面的函数：\n（1）onMeasure()，视图大小的将在这里最终确定，也就是说measure只是对onMeasure的一个包装，子类可以覆写onMeasure()方法实现自己的计算视图大小的方式，并通过setMeasuredDimension(width, height)保存计算结果。\n2、layout操作\nlayout操作用于设置视图在屏幕中显示的位置。在view中定义为final类型，要求子类不能修改。layout()函数中有两个基本操作：\n（1）setFrame（l,t,r,b），l,t,r,b即子视图在父视图中的具体位置，该函数用于将这些参数保存起来；\n（2）onLayout()，在View中这个函数什么都不会做，提供该函数主要是为viewGroup类型布局子视图用的；\n3、draw操作\ndraw操作利用前两部得到的参数，将视图显示在屏幕上，到这里也就完成了整个的视图绘制工作。子类也不应该修改该方法，因为其内部定义了绘图的基本操作：\n（1）绘制背景；\n（2）如果要视图显示渐变框，这里会做一些准备工作；\n（3）绘制视图本身，即调用onDraw()函数。在view中onDraw()是个空函数，也就是说具体的视图都要覆写该函数来实现自己的显示（比如TextView在这里实现了绘制文字的过程）。而对于ViewGroup则不需要实现该函数，因为作为容器是“没有内容“的，其包含了多个子view，而子View已经实现了自己的绘制方法，因此只需要告诉子view绘制自己就可以了，也就是下面的dispatchDraw()方法;\n（4）绘制子视图，即dispatchDraw()函数。在view中这是个空函数，具体的视图不需要实现该方法，它是专门为容器类准备的，也就是容器类必须实现该方法；\n（5）如果需要（应用程序调用了setVerticalFadingEdge或者setHorizontalFadingEdge），开始绘制渐变框；\n（6）绘制滚动条；\n从上面可以看出自定义View需要最少覆写onMeasure()和onDraw()两个方法。\n二、View类的构造方法\n创建自定义控件的3种主要实现方式:\n1）继承已有的控件来实现自定义控件: 主要是当要实现的控件和已有的控件在很多方面比较类似, 通过对已有控件的扩展来满足要求。\n2）通过继承一个布局文件实现自定义控件，一般来说做组合控件时可以通过这个方式来实现。\n注意此时不用onDraw方法，在构造广告中通过inflater加载自定义控件的布局文件，再addView(view)，自定义控件的图形界面就加载进来了。\n3）通过继承view类来实现自定义控件，使用GDI绘制出组件界面，一般无法通过上述两种方式来实现时用该方式。\n三、自定义View增加属性的两种方法：\n1）在View类中定义。通过构造函数中引入的AttributeSet 去查找XML布局的属性名称，然后找到它对应引用的资源ID去找值。\n案例：实现一个带文字的图片（图片、文字是onDraw方法重绘实现）\n![](http://common.cnblogs.com/images/copycode.gif) publicclassMyViewextendsView {privateString mtext;privateintmsrc;publicMyView(Context context) {super(context);\n}publicMyView(Context context, AttributeSet attrs) {super(context, attrs);intresourceId = 0;inttextId = attrs.getAttributeResourceValue(null, “Text”,0);intsrcId = attrs.getAttributeResourceValue(null, “Src”, 0);\nmtext=context.getResources().getText(textId).toString();\nmsrc=srcId;\n}\n@OverrideprotectedvoidonDraw(Canvas canvas) {\nPaint paint=newPaint();\npaint.setColor(Color.RED);\nInputStream is=getResources().openRawResource(msrc);\nBitmap mBitmap=BitmapFactory.decodeStream(is);intbh =mBitmap.getHeight();intbw =mBitmap.getWidth();\ncanvas.drawBitmap(mBitmap,0,0, paint);//canvas.drawCircle(40, 90, 15, paint);canvas.drawText(mtext, bw/2, 30, paint);\n}\n}\n![](http://common.cnblogs.com/images/copycode.gif) 布局文件：\n![](http://common.cnblogs.com/images/copycode.gif) ![](http://common.cnblogs.com/images/copycode.gif) 属性Text, Src在自定义View类的构造方法中读取。\n2）通过XML为View注册属性。与Android提供的标准属性写法一样。\n案例: 实现一个带文字说明的ImageView (ImageView+TextView组合，文字说明，可在布局文件中设置位置)\n![](http://common.cnblogs.com/images/copycode.gif) publicclassMyImageViewextendsLinearLayout {publicMyImageView(Context context) {super(context);}publicMyImageView(Context context, AttributeSet attrs) {super(context, attrs);intresourceId = -1;\nTypedArray typedArray=context.obtainStyledAttributes(attrs,\nR.styleable.MyImageView);\nImageView iv=newImageView(context);\nTextView tv=newTextView(context);intN =typedArray.getIndexCount();for(inti = 0; i \u0026lt; N; i++) {intattr =typedArray.getIndex(i);switch(attr) {caseR.styleable.MyImageView_Oriental:\nresourceId=typedArray.getInt(\nR.styleable.MyImageView_Oriental,0);this.setOrientation(resourceId == 1 ?LinearLayout.HORIZONTAL LinearLayout.VERTICAL);break;caseR.styleable.MyImageView_Text:\nresourceId=typedArray.getResourceId(\nR.styleable.MyImageView_Text,0);\ntv.setText(resourceId\u0026gt; 0 ?typedArray.getResources().getText(\nresourceId) : typedArray\n.getString(R.styleable.MyImageView_Text));break;caseR.styleable.MyImageView_Src:\nresourceId=typedArray.getResourceId(\nR.styleable.MyImageView_Src,0);\niv.setImageResource(resourceId\u0026gt; 0 ?resourceId:R.drawable.ic_launcher);break;\n}\n}\naddView(iv);\naddView(tv);\ntypedArray.recycle();\n}\n}\n![](http://common.cnblogs.com/images/copycode.gif) attrs.xml进行属性声明， 文件放在values目录下\n![](http://common.cnblogs.com/images/copycode.gif) ![](http://common.cnblogs.com/images/copycode.gif) MainActivity的布局文件：先定义命名空间 xmlns:uview=”http://schemas.android.com/apk/res/com.example.myimageview2″ （com.example.myimageview2为你\n在manifest中定义的包名）\n然后可以像使用系统的属性一样使用：uview:Oriental=”Vertical”\n![](http://common.cnblogs.com/images/copycode.gif) ![](http://common.cnblogs.com/images/copycode.gif) 四、控件绘制 onDraw()\n五、\n六：自定义View的方法\nonFinishInflate() 回调方法，当应用从XML加载该组件并用它构建界面之后调用的方法\nonMeasure() 检测View组件及其子组件的大小\nonLayout() 当该组件需要分配其子组件的位置、大小时\nonSizeChange() 当该组件的大小被改变时\nonDraw() 当组件将要绘制它的内容时\nonKeyDown 当按下某个键盘时\nonKeyUp 当松开某个键盘时\nonTrackballEvent 当发生轨迹球事件时\nonTouchEvent 当发生触屏事件时\nonWindowFocusChanged(boolean) 当该组件得到、失去焦点时\nonAtrrachedToWindow() 当把该组件放入到某个窗口时\nonDetachedFromWindow() 当把该组件从某个窗口上分离时触发的方法\nonWindowVisibilityChanged(int): 当包含该组件的窗口的可见性发生改变时触发的方法\n","permalink":"https://blog.zdltech.com/posts/android%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6/","summary":"\u003cp\u003e开发自定义控件的步骤:\u003c/p\u003e\n\u003cp\u003e1、了解View的工作原理\u003c/p\u003e\n\u003cp\u003e2、 编写继承自View的子类\u003c/p\u003e\n\u003cp\u003e3、 为自定义View类增加属性\u003c/p\u003e\n\u003cp\u003e4、 绘制控件\u003c/p\u003e\n\u003cp\u003e5、 响应用户消息\u003c/p\u003e\n\u003cp\u003e6 、自定义回调函数\u003c/p\u003e\n\u003cp\u003e一、View结构原理\u003c/p\u003e\n\u003cp\u003eAndroid系统的视图结构的设计也采用了组合模式，即View作为所有图形的基类，Viewgroup对View继承扩展为视图容器类。\u003c/p\u003e\n\u003cp\u003eView定义了绘图的基本操作\u003c/p\u003e\n\u003cp\u003e基本操作由三个函数完成：measure()、layout()、draw()，其内部又分别包含了onMeasure()、onLayout()、onDraw()三个子方法。具体操作如下：\u003c/p\u003e\n\u003cp\u003e1、measure操作\u003c/p\u003e\n\u003cp\u003emeasure操作主要用于计算视图的大小，即视图的宽度和长度。在view中定义为final类型，要求子类不能修改。measure()函数中又会调用下面的函数：\u003c/p\u003e\n\u003cp\u003e（1）onMeasure()，视图大小的将在这里最终确定，也就是说measure只是对onMeasure的一个包装，子类可以覆写onMeasure()方法实现自己的计算视图大小的方式，并通过setMeasuredDimension(width, height)保存计算结果。\u003c/p\u003e\n\u003cp\u003e2、layout操作\u003c/p\u003e\n\u003cp\u003elayout操作用于设置视图在屏幕中显示的位置。在view中定义为final类型，要求子类不能修改。layout()函数中有两个基本操作：\u003c/p\u003e\n\u003cp\u003e（1）setFrame（l,t,r,b），l,t,r,b即子视图在父视图中的具体位置，该函数用于将这些参数保存起来；\u003c/p\u003e\n\u003cp\u003e（2）onLayout()，在View中这个函数什么都不会做，提供该函数主要是为viewGroup类型布局子视图用的；\u003c/p\u003e\n\u003cp\u003e3、draw操作\u003c/p\u003e\n\u003cp\u003edraw操作利用前两部得到的参数，将视图显示在屏幕上，到这里也就完成了整个的视图绘制工作。子类也不应该修改该方法，因为其内部定义了绘图的基本操作：\u003c/p\u003e\n\u003cp\u003e（1）绘制背景；\u003c/p\u003e\n\u003cp\u003e（2）如果要视图显示渐变框，这里会做一些准备工作；\u003c/p\u003e\n\u003cp\u003e（3）绘制视图本身，即调用onDraw()函数。在view中onDraw()是个空函数，也就是说具体的视图都要覆写该函数来实现自己的显示（比如TextView在这里实现了绘制文字的过程）。而对于ViewGroup则不需要实现该函数，因为作为容器是“没有内容“的，其包含了多个子view，而子View已经实现了自己的绘制方法，因此只需要告诉子view绘制自己就可以了，也就是下面的dispatchDraw()方法;\u003c/p\u003e\n\u003cp\u003e（4）绘制子视图，即dispatchDraw()函数。在view中这是个空函数，具体的视图不需要实现该方法，它是专门为容器类准备的，也就是容器类必须实现该方法；\u003c/p\u003e\n\u003cp\u003e（5）如果需要（应用程序调用了setVerticalFadingEdge或者setHorizontalFadingEdge），开始绘制渐变框；\u003c/p\u003e\n\u003cp\u003e（6）绘制滚动条；\u003c/p\u003e\n\u003cp\u003e从上面可以看出自定义View需要最少覆写onMeasure()和onDraw()两个方法。\u003c/p\u003e\n\u003cp\u003e二、View类的构造方法\u003c/p\u003e\n\u003cp\u003e创建自定义控件的3种主要实现方式:\u003c/p\u003e\n\u003cp\u003e1）继承已有的控件来实现自定义控件: 主要是当要实现的控件和已有的控件在很多方面比较类似, 通过对已有控件的扩展来满足要求。\u003c/p\u003e\n\u003cp\u003e2）通过继承一个布局文件实现自定义控件，一般来说做组合控件时可以通过这个方式来实现。\u003c/p\u003e\n\u003cp\u003e注意此时不用onDraw方法，在构造广告中通过inflater加载自定义控件的布局文件，再addView(view)，自定义控件的图形界面就加载进来了。\u003c/p\u003e\n\u003cp\u003e3）通过继承view类来实现自定义控件，使用GDI绘制出组件界面，一般无法通过上述两种方式来实现时用该方式。\u003c/p\u003e\n\u003cp\u003e三、自定义View增加属性的两种方法：\u003c/p\u003e\n\u003cp\u003e1）在View类中定义。通过构造函数中引入的AttributeSet 去查找XML布局的属性名称，然后找到它对应引用的资源ID去找值。\u003c/p\u003e\n\u003cp\u003e案例：实现一个带文字的图片（图片、文字是onDraw方法重绘实现）\u003c/p\u003e\n\u003cdiv class=\"image-package imagebubble\"\u003e\n  \u003ca target=\"_blank\"\u003e![](http://common.cnblogs.com/images/copycode.gif)\n \u003c/a\u003e\n\u003c/div\u003e\n\u003cp\u003epublicclassMyViewextendsView {privateString mtext;privateintmsrc;publicMyView(Context context) {super(context);\u003c/p\u003e\n\u003cp\u003e}publicMyView(Context context, AttributeSet attrs) {super(context, attrs);intresourceId = 0;inttextId = attrs.getAttributeResourceValue(null, “Text”,0);intsrcId = attrs.getAttributeResourceValue(null, “Src”, 0);\u003c/p\u003e\n\u003cp\u003emtext=context.getResources().getText(textId).toString();\u003c/p\u003e\n\u003cp\u003emsrc=srcId;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e@OverrideprotectedvoidonDraw(Canvas canvas) {\u003c/p\u003e","title":"Android自定义控件"},{"content":"在github或者其他的git平台下载的android studio项目导入到自己的Android studio中会出现一堆问题，\n首先在导入之前先用自己的Android studio创建一个测试工程，主要使用测试工程下的2个文件，分别是：./build.gradle和./gradle/wrapper/gradle-wrapper.properties文件\n例如1.build.gradle\ndependencies {\nclasspath ‘com.android.tools.build:gradle:1.2.3’\n}\n修改classpath中的gradle修改为你当前android studio环境中的配置\n例如2.gradle/wrapper/gradle-wrapper.properties\ndistributionUrl=https://services.gradle.org/distributions/gradle-2.2.1-all.zip\n替换文件中的这句话，使用自己Android studio中相应语句\n修改完成以上以后，打开Android studio选择/import project按照提示导入。\n如何遇到导入的项目没有办法运行，这个时候我们运行 build/Rebuild Project进行重新编译项目。\n在此过程中遇到\nFAILURE: Build failed with an exception.\nWhat went wrong:\nTask ‘build.gradle’ not found in root project ‘XXX’.\nTry:\n说明我们导入的项目还没有符合我们的环境，我们需要进一步配置。\n打开cmd ,进入项目更目录执行\ngradlew\ngradlew build\n检查环境变量是否配置了gradle环境，没有自己配置下，在执行gradlew时会出现解压的目录地址，自己手动配置到环境变量就行了。\n紧接着执行\ngradle build\ngradle tasks //查看android gradle的所有任务\ngradle compileReleaseSource //生成debug apk ，在build/outpus/apk 文件夹下\n（下面2句可以不执行）\n到此项目导入配置完成，关闭项目，使用Android studio重新打开项目，如果能开到某个文件夹上面有一个手机图标，恭喜你，项目配置成功了。\n备注：以上命令可以在Android studio中的Terminal中执行。\n","permalink":"https://blog.zdltech.com/posts/android-studio%E7%AC%AC%E4%B8%80%E6%AC%A1%E5%AF%BC%E5%85%A5%E9%A1%B9%E7%9B%AE%E9%81%87%E5%88%B0%E7%9A%84%E9%97%AE%E9%A2%98%E5%92%8C%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/","summary":"\u003cp\u003e在github或者其他的git平台下载的android studio项目导入到自己的Android studio中会出现一堆问题，\u003c/p\u003e\n\u003cp\u003e首先在导入之前先用自己的Android studio创建一个测试工程，主要使用测试工程下的2个文件，分别是：./build.gradle和./gradle/wrapper/gradle-wrapper.properties文件\u003c/p\u003e\n\u003cp\u003e例如1.build.gradle\u003cbr\u003e\ndependencies {\u003cbr\u003e\nclasspath ‘com.android.tools.build:gradle:1.2.3’\u003cbr\u003e\n}\u003cbr\u003e\n修改classpath中的gradle修改为你当前android studio环境中的配置\u003c/p\u003e\n\u003cp\u003e例如2.gradle/wrapper/gradle-wrapper.properties\u003c/p\u003e\n\u003cp\u003edistributionUrl=https://services.gradle.org/distributions/gradle-2.2.1-all.zip\u003cbr\u003e\n替换文件中的这句话，使用自己Android studio中相应语句\u003c/p\u003e\n\u003cp\u003e修改完成以上以后，打开Android studio选择/import project按照提示导入。\u003c/p\u003e\n\u003cp\u003e如何遇到导入的项目没有办法运行，这个时候我们运行 build/Rebuild Project进行重新编译项目。\u003cbr\u003e\n在此过程中遇到\u003cbr\u003e\nFAILURE: Build failed with an exception.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eWhat went wrong:\u003cbr\u003e\nTask ‘build.gradle’ not found in root project ‘XXX’.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eTry:\u003cbr\u003e\n说明我们导入的项目还没有符合我们的环境，我们需要进一步配置。\u003cbr\u003e\n打开cmd ,进入项目更目录执行\u003cbr\u003e\ngradlew\u003cbr\u003e\ngradlew build\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e检查环境变量是否配置了gradle环境，没有自己配置下，在执行gradlew时会出现解压的目录地址，自己手动配置到环境变量就行了。\u003cbr\u003e\n紧接着执行\u003cbr\u003e\ngradle build\u003cbr\u003e\ngradle tasks //查看android gradle的所有任务\u003cbr\u003e\ngradle compileReleaseSource //生成debug apk ，在build/outpus/apk 文件夹下\u003cbr\u003e\n（下面2句可以不执行）\u003cbr\u003e\n到此项目导入配置完成，关闭项目，使用Android studio重新打开项目，如果能开到某个文件夹上面有一个手机图标，恭喜你，项目配置成功了。\u003c/p\u003e\n\u003cp\u003e备注：以上命令可以在Android studio中的Terminal中执行。\u003c/p\u003e","title":"Android studio第一次导入项目遇到的问题，和解决方案"},{"content":"A curated list of awesome Android UI/UX libraries.\n{#user-content-other-lists.anchor}Other lists Looking for Core Library? Check out wasabeef/awesome-android-libraries. Looking for iOS? Check out cjwirth/awesome-ios-ui {#user-content-mantainers.anchor}Mantainers wasabeef\nogaclejapan\n{#user-content-index-light-weight-pages.anchor}Index (light-weight pages) Material Layout Button List / Grid ViewPager Label / Form Image SeekBar Progress Menu ActionBar Dialog Calendar Graph Animation Parallax Effect (Blur… etc) Other {#user-content-material.anchor}Material Name \u0026lt;th\u0026gt; License \u0026lt;/th\u0026gt; \u0026lt;th\u0026gt; Demo \u0026lt;/th\u0026gt; [MaterialDesignLibrary](https://github.com/navasmdc/MaterialDesignLibrary) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary2.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary3.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary3.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary4.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary4.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary5.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary5.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary6.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary6.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary7.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary7.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary8.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary8.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary9.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary9.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary10.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary10.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary11.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary11.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary12.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary12.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary13.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary13.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary14.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary14.png) \u0026lt;/td\u0026gt; [DrawerArrowDrawable](https://github.com/ChrisRenke/DrawerArrowDrawable) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/DrawerArrowDrawable.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/DrawerArrowDrawable.gif) \u0026lt;/td\u0026gt; [MaterialTabs](https://github.com/neokree/MaterialTabs) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialTabs.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialTabs.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialTabs2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialTabs2.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialTabs3.jpeg)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialTabs3.jpeg) \u0026lt;/td\u0026gt; [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/PagerSlidingTabStrip.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/PagerSlidingTabStrip.gif) \u0026lt;/td\u0026gt; [material-ripple](https://github.com/balysv/material-ripple) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-ripple.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-ripple.gif) \u0026lt;/td\u0026gt; [RippleEffect](https://github.com/traex/RippleEffect) \u0026lt;td\u0026gt; [MIT](http://opensource.org/licenses/MIT) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RippleEffect.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RippleEffect.gif) \u0026lt;/td\u0026gt; [LDrawer](https://github.com/ikimuhendis/LDrawer) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/LDrawer.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/LDrawer.gif) \u0026lt;/td\u0026gt; [material-design-icons](https://github.com/google/material-design-icons) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-design-icons.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-design-icons.png) \u0026lt;/td\u0026gt; [AndroidMaterialDesignToolbar](https://github.com/tekinarslan/AndroidMaterialDesignToolbar) \u0026lt;td\u0026gt; UnKnown \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidMaterialDesignToolbar.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidMaterialDesignToolbar.gif) \u0026lt;/td\u0026gt; [MaterialEditText](https://github.com/rengwuxian/MaterialEditText) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialEditText.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialEditText.png) \u0026lt;/td\u0026gt; [material-menu](https://github.com/balysv/material-menu) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-menu.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-menu.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-menu2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-menu2.gif) \u0026lt;/td\u0026gt; [material-dialogs](https://github.com/afollestad/material-dialogs) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-dialogs.webp)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-dialogs.webp) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-dialogs2.webp)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-dialogs2.webp) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-dialogs3.webp)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-dialogs3.webp) \u0026lt;/td\u0026gt; [AlertDialogPro](https://github.com/fengdai/AlertDialogPro) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AlertDialogPro.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AlertDialogPro.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AlertDialogPro2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AlertDialogPro2.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AlertDialogPro3.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AlertDialogPro3.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AlertDialogPro4.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AlertDialogPro4.png) \u0026lt;/td\u0026gt; [MaterialNavigationDrawer](https://github.com/neokree/MaterialNavigationDrawer) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialNavigationDrawer.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialNavigationDrawer.png) \u0026lt;/td\u0026gt; [MaterialDialog](https://github.com/drakeet/MaterialDialog) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDialog.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDialog.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDialog2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDialog2.png) \u0026lt;/td\u0026gt; [materialish-progress](https://github.com/pnikosis/materialish-progress) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/materialish-progress.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/materialish-progress.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/materialish-progress2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/materialish-progress2.gif) \u0026lt;/td\u0026gt; [FloatingActionButton](https://github.com/makovkastar/FloatingActionButton) \u0026lt;td\u0026gt; [MIT](http://opensource.org/licenses/MIT) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/FloatingActionButton.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/FloatingActionButton.gif) \u0026lt;/td\u0026gt; [android-floating-action-button](https://github.com/futuresimple/android-floating-action-button) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-floating-action-button.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-floating-action-button.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-floating-action-button.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-floating-action-button.png) \u0026lt;/td\u0026gt; [snackbar](https://github.com/nispok/snackbar) \u0026lt;td\u0026gt; [MIT](http://opensource.org/licenses/MIT) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/snackbar.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/snackbar.png) \u0026lt;/td\u0026gt; [CircularReveal](https://github.com/ozodrukh/CircularReveal) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/CircularReveal.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/CircularReveal.gif) \u0026lt;/td\u0026gt; [material-range-bar](https://github.com/oli107/material-range-bar) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-range-bar.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-range-bar.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-range-bar2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-range-bar2.png) \u0026lt;/td\u0026gt; [Lollipop-AppCompat-Widgets-Skeleton](https://github.com/sachin1092/Lollipop-AppCompat-Widgets-Skeleton) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/LollipopAppCompatWidgetSkeleton.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/LollipopAppCompatWidgetSkeleton.gif) \u0026lt;/td\u0026gt; [Carbon](https://github.com/ZieIony/Carbon) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; NONE \u0026lt;/td\u0026gt; [material-calendarview](https://github.com/prolificinteractive/material-calendarview) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-calendarview.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-calendarview.gif) \u0026lt;/td\u0026gt; [Material](https://github.com/rey5137/material) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material2.gif)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material3.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material3.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material4.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material4.gif)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material5.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material5.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material6.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material6.gif)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material7.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material7.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material8.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material8.gif)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material9.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material9.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material10.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material10.gif)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material11.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material11.png) \u0026lt;/td\u0026gt; {#user-content-layout.anchor}Layout Name License Demo WaveView Apache License V2 ResideLayout Apache License V2 AndroidSwipeLayout MIT FreeFlow Apache License V2 SwipeBackLayout Apache License V2 Maskable Layout Apache License V2 ExpandableLayout MIT android-PullRefreshLayout MIT TileView MIT ShowcaseView Apache License V2 Ultra Pull To Refresh Apache License V2 AndroidViewHover UnKnown DraggablePanel Apache License V2 Slidr Apache License V2 Phoenix Pull-to-Refresh Apache License V2 Pull-to-Refresh.Tours Apache License V2 InboxLayout UnKnown SwipeBack UnKnown ArcLayout Apache License V2 Dragger Apache License V2 PhysicsLayout Apache License V2 BottomSheet License Bubbles for Android Apache License V2 AndroidSlidingUpPanel Apache License V2 android-transition Apache License V2 {#user-content-button.anchor}Button Name License Demo circular-progress-button Apache License V2 android-process-button Apache License V2 android-circlebutton Apache License V2 android-flat-button Apache License V2 MovingButton MIT LabelView Apache License V2 {#user-content-list\u0026ndash;grid.anchor}List / Grid Name \u0026lt;th\u0026gt; License \u0026lt;/th\u0026gt; \u0026lt;th\u0026gt; Demo \u0026lt;/th\u0026gt; [SuperRecyclerView](https://github.com/Malinskiy/SuperRecyclerView) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; NONE \u0026lt;/td\u0026gt; [RecyclerViewSwipeDismiss](https://github.com/CodeFalling/RecyclerViewSwipeDismiss) \u0026lt;td\u0026gt; UnKnown \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RecyclerViewSwipeDismiss.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RecyclerViewSwipeDismiss.gif) \u0026lt;/td\u0026gt; [FlabbyListView](https://github.com/jpardogo/FlabbyListView) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/FlabbyListView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/FlabbyListView.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/FlabbyListView2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/FlabbyListView2.gif) \u0026lt;/td\u0026gt; [recyclerview-stickyheaders](https://github.com/eowise/recyclerview-stickyheaders) \u0026lt;td\u0026gt; [MIT](http://opensource.org/licenses/MIT) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/recyclerview-stickyheaders.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/recyclerview-stickyheaders.gif) \u0026lt;/td\u0026gt; [ParallaxListView](https://github.com/Gnod/ParallaxListView) \u0026lt;td\u0026gt; UnKnown \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/ParallaxListView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/ParallaxListView.gif) \u0026lt;/td\u0026gt; [PullZoomView](https://github.com/Frank-Zhu/PullZoomView) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/PullZoomView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/PullZoomView.gif) \u0026lt;/td\u0026gt; [SwipeMenuListView](https://github.com/baoyongzhang/SwipeMenuListView) \u0026lt;td\u0026gt; [MIT](http://opensource.org/licenses/MIT) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/SwipeMenuListView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/SwipeMenuListView.gif) \u0026lt;/td\u0026gt; [discrollview](https://github.com/flavienlaurent/discrollview) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/discrollview.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/discrollview.gif) \u0026lt;/td\u0026gt; [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/StickyListHeaders.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/StickyListHeaders.gif) \u0026lt;/td\u0026gt; [ListBuddies](https://github.com/jpardogo/ListBuddies) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/ListBuddies.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/ListBuddies.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/ListBuddies.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/ListBuddies.gif) \u0026lt;/td\u0026gt; [Android-ObservableScrollView](https://github.com/ksoichiro/Android-ObservableScrollView) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView2.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView3.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView3.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView4.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView4.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView5.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView5.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView6.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView6.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView7.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView7.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView8.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView8.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView9.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView9.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView10.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView10.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView11.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView11.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView12.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView12.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView13.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView13.gif) \u0026lt;/td\u0026gt; [AsymmetricGridView](https://github.com/felipecsl/AsymmetricGridView) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AsymmetricGridView.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AsymmetricGridView.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AsymmetricGridView2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AsymmetricGridView2.png) \u0026lt;/td\u0026gt; [DynamicGrid](https://github.com/askerov/DynamicGrid) \u0026lt;td\u0026gt; [MIT](http://opensource.org/licenses/MIT) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/DynamicGrid.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/DynamicGrid.gif) \u0026lt;/td\u0026gt; [AndroidStaggeredGrid](https://github.com/etsy/AndroidStaggeredGrid) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidStaggeredGrid.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidStaggeredGrid.png) \u0026lt;/td\u0026gt; [SwipeListView](https://github.com/47deg/android-swipelistview) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-swipelistview.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-swipelistview.png) \u0026lt;/td\u0026gt; [android-parallax-recyclerview](https://github.com/kanytu/android-parallax-recyclerview) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-parallax-recyclerview.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-parallax-recyclerview.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-parallax-recyclerview2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-parallax-recyclerview2.gif) \u0026lt;/td\u0026gt; [BlurStickyHeaderListView](https://github.com/emmano/BlurStickyHeaderListView) \u0026lt;td\u0026gt; [MIT](http://opensource.org/licenses/MIT) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/BlurStickyHeaderListView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/BlurStickyHeaderListView.gif) \u0026lt;/td\u0026gt; [RecyclerView Animators](https://github.com/wasabeef/recyclerview-animators) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/recyclerview-animators.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/recyclerview-animators.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/recyclerview-animators2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/recyclerview-animators2.gif) \u0026lt;/td\u0026gt; [RecyclerView-FlexibleDivider](https://github.com/yqritc/RecyclerView-FlexibleDivider) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RecyclerView-FlexibleDivider.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RecyclerView-FlexibleDivider.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RecyclerView-FlexibleDivider2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RecyclerView-FlexibleDivider2.png) \u0026lt;/td\u0026gt; [AndroidTreeView](https://github.com/bmelnychuk/AndroidTreeView) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidTreeView.webp)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidTreeView.webp) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidTreeView2.webp)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidTreeView2.webp) \u0026lt;/td\u0026gt; [RecyclerViewFastScroller](https://github.com/danoz73/RecyclerViewFastScroller) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RecyclerViewFastScroller.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RecyclerViewFastScroller.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RecyclerViewFastScroller2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RecyclerViewFastScroller2.png) \u0026lt;/td\u0026gt; [RecyclerView-MultipleViewTypesAdapter](https://github.com/yqritc/RecyclerView-MultipleViewTypesAdapter) \u0026lt;td\u0026gt; [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0) \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RecyclerView-MultipleViewTypesAdapter.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RecyclerView-MultipleViewTypesAdapter.gif) \u0026lt;/td\u0026gt; {#user-content-viewpager.anchor}ViewPager Name License Demo ParallaxPagerTransformer UnKnown ViewPagerTransforms Apache License V2 CircleIndicator MIT Android ViewPagerIndicator Apache License V2 Android-ParallaxHeaderViewPager Apache License V2 freepager Apache License V2 SpringIndicator Apache License V2 SmartTabLayout Apache License V2 FlipViewPager.Draco Apache License V2 MaterialViewPager Apache License V2 {#user-content-label\u0026ndash;form.anchor}Label / Form Name License Demo Shimmer-android Apache License V2 Shimmer for Android BSD 2 License Titanic Apache License V2 MatchView Apache License V2 android-autofittextview Apache License V2 SecretTextView UnKnown TextJustify-Android Apache License V2 RoundedLetterView Apache License V2 TextDrawable Apache License V2 BabushkaText Apache License V2 ExpandableTextView Apache License V2 Float Labeled EditText Apache License V2 SizeAdjustingTextView GNU License NONE {#user-content-image.anchor}Image Name License Demo TouchImageView LICENSE NONE CircleImageView Apache License V2 android-shape-imageview Apache License V2 GifImageView MIT cropper Apache License V2 android-crop Apache License V2 SelectableRoundedImageView Apache License V2 RoundedImageView Apache License V2 CropImageView Apache License V2 {#user-content-seekbar.anchor}SeekBar Name License Demo DiscreteSeekBar Apache License V2 {#user-content-progress.anchor}Progress Name License Demo SmoothProgressBar Apache License V2 NumberProgressBar MIT CircleProgress UnKnown android-square-progressbar UnKnown GoogleProgressBar Apache License V2 Android-RoundCornerProgressBar Apache License V2 ElasticDownload Apache License V2 FABProgressCircle Apache License V2 {#user-content-menu.anchor}Menu Name License Demo CircularFloatingActionMenu MIT AndroidResideMenu MIT Folder-ResideMenu Apache License V2 Side-Menu.Android Apache License V2 Context-Menu.Android Apache License V2 GuillotineMenu-Android Apache License V2 {#user-content-actionbar.anchor}ActionBar Name License Demo FadingActionBar Apache License V2 GlassActionBar Apache License V2 NotBoringActionBar Apache License V2 {#user-content-dialog.anchor}Dialog Name License Demo DialogPlus Apache License V2 Sweet Alert MIT {#user-content-calendar.anchor}Calendar Name License Demo Caldroid MIT android-times-square Apache License V2 Android-MonthCalendarWidget Apache License V2 android-betterpickers Apache License V2 Android-Week-View Apache License V2 SilkCal MIT SublimePicker Apache License V2 MaterialDateTimePicker Apache License V2 CompactCalendarView MIT {#user-content-graph.anchor}Graph Name License Demo EazeGraph Apache License V2 hellocharts-android Apache License V2 MPAndroidChart Apache License V2 WilliamChart Apache License V2 {#user-content-animation.anchor}Animation Name License Demo AndroidViewAnimations MIT ListViewAnimations Apache License V2 AndroidImageSlider MIT transitions-everywhere Apache License V2 Android Ripple Background MIT android-flip MIT FragmentTransactionExtended Apache License V2 KenBurnsView Apache License V2 rebound BSD 2 License http://facebook.github.io/rebound/ Reachability Apache License V2 AnimationEasingFunctions MIT EasyAndroidAnimations UnKnown android-pathview Apache License V2 ViewRevealAnimator Apache License V2 ArcAnimator MIT SearchMenuAnim UnKnown Cross View Apache License V2 {#user-content-parallax.anchor}Parallax Name License Demo ParallaxEverywhere MIT {#user-content-effect.anchor}Effect Name License Demo EtsyBlur Apache License V2 BlurDialogFragment Apache License V2 BlurBehind MIT Android StackBlur Apache License V2 EdgeEffectOverride Apache License V2 {#user-content-other.anchor}Other Name License Demo Swipecards Apache License V2 Android-Bootstrap MIT Android PDFView GPL V3 Dspec Apache License V2 LolliPin Apache License V2 DrawableView Apache License V2 Material Shadow 9-Patch Apache License V2 SimpleFingerGestures Apache License v2 Decor Apache License V2 Voice Recording Visualizer Apache License V2 EasyFonts Apache License V2 转自：https://github.com/wasabeef/awesome-android-ui\n","permalink":"https://blog.zdltech.com/posts/list-of-android-uiux-libraries/","summary":"\u003cp\u003eA curated list of awesome Android UI/UX libraries.\u003c/p\u003e\n\u003ch2 id=\"user-content-other-listsanchorother-lists\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#other-lists\"\u003e\u003c/a\u003e{#user-content-other-lists.anchor}Other lists\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eLooking for Core Library? Check out\u003c/em\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-libraries\"\u003ewasabeef/awesome-android-libraries\u003c/a\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eLooking for iOS? Check out\u003c/em\u003e \u003ca href=\"https://github.com/cjwirth/awesome-ios-ui\"\u003ecjwirth/awesome-ios-ui\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"user-content-mantainersanchormantainers\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#mantainers\"\u003e\u003c/a\u003e{#user-content-mantainers.anchor}Mantainers\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/wasabeef\"\u003e\u003cimg alt=\"wasabeef\" loading=\"lazy\" src=\"https://avatars0.githubusercontent.com/u/1833474?v=3\u0026s=32\"\u003e wasabeef\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"https://github.com/ogaclejapan\"\u003e\u003cimg alt=\"ogaclejapan\" loading=\"lazy\" src=\"https://avatars0.githubusercontent.com/u/1496485?v=3\u0026s=32\"\u003e ogaclejapan\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"user-content-index-light-weight-pagesanchorindex-light-weight-pages\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#index-light-weight-pages\"\u003e\u003c/a\u003e{#user-content-index-light-weight-pages.anchor}Index \u003ccode\u003e(light-weight pages)\u003c/code\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Material.md\"\u003eMaterial\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Layout.md\"\u003eLayout\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Button.md\"\u003eButton\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/List-Grid.md\"\u003eList / Grid\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/ViewPager.md\"\u003eViewPager\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Label-Form.md\"\u003eLabel / Form\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Image.md\"\u003eImage\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/SeekBar.md\"\u003eSeekBar\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Progress.md\"\u003eProgress\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Menu.md\"\u003eMenu\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/ActionBar.md\"\u003eActionBar\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Dialog.md\"\u003eDialog\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Calendar.md\"\u003eCalendar\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Graph.md\"\u003eGraph\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Animation.md\"\u003eAnimation\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Parallax.md\"\u003eParallax\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Effect.md\"\u003eEffect (Blur… etc)\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/pages/Other.md\"\u003eOther\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"user-content-materialanchormaterial\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#material\"\u003e\u003c/a\u003e{#user-content-material.anchor}Material\u003c/h1\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003e\n      Name\n    \u003c/th\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;th\u0026gt;\n  License\n\u0026lt;/th\u0026gt;\n\n\u0026lt;th\u0026gt;\n  Demo\n\u0026lt;/th\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [MaterialDesignLibrary](https://github.com/navasmdc/MaterialDesignLibrary)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary2.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary3.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary3.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary4.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary4.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary5.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary5.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary6.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary6.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary7.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary7.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary8.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary8.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary9.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary9.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary10.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary10.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary11.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary11.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary12.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary12.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary13.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary13.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDesignLibrary14.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDesignLibrary14.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [DrawerArrowDrawable](https://github.com/ChrisRenke/DrawerArrowDrawable)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/DrawerArrowDrawable.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/DrawerArrowDrawable.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [MaterialTabs](https://github.com/neokree/MaterialTabs)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialTabs.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialTabs.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialTabs2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialTabs2.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialTabs3.jpeg)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialTabs3.jpeg)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/PagerSlidingTabStrip.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/PagerSlidingTabStrip.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [material-ripple](https://github.com/balysv/material-ripple)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-ripple.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-ripple.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [RippleEffect](https://github.com/traex/RippleEffect)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [MIT](http://opensource.org/licenses/MIT)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RippleEffect.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RippleEffect.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [LDrawer](https://github.com/ikimuhendis/LDrawer)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/LDrawer.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/LDrawer.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [material-design-icons](https://github.com/google/material-design-icons)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-design-icons.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-design-icons.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [AndroidMaterialDesignToolbar](https://github.com/tekinarslan/AndroidMaterialDesignToolbar)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  UnKnown\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidMaterialDesignToolbar.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidMaterialDesignToolbar.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [MaterialEditText](https://github.com/rengwuxian/MaterialEditText)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialEditText.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialEditText.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [material-menu](https://github.com/balysv/material-menu)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-menu.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-menu.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-menu2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-menu2.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [material-dialogs](https://github.com/afollestad/material-dialogs)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-dialogs.webp)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-dialogs.webp) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-dialogs2.webp)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-dialogs2.webp) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-dialogs3.webp)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-dialogs3.webp)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [AlertDialogPro](https://github.com/fengdai/AlertDialogPro)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AlertDialogPro.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AlertDialogPro.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AlertDialogPro2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AlertDialogPro2.png)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AlertDialogPro3.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AlertDialogPro3.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AlertDialogPro4.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AlertDialogPro4.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [MaterialNavigationDrawer](https://github.com/neokree/MaterialNavigationDrawer)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialNavigationDrawer.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialNavigationDrawer.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [MaterialDialog](https://github.com/drakeet/MaterialDialog)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDialog.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDialog.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDialog2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDialog2.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [materialish-progress](https://github.com/pnikosis/materialish-progress)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/materialish-progress.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/materialish-progress.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/materialish-progress2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/materialish-progress2.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [FloatingActionButton](https://github.com/makovkastar/FloatingActionButton)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [MIT](http://opensource.org/licenses/MIT)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/FloatingActionButton.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/FloatingActionButton.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [android-floating-action-button](https://github.com/futuresimple/android-floating-action-button)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-floating-action-button.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-floating-action-button.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-floating-action-button.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-floating-action-button.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [snackbar](https://github.com/nispok/snackbar)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [MIT](http://opensource.org/licenses/MIT)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/snackbar.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/snackbar.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [CircularReveal](https://github.com/ozodrukh/CircularReveal)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/CircularReveal.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/CircularReveal.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [material-range-bar](https://github.com/oli107/material-range-bar)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-range-bar.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-range-bar.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-range-bar2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-range-bar2.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [Lollipop-AppCompat-Widgets-Skeleton](https://github.com/sachin1092/Lollipop-AppCompat-Widgets-Skeleton)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/LollipopAppCompatWidgetSkeleton.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/LollipopAppCompatWidgetSkeleton.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [Carbon](https://github.com/ZieIony/Carbon)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  NONE\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [material-calendarview](https://github.com/prolificinteractive/material-calendarview)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/material-calendarview.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/material-calendarview.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [Material](https://github.com/rey5137/material)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material2.gif)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material3.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material3.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material4.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material4.gif)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material5.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material5.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material6.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material6.gif)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material7.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material7.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material8.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material8.gif)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material9.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material9.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material10.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material10.gif)[![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Material11.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Material11.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-layoutanchorlayout\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#layout\"\u003e\u003c/a\u003e{#user-content-layout.anchor}Layout\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/john990/WaveView\"\u003eWaveView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/waveview.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/waveview.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/kyze8439690/ResideLayout\"\u003eResideLayout\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/ResideLayout.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/ResideLayout.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/daimajia/AndroidSwipeLayout\"\u003eAndroidSwipeLayout\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidSwipeLayout.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidSwipeLayout.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidSwipeLayout2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidSwipeLayout2.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Comcast/FreeFlow\"\u003eFreeFlow\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/FreeFlow.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/FreeFlow.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Issacw0ng/SwipeBackLayout\"\u003eSwipeBackLayout\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SwipeBackLayout.webp\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SwipeBackLayout.webp\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SwipeBackLayout2.webp\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SwipeBackLayout2.webp\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/christophesmet/android_maskable_layout\"\u003eMaskable Layout\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android_maskable_layout.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android_maskable_layout.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/traex/ExpandableLayout\"\u003eExpandableLayout\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/ExpandableLayout.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/ExpandableLayout.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/baoyongzhang/android-PullRefreshLayout\"\u003eandroid-PullRefreshLayout\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-PullRefreshLayout.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-PullRefreshLayout.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/moagrius/TileView\"\u003eTileView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/TileView.jpeg\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/TileView.jpeg\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/TileView2.jpeg\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/TileView2.jpeg\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/amlcurran/ShowcaseView\"\u003eShowcaseView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/ShowcaseView.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/ShowcaseView.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/ShowcaseView2.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/ShowcaseView2.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh\"\u003eUltra Pull To Refresh\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-Ultra-Pull-To-Refresh.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-Ultra-Pull-To-Refresh.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-Ultra-Pull-To-Refresh2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-Ultra-Pull-To-Refresh2.gif\"\u003e\u003c/a\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-Ultra-Pull-To-Refresh3.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-Ultra-Pull-To-Refresh3.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-Ultra-Pull-To-Refresh4.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-Ultra-Pull-To-Refresh4.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/daimajia/AndroidViewHover\"\u003eAndroidViewHover\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eUnKnown\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidViewHover.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidViewHover.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/pedrovgs/DraggablePanel\"\u003eDraggablePanel\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/DraggablePanel.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/DraggablePanel.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/DraggablePanel2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/DraggablePanel2.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/r0adkll/Slidr\"\u003eSlidr\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Slidr.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Slidr.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Yalantis/Phoenix\"\u003ePhoenix Pull-to-Refresh\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Phoenix.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Phoenix.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Yalantis/Taurus\"\u003ePull-to-Refresh.Tours\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Taurus.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Taurus.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/zhaozhentao/InboxLayout\"\u003eInboxLayout\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eUnKnown\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/InboxLayout.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/InboxLayout.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/liuguangqiang/SwipeBack\"\u003eSwipeBack\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eUnKnown\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SwipeBack.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SwipeBack.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SwipeBack2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SwipeBack2.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/ogaclejapan/ArcLayout\"\u003eArcLayout\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/arclayout1.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/arclayout1.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/ppamorim/Dragger\"\u003eDragger\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Dragger.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Dragger.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Jawnnypoo/PhysicsLayout\"\u003ePhysicsLayout\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/PhysicsLayout.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/PhysicsLayout.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Flipboard/bottomsheet\"\u003eBottomSheet\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Flipboard/bottomsheet/blob/master/LICENSE\"\u003eLicense\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/BottomSheet.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/BottomSheet.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/txusballesteros/bubbles-for-android\"\u003eBubbles for Android\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/bubbles-for-android.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/bubbles-for-android.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/umano/AndroidSlidingUpPanel\"\u003eAndroidSlidingUpPanel\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidSlidingUpPanel.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidSlidingUpPanel.jpg\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/kaichunlin/android-transition\"\u003eandroid-transition\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-transition.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-transition.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-buttonanchorbutton\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#button\"\u003e\u003c/a\u003e{#user-content-button.anchor}Button\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/dmytrodanylyk/circular-progress-button\"\u003ecircular-progress-button\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/circular-progress-button.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/circular-progress-button.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/dmytrodanylyk/android-process-button\"\u003eandroid-process-button\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-process-button.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-process-button.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-process-button2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-process-button2.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/markushi/android-circlebutton\"\u003eandroid-circlebutton\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-circlebutton.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-circlebutton.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/hoang8f/android-flat-button\"\u003eandroid-flat-button\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-flat-button.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-flat-button.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/TheFinestArtist/MovingButton\"\u003eMovingButton\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/MovingButton.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/MovingButton.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/linger1216/labelview\"\u003eLabelView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/linger1216/labelview/blob/master/img/img1.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/linger1216/labelview/raw/master/img/img1.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-listgridanchorlist--grid\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#list--grid\"\u003e\u003c/a\u003e{#user-content-list\u0026ndash;grid.anchor}List / Grid\u003c/h1\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003e\n      Name\n    \u003c/th\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;th\u0026gt;\n  License\n\u0026lt;/th\u0026gt;\n\n\u0026lt;th\u0026gt;\n  Demo\n\u0026lt;/th\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [SuperRecyclerView](https://github.com/Malinskiy/SuperRecyclerView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  NONE\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [RecyclerViewSwipeDismiss](https://github.com/CodeFalling/RecyclerViewSwipeDismiss)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  UnKnown\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RecyclerViewSwipeDismiss.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RecyclerViewSwipeDismiss.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [FlabbyListView](https://github.com/jpardogo/FlabbyListView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/FlabbyListView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/FlabbyListView.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/FlabbyListView2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/FlabbyListView2.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [recyclerview-stickyheaders](https://github.com/eowise/recyclerview-stickyheaders)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [MIT](http://opensource.org/licenses/MIT)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/recyclerview-stickyheaders.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/recyclerview-stickyheaders.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [ParallaxListView](https://github.com/Gnod/ParallaxListView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  UnKnown\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/ParallaxListView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/ParallaxListView.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [PullZoomView](https://github.com/Frank-Zhu/PullZoomView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/PullZoomView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/PullZoomView.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [SwipeMenuListView](https://github.com/baoyongzhang/SwipeMenuListView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [MIT](http://opensource.org/licenses/MIT)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/SwipeMenuListView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/SwipeMenuListView.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [discrollview](https://github.com/flavienlaurent/discrollview)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/discrollview.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/discrollview.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/StickyListHeaders.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/StickyListHeaders.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [ListBuddies](https://github.com/jpardogo/ListBuddies)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/ListBuddies.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/ListBuddies.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/ListBuddies.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/ListBuddies.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [Android-ObservableScrollView](https://github.com/ksoichiro/Android-ObservableScrollView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView2.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView3.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView3.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView4.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView4.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView5.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView5.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView6.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView6.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView7.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView7.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView8.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView8.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView9.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView9.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView10.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView10.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView11.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView11.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView12.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView12.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ObservableScrollView13.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ObservableScrollView13.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [AsymmetricGridView](https://github.com/felipecsl/AsymmetricGridView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AsymmetricGridView.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AsymmetricGridView.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AsymmetricGridView2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AsymmetricGridView2.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [DynamicGrid](https://github.com/askerov/DynamicGrid)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [MIT](http://opensource.org/licenses/MIT)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/DynamicGrid.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/DynamicGrid.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [AndroidStaggeredGrid](https://github.com/etsy/AndroidStaggeredGrid)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidStaggeredGrid.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidStaggeredGrid.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [SwipeListView](https://github.com/47deg/android-swipelistview)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-swipelistview.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-swipelistview.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [android-parallax-recyclerview](https://github.com/kanytu/android-parallax-recyclerview)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-parallax-recyclerview.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-parallax-recyclerview.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-parallax-recyclerview2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-parallax-recyclerview2.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [BlurStickyHeaderListView](https://github.com/emmano/BlurStickyHeaderListView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [MIT](http://opensource.org/licenses/MIT)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/BlurStickyHeaderListView.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/BlurStickyHeaderListView.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [RecyclerView Animators](https://github.com/wasabeef/recyclerview-animators)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/recyclerview-animators.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/recyclerview-animators.gif) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/recyclerview-animators2.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/recyclerview-animators2.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [RecyclerView-FlexibleDivider](https://github.com/yqritc/RecyclerView-FlexibleDivider)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RecyclerView-FlexibleDivider.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RecyclerView-FlexibleDivider.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RecyclerView-FlexibleDivider2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RecyclerView-FlexibleDivider2.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [AndroidTreeView](https://github.com/bmelnychuk/AndroidTreeView)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidTreeView.webp)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidTreeView.webp) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidTreeView2.webp)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidTreeView2.webp)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [RecyclerViewFastScroller](https://github.com/danoz73/RecyclerViewFastScroller)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RecyclerViewFastScroller.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RecyclerViewFastScroller.png) [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RecyclerViewFastScroller2.png)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RecyclerViewFastScroller2.png)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      [RecyclerView-MultipleViewTypesAdapter](https://github.com/yqritc/RecyclerView-MultipleViewTypesAdapter)\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td\u0026gt;\n  [Apache License V2](https://www.apache.org/licenses/LICENSE-2.0)\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td\u0026gt;\n  [![](https://github.com/wasabeef/awesome-android-ui/raw/master/art/RecyclerView-MultipleViewTypesAdapter.gif)](https://github.com/wasabeef/awesome-android-ui/blob/master/art/RecyclerView-MultipleViewTypesAdapter.gif)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-viewpageranchorviewpager\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#viewpager\"\u003e\u003c/a\u003e{#user-content-viewpager.anchor}ViewPager\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/xgc1986/ParallaxPagerTransformer\"\u003eParallaxPagerTransformer\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eUnKnown\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/ParallaxPagerTransformer.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/ParallaxPagerTransformer.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/ToxicBakery/ViewPagerTransforms\"\u003eViewPagerTransforms\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/ViewPagerTransforms.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/ViewPagerTransforms.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/ongakuer/CircleIndicator\"\u003eCircleIndicator\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/CircleIndicator.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/CircleIndicator.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/JakeWharton/Android-ViewPagerIndicator\"\u003eAndroid ViewPagerIndicator\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ViewPagerIndicator.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ViewPagerIndicator.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/kmshack/Android-ParallaxHeaderViewPager\"\u003eAndroid-ParallaxHeaderViewPager\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-ParallaxHeaderViewPager.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-ParallaxHeaderViewPager.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/alexzaitsev/freepager\"\u003efreepager\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/freepager.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/freepager.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/chenupt/SpringIndicator\"\u003eSpringIndicator\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SpringIndicator.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SpringIndicator.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/ogaclejapan/SmartTabLayout\"\u003eSmartTabLayout\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/smarttablayout.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/smarttablayout.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Yalantis/FlipViewPager.Draco\"\u003eFlipViewPager.Draco\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/FlipViewPager-Draco.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/FlipViewPager-Draco.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/florent37/MaterialViewPager\"\u003eMaterialViewPager\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialViewPager.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialViewPager.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialViewPager2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialViewPager2.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-labelformanchorlabel--form\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#label--form\"\u003e\u003c/a\u003e{#user-content-label\u0026ndash;form.anchor}Label / Form\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/RomainPiel/Shimmer-android\"\u003eShimmer-android\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Shimmer-android.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Shimmer-android.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/facebook/shimmer-android\"\u003eShimmer for Android\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/BSD-2-Clause\"\u003eBSD 2 License\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/shimmer-android-fb.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/shimmer-android-fb.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/RomainPiel/Titanic\"\u003eTitanic\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Titanic.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Titanic.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Rogero0o/MatchView\"\u003eMatchView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/MatchView.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/MatchView.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/grantland/android-autofittextview\"\u003eandroid-autofittextview\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-autofittextview.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-autofittextview.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/matthewrkula/SecretTextView\"\u003eSecretTextView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eUnKnown\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SecretTextView.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SecretTextView.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/bluejamesbond/TextJustify-Android\"\u003eTextJustify-Android\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/TextJustify-Android.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/TextJustify-Android.png\"\u003e\u003c/a\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/TextJustify-Android2.jpeg\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/TextJustify-Android2.jpeg\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/pavlospt/RoundedLetterView\"\u003eRoundedLetterView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/RoundedLetterView.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/RoundedLetterView.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/amulyakhare/TextDrawable\"\u003eTextDrawable\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/TextDrawable.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/TextDrawable.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/TextDrawable2.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/TextDrawable2.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/quiqueqs/BabushkaText\"\u003eBabushkaText\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/BabushkaText.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/BabushkaText.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Manabu-GT/ExpandableTextView\"\u003eExpandableTextView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/ExpandableTextView.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/ExpandableTextView.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wrapp/floatlabelededittext\"\u003eFloat Labeled EditText\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/floatlabelededittext.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/floatlabelededittext.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/erchenger/SizeAdjustingTextView\"\u003eSizeAdjustingTextView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://www.gnu.org/licenses/gpl-3.0.en.html\"\u003eGNU License\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eNONE\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-imageanchorimage\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#image\"\u003e\u003c/a\u003e{#user-content-image.anchor}Image\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/MikeOrtiz/TouchImageView\"\u003eTouchImageView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://raw.githubusercontent.com/MikeOrtiz/TouchImageView/master/LICENSE\"\u003eLICENSE\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eNONE\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/hdodenhof/CircleImageView\"\u003eCircleImageView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/CircleImageView.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/CircleImageView.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/siyamed/android-shape-imageview\"\u003eandroid-shape-imageview\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-shape-imageview.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-shape-imageview.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-shape-imageview2.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-shape-imageview2.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/felipecsl/GifImageView\"\u003eGifImageView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/GifImageView.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/GifImageView.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/edmodo/cropper\"\u003ecropper\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/cropper.jpeg\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/cropper.jpeg\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/jdamcd/android-crop\"\u003eandroid-crop\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-crop.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-crop.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/pungrue26/SelectableRoundedImageView\"\u003eSelectableRoundedImageView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SelectableRoundedImageView.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SelectableRoundedImageView.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/vinc3m1/RoundedImageView\"\u003eRoundedImageView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/RoundedImageView.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/RoundedImageView.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/RoundedImageView2.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/RoundedImageView2.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/cesards/CropImageView\"\u003eCropImageView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/CropImageView.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/CropImageView.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-seekbaranchorseekbar\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#seekbar\"\u003e\u003c/a\u003e{#user-content-seekbar.anchor}SeekBar\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/AnderWeb/discreteSeekBar\"\u003eDiscreteSeekBar\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/discreteseekbar.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/discreteseekbar.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/discreteseekbar2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/discreteseekbar2.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-progressanchorprogress\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#progress\"\u003e\u003c/a\u003e{#user-content-progress.anchor}Progress\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/castorflex/SmoothProgressBar\"\u003eSmoothProgressBar\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SmoothProgressBar.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SmoothProgressBar.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/daimajia/NumberProgressBar\"\u003eNumberProgressBar\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/NumberProgressBar.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/NumberProgressBar.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/lzyzsd/CircleProgress\"\u003eCircleProgress\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eUnKnown\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/CircleProgress.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/CircleProgress.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/mrwonderman/android-square-progressbar\"\u003eandroid-square-progressbar\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eUnKnown\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-square-progressbar.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-square-progressbar.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-square-progressbar2.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-square-progressbar2.png\"\u003e\u003c/a\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-square-progressbar3.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-square-progressbar3.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/jpardogo/GoogleProgressBar\"\u003eGoogleProgressBar\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/GoogleProgressBar.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/GoogleProgressBar.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/GoogleProgressBar2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/GoogleProgressBar2.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/GoogleProgressBar3.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/GoogleProgressBar3.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/akexorcist/Android-RoundCornerProgressBar\"\u003eAndroid-RoundCornerProgressBar\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-RoundCornerProgressBar.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-RoundCornerProgressBar.png\"\u003e\u003c/a\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-RoundCornerProgressBar2.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-RoundCornerProgressBar2.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Tibolte/ElasticDownload\"\u003eElasticDownload\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/ElasticDownload.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/ElasticDownload.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/ElasticDownload2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/ElasticDownload2.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/JorgeCastilloPrz/FABProgressCircle\"\u003eFABProgressCircle\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/FABProgressCircle.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/FABProgressCircle.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-menuanchormenu\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#menu\"\u003e\u003c/a\u003e{#user-content-menu.anchor}Menu\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/oguzbilgener/CircularFloatingActionMenu\"\u003eCircularFloatingActionMenu\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/CircularFloatingActionMenu.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/CircularFloatingActionMenu.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/SpecialCyCi/AndroidResideMenu\"\u003eAndroidResideMenu\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidResideMenu.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidResideMenu.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/dkmeteor/Folder-ResideMenu\"\u003eFolder-ResideMenu\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Folder-ResideMenu.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Folder-ResideMenu.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Yalantis/Side-Menu.Android\"\u003eSide-Menu.Android\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Side-Menu.Android.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Side-Menu.Android.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Yalantis/Context-Menu.Android\"\u003eContext-Menu.Android\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Context-Menu.Android.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Context-Menu.Android.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Yalantis/GuillotineMenu-Android\"\u003eGuillotineMenu-Android\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/GuillotineMenu-Android.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/GuillotineMenu-Android.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-actionbaranchoractionbar\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#actionbar\"\u003e\u003c/a\u003e{#user-content-actionbar.anchor}ActionBar\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/ManuelPeinado/FadingActionBar\"\u003eFadingActionBar\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/FadingActionBar.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/FadingActionBar.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/ManuelPeinado/GlassActionBar\"\u003eGlassActionBar\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/GlassActionBar.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/GlassActionBar.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/flavienlaurent/NotBoringActionBar\"\u003eNotBoringActionBar\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/NotBoringActionBar.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/NotBoringActionBar.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-dialoganchordialog\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#dialog\"\u003e\u003c/a\u003e{#user-content-dialog.anchor}Dialog\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/orhanobut/dialogplus\"\u003eDialogPlus\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/DialogPlus.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/DialogPlus.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/DialogPlus2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/DialogPlus2.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/pedant/sweet-alert-dialog\"\u003eSweet Alert\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/swalert_change_type.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/swalert_change_type.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-calendaranchorcalendar\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#calendar\"\u003e\u003c/a\u003e{#user-content-calendar.anchor}Calendar\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/roomorama/Caldroid\"\u003eCaldroid\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Caldroid.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Caldroid.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/square/android-times-square\"\u003eandroid-times-square\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-times-square.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-times-square.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/romannurik/Android-MonthCalendarWidget\"\u003eAndroid-MonthCalendarWidget\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-MonthCalendarWidget.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-MonthCalendarWidget.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/derekbrameyer/android-betterpickers\"\u003eandroid-betterpickers\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-betterpickers.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-betterpickers.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/alamkanak/Android-Week-View\"\u003eAndroid-Week-View\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-Week-View.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-Week-View.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/NLMartian/SilkCal\"\u003eSilkCal\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SilkCat.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SilkCat.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/vikramkakkar/SublimePicker\"\u003eSublimePicker\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/sublimePicker_date.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/sublimePicker_date.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/sublimePicker_time.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/sublimePicker_time.png\"\u003e\u003c/a\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/sublimePicker_repeat.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/sublimePicker_repeat.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wdullaer/MaterialDateTimePicker\"\u003eMaterialDateTimePicker\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDateTimePicker_date.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDateTimePicker_date.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/MaterialDateTimePicker_time.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/MaterialDateTimePicker_time.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/SundeepK/CompactCalendarView\"\u003eCompactCalendarView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/compact-calendar-demo.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/compact-calendar-demo.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-graphanchorgraph\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#graph\"\u003e\u003c/a\u003e{#user-content-graph.anchor}Graph\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/blackfizz/EazeGraph\"\u003eEazeGraph\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/EazeGraph.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/EazeGraph.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/EazeGraph2.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/EazeGraph2.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/EazeGraph3.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/EazeGraph3.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/EazeGraph4.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/EazeGraph4.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/lecho/hellocharts-android\"\u003ehellocharts-android\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/hellocharts-android.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/hellocharts-android.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/hellocharts-android2.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/hellocharts-android2.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/hellocharts-android3.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/hellocharts-android3.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/PhilJay/MPAndroidChart\"\u003eMPAndroidChart\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/MPAndroidChart.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/MPAndroidChart.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/MPAndroidChart2.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/MPAndroidChart2.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/MPAndroidChart3.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/MPAndroidChart3.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/MPAndroidChart4.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/MPAndroidChart4.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/diogobernardino/WilliamChart\"\u003eWilliamChart\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/williamchart_line.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/williamchart_line.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/williamchart_bar.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/williamchart_bar.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-animationanchoranimation\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#animation\"\u003e\u003c/a\u003e{#user-content-animation.anchor}Animation\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/daimajia/AndroidViewAnimations\"\u003eAndroidViewAnimations\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/androidviewanimations.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/androidviewanimations.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/nhaarman/ListViewAnimations\"\u003eListViewAnimations\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/ListViewAnimations.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/ListViewAnimations.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/daimajia/AndroidImageSlider\"\u003eAndroidImageSlider\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/AndroidImageSlider.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/AndroidImageSlider.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/andkulikov/transitions-everywhere\"\u003etransitions-everywhere\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/transitions-everywhere.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/transitions-everywhere.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/skyfishjy/android-ripple-background\"\u003eAndroid Ripple Background\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-ripple-background.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-ripple-background.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-ripple-background2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-ripple-background2.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/openaphid/android-flip\"\u003eandroid-flip\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-flip.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-flip.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-flip2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-flip2.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/DesarrolloAntonio/FragmentTransactionExtended\"\u003eFragmentTransactionExtended\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/FragmentTransactionExtended.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/FragmentTransactionExtended.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/FragmentTransactionExtended2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/FragmentTransactionExtended2.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/flavioarfaria/KenBurnsView\"\u003eKenBurnsView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/KenBurnsView.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/KenBurnsView.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/facebook/rebound\"\u003erebound\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/BSD-2-Clause\"\u003eBSD 2 License\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://facebook.github.io/rebound/\"\u003ehttp://facebook.github.io/rebound/\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/sakebook/Reachability\"\u003eReachability\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Reachability.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Reachability.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/daimajia/AnimationEasingFunctions\"\u003eAnimationEasingFunctions\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/AnimationEasingFunctions.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/AnimationEasingFunctions.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/2359media/EasyAndroidAnimations\"\u003eEasyAndroidAnimations\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eUnKnown\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/EasyAndroidAnimations.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/EasyAndroidAnimations.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/geftimov/android-pathview\"\u003eandroid-pathview\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-pathview.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-pathview.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/sephiroth74/ViewRevealAnimator\"\u003eViewRevealAnimator\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/ViewRevealAnimator.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/ViewRevealAnimator.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/asyl/ArcAnimator\"\u003eArcAnimator\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/ArcAnimator.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/ArcAnimator.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/ArcAnimator2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/ArcAnimator2.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/kongnanlive/SearchMenuAnim\"\u003eSearchMenuAnim\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003eUnKnown\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SearchMenuAnim.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SearchMenuAnim.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/cdflynn/crossview\"\u003eCross View\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/crossview.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/crossview.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/crossview2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/crossview2.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-parallaxanchorparallax\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#parallax\"\u003e\u003c/a\u003e{#user-content-parallax.anchor}Parallax\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Narfss/ParallaxEverywhere\"\u003eParallaxEverywhere\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/parallax-everywhere.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/parallax-everywhere.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-effectanchoreffect\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#effect\"\u003e\u003c/a\u003e{#user-content-effect.anchor}Effect\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Manabu-GT/EtsyBlur\"\u003eEtsyBlur\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/EtsyBlur.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/EtsyBlur.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/tvbarthel/BlurDialogFragment\"\u003eBlurDialogFragment\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/BlurDialogFragment.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/BlurDialogFragment.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/BlurDialogFragment2.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/BlurDialogFragment2.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/faradaj/BlurBehind\"\u003eBlurBehind\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/BlurBehind.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/BlurBehind.png\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/BlurBehind2.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/BlurBehind2.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/kikoso/android-stackblur\"\u003eAndroid StackBlur\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-stackblur.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-stackblur.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/AndroidAlliance/EdgeEffectOverride\"\u003eEdgeEffectOverride\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/EdgeEffectOverride.jpeg\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/EdgeEffectOverride.jpeg\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"user-content-otheranchorother\"\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui#other\"\u003e\u003c/a\u003e{#user-content-other.anchor}Other\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eName\u003c/th\u003e\n          \u003cth\u003eLicense\u003c/th\u003e\n          \u003cth\u003eDemo\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Diolor/Swipecards\"\u003eSwipecards\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Swipecards.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Swipecards.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/Bearded-Hen/Android-Bootstrap\"\u003eAndroid-Bootstrap\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/MIT\"\u003eMIT\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/Android-Bootstrap.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/Android-Bootstrap.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/JoanZapata/android-pdfview\"\u003eAndroid PDFView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://opensource.org/licenses/GPL-3.0\"\u003eGPL V3\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-pdfview.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-pdfview.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/lucasr/dspec\"\u003eDspec\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/dspec.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/dspec.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/OrangeGangsters/LolliPin\"\u003eLolliPin\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/LolliPin.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/LolliPin.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/PaNaVTEC/DrawableView\"\u003eDrawableView\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/DrawableView.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/DrawableView.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/h6ah4i/android-materialshadowninepatch\"\u003eMaterial Shadow 9-Patch\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/android-materialshadowninepatch.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/android-materialshadowninepatch.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/championswimmer/SimpleFingerGestures_Android_Library\"\u003eSimpleFingerGestures\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/championswimmer/SimpleFingerGestures_Android_Library/blob/master/LICENSE\"\u003eApache License v2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SimpleFingerGestures1.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SimpleFingerGestures1.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SimpleFingerGestures2.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SimpleFingerGestures2.gif\"\u003e\u003c/a\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SimpleFingerGestures3.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SimpleFingerGestures3.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/SimpleFingerGestures4.gif\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/SimpleFingerGestures4.gif\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/chemouna/decor\"\u003eDecor\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/decor.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/decor.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/tyorikan/voice-recording-visualizer\"\u003eVoice Recording Visualizer\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"http://www.youtube.com/watch?v=fJTl1bgQ3j4\"\u003e\u003cimg alt=\"IMAGE demo\" loading=\"lazy\" src=\"https://camo.githubusercontent.com/dec65b58525ce17eff5e0318d3c39ae33760284a/687474703a2f2f696d672e796f75747562652e636f6d2f76692f664a546c31626751336a342f302e6a7067\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/vsvankhede/easyfonts\"\u003eEasyFonts\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\"\u003eApache License V2\u003c/a\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ca href=\"https://github.com/wasabeef/awesome-android-ui/blob/master/art/easyfonts.png\"\u003e\u003cimg loading=\"lazy\" src=\"https://github.com/wasabeef/awesome-android-ui/raw/master/art/easyfonts.png\"\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e转自：https://github.com/wasabeef/awesome-android-ui\u003c/p\u003e","title":"List of Android UI/UX Libraries"},{"content":"今天在使用Proguard keep一个 静态内部类的时候，混淆完之后一直找不到那个静态内部类，内心抓狂啊。\n最后在stackoverflow上找到了答案：\n**[html]** [view plain](http://blog.csdn.net/top_code/article/details/18225501#)[copy](http://blog.csdn.net/top_code/article/details/18225501#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/154763)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/154763/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - -keepattributes Exceptions,InnerClasses,\u0026amp;#8230; - -keep class [packagename].A{ - *; - } - -keep class [packagename].A$* { - *; - } 其中 A$* 表示所有A的内部类都保留下来，也可以如下使用：\n**[html]** [view plain](http://blog.csdn.net/top_code/article/details/18225501#)[copy](http://blog.csdn.net/top_code/article/details/18225501#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/154763)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/154763/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - -keepattributes Exceptions,InnerClasses,\u0026amp;#8230; - -keep class com.xxx.A{ *; } - -keep class com.xxx.A$B { *; } - -keep class com.xxx.A$C { *; } 这样可以根据需要只保留A的某一个内部类\n以下是proguard文件一部分\n**[html]** [view plain](http://blog.csdn.net/top_code/article/details/18225501#)[copy](http://blog.csdn.net/top_code/article/details/18225501#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/154763)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/154763/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - #-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod - -keepattributes Exceptions,InnerClasses,\u0026amp;#8230; - -keep class com.yulore.reverselookup.api.YuloreWindowConfiguration{ *; } - -keep class com.yulore.reverselookup.api.YuloreWindowConfiguration$Builder{ *; } 注意：第一行和第二行都可以解决问题\n转自：http://blog.csdn.net/top_code/article/details/18225501\n","permalink":"https://blog.zdltech.com/posts/proguard-keep-static-inner-class-proguard-keep%E4%B8%80%E4%B8%AA-%E9%9D%99%E6%80%81%E5%86%85%E9%83%A8%E7%B1%BB%E7%9A%84%E6%97%B6%E5%80%99/","summary":"\u003cp\u003e今天在使用Proguard keep一个 静态内部类的时候，混淆完之后一直找不到那个静态内部类，内心抓狂啊。\u003c/p\u003e\n\u003cp\u003e最后在stackoverflow上找到了答案：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/top_code/article/details/18225501#)[copy](http://blog.csdn.net/top_code/article/details/18225501#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/154763)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/154763/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- -keepattributes Exceptions,InnerClasses,\u0026amp;#8230;\n\n- -keep class [packagename].A{\n\n- *;\n\n- }\n\n- -keep class [packagename].A$* {\n\n- *;\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e其中 A$* 表示所有A的内部类都保留下来，也可以如下使用：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/top_code/article/details/18225501#)[copy](http://blog.csdn.net/top_code/article/details/18225501#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/154763)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/154763/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- -keepattributes Exceptions,InnerClasses,\u0026amp;#8230;\n\n- -keep class com.xxx.A{ *; }\n\n- -keep class com.xxx.A$B { *; }\n\n- -keep class com.xxx.A$C { *; }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Proguard keep static Inner Class Proguard keep一个 静态内部类的时候"},{"content":"emoji 表情 编码整理，有需要的朋友可以参考下。\nvar faces_array = {\n‘:bowtie:’:1,\n‘:smile:’:U+1F604,\n‘:laughing:’:U+1F606,\n‘:blush:’:U+1F60A,\n‘:smiley:’:U+1F603,\n‘:relaxed:’:U+263A,\n‘:smirk:’:U+1F60F,\n‘:heart_eyes:’:U+1F60D,\n‘:kissing_heart:’:U+1F618,\n‘:kissing_closed_eyes:’:U+1F61A,\n‘:flushed:’:U+1F633,\n‘:relieved:’:U+1F60C,\n‘:satisfied:’:U+1F606,\n‘:grin:’:U+1F601,\n‘:wink:’:U+1F609,\n‘:stuck_out_tongue_winking_eye:’:U+1F61C,\n‘:stuck_out_tongue_closed_eyes:’:U+1F61D,\n‘:grinning:’:U+1F601,\n‘:kissing:’:U+1F619,\n‘:kissing_smiling_eyes:’:U+1F617,\n‘:stuck_out_tongue:’:U+1F61C,\n‘:sleeping:’:22,\n‘:worried:’:U+1F61F,\n‘:frowning:’:U+1F627,\n‘:anguished:’:U+1F626,\n‘:open_mouth:’:U+1F62E,\n‘:grimacing:’:U+1F600,\n‘:confused:’:U+1F62F,\n‘:hushed:’:29,\n‘:expressionless:’:U+1F611,\n‘:unamused:’:U+1F612,\n‘:sweat_smile:’:U+1F605,\n‘:sweat:’:U+1F613,\n‘:disappointed_relieved:’:U+1F625,\n‘:weary:’:U+1F629,\n‘:pensive:’:U+1F614,\n‘:disappointed:’:U+1F61E,\n‘:confounded:’:U+1F616,\n‘:fearful:’:U+1F628,\n‘:cold_sweat:’:U+1F630,\n‘:persevere:’:U+1F623,\n‘:cry:’:U+1F622,\n‘:sob:’:U+1F62D,\n‘:joy:’:U+1F602,\n‘:astonished:’:U+1F632,\n‘:scream:’:U+1F631,\n‘:neckbeard:’:47,\n‘:tired_face:’:U+1F62B,\n‘:angry:’:U+1F620,\n‘:rage:’:U+1F621,\n‘:triumph:’:U+1F624,\n‘:sleepy:’:U+1F62A,\n‘:yum:’:U+1F60B,\n‘:mask:’:U+1F637,\n‘:sunglasses:’:U+1F60E,\n‘:dizzy_face:’:U+1F635,\n‘:imp:’:U+1F47F,\n‘:smiling_imp:’:U+1F608,\n‘:neutral_face:’:U+1F610,\n‘:no_mouth:’:U+1F636,\n‘:innocent:’:U+1F607,\n‘:alien:’:U+1F47D,\n‘:yellow_heart:’:U+1F49B,\n‘:blue_heart:’:U+1F499,\n‘:purple_heart:’:U+1F49C,\n‘:heart:’:U+2764,\n‘:green_heart:’:U+1F49A,\n‘:broken_heart:’:U+1F494,\n‘:heartbeat:’:U+1F493,\n‘:heartpulse:’:U+1F497,\n‘:two_hearts:’:U+1F495,\n‘:revolving_hearts:’:U+1F49E,\n‘:cupid:’:U+1F498,\n‘:sparkling_heart:’:U+1F496,\n‘:sparkles:’:U+2728,\n‘:star:’:U+2B50,\n‘:star2:’:U+1F31F,\n‘:dizzy:’:U+1F4AB,\n‘:boom:’:U+1F4A5,\n‘:collision:’:U+1F4A5,\n‘:anger:’:U+1F4A2,\n‘:exclamation:’:U+2757,\n‘:question:’:U+2753,\n‘:grey_exclamation:’:U+2755,\n‘:grey_question:’:U+2754,\n‘:zzz:’:U+1F4A4,\n‘:dash:’:U+1F4A8,\n‘:sweat_drops:’:U+1F4A6,\n‘:notes:’:U+1F3B6,\n‘:musical_note:’:U+1F3B5,\n‘:fire:’:U+1F525,\n‘:hankey:’:U+1F4A9,\n‘:poop:’:U+1F4A9,\n‘:shit:’:U+1F4A9,\n‘:+1:’:U+1F44D,\n‘:thumbsup:’:U+1F44D,\n‘:-1:’:U+1F44E,\n‘:thumbsdown:’:U+1F44E,\n‘:ok_hand:’:U+1F44C,\n‘:punch:’:U+1F44A,\n‘:facepunch:’:101,\n‘:fist:’:U+270A,\n‘:v:’:U+270C,\n‘:wave:’:U+1F44B,\n‘:hand:’:U+270B,\n‘:raised_hand:’:U+270B,\n‘:open_hands:’:U+1F450,\n‘:point_up:’:U+261D,\n‘:point_down:’:U+1F447,\n‘:point_left:’:U+1F448,\n‘:point_right:’:U+1F449,\n‘:raised_hands:’:U+1F64C,\n‘:pray:’:U+1F64F,\n‘:point_up_2:’:U+1F446,\n‘:clap:’:U+1F44F,\n‘:muscle:’:U+1F4AA,\n‘:metal:’:117,\n‘:fu:’:118,\n‘:walking:’:U+1F6B6,\n‘:runner:’:U+1F3C3,\n‘:running:’:U+1F3C3,\n‘:couple:’:U+1F46B,\n‘:family:’:U+1F46A,\n‘:two_men_holding_hands:’:U+1F46C,\n‘:two_women_holding_hands:’:U+1F46D,\n‘:dancer:’:U+1F483,\n‘:dancers:’:U+1F46F,\n‘:ok_woman:’:U+1F646,\n‘:no_good:’:U+1F645,\n‘:information_desk_person:’:U+1F481,\n‘:raising_hand:’:U+1F64B,\n‘:bride_with_veil:’:U+1F470,\n‘:person_with_pouting_face:’:U+1F64E,\n‘:person_frowning:’:U+1F64D,\n‘:bow:’:U+1F647,\n‘:couplekiss:’:U+1F48F,\n‘:couple_with_heart:’:U+1F491,\n‘:massage:’:U+1F486,\n‘:haircut:’:U+1F487,\n‘:nail_care:’:U+1F485,\n‘:boy:’:U+1F466,\n‘:girl:’:U+1F467,\n‘:woman:’:U+1F469,\n‘:man:’:U+1F468,\n‘:baby:’:U+1F476,\n‘:older_woman:’:U+1F475,\n‘:older_man:’:U+1F474,\n‘:person_with_blond_hair:’:U+1F471,\n‘:man_with_gua_pi_mao:’:U+1F472,\n‘:man_with_turban:’:U+1F473,\n‘:construction_worker:’:U+1F477,\n‘:cop:’:U+1F46E,\n‘:angel:’:U+1F47C,\n‘:princess:’:U+1F478,\n‘:smiley_cat:’:U+1F63A,\n‘:smile_cat:’:U+1F638,\n‘:heart_eyes_cat:’:U+1F63B,\n‘:kissing_cat:’:U+1F63D,\n‘:smirk_cat:’:U+1F63C,\n‘:scream_cat:’:U+1F640,\n‘:crying_cat_face:’:U+1F63F,\n‘:joy_cat:’:U+1F639,\n‘:pouting_cat:’:U+1F63E,\n‘:japanese_ogre:’:U+1F479,\n‘:japanese_goblin:’:U+1F47A,\n‘:see_no_evil:’:U+1F648,\n‘:hear_no_evil:’:U+1F649,\n‘:speak_no_evil:’:U+1F64A,\n‘:guardsman:’:U+1F482,\n‘:skull:’:U+1F480,\n‘:feet:’:U+1F463,\n‘:lips:’:U+1F444,\n‘:kiss:’:U+1F48B,\n‘:droplet:’:U+1F4A7,\n‘:ear:’:U+1F442,\n‘:eyes:’:U+1F440,\n‘:nose:’:U+1F443,\n‘:tongue:’:U+1F445,\n‘:love_letter:’:U+1F48C,\n‘:bust_in_silhouette:’:U+1F464,\n‘:busts_in_silhouette:’:U+1F465,\n‘:speech_balloon:’:U+1F4AC,\n‘:thought_balloon:’:U+1F4AD,\n‘:feelsgood:’:184,\n‘:finnadie:’:185,\n‘:goberserk:’:186,\n‘:godmode:’:187,\n‘:hurtrealbad:’:188,\n‘:rage1:’:189,\n‘:rage2:’:190,\n‘:rage3:’:191,\n‘:rage4:’:192,\n‘:suspect:’:193,\n‘:trollface:’:194,\n‘:sunny:’:U+2600,\n‘:umbrella:’:U+2614,\n‘:cloud:’:0x2601,\n‘:snowflake:’:U+2744,\n‘:snowman:’:U+26C4,\n‘:zap:’:U+26A1,\n‘:cyclone:’:U+1F300,\n‘:foggy:’:U+1F301,\n‘:ocean:’:U+1F30A,\n‘:cat:’:U+1F431,\n‘:dog:’:U+1F436,\n‘:mouse:’:U+1F430,\n‘:hamster:’:U+1F439,\n‘:rabbit:’:U+1F430,\n‘:wolf:’:U+1F43A,\n‘:frog:’:U+1F438,\n‘:tiger:’:U+1F42F,\n‘:koala:’:U+1F428,\n‘:bear:’:U+1F43B,\n‘:pig:’:U+1F437,\n‘:pig_nose:’:U+1F43D,\n‘:cow:’:U+1F42E,\n‘:boar:’:U+1F417,\n‘:monkey_face:’:U+1F435,\n‘:monkey:’:U+1F412,\n‘:horse:’:U+1F434,\n‘:racehorse:’:U+1F40E,\n‘:camel:’:U+1F42B,\n‘:sheep:’:U+1F411,\n‘:elephant:’:U+1F418,\n‘:panda_face:’:U+1F43C,\n‘:snake:’:U+1F40D,\n‘:bird:’:U+1F426,\n‘:baby_chick:’:U+1F424,\n‘:hatched_chick:’:U+1F425,\n‘:hatching_chick:’:U+1F423,\n‘:chicken:’:U+1F414,\n‘:penguin:’:U+1F427,\n‘:turtle:’:U+1F422,\n‘:bug:’:U+1F41B,\n‘:honeybee:’:U+1F41D,\n‘:ant:’:U+1F41C,\n‘:beetle:’:U+1F41E,\n‘:snail:’:U+1F40C,\n‘:octopus:’:U+1F419,\n‘:tropical_fish:’:U+1F420,\n‘:fish:’:U+1F41F,\n‘:whale:’:U+1F433,\n‘:whale2:’:U+1F40B,\n‘:dolphin:’:U+1F42C,\n‘:cow2:’:U+1F404,\n‘:ram:’:U+1F40F,\n‘:rat:’:U+1F400,\n‘:water_buffalo:’:U+1F403,\n‘:tiger2:’:U+1F405,\n‘:rabbit2:’:U+1F407,\n‘:dragon:’:U+1F432,\n‘:goat:’:U+1F410,\n‘:rooster:’:U+1F413,\n‘:dog2:’:U+1F415,\n‘:pig2:’:U+1F416,\n‘:mouse2:’:U+1F42D,\n‘:ox:’:U+1F402,\n‘:dragon_face:’:U+1F432,\n‘:blowfish:’:U+1F421,\n‘:crocodile:’:U+1F40A,\n‘:dromedary_camel:’:U+1F42A,\n‘:leopard:’:U+1F406,\n‘:cat2:’:U+1F408,\n‘:poodle:’:U+1F429,\n‘:paw_prints:’:U+1F43E,\n‘:bouquet:’:U+1F490,\n‘:cherry_blossom:’:U+1F338,\n‘:tulip:’:U+1F337,\n‘:four_leaf_clover:’:U+1F340,\n‘:rose:’:U+1F339,\n‘:sunflower:’:U+1F33B,\n‘:hibiscus:’:U+1F33A,\n‘:maple_leaf:’:U+1F341,\n‘:leaves:’:U+1F343,\n‘:fallen_leaf:’:U+1F342,\n‘:herb:’:U+1F33F,\n‘:mushroom:’:U+1F344,\n‘:cactus:’:U+1F335,\n‘:palm_tree:’:U+1F334,\n‘:evergreen_tree:’:U+1F332,\n‘:deciduous_tree:’:U+1F333,\n‘:chestnut:’:U+1F330,\n‘:seedling:’:U+1F331,\n‘:blossom:’:U+1F33C,\n‘:ear_of_rice:’:U+1F33E,\n‘:shell:’:U+1F41A,\n‘:globe_with_meridians:’:U+1F310,\n‘:sun_with_face:’:U+1F31E,\n‘:full_moon_with_face:’:U+1F31D,\n‘:new_moon_with_face:’:U+1F31A,\n‘:new_moon:’:U+1F311,\n‘:waxing_crescent_moon:’:U+1F312,\n‘:first_quarter_moon:’:U+1F313,\n‘:waxing_gibbous_moon:’:U+1F314,\n‘:full_moon:’:U+1F315,\n‘:waning_gibbous_moon:’:U+1F316,\n‘:last_quarter_moon:’:U+1F317,\n‘:waning_crescent_moon:’:U+1F318,\n‘:last_quarter_moon_with_face:’:U+1F31C,\n‘:first_quarter_moon_with_face:’:U+1F31B,\n‘:moon:’:U+1F319,\n‘:earth_africa:’:U+1F30D,\n‘:earth_americas:’:U+1F30E,\n‘:earth_asia:’:U+1F30F,\n‘:volcano:’:U+1F30B,\n‘:milky_way:’:U+1F30C,\n‘:partly_sunny:’:U+26C5,\n‘:octocat:’:308,\n‘:squirrel:’:309,\n‘:bamboo:’:U+1F38D,\n‘:gift_heart:’:U+1F49D,\n‘:dolls:’:U+1F38E,\n‘:school_satchel:’:U+1F392,\n‘:mortar_board:’:U+1F393,\n‘:flags:’:U+1F38F,\n‘:fireworks:’:U+1F386,\n‘:sparkler:’:U+1F387,\n‘:wind_chime:’:U+1F390,\n‘:rice_scene:’:U+1F391,\n‘:jack_o_lantern:’:U+1F383,\n‘:ghost:’:U+1F47B,\n‘:santa:’:U+1F385,\n‘:christmas_tree:’:U+1F384,\n‘:gift:’:U+1F381,\n‘:bell:’:U+1F514,\n‘:no_bell:’:U+1F515,\n‘:tanabata_tree:’:U+1F38B,\n‘:tada:’:U+1F389,\n‘:confetti_ball:’:U+1F38A,\n‘:balloon:’:U+1F388,\n‘:crystal_ball:’:U+1F52E,\n‘:cd:’:U+1F4BF,\n‘:dvd:’:U+1F4C0,\n‘:floppy_disk:’:U+1F4BE,\n‘:camera:’:U+1F4F7,\n‘:video_camera:’:U+1F4F9,\n‘:movie_camera:’:U+1F3A5,\n‘:computer:’:U+1F4BB,\n‘:tv:’:U+1F4FA,\n‘:iphone:’:U+1F4F1,\n‘:phone:’:U+260E,\n‘:telephone:’:U+260E,\n‘:telephone_receiver:’:U+1F4DE,\n‘:pager:’:U+1F4DF,\n‘:fax:’:U+1F4E0,\n‘:minidisc:’:U+1F4BD,\n‘:vhs:’:U+1F4FC,\n‘:sound:’:U+1F509,\n‘:speaker:’:U+1F50A,\n‘:mute:’:U+1F507,\n‘:loudspeaker:’:U+1F4E2,\n‘:mega:’:U+1F4E3,\n‘:hourglass:’:U+231B,\n‘:hourglass_flowing_sand:’:U+23F3,\n‘:alarm_clock:’:U+23F0,\n‘:watch:’:U+231A,\n‘:radio:’:U+1F4FB,\n‘:satellite:’:U+1F4E1,\n‘:loop:’:U+27BF,\n‘:mag:’:U+1F50D,\n‘:mag_right:’:U+1F50E,\n‘:unlock:’:U+1F513,\n‘:lock:’:U+1F512,\n‘:lock_with_ink_pen:’:U+1F50F,\n‘:closed_lock_with_key:’:U+1F510,\n‘:key:’:U+1F511,\n‘:bulb:’:U+1F4A1,\n‘:flashlight:’:U+1F526,\n‘:high_brightness:’:U+1F506,\n‘:low_brightness:’:U+1F505,\n‘:electric_plug:’:U+1F50C,\n‘:battery:’:U+1F50B,\n‘:calling:’:U+1F4F2,\n‘:email:’:U+1F4E9,\n‘:mailbox:’:U+1F4EB,\n‘:postbox:’:U+1F4EE,\n‘:bath:’:U+1F6C0,\n‘:bathtub:’:U+1F6C1,\n‘:shower:’:U+1F6BF,\n‘:toilet:’:U+1F6BD,\n‘:wrench:’:U+1F527,\n‘:nut_and_bolt:’:U+1F529,\n‘:hammer:’:U+1F528,\n‘:seat:’:U+1F4BA,\n‘:moneybag:’:U+1F4B0,\n‘:yen:’:U+1F4B4,\n‘:dollar:’:U+1F4B5,\n‘:pound:’:U+1F4B7,\n‘:euro:’:U+1F4B6,\n‘:credit_card:’:U+1F4B3,\n‘:money_with_wings:’:U+1F4B8,\n‘:e-mail:’:U+1F4E7,\n‘:inbox_tray:’:U+1F4E5,\n‘:outbox_tray:’:U+1F4E4,\n‘:envelope:’:U+2709,\n‘:incoming_envelope:’:U+1F4E8,\n‘:postal_horn:’:U+1F4EF,\n‘:mailbox_closed:’:U+1F4EA,\n‘:mailbox_with_mail:’:U+1F4EC,\n‘:mailbox_with_no_mail:’:U+1F4ED,\n‘:door:’:U+1F6AA,\n‘:smoking:’:U+1F6AC,\n‘:bomb:’:U+1F4A3,\n‘:gun:’:U+1F52B,\n‘:hocho:’:U+1F52A,\n‘:pill:’:U+1F48A,\n‘:syringe:’:U+1F489,\n‘:page_facing_up:’:U+1F4C4,\n‘:page_with_curl:’:U+1F4C3,\n‘:bookmark_tabs:’:U+1F4D1,\n‘:bar_chart:’:U+1F4CA,\n‘:chart_with_upwards_trend:’:U+1F4C8,\n‘:chart_with_downwards_trend:’:U+1F4C9,\n‘:scroll:’:U+1F4DC,\n‘:clipboard:’:U+1F4CB,\n‘:calendar:’:U+1F4C6,\n‘:date:’:U+1F4C5,\n‘:card_index:’:U+1F4C7,\n‘:file_folder:’:U+1F4C1,\n‘:open_file_folder:’:U+1F4C2,\n‘:scissors:’:U+2702,\n‘:pushpin:’:U+1F4CC,\n‘:paperclip:’:U+1F4CE,\n‘:black_nib:’:U+2712,\n‘:pencil2:’:U+270F,\n‘:straight_ruler:’:U+1F4CF,\n‘:triangular_ruler:’:U+1F4D0,\n‘:closed_book:’:U+1F4D5,\n‘:green_book:’:U+1F4D7,\n‘:blue_book:’:U+1F4D8,\n‘:orange_book:’:U+1F4D9,\n‘:notebook:’:U+1F4D3,\n‘:notebook_with_decorative_cover:’:U+1F4D4,\n‘:ledger:’:U+1F4D2,\n‘:books:’:U+1F4DA,\n‘:bookmark:’:U+1F516,\n‘:name_badge:’:U+1F4DB,\n‘:microscope:’:U+1F52C,\n‘:telescope:’:U+1F52D,\n‘:newspaper:’:U+1F4F0,\n‘:football:’:U+1F3C8,\n‘:basketball:’:U+1F3C0,\n‘:soccer:’:U+26BD,\n‘:baseball:’:U+26BE,\n‘:tennis:’:U+1F3BE,\n‘:8ball:’:U+1F3B1,\n‘:rugby_football:’:U+1F3C9,\n‘:bowling:’:U+1F3B3,\n‘:golf:’:U+26F3,\n‘:mountain_bicyclist:’:U+1F6B5,\n‘:bicyclist:’:U+1F6B4,\n‘:horse_racing:’:U+1F40E,\n‘:snowboarder:’:U+1F3C2,\n‘:swimmer:’:U+1F3CA,\n‘:surfer:’:U+1F3C4,\n‘:ski:’:U+1F3BF,\n‘:spades:’:U+2660,\n‘:hearts:’:U+2665,\n‘:clubs:’:U+2663,\n‘:diamonds:’:U+2666,\n‘:gem:’:U+1F48E,\n‘:ring:’:U+1F48D,\n‘:trophy:’:U+1F3C6,\n‘:musical_score:’:U+1F3BC,\n‘:musical_keyboard:’:U+1F3B9,\n‘:violin:’:U+1F3BB,\n‘:space_invader:’:U+1F47E,\n‘:video_game:’:U+1F3AE,\n‘:black_joker:’:U+1F0CF,\n‘:flower_playing_cards:’:U+1F3B4,\n‘:game_die:’:U+1F3B2,\n‘:dart:’:U+1F3AF,\n‘:mahjong:’:U+1F004,\n‘:clapper:’:U+1F3AC,\n‘:memo:’:U+1F4DD,\n‘:pencil:’:U+1F4DD,\n‘:book:’:U+1F4D6,\n‘:art:’:U+1F3A8,\n‘:microphone:’:U+1F3A4,\n‘:headphones:’:U+1F3A7,\n‘:trumpet:’:U+1F3BA,\n‘:saxophone:’:U+1F3B7,\n‘:guitar:’:U+1F3B8,\n‘:shoe:’:U+1F45F,\n‘:sandal:’:U+1F461,\n‘:high_heel:’:U+1F460,\n‘:lipstick:’:U+1F484,\n‘:boot:’:U+1F462,\n‘:shirt:’:U+1F455,\n‘:tshirt:’:U+1F455,\n‘:necktie:’:U+1F454,\n‘:womans_clothes:’:U+1F45A,\n‘:dress:’:U+1F457,\n‘:running_shirt_with_sash:’:U+1F3BD,\n‘:jeans:’:U+1F456,\n‘:kimono:’:U+1F458,\n‘:bikini:’:U+1F459,\n‘:ribbon:’:U+1F380,\n‘:tophat:’:U+1F3A9,\n‘:crown:’:U+1F451,\n‘:womans_hat:’:U+1F452,\n‘:mans_shoe:’:U+1F45E,\n‘:closed_umbrella:’:U+1F302,\n‘:briefcase:’:U+1F4BC,\n‘:handbag:’:U+1F45C,\n‘:pouch:’:U+1F45D,\n‘:purse:’:U+1F45B,\n‘:eyeglasses:’:U+1F453,\n‘:fishing_pole_and_fish:’:U+1F3A3,\n‘:coffee:’:U+2615,\n‘:tea:’:U+1F375,\n‘:sake:’:U+1F376,\n‘:baby_bottle:’:U+1F37C,\n‘:beer:’:U+1F37A,\n‘:beers:’:U+1F37B,\n‘:cocktail:’:U+1F378,\n‘:tropical_drink:’:U+1F379,\n‘:wine_glass:’:U+1F377,\n‘:fork_and_knife:’:U+1F374,\n‘:pizza:’:U+1F355,\n‘:hamburger:’:U+1F354,\n‘:fries:’:U+1F35F,\n‘:poultry_leg:’:U+1F357,\n‘:meat_on_bone:’:U+1F356,\n‘:spaghetti:’:U+1F35D,\n‘:curry:’:U+1F35B,\n‘:fried_shrimp:’:U+1F364,\n‘:bento:’:U+1F371,\n‘:sushi:’:U+1F363,\n‘:fish_cake:’:U+1F365,\n‘:rice_ball:’:U+1F359,\n‘:rice_cracker:’:U+1F358,\n‘:rice:’:U+1F35A,\n‘:ramen:’:U+1F35C,\n‘:stew:’:U+1F372,\n‘:oden:’:U+1F362,\n‘:dango:’:U+1F361,\n‘:egg:’:U+1F373,\n‘:bread:’:U+1F35E,\n‘:doughnut:’:U+1F369,\n‘:custard:’:U+1F36E,\n‘:icecream:’:U+1F366,\n‘:ice_cream:’:U+1F368,\n‘:shaved_ice:’:U+1F367,\n‘:birthday:’:U+1F382,\n‘:cake:’:U+1F370,\n‘:cookie:’:U+1F36A,\n‘:chocolate_bar:’:U+1F36B,\n‘:candy:’:U+1F36C,\n‘:lollipop:’:U+1F36D,\n‘:honey_pot:’:U+1F36F,\n‘:apple:’:U+1F34E,\n‘:green_apple:’:U+1F34F,\n‘:tangerine:’:U+1F34A,\n‘:lemon:’:U+1F34B,\n‘:cherries:’:U+1F352,\n‘:grapes:’:U+1F347,\n‘:watermelon:’:U+1F349,\n‘:strawberry:’:U+1F353,\n‘:peach:’:U+1F351,\n‘:melon:’:U+1F348,\n‘:banana:’:U+1F34C,\n‘:pear:’:U+1F350,\n‘:pineapple:’:U+1F34D,\n‘:sweet_potato:’:U+1F360,\n‘:eggplant:’:U+1F346,\n‘:tomato:’:U+1F345,\n‘:corn:’:U+1F33D,\n‘:house:’:U+1F3E0,\n‘:house_with_garden:’:U+1F3E1,\n‘:school:’:U+1F3EB,\n‘:office:’:U+1F3E2,\n‘:post_office:’:U+1F3E3,\n‘:hospital:’:U+1F3E5,\n‘:bank:’:U+1F3E6,\n‘:convenience_store:’:U+1F3EA,\n‘:love_hotel:’:U+1F3E9,\n‘:hotel:’:U+1F3E8,\n‘:wedding:’:U+1F492,\n‘:church:’:U+26EA,\n‘:department_store:’:U+1F3EC,\n‘:european_post_office:’:582,\n‘:city_sunrise:’:U+1F307,\n‘:city_sunset:’:U+1F306,\n‘:japanese_castle:’:U+1F3EF,\n‘:european_castle:’:U+1F3F0,\n‘:tent:’:U+26FA,\n‘:factory:’:U+1F3ED,\n‘:tokyo_tower:’:U+1F5FC,\n‘:japan:’:U+1F5FE,\n‘:mount_fuji:’:U+1F5FB,\n‘:sunrise_over_mountains:’:U+1F304,\n‘:sunrise:’:U+1F305,\n‘:stars:’:U+1F303,\n‘:statue_of_liberty:’:U+1F5FD,\n‘:bridge_at_night:’:U+1F309,\n‘:carousel_horse:’:U+1F3A0,\n‘:rainbow:’:U+1F308,\n‘:ferris_wheel:’:U+1F3A1,\n‘:fountain:’:U+26F2,\n‘:roller_coaster:’:U+1F3A2,\n‘:ship:’:U+1F6A2,\n‘:speedboat:’:U+1F6A4,\n‘:boat:’:U+26F5,\n‘:sailboat:’:U+26F5,\n‘:rowboat:’:U+1F6A3,\n‘:anchor:’:U+2693,\n‘:rocket:’:U+1F680,\n‘:airplane:’:U+2708,\n‘:helicopter:’:U+1F681,\n‘:steam_locomotive:’:U+1F682,\n‘:tram:’:U+1F68A,\n‘:mountain_railway:’:613,\n‘:bike:’:U+1F6B2,\n‘:aerial_tramway:’:U+1F6A1,\n‘:suspension_railway:’:U+1F69F,\n‘:mountain_cableway:’:U+1F6A0,\n‘:tractor:’:U+1F69C,\n‘:blue_car:’:U+1F699,\n‘:oncoming_automobile:’:U+1F698,\n‘:car:’:U+1F697,\n‘:red_car:’:U+1F697,\n‘:taxi:’:U+1F695,\n‘:oncoming_taxi:’:U+1F696,\n‘:articulated_lorry:’:625,\n‘:bus:’:U+1F68C,\n‘:oncoming_bus:’:U+1F68D,\n‘:rotating_light:’:U+1F6A8,\n‘:police_car:’:U+1F693,\n‘:oncoming_police_car:’:U+1F694,\n‘:fire_engine:’:U+1F692,\n‘:ambulance:’:U+1F691,\n‘:minibus:’:U+1F690,\n‘:truck:’:U+1F69A,\n‘:train:’:U+1F683,\n‘:station:’:U+1F689,\n‘:train2:’:U+1F685,\n‘:bullettrain_front:’:U+1F685,\n‘:bullettrain_side:’:U+1F684,\n‘:light_rail:’:U+1F688,\n‘:monorail:’:U+1F69D,\n‘:railway_car:’:U+1F683,\n‘:trolleybus:’:U+1F68E,\n‘:ticket:’:U+1F3AB,\n‘:fuelpump:’:U+26FD,\n‘:vertical_traffic_light:’:U+1F6A6,\n‘:traffic_light:’:U+1F6A5,\n‘:warning:’:U+26A0,\n‘:construction:’:U+1F6A7,\n‘:beginner:’:U+1F530,\n‘:atm:’:U+1F3E7,\n‘:slot_machine:’:U+1F3B0,\n‘:busstop:’:U+1F68F,\n‘:barber:’:U+1F488,\n‘:hotsprings:’:U+2668,\n‘:checkered_flag:’:U+1F3C1,\n‘:crossed_flags:’:U+1F38C,\n‘:izakaya_lantern:’:U+1F3EE,\n‘:moyai:’:U+1F5FF,\n‘:circus_tent:’:U+1F3AA,\n‘:performing_arts:’:U+1F3AD,\n‘:round_pushpin:’:U+1F4CD,\n‘:triangular_flag_on_post:’:U+1F6A9,\n‘:jp:’:U+1F1EF U+1F1F5,\n‘:kr:’:U+1F1F0 U+1F1F7,\n‘:cn:’:U+1F1E8 U+1F1F3,\n‘:us:’:U+1F1FA U+1F1F8,\n‘:fr:’:U+1F1EB U+1F1F7,\n‘:es:’:U+1F1EA U+1F1F8,\n‘:it:’:U+1F1EE U+1F1F9,\n‘:ru:’:U+1F1F7 U+1F1FA,\n‘:gb:’:U+1F1EC U+1F1E7,\n‘:uk:’:U+1F1EC U+1F1E7,\n‘:de:’:U+1F1E9 U+1F1EA,\n‘:one:’:U+0031 U+20E3,\n‘:two:’:U+0032 U+20E3,\n‘:three:’:U+0033 U+20E3,\n‘:four:’:U+0034 U+20E3,\n‘:five:’:U+0035 U+20E3,\n‘:six:’:U+0036 U+20E3,\n‘:seven:’:U+0037 U+20E3,\n‘:eight:’:U+0038 U+20E3,\n‘:nine:’:U+0039 U+20E3,\n‘:keycap_ten:’:U+1F51F,\n‘:1234:’:U+1F522,\n‘:zero:’:U+0030 U+20E3,\n‘:hash:’:U+0023 U+20E3,\n‘:symbols:’:U+1F523,\n‘:arrow_backward:’:U+25C0,\n‘:arrow_down:’:U+2B07,\n‘:arrow_forward:’:U+25B6,\n‘:arrow_left:’:U+2B05,\n‘:capital_abcd:’:U+1F520,\n‘:abcd:’:U+1F521,\n‘:abc:’:U+1F524,\n‘:arrow_lower_left:’:U+2199,\n‘:arrow_lower_right:’:U+2198,\n‘:arrow_right:’:U+27A1,\n‘:arrow_up:’:U+2B06,\n‘:arrow_upper_left:’:U+2196,\n‘:arrow_upper_right:’:U+2197,\n‘:arrow_double_down:’:U+23EC,\n‘:arrow_double_up:’:U+23EB,\n‘:arrow_down_small:’:U+1F53D,\n‘:arrow_heading_down:’:U+2935,\n‘:arrow_heading_up:’:U+2934,\n‘:leftwards_arrow_with_hook:’:U+21A9,\n‘:arrow_right_hook:’:U+21AA,\n‘:left_right_arrow:’:U+2194,\n‘:arrow_up_down:’:U+2195,\n‘:arrow_up_small:’:U+1F53D,\n‘:arrows_clockwise:’:U+1F503,\n‘:arrows_counterclockwise:’:U+1F504,\n‘:rewind:’:U+23EA,\n‘:fast_forward:’:U+23E9,\n‘:information_source:’:U+2139,\n‘:ok:’:U+1F197,\n‘:twisted_rightwards_arrows:’:U+1F500,\n‘:repeat:’:U+1F501,\n‘:repeat_one:’:U+1F502,\n‘:new:’:U+1F195,\n‘:top:’:U+1F51D,\n‘:up:’:U+1F199,\n‘:cool:’:U+1F192,\n‘:free:’:U+1F193,\n‘:ng:’:U+1F196,\n‘:cinema:’:U+1F3A6,\n‘:koko:’:728U+1F201\n‘:signal_strength:’:U+1F4F6,\n‘:u5272:’:U+1F239,\n‘:u5408:’:U+1F234,\n‘:u55b6:’:U+1F23A,\n‘:u6307:’:U+1F22F,\n‘:u6708:’:U+1F237,\n‘:u6709:’:U+1F236,\n‘:u6e80:’:U+1F235,\n‘:u7121:’:U+1F21A,\n‘:u7533:’:U+1F238,\n‘:u7a7a:’:U+1F233,\n‘:u7981:’:U+1F232,\n‘:sa:’:U+1F202,\n‘:restroom:’:U+1F6BB,\n‘:mens:’:U+1F6B9,\n‘:womens:’:U+1F6BA,\n‘:baby_symbol:’:U+1F6BC,\n‘:no_smoking:’:U+1F6AD,\n‘:parking:’:U+1F17F,\n‘:wheelchair:’:U+267F,\n‘:metro:’:U+1F687,\n‘:baggage_claim:’:U+1F6C4,\n‘:accept:’:U+1F251,\n‘:wc:’:U+1F6BE,\n‘:potable_water:’:U+1F6B0,\n‘:put_litter_in_its_place:’:U+1F6AE,\n‘:secret:’:U+3299,\n‘:congratulations:’:U+3297,\n‘:m:’:U+24C2,\n‘:passport_control:’:U+1F6C2,\n‘:left_luggage:’:U+1F6C5,\n‘:customs:’:U+1F6C3,\n‘:ideograph_advantage:’:U+1F250,\n‘:cl:’:U+1F191,\n‘:sos:’:U+1F198,\n‘:id:’:U+1F194,\n‘:no_entry_sign:’:U+1F6AB,\n‘:underage:’:U+1F51E,\n‘:no_mobile_phones:’:U+1F4F5,\n‘:do_not_litter:’:U+1F6AF,\n‘:non-potable_water:’:U+1F6B1,\n‘:no_bicycles:’:U+1F6B3,\n‘:no_pedestrians:’:U+1F6B7,\n‘:children_crossing:’:U+1F6B8,\n‘:no_entry:’:U+26D4,\n‘:eight_spoked_asterisk:’:U+2733,\n‘:eight_pointed_black_star:’:U+2734,\n‘:heart_decoration:’:U+1F49F,\n‘:vs:’:U+1F19A,\n‘:vibration_mode:’:U+1F4F3,\n‘:mobile_phone_off:’:U+1F4F4,\n‘:chart:’:U+1F4B9,\n‘:currency_exchange:’:U+1F4B1,\n‘:aries:’:U+2648,\n‘:taurus:’:U+2649,\n‘:gemini:’:U+264A,\n‘:cancer:’:U+264B,\n‘:leo:’:U+264C,\n‘:virgo:’:U+264D,\n‘:libra:’:U+264E,\n‘:scorpius:’:U+264F,\n‘:sagittarius:’:U+2650,\n‘:capricorn:’:U+2651,\n‘:aquarius:’:U+2652,\n‘:pisces:’:U+2653,\n‘:ophiuchus:’:U+26CE,\n‘:six_pointed_star:’:U+1F52F,\n‘:negative_squared_cross_mark:’:U+274E,\n‘:a:’:U+1F170,\n‘:b:’:U+1F171,\n‘:ab:’:U+1F18E,\n‘:o2:’:U+1F17E,\n‘:diamond_shape_with_a_dot_inside:’:U+1F4A0,\n‘:recycle:’:U+267B,\n‘:end:’:U+1F51A,\n‘:on:’:U+1F51B,\n‘:soon:’:U+1F51C,\n‘:clock1:’:U+1F550,\n‘:clock130:’:U+1F55C,\n‘:clock10:’:U+1F559,\n‘:clock1030:’:U+1F565,\n‘:clock11:’:U+1F55A,\n‘:clock1130:’:U+1F566,\n‘:clock12:’:U+1F55B,\n‘:clock1230:’:U+1F567,\n‘:clock2:’:U+1F551,\n‘:clock230:’:U+1F55D,\n‘:clock3:’:U+1F552,\n‘:clock330:’:U+1F55E,\n‘:clock4:’:U+1F553,\n‘:clock430:’:U+1F55F,\n‘:clock5:’:U+1F554,\n‘:clock530:’:U+1F560,\n‘:clock6:’:U+1F555,\n‘:clock630:’:U+1F561,\n‘:clock7:’:U+1F556,\n‘:clock730:’:U+1F562,\n‘:clock8:’:U+1F557,\n‘:clock830:’:U+1F563,\n‘:clock9:’:U+1F558,\n‘:clock930:’:U+1F564,\n‘:heavy_dollar_sign:’:U+1F4B2,\n‘:copyright:’:U+00A9,\n‘:registered:’:U+00AE,\n‘:tm:’:U+2122,\n‘:x:’:U+274C,\n‘:heavy_exclamation_mark:’:U+2757,\n‘:bangbang:’:U+203C,\n‘:interrobang:’:U+2049,\n‘:o:’:U+2B55,\n‘:heavy_multiplication_x:’:U+2716,\n‘:heavy_plus_sign:’:U+2795,\n‘:heavy_minus_sign:’:U+2796,\n‘:heavy_division_sign:’:U+2797,\n‘:white_flower:’:U+1F4AE,\n‘:100:’:U+1F4AF,\n‘:heavy_check_mark:’:U+2714,\n‘:ballot_box_with_check:’:U+2611,\n‘:radio_button:’:U+1F518,\n‘:link:’:U+1F517,\n‘:curly_loop:’:U+27B0,\n‘:wavy_dash:’:U+3030,\n‘:part_alternation_mark:’:U+303D,\n‘:trident:’:U+1F531,\n‘:black_square:’:U+2B1B,\n‘:white_square:’:U+2B1C,\n‘:white_check_mark:’:U+2705,\n‘:black_square_button:’:U+1F532,\n‘:white_square_button:’:U+1F533,\n‘:black_circle:’:U+26AB,\n‘:white_circle:’:U+26AA,\n‘:red_circle:’:U+1F534,\n‘:large_blue_circle:’:U+1F535,\n‘:large_blue_diamond:’:U+1F537,\n‘:large_orange_diamond:’:U+1F536,\n‘:small_blue_diamond:’:U+1F539,\n‘:small_orange_diamond:’:U+1F538,\n‘:small_red_triangle:’:U+1F53A,\n‘:small_red_triangle_down:’:U+1F53B,\n‘:shipit:’:868\n};\n还有一些没有找到对应的值，先备份一下；\n参考：\nhttp://www.emoji-cheat-sheet.com/ (最全的，但是没有unicode值)\nhttp://punchdrunker.github.io/iOSEmoji/table_html/index.html (unicode值表)\nhttp://code.iamcal.com/php/emoji/ (unicode值表)\n","permalink":"https://blog.zdltech.com/posts/emoji-%E8%A1%A8%E6%83%85-%E7%BC%96%E7%A0%81%E6%95%B4%E7%90%86/","summary":"\u003cp\u003eemoji 表情 编码整理，有需要的朋友可以参考下。\u003cbr\u003e\nvar faces_array = {\u003cbr\u003e\n‘:bowtie:’:1,\u003cbr\u003e\n‘:smile:’:U+1F604,\u003cbr\u003e\n‘:laughing:’:U+1F606,\u003cbr\u003e\n‘:blush:’:U+1F60A,\u003cbr\u003e\n‘:smiley:’:U+1F603,\u003cbr\u003e\n‘:relaxed:’:U+263A,\u003cbr\u003e\n‘:smirk:’:U+1F60F,\u003cbr\u003e\n‘:heart_eyes:’:U+1F60D,\u003cbr\u003e\n‘:kissing_heart:’:U+1F618,\u003cbr\u003e\n‘:kissing_closed_eyes:’:U+1F61A,\u003cbr\u003e\n‘:flushed:’:U+1F633,\u003cbr\u003e\n‘:relieved:’:U+1F60C,\u003cbr\u003e\n‘:satisfied:’:U+1F606,\u003cbr\u003e\n‘:grin:’:U+1F601,\u003cbr\u003e\n‘:wink:’:U+1F609,\u003cbr\u003e\n‘:stuck_out_tongue_winking_eye:’:U+1F61C,\u003cbr\u003e\n‘:stuck_out_tongue_closed_eyes:’:U+1F61D,\u003cbr\u003e\n‘:grinning:’:U+1F601,\u003cbr\u003e\n‘:kissing:’:U+1F619,\u003cbr\u003e\n‘:kissing_smiling_eyes:’:U+1F617,\u003cbr\u003e\n‘:stuck_out_tongue:’:U+1F61C,\u003cbr\u003e\n‘:sleeping:’:22,\u003cbr\u003e\n‘:worried:’:U+1F61F,\u003cbr\u003e\n‘:frowning:’:U+1F627,\u003cbr\u003e\n‘:anguished:’:U+1F626,\u003cbr\u003e\n‘:open_mouth:’:U+1F62E,\u003cbr\u003e\n‘:grimacing:’:U+1F600,\u003cbr\u003e\n‘:confused:’:U+1F62F,\u003cbr\u003e\n‘:hushed:’:29,\u003cbr\u003e\n‘:expressionless:’:U+1F611,\u003cbr\u003e\n‘:unamused:’:U+1F612,\u003cbr\u003e\n‘:sweat_smile:’:U+1F605,\u003cbr\u003e\n‘:sweat:’:U+1F613,\u003cbr\u003e\n‘:disappointed_relieved:’:U+1F625,\u003cbr\u003e\n‘:weary:’:U+1F629,\u003cbr\u003e\n‘:pensive:’:U+1F614,\u003cbr\u003e\n‘:disappointed:’:U+1F61E,\u003cbr\u003e\n‘:confounded:’:U+1F616,\u003cbr\u003e\n‘:fearful:’:U+1F628,\u003cbr\u003e\n‘:cold_sweat:’:U+1F630,\u003cbr\u003e\n‘:persevere:’:U+1F623,\u003cbr\u003e\n‘:cry:’:U+1F622,\u003cbr\u003e\n‘:sob:’:U+1F62D,\u003cbr\u003e\n‘:joy:’:U+1F602,\u003cbr\u003e\n‘:astonished:’:U+1F632,\u003cbr\u003e\n‘:scream:’:U+1F631,\u003cbr\u003e\n‘:neckbeard:’:47,\u003cbr\u003e\n‘:tired_face:’:U+1F62B,\u003cbr\u003e\n‘:angry:’:U+1F620,\u003cbr\u003e\n‘:rage:’:U+1F621,\u003cbr\u003e\n‘:triumph:’:U+1F624,\u003cbr\u003e\n‘:sleepy:’:U+1F62A,\u003cbr\u003e\n‘:yum:’:U+1F60B,\u003cbr\u003e\n‘:mask:’:U+1F637,\u003cbr\u003e\n‘:sunglasses:’:U+1F60E,\u003cbr\u003e\n‘:dizzy_face:’:U+1F635,\u003cbr\u003e\n‘:imp:’:U+1F47F,\u003cbr\u003e\n‘:smiling_imp:’:U+1F608,\u003cbr\u003e\n‘:neutral_face:’:U+1F610,\u003cbr\u003e\n‘:no_mouth:’:U+1F636,\u003cbr\u003e\n‘:innocent:’:U+1F607,\u003cbr\u003e\n‘:alien:’:U+1F47D,\u003cbr\u003e\n‘:yellow_heart:’:U+1F49B,\u003cbr\u003e\n‘:blue_heart:’:U+1F499,\u003cbr\u003e\n‘:purple_heart:’:U+1F49C,\u003cbr\u003e\n‘:heart:’:U+2764,\u003cbr\u003e\n‘:green_heart:’:U+1F49A,\u003cbr\u003e\n‘:broken_heart:’:U+1F494,\u003cbr\u003e\n‘:heartbeat:’:U+1F493,\u003cbr\u003e\n‘:heartpulse:’:U+1F497,\u003cbr\u003e\n‘:two_hearts:’:U+1F495,\u003cbr\u003e\n‘:revolving_hearts:’:U+1F49E,\u003cbr\u003e\n‘:cupid:’:U+1F498,\u003cbr\u003e\n‘:sparkling_heart:’:U+1F496,\u003cbr\u003e\n‘:sparkles:’:U+2728,\u003cbr\u003e\n‘:star:’:U+2B50,\u003cbr\u003e\n‘:star2:’:U+1F31F,\u003cbr\u003e\n‘:dizzy:’:U+1F4AB,\u003cbr\u003e\n‘:boom:’:U+1F4A5,\u003cbr\u003e\n‘:collision:’:U+1F4A5,\u003cbr\u003e\n‘:anger:’:U+1F4A2,\u003cbr\u003e\n‘:exclamation:’:U+2757,\u003cbr\u003e\n‘:question:’:U+2753,\u003cbr\u003e\n‘:grey_exclamation:’:U+2755,\u003cbr\u003e\n‘:grey_question:’:U+2754,\u003cbr\u003e\n‘:zzz:’:U+1F4A4,\u003cbr\u003e\n‘:dash:’:U+1F4A8,\u003cbr\u003e\n‘:sweat_drops:’:U+1F4A6,\u003cbr\u003e\n‘:notes:’:U+1F3B6,\u003cbr\u003e\n‘:musical_note:’:U+1F3B5,\u003cbr\u003e\n‘:fire:’:U+1F525,\u003cbr\u003e\n‘:hankey:’:U+1F4A9,\u003cbr\u003e\n‘:poop:’:U+1F4A9,\u003cbr\u003e\n‘:shit:’:U+1F4A9,\u003cbr\u003e\n‘:+1:’:U+1F44D,\u003cbr\u003e\n‘:thumbsup:’:U+1F44D,\u003cbr\u003e\n‘:-1:’:U+1F44E,\u003cbr\u003e\n‘:thumbsdown:’:U+1F44E,\u003cbr\u003e\n‘:ok_hand:’:U+1F44C,\u003cbr\u003e\n‘:punch:’:U+1F44A,\u003cbr\u003e\n‘:facepunch:’:101,\u003cbr\u003e\n‘:fist:’:U+270A,\u003cbr\u003e\n‘:v:’:U+270C,\u003cbr\u003e\n‘:wave:’:U+1F44B,\u003cbr\u003e\n‘:hand:’:U+270B,\u003cbr\u003e\n‘:raised_hand:’:U+270B,\u003cbr\u003e\n‘:open_hands:’:U+1F450,\u003cbr\u003e\n‘:point_up:’:U+261D,\u003cbr\u003e\n‘:point_down:’:U+1F447,\u003cbr\u003e\n‘:point_left:’:U+1F448,\u003cbr\u003e\n‘:point_right:’:U+1F449,\u003cbr\u003e\n‘:raised_hands:’:U+1F64C,\u003cbr\u003e\n‘:pray:’:U+1F64F,\u003cbr\u003e\n‘:point_up_2:’:U+1F446,\u003cbr\u003e\n‘:clap:’:U+1F44F,\u003cbr\u003e\n‘:muscle:’:U+1F4AA,\u003cbr\u003e\n‘:metal:’:117,\u003cbr\u003e\n‘:fu:’:118,\u003cbr\u003e\n‘:walking:’:U+1F6B6,\u003cbr\u003e\n‘:runner:’:U+1F3C3,\u003cbr\u003e\n‘:running:’:U+1F3C3,\u003cbr\u003e\n‘:couple:’:U+1F46B,\u003cbr\u003e\n‘:family:’:U+1F46A,\u003cbr\u003e\n‘:two_men_holding_hands:’:U+1F46C,\u003cbr\u003e\n‘:two_women_holding_hands:’:U+1F46D,\u003cbr\u003e\n‘:dancer:’:U+1F483,\u003cbr\u003e\n‘:dancers:’:U+1F46F,\u003cbr\u003e\n‘:ok_woman:’:U+1F646,\u003cbr\u003e\n‘:no_good:’:U+1F645,\u003cbr\u003e\n‘:information_desk_person:’:U+1F481,\u003cbr\u003e\n‘:raising_hand:’:U+1F64B,\u003cbr\u003e\n‘:bride_with_veil:’:U+1F470,\u003cbr\u003e\n‘:person_with_pouting_face:’:U+1F64E,\u003cbr\u003e\n‘:person_frowning:’:U+1F64D,\u003cbr\u003e\n‘:bow:’:U+1F647,\u003cbr\u003e\n‘:couplekiss:’:U+1F48F,\u003cbr\u003e\n‘:couple_with_heart:’:U+1F491,\u003cbr\u003e\n‘:massage:’:U+1F486,\u003cbr\u003e\n‘:haircut:’:U+1F487,\u003cbr\u003e\n‘:nail_care:’:U+1F485,\u003cbr\u003e\n‘:boy:’:U+1F466,\u003cbr\u003e\n‘:girl:’:U+1F467,\u003cbr\u003e\n‘:woman:’:U+1F469,\u003cbr\u003e\n‘:man:’:U+1F468,\u003cbr\u003e\n‘:baby:’:U+1F476,\u003cbr\u003e\n‘:older_woman:’:U+1F475,\u003cbr\u003e\n‘:older_man:’:U+1F474,\u003cbr\u003e\n‘:person_with_blond_hair:’:U+1F471,\u003cbr\u003e\n‘:man_with_gua_pi_mao:’:U+1F472,\u003cbr\u003e\n‘:man_with_turban:’:U+1F473,\u003cbr\u003e\n‘:construction_worker:’:U+1F477,\u003cbr\u003e\n‘:cop:’:U+1F46E,\u003cbr\u003e\n‘:angel:’:U+1F47C,\u003cbr\u003e\n‘:princess:’:U+1F478,\u003cbr\u003e\n‘:smiley_cat:’:U+1F63A,\u003cbr\u003e\n‘:smile_cat:’:U+1F638,\u003cbr\u003e\n‘:heart_eyes_cat:’:U+1F63B,\u003cbr\u003e\n‘:kissing_cat:’:U+1F63D,\u003cbr\u003e\n‘:smirk_cat:’:U+1F63C,\u003cbr\u003e\n‘:scream_cat:’:U+1F640,\u003cbr\u003e\n‘:crying_cat_face:’:U+1F63F,\u003cbr\u003e\n‘:joy_cat:’:U+1F639,\u003cbr\u003e\n‘:pouting_cat:’:U+1F63E,\u003cbr\u003e\n‘:japanese_ogre:’:U+1F479,\u003cbr\u003e\n‘:japanese_goblin:’:U+1F47A,\u003cbr\u003e\n‘:see_no_evil:’:U+1F648,\u003cbr\u003e\n‘:hear_no_evil:’:U+1F649,\u003cbr\u003e\n‘:speak_no_evil:’:U+1F64A,\u003cbr\u003e\n‘:guardsman:’:U+1F482,\u003cbr\u003e\n‘:skull:’:U+1F480,\u003cbr\u003e\n‘:feet:’:U+1F463,\u003cbr\u003e\n‘:lips:’:U+1F444,\u003cbr\u003e\n‘:kiss:’:U+1F48B,\u003cbr\u003e\n‘:droplet:’:U+1F4A7,\u003cbr\u003e\n‘:ear:’:U+1F442,\u003cbr\u003e\n‘:eyes:’:U+1F440,\u003cbr\u003e\n‘:nose:’:U+1F443,\u003cbr\u003e\n‘:tongue:’:U+1F445,\u003cbr\u003e\n‘:love_letter:’:U+1F48C,\u003cbr\u003e\n‘:bust_in_silhouette:’:U+1F464,\u003cbr\u003e\n‘:busts_in_silhouette:’:U+1F465,\u003cbr\u003e\n‘:speech_balloon:’:U+1F4AC,\u003cbr\u003e\n‘:thought_balloon:’:U+1F4AD,\u003cbr\u003e\n‘:feelsgood:’:184,\u003cbr\u003e\n‘:finnadie:’:185,\u003cbr\u003e\n‘:goberserk:’:186,\u003cbr\u003e\n‘:godmode:’:187,\u003cbr\u003e\n‘:hurtrealbad:’:188,\u003cbr\u003e\n‘:rage1:’:189,\u003cbr\u003e\n‘:rage2:’:190,\u003cbr\u003e\n‘:rage3:’:191,\u003cbr\u003e\n‘:rage4:’:192,\u003cbr\u003e\n‘:suspect:’:193,\u003cbr\u003e\n‘:trollface:’:194,\u003cbr\u003e\n‘:sunny:’:U+2600,\u003cbr\u003e\n‘:umbrella:’:U+2614,\u003cbr\u003e\n‘:cloud:’:0x2601,\u003cbr\u003e\n‘:snowflake:’:U+2744,\u003cbr\u003e\n‘:snowman:’:U+26C4,\u003cbr\u003e\n‘:zap:’:U+26A1,\u003cbr\u003e\n‘:cyclone:’:U+1F300,\u003cbr\u003e\n‘:foggy:’:U+1F301,\u003cbr\u003e\n‘:ocean:’:U+1F30A,\u003cbr\u003e\n‘:cat:’:U+1F431,\u003cbr\u003e\n‘:dog:’:U+1F436,\u003cbr\u003e\n‘:mouse:’:U+1F430,\u003cbr\u003e\n‘:hamster:’:U+1F439,\u003cbr\u003e\n‘:rabbit:’:U+1F430,\u003cbr\u003e\n‘:wolf:’:U+1F43A,\u003cbr\u003e\n‘:frog:’:U+1F438,\u003cbr\u003e\n‘:tiger:’:U+1F42F,\u003cbr\u003e\n‘:koala:’:U+1F428,\u003cbr\u003e\n‘:bear:’:U+1F43B,\u003cbr\u003e\n‘:pig:’:U+1F437,\u003cbr\u003e\n‘:pig_nose:’:U+1F43D,\u003cbr\u003e\n‘:cow:’:U+1F42E,\u003cbr\u003e\n‘:boar:’:U+1F417,\u003cbr\u003e\n‘:monkey_face:’:U+1F435,\u003cbr\u003e\n‘:monkey:’:U+1F412,\u003cbr\u003e\n‘:horse:’:U+1F434,\u003cbr\u003e\n‘:racehorse:’:U+1F40E,\u003cbr\u003e\n‘:camel:’:U+1F42B,\u003cbr\u003e\n‘:sheep:’:U+1F411,\u003cbr\u003e\n‘:elephant:’:U+1F418,\u003cbr\u003e\n‘:panda_face:’:U+1F43C,\u003cbr\u003e\n‘:snake:’:U+1F40D,\u003cbr\u003e\n‘:bird:’:U+1F426,\u003cbr\u003e\n‘:baby_chick:’:U+1F424,\u003cbr\u003e\n‘:hatched_chick:’:U+1F425,\u003cbr\u003e\n‘:hatching_chick:’:U+1F423,\u003cbr\u003e\n‘:chicken:’:U+1F414,\u003cbr\u003e\n‘:penguin:’:U+1F427,\u003cbr\u003e\n‘:turtle:’:U+1F422,\u003cbr\u003e\n‘:bug:’:U+1F41B,\u003cbr\u003e\n‘:honeybee:’:U+1F41D,\u003cbr\u003e\n‘:ant:’:U+1F41C,\u003cbr\u003e\n‘:beetle:’:U+1F41E,\u003cbr\u003e\n‘:snail:’:U+1F40C,\u003cbr\u003e\n‘:octopus:’:U+1F419,\u003cbr\u003e\n‘:tropical_fish:’:U+1F420,\u003cbr\u003e\n‘:fish:’:U+1F41F,\u003cbr\u003e\n‘:whale:’:U+1F433,\u003cbr\u003e\n‘:whale2:’:U+1F40B,\u003cbr\u003e\n‘:dolphin:’:U+1F42C,\u003cbr\u003e\n‘:cow2:’:U+1F404,\u003cbr\u003e\n‘:ram:’:U+1F40F,\u003cbr\u003e\n‘:rat:’:U+1F400,\u003cbr\u003e\n‘:water_buffalo:’:U+1F403,\u003cbr\u003e\n‘:tiger2:’:U+1F405,\u003cbr\u003e\n‘:rabbit2:’:U+1F407,\u003cbr\u003e\n‘:dragon:’:U+1F432,\u003cbr\u003e\n‘:goat:’:U+1F410,\u003cbr\u003e\n‘:rooster:’:U+1F413,\u003cbr\u003e\n‘:dog2:’:U+1F415,\u003cbr\u003e\n‘:pig2:’:U+1F416,\u003cbr\u003e\n‘:mouse2:’:U+1F42D,\u003cbr\u003e\n‘:ox:’:U+1F402,\u003cbr\u003e\n‘:dragon_face:’:U+1F432,\u003cbr\u003e\n‘:blowfish:’:U+1F421,\u003cbr\u003e\n‘:crocodile:’:U+1F40A,\u003cbr\u003e\n‘:dromedary_camel:’:U+1F42A,\u003cbr\u003e\n‘:leopard:’:U+1F406,\u003cbr\u003e\n‘:cat2:’:U+1F408,\u003cbr\u003e\n‘:poodle:’:U+1F429,\u003cbr\u003e\n‘:paw_prints:’:U+1F43E,\u003cbr\u003e\n‘:bouquet:’:U+1F490,\u003cbr\u003e\n‘:cherry_blossom:’:U+1F338,\u003cbr\u003e\n‘:tulip:’:U+1F337,\u003cbr\u003e\n‘:four_leaf_clover:’:U+1F340,\u003cbr\u003e\n‘:rose:’:U+1F339,\u003cbr\u003e\n‘:sunflower:’:U+1F33B,\u003cbr\u003e\n‘:hibiscus:’:U+1F33A,\u003cbr\u003e\n‘:maple_leaf:’:U+1F341,\u003cbr\u003e\n‘:leaves:’:U+1F343,\u003cbr\u003e\n‘:fallen_leaf:’:U+1F342,\u003cbr\u003e\n‘:herb:’:U+1F33F,\u003cbr\u003e\n‘:mushroom:’:U+1F344,\u003cbr\u003e\n‘:cactus:’:U+1F335,\u003cbr\u003e\n‘:palm_tree:’:U+1F334,\u003cbr\u003e\n‘:evergreen_tree:’:U+1F332,\u003cbr\u003e\n‘:deciduous_tree:’:U+1F333,\u003cbr\u003e\n‘:chestnut:’:U+1F330,\u003cbr\u003e\n‘:seedling:’:U+1F331,\u003cbr\u003e\n‘:blossom:’:U+1F33C,\u003cbr\u003e\n‘:ear_of_rice:’:U+1F33E,\u003cbr\u003e\n‘:shell:’:U+1F41A,\u003cbr\u003e\n‘:globe_with_meridians:’:U+1F310,\u003cbr\u003e\n‘:sun_with_face:’:U+1F31E,\u003cbr\u003e\n‘:full_moon_with_face:’:U+1F31D,\u003cbr\u003e\n‘:new_moon_with_face:’:U+1F31A,\u003cbr\u003e\n‘:new_moon:’:U+1F311,\u003cbr\u003e\n‘:waxing_crescent_moon:’:U+1F312,\u003cbr\u003e\n‘:first_quarter_moon:’:U+1F313,\u003cbr\u003e\n‘:waxing_gibbous_moon:’:U+1F314,\u003cbr\u003e\n‘:full_moon:’:U+1F315,\u003cbr\u003e\n‘:waning_gibbous_moon:’:U+1F316,\u003cbr\u003e\n‘:last_quarter_moon:’:U+1F317,\u003cbr\u003e\n‘:waning_crescent_moon:’:U+1F318,\u003cbr\u003e\n‘:last_quarter_moon_with_face:’:U+1F31C,\u003cbr\u003e\n‘:first_quarter_moon_with_face:’:U+1F31B,\u003cbr\u003e\n‘:moon:’:U+1F319,\u003cbr\u003e\n‘:earth_africa:’:U+1F30D,\u003cbr\u003e\n‘:earth_americas:’:U+1F30E,\u003cbr\u003e\n‘:earth_asia:’:U+1F30F,\u003cbr\u003e\n‘:volcano:’:U+1F30B,\u003cbr\u003e\n‘:milky_way:’:U+1F30C,\u003cbr\u003e\n‘:partly_sunny:’:U+26C5,\u003cbr\u003e\n‘:octocat:’:308,\u003cbr\u003e\n‘:squirrel:’:309,\u003cbr\u003e\n‘:bamboo:’:U+1F38D,\u003cbr\u003e\n‘:gift_heart:’:U+1F49D,\u003cbr\u003e\n‘:dolls:’:U+1F38E,\u003cbr\u003e\n‘:school_satchel:’:U+1F392,\u003cbr\u003e\n‘:mortar_board:’:U+1F393,\u003cbr\u003e\n‘:flags:’:U+1F38F,\u003cbr\u003e\n‘:fireworks:’:U+1F386,\u003cbr\u003e\n‘:sparkler:’:U+1F387,\u003cbr\u003e\n‘:wind_chime:’:U+1F390,\u003cbr\u003e\n‘:rice_scene:’:U+1F391,\u003cbr\u003e\n‘:jack_o_lantern:’:U+1F383,\u003cbr\u003e\n‘:ghost:’:U+1F47B,\u003cbr\u003e\n‘:santa:’:U+1F385,\u003cbr\u003e\n‘:christmas_tree:’:U+1F384,\u003cbr\u003e\n‘:gift:’:U+1F381,\u003cbr\u003e\n‘:bell:’:U+1F514,\u003cbr\u003e\n‘:no_bell:’:U+1F515,\u003cbr\u003e\n‘:tanabata_tree:’:U+1F38B,\u003cbr\u003e\n‘:tada:’:U+1F389,\u003cbr\u003e\n‘:confetti_ball:’:U+1F38A,\u003cbr\u003e\n‘:balloon:’:U+1F388,\u003cbr\u003e\n‘:crystal_ball:’:U+1F52E,\u003cbr\u003e\n‘:cd:’:U+1F4BF,\u003cbr\u003e\n‘:dvd:’:U+1F4C0,\u003cbr\u003e\n‘:floppy_disk:’:U+1F4BE,\u003cbr\u003e\n‘:camera:’:U+1F4F7,\u003cbr\u003e\n‘:video_camera:’:U+1F4F9,\u003cbr\u003e\n‘:movie_camera:’:U+1F3A5,\u003cbr\u003e\n‘:computer:’:U+1F4BB,\u003cbr\u003e\n‘:tv:’:U+1F4FA,\u003cbr\u003e\n‘:iphone:’:U+1F4F1,\u003cbr\u003e\n‘:phone:’:U+260E,\u003cbr\u003e\n‘:telephone:’:U+260E,\u003cbr\u003e\n‘:telephone_receiver:’:U+1F4DE,\u003cbr\u003e\n‘:pager:’:U+1F4DF,\u003cbr\u003e\n‘:fax:’:U+1F4E0,\u003cbr\u003e\n‘:minidisc:’:U+1F4BD,\u003cbr\u003e\n‘:vhs:’:U+1F4FC,\u003cbr\u003e\n‘:sound:’:U+1F509,\u003cbr\u003e\n‘:speaker:’:U+1F50A,\u003cbr\u003e\n‘:mute:’:U+1F507,\u003cbr\u003e\n‘:loudspeaker:’:U+1F4E2,\u003cbr\u003e\n‘:mega:’:U+1F4E3,\u003cbr\u003e\n‘:hourglass:’:U+231B,\u003cbr\u003e\n‘:hourglass_flowing_sand:’:U+23F3,\u003cbr\u003e\n‘:alarm_clock:’:U+23F0,\u003cbr\u003e\n‘:watch:’:U+231A,\u003cbr\u003e\n‘:radio:’:U+1F4FB,\u003cbr\u003e\n‘:satellite:’:U+1F4E1,\u003cbr\u003e\n‘:loop:’:U+27BF,\u003cbr\u003e\n‘:mag:’:U+1F50D,\u003cbr\u003e\n‘:mag_right:’:U+1F50E,\u003cbr\u003e\n‘:unlock:’:U+1F513,\u003cbr\u003e\n‘:lock:’:U+1F512,\u003cbr\u003e\n‘:lock_with_ink_pen:’:U+1F50F,\u003cbr\u003e\n‘:closed_lock_with_key:’:U+1F510,\u003cbr\u003e\n‘:key:’:U+1F511,\u003cbr\u003e\n‘:bulb:’:U+1F4A1,\u003cbr\u003e\n‘:flashlight:’:U+1F526,\u003cbr\u003e\n‘:high_brightness:’:U+1F506,\u003cbr\u003e\n‘:low_brightness:’:U+1F505,\u003cbr\u003e\n‘:electric_plug:’:U+1F50C,\u003cbr\u003e\n‘:battery:’:U+1F50B,\u003cbr\u003e\n‘:calling:’:U+1F4F2,\u003cbr\u003e\n‘:email:’:U+1F4E9,\u003cbr\u003e\n‘:mailbox:’:U+1F4EB,\u003cbr\u003e\n‘:postbox:’:U+1F4EE,\u003cbr\u003e\n‘:bath:’:U+1F6C0,\u003cbr\u003e\n‘:bathtub:’:U+1F6C1,\u003cbr\u003e\n‘:shower:’:U+1F6BF,\u003cbr\u003e\n‘:toilet:’:U+1F6BD,\u003cbr\u003e\n‘:wrench:’:U+1F527,\u003cbr\u003e\n‘:nut_and_bolt:’:U+1F529,\u003cbr\u003e\n‘:hammer:’:U+1F528,\u003cbr\u003e\n‘:seat:’:U+1F4BA,\u003cbr\u003e\n‘:moneybag:’:U+1F4B0,\u003cbr\u003e\n‘:yen:’:U+1F4B4,\u003cbr\u003e\n‘:dollar:’:U+1F4B5,\u003cbr\u003e\n‘:pound:’:U+1F4B7,\u003cbr\u003e\n‘:euro:’:U+1F4B6,\u003cbr\u003e\n‘:credit_card:’:U+1F4B3,\u003cbr\u003e\n‘:money_with_wings:’:U+1F4B8,\u003cbr\u003e\n‘:e-mail:’:U+1F4E7,\u003cbr\u003e\n‘:inbox_tray:’:U+1F4E5,\u003cbr\u003e\n‘:outbox_tray:’:U+1F4E4,\u003cbr\u003e\n‘:envelope:’:U+2709,\u003cbr\u003e\n‘:incoming_envelope:’:U+1F4E8,\u003cbr\u003e\n‘:postal_horn:’:U+1F4EF,\u003cbr\u003e\n‘:mailbox_closed:’:U+1F4EA,\u003cbr\u003e\n‘:mailbox_with_mail:’:U+1F4EC,\u003cbr\u003e\n‘:mailbox_with_no_mail:’:U+1F4ED,\u003cbr\u003e\n‘:door:’:U+1F6AA,\u003cbr\u003e\n‘:smoking:’:U+1F6AC,\u003cbr\u003e\n‘:bomb:’:U+1F4A3,\u003cbr\u003e\n‘:gun:’:U+1F52B,\u003cbr\u003e\n‘:hocho:’:U+1F52A,\u003cbr\u003e\n‘:pill:’:U+1F48A,\u003cbr\u003e\n‘:syringe:’:U+1F489,\u003cbr\u003e\n‘:page_facing_up:’:U+1F4C4,\u003cbr\u003e\n‘:page_with_curl:’:U+1F4C3,\u003cbr\u003e\n‘:bookmark_tabs:’:U+1F4D1,\u003cbr\u003e\n‘:bar_chart:’:U+1F4CA,\u003cbr\u003e\n‘:chart_with_upwards_trend:’:U+1F4C8,\u003cbr\u003e\n‘:chart_with_downwards_trend:’:U+1F4C9,\u003cbr\u003e\n‘:scroll:’:U+1F4DC,\u003cbr\u003e\n‘:clipboard:’:U+1F4CB,\u003cbr\u003e\n‘:calendar:’:U+1F4C6,\u003cbr\u003e\n‘:date:’:U+1F4C5,\u003cbr\u003e\n‘:card_index:’:U+1F4C7,\u003cbr\u003e\n‘:file_folder:’:U+1F4C1,\u003cbr\u003e\n‘:open_file_folder:’:U+1F4C2,\u003cbr\u003e\n‘:scissors:’:U+2702,\u003cbr\u003e\n‘:pushpin:’:U+1F4CC,\u003cbr\u003e\n‘:paperclip:’:U+1F4CE,\u003cbr\u003e\n‘:black_nib:’:U+2712,\u003cbr\u003e\n‘:pencil2:’:U+270F,\u003cbr\u003e\n‘:straight_ruler:’:U+1F4CF,\u003cbr\u003e\n‘:triangular_ruler:’:U+1F4D0,\u003cbr\u003e\n‘:closed_book:’:U+1F4D5,\u003cbr\u003e\n‘:green_book:’:U+1F4D7,\u003cbr\u003e\n‘:blue_book:’:U+1F4D8,\u003cbr\u003e\n‘:orange_book:’:U+1F4D9,\u003cbr\u003e\n‘:notebook:’:U+1F4D3,\u003cbr\u003e\n‘:notebook_with_decorative_cover:’:U+1F4D4,\u003cbr\u003e\n‘:ledger:’:U+1F4D2,\u003cbr\u003e\n‘:books:’:U+1F4DA,\u003cbr\u003e\n‘:bookmark:’:U+1F516,\u003cbr\u003e\n‘:name_badge:’:U+1F4DB,\u003cbr\u003e\n‘:microscope:’:U+1F52C,\u003cbr\u003e\n‘:telescope:’:U+1F52D,\u003cbr\u003e\n‘:newspaper:’:U+1F4F0,\u003cbr\u003e\n‘:football:’:U+1F3C8,\u003cbr\u003e\n‘:basketball:’:U+1F3C0,\u003cbr\u003e\n‘:soccer:’:U+26BD,\u003cbr\u003e\n‘:baseball:’:U+26BE,\u003cbr\u003e\n‘:tennis:’:U+1F3BE,\u003cbr\u003e\n‘:8ball:’:U+1F3B1,\u003cbr\u003e\n‘:rugby_football:’:U+1F3C9,\u003cbr\u003e\n‘:bowling:’:U+1F3B3,\u003cbr\u003e\n‘:golf:’:U+26F3,\u003cbr\u003e\n‘:mountain_bicyclist:’:U+1F6B5,\u003cbr\u003e\n‘:bicyclist:’:U+1F6B4,\u003cbr\u003e\n‘:horse_racing:’:U+1F40E,\u003cbr\u003e\n‘:snowboarder:’:U+1F3C2,\u003cbr\u003e\n‘:swimmer:’:U+1F3CA,\u003cbr\u003e\n‘:surfer:’:U+1F3C4,\u003cbr\u003e\n‘:ski:’:U+1F3BF,\u003cbr\u003e\n‘:spades:’:U+2660,\u003cbr\u003e\n‘:hearts:’:U+2665,\u003cbr\u003e\n‘:clubs:’:U+2663,\u003cbr\u003e\n‘:diamonds:’:U+2666,\u003cbr\u003e\n‘:gem:’:U+1F48E,\u003cbr\u003e\n‘:ring:’:U+1F48D,\u003cbr\u003e\n‘:trophy:’:U+1F3C6,\u003cbr\u003e\n‘:musical_score:’:U+1F3BC,\u003cbr\u003e\n‘:musical_keyboard:’:U+1F3B9,\u003cbr\u003e\n‘:violin:’:U+1F3BB,\u003cbr\u003e\n‘:space_invader:’:U+1F47E,\u003cbr\u003e\n‘:video_game:’:U+1F3AE,\u003cbr\u003e\n‘:black_joker:’:U+1F0CF,\u003cbr\u003e\n‘:flower_playing_cards:’:U+1F3B4,\u003cbr\u003e\n‘:game_die:’:U+1F3B2,\u003cbr\u003e\n‘:dart:’:U+1F3AF,\u003cbr\u003e\n‘:mahjong:’:U+1F004,\u003cbr\u003e\n‘:clapper:’:U+1F3AC,\u003cbr\u003e\n‘:memo:’:U+1F4DD,\u003cbr\u003e\n‘:pencil:’:U+1F4DD,\u003cbr\u003e\n‘:book:’:U+1F4D6,\u003cbr\u003e\n‘:art:’:U+1F3A8,\u003cbr\u003e\n‘:microphone:’:U+1F3A4,\u003cbr\u003e\n‘:headphones:’:U+1F3A7,\u003cbr\u003e\n‘:trumpet:’:U+1F3BA,\u003cbr\u003e\n‘:saxophone:’:U+1F3B7,\u003cbr\u003e\n‘:guitar:’:U+1F3B8,\u003cbr\u003e\n‘:shoe:’:U+1F45F,\u003cbr\u003e\n‘:sandal:’:U+1F461,\u003cbr\u003e\n‘:high_heel:’:U+1F460,\u003cbr\u003e\n‘:lipstick:’:U+1F484,\u003cbr\u003e\n‘:boot:’:U+1F462,\u003cbr\u003e\n‘:shirt:’:U+1F455,\u003cbr\u003e\n‘:tshirt:’:U+1F455,\u003cbr\u003e\n‘:necktie:’:U+1F454,\u003cbr\u003e\n‘:womans_clothes:’:U+1F45A,\u003cbr\u003e\n‘:dress:’:U+1F457,\u003cbr\u003e\n‘:running_shirt_with_sash:’:U+1F3BD,\u003cbr\u003e\n‘:jeans:’:U+1F456,\u003cbr\u003e\n‘:kimono:’:U+1F458,\u003cbr\u003e\n‘:bikini:’:U+1F459,\u003cbr\u003e\n‘:ribbon:’:U+1F380,\u003cbr\u003e\n‘:tophat:’:U+1F3A9,\u003cbr\u003e\n‘:crown:’:U+1F451,\u003cbr\u003e\n‘:womans_hat:’:U+1F452,\u003cbr\u003e\n‘:mans_shoe:’:U+1F45E,\u003cbr\u003e\n‘:closed_umbrella:’:U+1F302,\u003cbr\u003e\n‘:briefcase:’:U+1F4BC,\u003cbr\u003e\n‘:handbag:’:U+1F45C,\u003cbr\u003e\n‘:pouch:’:U+1F45D,\u003cbr\u003e\n‘:purse:’:U+1F45B,\u003cbr\u003e\n‘:eyeglasses:’:U+1F453,\u003cbr\u003e\n‘:fishing_pole_and_fish:’:U+1F3A3,\u003cbr\u003e\n‘:coffee:’:U+2615,\u003cbr\u003e\n‘:tea:’:U+1F375,\u003cbr\u003e\n‘:sake:’:U+1F376,\u003cbr\u003e\n‘:baby_bottle:’:U+1F37C,\u003cbr\u003e\n‘:beer:’:U+1F37A,\u003cbr\u003e\n‘:beers:’:U+1F37B,\u003cbr\u003e\n‘:cocktail:’:U+1F378,\u003cbr\u003e\n‘:tropical_drink:’:U+1F379,\u003cbr\u003e\n‘:wine_glass:’:U+1F377,\u003cbr\u003e\n‘:fork_and_knife:’:U+1F374,\u003cbr\u003e\n‘:pizza:’:U+1F355,\u003cbr\u003e\n‘:hamburger:’:U+1F354,\u003cbr\u003e\n‘:fries:’:U+1F35F,\u003cbr\u003e\n‘:poultry_leg:’:U+1F357,\u003cbr\u003e\n‘:meat_on_bone:’:U+1F356,\u003cbr\u003e\n‘:spaghetti:’:U+1F35D,\u003cbr\u003e\n‘:curry:’:U+1F35B,\u003cbr\u003e\n‘:fried_shrimp:’:U+1F364,\u003cbr\u003e\n‘:bento:’:U+1F371,\u003cbr\u003e\n‘:sushi:’:U+1F363,\u003cbr\u003e\n‘:fish_cake:’:U+1F365,\u003cbr\u003e\n‘:rice_ball:’:U+1F359,\u003cbr\u003e\n‘:rice_cracker:’:U+1F358,\u003cbr\u003e\n‘:rice:’:U+1F35A,\u003cbr\u003e\n‘:ramen:’:U+1F35C,\u003cbr\u003e\n‘:stew:’:U+1F372,\u003cbr\u003e\n‘:oden:’:U+1F362,\u003cbr\u003e\n‘:dango:’:U+1F361,\u003cbr\u003e\n‘:egg:’:U+1F373,\u003cbr\u003e\n‘:bread:’:U+1F35E,\u003cbr\u003e\n‘:doughnut:’:U+1F369,\u003cbr\u003e\n‘:custard:’:U+1F36E,\u003cbr\u003e\n‘:icecream:’:U+1F366,\u003cbr\u003e\n‘:ice_cream:’:U+1F368,\u003cbr\u003e\n‘:shaved_ice:’:U+1F367,\u003cbr\u003e\n‘:birthday:’:U+1F382,\u003cbr\u003e\n‘:cake:’:U+1F370,\u003cbr\u003e\n‘:cookie:’:U+1F36A,\u003cbr\u003e\n‘:chocolate_bar:’:U+1F36B,\u003cbr\u003e\n‘:candy:’:U+1F36C,\u003cbr\u003e\n‘:lollipop:’:U+1F36D,\u003cbr\u003e\n‘:honey_pot:’:U+1F36F,\u003cbr\u003e\n‘:apple:’:U+1F34E,\u003cbr\u003e\n‘:green_apple:’:U+1F34F,\u003cbr\u003e\n‘:tangerine:’:U+1F34A,\u003cbr\u003e\n‘:lemon:’:U+1F34B,\u003cbr\u003e\n‘:cherries:’:U+1F352,\u003cbr\u003e\n‘:grapes:’:U+1F347,\u003cbr\u003e\n‘:watermelon:’:U+1F349,\u003cbr\u003e\n‘:strawberry:’:U+1F353,\u003cbr\u003e\n‘:peach:’:U+1F351,\u003cbr\u003e\n‘:melon:’:U+1F348,\u003cbr\u003e\n‘:banana:’:U+1F34C,\u003cbr\u003e\n‘:pear:’:U+1F350,\u003cbr\u003e\n‘:pineapple:’:U+1F34D,\u003cbr\u003e\n‘:sweet_potato:’:U+1F360,\u003cbr\u003e\n‘:eggplant:’:U+1F346,\u003cbr\u003e\n‘:tomato:’:U+1F345,\u003cbr\u003e\n‘:corn:’:U+1F33D,\u003cbr\u003e\n‘:house:’:U+1F3E0,\u003cbr\u003e\n‘:house_with_garden:’:U+1F3E1,\u003cbr\u003e\n‘:school:’:U+1F3EB,\u003cbr\u003e\n‘:office:’:U+1F3E2,\u003cbr\u003e\n‘:post_office:’:U+1F3E3,\u003cbr\u003e\n‘:hospital:’:U+1F3E5,\u003cbr\u003e\n‘:bank:’:U+1F3E6,\u003cbr\u003e\n‘:convenience_store:’:U+1F3EA,\u003cbr\u003e\n‘:love_hotel:’:U+1F3E9,\u003cbr\u003e\n‘:hotel:’:U+1F3E8,\u003cbr\u003e\n‘:wedding:’:U+1F492,\u003cbr\u003e\n‘:church:’:U+26EA,\u003cbr\u003e\n‘:department_store:’:U+1F3EC,\u003cbr\u003e\n‘:european_post_office:’:582,\u003cbr\u003e\n‘:city_sunrise:’:U+1F307,\u003cbr\u003e\n‘:city_sunset:’:U+1F306,\u003cbr\u003e\n‘:japanese_castle:’:U+1F3EF,\u003cbr\u003e\n‘:european_castle:’:U+1F3F0,\u003cbr\u003e\n‘:tent:’:U+26FA,\u003cbr\u003e\n‘:factory:’:U+1F3ED,\u003cbr\u003e\n‘:tokyo_tower:’:U+1F5FC,\u003cbr\u003e\n‘:japan:’:U+1F5FE,\u003cbr\u003e\n‘:mount_fuji:’:U+1F5FB,\u003cbr\u003e\n‘:sunrise_over_mountains:’:U+1F304,\u003cbr\u003e\n‘:sunrise:’:U+1F305,\u003cbr\u003e\n‘:stars:’:U+1F303,\u003cbr\u003e\n‘:statue_of_liberty:’:U+1F5FD,\u003cbr\u003e\n‘:bridge_at_night:’:U+1F309,\u003cbr\u003e\n‘:carousel_horse:’:U+1F3A0,\u003cbr\u003e\n‘:rainbow:’:U+1F308,\u003cbr\u003e\n‘:ferris_wheel:’:U+1F3A1,\u003cbr\u003e\n‘:fountain:’:U+26F2,\u003cbr\u003e\n‘:roller_coaster:’:U+1F3A2,\u003cbr\u003e\n‘:ship:’:U+1F6A2,\u003cbr\u003e\n‘:speedboat:’:U+1F6A4,\u003cbr\u003e\n‘:boat:’:U+26F5,\u003cbr\u003e\n‘:sailboat:’:U+26F5,\u003cbr\u003e\n‘:rowboat:’:U+1F6A3,\u003cbr\u003e\n‘:anchor:’:U+2693,\u003cbr\u003e\n‘:rocket:’:U+1F680,\u003cbr\u003e\n‘:airplane:’:U+2708,\u003cbr\u003e\n‘:helicopter:’:U+1F681,\u003cbr\u003e\n‘:steam_locomotive:’:U+1F682,\u003cbr\u003e\n‘:tram:’:U+1F68A,\u003cbr\u003e\n‘:mountain_railway:’:613,\u003cbr\u003e\n‘:bike:’:U+1F6B2,\u003cbr\u003e\n‘:aerial_tramway:’:U+1F6A1,\u003cbr\u003e\n‘:suspension_railway:’:U+1F69F,\u003cbr\u003e\n‘:mountain_cableway:’:U+1F6A0,\u003cbr\u003e\n‘:tractor:’:U+1F69C,\u003cbr\u003e\n‘:blue_car:’:U+1F699,\u003cbr\u003e\n‘:oncoming_automobile:’:U+1F698,\u003cbr\u003e\n‘:car:’:U+1F697,\u003cbr\u003e\n‘:red_car:’:U+1F697,\u003cbr\u003e\n‘:taxi:’:U+1F695,\u003cbr\u003e\n‘:oncoming_taxi:’:U+1F696,\u003cbr\u003e\n‘:articulated_lorry:’:625,\u003cbr\u003e\n‘:bus:’:U+1F68C,\u003cbr\u003e\n‘:oncoming_bus:’:U+1F68D,\u003cbr\u003e\n‘:rotating_light:’:U+1F6A8,\u003cbr\u003e\n‘:police_car:’:U+1F693,\u003cbr\u003e\n‘:oncoming_police_car:’:U+1F694,\u003cbr\u003e\n‘:fire_engine:’:U+1F692,\u003cbr\u003e\n‘:ambulance:’:U+1F691,\u003cbr\u003e\n‘:minibus:’:U+1F690,\u003cbr\u003e\n‘:truck:’:U+1F69A,\u003cbr\u003e\n‘:train:’:U+1F683,\u003cbr\u003e\n‘:station:’:U+1F689,\u003cbr\u003e\n‘:train2:’:U+1F685,\u003cbr\u003e\n‘:bullettrain_front:’:U+1F685,\u003cbr\u003e\n‘:bullettrain_side:’:U+1F684,\u003cbr\u003e\n‘:light_rail:’:U+1F688,\u003cbr\u003e\n‘:monorail:’:U+1F69D,\u003cbr\u003e\n‘:railway_car:’:U+1F683,\u003cbr\u003e\n‘:trolleybus:’:U+1F68E,\u003cbr\u003e\n‘:ticket:’:U+1F3AB,\u003cbr\u003e\n‘:fuelpump:’:U+26FD,\u003cbr\u003e\n‘:vertical_traffic_light:’:U+1F6A6,\u003cbr\u003e\n‘:traffic_light:’:U+1F6A5,\u003cbr\u003e\n‘:warning:’:U+26A0,\u003cbr\u003e\n‘:construction:’:U+1F6A7,\u003cbr\u003e\n‘:beginner:’:U+1F530,\u003cbr\u003e\n‘:atm:’:U+1F3E7,\u003cbr\u003e\n‘:slot_machine:’:U+1F3B0,\u003cbr\u003e\n‘:busstop:’:U+1F68F,\u003cbr\u003e\n‘:barber:’:U+1F488,\u003cbr\u003e\n‘:hotsprings:’:U+2668,\u003cbr\u003e\n‘:checkered_flag:’:U+1F3C1,\u003cbr\u003e\n‘:crossed_flags:’:U+1F38C,\u003cbr\u003e\n‘:izakaya_lantern:’:U+1F3EE,\u003cbr\u003e\n‘:moyai:’:U+1F5FF,\u003cbr\u003e\n‘:circus_tent:’:U+1F3AA,\u003cbr\u003e\n‘:performing_arts:’:U+1F3AD,\u003cbr\u003e\n‘:round_pushpin:’:U+1F4CD,\u003cbr\u003e\n‘:triangular_flag_on_post:’:U+1F6A9,\u003cbr\u003e\n‘:jp:’:U+1F1EF U+1F1F5,\u003cbr\u003e\n‘:kr:’:U+1F1F0 U+1F1F7,\u003cbr\u003e\n‘:cn:’:U+1F1E8 U+1F1F3,\u003cbr\u003e\n‘:us:’:U+1F1FA U+1F1F8,\u003cbr\u003e\n‘:fr:’:U+1F1EB U+1F1F7,\u003cbr\u003e\n‘:es:’:U+1F1EA U+1F1F8,\u003cbr\u003e\n‘:it:’:U+1F1EE U+1F1F9,\u003cbr\u003e\n‘:ru:’:U+1F1F7 U+1F1FA,\u003cbr\u003e\n‘:gb:’:U+1F1EC U+1F1E7,\u003cbr\u003e\n‘:uk:’:U+1F1EC U+1F1E7,\u003cbr\u003e\n‘:de:’:U+1F1E9 U+1F1EA,\u003cbr\u003e\n‘:one:’:U+0031 U+20E3,\u003cbr\u003e\n‘:two:’:U+0032 U+20E3,\u003cbr\u003e\n‘:three:’:U+0033 U+20E3,\u003cbr\u003e\n‘:four:’:U+0034 U+20E3,\u003cbr\u003e\n‘:five:’:U+0035 U+20E3,\u003cbr\u003e\n‘:six:’:U+0036 U+20E3,\u003cbr\u003e\n‘:seven:’:U+0037 U+20E3,\u003cbr\u003e\n‘:eight:’:U+0038 U+20E3,\u003cbr\u003e\n‘:nine:’:U+0039 U+20E3,\u003cbr\u003e\n‘:keycap_ten:’:U+1F51F,\u003cbr\u003e\n‘:1234:’:U+1F522,\u003cbr\u003e\n‘:zero:’:U+0030 U+20E3,\u003cbr\u003e\n‘:hash:’:U+0023 U+20E3,\u003cbr\u003e\n‘:symbols:’:U+1F523,\u003cbr\u003e\n‘:arrow_backward:’:U+25C0,\u003cbr\u003e\n‘:arrow_down:’:U+2B07,\u003cbr\u003e\n‘:arrow_forward:’:U+25B6,\u003cbr\u003e\n‘:arrow_left:’:U+2B05,\u003cbr\u003e\n‘:capital_abcd:’:U+1F520,\u003cbr\u003e\n‘:abcd:’:U+1F521,\u003cbr\u003e\n‘:abc:’:U+1F524,\u003cbr\u003e\n‘:arrow_lower_left:’:U+2199,\u003cbr\u003e\n‘:arrow_lower_right:’:U+2198,\u003cbr\u003e\n‘:arrow_right:’:U+27A1,\u003cbr\u003e\n‘:arrow_up:’:U+2B06,\u003cbr\u003e\n‘:arrow_upper_left:’:U+2196,\u003cbr\u003e\n‘:arrow_upper_right:’:U+2197,\u003cbr\u003e\n‘:arrow_double_down:’:U+23EC,\u003cbr\u003e\n‘:arrow_double_up:’:U+23EB,\u003cbr\u003e\n‘:arrow_down_small:’:U+1F53D,\u003cbr\u003e\n‘:arrow_heading_down:’:U+2935,\u003cbr\u003e\n‘:arrow_heading_up:’:U+2934,\u003cbr\u003e\n‘:leftwards_arrow_with_hook:’:U+21A9,\u003cbr\u003e\n‘:arrow_right_hook:’:U+21AA,\u003cbr\u003e\n‘:left_right_arrow:’:U+2194,\u003cbr\u003e\n‘:arrow_up_down:’:U+2195,\u003cbr\u003e\n‘:arrow_up_small:’:U+1F53D,\u003cbr\u003e\n‘:arrows_clockwise:’:U+1F503,\u003cbr\u003e\n‘:arrows_counterclockwise:’:U+1F504,\u003cbr\u003e\n‘:rewind:’:U+23EA,\u003cbr\u003e\n‘:fast_forward:’:U+23E9,\u003cbr\u003e\n‘:information_source:’:U+2139,\u003cbr\u003e\n‘:ok:’:U+1F197,\u003cbr\u003e\n‘:twisted_rightwards_arrows:’:U+1F500,\u003cbr\u003e\n‘:repeat:’:U+1F501,\u003cbr\u003e\n‘:repeat_one:’:U+1F502,\u003cbr\u003e\n‘:new:’:U+1F195,\u003cbr\u003e\n‘:top:’:U+1F51D,\u003cbr\u003e\n‘:up:’:U+1F199,\u003cbr\u003e\n‘:cool:’:U+1F192,\u003cbr\u003e\n‘:free:’:U+1F193,\u003cbr\u003e\n‘:ng:’:U+1F196,\u003cbr\u003e\n‘:cinema:’:U+1F3A6,\u003cbr\u003e\n‘:koko:’:728U+1F201\u003cbr\u003e\n‘:signal_strength:’:U+1F4F6,\u003cbr\u003e\n‘:u5272:’:U+1F239,\u003cbr\u003e\n‘:u5408:’:U+1F234,\u003cbr\u003e\n‘:u55b6:’:U+1F23A,\u003cbr\u003e\n‘:u6307:’:U+1F22F,\u003cbr\u003e\n‘:u6708:’:U+1F237,\u003cbr\u003e\n‘:u6709:’:U+1F236,\u003cbr\u003e\n‘:u6e80:’:U+1F235,\u003cbr\u003e\n‘:u7121:’:U+1F21A,\u003cbr\u003e\n‘:u7533:’:U+1F238,\u003cbr\u003e\n‘:u7a7a:’:U+1F233,\u003cbr\u003e\n‘:u7981:’:U+1F232,\u003cbr\u003e\n‘:sa:’:U+1F202,\u003cbr\u003e\n‘:restroom:’:U+1F6BB,\u003cbr\u003e\n‘:mens:’:U+1F6B9,\u003cbr\u003e\n‘:womens:’:U+1F6BA,\u003cbr\u003e\n‘:baby_symbol:’:U+1F6BC,\u003cbr\u003e\n‘:no_smoking:’:U+1F6AD,\u003cbr\u003e\n‘:parking:’:U+1F17F,\u003cbr\u003e\n‘:wheelchair:’:U+267F,\u003cbr\u003e\n‘:metro:’:U+1F687,\u003cbr\u003e\n‘:baggage_claim:’:U+1F6C4,\u003cbr\u003e\n‘:accept:’:U+1F251,\u003cbr\u003e\n‘:wc:’:U+1F6BE,\u003cbr\u003e\n‘:potable_water:’:U+1F6B0,\u003cbr\u003e\n‘:put_litter_in_its_place:’:U+1F6AE,\u003cbr\u003e\n‘:secret:’:U+3299,\u003cbr\u003e\n‘:congratulations:’:U+3297,\u003cbr\u003e\n‘:m:’:U+24C2,\u003cbr\u003e\n‘:passport_control:’:U+1F6C2,\u003cbr\u003e\n‘:left_luggage:’:U+1F6C5,\u003cbr\u003e\n‘:customs:’:U+1F6C3,\u003cbr\u003e\n‘:ideograph_advantage:’:U+1F250,\u003cbr\u003e\n‘:cl:’:U+1F191,\u003cbr\u003e\n‘:sos:’:U+1F198,\u003cbr\u003e\n‘:id:’:U+1F194,\u003cbr\u003e\n‘:no_entry_sign:’:U+1F6AB,\u003cbr\u003e\n‘:underage:’:U+1F51E,\u003cbr\u003e\n‘:no_mobile_phones:’:U+1F4F5,\u003cbr\u003e\n‘:do_not_litter:’:U+1F6AF,\u003cbr\u003e\n‘:non-potable_water:’:U+1F6B1,\u003cbr\u003e\n‘:no_bicycles:’:U+1F6B3,\u003cbr\u003e\n‘:no_pedestrians:’:U+1F6B7,\u003cbr\u003e\n‘:children_crossing:’:U+1F6B8,\u003cbr\u003e\n‘:no_entry:’:U+26D4,\u003cbr\u003e\n‘:eight_spoked_asterisk:’:U+2733,\u003cbr\u003e\n‘:eight_pointed_black_star:’:U+2734,\u003cbr\u003e\n‘:heart_decoration:’:U+1F49F,\u003cbr\u003e\n‘:vs:’:U+1F19A,\u003cbr\u003e\n‘:vibration_mode:’:U+1F4F3,\u003cbr\u003e\n‘:mobile_phone_off:’:U+1F4F4,\u003cbr\u003e\n‘:chart:’:U+1F4B9,\u003cbr\u003e\n‘:currency_exchange:’:U+1F4B1,\u003cbr\u003e\n‘:aries:’:U+2648,\u003cbr\u003e\n‘:taurus:’:U+2649,\u003cbr\u003e\n‘:gemini:’:U+264A,\u003cbr\u003e\n‘:cancer:’:U+264B,\u003cbr\u003e\n‘:leo:’:U+264C,\u003cbr\u003e\n‘:virgo:’:U+264D,\u003cbr\u003e\n‘:libra:’:U+264E,\u003cbr\u003e\n‘:scorpius:’:U+264F,\u003cbr\u003e\n‘:sagittarius:’:U+2650,\u003cbr\u003e\n‘:capricorn:’:U+2651,\u003cbr\u003e\n‘:aquarius:’:U+2652,\u003cbr\u003e\n‘:pisces:’:U+2653,\u003cbr\u003e\n‘:ophiuchus:’:U+26CE,\u003cbr\u003e\n‘:six_pointed_star:’:U+1F52F,\u003cbr\u003e\n‘:negative_squared_cross_mark:’:U+274E,\u003cbr\u003e\n‘:a:’:U+1F170,\u003cbr\u003e\n‘:b:’:U+1F171,\u003cbr\u003e\n‘:ab:’:U+1F18E,\u003cbr\u003e\n‘:o2:’:U+1F17E,\u003cbr\u003e\n‘:diamond_shape_with_a_dot_inside:’:U+1F4A0,\u003cbr\u003e\n‘:recycle:’:U+267B,\u003cbr\u003e\n‘:end:’:U+1F51A,\u003cbr\u003e\n‘:on:’:U+1F51B,\u003cbr\u003e\n‘:soon:’:U+1F51C,\u003cbr\u003e\n‘:clock1:’:U+1F550,\u003cbr\u003e\n‘:clock130:’:U+1F55C,\u003cbr\u003e\n‘:clock10:’:U+1F559,\u003cbr\u003e\n‘:clock1030:’:U+1F565,\u003cbr\u003e\n‘:clock11:’:U+1F55A,\u003cbr\u003e\n‘:clock1130:’:U+1F566,\u003cbr\u003e\n‘:clock12:’:U+1F55B,\u003cbr\u003e\n‘:clock1230:’:U+1F567,\u003cbr\u003e\n‘:clock2:’:U+1F551,\u003cbr\u003e\n‘:clock230:’:U+1F55D,\u003cbr\u003e\n‘:clock3:’:U+1F552,\u003cbr\u003e\n‘:clock330:’:U+1F55E,\u003cbr\u003e\n‘:clock4:’:U+1F553,\u003cbr\u003e\n‘:clock430:’:U+1F55F,\u003cbr\u003e\n‘:clock5:’:U+1F554,\u003cbr\u003e\n‘:clock530:’:U+1F560,\u003cbr\u003e\n‘:clock6:’:U+1F555,\u003cbr\u003e\n‘:clock630:’:U+1F561,\u003cbr\u003e\n‘:clock7:’:U+1F556,\u003cbr\u003e\n‘:clock730:’:U+1F562,\u003cbr\u003e\n‘:clock8:’:U+1F557,\u003cbr\u003e\n‘:clock830:’:U+1F563,\u003cbr\u003e\n‘:clock9:’:U+1F558,\u003cbr\u003e\n‘:clock930:’:U+1F564,\u003cbr\u003e\n‘:heavy_dollar_sign:’:U+1F4B2,\u003cbr\u003e\n‘:copyright:’:U+00A9,\u003cbr\u003e\n‘:registered:’:U+00AE,\u003cbr\u003e\n‘:tm:’:U+2122,\u003cbr\u003e\n‘:x:’:U+274C,\u003cbr\u003e\n‘:heavy_exclamation_mark:’:U+2757,\u003cbr\u003e\n‘:bangbang:’:U+203C,\u003cbr\u003e\n‘:interrobang:’:U+2049,\u003cbr\u003e\n‘:o:’:U+2B55,\u003cbr\u003e\n‘:heavy_multiplication_x:’:U+2716,\u003cbr\u003e\n‘:heavy_plus_sign:’:U+2795,\u003cbr\u003e\n‘:heavy_minus_sign:’:U+2796,\u003cbr\u003e\n‘:heavy_division_sign:’:U+2797,\u003cbr\u003e\n‘:white_flower:’:U+1F4AE,\u003cbr\u003e\n‘:100:’:U+1F4AF,\u003cbr\u003e\n‘:heavy_check_mark:’:U+2714,\u003cbr\u003e\n‘:ballot_box_with_check:’:U+2611,\u003cbr\u003e\n‘:radio_button:’:U+1F518,\u003cbr\u003e\n‘:link:’:U+1F517,\u003cbr\u003e\n‘:curly_loop:’:U+27B0,\u003cbr\u003e\n‘:wavy_dash:’:U+3030,\u003cbr\u003e\n‘:part_alternation_mark:’:U+303D,\u003cbr\u003e\n‘:trident:’:U+1F531,\u003cbr\u003e\n‘:black_square:’:U+2B1B,\u003cbr\u003e\n‘:white_square:’:U+2B1C,\u003cbr\u003e\n‘:white_check_mark:’:U+2705,\u003cbr\u003e\n‘:black_square_button:’:U+1F532,\u003cbr\u003e\n‘:white_square_button:’:U+1F533,\u003cbr\u003e\n‘:black_circle:’:U+26AB,\u003cbr\u003e\n‘:white_circle:’:U+26AA,\u003cbr\u003e\n‘:red_circle:’:U+1F534,\u003cbr\u003e\n‘:large_blue_circle:’:U+1F535,\u003cbr\u003e\n‘:large_blue_diamond:’:U+1F537,\u003cbr\u003e\n‘:large_orange_diamond:’:U+1F536,\u003cbr\u003e\n‘:small_blue_diamond:’:U+1F539,\u003cbr\u003e\n‘:small_orange_diamond:’:U+1F538,\u003cbr\u003e\n‘:small_red_triangle:’:U+1F53A,\u003cbr\u003e\n‘:small_red_triangle_down:’:U+1F53B,\u003cbr\u003e\n‘:shipit:’:868\u003c/p\u003e","title":"emoji 表情 编码整理"},{"content":"一、概述： 在日常的app使用中，我们会在android 的app中看见 热门标签等自动换行的流式布局，今天，我们就来看看如何\n自定义一个类似热门标签那样的流式布局吧（源码下载在下面最后给出）\n类似的自定义布局。下面我们就来详细介绍流式布局的应用特点以及用的的技术点：\n1.流式布局的特点以及应用场景 特点：当上面一行的空间不够容纳新的TextView时候， 才开辟下一行的空间\n原理图：\n场景：主要用于关键词搜索或者热门标签等场景 2.自定义ViewGroup,重点重写下面两个方法\n1、onMeasure:测量子view的宽高，设置自己的宽和高\n2、onLayout:设置子view的位置\nonMeasure:根据子view的布局文件中属性，来为子view设置测量模式和测量值 测量=测量模式+测量值；\n测量模式有3种： EXACTLY：表示设置了精确的值，一般当childView设置其宽、高为精确值、match_parent时，ViewGroup会将其设置为EXACTLY； AT_MOST：表示子布局被限制在一个最大值内，一般当childView设置其宽、高为wrap_content时，ViewGroup会将其设置为AT_MOST； UNSPECIFIED：表示子布局想要多大就多大，一般出现在AadapterView的item的heightMode中、ScrollView的childView的heightMode中；此种模式比较少见。 3.LayoutParams ViewGroup LayoutParams :每个 ViewGroup 对应一个 LayoutParams; 即 ViewGroup -\u0026gt; LayoutParams getLayoutParams 不知道转为哪个对应的LayoutParams ,其实很简单，就是如下： 子View.getLayoutParams 得到的LayoutParams对应的就是 子View所在的父控件的LayoutParams; 例如，LinearLayout 里面的子view.getLayoutParams -\u0026gt;LinearLayout.LayoutParams 所以 咱们的FlowLayout 也需要一个LayoutParams，由于上面的效果图是子View的 margin， 所以应该使用MarginLayoutParams。即FlowLayout-\u0026gt;MarginLayoutParams\n4.最后来看看实现的最终效果图：\n二、热门标签的流式布局的实现：\n1. 自定义热门标签的ViewGroup实现\n根据上面的技术分析，自定义类继承于ViewGroup，并重写 onMeasure和onLayout等方法。具体实现代码如下：\n[Java] *纯文本查看* *复制代码* [?](http://www.apkbus.com/#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 001 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 002 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 003 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 004 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 005 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 006 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 007 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 008 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 009 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 010 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 011 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 012 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 013 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 014 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 015 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 016 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 017 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 018 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 019 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 020 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 021 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 022 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 023 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 024 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 025 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 026 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 027 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 028 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 029 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 030 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 031 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 032 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 033 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 034 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 035 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 036 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 037 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 038 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 039 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; 040 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; 041 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; 042 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; 043 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; 044 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; 045 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; 046 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; 047 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; 048 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; 049 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; 050 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; 051 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; 052 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; 053 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; 054 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; 055 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; 056 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; 057 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; 058 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; 059 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; 060 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; 061 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; 062 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; 063 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; 064 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; 065 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; 066 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; 067 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; 068 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; 069 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; 070 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; 071 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; 072 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; 073 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; 074 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; 075 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; 076 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; 077 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; 078 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; 079 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; 080 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; 081 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; 082 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; 083 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; 084 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; 085 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; 086 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; 087 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; 088 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; 089 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; 090 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; 091 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt; 092 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt; 093 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt; 094 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt; 095 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt; 096 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt; 097 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt; 098 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt; 099 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt; 100 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number101 index100 alt2\u0026quot;\u0026gt; 101 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number102 index101 alt1\u0026quot;\u0026gt; 102 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number103 index102 alt2\u0026quot;\u0026gt; 103 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number104 index103 alt1\u0026quot;\u0026gt; 104 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number105 index104 alt2\u0026quot;\u0026gt; 105 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number106 index105 alt1\u0026quot;\u0026gt; 106 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number107 index106 alt2\u0026quot;\u0026gt; 107 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number108 index107 alt1\u0026quot;\u0026gt; 108 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number109 index108 alt2\u0026quot;\u0026gt; 109 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number110 index109 alt1\u0026quot;\u0026gt; 110 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number111 index110 alt2\u0026quot;\u0026gt; 111 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number112 index111 alt1\u0026quot;\u0026gt; 112 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number113 index112 alt2\u0026quot;\u0026gt; 113 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number114 index113 alt1\u0026quot;\u0026gt; 114 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number115 index114 alt2\u0026quot;\u0026gt; 115 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number116 index115 alt1\u0026quot;\u0026gt; 116 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number117 index116 alt2\u0026quot;\u0026gt; 117 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number118 index117 alt1\u0026quot;\u0026gt; 118 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number119 index118 alt2\u0026quot;\u0026gt; 119 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number120 index119 alt1\u0026quot;\u0026gt; 120 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number121 index120 alt2\u0026quot;\u0026gt; 121 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number122 index121 alt1\u0026quot;\u0026gt; 122 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number123 index122 alt2\u0026quot;\u0026gt; 123 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number124 index123 alt1\u0026quot;\u0026gt; 124 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number125 index124 alt2\u0026quot;\u0026gt; 125 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number126 index125 alt1\u0026quot;\u0026gt; 126 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number127 index126 alt2\u0026quot;\u0026gt; 127 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number128 index127 alt1\u0026quot;\u0026gt; 128 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number129 index128 alt2\u0026quot;\u0026gt; 129 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number130 index129 alt1\u0026quot;\u0026gt; 130 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number131 index130 alt2\u0026quot;\u0026gt; 131 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number132 index131 alt1\u0026quot;\u0026gt; 132 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number133 index132 alt2\u0026quot;\u0026gt; 133 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number134 index133 alt1\u0026quot;\u0026gt; 134 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number135 index134 alt2\u0026quot;\u0026gt; 135 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number136 index135 alt1\u0026quot;\u0026gt; 136 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number137 index136 alt2\u0026quot;\u0026gt; 137 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number138 index137 alt1\u0026quot;\u0026gt; 138 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number139 index138 alt2\u0026quot;\u0026gt; 139 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number140 index139 alt1\u0026quot;\u0026gt; 140 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number141 index140 alt2\u0026quot;\u0026gt; 141 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number142 index141 alt1\u0026quot;\u0026gt; 142 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number143 index142 alt2\u0026quot;\u0026gt; 143 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number144 index143 alt1\u0026quot;\u0026gt; 144 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number145 index144 alt2\u0026quot;\u0026gt; 145 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number146 index145 alt1\u0026quot;\u0026gt; 146 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number147 index146 alt2\u0026quot;\u0026gt; 147 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number148 index147 alt1\u0026quot;\u0026gt; 148 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number149 index148 alt2\u0026quot;\u0026gt; 149 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number150 index149 alt1\u0026quot;\u0026gt; 150 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number151 index150 alt2\u0026quot;\u0026gt; 151 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number152 index151 alt1\u0026quot;\u0026gt; 152 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number153 index152 alt2\u0026quot;\u0026gt; 153 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number154 index153 alt1\u0026quot;\u0026gt; 154 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number155 index154 alt2\u0026quot;\u0026gt; 155 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number156 index155 alt1\u0026quot;\u0026gt; 156 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number157 index156 alt2\u0026quot;\u0026gt; 157 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number158 index157 alt1\u0026quot;\u0026gt; 158 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number159 index158 alt2\u0026quot;\u0026gt; 159 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number160 index159 alt1\u0026quot;\u0026gt; 160 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number161 index160 alt2\u0026quot;\u0026gt; 161 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number162 index161 alt1\u0026quot;\u0026gt; 162 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number163 index162 alt2\u0026quot;\u0026gt; 163 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number164 index163 alt1\u0026quot;\u0026gt; 164 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number165 index164 alt2\u0026quot;\u0026gt; 165 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number166 index165 alt1\u0026quot;\u0026gt; 166 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number167 index166 alt2\u0026quot;\u0026gt; 167 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;font color=``\u0026quot;#362e2b\u0026quot;``\u0026amp;gt;\u0026amp;lt;font style=``\u0026quot;background-color:rgb(255, 255, 255)\u0026quot;``\u0026amp;gt;\u0026amp;lt;font face=``\u0026quot;Arial\u0026quot;``\u0026amp;gt;\u0026amp;lt;font style=``\u0026quot;font-size:14px\u0026quot;``\u0026amp;gt;``package` `com.czm.flowlayout;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `import` `java.util.ArrayList;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `import` `java.util.List;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `import` `android.content.Context;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `import` `android.util.AttributeSet;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; `import` `android.view.View;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; `import` `android.view.ViewGroup;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; `/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``* ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``* @author caizhiming` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``* @created on 2015-4-13` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; `public` `class` `XCFlowLayout ``extends` `ViewGroup{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``//存储所有子View` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``private` `List\u0026amp;lt;List\u0026amp;lt;View\u0026amp;gt;\u0026amp;gt; mAllChildViews = ``new` `ArrayList\u0026amp;lt;\u0026amp;gt;();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``//每一行的高度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``private` `List\u0026amp;lt;Integer\u0026amp;gt; mLineHeight = ``new` `ArrayList\u0026amp;lt;\u0026amp;gt;();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``public` `XCFlowLayout(Context context) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``this``(context, ``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``// TODO Auto-generated constructor stub` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``public` `XCFlowLayout(Context context, AttributeSet attrs) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``this``(context, attrs, ````);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ``// TODO Auto-generated constructor stub` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ``public` `XCFlowLayout(Context context, AttributeSet attrs, ``int` `defStyle) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``super``(context, attrs, defStyle);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ``// TODO Auto-generated constructor stub` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``protected` `void` `onMeasure(``int` `widthMeasureSpec, ``int` `heightMeasureSpec) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; ` ``// TODO Auto-generated method stub` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; ` ``//父控件传进来的宽度和高度以及对应的测量模式` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; ` ``int` `sizeWidth = MeasureSpec.getSize(widthMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; ` ``int` `modeWidth = MeasureSpec.getMode(widthMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; ` ``int` `sizeHeight = MeasureSpec.getSize(heightMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; ` ``int` `modeHeight = MeasureSpec.getMode(heightMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; ` ``//如果当前ViewGroup的宽高为wrap_content的情况` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; ` ``int` `width = ````;``//自己测量的 宽度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; ` ``int` `height = ````;``//自己测量的高度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; ` ``//记录每一行的宽度和高度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; ` ``int` `lineWidth = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; ` ``int` `lineHeight = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; ` ``//获取子view的个数` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; ` ``int` `childCount = getChildCount();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; ` ``for``(``int` `i = ````;i \u0026amp;lt; childCount; i ++){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; ` ``View child = getChildAt(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; ` ``//测量子View的宽和高` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; ` ``measureChild(child, widthMeasureSpec, heightMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; ` ``//得到LayoutParams` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; ` ``MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; ` ``//子View占据的宽度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; ` ``int` `childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; ` ``//子View占据的高度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; ` ``int` `childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; ` ``//换行时候` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; ` ``if``(lineWidth + childWidth \u0026amp;gt; sizeWidth){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; ` ``//对比得到最大的宽度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; ` ``width = Math.max(width, lineWidth);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; ` ``//重置lineWidth` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; ` ``lineWidth = childWidth;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; ` ``//记录行高` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; ` ``height += lineHeight;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; ` ``lineHeight = childHeight;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; ` ``}``else``{``//不换行情况` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; ` ``//叠加行宽` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; ` ``lineWidth += childWidth;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; ` ``//得到最大行高` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; ` ``lineHeight = Math.max(lineHeight, childHeight);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; ` ``//处理最后一个子View的情况` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; ` ``if``(i == childCount -``1``){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; ` ``width = Math.max(width, lineWidth);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; ` ``height += lineHeight;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; ` ``//wrap_content` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; ` ``setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; ` ``modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; ` ``super``.onMeasure(widthMeasureSpec, heightMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; ` ``protected` `void` `onLayout(``boolean` `changed, ``int` `l, ``int` `t, ``int` `r, ``int` `b) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt; ` ``// TODO Auto-generated method stub` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt; ` ``mAllChildViews.clear();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt; ` ``mLineHeight.clear();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt; ` ``//获取当前ViewGroup的宽度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt; ` ``int` `width = getWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt; ` ``int` `lineWidth = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt; ` ``int` `lineHeight = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt; ` ``//记录当前行的view` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number101 index100 alt2\u0026quot;\u0026gt; ` ``List\u0026amp;lt;View\u0026amp;gt; lineViews = ``new` `ArrayList\u0026amp;lt;View\u0026amp;gt;();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number102 index101 alt1\u0026quot;\u0026gt; ` ``int` `childCount = getChildCount();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number103 index102 alt2\u0026quot;\u0026gt; ` ``for``(``int` `i = ````;i \u0026amp;lt; childCount; i ++){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number104 index103 alt1\u0026quot;\u0026gt; ` ``View child = getChildAt(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number105 index104 alt2\u0026quot;\u0026gt; ` ``MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number106 index105 alt1\u0026quot;\u0026gt; ` ``int` `childWidth = child.getMeasuredWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number107 index106 alt2\u0026quot;\u0026gt; ` ``int` `childHeight = child.getMeasuredHeight();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number108 index107 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number109 index108 alt2\u0026quot;\u0026gt; ` ``//如果需要换行` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number110 index109 alt1\u0026quot;\u0026gt; ` ``if``(childWidth + lineWidth + lp.leftMargin + lp.rightMargin \u0026amp;gt; width){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number111 index110 alt2\u0026quot;\u0026gt; ` ``//记录LineHeight` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number112 index111 alt1\u0026quot;\u0026gt; ` ``mLineHeight.add(lineHeight);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number113 index112 alt2\u0026quot;\u0026gt; ` ``//记录当前行的Views` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number114 index113 alt1\u0026quot;\u0026gt; ` ``mAllChildViews.add(lineViews);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number115 index114 alt2\u0026quot;\u0026gt; ` ``//重置行的宽高` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number116 index115 alt1\u0026quot;\u0026gt; ` ``lineWidth = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number117 index116 alt2\u0026quot;\u0026gt; ` ``lineHeight = childHeight + lp.topMargin + lp.bottomMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number118 index117 alt1\u0026quot;\u0026gt; ` ``//重置view的集合` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number119 index118 alt2\u0026quot;\u0026gt; ` ``lineViews = ``new` `ArrayList();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number120 index119 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number121 index120 alt2\u0026quot;\u0026gt; ` ``lineWidth += childWidth + lp.leftMargin + lp.rightMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number122 index121 alt1\u0026quot;\u0026gt; ` ``lineHeight = Math.max(lineHeight, childHeight + lp.topMargin + lp.bottomMargin);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number123 index122 alt2\u0026quot;\u0026gt; ` ``lineViews.add(child);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number124 index123 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number125 index124 alt2\u0026quot;\u0026gt; ` ``//处理最后一行` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number126 index125 alt1\u0026quot;\u0026gt; ` ``mLineHeight.add(lineHeight);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number127 index126 alt2\u0026quot;\u0026gt; ` ``mAllChildViews.add(lineViews);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number128 index127 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number129 index128 alt2\u0026quot;\u0026gt; ` ``//设置子View的位置` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number130 index129 alt1\u0026quot;\u0026gt; ` ``int` `left = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number131 index130 alt2\u0026quot;\u0026gt; ` ``int` `top = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number132 index131 alt1\u0026quot;\u0026gt; ` ``//获取行数` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number133 index132 alt2\u0026quot;\u0026gt; ` ``int` `lineCount = mAllChildViews.size();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number134 index133 alt1\u0026quot;\u0026gt; ` ``for``(``int` `i = ````; i \u0026amp;lt; lineCount; i ++){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number135 index134 alt2\u0026quot;\u0026gt; ` ``//当前行的views和高度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number136 index135 alt1\u0026quot;\u0026gt; ` ``lineViews = mAllChildViews.get(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number137 index136 alt2\u0026quot;\u0026gt; ` ``lineHeight = mLineHeight.get(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number138 index137 alt1\u0026quot;\u0026gt; ` ``for``(``int` `j = ````; j \u0026amp;lt; lineViews.size(); j ++){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number139 index138 alt2\u0026quot;\u0026gt; ` ``View child = lineViews.get(j);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number140 index139 alt1\u0026quot;\u0026gt; ` ``//判断是否显示` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number141 index140 alt2\u0026quot;\u0026gt; ` ``if``(child.getVisibility() == View.GONE){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number142 index141 alt1\u0026quot;\u0026gt; ` ``continue``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number143 index142 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number144 index143 alt1\u0026quot;\u0026gt; ` ``MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number145 index144 alt2\u0026quot;\u0026gt; ` ``int` `cLeft = left + lp.leftMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number146 index145 alt1\u0026quot;\u0026gt; ` ``int` `cTop = top + lp.topMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number147 index146 alt2\u0026quot;\u0026gt; ` ``int` `cRight = cLeft + child.getMeasuredWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number148 index147 alt1\u0026quot;\u0026gt; ` ``int` `cBottom = cTop + child.getMeasuredHeight();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number149 index148 alt2\u0026quot;\u0026gt; ` ``//进行子View进行布局` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number150 index149 alt1\u0026quot;\u0026gt; ` ``child.layout(cLeft, cTop, cRight, cBottom);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number151 index150 alt2\u0026quot;\u0026gt; ` ``left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number152 index151 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number153 index152 alt2\u0026quot;\u0026gt; ` ``left = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number154 index153 alt1\u0026quot;\u0026gt; ` ``top += lineHeight;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number155 index154 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number156 index155 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number157 index156 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number158 index157 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number159 index158 alt2\u0026quot;\u0026gt; ` ``* 与当前ViewGroup对应的LayoutParams` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number160 index159 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number161 index160 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number162 index161 alt1\u0026quot;\u0026gt; ` ``public` `LayoutParams generateLayoutParams(AttributeSet attrs) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number163 index162 alt2\u0026quot;\u0026gt; ` ``// TODO Auto-generated method stub` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number164 index163 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number165 index164 alt2\u0026quot;\u0026gt; ` ``return` `new` `MarginLayoutParams(getContext(), attrs);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number166 index165 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number167 index166 alt2\u0026quot;\u0026gt; `}\u0026amp;lt;/font\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 2.相关的布局文件：\n引用自定义控件：\n[Java] *纯文本查看* *复制代码* [?](http://www.apkbus.com/#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 01 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 02 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 03 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 04 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 05 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 06 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 07 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 08 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 09 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;font color=``\u0026quot;#362e2b\u0026quot;``\u0026amp;gt;\u0026amp;lt;font style=``\u0026quot;background-color:rgb(255, 255, 255)\u0026quot;``\u0026amp;gt;\u0026amp;lt;font face=``\u0026quot;Arial\u0026quot;``\u0026amp;gt;\u0026amp;lt;font style=``\u0026quot;font-size:14px\u0026quot;``\u0026amp;gt;\u0026amp;lt;RelativeLayout xmlns:android=``\u0026quot;\u0026amp;lt;a href=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;\u0026gt;http://schemas.android.com/apk/res/android\u0026amp;lt;/a\u0026gt;\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``xmlns:tools=``\u0026quot;\u0026amp;lt;a href=\u0026quot;http://schemas.android.com/tools\u0026quot;\u0026gt;http://schemas.android.com/tools\u0026amp;lt;/a\u0026gt;\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:id=``\u0026quot;@+id/container\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;match_parent\u0026quot;` `\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;com.czm.flowlayout.XCFlowLayout` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``android:id=``\u0026quot;@+id/flowlayout\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;match_parent\u0026quot;` `\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;/com.czm.flowlayout.XCFlowLayout\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; `\u0026amp;lt;/RelativeLayout\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; TextView的样式文件：\n[Java] *纯文本查看* *复制代码* [?](http://www.apkbus.com/#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 01 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 02 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 03 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 04 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 05 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 06 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 07 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 08 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 09 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;font color=``\u0026quot;#362e2b\u0026quot;``\u0026amp;gt;\u0026amp;lt;font style=``\u0026quot;background-color:rgb(255, 255, 255)\u0026quot;``\u0026amp;gt;\u0026amp;lt;font face=``\u0026quot;Arial\u0026quot;``\u0026amp;gt;\u0026amp;lt;font style=``\u0026quot;font-size:14px\u0026quot;``\u0026amp;gt;\u0026amp;lt;?xml version=``\u0026quot;1.0\u0026quot;` `encoding=``\u0026quot;utf-8\u0026quot;``?\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `\u0026amp;lt;shape xmlns:android=``\u0026quot;\u0026amp;lt;a href=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;\u0026gt;http://schemas.android.com/apk/res/android\u0026amp;lt;/a\u0026gt;\u0026quot;` `\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;solid android:color=``\u0026quot;#666666\u0026quot;` `/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;corners android:radius=``\u0026quot;10dp\u0026quot;` `/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;padding ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``android:left=``\u0026quot;5dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``android:right=``\u0026quot;5dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``android:top=``\u0026quot;5dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:bottom=``\u0026quot;5dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; `\u0026amp;lt;/shape\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 三、使用该自定义布局控件类\n最后，如何使用该自定义的热门标签控件类呢？很简单，请看下面实例代码：\n[Java] *纯文本查看* *复制代码* [?](http://www.apkbus.com/#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 01 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 02 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 03 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 04 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 05 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 06 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 07 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 08 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 09 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;font color=``\u0026quot;#362e2b\u0026quot;``\u0026amp;gt;\u0026amp;lt;font style=``\u0026quot;background-color:rgb(255, 255, 255)\u0026quot;``\u0026amp;gt;\u0026amp;lt;font face=``\u0026quot;Arial\u0026quot;``\u0026amp;gt;\u0026amp;lt;font style=``\u0026quot;font-size:14px\u0026quot;``\u0026amp;gt;``package` `com.czm.flowlayout;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `import` `android.app.Activity;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `import` `android.graphics.Color;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `import` `android.os.Bundle;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `import` `android.view.ViewGroup.LayoutParams;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `import` `android.view.ViewGroup.MarginLayoutParams;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; `import` `android.widget.TextView;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; `/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``* ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``* @author caizhiming` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``* @created on 2015-4-13` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; `public` `class` `MainActivity ``extends` `Activity {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``private` `String mNames[] = {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``\u0026quot;welcome\u0026quot;``,``\u0026quot;android\u0026quot;``,``\u0026quot;TextView\u0026quot;``,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``\u0026quot;apple\u0026quot;``,``\u0026quot;jamy\u0026quot;``,``\u0026quot;kobe bryant\u0026quot;``,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``\u0026quot;jordan\u0026quot;``,``\u0026quot;layout\u0026quot;``,``\u0026quot;viewgroup\u0026quot;``,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``\u0026quot;margin\u0026quot;``,``\u0026quot;padding\u0026quot;``,``\u0026quot;text\u0026quot;``,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``\u0026quot;name\u0026quot;``,``\u0026quot;type\u0026quot;``,``\u0026quot;search\u0026quot;``,``\u0026quot;logcat\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``};` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``private` `XCFlowLayout mFlowLayout;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``protected` `void` `onCreate(Bundle savedInstanceState) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``super``.onCreate(savedInstanceState);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``setContentView(R.layout.activity_main);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``initChildViews();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ``private` `void` `initChildViews() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ``// TODO Auto-generated method stub` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ``mFlowLayout = (XCFlowLayout) findViewById(R.id.flowlayout);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``MarginLayoutParams lp = ``new` `MarginLayoutParams(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; ` ``LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; ` ``lp.leftMargin = ``5``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; ` ``lp.rightMargin = ``5``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; ` ``lp.topMargin = ``5``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; ` ``lp.bottomMargin = ``5``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; ` ``for``(``int` `i = ````; i \u0026amp;lt; mNames.length; i ++){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; ` ``TextView view = ``new` `TextView(``this``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; ` ``view.setText(mNames[i]);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; ` ``view.setTextColor(Color.WHITE);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; ` ``view.setBackgroundDrawable(getResources().getDrawable(R.drawable.textview_bg));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; ` ``mFlowLayout.addView(view,lp);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; `}\u0026amp;lt;/font\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;\u0026amp;lt;/font\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 转自：http://www.apkbus.com/android-239725-1-1.html\n","permalink":"https://blog.zdltech.com/posts/android%E4%B8%AD%E5%B8%B8%E8%A7%81%E7%9A%84%E7%83%AD%E9%97%A8%E6%A0%87%E7%AD%BE%E7%9A%84%E6%B5%81%E5%BC%8F%E5%B8%83%E5%B1%80%E7%9A%84%E5%AE%9E%E7%8E%B0/","summary":"\u003cp\u003e\u003cspan style=\"color: #362e2b;\"\u003e\u003cspan style=\"font-family: Arial;\"\u003e\u003cstrong\u003e一、概述：\u003c/strong\u003e\n在日常的app使用中，我们会在android 的app中看见 热门标签等自动换行的流式布局，今天，我们就来看看如何\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #362e2b;\"\u003e\u003cspan style=\"font-family: Arial;\"\u003e自定义一个类似热门标签那样的流式布局吧（源码下载在下面最后给出）\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #362e2b;\"\u003e\u003cspan style=\"font-family: Arial;\"\u003e类似的自定义布局。下面我们就来详细介绍流式布局的应用特点以及用的的技术点：\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #362e2b;\"\u003e\u003cspan style=\"font-family: Arial;\"\u003e1.流式布局的特点以及应用场景\n特点：当上面一行的空间不够容纳新的TextView时候，\n才开辟下一行的空间\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #362e2b;\"\u003e\u003cspan style=\"font-family: Arial;\"\u003e　　原理图：\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #362e2b;\"\u003e\u003cspan style=\"font-family: Arial;\"\u003e　　\u003cimg loading=\"lazy\" src=\"http://www.apkbus.com/data/attachment/forum/201504/14/150953oufufcsisd7fush0.jpg\"\u003e\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #362e2b;\"\u003e\u003cspan style=\"font-family: Arial;\"\u003e    场景：主要用于关键词搜索或者热门标签等场景\n2.自定义ViewGroup,重点重写下面两个方法\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #362e2b;\"\u003e\u003cspan style=\"font-family: Arial;\"\u003e    1、onMeasure:测量子view的宽高，设置自己的宽和高\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #362e2b;\"\u003e\u003cspan style=\"font-family: Arial;\"\u003e    2、onLayout:设置子view的位置\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #362e2b;\"\u003e\u003cspan style=\"font-family: Arial;\"\u003e    onMeasure:根据子view的布局文件中属性，来为子view设置测量模式和测量值\n测量=测量模式+测量值；\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #362e2b;\"\u003e\u003cspan style=\"font-family: Arial;\"\u003e    测量模式有3种：\nEXACTLY：表示设置了精确的值，一般当childView设置其宽、高为精确值、match_parent时，ViewGroup会将其设置为EXACTLY；\nAT_MOST：表示子布局被限制在一个最大值内，一般当childView设置其宽、高为wrap_content时，ViewGroup会将其设置为AT_MOST；\nUNSPECIFIED：表示子布局想要多大就多大，一般出现在AadapterView的item的heightMode中、ScrollView的childView的heightMode中；此种模式比较少见。\n3.LayoutParams\nViewGroup LayoutParams :每个 ViewGroup 对应一个 LayoutParams; 即 ViewGroup -\u0026gt; LayoutParams\ngetLayoutParams 不知道转为哪个对应的LayoutParams ,其实很简单，就是如下：\n子View.getLayoutParams 得到的LayoutParams对应的就是 子View所在的父控件的LayoutParams;\n例如，LinearLayout 里面的子view.getLayoutParams -\u0026gt;LinearLayout.LayoutParams\n所以 咱们的FlowLayout 也需要一个LayoutParams，由于上面的效果图是子View的 margin，\n所以应该使用MarginLayoutParams。即FlowLayout-\u0026gt;MarginLayoutParams\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e","title":"Android中常见的热门标签的流式布局的实现"},{"content":"如有转载: http://blog.csdn.net/t12x3456\n随着应用不断迭代，业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高，重复作用的类越来越多)，相信很多人都遇到过如下的错误:\n**[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - UNEXPECTED TOP-LEVEL EXCEPTION: - java.lang.IllegalArgumentException: method ID not in [\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xffff\u0026lt;/span\u0026gt;]: \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;65536\u0026lt;/span\u0026gt; - at com.android.dx.merge.DexMerger$\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;6\u0026lt;/span\u0026gt;.updateIndex(DexMerger.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;501\u0026lt;/span\u0026gt;) - at com.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;282\u0026lt;/span\u0026gt;) - at com.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;490\u0026lt;/span\u0026gt;) - at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;167\u0026lt;/span\u0026gt;) - at com.android.dx.merge.DexMerger.merge(DexMerger.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;188\u0026lt;/span\u0026gt;) - at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;439\u0026lt;/span\u0026gt;) - at com.android.dx.command.dexer.Main.runMonoDex(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;287\u0026lt;/span\u0026gt;) - at com.android.dx.command.dexer.Main.run(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;230\u0026lt;/span\u0026gt;) - at com.android.dx.command.dexer.Main.main(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;199\u0026lt;/span\u0026gt;) - at com.android.dx.command.Main.main(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;103\u0026lt;/span\u0026gt;) 没错，你的应用中的Dex 文件方法数超过了最大值65536的上限,简单来说，应用爆棚了.\n** 那么让我们看一下为什么会引起这种错误:**\n在Android系统中，一个App的所有代码都在一个Dex文件里面。Dex是一个类似Jar的存储了多有Java编译字节码的归档文件。因为Android系统使用Dalvik虚拟机，所以需要把使用Java Compiler编译之后的class文件转换成Dalvik能够执行的class文件。这里需要强调的是，Dex和Jar一样是一个归档文件，里面仍然是Java代码对应的字节码文件。当Android系统启动一个应用的时候，有一步是对Dex进行优化，这个过程有一个专门的工具来处理，叫DexOpt。DexOpt的执行过程是在第一次加载Dex文件的时候执行的。这个过程会生成一个ODEX文件，即Optimised Dex。执行ODex的效率会比直接执行Dex文件的效率要高很多。但是在早期的Android系统中，DexOpt有一个问题，也就是这篇文章想要说明并解决的问题。DexOpt会把每一个类的方法id检索起来，存在一个链表结构里面。但是这个链表的长度是用一个short类型来保存的，导致了方法id的数目不能够超过65536个。当一个项目足够大的时候，显然这个方法数的上限是不够的。尽管在新版本的Android系统中，DexOpt修复了这个问题，但是我们仍然需要对低版本的Android系统做兼容.\n目前比较常用的方法：(1) 应用插件化,比如使用我正在参与开发的插件化框架 : https://github.com/singwhatiwanna/dynamic-load-apk ,如果有建议或者相关的问题,欢迎到Github上积极参与. (2) 分割Dex,多工程: 把所需要的.class文件或者是Jar文件和一些源码一起编译生成一个Jar文件。然后使用Android SDK提供的dx工具把Jar文件转成Dex文件。我们可以提前对它进行ODex操作，让它在被DexClassLoader加载的时候，跳过DexOpt的部分工作，从而加快加载的过程.(可参考facebook:https://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920,这里边还可以看到在2.3上动态改变LinearAlloc缓冲的解决思路) 这两种方法并不冲突,插件化除了解决应用爆棚，还有很多其他的优点，可以看我之前的文章,不再复述.\n当然,Google看来也意识到了目前应用方法数爆棚的问题, 目前在已经在API 21中提供了通用的解决方案，那就是android-support-multidex.jar. 这个jar包最低可以支持到API 4的版本(Android L及以上版本会默认支持mutidex).\n让我们看一下如何应用android-support-multidex.jar(以下都以在Anroid studio中的使用为例,使用eclipse开发需要安装gradle插件，其他基本上相同):\n**[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - afterEvaluate { - tasks.matching { - it.name.startsWith(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;dex\u0026amp;#8217;\u0026lt;/span\u0026gt;) - }.each { dx -\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (dx.additionalParameters == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - dx.additionalParameters = [] - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// optional\u0026lt;/span\u0026gt; - } - } 但是默认的Dalvik 类加载器只会寻找classes.dex,所以需要将它们进行合并才能使得被识别\n当然，现在有了android.support.multidex.jar的支持,一切都会变得非常简单,首先我们看一下相关源码的目录,具体的原理分析我会在之后的文章中进行讲解:\n**[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - android/support/multidex/BuildConfig.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; - android/support/multidex/MultiDex$V14.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; - android/support/multidex/MultiDex$V19.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; - android/support/multidex/MultiDex$V4.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; - android/support/multidex/MultiDex.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; - android/support/multidex/MultiDexApplication.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; - android/support/multidex/MultiDexExtractor$\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; - android/support/multidex/MultiDexExtractor.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; - android/support/multidex/ZipUtil$CentralDirectory.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; - android/support/multidex/ZipUtil.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; 具体集成:\n将如下配置加入工程 classPath中\n**[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - repositories { - jcenter() - } - - dependencies { - compile \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;com.google.android:multidex:0.1\u0026amp;#8217;\u0026lt;/span\u0026gt; - } MultiDex实现原理:\nApk在运行的时候，有一个dexpathlist，而Multidex的源码中，会根据你的系统版本号对dexpathlist做修改，将所有的dex都添加到dexpathlist中.\n接下来集成有两个步骤:\n一. 从sdk\\extras\\android\\support\\multidex\\library\\libs 目录将android-support-multidex.jar导入工程中\n二. 如果你的工程中已经含有Application类,那么让它继承android.support.multidex.MultiDexApplication类,\n** 如果你的Application已经继承了其他类并且不想做改动，那么还有另外一种使用方式,覆写attachBaseContext()方法:**\n**[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyApplication \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; FooApplication { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; attachBaseContext(Context base) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.attachBaseContext(base); - MultiDex.install(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - } - } 最后给出build.gradle中的完整配置:\n**[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - android { - compileSdkVersion \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;21\u0026lt;/span\u0026gt; - buildToolsVersion \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;21.1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; - - defaultConfig { - \u0026amp;#8230; - minSdkVersion \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt; - targetSdkVersion \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;21\u0026lt;/span\u0026gt; - \u0026amp;#8230; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Enabling multidex support.\u0026lt;/span\u0026gt; - multiDexEnabled \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt; - } - \u0026amp;#8230; - } - - dependencies { - compile \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;com.android.support:multidex:1.0.0\u0026amp;#8217;\u0026lt;/span\u0026gt; - } 使用MutiDex的主意事项\n一. 如果你继承了MutiDexApplication或者覆写了Application中的attachBaseContext()方法.\nApplication类中逻辑的注意事项:\nApplication 中的静态全局变量会比MutiDex的 instal()方法优先加载，所以建议避免在Application类中使用静态变量引用main classes.dex文件以外dex文件中的类，可以根据如下所示的方式进行修改:\n**[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Context mContext = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// put your logic here!\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// use the mContext instead of this here\u0026lt;/span\u0026gt; - } - }.run(); - } 二. 虽然Google解决了应用总方法数限制的问题，但并不意味着开发者可以任意扩大项目规模。Multidex仍有一些限制：\nDEX文件安装到设备的过程非常复杂，如果第二个DEX文件太大，可能导致应用无响应。此时应该使用ProGuard减小DEX文件的大小。 由于Dalvik linearAlloc的Bug，应用可能无法在Android 4.0之前的版本启动，如果你的应用要支持这些版本就要多执行测试。 同样因为Dalvik linearAlloc的限制，如果请求大量内存可能导致崩溃。Dalvik linearAlloc是一个固定大小的缓冲区。在应用的安装过程中，系统会运行一个名为dexopt的程序为该应用在当前机型中运行做准备。dexopt使用LinearAlloc来存储应用的方法信息。Android 2.2和2.3的缓冲区只有5MB，Android 4.x提高到了8MB或16MB。当方法数量过多导致超出缓冲区大小时，会造成dexopt崩溃。 Multidex构建工具还不支持指定哪些类必须包含在首个DEX文件中，因此可能会导致某些类库（例如某个类库需要从原生代码访问Java代码）无法使用。 避免应用过大、方法过多仍然是Android开发者要注意的问题。Mihai Parparita的开源项目dex-method-counts可以用于统计APK中每个包的方法数量。\n通常开发者自己的代码很难达到这样的方法数量限制，但随着第三方类库的加入，方法数就会迅速膨胀。因此选择合适的类库对Android开发者来说尤为重要。\n开发者应该避免使用Google Guava这样的类库，它包含了13000多个方法。尽量使用专为移动应用设计的Lite/Android版本类库，或者使用小类库替换大类库，例如用Google-gson替换Jackson JSON。而对于Google Protocol Buffers这样的数据交换格式，其标准实现会自动生成大量的方法。采用Square Wire的实现则可以很好地解决此问题。\n常见问题\nDexException: Library dex files are not supported in multi-dex mode,你可能会见到如下的错误:\n**[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - Error:Execution failed \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; task \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;:app:dexDebug\u0026amp;#8217;\u0026lt;/span\u0026gt;. - \u0026gt; com.android.ide.common.internal.LoggedErrorException: Failed to run command: - \u0026amp;#8230; - Error Code: - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; - Output: - UNEXPECTED TOP-LEVEL EXCEPTION: - com.android.dex.DexException: Library dex files are not supported in multi-dex mode - at com.android.dx.command.dexer.Main.runMultiDex(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;322\u0026lt;/span\u0026gt;) - at com.android.dx.command.dexer.Main.run(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;228\u0026lt;/span\u0026gt;) - at com.android.dx.command.dexer.Main.main(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;199\u0026lt;/span\u0026gt;) - at com.android.dx.command.Main.main(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;103\u0026lt;/span\u0026gt;) **[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - android { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// \u0026amp;#8230;\u0026lt;/span\u0026gt; - dexOptions { - preDexLibraries = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt; - } - } OutOfMemoryError: Java heap space\n当运行时如果看到如下错误:\n**[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_10\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_10\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - UNEXPECTED TOP-LEVEL ERROR: - java.lang.OutOfMemoryError: Java heap space 在dexOptions中有一个字段用来增加java堆内存大小:\n**[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_11\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_11\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - android { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// \u0026amp;#8230;\u0026lt;/span\u0026gt; - dexOptions { - javaMaxHeapSize \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;2g\u0026amp;#8221;\u0026lt;/span\u0026gt; - } - } - 使用eclipse的开发人员可以参考Google官方文档\nhttps://developer.android.com/tools/building/multidex.html#mdex-gradle\n需要安装支持gradle构建的插件，下载地址:\nhttp://dist.springsource.com/release/TOOLS/gradle (目前可能需要翻墙)\n参考相关资料:\n1. MutiDex 官方文档: https://developer.android.com/reference/android/support/multidex/MultiDex.html\n2. http://blog.osom.info/2014/10/multi-dex-to-rescue-from-infamous-65536.html\n另附android -support-mutidex.jar下载地址: http://download.csdn.net/detail/t12x3456/8143383\n补充注意事项：\n**[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_12\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_12\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - com.android.dex.DexException: Multiple dex files define L{\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt;}/BuildConfig; 如果遇到这个错误请进行如下检查：\n1. 主工程与依赖library工程包名是否重复\n2. 检查主工程与依赖library工程是否含有重复的support.jar或者其他jar包\n解决方案:\n1. 修改library工程包名\n2. 删除重复jar包\n3.手工添加lib包,增加如下配置\n**[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_13\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_13\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - dependencies { - compile fileTree(dir: \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;libs\u0026amp;#8217;\u0026lt;/span\u0026gt;, include: [\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;*.jar\u0026amp;#8217;\u0026lt;/span\u0026gt;]) - compile project(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;:lib-project-module\u0026amp;#8217;\u0026lt;/span\u0026gt;) - } ","permalink":"https://blog.zdltech.com/posts/android-%E4%BD%BF%E7%94%A8android-support-multidex%E8%A7%A3%E5%86%B3dex%E8%B6%85%E5%87%BA%E6%96%B9%E6%B3%95%E6%95%B0%E7%9A%84%E9%99%90%E5%88%B6%E9%97%AE%E9%A2%98%E8%AE%A9%E4%BD%A0%E7%9A%84%E5%BA%94/","summary":"\u003cp\u003e如有转载: \u003ca href=\"http://blog.csdn.net/t12x3456\"\u003ehttp://blog.csdn.net/t12x3456\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e随着应用不断迭代，业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高，重复作用的类越来越多)，相信很多人都遇到过如下的错误:\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/t12x3456/article/details/40837287#)[copy](http://blog.csdn.net/t12x3456/article/details/40837287#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/513619)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/513619/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- UNEXPECTED TOP-LEVEL EXCEPTION:\n\n- java.lang.IllegalArgumentException: method ID not in [\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xffff\u0026lt;/span\u0026gt;]: \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;65536\u0026lt;/span\u0026gt;\n\n- at com.android.dx.merge.DexMerger$\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;6\u0026lt;/span\u0026gt;.updateIndex(DexMerger.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;501\u0026lt;/span\u0026gt;)\n\n- at com.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;282\u0026lt;/span\u0026gt;)\n\n- at com.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;490\u0026lt;/span\u0026gt;)\n\n- at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;167\u0026lt;/span\u0026gt;)\n\n- at com.android.dx.merge.DexMerger.merge(DexMerger.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;188\u0026lt;/span\u0026gt;)\n\n- at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;439\u0026lt;/span\u0026gt;)\n\n- at com.android.dx.command.dexer.Main.runMonoDex(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;287\u0026lt;/span\u0026gt;)\n\n- at com.android.dx.command.dexer.Main.run(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;230\u0026lt;/span\u0026gt;)\n\n- at com.android.dx.command.dexer.Main.main(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;199\u0026lt;/span\u0026gt;)\n\n- at com.android.dx.command.Main.main(Main.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;103\u0026lt;/span\u0026gt;)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android 使用android-support-multidex解决Dex超出方法数的限制问题,让你的应用不再爆棚"},{"content":" 作者：Hannes Dorfmann 原文链接 : Ted Mosby – Software Architect 文章出自 : Android开发技术前线 译者 : Mr.Simple 我给这篇关于Android库的博客起的名字灵感来源于《老爸老妈浪漫史》中的建筑设计师Ted Mosby。这个Mosby库可以帮助大家在Android上通过Model-View-Presenter模式做出一个完善稳健、可重复使用的软件，还可以借助ViewState轻松实现屏幕翻转。\nModel-View-Presenter (MVP) MVP模式是一个把view从低层模型分离出来的一种现代模式。MVP由model–view–controller (MVC)软件模式衍生而来，常用于构建UI\nMVP中的M（model）代表的是将会显示在view（UI）中的数据。 MVP中的V（view）是显示数据（model）并且将用户指令（events）传送到presenter以便作用于那些数据的一个接口。View通常含有Presenter的引用。 MVP中的P（presenter）扮演的是“中间人”的作用（就如MVC中的controller），且presenter同时引用view和model。值得注意的是，“Model”这个词并不正确。严格意义上来说，它指的应该是检索或控制一个Model的业务逻辑层。举个例子，比如你的数据库里面包含了User，而你的View想要显示一个User列表，那么Presenter会引用数据库中的业务逻辑层（比如DAO）从而查询到一个User列表。如图1-1.\n从数据库中查询或显示User列表的具体流程如图1-2：\n以上工作流程图应该能够说明问题了。但是，还有以下几点值得注意的地方：\nPresenter不是一个OnClickListener。View主要是负责处理用户输入并调用presenter相应的方法。那么问题来了，为什么不把Presenter 直接做成一个OnClickListener，从而把“转发流程”给省略掉呢？大家想想，如果这样做的话，首先，presenter需要知道view的内部构件。举个例子，如果一个View有两个按钮，且这个view在这两个按钮上都把Presenter 注册成OnClickListener的话，那么发生点击事件时Presenter （在不知道view中按钮引用等内部构件的情况下）怎么能够区分出是哪一个按钮被点击了呢？Model，View和Presenter三者应解耦。其次，如果让Presenter 执行OnClickListener，Presenter就被绑定到了Android平台上。理论上来说presenter和业务逻辑层都是纯旧式的能够与桌面应用或其他任何java应用共享的java代码。 大家在第1步和第2步中可以看到，View 只执行Presenter 指示的操作：用户点击“load user button”（第1步）后，view并没有直接显示加载动画，而是在第2步presenter明确告诉其显示加载动画后才显示的。这一Model-View-Presenter的变体称之为MVP 被动视图。这个view可以说是要多笨有多笨。这时我们需要让presenter以一种更抽象的方式来控制view。比如，presenter在调用 view.showLoading() 时并不控制view的诸如动画等具体事项。所以presenter不应调用view.startAnimation() 等方法。 通过执行MVP被动视图，并发性以及多线程更容易处理。大家可以看到，第3步中数据库查询异步运行，并且presenter作为Listener/Observer，在数据准备显示时presenter收到通知。 Android上的MVP 目前为止一切顺利。但是大家怎么样把MVP运用到自己的Android 应用上呢？第一个问题在于，我们要把MVP模式运用到什么地方？Activity上、Fragment上、还是像RelativeLayout这类的ViewGroup上？我们来看看Android平板上的Gmail应用，如图1-3：\n在我看来，上图屏幕中有四个可以使用MVP的地方。我所说的“可以使用MVP的地方”是指屏幕上显示的、在逻辑上属于一个整体的UI元素。因此这些地方也可以称为是可以运用MVP的一个单独的UI单元。如图 1-4.\n看起来MVP似乎很适合运用到Activity，特别是Fragment上。通常Fragment只负责显示单一的如ListView之类的内容，就像依靠MailProvider 来获取一系列Mails的InboxPresenter 控制下的 InboxView一样。但是，MVP不仅仅限于Fragment或Activity，它还可以运用到SearchView中显示的ViewGroup中。在我的大多数app里面我都在Fragment运用MVP模式。但是大家可以自行决定把MVP运用到什么地方，前提是view是独立的，这样这样presenter才能在不与其他Presenter冲突的情况下控制View。\n我们为什么要实现MVP？ 我们如何在不使用MVP模式时显示Email列表到Fragment? 通常，我们需要获取并且合并本地SQL数据库和从IMAP邮件服务器获取的邮件列表，然后将邮件列表绑定到收件箱view中。那么，此时fragment的代码又会是怎么样的呢？我们需要运行两个AsyncTasks 并实现一个“等待机制”（等到两个任务将两者的加载数据合并到一个单独的mail列表）。我们还需要注意的是在加载时要显示加载动画（ProgressBar），之后用ListView替代。我们需要把所有的代码放到Fragment中吗？要是加载过程中出现错误怎么办？屏幕翻转怎么办？谁来负责撤销AsyncTasks ？这一系列的问题都可以通过MVP得到解决。让我们跟那些带有上千行大杂烩代码的activity和fragment说拜拜吧\n但是，在我们深入研究如何将MVP运用到Android中之前，我们需要弄清楚的一个问题是：Activity或Fragment究竟是一个View还是一个Presenter。Activity或Fragment似乎既是View也是Presenter，因为它们都有 onCreate() 或**onDestroy()**之类的生命周期回调功能，并且它们负责从一个UI控件到另一个UI 控件的转换（比如在加载时显示ProgressBar，然后显示带有数据的ListView）等View操作。大家可能会觉得这里的Activity或Fragment就是一个Controller，我猜可能也是这么一个初衷。但是在经历了几年的Android应用开发之后，我得出这么一个结论：我们应该把Activity或Fragment看作是一个不太智能的View，而不是把它们看作一个Presenter。后文我会给出原因。\n综上，我想给大家介绍一个在Android平台上开发基于MVP的应用的一个 Mosby库。\nMosby\n大家可以在Github和Maven Central上找到Mosby库。Mosby分为几个子模块，大家可以根据自己的需要选取组件。我们来回顾一下最重要的一个模块。\n核心模块 ( Core Module) 《老爸老妈浪漫史》中的建筑设计师Ted Mosby想建造一栋摩天大楼。而建造这样一栋宏伟的建筑必须打好坚实的地基。这对Android应用的开发来说是也是一样的道理。基本上，Core Module 分为两种类型：MosbyActivity 和MosbyFragment。这两者是所有其他activity或fragment子类的基类（相当于建筑的地基）。两者都使用我们大家所熟知的APT （Annotation Processing Tool）来减少一些样板式代码。MosbyActivity 和MosbyFragment 使用Butterknife进行view的注入，使用Icepick 将实例状态保存和存储到Bundle中，使用FragmentArgs注入Fragment参数。我们不需要再调用Butterknife.inject(this)等插入方法。这类代码已经包含在了MosbyActivity 和 MosbyFragment中。它是即时可用的。我们需要做的就是使用子类中相应的注解。核心模块与MVP没有关联，它只是写一个大型软件的基础。\nMVP模块( MVP Module ) Mosby库中的MVP模块使用泛型来确保类型安全。所有view的基类是MvpView。从根本上说这只是一个空的interface 。Presenter的基类是MvpPresenter：\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8947213802875-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8947213802875-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8947213802875-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8947213802875-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8947213802875-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8947213802875-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8947213802875-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8947213802875-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8947213802875-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;V\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8947213802875-4\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;attachView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;V\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;view\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8947213802875-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;detachView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;retainInstance\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8947213802875-6\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8947213802875-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 上文提到，我们把Activity和Fragment看做View。因此Mosby库的MVP模块提供了 属于MvpViews 的MvpActivity和MvpFragment作为Activity和Fragment的基类。\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-14\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-15\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-16\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-17\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-18\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-19\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-20\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-21\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-22\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-23\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-24\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-25\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-26\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-27\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-28\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-29\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-30\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-31\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-32\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-33\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-34\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-35\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-36\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-37\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde895e988916301-38\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpActivity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;P\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MosbyActivity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;P\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;presenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-4\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onCreate\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Bundle \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;savedInstanceState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onCreate\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;savedInstanceState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-6\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;presenter\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;createPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;presenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;attachView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-8\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onDestroy\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;presenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;detachView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-10\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-12\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;PcreatePresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-14\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-15\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpFragment\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;P\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MosbyFragment\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-16\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;Ppresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-17\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-18\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onViewCreated\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;View \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;view\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Nullable \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Bundle \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;savedInstanceState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-19\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onViewCreated\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;view\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;savedInstanceState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-20\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// Create the presenter if needed\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-21\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;presenter\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-22\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;presenter\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;createPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-23\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-24\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;presenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;attachView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-25\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-26\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-27\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onDestroyView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-28\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onDestroyView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-29\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;presenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;detachView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getRetainInstance\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-30\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-31\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-32\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;PcreatePresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-33\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-34\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-35\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-36\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onDestroy\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-37\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde895e988916301-38\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 这一理念主要是一个MvpView (也就是Fragment or Activity)会关联一个MvpPresenter，并且管理MbpPresenter的声明周期。大家从上面的代码片段可以看到，Mosby使用Activity和Fragement生命周期来实现这一目的。通常presenter是绑定在该生命周期上的。所以初始化或者清理一些东西等操作（例如撤销异步运行任务）应该在 presenter.onAttach()和 presenter.onDetach()上进行。我们稍后会谈到presenter如何使用setRetainInstanceState(true) “避开”Fragment中的生命周期。我相信大家也注意到了， MvpPresenter是一个interface 。MVP模块提供一个 MvpBasePresenter，这个MvpBasePresenter只持有View（是一个Fragment或Activity）的弱引用，从而避免内存泄露。因此，当presenter想要调用view方法时，我们需要查看isViewAttached() 并使用**getView()**来获取引用，以检查view是否连接到了presenter。\nLoading-Content-Error (LCE) 通常Fragment会一直重复做某一件事。它在后台加载数据，同时显示加载view（即ProgressBar），并在屏幕上显示加载的数据，或者当加载失败时显示view错误。如今，下拉刷新支持很容易实现，因为SwipeRefreshLayout是Android支持库的组成部分。为了避免重复执行这一工作流，Mosby库的MVP模块提供了MvpLceView。\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-14\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-15\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-16\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-17\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-18\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-19\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-20\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-21\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-22\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-23\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8969264340879-24\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpLceView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;M\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; * 显示一个加载中的视图\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-4\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; * loading view 必须有个id 为 R.id.loadingView的View\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; * @param pullToRefresh 如果是true,那么表示下拉刷新被触发了\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-6\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showLoading\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;pullToRefresh\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-8\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; * 显示 content view.\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-10\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; * \u0026lt;content view 的id必须是R.id.contentView\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-12\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showContent\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-14\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-15\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; * 显示错误信息\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-16\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-17\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showError\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;Throwable\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;e\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;pullToRefresh\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-18\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-19\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-20\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; * The data that should be displayed with {@link #showContent()}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-21\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-22\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;M\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-23\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8969264340879-24\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 针对那种类型的view我们可以采用 MvpLceActivity implements MvpLceView 和 MvpLceFragment implements MvpLceView。两者均假设解析的xml布局包括了含有R.id.loadingView,R.id.contentView和R.id.errorView的view。\n示例\n接下来要举的例子Github上也有中，我们使用CountriesAsyncLoader加载一系列的Country，并将其显示在Fragment的RecyclerView中。大家可以从这个链接https://db.tt/ycrCwt1L下载。\n首先我们要定义CountriesView这一view interface 。\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8971591298870-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8971591298870-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8971591298870-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;CountriesView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpLceView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Country\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8971591298870-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8971591298870-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 为什么要为View定义接口呢？\n1.因为定义了这个接口之后我们可以更改view的实现。我们可以简单地把代码从一个继承自 Activity的实现转移到继承自 Fragment的实现。\n2.模块性：我们可以移动独立的库项目中的整个业务逻辑层、Presenter以及View 接口，然后把这个包含了Presenter的库应用到各类app当中。下图中左侧是使用了嵌入在ViewPager中的Activity的kicker app，以及使用嵌入在ViewPager中的Fragment的meinVerein app，如图1-5。 两者采用的是同一个定义了View接口和Presenter且测试了单元的库。\n由于我们可以通过执行view接口来模拟view，所以我们可以很容易地编写单元测试。还有一个更简单的方法就是在presenter中引入java接口并使用模拟presenter对象来编写单元测试。\n还有一个良性副作用就是，定义了view接口之后，我们不用直接从presenter再回调activity/fragment方法。我们这样区分开来是因为在执行presenter时我们在IDE自动完成上看到的方法只是关于view接口的方法。就我个人体会来说，我觉得这个方法非常有用，特别是团队一起工作的时候。需要注意的是，除了定义一个CountriesView接口之外，我们还可以采用MvpLceView 。但是，定义一个专门的接口可以提高代码可读性，并且将来可以灵活地定义更多其他的与View相关的方法。\nNext we define our views xml layout file with the required ids:\n下一步我们需要按照指定的id来定义view xml 布局文件.\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-14\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-15\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-16\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-17\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-18\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-19\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-20\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-21\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-22\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-23\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-24\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-25\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-26\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-27\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-28\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-29\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-30\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-31\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-32\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-33\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-34\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-35\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-36\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-37\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-38\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde897a787162416-39\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;FrameLayoutxmlns\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout_width\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout_height\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-4\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-6\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;!\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026amp;#8212;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Loading \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026amp;#8212;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;ProgressBar\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-8\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;@+id/loadingView\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout_width\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-10\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout_height\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout_gravity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-12\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;indeterminate\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-14\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-15\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;!\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026amp;#8212;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Content \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026amp;#8212;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-16\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;support\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;v4\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;widget\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;SwipeRefreshLayout\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-17\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;@+id/contentView\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-18\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout_width\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-19\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout_height\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-20\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-21\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-22\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;support\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;v7\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;widget\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;RecyclerView\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-23\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;@+id/recyclerView\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-24\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout_width\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-25\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout_height\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-26\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-27\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-28\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;support\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;v4\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;widget\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;SwipeRefreshLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-29\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-30\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-31\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;!\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026amp;#8212;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Error \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;view\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026amp;#8212;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-32\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-33\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;@+id/errorView\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-34\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout_width\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-35\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout_height\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-36\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-37\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-38\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;FrameLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde897a787162416-39\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; CountriesPresenter控制CountriesView并运行CountriesAsyncLoader。\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-14\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-15\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-16\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-17\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-18\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-19\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-20\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-21\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-22\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-23\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-24\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-25\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-26\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-27\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-28\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8983414279052-29\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;CountriesPresenter\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpBasePresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;CountriesView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-4\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;loadCountries\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;pullToRefresh\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showLoading\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;pullToRefresh\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-6\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;CountriesAsyncLoader \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;countriesLoader\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;CountriesAsyncLoader\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-8\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;CountriesAsyncLoader\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;CountriesLoaderListener\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-10\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onSuccess\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;Country\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;countries\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-12\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;isViewAttached\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;countries\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-14\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showContent\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-15\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-16\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-17\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-18\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onError\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;Exception\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;e\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-19\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-20\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;isViewAttached\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-21\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showError\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;e\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;pullToRefresh\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-22\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-23\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-24\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-25\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-26\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;countriesLoader\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;execute\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-27\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-28\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8983414279052-29\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 实现CountriesView接口 的CountriesFragment 如下所示：\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-14\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-15\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-16\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-17\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-18\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-19\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-20\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-21\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-22\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-23\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-24\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-25\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-26\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-27\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-28\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-29\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-30\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-31\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-32\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-33\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-34\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-35\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-36\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-37\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-38\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-39\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-40\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-41\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-42\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde898c451857135-43\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;CountriesFragment\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;MvpLceFragment\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;SwipeRefreshLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;Country\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;CountriesView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;CountriesPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;CountriesView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;SwipeRefreshLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;OnRefreshListener\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-4\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;InjectView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;recyclerView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;RecyclerViewrecyclerView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-6\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;CountriesAdapteradapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-8\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onViewCreated\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;View \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;view\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Nullable \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Bundle \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;savedInstance\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onViewCreated\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;view\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;savedInstance\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-10\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// Setup contentView == SwipeRefreshView\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-12\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;contentView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setOnRefreshListener\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-14\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// Setup recycler view\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-15\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;adapter\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;CountriesAdapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getActivity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-16\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;recyclerView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setLayoutManager\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;LinearLayoutManager\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getActivity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-17\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;recyclerView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setAdapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;adapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-18\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;loadData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-19\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-20\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-21\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;loadData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;pullToRefresh\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-22\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;presenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;loadCountries\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;pullToRefresh\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-23\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-24\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-25\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;CountriesPresenter \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;createPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-26\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;SimpleCountriesPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-27\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-28\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-29\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// Just a shorthand that will be called in onCreateView()\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-30\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getLayoutRes\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-31\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;countries_list\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-32\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-33\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-34\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;Country\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-35\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;adapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setCountries\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-36\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;adapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;notifyDataSetChanged\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-37\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-38\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-39\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onRefresh\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-40\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;loadData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-41\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-42\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde898c451857135-43\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 代码数量也并不是很多嘛，对吧？这是因为基类已经执行了从加载view到content view或error view的转换。我们可能第一眼看到那一列MvpLceFragment类属参数会觉得灰心。但是我要解释一下：第一种类属参数代表的是content view的类型；第二种是指以fragment显示的Model；第三种是View接口;最后一种是Presenter的类型。总结起来就是：MvpLceFragment\u0026lt;AndroidView, Model, View接口, Presenter\u0026gt;。\n大家可能还注意到的一个点就是 getLayoutRes()，它是MosbyFragment引入的用于解析xml view布局的速记法。\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8995729811915-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8995729811915-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde8995729811915-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8995729811915-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;View \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onCreateView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;LayoutInflater \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;inflater\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;ViewGroup \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;container\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Bundle \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;savedInstanceState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8995729811915-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;Return\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;inflater\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;inflate\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getLayoutRes\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;container\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8995729811915-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde8995729811915-4\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 因此，我们不用重写onCreateView()，只需重写getLayoutRes()。一般来说，onCreateView()只能创建view而**onViewCreated()**需要被重写，以便为RecyclerView初始化Adapter等项。因此，千万不要忘记调用super.OnViewCreated()；\nViewState模块 看到这里大家应该大概了解了如何运用Mosby库。Mosby中的ViewState模块能帮助我们在Android开发中解决一些棘手的难题：处理屏幕旋转。\n问：如果把正在运行country这个例子的app并显示了一列country的设备从横屏旋转到竖屏，会出现什么情况？\n答：大家到这个视频链接https://youtu.be/9iSBGEIZmUw中看看，结果是一个新的 CountriesFragment会被实例化，app开始显示ProgressBar（并重新加载country列表）而不再在RecyclerView中显示country列表（屏幕旋转前的状态）\nMosby引入了ViewState来解决这个问题。原理就是，我们跟踪presenter从关联的View中调用的方法。比如，presenter调用的是view.showContent()，一旦showContent()被调用，view就会意识到其状态变更为**“showing content”，从而view把这一信息存储到一个ViewState。如果view在方向改变过程中遭到破坏，那么ViewState 就会被存储到Activity.onSaveInstanceState(Bundle) 或 Fragment.onSaveInstanceState(Bundle)中，并在Activity.onCreate(Bundle) 或Fragment.onActivityCreated(Bundle)**中修复。\n由于不是每种数据都能存储在Bundle中，所以不同的数据类型采用不同的ViewState 实现：数据类型ArrayList采用ArrayListLceViewState；数据类型Parcelable 采用Parcelable DataLceViewState；数据类型Serializeable采用SerializeableLceViewState。如果使用的是一个可保持( Retaining )的Fragment，那么 ViewState在屏幕旋转时不会被破坏，所以也就不需要存储到Bundle中。因此，它可以存储任何类型的数据。在这种情况下，我们需要使用RetainingFragmentLceViewState。存储一个ViewState比较容易。由于我们的架构比较整洁，我们的View又有接口，ViewState 可以向presenter一样通过调用同样的接口方法来修复相关联的view。举个例子，MvpLceView一般有3种状态，即：显示showContent()，showLoading()和showError()，所以ViewState本身会调用相应的方法来修复view的状态。\n那只是一些内部构件。如果大家想编写自定义的ViewState，了解以上内容就够了。ViewStates的使用非常简单。事实上，要把MvpLceFragment 迁移到MvpLceViewStateFragment ，我们只需要另外执行createViewState() 和 getData()。下面我们就在CountriesFragment中实践一下吧：\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-14\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-15\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-16\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-17\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-18\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-19\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-20\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-21\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-22\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-23\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-24\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-25\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-26\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-27\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-28\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-29\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-30\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-31\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-32\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-33\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-34\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-35\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-36\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-37\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-38\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-39\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-40\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-41\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-42\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-43\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-44\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-45\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-46\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-47\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-48\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-49\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-50\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-51\u0026quot;\u0026gt; 51 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-52\u0026quot;\u0026gt; 52 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-53\u0026quot;\u0026gt; 53 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89a0670759712-54\u0026quot;\u0026gt; 54 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;CountriesFragment\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;MvpLceViewStateFragment\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;SwipeRefreshLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;Country\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;CountriesView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;CountriesPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;CountriesView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;SwipeRefreshLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;OnRefreshListener\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-4\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;InjectView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;recyclerView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;RecyclerView \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;recyclerView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-6\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;CountriesAdapter \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;adapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-8\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;LceViewState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;Country\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;CountriesView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;createViewState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;RetainingFragmentLceViewState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;Country\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;CountriesView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-10\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-12\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;Country\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;adapter\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;?\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;adapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getCountries\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-14\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-15\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-16\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// The code below is the same as before\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-17\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-18\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onViewCreated\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;Viewview\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Nullable \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Bundle \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;savedInstance\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-19\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onViewCreated\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;view\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;savedInstance\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-20\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-21\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// Setup contentView == SwipeRefreshView\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-22\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;contentView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setOnRefreshListener\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-23\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-24\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// Setup recycler view\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-25\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;adapter\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;CountriesAdapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getActivity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-26\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;recyclerView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setLayoutManager\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;LinearLayoutManager\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getActivity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-27\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;recyclerView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setAdapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;adapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-28\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;loadData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-29\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-30\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-31\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-32\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;loadData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;pullToRefresh\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-33\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;presenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;loadCountries\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;pullToRefresh\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-34\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-35\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-36\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;CountriesPresenter \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;createPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-37\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;SimpleCountriesPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-38\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-39\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-40\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// Just a shorthand that will be called in onCreateView()\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-41\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getLayoutRes\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-42\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;countries_list\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-43\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-44\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-45\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;Country\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-46\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;adapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setCountries\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-47\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;adapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;notifyDataSetChanged\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-48\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-49\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-50\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onRefresh\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-51\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;loadData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-52\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-53\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89a0670759712-54\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 以上就是全部过程啦。我们不必更改presenter或其他代码。这里 是一个关于我们的获得ViewState支持的CountriesFragment的视频。在这个视频中我们可以看到，view在方位转变之后仍然处于同样的“状态”，即，view横屏显示country列表，随后横屏显示country列表。View能横屏显示下拉刷新指示，变更为竖屏时也能显示。\n自定义ViewState ViewState确实是一个强大且灵活的概念。看到这里我相信大家都了解了LCE (Loading-Content-Error) ViewState的易用性。下面我们就一起来编写自己的View和ViewState吧。我们的View只显示两类不同的数据对象：A和B。结果应该像这个视频https://youtu.be/9iSBGEIZmUw 中演示的这样：\n大家心里肯定觉得，这也不怎么样啊！别介啊，我只是想演示一下创建自己的ViewState是一件多么容易的事。\nView 接口和数据对象（model）如下所示：\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-14\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-15\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-16\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-17\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-18\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-19\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-20\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-21\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-22\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-23\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-24\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-25\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-26\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-27\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-28\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-29\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-30\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89ab268964111-31\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;A\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Parcelable\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-4\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;A\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-6\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-8\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getName\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-10\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-12\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;B\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Parcelable\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-14\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;foo\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-15\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-16\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;B\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;foo\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-17\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;foo\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;foo\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-18\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-19\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-20\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getFoo\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-21\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;foo\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-22\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-23\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-24\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-25\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-26\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-27\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;A\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-28\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-29\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showB\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;B\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;b\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-30\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89ab268964111-31\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 在这个简单的例子中我们没有加入业务逻辑层。因为我们假设在实际的app中如果有业务逻辑层的话会使整个生成A或B的操作变得复杂。Presenter如下所示：\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-14\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-15\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-16\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-17\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-18\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-19\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-20\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-21\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89b4737593017-22\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomPresenter\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpBasePresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Random \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;random\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Random\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-4\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;doA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-6\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;A\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;A\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;My name is A \u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;random\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;nextInt\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-cn\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-8\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;isViewAttached\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-10\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-12\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;doB\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-14\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;B\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;b\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;B\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;I am B \u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;random\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;nextInt\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-cn\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-15\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-16\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;isViewAttached\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-17\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showB\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;b\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-18\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-19\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-20\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-21\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89b4737593017-22\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 我们定义了实现了MyCustomView接口的MyCustomActivity。\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-14\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-15\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-16\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-17\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-18\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-19\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-20\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-21\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-22\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-23\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-24\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-25\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-26\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-27\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-28\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-29\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-30\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-31\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-32\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-33\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-34\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-35\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-36\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-37\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-38\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-39\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-40\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-41\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-42\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-43\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-44\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-45\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-46\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-47\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-48\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-49\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-50\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-51\u0026quot;\u0026gt; 51 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89bd895137755-52\u0026quot;\u0026gt; 52 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomActivity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MvpViewStateActivity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-4\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;InjectView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;textViewA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;TextViewaView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;InjectView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;textViewB\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;TextViewbView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-6\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onCreate\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Bundle \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;savedInstanceState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-8\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onCreate\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;savedInstanceState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setContentView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;my_custom_view\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-10\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-12\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;RestoreableViewState \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;createViewState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomViewState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// Our ViewState implementation\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-14\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-15\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-16\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// Will be called when no view state exist yet,\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-17\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// which is the case the first time MyCustomActivity starts\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-18\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onNew \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;ViewStateInstance\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-19\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;presenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;doA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-20\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-21\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-22\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomPresenter \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;createPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-23\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-24\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-25\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-26\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;A\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-27\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomViewState \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;vs\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;MyCustomViewState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;viewState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-28\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;vs\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setShowingA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-29\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;vs\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-30\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;aView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setText\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getName\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-31\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;aView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setVisibility\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;VISIBLE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-32\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;bView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setVisibility\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;GONE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-33\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-34\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-35\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showB\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;B\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;b\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-36\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomViewState \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;vs\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;MyCustomViewState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;viewState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-37\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;vs\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setShowingA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-38\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;vs\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;b\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-39\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;bView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setText\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;b\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getFoo\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-40\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;aView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setVisibility\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;GONE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-41\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;bView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setVisibility\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;VISIBLE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-42\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-43\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-44\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;OnClick\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;loadA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onLoadAClicked\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-45\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;presenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;doA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-46\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-47\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-48\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;OnClick\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;loadB\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onLoadBClicked\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-49\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;presenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;doB\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-50\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-51\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89bd895137755-52\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 由于我们没有LCE(Loading-Content-Error)，所以不把 MvpLceActivity作为基类。我们采用的是最普遍的支持 ViewState的MvpViewStateActivity作为基类。基本上我们的View只显示aView 或 bView。\n在**onNew ViewStateInstance()**中，我们需要明确在第一个Activity运行时需要做什么，因为先前并不存在ViewState 例子用于修复。在showA(A a) 和 showB(B b)中，我们需要将显示A 或 B的信息存储到ViewState。到这一步，我们就差不多完成了，现在只差MyCustomViewState执行这一步啦：\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-14\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-15\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-16\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-17\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-18\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-19\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-20\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-21\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-22\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-23\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-24\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-25\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-26\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-27\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-28\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-29\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-30\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-31\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-32\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-33\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-34\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-35\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-36\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-37\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-38\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-39\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-40\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-41\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-42\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-43\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89c6700562407-44\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;ublic\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomViewState\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;RestoreableViewState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;KEY_STATE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;MyCustomViewState-flag\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-4\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;KEY_DATA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;MyCustomViewState-data\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-6\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;showingA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// if false, then show B\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Parcelable \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// Can be A or B\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-8\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;saveInstanceState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Bundle \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;out\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-10\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;out\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;putBoolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;KEY_STATE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;showingA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;out\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;putParcelable\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;KEY_DATA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-12\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-14\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;restoreInstanceState\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Bundle \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;in\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-15\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;in\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;==\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-16\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-17\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-18\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-19\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;showingA\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;in\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getBoolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;KEY_STATE\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-20\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;in\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getParcelable\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;KEY_DATA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-21\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-22\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-23\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-24\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;@\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Override \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;apply\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyCustomView \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;view\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;retained\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-25\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-26\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;showingA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-27\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;view\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;A\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-28\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-29\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;view\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;showB\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;B\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-30\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-31\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-32\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-33\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-34\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; * @param a true if showing a, false if showing b\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-35\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-36\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setShowingA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-37\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;showingA\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-38\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-39\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-40\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setData\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Parcelable \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-41\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;data\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-42\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-43\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89c6700562407-44\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 大家可以看到，我们需要把ViewState保存到从**Activity.onSaveInstanceState()**调用的 **saveInstanceState()中，并且在从Activity.onCreate()调用的restoreInstanceState()**中修复viewstate的数据。apply()方法将会从Activity中调用以修复view state。我们像presenter一样通过调用同样的View interface 方法showA() 或 showB()来实现这一操作。\n大家可以看到，我们需要把ViewState保存到从**Activity.onSaveInstanceState()**调用的 **saveInstanceState()中，并且在从Activity.onCreate()调用的restoreInstanceState()**中修复viewstate的数据。apply()方法将会从Activity中调用以修复view state。我们像presenter一样通过调用同样的View interface 方法showA() 或 showB()来实现这一操作。\n这个外部的ViewState把view state修复的复杂性和职责从Activity代码中剥离，并入到这个单独的类中。而编写ViewState类的单元测试要比Activity类的单元测试容易得多。\n怎样处理后台线程？ 通常，Presenter会管理后台线程。Presenter如何处理后台线程取决于它所关联的Activity或者Fragment ，具体分为两种情况：\n可保持的Fragment : 如果你调用了Fragment的setRetainInstanceState(true)那么这个Fragment在屏幕旋转时就不会被销毁。只有该Fragment的GUI会被销毁，并且在屏幕旋转时重新调用onCreateView创建视图。这就是说当屏幕旋转时Fragment所有的成员成员变量和Presenter不会发生变化。在这个示例中，我们将新的视图关联到Presenter中。因此，Presenter不需要去掉任何正在运行中的后台任务，因为Presenter已经关联了新的视图。例如: 1.竖屏情况下启动应用\n2.实例化Fragment时会调用onCreate()、onCreateView()、createPresenter(), 然后通过调用presenter的attachView()函数将View关联到Presenter中。\n3. 下一步我们旋转手机屏幕，从竖屏切换到横屏；\n4. 此时onDestroyView() 会调用，而onDestroyView() 又会调用presenter的detachView(true)函数。我们注意到detachView有个参数为true,这是告诉presenter这个Fragment是可持有的Fragment（否则这个参数应该为false）。通过这个参数，presenter就知道它不需要取消正在运行的后台任务；\n5. 应用现在是横屏状态了，在旋转时onCreateView方法会被调用，但是createPresenter()函数不会被调用，因为我们会对presenter 进行不为空的判断，当presenter为空时才调用createPresenter()函数。而Fragment的setRetainInstanceState(true)会保持这个presenter对象，因此presenter此时不会被重新创建；\n6. 在调用了presenter的attachView()之后新创建的View会被重新关联到presenter中。\n7. ViewState会被恢复，但是没有后台任务会被取消，因此也没有后台任务需要重新启动。\nActivity和不保持的Fragment :在这个示例中工作流非常的简单。所有的东西都会被销毁，包括presenter。因此presenter对象应该取消所有正在运行的任务。例如 :\n我们采用非保持fragment在竖屏情况下启动app。 8.我们采用非保持fragment在竖屏情况下启动app。\n9.Fragment被实例化之后，调用onCreate()， onCreateView()，和createPresenter()，然后通过调用presenter.attachView()将view（fragment）附着到presenter。\n10.下一步我们旋转设备屏幕，从竖屏切换到横屏。\n11.此时onDestroyView() 会调用，而onDestroyView() 又会调用presenter的**detachView(true)**函数。Presenter取消后台任务。\n12. onSaveInstanceState(Bundle)被调用， ViewState被保存到Bundle中。\n13. App现在出于横屏状态。新的Fragment被实例化并调用onCreate()，onCreateView()和 createPresenter()来创建一个新的presenter例子，通过调用presenter.attachView()将新的view附着到新的presenter\n14. ViewState会从Bundle中恢复，且view的状态也会被恢复。如果ViewState是showLoading，那么presenter会重新启动后台线程来加载数据。\n15. 以下是获得ViewState支持的Activity的生命周期图解，如图1-6：\n以下是获得ViewState支持的Fragment的生命周期图解， 如图 1-7：\nRetrofit模块 Mosby提供了 LceRetrofitPresenter 和 LceCallback。为获得LCE方法showLoading(), showContent() 和 showError()支持的Retrofit编写presenter ，几行代码就能搞定。\n1 \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89d2834305473-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89d2834305473-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89d2834305473-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89d2834305473-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89d2834305473-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89d2834305473-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89d2834305473-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89d2834305473-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89d2834305473-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89d2834305473-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89d2834305473-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-558a20dde89d2834305473-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89d2834305473-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MembersPresenter \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;LceRetrofitPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;MembersView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;User\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89d2834305473-2\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89d2834305473-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;GithubApigithubApi\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89d2834305473-4\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89d2834305473-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MembersPresenter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;GithubApi \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;githubApi\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89d2834305473-6\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;githubApi\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;githubApi\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89d2834305473-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89d2834305473-8\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89d2834305473-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;loadSquareMembers\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;pullToRefresh\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89d2834305473-10\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;githubApi\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getMembers\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;square\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;LceCallback\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;pullToRefresh\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89d2834305473-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89d2834305473-12\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-558a20dde89d2834305473-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; Dagger模块 想在不依靠注入式的情况下写应用？Ted Mosby告诉你，这是行不通滴！Dagger是java依赖注入式框架最常用的方法，也是Android开发者们的心头好。Mosby支持Dagger1。Mosby通过一个叫做getObjectGraph()的方法提供Injector界面。通常，我们的应用模块非常广泛。要想轻松分享这一模块，我们需要把android.app.Application归入子类，使其执行Injector。之后所有的Activity和Fragment都可以通过调用getObjectGraph()来存取ObjectGraph，因为DaggerActivity and DaggerFragment也都是Injector。我们也可以通过重写Activity 或 Fragment中的 getObjcetGraph() ，从而调用plus(Module)以增加模块。我个人已经用到Dagger2了，它与Mosby也兼容。大家可以在Github上找到关于Dagger1 和 Dagger2的示例。点此这个链接https://db.tt/3fVqVdAzDagger1示例 apk；点此这个链接https://db.tt/z85y4fSYDagger2 示例 apk。\nRx模块 Observables赞爆了！现在稍微潮一点的小伙儿们都用RxJava了好吗！你猜结果怎么着？RxJava确实是太酷了！所以，Mosby给大家提供一个本质上是Subscriber的MvpLceRxPresenter，它能帮我们自动处理**onNext()， onCompleted() 和 onError()并回调相应的LCE方法，比如showLoading(), shwoContent() **和 showError()。它还将 RxAndroid 附带到observerOn() Android主要 UI 线程。你可能觉得，要是用了RxJava的话就不再需要Model View Presenter了。呃，那只是你的一家之言。在我看来，把View和Model清晰地区分开来非常重要。而且我也认为其中的某些好用的功能在没有MVP的情况下不容易执行。最后，大家要是还想回到过去那个Activity和Fragment包含了上千条又臭又长的代码行时代，那么我祝你在面条式代码的地狱里过得愉快。好了，废话不多说，我介绍的方法不属于面条式代码是因为Observerables引入了一个结构齐整的工作流，把Activity或Fragment做成一个BLOB的想法已经近在咫尺了。\n测试模块 大家可能注意到这里存在着一个测试模块。这个模块用于Mosby库的内部测试。但是，它也可以为我们自己的app所用。它使用Robolectric为我们的LCE Presenter， Activities 和 Fragments提供单元测试模板。它的基本功能是查看测试中的Presenter是否正确工作：通过观察presenter时候调用showLoading()，\nshowContent() 和 showError()。我们还可以验证setData()中的数据。所以我们可以为Presenter和底层编写类似黑匣子的测试。Mosby的测试模块也提供了测试MvpLceFragment 或 MvpLceActivity的可能性。它相当于一种“精简版”的UI 测试。这些测试通过查看xml布局是否包含R.id.loadingView， R.id.contentView 和R.id.errorView之类的指定id、loadingView是否可视，在加载view时，是否是错误的view可视、content view能否处理由setData()提交的已加载数据等方面来检验Fragment或Activity是否正常工作，是否遇到crashing。它和Espresso类的UI测试并不相同。我觉得没有必要为LCE View单独写一个UI 测试。\n以下是Ted Mosby库的一些测试小建议：\n编写传统的单元测试来测试业务逻辑层和model。 使用MvpLcePresenterTest来测试presenter。\n3.使用MvpLceFragmentTest 和 MvpLceActivityTest来测试MvpLceFragment 和 Activity。\n4.如果有必要，可以使用Espresso来编写UI测试。 测试模块尚未完成。大家可以看到这个模块是测试版，因为Robolectric 3.0还没完成，而且Android gradle plugin也没用完全支持传统的单元测试。android gradle plugin\n1.2应该会好得多。Robolectric 和 androids gradle plugin可以用了之后我会再写一篇关于Mosby，Dagger，Retrofit和RxJava单元测试的博客。\n","permalink":"https://blog.zdltech.com/posts/mvp%E6%A1%86%E6%9E%B6-ted-mosby%E7%9A%84%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84/","summary":"\u003cul\u003e\n\u003cli\u003e作者：Hannes Dorfmann\n\u003cul\u003e\n\u003cli\u003e原文链接 : \u003ca href=\"http://hannesdorfmann.com/android/mosby\"\u003eTed Mosby – Software Architect\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e文章出自 : \u003ca href=\"https://github.com/bboyfeiyu/android-tech-frontier\"\u003eAndroid开发技术前线\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e译者 : \u003ca href=\"https://github.com/bboyfeiyu\"\u003eMr.Simple\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e我给这篇关于Android库的博客起的名字灵感来源于《老爸老妈浪漫史》中的建筑设计师Ted Mosby。这个Mosby库可以帮助大家在Android上通过Model-View-Presenter模式做出一个完善稳健、可重复使用的软件，还可以借助ViewState轻松实现屏幕翻转。\u003c/p\u003e\n\u003ch2 id=\"model-view-presenter-mvp\"\u003eModel-View-Presenter (MVP)\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eMVP\u003c/strong\u003e模式是一个把view从低层模型分离出来的一种现代模式。\u003cstrong\u003eMVP\u003c/strong\u003e由model–view–controller (MVC)软件模式衍生而来，常用于构建UI\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eMVP\u003c/strong\u003e中的\u003cstrong\u003eM\u003c/strong\u003e（model）代表的是将会显示在view（UI）中的数据。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMVP\u003c/strong\u003e中的\u003cstrong\u003eV\u003c/strong\u003e（view）是显示数据（model）并且将用户指令（events）传送到presenter以便作用于那些数据的一个接口。View通常含有Presenter的引用。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMVP\u003c/strong\u003e中的\u003cstrong\u003eP\u003c/strong\u003e（presenter）扮演的是“中间人”的作用（就如MVC中的controller），且presenter同时引用view和model。值得注意的是，“Model”这个词并不正确。严格意义上来说，它指的应该是检索或控制一个Model的业务逻辑层。举个例子，比如你的数据库里面包含了User，而你的View想要显示一个User列表，那么Presenter会引用数据库中的业务逻辑层（比如DAO）从而查询到一个User列表。如图1-1.\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://hannesdorfmann.com/images/mosby/mvp-overview.png\"\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e从数据库中查询或显示User列表的具体流程如图1-2：\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://hannesdorfmann.com/images/mosby/mvp-workflow.png\"\u003e\u003c/p\u003e\n\u003cp\u003e以上工作流程图应该能够说明问题了。但是，还有以下几点值得注意的地方：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePresenter\u003c/strong\u003e不是一个\u003cstrong\u003eOnClickListener\u003c/strong\u003e。\u003cstrong\u003eView\u003c/strong\u003e主要是负责处理用户输入并调用presenter相应的方法。那么问题来了，为什么不把\u003cstrong\u003ePresenter\u003c/strong\u003e 直接做成一个\u003cstrong\u003eOnClickListener\u003c/strong\u003e，从而把“转发流程”给省略掉呢？大家想想，如果这样做的话，首先，\u003cstrong\u003epresenter\u003c/strong\u003e需要知道view的内部构件。举个例子，如果一个View有两个按钮，且这个view在这两个按钮上都把\u003cstrong\u003ePresenter\u003c/strong\u003e 注册成\u003cstrong\u003eOnClickListener\u003c/strong\u003e的话，那么发生点击事件时Presenter （在不知道view中按钮引用等内部构件的情况下）怎么能够区分出是哪一个按钮被点击了呢？Model，View和Presenter三者应解耦。其次，如果让Presenter 执行OnClickListener，Presenter就被绑定到了Android平台上。理论上来说\u003cstrong\u003epresenter\u003c/strong\u003e和业务逻辑层都是纯旧式的能够与桌面应用或其他任何java应用共享的java代码。\u003c/li\u003e\n\u003cli\u003e大家在第1步和第2步中可以看到，\u003cstrong\u003eView\u003c/strong\u003e 只执行\u003cstrong\u003ePresenter\u003c/strong\u003e 指示的操作：用户点击“load user button”（第1步）后，view并没有直接显示加载动画，而是在第2步presenter明确告诉其显示加载动画后才显示的。这一Model-View-Presenter的变体称之为MVP 被动视图。这个view可以说是要多笨有多笨。这时我们需要让presenter以一种更抽象的方式来控制view。比如，presenter在调用 \u003cstrong\u003eview.showLoading()\u003c/strong\u003e 时并不控制view的诸如动画等具体事项。所以presenter不应调用\u003cstrong\u003eview.startAnimation()\u003c/strong\u003e 等方法。\u003c/li\u003e\n\u003cli\u003e通过执行\u003cstrong\u003eMVP\u003c/strong\u003e被动视图，并发性以及多线程更容易处理。大家可以看到，第3步中数据库查询异步运行，并且\u003cstrong\u003epresenter作为Listener/Observer\u003c/strong\u003e，在数据准备显示时presenter收到通知。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"android上的mvp\"\u003e\u003cstrong\u003eAndroid\u003c/strong\u003e上的\u003cstrong\u003eMVP\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e目前为止一切顺利。但是大家怎么样把MVP运用到自己的Android 应用上呢？第一个问题在于，我们要把MVP模式运用到什么地方？Activity上、Fragment上、还是像RelativeLayout这类的ViewGroup上？我们来看看Android平板上的Gmail应用，如图1-3：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://hannesdorfmann.com/images/mosby/mvp-gmail.png\"\u003e\u003c/p\u003e\n\u003cp\u003e在我看来，上图屏幕中有四个可以使用MVP的地方。我所说的“可以使用MVP的地方”是指屏幕上显示的、在逻辑上属于一个整体的UI元素。因此这些地方也可以称为是可以运用MVP的一个单独的UI单元。如图 1-4.\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://hannesdorfmann.com/images/mosby/mvp-gmail-candidates.png\"\u003e\u003c/p\u003e\n\u003cp\u003e看起来MVP似乎很适合运用到Activity，特别是Fragment上。通常Fragment只负责显示单一的如ListView之类的内容，就像依靠\u003cstrong\u003eMailProvider\u003c/strong\u003e 来获取一系列\u003cstrong\u003eMails\u003c/strong\u003e的\u003cstrong\u003eInboxPresenter\u003c/strong\u003e 控制下的 \u003cstrong\u003eInboxView\u003c/strong\u003e一样。但是，\u003cstrong\u003eMVP\u003c/strong\u003e不仅仅限于Fragment或Activity，它还可以运用到SearchView中显示的ViewGroup中。在我的大多数app里面我都在Fragment运用MVP模式。但是大家可以自行决定把MVP运用到什么地方，前提是view是独立的，这样这样presenter才能在不与其他Presenter冲突的情况下控制View。\u003c/p\u003e\n\u003ch2 id=\"我们为什么要实现mvp\"\u003e我们为什么要实现\u003cstrong\u003eMVP\u003c/strong\u003e？\u003c/h2\u003e\n\u003cp\u003e我们如何在不使用MVP模式时显示Email列表到Fragment? 通常，我们需要获取并且合并本地SQL数据库和从IMAP邮件服务器获取的邮件列表，然后将邮件列表绑定到收件箱view中。那么，此时fragment的代码又会是怎么样的呢？我们需要运行两个\u003cstrong\u003eAsyncTasks\u003c/strong\u003e 并实现一个“等待机制”（等到两个任务将两者的加载数据合并到一个单独的mail列表）。我们还需要注意的是在加载时要显示加载动画（ProgressBar），之后用ListView替代。我们需要把所有的代码放到Fragment中吗？要是加载过程中出现错误怎么办？屏幕翻转怎么办？谁来负责撤销\u003cstrong\u003eAsyncTasks\u003c/strong\u003e ？这一系列的问题都可以通过MVP得到解决。让我们跟那些带有上千行大杂烩代码的activity和fragment说拜拜吧\u003c/p\u003e\n\u003cp\u003e但是，在我们深入研究如何将MVP运用到Android中之前，我们需要弄清楚的一个问题是：Activity或Fragment究竟是一个View还是一个Presenter。Activity或Fragment似乎既是\u003cstrong\u003eView\u003c/strong\u003e也是\u003cstrong\u003ePresenter\u003c/strong\u003e，因为它们都有 \u003cstrong\u003eonCreate()\u003c/strong\u003e 或**onDestroy()**之类的生命周期回调功能，并且它们负责从一个UI控件到另一个UI 控件的转换（比如在加载时显示ProgressBar，然后显示带有数据的ListView）等View操作。大家可能会觉得这里的Activity或Fragment就是一个Controller，我猜可能也是这么一个初衷。但是在经历了几年的Android应用开发之后，我得出这么一个结论：我们应该把Activity或Fragment看作是一个不太智能的View，而不是把它们看作一个Presenter。后文我会给出原因。\u003c/p\u003e\n\u003cp\u003e综上，我想给大家介绍一个在Android平台上开发基于MVP的应用的一个 \u003cstrong\u003eMosby\u003c/strong\u003e库。\u003cbr\u003e\n\u003cstrong\u003eMosby\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e大家可以在\u003ca href=\"https://github.com/sockeqwe/mosby\"\u003eGithub\u003c/a\u003e和Maven Central上找到Mosby库。Mosby分为几个子模块，大家可以根据自己的需要选取组件。我们来回顾一下最重要的一个模块。\u003c/p\u003e\n\u003ch2 id=\"核心模块--core-module\"\u003e核心模块 ( Core Module)\u003c/h2\u003e\n\u003cp\u003e《老爸老妈浪漫史》中的建筑设计师Ted Mosby想建造一栋摩天大楼。而建造这样一栋宏伟的建筑必须打好坚实的地基。这对Android应用的开发来说是也是一样的道理。基本上，\u003cstrong\u003eCore Module\u003c/strong\u003e 分为两种类型：\u003cstrong\u003eMosbyActivity\u003c/strong\u003e 和\u003cstrong\u003eMosbyFragment\u003c/strong\u003e。这两者是所有其他activity或fragment子类的基类（相当于建筑的地基）。两者都使用我们大家所熟知的APT \u003cstrong\u003e（Annotation Processing Tool）\u003cstrong\u003e来减少一些样板式代码。\u003cstrong\u003eMosbyActivity\u003c/strong\u003e 和\u003c/strong\u003eMosbyFragment\u003c/strong\u003e 使用Butterknife进行view的注入，使用Icepick 将实例状态保存和存储到Bundle中，使用FragmentArgs注入Fragment参数。我们不需要再调用Butterknife.inject(this)等插入方法。这类代码已经包含在了MosbyActivity 和 MosbyFragment中。它是即时可用的。我们需要做的就是使用子类中相应的注解。核心模块与MVP没有关联，它只是写一个大型软件的基础。\u003c/p\u003e","title":"MVP框架 – Ted Mosby的软件架构"},{"content":"概述 作为一个android开发者，在开发应用时，随着业务规模发展到一定程度，不断地加入新功能、添加新的类库，代码在急剧的膨胀，相应的apk包的大小也急剧增加， 那么终有一天，你会不幸遇到这个错误：\n生成的apk在android 2.3或之前的机器上无法安装，提示INSTALL_FAILED_DEXOPT 方法数量过多，编译时出错，提示： Conversion to Dalvik format failed:Unable to execute dex: method ID not in [0, 0xffff]: 65536 而问题产生的具体原因如下：\n无法安装（Android 2.3 INSTALL_FAILED_DEXOPT）问题，是由dexopt的LinearAlloc限制引起的，在Android版本不同分别经历了4M/5M/8M/16M限制，目前主流4.2.x系统上可能都已到16M， 在Gingerbread或者以下系统LinearAllocHdr分配空间只有5M大小的， 高于Gingerbread的系统提升到了8M。Dalvik linearAlloc是一个固定大小的缓冲区。在应用的安装过程中，系统会运行一个名为dexopt的程序为该应用在当前机型中运行做准备。dexopt使用LinearAlloc来存储应用的方法信息。Android 2.2和2.3的缓冲区只有5MB，Android 4.x提高到了8MB或16MB。当方法数量过多导致超出缓冲区大小时，会造成dexopt崩溃。 超过最大方法数限制的问题，是由于DEX文件格式限制，一个DEX文件中method个数采用使用原生类型short来索引文件中的方法，也就是4个字节共计最多表达65536个method，field/class的个数也均有此限制。对于DEX文件，则是将工程所需全部class文件合并且压缩到一个DEX文件期间，也就是Android打包的DEX过程中， 单个DEX文件可被引用的方法总数（自己开发的代码以及所引用的Android框架、类库的代码）被限制为65536； 插件化？ MultiDex？ 解决这个问题，一般有下面几种方案，一种方案是加大Proguard的力度来减小DEX的大小和方法数，但这是治标不治本的方案，随着业务代码的添加，方法数终究会到达这个限制，一种比较流行的方案是插件化方案，另外一种是采用google提供的MultiDex方案，以及google在推出MultiDex之前Android Developers博客介绍的通过自定义类加载过程， 再就是Facebook推出的为Android应用开发的Dalvik补丁， 但facebook博客里写的不是很详细；我们在插件化方案上也做了探索和尝试，发现部署插件化方案，首先需要梳理和修改各个业务线的代码，使之解耦，改动的面和量比较巨大，通过一定的探讨和分析，我们认为对我们目前来说采用MultiDex方案更靠谱一些，这样我们可以快速和简洁的对代码进行拆分，同时代码改动也在可以接受的范围内； 这样我们采用了google提供的MultiDex方式进行了开发。\n插件化方案在业内有不同的实现原理，这里不再一一列举，这里只列举下Google为构建超过65K方法数的应用提供官方支持的方案：MultiDex。\n首先使用Android SDK Manager升级到最新的Android SDK Build Tools和Android Support Library。然后进行以下两步操作：\n1.修改Gradle配置文件，启用MultiDex并包含MultiDex支持：\nandroid { compileSdkVersion 21 buildToolsVersion \u0026quot;21.1.0\u0026quot; defaultConfig { ... minSdkVersion 14 targetSdkVersion 21 ... // Enabling MultiDex support. MultiDexEnabled true } ... } dependencies { compile 'com.android.support:MultiDex:1.0.0' } 2.让应用支持多DEX文件。在官方文档中描述了三种可选方法：\n在AndroidManifest.xml的application中声明android.support.MultiDex.MultiDexApplication；\n如果你已经有自己的Application类，让其继承MultiDexApplication；\n如果你的Application类已经继承自其它类，你不想/能修改它，那么可以重写attachBaseContext()方法：\n@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } 并在Manifest中添加以下声明：\n\u0026lt;?xml version=\u0026quot;1.0\u0026quot; encoding=\u0026quot;utf-8\u0026quot;?\u0026gt; \u0026lt;manifest xmlns:android=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot; package=\u0026quot;com.example.android.MultiDex.myapplication\u0026quot;\u0026gt; \u0026lt;application ... android:name=\u0026quot;android.support.MultiDex.MultiDexApplication\u0026quot;\u0026gt; ... \u0026lt;/application\u0026gt; \u0026lt;/manifest\u0026gt; 如果已经有自己的Application，则让其继承MultiDexApplication即可.\nDex自动拆包及动态加载 MultiDex带来的问题 在第一版本采用MultiDex方案上线后，在Dalvik下MultiDex带来了下列几个问题：\n在冷启动时因为需要安装DEX文件，如果DEX文件过大时，处理时间过长，很容易引发ANR（Application Not Responding）； 采用MultiDex方案的应用可能不能在低于Android 4.0 (API level 14) 机器上启动，这个主要是因为Dalvik linearAlloc的一个bug (Issue 22586); 采用MultiDex方案的应用因为需要申请一个很大的内存，在运行时可能导致程序的崩溃，这个主要是因为Dalvik linearAlloc 的一个限制(Issue 78035). 这个限制在 Android 4.0 (API level 14)已经增加了, 应用也有可能在低于 Android 5.0 (API level 21)版本的机器上触发这个限制； 而在ART下MultiDex是不存在这个问题的，这主要是因为ART下采用Ahead-of-time (AOT) compilation技术，系统在APK的安装过程中会使用自带的dex2oat工具对APK中可用的DEX文件进行编译并生成一个可在本地机器上运行的文件，这样能提高应用的启动速度，因为是在安装过程中进行了处理这样会影响应用的安装速度，对ART感兴趣的可以参考一下ART和Dalvik的区别.\nMultiDex的基本原理是把通过DexFile来加载Secondary DEX，并存放在BaseDexClassLoader的DexPathList中。\n下面代码片段是BaseDexClassLoader findClass的过程:\nprotected Class\u0026lt;?\u0026gt; findClass(String name) throws ClassNotFoundException { List\u0026lt;Throwable\u0026gt; suppressedExceptions = new ArrayList\u0026lt;Throwable\u0026gt;(); Class c = pathList.findClass(name, suppressedExceptions); if (c == null) { ClassNotFoundException cnfe = new ClassNotFoundException(\u0026quot;Didn't find class \\\u0026quot;\u0026quot; + name + \u0026quot;\\\u0026quot; on path: \u0026quot; + pathList); for (Throwable t : suppressedExceptions) { cnfe.addSuppressed(t); } throw cnfe; } return c; } 下面代码片段为怎么通过DexFile来加载Secondary DEX并放到BaseDexClassLoader的DexPathList中:\nprivate static void install(ClassLoader loader, List\u0026lt;File\u0026gt; additionalClassPathEntries, File optimizedDirectory) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException { /* The patched class loader is expected to be a descendant of * dalvik.system.BaseDexClassLoader. We modify its * dalvik.system.DexPathList pathList field to append additional DEX * file entries. */ Field pathListField = findField(loader, \u0026quot;pathList\u0026quot;); Object dexPathList = pathListField.get(loader); ArrayList\u0026lt;IOException\u0026gt; suppressedExceptions = new ArrayList\u0026lt;IOException\u0026gt;(); expandFieldArray(dexPathList, \u0026quot;dexElements\u0026quot;, makeDexElements(dexPathList, new ArrayList\u0026lt;File\u0026gt;(additionalClassPathEntries), optimizedDirectory, suppressedExceptions)); try { if (suppressedExceptions.size() \u0026gt; 0) { for (IOException e : suppressedExceptions) { //Log.w(TAG, \u0026quot;Exception in makeDexElement\u0026quot;, e); } Field suppressedExceptionsField = findField(loader, \u0026quot;dexElementsSuppressedExceptions\u0026quot;); IOException[] dexElementsSuppressedExceptions = (IOException[]) suppressedExceptionsField.get(loader); if (dexElementsSuppressedExceptions == null) { dexElementsSuppressedExceptions = suppressedExceptions.toArray( new IOException[suppressedExceptions.size()]); } else { IOException[] combined = new IOException[suppressedExceptions.size() + dexElementsSuppressedExceptions.length]; suppressedExceptions.toArray(combined); System.arraycopy(dexElementsSuppressedExceptions, 0, combined, suppressedExceptions.size(), dexElementsSuppressedExceptions.length); dexElementsSuppressedExceptions = combined; } suppressedExceptionsField.set(loader, dexElementsSuppressedExceptions); } } catch(Exception e) { } } Dex自动拆包及动态加载方案简介 通过查看MultiDex的源码，我们发现MultiDex在冷启动时容易导致ANR的瓶颈， 在2.1版本之前的Dalvik的VM版本中， MultiDex的安装大概分为几步，第一步打开apk这个zip包，第二步把MultiDex的dex解压出来（除去Classes.dex之外的其他DEX，例如：classes2.dex， classes3.dex等等)，因为android系统在启动app时只加载了第一个Classes.dex，其他的DEX需要我们人工进行安装，第三步通过反射进行安装，这三步其实都比较耗时， 为了解决这个问题我们考虑是否可以把DEX的加载放到一个异步线程中，这样冷启动速度能提高不少，同时能够减少冷启动过程中的ANR，对于Dalvik linearAlloc的一个缺陷(Issue 22586)和限制(Issue 78035)，我们考虑是否可以人工对DEX的拆分进行干预，使每个DEX的大小在一定的合理范围内，这样就减少触发Dalvik linearAlloc的缺陷和限制； 为了实现这几个目的，我们需要解决下面三个问题：\n在打包过程中如何产生多个的DEX包？ 如果做到动态加载，怎么决定哪些DEX动态加载呢？ 如果启动后在工作线程中做动态加载，如果没有加载完而用户进行页面操作需要使用到动态加载DEX中的class怎么办？ 我们首先来分析如何解决第一个问题，在使用MultiDex方案时，我们知道BuildTool会自动把代码进行拆成多个DEX包，并且可以通过配置文件来控制哪些代码放到第一个DEX包中， 下图是Android的打包流程示意图：\n为了实现产生多个DEX包，我们可以在生成DEX文件的这一步中， 在Ant或gradle中自定义一个Task来干预DEX产生的过程，从而产生多个DEX，下图是在ant和gradle中干预产生DEX的自定task的截图:\ntasks.whenTaskAdded { task -\u0026gt; if (task.name.startsWith('proguard') \u0026amp;\u0026amp; (task.name.endsWith('Debug') || task.name.endsWith('Release'))) { task.doLast { makeDexFileAfterProguardJar(); } task.doFirst { delete \u0026quot;${project.buildDir}/intermediates/classes-proguard\u0026quot;; String flavor = task.name.substring('proguard'.length(), task.name.lastIndexOf(task.name.endsWith('Debug') ? \u0026quot;Debug\u0026quot; : \u0026quot;Release\u0026quot;)); generateMainIndexKeepList(flavor.toLowerCase()); } } else if (task.name.startsWith('zipalign') \u0026amp;\u0026amp; (task.name.endsWith('Debug') || task.name.endsWith('Release'))) { task.doFirst { ensureMultiDexInApk(); } } } 上一步解决了如何打包出多个DEX的问题了，那我们该怎么该根据什么来决定哪些class放到Main DEX，哪些放到Secondary DEX呢（这里的Main DEX是指在2.1版本的Dalvik VM之前由android系统在启动apk时自己主动加载的Classes.dex，而Secondary DEX是指需要我们自己安装进去的DEX，例如：Classes2.dex, Classes3.dex等）， 这个需要分析出放到Main DEX中的class依赖，需要确保把Main DEX中class所有的依赖都要放进来，否则在启动时会发生ClassNotFoundException, 这里我们的方案是把Service、Receiver、Provider涉及到的代码都放到Main DEX中，而把Activity涉及到的代码进行了一定的拆分，把首页Activity、Laucher Activity、欢迎页的Activity、城市列表页Activity等所依赖的class放到了Main DEX中，把二级、三级页面的Activity以及业务频道的代码放到了Secondary DEX中，为了减少人工分析class的依赖所带了的不可维护性和高风险性，我们编写了一个能够自动分析Class依赖的脚本， 从而能够保证Main DEX包含class以及他们所依赖的所有class都在其内，这样这个脚本就会在打包之前自动分析出启动到Main DEX所涉及的所有代码，保证Main DEX运行正常。\n随着第二个问题的迎刃而解，我们来到了比较棘手的第三问题，如果我们在后台加载Secondary DEX过程中，用户点击界面将要跳转到使用了在Secondary DEX中class的界面， 那此时必然发生ClassNotFoundException, 那怎么解决这个问题呢，在所有的Activity跳转代码处添加判断Secondary DEX是否加载完成？这个方法可行，但工作量非常大； 那有没有更好的解决方案呢？我们通过分析Activity的启动过程，发现Activity是由ActivityThread 通过Instrumentation来启动的，我们是否可以在Instrumentation中做一定的手脚呢？通过分析代码ActivityThread和Instrumentation发现，Instrumentation有关Activity启动相关的方法大概有：execStartActivity、newActivity等等，这样我们就可以在这些方法中添加代码逻辑进行判断这个Class是否加载了，如果加载则直接启动这个Activity，如果没有加载完成则启动一个等待的Activity显示给用户，然后在这个Activity中等待后台Secondary DEX加载完成，完成后自动跳转到用户实际要跳转的Activity；这样在代码充分解耦合，以及每个业务代码能够做到颗粒化的前提下，我们就做到Secondary DEX的按需加载了， 下面是Instrumentation添加的部分关键代码：\npublic ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) { ActivityResult activityResult = null; String className; if (intent.getComponent() != null) { className = intent.getComponent().getClassName(); } else { ResolveInfo resolveActivity = who.getPackageManager().resolveActivity(intent, 0); if (resolveActivity != null \u0026amp;\u0026amp; resolveActivity.activityInfo != null) { className = resolveActivity.activityInfo.name; } else { className = null; } } if (!TextUtils.isEmpty(className)) { boolean shouldInterrupted = !MeituanApplication.isDexAvailable(); if (MeituanApplication.sIsDexAvailable.get() || mByPassActivityClassNameList.contains(className)) { shouldInterrupted = false; } if (shouldInterrupted) { Intent interruptedIntent = new Intent(mContext, WaitingActivity.class); activityResult = execStartActivity(who, contextThread, token, target, interruptedIntent, requestCode); } else { activityResult = execStartActivity(who, contextThread, token, target, intent, requestCode); } } else { activityResult = execStartActivity(who, contextThread, token, target, intent, requestCode); } return activityResult; } public Activity newActivity(Class\u0026lt;?\u0026gt; clazz, Context context, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance) throws InstantiationException, IllegalAccessException { String className = \u0026quot;\u0026quot;; Activity newActivity = null; if (intent.getComponent() != null) { className = intent.getComponent().getClassName(); } boolean shouldInterrupted = !MeituanApplication.isDexAvailable(); if (MeituanApplication.sIsDexAvailable.get() || mByPassActivityClassNameList.contains(className)) { shouldInterrupted = false; } if (shouldInterrupted) { intent = new Intent(mContext, WaitingActivity.class); newActivity = mBase.newActivity(clazz, context, token, application, intent, info, title, parent, id, lastNonConfigurationInstance); } else { newActivity = mBase.newActivity(clazz, context, token, application, intent, info, title, parent, id, lastNonConfigurationInstance); } return newActivity; } 实际应用中我们还遇到另外一个比较棘手的问题， 就是Field的过多的问题，Field过多是由我们目前采用的代码组织结构引入的，我们为了方便多业务线、多团队并发协作的情况下开发，我们采用的aar的方式进行开发，并同时在aar依赖链的最底层引入了一个通用业务aar，而这个通用业务aar中包含了很多资源，而ADT14以及更高的版本中对Library资源处理时，Library的R资源不再是static final的了，详情请查看google官方说明，这样在最终打包时Library中的R没法做到内联，这样带来了R field过多的情况，导致需要拆分多个Secondary DEX，为了解决这个问题我们采用的是在打包过程中利用脚本把Libray中R field（例如ID、Layout、Drawable等）的引用替换成常量，然后删去Library中R.class中的相应Field。\n总结 上面就是我们在使用MultiDex过程中进化而来的DEX自动化拆包的方案， 这样我们就可以通过脚本控制来进行自动化的拆分DEX，然后在运行时自由的加载Secondary DEX，既能保证冷启动速度，又能减少运行时的内存占用。\n","permalink":"https://blog.zdltech.com/posts/%E7%BE%8E%E5%9B%A2android-dex%E8%87%AA%E5%8A%A8%E6%8B%86%E5%8C%85%E5%8F%8A%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E7%AE%80%E4%BB%8B/","summary":"\u003ch2 id=\"-\"\u003e概述\u003c/h2\u003e\n\u003cp\u003e作为一个android开发者，在开发应用时，随着业务规模发展到一定程度，不断地加入新功能、添加新的类库，代码在急剧的膨胀，相应的apk包的大小也急剧增加， 那么终有一天，你会不幸遇到这个错误：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e生成的apk在android 2.3或之前的机器上无法安装，提示INSTALL_FAILED_DEXOPT\u003c/li\u003e\n\u003cli\u003e方法数量过多，编译时出错，提示：\nConversion to Dalvik format failed:Unable to execute dex: method ID not in [0, 0xffff]: 65536\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e而问题产生的具体原因如下：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e无法安装（Android 2.3 INSTALL_FAILED_DEXOPT）问题，是由dexopt的LinearAlloc限制引起的，在Android版本不同分别经历了4M/5M/8M/16M限制，目前主流4.2.x系统上可能都已到16M， 在Gingerbread或者以下系统LinearAllocHdr分配空间只有5M大小的， 高于Gingerbread的系统提升到了8M。Dalvik linearAlloc是一个固定大小的缓冲区。在应用的安装过程中，系统会运行一个名为dexopt的程序为该应用在当前机型中运行做准备。dexopt使用LinearAlloc来存储应用的方法信息。Android 2.2和2.3的缓冲区只有5MB，Android 4.x提高到了8MB或16MB。当方法数量过多导致超出缓冲区大小时，会造成dexopt崩溃。\u003c/li\u003e\n\u003cli\u003e超过最大方法数限制的问题，是由于DEX文件格式限制，一个DEX文件中method个数采用使用原生类型short来索引文件中的方法，也就是4个字节共计最多表达65536个method，field/class的个数也均有此限制。对于DEX文件，则是将工程所需全部class文件合并且压缩到一个DEX文件期间，也就是Android打包的DEX过程中， 单个DEX文件可被引用的方法总数（自己开发的代码以及所引用的Android框架、类库的代码）被限制为65536；\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"-multidex-\"\u003e插件化？ MultiDex？\u003c/h2\u003e\n\u003cp\u003e解决这个问题，一般有下面几种方案，一种方案是加大Proguard的力度来减小DEX的大小和方法数，但这是治标不治本的方案，随着业务代码的添加，方法数终究会到达这个限制，一种比较流行的方案是插件化方案，另外一种是采用google提供的MultiDex方案，以及google在推出MultiDex之前Android Developers博客介绍的通过\u003ca href=\"http://android-developers.blogspot.hk/2011/07/custom-class-loading-in-dalvik.html\"\u003e自定义类加载过程\u003c/a\u003e， 再就是Facebook推出的为Android应用开发的\u003ca href=\"https://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920\"\u003eDalvik补丁\u003c/a\u003e， 但facebook博客里写的不是很详细；我们在插件化方案上也做了探索和尝试，发现部署插件化方案，首先需要梳理和修改各个业务线的代码，使之解耦，改动的面和量比较巨大，通过一定的探讨和分析，我们认为对我们目前来说采用MultiDex方案更靠谱一些，这样我们可以快速和简洁的对代码进行拆分，同时代码改动也在可以接受的范围内； 这样我们采用了google提供的MultiDex方式进行了开发。\u003c/p\u003e\n\u003cp\u003e插件化方案在业内有不同的实现原理，这里不再一一列举，这里只列举下Google为构建超过65K方法数的应用提供官方支持的方案：\u003ca href=\"https://developer.android.com/tools/building/MultiDex.html\"\u003eMultiDex\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e首先使用Android SDK Manager升级到最新的Android SDK Build Tools和Android Support Library。然后进行以下两步操作：\u003c/p\u003e\n\u003cp\u003e1.修改Gradle配置文件，启用MultiDex并包含MultiDex支持：\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  android {\n    compileSdkVersion 21 buildToolsVersion \u0026quot;21.1.0\u0026quot;\n\n    defaultConfig {\n        ...\n        minSdkVersion 14\n        targetSdkVersion 21\n        ...\n\n        // Enabling MultiDex support.\n        MultiDexEnabled true\n        }\n        ...\n    }\n    dependencies { compile 'com.android.support:MultiDex:1.0.0'\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e2.让应用支持多DEX文件。在官方文档中描述了三种可选方法：\u003c/p\u003e","title":"美团Android DEX自动拆包及动态加载简介"},{"content":" - [一简介](http://my.oschina.net/u/1424386/blog/336087#OSC_h1_1) - [二：线程池](http://my.oschina.net/u/1424386/blog/336087#OSC_h1_2) - [三：ThreadPoolExecutor详解](http://my.oschina.net/u/1424386/blog/336087#OSC_h1_3) Java线程池使用说明 \u0026amp;nbsp; 一简介 线程的使用在java中占有极其重要的地位，在jdk1.4极其之前的jdk版本中，关于线程池的使用是极其简陋的。在jdk1.5之后这一情况有了很大的改观。Jdk1.5之后加入了java.util.concurrent包，这个包中主要介绍java中线程以及线程池的使用。为我们在开发中处理线程的问题提供了非常大的帮助。 \u0026amp;nbsp; 二：线程池 **线程池的作用：** 线程池作用就是限制系统中执行线程的数量。 根据系统的环境情况，可以自动或手动设置线程数量，达到运行的最佳效果；少了浪费了系统资源，多了造成系统拥挤效率不高。用线程池控制线程数量，其他线程排队等候。一个任务执行完毕，再从队列的中取最前面的任务开始执行。若队列中没有等待进程，线程池的这一资源处于等待。当一个新任务需要运行时，如果线程池中有等待的工作线程，就可以开始运行了；否则进入等待队列。\n**为什么要用线程池:** 1.减少了创建和销毁线程的次数，每个工作线程都可以被重复利用，可执行多个任务。 2.可以根据系统的承受能力，调整线程池中工作线线程的数目，防止因为消耗过多的内存，而把服务器累趴下(每个线程需要大约1MB内存，线程开的越多，消耗的内存也就越大，最后死机)。 Java里面线程池的顶级接口是Executor，但是严格意义上讲Executor并不是一个线程池，而只是一个执行线程的工具。真正的线程池接口是ExecutorService。 比较重要的几个类： ExecutorService \u0026lt;td\u0026gt; 真正的线程池接口。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; ScheduledExecutorService \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 能和Timer/TimerTask类似，解决那些需要任务重复执行的问题。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; ThreadPoolExecutor \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; ExecutorService的默认实现。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; ScheduledThreadPoolExecutor \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 继承ThreadPoolExecutor的ScheduledExecutorService接口实现，周期性任务调度的类实现。 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 要配置一个线程池是比较复杂的，尤其是对于线程池的原理不是很清楚的情况下，很有可能配置的线程池不是较优的，因此在Executors类里面提供了一些静态工厂，生成一些常用的线程池。 **1. newSingleThreadExecutor** 创建一个单线程的线程池。这个线程池只有一个线程在工作，也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束，那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。 2.**newFixedThreadPool** 创建固定大小的线程池。每次提交一个任务就创建一个线程，直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变，如果某个线程因为执行异常而结束，那么线程池会补充一个新线程。 **3. newCachedThreadPool** 创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程， 那么就会回收部分空闲（60秒不执行任务）的线程，当任务数增加时，此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制，线程池大小完全依赖于操作系统（或者说JVM）能够创建的最大线程大小。 4.**newScheduledThreadPool** 创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。 **实例** **1：newSingleThreadExecutor** MyThread.java **public****class**MyThread **extends** Thread {@Override **public****void** run() { System.*out*.println(Thread.*currentThread*().getName() + \u0026amp;#8220;正在执行。。。\u0026amp;#8221;); } }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; TestSingleThreadExecutor.java \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; **public****class**TestSingleThreadExecutor {**public****static****void** main(String[] args) { //创建一个可重用固定线程数的线程池 ExecutorService pool = Executors.* newSingleThreadExecutor*(); //创建实现了Runnable接口对象，Thread对象当然也实现了Runnable接口 Thread t1 = **new** MyThread(); Thread t2 = **new** MyThread(); Thread t3 = **new** MyThread(); Thread t4 = **new** MyThread(); Thread t5 = **new** MyThread(); //将线程放入池中进行执行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); //关闭线程池 pool.shutdown(); } }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; **输出结果** \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; pool-1-thread-1正在执行。。。pool-1-thread-1正在执行。。。 pool-1-thread-1正在执行。。。 pool-1-thread-1正在执行。。。 pool-1-thread-1正在执行。。。\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; **2newFixedThreadPool** TestFixedThreadPool.Java \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; **public****class** TestFixedThreadPool {**public****static****void** main(String[] args) { //创建一个可重用固定线程数的线程池 ExecutorService pool = Executors.*newFixedThreadPool*(2); //创建实现了Runnable接口对象，Thread对象当然也实现了Runnable接口 Thread t1 = **new** MyThread(); Thread t2 = **new** MyThread(); Thread t3 = **new** MyThread(); Thread t4 = **new** MyThread(); Thread t5 = **new** MyThread(); //将线程放入池中进行执行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); //关闭线程池 pool.shutdown(); } }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; **输出结果** \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; pool-1-thread-1正在执行。。。pool-1-thread-2正在执行。。。 pool-1-thread-1正在执行。。。 pool-1-thread-2正在执行。。。 pool-1-thread-1正在执行。。。\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; 3** newCachedThreadPool** TestCachedThreadPool.java \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; **public****class** TestCachedThreadPool {**public****static****void** main(String[] args) { //创建一个可重用固定线程数的线程池 ExecutorService pool = Executors.*newCachedThreadPool*(); //创建实现了Runnable接口对象，Thread对象当然也实现了Runnable接口 Thread t1 = **new** MyThread(); Thread t2 = **new** MyThread(); Thread t3 = **new** MyThread(); Thread t4 = **new** MyThread(); Thread t5 = **new** MyThread(); //将线程放入池中进行执行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); //关闭线程池 pool.shutdown(); } }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; 输出结果： \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; pool-1-thread-2正在执行。。。pool-1-thread-4正在执行。。。 pool-1-thread-3正在执行。。。 pool-1-thread-1正在执行。。。 pool-1-thread-5正在执行。。。\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; 4**newScheduledThreadPool** TestScheduledThreadPoolExecutor.java \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; **public****class** TestScheduledThreadPoolExecutor {**public****static****void** main(String[] args) { ScheduledThreadPoolExecutor exec = **new** ScheduledThreadPoolExecutor(1); exec.scheduleAtFixedRate(**new** Runnable() {//每隔一段时间就触发异常 @Override **public****void** run() { //throw new RuntimeException(); System.*out*.println(\u0026amp;#8220;================\u0026amp;#8221;); } }, 1000, 5000, TimeUnit.*MILLISECONDS*); exec.scheduleAtFixedRate(**new** Runnable() {//每隔一段时间打印系统时间，证明两者是互不影响的 @Override **public****void** run() { System.*out*.println(System.*nanoTime*()); } }, 1000, 2000, TimeUnit.*MILLISECONDS*); } }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; 输出结果 \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; ================8384644549516 8386643829034 8388643830710 ================ 8390643851383 8392643879319 8400643939383\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; \u0026amp;nbsp; # \u0026lt;a rel=\u0026quot;nofollow\u0026quot; name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;三：ThreadPoolExecutor详解 ThreadPoolExecutor的完整构造方法的签名是：**ThreadPoolExecutor**`(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue\u0026amp;lt;Runnable\u0026amp;gt; workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)` . **maximumPoolSize**-池中允许的最大线程数。 **ThreadPoolExecutor是Executors类的底层实现。** 在JDK帮助文档中，有如此一段话： “强烈建议程序员使用较为方便的`Executors`工厂方法`Executors.newCachedThreadPool()`（无界线程池，可以进行自动线程回收）、`Executors.newFixedThreadPool(int)`（固定大小线程池）`Executors.newSingleThreadExecutor()`（单个后台线程） 它们均为大多数使用场景预定义了设置。” 下面介绍一下几个类的源码： **ExecutorService newFixedThreadPool (int nThreads):固定大小线程池。** 可以看到，corePoolSize和maximumPoolSize的大小是一样的（实际上，后面会介绍，如果使用无界queue的话maximumPoolSize参数是没有意义的），keepAliveTime和unit的设值表名什么？-就是该实现不想keep alive！最后的BlockingQueue选择了LinkedBlockingQueue，该queue有一个特点，他是无界的。 \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; 1. public static ExecutorService newFixedThreadPool(int nThreads) {2. return new ThreadPoolExecutor(nThreads, nThreads, 3. 0L, TimeUnit.MILLISECONDS, 4. new LinkedBlockingQueue\u0026lt;Runnable\u0026gt;()); 5. }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; **ExecutorService newSingleThreadExecutor()：单线程** \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; 1. public static ExecutorService newSingleThreadExecutor() {2. return new FinalizableDelegatedExecutorService 3. (new ThreadPoolExecutor(1, 1, 4. 0L, TimeUnit.MILLISECONDS, 5. new LinkedBlockingQueue\u0026lt;Runnable\u0026gt;())); 6. }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; **ExecutorService newCachedThreadPool()：无界线程池，可以进行自动线程回收** 这个实现就有意思了。首先是无界的线程池，所以我们可以发现maximumPoolSize为big big。其次BlockingQueue的选择上使用SynchronousQueue。可能对于该BlockingQueue有些陌生，简单说：该QUEUE中，每个插入操作必须等待另一个线程的对应移除操作。 \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; 1. public static ExecutorService newCachedThreadPool() {2. return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 3. 60L, TimeUnit.SECONDS, 4. new SynchronousQueue\u0026lt;Runnable\u0026gt;()); - } \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 先从[BlockingQueue](http://dongxuan.iteye.com/admin/blogs/901659/)\u0026lt;[Runnable](http://dongxuan.iteye.com/admin/blogs/901659/)\u0026gt; workQueue这个入参开始说起。在JDK中，其实已经说得很清楚了，一共有三种类型的queue。 所有BlockingQueue 都可用于传输和保持提交的任务。可以使用此队列与池大小进行交互： 如果运行的线程少于 corePoolSize，则 Executor始终首选添加新的线程，而不进行排队。（如果当前运行的线程小于corePoolSize，则任务根本不会存放，添加到queue中，而是直接抄家伙（thread）开始运行） 如果运行的线程等于或多于 corePoolSize，则 Executor始终首选将请求加入队列，**而不添加新的线程**。 如果无法将请求加入队列，则创建新的线程，除非创建此线程超出 maximumPoolSize，在这种情况下，任务将被拒绝。 **queue上的三种类型。** \u0026amp;nbsp; 排队有三种通用策略： **直接提交。**工作队列的默认选项是 SynchronousQueue，它将任务直接提交给线程而不保持它们。在此，如果不存在可用于立即运行任务的线程，则试图把任务加入队列将失败，因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界maximumPoolSizes 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时，此策略允许无界线程具有增长的可能性。 **无界队列。**使用无界队列（例如，不具有预定义容量的 LinkedBlockingQueue）将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。这样，创建的线程就不会超过 corePoolSize。（因此，maximumPoolSize的值也就无效了。）当每个任务完全独立于其他任务，即任务执行互不影响时，适合于使用无界队列；例如，在 Web页服务器中。这种排队可用于处理瞬态突发请求，当命令以超过队列所能处理的平均数连续到达时，此策略允许无界线程具有增长的可能性。 **有界队列。**当使用有限的 maximumPoolSizes时，有界队列（如 ArrayBlockingQueue）有助于防止资源耗尽，但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷：使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销，但是可能导致人工降低吞吐量。如果任务频繁阻塞（例如，如果它们是 I/O边界），则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小，CPU使用率较高，但是可能遇到不可接受的调度开销，这样也会降低吞吐量。 **BlockingQueue的选择。** **例子一：使用直接提交策略，也即SynchronousQueue。** 首先SynchronousQueue是无界的，也就是说他存数任务的能力是没有限制的，但是由于该Queue本身的特性，**在某次添加元素后必须等待其他线程取走后才能继续添加**。在这里不是核心线程便是新创建的线程，但是我们试想一样下，下面的场景。 我们使用一下参数构造ThreadPoolExecutor： 1. new ThreadPoolExecutor( 2. 2, 3, 30, TimeUnit.SECONDS, 3. new SynchronousQueue\u0026lt;Runnable\u0026gt;(), 4. new RecorderThreadFactory(\u0026amp;#8220;CookieRecorderPool\u0026amp;#8221;), - new ThreadPoolExecutor.CallerRunsPolicy()); new ThreadPoolExecutor( 2, 3, 30, TimeUnit.SECONDS, new SynchronousQueue\u0026lt;Runnable\u0026gt;(), new RecorderThreadFactory(\u0026amp;#8220;CookieRecorderPool\u0026amp;#8221;), new ThreadPoolExecutor.CallerRunsPolicy()); 当核心线程已经有2个正在运行. - 此时继续来了一个任务（A），根据前面介绍的“如果运行的线程等于或多于 corePoolSize，则 Executor始终首选将请求加入队列，**而不添加新的线程**。”,所以A被添加到queue中。 - 又来了一个任务（B），且核心2个线程还没有忙完，OK，接下来首先尝试1中描述，但是由于使用的SynchronousQueue，所以一定无法加入进去。 - 此时便满足了上面提到的“如果无法将请求加入队列，则创建新的线程，除非创建此线程超出maximumPoolSize，在这种情况下，任务将被拒绝。”，所以必然会新建一个线程来运行这个任务。 - 暂时还可以，但是如果这三个任务都还没完成，连续来了两个任务，第一个添加入queue中，后一个呢？queue中无法插入，而线程数达到了maximumPoolSize，所以只好执行异常策略了。 所以在使用SynchronousQueue通常要求maximumPoolSize是无界的，这样就可以避免上述情况发生（如果希望限制就直接使用有界队列）。对于使用SynchronousQueue的作用jdk中写的很清楚：此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。 什么意思？如果你的任务A1，A2有内部关联，A1需要先运行，那么先提交A1，再提交A2，当使用SynchronousQueue我们可以保证，A1必定先被执行，在A1么有被执行前，A2不可能添加入queue中。 **例子二：使用无界队列策略，即LinkedBlockingQueue** 这个就拿**newFixedThreadPool**来说，根据前文提到的规则： 如果运行的线程少于 corePoolSize，则 Executor 始终首选添加新的线程，而不进行排队。那么当任务继续增加，会发生什么呢？ 如果运行的线程等于或多于 corePoolSize，则 Executor 始终首选将请求加入队列，而不添加新的线程。OK，此时任务变加入队列之中了，那什么时候才会添加新线程呢？ 如果无法将请求加入队列，则创建新的线程，除非创建此线程超出 maximumPoolSize，在这种情况下，任务将被拒绝。这里就很有意思了，可能会出现无法加入队列吗？不像SynchronousQueue那样有其自身的特点，对于无界队列来说，总是可以加入的（资源耗尽，当然另当别论）。换句说，永远也不会触发产生新的线程！corePoolSize大小的线程数会一直运行，忙完当前的，就从队列中拿任务开始运行。所以要防止任务疯长，比如任务运行的实行比较长，而添加任务的速度远远超过处理任务的时间，而且还不断增加，不一会儿就爆了。 **例子三：有界队列，使用ArrayBlockingQueue。** 这个是最为复杂的使用，所以JDK不推荐使用也有些道理。与上面的相比，最大的特点便是可以防止资源耗尽的情况发生。 举例来说，请看如下构造方法： 1. new ThreadPoolExecutor( 2. 2, 4, 30, TimeUnit.SECONDS, 3. new ArrayBlockingQueue\u0026lt;Runnable\u0026gt;(2), 4. new RecorderThreadFactory(\u0026amp;#8220;CookieRecorderPool\u0026amp;#8221;), 5. new ThreadPoolExecutor.CallerRunsPolicy()); new ThreadPoolExecutor( 2, 4, 30, TimeUnit.SECONDS, new ArrayBlockingQueue\u0026lt;Runnable\u0026gt;(2), new RecorderThreadFactory(\u0026amp;#8220;CookieRecorderPool\u0026amp;#8221;), new ThreadPoolExecutor.CallerRunsPolicy()); 假设，所有的任务都永远无法执行完。 对于首先来的A,B来说直接运行，接下来，如果来了C,D，他们会被放到queue中，如果接下来再来E,F，则增加线程运行E，F。但是如果再来任务，队列无法再接受了，线程数也到达最大的限制了，所以就会使用拒绝策略来处理。 **keepAliveTime** jdk中的解释是：当线程数大于核心时，此为终止前多余的空闲线程等待新任务的最长时间。 有点拗口，其实这个不难理解，在使用了“池”的应用中，大多都有类似的参数需要配置。比如数据库连接池，DBCP中的maxIdle，minIdle参数。 什么意思？接着上面的解释，后来向老板派来的工人始终是“借来的”，俗话说“有借就有还”，但这里的问题就是什么时候还了，如果借来的工人刚完成一个任务就还回去，后来发现任务还有，那岂不是又要去借？这一来一往，老板肯定头也大死了。 \u0026amp;nbsp; 合理的策略：既然借了，那就多借一会儿。直到“某一段”时间后，发现再也用不到这些工人时，便可以还回去了。这里的某一段时间便是keepAliveTime的含义，TimeUnit为keepAliveTime值的度量。 \u0026amp;nbsp; **RejectedExecutionHandler** 另一种情况便是，即使向老板借了工人，但是任务还是继续过来，还是忙不过来，这时整个队伍只好拒绝接受了。 RejectedExecutionHandler接口提供了对于拒绝任务的处理的自定方法的机会。在ThreadPoolExecutor中已经默认包含了4中策略，因为源码非常简单，这里直接贴出来。 **CallerRunsPolicy**：线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制，能够减缓新任务的提交速度。 1. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { 2. if (!e.isShutdown()) { 3. r.run(); 4. } 5. } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } 这个策略显然不想放弃执行任务。但是由于池中已经没有任何资源了，那么就直接使用调用该execute的线程本身来执行。 **AbortPolicy：**处理程序遭到拒绝将抛出运行时RejectedExecutionException 1. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { 2. throw new RejectedExecutionException(); 3. } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException(); } 这种策略直接抛出异常，丢弃任务。 **DiscardPolicy：**不能执行的任务将被删除 1. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { 2. } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { } 这种策略和AbortPolicy几乎一样，也是丢弃任务，只不过他不抛出异常。 **DiscardOldestPolicy：**如果执行程序尚未关闭，则位于工作队列头部的任务将被删除，然后重试执行程序（如果再次失败，则重复此过程） 1. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { 2. if (!e.isShutdown()) { 3. e.getQueue().poll(); 4. e.execute(r); 5. } - } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } 该策略就稍微复杂一些，在pool没有关闭的前提下首先丢掉缓存在队列中的最早的任务，然后重新尝试运行该任务。这个策略需要适当小心。 设想:如果其他线程都还在运行，那么新来任务踢掉旧任务，缓存在queue中，再来一个任务又会踢掉queue中最老任务。 总结： keepAliveTime和maximumPoolSize及BlockingQueue的类型均有关系。如果BlockingQueue是无界的，那么永远不会触发maximumPoolSize，自然keepAliveTime也就没有了意义。 反之，如果核心数较小，有界BlockingQueue数值又较小，同时keepAliveTime又设的很小，如果任务频繁，那么系统就会频繁的申请回收线程。 \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue\u0026lt;Runnable\u0026gt;()); } ","permalink":"https://blog.zdltech.com/posts/java%E8%87%AA%E5%B8%A6%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%92%8C%E9%98%9F%E5%88%97%E8%AF%A6%E7%BB%86%E8%AE%B2%E8%A7%A3android%E4%B8%AD%E9%80%82%E7%94%A8/","summary":"\u003cdiv class=\"BlogAnchor\"\u003e\n  \u003cdiv id=\"AnchorContent\" class=\"AnchorContent\"\u003e\n\u003cpre\u003e\u003ccode\u003e  - [一简介](http://my.oschina.net/u/1424386/blog/336087#OSC_h1_1)\n  \n  - [二：线程池](http://my.oschina.net/u/1424386/blog/336087#OSC_h1_2)\n  \n  - [三：ThreadPoolExecutor详解](http://my.oschina.net/u/1424386/blog/336087#OSC_h1_3)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"BlogContent\"\u003e\n\u003cpre\u003e\u003ccode\u003e Java线程池使用说明\n\n\n\n\n\n\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch1 id=\"一简介\"\u003e\u003ca rel=\"nofollow\" name=\"t0\"\u003e\u003c/a\u003e一简介\u003c/h1\u003e\n\u003cpre\u003e\u003ccode\u003e线程的使用在java中占有极其重要的地位，在jdk1.4极其之前的jdk版本中，关于线程池的使用是极其简陋的。在jdk1.5之后这一情况有了很大的改观。Jdk1.5之后加入了java.util.concurrent包，这个包中主要介绍java中线程以及线程池的使用。为我们在开发中处理线程的问题提供了非常大的帮助。\n\n\n\n\n\n\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch1 id=\"二线程池\"\u003e\u003ca rel=\"nofollow\" name=\"t1\"\u003e\u003c/a\u003e二：线程池\u003c/h1\u003e\n\u003cpre\u003e\u003ccode\u003e**线程池的作用：**\n\n\n\n\n\n线程池作用就是限制系统中执行线程的数量。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e根据系统的环境情况，可以自动或手动设置线程数量，达到运行的最佳效果；少了浪费了系统资源，多了造成系统拥挤效率不高。用线程池控制线程数量，其他线程排队等候。一个任务执行完毕，再从队列的中取最前面的任务开始执行。若队列中没有等待进程，线程池的这一资源处于等待。当一个新任务需要运行时，如果线程池中有等待的工作线程，就可以开始运行了；否则进入等待队列。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e**为什么要用线程池:**\n\n\n\n\n\n1.减少了创建和销毁线程的次数，每个工作线程都可以被重复利用，可执行多个任务。\n\n\n\n\n\n2.可以根据系统的承受能力，调整线程池中工作线线程的数目，防止因为消耗过多的内存，而把服务器累趴下(每个线程需要大约1MB内存，线程开的越多，消耗的内存也就越大，最后死机)。\n\n\n\n\n\nJava里面线程池的顶级接口是Executor，但是严格意义上讲Executor并不是一个线程池，而只是一个执行线程的工具。真正的线程池接口是ExecutorService。\n\n\n\n\n\n比较重要的几个类：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003ctable border=\"1\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        ExecutorService\n      \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;td\u0026gt;\n    真正的线程池接口。\n  \u0026lt;/td\u0026gt;\n\u0026lt;/tr\u0026gt;\n\n\u0026lt;tr\u0026gt;\n  \u0026lt;td\u0026gt;\n    ScheduledExecutorService\n  \u0026lt;/td\u0026gt;\n  \n  \u0026lt;td\u0026gt;\n    能和Timer/TimerTask类似，解决那些需要任务重复执行的问题。\n  \u0026lt;/td\u0026gt;\n\u0026lt;/tr\u0026gt;\n\n\u0026lt;tr\u0026gt;\n  \u0026lt;td\u0026gt;\n    ThreadPoolExecutor\n  \u0026lt;/td\u0026gt;\n  \n  \u0026lt;td\u0026gt;\n    ExecutorService的默认实现。\n  \u0026lt;/td\u0026gt;\n\u0026lt;/tr\u0026gt;\n\n\u0026lt;tr\u0026gt;\n  \u0026lt;td\u0026gt;\n    ScheduledThreadPoolExecutor\n  \u0026lt;/td\u0026gt;\n  \n  \u0026lt;td\u0026gt;\n    继承ThreadPoolExecutor的ScheduledExecutorService接口实现，周期性任务调度的类实现。\n  \u0026lt;/td\u0026gt;\n\u0026lt;/tr\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/table\u003e\n\u003cpre\u003e\u003ccode\u003e要配置一个线程池是比较复杂的，尤其是对于线程池的原理不是很清楚的情况下，很有可能配置的线程池不是较优的，因此在Executors类里面提供了一些静态工厂，生成一些常用的线程池。\n\n\n\n\n\n**1. newSingleThreadExecutor**\n\n\n\n\n\n创建一个单线程的线程池。这个线程池只有一个线程在工作，也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束，那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。\n\n\n\n\n\n2.**newFixedThreadPool**\n\n\n\n\n\n创建固定大小的线程池。每次提交一个任务就创建一个线程，直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变，如果某个线程因为执行异常而结束，那么线程池会补充一个新线程。\n\n\n\n\n\n**3. newCachedThreadPool**\n\n\n\n\n\n创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程，\n\n\n\n\n\n那么就会回收部分空闲（60秒不执行任务）的线程，当任务数增加时，此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制，线程池大小完全依赖于操作系统（或者说JVM）能够创建的最大线程大小。\n\n\n\n\n\n4.**newScheduledThreadPool**\n\n\n\n\n\n创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。\n\n\n\n\n\n**实例**\n\n\n\n\n\n**1：newSingleThreadExecutor**\n\n\n\n\n\nMyThread.java\n\u003c/code\u003e\u003c/pre\u003e\n  \u003ctable border=\"1\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        **public****class**MyThread **extends** Thread {@Override\n\u003cpre\u003e\u003ccode\u003e      **public****void** run() {\n    \n\n    \n    \n\n      System.*out*.println(Thread.*currentThread*().getName() + \u0026amp;#8220;正在执行。。。\u0026amp;#8221;);\n    \n\n    \n    \n\n      }\n    \n\n    \n    \n\n      }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; \n      \n      \n\n        TestSingleThreadExecutor.java\n      \n\n      \n      \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n        \u0026lt;tr\u0026gt;\n          \u0026lt;td\u0026gt;\n            **public****class**TestSingleThreadExecutor {**public****static****void** main(String[] args) {\n\n            \n            \n\n              //创建一个可重用固定线程数的线程池\n            \n\n            \n            \n\n              ExecutorService pool = Executors.* newSingleThreadExecutor*();\n            \n\n            \n            \n\n              //创建实现了Runnable接口对象，Thread对象当然也实现了Runnable接口\n            \n\n            \n            \n\n              Thread t1 = **new** MyThread();\n            \n\n            \n            \n\n              Thread t2 = **new** MyThread();\n            \n\n            \n            \n\n              Thread t3 = **new** MyThread();\n            \n\n            \n            \n\n              Thread t4 = **new** MyThread();\n            \n\n            \n            \n\n              Thread t5 = **new** MyThread();\n            \n\n            \n            \n\n              //将线程放入池中进行执行\n            \n\n            \n            \n\n              pool.execute(t1);\n            \n\n            \n            \n\n              pool.execute(t2);\n            \n\n            \n            \n\n              pool.execute(t3);\n            \n\n            \n            \n\n              pool.execute(t4);\n            \n\n            \n            \n\n              pool.execute(t5);\n            \n\n            \n            \n\n              //关闭线程池\n            \n\n            \n            \n\n              pool.shutdown();\n            \n\n            \n            \n\n              }\n            \n\n            \n            \n\n              }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; \n              \n              \n\n                **输出结果**\n              \n\n              \n              \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n                \u0026lt;tr\u0026gt;\n                  \u0026lt;td\u0026gt;\n                    pool-1-thread-1正在执行。。。pool-1-thread-1正在执行。。。\n\n                    \n                    \n\n                      pool-1-thread-1正在执行。。。\n                    \n\n                    \n                    \n\n                      pool-1-thread-1正在执行。。。\n                    \n\n                    \n                    \n\n                      pool-1-thread-1正在执行。。。\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; \n                      \n                      \n\n                        **2newFixedThreadPool**\n                      \n\n                      \n                      \n\n                        TestFixedThreadPool.Java\n                      \n\n                      \n                      \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n                        \u0026lt;tr\u0026gt;\n                          \u0026lt;td\u0026gt;\n                            **public****class** TestFixedThreadPool {**public****static****void** main(String[] args) {\n\n                            \n                            \n\n                              //创建一个可重用固定线程数的线程池\n                            \n\n                            \n                            \n\n                              ExecutorService pool = Executors.*newFixedThreadPool*(2);\n                            \n\n                            \n                            \n\n                              //创建实现了Runnable接口对象，Thread对象当然也实现了Runnable接口\n                            \n\n                            \n                            \n\n                              Thread t1 = **new** MyThread();\n                            \n\n                            \n                            \n\n                              Thread t2 = **new** MyThread();\n                            \n\n                            \n                            \n\n                              Thread t3 = **new** MyThread();\n                            \n\n                            \n                            \n\n                              Thread t4 = **new** MyThread();\n                            \n\n                            \n                            \n\n                              Thread t5 = **new** MyThread();\n                            \n\n                            \n                            \n\n                              //将线程放入池中进行执行\n                            \n\n                            \n                            \n\n                              pool.execute(t1);\n                            \n\n                            \n                            \n\n                              pool.execute(t2);\n                            \n\n                            \n                            \n\n                              pool.execute(t3);\n                            \n\n                            \n                            \n\n                              pool.execute(t4);\n                            \n\n                            \n                            \n\n                              pool.execute(t5);\n                            \n\n                            \n                            \n\n                              //关闭线程池\n                            \n\n                            \n                            \n\n                              pool.shutdown();\n                            \n\n                            \n                            \n\n                              }\n                            \n\n                            \n                            \n\n                              }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; \n                              \n                              \n\n                                **输出结果**\n                              \n\n                              \n                              \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n                                \u0026lt;tr\u0026gt;\n                                  \u0026lt;td\u0026gt;\n                                    pool-1-thread-1正在执行。。。pool-1-thread-2正在执行。。。\n\n                                    \n                                    \n\n                                      pool-1-thread-1正在执行。。。\n                                    \n\n                                    \n                                    \n\n                                      pool-1-thread-2正在执行。。。\n                                    \n\n                                    \n                                    \n\n                                      pool-1-thread-1正在执行。。。\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; \n                                      \n                                      \n\n                                        3** newCachedThreadPool**\n                                      \n\n                                      \n                                      \n\n                                        TestCachedThreadPool.java\n                                      \n\n                                      \n                                      \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n                                        \u0026lt;tr\u0026gt;\n                                          \u0026lt;td\u0026gt;\n                                            **public****class** TestCachedThreadPool {**public****static****void** main(String[] args) {\n\n                                            \n                                            \n\n                                              //创建一个可重用固定线程数的线程池\n                                            \n\n                                            \n                                            \n\n                                              ExecutorService pool = Executors.*newCachedThreadPool*();\n                                            \n\n                                            \n                                            \n\n                                              //创建实现了Runnable接口对象，Thread对象当然也实现了Runnable接口\n                                            \n\n                                            \n                                            \n\n                                              Thread t1 = **new** MyThread();\n                                            \n\n                                            \n                                            \n\n                                              Thread t2 = **new** MyThread();\n                                            \n\n                                            \n                                            \n\n                                              Thread t3 = **new** MyThread();\n                                            \n\n                                            \n                                            \n\n                                              Thread t4 = **new** MyThread();\n                                            \n\n                                            \n                                            \n\n                                              Thread t5 = **new** MyThread();\n                                            \n\n                                            \n                                            \n\n                                              //将线程放入池中进行执行\n                                            \n\n                                            \n                                            \n\n                                              pool.execute(t1);\n                                            \n\n                                            \n                                            \n\n                                              pool.execute(t2);\n                                            \n\n                                            \n                                            \n\n                                              pool.execute(t3);\n                                            \n\n                                            \n                                            \n\n                                              pool.execute(t4);\n                                            \n\n                                            \n                                            \n\n                                              pool.execute(t5);\n                                            \n\n                                            \n                                            \n\n                                              //关闭线程池\n                                            \n\n                                            \n                                            \n\n                                              pool.shutdown();\n                                            \n\n                                            \n                                            \n\n                                              }\n                                            \n\n                                            \n                                            \n\n                                              }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; \n                                              \n                                              \n\n                                                输出结果：\n                                              \n\n                                              \n                                              \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n                                                \u0026lt;tr\u0026gt;\n                                                  \u0026lt;td\u0026gt;\n                                                    pool-1-thread-2正在执行。。。pool-1-thread-4正在执行。。。\n\n                                                    \n                                                    \n\n                                                      pool-1-thread-3正在执行。。。\n                                                    \n\n                                                    \n                                                    \n\n                                                      pool-1-thread-1正在执行。。。\n                                                    \n\n                                                    \n                                                    \n\n                                                      pool-1-thread-5正在执行。。。\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; \n                                                      \n                                                      \n\n                                                        4**newScheduledThreadPool**\n                                                      \n\n                                                      \n                                                      \n\n                                                        TestScheduledThreadPoolExecutor.java\n                                                      \n\n                                                      \n                                                      \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n                                                        \u0026lt;tr\u0026gt;\n                                                          \u0026lt;td\u0026gt;\n                                                            **public****class** TestScheduledThreadPoolExecutor {**public****static****void** main(String[] args) {\n\n                                                            \n                                                            \n\n                                                              ScheduledThreadPoolExecutor exec = **new** ScheduledThreadPoolExecutor(1);\n                                                            \n\n                                                            \n                                                            \n\n                                                              exec.scheduleAtFixedRate(**new** Runnable() {//每隔一段时间就触发异常\n                                                            \n\n                                                            \n                                                            \n\n                                                              @Override\n                                                            \n\n                                                            \n                                                            \n\n                                                              **public****void** run() {\n                                                            \n\n                                                            \n                                                            \n\n                                                              //throw new RuntimeException();\n                                                            \n\n                                                            \n                                                            \n\n                                                              System.*out*.println(\u0026amp;#8220;================\u0026amp;#8221;);\n                                                            \n\n                                                            \n                                                            \n\n                                                              }\n                                                            \n\n                                                            \n                                                            \n\n                                                              }, 1000, 5000, TimeUnit.*MILLISECONDS*);\n                                                            \n\n                                                            \n                                                            \n\n                                                              exec.scheduleAtFixedRate(**new** Runnable() {//每隔一段时间打印系统时间，证明两者是互不影响的\n                                                            \n\n                                                            \n                                                            \n\n                                                              @Override\n                                                            \n\n                                                            \n                                                            \n\n                                                              **public****void** run() {\n                                                            \n\n                                                            \n                                                            \n\n                                                              System.*out*.println(System.*nanoTime*());\n                                                            \n\n                                                            \n                                                            \n\n                                                              }\n                                                            \n\n                                                            \n                                                            \n\n                                                              }, 1000, 2000, TimeUnit.*MILLISECONDS*);\n                                                            \n\n                                                            \n                                                            \n\n                                                              }\n                                                            \n\n                                                            \n                                                            \n\n                                                              }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; \n                                                              \n                                                              \n\n                                                                输出结果\n                                                              \n\n                                                              \n                                                              \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n                                                                \u0026lt;tr\u0026gt;\n                                                                  \u0026lt;td\u0026gt;\n                                                                    ================8384644549516\n\n                                                                    \n                                                                    \n\n                                                                      8386643829034\n                                                                    \n\n                                                                    \n                                                                    \n\n                                                                      8388643830710\n                                                                    \n\n                                                                    \n                                                                    \n\n                                                                      ================\n                                                                    \n\n                                                                    \n                                                                    \n\n                                                                      8390643851383\n                                                                    \n\n                                                                    \n                                                                    \n\n                                                                      8392643879319\n                                                                    \n\n                                                                    \n                                                                    \n\n                                                                      8400643939383\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; \n                                                                      \n                                                                      \n\n                                                                        \u0026amp;nbsp;\n                                                                      \n\n                                                                      \n                                                                      # \u0026lt;a rel=\u0026quot;nofollow\u0026quot; name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;三：ThreadPoolExecutor详解\n                                                                      \n                                                                      \n\n                                                                        ThreadPoolExecutor的完整构造方法的签名是：**ThreadPoolExecutor**`(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue\u0026amp;lt;Runnable\u0026amp;gt; workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)` .\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                        **maximumPoolSize**-池中允许的最大线程数。\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                        **ThreadPoolExecutor是Executors类的底层实现。**\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                        在JDK帮助文档中，有如此一段话：\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                        “强烈建议程序员使用较为方便的`Executors`工厂方法`Executors.newCachedThreadPool()`（无界线程池，可以进行自动线程回收）、`Executors.newFixedThreadPool(int)`（固定大小线程池）`Executors.newSingleThreadExecutor()`（单个后台线程）\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                        它们均为大多数使用场景预定义了设置。”\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                        下面介绍一下几个类的源码：\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                        **ExecutorService  newFixedThreadPool (int nThreads):固定大小线程池。**\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                        可以看到，corePoolSize和maximumPoolSize的大小是一样的（实际上，后面会介绍，如果使用无界queue的话maximumPoolSize参数是没有意义的），keepAliveTime和unit的设值表名什么？-就是该实现不想keep alive！最后的BlockingQueue选择了LinkedBlockingQueue，该queue有一个特点，他是无界的。\n                                                                      \n\n                                                                      \n                                                                      \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n                                                                        \u0026lt;tr\u0026gt;\n                                                                          \u0026lt;td\u0026gt;\n                                                                            1.     public static ExecutorService newFixedThreadPool(int nThreads) {2.             return new ThreadPoolExecutor(nThreads, nThreads,\n\n                                                                            \n                                                                            \n\n                                                                              3.                                           0L, TimeUnit.MILLISECONDS,\n                                                                            \n\n                                                                            \n                                                                            \n\n                                                                              4.                                           new LinkedBlockingQueue\u0026lt;Runnable\u0026gt;());\n                                                                            \n\n                                                                            \n                                                                            \n\n                                                                              5.         }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; \n                                                                              \n                                                                              \n\n                                                                                **ExecutorService  newSingleThreadExecutor()：单线程**\n                                                                              \n\n                                                                              \n                                                                              \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n                                                                                \u0026lt;tr\u0026gt;\n                                                                                  \u0026lt;td\u0026gt;\n                                                                                    1.     public static ExecutorService newSingleThreadExecutor() {2.             return new FinalizableDelegatedExecutorService\n\n                                                                                    \n                                                                                    \n\n                                                                                      3.                 (new ThreadPoolExecutor(1, 1,\n                                                                                    \n\n                                                                                    \n                                                                                    \n\n                                                                                      4.                                         0L, TimeUnit.MILLISECONDS,\n                                                                                    \n\n                                                                                    \n                                                                                    \n\n                                                                                      5.                                         new LinkedBlockingQueue\u0026lt;Runnable\u0026gt;()));\n                                                                                    \n\n                                                                                    \n                                                                                    \n\n                                                                                      6.         }\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; \n                                                                                      \n                                                                                      \n\n                                                                                        **ExecutorService newCachedThreadPool()：无界线程池，可以进行自动线程回收**\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        这个实现就有意思了。首先是无界的线程池，所以我们可以发现maximumPoolSize为big big。其次BlockingQueue的选择上使用SynchronousQueue。可能对于该BlockingQueue有些陌生，简单说：该QUEUE中，每个插入操作必须等待另一个线程的对应移除操作。\n                                                                                      \n\n                                                                                      \n                                                                                      \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n                                                                                        \u0026lt;tr\u0026gt;\n                                                                                          \u0026lt;td\u0026gt;\n                                                                                            1.     public static ExecutorService newCachedThreadPool() {2.             return new ThreadPoolExecutor(0, Integer.MAX_VALUE,\n\n                                                                                            \n                                                                                            \n\n                                                                                              3.                                           60L, TimeUnit.SECONDS,\n                                                                                            \n\n                                                                                            \n                                                                                            \n\n                                                                                              4.                                           new SynchronousQueue\u0026lt;Runnable\u0026gt;());\n                                                                                            \n\n                                                                                            \n                                                                                            \n                                                                                              - }\n                                                                                              \n                                                                                            \n                                                                                          \u0026lt;/td\u0026gt;\n                                                                                        \u0026lt;/tr\u0026gt;\n                                                                                      \u0026lt;/table\u0026gt;\n                                                                                      \n                                                                                      \n\n                                                                                        先从[BlockingQueue](http://dongxuan.iteye.com/admin/blogs/901659/)\u0026lt;[Runnable](http://dongxuan.iteye.com/admin/blogs/901659/)\u0026gt; workQueue这个入参开始说起。在JDK中，其实已经说得很清楚了，一共有三种类型的queue。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        所有BlockingQueue 都可用于传输和保持提交的任务。可以使用此队列与池大小进行交互：\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        如果运行的线程少于 corePoolSize，则 Executor始终首选添加新的线程，而不进行排队。（如果当前运行的线程小于corePoolSize，则任务根本不会存放，添加到queue中，而是直接抄家伙（thread）开始运行）\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        如果运行的线程等于或多于 corePoolSize，则 Executor始终首选将请求加入队列，**而不添加新的线程**。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        如果无法将请求加入队列，则创建新的线程，除非创建此线程超出 maximumPoolSize，在这种情况下，任务将被拒绝。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **queue上的三种类型。**\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        \u0026amp;nbsp;\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        排队有三种通用策略：\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **直接提交。**工作队列的默认选项是 SynchronousQueue，它将任务直接提交给线程而不保持它们。在此，如果不存在可用于立即运行任务的线程，则试图把任务加入队列将失败，因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界maximumPoolSizes 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时，此策略允许无界线程具有增长的可能性。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **无界队列。**使用无界队列（例如，不具有预定义容量的 LinkedBlockingQueue）将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。这样，创建的线程就不会超过 corePoolSize。（因此，maximumPoolSize的值也就无效了。）当每个任务完全独立于其他任务，即任务执行互不影响时，适合于使用无界队列；例如，在 Web页服务器中。这种排队可用于处理瞬态突发请求，当命令以超过队列所能处理的平均数连续到达时，此策略允许无界线程具有增长的可能性。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **有界队列。**当使用有限的 maximumPoolSizes时，有界队列（如 ArrayBlockingQueue）有助于防止资源耗尽，但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷：使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销，但是可能导致人工降低吞吐量。如果任务频繁阻塞（例如，如果它们是 I/O边界），则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小，CPU使用率较高，但是可能遇到不可接受的调度开销，这样也会降低吞吐量。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **BlockingQueue的选择。**\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **例子一：使用直接提交策略，也即SynchronousQueue。**\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        首先SynchronousQueue是无界的，也就是说他存数任务的能力是没有限制的，但是由于该Queue本身的特性，**在某次添加元素后必须等待其他线程取走后才能继续添加**。在这里不是核心线程便是新创建的线程，但是我们试想一样下，下面的场景。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        我们使用一下参数构造ThreadPoolExecutor：\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        1.     new ThreadPoolExecutor(\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        2.                 2, 3, 30, TimeUnit.SECONDS,\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        3.                 new  SynchronousQueue\u0026lt;Runnable\u0026gt;(),\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        4.                 new RecorderThreadFactory(\u0026amp;#8220;CookieRecorderPool\u0026amp;#8221;),\n                                                                                      \n\n                                                                                      \n                                                                                      \n                                                                                        - new ThreadPoolExecutor.CallerRunsPolicy());\n                                                                                        \n                                                                                      \n                                                                                      \n                                                                                      \n\n                                                                                        new ThreadPoolExecutor(\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        2, 3, 30, TimeUnit.SECONDS,\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        new SynchronousQueue\u0026lt;Runnable\u0026gt;(),\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        new RecorderThreadFactory(\u0026amp;#8220;CookieRecorderPool\u0026amp;#8221;),\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        new ThreadPoolExecutor.CallerRunsPolicy());\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        当核心线程已经有2个正在运行.\n                                                                                      \n\n                                                                                      \n                                                                                      \n                                                                                        - 此时继续来了一个任务（A），根据前面介绍的“如果运行的线程等于或多于 corePoolSize，则 Executor始终首选将请求加入队列，**而不添加新的线程**。”,所以A被添加到queue中。\n                                                                                        \n                                                                                        - 又来了一个任务（B），且核心2个线程还没有忙完，OK，接下来首先尝试1中描述，但是由于使用的SynchronousQueue，所以一定无法加入进去。\n                                                                                        \n                                                                                        - 此时便满足了上面提到的“如果无法将请求加入队列，则创建新的线程，除非创建此线程超出maximumPoolSize，在这种情况下，任务将被拒绝。”，所以必然会新建一个线程来运行这个任务。\n                                                                                        \n                                                                                        - 暂时还可以，但是如果这三个任务都还没完成，连续来了两个任务，第一个添加入queue中，后一个呢？queue中无法插入，而线程数达到了maximumPoolSize，所以只好执行异常策略了。\n                                                                                        \n                                                                                      \n                                                                                      \n                                                                                      \n\n                                                                                        所以在使用SynchronousQueue通常要求maximumPoolSize是无界的，这样就可以避免上述情况发生（如果希望限制就直接使用有界队列）。对于使用SynchronousQueue的作用jdk中写的很清楚：此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        什么意思？如果你的任务A1，A2有内部关联，A1需要先运行，那么先提交A1，再提交A2，当使用SynchronousQueue我们可以保证，A1必定先被执行，在A1么有被执行前，A2不可能添加入queue中。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **例子二：使用无界队列策略，即LinkedBlockingQueue**\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        这个就拿**newFixedThreadPool**来说，根据前文提到的规则：\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        如果运行的线程少于 corePoolSize，则 Executor 始终首选添加新的线程，而不进行排队。那么当任务继续增加，会发生什么呢？\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        如果运行的线程等于或多于 corePoolSize，则 Executor 始终首选将请求加入队列，而不添加新的线程。OK，此时任务变加入队列之中了，那什么时候才会添加新线程呢？\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        如果无法将请求加入队列，则创建新的线程，除非创建此线程超出 maximumPoolSize，在这种情况下，任务将被拒绝。这里就很有意思了，可能会出现无法加入队列吗？不像SynchronousQueue那样有其自身的特点，对于无界队列来说，总是可以加入的（资源耗尽，当然另当别论）。换句说，永远也不会触发产生新的线程！corePoolSize大小的线程数会一直运行，忙完当前的，就从队列中拿任务开始运行。所以要防止任务疯长，比如任务运行的实行比较长，而添加任务的速度远远超过处理任务的时间，而且还不断增加，不一会儿就爆了。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **例子三：有界队列，使用ArrayBlockingQueue。**\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        这个是最为复杂的使用，所以JDK不推荐使用也有些道理。与上面的相比，最大的特点便是可以防止资源耗尽的情况发生。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        举例来说，请看如下构造方法：\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        1.     new ThreadPoolExecutor(\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        2.                 2, 4, 30, TimeUnit.SECONDS,\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        3.                 new ArrayBlockingQueue\u0026lt;Runnable\u0026gt;(2),\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        4.                 new RecorderThreadFactory(\u0026amp;#8220;CookieRecorderPool\u0026amp;#8221;),\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        5.                 new ThreadPoolExecutor.CallerRunsPolicy());\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        new ThreadPoolExecutor(\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        2, 4, 30, TimeUnit.SECONDS,\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        new ArrayBlockingQueue\u0026lt;Runnable\u0026gt;(2),\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        new RecorderThreadFactory(\u0026amp;#8220;CookieRecorderPool\u0026amp;#8221;),\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        new ThreadPoolExecutor.CallerRunsPolicy());\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        假设，所有的任务都永远无法执行完。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        对于首先来的A,B来说直接运行，接下来，如果来了C,D，他们会被放到queue中，如果接下来再来E,F，则增加线程运行E，F。但是如果再来任务，队列无法再接受了，线程数也到达最大的限制了，所以就会使用拒绝策略来处理。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **keepAliveTime**\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        jdk中的解释是：当线程数大于核心时，此为终止前多余的空闲线程等待新任务的最长时间。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        有点拗口，其实这个不难理解，在使用了“池”的应用中，大多都有类似的参数需要配置。比如数据库连接池，DBCP中的maxIdle，minIdle参数。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        什么意思？接着上面的解释，后来向老板派来的工人始终是“借来的”，俗话说“有借就有还”，但这里的问题就是什么时候还了，如果借来的工人刚完成一个任务就还回去，后来发现任务还有，那岂不是又要去借？这一来一往，老板肯定头也大死了。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        \u0026amp;nbsp;\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        合理的策略：既然借了，那就多借一会儿。直到“某一段”时间后，发现再也用不到这些工人时，便可以还回去了。这里的某一段时间便是keepAliveTime的含义，TimeUnit为keepAliveTime值的度量。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        \u0026amp;nbsp;\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **RejectedExecutionHandler**\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        另一种情况便是，即使向老板借了工人，但是任务还是继续过来，还是忙不过来，这时整个队伍只好拒绝接受了。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        RejectedExecutionHandler接口提供了对于拒绝任务的处理的自定方法的机会。在ThreadPoolExecutor中已经默认包含了4中策略，因为源码非常简单，这里直接贴出来。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **CallerRunsPolicy**：线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制，能够减缓新任务的提交速度。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        1.     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        2.                 if (!e.isShutdown()) {\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        3.                     r.run();\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        4.                 }\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        5.             }\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        if (!e.isShutdown()) {\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        r.run();\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        }\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        }\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        这个策略显然不想放弃执行任务。但是由于池中已经没有任何资源了，那么就直接使用调用该execute的线程本身来执行。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **AbortPolicy：**处理程序遭到拒绝将抛出运行时RejectedExecutionException\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        1.     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        2.                 throw new RejectedExecutionException();\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        3.             }\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        throw new RejectedExecutionException();\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        }\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        这种策略直接抛出异常，丢弃任务。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **DiscardPolicy：**不能执行的任务将被删除\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        1.     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        2.             }\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        }\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        这种策略和AbortPolicy几乎一样，也是丢弃任务，只不过他不抛出异常。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        **DiscardOldestPolicy：**如果执行程序尚未关闭，则位于工作队列头部的任务将被删除，然后重试执行程序（如果再次失败，则重复此过程）\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        1.     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        2.                 if (!e.isShutdown()) {\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        3.                     e.getQueue().poll();\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        4.                     e.execute(r);\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        5.                 }\n                                                                                      \n\n                                                                                      \n                                                                                      \n                                                                                        - }\n                                                                                        \n                                                                                      \n                                                                                      \n                                                                                      \n\n                                                                                        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        if (!e.isShutdown()) {\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        e.getQueue().poll();\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        e.execute(r);\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        }\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        }\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        该策略就稍微复杂一些，在pool没有关闭的前提下首先丢掉缓存在队列中的最早的任务，然后重新尝试运行该任务。这个策略需要适当小心。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        设想:如果其他线程都还在运行，那么新来任务踢掉旧任务，缓存在queue中，再来一个任务又会踢掉queue中最老任务。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        总结：\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        keepAliveTime和maximumPoolSize及BlockingQueue的类型均有关系。如果BlockingQueue是无界的，那么永远不会触发maximumPoolSize，自然keepAliveTime也就没有了意义。\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        反之，如果核心数较小，有界BlockingQueue数值又较小，同时keepAliveTime又设的很小，如果任务频繁，那么系统就会频繁的申请回收线程。\n                                                                                      \n\n                                                                                      \n                                                                                      \u0026lt;table border=\u0026quot;1\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n                                                                                        \u0026lt;tr\u0026gt;\n                                                                                          \u0026lt;td\u0026gt;\n                                                                                          \u0026lt;/td\u0026gt;\n                                                                                        \u0026lt;/tr\u0026gt;\n                                                                                      \u0026lt;/table\u0026gt;\n                                                                                      \n                                                                                      \n\n                                                                                        public static ExecutorService newFixedThreadPool(int nThreads) {\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        return new ThreadPoolExecutor(nThreads, nThreads,\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        0L, TimeUnit.MILLISECONDS,\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        new LinkedBlockingQueue\u0026lt;Runnable\u0026gt;());\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"java自带线程池和队列详细讲解，android中适用"},{"content":"前言 原 来的Android SDK中并没有下拉刷新组件，但是这个组件确实绝大多数APP必备的一个部件。好在google在v4包中出了一个 SwipeRefreshLayout，但是这个组件只支持下拉刷新，不支持上拉加载更多的操作。因此，我们就来简单的扩展一下这个组件以实现上拉下载的 目的。 基本原理 上 拉加载或者说滚动到底部时自动加载，都是通过判断是否滚动到了ListView或者其他View的底部，然后触发相应的操作，这里我们以ListView 来说明。因此我们需要在监听ListView的滚动事件,当ListView滚动到底部时自动触发加载操作；但是当用户支持手指滑动屏幕，没有滚动时，我 们也需要让它加载，因此这种情形就是上拉加载更多。所以我们需要在触摸事件里面进行判断，如果到了底部，且用户是上拉操作，那么执行加载更多。更多关于下 拉刷新、上拉加载请参考[打造通用的Android下拉刷新组件(适用于ListView、GridView等各类View)](http://blog.csdn.net/bboyfeiyu/article/details/39718861)。 时间有限，直接上代码吧。 实现代码 **[java]** [view plain](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[copy](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/503362)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/503362/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 继承自SwipeRefreshLayout,从而实现滑动到底部时上拉加载更多的功能.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author mrsimple\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; RefreshLayout \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; SwipeRefreshLayout \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnScrollListener { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 滑动到最下面时的上拉操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mTouchSlop; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * listview实例\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ListView mListView; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 上拉监听器, 到了最底部的上拉加载操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnLoadListener mOnLoadListener; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * ListView的加载中footer\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View mListViewFooter; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 按下时的y坐标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mYDown; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 抬起时的y坐标, 与mYDown一起用于滑动到底部时判断是上拉还是下拉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mLastY; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 是否在加载中 ( 上拉加载更多 )\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isLoading = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; RefreshLayout(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; RefreshLayout(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - - mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); - - mListViewFooter = LayoutInflater.from(context).inflate(R.layout.listview_footer, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; left, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; top, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; right, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bottom) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onLayout(changed, left, top, right, bottom); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始化ListView对象\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mListView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - getListView(); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 获取ListView对象\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; getListView() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childs = getChildCount(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (childs \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - View childView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (childView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;instanceof\u0026lt;/span\u0026gt; ListView) { - mListView = (ListView) childView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置滚动监听器给ListView, 使得滚动的情况下也可以自动加载\u0026lt;/span\u0026gt; - mListView.setOnScrollListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - Log.d(VIEW_LOG_TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;### 找到listview\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * (non-Javadoc)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent event) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; action = event.getAction(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (action) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 按下\u0026lt;/span\u0026gt; - mYDown = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getRawY(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 移动\u0026lt;/span\u0026gt; - mLastY = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getRawY(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 抬起\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (canLoad()) { - loadData(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(event); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 是否可以加载更多, 条件是到了最底部, listview不在加载中, 且为上拉操作.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canLoad() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; isBottom() \u0026amp;\u0026amp; !isLoading \u0026amp;\u0026amp; isPullUp(); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 判断是否到了最底部\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isBottom() { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mListView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mListView.getAdapter() != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mListView.getLastVisiblePosition() == (mListView.getAdapter().getCount() \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 是否是上拉操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isPullUp() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (mYDown \u0026amp;#8211; mLastY) \u0026gt;= mTouchSlop; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 如果到了最底部,而且是上拉操作.那么执行onLoad方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; loadData() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mOnLoadListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置状态\u0026lt;/span\u0026gt; - setLoading(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt; - mOnLoadListener.onLoad(); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param loading\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setLoading(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; loading) { - isLoading = loading; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isLoading) { - mListView.addFooterView(mListViewFooter); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - mListView.removeFooterView(mListViewFooter); - mYDown = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - mLastY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param loadListener\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnLoadListener(OnLoadListener loadListener) { - mOnLoadListener = loadListener; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onScrollStateChanged(AbsListView view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollState) { - - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onScroll(AbsListView view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; firstVisibleItem, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; visibleItemCount, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; totalItemCount) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滚动时到了最底部也可以加载更多\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (canLoad()) { - loadData(); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 加载更多的监听器\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author mrsimple\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnLoadListener { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLoad(); - } - } listview_footer.xml: **[html]** [view plain](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[copy](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/503362)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/503362/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@color/umeng_comm_comments_bg\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;8dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ProgressBar\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/pull_to_refresh_load_progress\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Widget.ProgressBar.Small.Inverse\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerHorizontal\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;100dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:indeterminate\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/pull_to_refresh_loadmore_text\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@string/load\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textAppearance\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;?android:attr/textAppearanceMedium\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/darker_gray\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;14sp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textStyle\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;bold\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 使用示例 refresh.xml布局文件： **[html]** [view plain](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[copy](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/503362)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/503362/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;myview.RefreshLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/swipe_layout\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ListView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/listview\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ListView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;myview.RefreshLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; activity中的使用 : **[java]** [view plain](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[copy](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/503362)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/503362/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author mrsimple\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - - setContentView(R.layout.refresh); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 模拟一些数据\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; List\u0026lt;String\u0026gt; datas = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;String\u0026gt;(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;; i++) { - datas.add(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;item \u0026amp;#8211; \u0026amp;#8220;\u0026lt;/span\u0026gt; + i); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 构造适配器\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; BaseAdapter adapter = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayAdapter\u0026lt;String\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, - android.R.layout.simple_list_item_1, - datas); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获取listview实例\u0026lt;/span\u0026gt; - ListView listView = (ListView) findViewById(R.id.listview); - listView.setAdapter(adapter); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获取RefreshLayout实例\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; RefreshLayout myRefreshListView = (RefreshLayout) - findViewById(R.id.swipe_layout); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置下拉刷新时的颜色值,颜色值需要定义在xml中\u0026lt;/span\u0026gt; - myRefreshListView - .setColorScheme(R.color.umeng_comm_text_topic_light_color, - R.color.umeng_comm_yellow, R.color.umeng_comm_green, - R.color.umeng_comm_linked_text); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置下拉刷新监听器\u0026lt;/span\u0026gt; - myRefreshListView.setOnRefreshListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnRefreshListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onRefresh() { - - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;refresh\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - - myRefreshListView.postDelayed(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 更新数据\u0026lt;/span\u0026gt; - datas.add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Date().toGMTString()); - adapter.notifyDataSetChanged(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 更新完后调用该方法结束刷新\u0026lt;/span\u0026gt; - myRefreshListView.setRefreshing(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); - } - }, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); - } - }); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载监听器\u0026lt;/span\u0026gt; - myRefreshListView.setOnLoadListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnLoadListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLoad() { - - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;load\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - - myRefreshListView.postDelayed(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - datas.add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Date().toGMTString()); - adapter.notifyDataSetChanged(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载完后调用该方法\u0026lt;/span\u0026gt; - myRefreshListView.setLoading(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); - } - }, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1500\u0026lt;/span\u0026gt;); - - } - }); - } - - } 效果图 ![](http://img.blog.csdn.net/20141009181845718) github链接 : [下拉刷新库](https://github.com/bboyfeiyu/android_my_pull_refresh_view) 。 示例在android_my_pull_demo工程中，进入demo后点击最后一个按钮查看效果即可。注意，在刷新和加载时，需要有一定的延时才能看到效果，这里我们用postDelay来模拟网络请求等延时操作，否则将看不到加载效果。 ","permalink":"https://blog.zdltech.com/posts/%E8%AE%A9android-support-v4%E4%B8%AD%E7%9A%84swiperefreshlayout%E6%94%AF%E6%8C%81%E4%B8%8A%E6%8B%89%E5%8A%A0%E8%BD%BD%E6%9B%B4%E5%A4%9A/","summary":"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cdiv\u003e\n  原 来的Android SDK中并没有下拉刷新组件，但是这个组件确实绝大多数APP必备的一个部件。好在google在v4包中出了一个 SwipeRefreshLayout，但是这个组件只支持下拉刷新，不支持上拉加载更多的操作。因此，我们就来简单的扩展一下这个组件以实现上拉下载的 目的。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch2 id=\"基本原理\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e基本原理\u003c/h2\u003e\n\u003cdiv\u003e\n  上 拉加载或者说滚动到底部时自动加载，都是通过判断是否滚动到了ListView或者其他View的底部，然后触发相应的操作，这里我们以ListView 来说明。因此我们需要在监听ListView的滚动事件,当ListView滚动到底部时自动触发加载操作；但是当用户支持手指滑动屏幕，没有滚动时，我 们也需要让它加载，因此这种情形就是上拉加载更多。所以我们需要在触摸事件里面进行判断，如果到了底部，且用户是上拉操作，那么执行加载更多。更多关于下 拉刷新、上拉加载请参考[打造通用的Android下拉刷新组件(适用于ListView、GridView等各类View)](http://blog.csdn.net/bboyfeiyu/article/details/39718861)。\n\u003c/div\u003e\n\u003cdiv\u003e\n  时间有限，直接上代码吧。\n\u003c/div\u003e\n\u003ch2 id=\"实现代码\"\u003e\u003ca name=\"t2\"\u003e\u003c/a\u003e实现代码\u003c/h2\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[copy](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/503362)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/503362/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n      \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n      \u0026lt;/embed\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 继承自SwipeRefreshLayout,从而实现滑动到底部时上拉加载更多的功能.\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author mrsimple\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; RefreshLayout \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; SwipeRefreshLayout \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnScrollListener {\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 滑动到最下面时的上拉操作\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mTouchSlop;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * listview实例\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ListView mListView;\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 上拉监听器, 到了最底部的上拉加载操作\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnLoadListener mOnLoadListener;\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * ListView的加载中footer\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View mListViewFooter;\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 按下时的y坐标\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mYDown;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 抬起时的y坐标, 与mYDown一起用于滑动到底部时判断是上拉还是下拉\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mLastY;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 是否在加载中 ( 上拉加载更多 )\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isLoading = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param context\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; RefreshLayout(Context context) {\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;);\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; RefreshLayout(Context context, AttributeSet attrs) {\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);\n  \n  - \n  - mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();\n  \n  - \n  - mListViewFooter = LayoutInflater.from(context).inflate(R.layout.listview_footer, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;,\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;);\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; left, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; top, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; right, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bottom) {\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onLayout(changed, left, top, right, bottom);\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始化ListView对象\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mListView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n  \n  - getListView();\n  \n  - }\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 获取ListView对象\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; getListView() {\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childs = getChildCount();\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (childs \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {\n  \n  - View childView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (childView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;instanceof\u0026lt;/span\u0026gt; ListView) {\n  \n  - mListView = (ListView) childView;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置滚动监听器给ListView, 使得滚动的情况下也可以自动加载\u0026lt;/span\u0026gt;\n  \n  - mListView.setOnScrollListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);\n  \n  - Log.d(VIEW_LOG_TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;### 找到listview\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n  \n  - }\n  \n  - }\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * (non-Javadoc)\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent)\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent event) {\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; action = event.getAction();\n  \n  - \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (action) {\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN:\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 按下\u0026lt;/span\u0026gt;\n  \n  - mYDown = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getRawY();\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n  \n  - \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE:\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 移动\u0026lt;/span\u0026gt;\n  \n  - mLastY = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getRawY();\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n  \n  - \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP:\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 抬起\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (canLoad()) {\n  \n  - loadData();\n  \n  - }\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;:\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(event);\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 是否可以加载更多, 条件是到了最底部, listview不在加载中, 且为上拉操作.\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canLoad() {\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; isBottom() \u0026amp;\u0026amp; !isLoading \u0026amp;\u0026amp; isPullUp();\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 判断是否到了最底部\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isBottom() {\n  \n  - \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mListView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mListView.getAdapter() != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mListView.getLastVisiblePosition() == (mListView.getAdapter().getCount() \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);\n  \n  - }\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 是否是上拉操作\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isPullUp() {\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (mYDown \u0026amp;#8211; mLastY) \u0026gt;= mTouchSlop;\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 如果到了最底部,而且是上拉操作.那么执行onLoad方法\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; loadData() {\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mOnLoadListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置状态\u0026lt;/span\u0026gt;\n  \n  - setLoading(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt;\n  \n  - mOnLoadListener.onLoad();\n  \n  - }\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param loading\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setLoading(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; loading) {\n  \n  - isLoading = loading;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isLoading) {\n  \n  - mListView.addFooterView(mListViewFooter);\n  \n  - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n  \n  - mListView.removeFooterView(mListViewFooter);\n  \n  - mYDown = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n  \n  - mLastY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n  \n  - }\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param loadListener\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnLoadListener(OnLoadListener loadListener) {\n  \n  - mOnLoadListener = loadListener;\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onScrollStateChanged(AbsListView view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollState) {\n  \n  - \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onScroll(AbsListView view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; firstVisibleItem, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; visibleItemCount,\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; totalItemCount) {\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滚动时到了最底部也可以加载更多\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (canLoad()) {\n  \n  - loadData();\n  \n  - }\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 加载更多的监听器\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @author mrsimple\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnLoadListener {\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLoad();\n  \n  - }\n  \n  - }\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  listview_footer.xml:\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[copy](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/503362)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/503362/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n      \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n      \u0026lt;/embed\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@color/umeng_comm_comments_bg\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;8dip\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n  \n  - \n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ProgressBar\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/pull_to_refresh_load_progress\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Widget.ProgressBar.Small.Inverse\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerHorizontal\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;100dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:indeterminate\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n  \n  - \n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/pull_to_refresh_loadmore_text\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dip\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@string/load\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textAppearance\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;?android:attr/textAppearanceMedium\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/darker_gray\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;14sp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textStyle\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;bold\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n  \n  - \n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003ch2 id=\"使用示例\"\u003e\u003ca name=\"t3\"\u003e\u003c/a\u003e使用示例\u003c/h2\u003e\n\u003cdiv\u003e\n  refresh.xml布局文件：\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[copy](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/503362)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/503362/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n      \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt;\n      \u0026lt;/embed\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;myview.RefreshLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/swipe_layout\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n  \n  - \n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ListView\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/listview\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ListView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n  \n  - \n  - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;myview.RefreshLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003eactivity中的使用 :\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[copy](http://blog.csdn.net/bboyfeiyu/article/details/39935329#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/503362)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/503362/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n      \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt;\n      \u0026lt;/embed\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author mrsimple\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity {\n  \n  - \n  - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) {\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);\n  \n  - \n  - setContentView(R.layout.refresh);\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 模拟一些数据\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; List\u0026lt;String\u0026gt; datas = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;String\u0026gt;();\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;; i++) {\n  \n  - datas.add(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;item \u0026amp;#8211; \u0026amp;#8220;\u0026lt;/span\u0026gt; + i);\n  \n  - }\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 构造适配器\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; BaseAdapter adapter = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayAdapter\u0026lt;String\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;,\n  \n  - android.R.layout.simple_list_item_1,\n  \n  - datas);\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获取listview实例\u0026lt;/span\u0026gt;\n  \n  - ListView listView = (ListView) findViewById(R.id.listview);\n  \n  - listView.setAdapter(adapter);\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获取RefreshLayout实例\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; RefreshLayout myRefreshListView = (RefreshLayout)\n  \n  - findViewById(R.id.swipe_layout);\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置下拉刷新时的颜色值,颜色值需要定义在xml中\u0026lt;/span\u0026gt;\n  \n  - myRefreshListView\n  \n  - .setColorScheme(R.color.umeng_comm_text_topic_light_color,\n  \n  - R.color.umeng_comm_yellow, R.color.umeng_comm_green,\n  \n  - R.color.umeng_comm_linked_text);\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置下拉刷新监听器\u0026lt;/span\u0026gt;\n  \n  - myRefreshListView.setOnRefreshListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnRefreshListener() {\n  \n  - \n  - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onRefresh() {\n  \n  - \n  - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;refresh\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show();\n  \n  - \n  - myRefreshListView.postDelayed(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() {\n  \n  - \n  - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() {\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 更新数据\u0026lt;/span\u0026gt;\n  \n  - datas.add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Date().toGMTString());\n  \n  - adapter.notifyDataSetChanged();\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 更新完后调用该方法结束刷新\u0026lt;/span\u0026gt;\n  \n  - myRefreshListView.setRefreshing(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;);\n  \n  - }\n  \n  - }, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;);\n  \n  - }\n  \n  - });\n  \n  - \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载监听器\u0026lt;/span\u0026gt;\n  \n  - myRefreshListView.setOnLoadListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnLoadListener() {\n  \n  - \n  - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLoad() {\n  \n  - \n  - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;load\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show();\n  \n  - \n  - myRefreshListView.postDelayed(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() {\n  \n  - \n  - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() {\n  \n  - datas.add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Date().toGMTString());\n  \n  - adapter.notifyDataSetChanged();\n  \n  - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载完后调用该方法\u0026lt;/span\u0026gt;\n  \n  - myRefreshListView.setLoading(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;);\n  \n  - }\n  \n  - }, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1500\u0026lt;/span\u0026gt;);\n  \n  - \n  - }\n  \n  - });\n  \n  - }\n  \n  - \n  - }\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003ch2 id=\"效果图\"\u003e\u003ca name=\"t4\"\u003e\u003c/a\u003e效果图\u003c/h2\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20141009181845718)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  github链接 : [下拉刷新库](https://github.com/bboyfeiyu/android_my_pull_refresh_view) 。\n\u003c/div\u003e\n\u003cdiv\u003e\n  示例在android_my_pull_demo工程中，进入demo后点击最后一个按钮查看效果即可。注意，在刷新和加载时，需要有一定的延时才能看到效果，这里我们用postDelay来模拟网络请求等延时操作，否则将看不到加载效果。\n\u003c/div\u003e","title":"让Android Support V4中的SwipeRefreshLayout支持上拉加载更多"},{"content":"转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/38868463\n前面写过一篇关于下拉刷新控件的博客下拉刷新控件终结者：PullToRefreshLayout，后来看到好多人还有上拉加载更多的需求，于是就在前面下拉刷新控件的基础上进行了改进，加了上拉加载的功能。不仅如此，我已经把它改成了对所有View都通用！可以随心所欲使用这两个功能~~\n我做了一个大集合的demo，实现了ListView、GridView、ExpandableListView、ScrollView、WebView、ImageView、TextView的下拉刷新和上拉加载。后面会提供demo的下载地址。（csdn上的demo有小bug，最新代码已上传到github：https://github.com/jingchenUSTC/PullToRefreshAndLoad)\n依照惯例，下面将会是一大波效果图：\ndemo首页也是可下拉的ListView，在底下可以加入table：\nListView：\nGridView：\nExpandableListView：\nScrollView：\nWebView：\nImageView：\nTextView：\n很不错吧？最后的ImageView和TextView是最简单的，直接在下面的接口方法里返回true。\n增加上拉加载很简单，和管理下拉头一样，再多管理一个上拉头，也不费事；至于把它改成通用的就需要统一一下View的行为了，为此，我定义了这样一个接口：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; Pullable - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 判断是否可以下拉，如果不需要下拉功能可以直接return false\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return true如果可以下拉否则返回false\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 判断是否可以上拉，如果不需要上拉功能可以直接return false\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return true如果可以上拉否则返回false\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp(); - } 从 接口名就可以看出它是一个提供判断是否可拉的方法的接口。这个接口的两个方法，canPullDown()是判断何时可以下拉的方 法，canPullUp()则是判断何时可以上拉，我在demo中的判断是滑到顶部的时候可以下拉，滑到底部的时候可以上拉。所有需要上拉和下拉的 View都需要实现这个接口。后面会给出一些View的实现。先来看看改进后的自定义的布局PullToRefreshLayout，增加了一个上拉头， 下拉头和上拉头之间的View是实现了Pullable接口的pullableView。相比前面的版本，这里有改动的需要注意的地方如下：\n1、增加了上拉头，相应的也增加了控制变量。\n2、拉动时消除content_view事件防止误触发不再使用反射，直接设置 event.setAction(MotionEvent.ACTION_CANCEL)。\n3、消除了拉动过程中的多点触碰导致的剧变。\n4、不再设置content_view的onTouListener，让使用者可以更加自由的设置监听器。\n这个PullToRefreshLayout只负责管理三个控件，如果一个View需要有上拉下拉功能则只需实现接口就行了。下面看PullToRefreshLayout的代码，注释写了好多：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Timer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.TimerTask; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.LinearGradient; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint.Style; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.RectF; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Shader.TileMode; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.AnimationUtils; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.LinearInterpolator; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.RotateAnimation; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.RelativeLayout; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview.Pullable; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 自定义的布局，用来管理三个子控件，其中一个是下拉头，一个是包含内容的pullableView（可以是实现Pullable接口的的任何View），\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 还有一个上拉头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author 陈靖\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullToRefreshLayout \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; RelativeLayout - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;PullToRefreshLayout\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; INIT = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; RELEASE_TO_REFRESH = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; REFRESHING = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; RELEASE_TO_LOAD = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; LOADING = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 操作完毕\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; DONE = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 当前状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; state = INIT; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnRefreshListener mListener; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新成功\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; SUCCEED = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; FAIL = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 按下Y坐标，上一个事件点Y坐标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; downY, lastY; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉的距离。注意：pullDownY和pullUpY不可能同时不为0\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; pullDownY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; pullUpY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放刷新的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; refreshDist = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放加载的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; loadmoreDist = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTimer timer; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 回滚速度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; MOVE_SPEED = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 第一次执行布局\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isLayout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 在刷新过程中滑动操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 手指滑动距离与下拉头的滑动距离比，中间会随正切函数变化\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; radio = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉箭头的转180°动画\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; RotateAnimation rotateAnimation; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 均匀旋转动画\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; RotateAnimation refreshingAnimation; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View refreshView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉的箭头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View pullView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新的图标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View refreshingView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果图标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View refreshStateImageView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果：成功或失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView refreshStateTextView; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View loadmoreView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉的箭头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View pullUpView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载的图标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View loadingView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载结果图标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View loadStateImageView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载结果：成功或失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView loadStateTextView; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 实现了Pullable接口的View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View pullableView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 过滤多点触碰\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mEvents; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这两个变量用来控制pull的方向，如果不加控制，当情况满足可上拉又可下拉时没法下拉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 执行自动回滚的handler\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - Handler updateHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 回弹速度随下拉距离moveDeltaY增大而增大\u0026lt;/span\u0026gt; - MOVE_SPEED = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt; * Math.tan(Math.PI / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; - / getMeasuredHeight() * (pullDownY + Math.abs(pullUpY)))); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isTouch) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新，且没有往上推的话则悬停，显示\u0026amp;#8221;正在刷新\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == REFRESHING \u0026amp;\u0026amp; pullDownY \u0026lt;= refreshDist) - { - pullDownY = refreshDist; - timer.cancel(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == LOADING \u0026amp;\u0026amp; -pullUpY \u0026lt;= loadmoreDist) - { - pullUpY = -loadmoreDist; - timer.cancel(); - } - - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - pullDownY -= MOVE_SPEED; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - pullUpY += MOVE_SPEED; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 已完成回弹\u0026lt;/span\u0026gt; - pullDownY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - pullView.clearAnimation(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 隐藏下拉头时有可能还在刷新，只有当前状态不是正在刷新时才改变状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state != REFRESHING \u0026amp;\u0026amp; state != LOADING) - changeState(INIT); - timer.cancel(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 已完成回弹\u0026lt;/span\u0026gt; - pullUpY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - pullUpView.clearAnimation(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 隐藏下拉头时有可能还在刷新，只有当前状态不是正在刷新时才改变状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state != REFRESHING \u0026amp;\u0026amp; state != LOADING) - changeState(INIT); - timer.cancel(); - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新布局,会自动调用onLayout\u0026lt;/span\u0026gt; - requestLayout(); - } - - }; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnRefreshListener(OnRefreshListener listener) - { - mListener = listener; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullToRefreshLayout(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - initView(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullToRefreshLayout(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - initView(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullToRefreshLayout(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - initView(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView(Context context) - { - timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTimer(updateHandler); - rotateAnimation = (RotateAnimation) AnimationUtils.loadAnimation( - context, R.anim.reverse_anim); - refreshingAnimation = (RotateAnimation) AnimationUtils.loadAnimation( - context, R.anim.rotating); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 添加匀速转动动画\u0026lt;/span\u0026gt; - LinearInterpolator lir = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearInterpolator(); - rotateAnimation.setInterpolator(lir); - refreshingAnimation.setInterpolator(lir); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; hide() - { - timer.schedule(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 完成刷新操作，显示刷新结果。注意：刷新完成后一定要调用这个方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param refreshResult\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * PullToRefreshLayout.SUCCEED代表成功，PullToRefreshLayout.FAIL代表失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; refreshFinish(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; refreshResult) - { - refreshingView.clearAnimation(); - refreshingView.setVisibility(View.GONE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (refreshResult) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; SUCCEED: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新成功\u0026lt;/span\u0026gt; - refreshStateImageView.setVisibility(View.VISIBLE); - refreshStateTextView.setText(R.string.refresh_succeed); - refreshStateImageView - .setBackgroundResource(R.drawable.refresh_succeed); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; FAIL: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新失败\u0026lt;/span\u0026gt; - refreshStateImageView.setVisibility(View.VISIBLE); - refreshStateTextView.setText(R.string.refresh_fail); - refreshStateImageView - .setBackgroundResource(R.drawable.refresh_failed); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果停留1秒\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() - { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) - { - changeState(DONE); - hide(); - } - }.sendEmptyMessageDelayed(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 加载完毕，显示加载结果。注意：加载完成后一定要调用这个方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param refreshResult\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * PullToRefreshLayout.SUCCEED代表成功，PullToRefreshLayout.FAIL代表失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; loadmoreFinish(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; refreshResult) - { - loadingView.clearAnimation(); - loadingView.setVisibility(View.GONE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (refreshResult) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; SUCCEED: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载成功\u0026lt;/span\u0026gt; - loadStateImageView.setVisibility(View.VISIBLE); - loadStateTextView.setText(R.string.load_succeed); - loadStateImageView.setBackgroundResource(R.drawable.load_succeed); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; FAIL: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载失败\u0026lt;/span\u0026gt; - loadStateImageView.setVisibility(View.VISIBLE); - loadStateTextView.setText(R.string.load_fail); - loadStateImageView.setBackgroundResource(R.drawable.load_failed); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果停留1秒\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() - { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) - { - changeState(DONE); - hide(); - } - }.sendEmptyMessageDelayed(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; changeState(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; to) - { - state = to; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (state) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; INIT: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉布局初始状态\u0026lt;/span\u0026gt; - refreshStateImageView.setVisibility(View.GONE); - refreshStateTextView.setText(R.string.pull_to_refresh); - pullView.clearAnimation(); - pullView.setVisibility(View.VISIBLE); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉布局初始状态\u0026lt;/span\u0026gt; - loadStateImageView.setVisibility(View.GONE); - loadStateTextView.setText(R.string.pullup_to_load); - pullUpView.clearAnimation(); - pullUpView.setVisibility(View.VISIBLE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; RELEASE_TO_REFRESH: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放刷新状态\u0026lt;/span\u0026gt; - refreshStateTextView.setText(R.string.release_to_refresh); - pullView.startAnimation(rotateAnimation); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; REFRESHING: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新状态\u0026lt;/span\u0026gt; - pullView.clearAnimation(); - refreshingView.setVisibility(View.VISIBLE); - pullView.setVisibility(View.INVISIBLE); - refreshingView.startAnimation(refreshingAnimation); - refreshStateTextView.setText(R.string.refreshing); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; RELEASE_TO_LOAD: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放加载状态\u0026lt;/span\u0026gt; - loadStateTextView.setText(R.string.release_to_load); - pullUpView.startAnimation(rotateAnimation); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; LOADING: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载状态\u0026lt;/span\u0026gt; - pullUpView.clearAnimation(); - loadingView.setVisibility(View.VISIBLE); - pullUpView.setVisibility(View.INVISIBLE); - loadingView.startAnimation(refreshingAnimation); - loadStateTextView.setText(R.string.loading); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; DONE: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新或加载完毕，啥都不做\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 不限制上拉或下拉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; releasePull() - { - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * （非 Javadoc）由父控件决定是否分发事件，防止事件冲突\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (ev.getActionMasked()) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: - downY = ev.getY(); - lastY = downY; - timer.cancel(); - mEvents = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - releasePull(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_DOWN: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_UP: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 过滤多点触碰\u0026lt;/span\u0026gt; - mEvents = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mEvents == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (((Pullable) pullableView).canPullDown() \u0026amp;\u0026amp; canPullDown - \u0026amp;\u0026amp; state != LOADING) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 可以下拉，正在加载时不能下拉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 对实际滑动距离做缩小，造成用力拉的感觉\u0026lt;/span\u0026gt; - pullDownY = pullDownY + (ev.getY() \u0026amp;#8211; lastY) / radio; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - pullDownY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt; getMeasuredHeight()) - pullDownY = getMeasuredHeight(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == REFRESHING) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新的时候触摸移动\u0026lt;/span\u0026gt; - isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (((Pullable) pullableView).canPullUp() \u0026amp;\u0026amp; canPullUp - \u0026amp;\u0026amp; state != REFRESHING) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 可以上拉，正在刷新时不能上拉\u0026lt;/span\u0026gt; - pullUpY = pullUpY + (ev.getY() \u0026amp;#8211; lastY) / radio; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - pullUpY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026lt; -getMeasuredHeight()) - pullUpY = -getMeasuredHeight(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == LOADING) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载的时候触摸移动\u0026lt;/span\u0026gt; - isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - releasePull(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - mEvents = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - lastY = ev.getY(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 根据下拉距离改变比例\u0026lt;/span\u0026gt; - radio = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; * Math.tan(Math.PI / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; / getMeasuredHeight() - * (pullDownY + Math.abs(pullUpY)))); - requestLayout(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026lt;= refreshDist - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026amp;\u0026amp; (state == RELEASE_TO_REFRESH || state == DONE)) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果下拉距离没达到刷新的距离且当前状态是释放刷新，改变状态为下拉刷新\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;changeState(INIT); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt;= refreshDist \u0026amp;\u0026amp; (state == INIT || state == DONE)) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果下拉距离达到刷新的距离且当前状态是初始状态刷新，改变状态为释放刷新\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;changeState(RELEASE_TO_REFRESH); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下面是判断上拉加载的，同上，注意pullUpY是负值\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (-pullUpY \u0026lt;= loadmoreDist - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026amp;\u0026amp; (state == RELEASE_TO_LOAD || state == DONE)) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;changeState(INIT); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (-pullUpY \u0026gt;= loadmoreDist \u0026amp;\u0026amp; (state == INIT || state == DONE)) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;changeState(RELEASE_TO_LOAD); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 因为刷新和加载操作不能同时进行，所以pullDownY和pullUpY不会同时不为0，因此这里用(pullDownY +\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Math.abs(pullUpY))就可以不对当前状态作区分了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((pullDownY + Math.abs(pullUpY)) \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止下拉过程中误触发长按事件和点击事件\u0026lt;/span\u0026gt; - ev.setAction(MotionEvent.ACTION_CANCEL); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt; refreshDist || -pullUpY \u0026gt; loadmoreDist) - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新时往下拉（正在加载时往上拉），释放后下拉头（上拉头）不隐藏\u0026lt;/span\u0026gt; - isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == RELEASE_TO_REFRESH) - { - changeState(REFRESHING); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - mListener.onRefresh(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == RELEASE_TO_LOAD) - { - changeState(LOADING); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - mListener.onLoadMore(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - } - hide(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 事件分发交给父类\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(ev); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始化下拉布局\u0026lt;/span\u0026gt; - pullView = refreshView.findViewById(R.id.pull_icon); - refreshStateTextView = (TextView) refreshView - .findViewById(R.id.state_tv); - refreshingView = refreshView.findViewById(R.id.refreshing_icon); - refreshStateImageView = refreshView.findViewById(R.id.state_iv); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始化上拉布局\u0026lt;/span\u0026gt; - pullUpView = loadmoreView.findViewById(R.id.pullup_icon); - loadStateTextView = (TextView) loadmoreView - .findViewById(R.id.loadstate_tv); - loadingView = loadmoreView.findViewById(R.id.loading_icon); - loadStateImageView = loadmoreView.findViewById(R.id.loadstate_iv); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isLayout) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这里是第一次进来的时候做一些初始化\u0026lt;/span\u0026gt; - refreshView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - pullableView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - loadmoreView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); - isLayout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - initView(); - refreshDist = ((ViewGroup) refreshView).getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - .getMeasuredHeight(); - loadmoreDist = ((ViewGroup) loadmoreView).getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - .getMeasuredHeight(); - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 改变子控件的布局，这里直接用(pullDownY + pullUpY)作为偏移量，这样就可以不对当前状态作区分\u0026lt;/span\u0026gt; - refreshView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, - (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY) \u0026amp;#8211; refreshView.getMeasuredHeight(), - refreshView.getMeasuredWidth(), (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY)); - pullableView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY), - pullableView.getMeasuredWidth(), (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY) - + pullableView.getMeasuredHeight()); - loadmoreView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, - (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY) + pullableView.getMeasuredHeight(), - loadmoreView.getMeasuredWidth(), - (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY) + pullableView.getMeasuredHeight() - + loadmoreView.getMeasuredHeight()); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTimer - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Timer timer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTask mTask; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTimer(Handler handler) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler; - timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Timer(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; schedule(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; period) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - mTask.cancel(); - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTask(handler); - timer.schedule(mTask, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, period); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; cancel() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - mTask.cancel(); - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTask \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; TimerTask - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTask(Handler handler) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() - { - handler.obtainMessage().sendToTarget(); - } - - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 刷新加载回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author chenjing\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnRefreshListener - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 刷新操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onRefresh(PullToRefreshLayout pullToRefreshLayout); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 加载操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLoadMore(PullToRefreshLayout pullToRefreshLayout); - } - - } 上面就是整个布局的代码，并不是很难。\n下面看各个View对Pullable接口的实现，ListView和GridView还有ExpandableListView的判断方法是一样的：\nPullableListView：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableListView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableListView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableListView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以下拉刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getFirstVisiblePosition() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getTop() \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到ListView的顶部了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以上拉加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getLastVisiblePosition() == (getCount() \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;)) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到底部了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getChildAt(getLastVisiblePosition() \u0026amp;#8211; getFirstVisiblePosition()) != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt( - getLastVisiblePosition() - \u0026amp;#8211; getFirstVisiblePosition()).getBottom() \u0026lt;= getMeasuredHeight()) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } PullableExpandableListView：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ExpandableListView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableExpandableListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ExpandableListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; - Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableExpandableListView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableExpandableListView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableExpandableListView(Context context, AttributeSet attrs, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以下拉刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getFirstVisiblePosition() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getTop() \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到顶部了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以上拉加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getLastVisiblePosition() == (getCount() \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;)) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到底部了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getChildAt(getLastVisiblePosition() \u0026amp;#8211; getFirstVisiblePosition()) != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt( - getLastVisiblePosition() - \u0026amp;#8211; getFirstVisiblePosition()).getBottom() \u0026lt;= getMeasuredHeight()) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - } PullableGridView：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableGridView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; GridView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableGridView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableGridView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableGridView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以下拉刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getFirstVisiblePosition() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getTop() \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到顶部了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以上拉加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getLastVisiblePosition() == (getCount() \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;)) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到底部了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getChildAt(getLastVisiblePosition() \u0026amp;#8211; getFirstVisiblePosition()) != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt( - getLastVisiblePosition() - \u0026amp;#8211; getFirstVisiblePosition()).getBottom() \u0026lt;= getMeasuredHeight()) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - } PullableScrollView：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ScrollView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableScrollView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ScrollView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableScrollView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableScrollView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableScrollView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollY() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollY() \u0026gt;= (getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getHeight() \u0026amp;#8211; getMeasuredHeight())) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - } PullableWebView：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.webkit.WebView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableWebView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; WebView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableWebView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableWebView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableWebView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollY() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollY() \u0026gt;= getContentHeight() * getScale() - \u0026amp;#8211; getMeasuredHeight()) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } ImageView和TextView就不贴了，我直接在方法里返回了true。\nOK了，整个demo的代码有点多，就不贴了。\n源码下载\n","permalink":"https://blog.zdltech.com/posts/android%E4%B8%8B%E6%8B%89%E5%88%B7%E6%96%B0%E4%B8%8A%E6%8B%89%E5%8A%A0%E8%BD%BD%E6%8E%A7%E4%BB%B6%E5%AF%B9%E6%89%80%E6%9C%89view%E9%80%9A%E7%94%A8-2/","summary":"\u003cp\u003e转载请声明出处\u003ca href=\"http://blog.csdn.net/zhongkejingwang/article/details/38868463\"\u003ehttp://blog.csdn.net/zhongkejingwang/article/details/38868463\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e前面写过一篇关于下拉刷新控件的博客\u003ca href=\"http://blog.csdn.net/zhongkejingwang/article/details/38340701\"\u003e下拉刷新控件终结者：PullToRefreshLayout\u003c/a\u003e，后来看到好多人还有上拉加载更多的需求，于是就在前面下拉刷新控件的基础上进行了改进，加了上拉加载的功能。不仅如此，我已经把它改成了对所有View都通用！可以随心所欲使用这两个功能~~\u003c/p\u003e\n\u003cp\u003e我做了一个大集合的demo，实现了ListView、GridView、ExpandableListView、ScrollView、WebView、ImageView、TextView的下拉刷新和上拉加载。后面会提供demo的下载地址。（csdn上的demo有小bug，最新代码已上传到github：\u003ca href=\"https://github.com/jingchenUSTC/PullToRefreshAndLoad\"\u003ehttps://github.com/jingchenUSTC/PullToRefreshAndLoad\u003c/a\u003e)\u003c/p\u003e\n\u003cp\u003e依照惯例，下面将会是一大波效果图：\u003c/p\u003e\n\u003cp\u003edemo首页也是可下拉的ListView，在底下可以加入table：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827132732390?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eListView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827133113883?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eGridView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827133157922?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eExpandableListView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827133245580?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eScrollView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827134146109?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eWebView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827134443946?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eImageView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827135142900?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eTextView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827135212228?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e很不错吧？最后的ImageView和TextView是最简单的，直接在下面的接口方法里返回true。\u003c/p\u003e\n\u003cp\u003e增加上拉加载很简单，和管理下拉头一样，再多管理一个上拉头，也不费事；至于把它改成通用的就需要统一一下View的行为了，为此，我定义了这样一个接口：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; Pullable\n\n- {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 判断是否可以下拉，如果不需要下拉功能可以直接return false\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return true如果可以下拉否则返回false\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown();\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 判断是否可以上拉，如果不需要上拉功能可以直接return false\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return true如果可以上拉否则返回false\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp();\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e从 接口名就可以看出它是一个提供判断是否可拉的方法的接口。这个接口的两个方法，canPullDown()是判断何时可以下拉的方 法，canPullUp()则是判断何时可以上拉，我在demo中的判断是滑到顶部的时候可以下拉，滑到底部的时候可以上拉。所有需要上拉和下拉的 View都需要实现这个接口。后面会给出一些View的实现。先来看看改进后的自定义的布局PullToRefreshLayout，增加了一个上拉头， 下拉头和上拉头之间的View是实现了Pullable接口的pullableView。相比前面的版本，这里有改动的需要注意的地方如下：\u003c/p\u003e","title":"Android下拉刷新上拉加载控件，对所有View通用！"},{"content":"导论 本文着重讲解Android3.0后推出的属性动画框架Property Animation——Animator。\n产生原因 3.0之前已有的动画框架——Animation存在一些局限性， Animation框架定义了透明度，旋转，缩放和位移几种常见的动画，而且控制的是整个View，实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值，然后调用canvas.concat(transformToApply.getMatrix())，通过矩阵运算完成动画帧，如果动画没有完成，继续调用invalidate()函数，启动下次绘制来驱动动画，动画过程中的帧之间间隙时间是绘制函数所消耗的时间，可能会导致动画消耗比较多的CPU资源，最重要的是，动画改变的只是显示，并不能相应事件。\n而在Animator框架中使用最多的是AnimatorSet和ObjectAnimator配合，使用ObjectAnimator进行更精细化控制，只控制一个对象的一个属性值，多个ObjectAnimator组合到AnimatorSet形成一个动画。而且ObjectAnimator能够自动驱动，可以调用setFrameDelay(longframeDelay)设置动画帧之间的间隙时间，调整帧率，减少动画过程中频繁绘制界面，而在不影响动画效果的前提下减少CPU资源消耗。因此，Anroid推出的强大的属性动画框架，基本可以实现所有的动画效果。\n强大的原因 因为属性动画框架操作的是真实的属性值，直接变化了对象的属性，因此可以很灵活的实现各种效果，而不局限于以前的4种动画效果。\nObjectAnimator ObjectAnimator是属性动画框架中最重要的实行类，创建一个ObjectAnimator只需通过他的静态工厂类直接返回一个ObjectAnimator对象。传的参数包括一个对象和对象的属性名字，但这个属性必须有get和set函数，内部会通过java反射机制来调用set函数修改对象属性值。还包括属性的初始值，最终值，还可以调用setInterpolator设置曲线函数。\nObjectAnimator实例 [view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - ObjectAnimator.ofFloat(view, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;rotationX\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0F, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;360\u0026lt;/span\u0026gt;.0F).setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;).start(); 这个例子很简单，针对view的属性rotationX进行持续时间为1000ms的0到360的角度变换。\nPS：可操纵的属性参数：x/y；scaleX/scaleY；rotationX/ rotationY；transitionX/ transitionY等等。\nPS：X是View最终的位置、translationX为最终位置与布局时初始位置的差。所以若就用translationX即为在原来基础上移动多少，X为最终多少。getX()的值为getLeft()与getTranslationX()的和。\n动画绘制过程的监听 [view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - animator.addUpdateListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorUpdateListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationUpdate(ValueAnimator arg0) { } }); 该方法用来监听动画绘制过程中的每一帧的改变，通过这个方法，我们可以在动画重绘的过程中，实现自己的逻辑。\n同时修改多个属性值 当然这个可以使用Animationset来实现，这里我们使用一种取巧的方法来实现：\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - ObjectAnimator anim = ObjectAnimator.ofFloat(view, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;xxx\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0F, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0F) .setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt;); anim.start(); anim.addUpdateListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorUpdateListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationUpdate(ValueAnimator animation) { floatcVal = (Float) animation.getAnimatedValue(); view.setAlpha(cVal); view.setScaleX(cVal); view.setScaleY(cVal); } }); 我们可以监听一个并不存在的属性，而在监听动画更新的方法中，去修改view的属性，监听一个不存在的属性的原因就是，我们只需要动画的变化值，通过这个值，我们自己来实现要修改的效果，实际上，更直接的方法，就是使用ValueAnimator来实现，其实ObjectAnimator就是ValueAnimator的子类，这个在下面会具体讲到。\n为不具有get/set方法的属性提供修改方法 Google在应用层为我们提供了2种解决方法，一种是通过自己写一个包装类，来为该属性提供get/set方法，还有一种是通过ValueAnimator来实现，ValueAnimator的方法我们在下面会具体讲解，这里讲解下如何使用自定义的包装类来给属性提供get/set方法。\n包装类 [view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; WrapperView { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View mTarget; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; WrapperView(View target) { mTarget = target; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getWidth() { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mTarget.getLayoutParams().width; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setWidth(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width) { mTarget.getLayoutParams().width = width; mTarget.requestLayout(); } } 使用方法：\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - ViewWrapper wrapper = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewWrapper(mButton);ObjectAnimator.ofInt(wrapper, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;width\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt;).setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5000\u0026lt;/span\u0026gt;).start(); 这样就间接给他加上了get/set方法，从而可以修改其属性实现动画效果。\n多动画效果的另一种实现方法——propertyValuesHolder [view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; propertyValuesHolder(View view) { PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;alpha\u0026amp;#8221;\u0026lt;/span\u0026gt;, 1f, 0f, 1f); PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;scaleX\u0026amp;#8221;\u0026lt;/span\u0026gt;, 1f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, 1f); PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;scaleY\u0026amp;#8221;\u0026lt;/span\u0026gt;, 1f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, 1f); ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY, pvhZ) .setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;).start(); } ValueAnimator 说简单点，ValueAnimator就是一个数值产生器，他本身不作用于任何一个对象，但是可以对产生的值进行动画处理。\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - ValueAnimator animator = ValueAnimator.ofFloat(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;); animator.setTarget(view); animator.setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;).start(); animator.addUpdateListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorUpdateListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationUpdate(ValueAnimator animation) { Float value = (Float) animation.getAnimatedValue(); imageView.setTranslationY(value); } }); 通过这个动画我们可以发现，和我们在上面提供的使用ObjectAnimator的方法很像，的确，我前面说这个才是专业的写法，就是这个原因，动画生成的原理就是通过差值器计算出来的一定规律变化的数值作用到对象上来实现对象效果的变化，因此我们可以使用ObjectAnimator来生成这些数，然后在动画重绘的监听中，完成自己的效果。\nValueAnimator是计算动画过程中变化的值，包含动画的开始值，结束值，持续时间等属性。但并没有把这些计算出来的值应用到具体的对象上面，所以也不会有什么的动画显示出来。要把计算出来的值应用到对象上，必须为ValueAnimator注册一个监听器ValueAnimator.AnimatorUpdateListener，该监听器负责更新对象的属性值。在实现这个监听器的时候，可以通过getAnimatedValue()的方法来获取当前帧的值。\nValueAnimator封装了一个TimeInterpolator，TimeInterpolator定义了属性值在开始值与结束值之间的插值方法。ValueAnimator还封装了一个TypeAnimator，根据开始、结束值与TimeIniterpolator计算得到的值计算出属性值。ValueAnimator根据动画已进行的时间跟动画总时间（duration）的比计算出一个时间因子（0~1），然后根据TimeInterpolator计算出另一个因子，最后TypeAnimator通过这个因子计算出属性值，例如在10ms时（total 40ms）：\n首先计算出时间因子，即经过的时间百分比：t=10ms/40ms=0.25\n经插值计算(inteplator)后的插值因子:大约为0.15，如果使用了AccelerateDecelerateInterpolator，计算公式为（input即为时间因子）：\n(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;\n最后根据TypeEvaluator计算出在10ms时的属性值：0.15*（40-0）=6pixel。如果使用TypeEvaluator为FloatEvaluator，计算方法为 ：\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Float evaluate(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; fraction, Number startValue, Number endValue) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; startFloat = startValue.floatValue(); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; startFloat + fraction * (endValue.floatValue() \u0026amp;#8211; startFloat); } 参数分别为上一步的插值因子，开始值与结束值。\nValueAnimator与ObjectAnimator实例 [view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.animtest;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.animation.TypeEvaluator;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.animation.ValueAnimator;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.animation.ValueAnimator.AnimatorUpdateListener;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.PointF;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.DisplayMetrics;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.WindowManager;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.BounceInterpolator;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.LinearInterpolator;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; AnimateFreeFall \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; screenHeight; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; screenWidth; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageView imageView; \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.animate_free_fall); DisplayMetrics metrics = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); screenHeight = metrics.heightPixels; screenWidth = metrics.widthPixels; imageView = (ImageView) findViewById(R.id.im); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; clean(View view) { imageView.setTranslationX(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); imageView.setTranslationY(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; freefall(View view) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; ValueAnimator animator = ValueAnimator.ofFloat(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, screenHeight \u0026amp;#8211; imageView.getHeight()); animator.setTarget(view); animator.setInterpolator(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BounceInterpolator()); animator.setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;).start(); animator.addUpdateListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorUpdateListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationUpdate(ValueAnimator animation) { Float value = (Float) animation.getAnimatedValue(); imageView.setTranslationY(value); } }); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; parabola(View view) { ValueAnimator animator = ValueAnimator.ofObject( \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TypeEvaluator\u0026lt;PointF\u0026gt;() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PointF evaluate(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; fraction, PointF arg1, PointF arg2) { PointF p = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PointF(); p.x = fraction * screenWidth; p.y = fraction * fraction * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.5f * screenHeight * 4f * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.5f; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; p; } }, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PointF(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)); animator.setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;800\u0026lt;/span\u0026gt;); animator.setInterpolator(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearInterpolator()); animator.start(); animator.addUpdateListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorUpdateListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationUpdate(ValueAnimator animator) { PointF p = (PointF) animator.getAnimatedValue(); imageView.setTranslationX(p.x); imageView.setTranslationY(p.y); } }); }} 效果如下图：\n![](http://img.blog.csdn.net/20140806150136437?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZWNsaXBzZXh5cw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 有一点需要注意的是，由于ofInt，ofFloat等无法使用，我们自定义了一个TypeValue，每次根据当前时间返回一个PointF对象，（PointF和Point的区别就是x,y的单位一个是float,一个是int point float的意思）PointF中包含了x,y的当前位置，然后在更新监听中更新。\n自定义TypeEvaluator传入的泛型可以根据自己的需求，自己设计个Bean。\n动画事件的监听 通过监听这个事件在属性的值更新时执行相应的操作，对于ValueAnimator一般要监听此事件执行相应的动作，不然Animation没意义（但是可用于计时），在ObjectAnimator（继承自ValueAnimator）中会自动更新属性，所以不必监听。在函数中会传递一个ValueAnimator参数，通过此参数的getAnimatedValue()取得当前动画属性值。\nPS：根据应用动画的对象或属性的不同，可能需要在onAnimationUpdate函数中调用invalidate()函数刷新视图通过动画的各种状态，我们可以监听动画的各种状态。\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - ObjectAnimator \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;anim\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;ObjectAnimator\u0026lt;/span\u0026gt;.ofFloat(view, \u0026amp;#8220;alpha\u0026amp;#8221;, 0.5f); anim.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { } @Override public void onAnimationCancel(Animator animation) { } }); anim.start(); 可以看见，API提供了开始、重复、结束、取消等各种状态的监听，同时，API还提供了一种简单的监听方法，可以不用监听所有的事件：\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - anim.addListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorListenerAdapter() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationEnd(Animator animation) { } }); 通过AnimatorListenerAdapter来选择你需要监听的事件\n动画监听的实例应用 [view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.animtest;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.animation.Animator;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.animation.AnimatorListenerAdapter;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.animation.ObjectAnimator;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; AnimateMoveInSecond \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageView imageView; \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(R.layout.animate_move_in_second); imageView = (ImageView) findViewById(R.id.imageView1); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; doit(View view) { ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;alpha\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, 0f); animator.setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); animator.start(); animator.addListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorListenerAdapter() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationEnd(Animator animation) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onAnimationEnd(animation); ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;alpha\u0026amp;#8221;\u0026lt;/span\u0026gt;, 0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f); animator.setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); animator.start(); imageView.setTranslationY(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;400\u0026lt;/span\u0026gt;); } }); }} 效果如下图：\n![](http://img.blog.csdn.net/20140806150251661?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZWNsaXBzZXh5cw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) AnimatorSet AnimatorSet用于实现多个动画的协同作用。效果如下：\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageView, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;scaleX\u0026amp;#8221;\u0026lt;/span\u0026gt;, 1f, 2f); ObjectAnimator animator2 = ObjectAnimator.ofFloat(imageView, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;scaleY\u0026amp;#8221;\u0026lt;/span\u0026gt;, 1f, 2f); ObjectAnimator animator3 = ObjectAnimator.ofFloat(imageView, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;translationY\u0026amp;#8221;\u0026lt;/span\u0026gt;, 0f, 500f); AnimatorSet set = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorSet(); set.setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); set.playTogether(animator1, animator2, animator3); set.start(); AnimatorSet中有一系列的顺序控制方法：playTogether、playSequentially、animSet.play().with()、defore()、after()等。用来实现多个动画的协同工作方式。\n使用xml来创建动画 属性动画于以前的动画一样，也支持通过xml文件来创建动画，下面是一个简单的例子：\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;objectAnimator\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026amp;#8221;http://schemas.android.com/apk/res/android\u0026amp;#8221;android\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:duration\u0026lt;/span\u0026gt;=\u0026amp;#8221;1000\u0026amp;#8243;\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:propertyName\u0026lt;/span\u0026gt;=\u0026amp;#8221;scaleX\u0026amp;#8221;\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:valueFrom\u0026lt;/span\u0026gt;=\u0026amp;#8221;1.0\u0026amp;#8243;\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:valueTo\u0026lt;/span\u0026gt;=\u0026amp;#8221;2.0\u0026amp;#8243;\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:valueType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;floatType\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;objectAnimator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; [view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scaleX(View view){\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载动画Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scalex);anim.setTarget(mMv);anim.start();}\u0026lt;/span\u0026gt; 布局动画 布局动画是指ViewGroup在布局时产生的动画效果\nLayoutTransition动画 通过LayoutTransition来实现容器在添加子view的时候的动画过渡效果：\n![](http://img.blog.csdn.net/20140806150431594?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZWNsaXBzZXh5cw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) [view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.animtest;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.animation.Animator;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.animation.AnimatorListenerAdapter;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.animation.Keyframe;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.animation.LayoutTransition;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.animation.ObjectAnimator;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.animation.PropertyValuesHolder;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Button;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; AnimateLayoutTransition \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LinearLayout ll; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LayoutTransition mTransition = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutTransition(); \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(R.layout.animate_layout_transition); ll = (LinearLayout) findViewById(R.id.ll); setupCustomAnimations(); ll.setLayoutTransition(mTransition); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; add(View view) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Button button = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Button(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); ll.addView(button); button.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { ll.removeView(button); } }); } \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 生成自定义动画 private void setupCustomAnimations() { // 动画：CHANGE_APPEARING // Changing while Adding PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt(\u0026amp;#8220;left\u0026amp;#8221;, 0, 1); PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt(\u0026amp;#8220;top\u0026amp;#8221;, 0, 1); PropertyValuesHolder pvhRight = PropertyValuesHolder.ofInt(\u0026amp;#8220;right\u0026amp;#8221;, 0, 1); PropertyValuesHolder pvhBottom = PropertyValuesHolder.ofInt(\u0026amp;#8220;bottom\u0026amp;#8221;, 0, 1); PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat(\u0026amp;#8220;scaleX\u0026amp;#8221;, 1f, 0f, 1f); PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofFloat(\u0026amp;#8220;scaleY\u0026amp;#8221;, 1f, 0f, 1f); final ObjectAnimator changeIn = ObjectAnimator.ofPropertyValuesHolder( this, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhScaleX, pvhScaleY).setDuration( mTransition.getDuration(LayoutTransition.CHANGE_APPEARING)); mTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, changeIn); changeIn.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator anim) { View view = (View) ((ObjectAnimator) anim).getTarget(); // View也支持此种动画执行方式了 view.setScaleX(1f); view.setScaleY(1f); } }); // 动画：CHANGE_DISAPPEARING // Changing while Removing Keyframe kf0 = Keyframe.ofFloat(0f, 0f); Keyframe kf1 = Keyframe.ofFloat(.9999f, 360f); Keyframe kf2 = Keyframe.ofFloat(1f, 0f); PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe( \u0026amp;#8220;rotation\u0026amp;#8221;, kf0, kf1, kf2); final ObjectAnimator changeOut = ObjectAnimator .ofPropertyValuesHolder(this, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhRotation) .setDuration( mTransition .getDuration(LayoutTransition.CHANGE_DISAPPEARING)); mTransition .setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeOut); changeOut.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator anim) { View view = (View) ((ObjectAnimator) anim).getTarget(); view.setRotation(0f); } }); // 动画：APPEARING // Adding ObjectAnimator animIn = ObjectAnimator.ofFloat(null, \u0026amp;#8220;rotationY\u0026amp;#8221;, 90f, 0f).setDuration( mTransition.getDuration(LayoutTransition.APPEARING)); mTransition.setAnimator(LayoutTransition.APPEARING, animIn); animIn.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator anim) { View view = (View) ((ObjectAnimator) anim).getTarget(); view.setRotationY(0f); } }); // 动画：DISAPPEARING // Removing ObjectAnimator animOut = ObjectAnimator.ofFloat(null, \u0026amp;#8220;rotationX\u0026amp;#8221;, 0f, 90f).setDuration( mTransition.getDuration(LayoutTransition.DISAPPEARING)); mTransition.setAnimator(LayoutTransition.DISAPPEARING, animOut); animOut.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator anim) { View view = (View) ((ObjectAnimator) anim).getTarget(); view.setRotationX(0f); } }); }}\u0026lt;/span\u0026gt; 上面的例子中自定义了 LayoutTransition来修改默认的过渡动画，如果保持默认则使用系统默认的动画效果。\n过渡的类型一共有四种：\nLayoutTransition.APPEARING 当一个View在ViewGroup中出现时，对此View设置的动画\nLayoutTransition.CHANGE_APPEARING当一个View在ViewGroup中出现时，对此View对其他View位置造成影响，对其他View设置的动画\nLayoutTransition.DISAPPEARING当一个View在ViewGroup中消失时，对此View设置的动画\nLayoutTransition.CHANGE_DISAPPEARING当一个View在ViewGroup中消失时，对此View对其他View位置造成影响，对其他View设置的动画\nLayoutTransition.CHANGE 不是由于View出现或消失造成对其他View位置造成影响，然后对其他View设置的动画。\n注意动画到底设置在谁身上，此View还是其他View。\nAnimateLayoutChanges动画 ViewGroup的xml属性中有一个默认的animateLayoutChanges属性，设置该属性，可以添加ViewGroup增加view的过渡效果：\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026amp;#8221;http://schemas.android.com/apk/res/android\u0026amp;#8221;android\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:id\u0026lt;/span\u0026gt;=\u0026amp;#8221;@+id/ll\u0026amp;#8221;\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:layout_width\u0026lt;/span\u0026gt;=\u0026amp;#8221;match_parent\u0026amp;#8221;\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:layout_height\u0026lt;/span\u0026gt;=\u0026amp;#8221;match_parent\u0026amp;#8221;\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:animateLayoutChanges\u0026lt;/span\u0026gt;=\u0026amp;#8221;true\u0026amp;#8221;\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Buttonandroid:id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;Buttonandroid:id\u0026lt;/span\u0026gt;=\u0026amp;#8221;@+id/button1\u0026amp;#8243;android\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:layout_width\u0026lt;/span\u0026gt;=\u0026amp;#8221;wrap_content\u0026amp;#8221;\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:layout_height\u0026lt;/span\u0026gt;=\u0026amp;#8221;wrap_content\u0026amp;#8221;\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:onClick\u0026lt;/span\u0026gt;=\u0026amp;#8221;add\u0026amp;#8221;\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;Add Button\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; LayoutAnimation动画 通过设置LayoutAnimation也同样可以实现布局动画效果，实例如下：\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.animtest;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.LayoutAnimationController;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.ScaleAnimation;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; AnimateLayoutAnimation \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(R.layout.animate_layout_animation); LinearLayout ll = (LinearLayout) findViewById(R.id.ll); ScaleAnimation sa = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ScaleAnimation(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); sa.setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2000\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 第二个参数dely ： the delay by which each child\u0026amp;#8217;s animation must be offset LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5F); // 设置显示的顺序 这个必须要在dely不为0的时候才有效 lac.setOrder(LayoutAnimationController.ORDER_NORMAL); ll.setLayoutAnimation(lac); }}\u0026lt;/span\u0026gt; View的animate方法 3.0后android对View也提供了直接作用的动画API：\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - view.animate().alpha(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).y(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;).setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;) .withStartAction(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { } }).withEndAction(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { runOnUiThread(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { } }); } }).start(); Interpolators（插值器） 插值器和估值器，是实现非线性动画的基础，了解这些东西，才能作出不一样的动画效果。所谓的插值器，就是通过一些数学物理公式，计算出一些数值，提供给动画来使用。就好比我们定义了起始值是0，结束值是100，但是这0到100具体是怎么变化的呢，这就是插值器产生的结果，线性的，就是匀速增长，加速的，就是按加速度增长。这些增加的算法公式，已经不需要我们来自己设计了，Android内置了7种插值器，基本可以满足需求，当然你也可以自定新的插值器。\nAccelerateInterpolator 加速\nDecelerate 减速\nAccelerateDecelerateInterpolator 开始，和结尾都很慢，但是，中间加速\nAnticipateInterpolator 开始向后一点，然后，往前抛\nOvershootInterpolator 往前抛超过一点，然后返回来\nAnticipateOvershootInterpolator 开始向后一点，往前抛过点，然后返回来\nBounceInterpolator 结束的时候弹一下\nLinearInterpolator 默认 匀速\nTypeEvalutors (估值器) 根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值，android提供了以下几个evalutor：\nIntEvaluator：属性的值类型为int；\nFloatEvaluator：属性的值类型为float；\nArgbEvaluator：属性的值类型为十六进制颜色值；\nTypeEvaluator：一个接口，可以通过实现该接口自定义Evaluator。\n自定义TypeEvalutor很简单，只需要实现一个方法，如FloatEvalutor的定义：\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; FloatEvaluator \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; TypeEvaluator { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object evaluate(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; fraction, Object startValue, Object endValue) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; startFloat = ((Number) startValue).floatValue(); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; startFloat + fraction * (((Number) endValue).floatValue() \u0026amp;#8211; startFloat); } } 根据动画执行的时间跟应用的Interplator，会计算出一个0~1之间的因子，即evalute函数中的fraction参数。\nKeyFrame keyFrame是一个 时间/值 对，通过它可以定义一个在特定时间的特定状态，即关键帧，而且在两个keyFrame之间可以定义不同的Interpolator，就好像多个动画的拼接，第一个动画的结束点是第二个动画的开始点。KeyFrame是抽象类，要通过ofInt(),ofFloat(),ofObject()获得适当的KeyFrame，然后通过PropertyValuesHolder.ofKeyframe获得PropertyValuesHolder对象，如以下例子：\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - Keyframe kf0 = Keyframe.ofInt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;400\u0026lt;/span\u0026gt;);Keyframe kf1 = Keyframe.ofInt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.25f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;);Keyframe kf2 = Keyframe.ofInt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.5f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;400\u0026lt;/span\u0026gt;);Keyframe kf4 = Keyframe.ofInt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.75f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;);Keyframe kf3 = Keyframe.ofInt(1f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt;);PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;width\u0026amp;#8221;\u0026lt;/span\u0026gt;, kf0, kf1, kf2, kf4, kf3);ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(btn2, pvhRotation);rotationAnim.setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2000\u0026lt;/span\u0026gt;); 上述代码的意思为：设置btn对象的width属性值使其：\n开始时 Width=400\n动画开始1/4时 Width=200\n动画开始1/2时 Width=400\n动画开始3/4时 Width=100\n动画结束时 Width=500\n第一个参数为时间百分比，第二个参数是在第一个参数的时间时的属性值。\n定义了一些Keyframe后，通过PropertyValuesHolder类的方法ofKeyframe一个PropertyValuesHolder对象，然后通过ObjectAnimator.ofPropertyValuesHolder获得一个Animator对象。\n用下面的代码可以实现同样的效果（上述代码时间值是线性，变化均匀）：\n[view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#) - ObjectAnimator oa=ObjectAnimator.ofInt(btn2, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;width\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;400\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;400\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt;);oa.setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2000\u0026lt;/span\u0026gt;);oa.start(); 代码下载地址：http://download.csdn.net/detail/x359981514/7721651\n","permalink":"https://blog.zdltech.com/posts/android%E5%8A%A8%E7%94%BB%E6%9C%BA%E5%88%B6%E5%85%A8%E8%A7%A3%E6%9E%90/","summary":"\u003ch1 id=\"导论\"\u003e导论\u003c/h1\u003e\n\u003cp\u003e本文着重讲解Android3.0后推出的属性动画框架Property Animation——Animator。\u003c/p\u003e\n\u003ch1 id=\"产生原因\"\u003e产生原因\u003c/h1\u003e\n\u003cp\u003e3.0之前已有的动画框架——Animation存在一些局限性， Animation框架定义了透明度，旋转，缩放和位移几种常见的动画，而且控制的是整个View，实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值，然后调用canvas.concat(transformToApply.getMatrix())，通过矩阵运算完成动画帧，如果动画没有完成，继续调用invalidate()函数，启动下次绘制来驱动动画，动画过程中的帧之间间隙时间是绘制函数所消耗的时间，可能会导致动画消耗比较多的CPU资源，最重要的是，动画改变的只是显示，并不能相应事件。\u003c/p\u003e\n\u003cp\u003e而在Animator框架中使用最多的是AnimatorSet和ObjectAnimator配合，使用ObjectAnimator进行更精细化控制，只控制一个对象的一个属性值，多个ObjectAnimator组合到AnimatorSet形成一个动画。而且ObjectAnimator能够自动驱动，可以调用setFrameDelay(longframeDelay)设置动画帧之间的间隙时间，调整帧率，减少动画过程中频繁绘制界面，而在不影响动画效果的前提下减少CPU资源消耗。因此，Anroid推出的强大的属性动画框架，基本可以实现所有的动画效果。\u003c/p\u003e\n\u003ch1 id=\"强大的原因\"\u003e强大的原因\u003c/h1\u003e\n\u003cp\u003e因为属性动画框架操作的是真实的属性值，直接变化了对象的属性，因此可以很灵活的实现各种效果，而不局限于以前的4种动画效果。\u003c/p\u003e\n\u003ch1 id=\"objectanimator\"\u003eObjectAnimator\u003c/h1\u003e\n\u003cp\u003eObjectAnimator是属性动画框架中最重要的实行类，创建一个ObjectAnimator只需通过他的静态工厂类直接返回一个ObjectAnimator对象。传的参数包括一个对象和对象的属性名字，但这个属性必须有get和set函数，内部会通过java反射机制来调用set函数修改对象属性值。还包括属性的初始值，最终值，还可以调用setInterpolator设置曲线函数。\u003c/p\u003e\n\u003ch2 id=\"objectanimator实例\"\u003eObjectAnimator实例\u003c/h2\u003e\n\u003cdiv class=\"dp-highlighter\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      [view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#)\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- ObjectAnimator.ofFloat(view, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;rotationX\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0F, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;360\u0026lt;/span\u0026gt;.0F).setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;).start();\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e这个例子很简单，针对view的属性rotationX进行持续时间为1000ms的0到360的角度变换。\u003cbr\u003e\nPS：可操纵的属性参数：x/y；scaleX/scaleY；rotationX/ rotationY；transitionX/ transitionY等等。\u003cbr\u003e\nPS：X是View最终的位置、translationX为最终位置与布局时初始位置的差。所以若就用translationX即为在原来基础上移动多少，X为最终多少。getX()的值为getLeft()与getTranslationX()的和。\u003c/p\u003e\n\u003ch2 id=\"动画绘制过程的监听\"\u003e动画绘制过程的监听\u003c/h2\u003e\n\u003cdiv class=\"dp-highlighter\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      [view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#)\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- animator.addUpdateListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorUpdateListener() {           \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;           \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationUpdate(ValueAnimator arg0) {         }       });\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e该方法用来监听动画绘制过程中的每一帧的改变，通过这个方法，我们可以在动画重绘的过程中，实现自己的逻辑。\u003c/p\u003e\n\u003ch1 id=\"同时修改多个属性值\"\u003e同时修改多个属性值\u003c/h1\u003e\n\u003cp\u003e当然这个可以使用Animationset来实现，这里我们使用一种取巧的方法来实现：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      [view plain](http://www.netfoucs.com/article/x359981514/92198.html#)[copy to clipboard](http://www.netfoucs.com/article/x359981514/92198.html#)[print](http://www.netfoucs.com/article/x359981514/92198.html#)[?](http://www.netfoucs.com/article/x359981514/92198.html#)\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- ObjectAnimator anim = ObjectAnimator.ofFloat(view, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;xxx\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0F, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0F)               .setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt;);      anim.start();       anim.addUpdateListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorUpdateListener() {           \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;           \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationUpdate(ValueAnimator animation) {                floatcVal = (Float) animation.getAnimatedValue();               view.setAlpha(cVal);                view.setScaleX(cVal);               view.setScaleY(cVal);           }       });\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e我们可以监听一个并不存在的属性，而在监听动画更新的方法中，去修改view的属性，监听一个不存在的属性的原因就是，我们只需要动画的变化值，通过这个值，我们自己来实现要修改的效果，实际上，更直接的方法，就是使用ValueAnimator来实现，其实ObjectAnimator就是ValueAnimator的子类，这个在下面会具体讲到。\u003c/p\u003e","title":"Android动画机制全解析"},{"content":"Android 5.0 Lollipop 是迄今为止最重大的一次发布，很大程度上是因为 material design —— 这是一门新的设计语言，它刷新了整个 Android 的用户体验。但是对于开发者来说，要设计出完全符合 material design 哲学的应用，是一个很大的挑战。Android Design Support Library 对此提供了很好的支持，里面汇集了很多重要的 material design 控件，支持所有 Android 2.1 及后续版本。里面你可以看到 navigation drawer view、floating labels、floating action button、snackbar、tabs，以及一套将它们紧密结合在一起的动作与滚动框架。\nNavigation View（导航视图） 无论从应用标识、内容导航，还是设计一致性来讲，navigation drawer 都是首当其冲的焦点。现在，NavigationView 让导航栏变得更简单，它提供了 navigation drawer 需要的框架，以及通过资源文件来自定义更多菜单项的能力。\n![navigationview](http://ac-lhzo7z96.clouddn.com/1433285108918) 你只需要将 NavigationView 作为 DrawerLayout 的内容视图来使用即可，例如：\n![drawerlayout](http://ac-lhzo7z96.clouddn.com/1433297055793) 这里你会注意到两个属性：app:heanderLaytout 用来控制 header 部分的布局；app:menu 指定了菜单资源。NavigationView 自动处理了状态栏的变化，保证可以在 API 21+ 的设备上正确运行。\n最简单的 drawer 菜单就是一个允许选择的菜单项集合，例如：\n![simplemenu](http://ac-lhzo7z96.clouddn.com/1433297095098) 选中的菜单会高亮显示，以提醒用户当前选择的是哪个菜单项。\n你也可以在菜单中使用 subheader 来实现独立的分组：\n![subheader_menu](http://ac-lhzo7z96.clouddn.com/1433297134486) 调用 setNavigationItemSelectedListener() 后，在菜单项被选中的时候，你会通过OnNavigationItemSelectedListener 得到回调。在处理回调时，你会知道是哪个菜单项被点击，此时你可以处理选择事件，修改选中状态，加载新的内容，以及通过代码来关闭 drawer，或者其他任何你想执行的操作。\n文字输入时的悬浮标签 尽管 EditText 已经为 material design 做了一些改善，但是还不够，譬如它在我们输入第一个字符的时候，就会自动隐藏掉提示标签。现在你该使用 TextInputLayout 了，它会在用户开始输入之后，自动将提示标签悬浮到 EditText 上方，这样用户就永远都能知道输入内容的上下文。\n![floatinglabel](http://ac-lhzo7z96.clouddn.com/1433285152184) 另外，你也可以通过调用 setError() 方法，在 EditText 下方显示一个出错提示消息。多么贴心的设计，有没有？\nFloating Action Button（浮动操作按钮） Floating action button 是一个圆形按钮，代表当前页面最重要的交互动作。Design Library 里面的 FloatingActionButton 给了你一个简单一致的实现，它会默认使用你主题中 colorAccent 属性定义的色调。\n![actionbutton](http://ac-lhzo7z96.clouddn.com/1433285184208) 在标准尺寸之外，它也支持 mini 尺寸。FloatActionButton 继承自 ImageView，所以你也可以使用android:src 或者其他方法（如 setImageDrawable()）来控制它的外观。\nSnackbar 如果要提供一个轻量、快速的操作反馈方式，那就非 Snackbar 莫属了。Snackbar 在屏幕最下方展示，包含文字和一个可选的操作，它会在一定时间后自动消失，用户也可以通过滑动手势来提前消除它。\nSnackbar 可以支持滑动手势，也可以响应点击动作，远比 Toast 强大，但是你会发现它的 API 非常眼熟：\n`\nSnackbar\n.make(parentLayout, R.string.snackbar_text, Snackbar.LENGTH_LONG)\n.setAction(R.string.snackbar_action, myOnClickListener)\n.show(); // Don’t forget to show!\n`\n你会注意到 make 的第一个参数，Snackbar 会试图寻找合适的父视图，来确保它能显示在底部的正确位置。\nTabs（选项卡） 在应用内，通过 tab 在不同视图间切换，这不是 material design 中的新概念。Tabs 一般用来作顶层导航，或者组织、展示应用内不同分组的内容。如下图所示：\n![tabs](http://ac-lhzo7z96.clouddn.com/1433285292968) Design Library 的 TabLayout 控件实现了固定 tab（所有 tab 平分秋色，宽度固定）和滚动 tab（宽度根据标题长度自适应，可以水平滑动）两种形式，你可以用代码来添加 tab：\n`\nTabLayout tabLayout = \u0026hellip;;\ntabLayout.addTab(tabLayout.newTab().setText(\u0026ldquo;Tab 1\u0026rdquo;));\n`\n如果你使用 ViewPager 来水平分页，可直接在 PagerAdapter.getPageTitle() 中来创建 tab，最后通过 setupWithViewPager() 方法将它们绑定在一起。这能确保内容变化时 tab 和 ViewPager 会自动同步起来。\nCoordinatorLayout、动画和滚屏 打造一个符合 material design 风格的应用，独特的视觉效果只是一方面，动作和手势也是非常重要的一部分。 Material design 里面包含了大量的手势，譬如点击的波纹效果和其他一些有用的转场动画。Design Library 介绍了 CoordinatorLayout 的布局方式，它提供了一个附加层，用来控制子视图间的点击事件，Design Library 里面很多控件都使用了这种布局。\nCoordinatorLayout 和浮动操作按钮 FloatingActionButton 就是一个绝好的例子。当你将 FloatingActionButton 作为子元素加入 CoordinatorLayout，然后将 CoordinatorLayout 作为参数传给 Snackbar.make() 的时候，Snackbar 没有显示到 FloatingActionButton 上面。FloatingActionButton 利用了 CoordinatorLayout 提供的额外回调接口，在 Snackbar 展现的时候自动上移，消失的时候自动复位，所有这一切都不需要写任何代码。\nCoordinatorLayout 还提供了一个 layout_anchor 的属性，连同 layout_anchorGravity 一起，可以用来放置与其他视图关联在一起的悬浮视图（如 FloatingActionButton）。\nCoordinatorLayout 和 App Bar CoordinatorLayout 的另一个主要使用场景，则与 appbar（以前的 actionBar）和滚屏相关。你可能已经在布局里面使用过 Toolbar，它允许你简单修改外观、整合图标以和其余部分一致。Design Library 将所有这些东西放到了下一级：使用 AppBarLayout，让你的 Toolbar 和其他视图（如 TabLayout 提供的 tab 视图），可以响应 ScrollingViewBehavior 标记的同级视图的滚动事件。此时你可以这样来创建一个布局：\n![coordinator_appbar](http://ac-lhzo7z96.clouddn.com/1433297219279) 现在，随着用户滚动 RecyclerView， AppBarLayout 也会响应这些事件（通过使用子节点的 scroll flag 来控制它们如何滚入和滚出屏幕）。Flags 包括：\nscroll： 这个标志会被设置到所有希望滚出屏幕的视图上，如果不设置这一标志，则视图会被一直保留在屏幕顶部。 enterAlways： 这个标志会确保任何下滑滚屏都会触发视图的展现，等于开启了一种「快速返回」模式。 enterAlwaysCollapsed： 如果设置了 minHeight 和这个标志，你的视图通常会折叠显示，只有当滚动视图已经到达了它的顶点以后才会打开到完整高度。 exitUntilCollapsed： 这个标志会导致视图在退出之前，一直被锁定。 注意一点：所有设置了 scroll 标志的视图必须在未设该标志的视图之前进行声明，这样可以确保所有的滚动视图都从顶部退出，而固定元素都不受影响。\n可伸缩的 Toolbars 直接将 Toolbar 加到 AppBarLayout 中，你就可以设置 enterAlwaysCollapsed /exitUntilCollapsed 等滚动标志，但是不同元素如何响应折叠动作，你没法更深入地控制。要达到这一点，你需要使用 CollapsingToolbarLayout：\n![coordinator_toolbar](http://ac-lhzo7z96.clouddn.com/1433297261485) 通过使用 app:layout_collapseMode=\u0026quot;pin\u0026quot; 来确保 Toolbar 会一直被保留在屏幕顶端。更进一步，当你组合使用 CollapsingToolbarLayout 和 Toolbar，在视图完全展现的时候，标题会自动放大，当视图折叠的时候，标题则会过渡到默认字号。注意这时候你需要调用 CollapsingToolbarLayout 的 setTitle()，而不是 Toolbar 的相应方法。\n除了将视图固定在屏幕之外，你还可以设置 app:layout_collapseMode=\u0026quot;parallax\u0026quot;（额外也需要增加 app:layout_collapseParallaxMultiplier=\u0026quot;0.7\u0026quot; 这样的属性来设置视差乘数）来达到视差滚动的效果。这种用法搭配 app:contentScrim=\u0026quot;?attr/colorPrimary\u0026quot; 属性效果非常好，例如下面这样：\nCoordinatorLayout 和自定义视图 还有一件重要的事情就是，CoordinatorLayout 并不是天生就理解 FloatingActionButton 或者 AppBarLayout 如何工作，它只是提供了一些 Coordinator.Behavior 的附加 API，允许子控件来更好地控制点击事件和手势。\n视图也可以使用 CoordinatorLayout.DefaultBehavior(YourView.Behavior.class) 来定义一个默认的行为，或者在 layout 文件中设置app:layout_behavior=\u0026quot;com.example.app.YourView$Behavior\u0026quot; 来达到同样的效果。\nDesign Library 框架允许任何视图与 CoordinatorLayout 组合使用。\n现已发布 Design Library 现在已经公开发布了，请确认在 SDK manager 中升级 Android Support Repository。对于 Gradle 项目来讲，你可以直接加入对 Design Library 的依赖：\n`\ncompile \u0026lsquo;com.android.support:design:22.2.0\u0026rsquo;\n`\n注意 ：Design Library 依赖于 Support v4 和 AppCompat Support 库，它们会自动被加进编译依赖里来。并且，这些新的 widget 在 Android Studio Layout 编辑器中也是可用的（在 CustomView 中找到他们）。\n对于构建一个具有一流外观和交互的现代应用，Design Library、AppCompat 和所有 Android Support Library 都是非常重要的工具，大家快来动手试试吧。\n","permalink":"https://blog.zdltech.com/posts/material-design%E5%BC%80%E5%8F%91%E5%88%A9%E5%99%A8/","summary":"\u003cp\u003eAndroid 5.0 Lollipop 是迄今为止最重大的一次发布，很大程度上是因为 material design —— 这是一门新的设计语言，它刷新了整个 Android 的用户体验。但是对于开发者来说，要设计出完全符合 material design 哲学的应用，是一个很大的挑战。Android Design Support Library 对此提供了很好的支持，里面汇集了很多重要的 material design 控件，支持所有 Android 2.1 及后续版本。里面你可以看到 navigation drawer view、floating labels、floating action button、snackbar、tabs，以及一套将它们紧密结合在一起的动作与滚动框架。\u003c/p\u003e\n\u003ch2 id=\"navigation-view导航视图\"\u003eNavigation View（导航视图）\u003c/h2\u003e\n\u003cp\u003e无论从应用标识、内容导航，还是设计一致性来讲，\u003ca href=\"http://www.google.com/design/spec/patterns/navigation-drawer.html\"\u003enavigation drawer\u003c/a\u003e 都是首当其冲的焦点。现在，NavigationView 让导航栏变得更简单，它提供了 navigation drawer 需要的框架，以及通过资源文件来自定义更多菜单项的能力。\u003c/p\u003e\n\u003cdiv\u003e\n  ![navigationview](http://ac-lhzo7z96.clouddn.com/1433285108918)\n\u003c/div\u003e\n\u003cp\u003e你只需要将 NavigationView 作为 DrawerLayout 的内容视图来使用即可，例如：\u003c/p\u003e\n\u003cdiv\u003e\n  ![drawerlayout](http://ac-lhzo7z96.clouddn.com/1433297055793)\n\u003c/div\u003e\n\u003cp\u003e这里你会注意到两个属性：\u003ccode\u003eapp:heanderLaytout\u003c/code\u003e 用来控制 header 部分的布局；\u003ccode\u003eapp:menu\u003c/code\u003e 指定了菜单资源。NavigationView 自动处理了状态栏的变化，保证可以在 API 21+ 的设备上正确运行。\u003c/p\u003e\n\u003cp\u003e最简单的 drawer 菜单就是一个允许选择的菜单项集合，例如：\u003c/p\u003e\n\u003cdiv\u003e\n  ![simplemenu](http://ac-lhzo7z96.clouddn.com/1433297095098)\n\u003c/div\u003e\n\u003cp\u003e选中的菜单会高亮显示，以提醒用户当前选择的是哪个菜单项。\u003c/p\u003e\n\u003cp\u003e你也可以在菜单中使用 subheader 来实现独立的分组：\u003c/p\u003e\n\u003cdiv\u003e\n  ![subheader_menu](http://ac-lhzo7z96.clouddn.com/1433297134486)\n\u003c/div\u003e\n\u003cp\u003e调用 \u003ccode\u003esetNavigationItemSelectedListener()\u003c/code\u003e 后，在菜单项被选中的时候，你会通过\u003ccode\u003eOnNavigationItemSelectedListener\u003c/code\u003e 得到回调。在处理回调时，你会知道是哪个菜单项被点击，此时你可以处理选择事件，修改选中状态，加载新的内容，以及通过代码来关闭 drawer，或者其他任何你想执行的操作。\u003c/p\u003e\n\u003ch2 id=\"文字输入时的悬浮标签\"\u003e文字输入时的悬浮标签\u003c/h2\u003e\n\u003cp\u003e尽管 EditText 已经为 material design 做了一些改善，但是还不够，譬如它在我们输入第一个字符的时候，就会自动隐藏掉提示标签。现在你该使用 TextInputLayout 了，它会在用户开始输入之后，自动将提示标签悬浮到 EditText 上方，这样用户就永远都能知道输入内容的上下文。\u003c/p\u003e","title":"Material Design开发利器"},{"content":"1 背景 还记得前面《Android应用setContentView与LayoutInflater加载解析机制源码分析》这篇文章吗？我们有分析到Activity中界面加载显示的基本流程原理，记不记得最终分析结果就是下面的关系：\n看见没有，如上图中id为content的内容就是整个View树的结构，所以对每个具体View对象的操作，其实就是个递归的实现。\n前面《Android触摸屏事件派发机制详解与源码分析一(View篇)》文章的3-1小节说过Android中的任何一个布局、任何一个控件其实都是直接或间接继承自View实现的，当然也包括我们后面一步一步引出的自定义控件也不例外，所以说这些View应该都具有相同的绘制流程与机制才能显示到屏幕上（因为他们都具备相同的父类View，可能每个控件的具体绘制逻辑有差异，但是主流程都是一样的）。经过总结发现每一个View的绘制过程都必须经历三个最主要的过程，也就是measure、layout和draw。\n既然一个View的绘制主要流程是这三步，那一定有一个开始地方呀，就像一个类从main函数执行一样呀。对于View的绘制开始调运地方这里先给出结论，本文后面会反过来分析原因的，先往下看就行。具体结论如下：\n整个View树的绘图流程是在ViewRootImpl类的performTraversals()方法（这个方法巨长）开始的，该函数做的执行过程主要是根据之前设置的状态，判断是否重新计算视图大小(measure)、是否重新放置视图的位置(layout)、以及是否重绘 (draw)，其核心也就是通过判断来选择顺序执行这三个方法中的哪个，如下：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;performTraversals\u0026amp;lt;/span\u0026gt;() { ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//最外层的根视图的widthMeasureSpec和heightMeasureSpec由来\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//lp.width和lp.height在创建ViewGroup实例时等于MATCH_PARENT\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height); ...... mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); ...... mView.layout(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mView.getMeasuredWidth(), mView.getMeasuredHeight()); ...... mView.draw(canvas); ...... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n` \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * Figures out the measure spec for the root view in a window based on it\u0026#39;s * layout params. * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; windowSize * The available width or height of the window * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; rootDimension * The layout params for one dimension (width or height) of the * window. * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; The measure spec to use to measure the root view. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getRootMeasureSpec\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; windowSize, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; rootDimension) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; measureSpec; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (rootDimension) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; ViewGroup.LayoutParams.MATCH_PARENT: \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Window can\u0026#39;t resize. Force root view to be windowSize.\u0026amp;lt;/span\u0026gt; measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; ...... } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; measureSpec; }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n可以看见这个方法的注释说是用来测Root View的。上面传入参数后这个函数走的是MATCH_PARENT，使用MeasureSpec.makeMeasureSpec方法组装一个MeasureSpec，MeasureSpec的specMode等于EXACTLY，specSize等于windowSize，也就是为何根视图总是全屏的原因。\n其中的mView就是View对象。如下就是整个流程的大致流程图：\n如下我们就依据View绘制的这三个主要流程进行详细剖析（基于Android5.1.1 API 22源码进行分析）。\n【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处，尊重分享成果】\n2 View绘制流程第一步：递归measure源码分析 整个View树的源码measure流程图如下：\n2-1 measure源码分析 先看下View的measure方法源码，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * \u0026amp;lt;p\u0026amp;gt; * This is called to find out how big a view should be. The parent * supplies constraint information in the width and height parameters. * \u0026amp;lt;/p\u0026amp;gt; * * \u0026amp;lt;p\u0026amp;gt; * The actual measurement work of a view is performed in * {@link #onMeasure(int, int)}, called by this method. Therefore, only * {@link #onMeasure(int, int)} can and must be overridden by subclasses. * \u0026amp;lt;/p\u0026amp;gt; * * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; widthMeasureSpec Horizontal space requirements as imposed by the * parent *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; heightMeasureSpec Vertical space requirements as imposed by the * parent * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @see\u0026amp;lt;/span\u0026gt; #onMeasure(int, int) */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//final方法，子类不可重写\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;measure\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; widthMeasureSpec, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; heightMeasureSpec) { ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//回调onMeasure()方法\u0026amp;lt;/span\u0026gt; onMeasure(widthMeasureSpec, heightMeasureSpec); ...... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n看见注释信息没有，他告诉你了很多重要信息。为整个View树计算实际的大小，然后设置实际的高和宽，每个View控件的实际宽高都是由父视图和自身决定的。实际的测量是在onMeasure方法进行，所以在View的子类需要重写onMeasure方法，这是因为measure方法是final的，不允许重载，所以View子类只能通过重载onMeasure来实现自己的测量逻辑。\n这个方法的两个参数都是父View传递过来的，也就是代表了父view的规格。他由两部分组成，高16位表示MODE，定义在MeasureSpec类（View的内部类）中，有三种类型，MeasureSpec.EXACTLY表示确定大小， MeasureSpec.AT_MOST表示最大大小， MeasureSpec.UNSPECIFIED不确定。低16位表示size，也就是父View的大小。对于系统Window类的DecorVIew对象Mode一般都为MeasureSpec.EXACTLY ，而size分别对应屏幕宽高。对于子View来说大小是由父View和子View共同决定的。\n在这里可以看出measure方法最终回调了View的onMeasure方法，我们来看下View的onMeasure源码，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * \u0026amp;lt;p\u0026amp;gt; * Measure the view and its content to determine the measured width and the * measured height. This method is invoked by {@link #measure(int, int)} and * should be overriden by subclasses to provide accurate and efficient * measurement of their contents. * \u0026amp;lt;/p\u0026amp;gt; * * \u0026amp;lt;p\u0026amp;gt; * \u0026amp;lt;strong\u0026amp;gt;CONTRACT:\u0026amp;lt;/strong\u0026amp;gt; When overriding this method, you * \u0026amp;lt;em\u0026amp;gt;must\u0026amp;lt;/em\u0026amp;gt; call {@link #setMeasuredDimension(int, int)} to store the * measured width and height of this view. Failure to do so will trigger an * \u0026amp;lt;code\u0026amp;gt;IllegalStateException\u0026amp;lt;/code\u0026amp;gt;, thrown by * {@link #measure(int, int)}. Calling the superclass\u0026#39; * {@link #onMeasure(int, int)} is a valid use. * \u0026amp;lt;/p\u0026amp;gt; * * \u0026amp;lt;p\u0026amp;gt; * The base class implementation of measure defaults to the background size, * unless a larger size is allowed by the MeasureSpec. Subclasses should * override {@link #onMeasure(int, int)} to provide better measurements of * their content. * \u0026amp;lt;/p\u0026amp;gt; * * \u0026amp;lt;p\u0026amp;gt; * If this method is overridden, it is the subclass\u0026#39;s responsibility to make * sure the measured height and width are at least the view\u0026#39;s minimum height * and width ({@link #getSuggestedMinimumHeight()} and * {@link #getSuggestedMinimumWidth()}). * \u0026amp;lt;/p\u0026amp;gt; * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; widthMeasureSpec horizontal space requirements as imposed by the parent. * The requirements are encoded with * {@link android.view.View.MeasureSpec}. *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; heightMeasureSpec vertical space requirements as imposed by the parent. * The requirements are encoded with * {@link android.view.View.MeasureSpec}. * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @see\u0026amp;lt;/span\u0026gt; #getMeasuredWidth() *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @see\u0026amp;lt;/span\u0026gt; #getMeasuredHeight() *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @see\u0026amp;lt;/span\u0026gt; #setMeasuredDimension(int, int) *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @see\u0026amp;lt;/span\u0026gt; #getSuggestedMinimumHeight() *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @see\u0026amp;lt;/span\u0026gt; #getSuggestedMinimumWidth() *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @see\u0026amp;lt;/span\u0026gt; android.view.View.MeasureSpec#getMode(int) *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @see\u0026amp;lt;/span\u0026gt; android.view.View.MeasureSpec#getSize(int) */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//View的onMeasure默认实现方法\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onMeasure\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; widthMeasureSpec, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\n43\n44\n45\n46\n47\n48\n49\n50\n51\n看见没有，其实注释已经很详细了（自定义View重写该方法的指导操作注释都有说明），不做过多解释。\n对于非ViewGroup的View而言，通过调用上面默认的onMeasure即可完成View的测量，当然你也可以重载onMeasure并调用setMeasuredDimension来设置任意大小的布局，但一般不这么做，因为这种做法不太好，至于为何不好，后面分析完你就明白了。\n我们可以看见onMeasure默认的实现仅仅调用了setMeasuredDimension，setMeasuredDimension函数是一个很关键的函数，它对View的成员变量mMeasuredWidth和mMeasuredHeight变量赋值，measure的主要目的就是对View树中的每个View的mMeasuredWidth和mMeasuredHeight进行赋值，所以一旦这两个变量被赋值意味着该View的测量工作结束。既然这样那我们就看看设置的默认尺寸大小吧，可以看见setMeasuredDimension传入的参数都是通过getDefaultSize返回的，所以再来看下getDefaultSize方法源码，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getDefaultSize\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; size, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; measureSpec) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; result = size; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//通过MeasureSpec解析获取mode与size\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; specMode = MeasureSpec.getMode(measureSpec); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; specSize = MeasureSpec.getSize(measureSpec); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (specMode) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; MeasureSpec.UNSPECIFIED: result = size; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; MeasureSpec.AT_MOST: \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; MeasureSpec.EXACTLY: result = specSize; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; result; }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n看见没有，如果specMode等于AT_MOST或EXACTLY就返回specSize，这就是系统默认的规格。\n回过头继续看上面onMeasure方法，其中getDefaultSize参数的widthMeasureSpec和heightMeasureSpec都是由父View传递进来的。getSuggestedMinimumWidth与getSuggestedMinimumHeight都是View的方法，具体如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getSuggestedMinimumWidth\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; (mBackground == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getSuggestedMinimumHeight\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; (mBackground == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); }` 1\n2\n3\n4\n5\n6\n7\n8\n看见没有，建议的最小宽度和高度都是由View的Background尺寸与通过设置View的miniXXX属性共同决定的。\n到此一次最基础的元素View的measure过程就完成了。上面说了View实际是嵌套的，而且measure是递归传递的，所以每个View都需要measure。实际能够嵌套的View一般都是ViewGroup的子类，所以在ViewGroup中定义了measureChildren, measureChild, measureChildWithMargins方法来对子视图进行测量，measureChildren内部实质只是循环调用measureChild，measureChild和measureChildWithMargins的区别就是是否把margin和padding也作为子视图的大小。如下我们以ViewGroup中稍微复杂的measureChildWithMargins方法来分析：\n` \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * Ask one of the children of this view to measure itself, taking into * account both the MeasureSpec requirements for this view and its padding * and margins. The child must have MarginLayoutParams The heavy lifting is * done in getChildMeasureSpec. * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; child The child to measure *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; parentWidthMeasureSpec The width requirements for this view *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; widthUsed Extra space that has been used up by the parent * horizontally (possibly by other children of the parent) *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; parentHeightMeasureSpec The height requirements for this view *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; heightUsed Extra space that has been used up by the parent * vertically (possibly by other children of the parent) */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;measureChildWithMargins\u0026amp;lt;/span\u0026gt;(View child, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; parentWidthMeasureSpec, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; widthUsed, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; parentHeightMeasureSpec, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; heightUsed) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获取子视图的LayoutParams\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//调整MeasureSpec\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//通过这两个参数以及子视图本身的LayoutParams来共同决定子视图的测量规格\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed, lp.height); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//调运子View的measure方法，子View的measure中会回调子View的onMeasure方法\u0026amp;lt;/span\u0026gt; child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n关于该方法的参数等说明注释已经描述的够清楚了。该方法就是对父视图提供的measureSpec参数结合自身的LayoutParams参数进行了调整，然后再来调用child.measure()方法，具体通过方法getChildMeasureSpec来进行参数调整。所以我们继续看下getChildMeasureSpec方法代码，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getChildMeasureSpec\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; spec, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; padding, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childDimension) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获取当前Parent View的Mode和Size\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; specMode = MeasureSpec.getMode(spec); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; specSize = MeasureSpec.getSize(spec); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获取Parent size与padding差值（也就是Parent剩余大小），若差值小于0直接返回0\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; size = Math.max(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, specSize - padding); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//定义返回值存储变量\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; resultSize = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; resultMode = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//依据当前Parent的Mode进行switch分支逻辑\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (specMode) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Parent has imposed an exact size on us\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//默认Root View的Mode就是EXACTLY\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; MeasureSpec.EXACTLY: \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (childDimension \u0026amp;gt;= \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//如果child的layout_wOrh属性在xml或者java中给予具体大于等于0的数值\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置child的size为真实layout_wOrh属性值，mode为EXACTLY\u0026amp;lt;/span\u0026gt; resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (childDimension == LayoutParams.MATCH_PARENT) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//如果child的layout_wOrh属性在xml或者java中给予MATCH_PARENT\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Child wants to be our size. So be it.\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置child的size为size，mode为EXACTLY\u0026amp;lt;/span\u0026gt; resultSize = size; resultMode = MeasureSpec.EXACTLY; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (childDimension == LayoutParams.WRAP_CONTENT) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//如果child的layout_wOrh属性在xml或者java中给予WRAP_CONTENT\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置child的size为size，mode为AT_MOST\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Child wants to determine its own size. It can\u0026#39;t be\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// bigger than us.\u0026amp;lt;/span\u0026gt; resultSize = size; resultMode = MeasureSpec.AT_MOST; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//其他Mode分支类似\u0026amp;lt;/span\u0026gt; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//将mode与size通过MeasureSpec方法整合为32位整数返回\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; MeasureSpec.makeMeasureSpec(resultSize, resultMode); }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n可以看见，getChildMeasureSpec的逻辑是通过其父View提供的MeasureSpec参数得到specMode和specSize，然后根据计算出来的specMode以及子View的childDimension（layout_width或layout_height）来计算自身的measureSpec，如果其本身包含子视图，则计算出来的measureSpec将作为调用其子视图measure函数的参数，同时也作为自身调用setMeasuredDimension的参数，如果其不包含子视图则默认情况下最终会调用onMeasure的默认实现，并最终调用到setMeasuredDimension。\n所以可以看见onMeasure的参数其实就是这么计算出来的。同时从上面的分析可以看出来，最终决定View的measure大小是View的setMeasuredDimension方法，所以我们可以通过setMeasuredDimension设定死值来设置View的mMeasuredWidth和mMeasuredHeight的大小，但是一个好的自定义View应该会根据子视图的measureSpec来设置mMeasuredWidth和mMeasuredHeight的大小，这样的灵活性更大，所以这也就是上面分析onMeasure时说View的onMeasure最好不要重写死值的原因。\n可以看见当通过setMeasuredDimension方法最终设置完成View的measure之后View的mMeasuredWidth和mMeasuredHeight成员才会有具体的数值，所以如果我们自定义的View或者使用现成的View想通过getMeasuredWidth()和getMeasuredHeight()方法来获取View测量的宽高，必须保证这两个方法在onMeasure流程之后被调用才能返回有效值。\n还记得前面《Android应用setContentView与LayoutInflater加载解析机制源码分析》文章3-3小节探讨的inflate方法加载一些布局显示时指定的大小失效问题吗？当时只给出了结论，现在给出了详细原因分析，我想不需要再做过多解释了吧。\n至此整个View绘制流程的第一步就分析完成了，可以看见，相对来说还是比较复杂的，接下来进行小结。\n2-2 measure原理总结 通过上面分析可以看出measure过程主要就是从顶层父View向子View递归调用view.measure方法（measure中又回调onMeasure方法）的过程。具体measure核心主要有如下几点：\nMeasureSpec（View的内部类）测量规格为int型，值由高16位规格模式specMode和低16位具体尺寸specSize组成。其中specMode只有三种值： `MeasureSpec.EXACTLY \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//确定模式，父View希望子View的大小是确定的，由specSize决定；\u0026amp;lt;/span\u0026gt; MeasureSpec.AT_MOST \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//最多模式，父View希望子View的大小最多是specSize指定的值；\u0026amp;lt;/span\u0026gt; MeasureSpec.UNSPECIFIED \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//未指定模式，父View完全依据子View的设计值来决定； \u0026amp;lt;/span\u0026gt;` 1\n2\n3\nView的measure方法是final的，不允许重载，View子类只能重载onMeasure来完成自己的测量逻辑。 最顶层DecorView测量时的MeasureSpec是由ViewRootImpl中getRootMeasureSpec方法确定的（LayoutParams宽高参数均为MATCH_PARENT，specMode是EXACTLY，specSize为物理屏幕大小）。 ViewGroup类提供了measureChild，measureChild和measureChildWithMargins方法，简化了父子View的尺寸计算。 只要是ViewGroup的子类就必须要求LayoutParams继承子MarginLayoutParams，否则无法使用layout_margin参数。 View的布局大小由父View和子View共同决定。 使用View的getMeasuredWidth()和getMeasuredHeight()方法来获取View测量的宽高，必须保证这两个方法在onMeasure流程之后被调用才能返回有效值。 【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处，尊重分享成果】\n3 View绘制流程第二步：递归layout源码分析 在上面的背景介绍就说过，当ViewRootImpl的performTraversals中measure执行完成以后会接着执行mView.layout，具体如下：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;performTraversals\u0026amp;lt;/span\u0026gt;() { ...... mView.layout(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mView.getMeasuredWidth(), mView.getMeasuredHeight()); ...... }` 1\n2\n3\n4\n5\n可以看见layout方法接收四个参数，这四个参数分别代表相对Parent的左、上、右、下坐标。而且还可以看见左上都为0，右下分别为上面刚刚测量的width和height。\n至此又回归到View的layout(int l, int t, int r, int b)方法中去实现具体逻辑了，所以接下来我们开始分析View的layout过程。\n整个View树的layout递归流程图如下：\n3-1 layout源码分析 layout既然也是递归结构，那我们先看下ViewGroup的layout方法，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;layout\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; l, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; t, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; r, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; b) { ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.layout(l, t, r, b); ...... }` 1\n2\n3\n4\n5\n6\n看着没有？ViewGroup的layout方法实质还是调运了View父类的layout方法，所以我们看下View的layout源码，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;layout\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; l, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; t, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; r, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; b) { ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//实质都是调用setFrame方法把参数分别赋值给mLeft、mTop、mRight和mBottom这几个变量\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//判断View的位置是否发生过变化，以确定有没有必要对当前的View进行重新layout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; changed = isLayoutModeOptical(mParent) ? setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//需要重新layout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (changed || (mPrivateFlags \u0026amp; PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//回调onLayout\u0026amp;lt;/span\u0026gt; onLayout(changed, l, t, r, b); ...... } ...... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n看见没有，类似measure过程，lauout调运了onLayout方法。\n对比上面View的layout和ViewGroup的layout方法可以发现，View的layout方法是可以在子类重写的，而ViewGroup的layout是不能在子类重写的，言外之意就是说ViewGroup中只能通过重写onLayout方法。那我们接下来看下ViewGroup的onLayout方法，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;abstract\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onLayout\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; changed, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; l, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; t, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; r, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; b);` 1\n2\n3\n看见没有？ViewGroup的onLayout()方法竟然是一个抽象方法，这就是说所有ViewGroup的子类都必须重写这个方法。所以在自定义ViewGroup控件中，onLayout配合onMeasure方法一起使用可以实现自定义View的复杂布局。自定义View首先调用onMeasure进行测量，然后调用onLayout方法动态获取子View和子View的测量大小，然后进行layout布局。重载onLayout的目的就是安排其children在父View的具体位置，重载onLayout通常做法就是写一个for循环调用每一个子视图的layout(l, t, r, b)函数，传入不同的参数l, t, r, b来确定每个子视图在父视图中的显示位置。\n再看下View的onLayout方法源码，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onLayout\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; changed, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom) { }` 1\n2\n我勒个去！是一个空方法，没啥可看的。\n既然这样那我们只能分析一个现有的继承ViewGroup的控件了，就拿LinearLayout来说吧，如下是LinearLayout中onLayout的一些代码：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ViewGroup\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onLayout\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; changed, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; l, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; t, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; r, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; b) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mOrientation == VERTICAL) { layoutVertical(l, t, r, b); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { layoutHorizontal(l, t, r, b); } } }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n看见没有，LinearLayout的layout过程是分Vertical和Horizontal的，这个就是xml布局的orientation属性设置的，我们为例说明ViewGroup的onLayout重写一般步骤就拿这里的VERTICAL模式来解释吧，如下是layoutVertical方法源码：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; layoutVertical(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; paddingLeft = mPaddingLeft; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childTop; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childLeft; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Where right end of child should go\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//计算父窗口推荐的子View宽度\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; width = right - left; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//计算父窗口推荐的子View右侧位置\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childRight = width - mPaddingRight; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Space available for child\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//child可使用空间大小\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childSpace = width - paddingLeft - mPaddingRight; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//通过ViewGroup的getChildCount方法获取ViewGroup的子View个数\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; count = getVirtualChildCount(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获取Gravity属性设置\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; majorGravity = mGravity \u0026amp; Gravity.VERTICAL_GRAVITY_MASK; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; minorGravity = mGravity \u0026amp; Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//依据majorGravity计算childTop的位置值\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (majorGravity) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; Gravity.BOTTOM: \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// mTotalLength contains the padding already\u0026amp;lt;/span\u0026gt; childTop = mPaddingTop + bottom - top - mTotalLength; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// mTotalLength contains the padding already\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; Gravity.CENTER_VERTICAL: childTop = mPaddingTop + (bottom - top - mTotalLength) / \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; Gravity.TOP: \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;default\u0026amp;lt;/span\u0026gt;: childTop = mPaddingTop; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//重点！！！开始遍历\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; count; i++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; View child = getVirtualChildAt(i); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (child == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { childTop += measureNullChild(i); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (child.getVisibility() != GONE) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//LinearLayout中其子视图显示的宽和高由measure过程来决定的，因此measure过程的意义就是为layout过程提供视图显示范围的参考值\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childWidth = child.getMeasuredWidth(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childHeight = child.getMeasuredHeight(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获取子View的LayoutParams\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; gravity = lp.gravity; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (gravity \u0026amp;lt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { gravity = minorGravity; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; layoutDirection = getLayoutDirection(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//依据不同的absoluteGravity计算childLeft位置\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (absoluteGravity \u0026amp; Gravity.HORIZONTAL_GRAVITY_MASK) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; Gravity.CENTER_HORIZONTAL: childLeft = paddingLeft + ((childSpace - childWidth) / \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;) + lp.leftMargin - lp.rightMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; Gravity.RIGHT: childLeft = childRight - childWidth - lp.rightMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; Gravity.LEFT: \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;default\u0026amp;lt;/span\u0026gt;: childLeft = paddingLeft + lp.leftMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (hasDividerBeforeChildAt(i)) { childTop += mDividerHeight; } childTop += lp.topMargin; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//通过垂直排列计算调运child的layout设置child的位置\u0026amp;lt;/span\u0026gt; setChildFrame(child, childLeft, childTop + getLocationOffset(child), childWidth, childHeight); childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child); i += getChildrenSkipCount(child, i); } } }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\n43\n44\n45\n46\n47\n48\n49\n50\n51\n52\n53\n54\n55\n56\n57\n58\n59\n60\n61\n62\n63\n64\n65\n66\n67\n68\n69\n70\n71\n72\n73\n74\n75\n76\n77\n78\n79\n80\n81\n82\n83\n84\n85\n86\n87\n从上面分析的ViewGroup子类LinearLayout的onLayout实现代码可以看出，一般情况下layout过程会参考measure过程中计算得到的mMeasuredWidth和mMeasuredHeight来安排子View在父View中显示的位置，但这不是必须的，measure过程得到的结果可能完全没有实际用处，特别是对于一些自定义的ViewGroup，其子View的个数、位置和大小都是固定的，这时候我们可以忽略整个measure过程，只在layout函数中传入的4个参数来安排每个子View的具体位置。\n到这里就不得不提getWidth()、getHeight()和getMeasuredWidth()、getMeasuredHeight()这两对方法之间的区别（上面分析measure过程已经说过getMeasuredWidth()、getMeasuredHeight()必须在onMeasure之后使用才有效）。可以看出来getWidth()与getHeight()方法必须在layout(int l, int t, int r, int b)执行之后才有效。那我们看下View源码中这些方法的实现吧，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getMeasuredWidth\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mMeasuredWidth \u0026amp; MEASURED_SIZE_MASK; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getMeasuredHeight\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mMeasuredHeight \u0026amp; MEASURED_SIZE_MASK; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getWidth\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mRight - mLeft; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getHeight\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mBottom - mTop; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getLeft\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mLeft; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getRight\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mRight; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getTop\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mTop; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getBottom\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mBottom; }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n这也解释了为什么有些情况下getWidth()和getMeasuredWidth()以及getHeight()和getMeasuredHeight()会得到不同的值，所以这里不做过多解释。\n到此整个View的layout过程分析就算结束了，接下来进行一些总结工作。\n3-2 layout原理总结 整个layout过程比较容易理解，从上面分析可以看出layout也是从顶层父View向子View的递归调用view.layout方法的过程，即父View根据上一步measure子View所得到的布局大小和布局参数，将子View放在合适的位置上。具体layout核心主要有以下几点：\nView.layout方法可被重载，ViewGroup.layout为final的不可重载，ViewGroup.onLayout为abstract的，子类必须重载实现自己的位置逻辑。 measure操作完成后得到的是对每个View经测量过的measuredWidth和measuredHeight，layout操作完成之后得到的是对每个View进行位置分配后的mLeft、mTop、mRight、mBottom，这些值都是相对于父View来说的。 凡是layout_XXX的布局属性基本都针对的是包含子View的ViewGroup的，当对一个没有父容器的View设置相关layout_XXX属性是没有任何意义的（前面《Android应用setContentView与LayoutInflater加载解析机制源码分析》也有提到过）。 使用View的getWidth()和getHeight()方法来获取View测量的宽高，必须保证这两个方法在onLayout流程之后被调用才能返回有效值。 【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处，尊重分享成果】\n4 View绘制流程第三步：递归draw源码分析 在上面的背景介绍就说过，当ViewRootImpl的performTraversals中measure和layout执行完成以后会接着执行mView.layout，具体如下：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;performTraversals\u0026amp;lt;/span\u0026gt;() { ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; Rect dirty = mDirty; ...... canvas = mSurface.lockCanvas(dirty); ...... mView.draw(canvas); ...... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\ndraw过程也是在ViewRootImpl的performTraversals()内部调运的，其调用顺序在measure()和layout()之后，这里的mView对于Actiity来说就是PhoneWindow.DecorView，ViewRootImpl中的代码会创建一个Canvas对象，然后调用View的draw()方法来执行具体的绘制工。所以又回归到了ViewGroup与View的树状递归draw过程。\n先来看下View树的递归draw流程图，如下：\n如下我们详细分析这一过程。\n4-1 draw源码分析 由于ViewGroup没有重写View的draw方法，所以如下直接从View的draw方法开始分析：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;draw\u0026amp;lt;/span\u0026gt;(Canvas canvas) { ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* * Draw traversal performs several drawing steps which must be executed * in the appropriate order: * * 1. Draw the background * 2. If necessary, save the canvas\u0026#39; layers to prepare for fading * 3. Draw view\u0026#39;s content * 4. Draw children * 5. If necessary, draw the fading edges and restore layers * 6. Draw decorations (scrollbars for instance) */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Step 1, draw the background, if needed\u0026amp;lt;/span\u0026gt; ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!dirtyOpaque) { drawBackground(canvas); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// skip step 2 \u0026amp; 5 if possible (common case)\u0026amp;lt;/span\u0026gt; ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Step 2, save the canvas\u0026#39; layers\u0026amp;lt;/span\u0026gt; ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (drawTop) { canvas.saveLayer(left, top, right, top + length, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;, flags); } ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Step 3, draw the content\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!dirtyOpaque) onDraw(canvas); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Step 4, draw the children\u0026amp;lt;/span\u0026gt; dispatchDraw(canvas); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Step 5, draw the fade effect and restore layers\u0026amp;lt;/span\u0026gt; ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (drawTop) { matrix.setScale(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;, fadeHeight * topFadeStrength); matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(left, top, right, top + length, p); } ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Step 6, draw decorations (scrollbars)\u0026amp;lt;/span\u0026gt; onDrawScrollBars(canvas); ...... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\n43\n44\n45\n46\n47\n48\n49\n50\n51\n看见整个View的draw方法很复杂，但是源码注释也很明显。从注释可以看出整个draw过程分为了6步。源码注释说（”skip step 2 \u0026amp; 5 if possible (common case)”）第2和5步可以跳过，所以我们接下来重点剩余四步。如下：\n第一步，对View的背景进行绘制。\n可以看见，draw方法通过调运drawBackground(canvas);方法实现了背景绘制。我们来看下这个方法源码，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawBackground\u0026amp;lt;/span\u0026gt;(Canvas canvas) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//获取xml中通过android:background属性或者代码中setBackgroundColor()、setBackgroundResource()等方法进行赋值的背景Drawable\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; Drawable background = mBackground; ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//根据layout过程确定的View位置来设置背景的绘制区域\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mBackgroundSizeChanged) { background.setBounds(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mRight - mLeft, mBottom - mTop); mBackgroundSizeChanged = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; rebuildOutline(); } ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//调用Drawable的draw()方法来完成背景的绘制工作\u0026amp;lt;/span\u0026gt; background.draw(canvas); ...... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n第三步，对View的内容进行绘制。\n可以看到，这里去调用了一下View的onDraw()方法，所以我们看下View的onDraw方法（ViewGroup也没有重写该方法），如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * Implement this to do your drawing. * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; canvas the canvas on which the background will be drawn */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDraw\u0026amp;lt;/span\u0026gt;(Canvas canvas) { }` 1\n2\n3\n4\n5\n6\n7\n可以看见，这是一个空方法。因为每个View的内容部分是各不相同的，所以需要由子类去实现具体逻辑。\n第四步，对当前View的所有子View进行绘制，如果当前的View没有子View就不需要进行绘制。\n我们来看下View的draw方法中的dispatchDraw(canvas);方法源码，可以看见如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * Called by draw to draw the child views. This may be overridden * by derived classes to gain control just before its children are drawn * (but after its own view has been drawn). *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; canvas the canvas on which to draw the view */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dispatchDraw\u0026amp;lt;/span\u0026gt;(Canvas canvas) { }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n看见没有，View的dispatchDraw()方法是一个空方法，而且注释说明了如果View包含子类需要重写他，所以我们有必要看下ViewGroup的dispatchDraw方法源码（这也就是刚刚说的对当前View的所有子View进行绘制，如果当前的View没有子View就不需要进行绘制的原因，因为如果是View调运该方法是空的，而ViewGroup才有实现），如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dispatchDraw\u0026amp;lt;/span\u0026gt;(Canvas canvas) { ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childrenCount = mChildrenCount; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; View[] children = mChildren; ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; childrenCount; i++) { ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; ((child.mViewFlags \u0026amp; VISIBILITY_MASK) == VISIBLE || child.getAnimation() != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { more |= drawChild(canvas, child, drawingTime); } } ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Draw any disappearing views that have animations\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mDisappearingChildren != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = disappearingCount; i \u0026amp;gt;= \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i--) { ...... more |= drawChild(canvas, child, drawingTime); } } ...... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n可以看见，ViewGroup确实重写了View的dispatchDraw()方法，该方法内部会遍历每个子View，然后调用drawChild()方法，我们可以看下ViewGroup的drawChild方法，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawChild\u0026amp;lt;/span\u0026gt;(Canvas canvas, View child, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;long\u0026amp;lt;/span\u0026gt; drawingTime) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; child.draw(canvas, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, drawingTime); }` 1\n2\n3\n可以看见drawChild()方法调运了子View的draw()方法。所以说ViewGroup类已经为我们重写了dispatchDraw()的功能实现，我们一般不需要重写该方法，但可以重载父类函数实现具体的功能。\n第六步，对View的滚动条进行绘制。\n可以看到，这里去调用了一下View的onDrawScrollBars()方法，所以我们看下View的onDrawScrollBars(canvas);方法，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * \u0026amp;lt;p\u0026amp;gt;Request the drawing of the horizontal and the vertical scrollbar. The * scrollbars are painted only if they have been awakened first.\u0026amp;lt;/p\u0026amp;gt; * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; canvas the canvas on which to draw the scrollbars * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @see\u0026amp;lt;/span\u0026gt; #awakenScrollBars(int) */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDrawScrollBars\u0026amp;lt;/span\u0026gt;(Canvas canvas) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//绘制ScrollBars分析不是我们这篇的重点，所以暂时不做分析\u0026amp;lt;/span\u0026gt; ...... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n可以看见其实任何一个View都是有（水平垂直）滚动条的，只是一般情况下没让它显示而已。\n到此，View的draw绘制部分源码分析完毕，我们接下来进行一些总结。\n4-2 draw原理总结 可以看见，绘制过程就是把View对象绘制到屏幕上，整个draw过程需要注意如下细节：\n如果该View是一个ViewGroup，则需要递归绘制其所包含的所有子View。 View默认不会绘制任何内容，真正的绘制都需要自己在子类中实现。 View的绘制是借助onDraw方法传入的Canvas类来进行的。 区分View动画和ViewGroup布局动画，前者指的是View自身的动画，可以通过setAnimation添加，后者是专门针对ViewGroup显示内部子视图时设置的动画，可以在xml布局文件中对ViewGroup设置layoutAnimation属性（譬如对LinearLayout设置子View在显示时出现逐行、随机、下等显示等不同动画效果）。 在获取画布剪切区（每个View的draw中传入的Canvas）时会自动处理掉padding，子View获取Canvas不用关注这些逻辑，只用关心如何绘制即可。 默认情况下子View的ViewGroup.drawChild绘制顺序和子View被添加的顺序一致，但是你也可以重载ViewGroup.getChildDrawingOrder()方法提供不同顺序。 【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处，尊重分享成果】\n5 View的invalidate和postInvalidate方法源码分析 你可能已经看见了，在上面分析View的三步绘制流程中最后都有调运一个叫invalidate的方法，这个方法是啥玩意？为何出现频率这么高？很简单，我们拿出来分析分析不就得了。\n5-1 invalidate方法源码分析 来看一下View类中的一些invalidate方法（ViewGroup没有重写这些方法），如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * Mark the area defined by dirty as needing to be drawn. If the view is * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some * point in the future. * \u0026amp;lt;p\u0026amp;gt; * This must be called from a UI thread. To call from a non-UI thread, call * {@link #postInvalidate()}. * \u0026amp;lt;p\u0026amp;gt; * \u0026amp;lt;b\u0026amp;gt;WARNING:\u0026amp;lt;/b\u0026amp;gt; In API 19 and below, this method may be destructive to * {@code dirty}. * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; dirty the rectangle representing the bounds of the dirty region */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//看见上面注释没有？public，只能在UI Thread中使用，别的Thread用postInvalidate方法，View是可见的才有效，回调onDraw方法,针对局部View\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;invalidate\u0026amp;lt;/span\u0026gt;(Rect dirty) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; scrollX = mScrollX; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; scrollY = mScrollY; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//实质还是调运invalidateInternal方法\u0026amp;lt;/span\u0026gt; invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, dirty.right - scrollX, dirty.bottom - scrollY, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The * coordinates of the dirty rect are relative to the view. If the view is * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some * point in the future. * \u0026amp;lt;p\u0026amp;gt; * This must be called from a UI thread. To call from a non-UI thread, call * {@link #postInvalidate()}. * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; l the left position of the dirty region *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; t the top position of the dirty region *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; r the right position of the dirty region *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; b the bottom position of the dirty region */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//看见上面注释没有？public，只能在UI Thread中使用，别的Thread用postInvalidate方法，View是可见的才有效，回调onDraw方法，针对局部View\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;invalidate\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; l, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; t, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; r, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; b) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; scrollX = mScrollX; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; scrollY = mScrollY; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//实质还是调运invalidateInternal方法\u0026amp;lt;/span\u0026gt; invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * Invalidate the whole view. If the view is visible, * {@link #onDraw(android.graphics.Canvas)} will be called at some point in * the future. * \u0026amp;lt;p\u0026amp;gt; * This must be called from a UI thread. To call from a non-UI thread, call * {@link #postInvalidate()}. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//看见上面注释没有？public，只能在UI Thread中使用，别的Thread用postInvalidate方法，View是可见的才有效，回调onDraw方法，针对整个View\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;invalidate\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//invalidate的实质还是调运invalidateInternal方法\u0026amp;lt;/span\u0026gt; invalidate(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * This is where the invalidate() work actually happens. A full invalidate() * causes the drawing cache to be invalidated, but this function can be * called with invalidateCache set to false to skip that invalidation step * for cases that do not need it (for example, a component that remains at * the same dimensions with the same content). * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; invalidateCache Whether the drawing cache for this view should be * invalidated as well. This is usually true for a full * invalidate, but may be set to false if the View\u0026#39;s contents or * dimensions have not changed. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//看见上面注释没有？default的权限，只能在UI Thread中使用，别的Thread用postInvalidate方法，View是可见的才有效，回调onDraw方法，针对整个View\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; invalidate(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; invalidateCache) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//实质还是调运invalidateInternal方法\u0026amp;lt;/span\u0026gt; invalidateInternal(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mRight - mLeft, mBottom - mTop, invalidateCache, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//！！！！！！看见没有，这是所有invalidate的终极调运方法！！！！！！\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; invalidateInternal(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; l, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; t, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; r, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; b, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; invalidateCache, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; fullInvalidate) { ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Propagate the damage rectangle to the parent view.\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; AttachInfo ai = mAttachInfo; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; ViewParent p = mParent; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (p != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; ai != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; l \u0026amp;lt; r \u0026amp;\u0026amp; t \u0026amp;lt; b) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; Rect damage = ai.mTmpInvalRect; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置刷新区域\u0026amp;lt;/span\u0026gt; damage.set(l, t, r, b); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//传递调运Parent ViewGroup的invalidateChild方法\u0026amp;lt;/span\u0026gt; p.invalidateChild(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, damage); } ...... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\n43\n44\n45\n46\n47\n48\n49\n50\n51\n52\n53\n54\n55\n56\n57\n58\n59\n60\n61\n62\n63\n64\n65\n66\n67\n68\n69\n70\n71\n72\n73\n74\n75\n76\n77\n78\n79\n80\n81\n82\n83\n84\n85\n86\n87\n88\n89\n90\n91\n92\n看见没有，View的invalidate（invalidateInternal）方法实质是将要刷新区域直接传递给了父ViewGroup的invalidateChild方法，在invalidate中，调用父View的invalidateChild，这是一个从当前向上级父View回溯的过程，每一层的父View都将自己的显示区域与传入的刷新Rect做交集 。所以我们看下ViewGroup的invalidateChild方法，源码如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;invalidateChild\u0026amp;lt;/span\u0026gt;(View child, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; Rect dirty) { ViewParent parent = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; AttachInfo attachInfo = mAttachInfo; ...... do { ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//循环层层上级调运，直到ViewRootImpl会返回null\u0026amp;lt;/span\u0026gt; parent = parent.invalidateChildInParent(location, dirty); ...... } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;while\u0026amp;lt;/span\u0026gt; (parent != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;); }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n这个过程最后传递到ViewRootImpl的invalidateChildInParent方法结束，所以我们看下ViewRootImpl的invalidateChildInParent方法，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; ViewParent \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;invalidateChildInParent\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] location, Rect dirty) { ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//View调运invalidate最终层层上传到ViewRootImpl后最终触发了该方法\u0026amp;lt;/span\u0026gt; scheduleTraversals(); ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; }` 1\n2\n3\n4\n5\n6\n7\n8\n看见没有？这个ViewRootImpl类的invalidateChildInParent方法直接返回了null，也就是上面ViewGroup中说的，层层上级传递到ViewRootImpl的invalidateChildInParent方法结束了那个do while循环。看见这里调运的scheduleTraversals这个方法吗？scheduleTraversals会通过Handler的Runnable发送一个异步消息，调运doTraversal方法，然后最终调用performTraversals()执行重绘。开头背景知识介绍说过的，performTraversals就是整个View数开始绘制的起始调运地方，所以说View调运invalidate方法的实质是层层上传到父级，直到传递到ViewRootImpl后触发了scheduleTraversals方法，然后整个View树开始重新按照上面分析的View绘制流程进行重绘任务。\n到此View的invalidate方法原理就分析完成了。\n5-2 postInvalidate方法源码分析 上面分析invalidate方法时注释中说该方法只能在UI Thread中执行，其他线程中需要使用postInvalidate方法，所以我们来分析分析postInvalidate这个方法源码。如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;postInvalidate\u0026amp;lt;/span\u0026gt;() { postInvalidateDelayed(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); }` 1\n2\n3\n继续看下他的调运方法postInvalidateDelayed，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;postInvalidateDelayed\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;long\u0026amp;lt;/span\u0026gt; delayMilliseconds) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// We try only with the AttachInfo because there\u0026#39;s no point in invalidating\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// if we are not attached to our window\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; AttachInfo attachInfo = mAttachInfo; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//核心，实质就是调运了ViewRootImpl.dispatchInvalidateDelayed方法\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (attachInfo != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { attachInfo.mViewRootImpl.dispatchInvalidateDelayed(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, delayMilliseconds); } }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n我们继续看他调运的ViewRootImpl类的dispatchInvalidateDelayed方法，如下源码：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dispatchInvalidateDelayed\u0026amp;lt;/span\u0026gt;(View view, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;long\u0026amp;lt;/span\u0026gt; delayMilliseconds) { Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view); mHandler.sendMessageDelayed(msg, delayMilliseconds); }` 1\n2\n3\n4\n看见没有，通过ViewRootImpl类的Handler发送了一条MSG_INVALIDATE消息，继续追踪这条消息的处理可以发现：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;handleMessage\u0026amp;lt;/span\u0026gt;(Message msg) { ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (msg.what) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; MSG_INVALIDATE: ((View) msg.obj).invalidate(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; ...... } ...... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n看见没有，实质就是又在UI Thread中调运了View的invalidate();方法，那接下来View的invalidate();方法我们就不说了，上名已经分析过了。\n到此整个View的postInvalidate方法就分析完成了。\n5-3 invalidate与postInvalidate方法总结 依据上面对View的invalidate分析我总结绘制如下流程图：\n依据上面对View的postInvalidate分析我总结绘制如下流程图：\n关于这两个方法的具体流程和原理上面也分析过了，流程图也给出了，相信已经很明确了，没啥需要解释的了。所以我们对其做一个整体总结，归纳出重点如下：\ninvalidate系列方法请求重绘View树（也就是draw方法），如果View大小没有发生变化就不会调用layout过程，并且只绘制那些“需要重绘的”View，也就是哪个View(View只绘制该View，ViewGroup绘制整个ViewGroup)请求invalidate系列方法，就绘制该View。\n常见的引起invalidate方法操作的原因主要有：\n直接调用invalidate方法.请求重新draw，但只会绘制调用者本身。 触发setSelection方法。请求重新draw，但只会绘制调用者本身。 触发setVisibility方法。 当View可视状态在INVISIBLE转换VISIBLE时会间接调用invalidate方法，继而绘制该View。当View的可视状态在INVISIBLE\\VISIBLE 转换为GONE状态时会间接调用requestLayout和invalidate方法，同时由于View树大小发生了变化，所以会请求measure过程以及draw过程，同样只绘制需要“重新绘制”的视图。 触发setEnabled方法。请求重新draw，但不会重新绘制任何View包括该调用者本身。 触发requestFocus方法。请求View树的draw过程，只绘制“需要重绘”的View。 5-4 通过invalidate方法分析结果回过头去解决一个背景介绍中的疑惑 分析完invalidate后需要你回过头去想一个问题。还记不记得这篇文章的开头背景介绍，我们说整个View绘制流程的最初代码是在ViewRootImpl类的performTraversals()方法中开始的。上面当时只是告诉你了这个结论，至于这个ViewRootImpl类的performTraversals()方法为何会被触发没有说明原因。现在我们就来分析一下这个触发的源头。\n让我们先把大脑思考暂时挪回到《Android应用setContentView与LayoutInflater加载解析机制源码分析》这篇博文的setContentView机制分析中（不清楚的请点击先看这篇文章再回过头来继续看）。我们先来看下那篇博文分析的PhoneWindow的setContentView方法源码，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setContentView\u0026amp;lt;/span\u0026gt;(View view, ViewGroup.LayoutParams params) { ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//如果mContentParent为空进行一些初始化，实质mContentParent是通过findViewById(ID_ANDROID_CONTENT);获取的id为content的FrameLayout的布局（不清楚的请先看《Android应用setContentView与LayoutInflater加载解析机制源码分析》文章）\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mContentParent == \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { installDecor(); } ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//把我们的view追加到mContentParent\u0026amp;lt;/span\u0026gt; mContentParent.addView(view, params); ...... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n这个方法是Activity中setContentView的实现，我们继续看下这个方法里调运的addView方法，也就是ViewGroup的addView方法，如下：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;addView\u0026amp;lt;/span\u0026gt;(View child) { addView(child, -\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;addView\u0026amp;lt;/span\u0026gt;(View child, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; index) { ...... addView(child, index, params); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;addView\u0026amp;lt;/span\u0026gt;(View child, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; index, LayoutParams params) { ...... \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//该方法稍后后面会详细分析\u0026amp;lt;/span\u0026gt; requestLayout(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//重点关注！！！\u0026amp;lt;/span\u0026gt; invalidate(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;); ...... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n看见addView调运invalidate方法没有？这不就真相大白了。当我们写一个Activity时，我们一定会通过setContentView方法将我们要展示的界面传入该方法，该方法会讲我们界面通过addView追加到id为content的一个FrameLayout（ViewGroup）中，然后addView方法中通过调运invalidate(true)去通知触发ViewRootImpl类的performTraversals()方法，至此递归绘制我们自定义的所有布局。\n【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处，尊重分享成果】\n6 View的requestLayout方法源码分析 6-1 requestLayout方法分析 和invalidate类似，其实在上面分析View绘制流程时或多或少都调运到了这个方法，而且这个方法对于View来说也比较重要，所以我们接下来分析一下他。如下View的requestLayout源码：\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;requestLayout\u0026amp;lt;/span\u0026gt;() { ...... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mParent != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; !mParent.isLayoutRequested()) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//由此向ViewParent请求布局\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//从这个View开始向上一直requestLayout，最终到达ViewRootImpl的requestLayout\u0026amp;lt;/span\u0026gt; mParent.requestLayout(); } ...... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n看见没有，当我们触发View的requestLayout时其实质就是层层向上传递，直到ViewRootImpl为止，然后触发ViewRootImpl的requestLayout方法，如下就是ViewRootImpl的requestLayout方法：\n` \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;requestLayout\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//View调运requestLayout最终层层上传到ViewRootImpl后最终触发了该方法\u0026amp;lt;/span\u0026gt; scheduleTraversals(); } }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n看见没有，类似于上面分析的invalidate过程，只是设置的标记不同，导致对于View的绘制流程中触发的方法不同而已。\n6-2 requestLayout方法总结 可以看见，这些方法都是大同小异。对于requestLayout方法来说总结如下：\nrequestLayout()方法会调用measure过程和layout过程，不会调用draw过程，也不会重新绘制任何View包括该调用者本身。\n7 View绘制流程总结 至此整个关于Android应用程序开发中的View绘制机制及相关重要方法都已经分析完毕。关于各个方法的总结这里不再重复，直接通过该文章前面的目录索引到相应方法的总结小节进行查阅即可。\n转自：http://blog.csdn.net/yanbober\n","permalink":"https://blog.zdltech.com/posts/android%E5%BA%94%E7%94%A8%E5%B1%82view%E7%BB%98%E5%88%B6%E6%B5%81%E7%A8%8B%E4%B8%8E%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/","summary":"\u003ch2 id=\"1-背景\"\u003e\u003cstrong\u003e1 背景\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e还记得前面\u003ca href=\"http://blog.csdn.net/yanbober/article/details/45970721\"\u003e《Android应用setContentView与LayoutInflater加载解析机制源码分析》\u003c/a\u003e这篇文章吗？我们有分析到Activity中界面加载显示的基本流程原理，记不记得最终分析结果就是下面的关系：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20150528211309106\"\u003e\u003c/p\u003e\n\u003cp\u003e看见没有，如上图中id为content的内容就是整个View树的结构，所以对每个具体View对象的操作，其实就是个递归的实现。\u003c/p\u003e\n\u003cp\u003e前面\u003ca href=\"http://blog.csdn.net/yanbober/article/details/45887547\"\u003e《Android触摸屏事件派发机制详解与源码分析一(View篇)》\u003c/a\u003e文章的3-1小节说过Android中的任何一个布局、任何一个控件其实都是直接或间接继承自View实现的，当然也包括我们后面一步一步引出的自定义控件也不例外，所以说这些View应该都具有相同的绘制流程与机制才能显示到屏幕上（因为他们都具备相同的父类View，可能每个控件的具体绘制逻辑有差异，但是主流程都是一样的）。经过总结发现每一个View的绘制过程都必须经历三个最主要的过程，也就是measure、layout和draw。\u003c/p\u003e\n\u003cp\u003e既然一个View的绘制主要流程是这三步，那一定有一个开始地方呀，就像一个类从main函数执行一样呀。对于View的绘制开始调运地方这里先给出结论，本文后面会反过来分析原因的，先往下看就行。具体结论如下：\u003c/p\u003e\n\u003cp\u003e整个View树的绘图流程是在ViewRootImpl类的performTraversals()方法（这个方法巨长）开始的，该函数做的执行过程主要是根据之前设置的状态，判断是否重新计算视图大小(measure)、是否重新放置视图的位置(layout)、以及是否重绘 (draw)，其核心也就是通过判断来选择顺序执行这三个方法中的哪个，如下：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;performTraversals\u0026amp;lt;/span\u0026gt;() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ......\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//最外层的根视图的widthMeasureSpec和heightMeasureSpec由来\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//lp.width和lp.height在创建ViewGroup实例时等于MATCH_PARENT\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ......\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ......\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mView.layout(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mView.getMeasuredWidth(), mView.getMeasuredHeight());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ......\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mView.draw(canvas);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ......\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e1\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e2\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e3\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e4\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e5\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e6\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e7\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e8\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e9\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e10\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e11\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e12\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e13\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e14\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`    \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * Figures out the measure spec for the root view in a window based on it\u0026#39;s\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     * layout params.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; windowSize\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *            The available width or height of the window\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @param\u0026amp;lt;/span\u0026gt; rootDimension\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *            The layout params for one dimension (width or height) of the\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *            window.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @return\u0026amp;lt;/span\u0026gt; The measure spec to use to measure the root view.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     */\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getRootMeasureSpec\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; windowSize, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; rootDimension) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; measureSpec;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (rootDimension) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; ViewGroup.LayoutParams.MATCH_PARENT:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// Window can\u0026#39;t resize. Force root view to be windowSize.\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ......\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; measureSpec;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e1\u003c/p\u003e","title":"Android应用层View绘制流程与源码分析"},{"content":"1 背景 前面分析那么多系统源码了，也该暂停下来休息一下，趁昨晚闲着看见一个有意思的需求就操练一下分析源码后的实例演练—-自定义控件。\n这个实例很适合新手入门自定义控件。先看下效果图：\n横屏模式如下：\n竖屏模式如下：\n看见没有，这个控件完全自定义的，连文字等都是自定义的，没有任何图片等资源，就仅仅是一个小的java文件，这个界面只有一个控件。如下咱们看下实现代码。\n!!!!!!! 下载Demo工程源码点击我\n【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处，尊重分享成果】\n2 实例代码 如下就是整个工程的源码了。\n自定义上面展示的控件AreaChartsView源码：\n`\u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * Author : yanbo * Date : 2015-06-03 * Time : 09:22 * Description : 自定义区域描述图表View */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AreaChartsView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;View\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; Paint mPaint; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] mZeroPos = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;]; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] mMaxYPos = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;]; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] mMaxXPos = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;]; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mWidth, mHight; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mRealWidth, mRealHight; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; String mTitleY, mTitleX; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;Integer\u0026amp;gt; mXLevel = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;Integer\u0026amp;gt; mYLevel = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;String\u0026amp;gt; mGridLevelText = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;Integer\u0026amp;gt; mGridColorLevel = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;Integer\u0026amp;gt; mGridTxtColorLevel = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mGridLevel = mXLevel.size() - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//title字符大小\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mXYTitleTextSize = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;40\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mMeasureXpos, mMeasureYpos; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AreaChartsView\u0026amp;lt;/span\u0026gt;(Context context, AttributeSet attrs) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;(context, attrs); mPaint = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setAntiAlias(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;); mPaint.setFilterBitmap(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onLayout\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; changed, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onLayout(changed, left, top, right, bottom); mWidth = getWidth(); mHight = getHeight(); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDraw\u0026amp;lt;/span\u0026gt;(Canvas canvas) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onDraw(canvas); initPosition(); drawXYTitle(canvas); drawXYLine(canvas); drawContent(canvas); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initPosition\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化坐标图的xy交点原点坐标\u0026amp;lt;/span\u0026gt; mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] = mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;; mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] = mHight - mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化坐标图的X轴最大值坐标\u0026amp;lt;/span\u0026gt; mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] = mWidth; mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] = mHight - mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化坐标图的Y轴最大值坐标\u0026amp;lt;/span\u0026gt; mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] = mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;; mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] = mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawXYTitle\u0026amp;lt;/span\u0026gt;(Canvas canvas) { mPaint.setColor(Color.parseColor(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#1FB0E7\u0026#34;\u0026amp;lt;/span\u0026gt;)); mPaint.setTextSize(mXYTitleTextSize); mPaint.setTextAlign(Paint.Align.LEFT); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画Y轴顶的title\u0026amp;lt;/span\u0026gt; canvas.drawText(mTitleY, mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] - mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;, mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] - mXYTitleTextSize, mPaint); mPaint.setTextAlign(Paint.Align.RIGHT); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画X轴顶的title\u0026amp;lt;/span\u0026gt; canvas.drawText(mTitleX, mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] + mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;, mPaint); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawXYLine\u0026amp;lt;/span\u0026gt;(Canvas canvas) { mPaint.setColor(Color.DKGRAY); mPaint.setTextAlign(Paint.Align.RIGHT); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画XY轴\u0026amp;lt;/span\u0026gt; canvas.drawLine(mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;], mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;], mPaint); canvas.drawLine(mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;], mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;], mPaint); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawContent\u0026amp;lt;/span\u0026gt;(Canvas canvas) { mGridLevel = mXLevel.size() - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//计算出偏移title等显示尺标后的真实XY轴长度，便于接下来等分\u0026amp;lt;/span\u0026gt; mRealWidth = (mWidth - mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;); mRealHight = (mHight - mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//算出等分间距\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; offsetX = mRealWidth/(mGridLevel); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; offsetY = mRealHight/(mGridLevel+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//循环绘制content\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; index=\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; index\u0026amp;lt;mGridLevel+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;; index++) { mPaint.setColor(Color.DKGRAY); mPaint.setTextAlign(Paint.Align.RIGHT); mPaint.setTextSize(mXYTitleTextSize-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//绘制X轴的那些坐标区间点，包含0点坐标\u0026amp;lt;/span\u0026gt; canvas.drawText(String.valueOf(mXLevel.get(index)), mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;]+(index*offsetX), mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] + mXYTitleTextSize, mPaint); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (index != \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//绘制Y轴坐标区间点，不包含0点坐标，X轴已经画过了\u0026amp;lt;/span\u0026gt; canvas.drawText(String.valueOf(mYLevel.get(index)), mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;]-(index*offsetY), mPaint); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (index == mGridLevel) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//坐标区间 = 真实区间 + 1\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } mPaint.setColor(mGridColorLevel.get(mGridLevel - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt; - index)); mPaint.setStyle(Paint.Style.FILL); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//绘制区间叠加图谱方块，从远到0坐标，因为小的图会覆盖大的图\u0026amp;lt;/span\u0026gt; canvas.drawRect(mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] + index*offsetY, mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;]-index*offsetX, mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;], mPaint); mPaint.setColor(mGridTxtColorLevel.get(index)); mPaint.setTextAlign(Paint.Align.RIGHT); mPaint.setTextSize(mXYTitleTextSize); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//绘制每个方块状态区间的提示文字\u0026amp;lt;/span\u0026gt; canvas.drawText(mGridLevelText.get(index), mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] - index * offsetX - mXYTitleTextSize, mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] + index * offsetY + mXYTitleTextSize, mPaint); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//绘制当前坐标\u0026amp;lt;/span\u0026gt; drawNotice(canvas, offsetX, offsetY); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawNotice\u0026amp;lt;/span\u0026gt;(Canvas canvas, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; offsetX, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; offsetY) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; realPosX = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; realPosY = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//计算传入的x值与真实屏幕坐标的像素值的百分比差值转换\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; index=\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; index\u0026amp;lt;mGridLevel; index++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mMeasureXpos \u0026amp;gt;= mXLevel.get(index) \u0026amp;\u0026amp; mMeasureXpos \u0026amp;lt; mXLevel.get(index+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;)) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; subValue = mMeasureXpos - mXLevel.get(index); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; offset = mXLevel.get(index+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) - mXLevel.get(index); realPosX = mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] + index*offsetX + (subValue / offset); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//计算传入的y值与真实屏幕坐标的像素值的百分比差值转换\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; index=\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; index\u0026amp;lt;mGridLevel; index++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mMeasureYpos \u0026amp;gt;= mYLevel.get(index) \u0026amp;\u0026amp; mMeasureYpos \u0026amp;lt; mYLevel.get(index+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;)) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; subValue = mMeasureYpos - mYLevel.get(index); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; offset = mYLevel.get(index+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) - mYLevel.get(index); realPosY = mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] - index*offsetY - (offsetY - (subValue / offset)); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画我们传入的坐标点的标记小红点\u0026amp;lt;/span\u0026gt; mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.FILL); canvas.drawCircle(realPosX, realPosY, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;8\u0026amp;lt;/span\u0026gt;, mPaint); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] centerPos = {mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] + mRealWidth/\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;, mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] - mRealHight/\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;}; mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); RectF rectF = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; Path path = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Path(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画红点旁边的提示框和文字，有四个区域，然后提示框的小三角指标方位不同\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (realPosX \u0026amp;lt;= centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] \u0026amp;\u0026amp; realPosY \u0026amp;gt;= centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;]) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//left-bottom\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画三角形\u0026amp;lt;/span\u0026gt; path.moveTo(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;); path.lineTo(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;); path.lineTo(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画矩形背景\u0026amp;lt;/span\u0026gt; rectF = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; RectF(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;40\u0026amp;lt;/span\u0026gt;, realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;200\u0026amp;lt;/span\u0026gt;, realPosY + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;30\u0026amp;lt;/span\u0026gt;); canvas.drawRoundRect(rectF, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, mPaint); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画提示框的文字\u0026amp;lt;/span\u0026gt; mPaint.reset(); mPaint.setColor(Color.RED); mPaint.setTextSize(mXYTitleTextSize - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;); canvas.drawText(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;(\u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureXpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;, \u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureYpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;)\u0026#34;\u0026amp;lt;/span\u0026gt;, realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;30\u0026amp;lt;/span\u0026gt;, realPosY, mPaint); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (realPosX \u0026amp;lt;= centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] \u0026amp;\u0026amp; realPosY \u0026amp;lt; centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;]) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//left-top\u0026amp;lt;/span\u0026gt; path.moveTo(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;); path.lineTo(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;); path.lineTo(realPosX + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;); rectF = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; RectF(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;20\u0026amp;lt;/span\u0026gt;, realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;200\u0026amp;lt;/span\u0026gt;, realPosY + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;50\u0026amp;lt;/span\u0026gt;); canvas.drawRoundRect(rectF, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, mPaint); mPaint.reset(); mPaint.setColor(Color.RED); mPaint.setTextSize(mXYTitleTextSize - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;); canvas.drawText(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;(\u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureXpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;, \u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureYpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;)\u0026#34;\u0026amp;lt;/span\u0026gt;, realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;30\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;20\u0026amp;lt;/span\u0026gt;, mPaint); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (realPosX \u0026amp;gt; centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] \u0026amp;\u0026amp; realPosY \u0026amp;gt;= centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;]) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//right-bottom\u0026amp;lt;/span\u0026gt; path.moveTo(realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;); path.lineTo(realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;); path.lineTo(realPosX - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;); rectF = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; RectF(realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;200\u0026amp;lt;/span\u0026gt;, realPosY-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;40\u0026amp;lt;/span\u0026gt;, realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;30\u0026amp;lt;/span\u0026gt;); canvas.drawRoundRect(rectF, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, mPaint); mPaint.reset(); mPaint.setColor(Color.RED); mPaint.setTextSize(mXYTitleTextSize - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;); canvas.drawText(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;(\u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureXpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;, \u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureYpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;)\u0026#34;\u0026amp;lt;/span\u0026gt;, realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;180\u0026amp;lt;/span\u0026gt;, realPosY, mPaint); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (realPosX \u0026amp;gt; centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] \u0026amp;\u0026amp; realPosY \u0026amp;lt; centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;]) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//right-top\u0026amp;lt;/span\u0026gt; path.moveTo(realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;); path.lineTo(realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;); path.lineTo(realPosX - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;); rectF = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; RectF(realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;200\u0026amp;lt;/span\u0026gt;, realPosY - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;20\u0026amp;lt;/span\u0026gt;, realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;50\u0026amp;lt;/span\u0026gt;); canvas.drawRoundRect(rectF, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, mPaint); mPaint.reset(); mPaint.setColor(Color.RED); mPaint.setTextSize(mXYTitleTextSize - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;); canvas.drawText(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;(\u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureXpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;, \u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureYpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;)\u0026#34;\u0026amp;lt;/span\u0026gt;, realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;180\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;30\u0026amp;lt;/span\u0026gt;, mPaint); } path.close(); mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); canvas.drawPath(path, mPaint); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置当前比值\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;updateValues\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; x, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; y) { mMeasureXpos = x; mMeasureYpos = y; postInvalidate(); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置XY轴顶角的title字体大小\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setTitleTextSize\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; size) { mXYTitleTextSize = size; } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化X轴的坐标区间点值，可以不均等分\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initXLevelOffset\u0026amp;lt;/span\u0026gt;(ArrayList\u0026amp;lt;Integer\u0026amp;gt; list) { mXLevel.clear(); mXLevel.addAll(list); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化Y轴的坐标区间点值，可以不均等分\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initYLevelOffset\u0026amp;lt;/span\u0026gt;(ArrayList\u0026amp;lt;Integer\u0026amp;gt; list) { mYLevel.clear(); mYLevel.addAll(list); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化每个区间的提示文字，如果不想显示可以设置\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initGridLevelText\u0026amp;lt;/span\u0026gt;(ArrayList\u0026amp;lt;String\u0026amp;gt; list) { mGridLevelText.clear(); mGridLevelText.addAll(list); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化每个区间的颜色\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initGridColorLevel\u0026amp;lt;/span\u0026gt;(ArrayList\u0026amp;lt;Integer\u0026amp;gt; list) { mGridColorLevel.clear(); mGridColorLevel.addAll(list); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化每个区间的提示文字颜色\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initGridTxtColorLevel\u0026amp;lt;/span\u0026gt;(ArrayList\u0026amp;lt;Integer\u0026amp;gt; list) { mGridTxtColorLevel.clear(); mGridTxtColorLevel.addAll(list); } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化XY轴title\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initTitleXY\u0026amp;lt;/span\u0026gt;(String x, String y) { mTitleX = x; mTitleY = y; } }` 再来看下布局文件：\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;RelativeLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:tools\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/tools\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;com.yanbober.customerviewdemo.areachartsview.AreaChartsView \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/area_charts_view\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_margin\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;10dp\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;RelativeLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 再看看主界面：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;MainActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AppCompatActivity\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; AreaChartsView mAreaChartsView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; Timer timer; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;(Bundle savedInstanceState) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mAreaChartsView = (AreaChartsView) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.findViewById(R.id.area_charts_view); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化自定义图表的规格和属性\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;Integer\u0026amp;gt; mXLevel = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); ArrayList\u0026amp;lt;Integer\u0026amp;gt; mYLevel = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); ArrayList\u0026amp;lt;String\u0026amp;gt; mGridLevelText = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); ArrayList\u0026amp;lt;Integer\u0026amp;gt; mGridColorLevel = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); ArrayList\u0026amp;lt;Integer\u0026amp;gt; mGridTxtColorLevel = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化x轴坐标区间\u0026amp;lt;/span\u0026gt; mXLevel.add(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); mXLevel.add(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;60\u0026amp;lt;/span\u0026gt;); mXLevel.add(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;90\u0026amp;lt;/span\u0026gt;); mXLevel.add(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;100\u0026amp;lt;/span\u0026gt;); mXLevel.add(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;110\u0026amp;lt;/span\u0026gt;); mXLevel.add(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;120\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化y轴坐标区间\u0026amp;lt;/span\u0026gt; mYLevel.add(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); mYLevel.add(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;90\u0026amp;lt;/span\u0026gt;); mYLevel.add(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;140\u0026amp;lt;/span\u0026gt;); mYLevel.add(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;160\u0026amp;lt;/span\u0026gt;); mYLevel.add(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;180\u0026amp;lt;/span\u0026gt;); mYLevel.add(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;200\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化区间颜色\u0026amp;lt;/span\u0026gt; mGridColorLevel.add(Color.parseColor(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#1FB0E7\u0026#34;\u0026amp;lt;/span\u0026gt;)); mGridColorLevel.add(Color.parseColor(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#4FC7F4\u0026#34;\u0026amp;lt;/span\u0026gt;)); mGridColorLevel.add(Color.parseColor(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#4FDDF2\u0026#34;\u0026amp;lt;/span\u0026gt;)); mGridColorLevel.add(Color.parseColor(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#90E9F4\u0026#34;\u0026amp;lt;/span\u0026gt;)); mGridColorLevel.add(Color.parseColor(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#B2F6F1\u0026#34;\u0026amp;lt;/span\u0026gt;)); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化区间文字提示颜色\u0026amp;lt;/span\u0026gt; mGridTxtColorLevel.add(Color.parseColor(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#EA8868\u0026#34;\u0026amp;lt;/span\u0026gt;)); mGridTxtColorLevel.add(Color.parseColor(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#EA8868\u0026#34;\u0026amp;lt;/span\u0026gt;)); mGridTxtColorLevel.add(Color.parseColor(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#EA8868\u0026#34;\u0026amp;lt;/span\u0026gt;)); mGridTxtColorLevel.add(Color.WHITE); mGridTxtColorLevel.add(Color.BLACK); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化区间文字\u0026amp;lt;/span\u0026gt; mGridLevelText.add(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;异常\u0026#34;\u0026amp;lt;/span\u0026gt;); mGridLevelText.add(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;过高\u0026#34;\u0026amp;lt;/span\u0026gt;); mGridLevelText.add(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;偏高\u0026#34;\u0026amp;lt;/span\u0026gt;); mGridLevelText.add(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;正常\u0026#34;\u0026amp;lt;/span\u0026gt;); mGridLevelText.add(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;偏低\u0026#34;\u0026amp;lt;/span\u0026gt;); mAreaChartsView.initGridColorLevel(mGridColorLevel); mAreaChartsView.initGridLevelText(mGridLevelText); mAreaChartsView.initGridTxtColorLevel(mGridTxtColorLevel); mAreaChartsView.initXLevelOffset(mXLevel); mAreaChartsView.initYLevelOffset(mYLevel); mAreaChartsView.initTitleXY(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;投入量(H)\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;产出量(H)\u0026#34;\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onStart\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onStart(); timer = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Timer(); timer.schedule(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; TimerTask() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;run\u0026amp;lt;/span\u0026gt;() { Random random = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Random(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; x = random.nextInt(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;120\u0026amp;lt;/span\u0026gt;) % (\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;120\u0026amp;lt;/span\u0026gt; + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; Random randomy = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Random(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; y = randomy.nextInt(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;200\u0026amp;lt;/span\u0026gt;) % (\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;200\u0026amp;lt;/span\u0026gt; + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//随机模拟赋值\u0026amp;lt;/span\u0026gt; mAreaChartsView.updateValues(x, y); } }, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1000\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onPause\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onPause(); timer.cancel(); } }` 转自：http://blog.csdn.net/yanbober\n3 总结 上面代码很简单，核心的都已经注释了，不需要过多解释。核心思路就是一些坐标点的计算。该控件支持设置mergin及width与hight等属性，支持自定义所有颜色及显示及坐标区分等，唯一缺陷就是没来得及写attr属性xml设置这些值，有兴趣的自己实现吧，我是没时间了。\n可以发现，自定义View无非就是重写前面文章分析的那三个方法而已。\n!!!!!!! 下载Demo工程源码点击我\n重点只提供实现思路，具体细节没时间优化。有需求的可以在下面讨论。\n","permalink":"https://blog.zdltech.com/posts/android%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6%E7%8A%B6%E6%80%81%E6%8F%90%E7%A4%BA%E5%9B%BE%E8%A1%A8/","summary":"\u003ch2 id=\"1-背景\"\u003e\u003cstrong\u003e1 背景\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e前面分析那么多系统源码了，也该暂停下来休息一下，趁昨晚闲着看见一个有意思的需求就操练一下分析源码后的实例演练—-自定义控件。\u003c/p\u003e\n\u003cp\u003e这个实例很适合新手入门自定义控件。先看下效果图：\u003c/p\u003e\n\u003cp\u003e横屏模式如下：\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20150603105834961\"\u003e\u003cbr\u003e\n竖屏模式如下：\u003cbr\u003e\n\u003cimg alt=\"这里写图片描述\" loading=\"lazy\" src=\"http://img.blog.csdn.net/20150603105737713\"\u003e\u003c/p\u003e\n\u003cp\u003e看见没有，这个控件完全自定义的，连文字等都是自定义的，没有任何图片等资源，就仅仅是一个小的java文件，这个界面只有一个控件。如下咱们看下实现代码。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://github.com/yanbober/Android-Blog-Source/tree/master/CustomerViewDemo\"\u003e!!!!!!! 下载Demo工程源码点击我\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e【工匠若水 \u003ca href=\"http://blog.csdn.net/yanbober\"\u003ehttp://blog.csdn.net/yanbober\u003c/a\u003e 转载烦请注明出处，尊重分享成果】\u003c/p\u003e\n\u003ch2 id=\"2-实例代码\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e\u003cstrong\u003e2 实例代码\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e如下就是整个工程的源码了。\u003c/p\u003e\n\u003cp\u003e自定义上面展示的控件AreaChartsView源码：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e * Author       : yanbo\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e * Date         : 2015-06-03\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e * Time         : 09:22\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e * Description  : 自定义区域描述图表View\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e */\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AreaChartsView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;View\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; Paint mPaint;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] mZeroPos = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] mMaxYPos = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] mMaxXPos = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mWidth, mHight;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mRealWidth, mRealHight;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; String mTitleY, mTitleX;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;Integer\u0026amp;gt; mXLevel = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;Integer\u0026amp;gt; mYLevel = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;String\u0026amp;gt; mGridLevelText = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;Integer\u0026amp;gt; mGridColorLevel = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;Integer\u0026amp;gt; mGridTxtColorLevel = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;\u0026amp;gt;();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mGridLevel = mXLevel.size() - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//title字符大小\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mXYTitleTextSize = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;40\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mMeasureXpos, mMeasureYpos;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;AreaChartsView\u0026amp;lt;/span\u0026gt;(Context context, AttributeSet attrs) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;(context, attrs);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Paint(Paint.ANTI_ALIAS_FLAG);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setAntiAlias(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setFilterBitmap(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onLayout\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; changed, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onLayout(changed, left, top, right, bottom);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mWidth = getWidth();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mHight = getHeight();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDraw\u0026amp;lt;/span\u0026gt;(Canvas canvas) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onDraw(canvas);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        initPosition();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        drawXYTitle(canvas);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        drawXYLine(canvas);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        drawContent(canvas);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initPosition\u0026amp;lt;/span\u0026gt;() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化坐标图的xy交点原点坐标\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] = mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] = mHight - mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化坐标图的X轴最大值坐标\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] = mWidth;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] = mHight - mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化坐标图的Y轴最大值坐标\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] = mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] = mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawXYTitle\u0026amp;lt;/span\u0026gt;(Canvas canvas) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setColor(Color.parseColor(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#1FB0E7\u0026#34;\u0026amp;lt;/span\u0026gt;));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setTextSize(mXYTitleTextSize);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setTextAlign(Paint.Align.LEFT);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画Y轴顶的title\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        canvas.drawText(mTitleY, mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] - mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;, mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] - mXYTitleTextSize, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setTextAlign(Paint.Align.RIGHT);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画X轴顶的title\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        canvas.drawText(mTitleX, mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] + mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawXYLine\u0026amp;lt;/span\u0026gt;(Canvas canvas) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setColor(Color.DKGRAY);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setTextAlign(Paint.Align.RIGHT);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画XY轴\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        canvas.drawLine(mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;], mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;], mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        canvas.drawLine(mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;], mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;], mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawContent\u0026amp;lt;/span\u0026gt;(Canvas canvas) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mGridLevel = mXLevel.size() - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//计算出偏移title等显示尺标后的真实XY轴长度，便于接下来等分\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mRealWidth = (mWidth - mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mRealHight = (mHight - mXYTitleTextSize * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//算出等分间距\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; offsetX = mRealWidth/(mGridLevel);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; offsetY = mRealHight/(mGridLevel+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//循环绘制content\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; index=\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; index\u0026amp;lt;mGridLevel+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;; index++) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setColor(Color.DKGRAY);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setTextAlign(Paint.Align.RIGHT);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setTextSize(mXYTitleTextSize-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//绘制X轴的那些坐标区间点，包含0点坐标\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            canvas.drawText(String.valueOf(mXLevel.get(index)), mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;]+(index*offsetX), mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] + mXYTitleTextSize, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (index != \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//绘制Y轴坐标区间点，不包含0点坐标，X轴已经画过了\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                canvas.drawText(String.valueOf(mYLevel.get(index)), mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;]-(index*offsetY), mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (index == mGridLevel) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//坐标区间 = 真实区间 + 1\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setColor(mGridColorLevel.get(mGridLevel - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt; - index));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setStyle(Paint.Style.FILL);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//绘制区间叠加图谱方块，从远到0坐标，因为小的图会覆盖大的图\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            canvas.drawRect(mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;], mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] + index*offsetY, mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;]-index*offsetX, mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;], mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setColor(mGridTxtColorLevel.get(index));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setTextAlign(Paint.Align.RIGHT);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setTextSize(mXYTitleTextSize);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//绘制每个方块状态区间的提示文字\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            canvas.drawText(mGridLevelText.get(index), mMaxXPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] - index * offsetX - mXYTitleTextSize,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    mMaxYPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] + index * offsetY + mXYTitleTextSize, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//绘制当前坐标\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        drawNotice(canvas, offsetX, offsetY);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawNotice\u0026amp;lt;/span\u0026gt;(Canvas canvas, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; offsetX, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; offsetY) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; realPosX = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; realPosY = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//计算传入的x值与真实屏幕坐标的像素值的百分比差值转换\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; index=\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; index\u0026amp;lt;mGridLevel; index++) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mMeasureXpos \u0026amp;gt;= mXLevel.get(index) \u0026amp;\u0026amp; mMeasureXpos \u0026amp;lt; mXLevel.get(index+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; subValue = mMeasureXpos - mXLevel.get(index);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; offset = mXLevel.get(index+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) - mXLevel.get(index);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                realPosX = mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] + index*offsetX + (subValue / offset);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//计算传入的y值与真实屏幕坐标的像素值的百分比差值转换\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; index=\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; index\u0026amp;lt;mGridLevel; index++) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mMeasureYpos \u0026amp;gt;= mYLevel.get(index) \u0026amp;\u0026amp; mMeasureYpos \u0026amp;lt; mYLevel.get(index+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; subValue = mMeasureYpos - mYLevel.get(index);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; offset = mYLevel.get(index+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) - mYLevel.get(index);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                realPosY = mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] - index*offsetY - (offsetY - (subValue / offset));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画我们传入的坐标点的标记小红点\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setColor(Color.RED);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setStyle(Paint.Style.FILL);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        canvas.drawCircle(realPosX, realPosY, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;8\u0026amp;lt;/span\u0026gt;, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] centerPos = {mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] + mRealWidth/\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;, mZeroPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;] - mRealHight/\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2\u0026amp;lt;/span\u0026gt;};\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setColor(Color.WHITE);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        RectF rectF = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        Path path = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Path();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画红点旁边的提示框和文字，有四个区域，然后提示框的小三角指标方位不同\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (realPosX \u0026amp;lt;= centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] \u0026amp;\u0026amp; realPosY \u0026amp;gt;= centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;]) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//left-bottom\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画三角形\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path.moveTo(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path.lineTo(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path.lineTo(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画矩形背景\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            rectF = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; RectF(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;40\u0026amp;lt;/span\u0026gt;, realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;200\u0026amp;lt;/span\u0026gt;, realPosY + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;30\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            canvas.drawRoundRect(rectF, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//画提示框的文字\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.reset();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setColor(Color.RED);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setTextSize(mXYTitleTextSize - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            canvas.drawText(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;(\u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureXpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;, \u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureYpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;)\u0026#34;\u0026amp;lt;/span\u0026gt;, realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;30\u0026amp;lt;/span\u0026gt;, realPosY, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (realPosX \u0026amp;lt;= centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] \u0026amp;\u0026amp; realPosY \u0026amp;lt; centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;]) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//left-top\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path.moveTo(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path.lineTo(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path.lineTo(realPosX + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            rectF = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; RectF(realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;20\u0026amp;lt;/span\u0026gt;, realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;200\u0026amp;lt;/span\u0026gt;, realPosY + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;50\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            canvas.drawRoundRect(rectF, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.reset();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setColor(Color.RED);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setTextSize(mXYTitleTextSize - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            canvas.drawText(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;(\u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureXpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;, \u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureYpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;)\u0026#34;\u0026amp;lt;/span\u0026gt;, realPosX+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;30\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;20\u0026amp;lt;/span\u0026gt;, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (realPosX \u0026amp;gt; centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] \u0026amp;\u0026amp; realPosY \u0026amp;gt;= centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;]) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//right-bottom\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path.moveTo(realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path.lineTo(realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path.lineTo(realPosX - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            rectF = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; RectF(realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;200\u0026amp;lt;/span\u0026gt;, realPosY-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;40\u0026amp;lt;/span\u0026gt;, realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;30\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            canvas.drawRoundRect(rectF, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.reset();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setColor(Color.RED);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setTextSize(mXYTitleTextSize - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            canvas.drawText(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;(\u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureXpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;, \u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureYpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;)\u0026#34;\u0026amp;lt;/span\u0026gt;, realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;180\u0026amp;lt;/span\u0026gt;, realPosY, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (realPosX \u0026amp;gt; centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;] \u0026amp;\u0026amp; realPosY \u0026amp;lt; centerPos[\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;]) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//right-top\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path.moveTo(realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path.lineTo(realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path.lineTo(realPosX - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            rectF = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; RectF(realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;200\u0026amp;lt;/span\u0026gt;, realPosY - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;20\u0026amp;lt;/span\u0026gt;, realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, realPosY + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;50\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            canvas.drawRoundRect(rectF, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;15\u0026amp;lt;/span\u0026gt;, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.reset();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setColor(Color.RED);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mPaint.setTextSize(mXYTitleTextSize - \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;5\u0026amp;lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            canvas.drawText(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;(\u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureXpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;, \u0026#34;\u0026amp;lt;/span\u0026gt;+mMeasureYpos+\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;)\u0026#34;\u0026amp;lt;/span\u0026gt;, realPosX-\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;180\u0026amp;lt;/span\u0026gt;, realPosY+\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;30\u0026amp;lt;/span\u0026gt;, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        path.close();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setColor(Color.WHITE);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        canvas.drawPath(path, mPaint);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置当前比值\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;updateValues\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; x, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; y) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mMeasureXpos = x;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mMeasureYpos = y;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        postInvalidate();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置XY轴顶角的title字体大小\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setTitleTextSize\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; size) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mXYTitleTextSize = size;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化X轴的坐标区间点值，可以不均等分\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initXLevelOffset\u0026amp;lt;/span\u0026gt;(ArrayList\u0026amp;lt;Integer\u0026amp;gt; list) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mXLevel.clear();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mXLevel.addAll(list);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化Y轴的坐标区间点值，可以不均等分\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initYLevelOffset\u0026amp;lt;/span\u0026gt;(ArrayList\u0026amp;lt;Integer\u0026amp;gt; list) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mYLevel.clear();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mYLevel.addAll(list);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化每个区间的提示文字，如果不想显示可以设置\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initGridLevelText\u0026amp;lt;/span\u0026gt;(ArrayList\u0026amp;lt;String\u0026amp;gt; list) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mGridLevelText.clear();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mGridLevelText.addAll(list);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化每个区间的颜色\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initGridColorLevel\u0026amp;lt;/span\u0026gt;(ArrayList\u0026amp;lt;Integer\u0026amp;gt; list) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mGridColorLevel.clear();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mGridColorLevel.addAll(list);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化每个区间的提示文字颜色\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initGridTxtColorLevel\u0026amp;lt;/span\u0026gt;(ArrayList\u0026amp;lt;Integer\u0026amp;gt; list) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mGridTxtColorLevel.clear();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mGridTxtColorLevel.addAll(list);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//初始化XY轴title\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initTitleXY\u0026amp;lt;/span\u0026gt;(String x, String y) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mTitleX = x;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mTitleY = y;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e再来看下布局文件：\u003c/p\u003e","title":"Android自定义控件（状态提示图表）"},{"content":"转载：http://blog.csdn.net/zhaokaiqiang1992\nAndroid的屏幕适配一直以来都在折磨着我们这些开发者，本篇文章以Google的官方文档为基础，全面而深入的讲解了Android屏幕适配的原因、重要概念、解决方案及最佳实践，我相信如果你能认真的学习本文，对于Android的屏幕适配，你将有所收获！\n- [Android屏幕适配出现的原因](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#android屏幕适配出现的原因) - [重要概念](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#重要概念) - [屏幕尺寸](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#屏幕尺寸) - [屏幕分辨率](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#屏幕分辨率) - [屏幕像素密度](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#屏幕像素密度) - [dpdipdpisppx](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#dpdipdpisppx) - [mdpihdpixdpixxdpi](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#mdpihdpixdpixxdpi) - [解决方案](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#解决方案) - [支持各种屏幕尺寸](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#支持各种屏幕尺寸) - [使用wrap_contentmatch_parentweight](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用wrapcontentmatchparentweight) - [使用相对布局禁用绝对布局](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用相对布局禁用绝对布局) - [使用限定符](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用限定符) - [使用尺寸限定符](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用尺寸限定符) - [使用最小宽度限定符](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用最小宽度限定符) - [使用布局别名](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用布局别名) - [使用屏幕方向限定符](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用屏幕方向限定符) - [使用自动拉伸位图](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用自动拉伸位图) - [支持各种屏幕密度](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#支持各种屏幕密度) - [使用非密度制约像素](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用非密度制约像素) - [提供备用位图](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#提供备用位图) - [实施自适应用户界面流程](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#实施自适应用户界面流程) - [确定当前布局](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#确定当前布局) - [根据当前布局做出响应](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#根据当前布局做出响应) - [重复使用其他活动中的片段](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#重复使用其他活动中的片段) - [处理屏幕配置变化](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#处理屏幕配置变化) - [最佳实践](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#最佳实践) - [关于高清设计图尺寸](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#关于高清设计图尺寸) - [ImageView的ScaleType属性](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#imageview的scaletype属性) - [动态设置](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#动态设置) - [更多参考资料](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#更多参考资料) Android屏幕适配出现的原因 在我们学习如何进行屏幕适配之前，我们需要先了解下为什么Android需要进行屏幕适配。\n由于Android系统的开放性，任何用户、开发者、OEM厂商、运营商都可以对Android进行定制，修改成他们想要的样子。\n但是这种“碎片化”到底到达什么程度呢？\n在2012年，OpenSignalMaps（以下简称OSM）发布了第一份Android碎片化报告，统计数据表明，\n2012年，支持Android的设备共有3997种。 2013年，支持Android的设备共有11868种。 2014年，支持Android的设备共有18796种。 下面这张图片所显示的内容足以充分说明当今Android系统碎片化问题的严重性，因为该图片中的每一个矩形都代表着一种Android设备。\n而随着支持Android系统的设备(手机、平板、电视、手表)的增多，设备碎片化、品牌碎片化、系统碎片化、传感器碎片化和屏幕碎片化的程度也在不断地加深。而我们今天要探讨的，则是对我们开发影响比较大的——屏幕的碎片化。\n下面这张图是Android屏幕尺寸的示意图，在这张图里面，蓝色矩形的大小代表不同尺寸，颜色深浅则代表所占百分比的大小。\n而与之相对应的，则是下面这张图。这张图显示了IOS设备所需要进行适配的屏幕尺寸和占比。\n当然，这张图片只是4,4s,5,5c,5s和平板的尺寸，现在还应该加上新推出的iphone6和plus，但是和Android的屏幕碎片化程度相比而言，还是差的太远。\n详细的统计数据请到这里查看\n现在你应该很清楚为什么要对Android的屏幕进行适配了吧？屏幕尺寸这么多，为了让我们开发的程序能够比较美观的显示在不同尺寸、分辨率、像素密度(这些概念我会在下面详细讲解)的设备上，那就要在开发的过程中进行处理，至于如何去进行处理，这就是我们今天的主题了。\n但是在开始进入主题之前，我们再来探讨一件事情，那就是Android设备的屏幕尺寸，从几寸的智能手机，到10寸的平板电脑，再到几十寸的数字电视，我们应该适配哪些设备呢？\n其实这个问题不应该这么考虑，因为对于具有相同像素密度的设备来说，像素越高，尺寸就越大，所以我们可以换个思路，将问题从单纯的尺寸大小转换到像素大小和像素密度的角度来。\n下图是2014年初，友盟统计的占比5%以上的6个主流分辨率，可以看出，占比最高的是480*800，320*480的设备竟然也占据了很大比例，但是和半年前的数据相比较，中低分辨率(320*480、480*800)的比例在减少，而中高分辨率的比例则在不断地增加。虽然每个分辨率所占的比例在变化，但是总的趋势没变，还是这六种，只是分辨率在不断地提高。\n所以说，我们只要尽量适配这几种分辨率，就可以在大部分的手机上正常运行了。\n当然了，这只是手机的适配，对于平板设备(电视也可以看做是平板)，我们还需要一些其他的处理。\n好了，到目前为止，我们已经弄清楚了Android开发为什么要进行适配，以及我们应该适配哪些对象，接下来，终于进入我们的正题了！\n首先，我们先要学习几个重要的概念。\n重要概念 什么是屏幕尺寸、屏幕分辨率、屏幕像素密度？\n什么是dp、dip、dpi、sp、px？他们之间的关系是什么？\n什么是mdpi、hdpi、xdpi、xxdpi？如何计算和区分？\n在下面的内容中我们将介绍这些概念。\n屏幕尺寸 屏幕尺寸指屏幕的对角线的长度，单位是英寸，1英寸=2.54厘米\n比如常见的屏幕尺寸有2.4、2.8、3.5、3.7、4.2、5.0、5.5、6.0等\n屏幕分辨率 屏幕分辨率是指在横纵向上的像素点数，单位是px，1px=1个像素点。一般以纵向像素*横向像素，如1960*1080。\n屏幕像素密度 屏幕像素密度是指每英寸上的像素点数，单位是dpi，即“dot per inch”的缩写。屏幕像素密度与屏幕尺寸和屏幕分辨率有关，在单一变化条件下，屏幕尺寸越小、分辨率越高，像素密度越大，反之越小。\ndp、dip、dpi、sp、px px我们应该是比较熟悉的，前面的分辨率就是用的像素为单位，大多数情况下，比如UI设计、Android原生API都会以px作为统一的计量单位，像是获取屏幕宽高等。\ndip和dp是一个意思，都是Density Independent Pixels的缩写，即密度无关像素，上面我们说过，dpi是屏幕像素密度，假如一英寸里面有160个像素，这个屏幕的像素密度就是160dpi，那么在这种情况下，dp和px如何换算呢？在Android中，规定以160dpi为基准，1dip=1px，如果密度是320dpi，则1dip=2px，以此类推。\n假如同样都是画一条320px的线，在480*800分辨率手机上显示为2/3屏幕宽度，在320*480的手机上则占满了全屏，如果使用dp为单位，在这两种分辨率下，160dp都显示为屏幕一般的长度。这也是为什么在Android开发中，写布局的时候要尽量使用dp而不是px的原因。\n而sp，即scale-independent pixels，与dp类似，但是可以根据文字大小首选项进行放缩，是设置字体大小的御用单位。\nmdpi、hdpi、xdpi、xxdpi 其实之前还有个ldpi，但是随着移动设备配置的不断升级，这个像素密度的设备已经很罕见了，所在现在适配时不需考虑。\nmdpi、hdpi、xdpi、xxdpi用来修饰Android中的drawable文件夹及values文件夹，用来区分不同像素密度下的图片和dimen值。\n那么如何区分呢？Google官方指定按照下列标准进行区分：\n名称 像素密度范围 mdpi 120dpi~160dpi hdpi 160dpi~240dpi xhdpi 240dpi~320dpi xxhdpi 320dpi~480dpi xxxhdpi 480dpi~640dpi 在进行开发的时候，我们需要把合适大小的图片放在合适的文件夹里面。下面以图标设计为例进行介绍。\n在设计图标时，对于五种主流的像素密度（MDPI、HDPI、XHDPI、XXHDPI 和 XXXHDPI）应按照 2:3:4:6:8 的比例进行缩放。例如，一个启动图标的尺寸为48×48 dp，这表示在 MDPI 的屏幕上其实际尺寸应为 48×48 px，在 HDPI 的屏幕上其实际大小是 MDPI 的 1.5 倍 (72×72 px)，在 XDPI 的屏幕上其实际大小是 MDPI 的 2 倍 (96×96 px)，依此类推。\n虽然 Android 也支持低像素密度 (LDPI) 的屏幕，但无需为此费神，系统会自动将 HDPI 尺寸的图标缩小到 1/2 进行匹配。\n下图为图标的各个屏幕密度的对应尺寸\n屏幕密度 图标尺寸 mdpi 48x48px hdpi 72x72px xhdpi 96x96px xxhdpi 144x144px xxxhdpi 192x192px 解决方案 支持各种屏幕尺寸 使用wrap_content、match_parent、weight 要确保布局的灵活性并适应各种尺寸的屏幕，应使用 “wrap_content” 和 “match_parent” 控制某些视图组件的宽度和高度。\n使用 “wrap_content”，系统就会将视图的宽度或高度设置成所需的最小尺寸以适应视图中的内容，而 “match_parent”（在低于 API 级别 8 的级别中称为 “fill_parent”）则会展开组件以匹配其父视图的尺寸。\n如果使用 “wrap_content” 和 “match_parent” 尺寸值而不是硬编码的尺寸，视图就会相应地仅使用自身所需的空间或展开以填满可用空间。此方法可让布局正确适应各种屏幕尺寸和屏幕方向。\n下面是一段示例代码\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:orientation\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;vertical\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/linearLayout1\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;center\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;50dp\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ImageView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/imageView1\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:src\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@drawable/logo\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:paddingRight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;30dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;left\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_weight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;View\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/view1\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_weight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;1\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Button\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/categorybutton\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@drawable/button_bg\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_weight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;120dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@style/CategoryButtonStyle\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/headlines\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.HeadlinesFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n下图是在横纵屏切换的时候的显示效果，我们可以看到这样可以很好的适配屏幕尺寸的变化。\nweight是线性布局的一个独特的属性，我们可以使用这个属性来按照比例对界面进行分配，完成一些特殊的需求。\n但是，我们对于这个属性的计算应该如何理解呢？\n首先看下面的例子，我们在布局中这样设置我们的界面\n我们在布局里面设置为线性布局，横向排列，然后放置两个宽度为0dp的按钮，分别设置weight为1和2，在效果图中，我们可以看到两个按钮按照1：2的宽度比例正常排列了，这也是我们经常使用到的场景，这是时候很好理解，Button1的宽度就是1/(1+2) = 1/3，Button2的宽度则是2/(1+2) = 2/3，我们可以很清楚的明白这种情景下的占比如何计算。\n但是假如我们的宽度不是0dp(wrap_content和0dp的效果相同)，则是match_parent呢？\n下面是设置为match_parent的效果\n我们可以看到，在这种情况下，占比和上面正好相反，这是怎么回事呢？说到这里，我们就不得不提一下weight的计算方法了。\nandroid:layout_weight的真实含义是:如果View设置了该属性并且有效，那么该 View的宽度等于原有宽度(android:layout_width)加上剩余空间的占比。\n从这个角度我们来解释一下上面的现象。在上面的代码中，我们设置每个Button的宽度都是match_parent，假设屏幕宽度为L，那么每个Button的宽度也应该都为L，剩余宽度就等于L-（L+L）= -L。\nButton1的weight=1，剩余宽度占比为1/(1+2)= 1/3，所以最终宽度为L+1/3*(-L)=2/3L，Button2的计算类似，最终宽度为L+2/3(-L)=1/3L。\n这是在水平方向上的，那么在垂直方向上也是这样吗？\n下面是测试代码和效果\n如果是垂直方向，那么我们应该改变的是layout_height的属性，下面是0dp的显示效果\n下面是match_parent的显示效果，结论和水平是完全一样的\n虽然说我们演示了match_parent的显示效果，并说明了原因，但是在真正用的时候，我们都是设置某一个属性为0dp，然后按照权重计算所占百分比。\n使用相对布局，禁用绝对布局 在开发中，我们大部分时候使用的都是线性布局、相对布局和帧布局，绝对布局由于适配性极差，所以极少使用。\n由于各种布局的特点不一样，所以不能说哪个布局好用，到底应该使用什么布局只能根据实际需求来确定。我们可以使用 LinearLayout 的嵌套实例并结合 “wrap_content” 和 “match_parent”，以便构建相当复杂的布局。不过，我们无法通过 LinearLayout 精确控制子视图的特殊关系；系统会将 LinearLayout 中的视图直接并排列出。\n如果我们需要将子视图排列出各种效果而不是一条直线，通常更合适的解决方法是使用 RelativeLayout，这样就可以根据各组件之间的特殊关系指定布局了。例如，我们可以将某个子视图对齐到屏幕左侧，同时将另一个视图对齐到屏幕右侧。\n下面的代码以官方Demo为例说明。\n`\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;RelativeLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;TextView \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/label\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:text\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;Type here:\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;EditText \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/entry\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_below\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@id/label\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Button \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/ok\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_below\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@id/entry\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_alignParentRight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;true\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_marginLeft\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;10dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:text\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;OK\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Button \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_toLeftOf\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@id/ok\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_alignTop\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@id/ok\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:text\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;Cancel\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;RelativeLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n在上面的代码中我们使用了相对布局，并且使用alignXXX等属性指定了子控件的位置，下面是这种布局方式在应对屏幕变化时的表现\n在小尺寸屏幕的显示\n在平板的大尺寸上的显示效果\n虽然控件的大小由于屏幕尺寸的增加而发生了改变，但是我们可以看到，由于使用了相对布局，所以控件之前的位置关系并没有发生什么变化，这说明我们的适配成功了。\n使用限定符 使用尺寸限定符 上面所提到的灵活布局或者是相对布局，可以为我们带来的优势就只有这么多了。虽然这些布局可以拉伸组件内外的空间以适应各种屏幕，但它们不一定能为每种屏幕都提供最佳的用户体验。因此，我们的应用不仅仅只实施灵活布局，还应该应针对各种屏幕配置提供一些备用布局。\n如何做到这一点呢？我们可以通过使用配置限定符，在运行时根据当前的设备配置自动选择合适的资源了，例如根据各种屏幕尺寸选择不同的布局。\n很多应用会在较大的屏幕上实施“双面板”模式，即在一个面板上显示项目列表，而在另一面板上显示对应内容。平板电脑和电视的屏幕已经大到可以同时容纳这两个面板了，但手机屏幕就需要分别显示。因此，我们可以使用以下文件以便实施这些布局：\nres/layout/main.xml，单面板（默认）布局：\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:orientation\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;vertical\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/headlines\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.HeadlinesFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\nres/layout-large/main.xml，双面板布局：\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:orientation\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;horizontal\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/headlines\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.HeadlinesFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;400dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_marginRight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;10dp\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/article\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.ArticleFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n请注意第二种布局名称目录中的 large 限定符。系统会在属于较大屏幕（例如 7 英寸或更大的平板电脑）的设备上选择此布局。系统会在较小的屏幕上选择其他布局（无限定符）。\n使用最小宽度限定符 在版本低于 3.2 的 Android 设备上，开发人员遇到的问题之一是“较大”屏幕的尺寸范围，该问题会影响戴尔 Streak、早期的 Galaxy Tab 以及大部分 7 英寸平板电脑。即使这些设备的屏幕属于“较大”的尺寸，但很多应用可能会针对此类别中的各种设备（例如 5 英寸和 7 英寸的设备）显示不同的布局。这就是 Android 3.2 版在引入其他限定符的同时引入“最小宽度”限定符的原因。\n最小宽度限定符可让您通过指定某个最小宽度（以 dp 为单位）来定位屏幕。例如，标准 7 英寸平板电脑的最小宽度为 600 dp，因此如果您要在此类屏幕上的用户界面中使用双面板（但在较小的屏幕上只显示列表），您可以使用上文中所述的单面板和双面板这两种布局，但您应使用 sw600dp 指明双面板布局仅适用于最小宽度为 600 dp 的屏幕，而不是使用 large 尺寸限定符。\nres/layout/main.xml，单面板（默认）布局：\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:orientation\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;vertical\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/headlines\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.HeadlinesFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\nres/layout-sw600dp/main.xml，双面板布局：\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:orientation\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;horizontal\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/headlines\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.HeadlinesFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;400dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_marginRight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;10dp\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/article\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.ArticleFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n也就是说，对于最小宽度大于等于 600 dp 的设备，系统会选择 layout-sw600dp/main.xml（双面板）布局，否则系统就会选择 layout/main.xml（单面板）布局。\n但 Android 版本低于 3.2 的设备不支持此技术，原因是这些设备无法将 sw600dp 识别为尺寸限定符，因此我们仍需使用 large 限定符。这样一来，就会有一个名称为 res/layout-large/main.xml 的文件（与 res/layout-sw600dp/main.xml 一样）。但是没有太大关系，我们将马上学习如何避免此类布局文件出现的重复。\n使用布局别名 最小宽度限定符仅适用于 Android 3.2 及更高版本。因此，如果我们仍需使用与较低版本兼容的概括尺寸范围（小、正常、大和特大）。例如，如果要将用户界面设计成在手机上显示单面板，但在 7 英寸平板电脑、电视和其他较大的设备上显示多面板，那么我们就需要提供以下文件：\nres/layout/main.xml: 单面板布局 res/layout-large: 多面板布局 res/layout-sw600dp: 多面板布局 后两个文件是相同的，因为其中一个用于和 Android 3.2 设备匹配，而另一个则是为使用较低版本 Android 的平板电脑和电视准备的。\n要避免平板电脑和电视的文件出现重复（以及由此带来的维护问题），您可以使用别名文件。例如，您可以定义以下布局：\nres/layout/main.xml，单面板布局 res/layout/main_twopanes.xml，双面板布局 然后添加这两个文件：\nres/values-large/layout.xml:\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;main\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;type\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;@layout/main_twopanes\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\nres/values-sw600dp/layout.xml:\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;main\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;type\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;@layout/main_twopanes\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n后两个文件的内容相同，但它们并未实际定义布局。它们只是将 main 设置成了 main_twopanes 的别名。由于这些文件包含 large 和 sw600dp 选择器，因此无论 Android 版本如何，系统都会将这些文件应用到平板电脑和电视上（版本低于 3.2 的平板电脑和电视会匹配 large，版本高于 3.2 的平板电脑和电视则会匹配 sw600dp）。\n使用屏幕方向限定符 某些布局会同时支持横向模式和纵向模式，但我们可以通过调整优化其中大部分布局的效果。在新闻阅读器示例应用中，每种屏幕尺寸和屏幕方向下的布局行为方式如下所示：\n小屏幕，纵向：单面板，带徽标 小屏幕，横向：单面板，带徽标 7 英寸平板电脑，纵向：单面板，带操作栏 7 英寸平板电脑，横向：双面板，宽，带操作栏 10 英寸平板电脑，纵向：双面板，窄，带操作栏 10 英寸平板电脑，横向：双面板，宽，带操作栏 电视，横向：双面板，宽，带操作栏 因此，这些布局中的每一种都定义在了 res/layout/ 目录下的某个 XML 文件中。为了继续将每个布局分配给各种屏幕配置，该应用会使用布局别名将两者相匹配：\nres/layout/onepane.xml:(单面板)\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:orientation\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;vertical\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/headlines\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.HeadlinesFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\nres/layout/onepane_with_bar.xml:(单面板带操作栏)\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:orientation\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;vertical\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/linearLayout1\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;center\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;50dp\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ImageView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/imageView1\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:src\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@drawable/logo\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:paddingRight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;30dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;left\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_weight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;View\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/view1\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_weight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;1\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Button\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/categorybutton\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@drawable/button_bg\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_weight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;0\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;120dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@style/CategoryButtonStyle\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/headlines\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.HeadlinesFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\nres/layout/twopanes.xml:(双面板，宽布局)\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:orientation\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;horizontal\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/headlines\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.HeadlinesFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;400dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_marginRight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;10dp\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/article\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.ArticleFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\nres/layout/twopanes_narrow.xml:(双面板，窄布局)\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:orientation\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;horizontal\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/headlines\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.HeadlinesFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;200dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_marginRight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;10dp\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/article\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.ArticleFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n既然我们已定义了所有可能的布局，那就只需使用配置限定符将正确的布局映射到各种配置即可。\n现在只需使用布局别名技术即可做到这一点：\nres/values/layouts.xml:\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;main_layout\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;type\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;@layout/onepane_with_bar\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;bool\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;has_two_panes\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;false\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;bool\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\nres/values-sw600dp-land/layouts.xml:\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;main_layout\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;type\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;@layout/twopanes\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;bool\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;has_two_panes\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;true\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;bool\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\nres/values-sw600dp-port/layouts.xml:\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;main_layout\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;type\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;@layout/onepane\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;bool\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;has_two_panes\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;false\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;bool\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\nres/values-large-land/layouts.xml:\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;main_layout\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;type\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;@layout/twopanes\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;bool\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;has_two_panes\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;true\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;bool\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\nres/values-large-port/layouts.xml:\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;main_layout\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;type\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;layout\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;@layout/twopanes_narrow\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;bool\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;has_two_panes\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;true\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;bool\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n使用自动拉伸位图 支持各种屏幕尺寸通常意味着您的图片资源还必须能适应各种尺寸。例如，无论要应用到什么形状的按钮上，按钮背景都必须能适应。\n如果在可以更改尺寸的组件上使用了简单的图片，您很快就会发现显示效果多少有些不太理想，因为系统会在运行时平均地拉伸或收缩您的图片。解决方法为使用自动拉伸位图，这是一种格式特殊的 PNG 文件，其中会指明可以拉伸以及不可以拉伸的区域。\n.9的制作，实际上就是在原图片上添加1px的边界，然后按照我们的需求，把对应的位置设置成黑色线，系统就会根据我们的实际需求进行拉伸。\n下图是对.9图的四边的含义的解释，左上边代表拉伸区域，右下边代表padding box，就是间隔区域，在下面，我们给出一个例子，方便大家理解。\n先看下面两张图，我们理解一下这四条线的含义。\n上图和下图的区别，就在于右下边的黑线不一样，具体的效果的区别，看右边的效果图。上图效果图中深蓝色的区域，代表内容区域，我们可以看到是在正中央的，这是因为我们在右下边的是两个点，这两个点距离上下左右四个方向的距离就是padding的距离，所以深蓝色内容区域在图片正中央，我们再看下图，由于右下边的黑线是图片长度，所以就没有padding，从效果图上的表现就是深蓝色区域和图片一样大，因此，我们可以利用右下边来控制内容与背景图边缘的padding。\n如果你还不明白，那么我们看下面的效果图，我们分别以图一和图二作为背景图，下面是效果图。\n我们可以看到，使用wrap_content属性设置长宽，图一比图二的效果大一圈，这是为什么呢？还记得我上面说的padding吗？\n这就是padding的效果提现，怎么证明呢？我们再看下面一张图，给图一添加padding=0，这样背景图设置的padding效果就没了，是不是两个一样大了？\nok，我想你应该明白右下边的黑线的含义了，下面我们再看一下左上边的效果。\n下面我们只设置了左上边线，效果图如下\n上面的线没有包住图标，下面的线正好包住了图标，从右边的效果图应该可以看出差别，黑线所在的区域就是拉伸区域，上图黑线所在的全是纯色，所以图标不变形，下面的拉伸区域包裹了图标，所以在拉伸的时候就会对图标进行拉伸，但是这样就会导致图标变形。注意到下面红线区域了嘛？这是系统提示我们的，因为这样拉伸，不符合要求，所以会提示一下。\n支持各种屏幕密度 使用非密度制约像素 由于各种屏幕的像素密度都有所不同，因此相同数量的像素在不同设备上的实际大小也有所差异，这样使用像素定义布局尺寸就会产生问题。因此，请务必使用 dp 或 sp 单位指定尺寸。dp 是一种非密度制约像素，其尺寸与 160 dpi 像素的实际尺寸相同。sp 也是一种基本单位，但它可根据用户的偏好文字大小进行调整（即尺度独立性像素），因此我们应将该测量单位用于定义文字大小。\n例如，请使用 dp（而非 px）指定两个视图间的间距：\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;Button\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:text\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@string/clickme\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_marginTop\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;20dp\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n请务必使用 sp 指定文字大小：\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;TextView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:textSize\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;20sp\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n除了介绍这些最基础的知识之外，我们下面再来讨论一下另外一个问题。\n经过上面的介绍，我们都清楚，为了能够规避不同像素密度的陷阱，Google推荐使用dp来代替px作为控件长度的度量单位，但是我们来看下面的一个场景。\n假如我们以Nexus5作为书写代码时查看效果的测试机型，Nexus5的总宽度为360dp，我们现在需要在水平方向上放置两个按钮，一个是150dp左对齐，另外一个是200dp右对齐，中间留有10dp间隔，那么在Nexus5上面的显示效果就是下面这样\n但是如果在Nexus S或者是Nexus One运行呢？下面是运行结果\n可以看到，两个按钮发生了重叠。\n我们都已经用了dp了，为什么会出现这种情况呢？\n你听我慢慢道来。\n虽然说dp可以去除不同像素密度的问题，使得1dp在不同像素密度上面的显示效果相同，但是还是由于Android屏幕设备的多样性，如果使用dp来作为度量单位，并不是所有的屏幕的宽度都是相同的dp长度，比如说，Nexus S和Nexus One属于hdpi，屏幕宽度是320dp，而Nexus 5属于xxhdpi，屏幕宽度是360dp，Galaxy Nexus属于xhdpi，屏幕宽度是384dp，Nexus 6 属于xxxhdpi，屏幕宽度是410dp。所以说，光Google自己一家的产品就已经有这么多的标准，而且屏幕宽度和像素密度没有任何关联关系，即使我们使用dp，在320dp宽度的设备和410dp的设备上，还是会有90dp的差别。当然，我们尽量使用match_parent和wrap_content，尽可能少的用dp来指定控件的具体长宽，再结合上权重，大部分的情况我们都是可以做到适配的。\n但是除了这个方法，我们还有没有其他的更彻底的解决方案呢？\n我们换另外一个思路来思考这个问题。\n下面的方案来自Android Day Day Up 一群的【blue-深圳】，谢谢他的分享精神\n因为分辨率不一样，所以不能用px；因为屏幕宽度不一样，所以要小心的用dp，那么我们可不可以用另外一种方法来统一单位，不管分辨率是多大，屏幕宽度用一个固定的值的单位来统计呢？\n答案是：当然可以。\n我们假设手机屏幕的宽度都是320某单位，那么我们将一个屏幕宽度的总像素数平均分成320份，每一份对应具体的像素就可以了。\n具体如何来实现呢？我们看下面的代码\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.File; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.FileNotFoundException; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.FileOutputStream; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.io.PrintWriter; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;MakeXml\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; String rootPath = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;C:\\\\Users\\\\Administrator\\\\Desktop\\\\layoutroot\\\\values-{0}x{1}\\\\\u0026#34;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; dw = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;320\u0026amp;lt;/span\u0026gt;f; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; dh = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;480\u0026amp;lt;/span\u0026gt;f; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; String WTemplate = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026amp;lt;dimen name=\\\u0026#34;x{0}\\\u0026#34;\u0026amp;gt;{1}px\u0026amp;lt;/dimen\u0026amp;gt;\\n\u0026#34;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; String HTemplate = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026amp;lt;dimen name=\\\u0026#34;y{0}\\\u0026#34;\u0026amp;gt;{1}px\u0026amp;lt;/dimen\u0026amp;gt;\\n\u0026#34;\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;main\u0026amp;lt;/span\u0026gt;(String[] args) { makeString(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;320\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;480\u0026amp;lt;/span\u0026gt;); makeString(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;480\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;800\u0026amp;lt;/span\u0026gt;); makeString(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;480\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;854\u0026amp;lt;/span\u0026gt;); makeString(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;540\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;960\u0026amp;lt;/span\u0026gt;); makeString(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;600\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1024\u0026amp;lt;/span\u0026gt;); makeString(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;720\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1184\u0026amp;lt;/span\u0026gt;); makeString(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;720\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1196\u0026amp;lt;/span\u0026gt;); makeString(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;720\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1280\u0026amp;lt;/span\u0026gt;); makeString(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;768\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1024\u0026amp;lt;/span\u0026gt;); makeString(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;800\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1280\u0026amp;lt;/span\u0026gt;); makeString(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1080\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1812\u0026amp;lt;/span\u0026gt;); makeString(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1080\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1920\u0026amp;lt;/span\u0026gt;); makeString(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1440\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;2560\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;makeString\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; w, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; h) { StringBuffer sb = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; StringBuffer(); sb.append(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026amp;lt;?xml version=\\\u0026#34;1.0\\\u0026#34; encoding=\\\u0026#34;utf-8\\\u0026#34;?\u0026amp;gt;\\n\u0026#34;\u0026amp;lt;/span\u0026gt;); sb.append(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026amp;lt;resources\u0026amp;gt;\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; cellw = w / dw; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;320\u0026amp;lt;/span\u0026gt;; i++) { sb.append(WTemplate.replace(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;{0}\u0026#34;\u0026amp;lt;/span\u0026gt;, i + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;).replace(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;{1}\u0026#34;\u0026amp;lt;/span\u0026gt;, change(cellw * i) + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;)); } sb.append(WTemplate.replace(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;{0}\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;320\u0026#34;\u0026amp;lt;/span\u0026gt;).replace(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;{1}\u0026#34;\u0026amp;lt;/span\u0026gt;, w + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;)); sb.append(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026amp;lt;/resources\u0026amp;gt;\u0026#34;\u0026amp;lt;/span\u0026gt;); StringBuffer sb2 = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; StringBuffer(); sb2.append(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026amp;lt;?xml version=\\\u0026#34;1.0\\\u0026#34; encoding=\\\u0026#34;utf-8\\\u0026#34;?\u0026amp;gt;\\n\u0026#34;\u0026amp;lt;/span\u0026gt;); sb2.append(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026amp;lt;resources\u0026amp;gt;\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; cellh = h / dh; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;480\u0026amp;lt;/span\u0026gt;; i++) { sb2.append(HTemplate.replace(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;{0}\u0026#34;\u0026amp;lt;/span\u0026gt;, i + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;).replace(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;{1}\u0026#34;\u0026amp;lt;/span\u0026gt;, change(cellh * i) + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;)); } sb2.append(HTemplate.replace(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;{0}\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;480\u0026#34;\u0026amp;lt;/span\u0026gt;).replace(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;{1}\u0026#34;\u0026amp;lt;/span\u0026gt;, h + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;)); sb2.append(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026amp;lt;/resources\u0026amp;gt;\u0026#34;\u0026amp;lt;/span\u0026gt;); String path = rootPath.replace(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;{0}\u0026#34;\u0026amp;lt;/span\u0026gt;, h + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;).replace(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;{1}\u0026#34;\u0026amp;lt;/span\u0026gt;, w + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt;); File rootFile = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File(path); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (!rootFile.exists()) { rootFile.mkdirs(); } File layxFile = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File(path + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;lay_x.xml\u0026#34;\u0026amp;lt;/span\u0026gt;); File layyFile = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; File(path + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;lay_y.xml\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;try\u0026amp;lt;/span\u0026gt; { PrintWriter pw = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; PrintWriter(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; FileOutputStream(layxFile)); pw.print(sb.toString()); pw.close(); pw = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; PrintWriter(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; FileOutputStream(layyFile)); pw.print(sb2.toString()); pw.close(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;catch\u0026amp;lt;/span\u0026gt; (FileNotFoundException e) { e.printStackTrace(); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;change\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;float\u0026amp;lt;/span\u0026gt; a) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; temp = (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;) (a * \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;100\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; temp / \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;100\u0026amp;lt;/span\u0026gt;f; } } ` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\n43\n44\n45\n46\n47\n48\n49\n50\n51\n52\n53\n54\n55\n56\n57\n58\n59\n60\n61\n62\n63\n64\n65\n66\n67\n68\n69\n70\n71\n72\n73\n74\n75\n76\n77\n78\n79\n80\n81\n代码应该很好懂，我们将一个屏幕宽度分为320份，高度480份，然后按照实际像素对每一个单位进行复制，放在对应values-widthxheight文件夹下面的lax.xml和lay.xml里面，这样就可以统一所有你想要的分辨率的单位了，下面是生成的一个320*480分辨率的文件，因为宽高分割之后总分数和像素数相同，所以x1就是1px，以此类推\n`\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x1\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x2\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;2.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x3\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;3.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x4\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;4.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x5\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;5.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x6\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;6.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x7\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;7.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x8\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;8.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x9\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;9.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x10\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;10.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; ...省略好多行 \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x300\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;300.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x301\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;301.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x302\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;302.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x303\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;303.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x304\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;304.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x305\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;305.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x306\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;306.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x307\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;307.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x308\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;308.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x309\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;309.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x310\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;310.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x311\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;311.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x312\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;312.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x313\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;313.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x314\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;314.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x315\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;315.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x316\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;316.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x317\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;317.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x318\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;318.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x319\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;319.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x320\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;320px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n那么1080*1960分辨率下是什么样子呢？我们可以看下，由于1080和320是3.37倍的关系，所以x1=3.37px\n`\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x1\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;3.37px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x2\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;6.75px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x3\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;10.12px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x4\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;13.5px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x5\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;16.87px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x6\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;20.25px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x7\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;23.62px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x8\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;27.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x9\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;30.37px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x10\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;33.75px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; ...省略好多行 \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x300\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1012.5px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x301\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1015.87px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x302\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1019.25px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x303\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1022.62px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x304\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1026.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x305\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1029.37px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x306\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1032.75px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x307\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1036.12px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x308\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1039.5px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x309\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1042.87px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x310\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1046.25px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x311\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1049.62px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x312\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1053.0px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x313\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1056.37px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x314\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1059.75px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x315\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1063.12px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x316\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1066.5px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x317\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1069.87px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x318\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1073.25px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x319\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1076.62px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;x320\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;1080px\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;dimen\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;resources\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n无论在什么分辨率下，x320都是代表屏幕宽度，y480都是代表屏幕高度。\n那么，我们应该如何使用呢？\n首先，我们要把生成的所有values文件夹放到res目录下，当设计师把UI高清设计图给你之后，你就可以根据设计图上的尺寸，以某一个分辨率的机型为基础，找到对应像素数的单位，然后设置给控件即可。\n下图还是两个Button，不同的是，我们把单位换成了我们在values文件夹下dimen的值，这样在你指定的分辨率下，不管宽度是320dp、360dp，还是410dp，就都可以完全适配了。\n但是，还是有个问题，为什么下面的三个没有适配呢？\n这是因为由于在生成的values文件夹里，没有对应的分辨率，其实一开始是报错的，因为默认的values没有对应dimen，所以我只能在默认values里面也创建对应文件，但是里面的数据却不好处理，因为不知道分辨率，我只好默认为x1=1dp保证尽量兼容。这也是这个解决方案的几个弊端，对于没有生成对应分辨率文件的手机，会使用默认values文件夹，如果默认文件夹没有，就会出现问题。\n所以说，这个方案虽然是一劳永逸，但是由于实际上还是使用的px作为长度的度量单位，所以多少和google的要求有所背离，不好说以后会不会出现什么不可预测的问题。其次，如果要使用这个方案，你必须尽可能多的包含所有的分辨率，因为这个是使用这个方案的基础，如果有分辨率缺少，会造成显示效果很差，甚至出错的风险，而这又势必会增加软件包的大小和维护的难度，所以大家自己斟酌，择优使用。\n更多信息可参考鸿洋的新文章Android 屏幕适配方案\n提供备用位图 由于 Android 可在具有各种屏幕密度的设备上运行，因此我们提供的位图资源应始终可以满足各类普遍密度范围的要求：低密度、中等密度、高密度以及超高密度。这将有助于我们的图片在所有屏幕密度上都能得到出色的质量和效果。\n要生成这些图片，我们应先提取矢量格式的原始资源，然后根据以下尺寸范围针对各密度生成相应的图片。\nxhdpi：2.0 hdpi：1.5 mdpi：1.0（最低要求） ldpi：0.75 也就是说，如果我们为 xhdpi 设备生成了 200×200 px尺寸的图片，就应该使用同一资源为 hdpi、mdpi 和 ldpi 设备分别生成 150×150、100×100 和 75×75 尺寸的图片。\n然后，将生成的图片文件放在 res/ 下的相应子目录中(mdpi、hdpi、xhdpi、xxhdpi)，系统就会根据运行您应用的设备的屏幕密度自动选择合适的图片。\n这样一来，只要我们引用 @drawable/id，系统都能根据相应屏幕的 dpi 选取合适的位图。\n还记得我们上面提到的图标设计尺寸吗？和这个其实是一个意思。\n但是还有个问题需要注意下，如果是.9图或者是不需要多个分辨率的图片，就放在drawable文件夹即可，对应分辨率的图片要正确的放在合适的文件夹，否则会造成图片拉伸等问题。\n实施自适应用户界面流程 前面我们介绍过，如何根据设备特点显示恰当的布局，但是这样做，会使得用户界面流程可能会有所不同。例如，如果应用处于双面板模式下，点击左侧面板上的项即可直接在右侧面板上显示相关内容；而如果该应用处于单面板模式下，点击相关的内容应该跳转到另外一个Activity进行后续的处理。所以我们应该按照下面的流程，一步步的完成自适应界面的实现。\n确定当前布局 由于每种布局的实施都会稍有不同，因此我们需要先确定当前向用户显示的布局。例如，我们可以先了解用户所处的是“单面板”模式还是“双面板”模式。要做到这一点，可以通过查询指定视图是否存在以及是否已显示出来。\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;NewsReaderActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;FragmentActivity\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; mIsDualPane; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;(Bundle savedInstanceState) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(R.layout.main_layout); View articleView = findViewById(R.id.article); mIsDualPane = articleView != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt; \u0026amp;\u0026amp; articleView.getVisibility() == View.VISIBLE; } }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n请注意，这段代码用于查询“报道”面板是否可用，与针对具体布局的硬编码查询相比，这段代码的灵活性要大得多。\n再举一个适应各种组件的存在情况的方法示例：在对这些组件执行操作前先查看它们是否可用。例如，新闻阅读器示例应用中有一个用于打开菜单的按钮，但只有在版本低于 3.0 的 Android 上运行该应用时，这个按钮才会存在，因为 API 级别 11 或更高级别中的 ActionBar 已取代了该按钮的功能。因此，您可以使用以下代码为此按钮添加事件侦听器：\n`Button catButton = (Button) findViewById(R\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.id\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.categorybutton\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; OnClickListener listener = \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* create your listener here */\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; if (catButton != null) { catButton\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.setOnClickListener\u0026amp;lt;/span\u0026gt;(listener)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; }` 1\n2\n3\n4\n5\n根据当前布局做出响应 有些操作可能会因当前的具体布局而产生不同的结果。例如，在新闻阅读器示例中，如果用户界面处于双面板模式下，那么点击标题列表中的标题就会在右侧面板中打开相应报道；但如果用户界面处于单面板模式下，那么上述操作就会启动一个独立活动：\n`@Override \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; onHeadlineSelected(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;index\u0026amp;lt;/span\u0026gt;) { mArtIndex = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;index\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mIsDualPane) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* display article on the right pane */\u0026amp;lt;/span\u0026gt; mArticleFragment.displayArticle(mCurrentCat.getArticle(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;index\u0026amp;lt;/span\u0026gt;)); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* start a separate activity */\u0026amp;lt;/span\u0026gt; Intent intent = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; Intent(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, ArticleActivity.class); intent.putExtra(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;catIndex\u0026#34;\u0026amp;lt;/span\u0026gt;, mCatIndex); intent.putExtra(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;artIndex\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;index\u0026amp;lt;/span\u0026gt;); startActivity(intent); } }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n同样，如果该应用处于双面板模式下，就应设置带导航标签的操作栏；但如果该应用处于单面板模式下，就应使用下拉菜单设置导航栏。因此我们的代码还应确定哪种情况比较合适：\n`final String CATEGORIES[] = { \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;热门报道\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;政治\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;经济\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Technology\u0026#34;\u0026amp;lt;/span\u0026gt; }\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; public void onCreate(Bundle savedInstanceState) { .... if (mIsDualPane) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* use tabs for navigation */\u0026amp;lt;/span\u0026gt; actionBar\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.setNavigationMode\u0026amp;lt;/span\u0026gt;(android\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.app\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.ActionBar\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.NAVIGATION\u0026amp;lt;/span\u0026gt;_MODE_TABS)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; int i\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; for (i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;; i \u0026amp;lt; CATEGORIES.length; i++) {\u0026amp;lt;/span\u0026gt; actionBar\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.addTab\u0026amp;lt;/span\u0026gt;(actionBar\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.newTab\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.setText\u0026amp;lt;/span\u0026gt;( CATEGORIES[i])\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.setTabListener\u0026amp;lt;/span\u0026gt;(handler))\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; } actionBar\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.setSelectedNavigationItem\u0026amp;lt;/span\u0026gt;(selTab)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; } else { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* use list navigation (spinner) */\u0026amp;lt;/span\u0026gt; actionBar\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.setNavigationMode\u0026amp;lt;/span\u0026gt;(android\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.app\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.ActionBar\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.NAVIGATION\u0026amp;lt;/span\u0026gt;_MODE_LIST)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; SpinnerAdapter adap = new ArrayAdapter(this, R\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.layout\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.headline\u0026amp;lt;/span\u0026gt;_item, CATEGORIES)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; actionBar\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.setListNavigationCallbacks\u0026amp;lt;/span\u0026gt;(adap, handler)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; } }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n重复使用其他活动中的片段 多屏幕设计中的重复模式是指，对于某些屏幕配置，已实施界面的一部分会用作面板；但对于其他配置，这部分就会以独立活动的形式存在。例如，在新闻阅读器示例中，对于较大的屏幕，新闻报道文本会显示在右侧面板中；但对于较小的屏幕，这些文本就会以独立活动的形式存在。\n在类似情况下，通常可以在多个活动中重复使用相同的 Fragment 子类以避免代码重复。例如，在双面板布局中使用了 ArticleFragment：\n`\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:orientation\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;horizontal\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/headlines\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.HeadlinesFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;400dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_marginRight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;10dp\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;fragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/article\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;com.example.android.newsreader.ArticleFragment\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n然后又在小屏幕的Activity布局中重复使用了它 ：\n`ArticleFragment frag = new ArticleFragment()\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; getSupportFragmentManager()\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.beginTransaction\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.add\u0026amp;lt;/span\u0026gt;(android\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.id\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.content\u0026amp;lt;/span\u0026gt;, frag)\u0026amp;lt;span class=\u0026#34;hljs-preprocessor\u0026#34;\u0026gt;.commit\u0026amp;lt;/span\u0026gt;()\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt;` 1\n2\n当然，这与在 XML 布局中声明片段的效果是一样的，但在这种情况下却没必要使用 XML 布局，因为报道片段是此活动中的唯一组件。\n请务必在设计片段时注意，不要针对具体活动创建强耦合。要做到这一点，通常可以定义一个接口，该接口概括了相关片段与其主活动交互所需的全部方式，然后让主活动实施该界面：\n例如，新闻阅读器应用的 HeadlinesFragment 会精确执行以下代码：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;HeadlinesFragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ListFragment\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; ... OnHeadlineSelectedListener mHeadlineSelectedListener = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* Must be implemented by host activity */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;interface\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;OnHeadlineSelectedListener\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onHeadlineSelected\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; index); } ... \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setOnHeadlineSelectedListener\u0026amp;lt;/span\u0026gt;(OnHeadlineSelectedListener listener) { mHeadlineSelectedListener = listener; } }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n然后，如果用户选择某个标题，相关片段就会通知由主活动指定的侦听器（而不是通知某个硬编码的具体活动）：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;HeadlinesFragment\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ListFragment\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; ... \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onItemClick\u0026amp;lt;/span\u0026gt;(AdapterView\u0026amp;lt;?\u0026amp;gt; parent, View view, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;long\u0026amp;lt;/span\u0026gt; id) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt; != mHeadlineSelectedListener) { mHeadlineSelectedListener.onHeadlineSelected(position); } } ... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n除此之外，我们还可以使用第三方框架，比如说使用“订阅-发布”模式的EventBus来更多的优化组件之间的通信，减少耦合。\n处理屏幕配置变化 如果我们使用独立Activity实施界面的独立部分，那么请注意，我们可能需要对特定配置变化（例如屏幕方向的变化）做出响应，以便保持界面的一致性。\n例如，在运行 Android 3.0 或更高版本的标准 7 英寸平板电脑上，如果新闻阅读器示例应用运行在纵向模式下，就会在使用独立活动显示新闻报道；但如果该应用运行在横向模式下，就会使用双面板布局。\n也就是说，如果用户处于纵向模式下且屏幕上显示的是用于阅读报道的活动，那么就需要在检测到屏幕方向变化（变成横向模式）后执行相应操作，即停止上述活动并返回主活动，以便在双面板布局中显示相关内容：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ArticleActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;FragmentActivity\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mCatIndex, mArtIndex; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;(Bundle savedInstanceState) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreate(savedInstanceState); mCatIndex = getIntent().getExtras().getInt(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;catIndex\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); mArtIndex = getIntent().getExtras().getInt(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;artIndex\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// If should be in two-pane mode, finish to return to main activity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (getResources().getBoolean(R.bool.has_two_panes)) { finish(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt;; } ... }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n通过上面几个步骤，我们就完全可以建立一个可以根据用户界面配置进行自适应的App了。\n最佳实践 关于高清设计图尺寸 Google官方给出的高清设计图尺寸有两种方案，一种是以mdpi设计，然后对应放大得到更高分辨率的图片，另外一种则是以高分辨率作为设计大小，然后按照倍数对应缩小到小分辨率的图片。\n根据经验，我更推荐第二种方法，因为小分辨率在生成高分辨率图片的时候，会出现像素丢失，我不知道是不是有方法可以阻止这种情况发生。\n而分辨率可以以1280*720或者是1960*1080作为主要分辨率进行设计。\nImageView的ScaleType属性 设置不同的ScaleType会得到不同的显示效果，一般情况下，设置为centerCrop能获得较好的适配效果。\n动态设置 有一些情况下，我们需要动态的设置控件大小或者是位置，比如说popwindow的显示位置和偏移量等，这个时候我们可以动态的获取当前的屏幕属性，然后设置合适的数值\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; ScreenSizeUtil { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getScreenWidth\u0026amp;lt;/span\u0026gt;(Activity activity) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; activity.getWindowManager().getDefaultDisplay().getWidth(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getScreenHeight\u0026amp;lt;/span\u0026gt;(Activity activity) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; activity.getWindowManager().getDefaultDisplay().getHeight(); } }` 1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n更多参考资料 chan奕迅(设计师角度) 友盟移动指数(最新的移动设备统计信息) 手机屏幕信息大全 ","permalink":"https://blog.zdltech.com/posts/android%E5%B1%8F%E5%B9%95%E9%80%82%E9%85%8D%E5%85%A8%E6%94%BB%E7%95%A5%E6%9C%80%E6%9D%83%E5%A8%81%E7%9A%84%E5%AE%98%E6%96%B9%E9%80%82%E9%85%8D%E6%8C%87%E5%AF%BC/","summary":"\u003cp\u003e转载：\u003ca href=\"http://blog.csdn.net/zhaokaiqiang1992\"\u003ehttp://blog.csdn.net/zhaokaiqiang1992\u003c/a\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eAndroid的屏幕适配一直以来都在折磨着我们这些开发者，本篇文章以Google的官方文档为基础，全面而深入的讲解了Android屏幕适配的原因、重要概念、解决方案及最佳实践，我相信如果你能认真的学习本文，对于Android的屏幕适配，你将有所收获！\u003c/p\u003e\u003c/blockquote\u003e\n\u003cdiv class=\"toc\"\u003e\n\u003cpre\u003e\u003ccode\u003e- [Android屏幕适配出现的原因](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#android屏幕适配出现的原因)\n\n- [重要概念](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#重要概念) \n    - [屏幕尺寸](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#屏幕尺寸)\n    \n    - [屏幕分辨率](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#屏幕分辨率)\n    \n    - [屏幕像素密度](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#屏幕像素密度)\n    \n    - [dpdipdpisppx](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#dpdipdpisppx)\n    \n    - [mdpihdpixdpixxdpi](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#mdpihdpixdpixxdpi)\n    \n  \n\n\n- [解决方案](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#解决方案) \n    - [支持各种屏幕尺寸](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#支持各种屏幕尺寸) \n        - [使用wrap_contentmatch_parentweight](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用wrapcontentmatchparentweight)\n        \n        - [使用相对布局禁用绝对布局](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用相对布局禁用绝对布局)\n        \n        - [使用限定符](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用限定符) \n            - [使用尺寸限定符](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用尺寸限定符)\n            \n            - [使用最小宽度限定符](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用最小宽度限定符)\n            \n            - [使用布局别名](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用布局别名)\n            \n            - [使用屏幕方向限定符](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用屏幕方向限定符)\n            \n            - [使用自动拉伸位图](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用自动拉伸位图)\n            \n          \n        \n      \n    \n    \n    - [支持各种屏幕密度](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#支持各种屏幕密度) \n        - [使用非密度制约像素](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用非密度制约像素)\n        \n        - [提供备用位图](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#提供备用位图)\n        \n      \n    \n    \n    - [实施自适应用户界面流程](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#实施自适应用户界面流程) \n        - [确定当前布局](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#确定当前布局)\n        \n        - [根据当前布局做出响应](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#根据当前布局做出响应)\n        \n        - [重复使用其他活动中的片段](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#重复使用其他活动中的片段)\n        \n        - [处理屏幕配置变化](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#处理屏幕配置变化)\n        \n      \n    \n    \n    - [最佳实践](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#最佳实践) \n        - [关于高清设计图尺寸](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#关于高清设计图尺寸)\n        \n        - [ImageView的ScaleType属性](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#imageview的scaletype属性)\n        \n        - [动态设置](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#动态设置)\n        \n      \n    \n    \n    - [更多参考资料](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#更多参考资料)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003ch1 id=\"android屏幕适配出现的原因\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003eAndroid屏幕适配出现的原因\u003c/h1\u003e\n\u003cp\u003e在我们学习如何进行屏幕适配之前，我们需要先了解下为什么Android需要进行屏幕适配。\u003c/p\u003e\n\u003cp\u003e由于Android系统的开放性，任何用户、开发者、OEM厂商、运营商都可以对Android进行定制，修改成他们想要的样子。\u003c/p\u003e\n\u003cp\u003e但是这种“碎片化”到底到达什么程度呢？\u003c/p\u003e\n\u003cp\u003e在2012年，OpenSignalMaps（以下简称OSM）发布了第一份Android碎片化报告，统计数据表明，\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e2012年，支持Android的设备共有3997种。\u003c/li\u003e\n\u003cli\u003e2013年，支持Android的设备共有11868种。\u003c/li\u003e\n\u003cli\u003e2014年，支持Android的设备共有18796种。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e下面这张图片所显示的内容足以充分说明当今Android系统碎片化问题的严重性，因为该图片中的每一个矩形都代表着一种Android设备。\u003c/p\u003e","title":"Android屏幕适配全攻略(最权威的官方适配指导)"},{"content":"随着 Google I/O 2015，新的 Android Design Support Library 也出现了。\nAndroid Design Support Library 给开发者带来了一些重要的 Material Design 组件，并且向下兼容到 Android 2.1，Navigation View就是其中之一，可用于方便地创建导航抽屉。\n效果如下：\n因为需要向下兼容，所以以下内容的 Activity 均继承于AppCompatActivity，使用的主题的父主题均为 AppCompat 的主题。\n基本步骤 通过Navigation View创建导航抽屉首先自然需要引入这个支持包：\ncompile 'com.android.support:design:22.2.0' 布局文件中加入以下代码：\n``` \u0026lt;android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\" xmlns:app=\"http://schemas.android.com/apk/res-auto\" android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\u0026gt; \u0026lt;span class=\u0026quot;c\u0026quot;\u0026gt;\u0026amp;lt;!-- 需要呈现的内容 --\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;android.support.design.widget.NavigationView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:layout_width=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;wrap_content\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:layout_height=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;match_parent\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:layout_gravity=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;start\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;app:headerLayout=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@layout/drawer_header\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;app:menu=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@menu/drawer\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;/android.support.v4.widget.DrawerLayout\u0026gt;\n\u0026lt;/div\u0026gt; 其中`app:headerLayout`用于指定一个任意的布局，作为导航抽屉的顶部，如效果图中的紫色带 Username 字样部分。 而`app:menu`用于指定导航抽屉的菜单项，具体代码如下： \u0026lt;div class=\u0026#34;codehilite\u0026#34;\u0026gt; \u0026lt;menu xmlns:android=\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot;\u0026gt;\n\u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;group\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:checkableBehavior=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;single\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:id=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@+id/nav_home\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:icon=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@drawable/ic_dashboard\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Home\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:id=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@+id/nav_messages\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:icon=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@drawable/ic_event\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Messages\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:id=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@+id/nav_friends\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:icon=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@drawable/ic_headset\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Friends\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:id=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@+id/nav_discussion\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:icon=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@drawable/ic_forum\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Discussion\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;/group\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Sub items\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;menu\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:icon=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@drawable/ic_dashboard\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Sub item 1\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:icon=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@drawable/ic_forum\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Sub item 2\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;/menu\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;/item\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;/menu\u0026gt;\n\u0026lt;/div\u0026gt; 其中通过`\u0026lt;group android:checkableBehavior=\u0026#34;single\u0026#34;\u0026gt;`设定一组菜单项为至多只有一个可被选中，非常适合用于通过导航抽屉切换呈现的 Fragment，若需要默认选中一个菜单项则只需要给指定 item 加上`android:checked=\u0026#34;true\u0026#34;`即可。并且可以通过子菜单的形式显示分割线和子标题。 到此为止布局文件部分就完成了，接下来只需要在Activity中设置监听器即可： \u0026lt;div class=\u0026#34;codehilite\u0026#34;\u0026gt; mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);\nNavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); if (navigationView != null) { navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem menuItem) { //切换相应 Fragment 等操作 menuItem.setChecked(true); mDrawerLayout.closeDrawers(); return false; } }); }\n\u0026lt;/div\u0026gt; 至此导航抽屉就基本完成了，但 Material Design 中建议导航抽屉应该在 status bar 上也显示，而 Android 5.0 及以上版本支持这一特性，因此还需要进一步处理。 # 针对 Android 5.0 及以上版本 {#toc_1} 首先由 window 来绘制 status bar 的背景，否则 status bar 为系统默认背景（原生是黑色背景），而 AppCompat 的主题已带如下属性： \u0026lt;div class=\u0026#34;codehilite\u0026#34;\u0026gt; \u0026lt;item name=\u0026ldquo;android:windowDrawsSystemBarBackgrounds\u0026rdquo;\u0026gt;true\u0026lt;/item\u0026gt;\n\u0026lt;/div\u0026gt; 确保 Android 5.0 以上版本使用的主题中并没有把该属性设置成 false 即可。 而通过 window 来绘制 status bar 的背景并不一定是我们需要的最终结果，因为 status bar 的背景在需要呈现的内容上和导航抽屉上不一定是一样的，而通过 window 来绘制则肯定是一样的，因此把 window 绘制的 status bar 的背景设置为透明，在 Android 5.0 以上版本使用的主题中加入如下代码： \u0026lt;div class=\u0026#34;codehilite\u0026#34;\u0026gt; \u0026lt;item name=\u0026ldquo;android:statusBarColor\u0026rdquo;\u0026gt;@android:color/transparent\u0026lt;/item\u0026gt;\n\u0026lt;/div\u0026gt; 接下来只需要`DrawerLayout`来接管 status bar 的背景的绘制工作即可，给布局文件中的`DrawerLayout`加入如下属性： \u0026lt;div class=\u0026#34;codehilite\u0026#34;\u0026gt; android:fitsSystemWindows=\u0026ldquo;true\u0026rdquo;\n\u0026lt;/div\u0026gt; 此时导航抽屉已经能够显示在 status bar 上。 至此理论上 Android 2.1 以上版本都能正常显示导航抽屉了，完整代码可参照 Github 上的一个 [Demo][1]。 ![](http://myihsan.farbox.com/_image/use-navigation-view-to-make-navigation-drawer/11-23-22.jpg) 通过`Navigation View`能够实现上图所示的导航抽屉，但有两处若不设置依旧会占着控件，十分不合理，分别是图标以及 4 处的子菜单标题。所以若需要没有图标的项目或单独加分割线则还得考虑使用自定义布局的形式实现导航抽屉。 但`Navigation View`优点依旧很明显，首先设置的图标经测试会被改变成合适的颜色，无论是选中还是未选中状态，无需任何代码即可达成下图效果，若使用自定义布局的形式可能需要设计未选中和选中两套图标或自己写代码动态改变颜色。 ![](http://myihsan.farbox.com/_image/use-navigation-view-to-make-navigation-drawer/15-33-07.jpg) 若还是觉得`Navigation View`不够好，又觉得自定义太麻烦，并且只需要兼容到 Android 2.3.3 或以上版本的话可以考虑使用使用 [MaterialDrawer][2] 开源控件，十分强大，能够实现`Navigation View`所有能够实现的效果，并且自由度更高，我通过这个开源控件完成了我毕业设计中所需的两个导航抽屉，具体效果如下图所示： ![](http://myihsan.farbox.com/_image/use-navigation-view-to-make-navigation-drawer/15-50-06.jpg) # 参考资料 {#toc_2} [Android Design Support Library][3]（Android Developers Blog） [1]: https://github.com/chrisbanes/cheesesquare/ [2]: https://github.com/mikepenz/MaterialDrawer [3]: http://android-developers.blogspot.fi/2015/05/android-design-support-library.html ","permalink":"https://blog.zdltech.com/posts/%E9%80%9A%E8%BF%87-navigation-view-%E5%88%9B%E5%BB%BA%E5%AF%BC%E8%88%AA%E6%8A%BD%E5%B1%89/","summary":"\u003cp\u003e随着 Google I/O 2015，新的 Android Design Support Library 也出现了。\u003c/p\u003e\n\u003cp\u003eAndroid Design Support Library 给开发者带来了一些重要的 Material Design 组件，并且向下兼容到 Android 2.1，\u003ccode\u003eNavigation View\u003c/code\u003e就是其中之一，可用于方便地创建导航抽屉。\u003c/p\u003e\n\u003cp\u003e效果如下：\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://myihsan.farbox.com/_image/use-navigation-view-to-make-navigation-drawer/21-42-24.jpg\"\u003e\u003cbr\u003e\n因为需要向下兼容，所以以下内容的 Activity 均继承于\u003ccode\u003eAppCompatActivity\u003c/code\u003e，使用的主题的父主题均为 AppCompat 的主题。\u003c/p\u003e\n\u003ch1 id=\"toc_0\"\u003e基本步骤\u003c/h1\u003e\n\u003cp\u003e通过\u003ccode\u003eNavigation View\u003c/code\u003e创建导航抽屉首先自然需要引入这个支持包：\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ecompile 'com.android.support:design:22.2.0'\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e布局文件中加入以下代码：\u003c/p\u003e\n\u003cdiv class=\"codehilite\"\u003e\n  ```\n\u003cspan class=\"nt\"\u003e\u0026lt;android.support.v4.widget.DrawerLayout\u003c/span\u003e\n        \u003cspan class=\"na\"\u003exmlns:android=\u003c/span\u003e\u003cspan class=\"s\"\u003e\"http://schemas.android.com/apk/res/android\"\u003c/span\u003e\n        \u003cspan class=\"na\"\u003exmlns:app=\u003c/span\u003e\u003cspan class=\"s\"\u003e\"http://schemas.android.com/apk/res-auto\"\u003c/span\u003e\n        \u003cspan class=\"na\"\u003eandroid:layout_width=\u003c/span\u003e\u003cspan class=\"s\"\u003e\"match_parent\"\u003c/span\u003e\n        \u003cspan class=\"na\"\u003eandroid:layout_height=\u003c/span\u003e\u003cspan class=\"s\"\u003e\"match_parent\"\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026gt;\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;c\u0026quot;\u0026gt;\u0026amp;lt;!-- 需要呈现的内容 --\u0026amp;gt;\u0026lt;/span\u0026gt;\n\n\u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;android.support.design.widget.NavigationView\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:layout_width=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;wrap_content\u0026quot;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:layout_height=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;match_parent\u0026quot;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:layout_gravity=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;start\u0026quot;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;app:headerLayout=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@layout/drawer_header\u0026quot;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;app:menu=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@menu/drawer\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/android.support.v4.widget.DrawerLayout\u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e其中`app:headerLayout`用于指定一个任意的布局，作为导航抽屉的顶部，如效果图中的紫色带 Username 字样部分。\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e而`app:menu`用于指定导航抽屉的菜单项，具体代码如下：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div class=\u0026#34;codehilite\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cspan class=\"nt\"\u003e\u0026lt;menu\u003c/span\u003e \u003cspan class=\"na\"\u003exmlns:android=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026ldquo;\u003ca href=\"http://schemas.android.com/apk/res/android%22\"\u003ehttp://schemas.android.com/apk/res/android\u0026quot;\u003c/a\u003e\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;group\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:checkableBehavior=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;single\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:id=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@+id/nav_home\u0026quot;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:icon=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@drawable/ic_dashboard\u0026quot;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Home\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:id=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@+id/nav_messages\u0026quot;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:icon=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@drawable/ic_event\u0026quot;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Messages\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:id=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@+id/nav_friends\u0026quot;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:icon=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@drawable/ic_headset\u0026quot;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Friends\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:id=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@+id/nav_discussion\u0026quot;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:icon=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@drawable/ic_forum\u0026quot;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Discussion\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;/group\u0026amp;gt;\u0026lt;/span\u0026gt;\n\n\u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Sub items\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;menu\u0026amp;gt;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt;\n            \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:icon=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@drawable/ic_dashboard\u0026quot;\u0026lt;/span\u0026gt;\n            \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Sub item 1\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;item\u0026lt;/span\u0026gt;\n            \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:icon=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;@drawable/ic_forum\u0026quot;\u0026lt;/span\u0026gt;\n            \u0026lt;span class=\u0026quot;na\u0026quot;\u0026gt;android:title=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;s\u0026quot;\u0026gt;\u0026quot;Sub item 2\u0026quot;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;/menu\u0026amp;gt;\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026quot;nt\u0026quot;\u0026gt;\u0026amp;lt;/item\u0026amp;gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/menu\u0026gt;\u003c/span\u003e\u003c/p\u003e","title":"通过 Navigation View 创建导航抽屉"},{"content":"教程 在 Android 中使用 data-binder 绑定布局 xml 与数据在前几天的 Google IO 2015 中，Google 在 support-v7 中新增了 data-binder，使用 data-binder 可以直接在布局的 xml 中绑定布局与数据，从而简化代码。因为 data-binder 是包含在 support-v7 包里面的，所以可以向下兼容到最低 Android 2.1 (API level 7+). Android的材料设计兼容库这个兼容库很容易和之前的 Android Support Library 22.1混淆，都是兼容库，区别是这个库多了个Design。 Android Support Library 22.1只是支持了一些基本控件的材料设计化，但是这个库更多的是对一些特效的实现，这个库和github上的很多开源项目是有很大关系的，material design的很多效果，同一种效果在github上有太多的实现，现在官方把部分效果标准化了。 Google I/O 2015 为 Android 开发者带来了哪些福利？先得说的便是，今年的更新有些不给力，至少显得不够 Geek。我也不打算接着盘点一些在 Keynote 中的资讯，想必很多人在各个站点已经看过不知道多少遍了，我接下来想说的一些是关于这次 Google I/O 为 Android 开发者们带来了怎样的福利。 Nexus6 With Android M开启多窗口模式昨天的Google IO之后，Google放出了Android M Preview for Nexus6. 固件大家可以去Google的官网去下，下好了刷完之后，就可以体验一下最新的Android M了。 使用Android Accessibility实现免Root自动批量安装功能对于国内Android设备，应用的自动批量安装/更新一直是一个痛点，在之前，第三方应用商店通常要求设备Root，然后调用系统的PackageManagerService命令行来实现后台安装。最近，豌豆荚利用Android Accessibility（辅助功能）在业内率先实现了免Root自动批量安装功能。 Android 9patch 图片解析堆溢出漏洞分析前谷歌公开了一个今年1月份更新的漏洞。这个漏洞修复了一个存在于Android 5.1版本以下图片渲染的问题，可以查看相关链接。9patch是Android上特有的一种图片格式，就是在普通的png图片的基础了增加了一些像素的边框，使之具有可随意拉伸、缩放的功能。 Gradle 修改 Maven 仓库地址要先说明的是本文说的“渠道”单指在AndroidManifest.xml 用定义的一个标识字符串（如友盟统计）。在代码或者通过其他文件定义的方式殊途同归。说起 Android 多渠道打包，真是八仙过海各显神通：有手动一个个耐心打包的，有用Ant或Maven重复跑编译任务的，有用apktool解包后再修改重打包的，有在build.gradle定义一堆flavor的，乃至有通过apk里META-INF/下的空文件来定义渠道的。 谷歌推荐的技术能力提升指南打好扎实的计算机科学基础对于成为一个成功的软件工程师是非常重要的。本指南主要关于如何提升自己的技术能力，非常适合学生用于制定教学课程，当然这里提供的网络资源，并不意味着就可以完全取代现有的课程，正式的课程安排还是要学的(除非你不想拿到毕业证书)。 Android应用setContentView与LayoutInflater加载解析机制源码分析其实之所以要说这个话题有几个原因：1.理解xml等控件是咋被显示的原理，通常大家写代码都是直接在onCreate里setContentView就完事，没怎么关注其实现原理。2.前面分析《Android触摸屏事件派发机制详解与源码分析三(Activity篇)》时提到了一些关于布局嵌套的问题，当时没有深入解释。 Android应用程序UI硬件加速渲染的预加载资源地图集服务（Asset Atlas Service）分析我们知道，Android系统在启动的时候，会对一些系统资源进行预加载。这样不仅使得应用程序在需要时可以快速地访问这些资源，还使得这些资源能够在不同应用程序之间进行共享。在硬件加速渲染环境中，这些预加载资源还有进一步优化的空间。 Android 不规则封闭区域填充 手指秒变油漆桶图像的填充有2种经典算法。 一种是种子填充法。种子填充法理论上能够填充任意区域和图形,但是这种算法存在大量的反复入栈和大规模的递归,降低了填充效率。 另一种是扫描线填充法。 Android屏幕适配全攻略(最权威的官方适配指导)Android的屏幕适配一直以来都在折磨着我们这些开发者，本篇文章以Google的官方文档为基础，全面而深入的讲解了Android屏幕适配的原因、重要概念、解决方案及最佳实践，我相信如果你能认真的学习本文，对于Android的屏幕适配，你将有所收获！ Android系统Root与静默安装静默安装，指的是安装时无需任何用户干预，直接按默认设置安装应用。因为，它的无需用户干预，很多情况下变成了用户压根不知道，应用不知不觉就安装上了。是在推广上极为流氓的手段，很类似PC上的捆绑安装。正因为静默安装时极为流氓的推广行为，所以，其推广价格也极其高。 代码\u0026amp;开源库 cheesesquareAndroid Design library的示例。 Android-NiceTab支持小圆点，背景模糊，图标cross fade等效果的自定义Tab. BGARefreshLayout-Android多种下拉刷新效果、上拉加载更多、可配置自定义头部广告位。 AnimateCheckBox自定义CheckBox，选中未选中的切换动画很赞。 SelectorInjection一个强大的selector注入器，它可以让view自动产生selector状态，免去了你写selector的麻烦。 ShareLoginLib第三方分享登录组件. AndroidGradleTemplateGradle + Android Studio + Robolectric + Espresso + Mockito + EasyMock/PowerMock + JaCoCo Android-Task可以在后台执行Task的Library。 FORMWatchFaceAnddroid Wear 表盘。 MultiThreadDownloader逻辑比较简单但实用的Android多线程断点续传下载器。 DatePickerAndroid日历选择器。 Material Calendar ViewMaterial Design风格的日历控件。 工具 Android Studio 1.3 Preview1The new version contains many new features.: New Allocation Tracker New Heap dump Viewer Many new code inspections to enforce framework and support library threading annotations, range annotations, call super, check result, etc. Missing permission checks and unhandled revocable permission checks Android M preview data binding Support Support for adding Google Services to the project in the project structure dialog (especially for Analytics) SDK update notifications, and brand new integrated SDK manager UI New quickfixes, such as automatic generation of a Parcelable implementation Many built-in live code templates Many other smaller features and bug fixes As announced at Google I/O, Android Studio 1.3 will include C/C++ support as well, but that is not included in the first couple of preview buil * [Android NDK r10e][28]Release Notes: \u0026lt;http://developer.android.com/intl/zh-cn/ndk/downloads/index.html#rel\u0026gt; * [GsonFormat][29]根据Gson库使用的要求,将JSONObject格式的String 解析成实体的 Android Studio 插件。 ### 视频 {#} 1. [Google I/O 2015的各种视频][30]墙内Google I/O 2015的各种视频，没有看的小伙伴赶紧去瞅瞅看吧。 2. [Android QQ音乐架构演进][31]随着移动互联网的不断蓬勃发展，更多用户在移动设备上使用音乐服务，QQ音乐移动客户端使用用户数也在屡创新高，QQ音乐为了达到更好的用户体验并实现用户的新需求，原有的框架已经不能优雅的实现新需求和优先。如何优雅的实现各种需求并在性能和稳定性得到提高，QQ音乐Android开发团队通过以下的篇章给大家分享QQ音乐架构演进带来的痛与乐。 转自：http://androidweekly.cn/android-dev-weekly-issue33/?utm_source=tuicool ","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E5%8F%91%E6%8A%80%E6%9C%AF%E5%91%A8%E6%8A%A5/","summary":"\u003ch3 id=\"\"\u003e教程\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\u003ca href=\"http://undownding.me/2015/05/31/android-data-binding/\"\u003e在 Android 中使用 data-binder 绑定布局 xml 与数据\u003c/a\u003e在前几天的 Google IO 2015 中，Google 在 support-v7 中新增了 data-binder，使用 data-binder 可以直接在布局的 xml 中绑定布局与数据，从而简化代码。因为 data-binder 是包含在 support-v7 包里面的，所以可以向下兼容到最低 Android 2.1 (API level 7+).\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://jcodecraeer.com/a/anzhuokaifa/developer/2015/0531/2958.html\"\u003eAndroid的材料设计兼容库\u003c/a\u003e这个兼容库很容易和之前的 Android Support Library 22.1混淆，都是兼容库，区别是这个库多了个Design。 Android Support Library 22.1只是支持了一些基本控件的材料设计化，但是这个库更多的是对一些特效的实现，这个库和github上的很多开源项目是有很大关系的，material design的很多效果，同一种效果在github上有太多的实现，现在官方把部分效果标准化了。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.jianshu.com/p/4f7f55471da2\"\u003eGoogle I/O 2015 为 Android 开发者带来了哪些福利？\u003c/a\u003e先得说的便是，今年的更新有些不给力，至少显得不够 Geek。我也不打算接着盘点一些在 Keynote 中的资讯，想必很多人在各个站点已经看过不知道多少遍了，我接下来想说的一些是关于这次 Google I/O 为 Android 开发者们带来了怎样的福利。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://androidperformance.com/2015/05/29/Nexus6-with-Android-M%E5%BC%80%E5%90%AF%E5%A4%9A%E7%AA%97%E5%8F%A3%E6%A8%A1%E5%BC%8F/\"\u003eNexus6 With Android M开启多窗口模式\u003c/a\u003e昨天的Google IO之后，Google放出了Android M Preview for Nexus6. 固件大家可以去Google的官网去下，下好了刷完之后，就可以体验一下最新的Android M了。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.infoq.com/cn/articles/android-accessibility-installing\"\u003e使用Android Accessibility实现免Root自动批量安装功能\u003c/a\u003e对于国内Android设备，应用的自动批量安装/更新一直是一个痛点，在之前，第三方应用商店通常要求设备Root，然后调用系统的PackageManagerService命令行来实现后台安装。最近，豌豆荚利用Android Accessibility（辅助功能）在业内率先实现了免Root自动批量安装功能。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://security.tencent.com/index.php/blog/msg/85\"\u003eAndroid 9patch 图片解析堆溢出漏洞分析\u003c/a\u003e前谷歌公开了一个今年1月份更新的漏洞。这个漏洞修复了一个存在于Android 5.1版本以下图片渲染的问题，可以查看相关链接。9patch是Android上特有的一种图片格式，就是在普通的png图片的基础了增加了一些像素的边框，使之具有可随意拉伸、缩放的功能。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.yrom.net/blog/2015/05/25/the_other_way_to_package_multi_channel_apks/\"\u003eGradle 修改 Maven 仓库地址\u003c/a\u003e要先说明的是本文说的“渠道”单指在AndroidManifest.xml 用定义的一个标识字符串（如友盟统计）。在代码或者通过其他文件定义的方式殊途同归。说起 Android 多渠道打包，真是八仙过海各显神通：有手动一个个耐心打包的，有用Ant或Maven重复跑编译任务的，有用apktool解包后再修改重打包的，有在build.gradle定义一堆flavor的，乃至有通过apk里META-INF/下的空文件来定义渠道的。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.imooc.com/wenda/detail/263443\"\u003e谷歌推荐的技术能力提升指南\u003c/a\u003e打好扎实的计算机科学基础对于成为一个成功的软件工程师是非常重要的。本指南主要关于如何提升自己的技术能力，非常适合学生用于制定教学课程，当然这里提供的网络资源，并不意味着就可以完全取代现有的课程，正式的课程安排还是要学的(除非你不想拿到毕业证书)。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/yanbober/article/details/45970721\"\u003eAndroid应用setContentView与LayoutInflater加载解析机制源码分析\u003c/a\u003e其实之所以要说这个话题有几个原因：1.理解xml等控件是咋被显示的原理，通常大家写代码都是直接在onCreate里setContentView就完事，没怎么关注其实现原理。2.前面分析《Android触摸屏事件派发机制详解与源码分析三(Activity篇)》时提到了一些关于布局嵌套的问题，当时没有深入解释。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/luoshengyang/article/details/45831269\"\u003eAndroid应用程序UI硬件加速渲染的预加载资源地图集服务（Asset Atlas Service）分析\u003c/a\u003e我们知道，Android系统在启动的时候，会对一些系统资源进行预加载。这样不仅使得应用程序在需要时可以快速地访问这些资源，还使得这些资源能够在不同应用程序之间进行共享。在硬件加速渲染环境中，这些预加载资源还有进一步优化的空间。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/45954255\"\u003eAndroid 不规则封闭区域填充 手指秒变油漆桶\u003c/a\u003e图像的填充有2种经典算法。\n\u003cul\u003e\n\u003cli\u003e一种是种子填充法。种子填充法理论上能够填充任意区域和图形,但是这种算法存在大量的反复入栈和大规模的递归,降低了填充效率。\u003c/li\u003e\n\u003cli\u003e另一种是扫描线填充法。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023\"\u003eAndroid屏幕适配全攻略(最权威的官方适配指导)\u003c/a\u003eAndroid的屏幕适配一直以来都在折磨着我们这些开发者，本篇文章以Google的官方文档为基础，全面而深入的讲解了Android屏幕适配的原因、重要概念、解决方案及最佳实践，我相信如果你能认真的学习本文，对于Android的屏幕适配，你将有所收获！\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/yzzst/article/details/45746853\"\u003eAndroid系统Root与静默安装\u003c/a\u003e静默安装，指的是安装时无需任何用户干预，直接按默认设置安装应用。因为，它的无需用户干预，很多情况下变成了用户压根不知道，应用不知不觉就安装上了。是在推广上极为流氓的手段，很类似PC上的捆绑安装。正因为静默安装时极为流氓的推广行为，所以，其推广价格也极其高。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"\"\u003e代码\u0026amp;开源库\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/chrisbanes/cheesesquare\"\u003echeesesquare\u003c/a\u003eAndroid Design library的示例。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/RobotAmiee/Android-NiceTab\"\u003eAndroid-NiceTab\u003c/a\u003e支持小圆点，背景模糊，图标cross fade等效果的自定义Tab.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/bingoogolapple/BGARefreshLayout-Android\"\u003eBGARefreshLayout-Android\u003c/a\u003e多种下拉刷新效果、上拉加载更多、可配置自定义头部广告位。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/hanks-zyh/AnimateCheckBox\"\u003eAnimateCheckBox\u003c/a\u003e自定义CheckBox，选中未选中的切换动画很赞。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/tianzhijiexian/SelectorInjection\"\u003eSelectorInjection\u003c/a\u003e一个强大的selector注入器，它可以让view自动产生selector状态，免去了你写selector的麻烦。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/lingochamp/ShareLoginLib\"\u003eShareLoginLib\u003c/a\u003e第三方分享登录组件.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/jaredsburrows/AndroidGradleTemplate\"\u003eAndroidGradleTemplate\u003c/a\u003eGradle + Android Studio + Robolectric + Espresso + Mockito + EasyMock/PowerMock + JaCoCo\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/vRallev/android-task\"\u003eAndroid-Task\u003c/a\u003e可以在后台执行Task的Library。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/romannurik/FORMWatchFace\"\u003eFORMWatchFace\u003c/a\u003eAnddroid Wear 表盘。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/AigeStudio/MultiThreadDownloader\"\u003eMultiThreadDownloader\u003c/a\u003e逻辑比较简单但实用的Android多线程断点续传下载器。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/AigeStudio/DatePicker\"\u003eDatePicker\u003c/a\u003eAndroid日历选择器。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/prolificinteractive/material-calendarview\"\u003eMaterial Calendar View\u003c/a\u003eMaterial Design风格的日历控件。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"\"\u003e工具\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\u003ca href=\"http://www.androiddevtools.cn/#android-studio\"\u003eAndroid Studio 1.3 Preview1\u003c/a\u003eThe new version contains many new features.:\n\u003cul\u003e\n\u003cli\u003eNew Allocation Tracker\u003c/li\u003e\n\u003cli\u003eNew Heap dump Viewer\u003c/li\u003e\n\u003cli\u003eMany new code inspections to enforce framework and support library threading annotations, range annotations, call super, check result, etc.\u003c/li\u003e\n\u003cli\u003eMissing permission checks and unhandled revocable permission checks\u003c/li\u003e\n\u003cli\u003eAndroid M preview data binding Support\u003c/li\u003e\n\u003cli\u003eSupport for adding Google Services to the project in the project structure dialog (especially for Analytics)\u003c/li\u003e\n\u003cli\u003eSDK update notifications, and brand new integrated SDK manager UI\u003c/li\u003e\n\u003cli\u003eNew quickfixes, such as automatic generation of a Parcelable implementation\u003c/li\u003e\n\u003cli\u003eMany built-in live code templates\u003c/li\u003e\n\u003cli\u003eMany other smaller features and bug fixes\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003eAs announced at Google I/O, Android Studio 1.3 will include C/C++ support as well, but that is not included in the first couple of preview buil \n\n  * [Android NDK r10e][28]Release Notes: \u0026lt;http://developer.android.com/intl/zh-cn/ndk/downloads/index.html#rel\u0026gt;\n  * [GsonFormat][29]根据Gson库使用的要求,将JSONObject格式的String 解析成实体的 Android Studio 插件。 \n\n### 视频 {#}\n\n  1. [Google I/O 2015的各种视频][30]墙内Google I/O 2015的各种视频，没有看的小伙伴赶紧去瞅瞅看吧。\n  2. [Android QQ音乐架构演进][31]随着移动互联网的不断蓬勃发展，更多用户在移动设备上使用音乐服务，QQ音乐移动客户端使用用户数也在屡创新高，QQ音乐为了达到更好的用户体验并实现用户的新需求，原有的框架已经不能优雅的实现新需求和优先。如何优雅的实现各种需求并在性能和稳定性得到提高，QQ音乐Android开发团队通过以下的篇章给大家分享QQ音乐架构演进带来的痛与乐。\n\n转自：http://androidweekly.cn/android-dev-weekly-issue33/?utm_source=tuicool\n\u003c/code\u003e\u003c/pre\u003e","title":"Android开发技术周报"},{"content":"Android中触摸事件传递过程中最重要的是dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()方法。这个是困扰初学者的问题之一，我开始也是。这里记录一下dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()的处理过程，以供记忆。\ndispatchTouchEvent是处理触摸事件分发,事件(多数情况)是从Activity的dispatchTouchEvent开始的。执行\nsuper.dispatchTouchEvent(ev)，事件向下分发。\nonInterceptTouchEvent是ViewGroup提供的方法，默认返回false，返回true表示拦截。\nonTouchEvent是View中提供的方法，ViewGroup也有这个方法，view中不提供onInterceptTouchEvent。view中默认返回true，表示消费了这个事件。\nView里，有两个回调函数 ：\n**[java]** [view plain](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[copy](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[print](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[?](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219578)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219578/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;27\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev)； - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent ev); ViewGroup里，有三个回调函数 ：\n**[java]** [view plain](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[copy](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[print](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[?](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219578)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219578/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;27\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev)； - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onInterceptTouchEvent(MotionEvent ev); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent ev); 在Activity里，有两个回调函数 ：\n**[java]** [view plain](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[copy](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[print](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[?](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219578)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219578/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;27\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev)； - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent ev); Android中默认情况下事件传递是由最终的view的接收到，传递过程是从父布局到子布局，也就是从Activity到ViewGroup到View的过程，默认情况，ViewGroup起到的是透传作用。Android中事件传递过程（按箭头方向）如下图,图片来自[qiushuiqifei]，谢谢[qiushuiqifei]整理。\n触摸事件是一连串ACTION_DOWN，ACTION_MOVE..MOVE…MOVE、最后ACTION_UP，触摸事件还有ACTION_CANCEL事件。事件都是从ACTION_DOWN开始的，Activity的dispatchTouchEvent()首先接收到ACTION_DOWN，执行super.dispatchTouchEvent(ev)，事件向下分发。\ndispatchTouchEvent()返回true，后续事件（ACTION_MOVE、ACTION_UP）会再传递，如果返回false，dispatchTouchEvent()就接收不到ACTION_UP、ACTION_MOVE。\n下面的几张图参考自[eoe]\n图1.ACTION_DOWN都没被消费\n图2-1.ACTION_DOWN被View消费了\n图2-2.后续ACTION_MOVE和UP在不被拦截的情况下都会去找VIEW\n图3.后续的被拦截了\n图4ACTION_DOWN一开始就被拦截\nandroid中的Touch事件都是从ACTION_DOWN开始的：\n单手指操作：ACTION_DOWN—ACTION_MOVE—-ACTION_UP\n","permalink":"https://blog.zdltech.com/posts/android%E4%B8%AD%E7%9A%84dispatchtoucheventonintercepttouchevent%E5%92%8Contouchevent/","summary":"\u003cp\u003eAndroid中触摸事件传递过程中最重要的是dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()方法。这个是困扰初学者的问题之一，我开始也是。这里记录一下dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()的处理过程，以供记忆。\u003c/p\u003e\n\u003cp\u003edispatchTouchEvent是处理触摸事件分发,事件(多数情况)是从Activity的dispatchTouchEvent开始的。执行\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003esuper\u003c/span\u003e.dispatchTouchEvent(ev)，事件向下分发。\u003c/p\u003e\n\u003cp\u003e    \u003cstrong\u003eonInterceptTouchEvent\u003c/strong\u003e是ViewGroup提供的方法，默认返回false，返回true表示拦截。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eonTouchEvent\u003c/strong\u003e是View中提供的方法，ViewGroup也有这个方法，view中不提供onInterceptTouchEvent。view中默认返回true，表示消费了这个事件。\u003c/p\u003e\n\u003cp\u003eView里，有两个回调函数 ：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[copy](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[print](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[?](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219578)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219578/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;27\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev)；\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent ev);\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eViewGroup里，有三个回调函数 ：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[copy](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[print](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[?](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219578)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219578/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;27\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev)；\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onInterceptTouchEvent(MotionEvent ev);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent ev);\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e在Activity里，有两个回调函数 ：\u003c/p\u003e","title":"Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()"},{"content":"首先讲一下我遇到的需求吧，页面是这样的，上边有东西，中间是列表，下边还有东西。首先我看到列表立刻就想到了用ListView，但是页面有限，只能用ScrollView包一下。想到就做呗。我就在ScrollView里面加了一个ListView, ListView设置的是wapcontent，这样就出现了ListView数据只显示出了一行。好的，解决问题的方案就来了。\n一．设置scrollView中的ListView内容全部显示，不能滑动，将滑动交给scrollView去做。\n做法：在设置adapter之前，重新计算ListView的高度，我这里写了一个方法：\njava代码 [![](http://www.eyeandroid.com/source/plugin/milu_hightLight/help.png)](http://www.eyeandroid.com/) - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 动态设置listView的高度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* count 总条目\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setListViewHeight(ListView listView, BaseAdapter adapter, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; count) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; totalHeight = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; count; i++) { - View listItem = adapter.getView(i, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, listView); - listItem.measure(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - totalHeight += listItem.getMeasuredHeight(); - } - - ViewGroup.LayoutParams params = listView.getLayoutParams(); - params.height = totalHeight + (listView.getDividerHeight() * count); - listView.setLayoutParams(params); - } 这样做的前提条件是布局文件中ListView的高度要指定，这样才能重新计算，不要设成wapcontent！\n二．不全部展示数据，二者皆可滑动。\n此方法不用重新计算ListView的高度，只需焦点在Listview上的时候，ScrollView能把滑动权主动交给Listview，这样需要重写ScrollView的一个方法，如下：\njava代码 [![](http://www.eyeandroid.com/source/plugin/milu_hightLight/help.png)](http://www.eyeandroid.com/) - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onInterceptTouchEvent(MotionEvent ev) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } 这样Scrollview就会根据焦点而让出滑动事件。\n三. 不重新计算ListView的高度，展示所有数据，ListView不可滑动。\n这个做法是重写ListView的onMeasure方法，如下：\njava代码 [![](http://www.eyeandroid.com/source/plugin/milu_hightLight/help.png)](http://www.eyeandroid.com/) - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 设置不滚动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE \u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, - MeasureSpec.AT_MOST); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMeasure(widthMeasureSpec, expandSpec); - - } 这种方法是同事告诉我的，我没有用过。\n做到这里，ScrollView和ListView的问题是解决了，但是ListView的效率问题出现了。\n你会发现在ListView的adapter里的getview方法重复执行了很多次，技术使用了缓存技术也是无用的。\n有时候数据只有两三个，但是getView方法却被执行了40多次。这样肯定是不行的。但是为什么单独使用ListView的时候却不会出现这种问题呢？\n这个原因肯定出在ScrollView和ListView共存上。Google了一下，外国人都不建议他们共存，但是需求是这样的怎么办呢？\n我的最终解决方案：自己写一个类似ListView的东西\n一. 最初:\njava代码 [![](http://www.eyeandroid.com/source/plugin/milu_hightLight/help.png)](http://www.eyeandroid.com/) - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 虚拟listview\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* @author JustMe\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; BaseAdapter adapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyOnItemClickListener onItemClickListener; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 通知更新listview\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; notifyChange() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; count = getChildCount(); - LayoutParams params = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(LayoutParams.FILL_PARENT, - LayoutParams.WRAP_CONTENT); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = count; i \u0026lt; adapter.getCount(); i++) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; index = i; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; LinearLayout layout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearLayout(getContext()); - layout.setLayoutParams(params); - layout.setOrientation(VERTICAL); - View v = adapter.getView(i, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - v.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (onItemClickListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - onItemClickListener.onItemClick(MyListView.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, - layout, index, adapter.getItem(index)); - } - } - }); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 每个条目下面的线\u0026lt;/span\u0026gt; - ImageView imageView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageView(getContext()); - imageView.setBackgroundResource(R.drawable.divider_list); - imageView.setLayoutParams(params); - layout.addView(v); - layout.addView(imageView); - addView(layout, index); - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyListView(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - initAttr(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyListView(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - initAttr(attrs); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 设置方向\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* @param attrs\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initAttr(AttributeSet attrs) { - setOrientation(VERTICAL); - } - - - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; BaseAdapter getAdapter() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; adapter; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 设置adapter并模拟listview添加数据\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* @param adpater\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setAdapter(BaseAdapter adpater) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.adapter = adpater; - - - notifyChange(); - - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 设置条目监听事件\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* @param onClickListener\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnItemClickListener(MyOnItemClickListener onClickListener) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onItemClickListener = onClickListener; - } - - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 点击事件监听\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* @author JustMe\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; MyOnItemClickListener { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onItemClick(ViewGroup parent, View view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, - Object o); - - } - } 这样实现了ListView的最基本的功能，并且提高了效率，例如，全选功能比以上那些方法的速度提高了2-3秒，页面也不卡顿。\n缺点是不能一次加载很多的数据，不然数据会显示的很慢，最好分页加载。说到分页，之前都是在ListView上加footerView，在这里也可以做到。\n二. 升级：\njava代码 [![](http://www.eyeandroid.com/source/plugin/milu_hightLight/help.png)](http://www.eyeandroid.com/) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; BaseAdapter adapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyOnItemClickListener onItemClickListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; footerViewAttached = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View footerview; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 通知更新listview\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; notifyChange() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; count = getChildCount(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (footerViewAttached) { - count\u0026amp;#8211;; - } - LayoutParams params = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = count; i \u0026lt; adapter.getCount(); i++) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; index = i; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; LinearLayout layout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearLayout(getContext()); - layout.setLayoutParams(params); - layout.setOrientation(VERTICAL); - View v = adapter.getView(i, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - v.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (onItemClickListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - onItemClickListener.onItemClick(MyListView.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, layout, index, - adapter.getItem(index)); - } - } - }); - ImageView imageView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageView(getContext()); - imageView.setBackgroundResource(R.drawable.divider_list); - imageView.setLayoutParams(params); - layout.addView(v); - layout.addView(imageView); - addView(layout, index); - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyListView(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - initAttr(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyListView(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - initAttr(attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initAttr(AttributeSet attrs) { - - setOrientation(VERTICAL); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 初始化footerview\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* @param footerView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initFooterView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View footerView) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.footerview = footerView; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 设置footerView监听事件\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* @param onClickListener\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setFooterViewListener(OnClickListener onClickListener) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.footerview.setOnClickListener(onClickListener); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; BaseAdapter getAdapter() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; adapter; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 设置adapter并模拟listview添加????数据\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* @param adpater\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setAdapter(BaseAdapter adpater) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.adapter = adpater; - - removeAllViews(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (footerViewAttached) - addView(footerview); - - notifyChange(); - - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 设置条目监听事件\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* @param onClickListener\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnItemClickListener(MyOnItemClickListener onClickListener) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onItemClickListener = onClickListener; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 没有下一页了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; noMorePages() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (footerview != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; footerViewAttached) { - removeView(footerview); - footerViewAttached = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 可能还有下一??\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; mayHaveMorePages() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!footerViewAttached \u0026amp;\u0026amp; footerview != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - addView(footerview); - footerViewAttached = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; MyOnItemClickListener { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onItemClick(ViewGroup parent, View view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, Object o); - - } - } 这样就可以添加footerView了。最终我是使用了这种方案。\n","permalink":"https://blog.zdltech.com/posts/scrollview%E4%B8%8Blistview%E7%94%9F%E5%AD%98%E4%B9%8B%E9%81%93/","summary":"\u003cp\u003e首先讲一下我遇到的需求吧，页面是这样的，上边有东西，中间是列表，下边还有东西。首先我看到列表立刻就想到了用ListView，但是页面有限，只能用ScrollView包一下。想到就做呗。我就在ScrollView里面加了一个ListView, ListView设置的是wapcontent，这样就出现了ListView数据只显示出了一行。好的，解决问题的方案就来了。\u003c/p\u003e\n\u003cp\u003e一．设置scrollView中的ListView内容全部显示，不能滑动，将滑动交给scrollView去做。\u003c/p\u003e\n\u003cp\u003e做法：在设置adapter之前，重新计算ListView的高度，我这里写了一个方法：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      java代码 [![](http://www.eyeandroid.com/source/plugin/milu_hightLight/help.png)](http://www.eyeandroid.com/)\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* 动态设置listView的高度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;* count 总条目\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setListViewHeight(ListView listView, BaseAdapter adapter,\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; count) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; totalHeight = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; count; i++) {\n\n- View listItem = adapter.getView(i, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, listView);\n\n- listItem.measure(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- totalHeight += listItem.getMeasuredHeight();\n\n- }\n\n- \n- ViewGroup.LayoutParams params = listView.getLayoutParams();\n\n- params.height = totalHeight + (listView.getDividerHeight() * count);\n\n- listView.setLayoutParams(params);\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e这样做的前提条件是\u003ca href=\"http://www.eyeandroid.com/misc.php?mod=tag\u0026amp;id=219\"\u003e布局\u003c/a\u003e文件中ListView的高度要指定，这样才能重新计算，不要设成wapcontent！\u003c/p\u003e","title":"ScrollView下，ListView生存之道"},{"content":"在开发中UI布局是我们都会遇到的问题，随着UI越来越多，布局的重复性、复杂度也会随之增长。Android官方给了几个优化的方法，但是网络上的资料基本上都是对官方资料的翻译，这些资料都特别的简单，经常会出现问题而不知其所以然。这篇文章就是对这些问题的更详细的说明，也欢迎大家多留言交流。\n一、include 首先用得最多的应该是include，按照官方的意思，include就是为了解决重复定义相同布局的问题。例如你有五个界面，这五个界面的顶部都有布局一模一样的一个返回按钮和一个文本控件，在不使用include的情况下你在每个界面都需要重新在xml里面写同样的返回按钮和文本控件的顶部栏，这样的重复工作会相当的恶心。使用include标签，我们只需要把这个会被多次使用的顶部栏独立成一个xml文件，然后在需要使用的地方通过include标签引入即可。其实就相当于C语言、C++中的include头文件一样，我们把一些常用的、底层的API封装起来，然后复用，需要的时候引入它即可，而不必每次都自己写一遍。示例如下 :\nmy_title_layout.xml\n`\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt; \u0026amp;lt;RelativeLayout xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34; android:layout_width=\u0026#34;match_parent\u0026#34; android:id=\u0026#34;@+id/my_title_parent_id\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; \u0026amp;gt; \u0026amp;lt;ImageButton android:id=\u0026#34;@+id/back_btn\u0026#34; android:layout_width=\u0026#34;wrap_content\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:src=\u0026#34;@drawable/ic_launcher\u0026#34; /\u0026amp;gt; \u0026amp;lt;TextView android:id=\u0026#34;@+id/title_tv\u0026#34; android:layout_width=\u0026#34;wrap_content\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:layout_centerVertical=\u0026#34;true\u0026#34; android:layout_marginLeft=\u0026#34;20dp\u0026#34; android:layout_toRightOf=\u0026#34;@+id/back_btn\u0026#34; android:gravity=\u0026#34;center\u0026#34; android:text=\u0026#34;我的title\u0026#34; android:textSize=\u0026#34;18sp\u0026#34; /\u0026amp;gt; \u0026amp;lt;/RelativeLayout\u0026amp;gt; ` include布局文件：\n`\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt; \u0026amp;lt;LinearLayout xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34; android:layout_width=\u0026#34;match_parent\u0026#34; android:layout_height=\u0026#34;match_parent\u0026#34; android:orientation=\u0026#34;vertical\u0026#34; \u0026amp;gt; \u0026amp;lt;include android:id=\u0026#34;@+id/my_title_ly\u0026#34; android:layout_width=\u0026#34;match_parent\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; layout=\u0026#34;@layout/my_title_layout\u0026#34; /\u0026amp;gt; \u0026amp;lt;!-- 代码省略 --\u0026amp;gt; \u0026amp;lt;/LinearLayout\u0026amp;gt; ` 这样我们就可以使用my_title_layout了。\n注意事项 使用include最常见的问题就是findViewById查找不到目标控件，其正确的使用形式如下: `View titleView = findViewById(R.id.my_title_ly) ; TextView titleTextView = (TextView)titleView.findViewById(R.id.title_tv) ; titleTextView.setText(\u0026#34;new Title\u0026#34;); ` 首先找到include的id, 例如这里include设置的id为“my_title_ly”，然后再对获取到的titleView.findViewById来查找目标布局中的子控件，例如title_tv就是my_title_layout.xml中定义的子控件。因此我们如果需要查找控件的话，可以设置include标签的id，通过这个id获取include对应的view以后，再通过对这个view进行findViewById才能正确查找。如果你设置了include标签的id，然后通过被include的布局的root view的id来查找子元素的话，则会报错，如下 :\n`View titleView = findViewById(R.id.my_title_parent_id) ; TextView titleTextView = (TextView)titleView.findViewById(R.id.title_tv) ; titleTextView.setText(\u0026#34;new Title\u0026#34;); ` 这样会报空指针异常，因为titleView没有找到，会报空指针。那么这是怎么回事呢？ 我们来分析它的源码看看吧。对于布局文件的解析，最终都会调用到LayoutInflater的inflate方法，该方法最终又会调用rInflate方法，我们看看这个方法。\n` /** * Recursive method used to descend down the xml hierarchy and instantiate * views, instantiate their children, and then call onFinishInflate(). */ void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException { final int depth = parser.getDepth(); int type; // 迭代xml中的所有元素，挨个解析 while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() \u0026amp;gt; depth) \u0026amp;\u0026amp; type != XmlPullParser.END_DOCUMENT) { if (type != XmlPullParser.START_TAG) { continue; } final String name = parser.getName(); if (TAG_REQUEST_FOCUS.equals(name)) { parseRequestFocus(parser, parent); } else if (TAG_INCLUDE.equals(name)) {// 如果xml中的节点是include节点，则调用parseInclude方法 if (parser.getDepth() == 0) { throw new InflateException(\u0026#34;\u0026amp;lt;include /\u0026amp;gt; cannot be the root element\u0026#34;); } parseInclude(parser, parent, attrs); } else if (TAG_MERGE.equals(name)) { throw new InflateException(\u0026#34;\u0026amp;lt;merge /\u0026amp;gt; must be the root element\u0026#34;); } else if (TAG_1995.equals(name)) { final View view = new BlinkLayout(mContext, attrs); final ViewGroup viewGroup = (ViewGroup) parent; final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs); rInflate(parser, view, attrs, true); viewGroup.addView(view, params); } else { final View view = createViewFromTag(parent, name, attrs); final ViewGroup viewGroup = (ViewGroup) parent; final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs); rInflate(parser, view, attrs, true); viewGroup.addView(view, params); } } if (finishInflate) parent.onFinishInflate(); } ` 这个方法其实就是遍历xml中的所有元素，然后挨个进行解析。例如解析到一个标签，那么就根据用户设置的一些layout_width、layout_height、id等属性来构造一个TextView对象，然后添加到父控件(ViewGroup类型)中。标签也是一样的，我们看到遇到include标签时，会调用parseInclude函数，这就是对标签的解析，我们看看吧。\n`private void parseInclude(XmlPullParser parser, View parent, AttributeSet attrs) throws XmlPullParserException, IOException { int type; if (parent instanceof ViewGroup) { final int layout = attrs.getAttributeResourceValue(null, \u0026#34;layout\u0026#34;, 0); if (layout == 0) {// include标签中没有设置layout属性，会抛出异常 final String value = attrs.getAttributeValue(null, \u0026#34;layout\u0026#34;); if (value == null) { throw new InflateException(\u0026#34;You must specifiy a layout in the\u0026#34; + \u0026#34; include tag: \u0026amp;lt;include layout=\\\u0026#34;@layout/layoutID\\\u0026#34; /\u0026amp;gt;\u0026#34;); } else { throw new InflateException(\u0026#34;You must specifiy a valid layout \u0026#34; + \u0026#34;reference. The layout ID \u0026#34; + value + \u0026#34; is not valid.\u0026#34;); } } else { final XmlResourceParser childParser = getContext().getResources().getLayout(layout); try {// 获取属性集，即在include标签中设置的属性 final AttributeSet childAttrs = Xml.asAttributeSet(childParser); while ((type = childParser.next()) != XmlPullParser.START_TAG \u0026amp;\u0026amp; type != XmlPullParser.END_DOCUMENT) { // Empty. } if (type != XmlPullParser.START_TAG) { throw new InflateException(childParser.getPositionDescription() + \u0026#34;: No start tag found!\u0026#34;); } // 1、解析include中的第一个元素 final String childName = childParser.getName(); // 如果第一个元素是merge标签，那么调用rInflate函数解析 if (TAG_MERGE.equals(childName)) { // Inflate all children. rInflate(childParser, parent, childAttrs, false); } else {// 2、我们例子中的情况会走到这一步,首先根据include的属性集创建被include进来的xml布局的根view // 这里的根view对应为my_title_layout.xml中的RelativeLayout final View view = createViewFromTag(parent, childName, childAttrs); final ViewGroup group = (ViewGroup) parent;// include标签的parent view ViewGroup.LayoutParams params = null; try {// 获3、取布局属性 params = group.generateLayoutParams(attrs); } catch (RuntimeException e) { params = group.generateLayoutParams(childAttrs); } finally { if (params != null) {// 被inlcude进来的根view设置布局参数 view.setLayoutParams(params); } } // 4、Inflate all children. 解析所有子控件 rInflate(childParser, view, childAttrs, true); // Attempt to override the included layout\u0026#39;s android:id with the // one set on the \u0026amp;lt;include /\u0026amp;gt; tag itself. TypedArray a = mContext.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View, 0, 0); int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID); // While we\u0026#39;re at it, let\u0026#39;s try to override android:visibility. int visibility = a.getInt(com.android.internal.R.styleable.View_visibility, -1); a.recycle(); // 5、将include中设置的id设置给根view,因此实际上my_title_layout.xml中的RelativeLayout的id会变成include标签中的id，include不设置id，那么也可以通过relative的找到. if (id != View.NO_ID) { view.setId(id); } switch (visibility) { case 0: view.setVisibility(View.VISIBLE); break; case 1: view.setVisibility(View.INVISIBLE); break; case 2: view.setVisibility(View.GONE); break; } // 6、将根view添加到父控件中 group.addView(view); } } finally { childParser.close(); } } } else { throw new InflateException(\u0026#34;\u0026amp;lt;include /\u0026amp;gt; can only be used inside of a ViewGroup\u0026#34;); } final int currentDepth = parser.getDepth(); while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() \u0026amp;gt; currentDepth) \u0026amp;\u0026amp; type != XmlPullParser.END_DOCUMENT) { // Empty } } ` 整个过程就是根据不同的标签解析不同的元素，首先会解析include元素，然后再解析被include进来的布局的root view元素。在我们的例子中对应的root view就是id为my_title_parent_id的RelativeLayout，然后再解析root view下面的所有元素，这个过程是从上面注释的2~4的过程，然后是设置布局参数。我们注意看注释5处，这里就解释了为什么include标签和被引入的布局的根元素都设置了id的情况下，通过被引入的根元素的id来查找子控件会找不到的情况。我们看到，注释5处的会判断include标签的id如果不是View.NO_ID的话会把该id设置给被引入的布局根元素的id，即此时在我们的例子中被引入的id为my_title_parent_id的根元素RelativeLayout的id被设置成了include标签中的id，即RelativeLayout的id被动态修改成了”my_title_ly”。因此此时我们再通过“my_title_parent_id”这个id来查找根元素就会找不到了！\n所以结论就是： 如果include中设置了id，那么就通过include的id来查找被include布局根元素的View；如果include中没有设置Id, 而被include的布局的根元素设置了id，那么通过该根元素的id来查找该view即可。拿到根元素后查找其子控件都是一样的。\n二、ViewStub 我们先看看官方的说明:\nViewStub is a lightweight view with no dimension and doesn’t draw anything or participate in the layout. As such, it’s cheap to inflate and cheap to leave in a view hierarchy. Each ViewStub simply needs to include the android:layout attribute to specify the layout to inflate.\n其实ViewStub就是一个宽高都为0的一个View，它默认是不可见的，只有通过调用setVisibility函数或者Inflate函数才会将其要装载的目标布局给加载出来，从而达到延迟加载的效果，这个要被加载的布局通过android:layout属性来设置。例如我们通过一个ViewStub来惰性加载一个消息流的评论列表，因为一个帖子可能并没有评论，此时我可以不加载这个评论的ListView，只有当有评论时我才把它加载出来，这样就去除了加载ListView带来的资源消耗以及延时，示例如下 :\n`\u0026amp;lt;ViewStub android:id=\u0026#34;@+id/stub_import\u0026#34; android:inflatedId=\u0026#34;@+id/stub_comm_lv\u0026#34; android:layout=\u0026#34;@layout/my_comment_layout\u0026#34; android:layout_width=\u0026#34;fill_parent\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:layout_gravity=\u0026#34;bottom\u0026#34; / ` my_comment_layout.xml如下:\n`\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt; \u0026amp;lt;ListView xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34; android:layout_width=\u0026#34;match_parent\u0026#34; android:id=\u0026#34;@+id/my_comm_lv\u0026#34; android:layout_height=\u0026#34;match_parent\u0026#34; \u0026amp;gt; \u0026amp;lt;/ListView\u0026amp;gt; ` 在运行时，我们只需要控制id为stub_import的ViewStub的可见性或者调用inflate()函数来控制是否加载这个评论列表即可。示例如下 :\n`public class MainActivity extends Activity { public void onCreate(Bundle b){ // main.xml中包含上面的ViewStub setContentView(R.layout.main); // 方式1，获取ViewStub, ViewStub listStub = (ViewStub) findViewById(R.id.stub_import); // 加载评论列表布局 listStub.setVisibility(View.VISIBLE); // 获取到评论ListView，注意这里是通过ViewStub的inflatedId来获取 ListView commLv = findViewById(R.id.stub_comm_lv); if ( listStub.getVisibility() == View.VISIBLE ) { // 已经加载, 否则还没有加载 } } } ` 通过setVisibility(View.VISIBILITY)来加载评论列表，此时你要获取到评论ListView对象的话，则需要通过findViewById来查找，而这个id并不是就是ViewStub的id。\n这是为什么呢 ？\n我们先看ViewStub的部分代码吧:\n` @SuppressWarnings({\u0026#34;UnusedDeclaration\u0026#34;}) public ViewStub(Context context, AttributeSet attrs, int defStyle) { TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ViewStub, defStyle, 0); // 获取inflatedId属性 mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID); mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0); a.recycle(); a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View, defStyle, 0); mID = a.getResourceId(R.styleable.View_id, NO_ID); a.recycle(); initialize(context); } private void initialize(Context context) { mContext = context; setVisibility(GONE);// 设置不可教案 setWillNotDraw(true);// 设置不绘制 } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(0, 0);// 宽高都为0 } @Override public void setVisibility(int visibility) { if (mInflatedViewRef != null) {// 如果已经加载过则只设置Visibility属性 View view = mInflatedViewRef.get(); if (view != null) { view.setVisibility(visibility); } else { throw new IllegalStateException(\u0026#34;setVisibility called on un-referenced view\u0026#34;); } } else {// 如果未加载,这加载目标布局 super.setVisibility(visibility); if (visibility == VISIBLE || visibility == INVISIBLE) { inflate();// 调用inflate来加载目标布局 } } } /** * Inflates the layout resource identified by {@link #getLayoutResource()} * and replaces this StubbedView in its parent by the inflated layout resource. * * @return The inflated layout resource. * */ public View inflate() { final ViewParent viewParent = getParent(); if (viewParent != null \u0026amp;\u0026amp; viewParent instanceof ViewGroup) { if (mLayoutResource != 0) { final ViewGroup parent = (ViewGroup) viewParent;// 获取ViewStub的parent view，也是目标布局根元素的parent view final LayoutInflater factory = LayoutInflater.from(mContext); final View view = factory.inflate(mLayoutResource, parent, false);// 1、加载目标布局 // 2、如果ViewStub的inflatedId不是NO_ID则把inflatedId设置为目标布局根元素的id，即评论ListView的id if (mInflatedId != NO_ID) { view.setId(mInflatedId); } final int index = parent.indexOfChild(this); parent.removeViewInLayout(this);// 3、将ViewStub自身从parent中移除 final ViewGroup.LayoutParams layoutParams = getLayoutParams(); if (layoutParams != null) { parent.addView(view, index, layoutParams);// 4、将目标布局的根元素添加到parent中，有参数 } else { parent.addView(view, index);// 4、将目标布局的根元素添加到parent中 } mInflatedViewRef = new WeakReference\u0026amp;lt;View\u0026amp;gt;(view); if (mInflateListener != null) { mInflateListener.onInflate(this, view); } return view; } else { throw new IllegalArgumentException(\u0026#34;ViewStub must have a valid layoutResource\u0026#34;); } } else { throw new IllegalStateException(\u0026#34;ViewStub must have a non-null ViewGroup viewParent\u0026#34;); } } ` 可以看到，其实最终加载目标布局的还是inflate()函数，在该函数中将加载目标布局，获取到根元素后，如果mInflatedId不为NO_ID则把mInflatedId设置为根元素的id，这也是为什么我们在获取评论ListView时会使用findViewById(R.id.stub_comm_lv)来获取，其中的stub_comm_lv就是ViewStub的inflatedId。当然如果你没有设置inflatedId的话还是可以通过评论列表的id来获取的，例如findViewById(R.id.my_comm_lv)。然后就是ViewStub从parent中移除、把目标布局的根元素添加到parent中。最后会把目标布局的根元素返回，因此我们在调用inflate()函数时可以直接获得根元素，省掉了findViewById的过程。\n还有一种方式加载目标布局的就是直接调用ViewStub的inflate()方法，示例如下 :\n`public class MainActivity extends Activity { // 把commLv2设置为类的成员变量 ListView commLv2 = null; // public void onCreate(Bundle b){ // main.xml中包含上面的ViewStub setContentView(R.layout.main); // 方式二 ViewStub listStub2 = (ViewStub) findViewById(R.id.stub_import) ; // 成员变量commLv2为空则代表未加载 if ( commLv2 == null ) { // 加载评论列表布局, 并且获取评论ListView,inflate函数直接返回ListView对象 commLv2 = (ListView)listStub2.inflate(); } else { // ViewStub已经加载 } } } ` 注意事项 判断是否已经加载过， 如果通过setVisibility来加载，那么通过判断可见性即可；如果通过inflate()来加载是不可以通过判断可见性来处理的，而需要使用方式2来进行判断。 findViewById的问题，注意ViewStub中是否设置了inflatedId，如果设置了则需要通过inflatedId来查找目标布局的根元素。 三、Merge 首先我们看官方的说明:\nThe tag helps eliminate redundant view groups in your view hierarchy when including one layout within another. For example, if your main layout is a vertical LinearLayout in which two consecutive views can be re-used in multiple layouts, then the re-usable layout in which you place the two views requires its own root view. However, using another LinearLayout as the root for the re-usable layout would result in a vertical LinearLayout inside a vertical LinearLayout. The nested LinearLayout serves no real purpose other than to slow down your UI performance.\n其实就是减少在include布局文件时的层级。标签是这几个标签中最让我费解的，大家可能想不到，标签竟然会是一个Activity，里面有一个LinearLayout对象。\n`/** * Exercise \u0026amp;lt;merge /\u0026amp;gt; tag in XML files. */ public class Merge extends Activity { private LinearLayout mLayout; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); mLayout = new LinearLayout(this); mLayout.setOrientation(LinearLayout.VERTICAL); LayoutInflater.from(this).inflate(R.layout.merge_tag, mLayout); setContentView(mLayout); } public ViewGroup getLayout() { return mLayout; } } ` 使用merge来组织子元素可以减少布局的层级。例如我们在复用一个含有多个子控件的布局时，肯定需要一个ViewGroup来管理，例如这样 :\n`\u0026amp;lt;FrameLayout xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34; android:layout_width=\u0026#34;fill_parent\u0026#34; android:layout_height=\u0026#34;fill_parent\u0026#34;\u0026amp;gt; \u0026amp;lt;ImageView android:layout_width=\u0026#34;fill_parent\u0026#34; android:layout_height=\u0026#34;fill_parent\u0026#34; android:scaleType=\u0026#34;center\u0026#34; android:src=\u0026#34;@drawable/golden_gate\u0026#34; /\u0026amp;gt; \u0026amp;lt;TextView android:layout_width=\u0026#34;wrap_content\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:layout_marginBottom=\u0026#34;20dip\u0026#34; android:layout_gravity=\u0026#34;center_horizontal|bottom\u0026#34; android:padding=\u0026#34;12dip\u0026#34; android:background=\u0026#34;#AA000000\u0026#34; android:textColor=\u0026#34;#ffffffff\u0026#34; android:text=\u0026#34;Golden Gate\u0026#34; /\u0026amp;gt; \u0026amp;lt;/FrameLayout\u0026amp;gt; ` 将该布局通过include引入时就会多引入了一个FrameLayout层级，此时结构如下 :\n使用merge标签就会消除上图中蓝色的FrameLayout层级。示例如下 :\n`\u0026amp;lt;merge xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;gt; \u0026amp;lt;ImageView android:layout_width=\u0026#34;fill_parent\u0026#34; android:layout_height=\u0026#34;fill_parent\u0026#34; android:scaleType=\u0026#34;center\u0026#34; android:src=\u0026#34;@drawable/golden_gate\u0026#34; /\u0026amp;gt; \u0026amp;lt;TextView android:layout_width=\u0026#34;wrap_content\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:layout_marginBottom=\u0026#34;20dip\u0026#34; android:layout_gravity=\u0026#34;center_horizontal|bottom\u0026#34; android:padding=\u0026#34;12dip\u0026#34; android:background=\u0026#34;#AA000000\u0026#34; android:textColor=\u0026#34;#ffffffff\u0026#34; android:text=\u0026#34;Golden Gate\u0026#34; /\u0026amp;gt; \u0026amp;lt;/merge\u0026amp;gt; ` 效果图如下 :\n那么它是如何实现的呢，我们还是看源码吧。相关的源码也是在LayoutInflater的inflate()函数中。\n`public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) { synchronized (mConstructorArgs) { final AttributeSet attrs = Xml.asAttributeSet(parser); Context lastContext = (Context)mConstructorArgs[0]; mConstructorArgs[0] = mContext; View result = root; try { // Look for the root node. int type; while ((type = parser.next()) != XmlPullParser.START_TAG \u0026amp;\u0026amp; type != XmlPullParser.END_DOCUMENT) { // Empty } if (type != XmlPullParser.START_TAG) { throw new InflateException(parser.getPositionDescription() + \u0026#34;: No start tag found!\u0026#34;); } final String name = parser.getName(); // m如果是erge标签，那么调用rInflate进行解析 if (TAG_MERGE.equals(name)) { if (root == null || !attachToRoot) { throw new InflateException(\u0026#34;\u0026amp;lt;merge /\u0026amp;gt; can be used only with a valid \u0026#34; + \u0026#34;ViewGroup root and attachToRoot=true\u0026#34;); } // 解析merge标签 rInflate(parser, root, attrs, false); } else { // 代码省略 } } catch (XmlPullParserException e) { // 代码省略 } return result; } } void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException { final int depth = parser.getDepth(); int type; while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() \u0026amp;gt; depth) \u0026amp;\u0026amp; type != XmlPullParser.END_DOCUMENT) { if (type != XmlPullParser.START_TAG) { continue; } final String name = parser.getName(); if (TAG_REQUEST_FOCUS.equals(name)) { parseRequestFocus(parser, parent); } else if (TAG_INCLUDE.equals(name)) { // 代码省略 parseInclude(parser, parent, attrs); } else if (TAG_MERGE.equals(name)) { throw new InflateException(\u0026#34;\u0026amp;lt;merge /\u0026amp;gt; must be the root element\u0026#34;); } else if (TAG_1995.equals(name)) { final View view = new BlinkLayout(mContext, attrs); final ViewGroup viewGroup = (ViewGroup) parent; final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs); rInflate(parser, view, attrs, true); viewGroup.addView(view, params); } else { // 我们的例子会进入这里 final View view = createViewFromTag(parent, name, attrs); // 获取merge标签的parent final ViewGroup viewGroup = (ViewGroup) parent; // 获取布局参数 final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs); // 递归解析每个子元素 rInflate(parser, view, attrs, true); // 将子元素直接添加到merge标签的parent view中 viewGroup.addView(view, params); } } if (finishInflate) parent.onFinishInflate(); } ` 其实就是如果是merge标签，那么直接将其中的子元素添加到merge标签parent中，这样就保证了不会引入额外的层级。\n在开发过程中，我们一定要尽量去深究一些常用技术点的本质，这样才能避免出了问题不知如何解决的窘境。追根究底才能知道为什么是这样，也是自我成长的必经之路。\n","permalink":"https://blog.zdltech.com/posts/viewstubincludemerge%E4%BD%BF%E7%94%A8%E4%B8%8E%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/","summary":"\u003cp\u003e在开发中UI布局是我们都会遇到的问题，随着UI越来越多，布局的重复性、复杂度也会随之增长。Android官方给了几个优化的方法，但是网络上的资料基本上都是对官方资料的翻译，这些资料都特别的简单，经常会出现问题而不知其所以然。这篇文章就是对这些问题的更详细的说明，也欢迎大家多留言交流。\u003c/p\u003e\n\u003ch2 id=\"一include\"\u003e一、include\u003c/h2\u003e\n\u003cp\u003e首先用得最多的应该是include，按照官方的意思，include就是为了解决重复定义相同布局的问题。例如你有五个界面，这五个界面的顶部都有布局一模一样的一个返回按钮和一个文本控件，在不使用include的情况下你在每个界面都需要重新在xml里面写同样的返回按钮和文本控件的顶部栏，这样的重复工作会相当的恶心。使用include标签，我们只需要把这个会被多次使用的顶部栏独立成一个xml文件，然后在需要使用的地方通过include标签引入即可。其实就相当于C语言、C++中的include头文件一样，我们把一些常用的、底层的API封装起来，然后复用，需要的时候引入它即可，而不必每次都自己写一遍。示例如下 :\u003c/p\u003e\n\u003cp\u003emy_title_layout.xml\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;RelativeLayout xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    android:layout_width=\u0026#34;match_parent\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    android:id=\u0026#34;@+id/my_title_parent_id\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    android:layout_height=\u0026#34;wrap_content\u0026#34; \u0026amp;gt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;ImageButton  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:id=\u0026#34;@+id/back_btn\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:layout_width=\u0026#34;wrap_content\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:layout_height=\u0026#34;wrap_content\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:src=\u0026#34;@drawable/ic_launcher\u0026#34; /\u0026amp;gt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;TextView  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:id=\u0026#34;@+id/title_tv\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:layout_width=\u0026#34;wrap_content\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:layout_height=\u0026#34;wrap_content\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:layout_centerVertical=\u0026#34;true\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:layout_marginLeft=\u0026#34;20dp\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:layout_toRightOf=\u0026#34;@+id/back_btn\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:gravity=\u0026#34;center\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:text=\u0026#34;我的title\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:textSize=\u0026#34;18sp\u0026#34; /\u0026amp;gt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/RelativeLayout\u0026amp;gt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003einclude布局文件：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;LinearLayout xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    android:layout_width=\u0026#34;match_parent\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    android:layout_height=\u0026#34;match_parent\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    android:orientation=\u0026#34;vertical\u0026#34; \u0026amp;gt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;include  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:id=\u0026#34;@+id/my_title_ly\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:layout_width=\u0026#34;match_parent\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android:layout_height=\u0026#34;wrap_content\u0026#34;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        layout=\u0026#34;@layout/my_title_layout\u0026#34; /\u0026amp;gt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;!-- 代码省略 --\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/LinearLayout\u0026amp;gt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这样我们就可以使用my_title_layout了。\u003c/p\u003e","title":"ViewStub、include、merge使用与源码分析"},{"content":"在android编码中，会有一些简便的写法和编码习惯，会导致我们的代码有很多内存泄露的问题。\n在这里做一个已知错误的总结（其中有一些是个人总结和参考其他博主的文章，在此表示感谢）。\n本文会不定时更新，将自己遇到的内存泄漏相关的问题记录下来并提供解决办法。\n1，编写单例的时候常出现的错误。\n错误方式：\npublic class Foo{\nprivate static Foo foo;\nprivate Context mContext;\nprivate Foo(Context mContext){\nthis.mContext = mContext;\n}\n// 普通单例，非线程安全\npublic static Foo getInstance(Context mContext){\nif(foo == null)\nfoo = new Foo(mContext);\nreturn foo;\n}\npublic void otherAction(){\nmContext.xxxx();\n….\n}\n}\n错误原因：\n如果我们在Activity A中或者其他地方使用Foo.getInstance()时，我们总是会顺手写一个『this』或者『mContext』（这个变量也是指向this）。试想一下，当前我们所用的Foo是单例，意味着被初始化后会一直存在与内存中，以方便我们以后调用的时候不会在此次创建Foo对象。但Foo中的『mContext』变量一直都会持有Activity A中的『Context』，导致Activity A即使执行了onDestroy方法，也不能够将自己销毁。但『applicationContext』就不同了，它一直伴随着我们应用存在（中途也可能会被销毁，但也会自动reCreate），所以就不用担心Foo中的『mContext』会持有某Activity的引用，让其无法销毁。\n正确方式：\npublic class Foo{\nprivate static Foo foo;\nprivate Context mContext;\nprivate Foo(Context mContext){\nthis.mContext = mContext;\n}\n// 普通单例，非线程安全\npublic static Foo getInstance(Context mContext){\nif(foo == null)\nfoo = new Foo(mContext.getApplicationContext());\nreturn foo;\n}\npublic void otherAction(){\nmContext.xxxx();\n….\n}\n}\n2，使用匿名内部类的时候经常出现的错误\n错误方式：\npublic class FooActivity extends Activity{\nprivate TextView textView;\nprivate Handler handler = new Handler(){\n@override\npublic void handlerMessage(Message msg){\n}\n};\n@override\npublic void onCreate(Bundle bundle){\nsuper.onCreate(bundle);\nsetContextView(R.layout.activity_foo_layout);\ntextView = (TextView)findViewById(R.id.textView);\nhandler.postDelayed(new Runnable(){\n@override\npublic void run(){\ntextView.setText(“ok”);\n};\n},1000 * 60 * 10);\n}\n}\n错误原因：\n当我们执行了FooActivity的finish方法，被延迟的消息会在被处理之前存在于主线程消息队列中10分钟，而这个消息中又包含了Handler的引用，而Handler是一个匿名内部类的实例，其持有外面的FooActivity的引用，所以这导致了FooActivity无法回收，进而导致FooActivity持有的很多资源都无法回收，所以产生了内存泄露。\n注意上面的new Runnable这里也是匿名内部类实现的，同样也会持有FooActivity的引用，也会阻止FooActivity被回收。\n一个静态的匿名内部类实例不会持有外部类的引用。\n正确方式：\npublic class FooActivity extends Activity{\nprivate TextView textView;\nprivate static class MyHandler extends Handler {\nprivate final WeakReference mActivity;\npublic MyHandler(FooActivity activity) {\nmActivity = new WeakReference(activity);\n}\n@Override\npublic void handleMessage(Message msg) {\nFooActivity activity = mActivity.get();\nif (activity != null) {\n// …\n}\n}\n}\nprivate final MyHandler handler = new MyHandler(this);\n@override\npublic void onCreate(Bundle bundle){\nsuper.onCreate(bundle);\nsetContextView(R.layout.activity_foo_layout);\ntextView = (TextView)findViewById(R.id.textView);\nhandler.postDelayed(new MyRunnable(textView),1000 * 60 * 10);\n}\nprivate static class MyRunnable implements Runnable{\nprivate WeakReference textViewWeakReference;\npublic MyRunnable(TextView textView){\ntextViewWeakReference = new WeakReference(textView);\n}\n@override\npublic void run(){\nfinal TextView textView = textViewWeakReference.get();\nif(textView != null){\ntextView.setText(“OK”);\n}\n};\n}\n}\n3，在使用handler后，记得在onDestroy里面handler.removeCallbacksAndMessages(object token);\nhandler.removeCallbacksAndMessages(null);\n// removeCallbacksAndMessages,当参数为null的时候，可以清除掉所有跟次handler相关的Runnable和Message，我们在onDestroy中调用次方法也就不会发生内存泄漏了。\n开发中需要注意的点以免内存泄漏：\n1，不要让生命周期长于Activity的对象持有到Activity的引用\n2，尽量使用Application的Context而不是Activity的Context\n3，尽量不要在Activity中使用非静态内部类，因为非静态内部类会隐式持有外部类实例的引用（具体可以查看细话Java：”失效”的private修饰符了解）。如果使用静态内部类，将外部实例引用作为弱引用持有。\n4，垃圾回收不能解决内存泄露，了解Android中垃圾回收机制\n获取context的方法，以及使用上context和applicationContext的区别：\n1，View.getContext,返回当前View对象的Context对象，通常是当前正在展示的Activity对象。\n2，Activity.getApplicationContext,获取当前Activity所在的(应用)进程的Context对象，通常我们使用Context对象时，要优先考虑这个全局的进程Context。\n3，ContextWrapper.getBaseContext():用来获取一个ContextWrapper进行装饰之前的Context，可以使用这个方法，这个方法在实际开发中使用并不多，也不建议使用。\n4，Activity.this 返回当前的Activity实例，如果是UI控件需要使用Activity作为Context对象，但是默认的Toast实际上使用ApplicationContext也可以。\n大家注意看到有一些NO上添加了一些数字，其实这些从能力上来说是YES，但是为什么说是NO呢？下面一个一个解释：\n数字1：启动Activity在这些类中是可以的，但是需要创建一个新的task。一般情况不推荐。\n数字2：在这些类中去layout inflate是合法的，但是会使用系统默认的主题样式，如果你自定义了某些样式可能不会被使用。\n数字3：在receiver为null时允许，在4.2或以上的版本中，用于获取黏性广播的当前值。（可以无视）\n注：ContentProvider、BroadcastReceiver之所以在上述表格中，是因为在其内部方法中都有一个context用于使用。\n好了，这里我们看下表格，重点看Activity和Application，可以看到，和UI相关的方法基本都不建议或者不可使用Application，并且，前三个操作基本不可能在Application中出现。实际上，只要把握住一点，凡是跟UI相关的，都应该使用Activity做为Context来处理；其他的一些操作，Service,Activity,Application等实例都可以，当然了，注意Context引用的持有，防止内存泄漏。\n本文参考：\nhttp://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1123/2047.html\nhttp://droidyue.com/blog/2014/12/28/in-android-handler-classes-should-be-static-or-leaks-might-occur/\nhttp://droidyue.com/blog/2015/04/12/avoid-memory-leaks-on-context-in-android/\nhttp://blog.csdn.net/lmj623565791/article/details/40481055\n转自：http://spencer-dev.lofter.com/post/d7b9e_6faf120\n","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E5%8F%91%E4%B8%AD%E5%8F%AF%E8%83%BD%E4%BC%9A%E5%AF%BC%E8%87%B4%E5%86%85%E5%AD%98%E6%B3%84%E9%9C%B2%E7%9A%84%E9%97%AE%E9%A2%98/","summary":"\u003cp\u003e在android编码中，会有一些简便的写法和编码习惯，会导致我们的代码有很多内存泄露的问题。\u003c/p\u003e\n\u003cp\u003e在这里做一个已知错误的总结（其中有一些是个人总结和参考其他博主的文章，在此表示感谢）。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e本文会不定时更新，将自己遇到的内存泄漏相关的问题记录下来并提供解决办法。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1，编写单例的时候常出现的错误。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e错误方式：\u003c/p\u003e\n\u003cp\u003epublic class Foo{\u003c/p\u003e\n\u003cp\u003eprivate static Foo foo;\u003c/p\u003e\n\u003cp\u003eprivate Context mContext;\u003c/p\u003e\n\u003cp\u003eprivate Foo(Context mContext){\u003c/p\u003e\n\u003cp\u003ethis.mContext = mContext;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e// 普通单例，非线程安全\u003c/p\u003e\n\u003cp\u003epublic static Foo getInstance(Context mContext){\u003c/p\u003e\n\u003cp\u003eif(foo == null)\u003c/p\u003e\n\u003cp\u003efoo = new Foo(\u003cstrong\u003emContext\u003c/strong\u003e);\u003c/p\u003e\n\u003cp\u003ereturn foo;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003epublic void otherAction(){\u003c/p\u003e\n\u003cp\u003emContext.xxxx();\u003c/p\u003e\n\u003cp\u003e….\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e错误原因：\u003c/p\u003e\n\u003cp\u003e如果我们在Activity A中或者其他地方使用Foo.getInstance()时，我们总是会顺手写一个『this』或者『mContext』（这个变量也是指向this）。试想一下，当前我们所用的Foo是单例，意味着被初始化后会一直存在与内存中，以方便我们以后调用的时候不会在此次创建Foo对象。但Foo中的『mContext』变量一直都会持有Activity A中的『Context』，导致Activity A即使执行了onDestroy方法，也不能够将自己销毁。但『applicationContext』就不同了，它一直伴随着我们应用存在（中途也可能会被销毁，但也会自动reCreate），所以就不用担心Foo中的『mContext』会持有某Activity的引用，让其无法销毁。\u003c/p\u003e\n\u003cp\u003e正确方式：\u003c/p\u003e\n\u003cp\u003epublic class Foo{\u003c/p\u003e\n\u003cp\u003eprivate static Foo foo;\u003c/p\u003e\n\u003cp\u003eprivate Context mContext;\u003c/p\u003e\n\u003cp\u003eprivate Foo(Context mContext){\u003c/p\u003e\n\u003cp\u003ethis.mContext = mContext;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e// 普通单例，非线程安全\u003c/p\u003e\n\u003cp\u003epublic static Foo getInstance(Context mContext){\u003c/p\u003e","title":"android开发中，可能会导致内存泄露的问题"},{"content":" 原文链接 : [Custom ViewGroups][1] 原文作者 : [Sriram Ramani][2] Android提供了几个ViewGroups如LinearLayout, RelativeLayout, FrameLayout来固定child Views的位置。在这些普通的ViewGroups中有多种使用选择。 例如：LinearLayout几乎支持HTML Flexbox的所有特性(除了包装)。在view之间你可以选择是否显示分割线(dividers),并且基于最大的child测量所有的children。RelativeLayout是一种限制性的解决方案。这些layouts都已经足够好了，但是当你的UI非常复杂的时候它们还能很好的解决么？\nViewGroup with a ProfilePhoto, Title, Subtitle and Menu button.\n上面的这种布局在Facebook app中是非常常见的。有头像、其它的view垂直摆在它的右侧、还有一个可选操作的view在最右边。这个布局可以通过使用LinearLayout嵌套或者一个RelativeLayout这样的普通ViewGroup实现。我们看一下当分别使用这两种布局的情况下在measure时会发生什么。\n使用LinearLayout完成布局的示例\n``` \u0026lt;LinearLayout android:layout_width=\"match_parent\" android:layout_height=\"wrap_content\"\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ProfilePhoto\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;40dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;40dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;0dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;wrap_content\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_weight\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;1\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;orientation\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;vertical\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Title\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;match_parent\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;wrap_content\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Subtitle\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;match_parent\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;wrap_content\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Menu\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;20dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;20dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;/LinearLayout\u0026gt;\n\u0026lt;/div\u0026gt; 在Nexus 5设备上measure发生时的情况如下 \u0026gt; LinearLayout [horizontal] [w: 1080 exactly, h: 1557 exactly ] \u0026gt; ProfilePhoto [w: 120 exactly, h: 120 exactly ] \u0026gt; LinearLayout [vertical] [w: 0 unspecified, h: 0 unspecified] \u0026gt; Title [w: 0 unspecified, h: 0 unspecified] \u0026gt; Subtitle [w: 0 unspecified, h: 0 unspecified] \u0026gt; Title [w: 222 exactly, h: 57 exactly ] \u0026gt; Subtitle [w: 222 exactly, h: 57 exactly ] \u0026gt; Menu [w: 60 exactly, h: 60 exactly ] \u0026gt; LinearLayout [vertical] [w: 900 exactly, h: 1557 at_most ] \u0026gt; Title [w: 900 exactly, h: 1557 at_most ] \u0026gt; Subtitle [w: 900 exactly, h: 1500 at_most ] ProfilePhoto和Menu只被测量了一次，因为它们有明确的宽高值。垂直的LinearLayout被测量了两次。第一次的时候，父LinearLayout要求以UNSPECIFIED spec的方式来测量。导致了垂直的LinearLayout也以这种方式测量它的子view.此时它在它们返回值的基础上以EXACTLY spec的方式测量它的子view，但是它还没有结束。一旦在测量ProfilePhoto和Menu之后，父布局知道可用于垂直的LinearLayout的尺寸大小。以AT_MOST height对Title 和 Subtitle测量之后导致了第二次传值。显然，每一个TextView (Title and Subtitle)被测量3次。第二次传值创建或者废弃Layouts，这些操作是昂贵的。如果想ViewGroup发挥更好的性能，首要的工作就是免去对TextViews的测量传值工作。 使用RelativeLayout效果会不会好一些? \u0026lt;div class=\u0026#34;highlight highlight-java\u0026#34;\u0026gt; \u0026lt;RelativeLayout android:layout_width=\u0026quot;match_parent\u0026quot; android:layout_height=\u0026quot;wrap_content\u0026quot;\u0026gt;\n\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ProfilePhoto\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;40dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;40dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_alignParentTop\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;true\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_alignParentLeft\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;true\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Menu\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;20dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;20dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_alignParentTop\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;true\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_alignParentRight\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;true\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Title\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;wrap_content\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;wrap_content\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_toRightOf\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;@id/profile_photo\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_toLeftOf\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;@id/menu\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Subtitle\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;wrap_content\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;wrap_content\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_below\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;@id/title\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_toRightOf\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;@id/profile_photo\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_toLeftOf\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;@id/menu\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;/RelativeLayout\u0026gt;\n\u0026lt;/div\u0026gt; 测量情况如下： \u0026gt; RelativeLayout [w: 1080 exactly, h: 1557 exactly] \u0026gt; Menu [w: 60 exactly, h: 1557 at_most] \u0026gt; ProfilePhoto [w: 120 exactly, h: 1557 at_most] \u0026gt; Title [w: 900 exactly, h: 1557 at_most] \u0026gt; Subtitle [w: 900 exactly, h: 1557 at_most] \u0026gt; Title [w: 900 exactly, h: 1557 at_most] \u0026gt; Subtitle [w: 900 exactly, h: 1500 at_most] \u0026gt; Menu [w: 60 exactly, h: 60 exactly] \u0026gt; ProfilePhoto [w: 120 exactly, h: 120 exactly] 正如先前提到的，RelativeLayout是通过solving constraints(分解约束。译者认为就是一层一层的测量)进行测量，上面的布局中ProfilePhoto和Menu没有依赖其它的参照物(siblings)，因此它们先被测量(with an AT_MOST height).这时Title(2个约束)和Subtitle(3个约束)才会被测量。此时所有view明确了自己想要的尺寸大小。RelativeLayout使用这些信息第二次传值给Title, Subtitle, Menu和ProfilePhoto。再重复一遍，每个view被测量了两次，因此这种方案稍佳。如果你和上面的LinearLayout例子相比较一下，最后用于测量所有leaf Views所使用的MeasureSpec是相同的-因此最后的输出结果是一样的。 怎么样才能免去对子view的测量传值呢？自定义一个ViewGroup是不是会有帮助？让我们分析一下这个布局。Title 和 Subtitle 总是在ProfilePhoto的左侧在Menu按钮的右侧。如果我们手工解决这个问题，需要计算出ProfilePhoto和Menu按钮的尺寸，并且使用剩下的尺寸再来计算Title 和 Subtitle。这时对每个view只进行一次测量传值。我们叫这种布局为ProfilePhotoLayout。 \u0026lt;div class=\u0026#34;highlight highlight-java\u0026#34;\u0026gt; public class ProfilePhotoLayout extends ViewGroup {\n\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ProfilePhoto\u0026lt;/span\u0026gt; mProfilePhoto; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Menu\u0026lt;/span\u0026gt; mMenu; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Title\u0026lt;/span\u0026gt; mTitle; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Subtitle\u0026lt;/span\u0026gt; mSubtitle; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;onMeasure\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;widthMeasureSpec\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;heightMeasureSpec\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;// 1. Setup initial constraints.\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthConstraints \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; getPaddingLeft() \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; getPaddingRight(); \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightContraints \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; getPaddingTop() \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; getPaddingBottom(); \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;// 2. Measure the ProfilePhoto\u0026lt;/span\u0026gt; measureChildWithMargins( mProfilePhoto, widthMeasureSpec, widthConstraints, heightMeasureSpec, heightConstraints); \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;// 3. Update the contraints.\u0026lt;/span\u0026gt; widthConstraints \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;+=\u0026lt;/span\u0026gt; mProfilePhoto\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMeasuredWidth(); width \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;+=\u0026lt;/span\u0026gt; mProfilePhoto\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMeasuredWidth(); height \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Math\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;max(mProfilePhoto\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMeasuredHeight(), height); \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;// 4. Measure the Menu.\u0026lt;/span\u0026gt; measureChildWithMargins( mMenu, widthMeasureSpec, widthConstraints, heightMeasureSpec, heightConstraints); \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;// 5. Update the constraints.\u0026lt;/span\u0026gt; widthConstraints \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;+=\u0026lt;/span\u0026gt; mMenu\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMeasuredWidth(); width \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;+=\u0026lt;/span\u0026gt; mMenu\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMeasuredWidth(); height \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Math\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;max(mMenu\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMeasuredHeight(), height); \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;// 6. Prepare the vertical MeasureSpec.\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; verticalWidthMeasureSpec \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;MeasureSpec\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;makeMeasureSpec( \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;MeasureSpec\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getSize(widthMeasureSpec) \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;-\u0026lt;/span\u0026gt; widthConstraints, \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;MeasureSpec\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMode(widthMeasureSpec)); \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; verticalHeightMeasureSpec \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;MeasureSpec\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;makeMeasureSpec( \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;MeasureSpec\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getSize(heightMeasureSpec) \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;-\u0026lt;/span\u0026gt; heightConstraints, \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;MeasureSpec\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMode(heightMeasureSpec)); \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;// 7. Measure the Title.\u0026lt;/span\u0026gt; measureChildWithMargins( mTitle, verticalWidthMeasureSpec, \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, verticalHeightMeasureSpec, \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;// 8. Measure the Subtitle.\u0026lt;/span\u0026gt; measureChildWithMargins( mSubtitle, verticalWidthMeasureSpec, \u0026lt;span class=\u0026quot;pl-c1\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, verticalHeightMeasureSpec, mTitle\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMeasuredHeight()); \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;// 9. Update the sizes.\u0026lt;/span\u0026gt; width \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;+=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Math\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;max(mTitle\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMeasuredWidth(), mSubtitle\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMeasuredWidth()); height \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Math\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;max(mTitle\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMeasuredHeight() \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; mSubtitle\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getMeasuredHeight(), height); \u0026lt;span class=\u0026quot;pl-c\u0026quot;\u0026gt;// 10. Set the dimension for this ViewGroup.\u0026lt;/span\u0026gt; setMeasuredDimension( resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec)); } \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-en\u0026quot;\u0026gt;measureChildWithMargins\u0026lt;/span\u0026gt;( \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;child\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;parentWidthMeasureSpec\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;widthUsed\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;parentHeightMeasureSpec\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pl-v\u0026quot;\u0026gt;heightUsed\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;MarginLayoutParams\u0026lt;/span\u0026gt; lp \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;MarginLayoutParams\u0026lt;/span\u0026gt;) child\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;getLayoutParams(); \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childWidthMeasureSpec \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; getChildMeasureSpec( parentWidthMeasureSpec, widthUsed \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; lp\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;leftMargin \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; lp\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;rightMargin, lp\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;width); \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childHeightMeasureSpec \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; getChildMeasureSpec( parentHeightMeasureSpec, heightUsed \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; lp\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;topMargin \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; lp\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;bottomMargin, lp\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;height); child\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;measure(childWidthMeasureSpec, childHeightMeasureSpec); } }\n\u0026lt;/div\u0026gt; 我们来分析一下代码。我们从已知的约束条件开始 — 所有边的内边距，另外还需要考虑的约束是使用固定值的控件的高和宽。Android提供了一个帮助方法-measureChildWithMargins()用于测量ViewGroup内的子view.然而它总是添加padding作为约束条件的一部分。因此我们复写这个方法自己来管理这些约束条件。从测量ProfilePhoto开始，测量完成后更新一下constraints。对menu按钮的测量亦是如此。 现在还剩下Title和Subtitle的宽度没有测量。Android还提供了另外一个帮助方法-makeMeasureSpec()，用于构造MeasureSpec,传入相应的size和mode返回一个MeasureSpec。接下来我们传入Title 和 Subtitle可用的width 和 height及相应的MeasureSpecs来测量Title 和 Subtitle。最后更新一下ViewGroup的尺寸。在这一步可以明确每个view都只被测量一次。 \u0026gt; ProfilePhotoLayout [w: 1080 exactly, h: 1557 exactly] \u0026gt; ProfilePhoto [w: 120 exactly, h: 120 exactly] \u0026gt; Menu [w: 60 exactly, h: 60 exactly] \u0026gt; Title [w: 900 exactly, h: 1557 at_most] \u0026gt; Subtitle [w: 900 exactly, h: 1500 at_most] 性能上是不是提升了？Facebook app中你看见的大多数布局都使用了这种布局，并且经证明确实提高了性能。我把没有提到的onLayout()方法留给读者作为练习。 你喜欢解决这种Android UI 工程问题么? Facebook在这方面缺少专业的人才。 [1]: https://sriramramani.wordpress.com/2015/05/06/custom-viewgroups/ [2]: https://sriramramani.wordpress.com/ ","permalink":"https://blog.zdltech.com/posts/%E5%90%ACfackbook%E5%B7%A5%E7%A8%8B%E5%B8%88%E8%AE%B2custom-viewgroups/","summary":"\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003e原文链接 : [Custom ViewGroups][1]\u003c/li\u003e\n\u003cli\u003e原文作者 : [Sriram Ramani][2]\u003c/li\u003e\n\u003c/ul\u003e\u003c/blockquote\u003e\n\u003cp\u003eAndroid提供了几个ViewGroups如LinearLayout, RelativeLayout, FrameLayout来固定child Views的位置。在这些普通的ViewGroups中有多种使用选择。 例如：LinearLayout几乎支持HTML Flexbox的所有特性(除了包装)。在view之间你可以选择是否显示分割线(dividers),并且基于最大的child测量所有的children。RelativeLayout是一种限制性的解决方案。这些layouts都已经足够好了，但是当你的UI非常复杂的时候它们还能很好的解决么？\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://camo.githubusercontent.com/a6a9af42f7ea610c28e42e954eb20ab3a2129b7c/68747470733a2f2f73726972616d72616d616e692e66696c65732e776f726470726573732e636f6d2f323031352f30352f637573746f6d2d766965772d67726f75702e706e673f773d3135393426683d323034\"\u003e\u003cimg loading=\"lazy\" src=\"https://camo.githubusercontent.com/a6a9af42f7ea610c28e42e954eb20ab3a2129b7c/68747470733a2f2f73726972616d72616d616e692e66696c65732e776f726470726573732e636f6d2f323031352f30352f637573746f6d2d766965772d67726f75702e706e673f773d3135393426683d323034\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eViewGroup with a ProfilePhoto, Title, Subtitle and Menu button.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e上面的这种布局在Facebook app中是非常常见的。有头像、其它的view垂直摆在它的右侧、还有一个可选操作的view在最右边。这个布局可以通过使用LinearLayout嵌套或者一个RelativeLayout这样的普通ViewGroup实现。我们看一下当分别使用这两种布局的情况下在measure时会发生什么。\u003c/p\u003e\n\u003cp\u003e使用LinearLayout完成布局的示例\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-java\"\u003e\n  ```\n\u003cspan class=\"pl-k\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eLinearLayout\u003c/span\u003e\n    android\u003cspan class=\"pl-k\"\u003e:\u003c/span\u003elayout_width\u003cspan class=\"pl-k\"\u003e=\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ematch_parent\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n    android\u003cspan class=\"pl-k\"\u003e:\u003c/span\u003elayout_height\u003cspan class=\"pl-k\"\u003e=\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ewrap_content\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"pl-k\"\u003e\u0026gt;\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;ProfilePhoto\u0026lt;/span\u0026gt;\n    android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;40dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n    android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;40dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;\n\n\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\n    android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;0dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n    android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;wrap_content\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n    android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_weight\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;1\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n    android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;orientation\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;vertical\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;\n\n    \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Title\u0026lt;/span\u0026gt;\n        android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;match_parent\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n        android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;wrap_content\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;\n\n    \u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Subtitle\u0026lt;/span\u0026gt;\n        android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;match_parent\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n        android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;wrap_content\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;\n\n\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;\n\n\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-smi\u0026quot;\u0026gt;Menu\u0026lt;/span\u0026gt;\n    android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_width\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;20dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n    android\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt;layout_height\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-s\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;20dp\u0026lt;span class=\u0026quot;pl-pds\u0026quot;\u0026gt;\u0026quot;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pl-k\u0026quot;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cspan class=\"pl-k\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-k\"\u003e/\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eLinearLayout\u003c/span\u003e\u003cspan class=\"pl-k\"\u003e\u0026gt;\u003c/span\u003e\u003c/p\u003e","title":"听FackBook工程师讲Custom ViewGroups"},{"content":" 1、添加权限：AndroidManifest.xml中必须使用许可\u0026#8221;android.permission.INTERNET\u0026#8221;,否则会出Web page not available错误。 2、在要Activity中生成一个WebView组件：WebView webView = new WebView(this); 3、设置WebView基本信息： 如果访问的页面中有Javascript，则webview必须设置支持Javascript。 webview.getSettings().setJavaScriptEnabled(true); 触摸焦点起作用 requestFocus(); 取消滚动条 this.setScrollBarStyle(SCROLLBARS_OUTSIDE_OVERLAY); 4、设置WevView要显示的网页： 互联网用：webView.loadUrl(\u0026#8220;http://www.google.com\u0026#8221;); 本地文件用：webView.loadUrl(\u0026#8220;file:///android_asset/XX.html\u0026#8221;); 本地文件存放在：assets文件中 5、如果希望点击链接由自己处理，而不是新开Android的系统browser中响应该链接。 给WebView添加一个事件监听对象（WebViewClient) 并重写其中的一些方法 shouldOverrideUrlLoading：对网页中超链接按钮的响应。 当按下某个连接时WebViewClient会调用这个方法，并传递参数：按下的url onLoadResource onPageStart onPageFinish onReceiveError onReceivedHttpAuthRequest 6、如果用webview点链接看了很多页以后，如果不做任何处理，点击系统“Back”键，整个浏览器会调用finish()而结束自身，如果希望浏览的网页回退而不是退出浏览器，需要在当前Activity中处理并消费掉该Back事件。 覆盖Activity类的onKeyDown(int keyCoder,KeyEvent event)方法。 [?](http://www.oschina.net/question/163910_26516#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `boolean` `onKeyDown(``int` `keyCoder,KeyEvent event){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``if``(webView.canGoBack() \u0026amp;\u0026amp; keyCoder == KeyEvent.KEYCODE_BACK){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``webview.goBack(); ``//goBack()表示返回webView的上一页面` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``return` `true``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``return` `false``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026amp;nbsp; ### Android监听WebView滑动到底部 MainActivity如下: \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_5859\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.open-open.com/lib/view/open1379383341959.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; 51 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; 52 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; 53 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; 54 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; 55 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; 56 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; 57 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; 58 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; 59 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; 60 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; 61 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; 62 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; 63 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; 64 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; 65 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; 66 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; 67 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; 68 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; 69 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; 70 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; 71 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; 72 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; 73 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; 74 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; 75 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; 76 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; 77 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; 78 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; 79 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; 80 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; 81 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; 82 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; 83 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; 84 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; 85 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; 86 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; 87 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; 88 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; 89 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; 90 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; 91 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `package` `cn.testwebview;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `import` `android.app.Activity;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `import` `android.graphics.Bitmap;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `import` `android.os.Bundle;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `import` `android.webkit.WebSettings;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `import` `android.webkit.WebView;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `import` `android.webkit.WebViewClient;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; `import` `cn.testwebview.TestWebView.ScrollInterface;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; `/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``* Demo描述:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``* 监听WebView滑动到底部` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``* 参考资料:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``* 1 http://blog.csdn.net/conant1989/article/details/8124582` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``* Thank you very much` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; `public` `class` `MainActivity ``extends` `Activity {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``private` `TestWebView mTestWebView;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``protected` `void` `onCreate(Bundle savedInstanceState) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``super``.onCreate(savedInstanceState);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``setContentView(R.layout.main);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``initWebView();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ``//设置WebView` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``private` `void` `initWebView() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ``mTestWebView = (TestWebView) findViewById(R.id.webView);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``mTestWebView.setVerticalScrollBarEnabled(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ``mTestWebView.setHorizontalScrollBarEnabled(``false``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ``mTestWebView.getSettings().setSupportZoom(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ``mTestWebView.getSettings().setBuiltInZoomControls(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``mTestWebView.getSettings().setJavaScriptEnabled(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; ` ``mTestWebView.getSettings().setDomStorageEnabled(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; ` ``mTestWebView.getSettings().setPluginsEnabled(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; ` ``mTestWebView.requestFocus();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; ` ``mTestWebView.getSettings().setUseWideViewPort(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; ` ``mTestWebView.getSettings().setLoadWithOverviewMode(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; ` ``mTestWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; ` ``mTestWebView.loadUrl(``\u0026quot;http://www.ifeng.com\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; ` ``mTestWebView.setWebViewClient(``new` `TestWebViewClient());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; ` ``webViewScroolChangeListener();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; ` ``//核心代码` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; ` ``private` `void` `webViewScroolChangeListener() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; ` ``mTestWebView.setOnCustomScroolChangeListener(``new` `ScrollInterface() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; ` ``public` `void` `onSChanged(``int` `l, ``int` `t, ``int` `oldl, ``int` `oldt) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; ` ``//WebView的总高度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; ` ``float` `webViewContentHeight=mTestWebView.getContentHeight() * mTestWebView.getScale();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; ` ``//WebView的现高度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; ` ``float` `webViewCurrentHeight=(mTestWebView.getHeight() + mTestWebView.getScrollY());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; ` ``System.out.println(``\u0026quot;webViewContentHeight=\u0026quot;``+webViewContentHeight);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; ` ``System.out.println(``\u0026quot;webViewCurrentHeight=\u0026quot;``+webViewCurrentHeight);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; ` ``if` `((webViewContentHeight-webViewCurrentHeight) == ````) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; ` ``System.out.println(``\u0026quot;WebView滑动到了底端\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; ` ``});` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; ` ``private` `class` `TestWebViewClient ``extends` `WebViewClient{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; ` ``public` `void` `onPageStarted(WebView view, String url, Bitmap favicon) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; ` ``super``.onPageStarted(view, url, favicon);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; ` ``public` `boolean` `shouldOverrideUrlLoading(WebView view, String url) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; ` ``view.loadUrl(url);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; ` ``return` `true``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; ` ``public` `void` `onPageFinished(WebView view, String url) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; ` ``super``.onPageFinished(view, url);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; ` ``public` `void` `onReceivedError(WebView view, ``int` `errorCode,String description, String failingUrl) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; ` ``super``.onReceivedError(view, errorCode, description, failingUrl);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; TestWebView如下: \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_625536\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.open-open.com/lib/view/open1379383341959.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `package` `cn.testwebview;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `import` `android.content.Context;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `import` `android.util.AttributeSet;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `import` `android.webkit.WebView;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `public` `class` `TestWebView ``extends` `WebView {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``public` `ScrollInterface mScrollInterface;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``public` `TestWebView(Context context) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``super``(context);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``public` `TestWebView(Context context, AttributeSet attrs, ``int` `defStyle) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``super``(context, attrs, defStyle);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``public` `TestWebView(Context context, AttributeSet attrs) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``super``(context, attrs);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``protected` `void` `onScrollChanged(``int` `l, ``int` `t, ``int` `oldl, ``int` `oldt) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``super``.onScrollChanged(l, t, oldl, oldt);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``mScrollInterface.onSChanged(l, t, oldl, oldt);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``public` `void` `setOnCustomScroolChangeListener(ScrollInterface scrollInterface) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ``this``.mScrollInterface = scrollInterface;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; ` ``public` `interface` `ScrollInterface {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; ` ``public` `void` `onSChanged(``int` `l, ``int` `t, ``int` `oldl, ``int` `oldt);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; main.xml如下: \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_380669\u0026quot; class=\u0026quot;syntaxhighlighter xml\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.open-open.com/lib/view/open1379383341959.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;``RelativeLayout` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``xmlns:android``=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``xmlns:tools``=``\u0026quot;http://schemas.android.com/tools\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``cn.testwebview.TestWebView` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/webView\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;fill_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;fill_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``android:text``=``\u0026quot;@string/hello_world\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``android:layout_centerInParent``=``\u0026quot;true\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; `\u0026amp;lt;/``RelativeLayout``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-webview-%E6%80%BB%E7%BB%93/","summary":"\u003cdiv\u003e\n  1、添加权限：AndroidManifest.xml中必须使用许可\u0026#8221;android.permission.INTERNET\u0026#8221;,否则会出Web page not available错误。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  2、在要Activity中生成一个WebView组件：WebView webView = new WebView(this);\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  3、设置WebView基本信息：\n\u003c/div\u003e\n\u003cdiv\u003e\n    如果访问的页面中有Javascript，则webview必须设置支持Javascript。\n\u003c/div\u003e\n\u003cdiv\u003e\n    webview.getSettings().setJavaScriptEnabled(true);\n\u003c/div\u003e\n\u003cdiv\u003e\n    触摸焦点起作用\n\u003c/div\u003e\n\u003cdiv\u003e\n    requestFocus();\n\u003c/div\u003e\n\u003cdiv\u003e\n    取消滚动条\n\u003c/div\u003e\n\u003cdiv\u003e\n    this.setScrollBarStyle(SCROLLBARS_OUTSIDE_OVERLAY);\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  4、设置WevView要显示的网页：\n\u003c/div\u003e\n\u003cdiv\u003e\n    互联网用：webView.loadUrl(\u0026#8220;http://www.google.com\u0026#8221;);\n\u003c/div\u003e\n\u003cdiv\u003e\n    本地文件用：webView.loadUrl(\u0026#8220;file:///android_asset/XX.html\u0026#8221;);  本地文件存放在：assets文件中\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  5、如果希望点击链接由自己处理，而不是新开Android的系统browser中响应该链接。\n\u003c/div\u003e\n\u003cdiv\u003e\n    给WebView添加一个事件监听对象（WebViewClient)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n    并重写其中的一些方法\n\u003c/div\u003e\n\u003cdiv\u003e\n  shouldOverrideUrlLoading：对网页中超链接按钮的响应。\n\u003c/div\u003e\n\u003cdiv\u003e\n   当按下某个连接时WebViewClient会调用这个方法，并传递参数：按下的url\n\u003c/div\u003e\n\u003cdiv\u003e\n  onLoadResource\n\u003c/div\u003e\n\u003cdiv\u003e\n  onPageStart\n\u003c/div\u003e\n\u003cdiv\u003e\n  onPageFinish\n\u003c/div\u003e\n\u003cdiv\u003e\n  onReceiveError\n\u003c/div\u003e\n\u003cdiv\u003e\n  onReceivedHttpAuthRequest\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  6、如果用webview点链接看了很多页以后，如果不做任何处理，点击系统“Back”键，整个浏览器会调用finish()而结束自身，如果希望浏览的网页回退而不是退出浏览器，需要在当前Activity中处理并消费掉该Back事件。\n\u003c/div\u003e\n\u003cdiv\u003e\n  覆盖Activity类的onKeyDown(int keyCoder,KeyEvent event)方法。\n  \u003cdiv\u003e\n    \u003cdiv id=\"highlighter_186784\" class=\"syntaxhighlighter  java\"\u003e\n      \u003cdiv class=\"toolbar\"\u003e\n        [?](http://www.oschina.net/question/163910_26516#)\n      \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          1\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          2\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          3\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          4\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          5\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n          6\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n          7\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n          8\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n          \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n            `public` `boolean` `onKeyDown(``int` `keyCoder,KeyEvent event){`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n            `    ``if``(webView.canGoBack() \u0026amp;\u0026amp; keyCoder == KeyEvent.KEYCODE_BACK){`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n            `           ``webview.goBack();   ``//goBack()表示返回webView的上一页面`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n            `            ``return` `true``;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n            `     ``}`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n            `     ``return` `false``;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n            `}`\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n  \n  \n\n    \u0026amp;nbsp;\n  \n\n  \n  ### Android监听WebView滑动到底部\n  \n  \n\n    MainActivity如下:\n  \n\n  \n  \u0026lt;div\u0026gt;\n    \u0026lt;div id=\u0026quot;highlighter_5859\u0026quot; class=\u0026quot;syntaxhighlighter  java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt;\n        [?](http://www.open-open.com/lib/view/open1379383341959.html#)\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n        \u0026lt;tr\u0026gt;\n          \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n              1\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n              2\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n              3\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n              4\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n              5\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n              6\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n              7\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n              8\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n              9\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n              10\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n              11\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n              12\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n              13\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n              14\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n              15\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n              16\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n              17\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n              18\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n              19\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n              20\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n              21\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n              22\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n              23\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n              24\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n              25\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n              26\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n              27\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n              28\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n              29\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n              30\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n              31\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n              32\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n              33\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt;\n              34\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt;\n              35\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt;\n              36\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt;\n              37\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt;\n              38\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt;\n              39\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt;\n              40\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt;\n              41\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt;\n              42\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt;\n              43\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt;\n              44\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt;\n              45\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt;\n              46\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt;\n              47\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt;\n              48\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt;\n              49\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt;\n              50\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt;\n              51\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt;\n              52\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt;\n              53\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt;\n              54\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt;\n              55\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt;\n              56\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt;\n              57\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt;\n              58\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt;\n              59\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt;\n              60\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt;\n              61\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt;\n              62\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt;\n              63\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt;\n              64\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt;\n              65\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt;\n              66\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt;\n              67\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt;\n              68\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt;\n              69\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt;\n              70\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt;\n              71\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt;\n              72\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt;\n              73\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt;\n              74\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt;\n              75\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt;\n              76\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt;\n              77\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt;\n              78\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt;\n              79\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt;\n              80\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt;\n              81\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt;\n              82\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt;\n              83\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt;\n              84\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt;\n              85\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt;\n              86\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt;\n              87\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt;\n              88\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt;\n              89\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt;\n              90\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt;\n              91\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n          \n          \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n              \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n                `package` `cn.testwebview;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n                `import` `android.app.Activity;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n                `import` `android.graphics.Bitmap;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n                `import` `android.os.Bundle;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n                `import` `android.webkit.WebSettings;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n                `import` `android.webkit.WebView;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n                `import` `android.webkit.WebViewClient;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n                `import` `cn.testwebview.TestWebView.ScrollInterface;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n                `/**`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n                ` ``* Demo描述:`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n                ` ``* 监听WebView滑动到底部`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n                ` ``*`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n                ` ``* 参考资料:`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n                ` ``* 1 http://blog.csdn.net/conant1989/article/details/8124582`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n                ` ``*   Thank you very much`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n                ` ``*/`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n                `public` `class` `MainActivity ``extends` `Activity {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n                `    ``private` `TestWebView mTestWebView;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n                `    ``@Override`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n                `    ``protected` `void` `onCreate(Bundle savedInstanceState) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n                `        ``super``.onCreate(savedInstanceState);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n                `        ``setContentView(R.layout.main);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n                `        ``initWebView();`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n                `    ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n                `    `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n                `    `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n                `    `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n                `    ``//设置WebView`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n                `    ``private` `void` `initWebView() {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n                `        ``mTestWebView = (TestWebView) findViewById(R.id.webView);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n                `        ``mTestWebView.setVerticalScrollBarEnabled(``true``);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n                `        ``mTestWebView.setHorizontalScrollBarEnabled(``false``);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n                `        ``mTestWebView.getSettings().setSupportZoom(``true``);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt;\n                `        ``mTestWebView.getSettings().setBuiltInZoomControls(``true``);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt;\n                `        ``mTestWebView.getSettings().setJavaScriptEnabled(``true``);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt;\n                `        `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt;\n                `        ``mTestWebView.getSettings().setDomStorageEnabled(``true``);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt;\n                `        ``mTestWebView.getSettings().setPluginsEnabled(``true``);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt;\n                `        ``mTestWebView.requestFocus();`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt;\n                `        `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt;\n                `        ``mTestWebView.getSettings().setUseWideViewPort(``true``);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt;\n                `        ``mTestWebView.getSettings().setLoadWithOverviewMode(``true``);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt;\n                `        ``mTestWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt;\n                `        `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt;\n                `        ``mTestWebView.loadUrl(``\u0026quot;http://www.ifeng.com\u0026quot;``);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt;\n                `        ``mTestWebView.setWebViewClient(``new` `TestWebViewClient());`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt;\n                `        ``webViewScroolChangeListener();`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt;\n                `        `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt;\n                `    ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt;\n                `    `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt;\n                `    ``//核心代码`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt;\n                `    ``private` `void` `webViewScroolChangeListener() {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt;\n                `        ``mTestWebView.setOnCustomScroolChangeListener(``new` `ScrollInterface() {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt;\n                `            ``@Override`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt;\n                `            ``public` `void` `onSChanged(``int` `l, ``int` `t, ``int` `oldl, ``int` `oldt) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt;\n                `                ``//WebView的总高度`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt;\n                `                ``float` `webViewContentHeight=mTestWebView.getContentHeight() * mTestWebView.getScale();`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt;\n                `                ``//WebView的现高度`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt;\n                `                ``float` `webViewCurrentHeight=(mTestWebView.getHeight() + mTestWebView.getScrollY());`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt;\n                `                ``System.out.println(``\u0026quot;webViewContentHeight=\u0026quot;``+webViewContentHeight);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt;\n                `                ``System.out.println(``\u0026quot;webViewCurrentHeight=\u0026quot;``+webViewCurrentHeight);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt;\n                `                ``if` `((webViewContentHeight-webViewCurrentHeight) == ````) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt;\n                `                    ``System.out.println(``\u0026quot;WebView滑动到了底端\u0026quot;``);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt;\n                `                ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt;\n                `            ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt;\n                `        ``});`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt;\n                `    ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt;\n                `    `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt;\n                `    ``private` `class` `TestWebViewClient ``extends` `WebViewClient{`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt;\n                `        ``@Override`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt;\n                `        ``public` `void` `onPageStarted(WebView view, String url, Bitmap favicon) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt;\n                `            ``super``.onPageStarted(view, url, favicon);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt;\n                `        ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt;\n                `        ``@Override`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt;\n                `        ``public` `boolean` `shouldOverrideUrlLoading(WebView view, String url) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt;\n                `            ``view.loadUrl(url);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt;\n                `            ``return` `true``;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt;\n                `        ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt;\n                `        ``@Override`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt;\n                `        ``public` `void` `onPageFinished(WebView view, String url) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt;\n                `            ``super``.onPageFinished(view, url);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt;\n                `            `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt;\n                `        ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt;\n                `        ``@Override`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt;\n                `        ``public` `void` `onReceivedError(WebView view, ``int` `errorCode,String description, String failingUrl) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt;\n                `            ``super``.onReceivedError(view, errorCode, description, failingUrl);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt;\n                `        ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt;\n                `    ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt;\n                `   `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt;\n                `}`\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n        \u0026lt;/tr\u0026gt;\n      \u0026lt;/table\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n\n    TestWebView如下:\n  \n\n  \n  \u0026lt;div\u0026gt;\n    \u0026lt;div id=\u0026quot;highlighter_625536\u0026quot; class=\u0026quot;syntaxhighlighter  java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt;\n        [?](http://www.open-open.com/lib/view/open1379383341959.html#)\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n        \u0026lt;tr\u0026gt;\n          \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n              1\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n              2\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n              3\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n              4\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n              5\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n              6\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n              7\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n              8\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n              9\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n              10\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n              11\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n              12\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n              13\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n              14\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n              15\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n              16\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n              17\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n              18\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n              19\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n              20\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n              21\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n              22\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n              23\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n              24\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n              25\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n              26\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n              27\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n              28\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n              29\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n              30\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n              31\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n              32\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n              33\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt;\n              34\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt;\n              35\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt;\n              36\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt;\n              37\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt;\n              38\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt;\n              39\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt;\n              40\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt;\n              41\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt;\n              42\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt;\n              43\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n          \n          \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n              \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n                `package` `cn.testwebview;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n                `import` `android.content.Context;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n                `import` `android.util.AttributeSet;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n                `import` `android.webkit.WebView;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n                `public` `class` `TestWebView ``extends` `WebView {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n                `    ``public` `ScrollInterface mScrollInterface;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n                `    ``public` `TestWebView(Context context) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n                `        ``super``(context);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n                `    ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n                `    ``public` `TestWebView(Context context, AttributeSet attrs, ``int` `defStyle) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n                `        ``super``(context, attrs, defStyle);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n                `    ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n                `    ``public` `TestWebView(Context context, AttributeSet attrs) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n                `        ``super``(context, attrs);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n                `    ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n                `    ``@Override`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n                `    ``protected` `void` `onScrollChanged(``int` `l, ``int` `t, ``int` `oldl, ``int` `oldt) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n                `        ``super``.onScrollChanged(l, t, oldl, oldt);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n                `        ``mScrollInterface.onSChanged(l, t, oldl, oldt);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n                `    ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n                `    ``public` `void` `setOnCustomScroolChangeListener(ScrollInterface scrollInterface) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n                `        ``this``.mScrollInterface = scrollInterface;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt;\n                `    ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt;\n                `    ``public` `interface` `ScrollInterface {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt;\n                `        ``public` `void` `onSChanged(``int` `l, ``int` `t, ``int` `oldl, ``int` `oldt);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt;\n                `    ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt;\n                `}`\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n        \u0026lt;/tr\u0026gt;\n      \u0026lt;/table\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n\n    \u0026amp;nbsp;\n  \n\n  \n  \n\n    main.xml如下:\n  \n\n  \n  \u0026lt;div\u0026gt;\n    \u0026lt;div id=\u0026quot;highlighter_380669\u0026quot; class=\u0026quot;syntaxhighlighter  xml\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt;\n        [?](http://www.open-open.com/lib/view/open1379383341959.html#)\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n        \u0026lt;tr\u0026gt;\n          \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n              1\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n              2\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n              3\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n              4\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n              5\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n              6\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n              7\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n              8\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n              9\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n              10\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n              11\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n              12\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n              13\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n              14\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n              15\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n              16\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n          \n          \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n              \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n                `\u0026amp;lt;``RelativeLayout`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n                `    ``xmlns:android``=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n                `    ``xmlns:tools``=``\u0026quot;http://schemas.android.com/tools\u0026quot;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n                `    ``android:layout_width``=``\u0026quot;match_parent\u0026quot;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n                `    ``android:layout_height``=``\u0026quot;match_parent\u0026quot;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n                `  ``\u0026amp;gt;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n                `    ``\u0026amp;lt;``cn.testwebview.TestWebView`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n                `        ``android:id``=``\u0026quot;@+id/webView\u0026quot;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n                `        ``android:layout_width``=``\u0026quot;fill_parent\u0026quot;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n                `        ``android:layout_height``=``\u0026quot;fill_parent\u0026quot;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n                `        ``android:text``=``\u0026quot;@string/hello_world\u0026quot;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n                `        ``android:layout_centerInParent``=``\u0026quot;true\u0026quot;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n                `    ``/\u0026amp;gt;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n                `\u0026amp;lt;/``RelativeLayout``\u0026amp;gt;`\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n        \u0026lt;/tr\u0026gt;\n      \u0026lt;/table\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n\n    \u0026amp;nbsp;\n  \n\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e","title":"Android WebView 总结"},{"content":"约几个月前，我正为公司的APP在Android手机上实现拍照截图而烦恼不已。\n上网搜索，确实有不少的例子，大多都是抄来抄去，而且水平多半处于demo的样子，可以用来讲解知识点，但是一碰到实际项目，就漏洞百出。\n当时我用大众化的解决方案，暂时性的做了一个拍照截图的功能，似乎看起来很不错。问题随之而来，我用的是小米手机，在别的手机上都运行正常，小米这里却总是碰钉子。虽然我是个理性的米粉，但是也暗地里把小米的工程师问候了个遍。真是惭愧！\n翻文档也找不出个答案来，我一直对com.android.camera.action.CROP持有大大的疑问，它是从哪里来，它能干什么，它接收处理什么类型的数据？Google对此却讳莫如深，在官方文档中只有Intent中有只言片语言及，却不甚详尽。\n随着项目的驱动，我不能抱着不了解原理就不往前走的心态，唯一要做的，是解决问题。最后在德问上找到一条解决方案，说是哪怕是大米也没问题。当时乐呵呵将代码改了改，确实在所有的手机上跑起来了，一时如释重负，对这个的疑问也抛诸脑后了。\n直到月前，BOSS要求将拍照上传到服务器的图片分辨率加倍。OK，加倍简单，增加outputX以及outputY不就得了？\n`1` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;outputX\u0026quot;``, outputX);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `2` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;outputY\u0026quot;``, outputY);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 这一增加，吓了我一跳。BOSS的手机拍到的照片几乎就是个缩略图，但是被我问候了全体工程师的小米在这个时候就体现出国产神机的范儿了，小米上的尺寸一切正常。这个为什么呢？我大致了解原因，却不知道如何解决。\n在Android中，Intent触发Camera程序，拍好照片后，将会返回数据，但是考虑到内存问题，Camera不会将全尺寸的图像返回给调用的Activity，一般情况下，有可能返回的是缩略图，比如120*160px。\n这是为什么呢？这不是一个Bug，而是经过精心设计的，却对开发者不透明。\n以我的小米手机为例，摄像头800W像素，根据我目前设置拍出来的图片尺寸为3200*2400px。有人说，那就返回呗，大不了耗1-2M的内存，不错，这个尺寸的图片确实只有1.8M左右的大小。但是你想不到的是，这个尺寸对应的Bitmap会耗光你应用程序的所有内存。Android出于安全性考虑，只会给你一个寒碜的缩略图。\n在Android2.3中，默认的Bitmap为32位，类型是ARGB_8888，也就意味着一个像素点占用4个字节的内存。我们来做一个简单的计算题：3200*2400*4 bytes = 30M。\n如此惊人的数字！哪怕你愿意为一张生命周期超不过10s的位图愿意耗费这么巨大的内存，Android也不会答应的。\n`1` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `Mobile devices typically have constrained system resources.` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `2` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `Android devices can have as little as 16MB of memory available to a single application.` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 这是Android Doc的原文，虽然不同手机系统的厂商可能围绕16M这个数字有微微的上调，但是这30M，一般的手机还真挥霍不起。也只有小米这种牛机，内存堪比个人PC，本着土财主般挥金如土的霸气才能做到。\nOK，说了这么多，无非是吐吐苦水，爆爆个人经历而已，实际的解决方案在哪里呢？\n我也是Google到的，话说一般百度不了的问题，那就Google或者直接StackOverFlow，只不过得看英文罢了。\n最后翻来覆去，我在国外的一个Android团队的博客中找到了相应的方案，印证了我的猜想同时也给出了实际的代码。\n我将这篇文章翻译成了中文，作为本博客的基础，建议详细看看。\n【译】如何使用Android MediaStore裁剪大图片\n这篇博客了不起的地方在于解决了Android对返回图片的大小限制，并且详细解释了裁剪图片的Intent附加数据的具体含义。OK，我只是站在巨人的肩膀上，改善方案，适应更广泛需求而已。\n拿图说事儿：\nIntent(“com.android.camera.action.CROP”)对应的所有可选数据都一目了然。在了解上面个个选项的含义之后，我们将目光着眼于三个极为重要的选项：\ndata、MediaStore.EXTRA_OUTPUT以及return-data。\ndata和MediaStore.EXTRA_OUTPUT都是可选的传入数据选项，你可以选择设置data为Bitmap，或者将相应的数据与URI关联起来，你也可以选择是否返回数据（return-data: true）。\n为什么还有不用返回数据的选项？如果对URI足够了解的话，应该知道URI与File相似，你所有的操作如裁剪将数据都保存在了URI中，你已经持有了相应的URI，也就无需多此一举，再返回Bitmap了。\n前面已经说到，可以设置data为Bitmap，但是这种操作的限制在于，你的Bitmap不能太大。因此，我们前进的思路似乎明确了：截大图用URI，小图用Bitmap。\n我将这个思路整理成一张图片：\n这篇主要让大家了解需求的来源，以及如何去思考分析并解决问题。下一篇博客将介绍具体的操作。\n基础篇：\n，我就拍照截图这一需求进行了详细的分析，试图让大家了解Android本身的限制，以及我们应当采取的实现方案。\n根据我们的分析与总结，图片的来源有拍照和相册，而可采取的操作有\n使用Bitmap并返回数据 使用Uri不返回数据 前面我们了解到，使用Bitmap有可能会导致图片过大，而不能返回实际大小的图片，我将采用大图Uri，小图Bitmap的数据存储方式。\n我们将要使用到URI来保存拍照后的图片：\n`1` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `private` `static` `final` `String IMAGE_FILE_LOCATION = ``\u0026quot;file:///sdcard/temp.jpg\u0026quot;``;//temp file` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `2` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `Uri imageUri = Uri.parse(IMAGE_FILE_LOCATION);``//The Uri to store the big bitmap` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 不难知道，我们从相册选取图片的Action为Intent.ACTION_GET_CONTENT。\n根据我们上一篇博客的分析，我准备好了两个实例的Intent。\n一、从相册截大图：\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `Intent intent = ``new` `Intent(Intent.ACTION_GET_CONTENT, ``null``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.setType(``\u0026quot;image/*\u0026quot;``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;crop\u0026quot;``, ``\u0026quot;true\u0026quot;``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;aspectX\u0026quot;``, ``2``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;aspectY\u0026quot;``, ``1``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;outputX\u0026quot;``, ``600``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;outputY\u0026quot;``, ``300``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;scale\u0026quot;``, ``true``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;return-data\u0026quot;``, ``false``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;outputFormat\u0026quot;``, Bitmap.CompressFormat.JPEG.toString());` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;noFaceDetection\u0026quot;``, ``true``); ``// no face detection` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `startActivityForResult(intent, CHOOSE_BIG_PICTURE);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 二、从相册截小图\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `Intent intent = ``new` `Intent(Intent.ACTION_GET_CONTENT, ``null``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.setType(``\u0026quot;image/*\u0026quot;``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;crop\u0026quot;``, ``\u0026quot;true\u0026quot;``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;aspectX\u0026quot;``, ``2``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;aspectY\u0026quot;``, ``1``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;outputX\u0026quot;``, ``200``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;outputY\u0026quot;``, ``100``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;scale\u0026quot;``, ``true``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;return-data\u0026quot;``, ``true``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;outputFormat\u0026quot;``, Bitmap.CompressFormat.JPEG.toString());` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(``\u0026quot;noFaceDetection\u0026quot;``, ``true``); ``// no face detection` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `startActivityForResult(intent, CHOOSE_SMALL_PICTURE);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 三、对应的onActivityResult可以这样处理返回的数据\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `switch` `(requestCode) {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `case` `CHOOSE_BIG_PICTURE:` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``Log.d(TAG, ``\u0026quot;CHOOSE_BIG_PICTURE: data = \u0026quot;` `+ data);``//it seems to be null` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``if``(imageUri != ``null``){` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``Bitmap bitmap = decodeUriAsBitmap(imageUri);``//decode bitmap` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``imageView.setImageBitmap(bitmap);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `case` `CHOOSE_SMALL_PICTURE:` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``if``(data != ``null``){` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``Bitmap bitmap = data.getParcelableExtra(``\u0026quot;data\u0026quot;``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``imageView.setImageBitmap(bitmap);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}``else``{` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `14` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``Log.e(TAG, ``\u0026quot;CHOOSE_SMALL_PICTURE: data = \u0026quot;` `+ data);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `15` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `16` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `17` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `default``:` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `18` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `19` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; `01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `private` `Bitmap decodeUriAsBitmap(Uri uri){` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``Bitmap bitmap = ``null``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``try` `{` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``} ``catch` `(FileNotFoundException e) {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``e.printStackTrace();` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``return` `null``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``return` `bitmap;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 效果图：\n大图 \u0026lt;td\u0026gt; 小图 \u0026lt;/td\u0026gt; [![](http://static.oschina.net/uploads/space/2012/1103/183645_yuLJ_245415.gif)](http://static.oschina.net/uploads/space/2012/1103/183645_yuLJ_245415.gif) \u0026lt;td\u0026gt; [![](http://static.oschina.net/uploads/space/2012/1103/183707_DnNy_245415.gif)](http://static.oschina.net/uploads/space/2012/1103/183707_DnNy_245415.gif) \u0026lt;/td\u0026gt; 我们学习到了如何使用Android相册截图。在这篇博客中，我将向大家展示如何拍照截图。\n拍照截图有点儿特殊，要知道，现在的Android智能手机的摄像头都是几百万的像素，拍出来的图片都是非常大的。因此，我们不能像对待相册截图一样使用Bitmap小图，无论大图小图都统一使用Uri进行操作。\n一、首先准备好需要使用到的Uri：\n`1` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `private` `static` `final` `String IMAGE_FILE_LOCATION = ``\u0026quot;file:///sdcard/temp.jpg\u0026quot;``;//temp file` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `2` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `Uri imageUri = Uri.parse(IMAGE_FILE_LOCATION);``//The Uri to store the big bitmap` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 二、使用MediaStore.ACTION_IMAGE_CAPTURE可以轻松调用Camera程序进行拍照：\n`1` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `Intent intent = ``new` `Intent(MediaStore.ACTION_IMAGE_CAPTURE);``//action is capture` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `2` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `3` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `startActivityForResult(intent, TAKE_BIG_PICTURE);``//or TAKE_SMALL_PICTURE` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 三、接下来就可以在 onActivityResult中拿到返回的数据（Uri），并将Uri传递给截图的程序。\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `switch` `(requestCode) {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `case` `TAKE_BIG_PICTURE:` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``Log.d(TAG, ``\u0026quot;TAKE_BIG_PICTURE: data = \u0026quot;` `+ data);``//it seems to be null` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``//TODO sent to crop` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``cropImageUri(imageUri, ``800``, ``400``, CROP_BIG_PICTURE);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `case` `TAKE_SMALL_PICTURE:` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``Log.i(TAG, ``\u0026quot;TAKE_SMALL_PICTURE: data = \u0026quot;` `+ data);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``//TODO sent to crop` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``cropImageUri(imageUri, ``300``, ``150``, CROP_SMALL_PICTURE);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `14` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `default``:` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `15` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `16` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 可以看到，无论是拍大图片还是小图片，都是使用的Uri，只是尺寸不同而已。我们将这个操作封装在一个方法里面。\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `private` `void` `cropImageUri(Uri uri, ``int` `outputX, ``int` `outputY, ``int` `requestCode){` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``Intent intent = ``new` `Intent(``\u0026quot;com.android.camera.action.CROP\u0026quot;``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``intent.setDataAndType(uri, ``\u0026quot;image/*\u0026quot;``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``intent.putExtra(``\u0026quot;crop\u0026quot;``, ``\u0026quot;true\u0026quot;``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``intent.putExtra(``\u0026quot;aspectX\u0026quot;``, ``2``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``intent.putExtra(``\u0026quot;aspectY\u0026quot;``, ``1``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``intent.putExtra(``\u0026quot;outputX\u0026quot;``, outputX);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``intent.putExtra(``\u0026quot;outputY\u0026quot;``, outputY);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``intent.putExtra(``\u0026quot;scale\u0026quot;``, ``true``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``intent.putExtra(``\u0026quot;return-data\u0026quot;``, ``false``);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``intent.putExtra(``\u0026quot;outputFormat\u0026quot;``, Bitmap.CompressFormat.JPEG.toString());` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``intent.putExtra(``\u0026quot;noFaceDetection\u0026quot;``, ``true``); ``// no face detection` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `14` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``startActivityForResult(intent, requestCode);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `15` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 四、最后一步，我们已经将数据传入裁剪图片程序，接下来要做的就是处理返回的数据了：\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `switch` `(requestCode) {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `case` `CROP_BIG_PICTURE:``//from crop_big_picture` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``Log.d(TAG, ``\u0026quot;CROP_BIG_PICTURE: data = \u0026quot;` `+ data);``//it seems to be null` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``if``(imageUri != ``null``){` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``Bitmap bitmap = decodeUriAsBitmap(imageUri);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``imageView.setImageBitmap(bitmap);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `case` `CROP_SMALL_PICTURE:` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``if``(imageUri != ``null``){` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``Bitmap bitmap = decodeUriAsBitmap(imageUri);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``imageView.setImageBitmap(bitmap);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}``else``{` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `14` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``Log.e(TAG, ``\u0026quot;CROP_SMALL_PICTURE: data = \u0026quot;` `+ data);` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `15` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `16` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `17` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `default``:` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `18` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `19` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 效果图：\n代码托管于GitHub，会不定期更新：https://github.com/ryanhoo/PhotoCropper​\n上篇：\nAndroid大图片裁剪终极解决方案（上：原理分析） 中篇：\nAndroid大图片裁剪终极解决方案（中：从相册截图） 下篇：\nAndroid大图片裁剪终极解决方案（下：拍照截图） 转自：http://blog.csdn.net/floodingfire/article/details/8144604\n","permalink":"https://blog.zdltech.com/posts/android%E5%A4%A7%E5%9B%BE%E7%89%87%E8%A3%81%E5%89%AA%E7%BB%88%E6%9E%81%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E4%B8%8A%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90/","summary":"\u003cp\u003e约几个月前，我正为公司的APP在Android手机上实现拍照截图而烦恼不已。\u003c/p\u003e\n\u003cp\u003e上网搜索，确实有不少的例子，大多都是抄来抄去，而且水平多半处于demo的样子，可以用来讲解知识点，但是一碰到实际项目，就漏洞百出。\u003c/p\u003e\n\u003cp\u003e当时我用大众化的解决方案，暂时性的做了一个拍照截图的功能，似乎看起来很不错。问题随之而来，我用的是小米手机，在别的手机上都运行正常，小米这里却总是碰钉子。虽然我是个理性的米粉，但是也暗地里把小米的工程师问候了个遍。真是惭愧！\u003c/p\u003e\n\u003cp\u003e翻文档也找不出个答案来，我一直对com.android.camera.action.CROP持有大大的疑问，它是从哪里来，它能干什么，它接收处理什么类型的数据？Google对此却讳莫如深，在官方文档中只有Intent中有只言片语言及，却不甚详尽。\u003c/p\u003e\n\u003cp\u003e随着项目的驱动，我不能抱着不了解原理就不往前走的心态，唯一要做的，是解决问题。最后在德问上找到一条解决方案，说是哪怕是大米也没问题。当时乐呵呵将代码改了改，确实在所有的手机上跑起来了，一时如释重负，对这个的疑问也抛诸脑后了。\u003c/p\u003e\n\u003cp\u003e直到月前，BOSS要求将拍照上传到服务器的图片分辨率加倍。OK，加倍简单，增加outputX以及outputY不就得了？\u003c/p\u003e\n\u003cdiv id=\"highlighter_947284\" class=\"syntaxhighlighter  \"\u003e\n  \u003cdiv class=\"lines\"\u003e\n    \u003cdiv class=\"line alt1\"\u003e\n      \u003ctable\u003e\n        \u003ctr\u003e\n          \u003ctd class=\"number\"\u003e\n            `1`\n          \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `intent.putExtra(``\u0026quot;outputX\u0026quot;``, outputX);`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `2`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `intent.putExtra(``\u0026quot;outputY\u0026quot;``, outputY);`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e这一增加，吓了我一跳。BOSS的手机拍到的照片几乎就是个缩略图，但是被我问候了全体工程师的小米在这个时候就体现出国产神机的范儿了，小米上的尺寸一切正常。这个为什么呢？我大致了解原因，却不知道如何解决。\u003c/p\u003e\n\u003cp\u003e在Android中，Intent触发Camera程序，拍好照片后，将会返回数据，但是考虑到内存问题，Camera不会将全尺寸的图像返回给调用的Activity，一般情况下，有可能返回的是缩略图，比如120*160px。\u003c/p\u003e\n\u003cp\u003e这是为什么呢？这不是一个Bug，而是经过精心设计的，却对开发者不透明。\u003c/p\u003e\n\u003cp\u003e以我的小米手机为例，摄像头800W像素，根据我目前设置拍出来的图片尺寸为3200*2400px。有人说，那就返回呗，大不了耗1-2M的内存，不错，这个尺寸的图片确实只有1.8M左右的大小。但是你想不到的是，这个尺寸对应的Bitmap会耗光你应用程序的所有内存。Android出于安全性考虑，只会给你一个寒碜的缩略图。\u003c/p\u003e\n\u003cp\u003e在Android2.3中，默认的Bitmap为32位，类型是ARGB_8888，也就意味着一个像素点占用4个字节的内存。我们来做一个简单的计算题：3200*2400*4 bytes =   30M。\u003c/p\u003e\n\u003cp\u003e如此惊人的数字！哪怕你愿意为一张生命周期超不过10s的位图愿意耗费这么巨大的内存，Android也不会答应的。\u003c/p\u003e\n\u003cdiv id=\"highlighter_559560\" class=\"syntaxhighlighter  \"\u003e\n  \u003cdiv class=\"lines\"\u003e\n    \u003cdiv class=\"line alt1\"\u003e\n      \u003ctable\u003e\n        \u003ctr\u003e\n          \u003ctd class=\"number\"\u003e\n            `1`\n          \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `Mobile devices typically have constrained system resources.`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `2`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `Android devices can have as little as 16MB of memory available to a single application.`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e这是Android Doc的原文，虽然不同手机系统的厂商可能围绕16M这个数字有微微的上调，但是这30M，一般的手机还真挥霍不起。也只有小米这种牛机，内存堪比个人PC，本着土财主般挥金如土的霸气才能做到。\u003c/p\u003e","title":"Android大图片裁剪终极解决方案（上：原理分析）"},{"content":"数字提醒大家肯定都见识过。QQ、微信等app中如果有消息或者提醒的时候，就会展现给用户一个红点或者带有数字的点。前段时间微信上流行把自己的头像换成带有数字提醒的头像，让那些有强迫症的人真是抓狂。\n下面我们就看一下怎么在自己的app中实现这种效果。\n开发者当然可以自己用相对布局来实现这样的效果。一个还好，但是多了呢！就会很繁琐。GitHub上有一个开源的第三方控件，叫做BadgeView。使用它可以很方面的实现想要的效果。\n先来怎么使用，简单的三行代码就可以实现数字提醒：\n**[java]** [view plain](http://blog.csdn.net/crazy1235/article/details/42262369#)[copy](http://blog.csdn.net/crazy1235/article/details/42262369#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/571341)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/571341/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - BadgeView badgeView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; com.jauker.widget.BadgeView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - badgeView.setTargetView(textView); - badgeView.setBadgeCount(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;); 看一下badgeview中常用的方法：\n**[java]** [view plain](http://blog.csdn.net/crazy1235/article/details/42262369#)[copy](http://blog.csdn.net/crazy1235/article/details/42262369#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/571341)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/571341/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - badgeView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BadgeView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - badgeView.setTargetView(layout); - badgeView.setBackground(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;12\u0026lt;/span\u0026gt;, Color.parseColor(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;#9b2eef\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - badgeView.setText(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;提示\u0026amp;#8221;\u0026lt;/span\u0026gt;); **[java]** [view plain](http://blog.csdn.net/crazy1235/article/details/42262369#)[copy](http://blog.csdn.net/crazy1235/article/details/42262369#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/571341)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/571341/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - badgeView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BadgeView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - badgeView.setTargetView(layout); - badgeView.setBadgeGravity(Gravity.BOTTOM | Gravity.CENTER); - badgeView.setBadgeCount(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;); **[java]** [view plain](http://blog.csdn.net/crazy1235/article/details/42262369#)[copy](http://blog.csdn.net/crazy1235/article/details/42262369#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/571341)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/571341/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - badgeView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BadgeView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - badgeView.setTargetView(layout); - badgeView.setBadgeGravity(Gravity.TOP | Gravity.LEFT); - badgeView.setTypeface(Typeface.create(Typeface.SANS_SERIF, - Typeface.ITALIC)); - badgeView.setBadgeCount(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); 实际上BadgeView这个类就是继承TextView的。很多TextView中设置字体的方法都适用于BadgeView。\nOK。效果实现完毕。\nBadgeView下载链接\nbadgeview.jar下载\nDEMO下载\n转载：http://blog.csdn.net/crazy1235/article/details/42262369\n","permalink":"https://blog.zdltech.com/posts/github%E6%8E%A7%E4%BB%B6%E4%B9%8Bbadgeview%E6%95%B0%E5%AD%97%E6%8F%90%E9%86%92/","summary":"\u003cp\u003e数字提醒大家肯定都见识过。QQ、微信等app中如果有消息或者提醒的时候，就会展现给用户一个红点或者带有数字的点。前段时间微信上流行把自己的头像换成带有数字提醒的头像，让那些有强迫症的人真是抓狂。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20141230102251478?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3JhenkxMjM1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e下面我们就看一下怎么在自己的app中实现这种效果。\u003c/p\u003e\n\u003cp\u003e开发者当然可以自己用相对布局来实现这样的效果。一个还好，但是多了呢！就会很繁琐。\u003ca href=\"https://github.com/\"\u003eGitHub\u003c/a\u003e上有一个开源的第三方控件，叫做\u003ca href=\"https://github.com/stefanjauker/BadgeView\"\u003eBadgeView\u003c/a\u003e。使用它可以很方面的实现想要的效果。\u003c/p\u003e\n\u003cp\u003e先来怎么使用，简单的三行代码就可以实现数字提醒：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/crazy1235/article/details/42262369#)[copy](http://blog.csdn.net/crazy1235/article/details/42262369#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/571341)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/571341/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- BadgeView badgeView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; com.jauker.widget.BadgeView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);\n\n- badgeView.setTargetView(textView);\n\n- badgeView.setBadgeCount(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;);\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e看一下badgeview中常用的方法：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/crazy1235/article/details/42262369#)[copy](http://blog.csdn.net/crazy1235/article/details/42262369#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/571341)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/571341/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- badgeView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BadgeView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);\n\n- badgeView.setTargetView(layout);\n\n- badgeView.setBackground(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;12\u0026lt;/span\u0026gt;, Color.parseColor(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;#9b2eef\u0026amp;#8221;\u0026lt;/span\u0026gt;));\n\n- badgeView.setText(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;提示\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"GitHub控件之BadgeView（数字提醒）"},{"content":"推送功能在手机应用开发中越来越重要，已经成为手机开发的必须。在Android应用开发中，由于众所周知的原因，Android消息推送我们不得不大费周折。本文就是用来和大家共同探讨一种Android消息推送的完美解决方案。\n一、消息推送基础\n消息推送，就是在互联网上通过定期传送用户需要的信息来减少信息过载的一项新技术。推送技术通过自动传送信息给用户，来减少用于网络上搜索的时间。它根据用户的兴趣来搜索、过滤信息，并将其定期推给用户，帮助用户高效率地发掘有价值的信息\n当我们开发需要和服务器交互的移动应用时，基本上都需要和服务器进行交互，包括上传数据到服务器，同时从服务器上获取数据。\n一般情况下，客户端与服务器之间通讯客户端是主动的，但这就存在一个问题就是一旦服务器数据有更新或者服务器要下发通知给客户端只能等客户端连接的时候才能实现。这种方式使消息失去了实时性。\n如何使客户端能够实时的收到服务器的消息和通知，总体来说有两种方式，第一种是客户端使用Pull（拉）的方式，就是隔一段时间就去服务器上获取一下信息，看是否有更新的信息出现。第二种就是 服务器使用Push（推送）的方式，当服务器端有新信息了，则把最新的信息Push到客户端上。这样，客户端就能自动的接收到消息。\n虽然Pull和Push两种方式都能实现获取服务器端更新信息的功能，但是明显来说Push方式比Pull方式更优越。因为Pull方式更费客户端的网络流量，更主要的是费电量，还需要我们的程序不停地去监测服务端的变化。\n二、几种常见的解决方案实现原理\n1）轮询(Pull)方式：客户端定时向服务器发送询问消息，一旦服务器有变化则立即同步消息。\n2）SMS(Push)方式：通过拦截SMS消息并且解析消息内容来了解服务器的命令，但这种方式一般用户在经济上很难承受。\n3）持久连接(Push)方式：客户端和服务器之间建立长久连接，这样就可以实现消息的及时行和实时性。\n三、消息推送解决方案概述\nA、C2DM云端推送方案\n在Android手机平台上，Google提供了C2DM（Cloudto Device Messaging）服务。Android Cloud to Device Messaging (C2DM)是一个用来帮助开发者从服务器向Android应用程序发送数据的服务。该服务提供了一个简单的、轻量级的机制，允许服务器可以通知移动应用程序直接与服务器进行通信，以便于从服务器获取应用程序更新和用户数据。\n该方案存在的主要问题是C2DM需要依赖于Google官方提供的C2DM服务器，由于国内的网络环境，这个服务经常不可用。\nB、MQTT协议实现Android推送\n采用MQTT协议实现Android推送功能也是一种解决方案。MQTT是一个轻量级的消息发布/订阅协议，它是实现基于手机客户端的消息推送服务器的理想解决方案。\nwmqtt.jar 是IBM提供的MQTT协议的实现。我们可以从这里（https://github.com/tokudu/AndroidPushNotificationsDemo）下载该项目的实例代码，并且可以找到一个采用PHP书写的服务器端实现（https://github.com/tokudu/PhpMQTTClient）。\nC、RSMB实现推送功能\nReally Small Message Broker (RSMB) ，是一个简单的MQTT代理，同样由IBM提供，其查看地址是：http://www.alphaworks.ibm.com/tech/rsmb。缺省打开1883端口，应用程序当中，它负责接收来自服务器的消息并将其转发给指定的移动设备。SAM是一个针对MQTT写的PHP库。我们可以从这个http://pecl.php.net/package/sam/download/0.2.0地址下载它.\nD、XMPP协议实现Android推送\nGoogle官方的C2DM服务器底层也是采用XMPP协议进行的封装。XMPP(可扩展通讯和表示协议)是基于可扩展标记语言（XML）的协议，它用于即时消息（IM）以及在线探测。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息。\nandroidpn是一个基于XMPP协议的java开源Android push notification实现。它包含了完整的客户端和服务器端。但也存在一些不足之处：\n1） 比如时间过长时，就再也收不到推送的信息了。\n2）性能上也不够稳定。\n3）如果将消息从服务器上推送出去，就不再管理了，不管消息是否成功到达客户端手机上。\n如果我们要使用androidpn，则还需要做大量的工作，需要理解XMPP协议、理解Androidpn的实现机制，需要调试内部存在的BUG。\nE、使用第三方平台\n目前国内、国外有一些推送平台可供使用，但是涉及到收费问题、保密问题、服务质量问题、扩展问题等等，又不得不是我们望而却步。\n四、消息推送完美方案\n综合以上论述，在建立Android消息推送方面可谓方案多多，但每一款方案都有其优缺点。但无论如何，还是自己搭建一个推送平台是上策。因为你有、他有不如自己有。\n举个例子，在搭建自有推送平台上建议使用《某某Android消息推送组件》。该组不仅可以拿来即用，并且还可以提供源码以便扩展，实现自己的特殊需求。\nA、推送原理\nAndroid消息推送组件基于XMPP协议实现Android推送。XMPP（可扩展通讯和表示协议）是基于可扩展标记语言（XML）的协议，它用于即时消息（IM）以及在线探测。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息。\nAndroid消息推送组件实现原理见下图：\n图1-消息推送原理图\nAndroid消息推送组件由服务器部分和客户端部分组成。每一部分都由XMPP协议组件和外部接口组件构成。XMPP协议组件负责服务器和Android客户端间的连接管理、消息通讯，外部接口组件负责接收应用系统、客户端应用的命令，向应用系统发送接收到的通知消息。\nAndroid消息组件提供基于Tomcat的服务器应用和Android开发jar包。其中基于Tomcat的服务器应用直接在Tomcat上部署即可，Android开发jar包引入Android项目即可。\nB 集成方式\n1）服务器部署\nAndroid消息组件Tomcat的服务器应用直接部署在Tomcat中，端口号任意设定。\n2）客户端jar包引用\n在Android项目中建立libs目录，然后将提供的Android开发jar包复制到该目录即可。见下图：\n图2-jar包引入图\n3）Android项目AndroidManifest.xml文件修改\n在该文件中增加以下权限：\n\u0026lt;uses-permission android:name=“android.permission.READ_PHONE_STATE” /\u0026gt;\n\u0026lt;uses-permission android:name=“android.permission.ACCESS_NETWORK_STATE” /\u0026gt;\n\u0026lt;uses-permission android:name=“android.permission.INTERNET” /\u0026gt;\n\u0026lt;uses-permission android:name=“android.permission.ACCESS_WIFI_STATE” /\u0026gt;\n\u0026lt;uses-permission android:name=“android.permission.CHANGE_WIFI_STATE” /\u0026gt;\n\u0026lt;uses-permission android:name=“android.permission.VIBRATE” /\u0026gt;\n在该文件中注册服务：\n\u0026lt;service android:enabled=“true”\nandroid:name=“com.bjjrs.server.NotificationService”\nandroid:label=“NotificationService”\u0026gt;\n\u0026lt;action android:name=“com.bjjrs.server.NotificationService” /\u0026gt;\n至此，Android消息组件集成工作完成。\nC、接口方式\n1）服务器端接口采用基于http协议的访问方式，采用http协议从服务器中获取各种信息，实现通知消息的推送。\n如使用以下方式和参数就可以实现各种用户消息的查询：\nhttp://localhost:8080/user.do?action=getAllUser\u0026amp;isOnline=\u0026amp;userID=\u0026amp;userType=\u0026amp;deptID=\u0026amp;deptName=\u0026amp;realName=\n使用如下方式就可以实现各种消息的推送：\nhttp://localhost:8080/notification.do?action=pushNoti\u0026amp;userNames=\u0026amp;title=\u0026amp;content=\n2）Android客户端接口采用广播机制。\n消息接收：当XMPP协议组件接收到推送消息时，将按照一定格式广播该消息，通知客户端其他应用接收并处理该消息。\n消息发送：客户端应用需要向服务器或者其他客户端发送即时消息时，只需按一定格式广播该消息，XMPP组件就会自动接收该消息并发送到指定的其他客户端。\nD、优势特点\n1）系统集成简单，无需复杂的设置。\n2）Android客户端应用和Android消息推送组件完全分离，通过接口相互调用，实现模块应用最优化。\n3）客户端通讯机制采用广播方式，给客户端应用带来极大的灵活性和可扩展性，可以自由处理接收到的推送消息。\n4）Android消息推送组件在服务器端具备消息存储、消息重发、消息路由等功能，在客户端部分具备断线重连、、收到确认、阅读确认、消息发送、命令执行等功能，确保消息能够推送到客户端，同时也保证客户端能够收到、阅读消息。\nE、 应用范围\nAndroid消息推送组件可在以下场景中使用：\n1）用于消息推送。如：通知下达、应急指挥等。\n2）用户及时消息交互。如在线聊天、工作情况交互等。\n3）用于远程控制。如控制远程客户端的状态、数据上报等。\n最后，希望转载的朋友能够尊重作者的劳动成果，加上转载地址。\nhttp://bbs.hiapk.com/thread-4652657-1-1.html\n","permalink":"https://blog.zdltech.com/posts/android%E6%B6%88%E6%81%AF%E6%8E%A8%E9%80%81%E5%AE%8C%E7%BE%8E%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E5%85%A8%E6%9E%90/","summary":"\u003cp\u003e推送功能在手机应用开发中越来越重要，已经成为手机开发的必须。在Android应用开发中，由于众所周知的原因，Android消息推送我们不得不大费周折。本文就是用来和大家共同探讨一种Android消息推送的完美解决方案。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一、消息推送基础\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e消息推送，就是在互联网上通过定期传送用户需要的信息来减少信息过载的一项新技术。推送技术通过自动传送信息给用户，来减少用于网络上搜索的时间。它根据用户的兴趣来搜索、过滤信息，并将其定期推给用户，帮助用户高效率地发掘有价值的信息\u003c/p\u003e\n\u003cp\u003e当我们开发需要和服务器交互的移动应用时，基本上都需要和服务器进行交互，包括上传数据到服务器，同时从服务器上获取数据。\u003c/p\u003e\n\u003cp\u003e一般情况下，客户端与服务器之间通讯客户端是主动的，但这就存在一个问题就是一旦服务器数据有更新或者服务器要下发通知给客户端只能等客户端连接的时候才能实现。这种方式使消息失去了实时性。\u003c/p\u003e\n\u003cp\u003e如何使客户端能够实时的收到服务器的消息和通知，总体来说有两种方式，第一种是客户端使用Pull（拉）的方式，就是隔一段时间就去服务器上获取一下信息，看是否有更新的信息出现。第二种就是 服务器使用Push（推送）的方式，当服务器端有新信息了，则把最新的信息Push到客户端上。这样，客户端就能自动的接收到消息。\u003c/p\u003e\n\u003cp\u003e虽然Pull和Push两种方式都能实现获取服务器端更新信息的功能，但是明显来说Push方式比Pull方式更优越。因为Pull方式更费客户端的网络流量，更主要的是费电量，还需要我们的程序不停地去监测服务端的变化。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e二、几种常见的解决方案实现原理\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e1）轮询(Pull)方式：客户端定时向服务器发送询问消息，一旦服务器有变化则立即同步消息。\u003c/p\u003e\n\u003cp\u003e2）SMS(Push)方式：通过拦截SMS消息并且解析消息内容来了解服务器的命令，但这种方式一般用户在经济上很难承受。\u003c/p\u003e\n\u003cp\u003e3）持久连接(Push)方式：客户端和服务器之间建立长久连接，这样就可以实现消息的及时行和实时性。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e三、消息推送解决方案概述\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eA、C2DM云端推送方案\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在Android手机平台上，Google提供了C2DM（Cloudto Device Messaging）服务。Android Cloud to Device Messaging (C2DM)是一个用来帮助开发者从服务器向Android应用程序发送数据的服务。该服务提供了一个简单的、轻量级的机制，允许服务器可以通知移动应用程序直接与服务器进行通信，以便于从服务器获取应用程序更新和用户数据。\u003c/p\u003e\n\u003cp\u003e该方案存在的主要问题是C2DM需要依赖于Google官方提供的C2DM服务器，由于国内的网络环境，这个服务经常不可用。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eB、MQTT协议实现Android推送\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e采用MQTT协议实现Android推送功能也是一种解决方案。MQTT是一个轻量级的消息发布/订阅协议，它是实现基于手机客户端的消息推送服务器的理想解决方案。\u003c/p\u003e\n\u003cp\u003ewmqtt.jar 是IBM提供的MQTT协议的实现。我们可以从这里（https://github.com/tokudu/AndroidPushNotificationsDemo）下载该项目的实例代码，并且可以找到一个采用PHP书写的服务器端实现（https://github.com/tokudu/PhpMQTTClient）。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eC、RSMB实现推送功能\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eReally Small Message Broker (RSMB) ，是一个简单的MQTT代理，同样由IBM提供，其查看地址是：http://www.alphaworks.ibm.com/tech/rsmb。缺省打开1883端口，应用程序当中，它负责接收来自服务器的消息并将其转发给指定的移动设备。SAM是一个针对MQTT写的PHP库。我们可以从这个http://pecl.php.net/package/sam/download/0.2.0地址下载它.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eD、XMPP协议实现Android推送\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eGoogle官方的C2DM服务器底层也是采用XMPP协议进行的封装。XMPP(可扩展通讯和表示协议)是基于可扩展标记语言（XML）的协议，它用于即时消息（IM）以及在线探测。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息。\u003c/p\u003e\n\u003cp\u003eandroidpn是一个基于XMPP协议的java开源Android push notification实现。它包含了完整的客户端和服务器端。但也存在一些不足之处：\u003c/p\u003e\n\u003cp\u003e1） 比如时间过长时，就再也收不到推送的信息了。\u003c/p\u003e\n\u003cp\u003e2）性能上也不够稳定。\u003c/p\u003e\n\u003cp\u003e3）如果将消息从服务器上推送出去，就不再管理了，不管消息是否成功到达客户端手机上。\u003c/p\u003e\n\u003cp\u003e如果我们要使用androidpn，则还需要做大量的工作，需要理解XMPP协议、理解Androidpn的实现机制，需要调试内部存在的BUG。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eE、使用第三方平台\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e目前国内、国外有一些推送平台可供使用，但是涉及到收费问题、保密问题、服务质量问题、扩展问题等等，又不得不是我们望而却步。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e四、消息推送完美方案\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e综合以上论述，在建立Android消息推送方面可谓方案多多，但每一款方案都有其优缺点。但无论如何，还是自己搭建一个推送平台是上策。因为你有、他有不如自己有。\u003c/p\u003e\n\u003cp\u003e举个例子，在搭建自有推送平台上建议使用《某某Android消息推送组件》。该组不仅可以拿来即用，并且还可以提供源码以便扩展，实现自己的特殊需求。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eA、推送原理\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eAndroid消息推送组件基于XMPP协议实现Android推送。XMPP（可扩展通讯和表示协议）是基于可扩展标记语言（XML）的协议，它用于即时消息（IM）以及在线探测。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息。\u003c/p\u003e\n\u003cp\u003eAndroid消息推送组件实现原理见下图：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"a.JPG\" loading=\"lazy\" src=\"http://s7.51cto.com/wyfs02/M00/23/15/wKioL1Mw8-Xw8-JxAABPp3oFFg8892.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e图1-消息推送原理图\u003c/p\u003e\n\u003cp\u003eAndroid消息推送组件由服务器部分和客户端部分组成。每一部分都由XMPP协议组件和外部接口组件构成。XMPP协议组件负责服务器和Android客户端间的连接管理、消息通讯，外部接口组件负责接收应用系统、客户端应用的命令，向应用系统发送接收到的通知消息。\u003c/p\u003e\n\u003cp\u003eAndroid消息组件提供基于Tomcat的服务器应用和Android开发jar包。其中基于Tomcat的服务器应用直接在Tomcat上部署即可，Android开发jar包引入Android项目即可。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eB 集成方式\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e1）服务器部署\u003c/p\u003e\n\u003cp\u003eAndroid消息组件Tomcat的服务器应用直接部署在Tomcat中，端口号任意设定。\u003c/p\u003e\n\u003cp\u003e2）客户端jar包引用\u003c/p\u003e\n\u003cp\u003e在Android项目中建立libs目录，然后将提供的Android开发jar包复制到该目录即可。见下图：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"b.JPG\" loading=\"lazy\" src=\"http://s2.51cto.com/wyfs02/M02/23/14/wKiom1Mw9A3BMEQAAABA9CRDCDg207.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e图2-jar包引入图\u003c/p\u003e\n\u003cp\u003e3）Android项目AndroidManifest.xml文件修改\u003c/p\u003e\n\u003cp\u003e在该文件中增加以下权限：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u0026lt;uses-permission android:name=\u003cspan class=\"string\"\u003e“android.permission.READ_PHONE_STATE”\u003c/span\u003e /\u0026gt;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u0026lt;uses-permission android:name=\u003cspan class=\"string\"\u003e“android.permission.ACCESS_NETWORK_STATE”\u003c/span\u003e /\u0026gt;\u003c/p\u003e","title":"Android消息推送完美解决方案全析"},{"content":"概述 RecyclerView出现已经有一段时间了，相信大家肯定不陌生了，大家可以通过导入support-v7对其进行使用。\n据官方的介绍，该控件用于在有限的窗口中展示大量数据集，其实这样功能的控件我们并不陌生，例如：ListView、GridView。\n那么有了ListView、GridView为什么还需要RecyclerView这样的控件呢？整体上看RecyclerView架构，提供了一种插拔式的体验，高度的解耦，异常的灵活，通过设置它提供的不同LayoutManager，ItemDecoration , ItemAnimator实现令人瞠目的效果。\n你想要控制其显示的方式，请通过布局管理器LayoutManager 你想要控制Item间的间隔（可绘制），请通过ItemDecoration 你想要控制Item增删的动画，请通过ItemAnimator 你想要控制点击、长按事件，请自己写（擦，这点尼玛。） 基本使用 鉴于我们对于ListView的使用特别的熟悉，对比下RecyclerView的使用代码：\n`mRecyclerView = findView(R.id.id_recyclerview); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置布局管理器\u0026amp;lt;/span\u0026gt; mRecyclerView.setLayoutManager(layout); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置adapter\u0026amp;lt;/span\u0026gt; mRecyclerView.setAdapter(adapter) \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置Item增加、移除动画\u0026amp;lt;/span\u0026gt; mRecyclerView.setItemAnimator(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DefaultItemAnimator()); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//添加分割线\u0026amp;lt;/span\u0026gt; mRecyclerView.addItemDecoration(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DividerItemDecoration( getActivity(), DividerItemDecoration.HORIZONTAL_LIST));` ok，相比较于ListView的代码，ListView可能只需要去设置一个adapter就能正常使用了。而RecyclerView基本需要上面一系列的步骤，那么为什么会添加这么多的步骤呢？\n那么就必须解释下RecyclerView的这个名字了，从它类名上看，RecyclerView代表的意义是，我只管Recycler View，也就是说RecyclerView只管回收与复用View，其他的你可以自己去设置。可以看出其高度的解耦，给予你充分的定制自由（所以你才可以轻松的通过这个控件实现ListView,GirdView，瀑布流等效果）。\nJust like ListView Activity `\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;package\u0026amp;lt;/span\u0026gt; com.zhy.sample.demo_recyclerview; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.util.ArrayList; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; java.util.List; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.os.Bundle; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.app.ActionBarActivity; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.LinearLayoutManager; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView.ViewHolder; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.LayoutInflater; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.View; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.ViewGroup; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.widget.TextView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;HomeActivity\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ActionBarActivity\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; RecyclerView mRecyclerView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; mDatas; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; HomeAdapter mAdapter; \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreate\u0026amp;lt;/span\u0026gt;(Bundle savedInstanceState) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(R.layout.activity_single_recyclerview); initData(); mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview); mRecyclerView.setLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; LinearLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;)); mRecyclerView.setAdapter(mAdapter = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; HomeAdapter()); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;protected\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;initData\u0026amp;lt;/span\u0026gt;() { mDatas = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; ArrayList\u0026amp;lt;String\u0026amp;gt;(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;A\u0026#39;\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#39;z\u0026#39;\u0026amp;lt;/span\u0026gt;; i++) { mDatas.add(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026amp;lt;/span\u0026gt; + (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;char\u0026amp;lt;/span\u0026gt;) i); } } class HomeAdapter extends RecyclerView.Adapter\u0026amp;lt;HomeAdapter.MyViewHolder\u0026amp;gt; { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; MyViewHolder \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreateViewHolder\u0026amp;lt;/span\u0026gt;(ViewGroup parent, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; viewType) { MyViewHolder holder = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; MyViewHolder(LayoutInflater.from( HomeActivity.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;).inflate(R.layout.item_home, parent, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;)); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; holder; } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onBindViewHolder\u0026amp;lt;/span\u0026gt;(MyViewHolder holder, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position) { holder.tv.setText(mDatas.get(position)); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getItemCount\u0026amp;lt;/span\u0026gt;() { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; mDatas.size(); } class MyViewHolder extends ViewHolder { TextView tv; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;MyViewHolder\u0026amp;lt;/span\u0026gt;(View view) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;(view); tv = (TextView) view.findViewById(R.id.id_num); } } } }` Activity的布局文件 `\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;RelativeLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:tools\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/tools\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;android.support.v7.widget.RecyclerView \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/id_recyclerview\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:divider\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#ffff0000\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:dividerHeight\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;10dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;RelativeLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` Item的布局文件 `\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;FrameLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#44ff0000\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;TextView \u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/id_num\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;50dp\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;center\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:text\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;1\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;FrameLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 这么看起来用法与ListView的代码基本一致哈~~\n看下效果图：\n看起来好丑，Item间应该有个分割线，当你去找时，你会发现RecyclerView并没有支持divider这样的属性。那么怎么办，你可以给Item的布局去设置margin，当然了这种方式不够优雅，我们文章开始说了，我们可以自由的去定制它，当然我们的分割线也是可以定制的。\nItemDecoration 我们可以通过该方法添加分割线：\nmRecyclerView.addItemDecoration()\n该方法的参数为RecyclerView.ItemDecoration，该类为抽象类，官方目前并没有提供默认的实现类（我觉得最好能提供几个）。\n该类的源码：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;abstract\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ItemDecoration\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDraw\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent, State state) { onDraw(c, parent); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDrawOver\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent, State state) { onDrawOver(c, parent); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getItemOffsets\u0026amp;lt;/span\u0026gt;(Rect outRect, View view, RecyclerView parent, State state) { getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(), parent); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Deprecated\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getItemOffsets\u0026amp;lt;/span\u0026gt;(Rect outRect, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; itemPosition, RecyclerView parent) { outRect.set(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); }` 当我们调用mRecyclerView.addItemDecoration()方法添加decoration的时候，RecyclerView在绘制的时候，去会绘制decorator，即调用该类的onDraw和onDrawOver方法，\nonDraw方法先于drawChildren onDrawOver在drawChildren之后，一般我们选择复写其中一个即可。 getItemOffsets 可以通过outRect.set()为每个Item设置一定的偏移量，主要用于绘制Decorator。 接下来我们看一个RecyclerView.ItemDecoration的实现类，该类很好的实现了RecyclerView添加分割线（当使用LayoutManager为LinearLayoutManager时）。\n该类参考自：DividerItemDecoration\n` \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;package\u0026amp;lt;/span\u0026gt; com.zhy.sample.demo_recyclerview; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the \u0026#34;License\u0026#34;); * limitations under the License. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.content.Context; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.content.res.TypedArray; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Canvas; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Rect; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.drawable.Drawable; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.LinearLayoutManager; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView.State; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.util.Log; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.View; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * This class is from the v7 samples of the Android SDK. It\u0026#39;s not by me! * \u0026amp;lt;p/\u0026amp;gt; * See the license above for details. */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DividerItemDecoration\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;RecyclerView\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ItemDecoration\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] ATTRS = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[]{ android.R.attr.listDivider }; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; VERTICAL_LIST = LinearLayoutManager.VERTICAL; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; Drawable mDivider; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; mOrientation; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DividerItemDecoration\u0026amp;lt;/span\u0026gt;(Context context, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; orientation) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); a.recycle(); setOrientation(orientation); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setOrientation\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; orientation) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (orientation != HORIZONTAL_LIST \u0026amp;\u0026amp; orientation != VERTICAL_LIST) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;throw\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; IllegalArgumentException(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;invalid orientation\u0026#34;\u0026amp;lt;/span\u0026gt;); } mOrientation = orientation; } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDraw\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent) { Log.v(\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;recyclerview - itemdecoration\u0026#34;\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;onDraw()\u0026#34;\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { drawHorizontal(c, parent); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawVertical\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left = parent.getPaddingLeft(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right = parent.getWidth() - parent.getPaddingRight(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount = parent.getChildCount(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; childCount; i++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; View child = parent.getChildAt(i); android.support.v7.widget.RecyclerView v = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView(parent.getContext()); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top = child.getBottom() + params.bottomMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawHorizontal\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top = parent.getPaddingTop(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom = parent.getHeight() - parent.getPaddingBottom(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount = parent.getChildCount(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; childCount; i++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; View child = parent.getChildAt(i); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left = child.getRight() + params.rightMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right = left + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getItemOffsets\u0026amp;lt;/span\u0026gt;(Rect outRect, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; itemPosition, RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mOrientation == VERTICAL_LIST) { outRect.set(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mDivider.getIntrinsicHeight()); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { outRect.set(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mDivider.getIntrinsicWidth(), \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); } } }` 该实现类可以看到通过读取系统主题中的 android.R.attr.listDivider作为Item间的分割线，并且支持横向和纵向。如果你不清楚它是怎么做到的读取系统的属性用于自身，请参考我的另一篇博文：Android 深入理解Android中的自定义属性\n获取到listDivider以后，该属性的值是个Drawable，在getItemOffsets中，outRect去设置了绘制的范围。onDraw中实现了真正的绘制。\n我们在原来的代码中添加一句：\n`mRecyclerView.addItemDecoration(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DividerItemDecoration(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, DividerItemDecoration.VERTICAL_LIST));` ok，现在再运行，就可以看到分割线的效果了。\n该分割线是系统默认的，你可以在theme.xml中找到该属性的使用情况。那么，使用系统的listDivider有什么好处呢？就是方便我们去随意的改变，该属性我们可以直接声明在：\n` \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;\u0026amp;lt;!-- Application theme. --\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;AppTheme\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;parent\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;AppBaseTheme\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;css\u0026#34;\u0026gt; \u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;name\u0026amp;lt;/span\u0026gt;=\u0026#34;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;android\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-pseudo\u0026#34;\u0026gt;:listDivider\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;span class=\u0026#34;hljs-at_rule\u0026#34;\u0026gt;@\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;drawable/divider_bg\u0026amp;lt;/item\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;style\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` 然后自己写个drawable即可，下面我们换一种分隔符：\n`\u0026amp;lt;?xml version=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;1.0\u0026#34;\u0026amp;lt;/span\u0026gt; encoding=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;utf-8\u0026#34;\u0026amp;lt;/span\u0026gt;?\u0026amp;gt; \u0026amp;lt;shape xmlns:android=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; android:shape=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;rectangle\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;gt; \u0026amp;lt;gradient android:centerColor=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#ff00ff00\u0026#34;\u0026amp;lt;/span\u0026gt; android:endColor=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#ff0000ff\u0026#34;\u0026amp;lt;/span\u0026gt; android:startColor=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;#ffff0000\u0026#34;\u0026amp;lt;/span\u0026gt; android:type=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;linear\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt; \u0026amp;lt;size android:height=\u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;4dp\u0026#34;\u0026amp;lt;/span\u0026gt;/\u0026amp;gt; \u0026amp;lt;/shape\u0026amp;gt;` 现在的样子是：\n当然了，你可以根据自己的需求，去随意的绘制，反正是画出来的，随便玩~~\nok，看到这，你可能觉得，这玩意真尼玛麻烦，完全不能比拟的心爱的ListView。那么继续看。\nLayoutManager 好了，上面实现了类似ListView样子的Demo，通过使用其默认的LinearLayoutManager。\nRecyclerView.LayoutManager吧，这是一个抽象类，好在系统提供了3个实现类：\nLinearLayoutManager 现行管理器，支持横向、纵向。 GridLayoutManager 网格布局管理器 StaggeredGridLayoutManager 瀑布就式布局管理器 上面我们已经初步体验了下LinearLayoutManager，接下来看GridLayoutManager。\nGridLayoutManager 我们尝试去实现类似GridView，秒秒钟的事情：\n`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//mRecyclerView.setLayoutManager(new LinearLayoutManager(this));\u0026amp;lt;/span\u0026gt; mRecyclerView.setLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; GridLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;,\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;));` 只需要修改LayoutManager即可，还是很nice的。\n当然了，改为GridLayoutManager以后，对于分割线，前面的DividerItemDecoration就不适用了，主要是因为它在绘制的时候，比如水平线，针对每个child的取值为：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left = parent.getPaddingLeft(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right = parent.getWidth() - parent.getPaddingRight();` 因为每个Item一行，这样是没问题的。而GridLayoutManager时，一行有多个childItem，这样就多次绘制了，并且GridLayoutManager时，Item如果为最后一列（则右边无间隔线）或者为最后一行（底部无分割线）。\n针对上述，我们编写了DividerGridItemDecoration。\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;package\u0026amp;lt;/span\u0026gt; com.zhy.sample.demo_recyclerview; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.content.Context; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.content.res.TypedArray; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Canvas; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.Rect; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.graphics.drawable.Drawable; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.GridLayoutManager; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView.LayoutManager; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.RecyclerView.State; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.support.v7.widget.StaggeredGridLayoutManager; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;import\u0026amp;lt;/span\u0026gt; android.view.View; \u0026amp;lt;span class=\u0026#34;hljs-javadoc\u0026#34;\u0026gt;/** * *\u0026amp;lt;span class=\u0026#34;hljs-javadoctag\u0026#34;\u0026gt; @author\u0026amp;lt;/span\u0026gt; zhy * */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DividerGridItemDecoration\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;RecyclerView\u0026amp;lt;/span\u0026gt;.\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;ItemDecoration\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;static\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] ATTRS = \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt;[] { android.R.attr.listDivider }; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; Drawable mDivider; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;DividerGridItemDecoration\u0026amp;lt;/span\u0026gt;(Context context) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); a.recycle(); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onDraw\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent, State state) { drawHorizontal(c, parent); drawVertical(c, parent); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getSpanCount\u0026amp;lt;/span\u0026gt;(RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 列数\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; spanCount = -\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;; LayoutManager layoutManager = parent.getLayoutManager(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; GridLayoutManager) { spanCount = ((GridLayoutManager) layoutManager).getSpanCount(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; StaggeredGridLayoutManager) { spanCount = ((StaggeredGridLayoutManager) layoutManager) .getSpanCount(); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; spanCount; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawHorizontal\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount = parent.getChildCount(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; childCount; i++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; View child = parent.getChildAt(i); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left = child.getLeft() - params.leftMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right = child.getRight() + params.rightMargin + mDivider.getIntrinsicWidth(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top = child.getBottom() + params.bottomMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;drawVertical\u0026amp;lt;/span\u0026gt;(Canvas c, RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount = parent.getChildCount(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; (\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; i = \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;; i \u0026amp;lt; childCount; i++) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; View child = parent.getChildAt(i); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; top = child.getTop() - params.topMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; bottom = child.getBottom() + params.bottomMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; left = child.getRight() + params.rightMargin; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; right = left + mDivider.getIntrinsicWidth(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;isLastColum\u0026amp;lt;/span\u0026gt;(RecyclerView parent, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; pos, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; spanCount, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount) { LayoutManager layoutManager = parent.getLayoutManager(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; GridLayoutManager) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; ((pos + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) % spanCount == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一列，则不需要绘制右边\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; StaggeredGridLayoutManager) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; orientation = ((StaggeredGridLayoutManager) layoutManager) .getOrientation(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (orientation == StaggeredGridLayoutManager.VERTICAL) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; ((pos + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) % spanCount == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一列，则不需要绘制右边\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { childCount = childCount - childCount % spanCount; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (pos \u0026amp;gt;= childCount)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一列，则不需要绘制右边\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;isLastRaw\u0026amp;lt;/span\u0026gt;(RecyclerView parent, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; pos, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; spanCount, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount) { LayoutManager layoutManager = parent.getLayoutManager(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; GridLayoutManager) { childCount = childCount - childCount % spanCount; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (pos \u0026amp;gt;= childCount)\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一行，则不需要绘制底部\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (layoutManager \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; StaggeredGridLayoutManager) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; orientation = ((StaggeredGridLayoutManager) layoutManager) .getOrientation(); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// StaggeredGridLayoutManager 且纵向滚动\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (orientation == StaggeredGridLayoutManager.VERTICAL) { childCount = childCount - childCount % spanCount; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一行，则不需要绘制底部\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (pos \u0026amp;gt;= childCount) \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// StaggeredGridLayoutManager 且横向滚动\u0026amp;lt;/span\u0026gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一行，则不需要绘制底部\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; ((pos + \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;) % spanCount == \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; } } } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;getItemOffsets\u0026amp;lt;/span\u0026gt;(Rect outRect, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; itemPosition, RecyclerView parent) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; spanCount = getSpanCount(parent); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; childCount = parent.getAdapter().getItemCount(); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (isLastRaw(parent, itemPosition, spanCount, childCount))\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一行，则不需要绘制底部\u0026amp;lt;/span\u0026gt; { outRect.set(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mDivider.getIntrinsicWidth(), \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (isLastColum(parent, itemPosition, spanCount, childCount))\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果是最后一列，则不需要绘制右边\u0026amp;lt;/span\u0026gt; { outRect.set(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mDivider.getIntrinsicHeight()); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; { outRect.set(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, \u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight()); } } }` 主要在getItemOffsets方法中，去判断如果是最后一行，则不需要绘制底部；如果是最后一列，则不需要绘制右边，整个判断也考虑到了StaggeredGridLayoutManager的横向和纵向，所以稍稍有些复杂。最重要还是去理解，如何绘制什么的不重要。一般如果仅仅是希望有空隙，还是去设置item的margin方便。\n最后的效果是：\nok，看到这，你可能还觉得RecyclerView不够强大？\n但是如果我们有这么个需求，纵屏的时候显示为ListView，横屏的时候显示两列的GridView，我们RecyclerView可以轻松搞定，而如果使用ListView去实现还是需要点功夫的~~~\n当然了，这只是皮毛，下面让你心服口服。\nStaggeredGridLayoutManager 瀑布流式的布局，其实他可以实现GridLayoutManager一样的功能，仅仅按照下列代码：\n`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// mRecyclerView.setLayoutManager(new GridLayoutManager(this,4));\u0026amp;lt;/span\u0026gt; mRecyclerView.setLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; StaggeredGridLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;, StaggeredGridLayoutManager.VERTICAL));` 这两种写法显示的效果是一致的，但是注意StaggeredGridLayoutManager构造的第二个参数传一个orientation，如果传入的是StaggeredGridLayoutManager.VERTICAL代表有多少列；那么传入的如果是StaggeredGridLayoutManager.HORIZONTAL就代表有多少行，比如本例如果改为：\n`mRecyclerView.setLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; StaggeredGridLayoutManager(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;4\u0026amp;lt;/span\u0026gt;, StaggeredGridLayoutManager.HORIZONTAL));` 那么效果为：\n可以看到，固定为4行，变成了左右滑动。有一点需要注意，如果是横向的时候，item的宽度需要注意去设置，毕竟横向的宽度没有约束了，应为控件可以横向滚动了。\n如果你需要一样横向滚动的GridView，那么恭喜你。\nok，接下来准备看大招，如果让你去实现个瀑布流，最起码不是那么随意就可以实现的吧？但是，如果使用RecyclerView，分分钟的事。\n那么如何实现？其实你什么都不用做，只要使用StaggeredGridLayoutManager我们就已经实现了，只是上面的item布局我们使用了固定的高度，下面我们仅仅在适配器的onBindViewHolder方法中为我们的item设置个随机的高度（代码就不贴了，最后会给出源码下载地址），看看效果图：\n是不是棒棒哒，通过RecyclerView去实现ListView、GridView、瀑布流的效果基本上没有什么区别，而且可以仅仅通过设置不同的LayoutManager即可实现。\n还有更nice的地方，就在于item增加、删除的动画也是可配置的。接下来看一下ItemAnimator。\nItemAnimator ItemAnimator也是一个抽象类，好在系统为我们提供了一种默认的实现类，期待系统多\n添加些默认的实现。\n借助默认的实现，当Item添加和移除的时候，添加动画效果很简单:\n`\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 设置item动画\u0026amp;lt;/span\u0026gt; mRecyclerView.setItemAnimator(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DefaultItemAnimator());` 系统为我们提供了一个默认的实现，我们为我们的瀑布流添加以上一行代码，效果为：\n如果是GridLayoutManager呢？动画效果为：\n注意，这里更新数据集不是用adapter.notifyDataSetChanged()而是\nnotifyItemInserted(position)与notifyItemRemoved(position)\n否则没有动画效果。\n上述为adapter中添加了两个方法：\n`\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;addData\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position) { mDatas.add(position, \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34;Insert One\u0026#34;\u0026amp;lt;/span\u0026gt;); notifyItemInserted(position); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;removeData\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position) { mDatas.remove(position); notifyItemRemoved(position); }` Activity中点击MenuItem触发：\n` \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onCreateOptionsMenu\u0026amp;lt;/span\u0026gt;(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;.onCreateOptionsMenu(menu); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onOptionsItemSelected\u0026amp;lt;/span\u0026gt;(MenuItem item) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;switch\u0026amp;lt;/span\u0026gt; (item.getItemId()) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; R.id.id_action_add: mAdapter.addData(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;case\u0026amp;lt;/span\u0026gt; R.id.id_action_delete: mAdapter.removeData(\u0026amp;lt;span class=\u0026#34;hljs-number\u0026#34;\u0026gt;1\u0026amp;lt;/span\u0026gt;); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;break\u0026amp;lt;/span\u0026gt;; } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;; }` 好了，到这我对这个控件已经不是一般的喜欢了~~~\n当然了只提供了一种动画，那么我们肯定可以去自定义各种nice的动画效果。\n高兴的是，github上已经有很多类似的项目了，这里我们直接引用下：RecyclerViewItemAnimators，大家自己下载查看。\n提供了SlideInOutLeftItemAnimator,SlideInOutRightItemAnimator,\nSlideInOutTopItemAnimator,SlideInOutBottomItemAnimator等动画效果。\nClick and LongClick 不过一个挺郁闷的地方就是，系统没有提供ClickListener和LongClickListener。\n不过我们也可以自己去添加，只是会多了些代码而已。\n实现的方式比较多，你可以通过mRecyclerView.addOnItemTouchListener去监听然后去判断手势，\n当然你也可以通过adapter中自己去提供回调，这里我们选择后者，前者的方式，大家有兴趣自己去实现。\n那么代码也比较简单：\n`class HomeAdapter extends RecyclerView.Adapter\u0026amp;lt;HomeAdapter.MyViewHolder\u0026amp;gt; { \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//...\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-class\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;interface\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;OnItemClickLitener\u0026amp;lt;/span\u0026gt; {\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; onItemClick(View view, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; onItemLongClick(View view , \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position); } \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; OnItemClickLitener mOnItemClickLitener; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;setOnItemClickLitener\u0026amp;lt;/span\u0026gt;(OnItemClickLitener mOnItemClickLitener) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;.mOnItemClickLitener = mOnItemClickLitener; } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onBindViewHolder\u0026amp;lt;/span\u0026gt;(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; MyViewHolder holder, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;final\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position) { holder.tv.setText(mDatas.get(position)); \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;// 如果设置了回调，则设置点击事件\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; (mOnItemClickLitener != \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;) { holder.itemView.setOnClickListener(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; OnClickListener() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onClick\u0026amp;lt;/span\u0026gt;(View v) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; pos = holder.getLayoutPosition(); mOnItemClickLitener.onItemClick(holder.itemView, pos); } }); holder.itemView.setOnLongClickListener(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; OnLongClickListener() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;boolean\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onLongClick\u0026amp;lt;/span\u0026gt;(View v) { \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; pos = holder.getLayoutPosition(); mOnItemClickLitener.onItemLongClick(holder.itemView, pos); \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;false\u0026amp;lt;/span\u0026gt;; } }); } } \u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//...\u0026amp;lt;/span\u0026gt; }` adapter中自己定义了个接口，然后在onBindViewHolder中去为holder.itemView去设置相应\n的监听最后回调我们设置的监听。\n最后别忘了给item添加一个drawable:\n`\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;selector\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:state_pressed\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;true\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:drawable\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@color/color_item_press\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:drawable\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@color/color_item_normal\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;item\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;selector\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;` Activity中去设置监听：\n` mAdapter.setOnItemClickLitener(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; OnItemClickLitener() { \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onItemClick\u0026amp;lt;/span\u0026gt;(View view, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position) { Toast.makeText(HomeActivity.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, position + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; click\u0026#34;\u0026amp;lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); } \u0026amp;lt;span class=\u0026#34;hljs-annotation\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;onItemLongClick\u0026amp;lt;/span\u0026gt;(View view, \u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; position) { Toast.makeText(HomeActivity.\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;, position + \u0026amp;lt;span class=\u0026#34;hljs-string\u0026#34;\u0026gt;\u0026#34; long click\u0026#34;\u0026amp;lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); mAdapter.removeData(position); } });` 测试效果：\nok，到此我们基本介绍了RecylerView常见用法，包含了：\n系统提供了几种LayoutManager的使用； 如何通过自定义ItemDecoration去设置分割线，或者一些你想作为分隔的drawable，注意这里\n巧妙的使用了系统的listDivider属性，你可以尝试添加使用divider和dividerHeight属性。 如何使用ItemAnimator为RecylerView去添加Item移除、添加的动画效果。 介绍了如何添加ItemClickListener与ItemLongClickListener。 可以看到RecyclerView可以实现：\nListView的功能 GridView的功能 横向ListView的功能，参考Android 自定义RecyclerView 实现真正的Gallery效果 横向ScrollView的功能 瀑布流效果 便于添加Item增加和移除动画 整个体验下来，感觉这种插拔式的设计太棒了，如果系统再能提供一些常用的分隔符，多添加些动画效果就更好了。\n通过简单改变下LayoutManager，就可以产生不同的效果，那么我们可以根据手机屏幕的宽度去动态设置LayoutManager，屏幕宽度一般的，显示为ListView；宽度稍大的显示两列的GridView或者瀑布流（或者横纵屏幕切换时变化，有点意思~）；显示的列数和宽度成正比。甚至某些特殊屏幕，让其横向滑动~~再选择一个nice的动画效果，相信这种插件式的编码体验一定会让你迅速爱上RecyclerView。\n参考资料 Android 自定义RecyclerView 实现真正的Gallery效果\nA First Glance at Android’s RecyclerView\nhttps://github.com/gabrielemariotti/RecyclerViewItemAnimators\nDividerItemDecoration\n转自：http://blog.csdn.net/lmj623565791/article/details/45059587\n","permalink":"https://blog.zdltech.com/posts/android-recyclerview-%E4%BD%BF%E7%94%A8%E5%AE%8C%E5%85%A8%E8%A7%A3%E6%9E%90-%E4%BD%93%E9%AA%8C%E8%89%BA%E6%9C%AF%E8%88%AC%E7%9A%84%E6%8E%A7%E4%BB%B6/","summary":"\u003ch3 id=\"概述\"\u003e概述\u003c/h3\u003e\n\u003cp\u003eRecyclerView出现已经有一段时间了，相信大家肯定不陌生了，大家可以通过导入support-v7对其进行使用。\u003cbr\u003e\n据官方的介绍，该控件用于在有限的窗口中展示大量数据集，其实这样功能的控件我们并不陌生，例如：ListView、GridView。\u003c/p\u003e\n\u003cp\u003e那么有了ListView、GridView为什么还需要RecyclerView这样的控件呢？整体上看RecyclerView架构，提供了一种插拔式的体验，高度的解耦，异常的灵活，通过设置它提供的不同LayoutManager，ItemDecoration , ItemAnimator实现令人瞠目的效果。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e你想要控制其显示的方式，请通过布局管理器LayoutManager\u003c/li\u003e\n\u003cli\u003e你想要控制Item间的间隔（可绘制），请通过ItemDecoration\u003c/li\u003e\n\u003cli\u003e你想要控制Item增删的动画，请通过ItemAnimator\u003c/li\u003e\n\u003cli\u003e你想要控制点击、长按事件，请自己写（擦，这点尼玛。）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"基本使用\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e基本使用\u003c/h3\u003e\n\u003cp\u003e鉴于我们对于ListView的使用特别的熟悉，对比下RecyclerView的使用代码：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`mRecyclerView = findView(R.id.id_recyclerview);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置布局管理器\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emRecyclerView.setLayoutManager(layout);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置adapter\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emRecyclerView.setAdapter(adapter)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//设置Item增加、移除动画\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emRecyclerView.setItemAnimator(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DefaultItemAnimator());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-comment\u0026#34;\u0026gt;//添加分割线\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emRecyclerView.addItemDecoration(\u0026amp;lt;span class=\u0026#34;hljs-keyword\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; DividerItemDecoration(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                getActivity(), DividerItemDecoration.HORIZONTAL_LIST));`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eok，相比较于ListView的代码，ListView可能只需要去设置一个adapter就能正常使用了。而RecyclerView基本需要上面一系列的步骤，那么为什么会添加这么多的步骤呢？\u003c/p\u003e\n\u003cp\u003e那么就必须解释下RecyclerView的这个名字了，从它类名上看，RecyclerView代表的意义是，我只管Recycler View，也就是说RecyclerView只管回收与复用View，其他的你可以自己去设置。可以看出其高度的解耦，给予你充分的定制自由（所以你才可以轻松的通过这个控件实现ListView,GirdView，瀑布流等效果）。\u003c/p\u003e\n\u003ch3 id=\"just-like-listview\"\u003e\u003ca name=\"t2\"\u003e\u003c/a\u003eJust like ListView\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eActivity\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epackage\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ezhy\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esample\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edemo_recyclerview;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e java\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eutil\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eArrayList;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e java\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eutil\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eList;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eos\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBundle;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eActionBarActivity;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLinearLayoutManager;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eRecyclerView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eRecyclerView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eViewHolder;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLayoutInflater;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eViewGroup;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eimport\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eTextView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-class\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eHomeActivity\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eActionBarActivity\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eprivate\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e RecyclerView mRecyclerView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eprivate\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e List\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;String\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt; mDatas;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eprivate\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e HomeAdapter mAdapter;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-annotation\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@Override\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eprotected\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eonCreate\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(Bundle savedInstanceState)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003esuper\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;.\u003c/span\u003eonCreate(savedInstanceState);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        setContentView(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elayout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eactivity_single_recyclerview);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        initData();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mRecyclerView \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (RecyclerView) findViewById(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid_recyclerview);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mRecyclerView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetLayoutManager(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e LinearLayoutManager(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ethis\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mRecyclerView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetAdapter(mAdapter \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e HomeAdapter());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eprotected\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003einitData\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        mDatas \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e ArrayList\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;String\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eint\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e i \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;A\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e; i \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt; \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;z\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e; i\u003cspan style=\"color:#ff79c6\"\u003e++\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mDatas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eadd(\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-string\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e (\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003echar\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e) i);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e HomeAdapter \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e RecyclerView\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAdapter\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;HomeAdapter\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMyViewHolder\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-annotation\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@Override\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e MyViewHolder \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eonCreateViewHolder\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(ViewGroup parent, \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eint\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e viewType)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            MyViewHolder holder \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e MyViewHolder(LayoutInflater\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003efrom(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    HomeActivity\u003cspan style=\"color:#ff79c6\"\u003e.\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ethis\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003einflate(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elayout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eitem_home, parent,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e holder;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-annotation\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@Override\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003evoid\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eonBindViewHolder\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(MyViewHolder holder, \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eint\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e position)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            holder\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etv\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetText(mDatas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eget(position));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-annotation\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e@Override\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eint\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003egetItemCount\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e mDatas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esize();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e MyViewHolder \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e ViewHolder\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            TextView tv;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003epublic\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eMyViewHolder\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(View view)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-keyword\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003esuper\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(view);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                tv \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (TextView) view\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003efindViewById(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid_num);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003eActivity的布局文件\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-tag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eRelativeLayout\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003exmlns:android\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003exmlns:tools\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://schemas.android.com/tools\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_width\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;match_parent\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_height\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;match_parent\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-tag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esupport\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ev7\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eRecyclerView\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:id\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;@+id/id_recyclerview\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:divider\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;#ffff0000\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:dividerHeight\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;10dp\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_width\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;match_parent\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_height\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;match_parent\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-tag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003elt;span \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;hljs-title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eRelativeLayout\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003eItem的布局文件\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u0026amp;lt;span class=\u0026#34;hljs-pi\u0026#34;\u0026gt;\u0026amp;lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;FrameLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;xmlns:android\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:background\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;#44ff0000\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;TextView\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/span\u0026gt;        \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:id\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;@+id/id_num\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_width\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:layout_height\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;50dp\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:gravity\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;center\u0026#34;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026amp;lt;span class=\u0026#34;hljs-attribute\u0026#34;\u0026gt;android:text\u0026amp;lt;/span\u0026gt;=\u0026amp;lt;span class=\u0026#34;hljs-value\u0026#34;\u0026gt;\u0026#34;1\u0026#34;\u0026amp;lt;/span\u0026gt; /\u0026amp;gt;\u0026amp;lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;span class=\u0026#34;hljs-tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026amp;lt;span class=\u0026#34;hljs-title\u0026#34;\u0026gt;FrameLayout\u0026amp;lt;/span\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这么看起来用法与ListView的代码基本一致哈~~\u003cbr\u003e\n看下效果图：\u003c/p\u003e","title":"Android RecyclerView 使用完全解析 体验艺术般的控件"},{"content":"设置Viewpager的viewPager.setCurrentItem(currentIndex+1);有一个动画滑动效果\nViewPagerScroller scroller = new ViewPagerScroller(this);\nscroller.initViewPagerScroll(viewPager);\n/**\nViewPager 滚动速度设置 */\npublic class ViewPagerScroller extends Scroller {\nprivate int mScrollDuration = 2000; // 滑动速度\n/**\n设置速度速度 @param duration\n*/\npublic void setScrollDuration(int duration) {\nthis.mScrollDuration = duration;\n} public ViewPagerScroller(Context context) {\nsuper(context);\n}\npublic ViewPagerScroller(Context context, Interpolator interpolator) {\nsuper(context, interpolator);\n}\n@SuppressLint(“NewApi”)\npublic ViewPagerScroller(Context context, Interpolator interpolator,\nboolean flywheel) {\nsuper(context, interpolator, flywheel);\n}\n@Override\npublic void startScroll(int startX, int startY, int dx, int dy, int duration) {\nsuper.startScroll(startX, startY, dx, dy, mScrollDuration);\n}\n@Override\npublic void startScroll(int startX, int startY, int dx, int dy) {\nsuper.startScroll(startX, startY, dx, dy, mScrollDuration);\n}\npublic void initViewPagerScroll(ViewPager viewPager) {\ntry {\nField mScroller = ViewPager.class.getDeclaredField(“mScroller”);\nmScroller.setAccessible(true);\nmScroller.set(viewPager, this);\n} catch (Exception e) {\ne.printStackTrace();\n}\n}\n}\n","permalink":"https://blog.zdltech.com/posts/%E8%AE%BE%E7%BD%AEviewpager%E7%9A%84viewpager-setcurrentitem%E6%9C%89%E4%B8%80%E4%B8%AA%E5%8A%A8%E7%94%BB%E6%BB%91%E5%8A%A8%E6%95%88%E6%9E%9C/","summary":"\u003cp\u003e设置Viewpager的viewPager.setCurrentItem(currentIndex+1);有一个动画滑动效果\u003c/p\u003e\n\u003cp\u003eViewPagerScroller scroller = new ViewPagerScroller(this);\u003cbr\u003e\nscroller.initViewPagerScroll(viewPager);\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eViewPager 滚动速度设置\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e*/\u003cbr\u003e\npublic class ViewPagerScroller extends Scroller {\u003cbr\u003e\nprivate int mScrollDuration = 2000; // 滑动速度\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e设置速度速度\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e@param duration\u003cbr\u003e\n*/\u003cbr\u003e\npublic void setScrollDuration(int duration) {\u003cbr\u003e\nthis.mScrollDuration = duration;\u003cbr\u003e\n}\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003epublic ViewPagerScroller(Context context) {\u003cbr\u003e\nsuper(context);\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003epublic ViewPagerScroller(Context context, Interpolator interpolator) {\u003cbr\u003e\nsuper(context, interpolator);\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e@SuppressLint(“NewApi”)\u003cbr\u003e\npublic ViewPagerScroller(Context context, Interpolator interpolator,\u003cbr\u003e\nboolean flywheel) {\u003cbr\u003e\nsuper(context, interpolator, flywheel);\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e@Override\u003cbr\u003e\npublic void startScroll(int startX, int startY, int dx, int dy, int duration) {\u003cbr\u003e\nsuper.startScroll(startX, startY, dx, dy, mScrollDuration);\u003cbr\u003e\n}\u003c/p\u003e","title":"设置Viewpager的viewPager.setCurrentItem有一个动画滑动效果"},{"content":"“A flexible view for providing a limited window into a large data set.”\n可以说是ListView的升级版，ListVie中我们需要自己写ViewHolder，当然你也可以不写，是在RecylerView中，是要让写的哟~RecyclerView适用于无法在一个屏幕范围内展现格式一样的数据时，需要用多行或多列来展示。例如展示联系人，图片，视频等。用户需要滑动屏幕来查看数据，这时RecyclerView的特性就有用武之地了。比如，当用户滑动使当前一个可视的Item滑出屏幕，这个Item的视图将会被回收并在一个新Item进入可视范围后重新被使用。可回收利用View是个很实用的功能，它不仅可以减少CPU不断inflate View的开销，而且可以节省缓存View的内存开销。\nRecylerView还有一大特色，就是动画！\nRecyclerView不再负责显示工作 和ListView不一样的是，RecyclerView不再负责Item的摆放等显示方面的功能。所有和布局、绘制等方面的工作都其拆分成不同的类进行管理。所以开发者可以自定义各种各样满足定制需求的的功能类。\nRecyclerView.Adapter \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;454\u0026quot;\u0026gt; 托管数据集合，为每个Item创建视图 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;326\u0026quot;\u0026gt; RecyclerView.ViewHolder \u0026lt;/td\u0026gt; \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;454\u0026quot;\u0026gt; 承载Item视图的子视图 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;326\u0026quot;\u0026gt; RecyclerView.LayoutManager \u0026lt;/td\u0026gt; \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;454\u0026quot;\u0026gt; 负责Item视图的布局 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;326\u0026quot;\u0026gt; RecyclerView.ItemDecoration \u0026lt;/td\u0026gt; \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;454\u0026quot;\u0026gt; 为每个Item视图添加子视图，在Demo中被用来绘制Divider \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;326\u0026quot;\u0026gt; RecyclerView.ItemAnimator \u0026lt;/td\u0026gt; \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;454\u0026quot;\u0026gt; 负责添加、删除数据时的动画效果 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; ViewHolder 关于ViewHolder，Google早就推荐开发者使用，但也只是建议。但是现在，RecyclerView.Adapter最终要求开发者必须使用ViewHolder。\n![复制代码](http://common.cnblogs.com/images/copycode.gif) public class MyViewHolder extends ViewHolder{ public ImageView iv; public TextView tv; public MyViewHolder(View rootView) { super(rootView); iv = (ImageView)rootView.findViewById(R.id.item_iv); tv = (TextView)rootView.findViewById(R.id.item_tv); } } ![复制代码](http://common.cnblogs.com/images/copycode.gif) RecyclerView.Adapter Adapter负责扮演两个角色：不仅为底部数据提供支持而且还负责为数据创建合适的视图。Adapter适用在Android很多控件，例如ListView、AutoCompleteTextView等。\n![复制代码](http://common.cnblogs.com/images/copycode.gif) public class MyAdapter extends Adapter\u0026amp;lt;MyViewHolder\u0026amp;gt; { private List\u0026amp;lt;Item\u0026amp;gt; mData; public MyAdapter(List\u0026amp;lt;Item\u0026amp;gt; data){ this.mData = data; } @Override public int getItemCount() { return mData.size(); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { Item bean = mData.get(position); holder.tv.setText(bean.tv); } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent,false); MyViewHolder vh = new MyViewHolder(itemView); return vh; } } ![复制代码](http://common.cnblogs.com/images/copycode.gif) onCreateViewHolder中负责为Item创建视图，onBindViewHolder负责将数据绑定到Item的视图上。\nRecyclerView.LayoutManager LayoutManager是RecyclerView中最有意思的类。该类负责将每个Item视图在RecylerView中的布局。目前Google提供了LayoutManager的一个子类：LinearLayoutManager。LinearLayoutManager提供了横向和竖向两种布局。\n``` MyLayoutManager manager = new MyLayoutManager(this); manager.setOrientation(LinearLayout.HORIZONTAL);//默认是LinearLayout.VERTICAL mRecyclerView.setLayoutManager(manager); ``` LinearLayoutManager提供了如下几个方法来帮助开发者获取屏幕上的顶部item和底部item：\nfindFirstVisibleItemPosition()\nfindFirstCompletelyVisibleItemPosition()\nfindLastVisibleItemPosition()\nfindLastCompletelyVisibleItemPosition()\nRecyclerView.ItemDecoration 通过ItemDecoration可以使各个Item在视觉上相互分开，其实和ListView的Divider很像。ItemDecoration并不是RecyclerView必须设置的，开发者可以不设置或者设置多个Decoration。RecyclerView会遍历所有的ItemDecoration并调用各自的绘图方法。\n![复制代码](http://common.cnblogs.com/images/copycode.gif) public class MyDecoration extends ItemDecoration {\nprivate static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; private Drawable mDivider; public MyDecoration(Context ctx){ final TypedArray a = ctx.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); } @Override public void onDraw(Canvas c, RecyclerView parent, State state) { int top = parent.getPaddingTop(); int bottom = parent.getHeight() - parent.getPaddingBottom(); int childCount = parent.getChildCount(); for(int i=0;i \u0026amp;lt; childCount;i++){ View child = parent.getChildAt(i); RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams)child.getLayoutParams(); int left = child.getRight() + layoutParams.rightMargin; int right = left + mDivider.getIntrinsicWidth(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } }\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ## RecyclerView.ItemAnimatior * 删除某一个Item * 添加一个新的Item * 移动某个Item Google提供了一个名为DefaultItemAnimator的默认ItemAnimator供开发者使用。如果开发者不为RecyclerView设置ItemAnimator，RecyclerView也会使用默认的DefaultItemAnimator。 显然，为了让动画效果起效，开发者必须通知Adapter数据有改变。之前我们使用Adapter时会调用notifyDataSetChanged()来通知Adapter数据改变并更新视图，现在RecyclerView,Adapter提供了许多notifyXyz()方法。 ## 流程 * 实例化RecyclerView * 为RecyclerView设置LayoutManager * 为RecyclerView设置Adapater * 如果有需求，可以设置一个或多个ItemDecorations，当然，也可以不设置 * 如果有需求，可以设置ItemAnimator ## 监听事件 RecyclerView不再负责Item视图的布局及显示，所以RecyclerView也没有为Item开放OnItemClick等点击事件，这就需要开发者自己实现。 因为ViewHolder我们可以拿到每个Item的根布局，所以如果我们为根布局设置单独的OnClick监听并将其开放给Adapter，那不就可以在组装RecyclerView时就能够设置ItemClickListener，只不过这个Listener不是设置到RecyclerView上而是设置到Adapter。 \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ``` public class MyViewHolder extends ViewHolder implements OnClickListener,OnLongClickListener{ public ImageView iv; public TextView tv; private MyItemClickListener mListener; private MyItemLongClickListener mLongClickListener; public MyViewHolder(View rootView,MyItemClickListener listener,MyItemLongClickListener longClickListener) { super(rootView); iv = (ImageView)rootView.findViewById(R.id.item_iv); tv = (TextView)rootView.findViewById(R.id.item_tv); this.mListener = listener; this.mLongClickListener = longClickListener; rootView.setOnClickListener(this); rootView.setOnLongClickListener(this); } /** * 点击监听 */ @Override public void onClick(View v) { if(mListener != null){ mListener.onItemClick(v,getPosition()); } } /** * 长按监听 */ @Override public boolean onLongClick(View arg0) { if(mLongClickListener != null){ mLongClickListener.onItemLongClick(arg0, getPosition()); } return true; } } \u0026lt;div class=\u0026quot;cnblogs_code_toolbar\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_copy\u0026quot;\u0026gt;\u0026lt;a title=\u0026quot;复制代码\u0026quot;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ## item长宽 \u0026lt;div class=\u0026quot;cnblogs_code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;cnblogs_code_toolbar\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_copy\u0026quot;\u0026gt;\u0026lt;a title=\u0026quot;复制代码\u0026quot;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ``` public class MyLayoutManager extends LinearLayoutManager {\npublic MyLayoutManager(Context context) { super(context); } @Override public void onMeasure(Recycler recycler, State state, int widthSpec,int heightSpec) { View view = recycler.getViewForPosition(0); if(view != null){ measureChild(view, widthSpec, heightSpec); int measuredWidth = MeasureSpec.getSize(widthSpec); int measuredHeight = view.getMeasuredHeight(); setMeasuredDimension(measuredWidth, measuredHeight); } } }\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 参考：http://www.grokkingandroid.com/first-glance-androids-recyclerview/ * 转自：http://www.cnblogs.com/yydcdut/p/4470225.html?utm_source=tuicool ","permalink":"https://blog.zdltech.com/posts/android-recyclerview/","summary":"\u003cp\u003e\u003cem\u003e“A flexible view for providing a limited window into a large data set.”\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e可以说是ListView的升级版，ListVie中我们需要自己写ViewHolder，当然你也可以不写，是在RecylerView中，是要让写的哟~RecyclerView适用于无法在一个屏幕范围内展现格式一样的数据时，需要用多行或多列来展示。例如展示联系人，图片，视频等。用户需要滑动屏幕来查看数据，这时RecyclerView的特性就有用武之地了。比如，当用户滑动使当前一个可视的Item滑出屏幕，这个Item的视图将会被回收并在一个新Item进入可视范围后重新被使用。可回收利用View是个很实用的功能，它不仅可以减少CPU不断inflate View的开销，而且可以节省缓存View的内存开销。\u003c/p\u003e\n\u003cp\u003eRecylerView还有一大特色，就是动画！\u003c/p\u003e\n\u003ch2 id=\"recyclerview不再负责显示工作\"\u003e\u003cstrong\u003eRecyclerView不再负责显示工作\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e和ListView不一样的是，RecyclerView不再负责Item的摆放等显示方面的功能。所有和布局、绘制等方面的工作都其拆分成不同的类进行管理。所以开发者可以自定义各种各样满足定制需求的的功能类。\u003c/p\u003e\n\u003cdiv\u003e\n  \u003ctable border=\"3\" cellspacing=\"0\" cellpadding=\"2\"\u003e\n    \u003ctr\u003e\n      \u003ctd valign=\"top\" width=\"326\"\u003e\n        RecyclerView.Adapter\n      \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;454\u0026quot;\u0026gt;\n    托管数据集合，为每个Item创建视图\n  \u0026lt;/td\u0026gt;\n\u0026lt;/tr\u0026gt;\n\n\u0026lt;tr\u0026gt;\n  \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;326\u0026quot;\u0026gt;\n    RecyclerView.ViewHolder\n  \u0026lt;/td\u0026gt;\n  \n  \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;454\u0026quot;\u0026gt;\n    承载Item视图的子视图\n  \u0026lt;/td\u0026gt;\n\u0026lt;/tr\u0026gt;\n\n\u0026lt;tr\u0026gt;\n  \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;326\u0026quot;\u0026gt;\n    RecyclerView.LayoutManager\n  \u0026lt;/td\u0026gt;\n  \n  \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;454\u0026quot;\u0026gt;\n    负责Item视图的布局\n  \u0026lt;/td\u0026gt;\n\u0026lt;/tr\u0026gt;\n\n\u0026lt;tr\u0026gt;\n  \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;326\u0026quot;\u0026gt;\n    RecyclerView.ItemDecoration\n  \u0026lt;/td\u0026gt;\n  \n  \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;454\u0026quot;\u0026gt;\n    为每个Item视图添加子视图，在Demo中被用来绘制Divider\n  \u0026lt;/td\u0026gt;\n\u0026lt;/tr\u0026gt;\n\n\u0026lt;tr\u0026gt;\n  \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;326\u0026quot;\u0026gt;\n    RecyclerView.ItemAnimator\n  \u0026lt;/td\u0026gt;\n  \n  \u0026lt;td valign=\u0026quot;top\u0026quot; width=\u0026quot;454\u0026quot;\u0026gt;\n    负责添加、删除数据时的动画效果\n  \u0026lt;/td\u0026gt;\n\u0026lt;/tr\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/table\u003e\n\u003c/div\u003e\n\u003ch2 id=\"viewholder\"\u003eViewHolder\u003c/h2\u003e\n\u003cp\u003e关于ViewHolder，Google早就推荐开发者使用，但也只是建议。但是现在，RecyclerView.Adapter最终要求开发者必须使用ViewHolder。\u003c/p\u003e","title":"Android — RecyclerView"},{"content":" [http://blog.csdn.net/shulianghan/article/details/41520569](http://blog.csdn.net/shulianghan/article/details/41520569?utm_source=tuicool) **博客地址 **: [http://blog.csdn.net/shulianghan/article/details/41520569](http://blog.csdn.net/shulianghan/article/details/41520569) 代码下载 : \u0026amp;#8212; **GitHub **: [https://github.com/han1202012/WheelViewDemo.git](https://github.com/han1202012/WheelViewDemo.git) \u0026amp;#8212; **CSDN **: [http://download.csdn.net/detail/han1202012/8208997](http://download.csdn.net/detail/han1202012/8208997) ; #### 博客总结 : 博文内容 : 本文完整地分析了 WheelView 所有的源码, 包括其 适配器类型 , 两种回调接口 ( 选中条目改变回调 , 和 开始结束滚动回调 ), 以及详细的分析了 WheelView 主题源码, 其中 组件宽高测量 , 手势监听器添加 , 以及 精准的绘图方法 是主要目的, 花了将近1周时间, 感觉很值, 在这里分享给大家; 自定义组件宽高获取策略 : MeasureSpec 最大模式 取 默认值 和 给定值中较小的那个 , 未定义模式取默认值 , 精准模式取 给定值 ; 自定义组件维护各种回调监听器策略 : 维护集合, 将监听器置于集合中, 回调接口时遍历集合元素, 回调每个元素的接口方法; 自定义组件手势监听器添加方法 : 创建手势监听器, 将手势监听器传入手势探测器, 在 onTouchEvent() 方法中回调手势监听器的 onTouchEvent()方法; ## 一. WheelView 简介 ## 1. WheelView 效果 在 Android 中实现类似与 IOS 的 WheelView 控件 : 如图 ![](http://img2.tuicool.com/bMfU7b.png) ## 2. WheelView 使用流程 ### (1) 基本流程简介 a. 创建 WheelView 组件 : 使用 构造方法 或者 从布局文件获取 WheelView 组件; b. 设置显示条目数 : 调用 WheelView 组件对象的 setVisibleItems 方法 设置; c. 设置是否循环 : 设置 WheelView 是否循环, 调用 setCyclic() 方法设置; d. 设置适配器 : 调用 WheelView 组件的 setAdapter() 方法设置; e. 设置条目改变监听器 : 调用 WheelView 组件对象的 addChangingListener() 方法设置; f. 设置滚动监听器 : 调用 WheelView 组件对象的 addScrollingListener() 方法设置; ### (2) 代码实例 a. 创建 WheelView 对象 : ``` //创建 WheelView 组件 final WheelView wheelLeft = new WheelView(context);\n**b. 设置 WheelView 显示条目数**: ``` \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//设置 WheelView 组件最多显示 5 个元素\u0026lt;/span\u0026gt; wheelLeft.setVisibleItems(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt;); **c. 设置 WheelView 是否滚动循环**: ``` //设置 WheelView 元素是否循环滚动 wheelLeft.setCyclic(false);\n**d. 设置 WheelView 适配器**: ``` //设置 WheelView 适配器 wheelLeft.setAdapter(new ArrayWheelAdapter\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;String\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;(left)); **e. 设置条目改变监听器**: ``` //为左侧的 WheelView 设置条目改变监听器 wheelLeft.addChangingListener(new OnWheelChangedListener() { @Override public void onChanged(WheelView wheel, int oldValue, int newValue) { //设置右侧的 WheelView 的适配器 wheelRight.setAdapter(new ArrayWheelAdapter\u0026lt;String\u0026gt;(right[newValue])); wheelRight.setCurrentItem(right[newValue].length / 2); } });\n**f. 设置滚动监听器**: ``` wheelLeft.addScrollingListener(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; OnWheelScrollListener() { \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onScrollingStarted(WheelView wheel) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onScrollingFinished(WheelView wheel) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; } }); ## 二. WheelView 适配器 监听器 相关接口分析 ## 1. 适配器 分析 这里定义了一个适配器接口, 以及两个适配器类, 一个用于任意类型的数据集适配, 一个用于数字适配; 适配器操作 : 在 WheelView.java 中通过 setAdapter(WheelAdapter adapter) 和 getAdapter() 方法设置 获取 适配器; \u0026amp;#8212; 适配器常用操作 : 在 WheelView 中定义了 getItem(), getItemsCount(), getMaxmiumLength() 方法获取 适配器的相关信息; ``` /**\n获取该 WheelView 的适配器 @return 返回适配器 */ public WheelAdapter getAdapter() { return adapter; }\n\u0026lt;span class=\u0026quot;javadoc\u0026quot;\u0026gt;/** 设置适配器 @param adapter 要设置的适配器 */ public void setAdapter(WheelAdapter adapter) { this.adapter = adapter; invalidateLayouts(); invalidate(); }\n### (1) 适配器接口 ( interface WheelAdapter ) 适配器接口 : **WheelAdapter** ; \u0026amp;#8212; 接口作用 : 该接口是所有适配器的接口, 适配器类都需要实现该接口; 接口抽象方法介绍 : \u0026amp;#8212; getItemsCount() : 获取适配器数据集合中元素个数; ``` \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 获取条目的个数 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@return\u0026lt;/span\u0026gt; * WheelView 的条目个数 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getItemsCount(); \u0026amp;#8212; getItem(int index) : 获取适配器集合的中指定索引元素; ``` /**\n根据索引位置获取 WheelView 的条目 @param index 条目的索引 @return WheelView 上显示的条目的值 */ public String getItem(int index);\n\u0026amp;#8212; getMaximumLength() : 获取 WheelView 在界面上的显示宽度; ``` \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 获取条目的最大长度. 用来定义 WheelView 的宽度. 如果返回 -1, 就会使用默认宽度 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@return\u0026lt;/span\u0026gt; * 条目的最大宽度 或者 -1 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getMaximumLength(); ### (2) 数组适配器 ( class ArrayWheelAdapter\u0026lt;T\u0026gt; implements WheelAdapter ) 适配器作用 : 该适配器可以传入 任何数据类型的数组 , 可以是 字符串数组, 也可以是任何对象的数组, 传入的数组作为适配器的数据源; 成员变量分析 : \u0026amp;#8212; 数据源 : ``` /** 适配器的数据源 */ private T items[];\n\u0026amp;#8212; WheelView 最大宽度 : ``` \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** WheelView 的宽度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; length; 构造方法分析 : \u0026amp;#8212; ArrayWheelAdapter(T items[], int length) : 传入 T 类型 对象数组, 以及 WheelView 的宽度; ``` /**\n构造方法 @param items 适配器数据源 集合 T 类型的数组 @param length 适配器数据源 集合 T 数组长度 */ public ArrayWheelAdapter(T items[], int length) { this.items = items; this.length = length; }\n\u0026amp;#8212; ArrayWheelAdapter(T items[]) : 传入 T 类型对象数组, 宽度使用默认的宽度; ``` \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 构造方法 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; items *\t适配器数据源集合 T 类型数组 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; ArrayWheelAdapter(T items[]) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;(items, DEFAULT_LENGTH); } 实现的父类方法分析 : \u0026amp;#8212; getItem(int index) : 根据索引获取数组中对应位置的对象的字符串类型; ``` @Override public String getItem(int index) { //如果这个索引值合法, 就返回 item 数组对应的元素的字符串形式 if (index \u0026gt;= \u0026amp;\u0026amp; index \u0026lt; items.length) { return items[index].toString(); } return null; }\n\u0026amp;#8212; getItemsCount() : 获取数据集广大小, 直接返回数组大小; ``` \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getItemsCount() { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//返回 item 数组的长度\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; items.length; } \u0026amp;#8212; getMaximumLength() : 获取 WheelView 的最大宽度; ``` @Override public int getMaximumLength() { //返回 item 元素的宽度 return length; }\n### (3) 数字适配器 ( class NumericWheelAdapter implements WheelAdapter ) NumericWheelAdapter 适配器作用 : 数字作为 WheelView 适配器的显示值; 成员变量分析 : \u0026amp;#8212; 最小值 : WheelView 数值显示的最小值; ``` \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 设置的最小值 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; minValue; \u0026amp;#8212; 最大值 : WheelView 数值显示的最大值; ``` /** 设置的最大值 */ private int maxValue;\n\u0026amp;#8212; **格式化字符串**: 用于字符串的格式化; ``` \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 格式化字符串, 用于格式化 货币, 科学计数, 十六进制 等格式 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; String format; 构造方法分析 : \u0026amp;#8212; NumericWheelAdapter() : 默认的构造方法, 使用默认的最大最小值; ``` /** * 默认的构造方法, 使用默认的最大最小值 */ public NumericWheelAdapter() { this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE); }\n\u0026amp;#8212; NumericWheelAdapter(int minValue, int maxValue) : 传入一个最大最小值; ``` \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 构造方法 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; minValue *\t最小值 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; maxValue *\t最大值 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; NumericWheelAdapter(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; minValue, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; maxValue) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;(minValue, maxValue, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;); } \u0026amp;#8212; NumericWheelAdapter(int minValue, int maxValue, String format) : 传入最大最小值, 以及数字格式化方式; ``` /**\n构造方法 @param minValue 最小值 @param maxValue 最大值 @param format 格式化字符串 */ public NumericWheelAdapter(int minValue, int maxValue, String format) { this.minValue = minValue; this.maxValue = maxValue; this.format = format; }\n实现的父类方法 : \u0026amp;#8212; 获取条目 : 如果需要格式化, 先进行格式化; ``` \u0026lt;span class=\u0026#34;variable\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; public String getItem(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;index\u0026lt;/span\u0026gt;) { String result = \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;index\u0026lt;/span\u0026gt; \u0026amp;gt;= \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;index\u0026lt;/span\u0026gt; \u0026amp;lt; getItemsCount()) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; value = minValue + \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;index\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;regexp\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;如果 \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;format\u0026lt;/span\u0026gt; 不为 null, 那么格式化字符串, 如果为 null, 直接返回数字 \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;format\u0026lt;/span\u0026gt; != null){ result = String.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;format\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;format\u0026lt;/span\u0026gt;, value); }\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt;{ result = Integer.toString(value); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; result; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; null; } \u0026amp;#8212; **获取元素个数 **: ``` @Override public int getItemsCount() { //返回数字总个数 return maxValue - minValue + 1; }\n\u0026amp;#8212; **获取 WheelView 最大宽度 **: ``` \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getMaximumLength() { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//获取 最大值 和 最小值 中的 较大的数字\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; max = Math.max(Math.abs(maxValue), Math.abs(minValue)); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//获取这个数字 的 字符串形式的 字符串长度\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; maxLen = Integer.toString(max).length(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (minValue \u0026amp;lt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { maxLen++; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; maxLen; } ## 2. 监听器相关接口 ### (1) 条目改变监听器 ( interface OnWheelChangedListener ) 监听器作用 : 在 WheelView 条目改变的时候, 回调该监听器的接口方法, 执行条目改变对应的操作; 接口方法介绍 : \u0026amp;#8212; onChanged(WheelView wheel, int oldValue, int newValue) : 传入 WheelView 组件对象, 以及 旧的 和 新的 条目值索引; ``` /**\n当前条目改变时回调该方法 @param wheel 条目改变的 WheelView 对象 @param oldValue WheelView 旧的条目值 @param newValue WheelView 新的条目值 */ void onChanged(WheelView wheel, int oldValue, int newValue);\n### (2) 滚动监听器 ( interface OnWheelScrollListener ) 滚动监听器作用 : 在 WheelView 滚动动作 开始 和 结束的时候回调对应的方法, 在对应方法中进行相应的操作; 接口方法介绍 : \u0026amp;#8212; 开始滚动方法 : 在滚动开始的时候回调该方法; ``` \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 在 WheelView 滚动开始的时候回调该接口 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; wheel *\t开始滚动的 WheelView 对象 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onScrollingStarted(WheelView wheel); \u0026amp;#8212; 停止滚动方法 : 在滚动结束的时候回调该方法; ``` /**\n在 WheelView 滚动结束的时候回调该接口 @param wheel 结束滚动的 WheelView 对象 */ void onScrollingFinished(WheelView wheel);\n## 三. WheelView 解析 ## 1. 触摸 点击 手势 动作操作控制组件 模块 ### (1) 创建手势监听器 手势监听器创建及对应方法 : \u0026amp;#8212; onDown(MotionEvent e) : 在按下的时候回调该方法, e 参数是按下的事件; \u0026amp;#8212; onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) : 滚动的时候回调该方法, e1 滚动第一次按下事件, e2 当前滚动的触摸事件, X 上一次滚动到这一次滚动 x 轴距离, Y 上一次滚动到这一次滚动 y 轴距离; \u0026amp;#8212; onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) : 快速急冲滚动时回调的方法, e1 e2 与上面参数相同, velocityX 是手势在 x 轴的速度, velocityY 是手势在 y 轴的速度; \u0026amp;#8212; 代码示例 : ``` \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 手势监听器监听到 滚动操作后回调 * * 参数解析 : * MotionEvent e1 : 触发滚动时第一次按下的事件 * MotionEvent e2 : 触发当前滚动的移动事件 * float distanceX : 自从上一次调用 该方法 到这一次 x 轴滚动的距离, * 注意不是 e1 到 e2 的距离, e1 到 e2 的距离是从开始滚动到现在的滚动距离 * float distanceY : 自从上一次回调该方法到这一次 y 轴滚动的距离 * * 返回值 : 如果事件成功触发, 执行完了方法中的操作, 返回true, 否则返回 false * (non-Javadoc) * @see android.view.GestureDetector.SimpleOnGestureListener#onScroll(android.view.MotionEvent, android.view.MotionEvent, float, float) */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onScroll(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; distanceX, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; distanceY) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//开始滚动, 并回调滚动监听器集合中监听器的 开始滚动方法\u0026lt;/span\u0026gt; startScrolling(); doScroll((\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt;) -distanceY); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 当一个急冲手势发生后 回调该方法, 会计算出该手势在 x 轴 y 轴的速率 * * 参数解析 : * -- MotionEvent e1 : 急冲动作的第一次触摸事件; * -- MotionEvent e2 : 急冲动作的移动发生的时候的触摸事件; * -- float velocityX : x 轴的速率 * -- float velocityY : y 轴的速率 * * 返回值 : 如果执行完毕返回 true, 否则返回false, 这个就是自己定义的 * * (non-Javadoc) * @see android.view.GestureDetector.SimpleOnGestureListener#onFling(android.view.MotionEvent, android.view.MotionEvent, float, float) */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; velocityX, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//计算上一次的 y 轴位置, 当前的条目高度 加上 剩余的 不够一行高度的那部分\u0026lt;/span\u0026gt; lastScrollY = currentItem * getItemHeight() + scrollingOffset; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果可以循环最大值是无限大, 不能循环就是条目数的高度值\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; maxY = isCyclic ? \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;0x7FFFFFFF\u0026lt;/span\u0026gt; : adapter.getItemsCount() * getItemHeight(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; minY = isCyclic ? -maxY : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * Scroll 开始根据一个急冲手势滚动, 滚动的距离与初速度有关 * 参数介绍 : * -- int startX : 开始时的 X轴位置 * -- int startY : 开始时的 y轴位置 * -- int velocityX : 急冲手势的 x 轴的初速度, 单位 px/s * -- int velocityY : 急冲手势的 y 轴的初速度, 单位 px/s * -- int minX : x 轴滚动的最小值 * -- int maxX : x 轴滚动的最大值 * -- int minY : y 轴滚动的最小值 * -- int maxY : y 轴滚动的最大值 */\u0026lt;/span\u0026gt; scroller.fling(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, lastScrollY, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt;) -velocityY / \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, minY, maxY); setNextMessage(MESSAGE_SCROLL); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } }; ### (2) 创建手势探测器 手势探测器创建 : 调用 其构造函数, 传入 上下文对象 和 手势监听器对象; \u0026amp;#8212; 禁止长按操作 : 调用 setIsLongpressEnabled(false) 方法, 禁止长按操作, 因为 长按操作会屏蔽滚动事件; ``` //创建一个手势处理 gestureDetector = new GestureDetector(context, gestureListener); /* * 是否允许长按操作, * 如果设置为 true 用户按下不松开, 会返回一个长按事件, * 如果设置为 false, 按下不松开滑动的话 会收到滚动事件. */ gestureDetector.setIsLongpressEnabled(false);\n### (3) 将手势探测器 与 组件结合 关联手势探测器 与 组件 : 在组件的 onTouchEvent(MotionEvent event) 方法中, 调用手势探测器的 gestureDetector.onTouchEvent(event) 方法即可; ``` \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 继承自 View 的触摸事件, 当出现触摸事件的时候, 就会回调该方法 * (non-Javadoc) * @see android.view.View#onTouchEvent(android.view.MotionEvent) */\u0026lt;/span\u0026gt; @Override \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; boolean onTouchEvent(MotionEvent \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;event\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//获取适配器\u0026lt;/span\u0026gt; WheelAdapter adapter = getAdapter(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (adapter == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * gestureDetector.onTouchEvent(event) : 分析给定的动作, 如果可用, 调用 手势检测器的 onTouchEvent 方法 * -- 参数解析 : ev , 触摸事件 * -- 返回值 : 如果手势监听器成功执行了该方法, 返回true, 如果执行出现意外 返回 false; */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (!gestureDetector.onTouchEvent(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;event\u0026lt;/span\u0026gt;) \u0026amp;\u0026amp; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;event\u0026lt;/span\u0026gt;.getAction() == MotionEvent.ACTION_UP) { justify(); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } ## 2. Scroller 简介 ### (1) Scroller 简介 Scroller 通用作用 : Scroller 组件并不是一个布局组件, 该组件是运行在后台的, 通过一些方法设定 Scroller 对象 的操作 或者 动画, 然后让 Scroller 运行在后台中 用于模拟滚动操作 , 在 适当的时机 获取该对象的坐标信息 , 这些信息是在后台运算出来的; Scroller 在本 View 中作用 : Android 的这个自定义的 WheelView 组件, 可以 平滑的滚动 , 当我们做一个 加速滑动时, 会根据速度计算出滑动的距离 , 这些数据都是在 Scroller 中计算出来的; ### (2) 设定 Scroller 对象的动作参数 终止滚动 : \u0026amp;#8212; 终止滚动 跳转到目标位置 : 终止平缓的动画, 直接跳转到最终的 x y 轴的坐标位置; ``` public void abortAnimation()\n\u0026amp;#8212; **终止滚动 停止在当前位置 **: 强行结束 Scroll 的滚动; ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; forceFinished(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; finished) 设置滚动参数 : \u0026amp;#8212; 设置最终 x 轴坐标 : ``` public void setFinalX(int newX)\n\u0026amp;#8212; 设置最终 y 轴坐标 : ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; setFinalY(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; newY) \u0026amp;#8212; 设置滚动摩擦力 : ``` public final void setFriction(float friction)\n设置动作 : \u0026amp;#8212; 开始滚动 : 传入参数 开始 x 位置, 开始 y 位置, x 轴滚动距离, y 轴滚动距离; ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; startScroll(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; startX, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; startY, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; dy) \u0026amp;#8212; **开始滚动 设定时间**: 最后一个参数是时间, 单位是 ms; ``` public void startScroll(int startX, int startY, int dx, int dy, int duration)\n\u0026amp;#8212; **急冲滚动**: 根据一个 急冲 手势进行滚动, 传入参数 : x轴开始位置, y轴开始位置, x 轴速度, y 轴速度, x 轴最小速度, x 轴最大速度, y 轴最小速度, y 轴最大速度; ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; fling(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; startX, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; startY, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; velocityX, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; velocityY, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; minX, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; maxX, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; minY, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; maxY) **延长滚动时间**: 延长滚动的时间, 让滚动滚的更远一些; ``` public void extendDuration(int extend)\n### (3) 获取 Scroll 后台运行参数 获取当前数据 : \u0026amp;#8212; 获取当前 x 轴坐标 : ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getCurrX() \u0026amp;#8212; 获取当前 y 轴坐标 : ``` public final int getCurrY()\n\u0026amp;#8212; 获取当前速度 : ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; getCurrVelocity() 获取开始结束时的数据 : \u0026amp;#8212; 获取开始 x 轴坐标 : ``` public final int getStartX()\n\u0026amp;#8212; 获取开始 y 轴坐标 : ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getStartY() \u0026amp;#8212; 获取最终 x 轴坐标 : 该参数只在急冲滚动时有效; ``` public final int getFinalX()\n\u0026amp;#8212; 获取最终 y 轴坐标 : 该参数只在急冲滚动时有效; ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getFinalY() 查看是否滚动完毕 : ``` public final boolean isFinished()\n获取从开始滚动到现在的时间 : ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; timePassed() 获取新位置 : 调用该方法可以获取新位置, 如果返回 true 说明动画还没执行完毕; ``` public boolean computeScrollOffset()\n### (4) Scroll 在 WheelView 中的运用 Scroller 创建 : ``` \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//使用默认的 时间 和 插入器 创建一个滚动器\u0026lt;/span\u0026gt; scroller = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; Scroller(context); 手势监听器 SimpleOnGestureListener 对象中的 onDown() 方法 : 如果滚动还在执行, 那么强行停止 Scroller 滚动; ``` //按下操作 public boolean onDown(MotionEvent e) { //如果滚动在执行 if (isScrollingPerformed) { //滚动强制停止, 按下的时候不能继续滚动 scroller.forceFinished(true); //清理信息 clearMessages(); return true; } return false; }\n当手势监听器 SimpleOnGestureListener 对象中有急冲动作时 onFling() 方法中 : 手势监听器监听到了 急冲动作, 那么 Scroller 也进行对应操作; ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; velocityX, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//计算上一次的 y 轴位置, 当前的条目高度 加上 剩余的 不够一行高度的那部分\u0026lt;/span\u0026gt; lastScrollY = currentItem * getItemHeight() + scrollingOffset; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果可以循环最大值是无限大, 不能循环就是条目数的高度值\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; maxY = isCyclic ? \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;0x7FFFFFFF\u0026lt;/span\u0026gt; : adapter.getItemsCount() * getItemHeight(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; minY = isCyclic ? -maxY : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * Scroll 开始根据一个急冲手势滚动, 滚动的距离与初速度有关 * 参数介绍 : * -- int startX : 开始时的 X轴位置 * -- int startY : 开始时的 y轴位置 * -- int velocityX : 急冲手势的 x 轴的初速度, 单位 px/s * -- int velocityY : 急冲手势的 y 轴的初速度, 单位 px/s * -- int minX : x 轴滚动的最小值 * -- int maxX : x 轴滚动的最大值 * -- int minY : y 轴滚动的最小值 * -- int maxY : y 轴滚动的最大值 */\u0026lt;/span\u0026gt; scroller.fling(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, lastScrollY, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt;) -velocityY / \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, minY, maxY); setNextMessage(MESSAGE_SCROLL); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } 动画控制 Handler 中 : \u0026amp;#8212; 滚动 : 获取当前 Scroller 的 y 轴位置, 与上一次的 y 轴位置对比, 如果 间距 delta 不为0, 就滚动; \u0026amp;#8212; 查看是否停止 : 如果现在距离 到 最终距离 小于最小滚动距离, 强制停止; \u0026amp;#8212; 执行 msg.what 指令 : 如果需要停止, 强制停止, 否则调整坐标; ``` /**\n动画控制器\nanimation handler\n可能会造成内存泄露 : 添加注解 HandlerLeak\nHandler 类应该应该为static类型，否则有可能造成泄露。\n在程序消息队列中排队的消息保持了对目标Handler类的应用。\n如果Handler是个内部类，那 么它也会保持它所在的外部类的引用。\n为了避免泄露这个外部类，应该将Handler声明为static嵌套类，并且使用对外部类的弱应用。 */ @SuppressLint(\u0026ldquo;HandlerLeak\u0026rdquo;) private Handler animationHandler = new Handler() { public void handleMessage(Message msg) { //回调该方法获取当前位置, 如果返回true, 说明动画还没有执行完毕 scroller.computeScrollOffset(); //获取当前 y 位置 int currY = scroller.getCurrY(); //获取已经滚动了的位置, 使用上一次位置 减去 当前位置 int delta = lastScrollY - currY; lastScrollY = currY; if (delta != ) { //改变值不为 0 , 继续滚动 doScroll(delta); }\n/*\n如果滚动到了指定的位置, 滚动还没有停止 这时需要强制停止 */ if (Math.abs(currY - scroller.getFinalY()) \u0026lt; MIN_DELTA_FOR_SCROLLING) { currY = scroller.getFinalY(); scroller.forceFinished(true); } /*\n如果滚动没有停止 再向 Handler 发送一个停止 */ if (!scroller.isFinished()) { animationHandler.sendEmptyMessage(msg.what); } else if (msg.what == MESSAGE_SCROLL) { justify(); } else { finishScrolling(); } } }; ## 3. StaticLayout 布局容器 ### (1) StaticLayout 解析 StaticLayout 解析 : 该组件用于显示文本, 一旦该文本被显示后, 就不能再编辑, 如果想要修改文本, 使用 DynamicLayout 布局即可; \u0026amp;#8212; 使用场景 : 一般情况下不会使用该组件, 当想要自定义组件 或者 想要使用 Canvas 绘制文本时 才使用该布局; 常用方法解析 : \u0026amp;#8212; 获取底部 Padding : 获取底部 到最后一行文字的 间隔, 单位是 px; ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getBottomPadding() \u0026amp;#8212; 获取顶部 Padding : ``` public int getTopPadding()\n\u0026amp;#8212; **获取省略个数**: 获取某一行需要省略的字符个数; ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getEllipsisCount(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; line) \u0026amp;#8212; **获取省略开始位置**: 获取某一行要省略的字符串的第一个位置索引; ``` public int getEllipsisStart(int line)\n\u0026amp;#8212; **获取省略的宽度**: 获取某一行省略字符串的宽度, 单位 px; ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getEllipsisStart(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; line) \u0026amp;#8212; **获取是否处理特殊符号**: ``` public boolean getLineContainsTab(int line)\n\u0026amp;#8212; **获取文字的行数**: ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getLineCount() \u0026amp;#8212; **获取顶部位置**: 获取某一行顶部的位置; ``` public int getLineTop(int line)\n\u0026amp;#8212; **获取某一行底部位置**: ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getLineDescent(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; line) \u0026amp;#8212; **获取行的方向**: 字符串从左至右 还是从右至左; ``` public final Directions getLineDirections(int line)\n\u0026amp;#8212; **获取某行第一个字符索引**: 获取的是 某一行 第一个字符 在整个字符串的索引; ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getLineStart(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; line) \u0026amp;#8212; **获取该行段落方向**: 获取该行文字方向, 左至右 或者 右至左; ``` public int getParagraphDirection(int line)\n\u0026amp;#8212; **获取某个垂直位置显示的行数**: ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getLineForVertical(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; vertical) ### (2) 布局显示 布局创建 : \u0026amp;#8212; 三种布局 : WheelView 中涉及到了三种 StaticLayout 布局, 普通条目布局 itemLayout, 选中条目布局 valueLayout, 标签布局 labelLayout; \u0026amp;#8212; 创建时机 : 在 View 组件 每次 onMeasure() 和 onDraw() 方法中都要重新创建对应布局; \u0026amp;#8212; 创建布局源码 : ``` /**\n创建布局 @param widthItems 布局条目宽度 @param widthLabel label 宽度 / private void createLayouts(int widthItems, int widthLabel) { / * 创建普通条目布局 * 如果 普通条目布局 为 null 或者 普通条目布局的宽度 大于 传入的宽度, 这时需要重新创建布局 * 如果 普通条目布局存在, 并且其宽度小于传入的宽度, 此时需要将 */ if (itemsLayout == null || itemsLayout.getWidth() \u0026gt; widthItems) {\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* * android.text.StaticLayout.StaticLayout( * CharSequence source, TextPaint paint, * int width, Alignment align, * float spacingmult, float spacingadd, boolean includepad) * 传入参数介绍 : * CharSequence source : 需要分行显示的字符串 * TextPaint paint : 绘制字符串的画笔 * int width : 条目的宽度 * Alignment align : Layout 的对齐方式, ALIGN_CENTER 居中对齐, ALIGN_NORMAL 左对齐, Alignment.ALIGN_OPPOSITE 右对齐 * float spacingmult : 行间距, 1.5f 代表 1.5 倍字体高度 * float spacingadd : 基础行距上增加多少 , 真实行间距 等于 spacingmult 和 spacingadd 的和 * boolean includepad : */\u0026lt;/span\u0026gt; itemsLayout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StaticLayout(buildText(isScrollingPerformed), itemsPaint, widthItems, widthLabel \u0026amp;gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, ADDITIONAL_ITEM_HEIGHT, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用 Layout 内置的方法 increaseWidthTo 将宽度提升到指定的宽度\u0026lt;/span\u0026gt; itemsLayout.increaseWidthTo(widthItems); } \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* * 创建选中条目 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isScrollingPerformed \u0026amp;\u0026amp; (valueLayout == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || valueLayout.getWidth() \u0026amp;gt; widthItems)) { String text = getAdapter() != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; ? getAdapter().getItem(currentItem) : \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; valueLayout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StaticLayout(text != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; ? text : \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;\u0026quot;\u0026lt;/span\u0026gt;, valuePaint, widthItems, widthLabel \u0026amp;gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, ADDITIONAL_ITEM_HEIGHT, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isScrollingPerformed) { valueLayout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { valueLayout.increaseWidthTo(widthItems); } \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* * 创建标签条目 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (widthLabel \u0026amp;gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (labelLayout == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || labelLayout.getWidth() \u0026amp;gt; widthLabel) { labelLayout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StaticLayout(label, valuePaint, widthLabel, Layout.Alignment.ALIGN_NORMAL, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, ADDITIONAL_ITEM_HEIGHT, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { labelLayout.increaseWidthTo(widthLabel); } } }\n## 4. 监听器管理 监听器集合维护 : \u0026amp;#8212; 定义监听器集合 : 在 View 组件中 定义一个 List 集合, 集合中存放 监听器元素; ``` \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 条目改变监听器集合 封装了条目改变方法, 当条目改变时回调 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026amp;lt;OnWheelChangedListener\u0026amp;gt; changingListeners = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; LinkedList\u0026amp;lt;OnWheelChangedListener\u0026amp;gt;(); \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 条目滚动监听器集合, 该监听器封装了 开始滚动方法, 结束滚动方法 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026amp;lt;OnWheelScrollListener\u0026amp;gt; scrollingListeners = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; LinkedList\u0026amp;lt;OnWheelScrollListener\u0026amp;gt;(); \u0026amp;#8212; 提供对监听器集合的添加删除接口 : 提供 对集合 进行 添加 和 删除的接口; ``` /**\n添加 WheelView 选择的元素改变监听器 @param listener the listener */ public void addChangingListener(OnWheelChangedListener listener) { changingListeners.add(listener); }\n\u0026lt;span class=\u0026quot;javadoc\u0026quot;\u0026gt;/** 移除 WheelView 元素改变监听器 @param listener the listener */ public void removeChangingListener(OnWheelChangedListener listener) { changingListeners.remove(listener); }\n\u0026amp;#8212; **调用监听器接口**: ``` \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 回调元素改变监听器集合的元素改变监听器元素的元素改变方法 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; oldValue *\t旧的 WheelView选中的值 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; newValue *\t新的 WheelView选中的值 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; notifyChangingListeners(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; oldValue, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; newValue) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;for\u0026lt;/span\u0026gt; (OnWheelChangedListener listener : changingListeners) { listener.onChanged(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;, oldValue, newValue); } } ## 5. 自定义 View 对象的宽高 ### (1) onMeasure 方法 MeasureSpec 模式解析 常规处理方法 : 组件的宽高有三种情况, widthMeasureSpec 有三种模式 最大模式, 精准模式, 未定义模式; \u0026amp;#8212; 最大模式 : 在 组件的宽或高 warp_content 属性时, 会使用最大模式; \u0026amp;#8212; 精准模式 : 当给组件宽 或者高 定义一个值 或者 使用 match_parent 时, 会使用精准模式; **处理宽高的常规代码** : ``` @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取宽度 和 高度的模式 和 大小\u0026lt;/span\u0026gt; int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec);\nLog.i(TAG, \u0026ldquo;宽度 : widthMode : \u0026ldquo; + getMode(widthMode) + \u0026rdquo; , widthSize : \u0026ldquo; + widthSize + \u0026quot;\\n\u0026rdquo; + \u0026ldquo;高度 : heightMode : \u0026ldquo; + getMode(heightMode) + \u0026rdquo; , heightSize : \u0026ldquo; + heightSize);\nint width = ; int height = ; /*\n精准模式 精准模式下 高度就是精确的高度 */ if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; //未定义模式 和 最大模式 } else { //未定义模式下 获取布局需要的高度 height = 100;\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//最大模式下 获取 布局高度 和 布局所需高度的最小值\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (heightMode == MeasureSpec.AT_MOST) { height = Math.min(height, heightSize); } }\nif (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { width = 100; if (heightMode == MeasureSpec.AT_MOST) { width = Math.min(width, widthSize); } }\nLog.i(TAG, \u0026ldquo;最终结果 : 宽度 : \u0026ldquo; + width + \u0026rdquo; , 高度 : \u0026ldquo; + height);\nsetMeasuredDimension(width, height);\n}\npublic String getMode(int mode) { String modeName = \u0026rdquo;\u0026quot;; if(mode == MeasureSpec.EXACTLY){ modeName = \u0026ldquo;精准模式\u0026rdquo;; }else if(mode == MeasureSpec.AT_MOST){ modeName = \u0026ldquo;最大模式\u0026rdquo;; }else if(mode == MeasureSpec.UNSPECIFIED){ modeName = \u0026ldquo;未定义模式\u0026rdquo;; }\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; modeName; }\n### (2) 测试上述代码 使用下面的自定义组件测试 : ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;package\u0026lt;/span\u0026gt; cn.org.octopus.wheelview; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Color; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;MyView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;View\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;octopus.my.view\u0026#34;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; MyView(Context context, AttributeSet attrs) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; MyView(Context context) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;(context); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; MyView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;.onMeasure(widthMeasureSpec, heightMeasureSpec); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//获取宽度 和 高度的模式 和 大小\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; widthMode = MeasureSpec.getMode(widthMeasureSpec); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; heightMode = MeasureSpec.getMode(heightMeasureSpec); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; widthSize = MeasureSpec.getSize(widthMeasureSpec); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; heightSize = MeasureSpec.getSize(heightMeasureSpec); Log.i(TAG, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;宽度 : widthMode : \u0026#34;\u0026lt;/span\u0026gt; + getMode(widthMode) + \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34; , widthSize : \u0026#34;\u0026lt;/span\u0026gt; + widthSize + \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;\\n\u0026#34;\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;高度 : heightMode : \u0026#34;\u0026lt;/span\u0026gt; + getMode(heightMode) + \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34; , heightSize : \u0026#34;\u0026lt;/span\u0026gt; + heightSize); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; width = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; height = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 精准模式 * 精准模式下 高度就是精确的高度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (heightMode == MeasureSpec.EXACTLY) { height = heightSize; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//未定义模式 和 最大模式\u0026lt;/span\u0026gt; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//未定义模式下 获取布局需要的高度\u0026lt;/span\u0026gt; height = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//最大模式下 获取 布局高度 和 布局所需高度的最小值\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (heightMode == MeasureSpec.AT_MOST) { height = Math.min(height, heightSize); } } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { width = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (heightMode == MeasureSpec.AT_MOST) { width = Math.min(width, widthSize); } } Log.i(TAG, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;最终结果 : 宽度 : \u0026#34;\u0026lt;/span\u0026gt; + width + \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34; , 高度 : \u0026#34;\u0026lt;/span\u0026gt; + height); setMeasuredDimension(width, height); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; String getMode(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; mode) { String modeName = \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt;(mode == MeasureSpec.EXACTLY){ modeName = \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;精准模式\u0026#34;\u0026lt;/span\u0026gt;; }\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt;(mode == MeasureSpec.AT_MOST){ modeName = \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;最大模式\u0026#34;\u0026lt;/span\u0026gt;; }\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt;(mode == MeasureSpec.UNSPECIFIED){ modeName = \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;未定义模式\u0026#34;\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; modeName; } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;.onDraw(canvas); canvas.drawColor(Color.BLUE); } } 给定具体值情况 : \u0026amp;#8212; 组件信息 : ``` \u0026lt;cn.org.octopus.wheelview.MyView android:layout_width=\u0026ldquo;300dip\u0026rdquo; android:layout_height=\u0026ldquo;300dip\u0026rdquo;/\u0026gt;\n\u0026amp;#8212; **日志信息**: ``` \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;24.304\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2609\u0026lt;/span\u0026gt;): 宽度 : widthMode : 精准模式 , widthSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;450\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;24.304\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2609\u0026lt;/span\u0026gt;): 高度 : heightMode : 最大模式 , heightSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;850\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;24.304\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2609\u0026lt;/span\u0026gt;): 最终结果 : 宽度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;450\u0026lt;/span\u0026gt; , 高度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;24.304\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2609\u0026lt;/span\u0026gt;): 宽度 : widthMode : 精准模式 , widthSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;450\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;24.304\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2609\u0026lt;/span\u0026gt;): 高度 : heightMode : 精准模式 , heightSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;450\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;24.304\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2609\u0026lt;/span\u0026gt;): 最终结果 : 宽度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;450\u0026lt;/span\u0026gt; , 高度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;450\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;24.335\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2609\u0026lt;/span\u0026gt;): 宽度 : widthMode : 精准模式 , widthSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;450\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;24.335\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2609\u0026lt;/span\u0026gt;): 高度 : heightMode : 最大模式 , heightSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;850\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;24.335\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2609\u0026lt;/span\u0026gt;): 最终结果 : 宽度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;450\u0026lt;/span\u0026gt; , 高度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;24.335\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2609\u0026lt;/span\u0026gt;): 宽度 : widthMode : 精准模式 , widthSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;450\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;24.335\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2609\u0026lt;/span\u0026gt;): 高度 : heightMode : 精准模式 , heightSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;450\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;24.335\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2609\u0026lt;/span\u0026gt;): 最终结果 : 宽度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;450\u0026lt;/span\u0026gt; , 高度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;450\u0026lt;/span\u0026gt; **warp_content 情况**: \u0026amp;#8212; 组件信息 : ``` \u0026lt;cn.org.octopus.wheelview.MyView android:layout_width=\u0026ldquo;wrap_content\u0026rdquo; android:layout_height=\u0026ldquo;wrap_content\u0026rdquo;/\u0026gt;\n\u0026amp;#8212; **日志信息**: ``` \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;47.351\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1803\u0026lt;/span\u0026gt;): 宽度 : widthMode : 最大模式 , widthSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;492\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;47.351\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1803\u0026lt;/span\u0026gt;): 高度 : heightMode : 最大模式 , heightSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;850\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;47.351\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1803\u0026lt;/span\u0026gt;): 最终结果 : 宽度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt; , 高度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;47.351\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1803\u0026lt;/span\u0026gt;): 宽度 : widthMode : 精准模式 , widthSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;47.351\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1803\u0026lt;/span\u0026gt;): 高度 : heightMode : 最大模式 , heightSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;802\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;47.351\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1803\u0026lt;/span\u0026gt;): 最终结果 : 宽度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt; , 高度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;47.390\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1803\u0026lt;/span\u0026gt;): 宽度 : widthMode : 最大模式 , widthSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;492\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;47.390\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1803\u0026lt;/span\u0026gt;): 高度 : heightMode : 最大模式 , heightSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;850\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;47.390\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1803\u0026lt;/span\u0026gt;): 最终结果 : 宽度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt; , 高度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;47.390\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1803\u0026lt;/span\u0026gt;): 宽度 : widthMode : 精准模式 , widthSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;47.390\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1803\u0026lt;/span\u0026gt;): 高度 : heightMode : 最大模式 , heightSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;802\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;47.390\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1803\u0026lt;/span\u0026gt;): 最终结果 : 宽度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt; , 高度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt; match_parent 情况 : \u0026amp;#8212; 组件信息 : ``` \u0026lt;cn.org.octopus.wheelview.MyView android:layout_width=\u0026ldquo;match_parent\u0026rdquo; android:layout_height=\u0026ldquo;match_parent\u0026rdquo;/\u0026gt;\n\u0026amp;#8212; 日志信息 : ``` \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt;:08.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;296\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2249\u0026lt;/span\u0026gt;): 宽度 : widthMode : 精准模式 , widthSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;492\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt;:08.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;296\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2249\u0026lt;/span\u0026gt;): 高度 : heightMode : 精准模式 , heightSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;850\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt;:08.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;296\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2249\u0026lt;/span\u0026gt;): 最终结果 : 宽度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;492\u0026lt;/span\u0026gt; , 高度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;850\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt;:08.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;296\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2249\u0026lt;/span\u0026gt;): 宽度 : widthMode : 精准模式 , widthSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;492\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt;:08.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;296\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2249\u0026lt;/span\u0026gt;): 高度 : heightMode : 精准模式 , heightSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;802\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt;:08.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;296\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2249\u0026lt;/span\u0026gt;): 最终结果 : 宽度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;492\u0026lt;/span\u0026gt; , 高度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;802\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt;:08.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;328\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2249\u0026lt;/span\u0026gt;): 宽度 : widthMode : 精准模式 , widthSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;492\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt;:08.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;328\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2249\u0026lt;/span\u0026gt;): 高度 : heightMode : 精准模式 , heightSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;850\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt;:08.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;328\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2249\u0026lt;/span\u0026gt;): 最终结果 : 宽度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;492\u0026lt;/span\u0026gt; , 高度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;850\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt;:08.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;328\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2249\u0026lt;/span\u0026gt;): 宽度 : widthMode : 精准模式 , widthSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;492\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt;:08.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;328\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2249\u0026lt;/span\u0026gt;): 高度 : heightMode : 精准模式 , heightSize : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;802\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;01\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt;:08.\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;328\u0026lt;/span\u0026gt;: I/octopus.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;my\u0026lt;/span\u0026gt;.view(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2249\u0026lt;/span\u0026gt;): 最终结果 : 宽度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;492\u0026lt;/span\u0026gt; , 高度 : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;802\u0026lt;/span\u0026gt; **博客地址 **: [http://blog.csdn.net/shulianghan/article/details/41520569#t17](http://blog.csdn.net/shulianghan/article/details/41520569#t17) 代码下载 : \u0026amp;#8212; **GitHub **: [https://github.com/han1202012/WheelViewDemo.git](https://github.com/han1202012/WheelViewDemo.git) \u0026amp;#8212; **CSDN **: [http://download.csdn.net/detail/han1202012/8208997](http://download.csdn.net/detail/han1202012/8208997) ; ## 四. 详细代码 ## 1. WheelAdapter ``` package cn.org.octopus.wheelview.widget;\n/**\nWheelView 适配器接口 @author han_shuliang(octopus_truth@163.com) / public interface WheelAdapter { /* * 获取条目的个数 * * @return * WheelView 的条目个数 */ public int getItemsCount();\n\u0026lt;span class=\u0026quot;javadoc\u0026quot;\u0026gt;/** * 根据索引位置获取 WheelView 的条目 * * \u0026lt;span class=\u0026quot;javadoctag\u0026quot;\u0026gt;@param\u0026lt;/span\u0026gt; index * 条目的索引 * \u0026lt;span class=\u0026quot;javadoctag\u0026quot;\u0026gt;@return\u0026lt;/span\u0026gt; * WheelView 上显示的条目的值 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getItem(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; index); \u0026lt;span class=\u0026quot;javadoc\u0026quot;\u0026gt;/** * 获取条目的最大长度. 用来定义 WheelView 的宽度. 如果返回 -1, 就会使用默认宽度 * * \u0026lt;span class=\u0026quot;javadoctag\u0026quot;\u0026gt;@return\u0026lt;/span\u0026gt; * 条目的最大宽度 或者 -1 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getMaximumLength(); }\n## 2. ArrayWheelAdapter ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;package\u0026lt;/span\u0026gt; cn.org.octopus.wheelview.widget; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * WheelView 的适配器类 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; \u0026amp;lt;T\u0026amp;gt; *\t元素类型 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;ArrayWheelAdapter\u0026lt;/span\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;T\u0026lt;/span\u0026gt;\u0026amp;gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;WheelAdapter\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 适配器的 元素集合(数据源) 默认长度为 -1 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; DEFAULT_LENGTH = -\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 适配器的数据源 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; T items[]; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** WheelView 的宽度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; length; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 构造方法 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; items *\t适配器数据源 集合 T 类型的数组 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; length *\t适配器数据源 集合 T 数组长度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; ArrayWheelAdapter(T items[], \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; length) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.items = items; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.length = length; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 构造方法 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; items *\t适配器数据源集合 T 类型数组 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; ArrayWheelAdapter(T items[]) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;(items, DEFAULT_LENGTH); } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; String getItem(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; index) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果这个索引值合法, 就返回 item 数组对应的元素的字符串形式\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (index \u0026amp;gt;= \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; index \u0026amp;lt; items.length) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; items[index].toString(); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getItemsCount() { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//返回 item 数组的长度\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; items.length; } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getMaximumLength() { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//返回 item 元素的宽度\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; length; } } ## 3. NumericWheelAdapter ``` package cn.org.octopus.wheelview.widget;\n/**\n显示数字的 WheelAdapter */ public class NumericWheelAdapter implements WheelAdapter { /** 默认最小值 */ public static final int DEFAULT_MAX_VALUE = 9;\n/** 默认最大值 */ private static final int DEFAULT_MIN_VALUE = ;\n/** 设置的最小值 / private int minValue; /* 设置的最大值 */ private int maxValue;\n/** 格式化字符串, 用于格式化 货币, 科学计数, 十六进制 等格式 */ private String format;\n/**\n默认的构造方法, 使用默认的最大最小值 */ public NumericWheelAdapter() { this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE); } /**\n构造方法 @param minValue 最小值 @param maxValue 最大值 */ public NumericWheelAdapter(int minValue, int maxValue) { this(minValue, maxValue, null); }\n/**\n构造方法 @param minValue 最小值 @param maxValue 最大值 @param format 格式化字符串 */ public NumericWheelAdapter(int minValue, int maxValue, String format) { this.minValue = minValue; this.maxValue = maxValue; this.format = format; }\n@Override public String getItem(int index) { String result = \u0026rdquo;\u0026quot;; if (index \u0026gt;= \u0026amp;\u0026amp; index \u0026lt; getItemsCount()) { int value = minValue + index; //如果 format 不为 null, 那么格式化字符串, 如果为 null, 直接返回数字 if(format != null){ result = String.format(format, value); }else{ result = Integer.toString(value); } return result; } return null; }\n@Override public int getItemsCount() { //返回数字总个数 return maxValue - minValue + 1; }\n@Override public int getMaximumLength() { //获取 最大值 和 最小值 中的 较大的数字 int max = Math.max(Math.abs(maxValue), Math.abs(minValue)); //获取这个数字 的 字符串形式的 字符串长度 int maxLen = Integer.toString(max).length(); if (minValue \u0026lt; ) { maxLen++; } return maxLen; } }\n## 4. OnWheelChangedListener ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;package\u0026lt;/span\u0026gt; cn.org.octopus.wheelview.widget; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 条目改变监听器 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;interface\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;OnWheelChangedListener\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 当前条目改变时回调该方法 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; wheel * 条目改变的 WheelView 对象 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; oldValue * WheelView 旧的条目值 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; newValue * WheelView 新的条目值 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onChanged(WheelView wheel, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; oldValue, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; newValue); } ## 5. OnWheelScrollListener ``` package cn.org.octopus.wheelview.widget;\n/**\nWheelView 滚动监听器 / public interface OnWheelScrollListener { /*\n在 WheelView 滚动开始的时候回调该接口 @param wheel 开始滚动的 WheelView 对象 */ void onScrollingStarted(WheelView wheel);\n/**\n在 WheelView 滚动结束的时候回调该接口 @param wheel 结束滚动的 WheelView 对象 */ void onScrollingFinished(WheelView wheel); }\n## 6. WheelView ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;package\u0026lt;/span\u0026gt; cn.org.octopus.wheelview.widget; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; java.util.LinkedList; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; cn.org.octopus.wheelview.R; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.annotation.SuppressLint; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Rect; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.drawable.Drawable; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.drawable.GradientDrawable; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.drawable.GradientDrawable.Orientation; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.text.Layout; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.text.StaticLayout; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.text.TextPaint; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.GestureDetector; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.GestureDetector.SimpleOnGestureListener; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.Interpolator; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Scroller; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * WheelView 主对象 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;WheelView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;View\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 滚动花费时间 Scrolling duration */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; SCROLLING_DURATION = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;400\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 最小的滚动值, 每次最少滚动一个单位 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; MIN_DELTA_FOR_SCROLLING = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 当前条目中的文字颜色 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; VALUE_TEXT_COLOR = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;0xF0FF6347\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 非当前条目的文字颜色 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; ITEMS_TEXT_COLOR = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;0xFF000000\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 顶部和底部的阴影颜色 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//private static final int[] SHADOWS_COLORS = new int[] { 0xFF5436EE, 0x0012CEAE, 0x0012CEAE };\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt;[] SHADOWS_COLORS = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt;[] { \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;0xFF111111\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;0x00AAAAAA\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;0x00AAAAAA\u0026lt;/span\u0026gt; }; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 额外的条目高度 Additional items height (is added to standard text item height) */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; ADDITIONAL_ITEM_HEIGHT = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 字体大小 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; TEXT_SIZE = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;24\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 顶部 和 底部 条目的隐藏大小, * 如果是正数 会隐藏一部份, * 0 顶部 和 底部的字正好紧贴 边缘, * 负数时 顶部和底部 与 字有一定间距 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; ITEM_OFFSET = TEXT_SIZE / \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** Additional width for items layout */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; ADDITIONAL_ITEMS_SPACE = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** Label offset */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; LABEL_OFFSET = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;8\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** Left and right padding value */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; PADDING = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 默认的可显示的条目数 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; DEF_VISIBLE_ITEMS = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** WheelView 适配器 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; WheelAdapter adapter = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 当前显示的条目索引 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; currentItem = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 条目宽度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; itemsWidth = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 标签宽度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; labelWidth = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 可见的条目数 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; visibleItems = DEF_VISIBLE_ITEMS; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 条目高度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; itemHeight = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 绘制普通条目画笔 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; TextPaint itemsPaint; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 绘制选中条目画笔 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; TextPaint valuePaint; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 普通条目布局 * StaticLayout 布局用于控制 TextView 组件, 一般情况下不会直接使用该组件, * 除非你自定义一个组件 或者 想要直接调用 Canvas.drawText() 方法 * */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; StaticLayout itemsLayout; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; StaticLayout labelLayout; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 选中条目布局 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; StaticLayout valueLayout; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 标签 在选中条目的右边出现 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; String label; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 选中条目的背景图片 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; Drawable centerDrawable; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 顶部阴影图片 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; GradientDrawable topShadow; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 底部阴影图片 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; GradientDrawable bottomShadow; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 是否在滚动 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; isScrollingPerformed; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 滚动的位置 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; scrollingOffset; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 手势检测器 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; GestureDetector gestureDetector; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * Scroll 类封装了滚动动作. * 开发者可以使用 Scroll 或者 Scroll 实现类 去收集产生一个滚动动画所需要的数据, 返回一个急冲滑动的手势. * 该对象可以追踪随着时间推移滚动的偏移量, 但是这些对象不会自动向 View 对象提供这些位置. * 如果想要使滚动动画看起来比较平滑, 开发者需要在适当的时机 获取 和 使用新的坐标; * */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; Scroller scroller; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 之前所在的 y 轴位置 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; lastScrollY; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 是否循环 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; isCyclic = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 条目改变监听器集合 封装了条目改变方法, 当条目改变时回调 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026amp;lt;OnWheelChangedListener\u0026amp;gt; changingListeners = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; LinkedList\u0026amp;lt;OnWheelChangedListener\u0026amp;gt;(); \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 条目滚动监听器集合, 该监听器封装了 开始滚动方法, 结束滚动方法 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026amp;lt;OnWheelScrollListener\u0026amp;gt; scrollingListeners = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; LinkedList\u0026amp;lt;OnWheelScrollListener\u0026amp;gt;(); \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 构造方法 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; WheelView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); initData(context); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 构造方法 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; WheelView(Context context, AttributeSet attrs) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); initData(context); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 构造方法 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; WheelView(Context context) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;(context); initData(context); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 初始化数据 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; context *\t上下文对象 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; initData(Context context) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//创建一个手势处理\u0026lt;/span\u0026gt; gestureDetector = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(context, gestureListener); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 是否允许长按操作, * 如果设置为 true 用户按下不松开, 会返回一个长按事件, * 如果设置为 false, 按下不松开滑动的话 会收到滚动事件. */\u0026lt;/span\u0026gt; gestureDetector.setIsLongpressEnabled(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//使用默认的 时间 和 插入器 创建一个滚动器\u0026lt;/span\u0026gt; scroller = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; Scroller(context); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 获取该 WheelView 的适配器 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@return\u0026lt;/span\u0026gt; * 返回适配器 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; WheelAdapter getAdapter() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; adapter; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 设置适配器 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; adapter *\t要设置的适配器 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; setAdapter(WheelAdapter adapter) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.adapter = adapter; invalidateLayouts(); invalidate(); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 设置 Scroll 的插入器 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; interpolator *\tthe interpolator */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; setInterpolator(Interpolator interpolator) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//强制停止滚动\u0026lt;/span\u0026gt; scroller.forceFinished(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//创建一个 Scroll 对象\u0026lt;/span\u0026gt; scroller = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; Scroller(getContext(), interpolator); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 获取课件条目数 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@return\u0026lt;/span\u0026gt; the count of visible items */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getVisibleItems() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; visibleItems; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 设置可见条目数 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; count *\tthe new count */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; setVisibleItems(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; count) { visibleItems = count; invalidate(); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 获取标签 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@return\u0026lt;/span\u0026gt; the label */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; String getLabel() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; label; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 设置标签 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; newLabel *\tthe label to set */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; setLabel(String newLabel) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (label == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; || !label.equals(newLabel)) { label = newLabel; labelLayout = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; invalidate(); } } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 添加 WheelView 选择的元素改变监听器 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; listener *\tthe listener */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; addChangingListener(OnWheelChangedListener listener) { changingListeners.add(listener); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 移除 WheelView 元素改变监听器 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; listener *\tthe listener */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; removeChangingListener(OnWheelChangedListener listener) { changingListeners.remove(listener); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 回调元素改变监听器集合的元素改变监听器元素的元素改变方法 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; oldValue *\t旧的 WheelView选中的值 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; newValue *\t新的 WheelView选中的值 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; notifyChangingListeners(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; oldValue, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; newValue) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;for\u0026lt;/span\u0026gt; (OnWheelChangedListener listener : changingListeners) { listener.onChanged(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;, oldValue, newValue); } } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 添加 WheelView 滚动监听器 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; listener *\tthe listener */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; addScrollingListener(OnWheelScrollListener listener) { scrollingListeners.add(listener); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 移除 WheelView 滚动监听器 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; listener *\tthe listener */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; removeScrollingListener(OnWheelScrollListener listener) { scrollingListeners.remove(listener); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 通知监听器开始滚动 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; notifyScrollingListenersAboutStart() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;for\u0026lt;/span\u0026gt; (OnWheelScrollListener listener : scrollingListeners) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//回调开始滚动方法\u0026lt;/span\u0026gt; listener.onScrollingStarted(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;); } } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 通知监听器结束滚动 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; notifyScrollingListenersAboutEnd() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;for\u0026lt;/span\u0026gt; (OnWheelScrollListener listener : scrollingListeners) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//回调滚动结束方法\u0026lt;/span\u0026gt; listener.onScrollingFinished(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;); } } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 获取当前选中元素的索引 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@return\u0026lt;/span\u0026gt; * 当前元素索引 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getCurrentItem() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; currentItem; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 设置当前元素的位置, 如果索引是错误的 不进行任何操作 * -- 需要考虑该 WheelView 是否能循环 * -- 根据是否需要滚动动画来确定是 ①滚动到目的位置 还是 ②晴空所有条目然后重绘 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; index *\t要设置的元素索引值 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; animated *\t动画标志位 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; setCurrentItem(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; index, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; animated) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果没有适配器或者元素个数为0 直接返回\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (adapter == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; || adapter.getItemsCount() == \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// throw?\u0026lt;/span\u0026gt; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//目标索引小于 0 或者大于 元素索引最大值(个数 -1)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (index \u0026amp;lt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt; || index \u0026amp;gt;= adapter.getItemsCount()) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//入股WheelView 可循环, 修正索引值, 如果不可循环直接返回\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (isCyclic) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;while\u0026lt;/span\u0026gt; (index \u0026amp;lt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { index += adapter.getItemsCount(); } index %= adapter.getItemsCount(); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// throw?\u0026lt;/span\u0026gt; } } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果当前的索引不是传入的 索引\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (index != currentItem) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 如果需要动画, 就滚动到目标位置 * 如果不需要动画, 重新设置布局 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (animated) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 开始滚动, 每个元素滚动间隔 400 ms, 滚动次数是 目标索引值 减去 当前索引值, 这是滚动的真实方法 */\u0026lt;/span\u0026gt; scroll(index - currentItem, SCROLLING_DURATION); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//所有布局设置为 null, 滚动位置设置为 0\u0026lt;/span\u0026gt; invalidateLayouts(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; old = currentItem; currentItem = index; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//便利回调元素改变监听器集合中的监听器元素中的元素改变方法\u0026lt;/span\u0026gt; notifyChangingListeners(old, currentItem); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//重绘\u0026lt;/span\u0026gt; invalidate(); } } } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 设置当前选中的条目, 没有动画, 当索引出错不做任何操作 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; index *\t要设置的索引 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; setCurrentItem(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; index) { setCurrentItem(index, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 获取 WheelView 是否可以循环 * -- 如果可循环 : 第一个之前是最后一个, 最后一个之后是第一个; * -- 如果不可循环 : 到第一个就不能上翻, 最后一个不能下翻 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@return\u0026lt;/span\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; isCyclic() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; isCyclic; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 设置 WheelView 循环标志 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; isCyclic *\tthe flag to set */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; setCyclic(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; isCyclic) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.isCyclic = isCyclic; invalidate(); invalidateLayouts(); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 使布局无效 * 将 选中条目 和 普通条目设置为 null, 滚动位置设置为0 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; invalidateLayouts() { itemsLayout = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; valueLayout = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; scrollingOffset = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 初始化资源 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; initResourcesIfNecessary() { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 设置绘制普通条目的画笔, 允许抗拒齿, 允许 fake-bold * 设置文字大小为 24 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (itemsPaint == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { itemsPaint = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FAKE_BOLD_TEXT_FLAG); itemsPaint.setTextSize(TEXT_SIZE); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 设置绘制选中条目的画笔 * 设置文字大小 24 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (valuePaint == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { valuePaint = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FAKE_BOLD_TEXT_FLAG | Paint.DITHER_FLAG); valuePaint.setTextSize(TEXT_SIZE); valuePaint.setShadowLayer(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;0.1\u0026lt;/span\u0026gt;f, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;0.1\u0026lt;/span\u0026gt;f, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;0xFFC0C0C0\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//选中的条目背景\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (centerDrawable == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { centerDrawable = getContext().getResources().getDrawable(R.drawable.wheel_val); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//创建顶部阴影图片\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (topShadow == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 构造方法中传入颜色渐变方向 * 阴影颜色 */\u0026lt;/span\u0026gt; topShadow = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//创建底部阴影图片\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (bottomShadow == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { bottomShadow = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 设置 View 组件的背景 */\u0026lt;/span\u0026gt; setBackgroundResource(R.drawable.wheel_bg); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 计算布局期望的高度 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; layout *\t组件的布局的 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@return\u0026lt;/span\u0026gt; * 布局需要的高度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getDesiredHeight(Layout layout) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (layout == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 布局需要的高度是 条目个数 * 可见条目数 减去 顶部和底部隐藏的一部份 减去 额外的条目高度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; desired = getItemHeight() * visibleItems - ITEM_OFFSET * \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; - ADDITIONAL_ITEM_HEIGHT; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 将计算的布局高度 与 最小高度比较, 取最大值\u0026lt;/span\u0026gt; desired = Math.max(desired, getSuggestedMinimumHeight()); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; desired; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 根据条目获取字符串 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; index *\t条目索引 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@return\u0026lt;/span\u0026gt; * 条目显示的字符串 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; String getTextItem(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; index) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (adapter == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; || adapter.getItemsCount() == \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//适配器显示的字符串个数\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; count = adapter.getItemsCount(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//考虑 index 小于 0 的情况\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; ((index \u0026amp;lt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt; || index \u0026amp;gt;= count) \u0026amp;\u0026amp; !isCyclic) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;while\u0026lt;/span\u0026gt; (index \u0026amp;lt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { index = count + index; } } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//index 大于 0\u0026lt;/span\u0026gt; index %= count; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; adapter.getItem(index); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 根据当前值创建 字符串 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; useCurrentValue * 是否在滚动 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@return\u0026lt;/span\u0026gt; the text * 生成的字符串 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; String buildText(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; useCurrentValue) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//创建字符串容器\u0026lt;/span\u0026gt; StringBuilder itemsText = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; StringBuilder(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//计算出显示的条目相对位置, 例如显示 5个, 第 3 个是正中见选中的布局\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; addItems = visibleItems / \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 遍历显示的条目 * 获取当前显示条目 上下 各 addItems 个文本, 将该文本添加到显示文本中去 * 如果不是最后一个 都加上回车 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; i = currentItem - addItems; i \u0026amp;lt;= currentItem + addItems; i++) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果在滚动\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (useCurrentValue || i != currentItem) { String text = getTextItem(i); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (text != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { itemsText.append(text); } } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (i \u0026amp;lt; currentItem + addItems) { itemsText.append(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;\\n\u0026#34;\u0026lt;/span\u0026gt;); } } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; itemsText.toString(); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 返回 条目的字符串 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@return\u0026lt;/span\u0026gt; * 条目最大宽度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getMaxTextLength() { WheelAdapter adapter = getAdapter(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (adapter == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果获取的最大条目宽度不为 -1, 可以直接返回该条目宽度\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; adapterLength = adapter.getMaximumLength(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (adapterLength \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; adapterLength; } String maxText = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; addItems = visibleItems / \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 遍历当前显示的条目, 获取字符串长度最长的那个, 返回这个最长的字符串长度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; i = Math.max(currentItem - addItems, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;); i \u0026amp;lt; Math.min(currentItem + visibleItems, adapter.getItemsCount()); i++) { String text = adapter.getItem(i); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (text != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; (maxText == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; || maxText.length() \u0026amp;lt; text.length())) { maxText = text; } } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; maxText != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; ? maxText.length() : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 获取每个条目的高度 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@return\u0026lt;/span\u0026gt; * 条目的高度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getItemHeight() { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果条目高度不为 0, 直接返回\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (itemHeight != \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; itemHeight; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果条目的高度为 0, 并且普通条目布局不为null, 条目个数大于 2 \u0026lt;/span\u0026gt; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (itemsLayout != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; itemsLayout.getLineCount() \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * itemsLayout.getLineTop(2) : 获取顶部第二行上面的垂直(y轴)位置, 如果行数等于 */\u0026lt;/span\u0026gt; itemHeight = itemsLayout.getLineTop(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;) - itemsLayout.getLineTop(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; itemHeight; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果上面都不符合, 使用整体高度处以 显示条目数\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; getHeight() / visibleItems; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 计算宽度并创建文字布局 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; widthSize *\t输入的布局宽度 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; mode *\t布局模式 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@return\u0026lt;/span\u0026gt; * 计算的宽度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; calculateLayoutWidth(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; widthSize, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; mode) { initResourcesIfNecessary(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; width = widthSize; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//获取最长的条目显示字符串字符个数\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; maxLength = getMaxTextLength(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (maxLength \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 使用方法 FloatMath.ceil() 方法有以下警告 * Use java.lang.Math#ceil instead of android.util.FloatMath#ceil() since it is faster as of API 8 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//float textWidth = FloatMath.ceil(Layout.getDesiredWidth(\u0026#34;0\u0026#34;, itemsPaint));\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//向上取整 计算一个字符串宽度\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; textWidth = (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt;) Math.ceil(Layout.getDesiredWidth(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;0\u0026#34;\u0026lt;/span\u0026gt;, itemsPaint)); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//获取字符串总的宽度\u0026lt;/span\u0026gt; itemsWidth = (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt;) (maxLength * textWidth); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { itemsWidth = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//总宽度加上一些间距\u0026lt;/span\u0026gt; itemsWidth += ADDITIONAL_ITEMS_SPACE; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// make it some more\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//计算 label 的长度\u0026lt;/span\u0026gt; labelWidth = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (label != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; label.length() \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { labelWidth = (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt;) Math.ceil(Layout.getDesiredWidth(label, valuePaint)); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//labelWidth = (int) FloatMath.ceil(Layout.getDesiredWidth(label, valuePaint));\u0026lt;/span\u0026gt; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; recalculate = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//精准模式\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (mode == MeasureSpec.EXACTLY) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//精准模式下, 宽度就是给定的宽度\u0026lt;/span\u0026gt; width = widthSize; recalculate = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//未定义模式\u0026lt;/span\u0026gt; width = itemsWidth + labelWidth + \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; * PADDING; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (labelWidth \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { width += LABEL_OFFSET; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 获取 ( 计算出来的宽度 与 最小宽度的 ) 最大值\u0026lt;/span\u0026gt; width = Math.max(width, getSuggestedMinimumWidth()); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//最大模式 如果 给定的宽度 小于 计算出来的宽度, 那么使用最小的宽度 ( 给定宽度 | 计算出来的宽度 )\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (mode == MeasureSpec.AT_MOST \u0026amp;\u0026amp; widthSize \u0026amp;lt; width) { width = widthSize; recalculate = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 重新计算宽度 , 如果宽度是给定的宽度, 不是我们计算出来的宽度, 需要重新进行计算 * 重新计算的宽度是用于 * * 计算 itemsWidth , 这个与返回的 宽度无关, 与创建布局有关 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (recalculate) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; pureWidth = width - LABEL_OFFSET - \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt; * PADDING; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (pureWidth \u0026amp;lt;= \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { itemsWidth = labelWidth = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (labelWidth \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;double\u0026lt;/span\u0026gt; newWidthItems = (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;double\u0026lt;/span\u0026gt;) itemsWidth * pureWidth / (itemsWidth + labelWidth); itemsWidth = (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt;) newWidthItems; labelWidth = pureWidth - itemsWidth; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { itemsWidth = pureWidth + LABEL_OFFSET; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// no label\u0026lt;/span\u0026gt; } } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (itemsWidth \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//创建布局\u0026lt;/span\u0026gt; createLayouts(itemsWidth, labelWidth); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; width; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 创建布局 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; widthItems *\t布局条目宽度 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; widthLabel *\tlabel 宽度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; createLayouts(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; widthItems, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; widthLabel) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 创建普通条目布局 * 如果 普通条目布局 为 null 或者 普通条目布局的宽度 大于 传入的宽度, 这时需要重新创建布局 * 如果 普通条目布局存在, 并且其宽度小于传入的宽度, 此时需要将 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (itemsLayout == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; || itemsLayout.getWidth() \u0026amp;gt; widthItems) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * android.text.StaticLayout.StaticLayout( * CharSequence source, TextPaint paint, * int width, Alignment align, * float spacingmult, float spacingadd, boolean includepad) * 传入参数介绍 : * CharSequence source : 需要分行显示的字符串 * TextPaint paint : 绘制字符串的画笔 * int width : 条目的宽度 * Alignment align : Layout 的对齐方式, ALIGN_CENTER 居中对齐, ALIGN_NORMAL 左对齐, Alignment.ALIGN_OPPOSITE 右对齐 * float spacingmult : 行间距, 1.5f 代表 1.5 倍字体高度 * float spacingadd : 基础行距上增加多少 , 真实行间距 等于 spacingmult 和 spacingadd 的和 * boolean includepad : */\u0026lt;/span\u0026gt; itemsLayout = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; StaticLayout(buildText(isScrollingPerformed), itemsPaint, widthItems, widthLabel \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt; ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;, ADDITIONAL_ITEM_HEIGHT, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//调用 Layout 内置的方法 increaseWidthTo 将宽度提升到指定的宽度\u0026lt;/span\u0026gt; itemsLayout.increaseWidthTo(widthItems); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 创建选中条目 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (!isScrollingPerformed \u0026amp;\u0026amp; (valueLayout == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; || valueLayout.getWidth() \u0026amp;gt; widthItems)) { String text = getAdapter() != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; ? getAdapter().getItem(currentItem) : \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; valueLayout = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; StaticLayout(text != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; ? text : \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;\u0026#34;\u0026lt;/span\u0026gt;, valuePaint, widthItems, widthLabel \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt; ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;, ADDITIONAL_ITEM_HEIGHT, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (isScrollingPerformed) { valueLayout = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { valueLayout.increaseWidthTo(widthItems); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 创建标签条目 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (widthLabel \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (labelLayout == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; || labelLayout.getWidth() \u0026amp;gt; widthLabel) { labelLayout = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; StaticLayout(label, valuePaint, widthLabel, Layout.Alignment.ALIGN_NORMAL, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;, ADDITIONAL_ITEM_HEIGHT, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { labelLayout.increaseWidthTo(widthLabel); } } } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 测量组件大小 * (non-Javadoc) * @see android.view.View#onMeasure(int, int) */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//获取宽度 和 高度的模式 和 大小\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; widthMode = MeasureSpec.getMode(widthMeasureSpec); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; heightMode = MeasureSpec.getMode(heightMeasureSpec); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; widthSize = MeasureSpec.getSize(widthMeasureSpec); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; heightSize = MeasureSpec.getSize(heightMeasureSpec); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//宽度就是 计算的布局的宽度\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; width = calculateLayoutWidth(widthSize, widthMode); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; height; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 精准模式 * 精准模式下 高度就是精确的高度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (heightMode == MeasureSpec.EXACTLY) { height = heightSize; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//未定义模式 和 最大模式\u0026lt;/span\u0026gt; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//未定义模式下 获取布局需要的高度\u0026lt;/span\u0026gt; height = getDesiredHeight(itemsLayout); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//最大模式下 获取 布局高度 和 布局所需高度的最小值\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (heightMode == MeasureSpec.AT_MOST) { height = Math.min(height, heightSize); } } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//设置组件的宽和高\u0026lt;/span\u0026gt; setMeasuredDimension(width, height); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 绘制组件 * (non-Javadoc) * @see android.view.View#onDraw(android.graphics.Canvas) */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;.onDraw(canvas); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果条目布局为 null, 就创建该布局\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (itemsLayout == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 如果 条目宽度为0, 说明该宽度没有计算, 先计算, 计算完之后会创建布局 * 如果 条目宽度 大于 0, 说明已经计算过宽度了, 直接创建布局 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (itemsWidth == \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { calculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//创建普通条目布局, 选中条目布局, 标签条目布局\u0026lt;/span\u0026gt; createLayouts(itemsWidth, labelWidth); } } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果条目宽度大于0\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (itemsWidth \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { canvas.save(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 使用平移方法忽略 填充的空间 和 顶部底部隐藏的一部份条目\u0026lt;/span\u0026gt; canvas.translate(PADDING, -ITEM_OFFSET); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//绘制普通条目\u0026lt;/span\u0026gt; drawItems(canvas); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//绘制选中条目\u0026lt;/span\u0026gt; drawValue(canvas); canvas.restore(); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//在中心位置绘制\u0026lt;/span\u0026gt; drawCenterRect(canvas); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//绘制阴影\u0026lt;/span\u0026gt; drawShadows(canvas); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * Draws shadows on top and bottom of control * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; canvas *\tthe canvas for drawing */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; drawShadows(Canvas canvas) { topShadow.setBounds(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, getWidth(), getHeight() / visibleItems); topShadow.draw(canvas); bottomShadow.setBounds(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, getHeight() - getHeight() / visibleItems, getWidth(), getHeight()); bottomShadow.draw(canvas); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 绘制选中条目 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; canvas *\t画布 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; drawValue(Canvas canvas) { valuePaint.setColor(VALUE_TEXT_COLOR); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//将当前 View 状态属性值 转为整型集合, 赋值给 普通条目布局的绘制属性\u0026lt;/span\u0026gt; valuePaint.drawableState = getDrawableState(); Rect bounds = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; Rect(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//获取选中条目布局的边界\u0026lt;/span\u0026gt; itemsLayout.getLineBounds(visibleItems / \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;, bounds); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 绘制标签\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (labelLayout != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { canvas.save(); canvas.translate(itemsLayout.getWidth() + LABEL_OFFSET, bounds.top); labelLayout.draw(canvas); canvas.restore(); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 绘制选中条目\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (valueLayout != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { canvas.save(); canvas.translate(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, bounds.top + scrollingOffset); valueLayout.draw(canvas); canvas.restore(); } } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 绘制普通条目 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; canvas *\t画布 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; drawItems(Canvas canvas) { canvas.save(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//获取 y 轴 定点高度\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; top = itemsLayout.getLineTop(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;); canvas.translate(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, -top + scrollingOffset); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//设置画笔颜色\u0026lt;/span\u0026gt; itemsPaint.setColor(ITEMS_TEXT_COLOR); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//将当前 View 状态属性值 转为整型集合, 赋值给 普通条目布局的绘制属性\u0026lt;/span\u0026gt; itemsPaint.drawableState = getDrawableState(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//将布局绘制到画布上\u0026lt;/span\u0026gt; itemsLayout.draw(canvas); canvas.restore(); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 绘制当前选中条目的背景图片 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; canvas *\t画布 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; drawCenterRect(Canvas canvas) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; center = getHeight() / \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; offset = getItemHeight() / \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;; centerDrawable.setBounds(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, center - offset, getWidth(), center + offset); centerDrawable.draw(canvas); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 继承自 View 的触摸事件, 当出现触摸事件的时候, 就会回调该方法 * (non-Javadoc) * @see android.view.View#onTouchEvent(android.view.MotionEvent) */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent event) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//获取适配器\u0026lt;/span\u0026gt; WheelAdapter adapter = getAdapter(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (adapter == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * gestureDetector.onTouchEvent(event) : 分析给定的动作, 如果可用, 调用 手势检测器的 onTouchEvent 方法 * -- 参数解析 : ev , 触摸事件 * -- 返回值 : 如果手势监听器成功执行了该方法, 返回true, 如果执行出现意外 返回 false; */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (!gestureDetector.onTouchEvent(event) \u0026amp;\u0026amp; event.getAction() == MotionEvent.ACTION_UP) { justify(); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 滚动 WheelView * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; delta *\t滚动的值 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; doScroll(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; delta) { scrollingOffset += delta; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//计算滚动的条目数, 使用滚动的值 处于 单个条目高度, 注意计算整数值\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; count = scrollingOffset / getItemHeight(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * pos 是滚动后的目标元素索引 * 计算当前位置, 当前条目数 减去 滚动的条目数 * 注意 滚动条目数可正 可负 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; pos = currentItem - count; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果是可循环的, 并且条目数大于0\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (isCyclic \u0026amp;\u0026amp; adapter.getItemsCount() \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//设置循环, 如果位置小于0, 那么该位置就显示最后一个元素\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;while\u0026lt;/span\u0026gt; (pos \u0026amp;lt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { pos += adapter.getItemsCount(); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果位置正无限大, 模条目数 取余\u0026lt;/span\u0026gt; pos %= adapter.getItemsCount(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// (前提 : 不可循环 条目数大于0, 可循环 条目数小于0, 条目数小于0, 不可循环) , 如果滚动在执行\u0026lt;/span\u0026gt; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (isScrollingPerformed) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//位置一旦小于0, 计算的位置就赋值为 0, 条目滚动数为0\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (pos \u0026amp;lt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { count = currentItem; pos = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//位置大于条目数的时候, 当前位置等于(条目数 - 1), 条目滚动数等于 当前位置 减去 (条目数 - 1)\u0026lt;/span\u0026gt; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (pos \u0026amp;gt;= adapter.getItemsCount()) { count = currentItem - adapter.getItemsCount() + \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;; pos = adapter.getItemsCount() - \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;; } } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// fix position\u0026lt;/span\u0026gt; pos = Math.max(pos, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;); pos = Math.min(pos, adapter.getItemsCount() - \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//滚动的高度\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; offset = scrollingOffset; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 如果当前位置不是滚动后的目标位置, 就将当前位置设置为目标位置 * 否则就重绘组件 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (pos != currentItem) { setCurrentItem(pos, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//重绘组件\u0026lt;/span\u0026gt; invalidate(); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 将滚动后剩余的小数部分保存\u0026lt;/span\u0026gt; scrollingOffset = offset - count * getItemHeight(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (scrollingOffset \u0026amp;gt; getHeight()) { scrollingOffset = scrollingOffset % getHeight() + getHeight(); } } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 手势监听器 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; SimpleOnGestureListener gestureListener = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; SimpleOnGestureListener() { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//按下操作\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onDown(MotionEvent e) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果滚动在执行\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (isScrollingPerformed) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//滚动强制停止, 按下的时候不能继续滚动\u0026lt;/span\u0026gt; scroller.forceFinished(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//清理信息\u0026lt;/span\u0026gt; clearMessages(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 手势监听器监听到 滚动操作后回调 * * 参数解析 : * MotionEvent e1 : 触发滚动时第一次按下的事件 * MotionEvent e2 : 触发当前滚动的移动事件 * float distanceX : 自从上一次调用 该方法 到这一次 x 轴滚动的距离, * 注意不是 e1 到 e2 的距离, e1 到 e2 的距离是从开始滚动到现在的滚动距离 * float distanceY : 自从上一次回调该方法到这一次 y 轴滚动的距离 * * 返回值 : 如果事件成功触发, 执行完了方法中的操作, 返回true, 否则返回 false * (non-Javadoc) * @see android.view.GestureDetector.SimpleOnGestureListener#onScroll(android.view.MotionEvent, android.view.MotionEvent, float, float) */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onScroll(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; distanceX, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; distanceY) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//开始滚动, 并回调滚动监听器集合中监听器的 开始滚动方法\u0026lt;/span\u0026gt; startScrolling(); doScroll((\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt;) -distanceY); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 当一个急冲手势发生后 回调该方法, 会计算出该手势在 x 轴 y 轴的速率 * * 参数解析 : * -- MotionEvent e1 : 急冲动作的第一次触摸事件; * -- MotionEvent e2 : 急冲动作的移动发生的时候的触摸事件; * -- float velocityX : x 轴的速率 * -- float velocityY : y 轴的速率 * * 返回值 : 如果执行完毕返回 true, 否则返回false, 这个就是自己定义的 * * (non-Javadoc) * @see android.view.GestureDetector.SimpleOnGestureListener#onFling(android.view.MotionEvent, android.view.MotionEvent, float, float) */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; velocityX, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//计算上一次的 y 轴位置, 当前的条目高度 加上 剩余的 不够一行高度的那部分\u0026lt;/span\u0026gt; lastScrollY = currentItem * getItemHeight() + scrollingOffset; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果可以循环最大值是无限大, 不能循环就是条目数的高度值\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; maxY = isCyclic ? \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;0x7FFFFFFF\u0026lt;/span\u0026gt; : adapter.getItemsCount() * getItemHeight(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; minY = isCyclic ? -maxY : \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * Scroll 开始根据一个急冲手势滚动, 滚动的距离与初速度有关 * 参数介绍 : * -- int startX : 开始时的 X轴位置 * -- int startY : 开始时的 y轴位置 * -- int velocityX : 急冲手势的 x 轴的初速度, 单位 px/s * -- int velocityY : 急冲手势的 y 轴的初速度, 单位 px/s * -- int minX : x 轴滚动的最小值 * -- int maxX : x 轴滚动的最大值 * -- int minY : y 轴滚动的最小值 * -- int maxY : y 轴滚动的最大值 */\u0026lt;/span\u0026gt; scroller.fling(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, lastScrollY, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt;) -velocityY / \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, minY, maxY); setNextMessage(MESSAGE_SCROLL); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } }; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// Handler 中的 Message 信息\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 滚动信息 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; MESSAGE_SCROLL = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 调整信息 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; MESSAGE_JUSTIFY = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 清空之前的 Handler 队列, 发送下一个消息到 Handler 中 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; message *\t要发送的消息 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; setNextMessage(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; message) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//清空 Handler 队列中的 what 消息\u0026lt;/span\u0026gt; clearMessages(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//发送消息到 Handler 中\u0026lt;/span\u0026gt; animationHandler.sendEmptyMessage(message); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 清空队列中的信息 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; clearMessages() { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//删除 Handler 执行队列中的滚动操作\u0026lt;/span\u0026gt; animationHandler.removeMessages(MESSAGE_SCROLL); animationHandler.removeMessages(MESSAGE_JUSTIFY); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 动画控制器 * animation handler * * 可能会造成内存泄露 : 添加注解 HandlerLeak * Handler 类应该应该为static类型，否则有可能造成泄露。 * 在程序消息队列中排队的消息保持了对目标Handler类的应用。 * 如果Handler是个内部类，那 么它也会保持它所在的外部类的引用。 * 为了避免泄露这个外部类，应该将Handler声明为static嵌套类，并且使用对外部类的弱应用。 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@SuppressLint\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;HandlerLeak\u0026#34;\u0026lt;/span\u0026gt;) \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; Handler animationHandler = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; Handler() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//回调该方法获取当前位置, 如果返回true, 说明动画还没有执行完毕\u0026lt;/span\u0026gt; scroller.computeScrollOffset(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//获取当前 y 位置\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; currY = scroller.getCurrY(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//获取已经滚动了的位置, 使用上一次位置 减去 当前位置\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; delta = lastScrollY - currY; lastScrollY = currY; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (delta != \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//改变值不为 0 , 继续滚动\u0026lt;/span\u0026gt; doScroll(delta); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 如果滚动到了指定的位置, 滚动还没有停止 * 这时需要强制停止 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (Math.abs(currY - scroller.getFinalY()) \u0026amp;lt; MIN_DELTA_FOR_SCROLLING) { currY = scroller.getFinalY(); scroller.forceFinished(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 如果滚动没有停止 * 再向 Handler 发送一个停止 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (!scroller.isFinished()) { animationHandler.sendEmptyMessage(msg.what); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (msg.what == MESSAGE_SCROLL) { justify(); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { finishScrolling(); } } }; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 调整 WheelView */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; justify() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (adapter == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//上一次的 y 轴的位置为 0\u0026lt;/span\u0026gt; lastScrollY = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; offset = scrollingOffset; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; itemHeight = getItemHeight(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 当滚动补偿 大于 0, 说明还有没有滚动的部分, needToIncrease 是 当前条目是否小于条目数 * 如果 滚动补偿不大于 0, needToIncrease 是当前条目是否大于 0 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; needToIncrease = offset \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt; ? currentItem \u0026amp;lt; adapter.getItemsCount() : currentItem \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; ((isCyclic || needToIncrease) \u0026amp;\u0026amp; Math.abs((\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt;) offset) \u0026amp;gt; (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt;) itemHeight / \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (offset \u0026amp;lt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) offset += itemHeight + MIN_DELTA_FOR_SCROLLING; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; offset -= itemHeight + MIN_DELTA_FOR_SCROLLING; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (Math.abs(offset) \u0026amp;gt; MIN_DELTA_FOR_SCROLLING) { scroller.startScroll(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, offset, SCROLLING_DURATION); setNextMessage(MESSAGE_JUSTIFY); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { finishScrolling(); } } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * WheelView 开始滚动 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; startScrolling() { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果没有滚动, 将滚动状态 isScrollingPerformed 设为 true\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (!isScrollingPerformed) { isScrollingPerformed = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//通知监听器开始滚动 回调所有的 滚动监听集合中 的 开始滚动方法\u0026lt;/span\u0026gt; notifyScrollingListenersAboutStart(); } } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 结束滚动 * 设置滚动状态为 false, 回调滚动监听器的停止滚动方法 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; finishScrolling() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (isScrollingPerformed) { notifyScrollingListenersAboutEnd(); isScrollingPerformed = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//设置布局无效\u0026lt;/span\u0026gt; invalidateLayouts(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//重绘布局\u0026lt;/span\u0026gt; invalidate(); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * 滚动 WheelView * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; itemsToSkip *\t滚动的元素个数 * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@param\u0026lt;/span\u0026gt; time *\t每次滚动的间隔 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; scroll(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; itemsToScroll, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; time) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//如果有滚动强制停止\u0026lt;/span\u0026gt; scroller.forceFinished(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); lastScrollY = scrollingOffset; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; offset = itemsToScroll * getItemHeight(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;/* * 给定 一个开始点, 滚动距离, 滚动间隔, 开始滚动 * * 参数解析 : * 1. 开始的 x 轴位置 * 2. 开始的 y 轴位置 * 3. 要滚动 x 轴距离 * 4. 要滚动 y 轴距离 * 5. 滚动花费的时间 */\u0026lt;/span\u0026gt; scroller.startScroll(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, lastScrollY, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;, offset - lastScrollY, time); setNextMessage(MESSAGE_SCROLL); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//设置开始滚动状态, 并回调滚动监听器方法\u0026lt;/span\u0026gt; startScrolling(); } } ## 7. Activity 主界面 ``` package cn.org.octopus.wheelview;\nimport android.app.Activity; import android.app.AlertDialog; import android.app.Fragment; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.widget.Button; import android.widget.LinearLayout; import cn.org.octopus.wheelview.widget.ArrayWheelAdapter; import cn.org.octopus.wheelview.widget.OnWheelChangedListener; import cn.org.octopus.wheelview.widget.OnWheelScrollListener; import cn.org.octopus.wheelview.widget.WheelView;\npublic class MainActivity extends Activity{\npublic static final String TAG = \u0026ldquo;octopus.activity\u0026rdquo;;\nprivate static Button bt_click;\npublic String province[] = new String[] { \u0026rdquo; 河北省 \u0026ldquo;, \u0026rdquo; 山西省 \u0026ldquo;, \u0026rdquo; 内蒙古 \u0026ldquo;, \u0026rdquo; 辽宁省 \u0026ldquo;, \u0026rdquo; 吉林省 \u0026ldquo;, \u0026rdquo; 黑龙江 \u0026ldquo;, \u0026rdquo; 江苏省 \u0026ldquo; };\npublic String city[][] = new String[][] { new String[] {\u0026rdquo; 石家庄 \u0026ldquo;, \u0026ldquo;唐山\u0026rdquo;, \u0026ldquo;秦皇岛\u0026rdquo;, \u0026ldquo;邯郸\u0026rdquo;, \u0026ldquo;邢台\u0026rdquo;, \u0026ldquo;保定\u0026rdquo;, \u0026ldquo;张家口\u0026rdquo;, \u0026ldquo;承德\u0026rdquo;, \u0026ldquo;沧州\u0026rdquo;, \u0026ldquo;廊坊\u0026rdquo;, \u0026ldquo;衡水\u0026rdquo;}, new String[] {\u0026ldquo;太原\u0026rdquo;, \u0026ldquo;大同\u0026rdquo;, \u0026ldquo;阳泉\u0026rdquo;, \u0026ldquo;长治\u0026rdquo;, \u0026ldquo;晋城\u0026rdquo;, \u0026ldquo;朔州\u0026rdquo;, \u0026ldquo;晋中\u0026rdquo;, \u0026ldquo;运城\u0026rdquo;, \u0026ldquo;忻州\u0026rdquo;, \u0026ldquo;临汾\u0026rdquo;, \u0026ldquo;吕梁\u0026rdquo;}, new String[] {\u0026ldquo;呼和浩特\u0026rdquo;, \u0026ldquo;包头\u0026rdquo;, \u0026ldquo;乌海\u0026rdquo;, \u0026ldquo;赤峰\u0026rdquo;, \u0026ldquo;通辽\u0026rdquo;, \u0026ldquo;鄂尔多斯\u0026rdquo;, \u0026ldquo;呼伦贝尔\u0026rdquo;, \u0026ldquo;巴彦淖尔\u0026rdquo;, \u0026ldquo;乌兰察布\u0026rdquo;, \u0026ldquo;兴安\u0026rdquo;, \u0026ldquo;锡林郭勒\u0026rdquo;, \u0026ldquo;阿拉善\u0026rdquo;}, new String[] {\u0026ldquo;沈阳\u0026rdquo;, \u0026ldquo;大连\u0026rdquo;, \u0026ldquo;鞍山\u0026rdquo;, \u0026ldquo;抚顺\u0026rdquo;, \u0026ldquo;本溪\u0026rdquo;, \u0026ldquo;丹东\u0026rdquo;, \u0026ldquo;锦州\u0026rdquo;, \u0026ldquo;营口\u0026rdquo;, \u0026ldquo;阜新\u0026rdquo;, \u0026ldquo;辽阳\u0026rdquo;, \u0026ldquo;盘锦\u0026rdquo;, \u0026ldquo;铁岭\u0026rdquo;, \u0026ldquo;朝阳\u0026rdquo;, \u0026ldquo;葫芦岛\u0026rdquo;}, new String[] {\u0026ldquo;长春\u0026rdquo;, \u0026ldquo;吉林\u0026rdquo;, \u0026ldquo;四平\u0026rdquo;, \u0026ldquo;辽源\u0026rdquo;, \u0026ldquo;通化\u0026rdquo;, \u0026ldquo;白山\u0026rdquo;, \u0026ldquo;松原\u0026rdquo;, \u0026ldquo;白城\u0026rdquo;, \u0026ldquo;延边\u0026rdquo;}, new String[] {\u0026ldquo;哈尔滨\u0026rdquo;, \u0026ldquo;齐齐哈尔\u0026rdquo;, \u0026ldquo;鸡西\u0026rdquo;, \u0026ldquo;鹤岗\u0026rdquo;, \u0026ldquo;双鸭山\u0026rdquo;, \u0026ldquo;大庆\u0026rdquo;, \u0026ldquo;伊春\u0026rdquo;, \u0026ldquo;佳木斯\u0026rdquo;, \u0026ldquo;七台河\u0026rdquo;, \u0026ldquo;牡丹江\u0026rdquo;, \u0026ldquo;黑河\u0026rdquo;, \u0026ldquo;绥化\u0026rdquo;, \u0026ldquo;大兴安岭\u0026rdquo;}, new String[] {\u0026ldquo;南京\u0026rdquo;, \u0026ldquo;无锡\u0026rdquo;, \u0026ldquo;徐州\u0026rdquo;, \u0026ldquo;常州\u0026rdquo;, \u0026ldquo;苏州\u0026rdquo;, \u0026ldquo;南通\u0026rdquo;, \u0026ldquo;连云港\u0026rdquo;, \u0026ldquo;淮安\u0026rdquo;, \u0026ldquo;盐城\u0026rdquo;, \u0026ldquo;扬州\u0026rdquo;, \u0026ldquo;镇江\u0026rdquo;, \u0026ldquo;泰州\u0026rdquo;, \u0026ldquo;宿迁\u0026rdquo;} };\n@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (savedInstanceState == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { getFragmentManager().beginTransaction() .add(R.id.container, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PlaceholderFragment()).commit(); } }\n/*\n点击事件 */ public void onClick(View view) { showSelectDialog(this, \u0026ldquo;选择地点\u0026rdquo;, province, city); } private void showSelectDialog(Context context, String title, final String[] left, final String[][] right) { //创建对话框 AlertDialog dialog = new AlertDialog.Builder(context).create(); //为对话框设置标题 dialog.setTitle(title); //创建对话框内容, 创建一个 LinearLayout LinearLayout llContent = new LinearLayout(context); //将创建的 LinearLayout 设置成横向的 llContent.setOrientation(LinearLayout.HORIZONTAL); //创建 WheelView 组件 final WheelView wheelLeft = new WheelView(context); //设置 WheelView 组件最多显示 5 个元素 wheelLeft.setVisibleItems(5); //设置 WheelView 元素是否循环滚动 wheelLeft.setCyclic(false); //设置 WheelView 适配器 wheelLeft.setAdapter(new ArrayWheelAdapter\u0026lt;String\u0026gt;(left)); //设置右侧的 WheelView final WheelView wheelRight = new WheelView(context); //设置右侧 WheelView 显示个数 wheelRight.setVisibleItems(5); //设置右侧 WheelView 元素是否循环滚动 wheelRight.setCyclic(true); //设置右侧 WheelView 的元素适配器 wheelRight.setAdapter(new ArrayWheelAdapter\u0026lt;String\u0026gt;(right[])); //设置 LinearLayout 的布局参数 LinearLayout.LayoutParams paramsLeft = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 4); paramsLeft.gravity = Gravity.LEFT; LinearLayout.LayoutParams paramsRight = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 6); paramsRight.gravity = Gravity.RIGHT; //将 WheelView 对象放到左侧 LinearLayout 中 llContent.addView(wheelLeft, paramsLeft); //将 WheelView 对象放到 右侧 LinearLayout 中 llContent.addView(wheelRight, paramsRight);\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//为左侧的 WheelView 设置条目改变监听器\u0026lt;/span\u0026gt; wheelLeft.addChangingListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnWheelChangedListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onChanged(WheelView wheel, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldValue, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; newValue) { \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置右侧的 WheelView 的适配器\u0026lt;/span\u0026gt; wheelRight.setAdapter(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayWheelAdapter\u0026amp;lt;String\u0026amp;gt;(right[newValue])); wheelRight.setCurrentItem(right[newValue].length / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); } }); wheelLeft.addScrollingListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnWheelScrollListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onScrollingStarted(WheelView wheel) { \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; } \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onScrollingFinished(WheelView wheel) { \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; } }); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置对话框点击事件 积极\u0026lt;/span\u0026gt; dialog.setButton(AlertDialog.BUTTON_POSITIVE, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;确定\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DialogInterface.OnClickListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(DialogInterface dialog, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; which) { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; leftPosition = wheelLeft.getCurrentItem(); String vLeft = left[leftPosition]; String vRight = right[leftPosition][wheelRight.getCurrentItem()]; bt_click.setText(vLeft + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;-\u0026quot;\u0026lt;/span\u0026gt; + vRight); dialog.dismiss(); } }); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置对话框点击事件 消极\u0026lt;/span\u0026gt; dialog.setButton(AlertDialog.BUTTON_NEGATIVE, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026quot;取消\u0026quot;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DialogInterface.OnClickListener() { \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(DialogInterface dialog, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; which) { dialog.dismiss(); } }); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将 LinearLayout 设置到 对话框中\u0026lt;/span\u0026gt; dialog.setView(llContent); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//显示对话框\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!dialog.isShowing()) { dialog.show(); } }\n@Override public boolean onCreateOptionsMenu(Menu menu) {\n\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Inflate the menu; this adds items to the action bar if it is present.\u0026lt;/span\u0026gt; getMenuInflater().inflate(R.menu.main, menu); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; }\n@Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); }\n/**\nA placeholder fragment containing a simple view. */ public static class PlaceholderFragment extends Fragment { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PlaceholderFragment() { } \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); bt_click = (Button)rootView.findViewById(R.id.bt_click); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; rootView; } }\n}\n**博客地址 **: [http://blog.csdn.net/shulianghan/article/details/41520569#t17](http://blog.csdn.net/shulianghan/article/details/41520569#t17) 代码下载 : \u0026amp;#8212; **GitHub **: [https://github.com/han1202012/WheelViewDemo.git](https://github.com/han1202012/WheelViewDemo.git) \u0026amp;#8212; **CSDN **: [http://download.csdn.net/detail/han1202012/8208997](http://download.csdn.net/detail/han1202012/8208997) ; \u0026lt;div\u0026gt; 代码下载 : \u0026amp;#8212; **GitHub **: [https://github.com/han1202012/WheelViewDemo.git](https://github.com/han1202012/WheelViewDemo.git) \u0026amp;#8212; **CSDN **: [http://download.csdn.net/detail/han1202012/8208997](http://download.csdn.net/detail/han1202012/8208997) ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **博客地址 **: [http://blog.csdn.net/shulianghan/article/details/41520569#t17](http://blog.csdn.net/shulianghan/article/details/41520569#t17) 代码下载 : \u0026amp;#8212; **GitHub **: [https://github.com/han1202012/WheelViewDemo.git](https://github.com/han1202012/WheelViewDemo.git) \u0026amp;#8212; **CSDN **: [http://download.csdn.net/detail/han1202012/8208997](http://download.csdn.net/detail/han1202012/8208997) ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **博客地址 **: [http://blog.csdn.net/shulianghan/article/details/41520569#t17](http://blog.csdn.net/shulianghan/article/details/41520569#t17) 代码下载 : \u0026amp;#8212; **GitHub **: [https://github.com/han1202012/WheelViewDemo.git](https://github.com/han1202012/WheelViewDemo.git) \u0026amp;#8212; **CSDN **: [http://download.csdn.net/detail/han1202012/8208997](http://download.csdn.net/detail/han1202012/8208997) ; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91-%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6-%E5%AE%BD%E9%AB%98%E9%80%82%E9%85%8D%E6%96%B9%E6%B3%95-%E6%89%8B%E5%8A%BF%E7%9B%91/","summary":"\u003cdiv class=\"article_meta\"\u003e\n  \u003cspan class=\"source\"\u003e  [http://blog.csdn.net/shulianghan/article/details/41520569](http://blog.csdn.net/shulianghan/article/details/41520569?utm_source=tuicool)\u003c/span\u003e\n\u003c/div\u003e\n\u003cdiv id=\"nei\" class=\"article_body\"\u003e\n  \u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e  **博客地址 **:  [http://blog.csdn.net/shulianghan/article/details/41520569](http://blog.csdn.net/shulianghan/article/details/41520569)\n\n\n\n\n\n  代码下载 :\n\n\n\n\n\n  \u0026amp;#8212; **GitHub **:  [https://github.com/han1202012/WheelViewDemo.git](https://github.com/han1202012/WheelViewDemo.git)\n\n\n\n\n\n  \u0026amp;#8212; **CSDN **:  [http://download.csdn.net/detail/han1202012/8208997](http://download.csdn.net/detail/han1202012/8208997) ;\n\n\n\n#### 博客总结 :\n\n\n\n  博文内容 : 本文完整地分析了 WheelView 所有的源码, 包括其 适配器类型 , 两种回调接口 ( 选中条目改变回调 , 和 开始结束滚动回调 ), 以及详细的分析了 WheelView 主题源码, 其中 组件宽高测量 , 手势监听器添加 , 以及 精准的绘图方法 是主要目的, 花了将近1周时间, 感觉很值, 在这里分享给大家;\n\n\n\n\n\n\n\n\n\n\n  自定义组件宽高获取策略 : MeasureSpec 最大模式 取 默认值 和 给定值中较小的那个 , 未定义模式取默认值 , 精准模式取 给定值 ;\n\n\n\n\n\n  自定义组件维护各种回调监听器策略 : 维护集合, 将监听器置于集合中, 回调接口时遍历集合元素, 回调每个元素的接口方法;\n\n\n\n\n\n  自定义组件手势监听器添加方法 : 创建手势监听器, 将手势监听器传入手势探测器, 在 onTouchEvent() 方法中回调手势监听器的 onTouchEvent()方法;\n\n\n\n## 一. WheelView 简介\n\n## 1. WheelView 效果\n\n\n\n  在 Android 中实现类似与 IOS 的 WheelView 控件 : 如图\n\n\n\n\n\n  ![](http://img2.tuicool.com/bMfU7b.png)\n\n\n\n## 2. WheelView 使用流程\n\n### (1) 基本流程简介\n\n\n\n\n\n\n\n\n  a. 创建 WheelView 组件 : 使用 构造方法 或者 从布局文件获取 WheelView 组件;\n\n\n\n\n\n  b. 设置显示条目数 : 调用 WheelView 组件对象的 setVisibleItems 方法 设置;\n\n\n\n\n\n  c. 设置是否循环 : 设置 WheelView 是否循环, 调用 setCyclic() 方法设置;\n\n\n\n\n\n  d. 设置适配器 : 调用 WheelView 组件的 setAdapter() 方法设置;\n\n\n\n\n\n  e. 设置条目改变监听器 : 调用 WheelView 组件对象的 addChangingListener() 方法设置;\n\n\n\n\n\n  f. 设置滚动监听器 : 调用 WheelView 组件对象的 addScrollingListener() 方法设置;\n\n\n\n### (2) 代码实例\n\n\n\n  a. 创建 WheelView 对象 :\n\n\n\n```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cspan class=\"comment\"\u003e//创建 WheelView 组件\u003c/span\u003e\n\u003cspan class=\"keyword\"\u003efinal\u003c/span\u003e WheelView wheelLeft = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e WheelView(context);\u003c/p\u003e","title":"【Android 应用开发】 自定义组件 宽高适配方法, 手势监听器操作组件, 回调接口维护策略, 绘制方法…"},{"content":"有图又真相，先上图再说。\n点击效果：\n设置虚线：\n**[html]** [view plain](http://blog.csdn.net/lan410812571/article/details/9946991#)[copy](http://blog.csdn.net/lan410812571/article/details/9946991#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/83373)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/83373/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:shape\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;line\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;stroke\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:dashGap\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;3dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:dashWidth\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;6dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:color\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#63a219\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;size\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1dp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 其中，破折线的宽度为dashWith，破折线之间的空隙的宽度为dashGap，当dashGap=0dp时，为实线\n设置圆角:\n**[html]** [view plain](http://blog.csdn.net/lan410812571/article/details/9946991#)[copy](http://blog.csdn.net/lan410812571/article/details/9946991#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/83373)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/83373/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:shape\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;rectangle\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;solid\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:color\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#FFFFFF\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;solid\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;stroke\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1dp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:color\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#63a219\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;stroke\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;corners\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:radius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10dp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 设置渐变填充和四个圆角半径：\n**[html]** [view plain](http://blog.csdn.net/lan410812571/article/details/9946991#)[copy](http://blog.csdn.net/lan410812571/article/details/9946991#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/83373)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/83373/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:shape\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;rectangle\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;corners\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:topLeftRadius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:topRightRadius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;7dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:bottomLeftRadius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:bottomRightRadius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;7dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;gradient\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:startColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#9cff00\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:endColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#197600\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:angle\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;270\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;stroke\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:color\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#63a219\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 设置渐变点击效果：\n**[html]** [view plain](http://blog.csdn.net/lan410812571/article/details/9946991#)[copy](http://blog.csdn.net/lan410812571/article/details/9946991#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/83373)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/83373/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;list_item_top\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:clickable\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;true\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:focusable\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;true\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:paddingTop\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;10dip\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:paddingBottom\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;10dip\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:paddingLeft\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;10dip\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:paddingRight\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;10dip\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:gravity\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;center_vertical\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:background\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;@drawable/background_view_rounded_top\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; **[html]** [view plain](http://blog.csdn.net/lan410812571/article/details/9946991#)[copy](http://blog.csdn.net/lan410812571/article/details/9946991#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/83373)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/83373/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;UTF-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;inset\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:insetLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0px\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:insetRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0px\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:state_pressed\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;gradient\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:angle\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;270.0\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:endColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@color/base_end_color_pressed\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:startColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@color/base_start_color_pressed\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;corners\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:bottomLeftRadius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:bottomRightRadius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:radius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;2.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:topLeftRadius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:topRightRadius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;stroke\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:color\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#eededede\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;gradient\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:angle\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;270.0\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:endColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@color/base_end_color_default\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:startColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@color/base_start_color_default\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;corners\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:bottomLeftRadius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:bottomRightRadius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:radius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;2.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:topLeftRadius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;11.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:topRightRadius\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;11.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;stroke\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:color\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#eededede\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;inset\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 重新补充：好久没有关注自己的博客，没有注意到各位的评论，关于4.0以上设备虚线会变实线的问题，下面几位仁兄已经给出了答案，\n代码中可以添加：\n**[java]** [view plain](http://blog.csdn.net/lan410812571/article/details/9946991#)[copy](http://blog.csdn.net/lan410812571/article/details/9946991#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/83373)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/83373/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - line.setLayerType(View.LAYER_TYPE_SOFTWARE, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); xml中可以添加：\n**[html]** [view plain](http://blog.csdn.net/lan410812571/article/details/9946991#)[copy](http://blog.csdn.net/lan410812571/article/details/9946991#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/83373)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/83373/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layerType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;software\u0026amp;#8221;\u0026lt;/span\u0026gt; 谢谢大家的参与！\n源码免费下载地址：免费下载\nhttp://download.csdn.net/detail/lan410812571/5925371\n转自：http://blog.csdn.net/lan410812571/article/details/9946991\n","permalink":"https://blog.zdltech.com/posts/android%E8%AE%BE%E7%BD%AE%E8%99%9A%E7%BA%BF%E5%9C%86%E8%A7%92%E6%B8%90%E5%8F%98/","summary":"\u003cp\u003e有图又真相，先上图再说。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20130813135445281?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuNDEwODEyNTcx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e点击效果：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20130813135610125?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuNDEwODEyNTcx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e设置虚线：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/lan410812571/article/details/9946991#)[copy](http://blog.csdn.net/lan410812571/article/details/9946991#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/83373)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/83373/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:shape\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;line\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;stroke\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:dashGap\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;3dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:dashWidth\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;6dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:color\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#63a219\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;size\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1dp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e其中，破折线的宽度为dashWith，破折线之间的空隙的宽度为dashGap，当dashGap=0dp时，为实线\u003c/p\u003e","title":"Android设置虚线、圆角、渐变"},{"content":" Android Studio 新建工程自动生成的 module 名为 app，尝试用 refactor-\u0026gt;rename 进行改变，发现会报错：failed to complete gradle execution already disposed:Module:app，百度居然又没有答案，google一下就有了，三个步骤： 1.refactor -\u0026gt; rename，先按常规修改这个； 2.修改 settings.gradle 中的模块名； 3.打开文件夹，修改文件夹名。 以上就完成了模块名的修改，最后不要忘了gradle同步一下\n","permalink":"https://blog.zdltech.com/posts/android-studio-%E4%BF%AE%E6%94%B9module%E5%90%8D/","summary":"\u003ch2 class=\"title\"\u003e\u003c/h2\u003e\n\u003cdiv class=\"text\"\u003e\n\u003cpre\u003e\u003ccode\u003eAndroid Studio 新建工程自动生成的 module 名为 app，尝试用 refactor-\u0026gt;rename 进行改变，发现会报错：failed to complete gradle execution already disposed:Module:app，百度居然又没有答案，google一下就有了，三个步骤：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e1.refactor -\u0026gt; rename，先按常规修改这个；\n2.修改 settings.gradle 中的模块名；\n3.打开文件夹，修改文件夹名。\n以上就完成了模块名的修改，最后不要忘了gradle同步一下\u003c/p\u003e\n\u003c/div\u003e","title":"Android Studio 修改module名"},{"content":"之前一直在windows下用source insight阅读android源码，效果非常好。\n后来远程异地服务器，网络限制，一直用ssh + vim，现在主要还是以这种方式。\n最近发现一个不错的东西（早就有了），在android源码中有这么一个目录development/tools/idegen。\n顾名思义，是生成ide的project文件，主要是生成intellij的project文件，当然也可用于android studio。\n使用之后，发现效果超棒，所以这里专门撰文推荐。\n1、效果图\n2、编译idegen模块\n源码要编过，不然idegen没法生成。\n提示：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `// 找不到idegen，需要全局编译一下` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `/*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `ubuntu:~/Data/cyanogenmod$ . development/tools/idegen/idegen.sh` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `Couldn't find idegen.jar. Please run make first.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `*/` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 但是我相信很多看源码的人是不需要编译的，所以只要我上传一个idegen.jar:\nhttp://jayfeng-files.stor.sinaapp.com/idegen.jar\n把这个文件copy到out/host/linux-x86/framework/目录下：\n1 \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `$ cp idegen.jar ../cyanogenmod/out/host/linux-x86/framework/idegen.jar` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 然后在cyanogenmod目录下执行：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `/*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `$ . development/tools/idegen/idegen.sh` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `Read excludes: 21ms` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `Traversed tree: 54700ms` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `*/` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 在我的电脑上花了54s多生成完毕，查看目录，多了2个文件：android.ipr和android.iml。\n3、导入到android studio\n打开Android studio，点击File \u0026gt; Open，选择刚刚生成的android.ipr就好了。\n过一会儿可以在android studio完美打开了，如前面的截图\n4、小结\n可以结合android studio，界面，智能提示都比source insight要好，超赞！\n转自：http://www.cnblogs.com/qianxudetianxia/p/3721202.html\n整个源码肯定分模块的，默认使用framework.jar没有源码，但是可以通过相应的模块attach source到当前源码的方式现实源码，比如阅读framework源码：\n这样再在framework中就可以再源码中跳转了\n","permalink":"https://blog.zdltech.com/posts/%E4%BD%BF%E7%94%A8android-studio%E9%98%85%E8%AF%BB%E6%95%B4%E4%B8%AAandroid%E6%BA%90%E7%A0%81/","summary":"\u003cp\u003e之前一直在windows下用source insight阅读android源码，效果非常好。\u003cbr\u003e\n后来远程异地服务器，网络限制，一直用ssh + vim，现在主要还是以这种方式。\u003cbr\u003e\n最近发现一个不错的东西（早就有了），在android源码中有这么一个目录development/tools/idegen。\u003cbr\u003e\n顾名思义，是生成ide的project文件，主要是生成intellij的project文件，当然也可用于android studio。\u003cbr\u003e\n使用之后，发现效果超棒，所以这里专门撰文推荐。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1、效果图\u003c/strong\u003e\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/i/31770/201405/102313274955502.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2、编译idegen模块\u003c/strong\u003e\u003cbr\u003e\n源码要编过，不然idegen没法生成。\u003cbr\u003e\n提示：\u003c/p\u003e\n\u003cdiv class=\"cnblogs_Highlighter sh-gutter\"\u003e\n  \u003cdiv\u003e\n    \u003cdiv id=\"highlighter_542160\" class=\"syntaxhighlighter  java\"\u003e\n      \u003ctable border=\"0\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n        \u003ctr\u003e\n          \u003ctd class=\"gutter\"\u003e\n            \u003cdiv class=\"line number1 index0 alt2\"\u003e\n              1\n            \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          2\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          3\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          4\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          5\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n          \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n            `// 找不到idegen，需要全局编译一下`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n            `/*`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n            `ubuntu:~/Data/cyanogenmod$ . development/tools/idegen/idegen.sh`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n            `Couldn't find idegen.jar. Please run make first.`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n            `*/`\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e但是我相信很多看源码的人是不需要编译的，所以只要我上传一个idegen.jar:\u003cbr\u003e\n\u003ca href=\"http://jayfeng-files.stor.sinaapp.com/idegen.jar\"\u003ehttp://jayfeng-files.stor.sinaapp.com/idegen.jar\u003c/a\u003e\u003cbr\u003e\n把这个文件copy到out/host/linux-x86/framework/目录下：\u003c/p\u003e","title":"使用Android Studio阅读整个Android源码"},{"content":"使用Canvas的drawText绘制文本是不会自动换行的，即使一个很长很长的字符串，drawText也只显示一行，超出部分被隐藏在屏幕之外。可以逐个计算每个字符的宽度，通过一定的算法将字符串分割成多个部分，然后分别调用drawText一部分一部分的显示， 但是这种显示效率会很低。\nStaticLayout是android中处理文字换行的一个工具类，StaticLayout已经实现了文本绘制换行处理，下面是如何使用StaticLayout的例子：\npackage com.example.amdroidstaticlayoutdemo;\nimport android.support.v4.app.Fragment;\nimport android.text.Layout.Alignment;\nimport android.text.StaticLayout;\nimport android.text.TextPaint;\nimport android.app.Activity;\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Paint.Style;\nimport android.os.Bundle;\nimport android.util.AttributeSet;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\nimport android.os.Build;\npublic class MainActivity extends Activity {\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\nsuper.onCreate(savedInstanceState);\nsetContentView(new MyView(this));\n}\npublic class MyView extends View {\nPaint mPaint; //画笔,包含了画几何图形、文本等的样式和颜色信息\npublic MyView(Context context) {\nsuper(context);\n}\npublic MyView(Context context, AttributeSet attrs){\nsuper(context, attrs);\n}\npublic void onDraw(Canvas canvas){\nsuper.onDraw(canvas);\nTextPaint tp = new TextPaint();\ntp.setColor(Color.BLUE);\ntp.setStyle(Style.FILL);\ntp.setTextSize(50);\nString message = “paint,draw paint指用颜色画,如油画颜料、水彩或者水墨画,而draw 通常指用铅笔、钢笔或者粉笔画,后者一般并不涂上颜料。两动词的相应名词分别为p”;\nStaticLayout myStaticLayout = new StaticLayout(message, tp, canvas.getWidth(), Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);\nmyStaticLayout.draw(canvas);\ncanvas.restore();\n}\n}\n}\n这跟TextView的效果是一样的，其实TextView也是调用**StaticLayout**来实现换行的。 StaticLayout的构造函数有三个：\npublic StaticLayout(CharSequence source, TextPaint paint, int width, Layout.Alignment align, float spacingmult, float spacingadd, boolean includepad) public StaticLayout(CharSequence source, int bufstart, int bufend, TextPaint paint, int outerwidth, Layout.Alignment align, float spacingmult, float spacingadd, boolean includepad)\npublic StaticLayout(CharSequence source, int bufstart, int bufend, TextPaint paint, int outerwidth, Layout.Alignment align, float spacingmult, float spacingadd, boolean includepad, TextUtils.TruncateAt ellipsize, int ellipsizedWidth)\nandroid StaticLayout参数解释\nStaticLayout(CharSequence source, int bufstart, int bufend,\nTextPaint paint, int outerwidth,\nAlignment align,\nfloat spacingmult, float spacingadd,\nboolean includepad,\nTextUtils.TruncateAt ellipsize, int ellipsizedWidth)\n1.需要分行的字符串\n2.需要分行的字符串从第几的位置开始\n3.需要分行的字符串到哪里结束\n4.画笔对象\n5.layout的宽度，字符串超出宽度时自动换行。\n6.layout的对其方式，有ALIGN_CENTER， ALIGN_NORMAL， ALIGN_OPPOSITE 三种。\n7.相对行间距，相对字体大小，1.5f表示行间距为1.5倍的字体高度。\n8.在基础行距上添加多少\n实际行间距等于这两者的和。\n9.参数未知\n10.从什么位置开始省略\n11.超过多少开始省略\n需要指出的是这个layout是默认画在Canvas的(0,0)点的，如果需要调整位置只能在draw之前移Canvas的起始坐标\ncanvas.translate(x,y);\n","permalink":"https://blog.zdltech.com/posts/android-staticlayout%E4%BD%BF%E7%94%A8%E8%AE%B2%E8%A7%A3/","summary":"\u003cp\u003e使用Canvas的drawText绘制文本是不会自动换行的，即使一个很长很长的字符串，drawText也只显示一行，超出部分被隐藏在屏幕之外。可以逐个计算每个字符的宽度，通过一定的算法将字符串分割成多个部分，然后分别调用drawText一部分一部分的显示， 但是这种显示效率会很低。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eStaticLayout\u003c/strong\u003e是android中处理文字换行的一个工具类，\u003cstrong\u003eStaticLayout\u003c/strong\u003e已经实现了文本绘制换行处理，下面是如何使用\u003cstrong\u003eStaticLayout\u003c/strong\u003e的例子：\u003c/p\u003e\n\u003cp\u003epackage com.example.amdroidstaticlayoutdemo;\u003cbr\u003e\nimport android.support.v4.app.Fragment;\u003cbr\u003e\nimport android.text.Layout.Alignment;\u003cbr\u003e\nimport android.text.StaticLayout;\u003cbr\u003e\nimport android.text.TextPaint;\u003cbr\u003e\nimport android.app.Activity;\u003cbr\u003e\nimport android.content.Context;\u003cbr\u003e\nimport android.graphics.Canvas;\u003cbr\u003e\nimport android.graphics.Color;\u003cbr\u003e\nimport android.graphics.Paint;\u003cbr\u003e\nimport android.graphics.Paint.Style;\u003cbr\u003e\nimport android.os.Bundle;\u003cbr\u003e\nimport android.util.AttributeSet;\u003cbr\u003e\nimport android.view.LayoutInflater;\u003cbr\u003e\nimport android.view.Menu;\u003cbr\u003e\nimport android.view.MenuItem;\u003cbr\u003e\nimport android.view.View;\u003cbr\u003e\nimport android.view.ViewGroup;\u003cbr\u003e\nimport android.widget.TextView;\u003cbr\u003e\nimport android.os.Build;\u003cbr\u003e\npublic class MainActivity extends Activity {\u003cbr\u003e\n@Override\u003cbr\u003e\nprotected void onCreate(Bundle savedInstanceState) {\u003cbr\u003e\nsuper.onCreate(savedInstanceState);\u003cbr\u003e\nsetContentView(new MyView(this));\u003cbr\u003e\n}\u003cbr\u003e\npublic class MyView extends View {\u003c/p\u003e\n\u003cp\u003ePaint mPaint; //画笔,包含了画几何图形、文本等的样式和颜色信息\u003cbr\u003e\npublic MyView(Context context) {\u003cbr\u003e\nsuper(context);\u003cbr\u003e\n}\u003c/p\u003e","title":"android staticlayout使用讲解"},{"content":"android:interpolator\nInterpolator 被用来修饰动画效果，定义动画的变化率，可以使存在的动画效果accelerated(加速)，decelerated(减速),repeated(重复),bounced(弹跳)等。\nandroid中的文档内容如下：\n![](http://img.blog.csdn.net/20131117161350500?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFzb24wNTM5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) AccelerateDecelerateInterpolator 在动画开始与结束的地方速率改变比较慢，在中间的时候加速 AccelerateInterpolator 在动画开始的地方速率改变比较慢，然后开始加速 AnticipateInterpolator 开始的时候向后然后向前甩 AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值 BounceInterpolator 动画结束的时候弹起 CycleInterpolator 动画循环播放特定的次数，速率改变沿着正弦曲线 DecelerateInterpolator 在动画开始的地方快然后慢 LinearInterpolator 以常量速率改变 OvershootInterpolator 向前甩一定值后再回到原来位置 如果android定义的interpolators不符合你的效果也可以自定义interpolators \u0026amp;nbsp; Android中的Interpolator nterpolator用于动画中的时间插值，其作用就是把0到1的浮点值变化映射到另一个浮点值变化。 本文列出Android API提供的Interpolator的若干种实现，列出源码，并且用一个程序绘制出其数学曲线。（项目链接附在文后）。 AccelerateDecelerateInterpolator ![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` /**\nAn interpolator where the rate of change starts and ends slowly but accelerates through the middle. */ public class AccelerateDecelerateInterpolator implements Interpolator { public AccelerateDecelerateInterpolator() { }\n@SuppressWarnings({\u0026quot;UnusedDeclaration\u0026quot;}) public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) { } public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; } }\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; ![](http://images.cnitblog.com/blog/325852/201309/29162553-398804596d514dd795c2f19539148ca2.png) \u0026amp;nbsp; ## AccelerateInterpolator \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ``` /** * An interpolator where the rate of change starts out slowly and * and then accelerates. * */ public class AccelerateInterpolator implements Interpolator { private final float mFactor; private final double mDoubleFactor; public AccelerateInterpolator() { mFactor = 1.0f; mDoubleFactor = 2.0; } /** * Constructor * * @param factor Degree to which the animation should be eased. Seting * factor to 1.0f produces a y=x^2 parabola. Increasing factor above * 1.0f exaggerates the ease-in effect (i.e., it starts even * slower and ends evens faster) */ public AccelerateInterpolator(float factor) { mFactor = factor; mDoubleFactor = 2 * mFactor; } public AccelerateInterpolator(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AccelerateInterpolator); mFactor = a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor, 1.0f); mDoubleFactor = 2 * mFactor; a.recycle(); } public float getInterpolation(float input) { if (mFactor == 1.0f) { return input * input; } else { return (float)Math.pow(input, mDoubleFactor); } } } \u0026lt;div class=\u0026quot;cnblogs_code_toolbar\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_copy\u0026quot;\u0026gt;\u0026lt;a title=\u0026quot;复制代码\u0026quot;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; ![](http://images.cnitblog.com/blog/325852/201309/29162735-9d46b2da759e4b668a5209557b6ee115.png) AnticipateInterpolator ![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` /**\nAn interpolator where the change starts backward then flings forward. */ public class AnticipateInterpolator implements Interpolator { private final float mTension;\npublic AnticipateInterpolator() { mTension = 2.0f; }\n/**\n@param tension Amount of anticipation. When tension equals 0.0f, there is no anticipation and the interpolator becomes a simple acceleration interpolator. */ public AnticipateInterpolator(float tension) { mTension = tension; }\npublic AnticipateInterpolator(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AnticipateInterpolator);\nmTension = a.getFloat(com.android.internal.R.styleable.AnticipateInterpolator_tension, 2.0f); a.recycle(); }\npublic float getInterpolation(float t) { // a(t) = t * t * ((tension + 1) * t - tension) return t * t * ((mTension + 1) * t - mTension); } }\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ![](http://images.cnitblog.com/blog/325852/201309/29162936-630167d6b6514c6c9fb8f8446b5cd251.png) \u0026amp;nbsp; \u0026amp;nbsp; ## AnticipateOvershootInterpolator \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ``` /** * An interpolator where the change starts backward then flings forward and overshoots * the target value and finally goes back to the final value. */ public class AnticipateOvershootInterpolator implements Interpolator { private final float mTension; public AnticipateOvershootInterpolator() { mTension = 2.0f * 1.5f; } /** * @param tension Amount of anticipation/overshoot. When tension equals 0.0f, * there is no anticipation/overshoot and the interpolator becomes * a simple acceleration/deceleration interpolator. */ public AnticipateOvershootInterpolator(float tension) { mTension = tension * 1.5f; } /** * @param tension Amount of anticipation/overshoot. When tension equals 0.0f, * there is no anticipation/overshoot and the interpolator becomes * a simple acceleration/deceleration interpolator. * @param extraTension Amount by which to multiply the tension. For instance, * to get the same overshoot as an OvershootInterpolator with * a tension of 2.0f, you would use an extraTension of 1.5f. */ public AnticipateOvershootInterpolator(float tension, float extraTension) { mTension = tension * extraTension; } public AnticipateOvershootInterpolator(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator); mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) * a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f); a.recycle(); } private static float a(float t, float s) { return t * t * ((s + 1) * t - s); } private static float o(float t, float s) { return t * t * ((s + 1) * t + s); } public float getInterpolation(float t) { // a(t, s) = t * t * ((s + 1) * t - s) // o(t, s) = t * t * ((s + 1) * t + s) // f(t) = 0.5 * a(t * 2, tension * extraTension), when t \u0026amp;lt; 0.5 // f(t) = 0.5 * (o(t * 2 - 2, tension * extraTension) + 2), when t \u0026amp;lt;= 1.0 if (t \u0026amp;lt; 0.5f) return 0.5f * a(t * 2.0f, mTension); else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f); } } \u0026lt;div class=\u0026quot;cnblogs_code_toolbar\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_copy\u0026quot;\u0026gt;\u0026lt;a title=\u0026quot;复制代码\u0026quot;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ![](http://images.cnitblog.com/blog/325852/201309/29163126-ca9aa8f0018e46ec839430f3c818a0e8.png) BounceInterpolator ![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` /**\nAn interpolator where the change bounces at the end. */ public class BounceInterpolator implements Interpolator { public BounceInterpolator() { }\n@SuppressWarnings({\u0026ldquo;UnusedDeclaration\u0026rdquo;}) public BounceInterpolator(Context context, AttributeSet attrs) { }\nprivate static float bounce(float t) { return t * t * 8.0f; }\npublic float getInterpolation(float t) { // _b(t) = t * t * 8 // bs(t) = _b(t) for t \u0026lt; 0.3535 // bs(t) = _b(t - 0.54719) + 0.7 for t \u0026lt; 0.7408 // bs(t) = _b(t - 0.8526) + 0.9 for t \u0026lt; 0.9644 // bs(t) = _b(t - 1.0435) + 0.95 for t \u0026lt;= 1.0 // b(t) = bs(t * 1.1226) t *= 1.1226f; if (t \u0026lt; 0.3535f) return bounce(t); else if (t \u0026lt; 0.7408f) return bounce(t - 0.54719f) + 0.7f; else if (t \u0026lt; 0.9644f) return bounce(t - 0.8526f) + 0.9f; else return bounce(t - 1.0435f) + 0.95f; } }\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; ![](http://images.cnitblog.com/blog/325852/201309/29163251-7079b1bb27c844aa8d007e6899688c2b.png) ## CycleInterpolator \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ``` /** * Repeats the animation for a specified number of cycles. The * rate of change follows a sinusoidal pattern. * */ public class CycleInterpolator implements Interpolator { public CycleInterpolator(float cycles) { mCycles = cycles; } public CycleInterpolator(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.CycleInterpolator); mCycles = a.getFloat(com.android.internal.R.styleable.CycleInterpolator_cycles, 1.0f); a.recycle(); } public float getInterpolation(float input) { return (float)(Math.sin(2 * mCycles * Math.PI * input)); } private float mCycles; } \u0026lt;div class=\u0026quot;cnblogs_code_toolbar\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_copy\u0026quot;\u0026gt;\u0026lt;a title=\u0026quot;复制代码\u0026quot;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; 参数为2时的曲线： ![](http://images.cnitblog.com/blog/325852/201309/29163456-495a2721492946f4a4d894443491e4d6.png) \u0026amp;nbsp; DecelerateInterpolator ![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` /**\nAn interpolator where the rate of change starts out quickly and and then decelerates. */ public class DecelerateInterpolator implements Interpolator { public DecelerateInterpolator() { }\n/** * Constructor * * @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces * an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the * ease-out effect (i.e., it starts even faster and ends evens slower) */ public DecelerateInterpolator(float factor) { mFactor = factor; } public DecelerateInterpolator(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.DecelerateInterpolator); mFactor = a.getFloat(com.android.internal.R.styleable.DecelerateInterpolator_factor, 1.0f); a.recycle(); } public float getInterpolation(float input) { float result; if (mFactor == 1.0f) { result = (float)(1.0f - (1.0f - input) * (1.0f - input)); } else { result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor)); } return result; } private float mFactor = 1.0f; }\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; ![](http://images.cnitblog.com/blog/325852/201309/29163621-d9ecec56e54a4416a3cbed447f36379b.png) ## LinearInterpolator \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ``` /** * An interpolator where the rate of change is constant * */ public class LinearInterpolator implements Interpolator { public LinearInterpolator() { } public LinearInterpolator(Context context, AttributeSet attrs) { } public float getInterpolation(float input) { return input; } } \u0026lt;div class=\u0026quot;cnblogs_code_toolbar\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_copy\u0026quot;\u0026gt;\u0026lt;a title=\u0026quot;复制代码\u0026quot;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; ![](http://images.cnitblog.com/blog/325852/201309/29163734-b31e9a2dcf84435288ba9188ca81c05a.png) OvershootInterpolator ![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` /**\nAn interpolator where the change flings forward and overshoots the last value\nthen comes back. */ public class OvershootInterpolator implements Interpolator { private final float mTension;\npublic OvershootInterpolator() { mTension = 2.0f; }\n/**\n@param tension Amount of overshoot. When tension equals 0.0f, there is no overshoot and the interpolator becomes a simple deceleration interpolator. */ public OvershootInterpolator(float tension) { mTension = tension; }\npublic OvershootInterpolator(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.OvershootInterpolator);\nmTension = a.getFloat(com.android.internal.R.styleable.OvershootInterpolator_tension, 2.0f); a.recycle(); }\npublic float getInterpolation(float t) { // _o(t) = t * t * ((tension + 1) * t + tension) // o(t) = _o(t - 1) + 1 t -= 1.0f; return t * t * ((mTension + 1) * t + mTension) + 1.0f; } }\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; ![](http://images.cnitblog.com/blog/325852/201309/29163839-66d3e2c296814c20848807cd05ae63f1.png) \u0026amp;nbsp; ## 项目链接： [https://github.com/mengdd/HelloInterpolator.git](https://github.com/mengdd/HelloInterpolator.git) ","permalink":"https://blog.zdltech.com/posts/android%E4%B9%8Binterpolator%E7%9A%84%E7%94%A8%E6%B3%95%E8%AF%A6%E8%A7%A3/","summary":"\u003cp\u003e\u003cstrong\u003eandroid:interpolator\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eInterpolator 被用来修饰动画效果，定义动画的变化率，可以使存在的动画效果accelerated(加速)，decelerated(减速),repeated(重复),bounced(弹跳)等。\u003c/p\u003e\n\u003cp\u003eandroid中的文档内容如下：\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e![](http://img.blog.csdn.net/20131117161350500?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFzb24wNTM5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\n\n\n\n\nAccelerateDecelerateInterpolator 在动画开始与结束的地方速率改变比较慢，在中间的时候加速\n\n\n\n\n\nAccelerateInterpolator  在动画开始的地方速率改变比较慢，然后开始加速\n\n\n\n\n\nAnticipateInterpolator 开始的时候向后然后向前甩\n\n\n\n\n\nAnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值\n\n\n\n\n\nBounceInterpolator   动画结束的时候弹起\n\n\n\n\n\nCycleInterpolator 动画循环播放特定的次数，速率改变沿着正弦曲线\n\n\n\n\n\nDecelerateInterpolator 在动画开始的地方快然后慢\n\n\n\n\n\nLinearInterpolator   以常量速率改变\n\n\n\n\n\nOvershootInterpolator    向前甩一定值后再回到原来位置\n\n\n\n\n\n如果android定义的interpolators不符合你的效果也可以自定义interpolators\n\n\n\n\n\n\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch1 id=\"android中的interpolator\"\u003eAndroid中的Interpolator\u003c/h1\u003e\n\u003cpre\u003e\u003ccode\u003enterpolator用于动画中的时间插值，其作用就是把0到1的浮点值变化映射到另一个浮点值变化。\n\n\n\n\n\n本文列出Android API提供的Interpolator的若干种实现，列出源码，并且用一个程序绘制出其数学曲线。（项目链接附在文后）。\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2\u003e\u003c/h2\u003e\n\u003ch2 id=\"acceleratedecelerateinterpolator\"\u003eAccelerateDecelerateInterpolator\u003c/h2\u003e\n  \u003cdiv class=\"cnblogs_code\"\u003e\n    \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n      \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAn interpolator where the rate of change starts and ends slowly but\u003c/li\u003e\n\u003cli\u003eaccelerates through the middle.\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e*/\npublic class AccelerateDecelerateInterpolator implements Interpolator {\npublic AccelerateDecelerateInterpolator() {\n}\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e@SuppressWarnings({\u0026quot;UnusedDeclaration\u0026quot;})\npublic AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {\n}\n\npublic float getInterpolation(float input) {\n    return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e}\u003c/p\u003e","title":"android之interpolator的用法详解"},{"content":"一、概述 当用户触摸屏幕的时候，会产生许多手势，例如down，up，scroll，filing等等。\n一般情况下，我们知道View类有个View.OnTouchListener内部接口，通过重写他的onTouch(View v, MotionEvent event)方法，我们可以处理一些touch事件，但是这个方法太过简单，如果需要处理一些复杂的手势，用这个接口就会很麻烦（因为我们要自己根据用户触摸的轨迹去判断是什么手势）。\nAndroid sdk给我们提供了GestureDetector（Gesture：手势Detector：识别）类，通过这个类我们可以识别很多的手势，主要是通过他的onTouchEvent(event)方法完成了不同手势的识别。虽然他能识别手势，但是不同的手势要怎么处理，应该是提供给程序员实现的。\nGestureDetector这个类对外提供了两个接口和一个外部类\n接口：OnGestureListener，OnDoubleTapListener\n内部类:SimpleOnGestureListener\n这个外部类，其实是两个接口中所有函数的集成，它包含了这两个接口里所有必须要实现的函数而且都已经重写，但所有方法体都是空的；不同点在于：该类是static class，程序员可以在外部继承这个类，重写里面的手势处理方法。\n下面我们先看OnGestureListener接口；\n二、GestureDetector.OnGestureListener—接口 1、基本讲解 如果我们写一个类并implements OnGestureListener，会提示有几个必须重写的函数，加上之后是这个样子的：\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; gesturelistener \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; GestureDetector.OnGestureListener{ - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDown(MotionEvent e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onShowPress(MotionEvent e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onSingleTapUp(MotionEvent e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onScroll(MotionEvent e1, MotionEvent e2, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceY) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLongPress(MotionEvent e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityX, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - } 可见，这里总共重写了六个函数，这些函数都在什么情况下才会触发呢，下面讲一下：\n**OnDown(MotionEvent e)：**用户按下屏幕就会触发；\n**onShowPress(MotionEvent e)：**如果是按下的时间超过瞬间，而且在按下的时候没有松开或者是拖动的，那么onShowPress就会执行，具体这个瞬间是多久，我也不清楚呃……\n**onLongPress(MotionEvent e)：**长按触摸屏，超过一定时长，就会触发这个事件\n触发顺序：\nonDown-\u0026gt;onShowPress-\u0026gt;onLongPress\n**onSingleTapUp(MotionEvent e)：**从名子也可以看出,一次单独的轻击抬起操作,也就是轻击一下屏幕，立刻抬起来，才会有这个触发，当然,如果除了Down以外还有其它操作,那就不再算是Single操作了,所以也就不会触发这个事件\n触发顺序：\n点击一下非常快的（不滑动）Touchup：\nonDown-\u0026gt;onSingleTapUp-\u0026gt;onSingleTapConfirmed\n点击一下稍微慢点的（不滑动）Touchup：\nonDown-\u0026gt;onShowPress-\u0026gt;onSingleTapUp-\u0026gt;onSingleTapConfirmed\n**onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) ：**滑屏，用户按下触摸屏、快速移动后松开，由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发\n参数解释：\ne1：第1个ACTION_DOWN MotionEvent\ne2：最后一个ACTION_MOVE MotionEvent\nvelocityX：X轴上的移动速度，像素/秒\nvelocityY：Y轴上的移动速度，像素/秒\n**onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY)：**在屏幕上拖动事件。无论是用手拖动view，或者是以抛的动作滚动，都会多次触发,这个方法 在ACTION_MOVE动作发生时就会触发\n滑屏：手指触动屏幕后，稍微滑动后立即松开\n拖动\nonDown——》onScroll—-》onScroll——》onFiling\n可见，无论是滑屏，还是拖动，影响的只是中间OnScroll触发的数量多少而已，最终都会触发onFling事件！\n2、实例 要使用GestureDetector，有三步要走：\n1、创建OnGestureListener监听函数：\n可以使用构造实例：\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - GestureDetector.OnGestureListener listener = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector.OnGestureListener(){ - - }; 也可以构造类：\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; gestureListener \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; GestureDetector.OnGestureListener{ - - } 2、创建GestureDetector实例mGestureDetector：\n构造函数有下面三个，根据需要选择：\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - GestureDetector gestureDetector=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(GestureDetector.OnGestureListener listener); - GestureDetector gestureDetector=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(Context context,GestureDetector.OnGestureListener listener); - GestureDetector gestureDetector=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(Context context,GestureDetector.SimpleOnGestureListener listener); 3、onTouch(View v, MotionEvent event)中拦截：\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mGestureDetector.onTouchEvent(event); - } 4、控件绑定\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - TextView tv = (TextView)findViewById(R.id.tv); - tv.setOnTouchListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); 现在进入实例阶段：\n首先，在主布局页面添加一个textView，并将其放大到整屏，方便在其上的手势识别，代码为：\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;RelativeLayout xmlns:android=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - xmlns:tools=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - tools:context=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.example.gesturedetectorinterface.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; - - \u0026lt;TextView - android:id=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@+id/tv\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_margin=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;50dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:background=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;#ff00ff\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:text=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@string/hello_world\u0026amp;#8221;\u0026lt;/span\u0026gt; /\u0026gt; - - \u0026lt;/RelativeLayout\u0026gt; 然后在JAVA代码中，依据上面的三步走原则，写出代码，并在所有的手势下添加上Toast提示并写上Log\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnTouchListener{ - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GestureDetector mGestureDetector; - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - mGestureDetector = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; gestureListener()); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//使用派生自OnGestureListener\u0026lt;/span\u0026gt; - - TextView tv = (TextView)findViewById(R.id.tv); - tv.setOnTouchListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - tv.setFocusable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - tv.setClickable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - tv.setLongClickable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 在onTouch()方法中，我们调用GestureDetector的onTouchEvent()方法，将捕捉到的MotionEvent交给GestureDetector \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 来分析是否有合适的callback函数来处理用户的手势 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mGestureDetector.onTouchEvent(event); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; gestureListener \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; GestureDetector.OnGestureListener{ - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 用户轻触触摸屏，由1个MotionEvent ACTION_DOWN触发 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDown(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDown\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDown\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 用户轻触触摸屏，尚未松开或拖动，由一个1个MotionEvent ACTION_DOWN触发 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 注意和onDown()的区别，强调的是没有松开或者拖动的状态 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 而onDown也是由一个MotionEventACTION_DOWN触发的，但是他没有任何限制，\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 也就是说当用户点击的时候，首先MotionEventACTION_DOWN，onDown就会执行，\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 如果在按下的瞬间没有松开或者是拖动的时候onShowPress就会执行，如果是按下的时间超过瞬间\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * （这块我也不太清楚瞬间的时间差是多少，一般情况下都会执行onShowPress），拖动了，就不执行onShowPress。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onShowPress(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onShowPress\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onShowPress\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 用户（轻触触摸屏后）松开，由一个1个MotionEvent ACTION_UP触发 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;///轻击一下屏幕，立刻抬起来，才会有这个触发\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//从名子也可以看出,一次单独的轻击抬起操作,当然,如果除了Down以外还有其它操作,那就不再算是Single操作了,所以这个事件 就不再响应\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onSingleTapUp(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSingleTapUp\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSingleTapUp\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 用户按下触摸屏，并拖动，由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onScroll(MotionEvent e1, MotionEvent e2, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceY) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture22\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onScroll:\u0026amp;#8221;\u0026lt;/span\u0026gt;+(e2.getX()-e1.getX()) +\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; \u0026amp;#8220;\u0026lt;/span\u0026gt;+distanceX); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onScroll\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG).show(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 用户长按触摸屏，由多个MotionEvent ACTION_DOWN触发 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLongPress(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onLongPress\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onLongPress\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG).show(); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 用户按下触摸屏、快速移动后松开，由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityX, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onFling\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onFling\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - }; - - - } 源码在博客底部给出。\n三、GestureDetector.OnDoubleTapListener—接口 1、构建 有两种方式设置双击监听：\n方法一：新建一个类同时派生自OnGestureListener和OnDoubleTapListener：\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; gestureListener \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; GestureDetector.OnGestureListener,GestureDetector.OnDoubleTapListener{ - } 方法二：使用GestureDetector::setOnDoubleTapListener();函数设置监听：\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_10\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_10\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//构建GestureDetector实例 \u0026lt;/span\u0026gt; - mGestureDetector = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; gestureListener()); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//使用派生自OnGestureListener\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; gestureListener \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; GestureDetector.OnGestureListener{ - - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置双击监听器\u0026lt;/span\u0026gt; - mGestureDetector.setOnDoubleTapListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; doubleTapListener()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; doubleTapListener \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; GestureDetector.OnDoubleTapListener{ - - } 注意：大家可以看到无论在方法一还是在方法二中，都需要派生自GestureDetector.OnGestureListener，前面我们说过GestureDetector 的构造函数，如下：\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_11\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_11\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - GestureDetector gestureDetector=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(GestureDetector.OnGestureListener listener); - GestureDetector gestureDetector=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(Context context,GestureDetector.OnGestureListener listener); - GestureDetector gestureDetector=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(Context context,GestureDetector.SimpleOnGestureListener listener); 可以看到，在构造函数中，除了后面要讲的SimpleOnGestureListener 以外的其它两个构造函数都必须是OnGestureListener的实例。所以要想使用OnDoubleTapListener的几个函数，就必须先实现OnGestureListener。\n2、函数讲解： 首先看一下OnDoubleTapListener接口必须重写的三个函数：\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_12\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_12\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; doubleTapListener \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; GestureDetector.OnDoubleTapListener{ - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onSingleTapConfirmed(MotionEvent e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDoubleTap(MotionEvent e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDoubleTapEvent(MotionEvent e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } **onSingleTapConfirmed(MotionEvent e)：**单击事件。用来判定该次点击是SingleTap而不是DoubleTap，如果连续点击两次就是DoubleTap手势，如果只点击一次，系统等待一段时间后没有收到第二次点击则判定该次点击为SingleTap而不是DoubleTap，然后触发SingleTapConfirmed事件。触发顺序是：OnDown-\u0026gt;OnsingleTapUp-\u0026gt;OnsingleTapConfirmed\n关于onSingleTapConfirmed和onSingleTapUp的一点区别： OnGestureListener有这样的一个方法onSingleTapUp，和onSingleTapConfirmed容易混淆。二者的区别是：onSingleTapUp，只要手抬起就会执行，而对于onSingleTapConfirmed来说，如果双击的话，则onSingleTapConfirmed不会执行。\n**onDoubleTap(MotionEvent e)：**双击事件\n**onDoubleTapEvent(MotionEvent e)：**双击间隔中发生的动作。指触发onDoubleTap以后，在双击之间发生的其它动作，包含down、up和move事件；下图是双击一下的Log输出：\n两点总结：\n1、从上图可以看出，在第二下点击时，先触发OnDoubleTap，然后再触发OnDown（第二次点击）\n2、其次在触发OnDoubleTap以后，就开始触发onDoubleTapEvent了，onDoubleTapEvent后面的数字代表了当前的事件，0指ACTION_DOWN，1指ACTION_UP，2 指ACTION_MOVE\n在上一个例子的基础上，我们再添加一个双击监听类，实现如下：\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_13\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_13\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnTouchListener{ - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GestureDetector mGestureDetector; - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - - mGestureDetector = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; gestureListener()); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//使用派生自OnGestureListener\u0026lt;/span\u0026gt; - mGestureDetector.setOnDoubleTapListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; doubleTapListener()); - - TextView tv = (TextView)findViewById(R.id.tv); - tv.setOnTouchListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - tv.setFocusable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - tv.setClickable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - tv.setLongClickable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 在onTouch()方法中，我们调用GestureDetector的onTouchEvent()方法，将捕捉到的MotionEvent交给GestureDetector \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 来分析是否有合适的callback函数来处理用户的手势 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mGestureDetector.onTouchEvent(event); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//OnGestureListener监听\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; gestureListener \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; GestureDetector.OnGestureListener{ - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDown(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDown\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDown\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onShowPress(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onShowPress\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onShowPress\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onSingleTapUp(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSingleTapUp\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSingleTapUp\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onScroll(MotionEvent e1, MotionEvent e2, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceY) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture22\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onScroll:\u0026amp;#8221;\u0026lt;/span\u0026gt;+(e2.getX()-e1.getX()) +\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; \u0026amp;#8220;\u0026lt;/span\u0026gt;+distanceX); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onScroll\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG).show(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLongPress(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onLongPress\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onLongPress\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG).show(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityX, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onFling\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onFling\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - }; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//OnDoubleTapListener监听\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; doubleTapListener \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; GestureDetector.OnDoubleTapListener{ - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onSingleTapConfirmed(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSingleTapConfirmed\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSingleTapConfirmed\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDoubleTap(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDoubleTap\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDoubleTap\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDoubleTapEvent(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDoubleTapEvent\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDoubleTapEvent\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - }; - } 双击一下，部分截图如下：\n双击所对应的触发事件顺序：\n轻轻单击一下，对应的事件触发顺序为：\n源码在博客底部给出。\n四、GestureDetector.SimpleOnGestureListener—类 它与前两个不同的是：\n1、这是一个类，在它基础上新建类的话，要用extends派生而不是用implements继承！\n2、OnGestureListener和OnDoubleTapListener接口里的函数都是强制必须重写的，即使用不到也要重写出来一个空函数但在SimpleOnGestureListener类的实例或派生类中不必如此，可以根据情况，用到哪个函数就重写哪个函数，因为SimpleOnGestureListener类本身已经实现了这两个接口的所有函数，只是里面全是空的而已。\n下面利用SimpleOnGestureListener类来重新实现上面的几个效果，代码如下：\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_14\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_14\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnTouchListener { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GestureDetector mGestureDetector; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - mGestureDetector = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; simpleGestureListener()); - - TextView tv = (TextView)findViewById(R.id.tv); - tv.setOnTouchListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - tv.setFocusable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - tv.setClickable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - tv.setLongClickable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mGestureDetector.onTouchEvent(event); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; simpleGestureListener \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; - GestureDetector.SimpleOnGestureListener { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*****OnGestureListener的函数*****/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDown(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDown\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDown\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT) - .show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onShowPress(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onShowPress\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onShowPress\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT) - .show(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onSingleTapUp(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSingleTapUp\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSingleTapUp\u0026amp;#8221;\u0026lt;/span\u0026gt;, - Toast.LENGTH_SHORT).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onScroll(MotionEvent e1, MotionEvent e2, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceY) { - + distanceX); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onScroll\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG) - .show(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLongPress(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onLongPress\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onLongPress\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG) - .show(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityX, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onFling\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onFling\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG) - .show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*****OnDoubleTapListener的函数*****/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onSingleTapConfirmed(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSingleTapConfirmed\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSingleTapConfirmed\u0026amp;#8221;\u0026lt;/span\u0026gt;, - Toast.LENGTH_LONG).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDoubleTap(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDoubleTap\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDoubleTap\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG) - .show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDoubleTapEvent(MotionEvent e) { - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDoubleTapEvent\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDoubleTapEvent\u0026amp;#8221;\u0026lt;/span\u0026gt;, - Toast.LENGTH_LONG).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - } - } 到此，有关GestureDetector的所有基础知识都讲解完了，下面给出一个小应用——识别用户是向左滑还是向右滑！\n源码在博客底部给出。\n五、OnFling应用——识别向左滑还是向右滑 这部分就有点意思了，可以说是上面知识的一个小应用，我们利用OnFling函数来识别当前用户是在向左滑还是向右滑，从而打出日志。先看下OnFling的参数：\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_15\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityX,\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) - 参数解释： - e1：第\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;个ACTION_DOWN MotionEvent - e2：最后一个ACTION_MOVE MotionEvent - velocityX：X轴上的移动速度，像素/秒 - velocityY：Y轴上的移动速度，像素/秒 首先，先说一下实现的功能：当用户向左滑动距离超过100px，且滑动速度超过100 px/s时,即判断为向左滑动;向右同理.代码如下:\n**[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_16\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_16\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnTouchListener { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GestureDetector mGestureDetector; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - mGestureDetector = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; simpleGestureListener()); - - TextView tv = (TextView)findViewById(R.id.tv); - tv.setOnTouchListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - tv.setFocusable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - tv.setClickable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - tv.setLongClickable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mGestureDetector.onTouchEvent(event); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; simpleGestureListener \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; - GestureDetector.SimpleOnGestureListener { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*****OnGestureListener的函数*****/\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; FLING_MIN_DISTANCE = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;, FLING_MIN_VELOCITY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 触发条件 ： \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// X轴的坐标位移大于FLING_MIN_DISTANCE，且移动速度大于FLING_MIN_VELOCITY个像素/秒 \u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 参数解释： \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// e1：第1个ACTION_DOWN MotionEvent \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// e2：最后一个ACTION_MOVE MotionEvent \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// velocityX：X轴上的移动速度，像素/秒 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// velocityY：Y轴上的移动速度，像素/秒 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityX, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) { - - - \u0026amp;\u0026amp; Math.abs(velocityX) \u0026gt; FLING_MIN_VELOCITY) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Fling left \u0026lt;/span\u0026gt; - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Fling left\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Fling Left\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - \u0026amp;\u0026amp; Math.abs(velocityX) \u0026gt; FLING_MIN_VELOCITY) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Fling right \u0026lt;/span\u0026gt; - Log.i(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MyGesture\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Fling right\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Fling Right\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - } - } 这段代码难度不大,就不再细讲,看下效果:\n源码在博客底部给出。\n源码地址：http://download.csdn.net/detail/harvic880925/7978943\n**转载：http://blog.csdn.net/harvic880925/article/details/39520901 **\n","permalink":"https://blog.zdltech.com/posts/%E7%94%A8%E6%88%B7%E6%89%8B%E5%8A%BF%E6%A3%80%E6%B5%8B-gesturedetector%E4%BD%BF%E7%94%A8%E8%AF%A6%E8%A7%A3/","summary":"\u003ch2 id=\"一概述\"\u003e一、概述\u003c/h2\u003e\n\u003cp\u003e当用户触摸屏幕的时候，会产生许多手势，例如down，up，scroll，filing等等。\u003cbr\u003e\n一般情况下，我们知道View类有个View.OnTouchListener内部接口，通过重写他的onTouch(View v, MotionEvent event)方法，我们可以处理一些touch事件，但是这个方法太过简单，如果需要处理一些复杂的手势，用这个接口就会很麻烦（因为我们要自己根据用户触摸的轨迹去判断是什么手势）。\u003cbr\u003e\nAndroid sdk给我们提供了GestureDetector（Gesture：手势Detector：识别）类，通过这个类我们可以识别很多的手势，主要是通过他的onTouchEvent(event)方法完成了不同手势的识别。虽然他能识别手势，但是不同的手势要怎么处理，应该是提供给程序员实现的。\u003c/p\u003e\n\u003cp\u003eGestureDetector这个类对外提供了两个接口和一个外部类\u003cbr\u003e\n接口：OnGestureListener，OnDoubleTapListener\u003cbr\u003e\n内部类:SimpleOnGestureListener\u003c/p\u003e\n\u003cp\u003e这个外部类，其实是两个接口中所有函数的集成，它包含了这两个接口里所有必须要实现的函数而且都已经重写，但所有方法体都是空的；不同点在于：该类是static class，程序员可以在外部继承这个类，重写里面的手势处理方法。\u003c/p\u003e\n\u003cp\u003e下面我们先看OnGestureListener接口；\u003c/p\u003e\n\u003ch2 id=\"二gesturedetectorongesturelistener8212接口\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e二、GestureDetector.OnGestureListener—接口\u003c/h2\u003e\n\u003ch3 id=\"1基本讲解\"\u003e\u003ca name=\"t2\"\u003e\u003c/a\u003e1、基本讲解\u003c/h3\u003e\n\u003cp\u003e如果我们写一个类并implements OnGestureListener，会提示有几个必须重写的函数，加上之后是这个样子的：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/harvic880925/article/details/39520901#)[copy](http://blog.csdn.net/harvic880925/article/details/39520901#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/475851)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/475851/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; gesturelistener \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; GestureDetector.OnGestureListener{\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDown(MotionEvent e) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onShowPress(MotionEvent e) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- \n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onSingleTapUp(MotionEvent e) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onScroll(MotionEvent e1, MotionEvent e2,\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceY) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLongPress(MotionEvent e) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- \n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityX,\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e可见，这里总共重写了六个函数，这些函数都在什么情况下才会触发呢，下面讲一下：\u003c/p\u003e","title":"用户手势检测-GestureDetector使用详解"},{"content":"Android里Scroller类是为了实现View平滑滚动的一个Helper类。通常在自定义的View时使用，在View中定义一个私有成员mScroller = new Scroller(context)。设置mScroller滚动的位置时，并不会导致View的滚动，通常是用mScroller记录/计算View滚动的位置，再重写View的computeScroll()，完成实际的滚动。\n相关API介绍如下\nJava代码 \u0026lt;embed src=\u0026quot;http://ipjmc.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;a title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://ipjmc.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; - mScroller.getCurrX() \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取mScroller当前水平滚动的位置\u0026lt;/span\u0026gt; - mScroller.getCurrY() \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取mScroller当前竖直滚动的位置\u0026lt;/span\u0026gt; - mScroller.getFinalX() \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取mScroller最终停止的水平位置\u0026lt;/span\u0026gt; - mScroller.getFinalY() \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取mScroller最终停止的竖直位置\u0026lt;/span\u0026gt; - mScroller.setFinalX(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; newX) \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置mScroller最终停留的水平位置，没有动画效果，直接跳到目标位置\u0026lt;/span\u0026gt; - mScroller.setFinalY(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; newY) \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置mScroller最终停留的竖直位置，没有动画效果，直接跳到目标位置\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//滚动，startX, startY为开始滚动的位置，dx,dy为滚动的偏移量, duration为完成滚动的时间\u0026lt;/span\u0026gt; - mScroller.startScroll(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startY, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dy) \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//使用默认完成时间250ms\u0026lt;/span\u0026gt; - mScroller.startScroll(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startY, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dy, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; duration) - - mScroller.computeScrollOffset() \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//返回值为boolean，true说明滚动尚未完成，false说明滚动已经完成。这是一个很重要的方法，通常放在View.computeScroll()中，用来判断是否滚动是否结束。\u0026lt;/span\u0026gt; 举例说明，自定义一个CustomView，使用Scroller实现滚动：\nJava代码 \u0026lt;embed src=\u0026quot;http://ipjmc.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;a title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://ipjmc.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Scroller; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; CustomView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Scroller\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Scroller mScroller; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; CustomView(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - mScroller = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Scroller(context); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用此方法滚动到目标位置\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; smoothScrollTo(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; fx, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; fy) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx = fx \u0026amp;#8211; mScroller.getFinalX(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dy = fy \u0026amp;#8211; mScroller.getFinalY(); - smoothScrollBy(dx, dy); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用此方法设置滚动的相对偏移\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; smoothScrollBy(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dy) { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置mScroller的滚动偏移量\u0026lt;/span\u0026gt; - mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy); - invalidate();\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//这里必须调用invalidate()才能保证computeScroll()会被调用，否则不一定会刷新界面，看不到滚动效果\u0026lt;/span\u0026gt; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll() { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//先判断mScroller滚动是否完成\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mScroller.computeScrollOffset()) { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//这里调用View的scrollTo()完成实际的滚动\u0026lt;/span\u0026gt; - scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//必须调用该方法，否则不一定能看到滚动效果\u0026lt;/span\u0026gt; - postInvalidate(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.computeScroll(); - } - } - 转自：http://ipjmc.iteye.com/blog/1615828 \u0026amp;nbsp; public class CustomView extends LinearLayout { private static final String TAG = CustomView.class.getName(); // 定义一个滑动 private Scroller mScroller; //手势 private GestureDetector mGestureDetector;\npublic CustomView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mScroller = new Scroller(context); mGestureDetector = new GestureDetector(context, new CustomGestureListener()); }\npublic CustomView(Context context, AttributeSet attrs) { super(context, attrs); mScroller = new Scroller(context); mGestureDetector = new GestureDetector(context, new CustomGestureListener()); }\npublic CustomView(Context context) { super(context); mScroller = new Scroller(context); mGestureDetector = new GestureDetector(context, new CustomGestureListener()); // setClickable(true); // setLongClickable(true); }\n// 调用此方法滚动到目标位置 public void smoothScrollTo(int fx, int fy) { int dx = fx – mScroller.getFinalX(); int dy = fy – mScroller.getFinalY(); smoothScrollBy(dx, dy); }\n// 调用此方法设置滚动的相对偏移 public void smoothScrollBy(int dx, int dy) { // 设置mScroller的滚动偏移量 mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy); invalidate();// 这里必须调用invalidate()才能保证computeScroll()会被调用，否则不一定会刷新界面，看不到滚动效果 }\n/** 完成实际的滚动 */ @Override public void computeScroll() { // 判断Scroll是否滚动完成 if (mScroller.computeScrollOffset()) { // 调用View 的scrollto完成实际的滚动 scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); //必须调用该方法，否则不一定能看到滚动效果 postInvalidate(); } super.computeScroll(); }\n@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP : Log.e(TAG, “get Sy” + getScrollY()); smoothScrollTo(0, 0); break; default: return mGestureDetector.onTouchEvent(event); } return super.onTouchEvent(event); }\nclass CustomGestureListener implements GestureDetector.OnGestureListener {\n@Override public boolean onDown(MotionEvent e) { // TODO Auto-generated method stub return true; }\n@Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub\n}\n@Override public boolean onSingleTapUp(MotionEvent e) { // TODO Auto-generated method stub return false; }\n@Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {\nint dis = (int)((distanceY-0.5)/2); Log.e(TAG, dis + “.”); smoothScrollBy(0, dis); return false; }\n@Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub\n}\n@Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // TODO Auto-generated method stub return false; }\n} }\nandroid 使用Scroller实现缓慢移动\n转载请声明:http://bbs.niuzhi.cc/thread-24-1-1.html\n在Launcher中的Workspace中实现了左右屏幕切换效果，里面就用到了Scroller记录滑动轨迹，实现一种缓慢地向左或向右移动的效果，这里我对这种效果进行总结:\n我们先看一个例子:点击按钮时红经块会从左边缓慢地移向左右，这个该怎么实现呢\n我们先来看一下，Scroller，这个对象里有startScroll方法\nvoid android.widget.Scroller.startScroll(int startX, int startY, int dx, int dy, int duration) 第一个参数是起始移动的x坐标值，第二个是起始移动的y坐标值，第三个第四个参数都是移到某点的坐标值，而**duration **当然就是执行移动的时间。这个有什么用呢。要知道有什么用还得再看一个方法\nboolean android.widget.[Scroller](http://blog.csdn.net/c_weibin/article/details/7438323).computeScrollOffset() 当startScroll执行过程中即在duration时间内，**computeScrollOffset **方法会一直返回false，但当动画执行完成后会返回返加true. 有了这两个方法还不够，我们还需要再重写viewGroup的一个方法， **computeScroll 这个方法什么时候会被调用呢** **官网上这样说的** public void computeScroll () Since: [API Level 1](http://developer.android.com/guide/appendix/api-levels.html#level1) Called by a parent to request that a child update its values for mScrollX and mScrollY if necessary. This will typically be done if the child is animating a scroll using a `\u0026amp;lt;a href=\u0026quot;http://developer.android.com/reference/android/widget/Scroller.html\u0026quot;\u0026gt;Scroller\u0026amp;lt;/a\u0026gt;` object. \u0026lt;/div\u0026gt; 当我们执行ontouch或invalidate(）或postInvalidate()都会导致这个方法的执行 **所以我们像下面这样调用，**postInvalidate执行后，会去调**computeScroll 方法，而这个方法里再去调\u0026lt;strong\u0026gt;postInvalidate，这样******就可以不断地去调用scrollTo方法了，直到mScroller动画结束，当然第一次时，我们需要手动去调用一次**postInvalidate才会去调用 **\u0026lt;/strong\u0026gt; computeScroll 方法 **[java]** [view plain](http://blog.csdn.net/c_weibin/article/details/7438323#)[copy](http://blog.csdn.net/c_weibin/article/details/7438323#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mScroller.computeScrollOffset()) { - scrollTo(mScroller.getCurrX(), \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - postInvalidate(); - } - } 下面附上上面那个例子的源代码 首先是MyViewGroup.java **[java]** [view plain](http://blog.csdn.net/c_weibin/article/details/7438323#)[copy](http://blog.csdn.net/c_weibin/article/details/7438323#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.wb; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Scroller; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyViewGroup \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; s1=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - Scroller mScroller=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyViewGroup(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - mScroller=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Scroller(context); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated constructor stub\u0026lt;/span\u0026gt; - } - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mScroller.computeScrollOffset()) { - scrollTo(mScroller.getCurrX(), \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - postInvalidate(); - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; beginScroll(){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!s1) { - mScroller.startScroll(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); - s1 = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - mScroller.startScroll(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); - s1 = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - invalidate(); - } - } 然后是WheelActivity.java **[java]** [view plain](http://blog.csdn.net/c_weibin/article/details/7438323#)[copy](http://blog.csdn.net/c_weibin/article/details/7438323#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.wb; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Color; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Gravity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AbsListView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AbsListView.LayoutParams; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AbsListView.OnScrollListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Adapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.BaseAdapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; WheelActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ListView listView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyViewGroup myViewGroup; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.main); - myViewGroup = (MyViewGroup) findViewById(R.id.myviewGroup); - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scroll(View view) { - - myViewGroup.beginScroll(); - - } - - } main.xml **[html]** [view plain](http://blog.csdn.net/c_weibin/article/details/7438323#)[copy](http://blog.csdn.net/c_weibin/article/details/7438323#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;scroll\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;scroll\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.wb.MyViewGroup\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/myviewGroup\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#ff0000\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;我在這\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.wb.MyViewGroup\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 源代码下载地址：[http://download.csdn.net/detail/c_weibin/4208751](http://download.csdn.net/detail/c_weibin/4208751) ","permalink":"https://blog.zdltech.com/posts/android-scroller%E7%AE%80%E5%8D%95%E7%94%A8%E6%B3%95/","summary":"\u003cp\u003eAndroid里Scroller类是为了实现View平滑滚动的一个Helper类。通常在自定义的View时使用，在View中定义一个私有成员mScroller = new Scroller(context)。设置mScroller滚动的位置时，并不会导致View的滚动，通常是用mScroller记录/计算View滚动的位置，再重写View的computeScroll()，完成实际的滚动。\u003c/p\u003e\n\u003cp\u003e相关API介绍如下\u003c/p\u003e\n\u003cdiv id=\"\" class=\"dp-highlighter\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      Java代码 \n\u003cpre\u003e\u003ccode\u003e  \u0026lt;embed src=\u0026quot;http://ipjmc.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt;\n  \u0026lt;/embed\u0026gt; \n  \n  \u0026lt;a title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://ipjmc.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- mScroller.getCurrX() \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取mScroller当前水平滚动的位置\u0026lt;/span\u0026gt;\n\n- mScroller.getCurrY() \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取mScroller当前竖直滚动的位置\u0026lt;/span\u0026gt;\n\n- mScroller.getFinalX() \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取mScroller最终停止的水平位置\u0026lt;/span\u0026gt;\n\n- mScroller.getFinalY() \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取mScroller最终停止的竖直位置\u0026lt;/span\u0026gt;\n\n- mScroller.setFinalX(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; newX) \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置mScroller最终停留的水平位置，没有动画效果，直接跳到目标位置\u0026lt;/span\u0026gt;\n\n- mScroller.setFinalY(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; newY) \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置mScroller最终停留的竖直位置，没有动画效果，直接跳到目标位置\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//滚动，startX, startY为开始滚动的位置，dx,dy为滚动的偏移量, duration为完成滚动的时间\u0026lt;/span\u0026gt;\n\n- mScroller.startScroll(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startY, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dy) \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//使用默认完成时间250ms\u0026lt;/span\u0026gt;\n\n- mScroller.startScroll(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startY, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dy, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; duration)\n\n- \n- mScroller.computeScrollOffset() \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//返回值为boolean，true说明滚动尚未完成，false说明滚动已经完成。这是一个很重要的方法，通常放在View.computeScroll()中，用来判断是否滚动是否结束。\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e举例说明，自定义一个CustomView，使用Scroller实现滚动：\u003c/p\u003e","title":"Android Scroller简单用法"},{"content":" 最近在做一个从图库选择图片或拍照,然后裁剪的功能.本来是没问题的,一直在用\n**[java]** [view plain](http://blog.csdn.net/tempersitu/article/details/20557383#)[copy](http://blog.csdn.net/tempersitu/article/details/20557383#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219069)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219069/fork) - Intent intent=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); 的方式来做,是调用系统图库来做,但是发现如果有图片是同步到google相册的话,图库里面能看到一个auto backup的目录,点进去选图片的话是无法获取到图片的路径的.因为那些图片根本就不存在于手机上.然后看到无论是百度贴吧,Instagram,或者还有些会选取图片做修改的app,都是用一个很漂亮的图片选择器(4.4以上,4.3的还是用系统旧的图库).\n而这个图片选择器可以屏蔽掉那个auto backup的目录.所以就开始打算用这个图片选择器来选图片了.\n这个方法就是\n**[java]** [view plain](http://blog.csdn.net/tempersitu/article/details/20557383#)[copy](http://blog.csdn.net/tempersitu/article/details/20557383#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219069)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219069/fork) - Intent intent=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(Intent.ACTION_GET_CONTENT);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//ACTION_OPEN_DOCUMENT\u0026lt;/span\u0026gt; - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;image/jpeg\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(android.os.Build.VERSION.SDK_INT\u0026gt;=android.os.Build.VERSION_CODES.KITKAT){ - startActivityForResult(intent, SELECT_PIC_KITKAT); - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - startActivityForResult(intent, SELECT_PIC); - } 为什么要分开不同版本呢?其实在4.3或以下可以直接用ACTION_GET_CONTENT的,在4.4或以上,官方建议用ACTION_OPEN_DOCUMENT,但其实都不算太大区别,区别是他们返回的Uri,那个才叫大区别.这就是困扰了我一整天的问题所在了.\n4.3或以下,选了图片之后,根据Uri来做处理,很多帖子都有了,我就不详细说了.主要是4.4,如果使用上面pick的原生方法来选图,返回的uri还是正常的,但如果用ACTION_GET_CONTENT的方法,返回的uri跟4.3是完全不一样的,4.3返回的是带文件路径的,而4.4返回的却是content://com.android.providers.media.documents/document/image:3951这样的,没有路径,只有图片编号的uri.这就导致接下来无法根据图片路径来裁剪的步骤了.\n还好找了很多方法,包括加权限啊什么的,中间还试过用一些方法,自己的app没崩溃,倒是让系统图库崩溃了,引发了java.lang.SecurityException.\n**[java]** [view plain](http://blog.csdn.net/tempersitu/article/details/20557383#)[copy](http://blog.csdn.net/tempersitu/article/details/20557383#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219069)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219069/fork) - Caused by: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{437b5d88 \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;9494\u0026lt;/span\u0026gt;:com.google.android.gallery3d/u0a20} (pid=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;9494\u0026lt;/span\u0026gt;, uid=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10020\u0026lt;/span\u0026gt;) requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS 看来4.4的系统还是有些bug.重点来了,4.4得到的uri,需要以下方法来获取文件的路径\n**[java]** [view plain](http://blog.csdn.net/tempersitu/article/details/20557383#)[copy](http://blog.csdn.net/tempersitu/article/details/20557383#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219069)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219069/fork) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String getPath(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Context context, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Uri uri) { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isKitKat = Build.VERSION.SDK_INT \u0026gt;= Build.VERSION_CODES.KITKAT; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// DocumentProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isKitKat \u0026amp;\u0026amp; DocumentsContract.isDocumentUri(context, uri)) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// ExternalStorageProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isExternalStorageDocument(uri)) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String docId = DocumentsContract.getDocumentId(uri); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String[] split = docId.split(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;:\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String type = split[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;primary\u0026amp;#8221;\u0026lt;/span\u0026gt;.equalsIgnoreCase(type)) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; Environment.getExternalStorageDirectory() + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;/\u0026amp;#8221;\u0026lt;/span\u0026gt; + split[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO handle non-primary volumes\u0026lt;/span\u0026gt; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// DownloadsProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isDownloadsDocument(uri)) { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String id = DocumentsContract.getDocumentId(uri); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Uri contentUri = ContentUris.withAppendedId( - Uri.parse(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;content://downloads/public_downloads\u0026amp;#8221;\u0026lt;/span\u0026gt;), Long.valueOf(id)); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; getDataColumn(context, contentUri, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// MediaProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isMediaDocument(uri)) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String docId = DocumentsContract.getDocumentId(uri); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String[] split = docId.split(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;:\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String type = split[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - - Uri contentUri = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;image\u0026amp;#8221;\u0026lt;/span\u0026gt;.equals(type)) { - contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;video\u0026amp;#8221;\u0026lt;/span\u0026gt;.equals(type)) { - contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;audio\u0026amp;#8221;\u0026lt;/span\u0026gt;.equals(type)) { - contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String selection = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;_id=?\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String[] selectionArgs = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; String[] { - split[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;] - }; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; getDataColumn(context, contentUri, selection, selectionArgs); - } - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// MediaStore (and general)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;content\u0026amp;#8221;\u0026lt;/span\u0026gt;.equalsIgnoreCase(uri.getScheme())) { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Return the remote address\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isGooglePhotosUri(uri)) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; uri.getLastPathSegment(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; getDataColumn(context, uri, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// File\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;file\u0026amp;#8221;\u0026lt;/span\u0026gt;.equalsIgnoreCase(uri.getScheme())) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; uri.getPath(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Get the value of the data column for this Uri. This is useful for\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * MediaStore Uris, and other file-based ContentProviders.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context The context.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param uri The Uri to query.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param selection (Optional) Filter used in the query.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param selectionArgs (Optional) Selection arguments used in the query.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return The value of the _data column, which is typically a file path.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String getDataColumn(Context context, Uri uri, String selection, - String[] selectionArgs) { - - Cursor cursor = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String column = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;_data\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String[] projection = { - column - }; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (cursor != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; cursor.moveToFirst()) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; index = cursor.getColumnIndexOrThrow(column); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; cursor.getString(index); - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;finally\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (cursor != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - cursor.close(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param uri The Uri to check.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return Whether the Uri authority is ExternalStorageProvider.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isExternalStorageDocument(Uri uri) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.android.externalstorage.documents\u0026amp;#8221;\u0026lt;/span\u0026gt;.equals(uri.getAuthority()); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param uri The Uri to check.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return Whether the Uri authority is DownloadsProvider.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isDownloadsDocument(Uri uri) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.android.providers.downloads.documents\u0026amp;#8221;\u0026lt;/span\u0026gt;.equals(uri.getAuthority()); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param uri The Uri to check.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return Whether the Uri authority is MediaProvider.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isMediaDocument(Uri uri) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.android.providers.media.documents\u0026amp;#8221;\u0026lt;/span\u0026gt;.equals(uri.getAuthority()); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param uri The Uri to check.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return Whether the Uri authority is Google Photos.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isGooglePhotosUri(Uri uri) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.google.android.apps.photos.content\u0026amp;#8221;\u0026lt;/span\u0026gt;.equals(uri.getAuthority()); - } 这样,就可以在4.4上用漂亮的图片选择器,选到我们想要的文件,又不会出问题了.\n昨天发现了个bug,如果在4.4上面不用”图片”来选,用”图库”来选,就会无法读取到图片路径,所以只需要加个判断,如果是用旧方式来选,就用旧方式来读,就是如果\nDocumentsContract.isDocumentUri(context, uri) 返回false的话,就用旧的方式\n**[java]** [view plain](http://blog.csdn.net/tempersitu/article/details/20557383#)[copy](http://blog.csdn.net/tempersitu/article/details/20557383#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219069)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219069/fork) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String selectImage(Context context,Intent data){ - Uri selectedImage = data.getData(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Log.e(TAG, selectedImage.toString());\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(selectedImage!=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - String uriStr=selectedImage.toString(); - String path=uriStr.substring(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;,uriStr.length()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(path.startsWith(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.sec.android.gallery3d\u0026amp;#8221;\u0026lt;/span\u0026gt;)){ - Log.e(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;It\u0026amp;#8217;s auto backup pic path:\u0026amp;#8221;\u0026lt;/span\u0026gt;+selectedImage.toString()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - } - String[] filePathColumn = { MediaStore.Images.Media.DATA }; - Cursor cursor = context.getContentResolver().query(selectedImage,filePathColumn, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - cursor.moveToFirst(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; columnIndex = cursor.getColumnIndex(filePathColumn[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]); - String picturePath = cursor.getString(columnIndex); - cursor.close(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; picturePath; - } 这样就OK的了\n转自：http://blog.csdn.net/tempersitu/article/details/20557383\nandroid拍照图片选取与图片剪裁 转载：http://blog.csdn.net/allen315410/article/details/39994913\n最近从以前的项目中扒下来一个常用的模块，在这里有必要记录一下的，就是android上获取图片以及裁剪图片，怎么样？这个功能是不是很常用啊，你随便打开一个App，只要它有注册功能都会有设置人物头像的功能，尤其在内容型的app中更为常见，那么这些功能是怎么实现的呢？今天，在这里就记录一下好了，防止以后的项目中也会用到，就直接拿来用好了。\n1.通过拍照或者图册获取图片（不需要剪裁） 这种获取图片的方式就比较次了，因为不设置图片的剪裁功能，有可能因为图片过大，导致OOM，但是这种方式也是有必要讲一下的，其获取图片的方式有两种，一是调用系统相机实时拍摄一张图片，二十打开设备上已有的图库，在图库中选择一张照片。这两种方式实现方法都是一个道理，无非就是通过Intent调用系统的东西。下面是源码，首先是图片选择方式的Activity，这个Activity被设置成了Dialog模式，需要进行设置一下。\n布局文件/res/layout/activity_select_photo.xml：\n**[html]** [view plain](http://blog.csdn.net/allen315410/article/details/39994913#)[copy](http://blog.csdn.net/allen315410/article/details/39994913#)[print](http://blog.csdn.net/allen315410/article/details/39994913#)[?](http://blog.csdn.net/allen315410/article/details/39994913#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/482399)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/482399/fork) - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/dialog_layout\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_alignParentBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/select_photo_up_bg\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/btn_take_photo\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;35dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/select_photo_bg\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;拍照选取\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textStyle\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;bold\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0.5px\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#828282\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/btn_pick_photo\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;35dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/select_photo_bg\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;相册选取\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textStyle\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;bold\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/btn_cancel\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;35dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/select_photo_bg\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;取消\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#ffff0000\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textStyle\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;bold\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 接着是获取图片Activity里的代码SelectPhotoActivity：\n**[java]** [view plain](http://blog.csdn.net/allen315410/article/details/39994913#)[copy](http://blog.csdn.net/allen315410/article/details/39994913#)[print](http://blog.csdn.net/allen315410/article/details/39994913#)[?](http://blog.csdn.net/allen315410/article/details/39994913#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/482399)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/482399/fork) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SelectPhotoActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnClickListener { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** 使用照相机拍照获取图片 */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; SELECT_PIC_BY_TACK_PHOTO = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** 使用相册中的图片 */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; SELECT_PIC_BY_PICK_PHOTO = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** 开启相机 */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Button btn_take_photo; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** 开启图册 */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Button btn_pick_photo; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** 取消 */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Button btn_cancel; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** 获取到的图片路径 */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String picPath; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Intent lastIntent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Uri photoUri; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** 从Intent获取图片路径的KEY */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String KEY_PHOTO_PATH = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;photo_path\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_select_photo); - btn_take_photo = (Button) findViewById(R.id.btn_take_photo); - btn_pick_photo = (Button) findViewById(R.id.btn_pick_photo); - btn_cancel = (Button) findViewById(R.id.btn_cancel); - - lastIntent = getIntent(); - - btn_take_photo.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - btn_pick_photo.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - btn_cancel.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (v.getId()) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.btn_take_photo : \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 开启相机\u0026lt;/span\u0026gt; - takePhoto(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.btn_pick_photo : \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 开启图册\u0026lt;/span\u0026gt; - pickPhoto(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.btn_cancel : \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 取消操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.finish(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt; : - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 拍照获取图片\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; takePhoto() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 执行拍照前，应该先判断SD卡是否存在\u0026lt;/span\u0026gt; - String SDState = Environment.getExternalStorageState(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (SDState.equals(Environment.MEDIA_MOUNTED)) { - Intent intent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MediaStore.ACTION_IMAGE_CAPTURE);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// \u0026amp;#8220;android.media.action.IMAGE_CAPTURE\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/***\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 需要说明一下，以下操作使用照相机拍照，拍照后的图片会存放在相册中的 这里使用的这种方式有一个好处就是获取的图片是拍照后的原图\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 如果不实用ContentValues存放照片路径的话，拍照后获取的图片为缩略图不清晰\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - ContentValues values = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ContentValues(); - photoUri = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getContentResolver().insert( - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); - intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, photoUri); - startActivityForResult(intent, SELECT_PIC_BY_TACK_PHOTO); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - Toast.makeText(getApplicationContext(), \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;内存卡不存在\u0026amp;#8221;\u0026lt;/span\u0026gt;, - Toast.LENGTH_SHORT).show(); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/***\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 从相册中取图片\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; pickPhoto() { - Intent intent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(); - intent.setType(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;image/*\u0026amp;#8221;\u0026lt;/span\u0026gt;); - intent.setAction(Intent.ACTION_GET_CONTENT); - startActivityForResult(intent, SELECT_PIC_BY_PICK_PHOTO); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent event) { - finish(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(event); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onActivityResult(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; requestCode, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; resultCode, Intent data) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (resultCode == Activity.RESULT_OK) { - doPhoto(requestCode, data); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onActivityResult(requestCode, resultCode, data); - } - - /** - * 选择图片后，获取图片的路径 - * - * \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@param\u0026lt;/span\u0026gt; requestCode - * \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@param\u0026lt;/span\u0026gt; data - */ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; doPhoto(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; requestCode, Intent data) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (requestCode == SELECT_PIC_BY_PICK_PHOTO) {\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 从相册取图片，有些手机有异常情况，请注意\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (data == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - Toast.makeText(getApplicationContext(), \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;选择图片文件出错\u0026amp;#8221;\u0026lt;/span\u0026gt;, - Toast.LENGTH_SHORT).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - } - photoUri = data.getData(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (photoUri == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - Toast.makeText(getApplicationContext(), \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;选择图片文件出错\u0026amp;#8221;\u0026lt;/span\u0026gt;, - Toast.LENGTH_SHORT).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - } - } - String[] pojo = {MediaStore.Images.Media.DATA}; - Cursor cursor = managedQuery(photoUri, pojo, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (cursor != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; columnIndex = cursor.getColumnIndexOrThrow(pojo[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]); - cursor.moveToFirst(); - picPath = cursor.getString(columnIndex); - cursor.close(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (picPath != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; (picPath.endsWith(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;.png\u0026amp;#8221;\u0026lt;/span\u0026gt;) || picPath.endsWith(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;.PNG\u0026amp;#8221;\u0026lt;/span\u0026gt;) - || picPath.endsWith(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;.jpg\u0026amp;#8221;\u0026lt;/span\u0026gt;) || picPath.endsWith(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;.JPG\u0026amp;#8221;\u0026lt;/span\u0026gt;))) { - lastIntent.putExtra(KEY_PHOTO_PATH, picPath); - setResult(Activity.RESULT_OK, lastIntent); - finish(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - Toast.makeText(getApplicationContext(), \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;选择图片文件不正确\u0026amp;#8221;\u0026lt;/span\u0026gt;, - Toast.LENGTH_SHORT).show(); - } - } - - } 因为这Activity是要设置成Dialog模式的，所以需要在清单文件中设置一下style，/res/values/styles.xml里添加如下：\n**[html]** [view plain](http://blog.csdn.net/allen315410/article/details/39994913#)[copy](http://blog.csdn.net/allen315410/article/details/39994913#)[print](http://blog.csdn.net/allen315410/article/details/39994913#)[?](http://blog.csdn.net/allen315410/article/details/39994913#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/482399)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/482399/fork) - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;AnimBottom\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;parent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Animation\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:windowEnterAnimation\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;@anim/push_bottom_in\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:windowExitAnimation\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;@anim/push_bottom_out\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;DialogStyleBottom\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;parent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:Theme.Dialog\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:windowAnimationStyle\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;@style/AnimBottom\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:windowFrame\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;@null\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:windowIsFloating\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;false\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:windowIsTranslucent\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;true\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:windowNoTitle\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;true\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:windowBackground\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;@android:color/transparent\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android:backgroundDimEnabled\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;true\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 在Activity的节点下，设置这个style：\n**[html]** [view plain](http://blog.csdn.net/allen315410/article/details/39994913#)[copy](http://blog.csdn.net/allen315410/article/details/39994913#)[print](http://blog.csdn.net/allen315410/article/details/39994913#)[?](http://blog.csdn.net/allen315410/article/details/39994913#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/482399)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/482399/fork) - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;com.example.croppictrue.SelectPhotoActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:screenOrientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;portrait\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:theme\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@style/DialogStyleBottom\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 添加权限：\n**[html]** [view plain](http://blog.csdn.net/allen315410/article/details/39994913#)[copy](http://blog.csdn.net/allen315410/article/details/39994913#)[print](http://blog.csdn.net/allen315410/article/details/39994913#)[?](http://blog.csdn.net/allen315410/article/details/39994913#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/482399)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/482399/fork) - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;uses-permission\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.permission.WRITE_EXTERNAL_STORAGE\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; 运行效果如下：\n2.通过拍照或者图册获取图片（需要剪裁） 上面第一种方式获取图片是没有经过剪裁的，但是大多项目需求是需要剪裁图片后再使用，例如修改用户头像等等功能。那么，下面，就奉上剪裁图片的代码吧：\n**[java]** [view plain](http://blog.csdn.net/allen315410/article/details/39994913#)[copy](http://blog.csdn.net/allen315410/article/details/39994913#)[print](http://blog.csdn.net/allen315410/article/details/39994913#)[?](http://blog.csdn.net/allen315410/article/details/39994913#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/482399)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/482399/fork) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; CropPictureActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** ImageView对象 */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageView iv_photo; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String[] items = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; String[]{\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;选择本地图片\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;拍照\u0026amp;#8221;\u0026lt;/span\u0026gt;}; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** 头像名称 */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String IMAGE_FILE_NAME = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;image.jpg\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** 请求码 */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; IMAGE_REQUEST_CODE = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; CAMERA_REQUEST_CODE = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; RESULT_REQUEST_CODE = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_crop); - iv_photo = (ImageView) findViewById(R.id.iv_photo); - iv_photo.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - showDialog(); - } - }); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 显示选择对话框\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; showDialog() { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AlertDialog.Builder(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;) - .setTitle(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;设置头像\u0026amp;#8221;\u0026lt;/span\u0026gt;) - .setItems(items, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DialogInterface.OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(DialogInterface dialog, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; which) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (which) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; : - Intent intentFromGallery = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(); - intentFromGallery.setType(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;image/*\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置文件类型\u0026lt;/span\u0026gt; - intentFromGallery - .setAction(Intent.ACTION_GET_CONTENT); - startActivityForResult(intentFromGallery, - IMAGE_REQUEST_CODE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; : - Intent intentFromCapture = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent( - MediaStore.ACTION_IMAGE_CAPTURE); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 判断存储卡是否可以用，可用进行存储\u0026lt;/span\u0026gt; - String state = Environment - .getExternalStorageState(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state.equals(Environment.MEDIA_MOUNTED)) { - File path = Environment - .getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); - File file = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; File(path, IMAGE_FILE_NAME); - intentFromCapture.putExtra( - MediaStore.EXTRA_OUTPUT, - Uri.fromFile(file)); - } - - startActivityForResult(intentFromCapture, - CAMERA_REQUEST_CODE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - }) - .setNegativeButton(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;取消\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DialogInterface.OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(DialogInterface dialog, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; which) { - dialog.dismiss(); - } - }).show(); - - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onActivityResult(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; requestCode, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; resultCode, Intent data) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 结果码不等于取消时候\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (resultCode != RESULT_CANCELED) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (requestCode) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; IMAGE_REQUEST_CODE : - startPhotoZoom(data.getData()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; CAMERA_REQUEST_CODE : - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 判断存储卡是否可以用，可用进行存储\u0026lt;/span\u0026gt; - String state = Environment.getExternalStorageState(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state.equals(Environment.MEDIA_MOUNTED)) { - File path = Environment - .getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); - File tempFile = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; File(path, IMAGE_FILE_NAME); - startPhotoZoom(Uri.fromFile(tempFile)); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - Toast.makeText(getApplicationContext(), - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;未找到存储卡，无法存储照片！\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; RESULT_REQUEST_CODE : \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 图片缩放完成后\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (data != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - getImageToView(data); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onActivityResult(requestCode, resultCode, data); - } - - /** - * 裁剪图片方法实现 - * - * \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@param\u0026lt;/span\u0026gt; uri - */ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; startPhotoZoom(Uri uri) { - Intent intent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.android.camera.action.CROP\u0026amp;#8221;\u0026lt;/span\u0026gt;); - intent.setDataAndType(uri, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;image/*\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置裁剪\u0026lt;/span\u0026gt; - intent.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;crop\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// aspectX aspectY 是宽高的比例\u0026lt;/span\u0026gt; - intent.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;aspectX\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - intent.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;aspectY\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// outputX outputY 是裁剪图片宽高\u0026lt;/span\u0026gt; - intent.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;outputX\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;340\u0026lt;/span\u0026gt;); - intent.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;outputY\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;340\u0026lt;/span\u0026gt;); - intent.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;return-data\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - startActivityForResult(intent, RESULT_REQUEST_CODE); - } - - /** - * 保存裁剪之后的图片数据 - * - * \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@param\u0026lt;/span\u0026gt; picdata - */ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; getImageToView(Intent data) { - Bundle extras = data.getExtras(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (extras != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - Bitmap photo = extras.getParcelable(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;data\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Drawable drawable = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BitmapDrawable(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getResources(), photo); - iv_photo.setImageDrawable(drawable); - } - } - } 效果图：\n在这个Activity里为了简便处理，我没有在选择图片时候start一个Dialog风格的Activity了，就直接一个普通的对话框提示用户选择，效果也许。其实实现的原理都比较简单，实现图片的剪裁就是发一个Intent请求，调用设备上所有具有剪裁图片功能的app去剪裁图片，我的设备上除了android系统自带的图库以外，还装有“快图浏览”这个app，这个app也自带一个图片剪裁的功能，所有当选择好图片后，会出现一个选择提示，用户可以根据提示选择到底使用哪个app提供的剪裁功能区剪裁图片。\n以上代码均在模拟器上测试过，由于模拟器对相机支持的不好，所以就没有演示打开相机拍摄图片了，有兴趣的朋友可以先请下载这个Demo的源码，运行在手机上试试看效果如何，如若疏漏之后，欢迎大家批评指正！\n源码请在这里下载\n","permalink":"https://blog.zdltech.com/posts/android-4-4%E4%BB%8E%E5%9B%BE%E5%BA%93%E9%80%89%E6%8B%A9%E5%9B%BE%E7%89%87%E8%8E%B7%E5%8F%96%E5%9B%BE%E7%89%87%E8%B7%AF%E5%BE%84%E5%B9%B6%E8%A3%81%E5%89%AA/","summary":"\u003cp\u003e\u003cspan class=\"Apple-converted-space\"\u003e \u003c/span\u003e    最近在做一个从图库选择图片或拍照,然后裁剪的功能.本来是没问题的,一直在用\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]**\u003cspan class=\"Apple-converted-space\"\u003e \u003c/span\u003e[view plain](http://blog.csdn.net/tempersitu/article/details/20557383#)[copy](http://blog.csdn.net/tempersitu/article/details/20557383#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219069)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219069/fork)\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- Intent intent=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e的方式来做,是调用系统图库来做,但是发现如果有图片是同步到google相册的话,图库里面能看到一个auto backup的目录,点进去选图片的话是无法获取到图片的路径的.因为那些图片根本就不存在于手机上.然后看到无论是百度贴吧,Instagram,或者还有些会选取图片做修改的app,都是用一个很漂亮的图片选择器(4.4以上,4.3的还是用系统旧的图库).\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140305170527218?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGVtcGVyc2l0dQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140305170551687?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGVtcGVyc2l0dQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e而这个图片选择器可以屏蔽掉那个auto backup的目录.所以就开始打算用这个图片选择器来选图片了.\u003cbr\u003e\n这个方法就是\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]**\u003cspan class=\"Apple-converted-space\"\u003e \u003c/span\u003e[view plain](http://blog.csdn.net/tempersitu/article/details/20557383#)[copy](http://blog.csdn.net/tempersitu/article/details/20557383#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219069)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219069/fork)\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- Intent intent=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(Intent.ACTION_GET_CONTENT);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//ACTION_OPEN_DOCUMENT\u0026lt;/span\u0026gt;\n\n- intent.addCategory(Intent.CATEGORY_OPENABLE);\n\n- intent.setType(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;image/jpeg\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(android.os.Build.VERSION.SDK_INT\u0026gt;=android.os.Build.VERSION_CODES.KITKAT){\n\n- startActivityForResult(intent, SELECT_PIC_KITKAT);\n\n- }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{\n\n- startActivityForResult(intent, SELECT_PIC);\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e为什么要分开不同版本呢?其实在4.3或以下可以直接用ACTION_GET_CONTENT的,在4.4或以上,官方建议用ACTION_OPEN_DOCUMENT,但其实都不算太大区别,区别是他们返回的Uri,那个才叫大区别.这就是困扰了我一整天的问题所在了.\u003c/p\u003e\n\u003cp\u003e4.3或以下,选了图片之后,根据Uri来做处理,很多帖子都有了,我就不详细说了.主要是4.4,如果使用上面pick的原生方法来选图,返回的uri还是正常的,但如果用ACTION_GET_CONTENT的方法,返回的uri跟4.3是完全不一样的,4.3返回的是带文件路径的,而4.4返回的却是content://com.android.providers.media.documents/document/image:3951这样的,没有路径,只有图片编号的uri.这就导致接下来无法根据图片路径来裁剪的步骤了.\u003c/p\u003e\n\u003cp\u003e还好找了很多方法,包括加权限啊什么的,中间还试过用一些方法,自己的app没崩溃,倒是让系统图库崩溃了,引发了java.lang.SecurityException.\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]**\u003cspan class=\"Apple-converted-space\"\u003e \u003c/span\u003e[view plain](http://blog.csdn.net/tempersitu/article/details/20557383#)[copy](http://blog.csdn.net/tempersitu/article/details/20557383#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219069)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219069/fork)\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- Caused by: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{437b5d88 \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;9494\u0026lt;/span\u0026gt;:com.google.android.gallery3d/u0a20} (pid=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;9494\u0026lt;/span\u0026gt;, uid=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10020\u0026lt;/span\u0026gt;) requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e看来4.4的系统还是有些bug.重点来了,4.4得到的uri,需要以下方法来获取文件的路径\u003c/p\u003e","title":"Android 4.4从图库选择图片,获取图片路径并裁剪"},{"content":"目前越来越多的app在注册或是进行对应操作时，要求获取短信验证码，在点击了获取短信验证码的按钮后，就是出现倒计时，比如倒计时120S，在倒计时 期间内，按钮点击是无效的，当倒计时结束后，如果你没有获取到验证码，可以再次点击。实现倒计时的方法很多，我们今天就通过继承 android. os.CountDownTimer类来实现！\n首先看下我们封装的倒计时工具类，主要为了在多个地方用到的话，用了多个构造方法，就是为了使用更灵活，只要传入对数就可以调用了：\n[?](http://www.open-open.com/code/view/1426335036826#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; 51 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; 52 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; 53 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; 54 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; 55 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; 56 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; 57 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; 58 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; 59 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; 60 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; 61 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; 62 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; 63 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; 64 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `MyCountTimer ``extends` `CountDownTimer {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `public` `static` `final` `int` `TIME_COUNT = ``121000``;``//时间防止从119s开始显示（以倒计时120s为例子）` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `private` `TextView btn;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `private` `int` `endStrRid;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `private` `int` `normalColor, timingColor;``//未计时的文字颜色，计时期间的文字颜色` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; `* 参数 millisInFuture 倒计时总时间（如60S，120s等）` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; `* 参数 countDownInterval 渐变时间（每次倒计1s）` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``* 参数 btn 点击的按钮(因为Button是TextView子类，为了通用我的参数设置为TextView）` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``* 参数 endStrRid 倒计时结束后，按钮对应显示的文字` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; `*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; `public` `MyCountTimer (``long` `millisInFuture, ``long` `countDownInterval, TextView btn, ``int` `endStrRid) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; `super``(millisInFuture, countDownInterval);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; `this``.btn = btn;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; `this``.endStrRid = endStrRid;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; `/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``*参数上面有注释` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; `*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; `public` `MyCountTimer (TextView btn, ``int` `endStrRid) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; `super``(TIME_COUNT, ``1000``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; `this``.btn = btn;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; `this``.endStrRid = endStrRid;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; `public` `MyCountTimer (TextView btn) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; `super``(TIME_COUNT, ``1000``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; `this``.btn = btn;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; `this``.endStrRid = R.string.txt_getMsgCode_validate;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; `public` `MyCountTimer (TextView tv_varify, ``int` `normalColor, ``int` `timingColor) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; `this``(tv_varify);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; `this``.normalColor = normalColor;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; `this``.timingColor = timingColor;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; `// 计时完毕时触发` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; `@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; `public` `void` `onFinish() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; `if``(normalColor \u0026amp;gt; ````){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; `btn.setTextColor(normalColor);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; `btn.setText(endStrRid);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; `btn.setEnabled(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; `// 计时过程显示` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; `@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; `public` `void` `onTick(``long` `millisUntilFinished) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; `if``(timingColor \u0026amp;gt; ````){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; `btn.setTextColor(timingColor);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; `btn.setEnabled(``false``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; `btn.setText(millisUntilFinished / ``1000` `+ ``\u0026quot;s\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 然后在你要实现倒计时的页面用就可以了：\n比如在AcvitityA中点击倒时间的按钮\nButton smsBtn=findViewById(R.id…..);\nMyCountTimertimeCount = new MyCountTimer(smsBtn, 0xfff30008, 0xff969696);//传入了文字颜色值\ntimeCount.start();\n如时你不传入颜色值的话，也可以在点击按钮smsBtn的布局文件中根据按钮状态来设置颜色。\n[?](http://www.open-open.com/code/view/1426335036826#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;``Button` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/rebind_sms_btn\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;120dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;45dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``android:layout_marginLeft``=``\u0026quot;5dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``android:layout_marginRight``=``\u0026quot;5dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``android:background``=``\u0026quot;@null\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``android:gravity``=``\u0026quot;center\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:text``=``\u0026quot;获取短信验证码\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``android:textColor``=``\u0026quot;@color/hkb_binder_phone_text_color\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``android:textSize``=``\u0026quot;16sp\u0026quot;` `/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 文字颜色对应的xml文件：\n[?](http://www.open-open.com/code/view/1426335036826#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;?``xml` `version``=``\u0026quot;1.0\u0026quot;` `encoding``=``\u0026quot;utf-8\u0026quot;``?\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `\u0026amp;lt;``selector` `xmlns:android``=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `android:state_enabled``=``\u0026quot;false\u0026quot;` `android:color``=``\u0026quot;#969696\u0026quot;``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `android:color``=``\u0026quot;#f30008\u0026quot;``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `\u0026amp;lt;/``selector``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 转自：http://www.open-open.com/code/view/1426335036826 在逛论坛的时候，看到一个网友提问，说到了CountDownTimer这个类，从名字上面大家就可以看出来，记录下载时间。将后台线程的创建和Handler队列封装成一个方便的类调用。\n查看了一下官方文档，这个类及其简单，只有四个方法，上面都涉及到了onTick，onFinsh、cancel和start。其中前面两个是抽象方法，所以要重写一下。\n下面是官方给的一个小例子：\n**[java]** [view plain](http://blog.csdn.net/lilu_leo/article/details/6941724#)[copy](http://blog.csdn.net/lilu_leo/article/details/6941724#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/629800)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/629800/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; CountdownTimer(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;30000\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTick(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; millisUntilFinished) { - mTextField.setText(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;seconds remaining: \u0026amp;#8220;\u0026lt;/span\u0026gt; + millisUntilFinished / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onFinish() { - mTextField.setText(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;done!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - }.start(); 直接用的那位网友的代码，自己稍微改动了一下，一个简单的小demo。\n**[java]** [view plain](http://blog.csdn.net/lilu_leo/article/details/6941724#)[copy](http://blog.csdn.net/lilu_leo/article/details/6941724#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/629800)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/629800/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; cn.demo; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.CountDownTimer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; NewActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyCount mc; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView tv; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.main); - tv = (TextView)findViewById(R.id.show); - mc = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyCount(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;30000\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); - mc.start(); - }\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//end func\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*定义一个倒计时的内部类*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyCount \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; CountDownTimer { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyCount(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; millisInFuture, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; countDownInterval) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(millisInFuture, countDownInterval); - } - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onFinish() { - tv.setText(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;finish\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTick(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; millisUntilFinished) { - tv.setText(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;请等待30秒(\u0026amp;#8220;\u0026lt;/span\u0026gt; + millisUntilFinished / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;)\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Toast.makeText(NewActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, millisUntilFinished / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG).show();\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//toast有显示时间延迟 \u0026lt;/span\u0026gt; - } - } - } 主要是重写onTick和onFinsh这两个方法，onFinish()中的代码是计时器结束的时候要做的事情；onTick(Long m)中的代码是你倒计时开始时要做的事情，参数m是直到完成的时间，构造方法MyCount()中的两个参数中，前者是倒计的时间数，后者是倒计时onTick事件响应的间隔时间，都是以毫秒为单位。例如要倒计时30秒，每秒中间间隔时间是1秒，两个参数可以这样MyCount(30000,1000)。 将后台线程的创建和Handler队列封装成为了一个方便的类调用。\n当你想取消的时候使用mc.cancel()方法就行了。\n转自：http://blog.csdn.net/lilu_leo/article/details/6941724\n","permalink":"https://blog.zdltech.com/posts/android%E8%8E%B7%E5%8F%96%E7%9F%AD%E4%BF%A1%E9%AA%8C%E8%AF%81%E7%A0%81%E5%80%92%E8%AE%A1%E6%97%B6/","summary":"\u003cp\u003e目前越来越多的app在注册或是进行对应操作时，要求获取短信验证码，在点击了获取短信验证码的按钮后，就是出现倒计时，比如倒计时120S，在倒计时 期间内，按钮点击是无效的，当倒计时结束后，如果你没有获取到验证码，可以再次点击。实现倒计时的方法很多，我们今天就通过继承 \u003ca href=\"http://blog.csdn.net/true100/article/details/44037359\"\u003eandroid\u003c/a\u003e. \u003ca href=\"http://blog.csdn.net/true100/article/details/44037359\"\u003eos\u003c/a\u003e.CountDownTimer类来实现！\u003c/p\u003e\n\u003cp\u003e首先看下我们封装的倒计时工具类，主要为了在多个地方用到的话，用了多个构造方法，就是为了使用更灵活，只要传入对数就可以调用了：\u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_397155\" class=\"syntaxhighlighter  java   \"\u003e\n    \u003cdiv class=\"toolbar\"\u003e\n      [?](http://www.open-open.com/code/view/1426335036826#)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n  \u0026lt;tr\u0026gt;\n    \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n        1\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        2\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n        3\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n        4\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n        5\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n        6\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n        7\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n        8\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n        9\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n        10\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n        11\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n        12\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n        13\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n        14\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n        15\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n        16\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n        17\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n        18\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n        19\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n        20\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n        21\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n        22\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n        23\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n        24\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n        25\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n        26\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n        27\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n        28\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n        29\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n        30\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n        31\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n        32\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n        33\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt;\n        34\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt;\n        35\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt;\n        36\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt;\n        37\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt;\n        38\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt;\n        39\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt;\n        40\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt;\n        41\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt;\n        42\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt;\n        43\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt;\n        44\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt;\n        45\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt;\n        46\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt;\n        47\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt;\n        48\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt;\n        49\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt;\n        50\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt;\n        51\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt;\n        52\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt;\n        53\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt;\n        54\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt;\n        55\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt;\n        56\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt;\n        57\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt;\n        58\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt;\n        59\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt;\n        60\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt;\n        61\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt;\n        62\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt;\n        63\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt;\n        64\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `public` `class` `MyCountTimer ``extends` `CountDownTimer {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          `public` `static` `final` `int` `TIME_COUNT = ``121000``;``//时间防止从119s开始显示（以倒计时120s为例子）`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `private` `TextView btn;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          `private` `int` `endStrRid;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          `private` `int` `normalColor, timingColor;``//未计时的文字颜色，计时期间的文字颜色`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n          `/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n          `* 参数 millisInFuture         倒计时总时间（如60S，120s等）`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n          `* 参数 countDownInterval    渐变时间（每次倒计1s）`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n          `        ``* 参数 btn               点击的按钮(因为Button是TextView子类，为了通用我的参数设置为TextView）`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n          `        ``* 参数 endStrRid   倒计时结束后，按钮对应显示的文字`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n          `*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n          `public` `MyCountTimer (``long` `millisInFuture, ``long` `countDownInterval, TextView btn, ``int` `endStrRid) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n          `super``(millisInFuture, countDownInterval);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n          `this``.btn = btn;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n          `this``.endStrRid = endStrRid;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n          `/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n          `          ``*参数上面有注释`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n          `*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n          `public`  `MyCountTimer (TextView btn, ``int` `endStrRid) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n          `super``(TIME_COUNT, ``1000``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n          `this``.btn = btn;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n          `this``.endStrRid = endStrRid;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n          `public` `MyCountTimer (TextView btn) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n          `super``(TIME_COUNT, ``1000``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt;\n          `this``.btn = btn;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt;\n          `this``.endStrRid = R.string.txt_getMsgCode_validate;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt;\n          `public` `MyCountTimer (TextView tv_varify, ``int` `normalColor, ``int` `timingColor) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt;\n          `this``(tv_varify);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt;\n          `this``.normalColor = normalColor;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt;\n          `this``.timingColor = timingColor;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt;\n          `// 计时完毕时触发`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt;\n          `@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt;\n          `public` `void` `onFinish() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt;\n          `if``(normalColor \u0026amp;gt; ````){`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt;\n          `btn.setTextColor(normalColor);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt;\n          `btn.setText(endStrRid);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt;\n          `btn.setEnabled(``true``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt;\n          `// 计时过程显示`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt;\n          `@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt;\n          `public` `void` `onTick(``long` `millisUntilFinished) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt;\n          `if``(timingColor \u0026amp;gt; ````){`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt;\n          `btn.setTextColor(timingColor);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt;\n          `btn.setEnabled(``false``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt;\n          `btn.setText(millisUntilFinished / ``1000` `+ ``\u0026quot;s\u0026quot;``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android获取短信验证码倒计时"},{"content":"1、 题外话\n相信大家对LayoutInflate都不陌生，特别在ListView的Adapter的getView方法中基本都会出现，使用inflate方法去加载一个布局，用于ListView的每个Item的布局。Inflate有三个参数，我在初学Android的时候这么理解的：\n对于Inflate的三个参数(int resource, ViewGroup root, boolean attachToRoot)\n如果inflate(layoutId, null )则layoutId的最外层的控件的宽高是没有效果的\n如果inflate(layoutId, root, false ) 则认为和上面效果是一样的\n如果inflate(layoutId, root, true ) 则认为这样的话layoutId的最外层控件的宽高才能正常显示\n如果你也这么认为，那么你有就必要好好阅读这篇文章，因为这篇文章首先会验证上面的理解是 错误的 ，然后从源码角度去解释，最后会从ViewGroup与View的角度去解释。\n2、 实践是验证真理的唯一标准\n下面我写一个特别常见的例子来验证上面的理解是错误的，一个特别简单的ListView，每个Item中放一个按钮：\nActivity的布局文件：\n\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;ListView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/tools\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;@+id/id_listview\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;fill_parent\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026lt;/span\u0026gt; \u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;ListView\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; ListView的Item的布局文件：\n\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Button\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/tools\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;@+id/id_btn\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;120dp\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;120dp\u0026#34;\u0026lt;/span\u0026gt; \u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Button\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; ListView的适配器：\n\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;package\u0026lt;/span\u0026gt; com.example.zhy_layoutinflater; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.BaseAdapter; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Button; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;MyAdapter\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;BaseAdapter\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; LayoutInflater mInflater; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; mDatas; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; MyAdapter(Context context, List\u0026amp;lt;String\u0026amp;gt; datas) { mInflater = LayoutInflater.from(context); mDatas = datas; } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getCount() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; mDatas.size(); } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; Object getItem(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; mDatas.get(position); } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;long\u0026lt;/span\u0026gt; getItemId(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; position; } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; View getView(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) { ViewHolder holder = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (convertView == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { holder = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; ViewHolder(); convertView = mInflater.inflate(R.layout.item, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\tconvertView = mInflater.inflate(R.layout.item, parent ,false);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\tconvertView = mInflater.inflate(R.layout.item, parent ,true);\u0026lt;/span\u0026gt; holder.mBtn = (Button) convertView.findViewById(R.id.id_btn); convertView.setTag(holder); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { holder = (ViewHolder) convertView.getTag(); } holder.mBtn.setText(mDatas.get(position)); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; convertView; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;ViewHolder\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; Button mBtn; } } 主Activity:\n\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;package\u0026lt;/span\u0026gt; com.example.zhy_layoutinflater; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Arrays; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;MainActivity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Activity\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; ListView mListView; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; MyAdapter mAdapter; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; mDatas = Arrays.asList(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;Hello\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;Java\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;Android\u0026#34;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = (ListView) findViewById(R.id.id_listview); mAdapter = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; MyAdapter(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;, mDatas); mListView.setAdapter(mAdapter); } } 好了，相信大家对这个例子都再熟悉不过了，没啥好说的，我们主要关注getView里面的inflate那行代码：下面我依次把getView里的写成：\n1、convertView = mInflater.inflate(R.layout.item, null);\n2、convertView = mInflater.inflate(R.layout.item, parent ,false);\n3、convertView = mInflater.inflate(R.layout.item, parent ,true);\n分别看效果图：\n图1：\n图2：\n图3：\nFATAL EXCEPTION: main java.lang.UnsupportedOperationException: addView(View, LayoutParams) \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;is\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;not\u0026lt;/span\u0026gt; supported \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;in\u0026lt;/span\u0026gt; AdapterView 嗯，没错没有图3，第三种写法会报错。\n由上面三行代码的变化，产生3个不同的结果，可以看到\ninflater(resId, null )的确不能正确处理宽高的值，但是inflater(resId,parent,false)并非和inflater(resId, null )效果一致，它可以看出完美的显示了宽和高。\n而inflater(resId,parent,true)报错了（错误的原因在解析源码的时候说）。\n由此可见：文章开始提出的理解是绝对错误的。\n3、源码解析\n下面我通过源码来解释，这三种写法真正的差异\n这三个方法，最终都会执行下面的代码：\n\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) { synchronized (mConstructorArgs) { final AttributeSet attrs = Xml.asAttributeSet(parser); Context lastContext = (Context)mConstructorArgs[\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;]; mConstructorArgs[\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;] = mContext; View result = root; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// Look for the root node.\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; type; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;while\u0026lt;/span\u0026gt; ((type = parser.next()) != XmlPullParser.START_TAG \u0026amp;\u0026amp; type != XmlPullParser.END_DOCUMENT) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// Empty\u0026lt;/span\u0026gt; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (type != XmlPullParser.START_TAG) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;throw\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; InflateException(parser.getPositionDescription() + \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;: No start tag found!\u0026#34;\u0026lt;/span\u0026gt;); } final String name = parser.getName(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (DEBUG) { System.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;out\u0026lt;/span\u0026gt;.println(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;**************************\u0026#34;\u0026lt;/span\u0026gt;); System.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;out\u0026lt;/span\u0026gt;.println(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;Creating root view: \u0026#34;\u0026lt;/span\u0026gt; + name); System.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;out\u0026lt;/span\u0026gt;.println(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;**************************\u0026#34;\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (TAG_MERGE.equals(name)) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (root == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; || !attachToRoot) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;throw\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; InflateException(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;\u0026amp;lt;merge /\u0026amp;gt; can be used only with a valid \u0026#34;\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;ViewGroup root and attachToRoot=true\u0026#34;\u0026lt;/span\u0026gt;); } rInflate(parser, root, attrs, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// Temp is the root view that was found in the xml\u0026lt;/span\u0026gt; View temp; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (TAG_1995.equals(name)) { temp = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; BlinkLayout(mContext, attrs); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { temp = createViewFromTag(root, name, attrs); } ViewGroup.LayoutParams \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (root != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (DEBUG) { System.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;out\u0026lt;/span\u0026gt;.println(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;Creating params from root: \u0026#34;\u0026lt;/span\u0026gt; + root); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// Create layout params that match root, if supplied\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt; = root.generateLayoutParams(attrs); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (!attachToRoot) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// Set the layout params for temp if we are not\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// attaching. (If we are, we use addView, below)\u0026lt;/span\u0026gt; temp.setLayoutParams(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;); } } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (DEBUG) { System.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;out\u0026lt;/span\u0026gt;.println(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;-----\u0026amp;gt; start inflating children\u0026#34;\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// Inflate all children under temp\u0026lt;/span\u0026gt; rInflate(parser, temp, attrs, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (DEBUG) { System.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;out\u0026lt;/span\u0026gt;.println(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;-----\u0026amp;gt; done inflating children\u0026#34;\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// We are supposed to attach all the views we found (int temp)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// to root. Do that now.\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (root != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; attachToRoot) { root.addView(temp, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// Decide whether to return the root that was passed in or the\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// top view found in xml.\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (root == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; || !attachToRoot) { result = temp; } } } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;catch\u0026lt;/span\u0026gt; (XmlPullParserException e) { InflateException ex = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; InflateException(e.getMessage()); ex.initCause(e); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;throw\u0026lt;/span\u0026gt; ex; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) { InflateException ex = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; InflateException( parser.getPositionDescription() + \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;: \u0026#34;\u0026lt;/span\u0026gt; + e.getMessage()); ex.initCause(e); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;throw\u0026lt;/span\u0026gt; ex; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;finally\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// Don\u0026#39;t retain static reference on context.\u0026lt;/span\u0026gt; mConstructorArgs[\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;] = lastContext; mConstructorArgs[\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;] = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; result; } } 第6行：首先声明了View result = root ；//最终返回值为result\n第43行执行了：temp = createViewFromTag(root, name, attrs);创建了View\n然后直接看48-59：\n\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt;(root==\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt; = root.generateLayoutParams(attrs); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (!attachToRoot) { temp.setLayoutParams(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;); } } 可以看到，当root为null,attachToRoot为false时，为temp设置了LayoutParams.\n继续往下，看73-75行：\n\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (root != \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; attachToRoot) { root.addView(temp, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;); } 当root不为null，attachToRoot为true时，将tmp按照params添加到root中。\n然后78-81行：\n\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (root == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt; || !attachToRoot) { result = temp; } 如果root为null，或者attachToRoot为false则，将temp赋值给result。\n最后返回result。 从上面的分析已经可以看出： Inflate(resId , null ) 只创建temp ,返回temp\nInflate(resId , parent, false )创建temp，然后执行temp.setLayoutParams(params);返回temp\nInflate(resId , parent, true ) 创建temp，然后执行root.addView(temp, params);最后返回root\n由上面已经能够解释：\nInflate(resId , null )不能正确处理宽和高是因为：layout_width,layout_height是相对了父级设置的，必须与父级的LayoutParams一致。而此temp的getLayoutParams为null\nInflate(resId , parent,false ) 可以正确处理，因为temp.setLayoutParams(params);这个params正是root.generateLayoutParams(attrs);得到的。\nInflate(resId , parent,true )不仅能够正确的处理，而且已经把resId这个view加入到了parent，并且返回的是parent，和以上两者返回值有绝对的区别，还记得文章前面的例子上，MyAdapter里面的getView报的错误:\njava.lang.UnsupportedOperationException: addView(View, LayoutParams) \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;is\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;not\u0026lt;/span\u0026gt; supported \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;in\u0026lt;/span\u0026gt; AdapterView 这是因为源码中调用了root.addView(temp, params);而此时的root是我们的ListView，ListView为AdapterView的子类:\n直接看AdapterView的源码：\n\u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; addView(View child) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;throw\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; UnsupportedOperationException(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;addView(View) is not supported in AdapterView\u0026#34;\u0026lt;/span\u0026gt;); } 可以看到这个错误为啥产生了。\n4、 进一步的解析\n上面我根据源码得出的结论可能大家还是有一丝的迷惑，我再写个例子论证我们上面得出的结论：\n主布局文件：\n\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Button\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/tools\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;@+id/id_btn\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;120dp\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;120dp\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;Button\u0026#34;\u0026lt;/span\u0026gt; \u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Button\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; 主Activity:\n\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;package\u0026lt;/span\u0026gt; com.example.zhy_layoutinflater; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.app.ListActivity; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;MainActivity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;ListActivity\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; LayoutInflater mInflater; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); mInflater = LayoutInflater.from(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;); View view1 = mInflater.inflate(R.layout.activity_main, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;); View view2 = mInflater.inflate(R.layout.activity_main, (ViewGroup)findViewById(android.R.id.content), \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); View view3 = mInflater.inflate(R.layout.activity_main, (ViewGroup)findViewById(android.R.id.content), \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); Log.e(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;TAG\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;view1 = \u0026#34;\u0026lt;/span\u0026gt; + view1 +\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34; , view1.layoutParams = \u0026#34;\u0026lt;/span\u0026gt; + view1.getLayoutParams()); Log.e(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;TAG\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;view2 = \u0026#34;\u0026lt;/span\u0026gt; + view2 +\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34; , view2.layoutParams = \u0026#34;\u0026lt;/span\u0026gt; + view2.getLayoutParams()); Log.e(\u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;TAG\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;view3 = \u0026#34;\u0026lt;/span\u0026gt; + view3 ); } } 可以看到我们的主Activity并没有执行setContentView，仅仅执行了LayoutInflater的3个方法。\n注：parent我们用的是Activity的内容区域：即android.R.id.content，是一个FrameLayout，我们在setContentView(resId)时，其实系统会自动为了包上一层FrameLayout（id=content）。\n按照我们上面的说法：\nview1的layoutParams 应该为null view2的layoutParams 应该不为null，且为FrameLayout.LayoutParams view3为FrameLayout，且将这个button添加到Activity的内容区域了（因为R.id.content代表Actvity内容区域） 下面看一下输出结果，和Activity的展示：\n\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;07\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;27\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;36.703\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;E\u0026lt;/span\u0026gt;/\u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;TAG\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2911\u0026lt;/span\u0026gt;)\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt; view1 = android.widget.\u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;Button\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;variable\u0026#34;\u0026gt;@429d1660\u0026lt;/span\u0026gt; , view1.layoutParams = null \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;07\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;27\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;36.703\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;E\u0026lt;/span\u0026gt;/\u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;TAG\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2911\u0026lt;/span\u0026gt;)\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt; view2 = android.widget.\u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;Button\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;variable\u0026#34;\u0026gt;@42a0e120\u0026lt;/span\u0026gt; , view2.layoutParams = android.widget.\u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;FrameLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;variable\u0026#34;\u0026gt;$LayoutParams\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;variable\u0026#34;\u0026gt;@42a0e9a0\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;07\u0026lt;/span\u0026gt;-\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;27\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;36.703\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;E\u0026lt;/span\u0026gt;/\u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;TAG\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2911\u0026lt;/span\u0026gt;)\u0026lt;span class=\u0026#34;symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt; view3 = android.widget.\u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;FrameLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;variable\u0026#34;\u0026gt;@42a0a240\u0026lt;/span\u0026gt; 效果图：\n可见，虽然我们没有执行setContentView，但是依然可以看到绘制的控件，是因为\nView view3 = mInflater.inflate(R.layout.activity_main,(ViewGroup)findViewById(android.R.id.content), true);\n这个方法内部已经执行了root.addView(temp , params); 上面已经解析过了。 也可以看出：和我们的推测完全一致，到此已经完全说明了inflate3个重载的方法的区别。相信大家以后在使用时也能选择出最好的方式。不过下面准备从ViewGroup和View的角度来说一下，为啥layoutParams为null，就不能这确的处理。 5、从ViewGroup和View的角度来解析\n如果大家对自定义ViewGroup和自定义View有一定的掌握，肯定不会对onMeasure方法陌生： ViewGroup的onMeasure方法所做的是：\n为childView设置测量模式和测量出来的值。\n如何设置呢？就是根据LayoutParams。 如果childView的宽为：LayoutParams. MATCH_PARENT，则设置模式为MeasureSpec.EXACTLY，且为childView计算宽度。 如果childView的宽为：固定值（即大于0），则设置模式为MeasureSpec.EXACTLY，且将lp.width直接作为childView的宽度。 如果childView的宽为：LayoutParams. WRAP_CONTENT，则设置模式为：MeasureSpec.AT_MOST 高度与宽度类似。 View的onMeasure方法： 主要做的就是根据ViewGroup传入的测量模式和测量值，计算自己应该的宽和高： 一般是这样的流程： 如果宽的模式是AT_MOST：则自己计算宽的值。 如果宽的模式是EXACTLY：则直接使用MeasureSpec.getSize(widthMeasureSpec); 对于最后一块，如果不清楚，不要紧，以后我会在自定义ViewGroup和自定义View时详细讲解的。\n大概就是这样的流程，真正的绘制过程肯定比这个要复杂，就是为了说明如果View的宽和高如果设置为准确值，则一定依赖于LayoutParams，所以我们的inflate(resId,null)才没能正确处理宽和高。\n","permalink":"https://blog.zdltech.com/posts/android-layoutinflate%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90-%E7%BB%99%E4%BD%A0%E5%B8%A6%E6%9D%A5%E5%85%A8%E6%96%B0%E7%9A%84%E8%AE%A4%E8%AF%86/","summary":"\u003cp\u003e1、 题外话\u003c/p\u003e\n\u003cp\u003e相信大家对LayoutInflate都不陌生，特别在ListView的Adapter的getView方法中基本都会出现，使用inflate方法去加载一个布局，用于ListView的每个Item的布局。Inflate有三个参数，我在初学Android的时候这么理解的：\u003c/p\u003e\n\u003cp\u003e对于Inflate的三个参数(int resource, ViewGroup root, boolean attachToRoot)\u003c/p\u003e\n\u003cp\u003e如果inflate(layoutId, null )则layoutId的最外层的控件的宽高是没有效果的\u003c/p\u003e\n\u003cp\u003e如果inflate(layoutId, root, false ) 则认为和上面效果是一样的\u003c/p\u003e\n\u003cp\u003e如果inflate(layoutId, root, true ) 则认为这样的话layoutId的最外层控件的宽高才能正常显示\u003c/p\u003e\n\u003cp\u003e如果你也这么认为，那么你有就必要好好阅读这篇文章，因为这篇文章首先会验证上面的理解是 错误的 ，然后从源码角度去解释，最后会从ViewGroup与View的角度去解释。\u003c/p\u003e\n\u003cp\u003e2、 实践是验证真理的唯一标准\u003c/p\u003e\n\u003cp\u003e下面我写一个特别常见的例子来验证上面的理解是错误的，一个特别简单的ListView，每个Item中放一个按钮：\u003c/p\u003e\n\u003cp\u003eActivity的布局文件：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;tag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eListView\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003exmlns:android\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003exmlns:tools\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://schemas.android.com/tools\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:id\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;@+id/id_listview\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_width\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;fill_parent\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_height\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;wrap_content\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;tag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eListView\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eListView的Item的布局文件：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;tag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eButton\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003exmlns:android\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003exmlns:tools\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://schemas.android.com/tools\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:id\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;@+id/id_btn\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_width\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;120dp\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;attribute\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eandroid:layout_height\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;120dp\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;tag\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026lt;\u003c/span\u003espan \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;title\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eButton\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eListView的适配器：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;package\u0026lt;/span\u0026gt; com.example.zhy_layoutinflater;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.BaseAdapter;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Button;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;MyAdapter\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;BaseAdapter\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; LayoutInflater mInflater;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026amp;lt;String\u0026amp;gt; mDatas;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; MyAdapter(Context context, List\u0026amp;lt;String\u0026amp;gt; datas)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    mInflater = LayoutInflater.from(context);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    mDatas = datas;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getCount()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; mDatas.size();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; Object getItem(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; position)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; mDatas.get(position);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;long\u0026lt;/span\u0026gt; getItemId(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; position)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; position;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; View getView(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ViewHolder holder = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (convertView == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      holder = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; ViewHolder();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      convertView = mInflater.inflate(R.layout.item, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\t\t\tconvertView = mInflater.inflate(R.layout.item, parent ,false);\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\t\t\tconvertView = mInflater.inflate(R.layout.item, parent ,true);\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      holder.mBtn = (Button) convertView.findViewById(R.id.id_btn);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      convertView.setTag(holder);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      holder = (ViewHolder) convertView.getTag();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    holder.mBtn.setText(mDatas.get(position));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; convertView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;ViewHolder\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  {\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    Button mBtn;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e主Activity:\u003c/p\u003e","title":"Android LayoutInflate深度解析 给你带来全新的认识"},{"content":"通过本篇文章，让你掌握新的技巧，请不用只看看一点，希望能够看完，让你很快明白不同的使用场景\nListView 和 Adapter 的基础\n工作原理:\nListView 针对List中每个item，要求 adapter “给我一个视图” (getView)。 一个新的视图被返回并显示 如果我们有上亿个项目要显示怎么办？为每个项目创建一个新视图？NO!这不可能！\n实际上Android为你缓存了视图。\nAndroid中有个叫做Recycler的构件，下图是他的工作原理：\n如果你有10亿个项目(item)，其中只有可见的项目存在内存中，其他的在Recycler中。 ListView先请求一个type1视图(getView)然后请求其他可见的项目。convertView在getView中是空(null)的。 当item1滚出屏幕，并且一个新的项目从屏幕低端上来时，ListView再请求一个type1视图。convertView此时不是空值了，它的值是item1。你只需设定新的数据然后返回convertView，不必重新创建一个视图。 请看下面的示例代码，这里在getView中使用了System.out进行输出\n[?](http://www.aitinan.com/3885.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; 51 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; 52 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; 53 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; 54 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; 55 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; 56 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; 57 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; 58 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; 59 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; 60 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; 61 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; 62 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; 63 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; 64 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; 65 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `MultipleItemsListextends ListActivity {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``private` `MyCustomAdapter mAdapter;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``public` `void` `onCreate(Bundle savedInstanceState) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``super``.onCreate(savedInstanceState);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``mAdapter = ``new` `MyCustomAdapter();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``for` `(``int` `i = ````; i \u0026amp;lt; ``50``; i++) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``mAdapter.addItem(``\u0026quot;item \u0026quot;` `+ i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``setListAdapter(mAdapter);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``private` `class` `MyCustomAdapterextends BaseAdapter {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``private` `ArrayList mData = ``new` `ArrayList();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``private` `LayoutInflater mInflater;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``public` `MyCustomAdapter() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``public` `void` `addItem(``final` `String item) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``mData.add(item);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``notifyDataSetChanged();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ``public` `int` `getCount() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``return` `mData.size();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``public` `String getItem(``int` `position) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; ` ``return` `mData.get(position);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; ` ``public` `long` `getItemId(``int` `position) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; ` ``return` `position;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; ` ``public` `View getView(``int` `position, View convertView, ViewGroup parent) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; ` ``System.out.println(``\u0026quot;getView \u0026quot;` `+ position + ``\u0026quot; \u0026quot;` `+ convertView);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; ` ``ViewHolder holder = ``null``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; ` ``if` `(convertView == ``null``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; ` ``convertView = mInflater.inflate(R.layout.item1, ``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; ` ``holder = ``new` `ViewHolder();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; ` ``holder.textView = (TextView)convertView.findViewById(R.id.text);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; ` ``convertView.setTag(holder);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; ` ``}``else` `{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; ` ``holder = (ViewHolder)convertView.getTag();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; ` ``holder.textView.setText(mData.get(position));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; ` ``return` `convertView;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; ` ``public` `static` `class` `ViewHolder {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; ` ``public` `TextView textView;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 执行程序，然后在Logcat中查看日志\ngetView 被调用 9 次 ，convertView 对于所有的可见项目是空值（如下）\n**[java]** [view plain](http://blog.csdn.net/droyon/article/details/10008277#)[copy](http://blog.csdn.net/droyon/article/details/10008277#) - 02-05 13:47:32.559: INFO/System.out(947): getView 0 null - 02-05 13:47:32.570: INFO/System.out(947): getView 1 null - 02-05 13:47:32.589: INFO/System.out(947): getView 2 null - 02-05 13:47:32.599: INFO/System.out(947): getView 3 null - 02-05 13:47:32.619: INFO/System.out(947): getView 4 null - 02-05 13:47:32.629: INFO/System.out(947): getView 5 null - 02-05 13:47:32.708: INFO/System.out(947): getView 6 null - 02-05 13:47:32.719: INFO/System.out(947): getView 7 null - 02-05 13:47:32.729: INFO/System.out(947): getView 8 null [?](http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html#) 然后稍微向下滚动List，直到item10出现：\nconvertView仍然是空值，因为recycler中没有视图（item1的边缘仍然可见，在顶端）\n[?](http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html#) \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; **[java]** [view plain](http://blog.csdn.net/droyon/article/details/10008277#)[copy](http://blog.csdn.net/droyon/article/details/10008277#) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - 02-05 13:48:25.169: INFO/System.out(947): getView 9 null \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 再滚动List\nconvertView不是空值了！item1离开屏幕到Recycler中去了，然后item11被创建\n[?](http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html#) \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; **[java]** [view plain](http://blog.csdn.net/droyon/article/details/10008277#)[copy](http://blog.csdn.net/droyon/article/details/10008277#) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - 02-05 13:48:42.879: INFO/System.out(947): getView 10 android.widget.LinearLayout@437430f8 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 再滚动：\n[?](http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html#) \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; **[java]** [view plain](http://blog.csdn.net/droyon/article/details/10008277#)[copy](http://blog.csdn.net/droyon/article/details/10008277#) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - 02-05 14:01:31.069: INFO/System.out(947): getView 11 android.widget.LinearLayout@437447d0 - 02-05 14:01:31.142: INFO/System.out(947): getView 12 android.widget.LinearLayout@43744ff8 - 02-05 14:01:31.279: INFO/System.out(947): getView 13 android.widget.LinearLayout@43743fa8 - 02-05 14:01:31.350: INFO/System.out(947): getView 14 android.widget.LinearLayout@43745820 - 02-05 14:01:31.429: INFO/System.out(947): getView 15 android.widget.LinearLayout@43746048 - 02-05 14:01:31.550: INFO/System.out(947): getView 16 android.widget.LinearLayout@43746870 - 02-05 14:01:31.669: INFO/System.out(947): getView 17 android.widget.LinearLayout@43747098 - 02-05 14:01:31.839: INFO/System.out(947): getView 18 android.widget.LinearLayout@437478c0 - 02-05 14:03:30.900: INFO/System.out(947): getView 19 android.widget.LinearLayout@43748df0 - 02-05 14:03:32.069: INFO/System.out(947): getView 20 android.widget.LinearLayout@437430f8 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; convertView 如我们所期待的非空了，在item11离开屏幕之后，它的视图(@437430f8)作为convertView容纳item21了\n不同的项目布局(item layout) 我们再举一个稍微复杂的例子，在上例的list中加入一些分隔线\n你需要做这些:\n重(@Override)写 getViewTypeCount() – 返回你有多少个不同的布局 重写 getItemViewType(int) – 由position返回view type id 根据view item的类型，在getView中创建正确的convertView 以下是代码：\n[?](http://www.aitinan.com/3885.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; 51 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; 52 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; 53 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; 54 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; 55 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; 56 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; 57 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; 58 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; 59 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; 60 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; 61 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; 62 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; 63 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; 64 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; 65 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; 66 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; 67 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; 68 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; 69 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; 70 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; 71 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; 72 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; 73 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; 74 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; 75 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; 76 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; 77 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; 78 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; 79 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; 80 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; 81 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; 82 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; 83 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; 84 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; 85 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; 86 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; 87 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; 88 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; 89 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; 90 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; 91 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt; 92 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt; 93 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt; 94 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt; 95 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt; 96 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt; 97 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt; 98 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt; 99 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt; 100 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `MultipleItemsListextends ListActivity {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``private` `MyCustomAdapter mAdapter;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``public` `void` `onCreate(Bundle savedInstanceState) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``super``.onCreate(savedInstanceState);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``mAdapter = ``new` `MyCustomAdapter();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``for` `(``int` `i = ``1``; i \u0026amp;lt; ``50``; i++) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``mAdapter.addItem(``\u0026quot;item \u0026quot;` `+ i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``if` `(i % ``4` `==````) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``mAdapter.addSeparatorItem(``\u0026quot;separator \u0026quot;` `+ i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``setListAdapter(mAdapter);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``private` `class` `MyCustomAdapterextends BaseAdapter {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``private` `static` `final` `int` `TYPE_ITEM = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``private` `static` `final` `int` `TYPE_SEPARATOR = ``1``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``private` `static` `final` `int` `TYPE_MAX_COUNT = TYPE_SEPARATOR + ``1``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``private` `ArrayList mData = ``new` `ArrayList();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``private` `LayoutInflater mInflater;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``private` `TreeSet mSeparatorsSet = ``new` `TreeSet();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``public` `MyCustomAdapter() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ``mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ``public` `void` `addItem(``final` `String item) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ``mData.add(item);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``notifyDataSetChanged();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; ` ``public` `void` `addSeparatorItem(``final` `String item) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; ` ``mData.add(item);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; ` ``// save separator position` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; ` ``mSeparatorsSet.add(mData.size() - ``1``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; ` ``notifyDataSetChanged();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; ` ``public` `int` `getItemViewType(``int` `position) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; ` ``return` `mSeparatorsSet.contains(position) ? TYPE_SEPARATOR : TYPE_ITEM;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; ` ``public` `int` `getViewTypeCount() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; ` ``return` `TYPE_MAX_COUNT;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; ` ``public` `int` `getCount() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; ` ``return` `mData.size();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; ` ``public` `String getItem(``int` `position) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; ` ``return` `mData.get(position);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; ` ``public` `long` `getItemId(``int` `position) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; ` ``return` `position;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; ` ``public` `View getView(``int` `position, View convertView, ViewGroup parent) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; ` ``ViewHolder holder = ``null``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; ` ``int` `type = getItemViewType(position);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; ` ``System.out.println(``\u0026quot;getView \u0026quot;` `+ position + ``\u0026quot; \u0026quot;` `+ convertView + ``\u0026quot; type = \u0026quot;` `+ type);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; ` ``if` `(convertView == ``null``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; ` ``holder = ``new` `ViewHolder();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; ` ``switch` `(type) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; ` ``case` `TYPE_ITEM:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; ` ``convertView = mInflater.inflate(R.layout.item1, ``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; ` ``holder.textView = (TextView)convertView.findViewById(R.id.text);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; ` ``case` `TYPE_SEPARATOR:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; ` ``convertView = mInflater.inflate(R.layout.item2, ``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; ` ``holder.textView = (TextView)convertView.findViewById(R.id.textSeparator);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; ` ``convertView.setTag(holder);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; ` ``}``else` `{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; ` ``holder = (ViewHolder)convertView.getTag();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; ` ``holder.textView.setText(mData.get(position));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt; ` ``return` `convertView;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt; ` ``public` `static` `class` `ViewHolder {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt; ` ``public` `TextView textView;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 运行程序，你会看到每4个item一个分割线\n看看日志，无异常，所有的convertView都是空的\n[?](http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html#) \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; **[java]** [view plain](http://blog.csdn.net/droyon/article/details/10008277#)[copy](http://blog.csdn.net/droyon/article/details/10008277#) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - 02-05 15:19:03.080: INFO/System.out(1035): getView 0 null type = 0 - 02-05 15:19:03.112: INFO/System.out(1035): getView 1 null type = 0 - 02-05 15:19:03.130: INFO/System.out(1035): getView 2 null type = 0 - 02-05 15:19:03.141: INFO/System.out(1035): getView 3 null type = 0 - 02-05 15:19:03.160: INFO/System.out(1035): getView 4 null type = 1 - 02-05 15:19:03.170: INFO/System.out(1035): getView 5 null type = 0 - 02-05 15:19:03.180: INFO/System.out(1035): getView 6 null type = 0 - 02-05 15:19:03.190: INFO/System.out(1035): getView 7 null type = 0 - 02-05 15:19:03.210: INFO/System.out(1035): getView 8 null type = 0 - 02-05 15:19:03.210: INFO/System.out(1035): getView 9 null type = 1 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 滚动list：\n[?](http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html#) \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; **[java]** [view plain](http://blog.csdn.net/droyon/article/details/10008277#)[copy](http://blog.csdn.net/droyon/article/details/10008277#) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - 02-05 15:19:54.160: INFO/System.out(1035): getView 10 null type = 0 - 02-05 15:19:57.440: INFO/System.out(1035): getView 11 android.widget.LinearLayout@43744528 type = 0 - 02-05 15:20:01.310: INFO/System.out(1035): getView 12 android.widget.LinearLayout@43744eb0 type = 0 - 02-05 15:20:01.880: INFO/System.out(1035): getView 13 android.widget.LinearLayout@437456d8 type = 0 - 02-05 15:20:02.869: INFO/System.out(1035): getView 14 null type = 1 - 02-05 15:20:06.489: INFO/System.out(1035): getView 15 android.widget.LinearLayout@43745f00 type = 0 - 02-05 15:20:07.749: INFO/System.out(1035): getView 16 android.widget.LinearLayout@43747170 type = 0 - 02-05 15:20:10.250: INFO/System.out(1035): getView 17 android.widget.LinearLayout@43747998 type = 0 - 02-05 15:20:11.661: INFO/System.out(1035): getView 18 android.widget.LinearLayout@437481c0 type = 0 - 02-05 15:20:13.180: INFO/System.out(1035): getView 19 android.widget.LinearLayout@437468a0 type = 1 - 02-05 15:20:16.900: INFO/System.out(1035): getView 20 android.widget.LinearLayout@437489e8 type = 0 - 02-05 15:20:25.690: INFO/System.out(1035): getView 21 android.widget.LinearLayout@4374a8d8 type = 0 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; convertView对于分割线是空的，直到第一个分割线可见，当其离开屏幕，视图去到Recycler并且convertView开始起作用。\n转自：http://www.aitinan.com/3885.html\nAndroid高手进阶：Adapter深入理解与优化 一般是针对包含多个元素的View，如ListView，GridView，ExpandableListview，的时候我们是给其设置一个Adapter。Adapter是与View之间提供数据的桥梁，也是提供每个Item的视图桥梁。\n以ListView为例，其工作原理为:\n● ListView针对List中每个item， adapter都会调用一个getView的方法获得布局视图\n●我们一般会Inflate一个新的View，填充数据并返回显示\n当然如果我们的Item很多话（比如上万个），都会新建一个View吗？很明显这样内存是接受不了的，Google也不会这么做，Android中有个叫做Recycler的构件，下图是他的工作原理：\n很明显，无论数据中是多少个item，在显示上Recycler只存储其中可见的View在内存中。当向下滑动时，顶部不可见Item直接回移动到下方再次填充数据变为新增项。这样就不用每次都新建一个View了。\n这个也就是我们在Adapter中常见的getView方法的调用，对应此方法我们就能看出，convertView就是每一Item在Recyler之前的布局视图。\npublic View getView(int position, View convertView, ViewGrouppare 所以，Android已经给我们提供了Recycler机制了，我们就应该利用此机制，而不是每次都去inflate一个View。\nExample\nDon’t\npublic View getView(int position, View convertView, ViewGroupparent){\nconvertView = LayoutInflater.from(mContext).inflate(R.layout.item_view,null);\n//dosomething… return converView;\n}\nDo\npublic View getView(int position, View convertView, ViewGroupparent){\nif (convertView ==null) {\nconvertView =LayoutInflater.from(mContext).inflate(R.layout.item_view, null);\n}\n//dosomething… return converView;\n}\nViewHolder的作用\n之前所说的Recycler模式是为了解决重复inflate时候造成的View资源浪费，还哪有什么方法何可再次优化我们的性能吗？答案是Yes。\n我们还是从getView中的每一个方法调用去查看，发现其实我们拿到convertView的时候，每次都会根据这个布局去findViewById。如下，使我们通常的写法：\nfindViewById是在解析layout.xml布局那种其中的子View，解析xml是一个力气活，所以Google也建议我们将这个费力不讨好的活优化起来，所以提出了ViewHolder的概念。\n即，使用一个静态类，保存xml中的各个子View的引用关系，这样就不必要每次都去解析xml了。如下：就是针对上面代码写的一个ViewHolder\nif (convertView == null) {\nconvertView = mInflater.inflate(R.layout.item_view, null);\n}\nTextView titleTextView = (TextView) convertView.findViewById(R.id.text));\nImageView iconImageView = (ImageView)convertView.findViewButId( R.id.icon));\n//DoSomething… findViewById是在解析layout.xml布局那种其中的子View，解析xml是一个力气活，所以Google也建议我们将这个费力不讨好的活优化起来，所以提出了ViewHolder的概念。\n即，使用一个静态类，保存xml中的各个子View的引用关系，这样就不必要每次都去解析xml了。如下：就是针对上面代码写的一个ViewHolder\nstatic class ViewHolder {\nTextView titleTextView;\nImageView iconImageView;\n}\n但是，在getView方法中我们只能拿到三个参数，position、convertView、viewGroup是拿不到我们自定义的ViewHolder的。所以，我们希望通过convertView拿到ViewHolder只能将其放在tag里。\n下面是一个完整的ViewHolder使用exmaple:\npublic View getView(int position, View convertView, ViewGroup parent) {\nViewHolder holder;\nif (convertView == null) {\nconvertView = mInflater.inflate(R.layout.item_view, null);\nholder = new ViewHolder();\nholder.titleTextView = (TextView) convertView.findViewById(R.id.text);\nholder.iconImageView = (ImageView) convertView.findViewById(R.id.icon);\nconvertView.setTag(holder);\n} else {\nholder = (ViewHolder) convertView.getTag();\n}\nholder.titleTextView.setText(DATA[pos].title);\nholder.iconImageView.setImageBitmap(DATA[pos].bitmap);\nreturn convertView;\n}\nstatic class ViewHolder {\nTextView titleTextView;\nImageView iconImageView;\n}\nTips. Support.v7中的RecyclerView 就是采用了此思想来制作的。\n多个类型的ViewType\n当我们在Adapter中调用方法getView的时候，如果整个列表中的Item View如果有多种类型布局，如：\n我们继续使用convertView来将数据从新填充貌似不可行了，因为每次返回的convertView类型都不一样，无法重用。\nAndroid在设计上的时候，也想到了这点。所以，在adapter中预留的两个方法。\npublic int getItemViewType(int position) ;\npublic int getViewTypeCount();\n只需要重新这两个方法，设置一下ItemViewType的个数和判断方法，Recycler就能有选择性的给出不同的convertView了。\nExample：\n@Override\npublic intgetItemViewType(int position) {\nif (DATA[pos].type == ) {\nreturn ;\n} else {\nreturn 1;\n}\n}\n@Override\npublic int getViewTypeCount() {\nreturn 2;\n}\n@Override\npublic View getView(int position, View convertView, ViewGroup arg2) {\nTitleViewHolder titleHolder;\nInfoViewHolder infoHolder;\nint type = getItemViewType(position);\nif (convertView == null) {\nswitch (type) {\ncase :\nconvertView = mInflater.inflate(R.layout.item_view, null);\ntitleHolder = new TitleViewHolder();\ntitleHolder.titleTextView = (TextView) convertView.findViewById(R.id.text);\ntitleHolder.iconImageView = (ImageView) convertView.findViewById(R.id.icon);\nconvertView.setTag(titleHolder);\nbreak;\ncase 1:\nconvertView = mInflater.inflate(R.layout.item_view2, null);\ninfoHolder = new InfoViewHolder();\ninfoHolder.titleTextView = (TextView) convertView.findViewById(R.id.text);\nconvertView.setTag(infoHolder);\nbreak;\n}\n} else {\nswitch (type) {\ncase :\ntitleHolder = (TitleViewHolder) convertView.getTag();\nbreak;\ncase 1:\ninfoHolder = (InfoViewHolder) convertView.getTag();\nbreak;\n}\n}\nswitch (type) {\ncase :\ntitleHolder.titleTextView.setText(DATA[pos].title);\nbreak;\ncase 1:\ninfoHolder.titleTextView.setText(DATA[pos].title);\ninfoHolder.iconImageView.setImageBitmap(DATA[pos].bitmap);\nbreak;\n}\nreturn convertView;\n}\nstatic class TitleViewHolder {\npublic ImageView iconImageView;\npublic TextView titleTextView;\n}\nstatic class InfoViewHolder {\nTextView titleTextView;\nImageView iconImageView;\n}\nNotifyDataSetChanged刷新机制\n当ListView中的数据发生了改变，我们希望刷新ListView中的View时，我们一般会调用NotifyDataSetChanged来刷新ListView。看一下它的源码：\npublic void notifyChanged() {\nsynchronized (mObservers) {\n// 向每一个子View发送onChanged mObservers.get(i).onChanged();\n}\n}\n}\n发 现它针对每一个子View都做了刷新，当然，如果我们的数据都变量还可以理解。但是，一般条件下，我们需要更新的View不多。频繁的调用 NotifyDataSetChanged方法，刷新整个界面不合适。这样会把界面上显示的所有item都全部重绘一次，即使只有一个view的内容发生 了变化。\n所以，我们可以写一个update的方法，来单独刷新一个View\nprivate void updateView(int itemIndex){\nintvisiblePosition = yourListView.getFirstVisiblePosition();\nViewHolder viewHolder =(ViewHolder)v.getTag();\nif(viewHolder!= null){\nviewHolder.titleTextView.setText(“我更新了”);\n}\n}\nAdapter中的网络图片优化\nListView中的每一项Item基本都会带着网络图片，当item比较多的时候，过多的网络请求和过多的图片存储都会是ListView变慢变卡。\n所以针对其做一下优化：\n● 采用线程池进行网络图片请求，网络图片请求获取后使用本地缓存处理（LRUCache），内存+本地文件缓存。当然，为了防止内存溢出与回收不及时，需要使用弱引用（WeakReference）来存储内存中的图片。\n● 对网络中取到的图片进行按比例缩放，以减少内存消耗。\n● 滑动的时候不需要对网络图片进行请求。因为，网络请求一般比较耗时，某Item的图片，在请求来的时候如果被Recycler换掉，图片就会对应不上该Item。\nTips.网络请求的工具类比较多不方便举例子，但是使用比较频繁的网络图片请求工具类就是Volley了，Volley提供了一个ImageLoader的工具类和NetworkImageView的网络图片请求View\n本文链接：http://www.eoeandroid.com/thread-536377-1-1.html\nAndroid应用之利用getItemViewType为Listview的item设置不同的布局 一、概述\n在项目的需求中，有一处需要显示一个交易记录的列表，这个列表很容易让人联想到用listview来实现，但是这个列表又有稍许不同的地方，那就是它里面的item并不是一样的布局，其中某些部分显示的是消费的记录，而有些地方显示的是充值的记录，也就对应了不同的item布局。而且，这两处地方都是从服务端获取数据的，这两个item的数据对应的类内容也各不相同，该怎么处理呢？\n下面来一步步实现这个效果。\n二、先看效果图\n![](http://www.it165.net/uploadfile/files/2014/0623/20140623173055635.jpg)\n三、实现步骤\n实现的原理就是listview的adapter中的一个关键的方法就是getItemViewType(getItemViewType),这个方法有一个参数是position，有了这个position我们就可以对list集合中的不同位置的数据进行不同的处理，进而标识不同的type，将list中的数据进行分类处理。\n首先进行，数据的准备：\n在这个项目中，数据源是从服务端获取的json数据，数据的格式如下：\n[view source](http://www.it165.net/pro/html/201406/16181.html#viewSource)[print](http://www.it165.net/pro/html/201406/16181.html#printSource)[?](http://www.it165.net/pro/html/201406/16181.html#about) `01.``{` \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `02.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;status_code\u0026quot;``: ``\u0026quot;0\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `03.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;result\u0026quot;``: [`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `04.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`{`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `05.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;mr_content\u0026quot;``: {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `06.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;point\u0026quot;``: ``\u0026quot;10\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `07.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;member_money\u0026quot;``: ``\u0026quot;100\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `08.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;pay_money\u0026quot;``: ``\u0026quot;300\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `09.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;cash\u0026quot;``: ``\u0026quot;200\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `10.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;bonus\u0026quot;``: ``\u0026quot;消费满200元立减50元餐券1张\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `11.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;activities\u0026quot;``: ``\u0026quot;三锅鸡1元任吃\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `12.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;coupon\u0026quot;``: ``\u0026quot;满100送50\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `13.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;branch_name\u0026quot;``: ``\u0026quot;四海一家\u0026quot;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `14.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`},`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `15.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;mr_id\u0026quot;``: ``\u0026quot;25\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `16.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;mr_createtime\u0026quot;``: ``\u0026quot;1333333333\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `17.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;mr_type\u0026quot;``: ``\u0026quot;0\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `18.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;user_id\u0026quot;``: ``\u0026quot;108\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `19.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;merchant_id\u0026quot;``: ``\u0026quot;1\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `20.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;branch_id\u0026quot;``: ``\u0026quot;1\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `21.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;branch_name\u0026quot;``: ``\u0026quot;ffff\u0026quot;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `22.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`},`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `23.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`{`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `24.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;mr_content\u0026quot;``: {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `25.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;member_money\u0026quot;``: ``\u0026quot;300\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `26.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;branch_name\u0026quot;``: ``\u0026quot;四海一家\u0026quot;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `27.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`},`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `28.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;mr_id\u0026quot;``: ``\u0026quot;30\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `29.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;mr_createtime\u0026quot;``: ``\u0026quot;1333333333\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `30.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;mr_type\u0026quot;``: ``\u0026quot;1\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `31.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;user_id\u0026quot;``: ``\u0026quot;108\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `32.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;merchant_id\u0026quot;``: ``\u0026quot;1\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `33.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;branch_id\u0026quot;``: ``\u0026quot;1\u0026quot;``,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `34.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;branch_name\u0026quot;``: ``\u0026quot;fff\u0026quot;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `35.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `36.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`],`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `37.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026quot;status_desc\u0026quot;``: ``\u0026quot;ok\u0026quot;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `38.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 可以看到其中mr_content这个字段，是一个自定义对象，但是两个mr_content的内容不同，这里是分别为mr_content的内容定义两个不同的类还是如何处理呢？\n一开始，我是分别为两个mr_content定义不同的类，后来发现这样行不通，因为这样做的话定义外层类的时候mr_content就无法指定数据类型了。所以，最后采用某人的方法将mr_content定义为一个类，将两个不同的mr_content的字段都定义进去，解析的时候不会出现问题，没有数据会显示null\n下面是我定义的mr_content字段的数据类型ComsumAndChargeRecordBean\n[view source](http://www.it165.net/pro/html/201406/16181.html#viewSource)[print](http://www.it165.net/pro/html/201406/16181.html#printSource)[?](http://www.it165.net/pro/html/201406/16181.html#about) `01.``public` `class` `ComsumAndChargeRecordBean {` \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `02.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `String branch_name;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `03.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `String pay_money;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `04.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `String coupon;``//使用特权`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `05.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `String activities;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `06.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `String member_money;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `07.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `String cash;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `08.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `String point;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `09.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `String bonus;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `10.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`// private String prestore_money;//预存款`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `11.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `12.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `String getBranch_name() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `13.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `branch_name;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `14.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `15.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `setBranch_name(String branch_name) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `16.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.branch_name = branch_name;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `17.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `18.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `String getPay_money() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `19.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `pay_money;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `20.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `21.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `setPay_money(String pay_money) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `22.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.pay_money = pay_money;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `23.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `24.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `String getCoupon() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `25.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `coupon;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `26.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `27.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `setCoupon(String coupon) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `28.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.coupon = coupon;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `29.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `30.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `String getActivities() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `31.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `activities;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `32.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `33.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `setActivities(String activities) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `34.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.activities = activities;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `35.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `36.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `String getMember_money() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `37.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `member_money;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `38.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `39.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `setMember_money(String member_money) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `40.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.member_money = member_money;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `41.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `42.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `String getCash() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `43.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `cash;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `44.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `45.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `setCash(String cash) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `46.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.cash = cash;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `47.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `48.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `String getPoint() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `49.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `point;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `50.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `51.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `setPoint(String point) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `52.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.point = point;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `53.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `54.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `String getBonus() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `55.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `bonus;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `56.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `57.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `void` `setBonus(String bonus) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `58.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.bonus = bonus;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `59.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `60.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 数据准备好了，下面是传入listview中进行显示：\n布局文件：\n[view source](http://www.it165.net/pro/html/201406/16181.html#viewSource)[print](http://www.it165.net/pro/html/201406/16181.html#printSource)[?](http://www.it165.net/pro/html/201406/16181.html#about) `01.``\u0026lt;?xml version=``\"1.0\"` `encoding=``\"utf-8\"``?\u0026gt;` \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `02.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026amp;lt;LinearLayout xmlns:android=``\u0026quot;\u0026amp;lt;a href=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;\u0026gt;http://schemas.android.com/apk/res/android\u0026amp;lt;/a\u0026gt;\u0026quot;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `03.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`android:layout_width=``\u0026quot;match_parent\u0026quot;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `04.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`android:layout_height=``\u0026quot;match_parent\u0026quot;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `05.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`android:orientation=``\u0026quot;vertical\u0026quot;` `\u0026amp;gt;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `06.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `07.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026amp;lt;include`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `08.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`android:id=``\u0026quot;@+id/traderecord_layout\u0026quot;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `09.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`layout=``\u0026quot;@layout/topview_activity\u0026quot;` `/\u0026amp;gt;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `10.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `11.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026amp;lt;ListView`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `12.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`android:id=``\u0026quot;@+id/lv_my_traderecord\u0026quot;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `13.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`android:layout_width=``\u0026quot;match_parent\u0026quot;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `14.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`android:layout_height=``\u0026quot;match_parent\u0026quot;` `\u0026amp;gt;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `15.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026amp;lt;/ListView\u0026amp;gt;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `16.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `17.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`\u0026amp;lt;/LinearLayout\u0026amp;gt;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 两个不同item的布局文件就省略了，相信大家都会，这个没什么难度\n下面是主界面代码：\n[view source](http://www.it165.net/pro/html/201406/16181.html#viewSource)[print](http://www.it165.net/pro/html/201406/16181.html#printSource)[?](http://www.it165.net/pro/html/201406/16181.html#about) `01.``\u0026lt;pre ``class``=``\"java\"` `name=``\"code\"``\u0026gt; ``protected` `void` `onCreate(Bundle savedInstanceState) {` \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `02.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`// TODO Auto-generated method stub`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `03.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`super``.onCreate(savedInstanceState);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `04.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`setContentView(R.layout.activity_trade_record);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `05.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `06.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`mListView = (ListView) findViewById(R.id.lv_my_traderecord);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `07.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`E_TempTradeRecordAdapter adapter = ``new` `E_TempTradeRecordAdapter(`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `08.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`E_TradeRecordActivity.``this``, myModel.tradeRecordList);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `09.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`mListView.setAdapter(adapter);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `10.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`adapter.notifyDataSetChanged();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `11.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; [view source](http://www.it165.net/pro/html/201406/16181.html#viewSource)[print](http://www.it165.net/pro/html/201406/16181.html#printSource)[?](http://www.it165.net/pro/html/201406/16181.html#about) `1.` 下面是adapter适配器的一部分代码：\n字段和构造函数：\n[view source](http://www.it165.net/pro/html/201406/16181.html#viewSource)[print](http://www.it165.net/pro/html/201406/16181.html#printSource)[?](http://www.it165.net/pro/html/201406/16181.html#about) `01.``private` `static` `final` `String TAG = ``\"E_TradeRecordAdapter\"``;` \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `02.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `static` `final` `int` `TYPE_COUNT = ``2``;``//item类型的总数`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `03.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `static` `final` `int` `TYPE_COMSUM = ````;``//消费类型`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `04.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `static` `final` `int` `TYPE_CHARGE = ``1``;``//充值类型`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `05.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `ArrayList\u0026amp;lt;TradeRecordBean\u0026amp;gt; dataList = ``new` `ArrayList\u0026amp;lt;TradeRecordBean\u0026amp;gt;();``//数据集合`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `06.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `Context mContext;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `07.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`private` `int` `currentType;``//当前item类型`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `08.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `09.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `E_TempTradeRecordAdapter(Context mContext,`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `10.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`ArrayList\u0026amp;lt;TradeRecordBean\u0026amp;gt; dataList) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `11.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`super``();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `12.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.dataList = dataList;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `13.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`this``.mContext = mContext;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `14.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 几个重要方法：\n[view source](http://www.it165.net/pro/html/201406/16181.html#viewSource)[print](http://www.it165.net/pro/html/201406/16181.html#printSource)[?](http://www.it165.net/pro/html/201406/16181.html#about) `01.``@Override` \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `02.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `int` `getCount() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `03.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`// TODO Auto-generated method stub`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `04.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `dataList.size();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `05.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `06.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `07.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `08.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `Object getItem(``int` `position) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `09.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`// TODO Auto-generated method stub`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `10.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `dataList.get(position);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `11.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `12.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `13.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `14.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `long` `getItemId(``int` `position) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `15.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`// TODO Auto-generated method stub`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `16.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `position;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `17.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 获取子item的类型 获取类型的数量 这里是根据字段Mr_type来确定的，json数据里面是根据这个字段来确定消费记录的类型的。总之，在为item设置不同的布局的时候肯定有一个标记用来区分不同的item，你可以用这个作为判断的标记，来设置不同的type。\n[view source](http://www.it165.net/pro/html/201406/16181.html#viewSource)[print](http://www.it165.net/pro/html/201406/16181.html#printSource)[?](http://www.it165.net/pro/html/201406/16181.html#about) `01.``@Override` \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `02.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `int` `getItemViewType(``int` `position) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `03.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`// TODO Auto-generated method stub`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `04.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`if` `(``\u0026quot;0\u0026quot;``.equals(dataList.get(position).getMr_type())) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `05.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `TYPE_COMSUM;``// 消费类型`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `06.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`} ``else` `if` `(``\u0026quot;1\u0026quot;``.equals(dataList.get(position).getMr_type())) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `07.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `TYPE_CHARGE;``// 充值类型`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `08.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`} ``else` `{`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `09.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `100``;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `10.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `11.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `12.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `13.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`@Override`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `14.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`public` `int` `getViewTypeCount() {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `15.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `TYPE_COUNT;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `16.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; viewholder：缓存这几个textview控件\n[view source](http://www.it165.net/pro/html/201406/16181.html#viewSource)[print](http://www.it165.net/pro/html/201406/16181.html#printSource)[?](http://www.it165.net/pro/html/201406/16181.html#about) `01.``/**` \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `02.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* 消费记录`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `03.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* @author yl`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `04.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`*`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `05.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`*/`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `06.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`class` `ComsumViewHolder {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `07.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`TextView branchnameCom;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `08.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`TextView comsumemoney;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `09.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`TextView useprevillage;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `10.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`TextView yuezhifu;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `11.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`TextView cash;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `12.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`TextView thisscore;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `13.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`TextView extrareward;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `14.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`TextView prestoremoney;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `15.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `16.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `17.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`/**`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `18.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* 充值记录`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `19.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`* @author yl`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `20.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`*`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `21.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`*/`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `22.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`class` `ChargeViewHolder {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `23.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`TextView branchnameCha;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `24.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`TextView prestoremoney;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `25.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`TextView extrasmoney;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `26.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`TextView totalmoney;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `27.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 最后是getview方法：其中有一个关键的方法\n[view source](http://www.it165.net/pro/html/201406/16181.html#viewSource)[print](http://www.it165.net/pro/html/201406/16181.html#printSource)[?](http://www.it165.net/pro/html/201406/16181.html#about) `1.``currentType = getItemViewType(position);` 这个方法获取到当前position的类型，也就是在前面的getItemViewType方法设置的类型。\n其中对convertView进行了复用和holder的使用，算是对listview的优化吧。\n当currentType == TYPE_COMSUM，消费类型时，加载comsumView = LayoutInflater.from(mContext).inflate( R.layout.traderecord_item_comsume, null);消费类型的布局文件。反之，加载充值类型的布局文件。这样就可以达到为不同的item设置不同的布局文件了。\n[view source](http://www.it165.net/pro/html/201406/16181.html#viewSource)[print](http://www.it165.net/pro/html/201406/16181.html#printSource)[?](http://www.it165.net/pro/html/201406/16181.html#about) `01.``public` `View getView(``int` `position, View convertView, ViewGroup parent) {` \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `02.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`// TODO Auto-generated method stub`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `03.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`View comsumView = ``null``;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `04.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`View chargeView = ``null``;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `05.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `06.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`ComsumAndChargeRecordBean record = (ComsumAndChargeRecordBean) dataList`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `07.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.get(position).getMr_content();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `08.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `09.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`currentType = getItemViewType(position);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `10.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`if` `(currentType == TYPE_COMSUM) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `11.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`ComsumViewHolder comsumHolder = ``null``;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `12.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`if` `(convertView == ``null``) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `13.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder = ``new` `ComsumViewHolder();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `14.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumView = LayoutInflater.from(mContext).inflate(`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `15.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`R.layout.traderecord_item_comsume, ``null``);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `16.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.branchnameCom = (TextView) comsumView`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `17.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.findViewById(R.id.tv_branch_name);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `18.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.comsumemoney = (TextView) comsumView`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `19.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.findViewById(R.id.tv_comsumemoney);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `20.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.useprevillage = (TextView) comsumView`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `21.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.findViewById(R.id.tv_useprevillage);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `22.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.yuezhifu = (TextView) comsumView`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `23.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.findViewById(R.id.tv_yuezhifu);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `24.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.cash = (TextView) comsumView`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `25.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.findViewById(R.id.tv_cash);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `26.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.thisscore = (TextView) comsumView`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `27.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.findViewById(R.id.tv_thisscore);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `28.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.extrareward = (TextView) comsumView`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `29.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.findViewById(R.id.tv_extrareward);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `30.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumView.setTag(comsumHolder);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `31.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`convertView = comsumView;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `32.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`} ``else` `{`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `33.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder = (ComsumViewHolder) convertView.getTag();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `34.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `35.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.branchnameCom.setText(DateFormatUtil.formatDate(Long`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `36.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.valueOf(dataList.get(position).getMr_createtime()))`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `37.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`+ ``\u0026quot; \u0026quot;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `38.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`+ record.getBranch_name());``// 消费时间和分店`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `39.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.comsumemoney.setText(record.getPay_money());``// 消费金额`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `40.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.useprevillage.setText(record.getCoupon());``// 使用特权`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `41.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.yuezhifu.setText(record.getMember_money());``// 余额支付`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `42.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.cash.setText(record.getCash());``// 现金支付`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `43.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.thisscore.setText(record.getPoint());``// 本次积分`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `44.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`comsumHolder.extrareward.setText(record.getBonus());``// 额外奖励`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `45.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`} ``else` `if` `(currentType == TYPE_CHARGE) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `46.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`ChargeViewHolder chargeHoler = ``null``;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `47.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`if` `(convertView == ``null``) {`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `48.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`chargeHoler = ``new` `ChargeViewHolder();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `49.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`chargeView = LayoutInflater.from(mContext).inflate(`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `50.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`R.layout.traderecord_item_chongzhi, ``null``);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `51.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`chargeHoler.branchnameCha = (TextView) chargeView`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `52.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.findViewById(R.id.tv_branchname_charge);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `53.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`chargeHoler.prestoremoney = (TextView) chargeView`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `54.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.findViewById(R.id.tv_prestoremoney);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `55.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`chargeHoler.extrasmoney = (TextView) chargeView`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `56.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.findViewById(R.id.tv_extrasmoney);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `57.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`chargeHoler.totalmoney = (TextView) chargeView`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `58.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.findViewById(R.id.tv_totalmoney);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `59.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`chargeView.setTag(chargeHoler);`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `60.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`convertView = chargeView;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `61.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`} ``else` `{`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `62.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`chargeHoler = (ChargeViewHolder) convertView.getTag();`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `63.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `64.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `65.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`chargeHoler.branchnameCha.setText(DateFormatUtil.formatDate(Long`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `66.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`.valueOf(dataList.get(position).getMr_createtime()))`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `67.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`+ ``\u0026quot; \u0026quot;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `68.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`+ record.getBranch_name());``// 消费时间和分店`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `69.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`// chargeHoler.prestoremoney.setText(record.getPrestore_money() +`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `70.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`// \u0026quot;元\u0026quot;);// 存款`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `71.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`chargeHoler.extrasmoney.setText(record.getMember_money() + ``\u0026quot;元\u0026quot;``);``// 余额`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `72.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`chargeHoler.totalmoney.setText(record.getMember_money() + ``\u0026quot;元\u0026quot;``);``// 合计`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `73.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; `74.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`return` `convertView;`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; `75.`\u0026lt;span class=\u0026quot;content\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;block\u0026quot;\u0026gt;`}`\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 上面就是整个效果的实现过程\n四、总结\n其实为listview的item设置不同的布局文件，达到上面的效果，步骤如下;\n1、为不同的item写不同的布局文件，设置统一的javabean类\n2、继承BaseAdapter类，实现getItemViewType(int position)和getViewTypeCount() 方法，根据这两个方法，为item设置不同的标记，也就是不同的type\n3、在getView方法中，利用getItemViewType(position)方法获取当前的type类型，然后根据不同的type类型，加载不同的item布局文件。\n4、其他的一些listview的优化同一般的listview没有很大区别。\n转自：http://www.it165.net/pro/html/201406/16181.html\n","permalink":"https://blog.zdltech.com/posts/adapter%E7%9A%84getviewtypecount%E5%92%8Cgetitemviewtype-%E4%BD%BF%E7%94%A8/","summary":"\u003cp\u003e通过本篇文章，让你掌握新的技巧，请不用只看看一点，希望能够看完，让你很快明白不同的使用场景\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eListView 和 Adapter 的基础\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e工作原理:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eListView 针对List中每个item，要求 adapter “给我一个视图” (getView)。\u003c/li\u003e\n\u003cli\u003e一个新的视图被返回并显示\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e如果我们有上亿个项目要显示怎么办？为每个项目创建一个新视图？NO!这不可能！\u003c/p\u003e\n\u003cp\u003e实际上Android为你缓存了视图。\u003c/p\u003e\n\u003cp\u003eAndroid中有个叫做Recycler的构件，下图是他的工作原理：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://android.amberfog.com/images/2010/02/listview_recycler.jpg\"\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e如果你有10亿个项目(item)，其中只有可见的项目存在内存中，其他的在Recycler中。\u003c/li\u003e\n\u003cli\u003eListView先请求一个type1视图(getView)然后请求其他可见的项目。convertView在getView中是空(null)的。\u003c/li\u003e\n\u003cli\u003e当item1滚出屏幕，并且一个新的项目从屏幕低端上来时，ListView再请求一个type1视图。convertView此时不是空值了，它的值是item1。你只需设定新的数据然后返回convertView，不必重新创建一个视图。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e请看下面的示例代码，这里在getView中使用了System.out进行输出\u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv\u003e\n    \u003cdiv id=\"highlighter_927201\"\u003e\n      \u003cdiv\u003e\n        \u003cdiv id=\"highlighter_651324\" class=\"syntaxhighlighter  java\"\u003e\n          \u003cdiv class=\"toolbar\"\u003e\n            [?](http://www.aitinan.com/3885.html#)\n          \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n        \u0026lt;tr\u0026gt;\n          \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n              1\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n              2\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n              3\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n              4\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n              5\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n              6\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n              7\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n              8\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n              9\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n              10\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n              11\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n              12\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n              13\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n              14\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n              15\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n              16\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n              17\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n              18\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n              19\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n              20\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n              21\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n              22\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n              23\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n              24\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n              25\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n              26\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n              27\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n              28\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n              29\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n              30\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n              31\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n              32\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n              33\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt;\n              34\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt;\n              35\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt;\n              36\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt;\n              37\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt;\n              38\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt;\n              39\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt;\n              40\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt;\n              41\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt;\n              42\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt;\n              43\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt;\n              44\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt;\n              45\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt;\n              46\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt;\n              47\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt;\n              48\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt;\n              49\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt;\n              50\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt;\n              51\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt;\n              52\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt;\n              53\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt;\n              54\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt;\n              55\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt;\n              56\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt;\n              57\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt;\n              58\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt;\n              59\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt;\n              60\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt;\n              61\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt;\n              62\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt;\n              63\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt;\n              64\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt;\n              65\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n          \n          \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n              \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n                `public` `class` `MultipleItemsListextends ListActivity {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n                `  `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n                `    ``private` `MyCustomAdapter mAdapter;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n                `  `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n                `    ``@Override`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n                `    ``public` `void` `onCreate(Bundle savedInstanceState) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n                `        ``super``.onCreate(savedInstanceState);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n                `        ``mAdapter = ``new` `MyCustomAdapter();`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n                `        ``for` `(``int` `i = ````; i \u0026amp;lt; ``50``; i++) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n                `            ``mAdapter.addItem(``\u0026quot;item \u0026quot;` `+ i);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n                `        ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n                `        ``setListAdapter(mAdapter);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n                `    ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n                `  `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n                `    ``private` `class` `MyCustomAdapterextends BaseAdapter {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n                `  `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n                `        ``private` `ArrayList mData = ``new` `ArrayList();`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n                `        ``private` `LayoutInflater mInflater;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n                `  `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n                `        ``public` `MyCustomAdapter() {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n                `            ``mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n                `        ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n                `  `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n                `        ``public` `void` `addItem(``final` `String item) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n                `            ``mData.add(item);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n                `            ``notifyDataSetChanged();`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n                `        ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n                `  `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n                `        ``@Override`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n                `        ``public` `int` `getCount() {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n                `            ``return` `mData.size();`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n                `        ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n                `  `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt;\n                `        ``@Override`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt;\n                `        ``public` `String getItem(``int` `position) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt;\n                `            ``return` `mData.get(position);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt;\n                `        ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt;\n                `  `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt;\n                `        ``@Override`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt;\n                `        ``public` `long` `getItemId(``int` `position) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt;\n                `            ``return` `position;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt;\n                `        ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt;\n                `  `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt;\n                `        ``@Override`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt;\n                `        ``public` `View getView(``int` `position, View convertView, ViewGroup parent) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt;\n                `            ``System.out.println(``\u0026quot;getView \u0026quot;` `+ position + ``\u0026quot; \u0026quot;` `+ convertView);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt;\n                `            ``ViewHolder holder = ``null``;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt;\n                `            ``if` `(convertView == ``null``) {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt;\n                `                ``convertView = mInflater.inflate(R.layout.item1, ``null``);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt;\n                `                ``holder = ``new` `ViewHolder();`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt;\n                `                ``holder.textView = (TextView)convertView.findViewById(R.id.text);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt;\n                `                ``convertView.setTag(holder);`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt;\n                `            ``}``else` `{`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt;\n                `                ``holder = (ViewHolder)convertView.getTag();`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt;\n                `            ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt;\n                `            ``holder.textView.setText(mData.get(position));`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt;\n                `            ``return` `convertView;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt;\n                `        ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt;\n                `  `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt;\n                `    ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt;\n                `  `\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt;\n                `    ``public` `static` `class` `ViewHolder {`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt;\n                `        ``public` `TextView textView;`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt;\n                `    ``}`\n              \u0026lt;/div\u0026gt;\n              \n              \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt;\n                `}`\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/td\u0026gt;\n        \u0026lt;/tr\u0026gt;\n      \u0026lt;/table\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e执行程序，然后在Logcat中查看日志\u003c/p\u003e","title":"Adapter的getViewTypeCount和getItemViewType 使用"},{"content":"android TypedValue.applyDimension()的作用\n这个方法是转变为标准尺寸的一个函数，例如\nint size = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, context.getResources().getDisplayMetrics());\n这里COMPLEX_UNIT_SP是单位，20是数值，也就是20sp。\nint size = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, context.getResources().getDisplayMetrics());\n这里COMPLEX_UNIT_DIP是单位，20是数值，也就是20dp。\n","permalink":"https://blog.zdltech.com/posts/android-typedvalue-applydimension%E7%9A%84%E4%BD%9C%E7%94%A8/","summary":"\u003cp\u003eandroid TypedValue.applyDimension()的作用\u003c/p\u003e\n\u003cp\u003e这个方法是转变为标准尺寸的一个函数，例如\u003cbr\u003e\nint size = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, context.getResources().getDisplayMetrics());\u003c/p\u003e\n\u003cp\u003e这里COMPLEX_UNIT_SP是单位，20是数值，也就是20sp。\u003c/p\u003e\n\u003cp\u003eint size = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, context.getResources().getDisplayMetrics());\u003c/p\u003e\n\u003cp\u003e这里COMPLEX_UNIT_DIP是单位，20是数值，也就是20dp。\u003c/p\u003e","title":"android TypedValue.applyDimension()的作用"},{"content":"转载：http://blog.csdn.net/singwhatiwanna/article/details/17515543\n前言 用过微信的都知道，微信对话列表滑动删除效果是很不错的，这个效果我们也可以有。思路其实很简单，弄个ListView，然后里面的每个item做成一个可以滑动的自定义控件即可。由于ListView是上下滑动而item是左右滑动，因此会有滑动冲突，也许你需要了解下android中点击事件的派发流程，请参考Android源码分析-点击事件派发机制。我的解决思路是这样的：重写ListView的onInterceptTouchEvent方法，在move的时候做判断，如果是左右滑动就返回false，否则返回true；重写SlideView（即自定义item控件）的onTouchEvent方法来处理滑动。整个思路没有问题，滑动冲突也解决了，可是ListView无法得到焦点了，也就是ListView无法处理点击事件了。让我们回想下问题出在哪里：我的理解是这样的，上述处理滑动本身没有问题，但是有一个副作用，就是会让外层View失去焦点且无法处理点击事件。常见的滑动冲突场景，比如launcher内部嵌入ListView却是没有问题的，因为这个时候launcher不需要获得焦点，需要获得焦点的是内部的ListView。因此，上述处理方式对于外部需要获得焦点的情况（比如外部是ListView）就不太适合了。于是我就和ttdevs探讨，发现他采用了另外一种思路，我从来没有想过还可以这样玩。下面介绍他的思路。\n新的思路 不考虑那么复杂，不采用主流玩法，所有的事件均由外层的ListView做拦截，同时把事件传递给SlideView做滑动，这种实现的确可以达到效果，而且代码很简单，根本不需要处理什么复杂的滑动冲突。\n效果 下面分别为微信和高仿效果\n代码分析 先看SlideView是如何实现的\n看layout xml：\n**[html]** [view plain](http://blog.csdn.net/singwhatiwanna/article/details/17515543#)[copy](http://blog.csdn.net/singwhatiwanna/article/details/17515543#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/125514)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/125514/fork) - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;merge\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/view_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/holder\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;120dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:clickable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/holder_bg\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/delete\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:drawableLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/del_icon_normal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerInParent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@color/floralwhite\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;删除\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;merge\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 上述xml文件中，所有的view都会被放在view_content中，而holder是放置诸如删除按钮之类的东西，我们的SlideView会加载这个布局。\n再看SlideView.java：\n**[java]** [view plain](http://blog.csdn.net/singwhatiwanna/article/details/17515543#)[copy](http://blog.csdn.net/singwhatiwanna/article/details/17515543#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/125514)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/125514/fork) - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * SlideView 继承自LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SlideView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;SlideView\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context mContext; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 用来放置所有view的容器\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LinearLayout mViewContent; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 用来放置内置view的容器，比如删除 按钮\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; RelativeLayout mHolder; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 弹性滑动对象，提供弹性滑动效果\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Scroller mScroller; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑动回调接口，用来向上层通知滑动事件\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnSlideListener mOnSlideListener; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 内置容器的宽度 单位：dp\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mHolderWidth = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;120\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 分别记录上次滑动的坐标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mLastX = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mLastY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 用来控制滑动角度，仅当角度a满足如下条件才进行滑动：tan a = deltaX / deltaY \u0026gt; 2\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; TAN = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnSlideListener { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// SlideView的三种状态：开始滑动，打开，关闭\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; SLIDE_STATUS_OFF = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; SLIDE_STATUS_START_SCROLL = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; SLIDE_STATUS_ON = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param view\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * current SlideView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param status\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * SLIDE_STATUS_ON, SLIDE_STATUS_OFF or\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * SLIDE_STATUS_START_SCROLL\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSlide(View view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; status); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SlideView(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - initView(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SlideView(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - initView(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() { - mContext = getContext(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始化弹性滑动对象\u0026lt;/span\u0026gt; - mScroller = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Scroller(mContext); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置其方向为横向\u0026lt;/span\u0026gt; - setOrientation(LinearLayout.HORIZONTAL); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 将slide_view_merge加载进来\u0026lt;/span\u0026gt; - View.inflate(mContext, R.layout.slide_view_merge, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - mViewContent = (LinearLayout) findViewById(R.id.view_content); - mHolderWidth = Math.round(TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, mHolderWidth, getResources() - .getDisplayMetrics())); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置按钮的内容，也可以设置图标啥的，我没写\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setButtonText(CharSequence text) { - ((TextView) findViewById(R.id.delete)).setText(text); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 将view加入到ViewContent中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setContentView(View view) { - mViewContent.addView(view); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 设置滑动回调\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnSlideListener(OnSlideListener onSlideListener) { - mOnSlideListener = onSlideListener; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 将当前状态置为关闭\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; shrink() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollX() != \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 根据MotionEvent来进行滑动，这个方法的作用相当于onTouchEvent\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果你不需要处理滑动冲突，可以直接重命名，照样能正常工作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onRequireTouchEvent(MotionEvent event) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getX(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getY(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollX = getScrollX(); - Log.d(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;x=\u0026amp;#8221;\u0026lt;/span\u0026gt; + x + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; y=\u0026amp;#8221;\u0026lt;/span\u0026gt; + y); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (event.getAction()) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!mScroller.isFinished()) { - mScroller.abortAnimation(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mOnSlideListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mOnSlideListener.onSlide(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, - OnSlideListener.SLIDE_STATUS_START_SCROLL); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (Math.abs(deltaX) \u0026lt; Math.abs(deltaY) * TAN) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑动不满足条件，不做横向滑动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 计算滑动终点是否合法，防止滑动越界\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (deltaX != \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (newScrollX \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - newScrollX = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (newScrollX \u0026gt; mHolderWidth) { - newScrollX = mHolderWidth; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.scrollTo(newScrollX, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; newScrollX = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这里做了下判断，当松开手的时候，会自动向两边滑动，具体向哪边滑，要看当前所处的位置\u0026lt;/span\u0026gt; - newScrollX = mHolderWidth; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 慢慢滑向终点\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(newScrollX, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 通知上层滑动事件\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mOnSlideListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mOnSlideListener.onSlide(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, - newScrollX == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; ? OnSlideListener.SLIDE_STATUS_OFF - : OnSlideListener.SLIDE_STATUS_ON); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - - mLastX = x; - mLastY = y; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; smoothScrollTo(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; destX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; destY) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 缓慢滚动到指定位置\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollX = getScrollX(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 以三倍时长滑向destX，效果就是慢慢滑动\u0026lt;/span\u0026gt; - mScroller.startScroll(scrollX, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, delta, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, Math.abs(delta) * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;); - invalidate(); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mScroller.computeScrollOffset()) { - scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); - postInvalidate(); - } - } - - } 上述代码做了很详细的说明，这就是滑动控件的完整代码，大家要明白的是：你所添加的view都是加在SlideView的子View : view_content中的，而不是直接加在SlideView中，只有这样我们才方便做滑动效果。\n接着看ListView的代码：核心就是下面这一个方法，将点击事件发送给SlideView处理。\n**[java]** [view plain](http://blog.csdn.net/singwhatiwanna/article/details/17515543#)[copy](http://blog.csdn.net/singwhatiwanna/article/details/17515543#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/125514)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/125514/fork) - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent event) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (event.getAction()) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getX(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getY(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//我们想知道当前点击了哪一行\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position = pointToPosition(x, y); - Log.e(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;postion=\u0026amp;#8221;\u0026lt;/span\u0026gt; + position); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (position != INVALID_POSITION) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//得到当前点击行的数据从而取出当前行的item。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//可能有人怀疑，为什么要这么干？为什么不用getChildAt(position)？\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//因为ListView会进行缓存，如果你不这么干，有些行的view你是得不到的。\u0026lt;/span\u0026gt; - MessageItem data = (MessageItem) getItemAtPosition(position); - mFocusedItemView = data.slideView; - Log.e(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;FocusedItemView=\u0026amp;#8221;\u0026lt;/span\u0026gt; + mFocusedItemView); - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//向当前点击的view发送滑动事件请求，其实就是向SlideView发请求\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mFocusedItemView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mFocusedItemView.onRequireTouchEvent(event); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(event); - } 最后看Activity的代码：\n**[java]** [view plain](http://blog.csdn.net/singwhatiwanna/article/details/17515543#)[copy](http://blog.csdn.net/singwhatiwanna/article/details/17515543#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/125514)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/125514/fork) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnItemClickListener, - OnClickListener, OnSlideListener { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ListViewCompat mListView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;MessageItem\u0026gt; mMessageItems = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;MainActivity.MessageItem\u0026gt;(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; SlideAdapter mSlideAdapter; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上次处于打开状态的SlideView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; SlideView mLastSlideViewWithStatusOn; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - initView(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() { - mListView = (ListViewCompat) findViewById(R.id.list); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;; i++) { - MessageItem item = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MessageItem(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (i % \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt; == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - item.iconRes = R.drawable.default_qq_avatar; - item.title = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;腾讯新闻\u0026amp;#8221;\u0026lt;/span\u0026gt;; - item.msg = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;青岛爆炸满月：大量鱼虾死亡\u0026amp;#8221;\u0026lt;/span\u0026gt;; - item.time = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;晚上18:18\u0026amp;#8221;\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - item.iconRes = R.drawable.wechat_icon; - item.title = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;微信团队\u0026amp;#8221;\u0026lt;/span\u0026gt;; - item.msg = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;欢迎你使用微信\u0026amp;#8221;\u0026lt;/span\u0026gt;; - item.time = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;12月18日\u0026amp;#8221;\u0026lt;/span\u0026gt;; - } - mMessageItems.add(item); - } - mSlideAdapter = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SlideAdapter(); - mListView.setAdapter(mSlideAdapter); - mListView.setOnItemClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SlideAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; BaseAdapter { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LayoutInflater mInflater; - - SlideAdapter() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(); - mInflater = getLayoutInflater(); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mMessageItems.size(); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object getItem(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mMessageItems.get(position); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getItemId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; position; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) { - ViewHolder holder; - SlideView slideView = (SlideView) convertView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (slideView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这里是我们的item\u0026lt;/span\u0026gt; - View itemView = mInflater.inflate(R.layout.list_item, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - - slideView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SlideView(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这里把item加入到slideView\u0026lt;/span\u0026gt; - slideView.setContentView(itemView); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下面是做一些数据缓存\u0026lt;/span\u0026gt; - holder = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewHolder(slideView); - slideView.setOnSlideListener(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - slideView.setTag(holder); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - holder = (ViewHolder) slideView.getTag(); - } - MessageItem item = mMessageItems.get(position); - item.slideView = slideView; - item.slideView.shrink(); - - holder.icon.setImageResource(item.iconRes); - holder.title.setText(item.title); - holder.msg.setText(item.msg); - holder.time.setText(item.time); - holder.deleteHolder.setOnClickListener(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; slideView; - } - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MessageItem { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; iconRes; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String title; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String msg; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String time; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SlideView slideView; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ViewHolder { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ImageView icon; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; TextView title; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; TextView msg; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; TextView time; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ViewGroup deleteHolder; - - ViewHolder(View view) { - icon = (ImageView) view.findViewById(R.id.icon); - title = (TextView) view.findViewById(R.id.title); - msg = (TextView) view.findViewById(R.id.msg); - time = (TextView) view.findViewById(R.id.time); - deleteHolder = (ViewGroup) view.findViewById(R.id.holder); - } - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onItemClick(AdapterView\u0026lt;?\u0026gt; parent, View view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; id) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这里处理ListItem的点击事件\u0026lt;/span\u0026gt; - Log.e(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onItemClick position=\u0026amp;#8221;\u0026lt;/span\u0026gt; + position); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSlide(View view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; status) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果当前存在已经打开的SlideView，那么将其关闭\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mLastSlideViewWithStatusOn != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; mLastSlideViewWithStatusOn != view) { - mLastSlideViewWithStatusOn.shrink(); - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 记录本次处于打开状态的view\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (status == SLIDE_STATUS_ON) { - mLastSlideViewWithStatusOn = (SlideView) view; - } - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这里处理删除按钮的点击事件，可以删除对话\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (v.getId() == R.id.holder) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position = mListView.getPositionForView(v); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (position != ListView.INVALID_POSITION) { - mMessageItems.remove(position); - mSlideAdapter.notifyDataSetChanged(); - } - Log.e(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onClick v=\u0026amp;#8221;\u0026lt;/span\u0026gt; + v); - } - } - } 代码我都特意写了注释，就不多说了。\n代码下载：http://download.csdn.net/detail/singwhatiwanna/6760085\n另外此博文采用了 ttdevs 所提供代码的部分思想(他的博客是http://blog.csdn.net/ttdevs)\n","permalink":"https://blog.zdltech.com/posts/%E9%AB%98%E4%BB%BF%E5%BE%AE%E4%BF%A1%E5%AF%B9%E8%AF%9D%E5%88%97%E8%A1%A8%E6%BB%91%E5%8A%A8%E5%88%A0%E9%99%A4%E6%95%88%E6%9E%9C/","summary":"\u003cp\u003e转载：http://blog.csdn.net/singwhatiwanna/article/details/17515543\u003c/p\u003e\n\u003ch2 id=\"前言\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003e前言\u003c/h2\u003e\n\u003cp\u003e用过微信的都知道，微信对话列表滑动删除效果是很不错的，这个效果我们也可以有。思路其实很简单，弄个ListView，然后里面的每个item做成一个可以滑动的自定义控件即可。由于ListView是上下滑动而item是左右滑动，因此会有滑动冲突，也许你需要了解下android中点击事件的派发流程，请参考\u003ca href=\"http://blog.csdn.net/singwhatiwanna/article/details/17339857\"\u003eAndroid源码分析-点击事件派发机制\u003c/a\u003e。我的解决思路是这样的：重写ListView的onInterceptTouchEvent方法，在move的时候做判断，如果是左右滑动就返回false，否则返回true；重写SlideView（即自定义item控件）的onTouchEvent方法来处理滑动。整个思路没有问题，滑动冲突也解决了，可是ListView无法得到焦点了，也就是ListView无法处理点击事件了。让我们回想下问题出在哪里：我的理解是这样的，上述处理滑动本身没有问题，但是有一个副作用，就是会让外层View失去焦点且无法处理点击事件。常见的滑动冲突场景，比如launcher内部嵌入ListView却是没有问题的，因为这个时候launcher不需要获得焦点，需要获得焦点的是内部的ListView。因此，上述处理方式对于外部需要获得焦点的情况（比如外部是ListView）就不太适合了。于是我就和ttdevs探讨，发现他采用了另外一种思路，我从来没有想过还可以这样玩。下面介绍他的思路。\u003c/p\u003e\n\u003ch2 id=\"新的思路\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e新的思路\u003c/h2\u003e\n\u003cp\u003e不考虑那么复杂，不采用主流玩法，所有的事件均由外层的ListView做拦截，同时把事件传递给SlideView做滑动，这种实现的确可以达到效果，而且代码很简单，根本不需要处理什么复杂的滑动冲突。\u003c/p\u003e\n\u003ch2 id=\"效果\"\u003e\u003ca name=\"t2\"\u003e\u003c/a\u003e效果\u003c/h2\u003e\n\u003cp\u003e下面分别为微信和高仿效果\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20131224003419203?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luZ3doYXRpd2FubmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20131224003445812?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luZ3doYXRpd2FubmE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003ch2 id=\"代码分析\"\u003e\u003ca name=\"t3\"\u003e\u003c/a\u003e代码分析\u003c/h2\u003e\n\u003cp\u003e先看SlideView是如何实现的\u003c/p\u003e\n\u003cp\u003e看layout xml：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]**\u003cspan class=\"Apple-converted-space\"\u003e \u003c/span\u003e[view plain](http://blog.csdn.net/singwhatiwanna/article/details/17515543#)[copy](http://blog.csdn.net/singwhatiwanna/article/details/17515543#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/125514)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/125514/fork)\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;merge\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/view_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/holder\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;120dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:clickable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/holder_bg\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/delete\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:drawableLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/del_icon_normal\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerInParent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@color/floralwhite\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;删除\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;merge\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e上述xml文件中，所有的view都会被放在view_content中，而holder是放置诸如删除按钮之类的东西，我们的SlideView会加载这个布局。\u003c/p\u003e","title":"高仿微信对话列表滑动删除效果"},{"content":"\n# [smark](http://www.cnblogs.com/smark/) [https://github.com/IKende/](https://github.com/IKende/) ## [TCP密集IO吞吐压力测试工具](http://www.cnblogs.com/smark/archive/2013/01/08/2850900.html) \u0026lt;div class=\u0026quot;postText\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;cnblogs_post_body\u0026quot;\u0026gt; 一 般在写一些网络服务应用的时候都比较关注服务在网络同时读写的能力，为了方便对这方面应用的测试所以写了这样一个测试的工具。工具的主要作用可以通过不同 的连接数来对一个服务应用进行一个读写压力请求，并实时查看当前IO的读写次数和每次请求的延时情况等。为大家介绍的这个工具是第二版，相对于第一版主要 引入了beetle 2.7提供更强的测试效能，在界面上也做了调整使其查看结果直观。 ## 工具应用界面 ![](http://images.cnitblog.com/blog/254151/201301/08122659-247f9367b4d44adb9053c7929de117b8.jpg) ### 功能简介 工具是测试服务端的网络读写能力，主要原理先向服务端发送一个请求，服务端根据请求进行一个应答;工具在得到应答后会再次进入下一次请求，通过这样一个循还来得到一个服务端的请求应答数量;用户可以根据自己的需要设置对应测试的连接数。 ### 发送数据定义 组件提供两种数据发送方式 String 通过UTF8对string编码后进行发送. base64String 由于工具不提供基于二制度的发送，所以提供一个基于base64String的发送方式，用户可以把需要发送的byte[]转成base64String即可。 添加头描述 如果有需要可以给发送数据添加一个int(4节字长度的头)，其值是消息长度+4 ### 测试结果 工具并不会提供一个完全整的测试结果，它只反映服务端的应答情况，如：总请求数，秒应答数和每个连接请求延时等。这些结果只是反映出服务端的网络读写效能。对于怎样的一个数值才算是好呢，这个就要根据硬件来评定。以下提供一个E1230下的网络处理效能的结果参考 ![](http://images.cnitblog.com/blog/254151/201301/08124458-d5d82f98baed4cd4b996b80148bcf97d.jpg) [下载工具](http://blog.henryfan.net/file.axd?file=2013%2f1%2fTCPPerformanceTest1.2.rar) (运行环境.net 4.0) 对工具有什么意见可以提一下，我会进一步完善它。 \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;MySignature\u0026quot;\u0026gt; 个人站:[www.ikende.com](http://www.ikende.com/) 个人开源项目github.com/IKende\n[elastic communication component for .net](http://ec.ikende.com/) c#组件设计交流群：47164588 c# socket :136485198 微博http://weibo.com/ikende ","permalink":"https://blog.zdltech.com/posts/tcp%E5%AF%86%E9%9B%86io%E5%90%9E%E5%90%90%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/","summary":"\u003cp\u003e\u003ca name=\"top\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv id=\"main\"\u003e\n  \u003cdiv id=\"header\"\u003e\n    # [smark](http://www.cnblogs.com/smark/)\n\u003cpre\u003e\u003ccode\u003e  [https://github.com/IKende/](https://github.com/IKende/)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"post\"\u003e\n    ## [TCP密集IO吞吐压力测试工具](http://www.cnblogs.com/smark/archive/2013/01/08/2850900.html)\n\u003cpre\u003e\u003ccode\u003e\u0026lt;div class=\u0026quot;postText\u0026quot;\u0026gt;\n  \u0026lt;div id=\u0026quot;cnblogs_post_body\u0026quot;\u0026gt;\n    \n\n      一 般在写一些网络服务应用的时候都比较关注服务在网络同时读写的能力，为了方便对这方面应用的测试所以写了这样一个测试的工具。工具的主要作用可以通过不同 的连接数来对一个服务应用进行一个读写压力请求，并实时查看当前IO的读写次数和每次请求的延时情况等。为大家介绍的这个工具是第二版，相对于第一版主要 引入了beetle 2.7提供更强的测试效能，在界面上也做了调整使其查看结果直观。\n    \n\n    \n    ## 工具应用界面\n    \n    \n\n      ![](http://images.cnitblog.com/blog/254151/201301/08122659-247f9367b4d44adb9053c7929de117b8.jpg)\n    \n\n    \n    ### 功能简介\n    \n    \n\n      工具是测试服务端的网络读写能力，主要原理先向服务端发送一个请求，服务端根据请求进行一个应答;工具在得到应答后会再次进入下一次请求，通过这样一个循还来得到一个服务端的请求应答数量;用户可以根据自己的需要设置对应测试的连接数。\n    \n\n    \n    ### 发送数据定义\n    \n    \n\n      组件提供两种数据发送方式\n    \n\n    \n    \n\n      String\n    \n\n    \n    \n\n      通过UTF8对string编码后进行发送.\n    \n\n    \n    \n\n      base64String\n    \n\n    \n    \n\n      由于工具不提供基于二制度的发送，所以提供一个基于base64String的发送方式，用户可以把需要发送的byte[]转成base64String即可。\n    \n\n    \n    \n\n      添加头描述\n    \n\n    \n    \n\n      如果有需要可以给发送数据添加一个int(4节字长度的头)，其值是消息长度+4\n    \n\n    \n    ### 测试结果\n    \n    \n\n      工具并不会提供一个完全整的测试结果，它只反映服务端的应答情况，如：总请求数，秒应答数和每个连接请求延时等。这些结果只是反映出服务端的网络读写效能。对于怎样的一个数值才算是好呢，这个就要根据硬件来评定。以下提供一个E1230下的网络处理效能的结果参考\n    \n\n    \n    \n\n      ![](http://images.cnitblog.com/blog/254151/201301/08124458-d5d82f98baed4cd4b996b80148bcf97d.jpg)\n    \n\n    \n    \n\n      [下载工具](http://blog.henryfan.net/file.axd?file=2013%2f1%2fTCPPerformanceTest1.2.rar) (运行环境.net 4.0)\n    \n\n    \n    \n\n      对工具有什么意见可以提一下，我会进一步完善它。\n    \n\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div id=\u0026quot;MySignature\u0026quot;\u0026gt;\n    \n\n      个人站:[www.ikende.com](http://www.ikende.com/)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e个人开源项目\u003ca href=\"http://github.com/IKende/\"\u003egithub.com/IKende\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e      [elastic communication component for .net](http://ec.ikende.com/)\n    \n\n    \n    \n\n      c#组件设计交流群：47164588\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003ec# socket :136485198 \u003ca href=\"http://weibo.com/ikende\"\u003e微博http://weibo.com/ikende\u003c/a\u003e\u003c/div\u003e \u003c/div\u003e \u003c/div\u003e \u003c/div\u003e\u003c/p\u003e","title":"TCP密集IO吞吐压力测试工具"},{"content":"friend.xml\n**[java]** [view plain](http://blog.csdn.net/csh159/article/details/8955029#)[copy](http://blog.csdn.net/csh159/article/details/8955029#)[print](http://blog.csdn.net/csh159/article/details/8955029#)[?](http://blog.csdn.net/csh159/article/details/8955029#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;?xml version=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; encoding=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;?\u0026gt; - \u0026lt;LinearLayout xmlns:android=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:orientation=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; - \u0026lt;RelativeLayout - android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:orientation=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; - - \u0026lt;ListView - android:id=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@+id/list_view\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:scrollbars=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;none\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; - \u0026lt;/ListView\u0026gt; - - \u0026lt;com.example.menu.MyLetterListView - android:id=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@+id/my_list_view\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;30dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_alignParentRight=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - /\u0026gt; - \u0026lt;/RelativeLayout\u0026gt; - - \u0026lt;/LinearLayout\u0026gt; friend_header.xml\n**[html]** [view plain](http://blog.csdn.net/csh159/article/details/8955029#)[copy](http://blog.csdn.net/csh159/article/details/8955029#)[print](http://blog.csdn.net/csh159/article/details/8955029#)[?](http://blog.csdn.net/csh159/article/details/8955029#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;FrameLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;2dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;2dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/friend_search_head_title\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:clickable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20sp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/friend_center_back\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;right|center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:clickable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;FrameLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; list_item.xml\n**[html]** [view plain](http://blog.csdn.net/csh159/article/details/8955029#)[copy](http://blog.csdn.net/csh159/article/details/8955029#)[print](http://blog.csdn.net/csh159/article/details/8955029#)[?](http://blog.csdn.net/csh159/article/details/8955029#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;UTF-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/alpha\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#333333\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#FFFFFF\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:visibility\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;gone\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/imageView\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_alignParentLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/contact_list_icon\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_below\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/alpha\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/divider\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_below\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/alpha\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;11.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_toRightOf\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/imageView\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/name\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_alignTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/divider\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;2.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;6.0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_toRightOf\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/divider\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:singleLine\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textAppearance\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;?android:textAppearanceMedium\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/number\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_alignLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/name\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_alignWithParentIfMissing\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_below\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/name\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:ellipsize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;marquee\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:singleLine\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textAppearance\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;?android:textAppearanceSmall\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; overlay.xml\n**[html]** [view plain](http://blog.csdn.net/csh159/article/details/8955029#)[copy](http://blog.csdn.net/csh159/article/details/8955029#)[print](http://blog.csdn.net/csh159/article/details/8955029#)[?](http://blog.csdn.net/csh159/article/details/8955029#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; suspend_search.xml\n**[html]** [view plain](http://blog.csdn.net/csh159/article/details/8955029#)[copy](http://blog.csdn.net/csh159/article/details/8955029#)[print](http://blog.csdn.net/csh159/article/details/8955029#)[?](http://blog.csdn.net/csh159/article/details/8955029#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; Friend.java\n**[java]** [view plain](http://blog.csdn.net/csh159/article/details/8955029#)[copy](http://blog.csdn.net/csh159/article/details/8955029#)[print](http://blog.csdn.net/csh159/article/details/8955029#)[?](http://blog.csdn.net/csh159/article/details/8955029#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.menu; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.HashMap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.regex.Pattern; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.menu.MyLetterListView.OnTouchingLetterChangedListener; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.AsyncQueryHandler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.ComponentName; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.ContentResolver; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.ContentValues; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.database.Cursor; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.PixelFormat; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.net.Uri; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.provider.ContactsContract; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.WindowManager; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AbsListView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AbsListView.OnScrollListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.BaseAdapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; Friend \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; BaseAdapter adapter; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ListView listview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView overlay; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageView suspend_search; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyLetterListView letterListView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; AsyncQueryHandler asyncQuery; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String NAME = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;name\u0026amp;#8221;\u0026lt;/span\u0026gt;, NUMBER = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;number\u0026amp;#8221;\u0026lt;/span\u0026gt;, - SORT_KEY = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sort_key\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; HashMap\u0026lt;String, Integer\u0026gt; alphaIndexer; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String[] sections; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; List\u0026lt;ContentValues\u0026gt; list = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;ContentValues\u0026gt;(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; WindowManager windowManager; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.friend); - windowManager = - (WindowManager) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getSystemService(Context.WINDOW_SERVICE); - asyncQuery = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyAsyncQueryHandler(getContentResolver()); - listview = (ListView) findViewById(R.id.list_view); - letterListView = (MyLetterListView) findViewById(R.id.my_list_view); - letterListView - .setOnTouchingLetterChangedListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LetterListViewListener()); - - alphaIndexer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;String, Integer\u0026gt;(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OverlayThread(); - initOverlay(); - initSuSearch(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (list.size() \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - } - - listview.setOnScrollListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnScrollListener() - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onScrollStateChanged(AbsListView view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollState) - { - suspend_search.setVisibility(View.VISIBLE); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onScroll(AbsListView view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; firstVisibleItem, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; visibleItemCount, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; totalItemCount) - { - suspend_search.setVisibility(View.GONE); - } - }); - suspend_search.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) - { - ComponentName friendcName = - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ComponentName(Friend.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.example.test_intent.FriendSearch\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Intent friend_viewIntent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(); - friend_viewIntent.setComponent(friendcName); - startActivity(friend_viewIntent); - Toast.makeText(getApplicationContext(), \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sousuo\u0026amp;#8221;\u0026lt;/span\u0026gt;, - Toast.LENGTH_LONG).show(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - } - }); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@SuppressWarnings\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;deprecation\u0026amp;#8221;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; getContent() - { - Cursor cur = - getContentResolver().query( - ContactsContract.Contacts.CONTENT_URI, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - startManagingCursor(cur); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onResume() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onResume(); - Uri uri = Uri.parse(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;content://com.android.contacts/data/phones\u0026amp;#8221;\u0026lt;/span\u0026gt;); - String[] projection = { \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;_id\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;display_name\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;data1\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sort_key\u0026amp;#8221;\u0026lt;/span\u0026gt; }; - asyncQuery.startQuery(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, uri, projection, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;sort_key COLLATE LOCALIZED asc\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyAsyncQueryHandler \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; AsyncQueryHandler - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyAsyncQueryHandler(ContentResolver cr) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(cr); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onQueryComplete(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; token, Object cookie, Cursor cursor) - { - - cursor.moveToFirst(); - Log.d(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;ccccc\u0026amp;#8221;\u0026lt;/span\u0026gt;, - cursor.getString(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; 000 \u0026amp;#8220;\u0026lt;/span\u0026gt; + cursor.getString(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) - + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; 000 \u0026amp;#8220;\u0026lt;/span\u0026gt; + cursor.getString(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;) + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; 000 \u0026amp;#8220;\u0026lt;/span\u0026gt; - + cursor.getString(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;)); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt; (cursor.moveToNext()) - { - ContentValues cv = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ContentValues(); - cv.put(NAME, cursor.getString(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;)); - cv.put(NUMBER, cursor.getString(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;)); - cv.put(SORT_KEY, cursor.getString(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;)); - list.add(cv); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (list.size() \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - setAdapter(list); - } - } - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setAdapter(List\u0026lt;ContentValues\u0026gt; list) - { - adapter = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ListAdapter(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, list); - listview.setAdapter(adapter); - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ListAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; BaseAdapter - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LayoutInflater inflater; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;ContentValues\u0026gt; list; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ListAdapter(Context context, List\u0026lt;ContentValues\u0026gt; list) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.inflater = LayoutInflater.from(context); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.list = list; - alphaIndexer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;String, Integer\u0026gt;(); - sections = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; String[list.size()]; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; list.size(); i++) - { - String currentStr = getAlpha(list.get(i).getAsString(SORT_KEY)); - String previewStr = - (i \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; ? getAlpha(list.get(i \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;).getAsString( - SORT_KEY)) : \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; \u0026amp;#8220;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!previewStr.equals(currentStr)) - { - String name = getAlpha(list.get(i).getAsString(SORT_KEY)); - alphaIndexer.put(name, i); - sections[i] = name; - } - } - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; list.size(); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object getItem(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; list.get(position); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getItemId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; position; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) - { - ViewHolder holder; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (convertView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - convertView = inflater.inflate(R.layout.list_item, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - holder = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewHolder(); - holder.alpha = (TextView) convertView.findViewById(R.id.alpha); - holder.name = (TextView) convertView.findViewById(R.id.name); - holder.number = - (TextView) convertView.findViewById(R.id.number); - convertView.setTag(holder); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - { - holder = (ViewHolder) convertView.getTag(); - } - - ContentValues cv = list.get(position); - holder.name.setText(cv.getAsString(NAME)); - holder.number.setText(cv.getAsString(NUMBER)); - String currentStr = - getAlpha(list.get(position).getAsString(SORT_KEY)); - String previewStr = - (position \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; ? getAlpha(list.get(position \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) - .getAsString(SORT_KEY)) : \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; \u0026amp;#8220;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!previewStr.equals(currentStr)) - { - holder.alpha.setVisibility(View.VISIBLE); - holder.alpha.setText(currentStr); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - { - holder.alpha.setVisibility(View.GONE); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; convertView; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ViewHolder - { - - TextView alpha; - - TextView name; - - TextView number; - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initSuSearch()\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 搜索\u0026lt;/span\u0026gt; - { - LayoutInflater inflater = LayoutInflater.from(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - suspend_search = - (ImageView) inflater.inflate(R.layout.suspend_search, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - WindowManager.LayoutParams lp = - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; WindowManager.LayoutParams(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;80\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;80\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;170\u0026lt;/span\u0026gt;, \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;280\u0026lt;/span\u0026gt;, - WindowManager.LayoutParams.TYPE_APPLICATION, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, - PixelFormat.TRANSLUCENT); - windowManager.addView(suspend_search, lp); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initOverlay() - { - LayoutInflater inflater = LayoutInflater.from(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - overlay = (TextView) inflater.inflate(R.layout.overlay, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - WindowManager.LayoutParams lp = - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; WindowManager.LayoutParams( - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;120\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;120\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, - WindowManager.LayoutParams.TYPE_APPLICATION, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, - PixelFormat.TRANSLUCENT); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// WindowManager windowManager = (WindowManager)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// this.getSystemService(Context.WINDOW_SERVICE);\u0026lt;/span\u0026gt; - windowManager.addView(overlay, lp); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; LetterListViewListener \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; - OnTouchingLetterChangedListener - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTouchingLetterChanged(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String s, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (alphaIndexer.get(s) != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position = alphaIndexer.get(s); - - listview.setSelection(position); - overlay.setText(sections[position]); - overlay.setVisibility(View.VISIBLE); - - } - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTouchingLetterEnd() - { - overlay.setVisibility(View.GONE); - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; OverlayThread \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Runnable - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() - { - overlay.setVisibility(View.GONE); - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String getAlpha(String str) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (str == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (str.trim().length() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; c = str.trim().substring(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;).charAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - - Pattern pattern = Pattern.compile(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;^[A-Za-z]+$\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pattern.matcher(c + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;).matches()) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (c + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;).toUpperCase(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDestroy() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (windowManager != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止内存泄露\u0026lt;/span\u0026gt; - { - windowManager.removeView(overlay); - windowManager.removeView(suspend_search); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDestroy(); - } - - } MyLetterListView.java\n**[java]** [view plain](http://blog.csdn.net/csh159/article/details/8955029#)[copy](http://blog.csdn.net/csh159/article/details/8955029#)[print](http://blog.csdn.net/csh159/article/details/8955029#)[?](http://blog.csdn.net/csh159/article/details/8955029#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.menu; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Color; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Typeface; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyLetterListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; View - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnTouchingLetterChangedListener onTouchingLetterChangedListener; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String[] b = { \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;A\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;B\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;C\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;D\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;E\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;F\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;G\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;H\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;J\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;K\u0026amp;#8221;\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;L\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;M\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;N\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;O\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;P\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Q\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;R\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;S\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;T\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;U\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;V\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;W\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;X\u0026amp;#8221;\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Y\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Z\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; }; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; choose = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Paint paint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; showBkg = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyLetterListView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyLetterListView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyLetterListView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDraw(canvas); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (showBkg) - { - canvas.drawColor(Color.parseColor(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;#40000000\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height = getHeight(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width = getWidth(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; singleHeight = height / b.length; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; b.length; i++) - { - paint.setTextSize(18f); - paint.setColor(Color.BLACK); - paint.setTypeface(Typeface.DEFAULT_BOLD); - paint.setAntiAlias(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (i == choose) - { - paint.setColor(Color.parseColor(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;#3399ff\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - paint.setFakeBoldText(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; xPos = width / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; \u0026amp;#8211; paint.measureText(b[i]) / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; yPos = singleHeight * i + singleHeight; - - canvas.drawText(b[i], xPos, yPos, paint); - - paint.reset(); - } - - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent event) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; action = event.getAction(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y = event.getY(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x = event.getX(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldChoose = choose; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; OnTouchingLetterChangedListener listener = - onTouchingLetterChangedListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; c = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (y / getHeight() * b.length); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (action) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: - showBkg = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (oldChoose != c \u0026amp;\u0026amp; listener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (c \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; c \u0026lt; b.length) - { - listener.onTouchingLetterChanged(b[c], y, x); - choose = c; - invalidate(); - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (oldChoose != c \u0026amp;\u0026amp; listener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (c \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; c \u0026lt; b.length) - { - listener.onTouchingLetterChanged(b[c], y, x); - choose = c; - invalidate(); - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - showBkg = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - choose = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - listener.onTouchingLetterEnd(); - invalidate(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent event) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(event); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnTouchingLetterChangedListener( - OnTouchingLetterChangedListener onTouchingLetterChangedListener) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onTouchingLetterChangedListener = onTouchingLetterChangedListener; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnTouchingLetterChangedListener - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTouchingLetterEnd(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTouchingLetterChanged(String s, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x); - } - } 别忘了加权限：\n**[html]** [view plain](http://blog.csdn.net/csh159/article/details/8955029#)[copy](http://blog.csdn.net/csh159/article/details/8955029#)[print](http://blog.csdn.net/csh159/article/details/8955029#)[?](http://blog.csdn.net/csh159/article/details/8955029#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;uses-permission\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.permission.READ_CONTACTS\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; 效果图：\n转自：http://blog.csdn.net/csh159/article/details/8955029\n","permalink":"https://blog.zdltech.com/posts/android%E4%BB%BF%E9%80%9A%E8%AE%AF%E5%BD%95/","summary":"\u003cp\u003efriend.xml\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/csh159/article/details/8955029#)[copy](http://blog.csdn.net/csh159/article/details/8955029#)[print](http://blog.csdn.net/csh159/article/details/8955029#)[?](http://blog.csdn.net/csh159/article/details/8955029#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;29\u0026quot; height=\u0026quot;15\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;?xml version=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; encoding=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;?\u0026gt;\n\n- \u0026lt;LinearLayout xmlns:android=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- android:orientation=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt;\n\n- \u0026lt;RelativeLayout\n\n- android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- android:orientation=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt;\n\n- \n- \u0026lt;ListView\n\n- android:id=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@+id/list_view\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- android:scrollbars=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;none\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt;\n\n- \u0026lt;/ListView\u0026gt;\n\n- \n- \u0026lt;com.example.menu.MyLetterListView\n\n- android:id=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@+id/my_list_view\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;30dip\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- android:layout_alignParentRight=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- /\u0026gt;\n\n- \u0026lt;/RelativeLayout\u0026gt;\n\n- \n- \u0026lt;/LinearLayout\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003efriend_header.xml\u003c/p\u003e","title":"android仿通讯录"},{"content":"excel表格中有A、B、C三列数据，希望导入到数据库users表中，对应的字段分别是name,sex,age 。\n在你的excel表格中增加一列，利用excel的公式自动生成sql语句，方法如下： 1、增加一列（D列） 2、在第一行的D列，就是D1中输入公式： =CONCATENATE(\u0026amp;#8220;insert into users (name,sex,age) values (\u0026amp;#8216;\u0026amp;#8221;,A1,\u0026amp;#8221;\u0026amp;#8216;,'\u0026amp;#8221;,B1,\u0026amp;#8221;\u0026amp;#8216;,'\u0026amp;#8221;,C1,\u0026amp;#8221;\u0026amp;#8216;);\u0026amp;#8221;) 3、此时D1已经生成了如下的sql语句： \u0026amp;#8220;insert into users (name,sex,age) values (\u0026amp;#8216;ls\u0026amp;#8217;,\u0026amp;#8217;女\u0026amp;#8217;,\u0026amp;#8217;24\u0026amp;#8217;)\u0026amp;#8221;; 4、将D1的公式复制到所有行的D列 5、此时D列已经生成了所有的sql语句 6、把D列复制到一个纯文本文件中 7、去掉SQL语句的双引号 ","permalink":"https://blog.zdltech.com/posts/%E6%8A%8Aexcel%E6%95%B0%E6%8D%AE%E7%94%9F%E6%88%90sql-insert%E8%AF%AD%E5%8F%A5/","summary":"\u003cp\u003eexcel表格中有A、B、C三列数据，希望导入到数据库users表中，对应的字段分别是name,sex,age 。\u003c/p\u003e\n\u003cdiv class=\"postBody\"\u003e\n  \u003cdiv id=\"cnblogs_post_body\"\u003e\n\u003cpre\u003e\u003ccode\u003e  在你的excel表格中增加一列，利用excel的公式自动生成sql语句，方法如下：\n\n\n\n\n\n  1、增加一列（D列）\n\n\n\n\n\n  2、在第一行的D列，就是D1中输入公式： =CONCATENATE(\u0026amp;#8220;insert into users (name,sex,age) values (\u0026amp;#8216;\u0026amp;#8221;,A1,\u0026amp;#8221;\u0026amp;#8216;,'\u0026amp;#8221;,B1,\u0026amp;#8221;\u0026amp;#8216;,'\u0026amp;#8221;,C1,\u0026amp;#8221;\u0026amp;#8216;);\u0026amp;#8221;)\n\n\n\n\n\n  3、此时D1已经生成了如下的sql语句： \u0026amp;#8220;insert into users (name,sex,age) values (\u0026amp;#8216;ls\u0026amp;#8217;,\u0026amp;#8217;女\u0026amp;#8217;,\u0026amp;#8217;24\u0026amp;#8217;)\u0026amp;#8221;;\n\n\n\n\n\n  4、将D1的公式复制到所有行的D列\n\n\n\n\n\n  5、此时D列已经生成了所有的sql语句\n\n\n\n\n\n  6、把D列复制到一个纯文本文件中\n\n\n\n\n\n  7、去掉SQL语句的双引号\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e","title":"把excel数据生成sql insert语句"},{"content":"在Java中，不存在Unsigned无符号数据类型，但可以轻而易举的完成Unsigned转换。\n方案一：如果在Java中进行流(Stream)数据处理，可以用DataInputStream类对Stream中的数据以Unsigned读取。\nJava在这方面提供了支持，可以用java.io.DataInputStream类对象来完成对流内数据的Unsigned读取，该类提供了如下方法：（1）int readUnsignedByte() //从流中读取一个0255(0xFF)的单字节数据，并以int数据类型的数据返回。返回的数据相当于C/C++语言中所谓的“BYTE”。（2）int readUnsignedShort() //从流中读取一个065535(0xFFFF)的双字节数据，并以int数据类型的数据返回。返回的数据相当于C/C++语言中所谓的“WORD”， 并且是以“低地址低字节”的方式返回的，所以程序员不需要额外的转换。\n方案二：利用Java位运算符，完成Unsigned转换。\n正常情况下，Java提供的数据类型是有符号signed类型的，可以通过位运算的方式得到它们相对应的无符号值，参见几个方法中的代码：\npublic int getUnsignedByte (byte data){ //将data字节型数据转换为0255 (0xFF 即BYTE)。return data\u0026amp;0x0FF;}\npublic int getUnsignedByte (short data){ //将data字节型数据转换为065535 (0xFFFF 即 WORD)。return data\u0026amp;0x0FFFF;}\npublic long getUnsignedIntt (int data){ //将int数据转换为0~4294967295 (0xFFFFFFFF即DWORD)。return data\u0026amp;0x0FFFFFFFFl;}\n灵活的运用这些技法，根本不存“二进制在Java中得不到全面支持”的论断！\n","permalink":"https://blog.zdltech.com/posts/java%E4%B8%AD%E6%97%A0%E7%AC%A6%E5%8F%B7%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%A4%84%E7%90%86/","summary":"\u003cp\u003e在Java中，不存在Unsigned无符号数据类型，但可以轻而易举的完成Unsigned转换。\u003cbr\u003e\n方案一：如果在Java中进行流(Stream)数据处理，可以用DataInputStream类对Stream中的数据以Unsigned读取。\u003cbr\u003e\nJava在这方面提供了支持，可以用java.io.DataInputStream类对象来完成对流内数据的Unsigned读取，该类提供了如下方法：（1）int   readUnsignedByte()    //从流中读取一个0\u003cdel\u003e255(0xFF)的单字节数据，并以int数据类型的数据返回。返回的数据相当于C/C++语言中所谓的“BYTE”。（2）int readUnsignedShort()   //从流中读取一个0\u003c/del\u003e65535(0xFFFF)的双字节数据，并以int数据类型的数据返回。返回的数据相当于C/C++语言中所谓的“WORD”， 并且是以“低地址低字节”的方式返回的，所以程序员不需要额外的转换。\u003cbr\u003e\n方案二：利用Java位运算符，完成Unsigned转换。\u003cbr\u003e\n正常情况下，Java提供的数据类型是有符号signed类型的，可以通过位运算的方式得到它们相对应的无符号值，参见几个方法中的代码：\u003cbr\u003e\npublic int getUnsignedByte (byte data){      //将data字节型数据转换为0\u003cdel\u003e255 (0xFF 即BYTE)。return data\u0026amp;0x0FF;}\u003cbr\u003e\npublic int getUnsignedByte (short data){      //将data字节型数据转换为0\u003c/del\u003e65535 (0xFFFF 即 WORD)。return data\u0026amp;0x0FFFF;}\u003cbr\u003e\npublic long getUnsignedIntt (int data){     //将int数据转换为0~4294967295 (0xFFFFFFFF即DWORD)。return data\u0026amp;0x0FFFFFFFFl;}\u003cbr\u003e\n灵活的运用这些技法，根本不存“二进制在Java中得不到全面支持”的论断！\u003c/p\u003e\n\u003cdiv id=\"xunlei_com_thunder_helper_plugin_d462f475-c18e-46be-bd10-327458d045bd\"\u003e\n\u003c/div\u003e","title":"java中无符号类型的处理"},{"content":"内容来自：https://github.com/android-cn/android-open-project-analysis 1. 介绍 1.1 关于 Android 的图案密码解锁，通过手势连接 3 * 3 的点矩阵绘制图案表示解锁密码。基于 Android Source Code。\n1.2 特点 支持: Android 1.6+ (API 4+)。 无特殊依赖。 支持手机与平板的布局。 Stealth mode (invisible pattern)。 包含 5 种主题： Dark/Light Light with dark action bar (API 14+) Dark/Light dialogs 有验证码模式。 1.3 使用 1.3.1 Manifest 配置 \u0026lt;activity android:name=\u0026quot;com.haibison.android.lockpattern.LockPatternActivity\u0026quot; android:theme=\u0026quot;@style/Alp.42447968.Theme.Dark\u0026quot; /\u0026gt; 1.3.2 创建图形锁模式 private static final int REQ_CREATE_PATTERN = 1; Intent intent = new Intent(LockPatternActivity.ACTION_CREATE_PATTERN, null, your-context, LockPatternActivity.class); startActivityForResult(intent, REQ_CREATE_PATTERN); @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQ_CREATE_PATTERN: { if (resultCode == RESULT_OK) { char[] pattern = data.getCharArrayExtra( LockPatternActivity.EXTRA_PATTERN); ... } break; } } } 1.3.3 验证图形锁 private static final int REQ_ENTER_PATTERN = 2; char[] savedPattern = ... Intent intent = new Intent(LockPatternActivity.ACTION_COMPARE_PATTERN, null, your-context, LockPatternActivity.class); intent.putExtra(LockPatternActivity.EXTRA_PATTERN, savedPattern); startActivityForResult(intent, REQ_ENTER_PATTERN); @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQ_ENTER_PATTERN: { switch (resultCode) { case RESULT_OK: // The user passed break; case RESULT_CANCELED: // The user cancelled the task break; case LockPatternActivity.RESULT_FAILED: // The user failed to enter the pattern break; case LockPatternActivity.RESULT_FORGOT_PATTERN: // The user forgot the pattern and invoked your recovery Activity. break; } int retryCount = data.getIntExtra( LockPatternActivity.EXTRA_RETRY_COUNT, 0); break; } } } 2. 总体设计 本项目较为简单，总体设计略过，具体实现请参考下面的分析。\n3. 流程图 3.1 创建解锁图案流程图 3.2 验证解锁图案流程图 4. 详细设计 4.1 类关系图 4.2 核心类功能介绍 4.2.1 LockPatternActivity.java LockPatternActivity类负责所有外部请求，根据ACTION_CREATE_PATTERN ACTION_COMPARE_PATTERN ACTION_VERIFY_CAPTCHA 等Action选择操作模式，加载设置后初始化LockPatternView，在用户完成操作后退出并返回结果。\n主要方法说明：\npublic void onCreate(Bundle savedInstanceState)\n首次创建时调用，根据 intent 设置 theme，设置 resultIntent，调用 loadSettings() initContentView()。 private void loadSettings()\n根据 metaData 与 Settings 类的内容得到显示模式、最少图形点数、自动存储、自定义加密等配置。 private void initContentView()\n根据 Aciton 与配置信息初始化 UI，实例化 OnPatternListener 设置到 LockPatternView 类的对象。 private void doCheckAndCreatePattern(final List pattern)\n首先检查 pattern 是否合法，然后判断 Intent 是否保存有特征码，如果没有就把 pattern 加密并提取特征码 put 到 Intent，如果有就把特征码解密并与 pattern 对比，根据对比结果设置 UI。 private void doComparePattern(final List pattern)\n首先检查 pattern 是否合法，然后从 Intent 或者 Settings 中 get 特征码，把特征码解密后与 pattern 对比，成功则调用 finishWithResultOk(null)，失败次数超过最大次数则调用 finishWithNegativeResult(result_failed)。 private void finishWithResultOk(char[] pattern) private void finishWithNegativeResult(int resultCode) 4.2.2 LockPatternView.java LockPatternView类主要是显示解锁的图形界面，在用户操作的时候显示连线与动画，用户操作完成后根据结果做提示。\n添加图形点\nprivate int getRowHit(float y)\n遍历所有图形点行高，寻找坐标 y 在哪个图案点的行高范围内。 private int getColumnHit(float x)\n遍历所有图形点列宽，寻找坐标 x 在哪个图案点的列宽范围内。 private Cell checkForNewHit(float x, float y)\n根据getRowHit(float y)与getColumnHit(float x)返回的行、列判断是否是新的图形点，如果是返回新点，否则返回 null。 private Cell detectAndAddHit(float x, float y)\n调用checkForNewHit(float x, float y)返回当前图形点，如图形点非 null，继续判断 pattern list 是否为空，如果不为空就把 last 与当前的图形点之间同一直线的其他点加入 list，然后把当前点加入 list。 按下事件\nhandleActionDown(MotionEvent event)\n首先清理屏幕，获取当前手指的坐标，调用detectAndAddHit(float x, float y)并判断其返回值发送通知与局部刷新。 移动事件\nprivate void handleActionMove(MotionEvent event)\n检查手指移动过程中每一个点的坐标，判断如果 pattern list 不为空，则把最后一个图形点的坐标与当前手指坐标的区域进行局部刷新，如果在移动过程中加入了新的图形点则以此点坐标继续局部刷新。 弹起事件\nprivate void handleActionUp(MotionEvent event)\n检查 pattern list 如果不为空则停止添加，发送完成消息，全局刷新。 4.2.3 LockPatternUtils.java 图形摘要并加密\npublic static String patternToSha1(List pattern)\n调用List\u0026lt;LockPatternView.Cell\u0026gt; pattern把pattern list进行信息摘要，然后使用SHA-1算法加密，返回加密的摘要。 public static String patternToString(List pattern)\n把pattern list进行信息摘要，从左上角起编号为00，至右下角止编号为08，按照list中点的顺序生成编号序列，返回序列。 5. 安全性分析 android-lockpattern默认的加密存储流程与Android系统的图形解锁是一致的，以Android系统为例来破解图形锁。\n5.1 加密存储过程 5.2 破解思路 图案总数固定：至少四个点、最多九个点、无重复点 加密较弱：单次SHA-1 最快的方法：暴力猜解 5.3 实战 首先获取系统图形锁加密摘要文件\nadb pull /data/system/gesture.key gesture.key\n参考4.2.3中的图形摘要规则，然后我写了一个python脚本，生成了9个点所有组合的摘要字符串，同时再生成对应的SHA-1 HEX，这个字典也就57m。\n把gesture.key中的加密字符串在字典中反查即可得出图形锁的原始信息摘要，然后就可以按步骤画图解锁了。\n","permalink":"https://blog.zdltech.com/posts/android-lock-pattern-%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/","summary":"\u003ch3 id=\"内容来自httpsgithubcomandroid-cnandroid-open-project-analysis\"\u003e内容来自：https://github.com/android-cn/android-open-project-analysis\u003c/h3\u003e\n\u003ch3 id=\"1-\"\u003e1. 介绍\u003c/h3\u003e\n\u003ch4 id=\"1-1-\"\u003e1.1 关于\u003c/h4\u003e\n\u003cp\u003eAndroid 的图案密码解锁，通过手势连接 3 * 3 的点矩阵绘制图案表示解锁密码。基于 \u003ca href=\"https://android.googlesource.com/platform/frameworks/base/+/master/core/java/com/android/internal/widget/LockPatternView.java\"\u003eAndroid Source Code\u003c/a\u003e。\u003c/p\u003e\n\u003ch4 id=\"1-2-\"\u003e1.2 特点\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e支持: Android 1.6+ (API 4+)。\u003c/li\u003e\n\u003cli\u003e无特殊依赖。\u003c/li\u003e\n\u003cli\u003e支持手机与平板的布局。\u003c/li\u003e\n\u003cli\u003eStealth mode (invisible pattern)。\u003c/li\u003e\n\u003cli\u003e包含 5 种主题：\n\u003cul\u003e\n\u003cli\u003eDark/Light\u003c/li\u003e\n\u003cli\u003eLight with dark action bar (API 14+)\u003c/li\u003e\n\u003cli\u003eDark/Light dialogs\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e有验证码模式。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"1-3-\"\u003e1.3 使用\u003c/h4\u003e\n\u003ch5 id=\"1-3-1-manifest-\"\u003e1.3.1 Manifest 配置\u003c/h5\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;activity\n    android:name=\u0026quot;com.haibison.android.lockpattern.LockPatternActivity\u0026quot;\n    android:theme=\u0026quot;@style/Alp.42447968.Theme.Dark\u0026quot; /\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch5 id=\"1-3-2-\"\u003e1.3.2 创建图形锁模式\u003c/h5\u003e\n\u003cpre\u003e\u003ccode\u003eprivate static final int REQ_CREATE_PATTERN = 1;\n\nIntent intent = new Intent(LockPatternActivity.ACTION_CREATE_PATTERN, null, your-context, LockPatternActivity.class);\nstartActivityForResult(intent, REQ_CREATE_PATTERN);\n\n\n@Override\nprotected void onActivityResult(int requestCode, int resultCode,\n        Intent data) {\n    switch (requestCode) {\n        case REQ_CREATE_PATTERN: {\n            if (resultCode == RESULT_OK) {\n                char[] pattern = data.getCharArrayExtra(\n                        LockPatternActivity.EXTRA_PATTERN);\n                ...\n            }\n            break;\n        }\n    }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch5 id=\"1-3-3-\"\u003e1.3.3 验证图形锁\u003c/h5\u003e\n\u003cpre\u003e\u003ccode\u003eprivate static final int REQ_ENTER_PATTERN = 2;\n\nchar[] savedPattern = ...\n\nIntent intent = new Intent(LockPatternActivity.ACTION_COMPARE_PATTERN, null,\n        your-context, LockPatternActivity.class);\nintent.putExtra(LockPatternActivity.EXTRA_PATTERN, savedPattern);\nstartActivityForResult(intent, REQ_ENTER_PATTERN);\n\n\n@Override\nprotected void onActivityResult(int requestCode, int resultCode,\n        Intent data) {\n    switch (requestCode) {\n        case REQ_ENTER_PATTERN: {\n\n            switch (resultCode) {\n            case RESULT_OK:\n                // The user passed\n                break;\n            case RESULT_CANCELED:\n                // The user cancelled the task\n                break;\n            case LockPatternActivity.RESULT_FAILED:\n                // The user failed to enter the pattern\n                break;\n            case LockPatternActivity.RESULT_FORGOT_PATTERN:\n                // The user forgot the pattern and invoked your recovery Activity.\n                break;\n            }\n\n            int retryCount = data.getIntExtra(\n                    LockPatternActivity.EXTRA_RETRY_COUNT, 0);\n\n            break;\n        }\n    }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3 id=\"2-\"\u003e2. 总体设计\u003c/h3\u003e\n\u003cp\u003e本项目较为简单，总体设计略过，具体实现请参考下面的分析。\u003c/p\u003e","title":"Android Lock Pattern 源码解析"},{"content":"内容来自：https://github.com/android-cn/android-open-project-analysis 1. 功能介绍 1.1 Dagger Dagger 是一款 Java 平台的依赖注入库，关于依赖注入，详细见 依赖注入简介。\nJava 的依赖注入库中，最有名的应该属 Google 的 Guice，Spring 也很有名，不过是专注于 J2EE 开发。Guice 的功能非常强大，但它是通过在运行时读取注解来实现依赖注入的，依赖的生成和注入需要依靠 Java 的反射机制，这对于对性能非常敏感的 Android 来说是一个硬伤。基于此，Dagger 应运而生。\nDagger 同样使用注解来实现依赖注入，但它利用 APT(Annotation Process Tool) 在编译时生成辅助类，这些类继承特定父类或实现特定接口，程序在运行时 Dagger 加载这些辅助类，调用相应接口完成依赖生成和注入。Dagger 对于程序的性能影响非常小，因此更加适用于 Android 应用的开发。\n1.2 依赖注入相关概念 **依赖(Dependency)：**如果在 Class A 中，有个属性是 Class B 的实例，则称 Class B 是 Class A 的依赖，本文中我们将 Class A 称为宿主(Host)，并且全文用 Host 表示；Class B 称为依赖(Dependency)，并且全文用 Dependency 表示。一个 Host 可能是另外一个类的 Dependency。\n**宿主(Host)：**如果 Class B 是 Class A 的 Dependency，则称 Class A 是 Class B 的宿主(Host)。\n**依赖注入：**如果 Class B 是 Class A 的 Dependency，B 的赋值不是写死在了类或构造函数中，而是通过构造函数或其他函数的参数传入，这种赋值方式我们称之为依赖注入。\n更详细介绍可见 依赖注入简介。\n1.3 Dagger 基本使用 本文将以一个简单的“老板和程序员” App 为例。\nActivity 中有一个 Boss 类属性，现在你想把一个 Boss 对象注入到这个 Activity 中，那么有两个问题需要解决：Boss 对象应该怎样被生成 以及 Boss 对象怎样被设置到 Activity 中。\n(1). Boss 对象怎样生成 在 Boss 类的构造函数前添加一个 @Inject 注解，Dagger 就会在需要获取 Boss 对象时，调用这个被标记的构造函数，从而生成一个 Boss 对象。\n`public class Boss { ... @Inject public Boss() { ... } ... } ` 需要注意的是，如果构造函数含有参数，Dagger 会在调用构造对象的时候先去获取这些参数(不然谁来传参？)，所以你要保证它的参数也提供可被 Dagger 调用到的生成函数。Dagger 可调用的对象生成方式有两种：一种是用 @Inject 修饰的构造函数，上面就是这种方式。另外一种是用 @Provides 修饰的函数，下面会讲到。\n(2). Boss 对象怎样被设置到 Activity 中 通过 @Inject 注解了构造函数之后，在 Activity 中的 Boss 属性声明之前也添加 @Inject 注解。像这种在属性前添加的 @Inject 注解的目的是告诉 Dagger 哪些属性需要被注入。\n`public class MainActivity extends Activity { @Inject Boss boss; ... } ` 最后，我们在合适的位置(例如 onCreate() 函数中)调用 ObjectGraph.inject() 函数，Dagger 就会自动调用上面 (1) 中的生成方法生成依赖的实例，并注入到当前对象(MainActivity)。\n`public class MainActivity extends Activity { @Inject Boss boss; @Override protected void onCreate(Bundle savedInstanceState) { ObjectGraph.create(AppModule.class).inject(this); } ... } ` `public void injectMembers(MainActivity paramMainActivity) { paramMainActivity.boss = ((Boss)boss.get()); …… } ` 上面我们已经通过 ObjectGraph.inject() 函数传入了 paramMainActivity，并且 boss 属性是 package 权限，所以 Dagger 只需要调用这个辅助类的 injectMembers() 函数即可完成依赖注入，这里的 boss.get() 会调用 Boss 的生成函数。\n到此为止，使用 Dagger 的 @Inject 方式将一个 Boss 对象注入到 MainActivity 的流程就完成了。\n(3). ObjectGraph.create(AppModule.class) 函数简介 上面 onCreate() 函数中出现了两个类：ObjectGraph 和 AppModule。其中 ObjectGraph 是由 Dagger 提供的类，可以简单理解为一个依赖管理类，它的 create() 函数的参数是一个数组，为所有需要用到的 Module(例如本例中的 AppModule)。AppModule 是一个自定义类，在 Dagger 中称为Module，通过 @Module 注解进行标记，代码如下：\n`@Module(injects = MainActivity.class) public class AppModule { } ` 可以看到，AppModule 是一个空类，除了一行注解外没有任何代码。\n@Module 注解表示这个类是一个Module，Module 的作用是提供信息，让 ObjectGraph 知道哪些类对象需要被依赖注入，以及该怎么生成某些依赖(这在下面会具体介绍)。例如，上面这段代码中声明了需要依赖注入的类为 MainActivity。\n需要在 Module 类中显式声明这些信息看起来很麻烦，多此一举的方式和 Dagger 的原理有关，下面会讲到。\n1.4 自定义依赖生成方式 (1). @Provides 修饰的生成函数 对构造函数进行注解是很好用的依赖对象生成方式，然而它并不适用于所有情况。例如：\n接口(Interface)是没有构造函数的，当然就不能对构造函数进行注解 第三方库提供的类，我们无法修改源码，因此也不能注解它们的构造函数 有些类需要提供统一的生成函数(一般会同时私有化构造函数)或需要动态选择初始化的配置，而不是使用一个单一的构造函数 对于以上三种情况，可以使用 @Provides 注解来标记自定义的生成函数，从而被 Dagger 调用。形式如下：\n`@Provides Coder provideCoder(Boss boss) { return new Coder(boss); } ` _和构造函数一样，@Provides 注解修饰的函数如果含有参数，它的所有参数也需要提供可被 Dagger 调用到的生成函数。_\n需要注意的是，所有 @Provides 注解的生成函数都需要在Module中定义实现，这就是上面提到的 Module 的作用之一——让 ObjectGraph 知道怎么生成某些依赖。\n`@Module public class AppModule { @Provides Coder provideCoder(Boss boss) { return new Coder(boss); } } ` (2). @Inject 和 @Provide 两种依赖生成方式区别 a. @Inject 用于注入可实例化的类，@Provides 可用于注入所有类\nb. @Inject 可用于修饰属性和构造函数，可用于任何非 Module 类，@Provides 只可用于用于修饰非构造函数，并且该函数必须在某个Module内部\nc. @Inject 修饰的函数只能是构造函数，@Provides 修饰的函数必须以 provide 开头\n1.5 单例 Dagger 支持单例(事实上单例也是依赖注入最常用的场景)，使用方式也很简单：\n`// @Inject 注解构造函数的单例模式 @Singleton public class Boss { ... @Inject public Boss() { ... } ... } ` `// @Provides 注解函数的单例模式 @Provides @Singleton Coder provideCoder(Boss boss) { return new Coder(boss); } ` 在相应函数添加 @Singleton 注解，依赖的对象就只会被初始化一次，之后的每次都会被直接注入相同的对象。\n1.6 Qualifier(限定符) 如果有两类程序员，他们的能力值 power 分别是 5 和 1000，应该怎样让 Dagger 对他们做出区分呢？使用 @Qualifier 注解即可。\n(1). 创建一个 @Qualifier 注解，用于区分两类程序员：\n`@Qualifier @Documented @Retention(RUNTIME) public @interface Level { String value() default \u0026#34;\u0026#34;; } ` (2). 为这两类程序员分别设置 @Provides 函数，并使用 @Qualifier 注解对他们做出不同的标记：\n`@Provides @Level(\u0026#34;low\u0026#34;) Coder provideLowLevelCoder() { Coder coder = new Coder(); coder.setName(\u0026#34;战五渣\u0026#34;); coder.setPower(5); return coder; } @Provides @Level(\u0026#34;high\u0026#34;) Coder provideHighLevelCoder() { Coder coder = new Coder(); coder.setName(\u0026#34;大神\u0026#34;); coder.setPower(1000); return coder; } ` (3). 在声明 @Inject 对象的时候，加上对应的 @Qualifier 注解。\n`@Inject @Level(\u0026#34;low\u0026#34;) Coder lowLevelCoder; @Inject @Level(\u0026#34;high\u0026#34;) Coder highLevelCoder; ` 1.7 编译时检查 实质上，Dagger 会在编译时对代码进行检查，并在检查不通过的时候报编译错误，具体原因请看下面的详细原理介绍。检查内容主要有三点：\n(1). 所有需要依赖注入的类，需要被显式声明在相应的Module中。\n(2). 一个Module中 所有 @Provides 函数的参数都必须在这个 Module 中提供相应的被 @Provides 修饰的函数，或者在 @Module 注解后添加 “complete = false” 注明这是一个不完整 Module，表示它依赖不属于这个 Module 的其他 Denpendency。\n(3). 一个Module中所有的 @Provides 函数都要被它声明的注入对象所使用，或者在 @Module 注解后添加 “library = ture” 注明它含有对外的 Denpendency，可能被其他Module依赖。\n1.8 Dagger 相关概念 **Module：**也叫 ModuleClass，指被 @Module 注解修饰的类，为 Dagger 提供需要依赖注入的 Host 信息及一些 Dependency 的生成方式。\n**ModuleAdapter：****Binding：**指由 APT 根据 @Inject 注解和 @Provides 注解自动生成，最终继承自 Binding.java 的类。为下面介绍的 DAG 图中的一个节点，每个 Host 及依赖都是一个 Binding。\n**InjectAdapter：****ProvidesAdapter：**每个被 @Provides 修饰的生成函数都会生成一个继承自 ProvidesBinding.java 的子类，ProvidesBinding.java 继承自 Binding.java，生成类以 Provide 函数名首字母大写加上 ProvidesAdapter 命名，是 Provide 函数所在 Module 对应生成的ModuleAdapter中的静态内部类。\nBinding 更具体信息在下面会介绍。\n**Binding 安装：**指将 Binding 添加到 Binding 库中。对 Dagger Linker.java 代码来说是将 Binding 添加到 Linker.bindings 属性中，Linker.bindings 属性表示某个 ObjectGraph 已安装的所有 Binding。对于下面的 DAG 图来说是将节点放到图中，但尚未跟其他任何节点连接起来。\n**Binding 连接：**把当前 Binding 和它内部依赖的 Binding 进行连接，即初始化这个 Binding 内部的所有 Binding，使它们可用。对 DAG 的角度说，就是把某个节点与其所依赖的各个节点连接起来。\n2. 总体设计 2.1 概述 事实上，Dagger 这个库的取名不仅仅来自它的本意“匕首”，同时也暗示了它的原理。Jake Wharton 在对 Dagger 的介绍中指出，Dagger 即 DAG-er，这里的 DAG 即数据结构中的 DAG——有向无环图(Directed Acyclic Graph)。也就是说，Dagger 是一个基于有向无环图结构的依赖注入库。\n2.2 DAG(有向无环图) 已经了解 DAG 的可以跳过这节。\nDAG 是数据结构的一种。在一组节点中，每一个节点指向一个或多个节点，但不存在一条正向的链最终重新指向自己(即不存在环)，这样的结构称为有向无环图，即 DAG。\n上图中的数据结构就是一个有向无环图。图中一共存在 6 个节点和 7 个箭头，但任何一个节点都无法从自己发射出的箭头通过某条回路重新指向自己。\n2.3 Dagger 中依赖注入与 DAG 的关系 Dagger 的运作机制，是运用 APT(Annotation Process Tool) 在编译时生成一些用于设定规则的代码，然后在运行时将这些规则进行动态组合 // TODO 不太理解意思，生成一个(或多个)DAG，然后由 DAG 来完成所有依赖的获取，实现依赖注入。关于 DAG 究竟是怎样一步步生成的，后面再讲，这里先说一下在 Dagger 中依赖注入与 DAG 的关系。\n我把前面那张图的每个节点重新命名，得到了上图。上图代表了某个应用程序内的一整套依赖关系，其中每个箭头都表示两个类之间依赖关系，Host 和 Dependency 都是其中的一个节点。\n可以看出，一个程序中的整套依赖关系其实就是一个 DAG。而实际上，Dagger 也是这么做的：预先建立一个 DAG，然后在需要获取对象的时候通过这个依赖关系图来获取到对象并返回，若获取失败则进行查找，查找到后再补充到 DAG 中。\nDagger 是支持传递依赖的。例如在上图中，当需要获取一个 CustomView，会首先获取一个 DataHelper 作为获取 CustomView 的必要参数；此时如果 DataHelper 还未初始化，则还要分别拿到 HttpHelper 和 Database 用来初始化 DataHelper；以此类推。\nDagger 不支持循环依赖，即依赖关系图中不能出现环。原因很简单，如果鸡依赖蛋，蛋依赖鸡，谁来创造世界？总有一个要先产生的。\n2.4 工作流程 (1). 编译时，通过 APT 查看所有 java 文件，并根据注解生成一些新的 java 文件，即InjectAdapter、ProvidesAdapter、ModuleAdapter，这些文件用于运行时辅助 DAG 的创建和完善。然后，将这些新生成的 java 文件和项目原有的 java 文件一并编译成 class 文件。\n(2). 运行时，在 Application 或某个具体模块的初始化处，使用ObjectGraph类来加载部分依赖(实质上是利用编译时生成的ModuleAdapters加载了所有的ProvidesBinding，后面会讲到)，形成一个不完整的依赖关系图。\n(3). 这个不完整的依赖关系图生成之后，就可以调用ObjectGraph的相应函数来获取实例和注入依赖了。实现依赖注入的函数有两个：ObjectGraph.get(Class\u0026lt;T\u0026gt; type)函数，用于直接获取对象；ObjectGraph.inject(T instance)函数，用于对指定对象进行属性的注入。在这些获取实例和注入依赖的过程中，如果用到了还未加载的依赖，程序会自动对它们进行加载(实质上是加载的编译时生成的InjectAdapter)。在此过程中，内存中的 DAG 也被补充地越来越完整。\n3. 流程图 3.1 编译时： 3.2 运行时(初始化后)： 4. 详细设计 4.1 类关系图 上图是 Dagger 整体框架最简类关系图。大致原理可以描述为：Linker通过Loader加载需要的Binding并把它们拼装成合理的依赖关系图 ObjectGraph，由ObjectGraph(其子类DaggerObjectGraph)最终实现依赖注入的管理。\nObjectGraph 是个抽象类，DaggerObjectGraph 是它目前唯一的子类，对 Dagger 的调用实际都是对 DaggerObjectGraph 的调用。\n4.2 类功能详细介绍 4.2.1 Binding.java —— 节点 Binding 是一个泛型抽象类，相当于依赖关系 DAG 图中的节点，依赖关系 DAG 图中得每一个节点都有一个由 APT 生成的继承自 Binding 的类与之对应，而依赖关系 DAG 图中的每一个节点与Host和Dependency一一对应，所以每个Host或Dependency必然有一个由 APT 生成的继承自 Binding 的子类与之对应，我们先简单的将这些生成类分为HostBinding和DependencyBinding。\n(1). Binding.java 实现的接口 Binding.java 实现了两个接口，第一个是 javax 的Provider接口，此接口提供了 get() 函数用于返回一个Dependency实例，当然也可以是Host实例。\n第二个接口是 Dagger 中的MembersInjector接口，此接口提供了 injectMembers() 用来向Host对象中注入(即设置)Dependency。\n单纯的DependencyBinding只要实现Provider接口，在 get() 函数中返回自己的实例即可。单纯的HostBinding只要实现MembersInjector，在 injectMembers() 函数中调用DependencyBinding的 get() 函数得到依赖，然后对自己的依赖进行注入即可。如果一个类既是Host又是Dependency，则与它对应的Binding这两个接口都需要实现。\n(2). 生成的 Binding 代码示例 如下的 Host 和 Dependency 类\n`public class Host { @Inject Dependency dependency; } public class Dependency { @Inject public Dependency() { …… } } ` 由 APT 生成的 Binding 应该类似\n`public final class Host\u0026amp;lt;span class=\u0026#34;katex math multi-line\u0026#34;\u0026gt;InjectAdapter extends Binding\u0026amp;lt;Host\u0026amp;gt; implements MembersInjector\u0026amp;lt;Host\u0026amp;gt; { private Binding\u0026amp;lt;Dependency\u0026amp;gt; dependencyBinding; …… public void attach(Linker linker) { dependencyBinding = (Dependency\u0026amp;lt;/span\u0026gt;InjectAdapter)linker.requestBinding(……); } public void injectMembers(Host host) { host.dependency = (Dependency)dependencyBinding.get(); } } ` `` HostBinding指的是生成类 Host$$InjectAdapter，DependencyBinding``HostBinding的 attach 方法用于得到DependencyBinding的实例，然后在 injectMembers() 函数中通过调用这个实例的 get() 函数注入 Dependency，DependencyBinding 的 get() 函数就是调用Dependency的生成方法。\n(3). Binding 分类 上面我们将生成的 Binding 子类简单分为了HostBinding和DependencyBinding，实际根据前面的注入方式我们知道依赖的生成方式有 @Inject 和 @Provides 两种，对这两种方式，Dagger 生成 Binding 子类的规则不同。\n对于 @Inject 方式的注入，APT 会在Dependency同一个 package 下以Dependency``Module内部，与此 Module 对应的ModuleAdapter``Host对应的 Binding，本文中我们统一称为HostBinding。这些HostBinding和被 @Module 修饰的Module injects 值中每个元素一一对应，他们提供 get()、injectMembers()、attach() 函数。\n第二种是 Inject Dependecy 对应的 Binding 子类，本文中我们统一称为InjectBinding。这些InjectBinding和所有含有 @Inject 修饰的构造函数的类一一对应，他们提供 get() 函数，不提供 injectMembers() 函数。如果它同时是个Host，也会提供 injectMembers() 函数。\n第三种是 Provide Dependecy 对应的 Binding 子类，本文中我们统一称为ProvidesBinding。ProvidesBinding 和 @Module 类中的被 @Provides 修饰的函数一一对应，他们只提供 get() 函数，不提供 injectMembers() 函数。\n上面三种 Binding 中，第一、二种会在 ObjectGraph.create 时加载进来，第三种在用的时候才会被动态加载。InjectBinding和ProvidesBinding统称为DependencyBinding。\nBinding.java 的主要函数：\n(1). get() 表示得到此 Binding 对应的Dependency。InjectBinding会在 get() 中调用被 @Inject 修饰的构造函数，ProvidesBinding会在 get() 函数中调用被 @Provides 修饰的生成函数。\n(2). injectMembers(T t) 表示向此 Binding 对应Host对象中注入依赖，这个函数的实现一般就是对被 @Inject 修饰的属性进行赋值，值为DependencyBinding的 get() 函数返回值。\n(3). attach(Linker linker) 表示HostBinding获取依赖的 Binding 即DependencyBinding对象，对于 DAG 图来说相当于把图中两个节点连接起来。对于DependencyBinding此函数为空。\n(4). getDependencies(…) 表示HostBinding得到依赖的DependencyBinding)，这个函数在对 DAG 图进行问题检测，比如循环依赖检测时用到。\nBinding.java 的主要属性：\n(1). provideKey 表示 Binding 所属 Host 或 Dependency 的类名，是 Binding 唯一的 key，在 Linker 管理 Binding 时会用到，作为存储所有 Binding 的 Map 的 key。对HostBinding值为 HostClassName.toString()，DependencyBinding值为 DependencyClassName.toString()。\n(2). membersKey // TODO。对HostBinding值为 members/ 加上 HostClassName.toString()，InjectBinding值为 members/ 加上 DependencyClassName.toString()，ProvidesBinding值为 null。ProvidesBinding值为 null，因为它默认就连接好了。\n(3). requiredBy 表示这个 Binding 属于谁，对HostBinding值为 HostClass.class，InjectBinding值为 DependencyClass.class，ProvidesBinding值为 ProvideMethodName.toString()。\n(4). bits 表示 Binding 特性的标志位，如是是否是单例(SINGLETON)、是否已连接(LINKED)，是否被访问(VISITING)、是否是可被其他 Module 依赖的 Library(LIBRARY)、是否依赖其他 Module 的 Binding(DEPENDED_ON)、是否不存在循环依赖(CYCLE_FREE)。\n4.2.2 Linker.java —— 拼装者 Linker 是 Dagger 最核心的大脑部分，它负责调用 Loader 加载 Binding，存储并管理所有 Binding、调用 attach 方法初始化依赖的 DependencyBinding。对于 DAG 图来说，Linker 就相当于一个管家，负责调用加载器加载节点到图中、存储并管理图中所有的节点，连接图中有依赖关系的节点，也就是 DAG 图的拼装。\nDagger 在运行时维护一个或多个Linker，Linker 与 ObjectGraph 一一对应。\nLinker.java 的主要属性：\n(1). bindings 本文称为 ObjectGraph 的 Binding 库，表示 ObjectGraph 已安装的所有 Binding，包括尚未连接的 Binding，对于 DAG 图来说就是所有在图中的节点，包括尚未跟其他任何节点连接起来的节点。\nbindings 数据结构为 HashMap，value 就是具体的 Binding，key 是用来唯一确定 Binding 的字符串，为 Binding.java 中的 provideKey 和 membersKey，具体形式是类名加上一个用于区分同类型的前缀。这些 Binding 不仅包含已连接的，也包含未连接的。\n(2). toLink 表示待连接的 Binding 队列，包含了所有待连接的 Binding。对于 DAG 图来说就是所有在图中但未和任何节点连接的节点。\n连接(Link)：从 DAG 的角度说，就是把某个节点与其所依赖的各个节点连接起来。而对于 Binding 来说，就是把当前 Binding 和它依赖的 Binding (ProvidesBinding)进行连接，即初始化这个 Binding 依赖的所有 Binding，使它们可用。\n(3). attachSuccess 一个标志，对于某个 Binding，在获取它依赖的DependencyBinding时，如果他所有的DependencyBinding都已经添加到Binding库中，attachSuccess 则为 true，否则为 false。如果为 false ，表示该 Binding 尚未连接，添加到待连接队列中，否则标记为已连接。\n(4). linkedBindings 默认为 null，只有在 linkAll() 函数被调用后才有效，用于存储所有已经连接的 Binding，同时也是一个标记，表示这个 ObjectGraph 已经不能被改变。\n(5). Loader plugin Loader 负责加载类，主要是加载 APT 生成的辅助类(InjectAdapter、ModuleAdapter)。\n(6). errors Linker.linkRequested() 运行过程中积累的 errors。\nLinker.java 的主要函数：\n(1). requestBinding(String key ……) 根据传入的 key 返回一个 Binding。首先，会尝试从 Bindings 变量(Binding 库)中查找这个 key，如果找到了，就将找到的 Binding 返回(如果找到后发现这个 Binding 还未连接，还需要它放进 toLink 中)；如果找不到，说明需要的 Binding 是一个InjectBinding(因为另一种 Binding——ProvidesBinding 在初始化时就已经加载完毕了)，就生成一个包含了这个 key 的DeferredBinding，并把它添加到 toLink(等待稍后载入)后返回 null。\n(2). linkRequested() 循环取出 toLink 中的 Binding：\n如果是个DeferredBinding载入相应的InjectAdapter后添加到toLink和bindings中，等待下次循环。\n否则调用 attach 函数进行连接，对于DependencyBinding连接完成。对于HostBinding利用 attach() 函数获取依赖的 Binding 即DependencyBinding对象，在获取DependencyBinding的过程中调用 requestBinding() 函数查找 Binding，不存在或未连接会继续添加到 toLink 队列中，如此循环。\n直到所有依赖DependencyBinding被初始化结束。\n对 DAG 图来说就是一次广度优先遍历。\n(3). installBindings(BindingsGroup toInstall) 安装 Bindings，表示将 Binding 添加到 ObjectGraph 中，但尚未连接。对 DAG 图来说就是就是将节点放到图中，但尚未和任何其他节点连接。\n(4). linkAll() 将 Binding 库中所有未连接的 Binding 添加到 toLink 中，调用 linkRequested() 进行连接。\n(5). fullyLinkedBindings() 返回已经全部连接的 Binding，如果没有调用过 linkAll() 则返回 null\n4.2.3 Loader.java —— 类加载器及对象生成器 Loader 是一个纯工具类，它通过 ClassLoader 加载 APT 生成的ModuleAdapter类和InjectAdapter类，并初始化一个该类对象返回。另外，Loader 是一个抽象类，在运行时，Dagger 使用的是 Loader 的子类FailoverLoader。\nLoader.java 的主要函数：\n(1). loadClass(ClassLoader classLoader, String name) 用指定的 ClassLoader 根据类名得到类，并缓存起来。\n(2). instantiate(String name, ClassLoader classLoader) 用指定的 ClassLoader 根据类名获取类的实例。\n(3). getModuleAdapter(Class moduleClass) 获取指定的 Module 类所对应的 ModuleAdapter 实例。\n(4). getAtInjectBinding(String key……) 根据 key 获取 Inject Dependecy 对应的 InjectAdapter 实例。\n(5). getStaticInjection(Class\u003c?\u003e injectedClass) 根据被注入的 Class 获取对应的 StaticInjection 实例。\nLoader.java 的主要变量：\n(1). Memoizer\u0026lt;classloader, memoizer\u0026lt;string,=”” class\u0026raquo; caches 用来缓存被初始化过的对象，是一个嵌套的 Memoizer 结构，Memoizer具体可看后面介绍，简单理解就是嵌套的 HashMap，第一层 Key 是 ClassLoader，第二层 Key 是 ClassName，Value 是 Class 对象。\n4.2.4 FailoverLoader.java FailoverLoader 是 Loader 的一个子类，它加载类的策略是首先查找 APT 生成的类，如果查找失败，则直接使用反射查找和初始化。\nFailoverLoader.java 的主要函数：\n(1). getModuleAdapter(Class moduleClass) 获取指定的 Module 类所对应的 ModuleAdapter 实例，如果在生成类中查找失败，则会调用 ReflectiveAtInjectBinding.create(type, mustHaveInjections) 通过反射直接初始化对象。\n(2). getAtInjectBinding(String key……) 根据 key 获取 Inject Dependecy 对应的 InjectAdapter 实例。如果在生成类中查找失败，则会调用 ReflectiveStaticInjection.create(injectedClass) 通过反射直接初始化对象。\n(3). getStaticInjection(Class\u003c?\u003e injectedClass) 根据被注入的 Class 获取对应的 StaticInjection 实例。\nFailoverLoader.java 的主要变量：\n(1). Memoizer\u0026lt;class\u003c?\u003e, ModuleAdapter\u003c?\u003e\u0026gt; loadedAdapters 用来缓存初始化过的 ModuleAdapter 对象，是一个嵌套的 Memoizer 结构，具体可看下面介绍，简单理解就是嵌套的 HashMap，第一层 Key 是 ClassLoader，第二层 Key 是 ClassName，Value 是 Class 对象。\n4.2.5 ObjectGraph —— 管理者 ObjectGraph 是个抽象类，负责 Dagger 所有的业务逻辑，Dagger 最关键流程都是从这个类发起的，包括依赖关系图创建、实例(依赖或宿主)获取、依赖注入。\nObjectGraph 主要函数有：\n(1). create(Object… modules) 这是个静态的构造函数，用于返回一个 ObjectGraph 的实例，是使用 Dagger 调用的第一个函数。参数为 ModuleClass 对象，函数作用是根据 ModuleClass 构建一个依赖关系图。此函数实现会直接调用\n`DaggerObjectGraph.makeGraph(null, new FailoverLoader(), modules) ` 返回一个DaggerObjectGraph对象，我们会在下面DaggerObjectGraph介绍中具体介绍实现过程。\n(2). inject(T instance) 抽象函数，表示向某个 Host 对象中注入依赖。\n(3). injectStatics() 抽象函数，表示向 ObjectGraph 中相关的 Host 注入静态属性。\n(4). get(Class type) 抽象函数，表示得到某个对象的实例，多用于得到依赖的实例。\n(5). plus(Object… modules) 抽象函数，表示返回一个新的包含当前 ObjectGraph 中所有 Binding 的 ObjectGraph。\n(6). validate() 抽象函数，表示对当前 ObjectGraph 做检查。\n4.2.6 DaggerObjectGraph DaggerObjectGraph 是 ObjectGraph 的静态内部类，也是 ObjectGraph 目前唯一的子类。因为 ObjectGraph 的 create() 函数直接返回了 DaggerObjectGraph 对象，所以对 Dagger 的调用实际都是对 DaggerObjectGraph 的调用。\nDaggerObjectGraph 主要属性有：\n(1). Map injectableTypes 记录了所有需要被依赖注入的 Host 类型，以 Host 的 ClassName 加上一定规则前缀(// TODO)做为 key，以其所对应的 Module 为 value。\n(2). Map staticInjections 记录了所有需要被静态依赖注入的 Host 类型，以 Host 的 ClassName 加上一定规则前缀(// TODO)做为 key，以其所对应的 Module 为 value。\n(3). Linker linker Linker 是 负责调用 Loader 加载 Binding，存储并管理所有 Binding、调用 attach 方法初始化依赖的 DependencyBinding。具体见上面Linker.java介绍。\n(4). Loader plugin Loader 负责通过 ClassLoader 加载 APT 生成的ModuleAdapter类和InjectAdapter类。\nPS： 这个变量名叫 plugin，实际也说明了 Dagger 的一大优势，就是它是支持 ClassLoader，这样通过 Dagger 实现依赖注入的 Android 应用，插件化时 Dagger 不会对其产生影响，而截止这个分析文档完成时，轻量级的 ButterKnife 都不支持多个 ClassLoader。\nDaggerObjectGraph 主要函数有：\n(1). makeGraph 函数 makeGraph 函数首先会通过 Modules.loadModules 函数得到所有的 ModuleAdapter；\n然后遍历所 有 ModuleAdapter，将其中需要依赖注入的 Host 类型(injectableTypes)、需要静态静态注入的 Host 类型(staticInjections)、所有的 Binding(这里是ProvidesBinding)都保存下来，做为新的 DaggerObjectGraph 对象构造入参。另一种 Binding —— InjectBinding 会在需要用到的时候进行动态载入；\n第三步新建 Linker 保存上面的 Binding；\n最后用这些变量一起构建新的 DaggerObjectGraph 对象。\n(2). inject(T instance) 表示向某个 Host 对象中注入依赖。首先根据下面的 getInjectableTypeBinding() 函数查找到 Host 对应的 InjectBinding，然后调用 injectMembers() 函数注入依赖，将依赖注入结束的 Host 返回。\n(3). injectStatics() 表示向 ObjectGraph 中相关的 Host 注入静态属性。\n(4). get(Class type) 表示得到某个对象的实例，多用于得到 Denpendency 的实例。首先根据下面的 getInjectableTypeBinding() 函数查找到 Denpendency 对应的 Binding，然后调用 get() 返回该 Denpendency 实例。\n(5). plus(Object… modules) 抽象函数，表示返回一个新的包含当前 ObjectGraph 中所有对象的 ObjectGraph。\n(6). validate() 表示对当前 ObjectGraph 做检查，首先会利用 Linker 查找到所有节点并连接起来，然后调用 ProblemDetector 进行检查。ProblemDetector 会在后面解释作用。\n(7). getInjectableTypeBinding(ClassLoader classLoader, String injectableKey, String key) 表示根据 key 得到某个 Binding。首先会从 ObjectGraph.injectableTypes 中得到其对应的 Module，然后通过 linker.requestBinding 查找其对应的 Binding，若未查找到的 Binding 或是尚未连接，则调用 linker.linkRequested() 得到 InjectBindng 并将其添加到 ObjectGraph 中，此时再次通过 linker.requestBinding 即可查找到其对应的 Binding，返回即可。\n(8). linkInjectableTypes() 查找 injectableTypes 记录的所有需要被依赖注入的 Host 类型对应的HostBinding。\n(9). linkStaticInjections() 查找 staticInjections 记录的所有需要被静态依赖注入的 Host 类型对应的HostBinding。\n(10) linkEverything() 首先检查是否连接过，没有的话，则先调用 linkInjectableTypes() 和 linkStaticInjections() 将所有 HostBinding 添加到 Linker 中，然后调用 linker.linkAll() 进行全部 Binding 的依赖关联。\n4.2.7 BindingsGroup.java 内部主要一个 LinkedHashMap 变量，key 为需要需要依赖注入的类类全名，value 为其对应的 Binding 对象。\n4.2.8 DeferredBinding.java DeferredBinding 是 Binding 的一个子类，实际就是一个标记，在 linker.requestBinding 时候如果某个 Binding 不存在，则生成一个 DeferredBinding 添加到 toLink 队列中，在 linker.linkRequested 如果碰到 DeferredBinding 则根据 key 获得真正的 Binding 添加到 toLink 队列中。\n4.2.9 Keys.java 这是个 Key 相关的工具类。 getMembersKey(Class\u0026lt;?\u0026gt; key) 用于返回以 “members/” + keyClassName 的字符串。\n(1). boxIfPrimitive(Type type) 函数用于将原始类型转换为复杂类型 // TODO 其他函数作用\n4.2.10 Memoizer.java 一个小的缓存抽象类，内部主要是一个用于存储数据的 HashMap 属性和两个读写重入锁。\nMemoizer 主要函数有：\n(1). create(K key) 需要子类实现的抽象函数，表示创建 Value 的方式。\n(2). get(K key) 表示根据 key 从缓存中得到 value，value 如果已经存在则直接返回，否则调用 create(K key) 函数新建 value，存入缓存并返回。\nMemoizer 主要用在 Loader 中，Loder 中包含一个嵌套的 Memoizer 变量，内外分别作为类和 ClassLoader 的缓存。\n4.2.11 ModuleAdapter.java ModuleAdapter 主要属性有：\n(1). Class moduleClass 表示 ModuleAdapter 对应的 ModuleClass。\n(2). injectableTypes String 数组，存储需要依赖注入的类类名。为 @Module 注解的 injects 属性值。\n(3). staticInjections Class 数组，存储有静态属性依赖需要注入的类。\n(4). boolean overrides 表示某个 Module 的 @Provides 函数可以覆盖其他 Module，建议只在测试以及开发模式使用。\n(5). includes 表示 Module 由哪些其他类组成。\n(6). boolean complete 表示这个 Module 需要的所有 Binding 是否可以互相提供依赖，即是否能组成一个完整的 DAG。True 表示可以，False 表示不可以。如果一个 Module 有外部依赖的 Bindings 则为 False。\n(7). boolean library 表示这个 Module 是否提供对外的DenpendencyBinding，True 表示是，False 表示所有 Binding 仅被自己用到。\n4.2.12 Modules.java Modules.java 对外只有一个静态的 loadModules 函数，作用是返回一组 Module 类所对应的一组 ModuleAdapter 实例。\n该 函数入参为 Loader 和一个 ModuleClass 对象数组 seedModulesOrClasses，函数返回一个 HashMap，key 为 ModuleAdapter 对象，Value 为类似入参的 ModuleClass 对象，返回结果不仅包含入参 ModuleClass 及其对应的ModuleAdapter，也包含入参 ModuleClass 嵌套的 ModuleClass 及其对应的ModuleAdapter。\nloadModules 的逻辑比较简单，先通过 Loader.getModuleAdapter() 函数依次得到入参 seedModulesOrClasses 对应的 ModuleAdapter，然后查找得到的 ModuleAdapter 嵌套的 ModuleClass 对应的 ModuleAdapter，ModuleAdapter 嵌套的 ModuleClass 都存放在 ModuleAdapter 的 includes 对象中，由 APT 在编译时解析生成。\n4.2.13 ProblemDetector.java Binding 问题检测。 ProblemDetector 主要函数有：\n(1). detectCircularDependencies(Collection bindings) 检测一组 Binding 是否存在循环依赖。\n(2). detectUnusedBinding(Collection bindings) 检测一组 Binding 中是否存在无用的 Binding，即既不依赖其他 Binding 也不被其他 Binding 依赖，对于 DAG 图来说就是孤立的节点。\n(3). detectProblems(Collection values) 检测一组 Binding 是否存在问题，直接调用上面两个函数检测。这个函数会被 DaggerObjectGraph.validate() 调用进行检测。\n4.2.14 BuiltInBinding.java ProvidesBinding 是 Binding 的子类，它的作用是在 attach 时就已经得到了最终的 Binding，get() 调用时直接返回即可。\n4.2.15 LazyBinding.java LazyBinding 是 Binding 的子类，它的作用是延迟实例化 Binding，调用它的 get() 函数时只是返回一个 Lazy 匿名内部类对象，只有调用这个对象的 get() 函数时才会 返回真正的 Dependency。\n这样做的一个好处就是如果，真正的 Binding 的生成很耗费性能，则可以在最开始时只生成轻量级的 LazyBinding，真正要使用时才初始化真正的 Binding。\n4.2.16 ProvidesBinding.java ProvidesBinding 是 Binding 的子类，对于 Provide 方式的注入，APT 会一个继承自 ProvidesBinding.java 的子类，该生成类以 Provide 函数名首字母大写加上 ProvidesAdapter 命名，是 Provide 函数所在 Module 对应生成的ModuleAdapter中的静态内部类。\nProvidesBinding 主要属性有：\n(1). moduleClass 表示被 @Provides 修饰的函数所在的 Module 类名。\n(2). methodName 表示被 @Provides 修饰的函数函数名。\n4.2.17 SetBinding.java SetBinding 是 Binding 的子类，它的不同处在于保存了父 Binding，这样就形成了一个链表。\n4.2.18 StaticInjection.java 4.2.19 Lazy.java Lazy 是一个接口，用来标记表示可以通过 get() 函数得到真正的对象。\n4.2.20 MembersInjector.java MembersInjector 是一个接口，提供了 injectMembers() 用来向Host对象中注入(即设置)Dependency，HostDependency需要实现此接口。\n4.2.21 Module.java Module 是一个运行时注解，可以用来修饰类、接口、Enum。用来为 Dagger 提供需要依赖注入的 Host 信息及一些 Dependency 的生成方式。Module 的属性都在ModuleAdapter.java\n4.2.22 Provides.java Provides 是一个注解，只可以用来修饰函数。\n每个被 @Provides 修饰的生成函数都会生成一个继承自 ProvidesBinding.java 的子类，ProvidesBinding.java 继承自 Binding.java，生成类以 Provide 函数名首字母大写加上 ProvidesAdapter 命名，是 Provide 函数所在 Module 对应生成的ModuleAdapter中的静态内部类。 Binding 更具体信息在下面会介绍。\n4.2.23 ErrorHandler Interface 位于 Linker.java 内部，表示处理 Linker.linkRequested() 运行过程中的 error。\n4.2.24 ThrowingErrorHandler.java 上面 ErrorHandler Interface 的实现类，将 errors 汇总后以 IllegalStateException 抛出，为 Linker.linkRequested() 运行过程中积累的 errors 的默认处理方式。\n5. 聊聊 Dagger 本身 Dagger 由于其自身的复杂性，其实是一个上手难度颇高的库，难学会、难用好。但从功能上来讲，它又是一个实用价值非常高的库。而且即将发布的 Dagger 2.0 已经被 Square 转手交给了 Google 来开发和维护，从今以后它就是 Google 的官方库了，那么不论从官方支持方面还是从流行度上面， Dagger 都将会有一个很大的提升。关于 Dagger 的功能和用法，我会写一篇文章详细讲述。在本文的最后，列两个可能比较多人会问的问题和简单的回答：\n(1). Dagger 适合什么样的项目 Dagger 是一个依赖注入库，而依赖注入是一种优秀的编程思想，它可以通过解耦项目来提升项目的可阅读性、可扩展性和可维护性，并使得单元测试更为方便。因此，Dagger 适用于所有项目。\n(2). Dagger 适合什么样的个人和团队 Dagger 适合有学习能力并且愿意学习的个人和团队。这里要注意，如果你是开发团队的负责人，在决定启用 Dagger 之前一定要确认你的所有队员(起码是大部分队员)都符合这样的条件，否则 Dagger 可能会起反作用，毕竟——它不是 ButterKnife。\n","permalink":"https://blog.zdltech.com/posts/dagger-%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/","summary":"\u003ch3 id=\"内容来自httpsgithubcomandroid-cnandroid-open-project-analysis\"\u003e内容来自：https://github.com/android-cn/android-open-project-analysis\u003c/h3\u003e\n\u003ch3 id=\"1-\"\u003e1. 功能介绍\u003c/h3\u003e\n\u003ch4 id=\"1-1-dagger\"\u003e1.1 Dagger\u003c/h4\u003e\n\u003cp\u003eDagger 是一款 Java 平台的依赖注入库，关于依赖注入，详细见 \u003ca href=\"https://github.com/android-cn/blog/tree/master/java/dependency-injection\"\u003e依赖注入简介\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003eJava 的依赖注入库中，最有名的应该属 Google 的 Guice，Spring 也很有名，不过是专注于 J2EE 开发。Guice 的功能非常强大，但它是通过在运行时读取注解来实现依赖注入的，依赖的生成和注入需要依靠 Java 的反射机制，这对于对性能非常敏感的 Android 来说是一个硬伤。基于此，Dagger 应运而生。\u003c/p\u003e\n\u003cp\u003eDagger 同样使用注解来实现依赖注入，但它利用 APT(Annotation Process Tool) 在编译时生成辅助类，这些类继承特定父类或实现特定接口，程序在运行时 Dagger 加载这些辅助类，调用相应接口完成依赖生成和注入。Dagger 对于程序的性能影响非常小，因此更加适用于 Android 应用的开发。\u003c/p\u003e\n\u003ch4 id=\"1-2-\"\u003e1.2 依赖注入相关概念\u003c/h4\u003e\n\u003cp\u003e**依赖(Dependency)：**如果在 Class A 中，有个属性是 Class B 的实例，则称 Class B 是 Class A 的依赖，本文中我们将 Class A 称为宿主(Host)，并且全文用 Host 表示；Class B 称为依赖(Dependency)，并且全文用 Dependency 表示。一个 Host 可能是另外一个类的 Dependency。\u003c/p\u003e\n\u003cp\u003e**宿主(Host)：**如果 Class B 是 Class A 的 Dependency，则称 Class A 是 Class B 的宿主(Host)。\u003c/p\u003e","title":"Dagger 源码解析"},{"content":"内容来自：https://github.com/android-cn/android-open-project-analysis 1. 功能介绍 HoloGraphLibrary 是一个可用于绘制图表的项目，支持绘制线状图、柱状图、饼状图。\n优点：图形设计友好，使用方便。\n2. 总体设计 本项目较为简单，总体设计请参考4.1类关系图。\n3. 流程图 本项目的每个控件的流程较为类似，可以抽象成一个流程图来理解。\n4. 详细设计 4.1 类关系图 其中LineGraph、BarGraph、PieGraph分别对应线状图、柱状图、饼状图控件。\n其他除 View 以外的类都表示封装的数据。\n4.2 核心类功能介绍 4.2.1 柱状图： Bar.java：用于表现一个柱体，构成柱状图的基本元素。封装了颜色，名字，BarStackSegment（下文将会涉及）数组等属性。若需要对Bar的每一个片段进行控制，改变BarStackSegment数组属性即可。\nBarStackSegment.java：一般来说，一个柱体用于展示一个类型的数据，而BarStackSegment是作为柱体的扩展部分，用在同一个柱体上不同区间展示不同数据。\nBarGraph.java：继承View类，表示柱状图控件，通过数据绘制负责柱状图。\n(1). onDraw 流程图\n(2). onDraw 源码分析\na. 绘制的样式定义（柱体颜色、宽度大小等属性）\n`public void onDraw(Canvas ca) { ... // 柱体的样式定义 float maxValue = 0; float padding = 7; int selectPadding = 4; float bottomPadding = 40; // 定义绘制柱体的区间 float usableHeight; if (showBarText) { this.p.setTextSize(40); this.p.getTextBounds(unit, 0, 1, r3); usableHeight = getHeight() - bottomPadding - Math.abs(r3.top - r3.bottom) - 26; } else { usableHeight = getHeight() - bottomPadding; } ... // 绘制柱体 int count = 0; for (Bar p : points) { // 绘制每个柱体里的自定义区间 if(p.getStackedBar()){ ... }else { // 若没有自定义区间，则正常绘制 ... } } ... } ` b. 绘制计算过程（详细看源码）\n1）绘制 X 轴\n2）确定柱体的数量\n3）计算柱体所需的宽度\n4）如果使用动画，柱体最大值（影响绘画的高度）使用动态计算的最大值\n5）计算 X 轴上标签的字体的大小（不考虑动画状态，否则会导致字体抖动）\n6）设置柱体边界\n7）绘制柱体\n8）创建选择区域\n9）绘制标签\n10）绘制柱体顶部的文字\n11）限制总体宽度，防止弹出\n12）若有使用后，设置监听，对进行动画更新\n4.2.2 饼状图 PieSlice.java：扇形，构成饼状图的基本元素。封装了颜色，值，标题，路径以及区域等属性。\nPieGraph.java：：继承View类，表示饼状图控件，通过数据绘制负责饼状图。\n(1). onDraw 流程图\n(2). 绘制计算过程（详细看源码）\n1）若有背景图片，设置背景图片\n2）设置扇形的开始的位置，大小，圆心\n3）计算不同的扇形的大小，从上次结束的位置进行绘制，记录好该扇形结束的位置。重复此步骤，直到所有扇形绘制完成\n4.2.3 折线图： LinePoint.java：折线的最基本元素，两点构成一条直线，属性包括二维坐标，路径以及区域等属性。\nLine.java：由点构成线，里面封装了一个包含LinePoint的数组。\nLineGraph.java：：继承View类，表示折线图控件，通过数据绘制负责折线图。\n(1). onDraw 流程图\n(2). 绘制计算过程（详细看源码）\n1）若需要填充，先对整个绘制范围内进行直线绘制，然后擦除折线以上的直线\n2）绘制 X 轴\n3）绘制折线\n4）绘制折点\n5. 杂谈 其实，这个项目的代码并不适写的很好，但无碍我们的使用，有兴趣的同学可以重构一下，也有开发者 fork 之后扩展得更加有趣。-\u0026gt;链接。对于控件类的开源库，可以把重点放在绘制以及事件处理上。\n**延伸：**关于 View 绘制的原理请浏览：View 绘制流程\n","permalink":"https://blog.zdltech.com/posts/holographlibrary-%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/","summary":"\u003ch3 id=\"内容来自httpsgithubcomandroid-cnandroid-open-project-analysis\"\u003e内容来自：https://github.com/android-cn/android-open-project-analysis\u003c/h3\u003e\n\u003ch3 id=\"1-\"\u003e1. 功能介绍\u003c/h3\u003e\n\u003cp\u003eHoloGraphLibrary 是一个可用于绘制图表的项目，支持绘制线状图、柱状图、饼状图。\u003c/p\u003e\n\u003cp\u003e优点：图形设计友好，使用方便。\u003c/p\u003e\n\u003ch3 id=\"2-\"\u003e2. 总体设计\u003c/h3\u003e\n\u003cp\u003e本项目较为简单，总体设计请参考\u003ccode\u003e4.1类关系图\u003c/code\u003e。\u003c/p\u003e\n\u003ch3 id=\"3-\"\u003e3. 流程图\u003c/h3\u003e\n\u003cp\u003e本项目的每个控件的流程较为类似，可以抽象成一个流程图来理解。\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"https://raw.githubusercontent.com/android-cn/android-open-project-analysis/master/holographlibrary/image/holographflow.png\"\u003e\u003c/p\u003e\n\u003ch3 id=\"4-\"\u003e4. 详细设计\u003c/h3\u003e\n\u003ch4 id=\"4-1-\"\u003e4.1 类关系图\u003c/h4\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://raw.githubusercontent.com/android-cn/android-open-project-analysis/master/holographlibrary/image/uml.png\"\u003e\u003cbr\u003e\n其中\u003ccode\u003eLineGraph\u003c/code\u003e、\u003ccode\u003eBarGraph\u003c/code\u003e、\u003ccode\u003ePieGraph\u003c/code\u003e分别对应线状图、柱状图、饼状图控件。\u003cbr\u003e\n其他除 View 以外的类都表示封装的数据。\u003c/p\u003e\n\u003ch4 id=\"4-2-\"\u003e4.2 核心类功能介绍\u003c/h4\u003e\n\u003ch5 id=\"4-2-1-\"\u003e4.2.1 柱状图：\u003c/h5\u003e\n\u003cp\u003e\u003ccode\u003eBar.java\u003c/code\u003e：用于表现一个柱体，构成柱状图的基本元素。封装了颜色，名字，\u003ccode\u003eBarStackSegment\u003c/code\u003e（下文将会涉及）数组等属性。若需要对\u003ccode\u003eBar\u003c/code\u003e的每一个片段进行控制，改变\u003ccode\u003eBarStackSegment\u003c/code\u003e数组属性即可。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eBarStackSegment.java\u003c/code\u003e：一般来说，一个柱体用于展示一个类型的数据，而\u003ccode\u003eBarStackSegment\u003c/code\u003e是作为柱体的扩展部分，用在同一个柱体上不同区间展示不同数据。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eBarGraph.java\u003c/code\u003e：继承\u003ccode\u003eView\u003c/code\u003e类，表示柱状图控件，通过数据绘制负责柱状图。\u003c/p\u003e\n\u003cp\u003e(1). onDraw 流程图\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"https://raw.githubusercontent.com/android-cn/android-open-project-analysis/master/holographlibrary/image/bargraphflow.png\"\u003e\u003c/p\u003e\n\u003cp\u003e(2). onDraw 源码分析\u003cbr\u003e\na. 绘制的样式定义（柱体颜色、宽度大小等属性）\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`public void onDraw(Canvas ca) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ...\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    // 柱体的样式定义\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    float maxValue = 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    float padding = 7;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    int selectPadding = 4;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    float bottomPadding = 40;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    // 定义绘制柱体的区间\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    float usableHeight;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    if (showBarText) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        this.p.setTextSize(40);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        this.p.getTextBounds(unit, 0, 1, r3);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        usableHeight = getHeight() - bottomPadding - Math.abs(r3.top - r3.bottom) - 26;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } else {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        usableHeight = getHeight() - bottomPadding;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ...                    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    // 绘制柱体\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    int count = 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    for (Bar p : points) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        // 绘制每个柱体里的自定义区间\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        if(p.getStackedBar()){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                 ...\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }else {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            // 若没有自定义区间，则正常绘制\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            ...\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ...\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eb. 绘制计算过程（详细看源码）\u003cbr\u003e\n1）绘制 X 轴\u003cbr\u003e\n2）确定柱体的数量\u003cbr\u003e\n3）计算柱体所需的宽度\u003cbr\u003e\n4）如果使用动画，柱体最大值（影响绘画的高度）使用动态计算的最大值\u003cbr\u003e\n5）计算 X 轴上标签的字体的大小（不考虑动画状态，否则会导致字体抖动）\u003cbr\u003e\n6）设置柱体边界\u003cbr\u003e\n7）绘制柱体\u003cbr\u003e\n8）创建选择区域\u003cbr\u003e\n9）绘制标签\u003cbr\u003e\n10）绘制柱体顶部的文字\u003cbr\u003e\n11）限制总体宽度，防止弹出\u003cbr\u003e\n12）若有使用后，设置监听，对进行动画更新\u003c/p\u003e","title":"HoloGraphLibrary 源码解析"},{"content":"内容来自：https://github.com/android-cn/android-open-project-analysis 1. 功能介绍 特性(Features)： 支持Pinch手势自由缩放。 支持双击放大/还原。 支持平滑滚动。 在滑动父控件下能够运行良好。（例如：ViewPager） 支持基于Matrix变化（放大/缩小/移动）的事件监听。 优势： PhotoView是ImageView的子类，自然的支持所有ImageView的源生行为。 任意项目可以非常方便的从ImageView升级到PhotoView，不用做任何额外的修改。 可以非常方便的与ImageLoader/Picasso之类的异步网络图片读取库集成使用。 事件分发做了很好的处理，可以方便的与ViewPager等同样支持滑动手势的控件集成。 2. 总体设计 PhotoView这个库实际上比较简单,关键点其实就是Touch事件处理和Matrix图形变换的应用.\n2.1 TouchEvent及手势事件处理 对TouchEvent分发流程不了解的建议先阅读 Android Touch事件传递机制\n本库中对Touch事件的处理流程请参考第三部分的流程图，会有一个比较直观的认识。\n2.2 Matrix 由于Matrix是Android系统源生API,很多开发者对此都比较熟悉,为了不影响阅读效果，故不在此详细叙述,如果对其不是很了解,可以查看本文档末尾的Matrix补充说明\n3. 流程图 Touch及手势事件判定及传递流程：\n如图，从架构上看，干净利落的将事件层层分离，交由不同的Detector处理，最后再将处理结果回调给PhtotViewAttacher中的Matrix去实现图形变换效果。\n4. 详细设计 4.1 核心类功能介绍 Core核心类 4.1.1 PhotoView PhotoView 类负责暴露所有供外部调用的API,其本身直接继承自ImageView,同时实现了IPhotoView接口. IPhotoView接口提供了缩放相关的设置属性 和操控matrix变化的回调接口.\n主要方法说明:\npublic PhotoView(Context context) public PhotoView(Context context, AttributeSet attr) public PhotoView(Context context, AttributeSet attr, int defStyle) 构造函数,完全与ImageView相同,你可以将PhotoView直接当做ImageView使用,完全兼容.\npublic void setPhotoViewRotation(float rotationDegree) 用于设置图片旋转角度.\n注意： 例如使用Android相机拍摄的相片,会根据拍摄时手机方向的不同,在EXIF中存储不同的旋转角度信息,显示时往往需要查询EXIF信息并将照片旋转至正确的方向. 通常我们处理这种问题有两种方案：\n通过Bitmap.createBitmap方式重建出正确方向的图片，再加载到ImageView中显示。(不建议使用，因为会占用双倍的内存，Bitmap的回收不是立即生效的。) 在ImageView中使用自定义Matrix将图片旋转到正确的方向。 由于PhotoView中对图片的 缩放 操作依赖对Matrix的操作，自定义Matrix会干扰 PhotoView 的缩放行为，所以PhotoView并不支持ScaleType.Matrix. 可参见PhotoViewAttacher源码：\n/** * @return true if the ScaleType is supported. */ private static boolean isSupportedScaleType(final ScaleType scaleType) { if (null == scaleType) { return false; } switch (scaleType) { case MATRIX: throw new IllegalArgumentException(scaleType.name() + \u0026quot; is not supported in PhotoView\u0026quot;); default: return true; } } 这里特意提供了一个额外的setPhotoViewRotation方法即是为了解决这个问题。\npublic boolean canZoom() public void setZoomable(boolean zoomable) 缩放功能开关及状态获取. 关闭后PhotoView将不再响应 缩放 动作.\npublic RectF getDisplayRect() public Matrix getDisplayMatrix() public boolean setDisplayMatrix(Matrix finalRectangle) 获取及设置当前 matrix 状态.\npublic ScaleType getScaleType() 获取缩放模式。使用的源生的ImageView.ScaleType. 在PhotoView中默认值为FIT_CENTER.\npublic void setAllowParentInterceptOnEdge(boolean allow) 设置标志位 是否允许父控件捕获发生在边缘的TouchEvent\n这个标志位实际上对应的是 ViewParent.requestDisallowInterceptTouchEvent(boolean flag)\n经常做自定义View处理TouchEvent的对这个方法应当都不陌生。\nPhotoView中英文注释：\n* Here we decide whether to let the ImageView's parent to start taking * over the touch event. * * First we check whether this function is enabled. We never want the * parent to take over if we're scaling. We then check the edge we're * on, and the direction of the scroll (i.e. if we're pulling against * the edge, aka 'overscrolling', let the parent take over). 对应的代码：\nViewParent parent = imageView.getParent(); if (mAllowParentInterceptOnEdge \u0026amp;\u0026amp; !mScaleDragDetector.isScaling()) { if (mScrollEdge == EDGE_BOTH || (mScrollEdge == EDGE_LEFT \u0026amp;\u0026amp; dx \u0026gt;= 1f) || (mScrollEdge == EDGE_RIGHT \u0026amp;\u0026amp; dx \u0026lt;= -1f)) { if (null != parent) parent.requestDisallowInterceptTouchEvent(false); } } else { if (null != parent) { parent.requestDisallowInterceptTouchEvent(true); } } 通过调用setAllowParentInterceptOnEdge(false),可以完全屏蔽父控件的TouchEvent. 这个设置是为了防止父控件响应InterceptTouchEvent.\n例如\nPhotoView外层是ScrollView,通过requestDisallowInterceptTouchEvent方法可以阻止ScrollView响应滑动手势.\nPhotoView本身已做好了相关处理,在PhotoView滚到图片边缘时,Scroll事件由父控件处理,在PhotoView未滚动到边缘时,Scroll事件由PhotoView处理.\n除非开发者有特殊的需求,否则不需要自己去调用该方法改变TouchEvent事件的阻断逻辑.\npublic void setImageDrawable(Drawable drawable) public void setImageResource(int resId) public void setImageURI(Uri uri) 重载了ImageView的3个设置图片的方法,以确保图片改变时PhotoViewAttacher及时更新视图和重置matrix状态\nprotected void onDetachedFromWindow() 重载了ImageView的方法,用于在视图被从Window中移除时,通知PhotoViewAttacher清空数据.\n4.1.2 IPhotoView IPhotoView接口定义了缩放相关的一组set/get方法.PhotoView是其实现类. 相关方法已在PhotoView中介绍,这里略过.\n4.1.3 PhotoViewAttacher 核心类\nprivate static boolean isSupportedScaleType(final ScaleType scaleType) 判断ScaleType是否支持。 这个判断中实际只有ScaleType.Matrix会返回false.\n由于PhotoView中 缩放 滑动操作都依赖Matrix,所以并不支持用户再传入自定义Matrix.\npublic void cleanup() PhotoView不再使用时,可用于释放相关资源。移除Observer, Listener.\npublic boolean setDisplayMatrix(Matrix finalMatrix) 通过Matrix来直接修改ImageView的显示状态。\nprivate void cancelFling() 取消惯性滑动。\nprivate boolean checkMatrixBounds() 检查当前显示范围是否处于边界上，并更新mScrollEdge标志位。\n处理TouchEvent时需要根据mScrollEdge标志位的状态来判断是否允许ViewParent的InterceptTouchEvent接收TouchEvent.\nprivate void resetMatrix() 重置Matrix状态，并恢复至FIT_CENTER状态\nprivate void updateBaseMatrix(Drawable d) 根据PhotoView的宽高和Drawable的宽高计算FIT_CENTER状态的Matrix.\npublic void onDrag(float dx, float dy) OnGestureListener接口回调的实现方法.\n实际完成拖拽/移动效果. 核心代码:\nmSuppMatrix.postTranslate(dx, dy); 通过改代码修改Matrix中View的起始位置,制造出图片被拖拽移动的效果.\npublic void onFling(float startX, float startY, float velocityX, float velocityY) OnGestureListener接口回调的实现方法. 实际完成惯性滑动效果.\n惯性滑动效果分两部分完成.\n调用\nmScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, 0, 0);\n进行惯性滑动辅助计算.\n对Scroller不了解的可以参考官方说明 Scroller\n简单来讲,Scroller是一个辅助计算器,它可以帮你计算出某一时刻View的滚动状态及位置,但是它本身不会对View进行任何更改\n使用了FlingRunnable和Compat.postOnAnimation(imageView,mFlingRunnable)在每一帧绘制前更新Matrix状态 关于FlingRunnable和Compat.postOnAnimation类的作用机制可以参考下面 4.1.4的说明. public void onScale(float scaleFactor, float focusX, float focusY) OnGestureListener接口回调的实现方法.\n实际完成缩放效果.\n核心代码:\nmSuppMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY); 对Matrix作用机制不了解的话,可以拉到文档最后,有一个针对Matrix的简略介绍.\n内部类 FlingRunnable 实现惯性滑动的动画效果.\n这个Runnable必须配合 View.postOnAnimation(view,runnable) 使用.\n在下一帧绘制前,系统会执行该Runnable,这样我们就可以在runnable中更新UI状态.\n原理上类似一个递归调用,每次UI绘制前更新UI状态,并指定下次UI更新前再执行自己.\n这种写法 与 使用循环或Handler每隔16ms刷新一次UI基本等价,但是更为方便快捷.\n更新UI的核心逻辑非常简单,根据mScroller计算出的偏移量更新Matrix状态:\nmSuppMatrix.postTranslate(dx, dy); 内部类 AnimatedZoomRunnable 实现双击时的 缩放动画.\n作用机制基本同上.\n区别是AnimatedZoomRunnable的执行进度由AccelerateDecelerateInterpolator控制.\n对Interpolator没有概念的可以参阅官方Demo Interpolator\n你也可以简单认为这就是一个动画进度控制器.\n核心逻辑依然很简单,根据动画进度缩小/放大图片\nmSuppMatrix.postScale(deltaScale, deltaScale, mFocalX, mFocalY); 接口及工具类 4.1.4 Compat 用于做View.postOnAnimation方法在低版本上的兼容.\n注：View.postOnAnimation (Runnable action) 在PhotoView中用于处理 双击 放大/缩小 惯性滑动时的动画效果.\n每次系统绘图前都会先执行这个Runnable回调，通过在此时改变视图状态以实现动画效果。该方法仅支持 api \u0026gt;= 16 所以PhotoView中使用了Compat类来做低版本兼容。\n实际上也可以使用android.support.v4.view.ViewCompat替代。 对比 android.support.v4.view.ViewCompat 和 uk.co.senab.photoview.Compat 其实现原理完全一致，都是通过view.postDelayed(runnable, frameTime)来实现.\n4.1.5 ScrollerProxy 抽象类,主要是为了做不用版本之间的兼容,具体说明见GingerScroller IcsScroller PreGingerScroller 这三个接口实现类的说明.\n4.1.6 GingerScroller ScrollerProxy 接口实现类 适用于 API 9 ~ 14 即 2.3 ~ 4.0 之间的所有Android版本. 其实现主要基于 android.widget.OverScroller\n4.1.7 IcsScroller 适用于 API 14 以上 即 4.0 以上的所有Android版本 其实现基于源生 android.widget.OverScroller , 没有任何修改.\n4.1.8 PreGingerScroller 适用于 API 9 以下 即 2.3 以下的所有Android版本 其实现主要基于 android.widget.Scroller\n4.1.9 GestureDetector 接口,主要是为了做不同版本之间的兼容,具体说明见 CupcakeGestureDetector,EclairGestureDetector,FroyoGestureDetector 三个接口的实现类.\n4.1.10 OnGestureListener 手势回调接口\n4.1.11 CupcakeGestureDetector 适用于 api \u0026lt; 7 的设备,此时PhotoView不支持双指pinch放大/缩小操作\n4.1.12 EclairGestureDetector 适用于 api \u0026gt;= 8 , 用于修正多指操控的问题,使TouchEvent的getActiveX getActiveY指向正确的Pointer,并将事件传递给 CupcakeGestureDetector 处理,此时PhotoView不支持双指pinch放大/缩小操作\n4.1.13 FroyoGestureDetector 适用于 api \u0026gt; 9 , 通过android.view.ScaleGestureDetector实现对Pinch手势的支持,并将事件传递给 EclairGestureDetector 处理\n注意: 以上3个类并不实际执行 放大/缩小 行为, 判断行为之后会回调给PhtotViewAttacher执行缩放/移动操作\n4.1.14 VersionedGestureDetector 提供GestureDetector的实例，由它根据系统版本决定实例化哪一个 GestureDetector ，主要是为了兼容Android的不同版本。 具体调用栈请参考总体设计中调用流程图,注意一点,PhotoViewAttacher本身就实现了OnGestureListener接口,实际的缩放操作是由PhotoViewAttacher完成的,而不是这里声明的各个GestureDetector.\n4.2 类关系图 5. 杂谈 该库唯一缺少的可能是 手势旋转 功能(可以参考QQ). 不过由于PhotoView中已将各级事件分开处理,从架构上来看可扩展性良好,自定义一个RotateGestureDetector来捕获旋转手势也可行. 但如何在不与ScaleGestureDetector冲突的情况下完成该功能会稍微有些麻烦. 如果不需要手势旋转的话，该库提供了单独的接口可以用代码设置旋转角度。\n6. Matrix补充说明 Matrix是一个 3×3 矩阵,使用Matrix可以对 Bitmap/Canvas 进行4类基本图形变换,使用起来非常简便，如果你对Matrix的抽象变换不熟悉，还可以使用android.graphics.Camera类进行辅助计算。 Camera类可以将矩阵变换抽象成 视点（摄像机） 在三维空间内的移动，更易于直观的理解其效果。\n矩阵如下：\n相关API使用起来非常简单。 效果用文字比较难表述，直接看图好了. 你也可以自己运行Demo Project\n虚影为原始位置，实图为变换后位置.\nAPI public void setTranslate(float dx, float dy) 对目标进行平移dx,dy * public void setScale(float sx, float sy, float px, float py) 以(px,py)为中心,横向上缩放比例sx,纵向缩放比例sy * public void setRotate(float degrees, float px, float py) 以(px,py)为中心,旋转degrees度 * public void setSkew(float kx, float ky, float px, float py) 图像的错切实际上是平面景物在投影平面上的非垂直投影。错切使图像中的图形产生扭变。 这里是以(px,py)为中心,扭曲图片的x轴和y轴. 这个用文字难以解释,请参考下面的实际效果图片. #### 原理 {#-} 如果你对矩阵变换背后的数学原理感兴趣且`线性代数`的内容没忘光的话，推荐这篇 [文章][5]. \u0026lt;div id=\u0026quot;xunlei_com_thunder_helper_plugin_d462f475-c18e-46be-bd10-327458d045bd\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/photoview-%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/","summary":"\u003ch3 id=\"内容来自httpsgithubcomandroid-cnandroid-open-project-analysis\"\u003e内容来自：https://github.com/android-cn/android-open-project-analysis\u003c/h3\u003e\n\u003ch3 id=\"1-\"\u003e1. 功能介绍\u003c/h3\u003e\n\u003ch5 id=\"-features-\"\u003e特性(Features)：\u003c/h5\u003e\n\u003cul\u003e\n\u003cli\u003e支持Pinch手势自由缩放。\u003c/li\u003e\n\u003cli\u003e支持双击放大/还原。\u003c/li\u003e\n\u003cli\u003e支持平滑滚动。\u003c/li\u003e\n\u003cli\u003e在滑动父控件下能够运行良好。（例如：ViewPager）\u003c/li\u003e\n\u003cli\u003e支持基于Matrix变化（放大/缩小/移动）的事件监听。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch5 id=\"-\"\u003e优势：\u003c/h5\u003e\n\u003cul\u003e\n\u003cli\u003ePhotoView是ImageView的子类，自然的支持所有ImageView的源生行为。\u003c/li\u003e\n\u003cli\u003e任意项目可以非常方便的从ImageView升级到PhotoView，不用做任何额外的修改。\u003c/li\u003e\n\u003cli\u003e可以非常方便的与ImageLoader/Picasso之类的异步网络图片读取库集成使用。\u003c/li\u003e\n\u003cli\u003e事件分发做了很好的处理，可以方便的与ViewPager等同样支持滑动手势的控件集成。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"2-\"\u003e2. 总体设计\u003c/h3\u003e\n\u003cp\u003ePhotoView这个库实际上比较简单,关键点其实就是Touch事件处理和Matrix图形变换的应用.\u003c/p\u003e\n\u003ch5 id=\"2-1-touchevent-\"\u003e2.1 TouchEvent及手势事件处理\u003c/h5\u003e\n\u003cp\u003e对TouchEvent分发流程不了解的建议先阅读 \u003ca href=\"http://www.trinea.cn/android/touch-event-delivery-mechanism/\"\u003eAndroid Touch事件传递机制\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e本库中对Touch事件的处理流程请参考第三部分的流程图，会有一个比较直观的认识。\u003c/p\u003e\n\u003ch5 id=\"2-2-matrix\"\u003e2.2 Matrix\u003c/h5\u003e\n\u003cp\u003e由于Matrix是Android系统源生API,很多开发者对此都比较熟悉,为了不影响阅读效果，故不在此详细叙述,如果对其不是很了解,可以查看本文档末尾的Matrix补充说明\u003c/p\u003e\n\u003ch3 id=\"3-\"\u003e3. 流程图\u003c/h3\u003e\n\u003cp\u003eTouch及手势事件判定及传递流程：\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"流程图\" loading=\"lazy\" src=\"https://raw.githubusercontent.com/android-cn/android-open-project-analysis/master/photoview/images/flow.png\"\u003e\u003c/p\u003e\n\u003cp\u003e如图，从架构上看，干净利落的将事件层层分离，交由不同的Detector处理，最后再将处理结果回调给PhtotViewAttacher中的Matrix去实现图形变换效果。\u003c/p\u003e\n\u003ch3 id=\"4-\"\u003e4. 详细设计\u003c/h3\u003e\n\u003ch3 id=\"4-1-\"\u003e4.1 核心类功能介绍\u003c/h3\u003e\n\u003ch3 id=\"core-\"\u003eCore核心类\u003c/h3\u003e\n\u003chr\u003e\n\u003ch5 id=\"4-1-1-photoview\"\u003e4.1.1 PhotoView\u003c/h5\u003e\n\u003cp\u003ePhotoView 类负责暴露所有供外部调用的API,其本身直接继承自ImageView,同时实现了IPhotoView接口. IPhotoView接口提供了缩放相关的设置属性 和操控matrix变化的回调接口.\u003c/p\u003e\n\u003cp\u003e主要方法说明:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003epublic PhotoView(Context context)\u003c/li\u003e\n\u003cli\u003epublic PhotoView(Context context, AttributeSet attr)\u003c/li\u003e\n\u003cli\u003epublic PhotoView(Context context, AttributeSet attr, int defStyle)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e构造函数,完全与ImageView相同,你可以将PhotoView直接当做ImageView使用,完全兼容.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003epublic void setPhotoViewRotation(float rotationDegree)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e用于设置图片旋转角度.\u003c/p\u003e\n\u003cp\u003e注意： 例如使用Android相机拍摄的相片,会根据拍摄时手机方向的不同,在EXIF中存储不同的旋转角度信息,显示时往往需要查询EXIF信息并将照片旋转至正确的方向. 通常我们处理这种问题有两种方案：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e通过Bitmap.createBitmap方式重建出正确方向的图片，再加载到ImageView中显示。(不建议使用，因为会占用双倍的内存，Bitmap的回收不是立即生效的。)\u003c/li\u003e\n\u003cli\u003e在ImageView中使用自定义Matrix将图片旋转到正确的方向。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e由于PhotoView中对图片的 缩放 操作依赖对Matrix的操作，自定义Matrix会干扰 PhotoView 的缩放行为，所以PhotoView并不支持ScaleType.Matrix. 可参见PhotoViewAttacher源码：\u003c/p\u003e","title":"PhotoView 源码解析"},{"content":"内容来自：https://github.com/android-cn/android-open-project-analysis 1. 功能介绍 xUtils一个Android公共库框架，主要包括四个部分：View，Db, Http, Bitmap 四个模块。\nView模块主要的功能是通过注解绑定UI，资源，事件。 Db模块是一个数据库orm框架， 简单的语句就能进行数据的操作。 Http模块主要访问网络，支持同步，异步方式的请求，支持文件的下载。 Bitmap模块是加载图片以及图片的处理， 支持加载本地，网络图片。而且支持图片的内存和本地缓存。 2. 详细设计 2.1 View模块 2.1.1 总体设计 流程和关系较少， 请看下面的详细分析\n2.1.2 流程图 2.1.3 核心类功能介绍 请先了解注解 ，动态代理 可以帮助到您， 如果已经了解请忽略。 注解和反射知识是这个模块的主要内容\n1.ViewUtils.java View和各种事件的注入以及资源的注入。\n(1)主要函数 ` private static void injectObject(Object handler, ViewFinder finder) ` 第一个参数Object handler代表的是需要注入的对象， 第二个参数是需要注入View（这个View就是handler的成员变量）所在的View或者Activity的包装对象。 该方法完成了View和各种事件的注入以及资源的注入。主要的原理就是通过反射和注解。\n完成Activity的setContentView。 完成View的注入。 完成资源的注入。 完成各种事件的注入。 2.ViewFinder.java (1)主要函数 ` public View findViewById(int id, int pid) public View findViewById(int id) ` 如果存在父View， 优先从父View寻找，否则从当前的View或者Activity中寻找。\n3.ResLoader.java ` public static Object loadRes(ResType type, Context context, int id) ` 获取资源文件值。支持多种资源的获取。\n4.EventListenerManager.java 事件的注入， 其中的设计是通过动态代理。\n`private final static DoubleKeyValueMap\u0026amp;lt;ViewInjectInfo, Class\u0026amp;lt;?\u0026amp;gt;, Object\u0026amp;gt; listenerCache = new DoubleKeyValueMap\u0026amp;lt;ViewInjectInfo, Class\u0026amp;lt;?\u0026amp;gt;, Object\u0026amp;gt;(); ` 存放监听事件接口map。 因为有些接口有多个函数， 代理会判断事件接口是否存在， 如果存在只增加代理方法就够了， 避免重新设置监听事件接口。\n`public static void addEventMethod( ViewFinder finder, ViewInjectInfo info, Annotation eventAnnotation, Object handler, Method method) ` 代理监听事件\n5.注解类 2.2 Db模块 2.2.1 总体设计 流程和关系较少， 请看下面的详细分析\n2.2.2 流程图 2.2.3 核心类功能介绍 注解、反射和数据库操作知识这个模块的主要内容\n1.DbUtils.java 主要功能数据库的创建，数据库的增删改查。\n` private static HashMap\u0026amp;lt;String, DbUtils\u0026amp;gt; daoMap = new HashMap\u0026amp;lt;String, DbUtils\u0026amp;gt;(); ` 存放DbUtils实例对象的map，每个数据库对应一个实例， key为数据库的名称。\n`private synchronized static DbUtils getInstance(DaoConfig daoConfig) ` 采取的是单例模式，根据DaoConfig创建数据库， 中间还涉及到数据库升级。\n` delete； findAll； findById； saveOrUpdate；// 当数据库没有时保存， 存在时修改。 update； ` 增删改查。\n2.DaoConfig.java ` private String dbName = \u0026#34;xUtils.db\u0026#34;; // default db name数据库名称 private int dbVersion = 1; //数据库版本 private DbUpgradeListener dbUpgradeListener; //升级监听事件 ` 数据库配置类。\n3.FindTempCache.java 在DbUtils的查询数据中\n` @SuppressWarnings(\u0026#34;unchecked\u0026#34;) public \u0026amp;lt;T\u0026amp;gt; List\u0026amp;lt;T\u0026amp;gt; findAll(Selector selector) throws DbException { .... String sql = selector.toString(); long seq = CursorUtils.FindCacheSequence.getSeq(); findTempCache.setSeq(seq); Object obj = findTempCache.get(sql);//优先从缓存读取 if (obj != null) { return (List\u0026amp;lt;T\u0026amp;gt;) obj; } ... } ` 数据库查询数据的缓存。在查询中会优先调用缓存中的数据\n4.SqlInfoBuilder.java sql建表、增删改语句的组合。\n`public static SqlInfo buildCreateTableSqlInfo(DbUtils db, Class\u0026amp;lt;?\u0026amp;gt; entityType) public static SqlInfo buildDeleteSqlInfo(DbUtils db, Class\u0026amp;lt;?\u0026amp;gt; entityType, Object idValue) public static SqlInfo buildDeleteSqlInfo(DbUtils db, Class\u0026amp;lt;?\u0026amp;gt; entityType, WhereBuilder whereBuilder) public static SqlInfo buildDeleteSqlInfo(DbUtils db, Object entity) public static SqlInfo buildInsertSqlInfo(DbUtils db, Object entity) public static SqlInfo buildUpdateSqlInfo(DbUtils db, Object entity, String... updateColumnNames) public static SqlInfo buildUpdateSqlInfo(DbUtils db, Object entity, WhereBuilder whereBuilder, String... updateColumnNames) ` 5.SqlInfo.java sql语句和值包装对象。\n6.Table.java 表对象。\n7.Column.java 表中列对象。\n8.Id.java 表对应的主键对象。\n9.Selector.java sql查询语句的组合。\n10.WhereBuilder.java sql条件语句的组合。\n2.3 Http模块 2.3.1 总体设计 2.3.2 流程图 2.3.3 类图 1.HttpUtils.java 支持异步同步访问网络数据， 断点下载文件。\n` //网络数据的缓存。 public final static HttpCache sHttpCache = new HttpCache(); //访问网络的HttpClient。 private final DefaultHttpClient httpClient; private final HttpContext httpContext = new BasicHttpContext(); //线程池。 private final static PriorityExecutor EXECUTOR = new PriorityExecutor(DEFAULT_POOL_SIZE); ` `public HttpUtils(int connTimeout, String userAgent) { //配置超时时间，UserAgent， http版本信息协议等一些信息 ..... //将配置的参数统一放到httpClient中 httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager(params, schemeRegistry), params); .... //下面这个关键，设置拦截器。 默认加上gizp压缩。 通过gizp压缩后的数据传输效率高很多。 httpClient.addRequestInterceptor(new HttpRequestInterceptor() { @Override public void process(org.apache.http.HttpRequest httpRequest, HttpContext httpContext) throws org.apache.http.HttpException, IOException { if (!httpRequest.containsHeader(HEADER_ACCEPT_ENCODING)) { httpRequest.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP); } } }); httpClient.addResponseInterceptor(new HttpResponseInterceptor() { @Override public void process(HttpResponse response, HttpContext httpContext) throws org.apache.http.HttpException, IOException { final HttpEntity entity = response.getEntity(); if (entity == null) { return; } final Header encoding = entity.getContentEncoding(); if (encoding != null) { for (HeaderElement element : encoding.getElements()) { if (element.getName().equalsIgnoreCase(\u0026#34;gzip\u0026#34;)) { //这里判断从服务器传输的数据是否需要通过gzip解压。 response.setEntity(new GZipDecompressingEntity(response.getEntity())); return; } } } } }); } ` ` //访问网络数据 private \u0026amp;lt;T\u0026amp;gt; HttpHandler\u0026amp;lt;T\u0026amp;gt; sendRequest(HttpRequest request, RequestParams params, RequestCallBack\u0026amp;lt;T\u0026amp;gt; callBack); //下载网络文件 public HttpHandler\u0026amp;lt;File\u0026amp;gt; download(HttpRequest.HttpMethod method, String url, String target, RequestParams params, boolean autoResume, boolean autoRename, RequestCallBack\u0026amp;lt;File\u0026amp;gt; callback); ` 2.HttpRequest.java 网络请求的包装类。 包括url， 访问请求方法， 参数值等。\n3.RequestCallBack.java 完成数据请求回调接口。\n4.HttpHandler.java 获取网络数据逻辑的实现。这里可以理解为系统内部AsyncTask。 访问网络数据处理流程图\n5.HttpCache.java 网络数据的缓存，内部包含LruMemoryCache。在获取数据的时候会判断是否过期。\n6.StringDownLoadHandler.java handleEntity()将网络io流转化为String。\n7.FileDownLoadHandler.java handleEntity()将网络io流转化为File。\n8.HttpException.java 统一异常\n2.4 Bitmap模块 2.4.1 总体设计 2.4.2 流程图 请查看http模块\n2.4.3 类图 1.BitmapUtils.java 图片的异步加载，支持本地和网络图片， 图片的压缩处理， 图片的内存缓存已经本地缓存。\n` private BitmapGlobalConfig globalConfig; // 线程池，缓存，和网络的配置 private BitmapDisplayConfig defaultDisplayConfig; //图片显示的配置 ` ` /** * @param container 表示需要显示图片的View * @param uri 图片的uri * @param displayConfig 图片显示的配置 * @param callBack 图片加载的回调接口 */ public \u0026amp;lt;T extends View\u0026amp;gt; void display(T container, String uri, BitmapDisplayConfig displayConfig, BitmapLoadCallBack\u0026amp;lt;T\u0026amp;gt; callBack) ` 设置图片流程图\n详细流程图\n2.BitmapLoadTask.java 加载图片的异步任务。在doInBackground中读取图片资源\n3.BitmapCache.java ` private LruDiskCache mDiskLruCache; //闪存缓存 private LruMemoryCache\u0026amp;lt;MemoryCacheKey, Bitmap\u0026amp;gt; mMemoryCache; //运存缓存 ` (1)主要函数 ` //下载网络图片， 然后根据配置压缩图片， 将图片缓存。 public Bitmap downloadBitmap(String uri, BitmapDisplayConfig config, final BitmapUtils.BitmapLoadTask\u0026amp;lt;?\u0026amp;gt; task) //从运存缓存中读取bitmap 在获取的时候会判断是否过期 public Bitmap getBitmapFromMemCache(String uri, BitmapDisplayConfig config) //从闪存缓存中读取bitmap public Bitmap getBitmapFromDiskCache(String uri, BitmapDisplayConfig config) ` 4.BitmapGlobalConfig.java 配置， 包括线程池， 缓存的大小。\n`//闪存缓存的路径 private String diskCachePath; //运存缓存的最大值 private int memoryCacheSize = 1024 * 1024 * 4; // 4MB //闪存缓存的最大值 private int diskCacheSize = 1024 * 1024 * 50; // 50M //从网络加载数据的线程池 private final static PriorityExecutor BITMAP_LOAD_EXECUTOR = new PriorityExecutor(DEFAULT_POOL_SIZE); //从闪存读取数据的线程池 private final static PriorityExecutor DISK_CACHE_EXECUTOR = new PriorityExecutor(2); //bitmap缓存的的时间 private long defaultCacheExpiry = 1000L * 60 * 60 * 24 * 30; // 30 days //bitmap缓存 private BitmapCache bitmapCache; ` 5.BitmapDisplayConfig.java ` //图片显示的大小 private BitmapSize bitmapMaxSize; //图片的动画 private Animation animation; // 图片加载过程中的显示图片 private Drawable loadingDrawable; // 图片加载失败的显示图片 private Drawable loadFailedDrawable; // 图片显示的配置色彩 private Bitmap.Config bitmapConfig = Bitmap.Config.RGB_565; ` 6.DefaultDownloader.java 获取bitmap， 支持三种获取路径， 本地文件，资产文件， 和网络图片。\n7.DefaultBitmapLoadCallBack.java 图片加载完成的的回调， 默认回调将获取的bitmap值传递给view。\n3. 杂谈 和Volley框架相比\n相同点： 1.采用了网络数据缓存机制。 2.通过handler进行线程通信 不同点： Volley的Http请求在 android 2.3 版本之前是通过HttpClient ，在之后的版本是通过URLHttpConnection。xUtils都是通过HttpClient请求网络（bitmap模块图片下载是通过 URLHttpConnection）。 URLHttpConnection默认支持GZIP压缩，api操作简单。 2.Volley将Http请求数据先缓存进byte[]， 然后是分配给不同的请求转化为需要的格式。xUtils是直接转化为想要的格式。 Volley：扩展性好， 但是不能存在大数据请求，否则就OOM。xUtils：不缓存入byte[] 支持大数据的请求， 速度比Volley稍快，但扩展性就低。 4.Volley访问网络数据时直接开启固定个数线程访问网络， 在run方法中执行死循环， 阻塞等待请求队列。 xUtils是开启线程池来管理线程。 缓存失效策略， volley的所有网络数据支持从http响应头中控制是否缓存和读取缓存失效时间，每个请求可以控制是否缓存和缓存失效时间。 Xutils网络数据请求是统一自定义缓存失效时间。 ","permalink":"https://blog.zdltech.com/posts/xutils-%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/","summary":"\u003ch3 id=\"内容来自httpsgithubcomandroid-cnandroid-open-project-analysis\"\u003e内容来自：https://github.com/android-cn/android-open-project-analysis\u003c/h3\u003e\n\u003ch3 id=\"1-\"\u003e1. 功能介绍\u003c/h3\u003e\n\u003cp\u003exUtils一个Android公共库框架，主要包括四个部分：View，Db, Http, Bitmap 四个模块。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eView模块主要的功能是通过注解绑定UI，资源，事件。\u003c/li\u003e\n\u003cli\u003eDb模块是一个数据库orm框架， 简单的语句就能进行数据的操作。\u003c/li\u003e\n\u003cli\u003eHttp模块主要访问网络，支持同步，异步方式的请求，支持文件的下载。\u003c/li\u003e\n\u003cli\u003eBitmap模块是加载图片以及图片的处理， 支持加载本地，网络图片。而且支持图片的内存和本地缓存。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"2-\"\u003e2. 详细设计\u003c/h3\u003e\n\u003ch4 id=\"2-1-view-\"\u003e2.1 View模块\u003c/h4\u003e\n\u003ch5 id=\"2-1-1-\"\u003e2.1.1 总体设计\u003c/h5\u003e\n\u003cp\u003e流程和关系较少， 请看下面的详细分析\u003c/p\u003e\n\u003ch5 id=\"2-1-2-\"\u003e2.1.2 流程图\u003c/h5\u003e\n\u003cp\u003e\u003cimg alt=\"流程图\" loading=\"lazy\" src=\"https://raw.githubusercontent.com/android-cn/android-open-project-analysis/master/xutils/image/view_sque.png\"\u003e\u003c/p\u003e\n\u003ch5 id=\"2-1-3-\"\u003e2.1.3 核心类功能介绍\u003c/h5\u003e\n\u003ch6 id=\"-https-github-com-android-cn-android-open-project-analysis-blob-master-tech-annotation-md-https-github-com-android-cn-android-open-project-analysis-blob-master-tech-proxy-md-\"\u003e请先了解\u003ca href=\"https://github.com/android-cn/android-open-project-analysis/blob/master/tech/annotation.md\"\u003e注解\u003c/a\u003e ，\u003ca href=\"https://github.com/android-cn/android-open-project-analysis/blob/master/tech/proxy.md\"\u003e动态代理\u003c/a\u003e 可以帮助到您， 如果已经了解请忽略。\u003c/h6\u003e\n\u003cp\u003e注解和反射知识是这个模块的主要内容\u003c/p\u003e\n\u003ch5 id=\"1-viewutils-java\"\u003e1.ViewUtils.java\u003c/h5\u003e\n\u003cp\u003eView和各种事件的注入以及资源的注入。\u003c/p\u003e\n\u003ch6 id=\"-1-\"\u003e(1)主要函数\u003c/h6\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`    private static void injectObject(Object handler, ViewFinder finder)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e第一个参数Object handler代表的是需要注入的对象， 第二个参数是需要注入View（这个View就是handler的成员变量）所在的View或者Activity的包装对象。 该方法完成了View和各种事件的注入以及资源的注入。主要的原理就是通过反射和注解。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e完成Activity的setContentView。\u003c/li\u003e\n\u003cli\u003e完成View的注入。\u003c/li\u003e\n\u003cli\u003e完成资源的注入。\u003c/li\u003e\n\u003cli\u003e完成各种事件的注入。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch5 id=\"2-viewfinder-java\"\u003e2.ViewFinder.java\u003c/h5\u003e\n\u003ch6 id=\"-1-\"\u003e(1)主要函数\u003c/h6\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`    public View findViewById(int id, int pid)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public View findViewById(int id)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e如果存在父View， 优先从父View寻找，否则从当前的View或者Activity中寻找。\u003c/p\u003e\n\u003ch5 id=\"3-resloader-java\"\u003e3.ResLoader.java\u003c/h5\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`    public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e Object loadRes(ResType type, Context context, int id)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e获取资源文件值。支持多种资源的获取。\u003c/p\u003e","title":"xUtils 源码解析"},{"content":"内容来自：https://github.com/android-cn/android-open-project-analysis 1. 功能介绍 1.1 Android Universal Image Loader Android Universal Image Loader 是一个强大的、可高度定制的图片缓存，本文简称为UIL。\n简单的说 UIL 就做了一件事——获取图片并显示在相应的控件上。\n1.2 基本使用 1.2.1 初始化 添加完依赖后在Application或Activity中初始化ImageLoader，如下：\n`public class YourApplication extends Application { @Override public void onCreate() { super.onCreate(); ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this) // 添加你的配置需求 .build(); ImageLoader.getInstance().init(configuration); } } ` 其中 configuration 表示ImageLoader的配置信息，可包括图片最大尺寸、线程池、缓存、下载器、解码器等等。\n1.2.2 Manifest 配置 `\u0026amp;lt;manifest\u0026amp;gt; \u0026amp;lt;uses-permission android:name=\u0026#34;android.permission.INTERNET\u0026#34; /\u0026amp;gt; \u0026amp;lt;uses-permission android:name=\u0026#34;android.permission.WRITE_EXTERNAL_STORAGE\u0026#34; /\u0026amp;gt; \u0026amp;lt;application android:name=\u0026#34;.YourApplication\u0026#34; …… \u0026amp;gt; …… \u0026amp;lt;/application\u0026amp;gt; \u0026amp;lt;/manifest\u0026amp;gt; ` 添加网络权限。如果允许磁盘缓存，需要添加写外设的权限。\n1.2.3 下载显示图片 下载图片，解析为 Bitmap 并在 ImageView 中显示。\n`imageLoader.displayImage(imageUri, imageView); ` 下载图片，解析为 Bitmap 传递给回调接口。\n`imageLoader.loadImage(imageUri, new SimpleImageLoadingListener() { @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { // 图片处理 } }); ` 以上是简单使用，更复杂 API 见本文详细设计。\n1.3 特点 可配置度高。支持任务线程池、下载器、解码器、内存及磁盘缓存、显示选项等等的配置。 包含内存缓存和磁盘缓存两级缓存。 支持多线程，支持异步和同步加载。 支持多种缓存算法、下载进度监听、ListView 图片错乱解决等。 2. 总体设计 2.1. 总体设计图 上面是 UIL 的总体设计图。整个库分为ImageLoaderEngine，Cache及ImageDownloader，ImageDecoder，BitmapDisplayer，BitmapProcessor五大模块，其中Cache分为MemoryCache和DiskCache两部分。\n简单的讲就是ImageLoader收到加载及显示图片的任务，并将它交给ImageLoaderEngine，ImageLoaderEngine分发任务到具体线程池去执行，任务通过Cache及ImageDownloader获取图片，中间可能经过BitmapProcessor和ImageDecoder处理，最终转换为Bitmap交给BitmapDisplayer在ImageAware中显示。\n2.2. UIL 中的概念 简单介绍一些概念，在4. 详细设计中会仔细介绍。\n**ImageLoaderEngine：**任务分发器，负责分发LoadAndDisplayImageTask和ProcessAndDisplayImageTask给具体的线程池去执行，本文中也称其为engine，具体参考4.2.6 ImageLoaderEngine.java。\n**ImageAware：**显示图片的对象，可以是ImageView等，具体参考4.2.9 ImageAware.java。\n**ImageDownloader：**图片下载器，负责从图片的各个来源获取输入流, 具体参考4.2.22 ImageDownloader.java。\n**Cache：**图片缓存，分为MemoryCache和DiskCache两部分。\n**MemoryCache：**内存图片缓存，可向内存缓存缓存图片或从内存缓存读取图片，具体参考4.2.24 MemoryCache.java。\n**DiskCache：**本地图片缓存，可向本地磁盘缓存保存图片或从本地磁盘读取图片，具体参考4.2.38 DiskCache.java。\n**ImageDecoder：**图片解码器，负责将图片输入流InputStream转换为Bitmap对象, 具体参考4.2.53 ImageDecoder.java。\n**BitmapProcessor：**图片处理器，负责从缓存读取或写入前对图片进行处理。具体参考4.2.61 BitmapProcessor.java。\n**BitmapDisplayer：**将Bitmap对象显示在相应的控件ImageAware上, 具体参考4.2.56 BitmapDisplayer.java。\n**LoadAndDisplayImageTask：**用于加载并显示图片的任务, 具体参考4.2.20 LoadAndDisplayImageTask.java。\n**ProcessAndDisplayImageTask：**用于处理并显示图片的任务, 具体参考4.2.19 ProcessAndDisplayImageTask.java。\n**DisplayBitmapTask：**用于显示图片的任务, 具体参考4.2.18 DisplayBitmapTask.java。\n3. 流程图 上图为图片加载及显示流程图，在uil库中给出，这里用中文重新画出。\n4. 详细设计 4.1 类关系图 4.2 核心类功能介绍 4.2.1 ImageLoader.java 图片加载器，对外的主要 API，采取了单例模式，用于图片的加载和显示。\n主要函数：\n(1). getInstance() 得到ImageLoader的单例。通过双层是否为 null 判断提高性能。\n(2). init(ImageLoaderConfiguration configuration) 初始化配置参数，参数configuration为ImageLoader的配置信息，包括图片最大尺寸、任务线程池、磁盘缓存、下载器、解码器等等。\n实现中会初始化ImageLoaderEngine engine属性，该属性为任务分发器。\n(3). displayImage(String uri, ImageAware imageAware, DisplayImageOptions options, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) 加载并显示图片或加载并执行回调接口。ImageLoader 加载图片主要分为三类接口：\ndisplayImage(…) 表示异步加载并显示图片到对应的ImageAware上。 loadImage(…) 表示异步加载图片并执行回调接口。 loadImageSync(…) 表示同步加载图片。 以上三类接口最终都会调用到这个函数进行图片加载。函数参数解释如下：\nuri: 图片的 uri。uri 支持多种来源的图片，包括 http、https、file、content、assets、drawable 及自定义，具体介绍可见ImageDownloader。\nimageAware: 一个接口，表示需要加载图片的对象，可包装 View。\noptions: 图片显示的配置项。比如加载前、加载中、加载失败应该显示的占位图片，图片是否需要在磁盘缓存，是否需要在内存缓存等。\nlistener: 图片加载各种时刻的回调接口，包括开始加载、加载失败、加载成功、取消加载四个时刻的回调函数。\nprogressListener: 图片加载进度的回调接口。\n函数流程图如下：\n4.2.2 ImageLoaderConfiguration.java ImageLoader的配置信息，包括图片最大尺寸、线程池、缓存、下载器、解码器等等。\n主要属性：\n(1). Resources resources 程序本地资源访问器，用于加载DisplayImageOptions中设置的一些 App 中图片资源。\n(2). int maxImageWidthForMemoryCache 内存缓存的图片最大宽度。\n(3). int maxImageHeightForMemoryCache 内存缓存的图片最大高度。\n(4). int maxImageWidthForDiskCache 磁盘缓存的图片最大宽度。\n(5). int maxImageHeightForDiskCache 磁盘缓存的图片最大高度。\n(6). BitmapProcessor processorForDiskCache 图片处理器，用于处理从磁盘缓存中读取到的图片。\n(7). Executor taskExecutor ImageLoaderEngine中用于执行从源获取图片任务的 Executor。\n(18). Executor taskExecutorForCachedImages ImageLoaderEngine中用于执行从缓存获取图片任务的 Executor。\n(19). boolean customExecutor 用户是否自定义了上面的 taskExecutor。\n(20). boolean customExecutorForCachedImages 用户是否自定义了上面的 taskExecutorForCachedImages。\n(21). int threadPoolSize 上面两个默认线程池的核心池大小，即最大并发数。\n(22). int threadPriority 上面两个默认线程池的线程优先级。\n(23). QueueProcessingType tasksProcessingType 上面两个默认线程池的线程队列类型。目前只有 FIFO, LIFO 两种可供选择。\n(24). MemoryCache memoryCache 图片内存缓存。\n(25). DiskCache diskCache 图片磁盘缓存，一般放在 SD 卡。\n(26). ImageDownloader downloader 图片下载器。\n(27). ImageDecoder decoder 图片解码器，内部可使用我们常用的BitmapFactory.decode(…)将图片资源解码成Bitmap对象。\n(28). DisplayImageOptions defaultDisplayImageOptions 图片显示的配置项。比如加载前、加载中、加载失败应该显示的占位图片，图片是否需要在磁盘缓存，是否需要在内存缓存等。\n(29). ImageDownloader networkDeniedDownloader 不允许访问网络的图片下载器。\n(30). ImageDownloader slowNetworkDownloader 慢网络情况下的图片下载器。\n4.2.3 ImageLoaderConfiguration.Builder.java 静态内部类 Builder 模式，用于构造参数繁多的ImageLoaderConfiguration。\n其属性与ImageLoaderConfiguration类似，函数多是属性设置函数。\n主要函数及含义：\n(1). build() 按照配置，生成 ImageLoaderConfiguration。代码如下：\n`public ImageLoaderConfiguration build() { initEmptyFieldsWithDefaultValues(); return new ImageLoaderConfiguration(this); } ` (2). initEmptyFieldsWithDefaultValues() 初始化值为null的属性。若用户没有配置相关项，UIL 会通过调用DefaultConfigurationFactory中的函数返回一个默认值当配置。\ntaskExecutorForCachedImages、taskExecutor及ImageLoaderEngine的taskDistributor的默认值如下：\nparameters taskDistributor taskExecutorForCachedImages/taskExecutor corePoolSize 3 maximumPoolSize Integer.MAX_VALUE 3 keepAliveTime 60 unit SECONDS MILLISECONDS workQueue SynchronousQueue LIFOLinkedBlockingDeque / LinkedBlockingQueue priority 5 3 diskCacheFileNameGenerator默认值为HashCodeFileNameGenerator。\nmemoryCache默认值为LruMemoryCache。如果内存缓存不允许缓存一张图片的多个尺寸，则用FuzzyKeyMemoryCache做封装，同一个图片新的尺寸会覆盖缓存中该图片老的尺寸。\ndiskCache默认值与diskCacheSize和diskCacheFileCount值有关，如果他们有一个大于 0，则默认为LruDiskCache，否则使用无大小限制的UnlimitedDiskCache。\ndownloader默认值为BaseImageDownloader。\ndecoder默认值为BaseImageDecoder。\n详细及其他属性默认值请到DefaultConfigurationFactory中查看。\n(3). denyCacheImageMultipleSizesInMemory() 设置内存缓存不允许缓存一张图片的多个尺寸，默认允许。\n后面会讲到 View 的 getWidth() 在初始化前后的不同值与这个设置的关系。\n(4). diskCacheSize(int maxCacheSize) 设置磁盘缓存的最大字节数，如果大于 0 或者下面的maxFileCount大于 0，默认的DiskCache会用LruDiskCache，否则使用无大小限制的UnlimitedDiskCache。\n(5). diskCacheFileCount(int maxFileCount) 设置磁盘缓存文件夹下最大文件数，如果大于 0 或者上面的maxCacheSize大于 0，默认的DiskCache会用LruDiskCache，否则使用无大小限制的UnlimitedDiskCache。\n4.2.4 ImageLoaderConfiguration.NetworkDeniedImageDownloader.java 静态内部类 不允许访问网络的图片下载器，实现了ImageDownloader接口。\n实现也比较简单，包装一个ImageDownloader对象，通过在 getStream(…) 函数中禁止 Http 和 Https Scheme 禁止网络访问，如下：\n`@Override public InputStream getStream(String imageUri, Object extra) throws IOException { switch (Scheme.ofUri(imageUri)) { case HTTP: case HTTPS: throw new IllegalStateException(); default: return wrappedDownloader.getStream(imageUri, extra); } } ` 4.2.5 ImageLoaderConfiguration.SlowNetworkImageDownloader.java 静态内部类 慢网络情况下的图片下载器，实现了ImageDownloader接口。\n通过包装一个ImageDownloader对象实现，在 getStream(…) 函数中当 Scheme 为 Http 和 Https 时，用FlushedInputStream代替InputStream处理慢网络情况，具体见后面FlushedInputStream的介绍。\n4.2.6 ImageLoaderEngine.java LoadAndDisplayImageTask和ProcessAndDisplayImageTask任务分发器，负责分发任务给具体的线程池。\n主要属性：\n(1). ImageLoaderConfiguration configuration ImageLoader的配置信息，可包括图片最大尺寸、线程池、缓存、下载器、解码器等等。\n(2). Executor taskExecutor 用于执行从源获取图片任务的 Executor，为configuration中的 taskExecutor，如果为null，则会调用DefaultConfigurationFactory.createExecutor(…)根据配置返回一个默认的线程池。\n(3). Executor taskExecutorForCachedImages 用于执行从缓存获取图片任务的 Executor，为configuration中的 taskExecutorForCachedImages，如果为null，则会调用DefaultConfigurationFactory.createExecutor(…)根据配置返回一个默认的线程池。\n(4). Executor taskDistributor 任务分发线程池，任务指LoadAndDisplayImageTask和ProcessAndDisplayImageTask，因为只需要分发给上面的两个 Executor 去执行任务，不存在较耗时或阻塞操作，所以用无并发数(Int 最大值)限制的线程池即可。\n(5). Map\u0026lt;integer, string=””\u0026gt; cacheKeysForImageAwares ImageAware与内存缓存 key 对应的 map，key 为ImageAware的 id，value 为内存缓存的 key。\n(6). Map\u0026lt;string, reentrantlock=””\u0026gt; uriLocks 图片正在加载的重入锁 map，key 为图片的 uri，value 为标识其正在加载的重入锁。\n(7). AtomicBoolean paused 是否被暂停。如果为true，则所有新的加载或显示任务都会等待直到取消暂停(为false)。\n(8). AtomicBoolean networkDenied 是否不允许访问网络，如果为true，通过ImageLoadingListener.onLoadingFailed(…)获取图片，则所有不在缓存中需要网络访问的请求都会失败，返回失败原因为网络访问被禁止。\n(9). AtomicBoolean slowNetwork 是否是慢网络情况，如果为true，则自动调用SlowNetworkImageDownloader下载图片。\n(10). Object pauseLock 暂停的等待锁，可在engine被暂停后调用这个锁等待。\n主要函数：\n(1). void submit(final LoadAndDisplayImageTask task) 添加一个LoadAndDisplayImageTask。直接用taskDistributor执行一个 Runnable，在 Runnable 内部根据图片是否被磁盘缓存过确定使用taskExecutorForCachedImages还是taskExecutor执行该 task。\n(2). void submit(ProcessAndDisplayImageTask task) 添加一个ProcessAndDisplayImageTask。直接用taskExecutorForCachedImages执行该 task。\n(3). void pause() 暂停图片加载任务。所有新的加载或显示任务都会等待直到取消暂停(为false)。\n(4). void resume() 继续图片加载任务。\n(5). stop() 暂停所有加载和显示图片任务并清除这里的内部属性值。\n(6). fireCallback(Runnable r) taskDistributor立即执行某个任务。\n(7). getLockForUri(String uri) 得到某个 uri 的重入锁，如果不存在则新建。\n(8). createTaskExecutor() 调用DefaultConfigurationFactory.createExecutor(…)创建一个线程池。\n(9). getLoadingUriForView(ImageAware imageAware) 得到某个imageAware正在加载的图片 uri。\n(10). prepareDisplayTaskFor(ImageAware imageAware, String memoryCacheKey) 准备开始一个Task。向cacheKeysForImageAwares中插入ImageAware的 id 和图片在内存缓存中的 key。\n(11). void cancelDisplayTaskFor(ImageAware imageAware) 取消一个显示任务。从cacheKeysForImageAwares中删除ImageAware对应元素。\n(12). denyNetworkDownloads(boolean denyNetworkDownloads) 设置是否不允许网络访问。\n(13). handleSlowNetwork(boolean handleSlowNetwork) 设置是否慢网络情况。\n4.2.7 DefaultConfigurationFactory.java 为ImageLoaderConfiguration及ImageLoaderEngine提供一些默认配置。\n主要函数：\n(1). createExecutor(int threadPoolSize, int threadPriority, QueueProcessingType tasksProcessingType) 创建线程池。\nthreadPoolSize表示核心池大小(最大并发数)。\nthreadPriority表示线程优先级。\ntasksProcessingType表示线程队列类型，目前只有 FIFO, LIFO 两种可供选择。\n内部实现会调用createThreadFactory(…)返回一个支持线程优先级设置，并且以固定规则命名新建的线程的线程工厂类DefaultConfigurationFactory.DefaultThreadFactory。\n(2). createTaskDistributor() 为ImageLoaderEngine中的任务分发器taskDistributor提供线程池，该线程池为 normal 优先级的无并发大小限制的线程池。\n(3). createFileNameGenerator() 返回一个HashCodeFileNameGenerator对象，即以 uri HashCode 为文件名的文件名生成器。\n(4). createDiskCache(Context context, FileNameGenerator diskCacheFileNameGenerator, long diskCacheSize, int diskCacheFileCount) 创建一个 Disk Cache。如果 diskCacheSize 或者 diskCacheFileCount 大于 0，返回一个LruDiskCache，否则返回无大小限制的UnlimitedDiskCache。\n(5). createMemoryCache(Context context, int memoryCacheSize) 创建一个 Memory Cache。返回一个LruMemoryCache，若 memoryCacheSize 为 0，则设置该内存缓存的最大字节数为 App 最大可用内存的 1/8。\n这里 App 的最大可用内存也支持系统在 Honeycomb之后(ApiLevel \u0026gt;= 11) application 中android:largeHeap=\u0026quot;true\u0026quot;的设置。\n(6). createImageDownloader(Context context) 创建图片下载器，返回一个BaseImageDownloader。\n(7). createImageDecoder(boolean loggingEnabled) 创建图片解码器，返回一个BaseImageDecoder。\n(8). createBitmapDisplayer() 创建图片显示器，返回一个SimpleBitmapDisplayer。\n4.2.8 DefaultConfigurationFactory.DefaultThreadFactory 默认的线程工厂类，为\nDefaultConfigurationFactory.createExecutor(…)\n和\nDefaultConfigurationFactory.createTaskDistributor(…)\n提供线程工厂。支持线程优先级设置，并且以固定规则命名新建的线程。\nPS：重命名线程是个很好的习惯，它的一大作用就是方便问题排查，比如性能优化，用 TraceView 查看线程，根据名字很容易分辨各个线程。\n4.2.9 ImageAware.java 需要显示图片的对象的接口，可包装 View 表示某个需要显示图片的 View。\n主要函数：\n(1). View getWrappedView() 得到被包装的 View，图片在该 View 上显示。\n(2). getWidth() 与 getHeight() 得到宽度高度，在计算图片缩放比例时会用到。\n(3). getId() 得到唯一标识 id。ImageLoaderEngine中用这个 id 标识正在加载图片的ImageAware和图片内存缓存 key 的对应关系，图片请求前会将内存缓存 key 与新的内存缓存 key 进行比较，如果不相等，则之前的图片请求会被取消。这样当ImageAware被复用时就不会因异步加载(前面任务未取消)而造成错乱了。\n4.2.10 ViewAware.java 封装 Android View 来显示图片的抽象类，实现了ImageAware接口，利用Reference来 Warp View 防止内存泄露。\n主要函数：\n(1). ViewAware(View view, boolean checkActualViewSize) 构造函数。\nview表示需要显示图片的对象。\ncheckActualViewSize表示通过getWidth()和getHeight()获取图片宽高时返回真实的宽和高，还是LayoutParams的宽高，true 表示返回真实宽和高。\n如果为true会导致一个问题，View在还没有初始化完成时加载图片，这时它的真实宽高为0，会取它LayoutParams的宽高，而图片缓存的 key 与这个宽高有关，所以当View初始化完成再次需要加载该图片时，getWidth()和getHeight()返回的宽高都已经变化，缓存 key 不一样，从而导致缓存命中失败会再次从网络下载一次图片。可通过ImageLoaderConfiguration.Builder.denyCacheImageMultipleSizesInMemory()设置不允许内存缓存缓存一张图片的多个尺寸。\n(2). setImageDrawable(Drawable drawable) 如果当前操作在主线程并且 View 没有被回收，则调用抽象函数setImageDrawableInto(Drawable drawable, View view)去向View设置图片。\n(3). setImageBitmap(Bitmap bitmap) 如果当前操作在主线程并且 View 没有被回收，则调用抽象函数setImageBitmapInto(Bitmap bitmap, View view)去向View设置图片。\n4.2.11 ImageViewAware.java 封装 Android ImageView 来显示图片的ImageAware，继承了ViewAware，利用Reference来 Warp View 防止内存泄露。\n如果getWidth()函数小于等于0，会利用反射获取mMaxWidth的值作为宽。\n如果getHeight()函数小于等于0，会利用反射获取mMaxHeight的值作为高。\n4.2.12 NonViewAware.java 仅包含处理图片相关信息却没有需要显示图片的 View 的ImageAware，实现了ImageAware接口。常用于加载图片后调用回调接口而不是显示的情况。\n4.2.13 DisplayImageOptions.java 图片显示的配置项。比如加载前、加载中、加载失败应该显示的占位图片，图片是否需要在磁盘缓存，是否需要在 memory 缓存等。\n主要属性及含义：\n(1). int imageResOnLoading 图片正在加载中的占位图片的 resource id，优先级比下面的imageOnLoading高，当存在时，imageOnLoading不起作用。\n(2). int imageResForEmptyUri 空 uri 时的占位图片的 resource id，优先级比下面的imageForEmptyUri高，当存在时，imageForEmptyUri不起作用。\n(3). int imageResOnFail 加载失败时的占位图片的 resource id，优先级比下面的imageOnFail高，当存在时，imageOnFail不起作用。\n(4). Drawable imageOnLoading 加载中的占位图片的 drawabled 对象，默认为 null。\n(5). Drawable imageForEmptyUri 空 uri 时的占位图片的 drawabled 对象，默认为 null。\n(6). Drawable imageOnFail 加载失败时的占位图片的 drawabled 对象，默认为 null。\n(7). boolean resetViewBeforeLoading 在加载前是否重置 view，通过 Builder 构建的对象默认为 false。\n(8). boolean cacheInMemory 是否缓存在内存中，通过 Builder 构建的对象默认为 false。\n(9). boolean cacheOnDisk 是否缓存在磁盘中，通过 Builder 构建的对象默认为 false。\n(10). ImageScaleType imageScaleType 图片的缩放类型，通过 Builder 构建的对象默认为IN_SAMPLE_POWER_OF_2。\n(11). Options decodingOptions; 为 BitmapFactory.Options，用于BitmapFactory.decodeStream(imageStream, null, decodingOptions)得到图片尺寸等信息。\n(12). int delayBeforeLoading 设置在开始加载前的延迟时间，单位为毫秒，通过 Builder 构建的对象默认为 0。\n(13). boolean considerExifParams 是否考虑图片的 EXIF 信息，通过 Builder 构建的对象默认为 false。\n(14). Object extraForDownloader 下载器需要的辅助信息。下载时传入ImageDownloader.getStream(String, Object)的对象，方便用户自己扩展，默认为 null。\n(15). BitmapProcessor preProcessor 缓存在内存之前的处理程序，默认为 null。\n(16). BitmapProcessor postProcessor 缓存在内存之后的处理程序，默认为 null。\n(17). BitmapDisplayer displayer 图片的显示方式，通过 Builder 构建的对象默认为SimpleBitmapDisplayer。\n(18). Handler handler handler 对象，默认为 null。\n(19). boolean isSyncLoading 是否同步加载，通过 Builder 构建的对象默认为 false。\n4.2.14 DisplayImageOptions.Builder.java 静态内部类 Builder 模式，用于构造参数繁多的DisplayImageOptions。\n其属性与DisplayImageOptions类似，函数多是属性设置函数。\n4.2.15 ImageLoadingListener.java 图片加载各种时刻的回调接口，可在图片加载的某些点做监听。\n包括开始加载(onLoadingStarted)、加载失败(onLoadingFailed)、加载成功(onLoadingComplete)、取消加载(onLoadingCancelled)四个回调函数。\n4.2.16 SimpleImageLoadingListener.java 实现ImageLoadingListener接口，不过各个函数都是空实现，表示不在 Image 加载过程中做任何回调监听。\nImageLoader.displayImage(…)函数中当入参listener为空时的默认值。\n4.2.17 ImageLoadingProgressListener.java Image 加载进度的回调接口。其中抽象函数\n`void onProgressUpdate(String imageUri, View view, int current, int total) ` 会在获取图片存储到文件系统时被回调。其中total表示图片总大小，为网络请求结果Response Header中content-length字段，如果不存在则为 -1。\n4.2.18 DisplayBitmapTask.java 显示图片的Task，实现了Runnable接口，必须在主线程调用。\n主要函数：\n(1) run() 首先判断imageAware是否被 GC 回收，如果是直接调用取消加载回调接口ImageLoadingListener.onLoadingCancelled(…)；\n否则判断imageAware是否被复用，如果是直接调用取消加载回调接口ImageLoadingListener.onLoadingCancelled(…)；\n否则调用displayer显示图片，并将imageAware从正在加载的 map 中移除。调用加载成功回调接口ImageLoadingListener.onLoadingComplete(…)。\n对于 ListView 或是 GridView 这类会缓存 Item 的 View 来说，单个 Item 中如果含有 ImageView，在滑动过程中可能因为异步加载及 View 复用导致图片错乱，这里对imageAware是否被复用的判断就能很好的解决这个问题。原因类似：Android ListView 滑动过程中图片显示重复错位闪烁问题原因及解决方案。\n4.2.19 ProcessAndDisplayImageTask.java 处理并显示图片的Task，实现了Runnable接口。\n主要函数：\n(1) run() 主要通过 imageLoadingInfo 得到BitmapProcessor处理图片，并用处理后的图片和配置新建一个DisplayBitmapTask在ImageAware中显示图片。\n4.2.20 LoadAndDisplayImageTask.java 加载并显示图片的Task，实现了Runnable接口，用于从网络、文件系统或内存获取图片并解析，然后调用DisplayBitmapTask在ImageAware中显示图片。\n主要函数：\n(1) run() 获取图片并显示，核心代码如下：\n`bmp = configuration.memoryCache.get(memoryCacheKey); if (bmp == null || bmp.isRecycled()) { bmp = tryLoadBitmap(); ... ... ... if (bmp != null \u0026amp;\u0026amp; options.isCacheInMemory()) { L.d(LOG_CACHE_IMAGE_IN_MEMORY, memoryCacheKey); configuration.memoryCache.put(memoryCacheKey, bmp); } } …… DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(bmp, imageLoadingInfo, engine, loadedFrom); runTask(displayBitmapTask, syncLoading, handler, engine); ` 从上面代码段中可以看到先是从内存缓存中去读取 bitmap 对象，若 bitmap 对象不存在，则调用 tryLoadBitmap() 函数获取 bitmap 对象，获取成功后若在 DisplayImageOptions.Builder 中设置了 cacheInMemory(true), 同时将 bitmap 对象缓存到内存中。\n最后新建DisplayBitmapTask显示图片。\n函数流程图如下：\n判断图片的内存缓存是否存在，若存在直接执行步骤 8； 判断图片的磁盘缓存是否存在，若存在直接执行步骤 5； 从网络上下载图片； 将图片缓存在磁盘上； 将图片 decode 成 bitmap 对象； 根据DisplayImageOptions配置对图片进行预处理(Pre-process Bitmap)； 将 bitmap 对象缓存到内存中； 根据DisplayImageOptions配置对图片进行后处理(Post-process Bitmap)； 执行DisplayBitmapTask将图片显示在相应的控件上。\n流程图可以参见3. 流程图。 (2) tryLoadBitmap() 从磁盘缓存或网络获取图片，核心代码如下：\n`File imageFile = configuration.diskCache.get(uri); if (imageFile != null \u0026amp;\u0026amp; imageFile.exists()) { ... bitmap = decodeImage(Scheme.FILE.wrap(imageFile.getAbsolutePath())); } if (bitmap == null || bitmap.getWidth() \u0026amp;lt;= 0 || bitmap.getHeight() \u0026amp;lt;= 0) { ... String imageUriForDecoding = uri; if (options.isCacheOnDisk() \u0026amp;\u0026amp; tryCacheImageOnDisk()) { imageFile = configuration.diskCache.get(uri); if (imageFile != null) { imageUriForDecoding = Scheme.FILE.wrap(imageFile.getAbsolutePath()); } } checkTaskNotActual(); bitmap = decodeImage(imageUriForDecoding); ... } ` 首先根据 uri 看看磁盘中是不是已经缓存了这个文件，如果已经缓存，调用 decodeImage 函数，将图片文件 decode 成 bitmap 对象； 如果 bitmap 不合法或缓存文件不存在，判断是否需要缓存在磁盘，需要则调用tryCacheImageOnDisk()函数去下载并缓存图片到本地磁盘，再通过decodeImage(imageUri)函数将图片文件decode成bitmap对象，否则直接通过decodeImage(imageUriForDecoding)下载图片并解析。\n(3) tryCacheImageOnDisk() 下载图片并存储在磁盘内，根据磁盘缓存图片最长宽高的配置处理图片。\n` loaded = downloadImage(); ` 主要就是这一句话，调用下载器下载并保存图片。\n如果你在ImageLoaderConfiguration中还配置了maxImageWidthForDiskCache或者maxImageHeightForDiskCache，还会调用resizeAndSaveImage()函数，调整图片尺寸，并保存新的图片文件。\n(4) downloadImage() 下载图片并存储在磁盘内。调用getDownloader()得到ImageDownloader去下载图片。\n(4) resizeAndSaveImage(int maxWidth, int maxHeight) 从磁盘缓存中得到图片，重新设置大小及进行一些处理后保存。\n(5) getDownloader() 根据ImageLoaderEngine配置得到下载器。\n如果不允许访问网络，则使用不允许访问网络的图片下载器NetworkDeniedImageDownloader；如果是慢网络情况，则使用慢网络情况下的图片下载器SlowNetworkImageDownloader；否则直接使用ImageLoaderConfiguration中的downloader。\n4.2.21 ImageLoadingInfo.java 加载和显示图片任务需要的信息。\nString uri 图片 url。\nString memoryCacheKey 图片缓存 key。\nImageAware imageAware 需要加载图片的对象。\nImageSize targetSize 图片的显示尺寸。\nDisplayImageOptions options 图片显示的配置项。\nImageLoadingListener listener 图片加载各种时刻的回调接口。\nImageLoadingProgressListener progressListener 图片加载进度的回调接口。\nReentrantLock loadFromUriLock 图片加载中的重入锁。\n4.2.22 ImageDownloader.java 图片下载接口。待实现函数\n`getStream(String imageUri, Object extra) ` 表示通过 uri 得到 InputStream。\n通过内部定义的枚举Scheme, 可以看出 UIL 支持哪些图片来源。\n`HTTP(\u0026#34;http\u0026#34;), HTTPS(\u0026#34;https\u0026#34;), FILE(\u0026#34;file\u0026#34;), CONTENT(\u0026#34;content\u0026#34;), ASSETS(\u0026#34;assets\u0026#34;), DRAWABLE(\u0026#34;drawable\u0026#34;), UNKNOWN(\u0026#34;\u0026#34;); ` 4.2.23 BaseImageDownloader.java ImageDownloader的具体实现类。得到上面各种Scheme对应的图片 InputStream。\n主要函数\n(1). getStream(String imageUri, Object extra) 在getStream(…)函数内根据不同Scheme类型获取图片输入流。\n`@Override public InputStream getStream(String imageUri, Object extra) throws IOException { switch (Scheme.ofUri(imageUri)) { case HTTP: case HTTPS: return getStreamFromNetwork(imageUri, extra); case FILE: return getStreamFromFile(imageUri, extra); case CONTENT: return getStreamFromContent(imageUri, extra); case ASSETS: return getStreamFromAssets(imageUri, extra); case DRAWABLE: return getStreamFromDrawable(imageUri, extra); case UNKNOWN: default: return getStreamFromOtherSource(imageUri, extra); } } ` 具体见下面各函数介绍。\n(2). getStreamFromNetwork(String imageUri, Object extra) 通过HttpURLConnection从网络获取图片的InputStream。支持 response code 为 3xx 的重定向。这里有个小细节代码如下：\n`try { imageStream = conn.getInputStream(); } catch (IOException e) { // Read all data to allow reuse connection (http://bit.ly/1ad35PY) IoUtils.readAndCloseStream(conn.getErrorStream()); throw e; } ` 在发生异常时会调用conn.getErrorStream()继续读取 Error Stream，这是为了利于网络连接回收及复用。但有意思的是在 Froyo(2.2) 之前，HttpURLConnection 有个重大 Bug，调用 close() 函数会影响连接池，导致连接复用失效，不少库通过在 2.3 之前使用 AndroidHttpClient 解决这个问题。\n(3). getStreamFromFile(String imageUri, Object extra) 从文件系统获取图片的InputStream。如果 uri 是 video 类型，则需要单独得到 video 的缩略图返回，否则按照一般读取文件操作返回。\n(4). getStreamFromContent(String imageUri, Object extra) 从 ContentProvider 获取图片的InputStream。\n如果是 video 类型，则先从MediaStore得到 video 的缩略图返回；\n如果是联系人类型，通过ContactsContract.Contacts.openContactPhotoInputStream(res, uri)读取内容返回。\n否则通过 ContentResolver.openInputStream(…) 读取内容返回。\n(5). getStreamFromAssets(String imageUri, Object extra) 从 Assets 中获取图片的InputStream。\n(6). getStreamFromDrawable(String imageUri, Object extra) 从 Drawable 资源中获取图片的InputStream。\n(7). getStreamFromOtherSource(String imageUri, Object extra) UNKNOWN(自定义)类型的处理，目前是直接抛出不支持的异常。\n4.2.24 MemoryCache.java Bitmap 内存缓存接口，需要实现的接口包括 get(…)、put(…)、remove(…)、clear()、keys()。\n4.2.25 BaseMemoryCache.java 实现了MemoryCache主要函数的抽象类，以 Map\u0026lt;string, reference\u0026lt;bitmap=””\u0026raquo; softMap 做为缓存池，利于虚拟机在内存不足时回收缓存对象。提供抽象函数：\n`protected abstract Reference\u0026amp;lt;Bitmap\u0026amp;gt; createReference(Bitmap value) ` 表示根据 Bitmap 创建一个 Reference 做为缓存对象。Reference 可以是 WeakReference、SoftReference 等。\n4.2.26 WeakMemoryCache.java 以WeakReference\u0026lt;Bitmap\u0026gt;做为缓存 value 的内存缓存，实现了BaseMemoryCache。\n实现了BaseMemoryCache的createReference(Bitmap value)函数，直接返回一个new WeakReference\u0026lt;Bitmap\u0026gt;(value)做为缓存 value。\n4.2.27 LimitedMemoryCache.java 限制总字节大小的内存缓存，继承自BaseMemoryCache的抽象类。\n会在 put(…) 函数中判断总体大小是否超出了上限，是则循环删除缓存对象直到小于上限。删除顺序由抽象函数\n`protected abstract Bitmap removeNext() ` 决定。抽象函数\n`protected abstract int getSize(Bitmap value) ` 表示每个元素大小。\n4.2.28 LargestLimitedMemoryCache.java 限制总字节大小的内存缓存，会在缓存满时优先删除 size 最大的元素，继承自LimitedMemoryCache。\n实现了LimitedMemoryCache缓存removeNext()函数，总是返回当前缓存中 size 最大的元素。\n4.2.29 UsingFreqLimitedMemoryCache.java 限制总字节大小的内存缓存，会在缓存满时优先删除使用次数最少的元素，继承自LimitedMemoryCache。\n实现了LimitedMemoryCache缓存removeNext()函数，总是返回当前缓存中使用次数最少的元素。\n4.2.30 LRULimitedMemoryCache.java 限制总字节大小的内存缓存，会在缓存满时优先删除最近最少使用的元素，继承自LimitedMemoryCache。\n通过new LinkedHashMap\u0026lt;String, Bitmap\u0026gt;(10, 1.1f, true)作为缓存池。LinkedHashMap 第三个参数表示是否需要根据访问顺序(accessOrder)排序，true 表示根据accessOrder排序，最近访问的跟最新加入的一样放到最后面，false 表示根据插入顺序排序。这里为 true 且缓存满时始终删除第一个元素，即始终删除最近最少访问的元素。\n实现了LimitedMemoryCache缓存removeNext()函数，总是返回第一个元素，即最近最少使用的元素。\n4.2.31 FIFOLimitedMemoryCache.java 限制总字节大小的内存缓存，会在缓存满时优先删除先进入缓存的元素，继承自LimitedMemoryCache。\n实现了LimitedMemoryCache缓存removeNext()函数，总是返回最先进入缓存的元素。\n以上所有LimitedMemoryCache子类都有个问题，就是 Bitmap 虽然通过WeakReference\u0026lt;Bitmap\u0026gt;包装，但实际根本不会被虚拟机回收，因为他们子类中同时都保留了 Bitmap 的强引用。大都是 UIL 早期实现的版本，不推荐使用。\n4.2.32 LruMemoryCache.java 限制总字节大小的内存缓存，会在缓存满时优先删除最近最少使用的元素，实现了MemoryCache。LRU(Least Recently Used) 为最近最少使用算法。\n以new LinkedHashMap\u0026lt;String, Bitmap\u0026gt;(0, 0.75f, true)作为缓存池。LinkedHashMap 第三个参数表示是否需要根据访问顺序(accessOrder)排序，true 表示根据accessOrder排序，最近访问的跟最新加入的一样放到最后面，false 表示根据插入顺序排序。这里为 true 且缓存满时始终删除第一个元素，即始终删除最近最少访问的元素。\n在put(…)函数中通过trimToSize(int maxSize)函数判断总体大小是否超出了上限，是则删除第缓存池中第一个元素，即最近最少使用的元素，直到总体大小小于上限。\nLruMemoryCache功能上与LRULimitedMemoryCache类似，不过在实现上更加优雅。用简单的实现接口方式，而不是不断继承的方式。\n4.2.33 LimitedAgeMemoryCache.java 限制了对象最长存活周期的内存缓存。\nMemoryCache的装饰者，相当于为MemoryCache添加了一个特性。以一个MemoryCache内存缓存和一个 maxAge 做为构造函数入参。在 get(…) 时判断如果对象存活时间已经超过设置的最长时间，则删除。\n4.2.34 FuzzyKeyMemoryCache.java 可以将某些原本不同的 key 看做相等，在 put 时删除这些相等的 key。\nMemoryCache的装饰者，相当于为MemoryCache添加了一个特性。以一个MemoryCache内存缓存和一个 keyComparator 做为构造函数入参。在 put(…) 时判断如果 key 与缓存中已有 key 经过Comparator比较后相等，则删除之前的元素。\n4.2.35 FileNameGenerator.java 根据 uri 得到文件名的接口。\n4.2.36 HashCodeFileNameGenerator.java 以 uri 的 hashCode 作为文件名。\n4.2.37 Md5FileNameGenerator.java 以 uri 的 MD5 值作为文件名。\n4.2.38 DiskCache.java 图片的磁盘缓存接口。\n主要函数:\n(1) File get(String imageUri) 根据原始图片的 uri 去获取缓存图片的文件。\n(2) boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) 保存 imageStream 到磁盘中，listener 表示保存进度且可在其中取消某些段的保存。\n(3) boolean save(String imageUri, Bitmap bitmap) 保存图片到磁盘。\n(4) boolean remove(String imageUri) 根据图片 uri 删除缓存图片。\n(5) void close() 关闭磁盘缓存，并释放资源。\n(6) void clear() 清空磁盘缓存。\n(7) File getDirectory() 得到磁盘缓存的根目录。\n4.2.39 BaseDiskCache.java 一个无大小限制的本地图片缓存，实现了DiskCache主要函数的抽象类。\n图片缓存在cacheDir文件夹内，当cacheDir不可用时，则使用备库reserveCacheDir。\n主要函数：\n(1). save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) 先根据imageUri得到目标文件，将imageStream先写入与目标文件同一文件夹的 .tmp 结尾的临时文件内，若未被listener取消且写入成功则将临时文件重命名为目标文件并返回 true，否则删除临时文件并返回 false。\n(2). save(String imageUri, Bitmap bitmap) 先根据imageUri得到目标文件，通过Bitmap.compress(…)函数将bitmap先写入与目标文件同一文件夹的 .tmp 结尾的临时文件内，若写入成功则将临时文件重命名为目标文件并返回 true，否则删除临时文件并返回 false。\n(3). File getFile(String imageUri) 根据 imageUri 和 fileNameGenerator得到文件名，返回cacheDir内该文件，若cacheDir不可用，则使用备库reserveCacheDir。\n4.2.40 LimitedAgeDiskCache.java 限制了缓存对象最长存活周期的磁盘缓存，继承自BaseDiskCache。\n在 get(…) 时判断如果缓存对象存活时间已经超过设置的最长时间，则删除。在 save(…) 时保存当存时间作为对象的创建时间。\n4.2.41 UnlimitedDiskCache.java 一个无大小限制的本地图片缓存。与BaseDiskCache无异，只是用了个意思明确的类名。\n4.2.42 DiskLruCache.java 限制总字节大小的内存缓存，会在缓存满时优先删除最近最少使用的元素。\n通过缓存目录下名为journal的文件记录缓存的所有操作，并在缓存open时读取journal的文件内容存储到LinkedHashMap\u0026lt;String, Entry\u0026gt; lruEntries中，后面get(String key)获取缓存内容时，会先从lruEntries中得到图片文件名返回文件。\nLRU 的实现跟上面内存缓存类似，lruEntries为new LinkedHashMap\u0026lt;String, Entry\u0026gt;(0, 0.75f, true)，LinkedHashMap 第三个参数表示是否需要根据访问顺序(accessOrder)排序，true 表示根据accessOrder排序，最近访问的跟最新加入的一样放到最后面，false 表示根据插入顺序排序。这里为 true 且缓存满时trimToSize()函数始终删除第一个元素，即始终删除最近最少访问的文件。\n来源于 JakeWharton 的开源项目 DiskLruCache，具体分析请等待 DiskLruCache 源码解析 完成。\n4.2.43 LruDiskCache.java 限制总字节大小的内存缓存，会在缓存满时优先删除最近最少使用的元素，实现了DiskCache。\n内部有个DiskLruCache cache属性，缓存的存、取操作基本都是由该属性代理完成。\n4.2.44 StrictLineReader.java 通过readLine()函数从InputStream中读取一行，目前仅用于磁盘缓存操作记录文件journal的解析。\n4.2.45 Util.java 工具类。\nString readFully(Reader reader)读取 reader 中内容。\ndeleteContents(File dir)递归删除文件夹内容。\n4.2.46 ContentLengthInputStream.java InputStream的装饰者，可通过available()函数得到 InputStream 对应数据源的长度(总字节数)。主要用于计算文件存储进度即图片下载进度时的总进度。\n4.2.47 FailReason.java 图片下载及显示时的错误原因，目前包括：\nIO_ERROR 网络连接或是磁盘存储错误。\nDECODING_ERROR decode image 为 Bitmap 时错误。\nNETWORK_DENIED 当图片不在缓存中，且设置不允许访问网络时的错误。\nOUT_OF_MEMORY 内存溢出错误。\nUNKNOWN 未知错误。\n4.2.48 FlushedInputStream.java 为了解决早期 Android 版本BitmapFactory.decodeStream(…)在慢网络情况下 decode image 异常的 Bug。\n主要通过重写FilterInputStream的 skip(long n) 函数解决，确保 skip(long n) 始终跳过了 n 个字节。如果返回结果即跳过的字节数小于 n，则不断循环直到 skip(long n) 跳过 n 字节或到达文件尾。\n4.2.49 ImageScaleType.java Image 的缩放类型，目前包括：\nNONE不缩放。\nNONE_SAFE根据需要以整数倍缩小图片，使得其尺寸不超过 Texture 可接受最大尺寸。\nIN_SAMPLE_POWER_OF_2根据需要以 2 的 n 次幂缩小图片，使其尺寸不超过目标大小，比较快的缩小方式。\nIN_SAMPLE_INT根据需要以整数倍缩小图片，使其尺寸不超过目标大小。\nEXACTLY根据需要缩小图片到宽或高有一个与目标尺寸一致。\nEXACTLY_STRETCHED根据需要缩放图片到宽或高有一个与目标尺寸一致。\n4.2.50 ViewScaleType.java ImageAware的 ScaleType。\n将 ImageView 的 ScaleType 简化为两种FIT_INSIDE和CROP两种。FIT_INSIDE表示将图片缩放到至少宽度和高度有一个小于等于 View 的对应尺寸，CROP表示将图片缩放到宽度和高度都大于等于 View 的对应尺寸。\n4.2.51 ImageSize.java 表示图片宽高的类。\nscaleDown(…) 等比缩小宽高。\nscale(…) 等比放大宽高。\n4.2.52 LoadedFrom.java 图片来源枚举类，包括网络、磁盘缓存、内存缓存。\n4.2.53 ImageDecoder.java 将图片转换为 Bitmap 的接口，抽象函数：\n`Bitmap decode(ImageDecodingInfo imageDecodingInfo) throws IOException; ` 表示根据ImageDecodingInfo信息得到图片并根据参数将其转换为 Bitmap。\n4.2.54 BaseImageDecoder.java 实现了ImageDecoder。调用ImageDownloader获取图片，然后根据ImageDecodingInfo或图片 Exif 信息处理图片转换为 Bitmap。\n主要函数：\n(1). decode(ImageDecodingInfo decodingInfo) 调用ImageDownloader获取图片，再调用defineImageSizeAndRotation(…)函数得到图片的相关信息，调用prepareDecodingOptions(…)得到图片缩放的比例，调用BitmapFactory.decodeStream将 InputStream 转换为 Bitmap，最后调用considerExactScaleAndOrientatiton(…)根据参数将图片放大、翻转、旋转为合适的样子返回。\n(2). defineImageSizeAndRotation(InputStream imageStream, ImageDecodingInfo decodingInfo) 得到图片真实大小以及 Exif 信息(设置考虑 Exif 的条件下)。\n(3). defineExifOrientation(String imageUri) 得到图片 Exif 信息中的翻转以及旋转角度信息。\n(4). prepareDecodingOptions(ImageSize imageSize, ImageDecodingInfo decodingInfo) 得到图片缩放的比例。\n如果scaleType等于ImageScaleType.NONE，则缩放比例为 1； 如果scaleType等于ImageScaleType.NONE_SAFE，则缩放比例为 (int)Math.ceil(Math.max((float)srcWidth / maxWidth, (float)srcHeight / maxHeight))； 否则，调用ImageSizeUtils.computeImageSampleSize(…)计算缩放比例。\n在 computeImageSampleSize(…) 中 如果viewScaleType等于ViewScaleType.FIT_INSIDE；\n1.1 如果scaleType等于ImageScaleType.IN_SAMPLE_POWER_OF_2，则缩放比例从 1 开始不断 *2 直到宽或高小于最大尺寸；\n1.2 否则取宽和高分别与最大尺寸比例中较大值，即Math.max(srcWidth / targetWidth, srcHeight / targetHeight)。 如果scaleType等于ViewScaleType.CROP；\n2.1 如果scaleType等于ImageScaleType.IN_SAMPLE_POWER_OF_2，则缩放比例从 1 开始不断 *2 直到宽和高都小于最大尺寸。\n2.2 否则取宽和高分别与最大尺寸比例中较小值，即Math.min(srcWidth / targetWidth, srcHeight / targetHeight)。 最后判断宽和高是否超过最大值，如果是 *2 或是 +1 缩放。 (5). considerExactScaleAndOrientatiton(Bitmap subsampledBitmap, ImageDecodingInfo decodingInfo, int rotation, boolean flipHorizontal) 根据参数将图片放大、翻转、旋转为合适的样子返回。\n4.2.55 ImageDecodingInfo.java Image Decode 需要的信息。\nString imageKey 图片。\nString imageUri 图片 uri，可能是缓存文件的 uri。\nString originalImageUri 图片原 uri。\nImageSize targetSize 图片的显示尺寸。\nimageScaleType 图片的 ScaleType。\nImageDownloader downloader 图片的下载器。\nObject extraForDownloader 下载器需要的辅助信息。\nboolean considerExifParams 是否需要考虑图片 Exif 信息。\nOptions decodingOptions 图片的解码信息，为 BitmapFactory.Options。\n4.2.56 BitmapDisplayer.java 在ImageAware中显示 bitmap 对象的接口。可在实现中对 bitmap 做一些额外处理，比如加圆角、动画效果。\n4.2.57 FadeInBitmapDisplayer.java 图片淡入方式显示在ImageAware中，实现了BitmapDisplayer接口。\n4.2.58 RoundedBitmapDisplayer.java 为图片添加圆角显示在ImageAware中，实现了BitmapDisplayer接口。主要通过BitmapShader实现。\n4.2.59 RoundedVignetteBitmapDisplayer.java 为图片添加渐变效果的圆角显示在ImageAware中，实现了BitmapDisplayer接口。主要通过RadialGradient实现。\n4.2.60 SimpleBitmapDisplayer.java 直接将图片显示在ImageAware中，实现了BitmapDisplayer接口。\n4.2.61 BitmapProcessor.java 图片处理接口。可用于对图片预处理(Pre-process Bitmap)和后处理(Post-process Bitmap)。抽象函数：\n`public interface BitmapProcessor { Bitmap process(Bitmap bitmap); } ` 用户可以根据自己需求去实现它。比如你想要为你的图片添加一个水印，那么可以自己去实现 BitmapProcessor 接口，在DisplayImageOptions中配置 Pre-process 阶段预处理图片，这样设置后存储在文件系统以及内存缓存中的图片都是加了水印后的。如果只希望在显示时改变不动原图片，可以在BitmapDisplayer中处理。\n4.2.62 PauseOnScrollListener.java 可在 View 滚动过程中暂停图片加载的 Listener，实现了 OnScrollListener 接口。\n它的好处是防止滚动中不必要的图片加载，比如快速滚动不希望滚动中的图片加载。在 ListView 或 GridView 中 item 加载图片最好使用它，简单的一行代码:\n`gridView.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), false, true)); ` 主要的成员变量：\npauseOnScroll 触摸滑动(手指依然在屏幕上)过程中是否暂停图片加载。\npauseOnFling 甩指滚动(手指已离开屏幕)过程中是否暂停图片加载。\nexternalListener 自定义的 OnScrollListener 接口，适用于 View 原来就有自定义 OnScrollListener 情况设置。\n实现原理：\n重写onScrollStateChanged(…)函数判断不同的状态下暂停或继续图片加载。\nOnScrollListener.SCROLL_STATE_IDLE表示 View 处于空闲状态，没有在滚动，这时候会加载图片。\nOnScrollListener.SCROLL_STATE_TOUCH_SCROLL表示 View 处于触摸滑动状态，手指依然在屏幕上，通过pauseOnScroll变量确定是否需要暂停图片加载。这种时候大都属于慢速滚动浏览状态，所以建议继续图片加载。\nOnScrollListener.SCROLL_STATE_FLING表示 View 处于甩指滚动状态，手指已离开屏幕，通过pauseOnFling变量确定是否需要暂停图片加载。这种时候大都属于快速滚动状态，所以建议暂停图片加载以节省资源。\n4.2.63 QueueProcessingType.java 任务队列的处理类型，包括FIFO先进先出、LIFO后进先出。\n4.2.64 LIFOLinkedBlockingDeque.java 后进先出阻塞队列。重写LinkedBlockingDeque的offer(…)函数如下：\n`@Override public boolean offer(T e) { return super.offerFirst(e); } ` 让LinkedBlockingDeque插入总在最前，而remove()本身始终删除第一个元素，所以就变为了后进先出阻塞队列。\n实际一般情况只重写offer(…)函数是不够的，但因为ThreadPoolExecutor默认只用到了BlockingQueue的offer(…)函数，所以这种简单重写后做为ThreadPoolExecutor的任务队列没问题。\nLIFOLinkedBlockingDeque.java包下的LinkedBlockingDeque.java、BlockingDeque.java、Deque.java都是 Java 1.6 源码中的，这里不做分析。\n4.2.65 DiskCacheUtils.java 磁盘缓存工具类，可用于查找或删除某个 uri 对应的磁盘缓存。\n4.2.66 MemoryCacheUtils.java 内存缓存工具类。可用于根据 uri 生成内存缓存 key，缓存 key 比较，根据 uri 得到所有相关的 key 或图片，删除某个 uri 的内存缓存。\ngenerateKey(String imageUri, ImageSize targetSize)\n根据 uri 生成内存缓存 key，key 规则为[imageUri]_[width]x[height]。\n4.2.67 StorageUtils.java 得到图片 SD 卡缓存目录路径。\n缓存目录优先选择/Android/data/[app_package_name]/cache；若无权限或不可用，则选择 App 在文件系统的缓存目录context.getCacheDir()；若无权限或不可用，则选择/data/data/[app_package_name]/cache。\n如果缓存目录选择了/Android/data/[app_package_name]/cache，则新建.nomedia文件表示不允许类似 Galley 这些应用显示此文件夹下图片。不过在 4.0 系统有 Bug 这种方式不生效。\n4.2.68 ImageSizeUtils.java 用于计算图片尺寸、缩放比例相关的工具类。\n4.2.69 IoUtils.java IO 相关工具类，包括 stream 拷贝，关闭等。\n4.2.70 L.java Log 工具类。\n5. 杂谈 聊聊 LRU UIL 的内存缓存默认使用了 LRU 算法。 LRU: Least Recently Used 近期最少使用算法, 选用了基于链表结构的 LinkedHashMap 作为存储结构。\n假设情景：内存缓存设置的阈值只够存储两个 bitmap 对象，当 put 第三个 bitmap 对象时，将近期最少使用的 bitmap 对象移除。\n图1: 初始化 LinkedHashMap, 并按使用顺序来排序, accessOrder = true;\n图2: 向缓存池中放入 bitmap1 和 bitmap2 两个对象。\n图3: 继续放入第三个 bitmap3，根据假设情景，将会超过设定缓存池阈值。\n图4: 释放对 bitmap1 对象的引用。\n图5: bitmap1 对象被 GC 回收。\n","permalink":"https://blog.zdltech.com/posts/android-universal-image-loader-%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/","summary":"\u003ch3 id=\"内容来自httpsgithubcomandroid-cnandroid-open-project-analysis\"\u003e内容来自：https://github.com/android-cn/android-open-project-analysis\u003c/h3\u003e\n\u003ch3 id=\"1-\"\u003e1. 功能介绍\u003c/h3\u003e\n\u003ch4 id=\"1-1-android-universal-image-loader\"\u003e1.1 Android Universal Image Loader\u003c/h4\u003e\n\u003cp\u003eAndroid Universal Image Loader 是一个强大的、可高度定制的图片缓存，本文简称为\u003ccode\u003eUIL\u003c/code\u003e。\u003cbr\u003e\n简单的说 UIL 就做了一件事——获取图片并显示在相应的控件上。\u003c/p\u003e\n\u003ch4 id=\"1-2-\"\u003e1.2 基本使用\u003c/h4\u003e\n\u003ch5 id=\"1-2-1-\"\u003e1.2.1 初始化\u003c/h5\u003e\n\u003cp\u003e添加完依赖后在\u003ccode\u003eApplication\u003c/code\u003e或\u003ccode\u003eActivity\u003c/code\u003e中初始化\u003ccode\u003eImageLoader\u003c/code\u003e，如下：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`public \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e YourApplication \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e Application {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public void onCreate() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        super\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonCreate();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ImageLoaderConfiguration configuration \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new ImageLoaderConfiguration\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBuilder(this)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 添加你的配置需求\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ebuild();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ImageLoader\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetInstance()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003einit(configuration);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其中 configuration 表示\u003ccode\u003eImageLoader\u003c/code\u003e的配置信息，可包括图片最大尺寸、线程池、缓存、下载器、解码器等等。\u003c/p\u003e\n\u003ch5 id=\"1-2-2-manifest-\"\u003e1.2.2 Manifest 配置\u003c/h5\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zed\" data-lang=\"zed\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;manifest\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;uses\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epermission\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e:\u003c/span\u003ename\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026#34;android.\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epermission\u003c/span\u003e.INTERNET\u0026#34; \u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;uses\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epermission\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e:\u003c/span\u003ename\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026#34;android.\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epermission\u003c/span\u003e.WRITE_EXTERNAL_STORAGE\u0026#34; \u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;application\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        android\u003cspan style=\"color:#ff79c6\"\u003e:\u003c/span\u003ename\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026#34;.YourApplication\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        …… \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ……\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003eapplication\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003emanifest\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e添加网络权限。如果允许磁盘缓存，需要添加写外设的权限。\u003c/p\u003e","title":"Android Universal Image Loader 源码分析"},{"content":"1. 功能介绍 1.1. Volley Volley 是 Google 推出的 Android 异步网络请求框架和图片加载框架。在 Google I/O 2013 大会上发布。\n名字由来：a burst or emission of many things or a large amount at once\n发布演讲时候的配图\n从名字由来和配图中无数急促的火箭可以看出 Volley 的特点：特别适合数据量小，通信频繁的网络操作。（个人认为 Android 应用中绝大多数的网络操作都属于这种类型）。\n1.2 Volley 的主要特点 (1). 扩展性强。Volley 中大多是基于接口的设计，可配置性强。\n(2). 一定程度符合 Http 规范，包括返回 ResponseCode(2xx、3xx、4xx、5xx）的处理，请求头的处理，缓存机制的支持等。并支持重试及优先级定义。\n(3). 默认 Android2.3 及以上基于 HttpURLConnection，2.3 以下基于 HttpClient 实现，这两者的区别及优劣在4.2.1 Volley中具体介绍。\n(4). 提供简便的图片加载工具。\n2. 总体设计 2.1. 总体设计图 上面是 Volley 的总体设计图，主要是通过两种Diapatch Thread不断从RequestQueue中取出请求，根据是否已缓存调用Cache或Network这两类数据获取接口之一，从内存缓存或是服务器取得请求的数据，然后交由ResponseDelivery去做结果分发及回调处理。\n2.2. Volley 中的概念 简单介绍一些概念，在详细设计中会仔细介绍。\nVolley 的调用比较简单，通过 newRequestQueue(…) 函数新建并启动一个请求队列RequestQueue后，只需要往这个RequestQueue不断 add Request 即可。\n**Volley：**Volley 对外暴露的 API，通过 newRequestQueue(…) 函数新建并启动一个请求队列RequestQueue。\n**Request：**表示一个请求的抽象类。StringRequest、JsonRequest、ImageRequest 都是它的子类，表示某种类型的请求。\n**RequestQueue：**表示请求队列，里面包含一个CacheDispatcher(用于处理走缓存请求的调度线程)、NetworkDispatcher数组(用于处理走网络请求的调度线程)，一个ResponseDelivery(返回结果分发接口)，通过 start() 函数启动时会启动CacheDispatcher和NetworkDispatchers。\n**CacheDispatcher：**一个线程，用于调度处理走缓存的请求。启动后会不断从缓存请求队列中取请求处理，队列为空则等待，请求处理结束则将结果传递给ResponseDelivery去执行后续处理。当结果未缓存过、缓存失效或缓存需要刷新的情况下，该请求都需要重新进入NetworkDispatcher去调度处理。\n**NetworkDispatcher：**一个线程，用于调度处理走网络的请求。启动后会不断从网络请求队列中取请求处理，队列为空则等待，请求处理结束则将结果传递给ResponseDelivery去执行后续处理，并判断结果是否要进行缓存。\n**ResponseDelivery：**返回结果分发接口，目前只有基于ExecutorDelivery的在入参 handler 对应线程内进行分发。\n**HttpStack：**处理 Http 请求，返回请求结果。目前 Volley 中有基于 HttpURLConnection 的HurlStack和 基于 Apache HttpClient 的HttpClientStack。\n**Network：**调用HttpStack处理请求，并将结果转换为可被ResponseDelivery处理的NetworkResponse。\n**Cache：**缓存请求结果，Volley 默认使用的是基于 sdcard 的DiskBasedCache。NetworkDispatcher得到请求结果后判断是否需要存储在 Cache，CacheDispatcher会从 Cache 中取缓存结果。\n3. 流程图 Volley 请求流程图\n上图是 Volley 请求时的流程图，在 Volley 的发布演讲中给出，我在这里将其用中文重新画出。\n4. 详细设计 4.1 类关系图 这是 Volley 框架的主要类关系图\n图中红色圈内的部分，组成了 Volley 框架的核心，围绕 RequestQueue 类，将各个功能点以组合的方式结合在了一起。各个功能点也都是以接口或者抽象类的形式提供。\n红色圈外面的部分，在 Volley 源码中放在了toolbox包中，作为 Volley 为各个功能点提供的默认的具体实现。\n通过类图我们看出， Volley 有着非常好的拓展性。通过各个功能点的接口，我们可以给出自定义的，更符合我们需求的具体实现。\n多用组合，少用继承；针对接口编程，不针对具体实现编程。\n优秀框架的设计，令人叫绝，受益良多。\n4.2 核心类功能介绍 4.2.1 Volley.java 这个和 Volley 框架同名的类，其实是个工具类，作用是构建一个可用于添加网络请求的RequestQueue对象。\n(1). 主要函数\nVolley.java 有两个重载的静态方法。\n`public static RequestQueue newRequestQueue(Context context) public static RequestQueue newRequestQueue(Context context, HttpStack stack) ` 第一个方法的实现调用了第二个方法，传 HttpStack 参数为 null。\n第二个方法中，如果 HttpStatck 参数为 null，则如果系统在 Gingerbread 及之后(即 API Level \u0026gt;= 9)，采用基于 HttpURLConnection 的 HurlStack，如果小于 9，采用基于 HttpClient 的 HttpClientStack。\n`if (stack == null) { if (Build.VERSION.SDK_INT \u0026amp;gt;= 9) { stack = new HurlStack(); } else { stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } } ` 得到了 HttpStack,然后通过它构造一个代表网络（Network）的具体实现BasicNetwork。\n接着构造一个代表缓存（Cache）的基于 Disk 的具体实现DiskBasedCache。\n最后将网络（Network）对象和缓存（Cache）对象传入构建一个 RequestQueue，启动这个 RequestQueue，并返回。\n`Network network = new BasicNetwork(stack); RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); queue.start(); return queue; ` 我们平时大多采用Volly.newRequestQueue(context)的默认实现，构建RequestQueue。\n通过源码可以看出，我们可以抛开 Volley 工具类构建自定义的RequestQueue，采用自定义的HttpStatck，采用自定义的Network实现，采用自定义的Cache实现等来构建RequestQueue。\n优秀框架的高可拓展性的魅力来源于此啊\n(2). HttpURLConnection 和 AndroidHttpClient(HttpClient 的封装)如何选择及原因：\n在 Froyo(2.2) 之前，HttpURLConnection 有个重大 Bug，调用 close() 函数会影响连接池，导致连接复用失效，所以在 Froyo 之前使用 HttpURLConnection 需要关闭 keepAlive。\n另外在 Gingerbread(2.3) HttpURLConnection 默认开启了 gzip 压缩，提高了 HTTPS 的性能，Ice Cream Sandwich(4.0) HttpURLConnection 支持了请求结果缓存。\n再加上 HttpURLConnection 本身 API 相对简单，所以对 Android 来说，在 2.3 之后建议使用 HttpURLConnection，之前建议使用 AndroidHttpClient。\n(3). 关于 User Agent\n通过代码我们发现如果是使用 AndroidHttpClient，Volley 还会将请求头中的 User-Agent 字段设置为 App 的 {packageName}/{versionCode}，如果异常则使用 “volley/0″，不过这个获取 User-Agent 的操作应该放到 if else 内部更合适。而对于 HttpURLConnection 却没有任何操作，为什么呢？\n如果用 Fiddler 或 Charles 对数据抓包我们会发现，我们会发现 HttpURLConnection 默认是有 User-Agent 的，类似：\n`Dalvik/1.6.0 (Linux; U; Android 4.1.1; Google Nexus 4 - 4.1.1 - API 16 - 768x1280_1 Build/JRO03S) ` 经常用 WebView 的同学会也许会发现似曾相识，是的，WebView 默认的 User-Agent 也是这个。实际在请求发出之前，会检测 User-Agent 是否为空，如果不为空，则加上系统默认 User-Agent。在 Android 2.1 之后，我们可以通过\n`String userAgent = System.getProperty(\u0026#34;http.agent\u0026#34;); ` 得到系统默认的 User-Agent，Volley 如果希望自定义 User-Agent，可在自定义 Request 中重写 getHeaders() 函数\n`@Override public Map\u0026amp;lt;String, String\u0026amp;gt; getHeaders() throws AuthFailureError { // self-defined user agent Map\u0026amp;lt;String, String\u0026amp;gt; headerMap = new HashMap\u0026amp;lt;String, String\u0026amp;gt;(); headerMap.put(\u0026#34;User-Agent\u0026#34;, \u0026#34;android-open-project-analysis/1.0\u0026#34;); return headerMap; } ` 4.2.2 Request.java 代表一个网络请求的抽象类。我们通过构建一个Request类的非抽象子类(StringRequest、JsonRequest、ImageRequest或自定义)对象，并将其加入到·RequestQueue·中来完成一次网络请求操作。\nVolley 支持 8 种 Http 请求方式 GET, POST, PUT, DELETE, HEAD, OPTIONS, TRACE, PATCH\nRequest 类中包含了请求 url，请求请求方式，请求 Header，请求 Body，请求的优先级等信息。\n因为是抽象类，子类必须重写的两个方法。\n`abstract protected Response\u0026amp;lt;T\u0026amp;gt; parseNetworkResponse(NetworkResponse response); ` 子类重写此方法，将网络返回的原生字节内容，转换成合适的类型。此方法会在工作线程中被调用。\n`abstract protected void deliverResponse(T response); ` 子类重写此方法，将解析成合适类型的内容传递给它们的监听回调。\n以下两个方法也经常会被重写\n`public byte[] getBody() ` 重写此方法，可以构建用于 POST、PUT、PATCH 请求方式的 Body 内容。\n`protected Map\u0026amp;lt;String, String\u0026amp;gt; getParams() ` 在上面getBody函数没有被重写情况下，此方法的返回值会被 key、value 分别编码后拼装起来转换为字节码作为 Body 内容。\n4.2.3 RequestQueue.java Volley 框架的核心类，将请求Request加入到一个运行的RequestQueue中，来完成请求操作。\n(1). 主要成员变量 RequestQueue 中维护了两个基于优先级的 Request 队列，缓存请求队列和网络请求队列。\n放在缓存请求队列中的 Request，将通过缓存获取数据；放在网络请求队列中的 Request，将通过网络获取数据。\n`private final PriorityBlockingQueue\u0026amp;lt;Request\u0026amp;lt;?\u0026amp;gt;\u0026amp;gt; mCacheQueue = new PriorityBlockingQueue\u0026amp;lt;Request\u0026amp;lt;?\u0026amp;gt;\u0026amp;gt;(); private final PriorityBlockingQueue\u0026amp;lt;Request\u0026amp;lt;?\u0026amp;gt;\u0026amp;gt; mNetworkQueue = new PriorityBlockingQueue\u0026amp;lt;Request\u0026amp;lt;?\u0026amp;gt;\u0026amp;gt;(); ` 维护了一个正在进行中，尚未完成的请求集合。\n`private final Set\u0026amp;lt;Request\u0026amp;lt;?\u0026amp;gt;\u0026amp;gt; mCurrentRequests = new HashSet\u0026amp;lt;Request\u0026amp;lt;?\u0026amp;gt;\u0026amp;gt;(); ` 维护了一个等待请求的集合，如果一个请求正在被处理并且可以被缓存，后续的相同 url 的请求，将进入此等待队列。\n`private final Map\u0026amp;lt;String, Queue\u0026amp;lt;Request\u0026amp;lt;?\u0026amp;gt;\u0026amp;gt;\u0026amp;gt; mWaitingRequests = new HashMap\u0026amp;lt;String, Queue\u0026amp;lt;Request\u0026amp;lt;?\u0026amp;gt;\u0026amp;gt;\u0026amp;gt;(); ` (2). 启动队列 创建出 RequestQueue 以后，调用 start 方法，启动队列。\n`/** * Starts the dispatchers in this queue. */ public void start() { stop(); // Make sure any currently running dispatchers are stopped. // Create the cache dispatcher and start it. mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start(); // Create network dispatchers (and corresponding threads) up to the pool size. for (int i = 0; i \u0026amp;lt; mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); } } ` start 方法中，开启一个缓存调度线程CacheDispatcher和 n 个网络调度线程NetworkDispatcher，这里 n 默认为4，存在优化的余地，比如可以根据 CPU 核数以及网络类型计算更合适的并发数。\n缓存调度线程不断的从缓存请求队列中取出 Request 去处理，网络调度线程不断的从网络请求队列中取出 Request 去处理。\n(3). 加入请求 `public \u0026amp;lt;T\u0026amp;gt; Request\u0026amp;lt;T\u0026amp;gt; add(Request\u0026amp;lt;T\u0026amp;gt; request); ` 流程图如下：\n(4). 请求完成 `void finish(Request\u0026amp;lt;?\u0026amp;gt; request) ` Request 请求结束\n(1). 首先从正在进行中请求集合mCurrentRequests中移除该请求。\n(2). 然后查找请求等待集合mWaitingRequests中是否存在等待的请求，如果存在，则将等待队列移除，并将等待队列所有的请求添加到缓存请求队列中，让缓存请求处理线程CacheDispatcher自动处理。\n(5). 请求取消 `public void cancelAll(RequestFilter filter) public void cancelAll(final Object tag) ` 取消当前请求集合中所有符合条件的请求。\nfilter 参数表示可以按照自定义的过滤器过滤需要取消的请求。\ntag 表示按照Request.setTag设置好的 tag 取消请求，比如同属于某个 Activity 的。\n4.2.4 CacheDispatcher.java 一个线程，用于调度处理走缓存的请求。启动后会不断从缓存请求队列中取请求处理，队列为空则等待，请求处理结束则将结果传递给ResponseDelivery 去执行后续处理。当结果未缓存过、缓存失效或缓存需要刷新的情况下，该请求都需要重新进入NetworkDispatcher去调度处理。\n(1). 成员变量 BlockingQueue\u0026lt;Request\u0026lt;?\u0026gt;\u0026gt; mCacheQueue 缓存请求队列\nBlockingQueue\u0026lt;Request\u0026lt;?\u0026gt;\u0026gt; mNetworkQueue 网络请求队列\nCache mCache 缓存类，代表了一个可以获取请求结果，存储请求结果的缓存\nResponseDelivery mDelivery 请求结果传递类\n(2). 处理流程图 4.2.5 NetworkDispatcher.java 一个线程，用于调度处理走网络的请求。启动后会不断从网络请求队列中取请求处理，队列为空则等待，请求处理结束则将结果传递给 ResponseDelivery 去执行后续处理，并判断结果是否要进行缓存。\n(1). 成员变量 BlockingQueue\u0026lt;Request\u0026lt;?\u0026gt;\u0026gt; mQueue 网络请求队列\nNetwork mNetwork 网络类，代表了一个可以执行请求的网络\nCache mCache 缓存类，代表了一个可以获取请求结果，存储请求结果的缓存\nResponseDelivery mDelivery 请求结果传递类，可以传递请求的结果或者错误到调用者\n(2). 处理流程图 4.2.6 Cache.java 缓存接口，代表了一个可以获取请求结果，存储请求结果的缓存。\n(1). 主要方法： public Entry get(String key); 通过 key 获取请求的缓存实体\npublic void put(String key, Entry entry); 存入一个请求的缓存实体\npublic void remove(String key); 移除指定的缓存实体\npublic void clear(); 清空缓存\n(2). 代表缓存实体的内部类 Entry 成员变量和方法\nbyte[] data 请求返回的数据（Body 实体）\nString etag Http 响应首部中用于缓存新鲜度验证的 ETag\nlong serverDate Http 响应首部中的响应产生时间\nlong ttl 缓存的过期时间\nlong softTtl 缓存的新鲜时间\nMap\u0026lt;String, String\u0026gt; responseHeaders 响应的 Headers\nboolean isExpired() 判断缓存是否过期，过期缓存不能继续使用\nboolean refreshNeeded() 判断缓存是否新鲜，不新鲜的缓存需要发到服务端做新鲜度的检测\n4.2.7 DiskBasedCache.java 继承 Cache 类，基于 Disk 的缓存实现类。\n(1). 主要方法： public synchronized void initialize() 初始化，扫描缓存目录得到所有缓存数据摘要信息放入内存。\npublic synchronized Entry get(String key) 从缓存中得到数据。先从摘要信息中得到摘要信息，然后读取缓存数据文件得到内容。\npublic synchronized void put(String key, Entry entry) 将数据存入缓存内。先检查缓存是否会满，会则先删除缓存中部分数据，然后再新建缓存文件。\nprivate void pruneIfNeeded(int neededSpace) 检查是否能再分配 neededSpace 字节的空间，如果不能则删除缓存中部分数据。\npublic synchronized void clear() 清空缓存。 public synchronized void remove(String key) 删除缓存中某个元素。\n(2). CacheHeader 类 CacheHeader 是缓存文件摘要信息，存储在缓存文件的头部，与上面的Cache.Entry相似。\n4.2.8 NoCache.java 继承 Cache 类，不做任何操作的缓存实现类，可将它作为构建RequestQueue的参数以实现一个不带缓存的请求队列。\n4.2.9 Network.java 代表网络的接口，处理网络请求。\n唯一的方法，用于执行特定请求。\n`public NetworkResponse performRequest(Request\u0026amp;lt;?\u0026amp;gt; request) throws VolleyError; ` 4.2.10 NetworkResponse.java Network中方法 performRequest 的返回值，Request的 parseNetworkResponse(…) 方法入参，是 Volley 中用于内部 Response 转换的一级。\n封装了网络请求响应的 StatusCode，Headers 和 Body 等。\n(1). 成员变量 int statusCode Http 响应状态码\nbyte[] data Body 数据\nMap\u0026lt;String, String\u0026gt; headers 响应 Headers\nboolean notModified 表示是否为 304 响应\nlong networkTimeMs 请求耗时\n(2). Volley 的内部 Response 转换流程图 从上到下表示从得到数据后一步步的处理，箭头旁的注释表示该步处理后的实体类。\n4.2.11 BasicNetwork.java 实现 Network，Volley 中默认的网络接口实现类。调用HttpStack处理请求，并将结果转换为可被ResponseDelivery处理的NetworkResponse。\n主要实现了以下功能：\n(1). 利用 HttpStack 执行网络请求。\n(2). 如果 Request 中带有实体信息，如 Etag,Last-Modify 等，则进行缓存新鲜度的验证，并处理 304（Not Modify）响应。\n(3). 如果发生超时，认证失败等错误，进行重试操作，直到成功、抛出异常(不满足重试策略等)结束。\n4.2.12 HttpStack.java 用于处理 Http 请求，返回请求结果的接口。目前 Volley 中的实现有基于 HttpURLConnection 的 HurlStack 和 基于 Apache HttpClient 的 HttpClientStack。\n唯一方法，执行请求\n`public HttpResponse performRequest(Request\u0026amp;lt;?\u0026amp;gt; request, Map\u0026amp;lt;String, String\u0026amp;gt; additionalHeaders) throws IOException, AuthFailureError; ` 执行 Request 代表的请求，第二个参数表示发起请求之前，添加额外的请求 Headers。\n4.2.13 HttpClientStack.java 实现 HttpStack 接口，利用 Apache 的 HttpClient 进行各种请求方式的请求。\n基本就是 org.apache.http 包下面相关类的常见用法，不做详解，不过与下面 HttpURLConnection 做下对比就能发现 HttpURLConnection 的 API 相对简单的多。\n4.2.14 HurlStack.java 实现 HttpStack 接口，利用 Java 的 HttpURLConnection 进行各种请求方式的请求。\n4.2.15 Response.java 封装了经过解析后的数据，用于传输。并且有两个内部接口 Listener 和 ErrorListener 分别可表示请求失败和成功后的回调。\nResponse 的构造函数被私有化，而通过两个函数名更易懂的静态方法构建对象。\n4.2.16 ByteArrayPool.java byte[] 的回收池，用于 byte[] 的回收再利用，减少了内存的分配和回收。 主要通过一个元素长度从小到大排序的ArrayList作为 byte[] 的缓存，另有一个按使用时间先后排序的ArrayList属性用于缓存满时清理元素。\n`public synchronized void returnBuf(byte[] buf) ` 将用过的 byte[] 回收，根据 byte[] 长度按照从小到大的排序将 byte[] 插入到缓存中合适位置。\n`public synchronized byte[] getBuf(int len) ` 获取长度不小于 len 的 byte[]，遍历缓存，找出第一个长度大于传入参数len的 byte[]，并返回；如果最终没有合适的byte[]，new 一个返回。\n`private synchronized void trim() ` 当缓存的 byte 超过预先设置的大小时，按照先进先出的顺序删除最早的 byte[]。\n4.2.17 PoolingByteArrayOutputStream.java 继承ByteArrayOutputStream，原始 ByteArrayOutputStream 中用于接受写入 bytes 的 buf，每次空间不足时便会 new 更大容量的 byte[]，而 PoolingByteArrayOutputStream 使用了 ByteArrayPool 作为 Byte[] 缓存来减少这种操作，从而提高性能。\n4.2.18 HttpHeaderParser.java Http header 的解析工具类，在 Volley 中主要作用是用于解析 Header 从而判断返回结果是否需要缓存，如果需要返回 Header 中相关信息。\n有三个方法\n`public static long parseDateAsEpoch(String dateStr) ` 解析时间，将 RFC1123 的时间格式，解析成 epoch 时间\n`public static String parseCharset(Map\u0026amp;lt;String, String\u0026amp;gt; headers) ` 解析编码集，在 Content-Type 首部中获取编码集，如果没有找到，默认返回 ISO-8859-1\n`public static Cache.Entry parseCacheHeaders(NetworkResponse response) ` 比较重要的方法，通过网络响应中的缓存控制 Header 和 Body 内容，构建缓存实体。如果 Header 的 Cache-Control 字段含有no-cache或no-store表示不缓存，返回 null。\n(1). 根据 Date 首部，获取响应生成时间\n(2). 根据 ETag 首部，获取响应实体标签\n(3). 根据 Cache－Control 和 Expires 首部，计算出缓存的过期时间，和缓存的新鲜度时间\n两点需要说明下：\n1.没有处理Last-Modify首部，而是处理存储了Date首部，并在后续的新鲜度验证时，使用Date来构建If-Modified-Since。 这与 Http 1.1 的语义有些违背。\n2.计算过期时间，Cache－Control 首部优先于 Expires 首部。\n4.2.19 RetryPolicy.java 重试策略接口\n有三个方法：\n`public int getCurrentTimeout(); ` 获取当前请求用时（用于Log）\n`public int getCurrentRetryCount(); ` 获取已经重试的次数（用于Log）\n`public void retry(VolleyError error) throws VolleyError; ` 确定是否重试，参数为这次异常的具体信息。在请求异常时此接口会被调用，可在此函数实现中抛出传入的异常表示停止重试。\n4.2.20 DefaultRetryPolicy.java 实现 RetryPolicy，Volley 默认的重试策略实现类。主要通过在 retry(…) 函数中判断重试次数是否达到上限确定是否继续重试。\n其中mCurrentTimeoutMs变量表示已经重试次数。\nmBackoffMultiplier表示每次重试之前的 timeout 该乘以的因子。\nmCurrentTimeoutMs变量表示当前重试的 timeout 时间，会以mBackoffMultiplier作为因子累计前几次重试的 timeout。\n4.2.21 ResponseDelivery.java 请求结果的传输接口，用于传递请求结果或者请求错误。\n有三个方法：\n`public void postResponse(Request\u0026amp;lt;?\u0026amp;gt; request, Response\u0026amp;lt;?\u0026amp;gt; response); ` 此方法用于传递请求结果，request 和 response 参数分别表示请求信息和返回结果信息。\n`public void postResponse(Request\u0026amp;lt;?\u0026amp;gt; request, Response\u0026amp;lt;?\u0026amp;gt; response, Runnable runnable); ` 此方法用于传递请求结果，并在完成传递后执行 Runnable。\n`public void postError(Request\u0026amp;lt;?\u0026amp;gt; request, VolleyError error); ` 此方法用于传输请求错误。\n4.2.22 ExecutorDelivery.java 请求结果传输接口具体实现类。\n在 Handler 对应线程中传输缓存调度线程或者网络调度线程中产生的请求结果或请求错误，会在请求成功的情况下调用 Request.deliverResponse(…) 函数，失败时调用 Request.deliverError(…) 函数。\n4.2.23 StringRequest.java 继承 Request 类,代表了一个返回值为 String 的请求。将网络返回的结果数据解析为 String 类型。通过构造函数的 listener 传参，支持请求成功后的 onResponse(…) 回调。\n4.2.24 JsonRequest.java 抽象类，继承自 Request，代表了 body 为 JSON 的请求。提供了构建 JSON 请求参数的方法。\n4.2.25 JsonObjectRequest.java 继承自 JsonRequest，将网络返回的结果数据解析为 JSONObject 类型。\n4.2.26 JsonArrayRequest.java 继承自 JsonRequest，将网络返回的结果数据解析为 JSONArray 类型。\n4.2.27 ImageRequest.java 继承 Request 类，代表了一个返回值为 Image 的请求。将网络返回的结果数据解析为 Bitmap 类型。\n可以设置图片的最大宽度和最大高度，并计算出合适尺寸返回。每次最多解析一张图片防止 OOM。\n4.2.28 ImageLoader.java 封装了 ImageRequst 的方便使用的图片加载工具类。\n1.可以设置自定义的ImageCache，可以是内存缓存，也可以是 Disk 缓存，将获取的图片缓存起来，重复利用，减少请求。\n2.可以定义图片请求过程中显示的图片和请求失败后显示的图片。\n3.相同请求（相同地址，相同大小）只发送一个，可以避免重复请求。\n// TODO\n4.2.29 NetworkImageView.java 利用 ImageLoader，可以加载网络图片的 ImageView\n有三个公开的方法：\n`public void setDefaultImageResId(int defaultImage) ` 设置默认图片，加载图片过程中显示。\n`public void setErrorImageResId(int errorImage) ` 设置错误图片，加载图片失败后显示。\n`public void setImageUrl(String url, ImageLoader imageLoader) ` 设置网络图片的 Url 和 ImageLoader，将利用这个 ImageLoader 去获取网络图片。\n如果有新的图片加载请求，会把这个ImageView上旧的加载请求取消。\n4.2.30 ClearCacheRequest.java 用于人为清空 Http 缓存的请求。\n添加到 RequestQueue 后能很快执行，因为优先级很高，为Priority.IMMEDIATE。并且清空缓存的方法mCache.clear()写在了isCanceled()方法体中，能最早的得到执行。\nClearCacheRequest 的写法不敢苟同，目前看来唯一的好处就是可以将清空缓存操作也当做一个请求。而在isCanceled()中做清空操作本身就造成了歧义，不看源码没人知道在NetworkDispatcher run 方法循环的过程中，isCanceled()这个读操作竟然做了可能造成缓存被清空。只能跟源码的解释一样当做一个 Hack 操作。\n4.2.31 Authenticator.java 身份认证接口，用于基本认证或者摘要认证。这个类是 Volley 用于和身份验证打通的接口，比如 OAuth，不过目前的使用不是特别广泛和 Volley 的内部结合也不是特别紧密。\n4.2.32 AndroidAuthenticator.java 继承 Authenticator，基于 Android AccountManager 的认证交互实现类。\n4.2.33 VolleyLog.java Volley 的 Log 工具类。\n4.2.34 VolleyError.java Volley 中所有错误异常的父类，继承自 Exception，可通过此类设置和获取 NetworkResponse 或者请求的耗时。\n4.2.35 AuthFailureError.java 继承自 VolleyError，代表请求认证失败错误，如 RespondeCode 的 401 和 403。\n4.2.36 NetworkError.java 继承自 VolleyError，代表网络错误。\n4.2.37 ParseError.java 继承自 VolleyError，代表内容解析错误。\n4.2.38 ServerError.java 继承自 VolleyError，代表服务端错误。\n4.2.39 TimeoutError.java 继承自 VolleyError，代表请求超时错误。\n4.2.40 NoConnectionError.java 继承自NetworkError，代表无法建立连接错误。\n5. 杂谈 5.1 关于 Http 缓存 Volley 构建了一套相对完整的符合 Http 语义的缓存机制。\n优点和特点\n(1). 根据Cache-Control和Expires首部来计算缓存的过期时间。如果两个首部都存在情况下，以Cache-Control为准。\n(2). 利用If-None-Match和If-Modified-Since对过期缓存或者不新鲜缓存，进行请求再验证，并处理 304 响应，更新缓存。\n(3). 默认的缓存实现，将缓存以文件的形式存储在 Disk，程序退出后不会丢失。\n我个人认为的不足之处\n缓存的再验证方面，在构建If-Modified-Since请求首部时，Volley 使用了服务端响应的Date首部，没有使用Last-Modified首部。整个框架没有使用Last-Modified首部。这与 Http 语义不符。\n`private void addCacheHeaders(Map\u0026amp;lt;String, String\u0026amp;gt; headers, Cache.Entry entry) { // If there\u0026#39;s no cache entry, we\u0026#39;re done. if (entry == null) { return; } if (entry.etag != null) { headers.put(\u0026#34;If-None-Match\u0026#34;, entry.etag); } if (entry.serverDate \u0026amp;gt; 0) { Date refTime = new Date(entry.serverDate); headers.put(\u0026#34;If-Modified-Since\u0026#34;, DateUtils.formatDate(refTime)); } } ` 服务端根据请求时通过If-Modified-Since首部传过来的时间，判断资源文件是否在If-Modified-Since时间 以后 有改动，如果有改动，返回新的请求结果。如果没有改动，返回 304 not modified。\nLast-Modified代表了资源文件的最后修改时间。通常使用这个首部构建If-Modified-Since的时间。\nDate代表了响应产生的时间，正常情况下Date时间在Last-Modified时间之后。也就是Date\u0026gt;=Last-Modified。\n通过以上原理，既然Date\u0026gt;=Last-Modified。那么我利用Date构建，也是完全正确的。\n可能的问题出在服务端的 Http 实现上，如果服务端完全遵守 Http 语义，采用时间比较的方式来验证If-Modified-Since，判断服务器资源文件修改时间是不是在If-Modified-Since之后。那么使用Date完全正确。\n可是有的服务端实现不是比较时间，而是直接的判断服务器资源文件修改时间，是否和If-Modified-Since所传时间相等。这样使用Date就不能实现正确的再验证，因为Date的时间总不会和服务器资源文件修改时间相等。\n尽管使用Date可能出现的不正确情况，归结于服务端没有正确的实现 Http 语义。\n但我还是希望Volley也能完全正确的实现Http语义，至少同时处理Last-Modified和Date,并且优先使用Last-Modified。\n5.2 Bug (1). BasicNetwork.performRequest(…) 如下代码：\n`@Override public NetworkResponse performRequest(Request\u0026amp;lt;?\u0026amp;gt; request) throws VolleyError { …… while (true) { …… try { …… } catch (IOException e) { int statusCode = 0; NetworkResponse networkResponse = null; …… if (responseContents != null) { …… } else { throw new NetworkError(networkResponse); } } } } ` BasicNetwork.performRequest(…) 最后的\n`throw new NetworkError(networkResponse); ` 应该是\n`throw new NetworkError(e); ` 更合理。\n","permalink":"https://blog.zdltech.com/posts/volley-%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/","summary":"\u003ch3 id=\"1-\"\u003e1. 功能介绍\u003c/h3\u003e\n\u003ch4 id=\"1-1-volley\"\u003e1.1. Volley\u003c/h4\u003e\n\u003cp\u003eVolley 是 Google 推出的 Android 异步网络请求框架和图片加载框架。在 Google I/O 2013 大会上发布。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e名字由来：a burst or emission of many things or a large amount at once\u003cbr\u003e\n发布演讲时候的配图\u003cbr\u003e\n\u003cimg alt=\"Volley\" loading=\"lazy\" src=\"https://raw.githubusercontent.com/android-cn/android-open-project-analysis/master/volley/image/volley.png\"\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e从名字由来和配图中无数急促的火箭可以看出 Volley 的特点：特别适合\u003cstrong\u003e数据量小，通信频繁\u003c/strong\u003e的网络操作。（个人认为 Android 应用中绝大多数的网络操作都属于这种类型）。\u003c/p\u003e\n\u003ch4 id=\"1-2-volley-\"\u003e1.2 Volley 的主要特点\u003c/h4\u003e\n\u003cp\u003e(1). 扩展性强。Volley 中大多是基于接口的设计，可配置性强。\u003cbr\u003e\n(2). 一定程度符合 Http 规范，包括返回 ResponseCode(2xx、3xx、4xx、5xx）的处理，请求头的处理，缓存机制的支持等。并支持重试及优先级定义。\u003cbr\u003e\n(3). 默认 Android2.3 及以上基于 HttpURLConnection，2.3 以下基于 HttpClient 实现，这两者的区别及优劣在\u003ccode\u003e4.2.1 Volley\u003c/code\u003e中具体介绍。\u003cbr\u003e\n(4). 提供简便的图片加载工具。\u003c/p\u003e\n\u003ch3 id=\"2-\"\u003e2. 总体设计\u003c/h3\u003e\n\u003ch4 id=\"2-1-\"\u003e2.1. 总体设计图\u003c/h4\u003e\n\u003cp\u003e\u003cimg alt=\"总体设计图\" loading=\"lazy\" src=\"https://raw.githubusercontent.com/android-cn/android-open-project-analysis/master/volley/image/design.png\"\u003e\u003cbr\u003e\n上面是 Volley 的总体设计图，主要是通过两种\u003ccode\u003eDiapatch Thread\u003c/code\u003e不断从\u003ccode\u003eRequestQueue\u003c/code\u003e中取出请求，根据是否已缓存调用\u003ccode\u003eCache\u003c/code\u003e或\u003ccode\u003eNetwork\u003c/code\u003e这两类数据获取接口之一，从内存缓存或是服务器取得请求的数据，然后交由\u003ccode\u003eResponseDelivery\u003c/code\u003e去做结果分发及回调处理。\u003c/p\u003e\n\u003ch4 id=\"2-2-volley-\"\u003e2.2. Volley 中的概念\u003c/h4\u003e\n\u003cp\u003e简单介绍一些概念，在\u003ccode\u003e详细设计\u003c/code\u003e中会仔细介绍。\u003cbr\u003e\nVolley 的调用比较简单，通过 newRequestQueue(…) 函数新建并启动一个请求队列\u003ccode\u003eRequestQueue\u003c/code\u003e后，只需要往这个\u003ccode\u003eRequestQueue\u003c/code\u003e不断 add Request 即可。\u003c/p\u003e","title":"Volley 源码解析"},{"content":"本文将介绍几个对安卓开发者有用的几个工具。\n设计师/开发者工具\nAndroid Button Maker 是一个产生按钮代码的在线工具。Android API提供了由xml定义的Drawable，可以定义形状、颜色、渐变等。基于这种方式生产的按钮要比普通的png按钮速度快很多。你可以在这个工具的设置界面中自定义按钮的属性，然后获取代码。\n1427680999497361.png\nAndroid Pixel Calculator\n帮助你搞清楚dp, px, sp, in, mm 和pt关系以及相互转换的工具。\n1427681547132533.png\n优化png图片的开源工具\nOptiPNG 、PNGCrush 和TinyPNG 是几个用于优化PNG图片的开源命令行工具。你可以通过各种各样的算法来压缩png图片。如果你的app高度依赖于美工设计的图片，你应该考虑使用它们来减小图片的大小。\nAndroid Asset Studio\n一个基于web的安卓资源生成工具，可以生成图标、样式等资源文件。目前可以生成：\nLauncher 图标\nAction bar and tab 图标\nNotification 图标\nNavigation drawer indicator\n普通图标\nOTHER GENERATORS — MISCELLANEOUS ASSET CREATION TOOLS\n点9图片\nOfficial Android Device Art Generator\nCOMMUNITY TOOLS — SIMILAR TOOLS FROM THE OPEN SOURCE COMMUNITY\nAndroid Action Bar Style Generator by Jeff Gilfelt\nAndroid Holo Colors Generator by Jérôme Van Der Linden\n开发者工具\nandroid-unused-resources\n安卓开发中往往会产生非常多的废弃文件，包括布局、图片等。android-unused-resources 可以帮助你检测出这些文件，并清除它们。减小apk的体积。\nAndroid Layout Finder\nAndroid Layout Finder帮助你根据xml布局生成java代码。你只需将xml布局的代码拷贝进第一个输入框，选择需要的view，然后代码就自动生成了。不需要反复的书写findViewById()。\n1427681041107101.png\n与Android Layout Finder类似，eclipse插件 android-code-generator-plugin 也能根据xml生成activity代码。\nJSON to POJO\n将JSON或者JSON-Schema转换成普通java对象（JavaBean）的工具。不过Json的字符限制在51200以内。\n1427681071714628.png\n转自：http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0330/2668.html\n","permalink":"https://blog.zdltech.com/posts/%E5%87%A0%E4%B8%AA%E5%AE%89%E5%8D%93%E5%BC%80%E5%8F%91%E8%BE%85%E5%8A%A9%E5%B7%A5%E5%85%B7/","summary":"\u003cp\u003e本文将介绍几个对安卓开发者有用的几个工具。\u003c/p\u003e\n\u003cp\u003e设计师/开发者工具\u003cbr\u003e\nAndroid Button Maker 是一个产生按钮代码的在线工具。Android API提供了由xml定义的Drawable，可以定义形状、颜色、渐变等。基于这种方式生产的按钮要比普通的png按钮速度快很多。你可以在这个工具的设置界面中自定义按钮的属性，然后获取代码。\u003c/p\u003e\n\u003cp\u003e1427680999497361.png\u003c/p\u003e\n\u003cp\u003eAndroid Pixel Calculator\u003c/p\u003e\n\u003cp\u003e帮助你搞清楚dp, px, sp, in, mm 和pt关系以及相互转换的工具。\u003c/p\u003e\n\u003cp\u003e1427681547132533.png\u003c/p\u003e\n\u003cp\u003e优化png图片的开源工具\u003c/p\u003e\n\u003cp\u003eOptiPNG 、PNGCrush 和TinyPNG 是几个用于优化PNG图片的开源命令行工具。你可以通过各种各样的算法来压缩png图片。如果你的app高度依赖于美工设计的图片，你应该考虑使用它们来减小图片的大小。\u003c/p\u003e\n\u003cp\u003eAndroid Asset Studio\u003c/p\u003e\n\u003cp\u003e一个基于web的安卓资源生成工具，可以生成图标、样式等资源文件。目前可以生成：\u003c/p\u003e\n\u003cp\u003eLauncher 图标\u003c/p\u003e\n\u003cp\u003eAction bar and tab 图标\u003c/p\u003e\n\u003cp\u003eNotification 图标\u003c/p\u003e\n\u003cp\u003eNavigation drawer indicator\u003c/p\u003e\n\u003cp\u003e普通图标\u003c/p\u003e\n\u003cp\u003eOTHER GENERATORS — MISCELLANEOUS ASSET CREATION TOOLS\u003c/p\u003e\n\u003cp\u003e点9图片\u003c/p\u003e\n\u003cp\u003eOfficial Android Device Art Generator\u003c/p\u003e\n\u003cp\u003eCOMMUNITY TOOLS — SIMILAR TOOLS FROM THE OPEN SOURCE COMMUNITY\u003c/p\u003e\n\u003cp\u003eAndroid Action Bar Style Generator by Jeff Gilfelt\u003c/p\u003e","title":"几个安卓开发辅助工具"},{"content":"\u003c?php //\u0026#8211;调用方法/demo.php?url=http://v.youku.com/v\\_show/id\\_XMzkyODA2NTEy.html echo getYoukuFlv(_GET[\u0026#8216;url\u0026#8217;]); function getYoukuFlv(url){ preg_match(\u0026#8220;#id_(.*?)\\.html#\u0026#8221;,url,out); id=out[1]; content=get_curl_contents(\u0026#8216;http://v.youku.com/player/getPlayList/VideoIDS/\u0026#8217;.id); data=json_decode(content); foreach(data-\u003edata[0]-\u003estreamfileids ASk=\u003ev){sid=getSid(); fileid=getfileid(v,data-\u003edata[0]-\u003eseed);one=(data-\u003edata[0]-\u003esegs-\u003ek); if(k == \u0026#8216;flv\u0026#8217; ||k == \u0026#8216;mp4\u0026#8217;) return \u0026#8220;http://f.youku.com/player/getFlvPath/sid/{sid}_00/st/{k}/fileid/{fileid}?K={one[0]-\u003ek}\u0026#8221;; continue; } } function get_curl_contents(url,second = 5){ if(!function_exists(\u0026#8216;curl_init\u0026#8217;)) die(\u0026#8216;php.ini未开启php_curl.dll\u0026#8217;); c = curl_init(); curl_setopt(c,CURLOPT_URL,url);UserAgent=_SERVER[\u0026#8216;HTTP_USER_AGENT\u0026#8217;]; curl_setopt(c,CURLOPT_USERAGENT,UserAgent); curl_setopt(c,CURLOPT_HEADER,0); curl_setopt(c,CURLOPT_TIMEOUT,second); curl_setopt(c,CURLOPT_RETURNTRANSFER, true);cnt = curl_exec(c);cnt=mb_check_encoding(cnt,\u0026#8217;utf-8\u0026#8242;)?iconv(\u0026#8216;gbk\u0026#8217;,\u0026#8217;utf-8//IGNORE\u0026#8217;,cnt):cnt; //字符编码转换 curl_close(c); return cnt; } function getSid() {sid = time().(rand(0,9000)+10000); return sid; } function getkey(key1,key2){a = hexdec(key1);b = a ^ 0xA55AA5A5;b = dechex(b); returnkey2.b; } function getfileid(fileId,seed) {mixed = getMixString(seed);ids = explode(\u0026#8220;*\u0026#8221;,fileId); unset(ids[count(ids)-1]);realId = \u0026#8220;\u0026#8221;; for (i=0;i \u003c count(ids);++i) { idx =ids[i];realId .= substr(mixed,idx,1); } return realId; } function getMixString(seed) { mixed = \u0026#8220;\u0026#8221;;source = \u0026#8220;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/\\\\:._-1234567890\u0026#8221;; len = strlen(source); for(i=0;i\u003c len;++i){ seed = (seed * 211 + 30031) % 65536; index = (seed / 65536 * strlen(source));c = substr(source,index,1); mixed .=c; source = str_replace(c, \u0026#8220;\u0026#8221;,source); } returnmixed; } ?\u003e ","permalink":"https://blog.zdltech.com/posts/%E8%8E%B7%E5%8F%96%E4%BC%98%E9%85%B7%E8%A7%86%E9%A2%91%E7%9C%9F%E5%AE%9E%E4%B8%8B%E8%BD%BD%E5%9C%B0%E5%9D%80%E7%9A%84php%E6%BA%90%E4%BB%A3%E7%A0%81/","summary":"\u003c?php  \n//\u0026#8211;调用方法/demo.php?url=http://v.youku.com/v\\_show/id\\_XMzkyODA2NTEy.html  \necho getYoukuFlv(\u003cspan class=\"katex math inline\"\u003e_GET[\u0026#8216;url\u0026#8217;]);\n \n\n\n  function getYoukuFlv(\u003c/span\u003eurl){\n preg_match(\u0026#8220;#id_(.*?)\\.html#\u0026#8221;,\u003cspan class=\"katex math inline\"\u003eurl,\u003c/span\u003eout);\n \u003cspan class=\"katex math inline\"\u003eid=\u003c/span\u003eout[1];\n \u003cspan class=\"katex math inline\"\u003econtent=get_curl_contents(\u0026#8216;http://v.youku.com/player/getPlayList/VideoIDS/\u0026#8217;.\u003c/span\u003eid);\n \u003cspan class=\"katex math inline\"\u003edata=json_decode(\u003c/span\u003econtent);\n foreach(\u003cspan class=\"katex math inline\"\u003edata-\u003edata[0]-\u003estreamfileids AS\u003c/span\u003ek=\u003e\u003cspan class=\"katex math inline\"\u003ev){\u003c/span\u003esid=getSid();\n \u003cspan class=\"katex math inline\"\u003efileid=getfileid(\u003c/span\u003ev,\u003cspan class=\"katex math inline\"\u003edata-\u003edata[0]-\u003eseed);\u003c/span\u003eone=(\u003cspan class=\"katex math inline\"\u003edata-\u003edata[0]-\u003esegs-\u003e\u003c/span\u003ek);\n if(\u003cspan class=\"katex math inline\"\u003ek == \u0026#8216;flv\u0026#8217; ||\u003c/span\u003ek == \u0026#8216;mp4\u0026#8217;) return \u0026#8220;http://f.youku.com/player/getFlvPath/sid/{\u003cspan class=\"katex math inline\"\u003esid}_00/st/{\u003c/span\u003ek}/fileid/{\u003cspan class=\"katex math inline\"\u003efileid}?K={\u003c/span\u003eone[0]-\u003ek}\u0026#8221;;\n continue;\n }\n }\n function get_curl_contents(\u003cspan class=\"katex math inline\"\u003eurl,\u003c/span\u003esecond = 5){\n if(!function_exists(\u0026#8216;curl_init\u0026#8217;)) die(\u0026#8216;php.ini未开启php_curl.dll\u0026#8217;);\n \u003cspan class=\"katex math inline\"\u003ec = curl_init();\n curl_setopt(\u003c/span\u003ec,CURLOPT_URL,\u003cspan class=\"katex math inline\"\u003eurl);\u003c/span\u003eUserAgent=\u003cspan class=\"katex math inline\"\u003e_SERVER[\u0026#8216;HTTP_USER_AGENT\u0026#8217;];\n curl_setopt(\u003c/span\u003ec,CURLOPT_USERAGENT,\u003cspan class=\"katex math inline\"\u003eUserAgent);\n curl_setopt(\u003c/span\u003ec,CURLOPT_HEADER,0);\n curl_setopt(\u003cspan class=\"katex math inline\"\u003ec,CURLOPT_TIMEOUT,\u003c/span\u003esecond);\n curl_setopt(\u003cspan class=\"katex math inline\"\u003ec,CURLOPT_RETURNTRANSFER, true);\u003c/span\u003ecnt = curl_exec(\u003cspan class=\"katex math inline\"\u003ec);\u003c/span\u003ecnt=mb_check_encoding(\u003cspan class=\"katex math inline\"\u003ecnt,\u0026#8217;utf-8\u0026#8242;)?iconv(\u0026#8216;gbk\u0026#8217;,\u0026#8217;utf-8//IGNORE\u0026#8217;,\u003c/span\u003ecnt):\u003cspan class=\"katex math inline\"\u003ecnt; //字符编码转换\n curl_close(\u003c/span\u003ec);\n return \u003cspan class=\"katex math inline\"\u003ecnt;\n }\n function getSid() {\u003c/span\u003esid = time().(rand(0,9000)+10000);\n return \u003cspan class=\"katex math inline\"\u003esid;\n }\n function getkey(\u003c/span\u003ekey1,\u003cspan class=\"katex math inline\"\u003ekey2){\u003c/span\u003ea = hexdec(\u003cspan class=\"katex math inline\"\u003ekey1);\u003c/span\u003eb = \u003cspan class=\"katex math inline\"\u003ea ^ 0xA55AA5A5;\u003c/span\u003eb = dechex(\u003cspan class=\"katex math inline\"\u003eb);\n return\u003c/span\u003ekey2.\u003cspan class=\"katex math inline\"\u003eb;\n }\n function getfileid(\u003c/span\u003efileId,\u003cspan class=\"katex math inline\"\u003eseed) {\u003c/span\u003emixed = getMixString(\u003cspan class=\"katex math inline\"\u003eseed);\u003c/span\u003eids = explode(\u0026#8220;*\u0026#8221;,\u003cspan class=\"katex math inline\"\u003efileId);\n unset(\u003c/span\u003eids[count(\u003cspan class=\"katex math inline\"\u003eids)-1]);\u003c/span\u003erealId = \u0026#8220;\u0026#8221;;\n for (\u003cspan class=\"katex math inline\"\u003ei=0;\u003c/span\u003ei \u003c count(\u003cspan class=\"katex math inline\"\u003eids);++\u003c/span\u003ei) {\n \u003cspan class=\"katex math inline\"\u003eidx =\u003c/span\u003eids[\u003cspan class=\"katex math inline\"\u003ei];\u003c/span\u003erealId .= substr(\u003cspan class=\"katex math inline\"\u003emixed,\u003c/span\u003eidx,1);\n }\n return \u003cspan class=\"katex math inline\"\u003erealId;\n }\n function getMixString(\u003c/span\u003eseed) {\n \u003cspan class=\"katex math inline\"\u003emixed = \u0026#8220;\u0026#8221;;\u003c/span\u003esource = \u0026#8220;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/\\\\:._-1234567890\u0026#8221;;\n \u003cspan class=\"katex math inline\"\u003elen = strlen(\u003c/span\u003esource);\n for(\u003cspan class=\"katex math inline\"\u003ei=0;\u003c/span\u003ei\u003c \u003cspan class=\"katex math inline\"\u003elen;++\u003c/span\u003ei){\n \u003cspan class=\"katex math inline\"\u003eseed = (\u003c/span\u003eseed * 211 + 30031) % 65536;\n \u003cspan class=\"katex math inline\"\u003eindex = (\u003c/span\u003eseed / 65536 * strlen(\u003cspan class=\"katex math inline\"\u003esource));\u003c/span\u003ec = substr(\u003cspan class=\"katex math inline\"\u003esource,\u003c/span\u003eindex,1);\n \u003cspan class=\"katex math inline\"\u003emixed .=\u003c/span\u003ec;\n \u003cspan class=\"katex math inline\"\u003esource = str_replace(\u003c/span\u003ec, \u0026#8220;\u0026#8221;,\u003cspan class=\"katex math inline\"\u003esource);\n }\n return\u003c/span\u003emixed;\n }\n ?\u003e","title":"获取优酷视频真实下载地址的PHP源代码"},{"content":"取精华、去糟粕！适合iOS开发者的15大网站推荐\n1.objc.io\nhttp://www.objc.io/\n2.Subjective-C\nhttp://subjc.com/\n3.NSHipster\nhttp://nshipster.com/\n4.Peter Steinberger\nhttp://petersteinberger.com/\n5.Ole Begemann\nhttp://oleb.net/\n6.Florian Kugler\nhttp://floriankugler.com/\n7.NSBlog\nhttps://www.mikeash.com/pyblog/\n8.Cocoa\nhttp://cocoa.tumblr.com/\n9.Krzysztof Zabłocki\nhttp://www.merowing.info/\n10.iOS Development tips\nhttp://iosdevtips.co/\n11.iOS Dev Weekly\n12.iOS Developer Tips\nhttp://iosdevelopertips.com/\n13.iOS Goodies\nhttp://ios-goodies.com/\n14.Design+Code\nhttps://designcode.io/\n15. AppCoda\nhttp://www.appcoda.com/\n1、anddev\n国外非常好的一个Android开发者论坛，论坛版块划分完全面向开发者，从入门到进阶话题很全面，版主的水平也非常高，经常会出一些教程。\n地址：http://www.anddev.org\n2、 helloAndroid\n以教程为最大特色的国外网站对大家系统学习Android知识非常有帮助\n地址：http://www.helloandroid.com\n3、安卓之家\n国内专注于android开发的论坛，刚开不久，相对来说比较冷清，但论坛的理念所在我比较认可，感觉向市委Android开发者提供了一站式服务\n地址：http://www.androidzj.com\n4、 ACC 开发者论坛\n国内的Android开发论坛，相对eoe要冷清得多，不过国人开源项目CoolReader在这里发布，给论坛增色不少。\n地址：http://androidos.cc\n5、安卓视线 – Android开源项目分享平台\n引用一下网站的介绍：Android是Google开发的基于Linux平台的开源手机操作系统。Android为我们勾画了一个美好的移动互联网前景，学习Android开源代码是掌握Android的一个最佳途径，我们希望每个对Android感兴趣的人都能够在这里掌握更多的知识、获得更多的灵感。\n每天都有最新的Android开源项目推荐，对于大家学习优秀开源项目，开拓思路非常有帮助。\n地址：http://www.androideye.com\n6、安卓航班网\n很不错的安卓开发者论坛，有很多安卓学习的资料， 也有很多android源码项目可以下载，非常方便。适合初学者和高手进阶的好地方！\n地址：http://www.apkway.com\nAndroid开发者必备的42个链接\n2013-12-30 13:46 佚名 看看新闻 字号：T | T\n一键收藏，随时查看，分享好友！\n下面收集了42个帮助大家学习Android的内容链接，部分内容是面向初学者的，帮助大家从头开始学习Android开发，其他则面向较高级的开发者。希望推荐的这些内容对你有帮助。\nAD：WOT2015 互联网运维与开发者大会 热销抢票\n下面收集了42个帮助大家学习Android的内容链接，部分内容是面向初学者的，帮助大家从头开始学习Android开发，其他则面向较高级的开发者。希望推荐的这些内容对你有帮助。\n官方网站\n1、谷歌Android开发者页面\n这里是主站点，在这您可以找到一切资源帮助您开始Android开发。此站包含了很多关于学习基础知识的资源，完整的API引用，以及你开始开发所需的各种工具。此站共分为五个部分：\n作为初学者，你应该从工具开始，这部分讲解了如何安装AndroidSDK。\n教程为你提供了关于Android的基本介绍，教给你如何写出你的第一个程序。它包括很多的资源，即便成为高级程序员你仍需阅读这里面的文章。\nAPI指南是对于不同API更技术性的手册，在更加深入理解Android内部工作方面十分有用。\n参考手册包含关于Android库的完整的类引用。\n在Google Services部分你会找到更多库的信息，这些库可以让你连接到Google的服务，例如地图和Google+。\n教程\n2、Vogella的Android教程\n这里面包括许多给初学者以及高级Android开发者的教程。这些文章由Lars Vogel编写，文章十分专业，为你提供对Android架构的深入理解。\n3、EduMobile Android开发与编程\n在这里你可以找到许多基于单独话题的教程。这些教程并非按照循序渐进的顺序排列的，但是却包含了多种多样的独立话题。\n4、CoreServletsAndroid编程教程\n这是一个更循序渐进的教程系列，可以在你迈出Android编程的第一步时为你指导。\n5、给初学者的AndroidLinux编程\n该教程由三部分组成的，是由linux.com主办目标受众是具有Java背景的Android初学者。\n6、Android快乐编程\n这是一个程序员学习Android的博客。Kinam Choi在他了解Android架构过程中通过他的经验帮助你来理解。\n7、Styling Android\n在这个博客中Mark Allison 专注于设计和Android应用程序的布局。对于那些想要写出有着杰出UI、漂亮的程序的人来说，这是非常有用的资源。\n8、“How To Make An Android App”XDA 论坛\n这里包含了一系列的论坛帖子，这些帖子指导你开发简单的Android应用程序。\n视频教程\n9、TheNewBoston Android教程\n这里有200个视频教程，这些教程专注于Android开发的各个方面，从下载和安装AndroidSDK开始。大多数视频在5分钟左右，这使得你可以在任何小憩的时候看上一段。\n10、Derek Banas Android开发教程\nDerek定期的上传关于各种主题的视频教程。目前共有五个关于Android开发的视频。\n11、 “如何进行Android编程”\n这里有10个简单的视频为你介绍Android开发。有些视频是其它教程很少涉及到的内容。全部看完10个视频大概需要两个小时左右。\n12、Android开发者\n如果你想紧跟Android开发的步伐，那么你应该订阅官方的Android开发者（Android Developers）频道。这里你会学习到最新的特性以及独门绝技。\n13、Android Authority（Android权威）\n这是另一个专注于Android的频道。主要是面向用户，但是作为一个好的开发者，你也应该时刻了解用户的观点。\n工具\n14、ADT Plugin for Eclipse（ADT 插件）\n对于新手而言，这是目前开发程序的标准的方式，也是最佳选项。Android Developer Tools插件在Eclipse中集成了AndroidSDK并且包括一个图形化的布局编辑器，它能自动生成布局XML文件。如果你不喜欢Eclipse，你也可以尝试用IntelliJ IDEA 12来替代。\n15、AndroidAnnotations\nAndroidAnnotations 通过使用Java注解来创建样板代码，从而简化了Android应用程序的开发。它负责替你来最常用的任务从而显著地提高代码开发速度，同时增加了代码的可读性。\n16、RoboGuice\nRoboGuice的目的在与为Android开发加入依赖注入。 RoboGuice同时利用了标注以及Java映像来达到它的目标。\n资源\n17、The Ultimate Android Library (T.U.A.L) 终极Android库\n这是一个展现了许多定制库、图标和视图的程序。你可以在你的设备上安装这个程序并且在action中看到这些元素。你也可以在他们的网站上贡献新的的库。\n18、AndroidViews\n这里有许多定制视图、库和其它资源。你不用重新发明已有的东西，所以可以节省很多时间。\n19、Chupa Mobile\n如果你愿意为应用程序组件花钱的话，那么这个市场就是为你而存在的。同是你也可以考虑卖出你自己的定制组件，小工具等等。\nAPP UI 设计\n20、官方设计指南\n这是Android网页上的官方站点。它包含所有程序设计的基本信息。\n21、Android Patterns\n这是一个UI模式的目录，它解释了与你的应用程序交互的最常用和直观的方法。如果你想为用户创建无缝体验，那么这个网站是必须要看的。\n22、Android App Patterns\n这里有很多截图，这些截图来自不同种类的应用程序。例如，你可以比较各种导航界面来发现哪一种最适合你的程序。\n23、Mobile Patterns\n这是另一个有很多截图的网站，既有Android的也有iPhone。\n24、30 Web、Mobile Wireframe Toolkits\n这是一篇文章，文章包含了30个资源的链接。Wireframe 工具包让你可以更加专业地布局你的程序设计。\n25、Graphic Designers Cheatsheet\n如果你想创建、实现你想要的布局，并快速发布的话，这是一个非常有用的资源。\n灵感\n26、Android Niceties\n这是Tumblr上的一些内容展示了最优美的Android程序，它是启发灵感的好资源。\n27、Lovely.ui\n这是一个展示漂亮的手机程序的网站。不仅有Android程序也有其他的，但是对于手机程序设计者来说都非常有用。\n博客\n28、Android官方开发者博客\n这个官方博客来自于谷歌的Android开发者。与这些内部人士保持联系以获得最新资讯是非常有必要的。\n29、Android周刊\n这个其实不太像是一个博客，它更像是一个每周的新闻通讯，它让你知道最新的Android开发的问题。\n30、Cyril Mottier\n这是一个非常好的博客，它关注与Android界当前的发展趋势。\n31、The Commons Blog\n对于了解Android开发的更深层次的信息， 这个博客是非常必要的读物。Mark Murphy关注与开发者需要注意的细节以及陷阱。\n32、Android UI Patterns\n在Juhani的这个博客中，他专注于应用程序的设计和可用性。\n人物\n要保证时刻获取最新的Android开发的信息，最好的方式就是与那些开发或为架构出力的人们保持联系。因为Android是谷歌创建的，你会发现开发者社区主要在Google+上（而不是Facebook上）。但是你同样可以在其他社交网站上找到他们。\n33、Mark Murphy （Commonsware）\nMark Murphy撰写了“The Busy Coder’s Guide to Android Development”这本书，此书共有2300页，其中包含了大量有用的信息。他主要使用Google+，但他也有一个自己的网站，同时也会在stack overflow上回答问题。\n34、Tor Norbye\nTor Norbye是谷歌公司Android部门的一员。在Android开发上，他从事视觉工具方面的工作。你也可在Twitter和YouTube上找到他，同时他也是The Java Posse的一员。他的博客已经不在更新，因为他已经把主要活动转移至Google+。\n35、Romain Guy\nRomain Guy是AndroidUI部门内部的专家，他专注于图形性能和动画。他使用Google+和Twitter, 也在Stackoverflow上回答问题，同时有自己的博客。请务必看看他的这个在2013 Google I/O大会上关于Android图形和性能以及动画的视频。\n36、Dianne Hackborn\nDianne Hackborn是一名Android架构工程师。除了使用Google+，他还在Stackoverflow上回答问题。\n37、Chris Banes\nChris Banes是ActionBar-PullToRefresh、PhotoView和Android-BitmapCache的作者，这三个均为对于Android开发者非常有用的库。你可以在Google+、Twitter、Stackoverflow、博客甚至Facebook上找到他。\n38、Jake Wharton\nJake Wharton是Android-ViewPagerIndicator和ActionBarSherlock的开发者，这两者简化了所有版本Android中action bar设计模式的使用。他使用Google+、Twitter，同时也在Stackoverflow上回答问题。\n39、Roman Nurik\nRoman Nurik对于Android的贡献主要是改善了用户体验和视觉设计。你可以在Google+、Twitter、Stackoverflow和Dribbble上关注他。\n40、Adam Powell\nAdam Powell是一名Android架构开发者，他主要从事UI工具箱的工作。你可以在Google+、Twitter和Stackoverflow上找到他。\n41、Richard Hyndman\nRichard Hyndman是Android开发组的一员。他主要在Google+和Twitter上发帖。\n42、Cyril Mottier\nCyril Mottier 是GreenDroid和常规blogger的开发者。你可以在Google+和Twitter上找到他。\niOS开发常用国外网站清单 (2013-05-03 16:32:10)转载▼\n标签： apple iphone 移动开发 教育 游戏\n工欲善其事必先利其器，最近发现临时查找一些东西容易浪费时间，花了点时间整理一下常用的网站，方便以后备用。\n国内的code4app,ui4app,cocoachina,oschina,csdn就不说了，基本上很好用。不过国外网站上的好东西更多，可惜找起来也更费时间，需要整理一下。\n主要分开发教程、示例项目、UI设计、问题解决几块。\n开发教程：\n即便过了入门阶段，还是要经常看看一些不错的实例教程。\n1.http://mobile.tutsplus.com/category/tutorials/iphone/\n比较新的一个网站，以前没注意到。\n其中有一篇文章着重推荐，学习iOS游戏开发可以参考的10个实例（源代码都在github上）：\nhttp://mobile.tutsplus.com/tutorials/iphone/learn-ios-game-development-by-example-10-projects-to-get-you-started/\n2.http://www.raywenderlich.com\n这个就不用说了，基本每个学iOS开发的都知道\n3.http://iphonedevsdk.com/forum/iphone-sdk-tutorials/\niphonedevsdk.com的子论坛，以前没注意到，还是有一些好东西的\n4.http://www.iphonegametutorials.com\n游戏开发教程，可惜从2012年4月就停更了。\n5.http://www.iossdktutorials.com/tutorials/\n教程不多，可以看看\n6.http://timroadley.com/tutorials-index/\n内容不多，但都很不错\n7.http://www.learn-cocos2d.com/blog/\nKobold2d引擎(cocos2d引擎的变种）和learn \u0026amp;master cocos2d一书的作者Steffen Itterheim的博客，主要和ios,cocos2d,kobold2d开发有关\n8.https://developers.facebook.com/docs/tutorials/ios-sdk-games/\nfacebook的游戏教程，当然是教你如何在游戏中整合iOS特性的，最新的是一周前刚更新\n9.http://maniacdev.com/category/ios-developer-tutorial\n如果没有网站左侧的广告，会让人感觉好一点\n推荐最新的2013年5月1号的一篇教程，如果使用parse和Opentok开发一款iphone视频聊天应用（还没来得及看，目测还可以，有空的时候再看）\nhttp://www.iphonegamezone.net/ios-tutorial-create-iphone-video-chat-app-using-parse-and-opentok-tokbox/\n10.http://www.touch-code-magazine.com\n一些零散的教程\n11.http://www.idevgames.com/articles\n游戏相关的教程\n示例项目：\n好的示例和开源项目不光可以学到东西，也可以节省不少时间。\n1.http://www.raywenderlich.com/store\nios游戏开发的starter kit，不过都要花美金\n2.http://iphonegamekit.com\nios游戏开发的starter kit，不过都要花美金\n3.http://www.cartoonsmart.com/iphone_index.php5\nios游戏开发的starter kit，不过都要花美金\n4.unity3d 的asset store\n要花钱的\n5.github\n最多最好又免费，比如找游戏源代码搜game，然后选objective-c语言，就可以看到很多。可以选择用stars,forks,last updated来排序\nhttps://github.com/search?l=Objective-C\u0026amp;p=2\u0026amp;q=game\u0026amp;s=stars\u0026amp;type=Repositories\n6.source forge\n不多说了\n7.教程网站里面基本上都有一些示例项目，有时候还会专门整理出来方便开发者，比如下面这些就很有用：\n开源ios游戏及其源代码：\n[Open Source iOS Game List \u0026amp;#8211; Source Code To Games In The App Store](https://maniacdev.com/open-source-ios-game-list-source-code-to-games-in-the-app-store) \u0026lt;/div\u0026gt; 开源ios应用及其源代码 \u0026lt;div class=\u0026quot;video-container\u0026quot;\u0026gt; \u0026lt;blockquote class=\u0026quot;wp-embedded-content\u0026quot; data-secret=\u0026quot;nJvBvUzywv\u0026quot;\u0026gt; [Open Source iPhone App Store Apps](https://maniacdev.com/open-source-iphone-app-store-apps) \u0026lt;/blockquote\u0026gt; \u0026lt;/div\u0026gt; 8.Y-C hacker news https://news.ycombinator.com 偶尔会有一些教程，虽然数量少，但都是高质量的东西，而且可以第一时间了解最新的技术动向，比如上面去年曾经有关于parse的非常详尽的教程。\n9.https://developer.apple.com/library/ios/navigation/index.html?section=Resource+Types\u0026amp;topic=Sample+Code 苹果官方的小示例项目，虽然不算完整项目，但对于学新东西和新功能还是挺方便的。\n另外在unity3d和unreal引擎的官方和第三方论坛里面也有一些ios游戏开发教程和starter kit，不过我个人目前还没用过这两种引擎，先记下来再说。另外如parse这些官网里面也有针对特定服务的开发教程和示例项目。 不过总体感觉上面这些网站都没有国内的code4app和ui4app好用，必须得说code4app和cocoachina都很给力，可惜上面的完整游戏示例项目还是少了点。 UI设计相关： 个人涉及的不多，先把别人整理的放在这里备用： 1.http://www.patternsofdesign.co.uk/ 专注于分享iOS应用UI界面的细节，按照设计元素进行分类，按照iOS常用功能对各类UI进行分类展示。 2.http://pttrns.com/ Splashscreens / iOS UI Patterns (beta) ，整理/罗列了许多精彩的iOS 应用界面截图，并且按照分类将这些截图分类，比如Activity，Login，About，Calendar，Seeting，Share等各种类型的不同应用的实现效果。 3.http://www.appsites.com/ 优秀移动应用网站设计\n4.http://dribbble.com/ 设计师交流和分享自己设计作品的社区。上面有很多非常棒的移动产品设计作品。\n5.http://www.tappgala.com/ 分享最棒的手机产品界面设计\n6.http://www.mobiledesignpatterngallery.com/ 移动设计书籍、移动原型分享的网站。\n7.http://www.iosinspires.me/ 主要是展示优秀的iOS平台上应用的设计，icon及相关资源\n8.http://www.cocoacontrols.com ios和mac控件 问题解决： 这个算是平时最需要用的了，虽然第一反应是用google，但也有些搜不到，就只能求人帮忙了 1.http://stackoverflow.com 最强大的编程问答网站\n2.http://www.developerfeed.com/profile/ios-developer 有点类似stack overflow\n3.https://devforums.apple.com 苹果官方开发者论坛，有很多苹果的黄马甲在，不光是技术层面的，曾经帮我们解决了不少上线相关的问题 4.http://iphonedevsdk.com/forum 最常去的苹果开发论坛之一。 这个网站清单长期更新中，需要不断补充完善，google虽然强大，但要找到特定的内容还是要花时间。如果有个开发用的垂直搜索引擎就好了，可以省掉不少时间。 里罗列了一些不同的网站，教你如何创建用户界面和伟大的应用程序以及App Store的开发。这些教程中的大部分是完全免费的。 1) Apple Learning Objective C 2) Design then Code 3) Mobile Tutsplus 4) Team Tree House 5) Introduction to iOS Development Coding your First Application 6) Stackoverflow – iOS 7) iPhone App Development Where to Start 8) iPhonedev 9) Lynda 10) Raywenderlich via zoomzum http://www.oschina.net/news/33276/10-best-sites-to-learn-ios-development 1、http://developer.apple.com/iphone/library 官方代码实例\n2、www.cocoachina.com 中国苹果开发者\n3、http://www.tipb.com/ 国外的一些文章博客，介绍iphone的特性和开发\n4、http://www.iphonedevsdk.com/forum/ iPhoneDev SDK\n5、http://iphone.tgbus.com/kuihua/ iphone 宝典\n6、http://www.iphonetw.net/forum/thread.php?fid=9 台湾iphone开发俱乐部\n7、http://www.175iphone.com/ iphone资源网\n8、http://lichen1985.com/blog/ 雨雪霏霏 blog http://blog.sina.com.cn/s/blog_672b7fe50100inpb.html\n9、http://www.iphone-geek.cn/recommendation iPhone 新闻，编程，技巧与提示，代码，教程\n10、http://www.1000phone.net/forum.php?gid=36 iPhone 论坛、实例、开发资料等\n11 英文文档 http://www.cocoadevcentral.com/\n12 oc 理论 http://www.cnblogs.com/yaski/\n13 站内文章 http://blog.csdn.net/zaitianaoxiang/article/details/7169673\n14 ios 网络 http://blog.sina.com.cn/s/blog_63ae1c4a01011cap.html\n","permalink":"https://blog.zdltech.com/posts/%E7%BD%91%E5%9D%80%E6%94%B6%E9%9B%86/","summary":"\u003cp\u003e取精华、去糟粕！适合iOS开发者的15大网站推荐\u003cbr\u003e\n1.objc.io\u003cbr\u003e\n\u003ca href=\"http://www.objc.io/\"\u003ehttp://www.objc.io/\u003c/a\u003e\u003cbr\u003e\n2.Subjective-C\u003cbr\u003e\n\u003ca href=\"http://subjc.com/\"\u003ehttp://subjc.com/\u003c/a\u003e\u003cbr\u003e\n3.NSHipster\u003cbr\u003e\n\u003ca href=\"http://nshipster.com/\"\u003ehttp://nshipster.com/\u003c/a\u003e\u003cbr\u003e\n4.Peter Steinberger\u003cbr\u003e\n\u003ca href=\"http://petersteinberger.com/\"\u003ehttp://petersteinberger.com/\u003c/a\u003e\u003cbr\u003e\n5.Ole Begemann\u003cbr\u003e\n\u003ca href=\"http://oleb.net/\"\u003ehttp://oleb.net/\u003c/a\u003e\u003cbr\u003e\n6.Florian Kugler\u003cbr\u003e\n\u003ca href=\"http://floriankugler.com/\"\u003ehttp://floriankugler.com/\u003c/a\u003e\u003cbr\u003e\n7.NSBlog\u003cbr\u003e\n\u003ca href=\"https://www.mikeash.com/pyblog/\"\u003ehttps://www.mikeash.com/pyblog/\u003c/a\u003e\u003cbr\u003e\n8.Cocoa\u003cbr\u003e\n\u003ca href=\"http://cocoa.tumblr.com/\"\u003ehttp://cocoa.tumblr.com/\u003c/a\u003e\u003cbr\u003e\n9.Krzysztof Zabłocki\u003cbr\u003e\n\u003ca href=\"http://www.merowing.info/\"\u003ehttp://www.merowing.info/\u003c/a\u003e\u003cbr\u003e\n10.iOS Development tips\u003cbr\u003e\n\u003ca href=\"http://iosdevtips.co/\"\u003ehttp://iosdevtips.co/\u003c/a\u003e\u003cbr\u003e\n11.iOS Dev Weekly\u003c/p\u003e\n\u003cdiv class=\"video-container\"\u003e\n\u003c/div\u003e\n\u003cp\u003e12.iOS Developer Tips\u003cbr\u003e\n\u003ca href=\"http://iosdevelopertips.com/\"\u003ehttp://iosdevelopertips.com/\u003c/a\u003e\u003cbr\u003e\n13.iOS Goodies\u003cbr\u003e\n\u003ca href=\"http://ios-goodies.com/\"\u003ehttp://ios-goodies.com/\u003c/a\u003e\u003cbr\u003e\n14.Design+Code\u003cbr\u003e\n\u003ca href=\"https://designcode.io/\"\u003ehttps://designcode.io/\u003c/a\u003e\u003cbr\u003e\n15. AppCoda\u003cbr\u003e\n\u003ca href=\"http://www.appcoda.com/\"\u003ehttp://www.appcoda.com/\u003c/a\u003e\u003cbr\u003e\n1、anddev\u003cbr\u003e\n国外非常好的一个Android开发者论坛，论坛版块划分完全面向开发者，从入门到进阶话题很全面，版主的水平也非常高，经常会出一些教程。\u003cbr\u003e\n地址：http://www.anddev.org\u003cbr\u003e\n2、 helloAndroid\u003cbr\u003e\n以教程为最大特色的国外网站对大家系统学习Android知识非常有帮助\u003cbr\u003e\n地址：http://www.helloandroid.com\u003c/p\u003e\n\u003cp\u003e3、安卓之家\u003cbr\u003e\n国内专注于android开发的论坛，刚开不久，相对来说比较冷清，但论坛的理念所在我比较认可，感觉向市委Android开发者提供了一站式服务\u003cbr\u003e\n地址：http://www.androidzj.com\u003c/p\u003e\n\u003cp\u003e4、 ACC 开发者论坛\u003cbr\u003e\n国内的Android开发论坛，相对eoe要冷清得多，不过国人开源项目CoolReader在这里发布，给论坛增色不少。\u003cbr\u003e\n地址：http://androidos.cc\u003c/p\u003e\n\u003cp\u003e5、安卓视线 – Android开源项目分享平台\u003cbr\u003e\n引用一下网站的介绍：Android是Google开发的基于Linux平台的开源手机操作系统。Android为我们勾画了一个美好的移动互联网前景，学习Android开源代码是掌握Android的一个最佳途径，我们希望每个对Android感兴趣的人都能够在这里掌握更多的知识、获得更多的灵感。\u003cbr\u003e\n每天都有最新的Android开源项目推荐，对于大家学习优秀开源项目，开拓思路非常有帮助。\u003cbr\u003e\n地址：http://www.androideye.com\u003c/p\u003e\n\u003cp\u003e6、安卓航班网\u003cbr\u003e\n很不错的安卓开发者论坛，有很多安卓学习的资料， 也有很多android源码项目可以下载，非常方便。适合初学者和高手进阶的好地方！\u003cbr\u003e\n地址：http://www.apkway.com\u003cbr\u003e\nAndroid开发者必备的42个链接\u003cbr\u003e\n2013-12-30 13:46 佚名 看看新闻 字号：T | T\u003cbr\u003e\n一键收藏，随时查看，分享好友！\u003cbr\u003e\n下面收集了42个帮助大家学习Android的内容链接，部分内容是面向初学者的，帮助大家从头开始学习Android开发，其他则面向较高级的开发者。希望推荐的这些内容对你有帮助。\u003cbr\u003e\nAD：WOT2015 互联网运维与开发者大会 热销抢票\u003cbr\u003e\n下面收集了42个帮助大家学习Android的内容链接，部分内容是面向初学者的，帮助大家从头开始学习Android开发，其他则面向较高级的开发者。希望推荐的这些内容对你有帮助。\u003c/p\u003e\n\u003cp\u003e官方网站\u003c/p\u003e\n\u003cp\u003e1、谷歌Android开发者页面\u003c/p\u003e\n\u003cp\u003e这里是主站点，在这您可以找到一切资源帮助您开始Android开发。此站包含了很多关于学习基础知识的资源，完整的API引用，以及你开始开发所需的各种工具。此站共分为五个部分：\u003c/p\u003e","title":"网址收集"},{"content":"本文主要分享自己在appstore项目中的性能调优点，包括同步改异步、缓存、Layout优化、数据库优化、算法优化、延迟执行等。\n性能优化专题已完成五部分：\n性能优化总纲——性能问题及性能调优方式\n性能优化第三篇——Java(Android)代码优化\n性能优化第二篇——布局优化\n性能优化第一篇——数据库性能优化\n性能优化实例\n一、性能瓶颈点\n整个页面主要由6个Page的ViewPager，每个Page为一个GridView，GridView一屏大概显示4*4的item信息(本文最后有附图)。由于网络数据获取较多且随时需要保持页面内app下载进度及状态，所以出现以下性能问题\na. ViewPager左右滑动明显卡顿\nb. GridView上下滚动明显卡顿\nc. 其他Activity返回ViewPager Activity较慢\nd. 网络获取到展现速度较慢\n**\n二、性能调试及定位**\n主要使用Traceview、monkey、monkey runner调试，traceview类似java web调优的visualvm，使用方法如下：\n在需要调优的activity onCreate函数中添加\n1 \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef3f771207698-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;os\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;debug\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;startMethodTracing\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;Entertainment\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; onDestrory函数中添加\n1 \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef54202315585-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;os\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;debug\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;stopMethodTracing\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 程序退出后会在sd卡根目录下生成Entertainment.trace这个文件，cmd到android sdk的tools目录下运行traceview.bat Entertainment.trace即可，截图如下\n从中可以看出各个函数的调用时间、调用次数、平均调用时间、时间占用百分比等从而定位到耗时的操作。monkey、monkey runner更详细的见后面博客介绍\n**\n三、性能调优点**\n主要包括同步改异步、缓存、Layout优化、数据库优化、算法优化、延迟执行。\n1. 同步改异步\n这个就不用多讲了，耗时操作放在线程中执行防止占用主线程，一定程度上解决anr。\n但需要注意线程和service结合（防止activity被回收后线程也被回收）以及线程的数量\n线程池使用可见java的线程池\n**\n2. 缓存**\njava的对象创建需要分配资源较耗费时间，加上创建的对象越多会造成越频繁的gc影响系统响应。主要使用单例模式、缓存(图片缓存、线程池、View缓存、IO缓存、消息缓存、通知栏notification缓存)及其他方式减少对象创建。\n(1). 单例模式\n对于创建开销较大的类可使用此方法，保证全局一个实例，在程序运行过程中该类不会因新建额外对象产生开销。示例代码如下：\n单例模式 \u0026lt;div class=\u0026quot;crayon-tools\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-expand-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-copy-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;crayon-language\u0026quot;\u0026gt;Java\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt; \u0026lt;table class=\u0026quot;crayon-table\u0026quot;\u0026gt; \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;crayon-nums \u0026quot; data-settings=\u0026quot;show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-1\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-14\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-15\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-16\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-17\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-18\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-19\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-20\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef64731569061-21\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Singleton\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-2\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;Object\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;obj\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;Object\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-4\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Singleton \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;instance\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-6\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Singleton\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-8\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Singleton \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getInstance\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-10\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// if already inited, no need to get lock everytime\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;instance\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-12\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;obj\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;instance\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-14\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;instance\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Singleton\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-15\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-16\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-17\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-18\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-19\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;instance\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-20\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef64731569061-21\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt; ** (2). 缓存 程序中用到了图片缓存、线程池、View缓存、IO缓存、消息缓存、通知栏notification缓存**等。 **a. 图片缓存：**见ImageCache和ImageSdCache\n** b. 线程池：**使用Java的Executors类，通过newCachedThreadPool、newFixedThreadPool、newSingleThreadExecutor、newScheduledThreadPool提供四种不同类型的线程池\n** c. View缓存：**\n可见[ListView缓存机制](http://www.trinea.cn/android/android-listview%e6%bb%91%e5%8a%a8%e8%bf%87%e7%a8%8b%e4%b8%ad%e5%9b%be%e7%89%87%e6%98%be%e7%a4%ba%e9%87%8d%e5%a4%8d%e9%94%99%e4%b9%b1%e9%97%aa%e7%83%81%e9%97%ae%e9%a2%98%e8%a7%a3%e5%86%b3/) \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-arduino-ide crayon-font-monaco crayon-os-pc print-yes\u0026quot; data-settings=\u0026quot; no-popup scroll-mouseover wrap\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-toolbar\u0026quot; data-settings=\u0026quot; show\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-title\u0026quot;\u0026gt;listView的getView缓存\u0026lt;/span\u0026gt; \u0026lt;div class=\u0026quot;crayon-tools\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-expand-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-copy-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;crayon-language\u0026quot;\u0026gt;Java\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt; \u0026lt;table class=\u0026quot;crayon-table\u0026quot;\u0026gt; \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;crayon-nums \u0026quot; data-settings=\u0026quot;show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-1\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-14\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-15\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-16\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-17\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-18\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-19\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-20\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-21\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-22\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-23\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-24\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef74524581893-25\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-n\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-2\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;View \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;position\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;View \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;convertView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;ViewGroup \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;parent\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;ViewHolder \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;holder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-4\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;convertView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;==\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;convertView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;inflater\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;inflate\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;layout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;type_item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-6\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;holder\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;ViewHolder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;holder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;imageView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;convertView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;findViewById\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;app_icon\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-8\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;holder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;textView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;convertView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;findViewById\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;app_name\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;convertView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setTag\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;holder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-10\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;holder\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;ViewHolder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;convertView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getTag\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-12\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;holder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;imageView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setImageResource\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;R\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;drawable\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;index_default_image\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-14\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;holder\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;textView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;setText\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-15\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;convertView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-16\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-17\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-18\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-19\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; * ViewHolder\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-20\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-21\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;ViewHolder\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-22\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-23\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;ImageView \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;imageView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-24\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;TextView \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;textView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef74524581893-25\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt; 通过convertView是否为null减少layout inflate次数，通过静态的ViewHolder减少findViewById的次数，这两个函数尤其是inflate是相当费时间的 ** d. IO缓存：** 使用具有缓存策略的输入流，BufferedInputStream替代InputStream，BufferedReader替代Reader，BufferedReader替代BufferedInputStream.对文件、网络IO皆适用。\n** e. 消息缓存：**通过 Handler 的 obtainMessage 回收 Message 对象，减少 Message 对象的创建开销 handler.sendMessage(handler.obtainMessage(1));\n** f. 通知栏notification缓存：**下载中需要不断改变通知栏进度条状态，如果不断新建Notification会导致通知栏很卡。这里我们可以使用最简单的缓存 Map\u0026lt;String, Notification\u0026gt; notificationMap = new HashMap\u0026lt;String, Notification\u0026gt;();如果notificationMap中不存在，则新建notification并且put into map.\n** (3). 其他** **能创建基类解决问题就不用具体子类：**除需要设置优先级的线程使用new Thread创建外，其余线程创建使用new Runnable。因为子类会有自己的属性创建需要更多开销。 **控制最大并发数量：**使用Java的Executors类，通过Executors.newFixedThreadPool(nThreads)控制线程池最大线程并发 对于http请求增加timeout\n\u0026amp;nbsp; **3. [Layout优化](http://www.trinea.cn/android/layout-performance/)** 使用抽象布局标签(include, viewstub, merge)、去除不必要的嵌套和View节点、减少不必要的infalte及其他Layout方面可调优点，顺带提及布局调优相关工具(hierarchy viewer和lint)。具体可见性能优化之布局优化 TextView属性优化：TextView的android:ellipsize=”marquee”跑马灯效果极耗性能，具体原因还在深入源码中\n\u0026amp;nbsp; **4. 数据库优化** 主要包括索引和事务及针对Sqlite的优化。具体可见性能优化之数据库优化\n** 算法优化** 这个就是个博大精深的话题了，只介绍本应用中使用的。 使用hashMap代替arrayList，时间复杂度降低一个数量级\n** 延迟执行** 对于很多耗时逻辑没必要立即执行，这时候我们可以将其延迟执行。 线程延迟执行 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10); 消息延迟发送 handler.sendMessageDelayed(handler.obtainMessage(0), 1000);\n** 四、本程序性能调优结果** 1. ViewPager左右滑动明显卡顿 2. GridView上下滚动明显卡顿 (1). 去掉TextView的android:ellipsize=”marquee” (2). 修改图片缓存的最大线程数，增加http timeout (3). 修改设置app是否已安装的状态，具体代码修改如下：\n\u0026lt;div id=\u0026quot;crayon-551b51a07ef89354600387\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-arduino-ide crayon-font-monaco crayon-os-pc print-yes\u0026quot; data-settings=\u0026quot; no-popup minimize scroll-mouseover wrap\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-toolbar\u0026quot; data-settings=\u0026quot; show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-tools\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-expand-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-copy-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;crayon-language\u0026quot;\u0026gt;Java\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt; \u0026lt;table class=\u0026quot;crayon-table\u0026quot;\u0026gt; \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;crayon-nums \u0026quot; data-settings=\u0026quot;show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef89354600387-1\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef89354600387-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef89354600387-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef89354600387-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef89354600387-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef89354600387-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef89354600387-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef89354600387-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e \u0026quot;\u0026gt;\u0026lt;PackageInfo\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;installedPackageList\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getPackageManager\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getInstalledPackages\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;PackageManager\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;GET_UNINSTALLED_PACKAGES\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef89354600387-2\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;List\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e \u0026quot;\u0026gt;\u0026lt;App\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;installedAppList\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;function\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;installedAppList\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef89354600387-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;App \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;app\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;appList\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef89354600387-4\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;App \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;installedApp\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;installedAppList\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef89354600387-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef89354600387-6\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef89354600387-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt; 修改为 \u0026lt;div id=\u0026quot;crayon-551b51a07ef94240085498\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-arduino-ide crayon-font-monaco crayon-os-pc print-yes\u0026quot; data-settings=\u0026quot; no-popup minimize scroll-mouseover wrap\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-toolbar\u0026quot; data-settings=\u0026quot; show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-tools\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-expand-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-copy-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;crayon-language\u0026quot;\u0026gt;Java\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt; \u0026lt;table class=\u0026quot;crayon-table\u0026quot;\u0026gt; \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;crayon-nums \u0026quot; data-settings=\u0026quot;show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef94240085498-1\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef94240085498-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef94240085498-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef94240085498-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef94240085498-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef94240085498-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef94240085498-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07ef94240085498-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef94240085498-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;App \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;app\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;appList\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef94240085498-2\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;Pair\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;Integer\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;versionInfo\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;INSTALLED_APP_MAP\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;get\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;app\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getPackageName\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef94240085498-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;versionInfo\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;!=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef94240085498-4\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef94240085498-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef94240085498-6\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef94240085498-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07ef94240085498-8\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt; 从每次获取List\u0026lt;PackageInfo\u0026gt; installedAppList = getPackageManager().getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);修改为只在有应用安装或卸载广播时获取应用列表，并且用hashMap代替installedAppList减少查询时间。 将平均执行时间从201ms降低到1ms。 ** 其他Activity返回ViewPager Activity较慢** 定位：在onStart函数 解决：使用延迟策略，具体代码修改如下：\n\u0026lt;div id=\u0026quot;crayon-551b51a07efa0984029811\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-arduino-ide crayon-font-monaco crayon-os-pc print-yes\u0026quot; data-settings=\u0026quot; no-popup minimize scroll-mouseover wrap\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-toolbar\u0026quot; data-settings=\u0026quot; show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-tools\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-expand-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-copy-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;crayon-language\u0026quot;\u0026gt;Java\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt; \u0026lt;table class=\u0026quot;crayon-table\u0026quot;\u0026gt; \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;crayon-nums \u0026quot; data-settings=\u0026quot;show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efa0984029811-1\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efa0984029811-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efa0984029811-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efa0984029811-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efa0984029811-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efa0984029811-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-n\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efa0984029811-2\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onStart\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efa0984029811-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onStart\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efa0984029811-4\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;appUpdateListAdapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;notifyDataSetChanged\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efa0984029811-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt; 改为 \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-arduino-ide crayon-font-monaco crayon-os-pc print-yes\u0026quot; data-settings=\u0026quot; no-popup scroll-mouseover wrap\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-toolbar\u0026quot; data-settings=\u0026quot; show\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-title\u0026quot;\u0026gt;优化后代码\u0026lt;/span\u0026gt; \u0026lt;div class=\u0026quot;crayon-tools\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-expand-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-copy-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;crayon-language\u0026quot;\u0026gt;Java\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt; \u0026lt;table class=\u0026quot;crayon-table\u0026quot;\u0026gt; \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;crayon-nums \u0026quot; data-settings=\u0026quot;show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-1\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-7\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-8\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-9\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-10\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-11\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-12\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-13\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-14\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-15\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-16\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-17\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-18\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-19\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-20\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efaa052277268-21\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onStart\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-2\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;onStart\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-c\u0026quot;\u0026gt;// delay send message\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-4\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;handler\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;sendMessageDelayed\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;handler\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;obtainMessage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;MessageConstants\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;WHAT_NOTIFY_DATA_CHANGED\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-cn\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-6\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-7\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;MyHandler\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Handler\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-8\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-9\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-n\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-10\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-m\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;handleMessage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;Message \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;msg\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-11\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;handleMessage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;msg\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-12\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-13\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;msg\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;what\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-14\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;MessageConstants\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;WHAT_NOTIFY_DATA_CHANGED\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;:\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-15\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;appUpdateListAdapter\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;!=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-16\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;appUpdateListAdapter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;notifyDataSetChanged\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-17\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-18\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-19\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-20\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-h\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efaa052277268-21\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt; ** 网络获取到展现速度较慢**\n定位：在HttpURLConnection.getInputStream()之后的处理 解决：使用BufferedReader替代BufferedInputStream获取时间从100ms降低到3ms，具体代码修改如下：\n\u0026lt;div id=\u0026quot;crayon-551b51a07efb7617197317\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-arduino-ide crayon-font-monaco crayon-os-pc print-yes\u0026quot; data-settings=\u0026quot; no-popup minimize scroll-mouseover wrap\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-toolbar\u0026quot; data-settings=\u0026quot; show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-tools\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-expand-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-copy-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;crayon-language\u0026quot;\u0026gt;Java\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt; \u0026lt;table class=\u0026quot;crayon-table\u0026quot;\u0026gt; \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;crayon-nums \u0026quot; data-settings=\u0026quot;show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efb7617197317-1\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efb7617197317-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efb7617197317-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efb7617197317-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efb7617197317-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efb7617197317-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;HttpURLConnection \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;con\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;HttpURLConnection\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;url\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;openConnection\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efb7617197317-2\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;InputStream \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;input\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;con\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getInputStream\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efb7617197317-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efb7617197317-4\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efb7617197317-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt; 改为 \u0026lt;div id=\u0026quot;crayon-551b51a07efcc003116771\u0026quot; class=\u0026quot;crayon-syntax crayon-theme-arduino-ide crayon-font-monaco crayon-os-pc print-yes\u0026quot; data-settings=\u0026quot; no-popup minimize scroll-mouseover wrap\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-toolbar\u0026quot; data-settings=\u0026quot; show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-tools\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-expand-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-button crayon-copy-button\u0026quot; title=\u0026quot;Expand Code\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span class=\u0026quot;crayon-language\u0026quot;\u0026gt;Java\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-plain-wrap\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-main\u0026quot;\u0026gt; \u0026lt;table class=\u0026quot;crayon-table\u0026quot;\u0026gt; \u0026lt;tr class=\u0026quot;crayon-row\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;crayon-nums \u0026quot; data-settings=\u0026quot;show\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-nums-content\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efcc003116771-1\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efcc003116771-2\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efcc003116771-3\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efcc003116771-4\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efcc003116771-5\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;crayon-num crayon-striped-num\u0026quot; data-line=\u0026quot;crayon-551b51a07efcc003116771-6\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efcc003116771-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;HttpURLConnection \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;con\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;HttpURLConnection\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;url\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;openConnection\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efcc003116771-2\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;BufferedReader \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;input\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;BufferedReader\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-r\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;InputStreamReader\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;con\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;getInputStream\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efcc003116771-3\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;String\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-i\u0026quot;\u0026gt;s\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efcc003116771-4\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-st\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;s\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;input\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;readLine\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-o\u0026quot;\u0026gt;!=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-t\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efcc003116771-5\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026quot;crayon-551b51a07efcc003116771-6\u0026quot; class=\u0026quot;crayon-line crayon-striped-line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 转自：http://www.trinea.cn/android/android-performance-demo/ \u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android%E6%80%A7%E8%83%BD%E8%B0%83%E4%BC%98/","summary":"\u003cp\u003e本文主要分享自己在appstore项目中的性能调优点，包括\u003cstrong\u003e同步改异步、缓存、Layout优化、数据库优化、算法优化、延迟执行\u003c/strong\u003e等。\u003c/p\u003e\n\u003cp\u003e性能优化专题已完成五部分：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.trinea.cn/android/performance/\"\u003e性能优化总纲——性能问题及性能调优方式\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"http://www.trinea.cn/android/java-android-performance/\"\u003e性能优化第三篇——Java(Android)代码优化\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"http://www.trinea.cn/android/layout-performance/\"\u003e性能优化第二篇——布局优化\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"http://www.trinea.cn/android/database-performance/\"\u003e性能优化第一篇——数据库性能优化\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.trinea.cn/android/android%e6%80%a7%e8%83%bd%e8%b0%83%e4%bc%98/\"\u003e性能优化实例\u003c/a\u003e\u003ca href=\"http://www.trinea.cn/android/android%e6%80%a7%e8%83%bd%e8%b0%83%e4%bc%98/\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一、性能瓶颈点\u003c/strong\u003e\u003cbr\u003e\n整个页面主要由6个Page的ViewPager，每个Page为一个GridView，GridView一屏大概显示4*4的item信息(本文最后有附图)。由于网络数据获取较多且随时需要保持页面内app下载进度及状态，所以出现以下性能问题\u003cbr\u003e\na.  ViewPager左右滑动明显卡顿\u003cbr\u003e\nb.  GridView上下滚动明显卡顿\u003cbr\u003e\nc.  其他Activity返回ViewPager Activity较慢\u003cbr\u003e\nd.  网络获取到展现速度较慢\u003c/p\u003e\n\u003cp\u003e**\u003cbr\u003e\n二、性能调试及定位**\u003cbr\u003e\n主要使用\u003ca href=\"http://www.trinea.cn/android/android%e6%80%a7%e8%83%bd%e8%b0%83%e4%bc%98%e5%b7%a5%e5%85%b7traceview%e4%bb%8b%e7%bb%8d/\"\u003eTraceview\u003c/a\u003e、monkey、monkey runner调试，traceview类似java web调优的visualvm，使用方法如下：\u003cbr\u003e\n在需要调优的activity onCreate函数中添加\u003c/p\u003e\n\u003cdiv id=\"crayon-551b51a07ef3f771207698\" class=\"crayon-syntax crayon-theme-arduino-ide crayon-font-monaco crayon-os-pc print-yes\" data-settings=\" no-popup minimize scroll-mouseover wrap\"\u003e\n  \u003cdiv class=\"crayon-plain-wrap\"\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"crayon-main\"\u003e\n    \u003ctable class=\"crayon-table\"\u003e\n      \u003ctr class=\"crayon-row\"\u003e\n        \u003ctd class=\"crayon-nums \" data-settings=\"show\"\u003e\n          \u003cdiv class=\"crayon-nums-content\"\u003e\n            \u003cdiv class=\"crayon-num\" data-line=\"crayon-551b51a07ef3f771207698-1\"\u003e\n              1\n            \u003c/div\u003e\n          \u003c/div\u003e\n        \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt;\n        \u0026lt;div id=\u0026quot;crayon-551b51a07ef3f771207698-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt;\n          \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;os\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;debug\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;startMethodTracing\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-s\u0026quot;\u0026gt;\u0026amp;#8220;Entertainment\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003eonDestrory函数中添加\u003c/p\u003e\n\u003cdiv id=\"crayon-551b51a07ef54202315585\" class=\"crayon-syntax crayon-theme-arduino-ide crayon-font-monaco crayon-os-pc print-yes\" data-settings=\" no-popup minimize scroll-mouseover wrap\"\u003e\n  \u003cdiv class=\"crayon-plain-wrap\"\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"crayon-main\"\u003e\n    \u003ctable class=\"crayon-table\"\u003e\n      \u003ctr class=\"crayon-row\"\u003e\n        \u003ctd class=\"crayon-nums \" data-settings=\"show\"\u003e\n          \u003cdiv class=\"crayon-nums-content\"\u003e\n            \u003cdiv class=\"crayon-num\" data-line=\"crayon-551b51a07ef54202315585-1\"\u003e\n              1\n            \u003c/div\u003e\n          \u003c/div\u003e\n        \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;td class=\u0026quot;crayon-code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;crayon-pre\u0026quot;\u0026gt;\n        \u0026lt;div id=\u0026quot;crayon-551b51a07ef54202315585-1\u0026quot; class=\u0026quot;crayon-line\u0026quot;\u0026gt;\n          \u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;os\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-v\u0026quot;\u0026gt;debug\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-e\u0026quot;\u0026gt;stopMethodTracing\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;crayon-sy\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e程序退出后会在sd卡根目录下生成Entertainment.trace这个文件，cmd到android sdk的tools目录下运行traceview.bat Entertainment.trace即可，截图如下\u003c/p\u003e","title":"Android性能调优"},{"content":"转载：http://blog.csdn.net/guolin_blog/article/details/12921889\n有段时间没写博客了，感觉都有些生疏了呢。最近繁忙的工作终于告一段落，又有时间写文章了，接下来还会继续坚持每一周篇的节奏。\n有不少朋友跟我反应，都希望我可以写一篇关于View的文章，讲一讲View的工作原理以及自定义View的方法。没错，承诺过的文章我是一定要兑现的，而且在View这个话题上我还准备多写几篇，尽量能将这个知识点讲得透彻一些。那么今天就从LayoutInflater开始讲起吧。\n相信接触Android久一点的朋友对于LayoutInflater一定不会陌生，都会知道它主要是用于加载布局的。而刚接触Android的朋友可能对LayoutInflater不怎么熟悉，因为加载布局的任务通常都是在Activity中调用setContentView()方法来完成的。其实setContentView()方法的内部也是使用LayoutInflater来加载布局的，只不过这部分源码是internal的，不太容易查看到。那么今天我们就来把LayoutInflater的工作流程仔细地剖析一遍，也许还能解决掉某些困扰你心头多年的疑惑。\n先来看一下LayoutInflater的基本用法吧，它的用法非常简单，首先需要获取到LayoutInflater的实例，有两种方法可以获取到，第一种写法如下：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - LayoutInflater layoutInflater = LayoutInflater.from(context); 当然，还有另外一种写法也可以完成同样的效果：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - LayoutInflater layoutInflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 其实第一种就是第二种的简单写法，只是Android给我们做了一下封装而已。得到了LayoutInflater的实例之后就可以调用它的inflate()方法来加载布局了，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - layoutInflater.inflate(resourceId, root); inflate()方法一般接收两个参数，第一个参数就是要加载的布局id，第二个参数是指给该布局的外部再嵌套一层父布局，如果不需要就直接传null。这样就成功成功创建了一个布局的实例，之后再将它添加到指定的位置就可以显示出来了。\n下面我们就通过一个非常简单的小例子，来更加直观地看一下LayoutInflater的用法。比如说当前有一个项目，其中MainActivity对应的布局文件叫做activity_main.xml，代码如下所示：\n**[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/main_layout\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 这个布局文件的内容非常简单，只有一个空的LinearLayout，里面什么控件都没有，因此界面上应该不会显示任何东西。\n那么接下来我们再定义一个布局文件，给它取名为button_layout.xml，代码如下所示：\n**[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;Button\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 这个布局文件也非常简单，只有一个Button按钮而已。现在我们要想办法，如何通过LayoutInflater来将button_layout这个布局添加到主布局文件的LinearLayout中。根据刚刚介绍的用法，修改MainActivity中的代码，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LinearLayout mainLayout; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - mainLayout = (LinearLayout) findViewById(R.id.main_layout); - LayoutInflater layoutInflater = LayoutInflater.from(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - View buttonLayout = layoutInflater.inflate(R.layout.button_layout, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - mainLayout.addView(buttonLayout); - } - - } 可以看到，这里先是获取到了LayoutInflater的实例，然后调用它的inflate()方法来加载button_layout这个布局，最后调用LinearLayout的addView()方法将它添加到LinearLayout中。\n现在可以运行一下程序，结果如下图所示：\nButton在界面上显示出来了！说明我们确实是借助LayoutInflater成功将button_layout这个布局添加到LinearLayout中了。LayoutInflater技术广泛应用于需要动态添加View的时候，比如在ScrollView和ListView中，经常都可以看到LayoutInflater的身影。\n当然，仅仅只是介绍了如何使用LayoutInflater显然是远远无法满足大家的求知欲的，知其然也要知其所以然，接下来我们就从源码的角度上看一看LayoutInflater到底是如何工作的。\n不管你是使用的哪个inflate()方法的重载，最终都会辗转调用到LayoutInflater的如下代码中：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View inflate(XmlPullParser parser, ViewGroup root, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; attachToRoot) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; (mConstructorArgs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; AttributeSet attrs = Xml.asAttributeSet(parser); - mConstructorArgs[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;] = mContext; - View result = root; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; type; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt; ((type = parser.next()) != XmlPullParser.START_TAG \u0026amp;\u0026amp; - type != XmlPullParser.END_DOCUMENT) { - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (type != XmlPullParser.START_TAG) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throw\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; InflateException(parser.getPositionDescription() - + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;: No start tag found!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String name = parser.getName(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (TAG_MERGE.equals(name)) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (root == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || !attachToRoot) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throw\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; InflateException(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;merge can be used only with a valid \u0026amp;#8220;\u0026lt;/span\u0026gt; - + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;ViewGroup root and attachToRoot=true\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - rInflate(parser, root, attrs); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - View temp = createViewFromTag(name, attrs); - ViewGroup.LayoutParams params = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (root != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - params = root.generateLayoutParams(attrs); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!attachToRoot) { - temp.setLayoutParams(params); - } - } - rInflate(parser, temp, attrs); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (root != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; attachToRoot) { - root.addView(temp, params); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (root == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || !attachToRoot) { - result = temp; - } - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (XmlPullParserException e) { - InflateException ex = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; InflateException(e.getMessage()); - ex.initCause(e); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throw\u0026lt;/span\u0026gt; ex; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) { - InflateException ex = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; InflateException( - parser.getPositionDescription() - + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;: \u0026amp;#8220;\u0026lt;/span\u0026gt; + e.getMessage()); - ex.initCause(e); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throw\u0026lt;/span\u0026gt; ex; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; result; - } - } 从这里我们就可以清楚地看出，LayoutInflater其实就是使用Android提供的pull解析方式来解析布局文件的。不熟悉pull解析方式的朋友可以网上搜一下，教程很多，我就不细讲了，这里我们注意看下第23行，调用了createViewFromTag()这个方法，并把节点名和参数传了进去。看到这个方法名，我们就应该能猜到，它是用于根据节点名来创建View对象的。确实如此，在createViewFromTag()方法的内部又会去调用createView()方法，然后使用反射的方式创建出View的实例并返回。\n当然，这里只是创建出了一个根布局的实例而已，接下来会在第31行调用rInflate()方法来循环遍历这个根布局下的子元素，代码如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; rInflate(XmlPullParser parser, View parent, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; AttributeSet attrs) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; XmlPullParserException, IOException { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; depth = parser.getDepth(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; type; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt; (((type = parser.next()) != XmlPullParser.END_TAG || - parser.getDepth() \u0026gt; depth) \u0026amp;\u0026amp; type != XmlPullParser.END_DOCUMENT) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (type != XmlPullParser.START_TAG) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;continue\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String name = parser.getName(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (TAG_REQUEST_FOCUS.equals(name)) { - parseRequestFocus(parser, parent); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (TAG_INCLUDE.equals(name)) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (parser.getDepth() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throw\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; InflateException(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;include /\u0026gt; cannot be the root element\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - parseInclude(parser, parent, attrs); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (TAG_MERGE.equals(name)) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throw\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; InflateException(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026lt;merge /\u0026gt; must be the root element\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View view = createViewFromTag(name, attrs); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; ViewGroup viewGroup = (ViewGroup) parent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs); - rInflate(parser, view, attrs); - viewGroup.addView(view, params); - } - } - parent.onFinishInflate(); - } 可以看到，在第21行同样是createViewFromTag()方法来创建View的实例，然后还会在第24行递归调用rInflate()方法来查找这个View下的子元素，每次递归完成后则将这个View添加到父布局当中。\n这样的话，把整个布局文件都解析完成后就形成了一个完整的DOM结构，最终会把最顶层的根布局返回，至此inflate()过程全部结束。\n比较细心的朋友也许会注意到，inflate()方法还有个接收三个参数的方法重载，结构如下：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - inflate(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; resource, ViewGroup root, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; attachToRoot) 那么这第三个参数attachToRoot又是什么意思呢？其实如果你仔细去阅读上面的源码应该可以自己分析出答案，这里我先将结论说一下吧，感兴趣的朋友可以再阅读一下源码，校验我的结论是否正确。\n如果root为null，attachToRoot将失去作用，设置任何值都没有意义。\n如果root不为null，attachToRoot设为true，则会在加载的布局文件的最外层再嵌套一层root布局。\n如果root不为null，attachToRoot设为false，则root参数失去作用。\n在不设置attachToRoot参数的情况下，如果root不为null，attachToRoot参数默认为true。\n好了，现在对LayoutInflater的工作原理和流程也搞清楚了，你该满足了吧。额。。。。还嫌这个例子中的按钮看起来有点小，想要调大一些？那简单的呀，修改button_layout.xml中的代码，如下所示：\n**[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_10\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_10\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;300dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;80dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;Button\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 这里我们将按钮的宽度改成300dp，高度改成80dp，这样够大了吧？现在重新运行一下程序来观察效果。咦？怎么按钮还是原来的大小，没有任何变化！是不是按钮仍然不够大，再改大一点呢？还是没有用！\n其实这里不管你将Button的layout_width和layout_height的值修改成多少，都不会有任何效果的，因为这两个值现在已经完全失去了作用。平时我们经常使用layout_width和layout_height来设置View的大小，并且一直都能正常工作，就好像这两个属性确实是用于设置View的大小的。而实际上则不然，它们其实是用于设置View在布局中的大小的，也就是说，首先View必须存在于一个布局中，之后如果将layout_width设置成match_parent表示让View的宽度填充满布局，如果设置成wrap_content表示让View的宽度刚好可以包含其内容，如果设置成具体的数值则View的宽度会变成相应的数值。这也是为什么这两个属性叫作layout_width和layout_height，而不是width和height。\n再来看一下我们的button_layout.xml吧，很明显Button这个控件目前不存在于任何布局当中，所以layout_width和layout_height这两个属性理所当然没有任何作用。那么怎样修改才能让按钮的大小改变呢？解决方法其实有很多种，最简单的方式就是在Button的外面再嵌套一层布局，如下所示：\n**[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_11\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_11\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;300dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;80dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;Button\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 可以看到，这里我们又加入了一个RelativeLayout，此时的Button存在与RelativeLayout之中，layout_width和layout_height属性也就有作用了。当然，处于最外层的RelativeLayout，它的layout_width和layout_height则会失去作用。现在重新运行一下程序，结果如下图所示：\nOK！按钮的终于可以变大了，这下总算是满足大家的要求了吧。\n看到这里，也许有些朋友心中会有一个巨大的疑惑。不对呀！平时在Activity中指定布局文件的时候，最外层的那个布局是可以指定大小的呀，layout_width和layout_height都是有作用的。确实，这主要是因为，在setContentView()方法中，Android会自动在布局文件的最外层再嵌套一个FrameLayout，所以layout_width和layout_height属性才会有效果。那么我们来证实一下吧，修改MainActivity中的代码，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_12\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_12\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LinearLayout mainLayout; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - mainLayout = (LinearLayout) findViewById(R.id.main_layout); - ViewParent viewParent = mainLayout.getParent(); - Log.d(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;TAG\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;the parent of mainLayout is \u0026amp;#8220;\u0026lt;/span\u0026gt; + viewParent); - } - - } 可以看到，这里通过findViewById()方法，拿到了activity_main布局中最外层的LinearLayout对象，然后调用它的getParent()方法获取它的父布局，再通过Log打印出来。现在重新运行一下程序，结果如下图所示：\n非常正确！LinearLayout的父布局确实是一个FrameLayout，而这个FrameLayout就是由系统自动帮我们添加上的。\n说到这里，虽然setContentView()方法大家都会用，但实际上Android界面显示的原理要比我们所看到的东西复杂得多。任何一个Activity中显示的界面其实主要都由两部分组成，标题栏和内容布局。标题栏就是在很多界面顶部显示的那部分内容，比如刚刚我们的那个例子当中就有标题栏，可以在代码中控制让它是否显示。而内容布局就是一个FrameLayout，这个布局的id叫作content，我们调用setContentView()方法时所传入的布局其实就是放到这个FrameLayout中的，这也是为什么这个方法名叫作setContentView()，而不是叫setView()。\n最后再附上一张Activity窗口的组成图吧，以便于大家更加直观地理解：\n相信每个Android程序员都知道，我们每天的开发工作当中都在不停地跟View打交道，Android中的任何一个布局、任何一个控件其实都是直接或间接继承自View的，如TextView、Button、ImageView、ListView等。这些控件虽然是Android系统本身就提供好的，我们只需要拿过来使用就可以了，但你知道它们是怎样被绘制到屏幕上的吗？多知道一些总是没有坏处的，那么我们赶快进入到本篇文章的正题内容吧。\n要知道，任何一个视图都不可能凭空突然出现在屏幕上，它们都是要经过非常科学的绘制流程后才能显示出来的。每一个视图的绘制过程都必须经历三个最主要的阶段，即onMeasure()、onLayout()和onDraw()，下面我们逐个对这三个阶段展开进行探讨。\n一. onMeasure() measure是测量的意思，那么onMeasure()方法顾名思义就是用于测量视图的大小的。View系统的绘制流程会从ViewRoot的performTraversals()方法中开始，在其内部调用View的measure()方法。measure()方法接收两个参数，widthMeasureSpec和heightMeasureSpec，这两个值分别用于确定视图的宽度和高度的规格和大小。\nMeasureSpec的值由specSize和specMode共同组成的，其中specSize记录的是大小，specMode记录的是规格。specMode一共有三种类型，如下所示：\nEXACTLY 表示父视图希望子视图的大小应该是由specSize的值来决定的，系统默认会按照这个规则来设置子视图的大小，开发人员当然也可以按照自己的意愿设置成任意的大小。\nAT_MOST 表示子视图最多只能是specSize中指定的大小，开发人员应该尽可能小得去设置这个视图，并且保证不会超过specSize。系统默认会按照这个规则来设置子视图的大小，开发人员当然也可以按照自己的意愿设置成任意的大小。\nUNSPECIFIED 表示开发人员可以将视图按照自己的意愿设置成任意的大小，没有任何限制。这种情况比较少见，不太会用到。\n那么你可能会有疑问了，widthMeasureSpec和heightMeasureSpec这两个值又是从哪里得到的呢？通常情况下，这两个值都是由父视图经过计算后传递给子视图的，说明父视图会在一定程度上决定子视图的大小。但是最外层的根视图，它的widthMeasureSpec和heightMeasureSpec又是从哪里得到的呢？这就需要去分析ViewRoot中的源码了，观察performTraversals()方法可以发现如下代码：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width); - childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); 可以看到，这里调用了getRootMeasureSpec()方法去获取widthMeasureSpec和heightMeasureSpec的值，注意方法中传入的参数，其中lp.width和lp.height在创建ViewGroup实例的时候就被赋值了，它们都等于MATCH_PARENT。然后看下getRootMeasureSpec()方法中的代码，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getRootMeasureSpec(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; windowSize, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; rootDimension) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; measureSpec; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (rootDimension) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; ViewGroup.LayoutParams.MATCH_PARENT: - measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; ViewGroup.LayoutParams.WRAP_CONTENT: - measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; measureSpec; - } 可以看到，这里使用了MeasureSpec.makeMeasureSpec()方法来组装一个MeasureSpec，当rootDimension参数等于MATCH_PARENT的时候，MeasureSpec的specMode就等于EXACTLY，当rootDimension等于WRAP_CONTENT的时候，MeasureSpec的specMode就等于AT_MOST。并且MATCH_PARENT和WRAP_CONTENT时的specSize都是等于windowSize的，也就意味着根视图总是会充满全屏的。\n介绍了这么多MeasureSpec相关的内容，接下来我们看下View的measure()方法里面的代码吧，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; measure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((mPrivateFlags \u0026amp; FORCE_LAYOUT) == FORCE_LAYOUT || - widthMeasureSpec != mOldWidthMeasureSpec || - heightMeasureSpec != mOldHeightMeasureSpec) { - mPrivateFlags \u0026amp;= ~MEASURED_DIMENSION_SET; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (ViewDebug.TRACE_HIERARCHY) { - ViewDebug.trace(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, ViewDebug.HierarchyTraceType.ON_MEASURE); - } - onMeasure(widthMeasureSpec, heightMeasureSpec); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((mPrivateFlags \u0026amp; MEASURED_DIMENSION_SET) != MEASURED_DIMENSION_SET) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throw\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; IllegalStateException(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onMeasure() did not set the\u0026amp;#8221;\u0026lt;/span\u0026gt; - + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; measured dimension by calling\u0026amp;#8221;\u0026lt;/span\u0026gt; - + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; setMeasuredDimension()\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - mPrivateFlags |= LAYOUT_REQUIRED; - } - mOldWidthMeasureSpec = widthMeasureSpec; - mOldHeightMeasureSpec = heightMeasureSpec; - } 注意观察，measure()这个方法是final的，因此我们无法在子类中去重写这个方法，说明Android是不允许我们改变View的measure框架的。然后在第9行调用了onMeasure()方法，这里才是真正去测量并设置View大小的地方，默认会调用getDefaultSize()方法来获取视图的大小，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getDefaultSize(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; size, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; measureSpec) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; result = size; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; specMode = MeasureSpec.getMode(measureSpec); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; specSize = MeasureSpec.getSize(measureSpec); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (specMode) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MeasureSpec.UNSPECIFIED: - result = size; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MeasureSpec.AT_MOST: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MeasureSpec.EXACTLY: - result = specSize; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; result; - } 这里传入的measureSpec是一直从measure()方法中传递过来的。然后调用MeasureSpec.getMode()方法可以解析出specMode，调用MeasureSpec.getSize()方法可以解析出specSize。接下来进行判断，如果specMode等于AT_MOST或EXACTLY就返回specSize，这也是系统默认的行为。之后会在onMeasure()方法中调用setMeasuredDimension()方法来设定测量出的大小，这样一次measure过程就结束了。\n当然，一个界面的展示可能会涉及到很多次的measure，因为一个布局中一般都会包含多个子视图，每个视图都需要经历一次measure过程。ViewGroup中定义了一个measureChildren()方法来去测量子视图的大小，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; measureChildren(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; size = mChildrenCount; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View[] children = mChildren; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; size; ++i) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View child = children[i]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((child.mViewFlags \u0026amp; VISIBILITY_MASK) != GONE) { - measureChild(child, widthMeasureSpec, heightMeasureSpec); - } - } - } 这里首先会去遍历当前布局下的所有子视图，然后逐个调用measureChild()方法来测量相应子视图的大小，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; measureChild(View child, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; parentWidthMeasureSpec, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; parentHeightMeasureSpec) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; LayoutParams lp = child.getLayoutParams(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, - mPaddingLeft + mPaddingRight, lp.width); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, - mPaddingTop + mPaddingBottom, lp.height); - child.measure(childWidthMeasureSpec, childHeightMeasureSpec); - } 可以看到，在第4行和第6行分别调用了getChildMeasureSpec()方法来去计算子视图的MeasureSpec，计算的依据就是布局文件中定义的MATCH_PARENT、WRAP_CONTENT等值，这个方法的内部细节就不再贴出。然后在第8行调用子视图的measure()方法，并把计算出的MeasureSpec传递进去，之后的流程就和前面所介绍的一样了。\n当然，onMeasure()方法是可以重写的，也就是说，如果你不想使用系统默认的测量方式，可以按照自己的意愿进行定制，比如：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; View { - - \u0026amp;#8230;\u0026amp;#8230; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) { - setMeasuredDimension(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;); - } - - } 这样的话就把View默认的测量流程覆盖掉了，不管在布局文件中定义MyView这个视图的大小是多少，最终在界面上显示的大小都将会是200*200。\n需要注意的是，在setMeasuredDimension()方法调用之后，我们才能使用getMeasuredWidth()和getMeasuredHeight()来获取视图测量出的宽高，以此之前调用这两个方法得到的值都会是0。\n由此可见，视图大小的控制是由父视图、布局文件、以及视图本身共同完成的，父视图会提供给子视图参考的大小，而开发人员可以在XML文件中指定视图的大小，然后视图本身会对最终的大小进行拍板。\n到此为止，我们就把视图绘制流程的第一阶段分析完了。\n二. onLayout() measure过程结束后，视图的大小就已经测量好了，接下来就是layout的过程了。正如其名字所描述的一样，这个方法是用于给视图进行布局的，也就是确定视图的位置。ViewRoot的performTraversals()方法会在measure结束后继续执行，并调用View的layout()方法来执行此过程，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - host.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, host.mMeasuredWidth, host.mMeasuredHeight); layout()方法接收四个参数，分别代表着左、上、右、下的坐标，当然这个坐标是相对于当前视图的父视图而言的。可以看到，这里还把刚才测量出的宽度和高度传到了layout()方法中。那么我们来看下layout()方法中的代码是什么样的吧，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; layout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldL = mLeft; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldT = mTop; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldB = mBottom; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldR = mRight; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed = setFrame(l, t, r, b); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (changed || (mPrivateFlags \u0026amp; LAYOUT_REQUIRED) == LAYOUT_REQUIRED) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (ViewDebug.TRACE_HIERARCHY) { - ViewDebug.trace(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, ViewDebug.HierarchyTraceType.ON_LAYOUT); - } - onLayout(changed, l, t, r, b); - mPrivateFlags \u0026amp;= ~LAYOUT_REQUIRED; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mOnLayoutChangeListeners != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - ArrayList\u0026lt;OnLayoutChangeListener\u0026gt; listenersCopy = - (ArrayList\u0026lt;OnLayoutChangeListener\u0026gt;) mOnLayoutChangeListeners.clone(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; numListeners = listenersCopy.size(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; numListeners; ++i) { - listenersCopy.get(i).onLayoutChange(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, l, t, r, b, oldL, oldT, oldR, oldB); - } - } - } - mPrivateFlags \u0026amp;= ~FORCE_LAYOUT; - } 在layout()方法中，首先会调用setFrame()方法来判断视图的大小是否发生过变化，以确定有没有必要对当前的视图进行重绘，同时还会在这里把传递过来的四个参数分别赋值给mLeft、mTop、mRight和mBottom这几个变量。接下来会在第11行调用onLayout()方法，正如onMeasure()方法中的默认行为一样，也许你已经迫不及待地想知道onLayout()方法中的默认行为是什么样的了。进入onLayout()方法，咦？怎么这是个空方法，一行代码都没有？！\n没错，View中的onLayout()方法就是一个空方法，因为onLayout()过程是为了确定视图在布局中所在的位置，而这个操作应该是由布局来完成的，即父视图决定子视图的显示位置。既然如此，我们来看下ViewGroup中的onLayout()方法是怎么写的吧，代码如下：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_10\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_10\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b); 可以看到，ViewGroup中的onLayout()方法竟然是一个抽象方法，这就意味着所有ViewGroup的子类都必须重写这个方法。没错，像LinearLayout、RelativeLayout等布局，都是重写了这个方法，然后在内部按照各自的规则对子视图进行布局的。由于LinearLayout和RelativeLayout的布局规则都比较复杂，就不单独拿出来进行分析了，这里我们尝试自定义一个布局，借此来更深刻地理解onLayout()的过程。\n自定义的这个布局目标很简单，只要能够包含一个子视图，并且让子视图正常显示出来就可以了。那么就给这个布局起名叫做SimpleLayout吧，代码如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_11\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_11\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SimpleLayout \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ViewGroup { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SimpleLayout(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMeasure(widthMeasureSpec, heightMeasureSpec); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getChildCount() \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - View childView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - measureChild(childView, widthMeasureSpec, heightMeasureSpec); - } - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getChildCount() \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - View childView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - childView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, childView.getMeasuredWidth(), childView.getMeasuredHeight()); - } - } - - } 代码非常的简单，我们来看下具体的逻辑吧。你已经知道，onMeasure()方法会在onLayout()方法之前调用，因此这里在onMeasure()方法中判断SimpleLayout中是否有包含一个子视图，如果有的话就调用measureChild()方法来测量出子视图的大小。\n接着在onLayout()方法中同样判断SimpleLayout是否有包含一个子视图，然后调用这个子视图的layout()方法来确定它在SimpleLayout布局中的位置，这里传入的四个参数依次是0、0、childView.getMeasuredWidth()和childView.getMeasuredHeight()，分别代表着子视图在SimpleLayout中左上右下四个点的坐标。其中，调用childView.getMeasuredWidth()和childView.getMeasuredHeight()方法得到的值就是在onMeasure()方法中测量出的宽和高。\n这样就已经把SimpleLayout这个布局定义好了，下面就是在XML文件中使用它了，如下所示：\n**[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_12\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_12\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.viewtest.SimpleLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_launcher\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.viewtest.SimpleLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 可以看到，我们能够像使用普通的布局文件一样使用SimpleLayout，只是注意它只能包含一个子视图，多余的子视图会被舍弃掉。这里SimpleLayout中包含了一个ImageView，并且ImageView的宽高都是wrap_content。现在运行一下程序，结果如下图所示：\nOK！ImageView成功已经显示出来了，并且显示的位置也正是我们所期望的。如果你想改变ImageView显示的位置，只需要改变childView.layout()方法的四个参数就行了。\n在onLayout()过程结束后，我们就可以调用getWidth()方法和getHeight()方法来获取视图的宽高了。说到这里，我相信很多朋友长久以来都会有一个疑问，getWidth()方法和getMeasureWidth()方法到底有什么区别呢？它们的值好像永远都是相同的。其实它们的值之所以会相同基本都是因为布局设计者的编码习惯非常好，实际上它们之间的差别还是挺大的。\n首先getMeasureWidth()方法在measure()过程结束后就可以获取到了，而getWidth()方法要在layout()过程结束后才能获取到。另外，getMeasureWidth()方法中的值是通过setMeasuredDimension()方法来进行设置的，而getWidth()方法中的值则是通过视图右边的坐标减去左边的坐标计算出来的。\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_13\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_13\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getChildCount() \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - View childView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - childView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;); - } - } 到此为止，我们把视图绘制流程的第二阶段也分析完了。\n三. onDraw() measure和layout的过程都结束后，接下来就进入到draw的过程了。同样，根据名字你就能够判断出，在这里才真正地开始对视图进行绘制。ViewRoot中的代码会继续执行并创建出一个Canvas对象，然后调用View的draw()方法来执行具体的绘制工作。draw()方法内部的绘制过程总共可以分为六步，其中第二步和第五步在一般情况下很少用到，因此这里我们只分析简化后的绘制过程。代码如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_14\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_14\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; draw(Canvas canvas) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (ViewDebug.TRACE_HIERARCHY) { - ViewDebug.trace(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, ViewDebug.HierarchyTraceType.DRAW); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; privateFlags = mPrivateFlags; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dirtyOpaque = (privateFlags \u0026amp; DIRTY_MASK) == DIRTY_OPAQUE \u0026amp;\u0026amp; - (mAttachInfo == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || !mAttachInfo.mIgnoreDirtyState); - mPrivateFlags = (privateFlags \u0026amp; ~DIRTY_MASK) | DRAWN; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Step 1, draw the background, if needed\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; saveCount; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!dirtyOpaque) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Drawable background = mBGDrawable; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (background != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollX = mScrollX; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollY = mScrollY; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mBackgroundSizeChanged) { - mBackgroundSizeChanged = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((scrollX | scrollY) == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - background.draw(canvas); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - canvas.translate(scrollX, scrollY); - background.draw(canvas); - canvas.translate(-scrollX, -scrollY); - } - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewFlags = mViewFlags; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; horizontalEdges = (viewFlags \u0026amp; FADING_EDGE_HORIZONTAL) != \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; verticalEdges = (viewFlags \u0026amp; FADING_EDGE_VERTICAL) != \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!verticalEdges \u0026amp;\u0026amp; !horizontalEdges) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Step 3, draw the content\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!dirtyOpaque) onDraw(canvas); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Step 4, draw the children\u0026lt;/span\u0026gt; - dispatchDraw(canvas); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Step 6, draw decorations (scrollbars)\u0026lt;/span\u0026gt; - onDrawScrollBars(canvas); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// we\u0026amp;#8217;re done\u0026amp;#8230;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - } - } 可以看到，第一步是从第9行代码开始的，这一步的作用是对视图的背景进行绘制。这里会先得到一个mBGDrawable对象，然后根据layout过程确定的视图位置来设置背景的绘制区域，之后再调用Drawable的draw()方法来完成背景的绘制工作。那么这个mBGDrawable对象是从哪里来的呢？其实就是在XML中通过android:background属性设置的图片或颜色。当然你也可以在代码中通过setBackgroundColor()、setBackgroundResource()等方法进行赋值。\n接下来的第三步是在第34行执行的，这一步的作用是对视图的内容进行绘制。可以看到，这里去调用了一下onDraw()方法，那么onDraw()方法里又写了什么代码呢？进去一看你会发现，原来又是个空方法啊。其实也可以理解，因为每个视图的内容部分肯定都是各不相同的，这部分的功能交给子类来去实现也是理所当然的。\n第三步完成之后紧接着会执行第四步，这一步的作用是对当前视图的所有子视图进行绘制。但如果当前的视图没有子视图，那么也就不需要进行绘制了。因此你会发现View中的dispatchDraw()方法又是一个空方法，而ViewGroup的dispatchDraw()方法中就会有具体的绘制代码。\n以上都执行完后就会进入到第六步，也是最后一步，这一步的作用是对视图的滚动条进行绘制。那么你可能会奇怪，当前的视图又不一定是ListView或者ScrollView，为什么要绘制滚动条呢？其实不管是Button也好，TextView也好，任何一个视图都是有滚动条的，只是一般情况下我们都没有让它显示出来而已。绘制滚动条的代码逻辑也比较复杂，这里就不再贴出来了，因为我们的重点是第三步过程。\n通过以上流程分析，相信大家已经知道，View是不会帮我们绘制内容部分的，因此需要每个视图根据想要展示的内容来自行绘制。如果你去观察TextView、ImageView等类的源码，你会发现它们都有重写onDraw()这个方法，并且在里面执行了相当不少的绘制逻辑。绘制的方式主要是借助Canvas这个类，它会作为参数传入到onDraw()方法中，供给每个视图使用。Canvas这个类的用法非常丰富，基本可以把它当成一块画布，在上面绘制任意的东西，那么我们就来尝试一下吧。\n这里简单起见，我只是创建一个非常简单的视图，并且用Canvas随便绘制了一点东西，代码如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_15\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; View { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Paint mPaint; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyView(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - mPaint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(Paint.ANTI_ALIAS_FLAG); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) { - mPaint.setColor(Color.YELLOW); - canvas.drawRect(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, getWidth(), getHeight(), mPaint); - mPaint.setColor(Color.BLUE); - mPaint.setTextSize(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;); - String text = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Hello View\u0026amp;#8221;\u0026lt;/span\u0026gt;; - canvas.drawText(text, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, getHeight() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, mPaint); - } - } 可以看到，我们创建了一个自定义的MyView继承自View，并在MyView的构造函数中创建了一个Paint对象。Paint就像是一个画笔一样，配合着Canvas就可以进行绘制了。这里我们的绘制逻辑比较简单，在onDraw()方法中先是把画笔设置成黄色，然后调用Canvas的drawRect()方法绘制一个矩形。然后在把画笔设置成蓝色，并调整了一下文字的大小，然后调用drawText()方法绘制了一段文字。\n就这么简单，一个自定义的视图就已经写好了，现在可以在XML中加入这个视图，如下所示：\n**[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/16330267#)[copy](http://blog.csdn.net/guolin_blog/article/details/16330267#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/128167)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/128167/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_16\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_16\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.viewtest.MyView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;200dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;100dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 将MyView的宽度设置成200dp，高度设置成100dp，然后运行一下程序，结果如下图所示：\n图中显示的内容也正是MyView这个视图的内容部分了。由于我们没给MyView设置背景，因此这里看不出来View自动绘制的背景效果。\n当然了Canvas的用法还有很多很多，这里我不可能把Canvas的所有用法都列举出来，剩下的就要靠大家自行去研究和学习了。\n","permalink":"https://blog.zdltech.com/posts/android-layoutinflater%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90%E5%B8%A6%E4%BD%A0%E4%B8%80%E6%AD%A5%E6%AD%A5%E6%B7%B1%E5%85%A5%E4%BA%86%E8%A7%A3view%E4%B8%80/","summary":"\u003cp\u003e转载：\u003ca href=\"http://blog.csdn.net/guolin_blog/article/details/12921889\"\u003ehttp://blog.csdn.net/guolin_blog/article/details/12921889\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e有段时间没写博客了，感觉都有些生疏了呢。最近繁忙的工作终于告一段落，又有时间写文章了，接下来还会继续坚持每一周篇的节奏。\u003c/p\u003e\n\u003cp\u003e有不少朋友跟我反应，都希望我可以写一篇关于View的文章，讲一讲View的工作原理以及自定义View的方法。没错，承诺过的文章我是一定要兑现的，而且在View这个话题上我还准备多写几篇，尽量能将这个知识点讲得透彻一些。那么今天就从LayoutInflater开始讲起吧。\u003c/p\u003e\n\u003cp\u003e相信接触Android久一点的朋友对于LayoutInflater一定不会陌生，都会知道它主要是用于加载布局的。而刚接触Android的朋友可能对LayoutInflater不怎么熟悉，因为加载布局的任务通常都是在Activity中调用setContentView()方法来完成的。其实setContentView()方法的内部也是使用LayoutInflater来加载布局的，只不过这部分源码是internal的，不太容易查看到。那么今天我们就来把LayoutInflater的工作流程仔细地剖析一遍，也许还能解决掉某些困扰你心头多年的疑惑。\u003c/p\u003e\n\u003cp\u003e先来看一下LayoutInflater的基本用法吧，它的用法非常简单，首先需要获取到LayoutInflater的实例，有两种方法可以获取到，第一种写法如下：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- LayoutInflater layoutInflater = LayoutInflater.from(context);\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e当然，还有另外一种写法也可以完成同样的效果：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- LayoutInflater layoutInflater = (LayoutInflater) context\n\n- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e其实第一种就是第二种的简单写法，只是Android给我们做了一下封装而已。得到了LayoutInflater的实例之后就可以调用它的inflate()方法来加载布局了，如下所示：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/12921889#)[copy](http://blog.csdn.net/guolin_blog/article/details/12921889#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/118597)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/118597/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- layoutInflater.inflate(resourceId, root);\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003einflate()方法一般接收两个参数，第一个参数就是要加载的布局id，第二个参数是指给该布局的外部再嵌套一层父布局，如果不需要就直接传null。这样就成功成功创建了一个布局的实例，之后再将它添加到指定的位置就可以显示出来了。\u003c/p\u003e","title":"Android LayoutInflater原理分析，带你一步步深入了解View(一)"},{"content":"AndroidDevTools\nGoogle Android官方教程 Android Training Course in Chinese\nAndroid基础 上面可能是一个比较全面系统的培训教程，对于新手们可能对某些需要着重掌握的东西比较迷茫，于是整理下个人认为新手们必须要掌握的知识点，顺便也会附带相应觉得不错的讲解博客地址。\n两分钟彻底让你明白Android Activity生命周期(图文)! Activity实际开发中使用频率最高，这个必须要理解\nAndroid四大基本组件介绍与生命周期 Android中的四大组件必须得知道，也是面试常问到的\nListView的基本使用与优化 ListView是所有控件中最常使用且对新手来说比较复杂的用法，各种Adapter的使用以及ListView的优化都是必须掌握的\nAndroid系统用于Activity的标准Intent Intent解决了Android中四大组件的通讯，非常有用，这篇博客收集整理了系统的标准Intent\nAndroid 屏幕适配 介绍一些Android屏幕适配的基础\nAndroid中SQLite应用详解 Android中的SQLite需要掌握，这篇博客很适合新手\nAndroid Fragment完全解析 3.0之后新加的Fragment，必须要掌握，目前使用的场景也是越来越普遍了\nAndroid中级 Android应用程序的生命周期 Android的应用程序的生命周期需要理解，面试也是经常会被问的\n带你一步步深入了解View View做为UI开发中最常用到的，必须要深入理解\nAndroid Service完全解析 Service作为Android四大组件之一，在每一个应用程序中都扮演着非常重要的角色\nAndroid Gson 目前比较常用比较流行的数据格式就是json了，这篇博客教你如何使用Google Gson库来进行json解析\nAndroid 布局优化 Android开发中经常会用到xml布局，那么布局优化方面的知识更是需要掌握的了\nAndroid中Intent传递对象的两种方法(Serializable,Parcelable) 详细讲解了Android中Intent中如何传递对象\nAndroid异步消息处理机制完全解析 Android开发中异步操作是经常使用的，必须理解掌握\nAndroid AsyncTask完全解析 Android异步操作的另一种方法\nAndroid Custom Loading 很早的一个小demo，教你如何做一个App的Loading动画\nAndroid进阶 Android Gradle Google官方Android新的构建系统，可以很方便的管理依赖、编译打包等\nAndroid 性能优化 一系列的性能调优教程，让你的代码以及App更畅通！\n一个完整的开源项目–9GAG 一个开源客户端，教你使用Studio、Gradle以及一些流行的开源库快速开发一个不错的Android客户端\n整理的Android开发资源 自己整理的一些Android开发资源，包括开发、工具、设计等，相信会对你有用的\nAndroid设计 在开发一款Android App之前，你需要了解下Android平台的设计规范，这里有一系列关于Android Design的讲解以及Google最新推出的Material Design中文翻译版\nAndroid Design Material Design Android兼容库 在了解了设计规范准备着手开发你的App时，你还需要考虑你的App支持的版本，如果是全新的App，从目前的市场份额来看，建议直接支持4.0+，虽然2.3的份额仍然有一部分，但是这部分真正用来使用App的人又能有多少呢。当然如果你的公司必须要求支持2.x的版本，那么也不用担心，下面整理了几个满足你适配的一些兼容库:\nActionBarSherlock 大神JakeWharton的一个ActionBar的兼容库，支持在2.x版本使用ActionBar\nActionBar Compact 在这之前使用ActionBar基本都会使用上述JakeWharton的兼容库，但是目前Google有了自己的一套ActionBar兼容库，推荐使用ActionBar Compact，具体介绍及使用方法详见我的这篇博客\nNineOldAndroids Android 3.0之前开放的一些新的动画api–Property Animation，大神JakeWharton的又一大作，可以让你在2.x版本的sdk可以使用属性动画.\nAndroid Support V4 如果需要兼容2.x的版本，在使用如下类的时候你需要使用v4包下的，如Fragment, FragmentManager, FragmentActivity, FragmentPagerAdapter, CursorLoader, LoaderManager, AsyncTaskLoader\n当然v4包下面除了以上还有一些新的控件你必须知道\nNavigation Drawer(导航抽屉)\n在这之前在Android上实现一个抽屉导航你可能会用到SlidingMenu开源库，如今你可以使用官方的DrawerLayout控件很容易实现\nSlidingPaneLayout\nSlidingPaneLayout是V4包中新添加的组件，可以实现两列面板的切换, 具体使用与效果见博客链接\nSwipeRefreshLayout\nSwipeRefreshLayout是Google在support v4 19.1版本的library更新的一个下拉刷新组件,使用起来很方便,可以很方便的实现Google Now的效果\nAndroid开发必知的一些开源库 说到开源库就不得不提GitHub，只能说是目前最活跃的开源社区，不知道的赶紧去注册个账号使用起来，绝对是你快速提升技术的利器。\nVolley App开发中免不了要和服务端进行交互，而volley是Google官方推出的一个开源的网络通信库，它能使网络通信更简单，更快速。\nVolley完全解析 Android volley sample ActiveAndroid ActiveAndroid算是一个轻量级的ORM(对象关系映射(Object Relation Mapping))框架，简单地通过如save()和delete()等方法来做到增删改查等操作。\nActiveAndroid–Android轻量级ORM框架 Retrofit Retrofit和Java领域的ORM概念类似， ORM把结构化数据转换为Java对象，而Retrofit 把REST API返回的数据转化为Java对象方便操作。同时还封装了网络代码的调用。\nRetrofit – Java(Android) 的REST 接口封装类库 Android-Universal-Image-Loader Android-Universal-Image-Loader是一个强大的开源图片异步加载库，该项目的目的是提供一个可重复使用的仪器为异步图像加载，缓存和显示。\nAndroid-Universal-Image-Loader Android开源项目分类汇总 非常全面的GitHub开源项目汇总，不需要重复发明轮子，尽情遨游在开源世界里吧\nAndroid网址或Blog Android官网 身为Android开发者不知道这个网站就太说不过去了，上面有你任何你需要的东西\nAndroid Developers Blog Android官网博客, 在上面可以关注Android最新的进展与最权威的博客(须翻墙)\nAndroid开源项目汇总 我的好朋友Trinea整理的非常全面的GitHub开源项目汇总，不需要重复发明轮子，尽情遨游在开源世界里吧\nAndroid的开源库 国外整理的Android开源库汇总，和上面的比起来分类更明确，你总能很方便的找到你需要的开源库\nAndroid Weekly 每周都会有一篇技术博文，介绍新技术、新潮点，可直接邮件订阅，让你时刻紧跟潮流\nAndroid Views 专注Android UI与效果的网站（不过目前貌似已经关站了…）\nAppance Android 也是开源代码合集，很多超赞的效果，不过是多平台的\nAndroidDevTools 翻墙有困难？没关系，这里整理了各种开发工具与SDK等，除此之外还有教程以及设计工具等。\nAndroid Arsenal 国外整理的各种Android开源库、组件。分类整理，瀑布流展示，支持关键字搜索，你值得拥有，强烈推荐！！\n源代码托管 GitHub 身为程序员不知道GitHub的就太out了，可以让你和国际接轨的开源社区，也是目前最活跃的开源社区，免费托管公开代码，不过私有代码是收费的\nBitbucket 如果你不想公开你的源代码，这个是首选，无限免费私有空间，不过我更喜欢开源，所以我更愿意选择GitHub\n开发工具 Eclipse ADT Google帮你集成了一个完整的Android开发环境，包含一个定制的Eclipse + ADT plugin，以及最新的SDK及源码\nAndroid Studio Google最新推出的Android开发工具，个人认为也是Android开发工具的未来，但是不太稳定而且编译依赖Gradle，有一定门槛，新手们或者商业项目中不建议使用。\nUI设计类 Android Design 个人认为遵循Android设计原则的App才能称作是一个好App，所以在开发一个App之前请仔细阅读了解下Android的设计规范\nDribblbe 设计界大名鼎鼎的Dribbble\nAndroid Niceties 比较不错的Android App设计整理\nAndroidAssetStudio 在线生成Android各种图片资源的网站，原作者是原Android Team的成员，为Android的设计做出非常大的贡献\nGraphicBurger 各种扁平化设计资源，你还在为没设计资源而烦恼么？\nGoogle 最近由于各种原因Google在国内访问不了，离开了Google搜索程序员们还怎么干活，在这里贡献两个搜索引擎，本质其实都是Google搜索\nhttp://www.aol.com/ 相当于Google的英文搜索 http://goog.sinaapp.com/ 相当于Google的中文搜索 http://www.gfsoso.com/ 谷粉搜搜 ","permalink":"https://blog.zdltech.com/posts/android%E8%B5%84%E6%BA%90%E6%8E%A8%E8%8D%90/","summary":"\u003cp\u003e\u003ca href=\"http://www.androiddevtools.cn/\"\u003eAndroidDevTools\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"google-android\"\u003eGoogle Android官方教程\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://hukai.me/android-training-course-in-chinese/index.html\"\u003eAndroid Training Course in Chinese\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"android\"\u003eAndroid基础\u003c/h2\u003e\n\u003cp\u003e上面可能是一个比较全面系统的培训教程，对于新手们可能对某些需要着重掌握的东西比较迷茫，于是整理下个人认为新手们必须要掌握的知识点，顺便也会附带相应觉得不错的讲解博客地址。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/android_tutor/article/details/5772285\"\u003e两分钟彻底让你明白Android Activity生命周期(图文)!\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eActivity实际开发中使用频率最高，这个必须要理解\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.cnblogs.com/bravestarrhu/archive/2012/05/02/2479461.html\"\u003eAndroid四大基本组件介绍与生命周期\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAndroid中的四大组件必须得知道，也是面试常问到的\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.cnblogs.com/noTice520/archive/2011/12/05/2276379.html\"\u003eListView的基本使用与优化\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eListView是所有控件中最常使用且对新手来说比较复杂的用法，各种Adapter的使用以及ListView的优化都是必须掌握的\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/zhangjg_blog/article/details/10901293\"\u003eAndroid系统用于Activity的标准Intent\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIntent解决了Android中四大组件的通讯，非常有用，这篇博客收集整理了系统的标准Intent\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://stormzhang.github.io/android/2014/05/16/android-screen-adaptation/\"\u003eAndroid 屏幕适配\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e介绍一些Android屏幕适配的基础\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/liuhe688/article/details/6715983\"\u003eAndroid中SQLite应用详解\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAndroid中的SQLite需要掌握，这篇博客很适合新手\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/guolin_blog/article/details/8881711\"\u003eAndroid Fragment完全解析\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e3.0之后新加的Fragment，必须要掌握，目前使用的场景也是越来越普遍了\u003c/p\u003e\n\u003ch2 id=\"android-1\"\u003eAndroid中级\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/android_tutor/article/details/4952960\"\u003eAndroid应用程序的生命周期\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAndroid的应用程序的生命周期需要理解，面试也是经常会被问的\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/guolin_blog/article/details/12921889\"\u003e带你一步步深入了解View\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eView做为UI开发中最常用到的，必须要深入理解\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/guolin_blog/article/details/11952435\"\u003eAndroid Service完全解析\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eService作为Android四大组件之一，在每一个应用程序中都扮演着非常重要的角色\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://stormzhang.github.io/android/2014/05/22/android-gson/\"\u003eAndroid Gson\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e目前比较常用比较流行的数据格式就是json了，这篇博客教你如何使用Google Gson库来进行json解析\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://stormzhang.github.io/android/2014/04/10/android-optimize-layout/\"\u003eAndroid 布局优化\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAndroid开发中经常会用到xml布局，那么布局优化方面的知识更是需要掌握的了\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/android_tutor/article/details/5740845\"\u003eAndroid中Intent传递对象的两种方法(Serializable,Parcelable)\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e详细讲解了Android中Intent中如何传递对象\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/guolin_blog/article/details/9991569\"\u003eAndroid异步消息处理机制完全解析\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAndroid开发中异步操作是经常使用的，必须理解掌握\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://blog.csdn.net/guolin_blog/article/details/11711405\"\u003eAndroid AsyncTask完全解析\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAndroid异步操作的另一种方法\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://stormzhang.github.io/openandroid/2013/11/15/android-custom-loading/\"\u003eAndroid Custom Loading\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e很早的一个小demo，教你如何做一个App的Loading动画\u003c/p\u003e\n\u003ch2 id=\"android-2\"\u003eAndroid进阶\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://stormzhang.github.io/android/2014/02/28/android-gradle/\"\u003eAndroid Gradle\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eGoogle官方Android新的构建系统，可以很方便的管理依赖、编译打包等\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.trinea.cn/android/android-performance-demo/\"\u003eAndroid 性能优化\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e一系列的性能调优教程，让你的代码以及App更畅通！\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/stormzhang/9GAG\"\u003e一个完整的开源项目–9GAG\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e一个开源客户端，教你使用Studio、Gradle以及一些流行的开源库快速开发一个不错的Android客户端\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://stormzhang.github.io/android/2014/06/05/android-awesome-resources/\"\u003e整理的Android开发资源\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e自己整理的一些Android开发资源，包括开发、工具、设计等，相信会对你有用的\u003c/p\u003e\n\u003ch2 id=\"android-3\"\u003eAndroid设计\u003c/h2\u003e\n\u003cp\u003e在开发一款Android App之前，你需要了解下Android平台的设计规范，这里有一系列关于Android Design的讲解以及Google最新推出的Material Design中文翻译版\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.geekpark.net/tag/Android%20Design\"\u003eAndroid Design\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://design.1sters.com/\"\u003eMaterial Design\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"android-4\"\u003eAndroid兼容库\u003c/h2\u003e\n\u003cp\u003e在了解了设计规范准备着手开发你的App时，你还需要考虑你的App支持的版本，如果是全新的App，从目前的市场份额来看，建议直接支持4.0+，虽然2.3的份额仍然有一部分，但是这部分真正用来使用App的人又能有多少呢。当然如果你的公司必须要求支持2.x的版本，那么也不用担心，下面整理了几个满足你适配的一些兼容库:\u003c/p\u003e","title":"Android资源推荐"},{"content":"/**\n获取当前应用程序的版本号 */\nprivate String getVersion() {\nString st = getResources().getString(R.string.Version_number_is_wrong);\nPackageManager pm = getPackageManager();\ntry {\nPackageInfo packinfo = pm.getPackageInfo(getPackageName(), 0);\nString version = packinfo.versionName;\nreturn version;\n} catch (NameNotFoundException e) {\ne.printStackTrace();\nreturn st;\n}\n}\n设置字符串点击启动指定Activity，部分字体高亮显示 // 创建一个 SpannableString对象 SpannableString sp = \u0026lt;span class=\u0026quot;s1\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SpannableString( \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt; getString(R.string.\u0026lt;/span\u0026gt;activity_frogetpwd_newuserreader_str\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;));\u0026lt;/span\u0026gt; // 设置超链接 \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt; Spanned.\u0026lt;/span\u0026gt;SPAN_EXCLUSIVE_EXCLUSIVE\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; // 设置背景高亮样式一 // sp.setSpan(new BackgroundColorSpan(Color.RED), 17, 19, // Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // 设置高亮样式二 \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt; Spannable.\u0026lt;/span\u0026gt;SPAN_EXCLUSIVE_EXCLUSIVE\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; // // 设置斜体 // sp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD_ITALIC), 27, // 29, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); myTextView.setText(sp); // 设置TextView可点击 myTextView.setMovementMethod(LinkMovementMethod.getInstance()); /** * 自定义URLSpan的点击事件 * * \u0026lt;span class=\u0026quot;s1\u0026quot;\u0026gt;@author\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;jason\u0026lt;/span\u0026gt; * */ \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyURLSpan \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ClickableSpan { \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;mUrl\u0026lt;/span\u0026gt;; MyURLSpan(String url) { \u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;mUrl\u0026lt;/span\u0026gt; = url; } @Override \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View widget) { Toast.makeText(RegisterActivity.\u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;mUrl\u0026lt;/span\u0026gt;, Toast.\u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;LENGTH_LONG\u0026lt;/span\u0026gt;) .show(); widget.setBackgroundColor(Color.parseColor(\u0026lt;span class=\u0026quot;s6\u0026quot;\u0026gt;\u0026amp;#8220;#00000000\u0026amp;#8221;\u0026lt;/span\u0026gt;)); } } ","permalink":"https://blog.zdltech.com/posts/android%E5%B8%B8%E7%94%A8%E6%96%B9%E6%B3%95%E6%94%B6%E9%9B%86/","summary":"\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e获取当前应用程序的版本号\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e*/\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003eprivate\u003c/span\u003e String getVersion() {\u003c/p\u003e\n\u003cp\u003eString st = getResources().getString(R.string.\u003cspan class=\"s3\"\u003eVersion_number_is_wrong\u003c/span\u003e);\u003c/p\u003e\n\u003cp\u003ePackageManager pm = getPackageManager();\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003etry\u003c/span\u003e {\u003c/p\u003e\n\u003cp\u003ePackageInfo packinfo = pm.getPackageInfo(getPackageName(), 0);\u003c/p\u003e\n\u003cp\u003eString version = packinfo.\u003cspan class=\"s3\"\u003eversionName\u003c/span\u003e;\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003ereturn\u003c/span\u003e version;\u003c/p\u003e\n\u003cp\u003e} \u003cspan class=\"s2\"\u003ecatch\u003c/span\u003e (NameNotFoundException e) {\u003c/p\u003e\n\u003cp\u003ee.printStackTrace();\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003ereturn\u003c/span\u003e st;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e设置字符串点击启动指定Activity，部分字体高亮显示\n\n\n\n\n\n// 创建一个 SpannableString对象\n\n\n\n\n\nSpannableString sp = \u0026lt;span class=\u0026quot;s1\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SpannableString(\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt; getString(R.string.\u0026lt;/span\u0026gt;activity_frogetpwd_newuserreader_str\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;));\u0026lt;/span\u0026gt;\n\n\n\n\n\n// 设置超链接\n\n\n\n\n\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt; Spanned.\u0026lt;/span\u0026gt;SPAN_EXCLUSIVE_EXCLUSIVE\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n// 设置背景高亮样式一\n\n\n\n\n\n// sp.setSpan(new BackgroundColorSpan(Color.RED), 17, 19,\n\n\n\n\n\n// Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);\n\n\n\n\n\n// 设置高亮样式二\n\n\n\n\n\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt; Spannable.\u0026lt;/span\u0026gt;SPAN_EXCLUSIVE_EXCLUSIVE\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n// // 设置斜体\n\n\n\n\n\n// sp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD_ITALIC), 27,\n\n\n\n\n\n// 29, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);\n\n\n\n\n\nmyTextView.setText(sp);\n\n\n\n\n\n// 设置TextView可点击\n\n\n\n\n\nmyTextView.setMovementMethod(LinkMovementMethod.getInstance());\n\n\n\n\n\n/**\n\n\n\n\n\n* 自定义URLSpan的点击事件\n\n\n\n\n\n*\n\n\n\n\n\n* \u0026lt;span class=\u0026quot;s1\u0026quot;\u0026gt;@author\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;jason\u0026lt;/span\u0026gt;\n\n\n\n\n\n*\n\n\n\n\n\n*/\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyURLSpan \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ClickableSpan {\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String \u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;mUrl\u0026lt;/span\u0026gt;;\n\n\n\n\n\nMyURLSpan(String url) {\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;mUrl\u0026lt;/span\u0026gt; = url;\n\n\n\n\n\n}\n\n\n\n\n\n@Override\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View widget) {\n\n\n\n\n\nToast.makeText(RegisterActivity.\u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;mUrl\u0026lt;/span\u0026gt;, Toast.\u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;LENGTH_LONG\u0026lt;/span\u0026gt;)\n\n\n\n\n\n.show();\n\n\n\n\n\nwidget.setBackgroundColor(Color.parseColor(\u0026lt;span class=\u0026quot;s6\u0026quot;\u0026gt;\u0026amp;#8220;#00000000\u0026amp;#8221;\u0026lt;/span\u0026gt;));\n\n\n\n\n\n}\n\n\n\n\n\n}\n\u003c/code\u003e\u003c/pre\u003e","title":"Android常用方法收集"},{"content":" **一、概述** 在上一篇博文中，我们给大家介绍了Android自定义控件系列的基础篇。链接： http://www.cnblogs.com/jerehedu/p/4360066.html\n这一篇博文中，我们将在基础篇的基础上，再通过重写ondraw（）方法和自定义属性实现圆形进度条，效果如图所示：\n**二、实现步骤** 1、 编写自定义组件MyCircleProgress扩展View \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;MyCircleProgress\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;View\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; … } 2、 在MyCircleProgress类中，定制属性 \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; progress = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;进度实际值,当前进度\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/**\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt; * 自定义控件属性，可灵活的设置圆形进度条的大小、颜色、类型等 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; mR;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;圆半径，决定圆大小\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; bgColor;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;圆或弧的背景颜色\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; fgColor;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;圆或弧的前景颜色，即绘制时的颜色\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; drawStyle; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;绘制类型 FILL画圆形进度条，STROKE绘制弧形进度条\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; strokeWidth;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;STROKE绘制弧形的弧线的宽度\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; max;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;最大值，设置进度的最大值\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/**\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt; * 设置进度，此为线程安全控件，由于考虑多线的问题，需要同步 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;synchronized\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; setProgress(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; progress) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt;(progress\u0026amp;lt;\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;){ progress=\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; }\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt;(progress\u0026amp;gt;max){ progress=max; }\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.progress = progress; }\t} \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getMax() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; max;\t} 3、 为定制的属性编写attrs.xml资源，该资源文件放在res/values目录下，内容如下：\n\u0026lt;span class=\u0026#34;pi\u0026#34;\u0026gt;\u0026amp;lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pi\u0026#34;\u0026gt;xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;declare-styleable\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;CircleProgressBar\u0026#34;\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;attr\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;bgColor\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;format\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;color\u0026#34;\u0026lt;/span\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;attr\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;fgColor\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;format\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;color\u0026#34;\u0026lt;/span\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;attr\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;r\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;format\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;integer\u0026#34;\u0026lt;/span\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;attr\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;strokeWidth\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;format\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;integer\u0026#34;\u0026lt;/span\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;attr\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;drawStyle\u0026#34;\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;enum\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;STROKE\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;value\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;0\u0026#34;\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;enum\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;enum\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;FILL\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;value\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;1\u0026#34;\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;enum\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;attr\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;attr\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;max\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;format\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;integer\u0026#34;\u0026lt;/span\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;declare-styleable\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; 4、 在MyCircleProgress类中定义构造函数，初始化属性 \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; initProperty(AttributeSet attrs){ TypedArray tArray = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressBar); mR=tArray.getInteger(R.styleable.CircleProgressBar_r,\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt;); bgColor=tArray.getColor(R.styleable.CircleProgressBar_bgColor, Color.GRAY); fgColor=tArray.getColor(R.styleable.CircleProgressBar_fgColor, Color.RED); drawStyle=tArray.getInt(R.styleable.CircleProgressBar_drawStyle, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;); strokeWidth=tArray.getInteger(R.styleable.CircleProgressBar_strokeWidth, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt;); max=tArray.getInteger(R.styleable.CircleProgressBar_max, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt;); }\t\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; MyCircleProgress(Context context, AttributeSet attrs) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.context = context; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.paint = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; Paint(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.paint.setAntiAlias(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt; 消除锯齿\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.paint.setStyle(Style.STROKE); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt; 绘制空心圆或 空心矩形\u0026lt;/span\u0026gt; initProperty(attrs);\t} 5、 在MainActivity中布局文件中添加MyCircleProgress组件，如下所示 \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/android\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/tools\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;xmlns:app\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;http://schemas.android.com/apk/res/com.jereh.mydrawcircleprogress\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;@dimen/activity_vertical_margin\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;@dimen/activity_horizontal_margin\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:paddingRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;@dimen/activity_horizontal_margin\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;@dimen/activity_vertical_margin\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;.MainActivity\u0026#34;\u0026lt;/span\u0026gt; \u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;com.jereh.views.MyCircleProgress \u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;@+id/MyCircleProgress\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;app:r\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;45\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;app:strokeWidth\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;10\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;app:bgColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;#cccccc\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;app:fgColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;#ff0000\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;app:drawStyle\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;FILL\u0026#34;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;attribute\u0026#34;\u0026gt;app:max\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026#34;value\u0026#34;\u0026gt;\u0026#34;50\u0026#34;\u0026lt;/span\u0026gt; /\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;tag\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; 6、 自定义组件MyCircleProgress中重写onDraw方法： \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;.onDraw(canvas); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; center = getWidth() / \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt; 圆心位置\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.paint.setColor(bgColor); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.paint.setStrokeWidth(strokeWidth); canvas.drawCircle(center, center, mR, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.paint); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt; 绘制圆环\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.paint.setColor(fgColor); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt;(drawStyle==\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;){ \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.paint.setStyle(Style.STROKE); opt=\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;; }\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt;{ \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.paint.setStyle(Style.FILL); opt=\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; top = (center - mR); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; bottom = (center + mR); RectF oval = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; RectF(top, top, bottom, bottom); canvas.drawArc(oval, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;270\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;360\u0026lt;/span\u0026gt;*progress/max, opt, paint); } 7、编写MainActivity \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;MainActivity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Activity\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; MyCircleProgress progressView; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); setContentView(R.layout.activity_main); progressView = (MyCircleProgress) findViewById(R.id.MyCircleProgress); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; ProgressAnimation().execute(); } \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;ProgressAnimation\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;AsyncTask\u0026lt;/span\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Void\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Integer\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Void\u0026lt;/span\u0026gt;\u0026amp;gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; Void doInBackground(Void... params) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;进度值不断的变化\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026amp;lt; progressView.getMax(); i++) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;try\u0026lt;/span\u0026gt; { publishProgress(i); Thread.sleep(\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;100\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;catch\u0026lt;/span\u0026gt; (InterruptedException e) { e.printStackTrace(); } } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onProgressUpdate(Integer... values) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;更新进度值\u0026lt;/span\u0026gt; progressView.setProgress(values[\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;]); progressView.invalidate(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;.onProgressUpdate(values); } } } ","permalink":"https://blog.zdltech.com/posts/android%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6%E7%B3%BB%E5%88%97%E4%B9%8B%E5%BA%94%E7%94%A8%E7%AF%87-%E5%9C%86%E5%BD%A2%E8%BF%9B%E5%BA%A6%E6%9D%A1/","summary":"\u003cdiv\u003e\n  **一、概述**\n\u003c/div\u003e\n\u003cp\u003e在上一篇博文中，我们给大家介绍了Android自定义控件系列的基础篇。链接： \u003ca href=\"http://www.cnblogs.com/jerehedu/p/4360066.html\"\u003ehttp://www.cnblogs.com/jerehedu/p/4360066.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这一篇博文中，我们将在基础篇的基础上，再通过重写ondraw（）方法和自定义属性实现圆形进度条，效果如图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img1.tuicool.com/Z7F3Yv2.png\"\u003e\u003cimg loading=\"lazy\" src=\"http://img0.tuicool.com/zQVBruZ.png\"\u003e\u003c/p\u003e\n\u003cdiv\u003e\n  **二、实现步骤**\n\u003c/div\u003e\n\u003ch4 id=\"1-编写自定义组件mycircleprogress扩展view\"\u003e1、  编写自定义组件MyCircleProgress扩展View\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;MyCircleProgress\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;View\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e…    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"2-在mycircleprogress类中定制属性\"\u003e2、  在MyCircleProgress类中，定制属性\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; progress  = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;进度实际值,当前进度\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/**\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * 自定义控件属性，可灵活的设置圆形进度条的大小、颜色、类型等\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   */\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; mR;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;圆半径，决定圆大小\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; bgColor;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;圆或弧的背景颜色\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; fgColor;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;圆或弧的前景颜色，即绘制时的颜色\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; drawStyle; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;绘制类型 FILL画圆形进度条，STROKE绘制弧形进度条\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; strokeWidth;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;STROKE绘制弧形的弧线的宽度\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; max;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;最大值，设置进度的最大值\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/**\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   * 设置进度，此为线程安全控件，由于考虑多线的问题，需要同步 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   */\u0026lt;/span\u0026gt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;synchronized\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; setProgress(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; progress) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt;(progress\u0026amp;lt;\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      progress=\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt;(progress\u0026amp;gt;max){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      progress=max;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt;{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;.progress = progress;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\t\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; getMax() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; max;\t}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e3、  为定制的属性编写attrs.xml资源，该资源文件放在res/values目录下，内容如下：\u003c/p\u003e","title":"Android自定义控件系列之应用篇——圆形进度条"},{"content":"由于java的字节序和网络字节序一致（高位在前），给出换算方法，亲测OK\npublic static void main(String[] args) {\nbyte[] bs=new byte[2];\nshort dvalue=1;\nUtils.putShort(bs, dvalue, 0);\nfor (int i = 0; i \u0026lt; bs.length; i++) {\nSystem.out.println(bs[i]);\n}\n}\n/**\n将32位的int值放到4字节的里 @param num @return\n*/\npublic static byte[] int2byteArray(int num) {\nbyte[] result = new byte[4];\nresult[0] = (byte) (num \u0026raquo;\u0026gt; 24);// 取最高8位放到0下标\nresult[1] = (byte) (num \u0026raquo;\u0026gt; 16);// 取次高8为放到1下标\nresult[2] = (byte) (num \u0026raquo;\u0026gt; 8); // 取次低8位放到2下标\nresult[3] = (byte) (num); // 取最低8位放到3下标\nreturn result;\n} /**\n将4字节的byte数组转成一个int值 @param b @return\n*/\npublic static int byteArray2int(byte[] b) {\nbyte[] a = new byte[4];\nint i = a.length – 1, j = b.length – 1;\nfor (; i \u0026gt;= 0; i–, j–) {// 从b的尾部(即int值的低位)开始copy数据\nif (j \u0026gt;= 0)\na[i] = b[j];\nelse\na[i] = 0;// 如果b.length不足4,则将高位补0\n}\nint v0 = (a[0] \u0026amp; 0xff) \u0026laquo; 24;// \u0026amp;0xff将byte值无差异转成int,避免Java自动类型提升后,会保留高位的符号位\nint v1 = (a[1] \u0026amp; 0xff) \u0026laquo; 16;\nint v2 = (a[2] \u0026amp; 0xff) \u0026laquo; 8;\nint v3 = (a[3] \u0026amp; 0xff);\nreturn v0 + v1 + v2 + v3;\n} /**\n转换short为byte @param b @param s 需要转换的short @param index\n*/\npublic static void putShort(byte b[], short s, int index) {\nb[index + 0] = (byte) (s \u0026raquo; 8);\nb[index + 1] = (byte) (s \u0026raquo; 0);\n} /**\n通过byte数组取到short @param b @param index 第几位开始取 @return\n*/\npublic static short getShort(byte[] b, int index) {\nreturn (short) (((b[index + 1] \u0026laquo; 8) | b[index + 0] \u0026amp; 0xff));\n} /**\n字符到字节转换 @param ch @return\n*/\npublic static void putChar(byte[] bb, char ch, int index) {\nint temp = (int) ch;\n// byte[] b = new byte[2];\nfor (int i = 0; i \u0026lt; 2; i++) {\n// 将最高位保存在最低位\nbb[index + i] = new Integer(temp \u0026amp; 0xff).byteValue();\ntemp = temp \u0026raquo; 8; // 向右移8位\n}\n} /**\n字节到字符转换 @param b @return\n*/\npublic static char getChar(byte[] b, int index) {\nint s = 0;\nif (b[index + 1] \u0026gt; 0)\ns += b[index + 1];\nelse\ns += 256 + b[index + 0];\ns *= 256;\nif (b[index + 0] \u0026gt; 0)\ns += b[index + 1];\nelse\ns += 256 + b[index + 0];\nchar ch = (char) s;\nreturn ch;\n} /**\nfloat转换byte @param bb @param x @param index\n*/\npublic static void putFloat(byte[] bb, float x, int index) {\n// byte[] b = new byte[4];\nint l = Float.floatToIntBits(x);\nfor (int i = 0; i \u0026lt; 4; i++) {\nbb[index + i] = new Integer(l).byteValue();\nl = l \u0026raquo; 8;\n}\n} /**\n通过byte数组取得float @param bb @param index @return\n*/\npublic static float getFloat(byte[] b, int index) {\nint l;\nl = b[index + 0];\nl \u0026amp;= 0xff;\nl |= ((long) b[index + 1] \u0026laquo; 8);\nl \u0026amp;= 0xffff;\nl |= ((long) b[index + 2] \u0026laquo; 16);\nl \u0026amp;= 0xffffff;\nl |= ((long) b[index + 3] \u0026laquo; 24);\nreturn Float.intBitsToFloat(l);\n} /**\ndouble转换byte @param bb @param x @param index\n*/\npublic static void putDouble(byte[] bb, double x, int index) {\n// byte[] b = new byte[8];\nlong l = Double.doubleToLongBits(x);\nfor (int i = 0; i \u0026lt; 4; i++) {\nbb[index + i] = new Long(l).byteValue();\nl = l \u0026raquo; 8;\n}\n} /**\n通过byte数组取得double @param bb @param index @return\n*/\npublic static double getDouble(byte[] b, int index) {\nlong l;\nl = b[0];\nl \u0026amp;= 0xff;\nl |= ((long) b[1] \u0026laquo; 8);\nl \u0026amp;= 0xffff;\nl |= ((long) b[2] \u0026laquo; 16);\nl \u0026amp;= 0xffffff;\nl |= ((long) b[3] \u0026laquo; 24);\nl \u0026amp;= 0xffffffffl;\nl |= ((long) b[4] \u0026laquo; 32);\nl \u0026amp;= 0xffffffffffl;\nl |= ((long) b[5] \u0026laquo; 40);\nl \u0026amp;= 0xffffffffffffl;\nl |= ((long) b[6] \u0026laquo; 48);\nl \u0026amp;= 0xffffffffffffffl;\nl |= ((long) b[7] \u0026laquo; 56);\nreturn Double.longBitsToDouble(l);\n} ","permalink":"https://blog.zdltech.com/posts/java%E4%B8%ADbyte%E4%B8%8E-intshortcharfloatdouble%E4%B9%8B%E9%97%B4%E7%9A%84%E8%BD%AC%E6%8D%A2/","summary":"\u003cp\u003e由于java的字节序和网络字节序一致（高位在前），给出换算方法，亲测OK\u003cbr\u003e\npublic static void main(String[] args) {\u003cbr\u003e\nbyte[] bs=new byte[2];\u003cbr\u003e\nshort dvalue=1;\u003cbr\u003e\nUtils.putShort(bs, dvalue, 0);\u003cbr\u003e\nfor (int i = 0; i \u0026lt; bs.length; i++) {\u003cbr\u003e\nSystem.out.println(bs[i]);\u003cbr\u003e\n}\u003cbr\u003e\n}\u003cbr\u003e\n/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e将32位的int值放到4字节的里\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e@param num\u003c/li\u003e\n\u003cli\u003e@return\u003cbr\u003e\n*/\u003cbr\u003e\npublic static byte[] int2byteArray(int num) {\u003cbr\u003e\nbyte[] result = new byte[4];\u003cbr\u003e\nresult[0] = (byte) (num \u0026raquo;\u0026gt; 24);// 取最高8位放到0下标\u003cbr\u003e\nresult[1] = (byte) (num \u0026raquo;\u0026gt; 16);// 取次高8为放到1下标\u003cbr\u003e\nresult[2] = (byte) (num \u0026raquo;\u0026gt; 8); // 取次低8位放到2下标\u003cbr\u003e\nresult[3] = (byte) (num); // 取最低8位放到3下标\u003cbr\u003e\nreturn result;\u003cbr\u003e\n}\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e/**\u003c/p\u003e","title":"java中byte与 int、short、char、float、double之间的转换"},{"content":"1、亲自打开网站，体会访问速度。\n2、邀请QQ上不同地区的好友打开网站，体会访问速度。\n3、通过第三方网站检测访问速度，推荐使用http://www.webkaka.com/，这个网站可以检测各地访问情况。\n4、通过ping值情况检测。很多客户不知道如何去ping一个网站或IP，下面详细说明操作步骤：\n（1）点击开始菜单，再点击运行。\n（2）输入ping www.yourdomain.com -t ，其中www.yourdomain.com换成您的域名或IP，点击确定。\n（3）分析ping的结果一般50ms以内是非常快的，100ms以内的速度还可以接受。另外没有掉包，数值都是连续显示的，如果显示几行就掉包一次，那网站访问速度肯定不理想。\n5、通过第三方网站检测ping值，如http://ping.chinaz.com（国内测试点），http://www.just-ping.com（全球测试点）。\n网页载入速度对于一个网站来讲很关键，Google已经将一个网站的载入速度列入了网站关键字排名的考虑因素当中，也就是说如果你的网站有足够的内容，而且载入速度比别人的网站更快一步的话，那么你就是获得更好的排名。那么下面就赶快测试你的网站，提高网站访问速度吧。\n1：用Ping命令简单测网站速度的方法\nPing可以用来检查网络是否通畅或者网络连接速度，点击开始→运行 在运行中输入“cmd”回车或点击确定，输入ping www.你的网址.com 就可以了。\n用Ping命令简单测网站速度的方法-卢松松博客\n（新手只需注意本图红框里的含义即可）\nPing结果属于表示，bytes表示发送多少字节，time是时间，时间越小速度越快，TTL可以判断对方操作系统，TTL=119是XP系统，但TTL一般不准，服务器可以修改注册表更改TTL类型，更详细测速的办法，请多多搜索。\n新手只需看最下面一行即可，最短时间、最长时间和平均时间（时间越短越好），这样你就能大致判断出网站的速度了。\n同样，站长之家的ping工具也不错，网址：http://ping.chinaz.com/\n2：用tracert命令简单测网站速度的方法\n测试方法和ping命令类似，只是ping换成tracert www.你的网址.com， tracert就是用来检测从终端客户到你的服务器所在机房的“跳数”和响应时间，也就是测试出服务器与全国各地客户的连接速度，当到达任何一个网关的时候,tracert会进行三次测试,并把三次测试的结果以ms为单位显示，当然time时间越短越好。\n3：全方位的免费网站速度测试工具 — GTmetrix\ngtmetrix.com提供了丰富的详细的测量结果，它结合了Google Page Speed和Yahoo! YSlow的网页速度测试功能，并且提供可行的建议帮你改善网站速度。无需注册为会员即可使用该工具，并建议如何来优化网页中每个元素的，最重要的是会根据网站的具体情况，直接告诉你导致网站加载速度变慢的根源在哪里。\n做为GTmetrix注册会员，你可以设置每天、每周或每月自动测试一次你的网站，可设置测试记录自动保存，还能够同时对4个网址进行对比测试。如果你不知道自己的载入速度到底是快还是慢，你可以输入一个名站来对比结果，比如Google.com\n网址：http://gtmetrix.com\n4：比较哪个网站载入速度较快 — WhichLoadsFaster\n2010年7月7日，FastSoft推出免费动态网站加速互动演示网站 WhichLoadsFaster.com WhichLoadsFaster是一个免费公开网速测试工具，用以促进Web网站间良性竞争让网页浏览速度更快。\n它是通过你的连接，在你的浏览器里，让两个真实的网页在你面前展示出来。所以使用WhichLoadsFaster是反应当前你的网络下来对比两个站的速度的。\n网址：http://whichloadsfaster.com/\n5：国内免费的网站速度测试平台 — WebKaka\n卡卡网是国内的一家帮你测试网站页面载入速度的免费站长工具，即时检测你的网站在全国各地访问的有效性、响应时间以及打开速度，目前在全国15个省市、美国、澳大利亚、日本等8个国家均设有检测点。此类网站速度测试工具基本都是国外的，国内的测速服务还比较少。卡卡网主要有网站速度测试、ping检测、路由追踪等功能。\n网址：http://www.webkaka.com\n当然还有其他很不错的在线网速测试的网站，比如speedtest.cn，speedtest.net等，同时，在你选择网站空间时，能用到本文的一些小方法，相信对你选择物美价廉的空间是个不错的办法\n","permalink":"https://blog.zdltech.com/posts/%E6%A3%80%E6%B5%8B%E7%BD%91%E7%AB%99%E8%AE%BF%E9%97%AE%E9%80%9F%E5%BA%A6%E7%9A%84%E6%96%B9%E6%B3%95/","summary":"\u003cp\u003e1、亲自打开网站，体会访问速度。\u003c/p\u003e\n\u003cp\u003e2、邀请QQ上不同地区的好友打开网站，体会访问速度。\u003c/p\u003e\n\u003cp\u003e3、通过第三方网站检测访问速度，推荐使用\u003ca href=\"http://www.webkaka.com/\"\u003ehttp://www.webkaka.com/\u003c/a\u003e，这个网站可以检测各地访问情况。\u003c/p\u003e\n\u003cp\u003e4、通过ping值情况检测。很多客户不知道\u003cspan class=\"t_tag\"\u003e如何\u003c/span\u003e去ping一个网站或IP，下面详细说明操作步骤：\u003c/p\u003e\n\u003cp\u003e（1）点击开始菜单，再点击运行。\u003c/p\u003e\n\u003cp\u003e（2）输入ping \u003ca href=\"http://www.yourdomain.com/\"\u003ewww.yourdomain.com\u003c/a\u003e -t ，其中\u003ca href=\"http://www.yourdomain.com/\"\u003ewww.yourdomain.com\u003c/a\u003e换成您的\u003cspan class=\"t_tag\"\u003e域名\u003c/span\u003e或IP，点击确定。\u003c/p\u003e\n\u003cp\u003e（3）分析ping的结果一般50ms以内是非常快的，100ms以内的速度还可以接受。另外没有掉包，数值都是连续显示的，如果显示几行就掉包一次，那网站访问速度肯定不理想。\u003cbr\u003e\n5、通过第三方网站检测ping值，如\u003ca href=\"http://ping.chinaz.com/\"\u003ehttp://ping.chinaz.com\u003c/a\u003e（国内测试点），\u003ca href=\"http://www.just-ping.com/\"\u003ehttp://www.just-ping.com\u003c/a\u003e（全球测试点）。\u003c/p\u003e\n\u003cp\u003e网页载入速度对于一个网站来讲很关键，Google已经将一个网站的载入速度列入了网站关键字排名的考虑因素当中，也就是说如果你的网站有足够的内容，而且载入速度比别人的网站更快一步的话，那么你就是获得更好的排名。那么下面就赶快测试你的网站，提高网站访问速度吧。\u003c/p\u003e\n\u003cp\u003e1：用Ping命令简单测网站速度的方法\u003c/p\u003e\n\u003cp\u003ePing可以用来检查网络是否通畅或者网络连接速度，点击开始→运行 在运行中输入“cmd”回车或点击确定，输入ping www.你的网址.com 就可以了。\u003c/p\u003e\n\u003cp\u003e用Ping命令简单测网站速度的方法-卢松松博客\u003c/p\u003e\n\u003cp\u003e（新手只需注意本图红框里的含义即可）\u003c/p\u003e\n\u003cp\u003ePing结果属于表示，bytes表示发送多少字节，time是时间，时间越小速度越快，TTL可以判断对方操作系统，TTL=119是XP系统，但TTL一般不准，服务器可以修改注册表更改TTL类型，更详细测速的办法，请多多搜索。\u003c/p\u003e\n\u003cp\u003e新手只需看最下面一行即可，最短时间、最长时间和平均时间（时间越短越好），这样你就能大致判断出网站的速度了。\u003c/p\u003e\n\u003cp\u003e同样，站长之家的ping工具也不错，网址：http://ping.chinaz.com/\u003c/p\u003e\n\u003cp\u003e2：用tracert命令简单测网站速度的方法\u003c/p\u003e\n\u003cp\u003e测试方法和ping命令类似，只是ping换成tracert www.你的网址.com， tracert就是用来检测从终端客户到你的服务器所在机房的“跳数”和响应时间，也就是测试出服务器与全国各地客户的连接速度，当到达任何一个网关的时候,tracert会进行三次测试,并把三次测试的结果以ms为单位显示，当然time时间越短越好。\u003c/p\u003e\n\u003cp\u003e3：全方位的免费网站速度测试工具 — GTmetrix\u003c/p\u003e\n\u003cp\u003egtmetrix.com提供了丰富的详细的测量结果，它结合了Google Page Speed和Yahoo! YSlow的网页速度测试功能，并且提供可行的建议帮你改善网站速度。无需注册为会员即可使用该工具，并建议如何来优化网页中每个元素的，最重要的是会根据网站的具体情况，直接告诉你导致网站加载速度变慢的根源在哪里。\u003c/p\u003e\n\u003cp\u003e做为GTmetrix注册会员，你可以设置每天、每周或每月自动测试一次你的网站，可设置测试记录自动保存，还能够同时对4个网址进行对比测试。如果你不知道自己的载入速度到底是快还是慢，你可以输入一个名站来对比结果，比如Google.com\u003c/p\u003e\n\u003cp\u003e网址：http://gtmetrix.com\u003c/p\u003e\n\u003cp\u003e4：比较哪个网站载入速度较快 — WhichLoadsFaster\u003c/p\u003e\n\u003cp\u003e2010年7月7日，FastSoft推出免费动态网站加速互动演示网站 WhichLoadsFaster.com WhichLoadsFaster是一个免费公开网速测试工具，用以促进Web网站间良性竞争让网页浏览速度更快。\u003c/p\u003e\n\u003cp\u003e它是通过你的连接，在你的浏览器里，让两个真实的网页在你面前展示出来。所以使用WhichLoadsFaster是反应当前你的网络下来对比两个站的速度的。\u003c/p\u003e\n\u003cp\u003e网址：http://whichloadsfaster.com/\u003c/p\u003e\n\u003cp\u003e5：国内免费的网站速度测试平台 — WebKaka\u003c/p\u003e\n\u003cp\u003e卡卡网是国内的一家帮你测试网站页面载入速度的免费站长工具，即时检测你的网站在全国各地访问的有效性、响应时间以及打开速度，目前在全国15个省市、美国、澳大利亚、日本等8个国家均设有检测点。此类网站速度测试工具基本都是国外的，国内的测速服务还比较少。卡卡网主要有网站速度测试、ping检测、路由追踪等功能。\u003c/p\u003e\n\u003cp\u003e网址：http://www.webkaka.com\u003c/p\u003e\n\u003cp\u003e当然还有其他很不错的在线网速测试的网站，比如speedtest.cn，speedtest.net等，同时，在你选择网站空间时，能用到本文的一些小方法，相信对你选择物美价廉的空间是个不错的办法\u003c/p\u003e","title":"检测网站访问速度的方法"},{"content":"相关概念\n**分辨率：**整个屏幕的像素数目，为了表示方便一般用屏幕的像素宽度（水平像素数目）乘以像素高度表示，形如1280×720，反之分辨率为1280×720的屏幕，像素宽度不一定为1280\n**屏幕密度：**表示单位面积内的像素个数，通常用dpi为单位，即每英寸多少个像素点\npx**：**长度单位，以具体像素为单位\ndp**：**长度单位，与具体屏幕密度无关，显示的时候根据具体平台屏幕密度的不同最终转换为相应的像素长度，具体转换规则是: 1dp =（目标屏幕密度/标准密度）*px,标准密度为160dpi，例如，1dp长度在密度为160dpi的平台表示一个像素的长度，而在240dpi的平台则表示1.5个像素的长度\n**屏幕尺寸：**屏幕的大小，通常用屏幕对角线的长度表示\nAndroid界面适配机制 UI界面在不同平台的适配受屏幕尺寸和屏幕密度影响，Android适配机制就是在资源后面添加对这两种因素的限定，通过不同的限定区分不同的平台资源，Android在使用资源的时候会优先选择满足本平台限定的资源，再找最接近条件的，再找默认（即不加限定），通过选择适合当前平台的资源来完成不同平台的适配。\n屏幕尺寸分为：small,normal,large,xlarge分别表示小，中，大，超大屏\n屏幕密度分为：ldpi,mdpi,hdpi,xhdpi，它们的标准值分别是：120dpi，160dpi，240dpi，320dpi\n以上划分均表示的是一个范围：\n在资源目录后面加上上面的限定就能为资源指定特定的适用平台，如下所示\n表示大屏，中密度布局会选择上面那个main.xml，超大屏，中密度会选择下面那个main.xml\n在实际开发过程中屏幕尺寸不够直观，android将其转换为分辨率表示，根据屏幕具体分辨率可选择相应的限定符\n小结：通过加上上述限定可以实现一个apk适配几种主流的屏幕尺寸和屏幕密度，这种限定方式比较适用于对外发布应用，不知道终端具体参数的情况，但是不能做到精确适配，对于屏幕尺寸和密度相差不大的两种平台不能很好的区分。\n为了解决上述问题，自Android3.2开始，引入了精确适配，理论上可以适配任意像素宽度，高度，屏幕密度的平台，需用以下方式添加限定符\n其中w1280dp表示屏幕宽度为1280dp，h752dp表示屏幕高度为752dp，160dpi表示屏幕密度，其中屏幕宽，高必须以dp为单位，在知道屏幕像素宽高度的情况下可以通过公式：1dp = （目标屏幕密度/标准密度）*px 转换成dp单位。\n例如：某平台屏幕宽，高分别为1920px，720px，屏幕密度为240dpi\n适配该平台的限定为：\n或者\n根据公式1dp=（240/160）px=1.5px,宽度，高度转为dp单位分别是1280dp和480dp.\nAndroid自适应不同分辨率或不同屏幕大小的layout布局(横屏|竖屏)\n一：不同的layout\nAndroid手机屏幕大小不一，有480×320, 640×360, 800×480.怎样才能让App自动适应不同的屏幕呢？\n其实很简单，只需要在res目录下创建不同的layout文件夹，比如layout-640×360,layout-800×480,所有的layout文件在编译之后都会写入R.java里，而系统会根据屏幕的大小自己选择合适的layout进行使用。\n二：hdpi、mdpi、ldpi\n在之前的版本中，只有一个drawable，而2.1版本中有drawable-mdpi、drawable-ldpi、drawable-hdpi三个，这三个主要是为了支持多分辨率。\ndrawable- hdpi、drawable- mdpi、drawable-ldpi的区别：\n(1)drawable-hdpi里面存放高分辨率的图片,如WVGA (480×800),FWVGA (480×854)\n(2)drawable-mdpi里面存放中等分辨率的图片,如HVGA (320×480)\n(3)drawable-ldpi里面存放低分辨率的图片,如QVGA (240×320)\n系统会根据机器的分辨率来分别到这几个文件夹里面去找对应的图片。\n更正：应该是对应不同density 的图片\n在开发程序时为了兼容不同平台不同屏幕，建议各自文件夹根据需求均存放不同版本图片。\n[i]备注：三者的解析度不一样，就像你把电脑的分辨率调低，图片会变大一样，反之分辨率高，图片缩小。 [/i]\n屏幕方向：\n横屏竖屏自动切换：\n可以在res目录下建立layout-port-800×600和layout-land两个目录，里面分别放置竖屏和横屏两种布局文件，这样在手机屏幕方向变化的时候系统会自动调用相应的布局文件，避免一种布局文件无法满足两种屏幕显示的问题。\n不同分辨率横屏竖屏自动切换：\n以800×600为例\n可以在res目录下建立layout-port-800×600和layout-land-800×600两个目录\n不切换：\n以下步骤是网上流传的，不过我自己之前是通过图形化界面实现这个配置，算是殊途同归，有空我会把图片贴上来。\n还要说明一点：每个activity都有这个属性screenOrientation，每个activity都需要设置，可以设置为竖屏（portrait），也可以设置为无重力感应（nosensor）。\n要让程序界面保持一个方向，不随手机方向转动而变化的处理办法：\n在AndroidManifest.xml里面配置一下就可以了。加入这一行android:screenOrientation=”landscape”。\n例如（landscape是横向，portrait是纵向）：\nJava代码:\n\u003c?xml version=\u0026#8221;1.0\u0026#8243; encoding=\u0026#8221;utf-8\u0026#8243;?\u003e \u0026lt;manifestxmlns:android=”http://schemas.android.com/apk/res/android”\npackage=”com.ray.linkit”\nandroid:versionCode=”1″\nandroid:versionName=”1.0″\u0026gt;\n\u0026lt;application android:icon=”@drawable/icon”android:label=”@string/app_name”\u0026gt;\n另外，android中每次屏幕的切换动会重启Activity，所以应该在Activity销毁前保存当前活动的状态，在Activity再次Create的时候载入配置，那样，进行中的游戏就不会自动重启了！\n有的程序适合从竖屏切换到横屏，或者反过来，这个时候怎么办呢？可以在配置Activity的地方进行如下的配置android:screenOrientation=”portrait”。这样就可以保证是竖屏总是竖屏了，或者landscape横向。\n而 有的程序是适合横竖屏切换的。如何处理呢？首先要在配置Activity的时候进行如下的配 置：android:configChanges=”keyboardHidden|orientation”，另外需要重写Activity的 onConfigurationChanged方法。实现方式如下，不需要做太多的内容：\n@Override\npublic void onConfigurationChanged(Configuration newConfig) {\nsuper.onConfigurationChanged(newConfig);\nif (this.getResources().getConfiguration().orientation ==Configuration.ORIENTATION_LANDSCAPE) {\n// land do nothing is ok\n} else if (this.getResources().getConfiguration().orientation ==Configuration.ORIENTATION_PORTRAIT) {\n// port do nothing is ok\n}\n}\n写 一个支持多分辨的程序，基于1.6开发的，建立了三个资源文件夹drawable-hdpi drawable-mdpidrawable-ldpi，里面分别存放72*72 48*48 36*36的icon图标文件。当我在G1（1.5的系统）上测试时，图标应该自适应为48*48才对啊，但实际显示的是36*36。怎么才能让其自适应 48*48的icon图标呢\n解决办法 drawable-hdpi drawable-mdpi drawable-ldpi改成drawable-480X320 drawable-800X480的多分辨支持的文件夹\n对 于Android游戏开发我们不得不像iPhone那样思考兼容 Android平板电脑，对于苹果要考虑iPad、iPhone 3GS和iPhone 4等屏幕之间的兼容性，对于几乎所有的分辨率总结了大约超过20中粉笔阿女郎的大小和对应关系，对于开发Android游戏而言可以考虑到未来的3.0以 及很多平板电脑的需要。\n常规的我们可能只考虑QVGA，HVGA，WVGA，FWVGA和DVGA，但是抛去了手机不谈，可能平板使用类似WSVGA的1024×576以及WXGA的1280×768等等。\nQVGA = 320 * 240;\nWQVGA = 320 * 480;\nWQVGA2 = 400 * 240;\nWQVGA3 = 432 * 240;\nHVGA = 480 * 320;\nVGA = 640 * 480;\nWVGA = 800 * 480;\nWVGA2 = 768 * 480;\nFWVGA = 854 * 480;\nDVGA = 960 * 640;\nPAL = 576 * 520;\nNTSC = 486 * 440;\nSVGA = 800 * 600;\nWSVGA […]\n这是一个比较有代表性的Android软件资源包，drawable里面存放的是应用的图标文件，layout存放的是布局，简单说就是这些图标如何摆放。为什么Android上需要这么多资源包文件和布局文件是我们接下来需要讨论的问题。\nAndroid 设备屏幕的尺寸是各式各样的，如小米是4英寸的，Xoom平板是10英寸；分辨率也千奇百怪，800×480，960×540等；Android版本的碎 片化问题更是萦绕于心，不过在设计应用时可以分为两大块：3.0之前的版本和3.0之后的版本。这种情况会带来什么问题我们用三个假设来说明一下。\n假设你的手上有两个4英寸的设备，设备A的分辨率是800×480，设备B的分辨率是1600×960。你在设备A上设计了一个64×64像素的图标，感觉它大小正合适，但放到设备B上的时候，这个图标看上去就只有之前一半大小了。\n假设你手上的两个设备，设备A是4英寸，设备B是10英寸。在设备A上方放了一个tab控件，有三个页签。放到设备B上看时tab控件的三个页签被拉得很长，本来放6个页签的空间只放了三个页签。\n假设你手上的两个设备，设备A装的是Android2.3，设备B装的是Android4.0，而设备B没有menu建，风格也不一样。你发现两个设备上用同一套风格的皮肤并不合适。\nGoogle 提供了一套体系去解决这些问题。我们再回到上面的那张图，drawable文件夹有ldpi、mdpi、hdpi、xhdpi四种。dpi指像素/英寸， 而ldpi指120，mdpi指160，hdpi指240，xhdpi指320。小米手机是4英寸、854×480的分辨率，那么小米手机的dpi就是 854的平方加480的平方和开2次方后除以4，结果大约是245。如果应用安装在小米手机上，那么系统会调用图中drawable-hdpi里面的资 源。这样，你只要做4套资源分别放在drawable-ldpi、drawable-mdpi、drawable-hdpi以及drawable- xdpi下（图标可以按照3：4：6：8的比例制作图片资源），那么就可以解决上面假设1当中提到的问题。\n对于相同 dpi、但尺寸不一样的设备，可以通过layout文件控制各种资源的布局。Google将设备分为small（2～3英寸）、normal（4英寸左 右）、large（5～7英寸）、xlarge（7英寸以上）。在上面的假设2种，我们可以在layout-normal里配置3个页签的tab栏，在 layout-xlarge里配置6个页签的tab栏。如果应用在所有设备上布局都一样，那么就不用考虑针对不同尺寸的layout。从图中那些 layout*文件夹可以看出，该应用在hdpi及xhdpi上支持横竖屏，而且横竖屏的布局不一致，但没有考虑不同尺寸的设备使用不同布局的情况。\nAndroid3.0 之前的风格与Android3.0（包含3.0）之后的风格区别很大，图中那个应用就使用了两种风格的资源及布局。Android2.3的小米会使用 drawable-hdpi及layout-hdpi当中的文件，而Android4.0的小米就会使用drawable-hdpi-v11及 layout-hdpi-v11里面的文件。\n今天就到此为止了，有空的时候再说说9-Patch的使用。这篇文章也就只能起到抛砖引玉的作用，在实际设计应用的时候还需要多去参考其他文档资料，特别是Android开发的官方文档。\n转自：http://www.cnblogs.com/maxinliang/p/3170711.html\n","permalink":"https://blog.zdltech.com/posts/android%E5%A4%9A%E5%88%86%E8%BE%A8%E7%8E%87%E5%A4%9A%E5%B1%8F%E5%B9%95%E5%AF%86%E5%BA%A6%E4%B8%8Bui%E9%80%82%E9%85%8D%E6%96%B9%E6%A1%88/","summary":"\u003cp\u003e\u003cstrong\u003e相关概念\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e**分辨率：**整个屏幕的像素数目，为了表示方便一般用屏幕的像素宽度（水平像素数目）乘以像素高度表示，形如1280×720，反之分辨率为1280×720的屏幕，像素宽度不一定为1280\u003c/p\u003e\n\u003cp\u003e**屏幕密度：**表示单位面积内的像素个数，通常用dpi为单位，即每英寸多少个像素点\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003epx\u003c/strong\u003e**：**长度单位，以具体像素为单位\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003edp\u003c/strong\u003e**：**长度单位，与具体屏幕密度无关，显示的时候根据具体平台屏幕密度的不同最终转换为相应的像素长度，具体转换规则是: 1dp =（目标屏幕密度/标准密度）*px,标准密度为160dpi，例如，1dp长度在密度为160dpi的平台表示一个像素的长度，而在240dpi的平台则表示1.5个像素的长度\u003c/p\u003e\n\u003cp\u003e**屏幕尺寸：**屏幕的大小，通常用屏幕对角线的长度表示\u003c/p\u003e\n\u003ch1 id=\"android界面适配机制\"\u003eAndroid界面适配机制\u003c/h1\u003e\n\u003cp\u003eUI界面在不同平台的适配受屏幕尺寸和屏幕密度影响，Android适配机制就是在资源后面添加对这两种因素的限定，通过不同的限定区分不同的平台资源，Android在使用资源的时候会优先选择满足本平台限定的资源，再找最接近条件的，再找默认（即不加限定），通过选择适合当前平台的资源来完成不同平台的适配。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e屏幕尺寸分为：small,normal,large,xlarge分别表示小，中，大，超大屏\u003c/p\u003e\n\u003cp\u003e屏幕密度分为：ldpi,mdpi,hdpi,xhdpi，它们的标准值分别是：120dpi，160dpi，240dpi，320dpi\u003c/p\u003e\n\u003cp\u003e以上划分均表示的是一个范围：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://www.jcodecraeer.com/uploads/20130627/13722624421110.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e在资源目录后面加上上面的限定就能为资源指定特定的适用平台，如下所示\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://www.jcodecraeer.com/uploads/20130627/13722624942474.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e表示大屏，中密度布局会选择上面那个main.xml，超大屏，中密度会选择下面那个main.xml\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e在实际开发过程中屏幕尺寸不够直观，android将其转换为分辨率表示，根据屏幕具体分辨率可选择相应的限定符\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://www.jcodecraeer.com/uploads/20130627/13722625497179.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e小结：通过加上上述限定可以实现一个apk适配几种主流的屏幕尺寸和屏幕密度，这种限定方式比较适用于对外发布应用，不知道终端具体参数的情况，但是不能做到精确适配，对于屏幕尺寸和密度相差不大的两种平台不能很好的区分。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e为了解决上述问题，自Android3.2开始，引入了精确适配，理论上可以适配任意像素宽度，高度，屏幕密度的平台，需用以下方式添加限定符\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://www.jcodecraeer.com/uploads/20130627/13722625806649.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e其中w1280dp表示屏幕宽度为1280dp，h752dp表示屏幕高度为752dp，160dpi表示屏幕密度，其中屏幕宽，高必须以dp为单位，在知道屏幕像素宽高度的情况下可以通过公式：1dp = （目标屏幕密度/标准密度）*px 转换成dp单位。\u003c/p\u003e\n\u003cp\u003e例如：某平台屏幕宽，高分别为1920px，720px，屏幕密度为240dpi\u003c/p\u003e\n\u003cp\u003e适配该平台的限定为：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://www.jcodecraeer.com/uploads/20130627/13722626152563.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e或者\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://www.jcodecraeer.com/uploads/20130627/13722626311624.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e根据公式1dp=（240/160）px=1.5px,宽度，高度转为dp单位分别是1280dp和480dp.\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAndroid自适应不同分辨率或不同屏幕大小的layout布局(横屏|竖屏\u003c/strong\u003e)\u003cbr\u003e\n一：不同的layout\u003cbr\u003e\nAndroid手机屏幕大小不一，有480×320, 640×360, 800×480.怎样才能让App自动适应不同的屏幕呢？\u003cbr\u003e\n其实很简单，只需要在res目录下创建不同的layout文件夹，比如layout-640×360,layout-800×480,所有的layout文件在编译之后都会写入R.java里，而系统会根据屏幕的大小自己选择合适的layout进行使用。\u003cbr\u003e\n二：hdpi、mdpi、ldpi\u003cbr\u003e\n在之前的版本中，只有一个drawable，而2.1版本中有drawable-mdpi、drawable-ldpi、drawable-hdpi三个，这三个主要是为了支持多分辨率。\u003cbr\u003e\ndrawable- hdpi、drawable- mdpi、drawable-ldpi的区别：\u003cbr\u003e\n(1)drawable-hdpi里面存放高分辨率的图片,如WVGA (480×800),FWVGA (480×854)\u003cbr\u003e\n(2)drawable-mdpi里面存放中等分辨率的图片,如HVGA (320×480)\u003cbr\u003e\n(3)drawable-ldpi里面存放低分辨率的图片,如QVGA (240×320)\u003cbr\u003e\n系统会根据机器的分辨率来分别到这几个文件夹里面去找对应的图片。\u003cbr\u003e\n更正：应该是对应不同density 的图片\u003cbr\u003e\n在开发程序时为了兼容不同平台不同屏幕，建议各自文件夹根据需求均存放不同版本图片。\u003cbr\u003e\n[i]备注：三者的解析度不一样，就像你把电脑的分辨率调低，图片会变大一样，反之分辨率高，图片缩小。 [/i]\u003cbr\u003e\n屏幕方向：\u003cbr\u003e\n横屏竖屏自动切换：\u003cbr\u003e\n可以在res目录下建立layout-port-800×600和layout-land两个目录，里面分别放置竖屏和横屏两种布局文件，这样在手机屏幕方向变化的时候系统会自动调用相应的布局文件，避免一种布局文件无法满足两种屏幕显示的问题。\u003cbr\u003e\n不同分辨率横屏竖屏自动切换：\u003cbr\u003e\n以800×600为例\u003cbr\u003e\n可以在res目录下建立layout-port-800×600和layout-land-800×600两个目录\u003cbr\u003e\n不切换：\u003cbr\u003e\n以下步骤是网上流传的，不过我自己之前是通过图形化界面实现这个配置，算是殊途同归，有空我会把图片贴上来。\u003cbr\u003e\n还要说明一点：每个activity都有这个属性screenOrientation，每个activity都需要设置，可以设置为竖屏（portrait），也可以设置为无重力感应（nosensor）。\u003cbr\u003e\n要让程序界面保持一个方向，不随手机方向转动而变化的处理办法：\u003c/p\u003e\n\u003cp\u003e在AndroidManifest.xml里面配置一下就可以了。加入这一行android:screenOrientation=”landscape”。\u003cbr\u003e\n例如（landscape是横向，portrait是纵向）：\u003c/p\u003e\n\u003cp\u003eJava代码:\u003c/p\u003e\n\u003c?xml version=\u0026#8221;1.0\u0026#8243; encoding=\u0026#8221;utf-8\u0026#8243;?\u003e  \n\u003cp\u003e\u0026lt;manifestxmlns:android=”http://schemas.android.com/apk/res/android”\u003cbr\u003e\npackage=”com.ray.linkit”\u003cbr\u003e\nandroid:versionCode=”1″\u003cbr\u003e\nandroid:versionName=”1.0″\u0026gt;\u003cbr\u003e\n\u0026lt;application android:icon=”@drawable/icon”android:label=”@string/app_name”\u0026gt;\u003cbr\u003e\n\u003cactivity android:name=\u0026#8221;.Main\u0026#8221;  \nandroid:label=\u0026#8221;@string/app_name\u0026#8221;  \nandroid:screenOrientation=\u0026#8221;portrait\u0026#8221;\u003e\u003cbr\u003e\n\u003cintent-filter\u003e\u003cbr\u003e\n\u003caction android:name=\u0026#8221;android.intent.action.MAIN\u0026#8221; /\u003e\u003cbr\u003e\n\u003ccategory android:name=\u0026#8221;android.intent.category.LAUNCHER\u0026#8221; /\u003e\u003cbr\u003e\n\u003c/intent-filter\u003e\u003cbr\u003e\n\u003c/activity\u003e\u003cbr\u003e\n\u003cactivity android:name=\u0026#8221;.GamePlay\u0026#8221;  \nandroid:screenOrientation=\u0026#8221;portrait\u0026#8221;\u003e\u003c/activity\u003e\u003cbr\u003e\n\u003cactivity android:name=\u0026#8221;.OptionView\u0026#8221;  \nandroid:screenOrientation=\u0026#8221;portrait\u0026#8221;\u003e\u003c/activity\u003e\u003cbr\u003e\n\u003c/application\u003e\u003cbr\u003e\n\u003cuses-sdk android:minSdkVersion=\u0026#8221;3\u0026#8243; /\u003e\u003cbr\u003e\n\u003c/manifest\u003e\u003cbr\u003e\n另外，android中每次屏幕的切换动会重启Activity，所以应该在Activity销毁前保存当前活动的状态，在Activity再次Create的时候载入配置，那样，进行中的游戏就不会自动重启了！\u003cbr\u003e\n有的程序适合从竖屏切换到横屏，或者反过来，这个时候怎么办呢？可以在配置Activity的地方进行如下的配置android:screenOrientation=”portrait”。这样就可以保证是竖屏总是竖屏了，或者landscape横向。\u003cbr\u003e\n而 有的程序是适合横竖屏切换的。如何处理呢？首先要在配置Activity的时候进行如下的配 置：android:configChanges=”keyboardHidden|orientation”，另外需要重写Activity的 onConfigurationChanged方法。实现方式如下，不需要做太多的内容：\u003c/p\u003e","title":"android多分辨率多屏幕密度下UI适配方案"},{"content":"看过oschina-app的数字提醒标签BadgeView的使用过程，才发现以前项目中的实现逻辑有问题。以前待的项目组没个牛人，从我干第一个项目就我负责开发设计和管理，可想而知，顶多也就实现功能交工。说到底就是经验不足，所以有时间还是多看看别人的代码。本来是想主要讲oschina-app里面提醒标签的实现逻辑，但我觉得标签控件BadgeView有必要说下。\nBadgeView是一个开源的ui项目，其实就一个ui工具类，BadgeView是对TextView的重写，他的代码就不贴了，可以到git上下最新的吧：https://github.com/jgilfelt/android-viewbadger\n在这里主要说下他的用法，它可以设置标签的背景、颜色、位置、动画、文字等，对一般的需求足以满足了，先看下git上demo的效果：\n默认属性标签代码：\n**[java]** [view plain](http://blog.csdn.net/xiangxue336/article/details/21073571#)[copy](http://blog.csdn.net/xiangxue336/article/details/21073571#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/230977)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/230977/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// *** default badge ***\u0026lt;/span\u0026gt; - - View target = findViewById(R.id.default_target); - BadgeView badge = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BadgeView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, target); - badge.setText(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt;); - badge.show(); 默认是显示在右上角，红色的背景白色字体，这些个默认属性是可以在BadgeView里面设置的。\n设置position代码：\n**[java]** [view plain](http://blog.csdn.net/xiangxue336/article/details/21073571#)[copy](http://blog.csdn.net/xiangxue336/article/details/21073571#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/230977)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/230977/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// *** set position ***\u0026lt;/span\u0026gt; - - btnPosition = (Button) findViewById(R.id.position_target); - badge1 = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BadgeView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, btnPosition); - badge1.setText(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;12\u0026amp;#8221;\u0026lt;/span\u0026gt;); - badge1.setBadgePosition(BadgeView.POSITION_CENTER); - btnPosition.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - badge1.toggle(); - } - }); toggle方法是控制标签的现实和隐藏的。\n在BadgeView中定义了5种显示位置：\n**[java]** [view plain](http://blog.csdn.net/xiangxue336/article/details/21073571#)[copy](http://blog.csdn.net/xiangxue336/article/details/21073571#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/230977)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/230977/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; POSITION_TOP_LEFT = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; POSITION_TOP_RIGHT = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; POSITION_BOTTOM_LEFT = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; POSITION_BOTTOM_RIGHT = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; POSITION_CENTER = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;; 设置字体大小、颜色、背景色：\n**[java]** [view plain](http://blog.csdn.net/xiangxue336/article/details/21073571#)[copy](http://blog.csdn.net/xiangxue336/article/details/21073571#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/230977)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/230977/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - badge2.setTextColor(Color.BLUE); - badge2.setBadgeBackgroundColor(Color.YELLOW); - badge2.setTextSize(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;12\u0026lt;/span\u0026gt;); 设置显示边距、显示隐藏动画：\n**[java]** [view plain](http://blog.csdn.net/xiangxue336/article/details/21073571#)[copy](http://blog.csdn.net/xiangxue336/article/details/21073571#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/230977)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/230977/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - badge4.setBadgeMargin(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;15\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;); - badge4.setBadgeBackgroundColor(Color.parseColor(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;#A4C639\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - btnAnim2.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - TranslateAnimation anim = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TranslateAnimation(-\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - anim.setInterpolator(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BounceInterpolator()); - anim.setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); - badge4.toggle(anim, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - } - }); toggle(anim, null)方法中，第一个参数是显示时候的动画，第二个参数是隐藏时候的动画。\n设置图片背景和点击事件：\n**[java]** [view plain](http://blog.csdn.net/xiangxue336/article/details/21073571#)[copy](http://blog.csdn.net/xiangxue336/article/details/21073571#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/230977)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/230977/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - badge6.setBackgroundResource(R.drawable.badge_ifaux); - badge6.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - Toast.makeText(DemoActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;clicked badge\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); - } - }); 一般背景图片要经过.9处理，因为随着显示数字增大背景图片只是横向拉伸。\n标签有时候往往会有点击一次加以的需求，这里也提供了现成的方法\n**[java]** [view plain](http://blog.csdn.net/xiangxue336/article/details/21073571#)[copy](http://blog.csdn.net/xiangxue336/article/details/21073571#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/230977)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/230977/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - btnIncrement.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (badge8.isShown()) { - badge8.increment(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - badge8.show(); - } - } - ); 到此BadgeView的所有使用方法介绍差不多了，别人搞好的东西，使用起来很简单，主要记录下方法他能提供的功能。如果有特殊的需求可以对BadgeView进行改造。下节主要分析下，oschina-app里面对BadgeView的使用逻辑流程。\noschina-app完整源码下载：[http://download.csdn.net/detail/xiangxue336/7023661](http://download.csdn.net/detail/xiangxue336/7023661) 转自：http://blog.csdn.net/xiangxue336/article/details/21073571 \u0026amp;nbsp; 相关的git项目地址： https://github.com/jgilfelt/android-viewbadger https://github.com/stefanjauker/BadgeView https://github.com/chenupt/BezierDemo https://github.com/chenupt/SpringIndicator ","permalink":"https://blog.zdltech.com/posts/oschina-app%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E6%8F%90%E9%86%92%E6%A0%87%E7%AD%BEbadgeview%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95httpsgithub-comchenuptbezierdemo/","summary":"\u003cp\u003e看过oschina-app的数字提醒标签BadgeView的使用过程，才发现以前项目中的实现逻辑有问题。以前待的项目组没个牛人，从我干第一个项目就我负责开发设计和管理，可想而知，顶多也就实现功能交工。说到底就是经验不足，所以有时间还是多看看别人的代码。本来是想主要讲oschina-app里面提醒标签的实现逻辑，但我觉得标签控件BadgeView有必要说下。\u003c/p\u003e\n\u003cp\u003eBadgeView是一个开源的ui项目，其实就一个ui工具类，BadgeView是对TextView的重写，他的代码就不贴了，可以到git上下最新的吧：\u003ca href=\"https://github.com/jgilfelt/android-viewbadger\"\u003ehttps://github.com/jgilfelt/android-viewbadger\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e在这里主要说下他的用法，它可以设置标签的背景、颜色、位置、动画、文字等，对一般的需求足以满足了，先看下git上demo的效果：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140312095218421?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhbmd4dWUzMzY=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e默认属性标签代码：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/xiangxue336/article/details/21073571#)[copy](http://blog.csdn.net/xiangxue336/article/details/21073571#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/230977)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/230977/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// *** default badge ***\u0026lt;/span\u0026gt;\n\n- \n- View target = findViewById(R.id.default_target);\n\n- BadgeView badge = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BadgeView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, target);\n\n- badge.setText(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- badge.show();\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e默认是显示在右上角，红色的背景白色字体，这些个默认属性是可以在BadgeView里面设置的。\u003c/p\u003e\n\u003cp\u003e设置position代码：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/xiangxue336/article/details/21073571#)[copy](http://blog.csdn.net/xiangxue336/article/details/21073571#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/230977)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/230977/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// *** set position ***\u0026lt;/span\u0026gt;\n\n- \n- btnPosition = (Button) findViewById(R.id.position_target);\n\n- badge1 = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BadgeView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, btnPosition);\n\n- badge1.setText(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;12\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- badge1.setBadgePosition(BadgeView.POSITION_CENTER);\n\n- btnPosition.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) {\n\n- badge1.toggle();\n\n- }\n\n- });\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003etoggle方法是控制标签的现实和隐藏的。\u003c/p\u003e","title":"oschina-app源码分析-提醒标签BadgeView使用方法https://github.com/chenupt/BezierDemo"},{"content":" Java代码 \u0026lt;embed src=\u0026quot;http://androidbin.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;a title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://androidbin.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; - Paint p = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(Paint.ANTI_ALIAS_FLAG); - p.setStyle(Style.STROKE); - p.setColor(Color.WHITE); - p.setStrokeWidth(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - PathEffect effects = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DashPathEffect(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] { \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;}, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - p.setPathEffect(effects); - canvas.drawLine(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;40\u0026lt;/span\u0026gt;, mWidth, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;40\u0026lt;/span\u0026gt;, p); DashPathEffect是PathEffect类的一个子类,可以使paint画出类似虚线的样子,并且可以任意指定虚实的排列方式.\n代码中的float数组,必须是偶数长度,且\u0026gt;=2,指定了多少长度的实线之后再画多少长度的空白.\n如本代码中,绘制长度1的实线,再绘制长度2的空白,再绘制长度4的实线,再绘制长度8的空白,依次重复.1是偏移量,可以不用理会.\n效果如下:\n简单介绍下 PathEffect类:\nPathEffect是用来控制绘制轮廓(线条)的方式。\nPathEffect对于绘制Path基本图形特别有用，但是它们也可以应用到任何Paint中从而影响线条绘制的方式。\n使用PathEffect，可以改变一个形状的边角的外观并且控制轮廓的外表。\nAndroid包含了多个PathEffect，包括：\nCornerPathEffect 可以使用圆角来代替尖锐的角从而对基本图形的形状尖锐的边角进行平滑。\nDashPathEffect 可以使用DashPathEffect来创建一个虚线的轮廓(短横线/小圆点)，而不是使用实线。你还可以指定任意的虚/实线段的重复模式。\nDiscretePathEffect 与DashPathEffect相似，但是添加了随机性。当绘制它的时候，需要指定每一段的长度和与原始路径的偏离度。\nPathDashPathEffect 这种效果可以定义一个新的形状(路径)并将其用作原始路径的轮廓标记。\n下面的效果可以在一个Paint中组合使用多个Path Effect。\nSumPathEffect 顺序地在一条路径中添加两种效果，这样每一种效果都可以应用到原始路径中，而且两种结果可以结合起来。\nComposePathEffect 将两种效果组合起来应用，先使用第一种效果，然后在这种效果的基础上应用第二种效果。\n对象形状的PathEffect的改变会影响到形状的区域。这就能够保证应用到相同形状的填充效果将会绘制到新的边界中。\n例如：只要修改相关属性相信就可以满足你的要求\npublic class DashedLineView extends View {\npublic DashedLineView(Context context, AttributeSet attrs,\nint defStyleAttr, int defStyleRes) {\nthis(context, attrs, defStyleAttr);\n}\npublic DashedLineView(Context context, AttributeSet attrs, int defStyleAttr) {\nsuper(context, attrs, defStyleAttr);\n}\npublic DashedLineView(Context context, AttributeSet attrs) {\nsuper(context, attrs);\n}\npublic DashedLineView(Context context) {\nsuper(context);\n}\n@SuppressLint(“DrawAllocation”)\n@Override\nprotected void onDraw(Canvas canvas) {\n// TODO Auto-generated method stub\nsuper.onDraw(canvas);\nPaint paint = new Paint(Paint.ANTI_ALIAS_FLAG);\npaint.setStyle(Paint.Style.STROKE);\npaint.setColor(Color.BLACK);\npaint.setStrokeWidth(0.5f);\nPath path = new Path();\npath.moveTo(0, 10);\npath.lineTo(getWidth(), 10);\nPathEffect effects = new DashPathEffect(new float[] { 5, 5, 5, 5 }, 1);\npaint.setPathEffect(effects);\ncanvas.drawPath(path, paint);\n}\n}\n","permalink":"https://blog.zdltech.com/posts/android%E4%B8%AD%E7%94%BB%E8%99%9A%E7%BA%BF-patheffect%E7%B1%BB%E7%AE%80%E5%8D%95%E8%AE%A4%E8%AF%86/","summary":"\u003cdiv id=\"\" class=\"dp-highlighter\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      Java代码 \n\u003cpre\u003e\u003ccode\u003e  \u0026lt;embed src=\u0026quot;http://androidbin.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;14\u0026quot; height=\u0026quot;15\u0026quot;\u0026gt;\n  \u0026lt;/embed\u0026gt; \n  \n  \u0026lt;a title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://androidbin.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- Paint p = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(Paint.ANTI_ALIAS_FLAG);\n\n- p.setStyle(Style.STROKE);\n\n- p.setColor(Color.WHITE);\n\n- p.setStrokeWidth(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);\n\n- PathEffect effects = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DashPathEffect(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] { \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;}, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);\n\n- p.setPathEffect(effects);\n\n- canvas.drawLine(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;40\u0026lt;/span\u0026gt;, mWidth, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;40\u0026lt;/span\u0026gt;, p);\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003eDashPathEffect是PathEffect类的一个子类,可以使paint画出类似虚线的样子,并且可以任意指定虚实的排列方式.\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e代码中的float数组,必须是偶数长度,且\u0026gt;=2,指定了多少长度的实线之后再画多少长度的空白.\u003c/p\u003e\n\u003cp\u003e如本代码中,绘制长度1的实线,再绘制长度2的空白,再绘制长度4的实线,再绘制长度8的空白,依次重复.1是偏移量,可以不用理会.\u003c/p\u003e\n\u003cp\u003e效果如下:\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://dl.iteye.com/upload/attachment/0066/6551/80fe6292-6ac4-3be4-8620-9d0858a74bc0.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e简单介绍下 PathEffect类:\u003c/p\u003e\n\u003cp\u003ePathEffect是用来控制绘制轮廓(线条)的方式。\u003c/p\u003e\n\u003cp\u003ePathEffect对于绘制Path基本图形特别有用，但是它们也可以应用到任何Paint中从而影响线条绘制的方式。\u003c/p\u003e\n\u003cp\u003e使用PathEffect，可以改变一个形状的边角的外观并且控制轮廓的外表。\u003c/p\u003e\n\u003cp\u003eAndroid包含了多个PathEffect，包括：\u003c/p\u003e\n\u003cp\u003eCornerPathEffect  可以使用圆角来代替尖锐的角从而对基本图形的形状尖锐的边角进行平滑。\u003c/p\u003e","title":"android中画虚线–.PathEffect类简单认识"},{"content":"转自: http://blog.csdn.net/taotao19880301/article/details/17119249\n工程中使用了fastjson，无奈，对工程做混淆的时候总是报错过不去，后来过去了又出现使用fastjson的地方数据不正确的问题，试了好多办法才成功，废话不多说，添加的代码：\n[view plain](http://www.programgo.com/article/6267404252/#) - ##\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;Begin: proguard configuration \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; fastjson \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;- - - #-keepnames \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; * \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; java.io.Serializable - -keep \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; * \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; java.io.Serializable { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; *; - } - -keepclassmembers \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; * \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; java.io.Serializable { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; serialVersionUID; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; java.io.ObjectStreamField[] serialPersistentFields; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; writeObject(java.io.ObjectOutputStream); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; readObject(java.io.ObjectInputStream); - java.lang.Object writeReplace(); - java.lang.Object readResolve(); - } - -dontwarn android.support.** - -dontwarn com.alibaba.fastjson.** - - -dontskipnonpubliclibraryclassmembers - -dontskipnonpubliclibraryclasses - - -libraryjars libs/fastjson.jar - -keep \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; com.alibaba.fastjson.** { *; } - - -keepclassmembers \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; * { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;methods\u0026gt;; - } - - ##\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;End: proguard configuration \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; fastjson \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;- Gson的混淆：\n[view plain](http://www.programgo.com/article/6267404252/#) - ##\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;Begin: proguard configuration \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; Gson \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;- - # Gson uses generic type information stored in a \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; file when working with fields. Proguard - # removes such information by \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;, so configure it to keep all of it. - -keepattributes Signature - - # For using GSON \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Expose\u0026lt;/span\u0026gt; annotation - -keepattributes *Annotation* - - # Gson specific classes - -keep \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; sun.misc.Unsafe { *; } - #-keep \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; com.google.gson.stream.** { *; } - - - # Application classes that will be serialized/deserialized over Gson - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;color:#ff0000;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;-keep \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; cn.howie.base.data.** { *; } - -keep \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; cn.howie.base.bean.** { *; }\u0026lt;/span\u0026gt; - - - ##\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;End: proguard configuration \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; Gson \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;- 其中红色部分必须为自己项目中的实体类，否则混淆后无法正常显示数据，网上有好多博客都很坑，直接把google文档的代码直接贴出来了，一定要修改红色部分。\n","permalink":"https://blog.zdltech.com/posts/%E5%B7%A5%E7%A8%8B%E5%B8%A6%E6%9C%89fastjson%E6%88%96gson%E7%AD%89%E7%9A%84%E7%AC%AC%E4%B8%89%E6%96%B9%E5%8C%85%E7%9A%84%E6%B7%B7%E6%B7%86%E9%85%8D%E7%BD%AE/","summary":"\u003cp\u003e\u003cstrong\u003e转自\u003c/strong\u003e: \u003ca href=\"http://blog.csdn.net/taotao19880301/article/details/17119249\"\u003ehttp://blog.csdn.net/taotao19880301/article/details/17119249\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e工程中使用了fastjson，无奈，对工程做混淆的时候总是报错过不去，后来过去了又出现使用fastjson的地方数据不正确的问题，试了好多办法才成功，废话不多说，添加的代码：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      [view plain](http://www.programgo.com/article/6267404252/#)\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- ##\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;Begin: proguard configuration \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; fastjson  \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;-\n\n- \n- #-keepnames \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; * \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; java.io.Serializable\n\n- -keep \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; * \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; java.io.Serializable {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; *;\n\n- }\n\n- -keepclassmembers \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; * \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; java.io.Serializable {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; serialVersionUID;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; java.io.ObjectStreamField[] serialPersistentFields;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; writeObject(java.io.ObjectOutputStream);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; readObject(java.io.ObjectInputStream);\n\n- java.lang.Object writeReplace();\n\n- java.lang.Object readResolve();\n\n- }\n\n- -dontwarn android.support.**\n\n- -dontwarn com.alibaba.fastjson.**\n\n- \n- -dontskipnonpubliclibraryclassmembers\n\n- -dontskipnonpubliclibraryclasses\n\n- \n- -libraryjars libs/fastjson.jar\n\n- -keep \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; com.alibaba.fastjson.** { *; }\n\n- \n- -keepclassmembers \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; * {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;methods\u0026gt;;\n\n- }\n\n- \n- ##\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;End: proguard configuration \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; fastjson  \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;-\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003eGson的混淆：\u003c/p\u003e","title":"工程带有Fastjson或Gson等的第三方包的混淆配置"},{"content":"转载请注明出处：http://blog.csdn.net/guolin_blog/article/details/8689140\n大家好，今天给大家带来一个仿360手机卫士悬浮窗效果的教程，在开始之前请允许我说几句不相干的废话。\n不知不觉我发现自己接触Android已有近三个年头了，期间各种的成长少不了各位高手的帮助，总是有很多高手喜欢把自己的经验写在网上，供大家来学习，我也是从中受惠了很多，在此我深表感谢。可是我发现我却从来没有将自己平时的一些心得拿出来与大家分享，共同学习，太没有奉献精神了。于是我痛定思痛，决定从今天开始写博客，希望可以指点在我后面的开发者，更快地进入Android开发者的行列当中。\n好了，废话就说这么多，下面开始进入今天的主题吧。\n360手机卫士我相信大家都知道，好多人手机上都会装这一款软件，那么我们对它的一个桌面悬浮窗效果想必都不会陌生。请看下图：\n首先是一个小的悬浮窗显示的是当前使用了百分之多少的内存，点击一下小悬浮窗，就会弹出一个大的悬浮窗，可以一键加速。好，我们现在就来模拟实现一下类似的效果。\n先谈一下基本的实现原理，这种桌面悬浮窗的效果很类似与Widget，但是它比Widget要灵活的多。主要是通过WindowManager这个类来实现的，调用这个类的addView方法用于添加一个悬浮窗，updateViewLayout方法用于更新悬浮窗的参数，removeView用于移除悬浮窗。其中悬浮窗的参数有必要详细说明一下。\nWindowManager.LayoutParams这个类用于提供悬浮窗所需的参数，其中有几个经常会用到的变量：\ntype值用于确定悬浮窗的类型，一般设为2002，表示在所有应用程序之上，但在状态栏之下。\nflags值用于确定悬浮窗的行为，比如说不可聚焦，非模态对话框等等，属性非常多，大家可以查看文档。\ngravity值用于确定悬浮窗的对齐方式，一般设为左上角对齐，这样当拖动悬浮窗的时候方便计算坐标。\nx值用于确定悬浮窗的位置，如果要横向移动悬浮窗，就需要改变这个值。\ny值用于确定悬浮窗的位置，如果要纵向移动悬浮窗，就需要改变这个值。\nwidth值用于指定悬浮窗的宽度。\nheight值用于指定悬浮窗的高度。\n创建悬浮窗这种窗体需要向用户申请权限才可以的，因此还需要在AndroidManifest.xml中加入\n原理介绍完了，下面我们开始用代码实现。首先在Eclipse中新建一个Android项目，项目名就叫做360FloatWindowDemo。然后写一下布局文件，布局文件非常简单，只有一个按钮，打开或新建activity_main.xml，加入如下代码：\n**[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/8689140#)[copy](http://blog.csdn.net/guolin_blog/article/details/8689140#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/start_float_window\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;Start Float Window\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 然后再新建一个名为float_window_small.xml的布局文件，用于做为小悬浮窗的布局，在其中加入如下代码：\n**[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/8689140#)[copy](http://blog.csdn.net/guolin_blog/article/details/8689140#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;UTF-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/small_window_layout\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;60dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;25dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bg_small\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/percent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#ffffff\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 再新建一个名为float_window_big.xml的布局文件，用于做为大悬浮窗的布局，在其中加入如下代码：\n**[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/8689140#)[copy](http://blog.csdn.net/guolin_blog/article/details/8689140#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;UTF-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/big_window_layout\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;200dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;100dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bg_big\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/close\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;100dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;40dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;12dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;关闭悬浮窗\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/back\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;100dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;40dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;返回\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 两个悬浮窗布局文件中用到的图片资源，大家可以随便找点图片来代替，同时我会给出源码，大家也可以从源码中取出。然后打开或创建MainActivity，这是项目的主界面，在里面加入如下代码：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/8689140#)[copy](http://blog.csdn.net/guolin_blog/article/details/8689140#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - Button startFloatWindow = (Button) findViewById(R.id.start_float_window); - startFloatWindow.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View arg0) { - Intent intent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, FloatWindowService.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - startService(intent); - finish(); - } - }); - } - } 这里可以看到，MainActivity的代码非窗简单，就是对开启悬浮窗的按钮注册了一个点击事件，用于打开一个服务，然后关闭当前Activity。创建悬浮窗的逻辑都交给服务去做了。好，现在我们来创建这个服务。新建一个名为FloatWindowService的类，这个类继承自Service，在里面加入如下代码：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/8689140#)[copy](http://blog.csdn.net/guolin_blog/article/details/8689140#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; FloatWindowService \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Service { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 用于在线程中创建或移除悬浮窗。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 定时器，定时进行检测当前应该创建还是移除悬浮窗。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Timer timer; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; IBinder onBind(Intent intent) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; onStartCommand(Intent intent, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; flags, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startId) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 开启定时器，每隔0.5秒刷新一次\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (timer == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Timer(); - timer.scheduleAtFixedRate(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; RefreshTask(), \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt;); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onStartCommand(intent, flags, startId); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDestroy() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDestroy(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Service被终止的同时也停止定时器继续运行\u0026lt;/span\u0026gt; - timer.cancel(); - timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; RefreshTask \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; TimerTask { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 当前界面是桌面，且没有悬浮窗显示，则创建悬浮窗。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isHome() \u0026amp;\u0026amp; !MyWindowManager.isWindowShowing()) { - handler.post(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - MyWindowManager.createSmallWindow(getApplicationContext()); - } - }); - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 当前界面不是桌面，且有悬浮窗显示，则移除悬浮窗。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isHome() \u0026amp;\u0026amp; MyWindowManager.isWindowShowing()) { - handler.post(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - MyWindowManager.removeSmallWindow(getApplicationContext()); - MyWindowManager.removeBigWindow(getApplicationContext()); - } - }); - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 当前界面是桌面，且有悬浮窗显示，则更新内存数据。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isHome() \u0026amp;\u0026amp; MyWindowManager.isWindowShowing()) { - handler.post(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - MyWindowManager.updateUsedPercent(getApplicationContext()); - } - }); - } - } - - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 判断当前界面是否是桌面\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isHome() { - ActivityManager mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); - List\u0026lt;RunningTaskInfo\u0026gt; rti = mActivityManager.getRunningTasks(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; getHomes().contains(rti.get(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).topActivity.getPackageName()); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 获得属于桌面的应用的应用包名称\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return 返回包含所有包名的字符串列表\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;String\u0026gt; getHomes() { - List\u0026lt;String\u0026gt; names = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;String\u0026gt;(); - PackageManager packageManager = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getPackageManager(); - Intent intent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(Intent.ACTION_MAIN); - intent.addCategory(Intent.CATEGORY_HOME); - List\u0026lt;ResolveInfo\u0026gt; resolveInfo = packageManager.queryIntentActivities(intent, - PackageManager.MATCH_DEFAULT_ONLY); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (ResolveInfo ri : resolveInfo) { - names.add(ri.activityInfo.packageName); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; names; - } - } FloatWindowService的onStartCommand方法中开启了一个定时器，每隔500毫秒就会执行RefreshTask。在RefreshTask当中，要进行判断，如果手机当前是在桌面的话，就应该显示悬浮窗，如果手机打开了某一个应用程序，就应该移除悬浮窗，如果手机在桌面的话，还应该更新内存使用百分比的数据。而当FloatWindowService被销毁的时候，应该将定时器停止，否则它还会一直运行。\n从上面的代码我们也可以看出，创建和移除悬浮窗，以及更新悬浮窗内的数据，都是由MyWindowManager这个类来管理的，比起直接把这些代码写在Activity或Service当中，使用一个专门的工具类来管理要好的多。不过要想创建悬浮窗，还是先要把悬浮窗的View写出来。\n新建一个名叫FloatWindowSmallView的类，继承自LinearLayout。新建一个名叫FloatWindowBigView的类，也继承自LinearLayout。\n在FloatWindowSmallView中加入如下代码：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/8689140#)[copy](http://blog.csdn.net/guolin_blog/article/details/8689140#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; FloatWindowSmallView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 记录小悬浮窗的宽度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewWidth; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 记录小悬浮窗的高度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewHeight; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 记录系统状态栏的高度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; statusBarHeight; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 用于更新小悬浮窗的位置\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; WindowManager windowManager; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 小悬浮窗的参数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; WindowManager.LayoutParams mParams; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 记录当前手指位置在屏幕上的横坐标值\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; xInScreen; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 记录当前手指位置在屏幕上的纵坐标值\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; yInScreen; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 记录手指按下时在屏幕上的横坐标的值\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; xDownInScreen; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 记录手指按下时在屏幕上的纵坐标的值\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; yDownInScreen; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 记录手指按下时在小悬浮窗的View上的横坐标的值\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; xInView; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 记录手指按下时在小悬浮窗的View上的纵坐标的值\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; yInView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; FloatWindowSmallView(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - LayoutInflater.from(context).inflate(R.layout.float_window_small, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - View view = findViewById(R.id.small_window_layout); - viewWidth = view.getLayoutParams().width; - viewHeight = view.getLayoutParams().height; - TextView percentView = (TextView) findViewById(R.id.percent); - percentView.setText(MyWindowManager.getUsedPercentValue(context)); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent event) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (event.getAction()) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 手指按下时记录必要数据,纵坐标的值都需要减去状态栏高度\u0026lt;/span\u0026gt; - xInView = event.getX(); - yInView = event.getY(); - xDownInScreen = event.getRawX(); - yDownInScreen = event.getRawY() \u0026amp;#8211; getStatusBarHeight(); - xInScreen = event.getRawX(); - yInScreen = event.getRawY() \u0026amp;#8211; getStatusBarHeight(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - xInScreen = event.getRawX(); - yInScreen = event.getRawY() \u0026amp;#8211; getStatusBarHeight(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 手指移动的时候更新小悬浮窗的位置\u0026lt;/span\u0026gt; - updateViewPosition(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果手指离开屏幕时，xDownInScreen和xInScreen相等，且yDownInScreen和yInScreen相等，则视为触发了单击事件。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (xDownInScreen == xInScreen \u0026amp;\u0026amp; yDownInScreen == yInScreen) { - openBigWindow(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 将小悬浮窗的参数传入，用于更新小悬浮窗的位置。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param params\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 小悬浮窗的参数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setParams(WindowManager.LayoutParams params) { - mParams = params; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 更新小悬浮窗在屏幕中的位置。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; updateViewPosition() { - mParams.x = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (xInScreen \u0026amp;#8211; xInView); - mParams.y = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (yInScreen \u0026amp;#8211; yInView); - windowManager.updateViewLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, mParams); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 打开大悬浮窗，同时关闭小悬浮窗。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; openBigWindow() { - MyWindowManager.createBigWindow(getContext()); - MyWindowManager.removeSmallWindow(getContext()); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 用于获取状态栏的高度。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return 返回状态栏高度的像素值。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getStatusBarHeight() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (statusBarHeight == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - Class\u0026lt;?\u0026gt; c = Class.forName(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.android.internal.R$dimen\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Object o = c.newInstance(); - Field field = c.getField(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;status_bar_height\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x = (Integer) field.get(o); - statusBarHeight = getResources().getDimensionPixelSize(x); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) { - e.printStackTrace(); - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; statusBarHeight; - } 其中，对这个View的onTouchEvent事件进行了重写，用于实现拖动和点击的效果。如果发现用户触发了ACTION_DOWN事件，会记录按下时的坐标等数据。如果发现用户触发了ACTION_MOVE事件，则根据当前移动的坐标更新悬浮窗在屏幕中的位置。如果发现用户触发了ACTION_UP事件，会和ACTION_DOWN中记下的坐标对比，如果发现是相同的，则视为用户对悬浮窗进行了点击。点击小悬浮窗则打开大悬浮窗，然后我们来实现大悬浮窗的View。\n在FloatWindowBigView中加入如下代码：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/8689140#)[copy](http://blog.csdn.net/guolin_blog/article/details/8689140#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; FloatWindowBigView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 记录大悬浮窗的宽度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewWidth; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 记录大悬浮窗的高度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewHeight; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; FloatWindowBigView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - LayoutInflater.from(context).inflate(R.layout.float_window_big, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - View view = findViewById(R.id.big_window_layout); - viewWidth = view.getLayoutParams().width; - viewHeight = view.getLayoutParams().height; - Button close = (Button) findViewById(R.id.close); - Button back = (Button) findViewById(R.id.back); - close.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 点击关闭悬浮窗的时候，移除所有悬浮窗，并停止Service\u0026lt;/span\u0026gt; - MyWindowManager.removeBigWindow(context); - MyWindowManager.removeSmallWindow(context); - Intent intent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(getContext(), FloatWindowService.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - context.stopService(intent); - } - }); - back.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 点击返回的时候，移除大悬浮窗，创建小悬浮窗\u0026lt;/span\u0026gt; - MyWindowManager.removeBigWindow(context); - MyWindowManager.createSmallWindow(context); - } - }); - } - } 比起FloatWindowSmallView，FloatWindowBigView要简单的多，其中只有两个按钮，点击close按钮，将悬浮窗全部移除，并将Service终止。单击back按钮则移除大悬浮窗，重新创建小悬浮窗。\n现在两个悬浮窗的View都已经写好了，我们来创建MyWindowManager，代码如下：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/8689140#)[copy](http://blog.csdn.net/guolin_blog/article/details/8689140#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyWindowManager { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 小悬浮窗View的实例\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; FloatWindowSmallView smallWindow; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 大悬浮窗View的实例\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; FloatWindowBigView bigWindow; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 小悬浮窗View的参数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; LayoutParams smallWindowParams; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 大悬浮窗View的参数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; LayoutParams bigWindowParams; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 用于控制在屏幕上添加或移除悬浮窗\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; WindowManager mWindowManager; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 用于获取手机可用内存\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; ActivityManager mActivityManager; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 创建一个小悬浮窗。初始位置为屏幕的右部中间位置。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 必须为应用程序的Context.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; createSmallWindow(Context context) { - WindowManager windowManager = getWindowManager(context); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; screenWidth = windowManager.getDefaultDisplay().getWidth(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; screenHeight = windowManager.getDefaultDisplay().getHeight(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (smallWindow == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - smallWindow = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; FloatWindowSmallView(context); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (smallWindowParams == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - smallWindowParams = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(); - smallWindowParams.type = LayoutParams.TYPE_PHONE; - smallWindowParams.format = PixelFormat.RGBA_8888; - smallWindowParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL - | LayoutParams.FLAG_NOT_FOCUSABLE; - smallWindowParams.gravity = Gravity.LEFT | Gravity.TOP; - smallWindowParams.width = FloatWindowSmallView.viewWidth; - smallWindowParams.height = FloatWindowSmallView.viewHeight; - smallWindowParams.x = screenWidth; - smallWindowParams.y = screenHeight / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - } - smallWindow.setParams(smallWindowParams); - windowManager.addView(smallWindow, smallWindowParams); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 将小悬浮窗从屏幕上移除。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 必须为应用程序的Context.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; removeSmallWindow(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (smallWindow != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - WindowManager windowManager = getWindowManager(context); - windowManager.removeView(smallWindow); - smallWindow = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 创建一个大悬浮窗。位置为屏幕正中间。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 必须为应用程序的Context.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; createBigWindow(Context context) { - WindowManager windowManager = getWindowManager(context); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; screenWidth = windowManager.getDefaultDisplay().getWidth(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; screenHeight = windowManager.getDefaultDisplay().getHeight(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (bigWindow == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - bigWindow = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; FloatWindowBigView(context); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (bigWindowParams == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - bigWindowParams = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(); - bigWindowParams.x = screenWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; \u0026amp;#8211; FloatWindowBigView.viewWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - bigWindowParams.y = screenHeight / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; \u0026amp;#8211; FloatWindowBigView.viewHeight / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - bigWindowParams.type = LayoutParams.TYPE_PHONE; - bigWindowParams.format = PixelFormat.RGBA_8888; - bigWindowParams.gravity = Gravity.LEFT | Gravity.TOP; - bigWindowParams.width = FloatWindowBigView.viewWidth; - bigWindowParams.height = FloatWindowBigView.viewHeight; - } - windowManager.addView(bigWindow, bigWindowParams); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 将大悬浮窗从屏幕上移除。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 必须为应用程序的Context.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; removeBigWindow(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (bigWindow != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - WindowManager windowManager = getWindowManager(context); - windowManager.removeView(bigWindow); - bigWindow = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 更新小悬浮窗的TextView上的数据，显示内存使用的百分比。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 可传入应用程序上下文。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; updateUsedPercent(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (smallWindow != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - TextView percentView = (TextView) smallWindow.findViewById(R.id.percent); - percentView.setText(getUsedPercentValue(context)); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 是否有悬浮窗(包括小悬浮窗和大悬浮窗)显示在屏幕上。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return 有悬浮窗显示在桌面上返回true，没有的话返回false。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isWindowShowing() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; smallWindow != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || bigWindow != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 如果WindowManager还未创建，则创建一个新的WindowManager返回。否则返回当前已创建的WindowManager。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 必须为应用程序的Context.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return WindowManager的实例，用于控制在屏幕上添加或移除悬浮窗。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; WindowManager getWindowManager(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mWindowManager == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mWindowManager; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 如果ActivityManager还未创建，则创建一个新的ActivityManager返回。否则返回当前已创建的ActivityManager。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 可传入应用程序上下文。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return ActivityManager的实例，用于获取手机可用内存。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; ActivityManager getActivityManager(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mActivityManager == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mActivityManager; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 计算已使用内存的百分比，并返回。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 可传入应用程序上下文。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return 已使用内存的百分比，以字符串形式返回。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String getUsedPercentValue(Context context) { - String dir = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;/proc/meminfo\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - FileReader fr = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; FileReader(dir); - BufferedReader br = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BufferedReader(fr, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2048\u0026lt;/span\u0026gt;); - String memoryLine = br.readLine(); - String subMemoryLine = memoryLine.substring(memoryLine.indexOf(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;MemTotal:\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - br.close(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; totalMemorySize = Integer.parseInt(subMemoryLine.replaceAll(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\\\\D+\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; availableSize = getAvailableMemory(context) / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1024\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; percent = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) ((totalMemorySize \u0026amp;#8211; availableSize) / (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) totalMemorySize * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; percent + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;%\u0026amp;#8221;\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) { - e.printStackTrace(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;悬浮窗\u0026amp;#8221;\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 获取当前可用内存，返回数据以字节为单位。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 可传入应用程序上下文。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return 当前可用内存。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getAvailableMemory(Context context) { - ActivityManager.MemoryInfo mi = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ActivityManager.MemoryInfo(); - getActivityManager(context).getMemoryInfo(mi); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mi.availMem; - } - - } 这个类负责了控制大悬浮窗，小悬浮窗的创建和移除，系统内存使用百分比的计算等操作。\n到这里基本所有的代码都已经写完了，然后我们来看一下AndroidManifest.xml文件吧，里面代码如下：\n**[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/8689140#)[copy](http://blog.csdn.net/guolin_blog/article/details/8689140#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;manifest\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;com.demo.floatwindowdemo\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:versionCode\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:versionName\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;uses-permission\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.permission.SYSTEM_ALERT_WINDOW\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;uses-sdk\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:minSdkVersion\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;8\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:targetSdkVersion\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;8\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;application\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:allowBackup\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:icon\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_launcher\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:label\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@string/app_name\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:theme\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@style/AppTheme\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;com.demo.floatwindowdemo.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:label\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@string/app_name\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;action\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.action.MAIN\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;category\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.category.LAUNCHER\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;service\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;.FloatWindowService\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;service\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;application\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;manifest\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 比较简单，记得把Activity和Service在里面注册好，还有一个权限声明需要添加的android.permission.SYSTEM_ALERT_WINDOW，表示需要用户授权允许创建系统提示窗口，也就是我们的桌面悬浮窗。\n好了，现在让我们运行一下项目吧，效果如下图，主界面只有一个简单的按钮，点击按钮后，Activity被关闭，小悬浮窗显示在桌面上。其中显示着当前内存使用的百分比。\n小悬浮窗是可以自由拖动的，如果打开了其它的应用程序，小悬浮窗会自动隐藏，回到桌面后小悬浮窗又会显示出来。\n如果点击了小悬浮窗会弹出大悬浮窗来，这里我们大悬浮窗做的比较简单，就只有两个按钮。大悬浮窗展示的时候手机的所有其它程序是不可点的，因为焦点都在悬浮窗上了。点击返回按钮会重新展示小悬浮窗，点击关闭悬浮窗按钮，Service也会一起停掉。\n360手机卫士的一键加速功能我们就不做了，就像独孤九剑一样，重要的是剑意而不是剑招，我相信大家学会了创建悬浮窗的基本原理后可以做出比360更有创意的东西。\n如果大家还有什么疑问，请在下面留言。\n对桌面悬浮窗感兴趣的朋友可以继续阅读 Android桌面悬浮窗进阶，QQ手机管家小火箭效果实现 。\n源码下载，请点击这里\n补充： 有朋友跟我反应，上面的代码在Android 3.0以上的系统运行会崩溃，我看了一下，确实如此，主要是3.0之后想要获取正在运行的任务，需要加上权限声明。在AndroidManifest.xml中加入 即可解决此问题。 ","permalink":"https://blog.zdltech.com/posts/android%E6%A1%8C%E9%9D%A2%E6%82%AC%E6%B5%AE%E7%AA%97%E6%95%88%E6%9E%9C%E5%AE%9E%E7%8E%B0%E4%BB%BF360%E6%89%8B%E6%9C%BA%E5%8D%AB%E5%A3%AB%E6%82%AC%E6%B5%AE%E7%AA%97%E6%95%88%E6%9E%9C/","summary":"\u003cp\u003e转载请注明出处：\u003ca href=\"http://blog.csdn.net/guolin_blog/article/details/8689140\"\u003ehttp://blog.csdn.net/guolin_blog/article/details/8689140\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e大家好，今天给大家带来一个仿360手机卫士悬浮窗效果的教程，在开始之前请允许我说几句不相干的废话。\u003c/p\u003e\n\u003cp\u003e不知不觉我发现自己接触Android已有近三个年头了，期间各种的成长少不了各位高手的帮助，总是有很多高手喜欢把自己的经验写在网上，供大家来学习，我也是从中受惠了很多，在此我深表感谢。可是我发现我却从来没有将自己平时的一些心得拿出来与大家分享，共同学习，太没有奉献精神了。于是我痛定思痛，决定从今天开始写博客，希望可以指点在我后面的开发者，更快地进入Android开发者的行列当中。\u003c/p\u003e\n\u003cp\u003e好了，废话就说这么多，下面开始进入今天的主题吧。\u003c/p\u003e\n\u003cp\u003e360手机卫士我相信大家都知道，好多人手机上都会装这一款软件，那么我们对它的一个桌面悬浮窗效果想必都不会陌生。请看下图：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.my.csdn.net/uploads/201303/18/1363616413_6003.png\"\u003e                        \u003cimg loading=\"lazy\" src=\"http://img.my.csdn.net/uploads/201303/18/1363616427_5380.png\"\u003e\u003c/p\u003e\n\u003cp\u003e首先是一个小的悬浮窗显示的是当前使用了百分之多少的内存，点击一下小悬浮窗，就会弹出一个大的悬浮窗，可以一键加速。好，我们现在就来模拟实现一下类似的效果。\u003c/p\u003e\n\u003cp\u003e先谈一下基本的实现原理，这种桌面悬浮窗的效果很类似与Widget，但是它比Widget要灵活的多。主要是通过WindowManager这个类来实现的，调用这个类的addView方法用于添加一个悬浮窗，updateViewLayout方法用于更新悬浮窗的参数，removeView用于移除悬浮窗。其中悬浮窗的参数有必要详细说明一下。\u003c/p\u003e\n\u003cp\u003eWindowManager.LayoutParams这个类用于提供悬浮窗所需的参数，其中有几个经常会用到的变量：\u003c/p\u003e\n\u003cp\u003etype值用于确定悬浮窗的类型，一般设为2002，表示在所有应用程序之上，但在状态栏之下。\u003c/p\u003e\n\u003cp\u003eflags值用于确定悬浮窗的行为，比如说不可聚焦，非模态对话框等等，属性非常多，大家可以查看文档。\u003c/p\u003e\n\u003cp\u003egravity值用于确定悬浮窗的对齐方式，一般设为左上角对齐，这样当拖动悬浮窗的时候方便计算坐标。\u003c/p\u003e\n\u003cp\u003ex值用于确定悬浮窗的位置，如果要横向移动悬浮窗，就需要改变这个值。\u003c/p\u003e\n\u003cp\u003ey值用于确定悬浮窗的位置，如果要纵向移动悬浮窗，就需要改变这个值。\u003c/p\u003e\n\u003cp\u003ewidth值用于指定悬浮窗的宽度。\u003c/p\u003e\n\u003cp\u003eheight值用于指定悬浮窗的高度。\u003c/p\u003e\n\u003cp\u003e创建悬浮窗这种窗体需要向用户申请权限才可以的，因此还需要在AndroidManifest.xml中加入\u003cuses-permission android:name=\u0026#8221;android.permission.SYSTEM\\_ALERT\\_WINDOW\u0026#8221; /\u003e\u003c/p\u003e\n\u003cp\u003e原理介绍完了，下面我们开始用代码实现。首先在Eclipse中新建一个Android项目，项目名就叫做360FloatWindowDemo。然后写一下布局文件，布局文件非常简单，只有一个按钮，打开或新建activity_main.xml，加入如下代码：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/8689140#)[copy](http://blog.csdn.net/guolin_blog/article/details/8689140#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/start_float_window\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;Start Float Window\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e然后再新建一个名为float_window_small.xml的布局文件，用于做为小悬浮窗的布局，在其中加入如下代码：\u003c/p\u003e","title":"Android桌面悬浮窗效果实现，仿360手机卫士悬浮窗效果"},{"content":"转帖（http://blog.csdn.net/xiaanming/article/details/17718579）\n在Android开发中，我们常常用到ListView和GridView，而有的时候系统的ListView，GridView并不能满足我们的需求，所以我们需要自己定义一个ListView或者GridView,我的上一篇文章中就是自定义的一个左右滑动删除item的例子，大家有兴趣的可以去看看 Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果，今天这篇文章就给大家来自定义GridView的控件，GridView主要是来显示网格的控件，在Android的开发中使用很普通，相对于TextView，Button这些控件来说要来的复杂些，今天给大家带来长按GridView的item,然后将其拖拽其他item上面，使得GridView的item发生交换，比较典型的就是我们的Launcher，网上有很多关于GridView的拖动的Demo，但是大部分都是相同的，而且存在一些Bug,而且大部分都是点击GridView的item然后进行拖动，或者item之间不进行实时交换，今天给大家更加详细的介绍GridView拖拽，并且将Demo做的更完美，大家更容易接受，也许很多人听到这个感觉实现起来很复杂，就关掉的这篇文章，其实告诉大家，只要知道了思路就感觉一点都不复杂了，不信大家可以接着往下看看，首先还是跟大家说说实现的思路\n根据手指按下的X,Y坐标来获取我们在GridView上面点击的item 手指按下的时候使用Handler和Runnable来实现一个定时器，假如定时时间为1000毫秒，在1000毫秒内，如果手指抬起了移除定时器，没有抬起并且手指点击在GridView的item所在的区域，则表示我们长按了GridView的item 如果我们长按了item则隐藏item,然后使用WindowManager来添加一个item的镜像在屏幕用来代替刚刚隐藏的item 当我们手指在屏幕移动的时候，更新item镜像的位置，然后在根据我们移动的X,Y的坐标来获取移动到GridView的哪一个位置 到GridView的item过多的时候，可能一屏幕显示不完，我们手指拖动item镜像到屏幕下方，要触发GridView想上滚动，同理，当我们手指拖动item镜像到屏幕上面，触发GridView向下滚动 GridView交换数据，刷新界面，移除item的镜像 看完上面的这些思路你是不是找到了些感觉了呢，心里痒痒的想动手试试吧，好吧，接下来就带大家根据思路来实现可拖拽的GridView，新建一个项目就叫DragGridView\n新建一个类DragGridView继承GridView,先来看看DragGridView的代码，然后在根据代码进行相关的讲解\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17718579#)[copy](http://blog.csdn.net/xiaanming/article/details/17718579#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/143802)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/143802/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.draggridview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.PixelFormat; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Rect; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Vibrator; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Gravity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.WindowManager; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; DragGridView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; GridView{ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * DragGridView的item长按响应的时间， 默认是1000毫秒，也可以自行设置\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; dragResponseMS = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 是否可以拖拽，默认不可以\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isDrag = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDownX; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDownY; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveX; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveY; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 正在拖拽的position\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDragPosition; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 刚开始拖拽的item对应的View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View mStartDragItemView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 用于拖拽的镜像，这里直接用一个ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageView mDragImageView; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 震动器\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Vibrator mVibrator; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; WindowManager mWindowManager; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * item镜像的布局参数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; WindowManager.LayoutParams mWindowLayoutParams; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 我们拖拽的item对应的Bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap mDragBitmap; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 按下的点到所在item的上边缘的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mPoint2ItemTop ; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 按下的点到所在item的左边缘的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mPoint2ItemLeft; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * DragGridView距离屏幕顶部的偏移量\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mOffset2Top; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * DragGridView距离屏幕左边的偏移量\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mOffset2Left; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 状态栏的高度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mStatusHeight; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * DragGridView自动向下滚动的边界值\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDownScrollBorder; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * DragGridView自动向上滚动的边界值\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mUpScrollBorder; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * DragGridView自动滚动的速度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; speed = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * item发生变化回调的接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnChanageListener onChanageListener; - - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; DragGridView(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; DragGridView(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, attrs, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; DragGridView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); - mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - mStatusHeight = getStatusHeight(context); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取状态栏的高度\u0026lt;/span\u0026gt; - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler mHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//用来处理是否为长按的Runnable\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Runnable mLongClickRunnable = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - isDrag = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置可以拖拽\u0026lt;/span\u0026gt; - mVibrator.vibrate(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;50\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//震动一下\u0026lt;/span\u0026gt; - mStartDragItemView.setVisibility(View.INVISIBLE);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//隐藏该item\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//根据我们按下的点显示item镜像\u0026lt;/span\u0026gt; - createDragImage(mDragBitmap, mDownX, mDownY); - } - }; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 设置回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param onChanageListener\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnChangeListener(OnChanageListener onChanageListener){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onChanageListener = onChanageListener; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 设置响应拖拽的毫秒数，默认是1000毫秒\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param dragResponseMS\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setDragResponseMS(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; dragResponseMS) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.dragResponseMS = dragResponseMS; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt;(ev.getAction()){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: - mDownX = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) ev.getX(); - mDownY = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) ev.getY(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//根据按下的X,Y坐标获取所点击item的position\u0026lt;/span\u0026gt; - mDragPosition = pointToPosition(mDownX, mDownY); - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mDragPosition == AdapterView.INVALID_POSITION){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(ev); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//使用Handler延迟dragResponseMS执行mLongClickRunnable\u0026lt;/span\u0026gt; - mHandler.postDelayed(mLongClickRunnable, dragResponseMS); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//根据position获取该item所对应的View\u0026lt;/span\u0026gt; - mStartDragItemView = getChildAt(mDragPosition \u0026amp;#8211; getFirstVisiblePosition()); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//下面这几个距离大家可以参考我的博客上面的图来理解下\u0026lt;/span\u0026gt; - mPoint2ItemTop = mDownY \u0026amp;#8211; mStartDragItemView.getTop(); - mPoint2ItemLeft = mDownX \u0026amp;#8211; mStartDragItemView.getLeft(); - - mOffset2Top = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (ev.getRawY() \u0026amp;#8211; mDownY); - mOffset2Left = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (ev.getRawX() \u0026amp;#8211; mDownX); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取DragGridView自动向上滚动的偏移量，小于这个值，DragGridView向下滚动\u0026lt;/span\u0026gt; - mDownScrollBorder = getHeight() /\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取DragGridView自动向下滚动的偏移量，大于这个值，DragGridView向上滚动\u0026lt;/span\u0026gt; - mUpScrollBorder = getHeight() * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;/\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;; - - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//开启mDragItemView绘图缓存\u0026lt;/span\u0026gt; - mStartDragItemView.setDrawingCacheEnabled(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取mDragItemView在缓存中的Bitmap对象\u0026lt;/span\u0026gt; - mDragBitmap = Bitmap.createBitmap(mStartDragItemView.getDrawingCache()); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//这一步很关键，释放绘图缓存，避免出现重复的镜像\u0026lt;/span\u0026gt; - mStartDragItemView.destroyDrawingCache(); - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveX = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)ev.getX(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveY = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) ev.getY(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//如果我们在按下的item上面移动，只要不超过item的边界我们就不移除mRunnable\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!isTouchInItem(mStartDragItemView, moveX, moveY)){ - mHandler.removeCallbacks(mLongClickRunnable); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - mHandler.removeCallbacks(mLongClickRunnable); - mHandler.removeCallbacks(mScrollRunnable); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(ev); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 是否点击在GridView的item上面\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param itemView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param x\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param y\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isTouchInItem(View dragView, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(dragView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; leftOffset = dragView.getLeft(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; topOffset = dragView.getTop(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(x \u0026lt; leftOffset || x \u0026gt; leftOffset + dragView.getWidth()){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(y \u0026lt; topOffset || y \u0026gt; topOffset + dragView.getHeight()){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent ev) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(isDrag \u0026amp;\u0026amp; mDragImageView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt;(ev.getAction()){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - moveX = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) ev.getX(); - moveY = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) ev.getY(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//拖动item\u0026lt;/span\u0026gt; - onDragItem(moveX, moveY); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - onStopDrag(); - isDrag = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 创建拖动的镜像\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param bitmap \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param downX\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 按下的点相对父控件的X坐标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param downY\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 按下的点相对父控件的X坐标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; createDragImage(Bitmap bitmap, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; downX , \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; downY){ - mWindowLayoutParams = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; WindowManager.LayoutParams(); - mWindowLayoutParams.format = PixelFormat.TRANSLUCENT; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//图片之外的其他地方透明\u0026lt;/span\u0026gt; - mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT; - mWindowLayoutParams.x = downX \u0026amp;#8211; mPoint2ItemLeft + mOffset2Left; - mWindowLayoutParams.y = downY \u0026amp;#8211; mPoint2ItemTop + mOffset2Top \u0026amp;#8211; mStatusHeight; - mWindowLayoutParams.alpha = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.55f; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//透明度\u0026lt;/span\u0026gt; - mWindowLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; - mWindowLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; - mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE ; - - mDragImageView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageView(getContext()); - mDragImageView.setImageBitmap(bitmap); - mWindowManager.addView(mDragImageView, mWindowLayoutParams); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 从界面上面移动拖动镜像\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; removeDragImage(){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mDragImageView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - mWindowManager.removeView(mDragImageView); - mDragImageView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 拖动item，在里面实现了item镜像的位置更新，item的相互交换以及GridView的自行滚动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param x\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param y\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDragItem(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveY){ - mWindowLayoutParams.x = moveX \u0026amp;#8211; mPoint2ItemLeft + mOffset2Left; - mWindowLayoutParams.y = moveY \u0026amp;#8211; mPoint2ItemTop + mOffset2Top \u0026amp;#8211; mStatusHeight; - mWindowManager.updateViewLayout(mDragImageView, mWindowLayoutParams); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//更新镜像的位置\u0026lt;/span\u0026gt; - onSwapItem(moveX, moveY); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//GridView自动滚动\u0026lt;/span\u0026gt; - mHandler.post(mScrollRunnable); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 当moveY的值大于向上滚动的边界值，触发GridView自动向上滚动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 当moveY的值小于向下滚动的边界值，触犯GridView自动向下滚动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 否则不进行滚动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Runnable mScrollRunnable = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollY; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(moveY \u0026gt; mUpScrollBorder){ - scrollY = speed; - mHandler.postDelayed(mScrollRunnable, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;25\u0026lt;/span\u0026gt;); - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(moveY \u0026lt; mDownScrollBorder){ - scrollY = -speed; - mHandler.postDelayed(mScrollRunnable, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;25\u0026lt;/span\u0026gt;); - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - scrollY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - mHandler.removeCallbacks(mScrollRunnable); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//当我们的手指到达GridView向上或者向下滚动的偏移量的时候，可能我们手指没有移动，但是DragGridView在自动的滚动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//所以我们在这里调用下onSwapItem()方法来交换item\u0026lt;/span\u0026gt; - onSwapItem(moveX, moveY); - - - smoothScrollBy(scrollY, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;); - } - }; - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 交换item,并且控制item之间的显示与隐藏效果\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param moveX\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param moveY\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSwapItem(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveY){ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取我们手指移动到的那个item的position\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; tempPosition = pointToPosition(moveX, moveY); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//假如tempPosition 改变了并且tempPosition不等于-1,则进行交换\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(tempPosition != mDragPosition \u0026amp;\u0026amp; tempPosition != AdapterView.INVALID_POSITION){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(onChanageListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - onChanageListener.onChange(mDragPosition, tempPosition); - } - - getChildAt(tempPosition \u0026amp;#8211; getFirstVisiblePosition()).setVisibility(View.INVISIBLE);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//拖动到了新的item,新的item隐藏掉\u0026lt;/span\u0026gt; - getChildAt(mDragPosition \u0026amp;#8211; getFirstVisiblePosition()).setVisibility(View.VISIBLE);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//之前的item显示出来\u0026lt;/span\u0026gt; - - mDragPosition = tempPosition; - } - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 停止拖拽我们将之前隐藏的item显示出来，并将镜像移除\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onStopDrag(){ - View view = getChildAt(mDragPosition \u0026amp;#8211; getFirstVisiblePosition()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(view != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - view.setVisibility(View.VISIBLE); - } - ((DragAdapter)\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getAdapter()).setItemHide(-\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - removeDragImage(); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 获取状态栏的高度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param context\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getStatusHeight(Context context){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; statusHeight = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - Rect localRect = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect(); - ((Activity) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(localRect); - statusHeight = localRect.top; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; == statusHeight){ - Class\u0026lt;?\u0026gt; localClass; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - localClass = Class.forName(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.android.internal.R$dimen\u0026amp;#8221;\u0026lt;/span\u0026gt;); - Object localObject = localClass.newInstance(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i5 = Integer.parseInt(localClass.getField(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;status_bar_height\u0026amp;#8221;\u0026lt;/span\u0026gt;).get(localObject).toString()); - statusHeight = context.getResources().getDimensionPixelSize(i5); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) { - e.printStackTrace(); - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; statusHeight; - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnChanageListener{ - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 当item交换位置的时候回调的方法，我们只需要在该方法中实现数据的交换即可\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param form\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 开始的position\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param to \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 拖拽到的position\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onChange(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; form, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; to); - } - } 首先看DragGridView的事件分发方法，不了解Android事件分发的可以先去了解下，Android事件分发对于自定义控件很重要，简单说下，当我们点击DragGridView的Item,先会去执行dispatchTouchEvent()方法将事件分发下去，所以我们要重写dispatchTouchEvent()方法在手指按下的时候根据pointToPosition()方法来获取我们按下的item的position,根据getChildAt()方法来获取该position上面所对应的View, 并且开启长按的定时器，默认时间为1000毫秒，如果在1000毫秒内手指抬起或者手指在屏幕上滑动出了该item，则取消长按定时器，否则就表示可以进行拖拽，手机友好的震动一下，隐藏我们长按的Item，屏幕调用createDragImage()方法来创建我们长按的item的镜像，创建Item的镜像使用的是WindowManager类，该类可以创建一个窗体显示在Activity之上，再此之前大家先要理解这几个距离，理解这几个距离之前要首先知道getRawX(),getRawY()和getX(),getY()的区别，getRawX(),getRawY()是相对于屏幕的原点的距离，而getX(),getY()是相对于控件左上方的点的距离，为了方便大家理解我用Word简单的画了下图，画得不好，大家将就的看下，红色框框为我们的GridView\nmPoint2ItemTop 手指按下的点到该Item的上边缘的距离，如上图的1号线 mPoint2ItemLeft 手指按下的点到该Item的左边缘的距离，如上图的2号线 mOffset2Top DragGridView的上边缘到屏幕上边缘的距离，如上图的3号线，这个距离包裹状态栏，标题栏，或者一些在DragGridView上面的布局的高度，这个很重要我们现实Item镜像需要用到 mOffset2Left DragGridView的左边缘到屏幕左边缘的距离，如上图的4号线，我这个Demo的这个距离为0，因为我设置DragGridView的宽度为充满屏幕，但是我们要考虑假如DragGridView与屏幕左边缘设置了间隙或者左边有其他的布局的情形 mDownScrollBorder 这个距离表示当DragGridView的item过多的时候，手机一屏显示不完全，我们拖动Item镜像到这个高度的时候，DragGridView自动向下滚动，如上图的5号线 .mUpScrollBorder 这个和mDownScrollBorder相反，当我们大于这个高度的时候，DragGridView自动向上滚动，如上图的6号线 理解了这六个距离，我们就来看看创建Item镜像的方法里面，其他的我不多说，首先设置format为PixelFormat.TRANSLUCENT，表示除了我们显示图片和文字的其他地方为透明，之后就是x，y这两个距离的计算，计算的是item的左上角的坐标，理解了上面这六个距离我们很容易得出x,y的坐标，可是你会发现y的坐标减去了状态栏的高度，这点大家需要注意下，另外我们需要获取item的绘制缓存的Bitmap对象，然后将Bitmap设置到一个ImageView上面，为什么要这么做呢？如果调用addView()方法将item 直接添加到WindowManager里面，会有异常产生，因为item已经有了自己归属的父容器DragGridView，所有我们这里使用一个ImageView来代替item添加到WindowManager里面 上面已经完成了开始拖拽的准备工作，要想拖动镜像我们还需要重写onTouchEvent()方法，获取移动的X,Y的坐标，利用WindowManager的updateViewLayout方法就能对镜像进行拖动，拖动的镜像的时候为了有更好的用户体验，我们还要做item的实时交换效果，我们利用手指移动的X,Y坐标，利用pointToPosition()来获取拖拽到的position,然后将之前的item显示出来，将拖拽到的item进行隐藏，这样子就完成了item在界面上面的交换，但是数据交换我这里没有做，所以我提供了回调接口OnChanageListener，我们只需要自己实现数据的交换逻辑然后刷新DragGridView即可，我们还需要实现DragGridView的自动向上滚动或者向下滚动，使用Handler和mScrollRunnable利用smoothScrollToPositionFromTop()来实现DragGridView滚动，具体的实现大家可以看代码 手指离开界面，将item的镜像移除，并将拖拽到的item显示出来，这样子就实现了GirdView的拖拽效果啦，接下来我们来使用下我们自定义可拖拽的GridView吧，先看主界面布局，只有我们自定义的一个DragGridView\n**[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/17718579#)[copy](http://blog.csdn.net/xiaanming/article/details/17718579#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/143802)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/143802/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.draggridview.DragGridView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/dragGridView\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:listSelector\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/transparent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:cacheColorHint\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/transparent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:verticalSpacing\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:horizontalSpacing\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:stretchMode\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;columnWidth\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:numColumns\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;3\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.draggridview.DragGridView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 接下来我们看看DragGridView的item的布局，上面一个ImageView下面一个TextView **[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/17718579#)[copy](http://blog.csdn.net/xiaanming/article/details/17718579#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/143802)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/143802/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/transparent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/item_image\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scaleType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;centerCrop\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerHorizontal\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/item_text\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_below\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/item_image\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerHorizontal\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 布局搞定了我们就来看看主页面MainActivity的代码吧 **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17718579#)[copy](http://blog.csdn.net/xiaanming/article/details/17718579#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/143802)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/143802/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.draggridview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Collections; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.HashMap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.SimpleAdapter; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.draggridview.DragGridView.OnChanageListener; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;HashMap\u0026lt;String, Object\u0026gt;\u0026gt; dataSourceList = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;HashMap\u0026lt;String, Object\u0026gt;\u0026gt;(); - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - DragGridView mDragGridView = (DragGridView) findViewById(R.id.dragGridView); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;30\u0026lt;/span\u0026gt;; i++) { - HashMap\u0026lt;String, Object\u0026gt; itemHashMap = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;String, Object\u0026gt;(); - itemHashMap.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;item_image\u0026amp;#8221;\u0026lt;/span\u0026gt;,R.drawable.com_tencent_open_notice_msg_icon_big); - itemHashMap.put(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;item_text\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;拖拽 \u0026amp;#8220;\u0026lt;/span\u0026gt; + Integer.toString(i)); - dataSourceList.add(itemHashMap); - } - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; SimpleAdapter mSimpleAdapter = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SimpleAdapter(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, dataSourceList, - R.layout.grid_item, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; String[] { \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;item_image\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;item_text\u0026amp;#8221;\u0026lt;/span\u0026gt; }, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] { R.id.item_image, R.id.item_text }); - - mDragGridView.setAdapter(mSimpleAdapter); - - mDragGridView.setOnChangeListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnChanageListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onChange(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; from, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; to) { - HashMap\u0026lt;String, Object\u0026gt; temp = dataSourceList.get(from); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//直接交互item\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// dataSourceList.set(from, dataSourceList.get(to));\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// dataSourceList.set(to, temp);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// dataSourceList.set(to, temp);\u0026lt;/span\u0026gt; - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//这里的处理需要注意下\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(from \u0026lt; to){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i=from; i\u0026lt;to; i++){ - Collections.swap(dataSourceList, i, i+\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - } - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(from \u0026gt; to){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i=from; i\u0026gt;to; i\u0026amp;#8211;){ - Collections.swap(dataSourceList, i, i-\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - } - } - - dataSourceList.set(to, temp); - - mSimpleAdapter.notifyDataSetChanged(); - - - } - }); - - } - - } 这里面的代码还是比较简单，主要讲下onChange()方法，我们要为mDragGridView设置一个OnChanageListener的回调接口，在onChange()方法里面实现数据的交换逻辑，第一个参数from为item开始的位置，第二个参数to为item拖拽到的位置，刚开始我使用的交换逻辑是 **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17718579#)[copy](http://blog.csdn.net/xiaanming/article/details/17718579#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/143802)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/143802/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - HashMap\u0026lt;String, Object\u0026gt; temp = dataSourceList.get(from); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//直接交互item\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// dataSourceList.set(from, dataSourceList.get(to));\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// dataSourceList.set(to, temp);\u0026lt;/span\u0026gt; 直接交换的item的数据，然后看了下网易新闻的拖拽的GridView，他不是直接实现两个item直接的数据交换，所以将数据交换逻辑改成了下面的方式 简单说下，数据的交换逻辑，比如我们将position从5拖拽到7这个位置，我注释掉的逻辑是直接将5和7的数据交换，而后面的那种逻辑是将6的位置数据移动到5，将7的位置移动到6，然后再7显示5 6-\u0026gt;5, 7-\u0026gt;6, 5-\u0026gt;7不知道大家理解了没有。\n接下来我们来运行下项目，在运行之前我们不要忘了在AndroidManifest.xml里面加入震动的权限 ![](http://img.blog.csdn.net/20131231174313125) 好了，今天的讲解就到此结束，效果还不错吧，看完这篇文章你是不是觉得GridView拖拽也不是那么难实现呢？你心里是不是也大概有自己的一个思路，建议大家自己敲敲看看，可以自己去实现下ListView的拖拽实现，ListView比GridView简单些，好的学习方法不是看得懂人家的代码，而是看完代码自己根据脑海里的思路自己敲出来，所以还是鼓励大家多敲代码，不明白的同学在下面留言，我会为大家解答的！ [项目源码，点击下载](http://download.csdn.net/detail/xiaanming/6812885) PS:上面的代码在4.0以上的机器上面运行是OK的，但是在4.0以下的机器存在几个问题，首先是兼容性的问题，首先smoothScrollToPositionFromTop()方法在2.x的机器是不存在的，但是我们可以使用smoothScrollBy()来代替上面的方法使得GridView滚动 注意：很多朋友说运行在2.3的机器上面拖动的时候出现某些item无缘无故的隐藏了，笔者在写demo的时候一直用的是4.0的真机运行的，后面博主使用模拟器运行在2.3的机器上面，确实存在很多朋友反应的问题，原因就是因为博主使用的是SimpleAdapter，SimpleAdapter会复用Item，所以才导致本不该隐藏的item隐藏了，但是为什么运行在博主4.0的机器上面不出现问题，博主也很纳闷，现在我对其做出了修改，采用自定义Adapter，对item不采用复用的原则，虽然效率上面有点点不足，但是如果对于item不多的GridView，效率不足可以忽略，新修改的代码可以运行在2.X以上的机器不出现朋友们所说的问题了，并且添加了Item的移动动画效果，非常感谢大家提出的问题！ [添加item交换动画，点击下载](http://download.csdn.net/detail/xiaanming/7302793) ","permalink":"https://blog.zdltech.com/posts/android-%E5%8F%AF%E6%8B%96%E6%8B%BD%E7%9A%84gridview%E6%95%88%E6%9E%9C%E5%AE%9E%E7%8E%B0-%E9%95%BF%E6%8C%89%E5%8F%AF%E6%8B%96%E6%8B%BD%E5%92%8Citem%E5%AE%9E%E6%97%B6%E4%BA%A4%E6%8D%A2/","summary":"\u003cp\u003e转帖（\u003ca href=\"http://blog.csdn.net/xiaanming/article/details/17718579\"\u003ehttp://blog.csdn.net/xiaanming/article/details/17718579\u003c/a\u003e）\u003c/p\u003e\n\u003cp\u003e在Android开发中，我们常常用到ListView和GridView，而有的时候系统的ListView，GridView并不能满足我们的需求，所以我们需要自己定义一个ListView或者GridView,我的上一篇文章中就是自定义的一个左右滑动删除item的例子，大家有兴趣的可以去看看 \u003ca href=\"http://blog.csdn.net/xiaanming/article/details/17539199\"\u003eAndroid 使用Scroller实现绚丽的ListView左右滑动删除Item效果\u003c/a\u003e，今天这篇文章就给大家来自定义GridView的控件，GridView主要是来显示网格的控件，在Android的开发中使用很普通，相对于TextView，Button这些控件来说要来的复杂些，今天给大家带来长按GridView的item,然后将其拖拽其他item上面，使得GridView的item发生交换，比较典型的就是我们的Launcher，网上有很多关于GridView的拖动的Demo，但是大部分都是相同的，而且存在一些Bug,而且大部分都是点击GridView的item然后进行拖动，或者item之间不进行实时交换，今天给大家更加详细的介绍GridView拖拽，并且将Demo做的更完美，大家更容易接受，也许很多人听到这个感觉实现起来很复杂，就关掉的这篇文章，其实告诉大家，只要知道了思路就感觉一点都不复杂了，不信大家可以接着往下看看，首先还是跟大家说说实现的思路\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e根据手指按下的X,Y坐标来获取我们在GridView上面点击的item\u003c/li\u003e\n\u003cli\u003e手指按下的时候使用Handler和Runnable来实现一个定时器，假如定时时间为1000毫秒，在1000毫秒内，如果手指抬起了移除定时器，没有抬起并且手指点击在GridView的item所在的区域，则表示我们长按了GridView的item\u003c/li\u003e\n\u003cli\u003e如果我们长按了item则隐藏item,然后使用WindowManager来添加一个item的镜像在屏幕用来代替刚刚隐藏的item\u003c/li\u003e\n\u003cli\u003e当我们手指在屏幕移动的时候，更新item镜像的位置，然后在根据我们移动的X,Y的坐标来获取移动到GridView的哪一个位置\u003c/li\u003e\n\u003cli\u003e到GridView的item过多的时候，可能一屏幕显示不完，我们手指拖动item镜像到屏幕下方，要触发GridView想上滚动，同理，当我们手指拖动item镜像到屏幕上面，触发GridView向下滚动\u003c/li\u003e\n\u003cli\u003eGridView交换数据，刷新界面，移除item的镜像\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e看完上面的这些思路你是不是找到了些感觉了呢，心里痒痒的想动手试试吧，好吧，接下来就带大家根据思路来实现可拖拽的GridView，新建一个项目就叫DragGridView\u003cbr\u003e\n新建一个类DragGridView继承GridView,先来看看DragGridView的代码，然后在根据代码进行相关的讲解\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17718579#)[copy](http://blog.csdn.net/xiaanming/article/details/17718579#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/143802)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/143802/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.draggridview;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.PixelFormat;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Rect;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Vibrator;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Gravity;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.WindowManager;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; DragGridView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; GridView{\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * DragGridView的item长按响应的时间， 默认是1000毫秒，也可以自行设置\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; dragResponseMS = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 是否可以拖拽，默认不可以\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isDrag = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDownX;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDownY;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveX;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveY;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 正在拖拽的position\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDragPosition;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 刚开始拖拽的item对应的View\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View mStartDragItemView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 用于拖拽的镜像，这里直接用一个ImageView\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageView mDragImageView;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 震动器\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Vibrator mVibrator;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; WindowManager mWindowManager;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * item镜像的布局参数\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; WindowManager.LayoutParams mWindowLayoutParams;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 我们拖拽的item对应的Bitmap\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap mDragBitmap;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 按下的点到所在item的上边缘的距离\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mPoint2ItemTop ;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 按下的点到所在item的左边缘的距离\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mPoint2ItemLeft;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * DragGridView距离屏幕顶部的偏移量\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mOffset2Top;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * DragGridView距离屏幕左边的偏移量\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mOffset2Left;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 状态栏的高度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mStatusHeight;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * DragGridView自动向下滚动的边界值\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDownScrollBorder;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * DragGridView自动向上滚动的边界值\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mUpScrollBorder;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * DragGridView自动滚动的速度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; speed = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * item发生变化回调的接口\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnChanageListener onChanageListener;\n\n- \n- \n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; DragGridView(Context context) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; DragGridView(Context context, AttributeSet attrs) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, attrs, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; DragGridView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle);\n\n- mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);\n\n- mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);\n\n- mStatusHeight = getStatusHeight(context); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取状态栏的高度\u0026lt;/span\u0026gt;\n\n- \n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler mHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler();\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//用来处理是否为长按的Runnable\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Runnable mLongClickRunnable = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() {\n\n- isDrag = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置可以拖拽\u0026lt;/span\u0026gt;\n\n- mVibrator.vibrate(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;50\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//震动一下\u0026lt;/span\u0026gt;\n\n- mStartDragItemView.setVisibility(View.INVISIBLE);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//隐藏该item\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//根据我们按下的点显示item镜像\u0026lt;/span\u0026gt;\n\n- createDragImage(mDragBitmap, mDownX, mDownY);\n\n- }\n\n- };\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 设置回调接口\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param onChanageListener\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnChangeListener(OnChanageListener onChanageListener){\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onChanageListener = onChanageListener;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 设置响应拖拽的毫秒数，默认是1000毫秒\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param dragResponseMS\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setDragResponseMS(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; dragResponseMS) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.dragResponseMS = dragResponseMS;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt;(ev.getAction()){\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN:\n\n- mDownX = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) ev.getX();\n\n- mDownY = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) ev.getY();\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//根据按下的X,Y坐标获取所点击item的position\u0026lt;/span\u0026gt;\n\n- mDragPosition = pointToPosition(mDownX, mDownY);\n\n- \n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mDragPosition == AdapterView.INVALID_POSITION){\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(ev);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//使用Handler延迟dragResponseMS执行mLongClickRunnable\u0026lt;/span\u0026gt;\n\n- mHandler.postDelayed(mLongClickRunnable, dragResponseMS);\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//根据position获取该item所对应的View\u0026lt;/span\u0026gt;\n\n- mStartDragItemView = getChildAt(mDragPosition \u0026amp;#8211; getFirstVisiblePosition());\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//下面这几个距离大家可以参考我的博客上面的图来理解下\u0026lt;/span\u0026gt;\n\n- mPoint2ItemTop = mDownY \u0026amp;#8211; mStartDragItemView.getTop();\n\n- mPoint2ItemLeft = mDownX \u0026amp;#8211; mStartDragItemView.getLeft();\n\n- \n- mOffset2Top = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (ev.getRawY() \u0026amp;#8211; mDownY);\n\n- mOffset2Left = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (ev.getRawX() \u0026amp;#8211; mDownX);\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取DragGridView自动向上滚动的偏移量，小于这个值，DragGridView向下滚动\u0026lt;/span\u0026gt;\n\n- mDownScrollBorder = getHeight() /\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取DragGridView自动向下滚动的偏移量，大于这个值，DragGridView向上滚动\u0026lt;/span\u0026gt;\n\n- mUpScrollBorder = getHeight() * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;/\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;;\n\n- \n- \n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//开启mDragItemView绘图缓存\u0026lt;/span\u0026gt;\n\n- mStartDragItemView.setDrawingCacheEnabled(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取mDragItemView在缓存中的Bitmap对象\u0026lt;/span\u0026gt;\n\n- mDragBitmap = Bitmap.createBitmap(mStartDragItemView.getDrawingCache());\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//这一步很关键，释放绘图缓存，避免出现重复的镜像\u0026lt;/span\u0026gt;\n\n- mStartDragItemView.destroyDrawingCache();\n\n- \n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE:\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveX = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)ev.getX();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveY = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) ev.getY();\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//如果我们在按下的item上面移动，只要不超过item的边界我们就不移除mRunnable\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!isTouchInItem(mStartDragItemView, moveX, moveY)){\n\n- mHandler.removeCallbacks(mLongClickRunnable);\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP:\n\n- mHandler.removeCallbacks(mLongClickRunnable);\n\n- mHandler.removeCallbacks(mScrollRunnable);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(ev);\n\n- }\n\n- \n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 是否点击在GridView的item上面\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param itemView\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param x\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param y\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isTouchInItem(View dragView, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y){\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(dragView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; leftOffset = dragView.getLeft();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; topOffset = dragView.getTop();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(x \u0026lt; leftOffset || x \u0026gt; leftOffset + dragView.getWidth()){\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(y \u0026lt; topOffset || y \u0026gt; topOffset + dragView.getHeight()){\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent ev) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(isDrag \u0026amp;\u0026amp; mDragImageView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt;(ev.getAction()){\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE:\n\n- moveX = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) ev.getX();\n\n- moveY = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) ev.getY();\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//拖动item\u0026lt;/span\u0026gt;\n\n- onDragItem(moveX, moveY);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP:\n\n- onStopDrag();\n\n- isDrag = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev);\n\n- }\n\n- \n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 创建拖动的镜像\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param bitmap \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param downX\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     *          按下的点相对父控件的X坐标\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param downY\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     *          按下的点相对父控件的X坐标\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; createDragImage(Bitmap bitmap, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; downX , \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; downY){\n\n- mWindowLayoutParams = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; WindowManager.LayoutParams();\n\n- mWindowLayoutParams.format = PixelFormat.TRANSLUCENT; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//图片之外的其他地方透明\u0026lt;/span\u0026gt;\n\n- mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;\n\n- mWindowLayoutParams.x = downX \u0026amp;#8211; mPoint2ItemLeft + mOffset2Left;\n\n- mWindowLayoutParams.y = downY \u0026amp;#8211; mPoint2ItemTop + mOffset2Top \u0026amp;#8211; mStatusHeight;\n\n- mWindowLayoutParams.alpha = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.55f; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//透明度\u0026lt;/span\u0026gt;\n\n- mWindowLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;\n\n- mWindowLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;\n\n- mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE\n\n- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE ;\n\n- \n- mDragImageView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageView(getContext());\n\n- mDragImageView.setImageBitmap(bitmap);\n\n- mWindowManager.addView(mDragImageView, mWindowLayoutParams);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 从界面上面移动拖动镜像\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; removeDragImage(){\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mDragImageView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){\n\n- mWindowManager.removeView(mDragImageView);\n\n- mDragImageView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n- }\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 拖动item，在里面实现了item镜像的位置更新，item的相互交换以及GridView的自行滚动\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param x\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param y\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDragItem(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveY){\n\n- mWindowLayoutParams.x = moveX \u0026amp;#8211; mPoint2ItemLeft + mOffset2Left;\n\n- mWindowLayoutParams.y = moveY \u0026amp;#8211; mPoint2ItemTop + mOffset2Top \u0026amp;#8211; mStatusHeight;\n\n- mWindowManager.updateViewLayout(mDragImageView, mWindowLayoutParams); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//更新镜像的位置\u0026lt;/span\u0026gt;\n\n- onSwapItem(moveX, moveY);\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//GridView自动滚动\u0026lt;/span\u0026gt;\n\n- mHandler.post(mScrollRunnable);\n\n- }\n\n- \n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 当moveY的值大于向上滚动的边界值，触发GridView自动向上滚动\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 当moveY的值小于向下滚动的边界值，触犯GridView自动向下滚动\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 否则不进行滚动\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Runnable mScrollRunnable = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollY;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(moveY \u0026gt; mUpScrollBorder){\n\n- scrollY = speed;\n\n- mHandler.postDelayed(mScrollRunnable, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;25\u0026lt;/span\u0026gt;);\n\n- }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(moveY \u0026lt; mDownScrollBorder){\n\n- scrollY = -speed;\n\n- mHandler.postDelayed(mScrollRunnable, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;25\u0026lt;/span\u0026gt;);\n\n- }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{\n\n- scrollY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- mHandler.removeCallbacks(mScrollRunnable);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//当我们的手指到达GridView向上或者向下滚动的偏移量的时候，可能我们手指没有移动，但是DragGridView在自动的滚动\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//所以我们在这里调用下onSwapItem()方法来交换item\u0026lt;/span\u0026gt;\n\n- onSwapItem(moveX, moveY);\n\n- \n- \n- smoothScrollBy(scrollY, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;);\n\n- }\n\n- };\n\n- \n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 交换item,并且控制item之间的显示与隐藏效果\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param moveX\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param moveY\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSwapItem(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveY){\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取我们手指移动到的那个item的position\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; tempPosition = pointToPosition(moveX, moveY);\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//假如tempPosition 改变了并且tempPosition不等于-1,则进行交换\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(tempPosition != mDragPosition \u0026amp;\u0026amp; tempPosition != AdapterView.INVALID_POSITION){\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(onChanageListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){\n\n- onChanageListener.onChange(mDragPosition, tempPosition);\n\n- }\n\n- \n- getChildAt(tempPosition \u0026amp;#8211; getFirstVisiblePosition()).setVisibility(View.INVISIBLE);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//拖动到了新的item,新的item隐藏掉\u0026lt;/span\u0026gt;\n\n- getChildAt(mDragPosition \u0026amp;#8211; getFirstVisiblePosition()).setVisibility(View.VISIBLE);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//之前的item显示出来\u0026lt;/span\u0026gt;\n\n- \n- mDragPosition = tempPosition;\n\n- }\n\n- }\n\n- \n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 停止拖拽我们将之前隐藏的item显示出来，并将镜像移除\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onStopDrag(){\n\n- View view = getChildAt(mDragPosition \u0026amp;#8211; getFirstVisiblePosition());\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(view != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){\n\n- view.setVisibility(View.VISIBLE);\n\n- }\n\n- ((DragAdapter)\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getAdapter()).setItemHide(-\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);\n\n- removeDragImage();\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 获取状态栏的高度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param context\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getStatusHeight(Context context){\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; statusHeight = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- Rect localRect = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect();\n\n- ((Activity) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(localRect);\n\n- statusHeight = localRect.top;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; == statusHeight){\n\n- Class\u0026lt;?\u0026gt; localClass;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\n- localClass = Class.forName(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.android.internal.R$dimen\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- Object localObject = localClass.newInstance();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i5 = Integer.parseInt(localClass.getField(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;status_bar_height\u0026amp;#8221;\u0026lt;/span\u0026gt;).get(localObject).toString());\n\n- statusHeight = context.getResources().getDimensionPixelSize(i5);\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) {\n\n- e.printStackTrace();\n\n- }\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; statusHeight;\n\n- }\n\n- \n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @author xiaanming\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     *\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnChanageListener{\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         * 当item交换位置的时候回调的方法，我们只需要在该方法中实现数据的交换即可\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         * @param form\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         *          开始的position\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         * @param to \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         *          拖拽到的position\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onChange(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; form, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; to);\n\n- }\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e首先看DragGridView的事件分发方法，不了解Android事件分发的可以先去了解下，Android事件分发对于自定义控件很重要，简单说下，当我们点击DragGridView的Item,先会去执行dispatchTouchEvent()方法将事件分发下去，所以我们要重写dispatchTouchEvent()方法在手指按下的时候根据pointToPosition()方法来获取我们按下的item的position,根据getChildAt()方法来获取该position上面所对应的View, 并且开启长按的定时器，默认时间为1000毫秒，如果在1000毫秒内手指抬起或者手指在屏幕上滑动出了该item，则取消长按定时器，否则就表示可以进行拖拽，手机友好的震动一下，隐藏我们长按的Item，屏幕调用createDragImage()方法来创建我们长按的item的镜像，创建Item的镜像使用的是WindowManager类，该类可以创建一个窗体显示在Activity之上，再此之前大家先要理解这几个距离，理解这几个距离之前要首先知道getRawX(),getRawY()和getX(),getY()的区别，getRawX(),getRawY()是相对于屏幕的原点的距离，而getX(),getY()是相对于控件左上方的点的距离，为了方便大家理解我用Word简单的画了下图，画得不好，大家将就的看下，红色框框为我们的GridView\u003c/p\u003e","title":"Android 可拖拽的GridView效果实现, 长按可拖拽和item实时交换"},{"content":"转载（http://blog.csdn.net/xiaanming/article/details/20934541）\n今天给大家带来一个向右滑动销毁Activity的效果，Activtiy随着手指的移动而移动，该效果在Android应用中还是比较少见的，在IOS中就比较常见了，例如“网易新闻” ,”美食杰” , “淘宝”等应用采用此效果，而Android应用中“知乎”采用的也是这种滑动切换Activity的效果， 不过我发现“淘宝”并没有随着手势的移动而移动，只是捕捉到滑动手势，然后产生平滑切换界面的动画效果，这个在Android中还是很好实现的, 网上很多滑动切换Activity的Demo貌似都是这种效果的吧，如果要实现类似“网易新闻”的随手势的滑动而滑动，似乎就要复杂一些了，我之前在IOS中看到”网易新闻”的这种效果就很感兴趣，然后群里也有朋友问我怎么实现类似“知乎”这个应用的滑动切换的效果，我也特意去下了一个“知乎”，在之前的实现中我遇到了一些瓶颈，没有实现出来就搁置了在那里，今天无意中看到给Activity设置透明的背景，于是乎我恍然大悟，真是灵感来源于瞬间，不能强求啊，然后自己就将此效果实现了出来，给大家分享一下，希望给有此需求的你一点点帮助。\n不知道大家对Scroller这个类以及View的scrollBy() 和scrollTo()的使用熟悉不？我之前介绍了Scroller类的滑动实现原理Android 带你从源码的角度解析Scroller的滚动实现原理，在那里面也介绍了scrollBy() 和scrollTo()方法，不明白的同学可以去看看，这对实现此效果有很大的帮助，了解scrollBy() 和scrollTo()的朋友应该知道，如果想对某个View（例如Button）就行滚动,我们直接调用该View(Button)的scrollBy()方法，并不是该View(Button)进行滚动，而是该View里面的内容（Button上面的文字）进行滚动，所以我们假如要让View整体滚动就需要对其View的父布局调用scrollBy()方法，回到这篇文章来，假如我们想要对一个Activity进行滚动，我们就需求对这个Activity布局文件的顶层布局的父布局进行滚动\n例如下面的XML布局文件\n**[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/20934541#)[copy](http://blog.csdn.net/xiaanming/article/details/20934541#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/232806)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/232806/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 如果我们对LinearLayout进行滚动，并不能实现我们想要的效果，而只能对LinearLayout里面的内容或者说是子View进行滚动，所以我们需要获取利用LinearLayout的getParent()方法获取父布局，其实Android系统会对我们的布局文件的最外层套一个FrameLayout，所以我们其实就是对FrameLayout进行滚动就行了\n了解了实现的原理之后，我们就来编写代码吧，首先新建一个android工程，取名SildingFinish\n由于我们的需求可能不是在一个界面提供这个滑动切换的效果，所以我们应该将这部分滑动的逻辑抽取出来，我这里就他写成了一个扩展RelativeLayout的自定义布局SildingFinishLayout，首先我们看其代码\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20934541#)[copy](http://blog.csdn.net/xiaanming/article/details/20934541#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/232806)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/232806/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.view; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnTouchListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewConfiguration; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AbsListView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.RelativeLayout; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ScrollView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Scroller; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 自定义可以滑动的RelativeLayout, 类似于IOS的滑动删除页面效果，当我们要使用\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 此功能的时候，需要将该Activity的顶层布局设置为SildingFinishLayout，\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 然后需要调用setTouchView()方法来设置需要滑动的View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SildingFinishLayout \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; RelativeLayout \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; - OnTouchListener { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * SildingFinishLayout布局的父布局\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ViewGroup mParentView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 处理滑动逻辑的View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View touchView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 滑动的最小距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mTouchSlop; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 按下点的X坐标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; downX; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 按下点的Y坐标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; downY; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 临时存储X坐标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; tempX; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 滑动类\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Scroller mScroller; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * SildingFinishLayout的宽度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewWidth; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 记录是否正在滑动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isSilding; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnSildingFinishListener onSildingFinishListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isFinish; - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SildingFinishLayout(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, attrs, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SildingFinishLayout(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - - mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); - mScroller = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Scroller(context); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onLayout(changed, l, t, r, b); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (changed) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获取SildingFinishLayout所在布局的父布局\u0026lt;/span\u0026gt; - mParentView = (ViewGroup) \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getParent(); - viewWidth = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getWidth(); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 设置OnSildingFinishListener, 在onSildingFinish()方法中finish Activity\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param onSildingFinishListener\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnSildingFinishListener( - OnSildingFinishListener onSildingFinishListener) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onSildingFinishListener = onSildingFinishListener; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 设置Touch的View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param touchView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setTouchView(View touchView) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.touchView = touchView; - touchView.setOnTouchListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getTouchView() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; touchView; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 滚动出界面\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scrollRight() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; delta = (viewWidth + mParentView.getScrollX()); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 调用startScroll方法来设置一些滚动的参数，我们在computeScroll()方法中调用scrollTo来滚动item\u0026lt;/span\u0026gt; - mScroller.startScroll(mParentView.getScrollX(), \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, -delta + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, - Math.abs(delta)); - postInvalidate(); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 滚动到起始位置\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scrollOrigin() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; delta = mParentView.getScrollX(); - mScroller.startScroll(mParentView.getScrollX(), \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, -delta, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, - Math.abs(delta)); - postInvalidate(); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * touch的View是否是AbsListView， 例如ListView, GridView等其子类\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isTouchOnAbsListView() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; touchView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;instanceof\u0026lt;/span\u0026gt; AbsListView ? \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt; : \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * touch的view是否是ScrollView或者其子类\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isTouchOnScrollView() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; touchView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;instanceof\u0026lt;/span\u0026gt; ScrollView ? \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt; : \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (event.getAction()) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: - downX = tempX = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getRawX(); - downY = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getRawY(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; moveX = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getRawX(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; deltaX = tempX \u0026amp;#8211; moveX; - tempX = moveX; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (Math.abs(moveX \u0026amp;#8211; downX) \u0026gt; mTouchSlop - \u0026amp;\u0026amp; Math.abs((\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getRawY() \u0026amp;#8211; downY) \u0026lt; mTouchSlop) { - isSilding = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 若touchView是AbsListView，\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 则当手指滑动，取消item的点击事件，不然我们滑动也伴随着item点击事件的发生\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isTouchOnAbsListView()) { - MotionEvent cancelEvent = MotionEvent.obtain(event); - cancelEvent - .setAction(MotionEvent.ACTION_CANCEL - | (event.getActionIndex() \u0026lt;\u0026lt; MotionEvent.ACTION_POINTER_INDEX_SHIFT)); - v.onTouchEvent(cancelEvent); - } - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (moveX \u0026amp;#8211; downX \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; isSilding) { - mParentView.scrollBy(deltaX, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 屏蔽在滑动过程中ListView ScrollView等自己的滑动事件\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isTouchOnScrollView() || isTouchOnAbsListView()) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - isSilding = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mParentView.getScrollX() \u0026lt;= -viewWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;) { - isFinish = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - scrollRight(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - scrollOrigin(); - isFinish = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 假如touch的view是AbsListView或者ScrollView 我们处理完上面自己的逻辑之后\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 再交给AbsListView, ScrollView自己处理其自己的逻辑\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isTouchOnScrollView() || isTouchOnAbsListView()) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; v.onTouchEvent(event); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 其他的情况直接返回true\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 调用startScroll的时候scroller.computeScrollOffset()返回true，\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mScroller.computeScrollOffset()) { - mParentView.scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); - postInvalidate(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mScroller.isFinished()) { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (onSildingFinishListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; isFinish) { - onSildingFinishListener.onSildingFinish(); - } - } - } - } - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnSildingFinishListener { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSildingFinish(); - } - - } 我们在onLayout()方法中利用getParent()方法获取该布局的父布局和获取其控件的宽度，主要是为之后的实现做准备工作。\n我们的滑动逻辑主要是利用View的scrollBy() 方法, scrollTo()方法和Scroller类来实现的，当手指拖动视图的时候，我们监听手指在屏幕上滑动的距离利用View的scrollBy() 方法使得View随着手指的滑动而滑动，而当手指离开屏幕，我们在根据逻辑使用Scroller类startScroll()方法设置滑动的参数，然后再根据View的scrollTo进行滚动。\n对于View的滑动，存在一些Touch事件消费的处理等问题，因此我们需要对View的整个Touch事件很熟悉 ,最主要的就是Activity里面有一些ListView、 GridView、ScrollView等控件了， 假如我们Activity里面存在ListView、GridView等控件的话，我们对Activity的最外层布局进行滚动根本就无效果，因为Touch事件被ListView、GridView等控件消费了，所以Activity的最外层布局根本得不到Touch事件，也就实现不了Touch逻辑了，所以为了解决此Touch事件问题我提供了setTouchView(View touchView) 方法，这个方法是将Touch事件动态的设置到到View上面，所以针对上面的问题，我们将OnTouchListener直接设置到ListView、GridView上面，这样子就避免了Activity的最外层接受不到Touch事件的问题了\n接下来看onTouch()方法\n首先我们在ACTION_DOWN记录按下点的X,Y坐标\n然后在ACTION_MOVE中判断，如果我们在水平方向滑动的距离大于mTouchSlop并且在竖直方向滑动的距离小于mTouchSlop，表示Activity处于滑动状态，我们判断如果touchView是ListView、GridView或者其子类的时候，因为我们手指在ListView、GridView上面，伴随着item的点击事件的发生，所以我们对touchView设置ACTION_CANCEL来取消item的点击事件，然后对该布局的父布局调用scrollBy()进行滚动，并且如果TouchView是AbsListView或者ScrollView直接返回true,来取消AbsListView或者ScrollView本身的ACTION_MOVE事件，最直观的感受就是我们在滑动Activity的时候，禁止AbsListView或者ScrollView的上下滑动\n最后在ACTION_UP中判断如果手指滑动的距离大于控件长度的二分之一，表示将Activity滑出界面，否则滑动到起始位置，我们利用Scroller类的startScroll()方法设置好开始位置，滑动距离和时间，然后调用postInvalidate()刷新界面，之后就到computeScroll()方法中，我们利用scrollTo()方法对该布局的父布局进行滚动，滚动结束之后，我们判断界面是否滑出界面，如果是就调用OnSildingFinishListener接口的onSildingFinish（）方法，所以只要在onSildingFinish()方法中finish界面就行了\n整个滑动布局的代码就是这个样子，接下来我们就来使用了，主界面Activity只有三个按钮，分别跳转到普通布局的Activity,有ListView的Activity和有ScrollView的Activity中\n**[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/20934541#)[copy](http://blog.csdn.net/xiaanming/article/details/20934541#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/232806)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/232806/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/normal_activity\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;普通的Activity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/absListview_activity\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;有AbsListView的Activity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/scrollview_activity\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;有ScrollView的Activity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 然后就是MainActivity的代码，根据ID实例化Button，然后为Button设置OnClickListener事件，不同的按钮跳转到不同的Activity，然后设置从右向左滑动的动画，重写onBackPressed()方法，当我们按下手机物理键盘的返回键，添加从左向右滑出的动画\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20934541#)[copy](http://blog.csdn.net/xiaanming/article/details/20934541#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/232806)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/232806/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.slidingfinish; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Button; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.slidingfinish.R; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnClickListener { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - requestWindowFeature(Window.FEATURE_NO_TITLE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - Button mButtonNormal = (Button) findViewById(R.id.normal_activity); - mButtonNormal.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - - Button mButtonAbs = (Button) findViewById(R.id.absListview_activity); - mButtonAbs.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - - Button mButtonScroll = (Button) findViewById(R.id.scrollview_activity); - mButtonScroll.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - Intent mIntent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (v.getId()) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.normal_activity: - mIntent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, NormalActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.absListview_activity: - mIntent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, AbsActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.scrollview_activity: - mIntent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, ScrollActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - - startActivity(mIntent); - overridePendingTransition(R.anim.base_slide_right_in, R.anim.base_slide_remain); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Press the back button in mobile phone\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onBackPressed() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onBackPressed(); - overridePendingTransition(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, R.anim.base_slide_right_out); - } - - } 在这里我之贴出含有ListView的Activity的代码，先看布局，我们自定义滑动布局SildingFinishLayout应该放在XML的最顶层\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20934541#)[copy](http://blog.csdn.net/xiaanming/article/details/20934541#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/232806)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/232806/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;?xml version=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; encoding=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;UTF-8\u0026amp;#8221;\u0026lt;/span\u0026gt;?\u0026gt; - \u0026lt;com.example.view.SildingFinishLayout xmlns:android=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - xmlns:tools=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:id=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@+id/sildingFinishLayout\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:background=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;#556677\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; - - \u0026lt;ListView - android:id=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@+id/listView\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:cacheColorHint=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/transparent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; - \u0026lt;/ListView\u0026gt; - - - \u0026lt;/com.example.view.SildingFinishLayout\u0026gt; **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20934541#)[copy](http://blog.csdn.net/xiaanming/article/details/20934541#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/232806)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/232806/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.slidingfinish; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView.OnItemClickListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ArrayAdapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.slidingfinish.R; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.view.SildingFinishLayout; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.view.SildingFinishLayout.OnSildingFinishListener; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; AbsActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;String\u0026gt; list = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;String\u0026gt;(); - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - requestWindowFeature(Window.FEATURE_NO_TITLE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_abslistview); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;30\u0026lt;/span\u0026gt;; i++) { - list.add(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;测试数据\u0026amp;#8221;\u0026lt;/span\u0026gt; + i); - } - - ListView mListView = (ListView) findViewById(R.id.listView); - ArrayAdapter\u0026lt;String\u0026gt; adapter = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayAdapter\u0026lt;String\u0026gt;( - AbsActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, android.R.layout.simple_list_item_1, list); - mListView.setAdapter(adapter); - - SildingFinishLayout mSildingFinishLayout = (SildingFinishLayout) findViewById(R.id.sildingFinishLayout); - mSildingFinishLayout - .setOnSildingFinishListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnSildingFinishListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSildingFinish() { - AbsActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.finish(); - } - }); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// touchView要设置到ListView上面\u0026lt;/span\u0026gt; - mSildingFinishLayout.setTouchView(mListView); - - mListView.setOnItemClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnItemClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onItemClick(AdapterView\u0026lt;?\u0026gt; parent, View view, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; id) { - - startActivity(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(AbsActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, NormalActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;)); - overridePendingTransition(R.anim.base_slide_right_in, - R.anim.base_slide_remain); - } - }); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Press the back button in mobile phone\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onBackPressed() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onBackPressed(); - overridePendingTransition(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, R.anim.base_slide_right_out); - } - - } 利用ID找到SildingFinishLayout实例，利用setTouchView（）方法设置touchView到ListView上面，然后调用setOnSildingFinishListener（）设置OnSildingFinishListener，在onSildingFinish（）中finish界面就可以啦。\n在运行项目之前还有一个很重要的操作，也是之前我被卡到的问题，就是我们需要对Activity设置为透明，即设置主题android:theme=”@android:style/Theme.Translucent”\n**[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/20934541#)[copy](http://blog.csdn.net/xiaanming/article/details/20934541#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/232806)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/232806/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;.AbsActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:theme\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Theme.Translucent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;.NormalActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:theme\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Theme.Translucent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;.ScrollActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:theme\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Theme.Translucent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 好了，现在我们可以运行项目看看效果啦\n正是我们想要的效果，如果想要加入滑动切换界面的效果只需要三步就行了，首先将Activity布局的最外层修改为SildingFinishLayout，然后在Activity里面调用setTouchView()方法设置touchView，设置OnSildingFinishListener监听在onSildingFinish()方法中finish界面，最后设置Activity的背景为透明（不是设置Activity布局文件的最顶层布局背景颜色透明，这点要区分一下）是不是很方便呢？好了,今天的讲解到这里就结束了，有疑问的朋友请在下面留言，有兴趣的朋友可以下载源码看看！\n项目源码，点击下载\n博主后面又改了下代码，写了一个简洁加强版的demo,代码更加简洁了，也对里面是ViewPager做了处理，并且加了边界的阴影效果，也不必要调用setTouchView()来设置那个View响应滚动，对SildingFinishLayout里面的子View是什么没有任何关系，如果大家想使用此效果的话，建议下载如下版本\n加强简洁版，点击下载\n","permalink":"https://blog.zdltech.com/posts/android-%E5%90%91%E5%8F%B3%E6%BB%91%E5%8A%A8%E9%94%80%E6%AF%81finishactivity-%E9%9A%8F%E7%9D%80%E6%89%8B%E5%8A%BF%E7%9A%84%E6%BB%91%E5%8A%A8%E8%80%8C%E6%BB%91%E5%8A%A8%E7%9A%84/","summary":"\u003cp\u003e转载（\u003ca href=\"http://blog.csdn.net/xiaanming/article/details/20934541\"\u003ehttp://blog.csdn.net/xiaanming/article/details/20934541\u003c/a\u003e）\u003c/p\u003e\n\u003cp\u003e今天给大家带来一个向右滑动销毁Activity的效果，Activtiy随着手指的移动而移动，该效果在Android应用中还是比较少见的，在IOS中就比较常见了，例如“网易新闻” ,”美食杰” , “淘宝”等应用采用此效果，而Android应用中“知乎”采用的也是这种滑动切换Activity的效果， 不过我发现“淘宝”并没有随着手势的移动而移动，只是捕捉到滑动手势，然后产生平滑切换界面的动画效果，这个在Android中还是很好实现的,  网上很多滑动切换Activity的Demo貌似都是这种效果的吧，如果要实现类似“网易新闻”的随手势的滑动而滑动，似乎就要复杂一些了，我之前在IOS中看到”网易新闻”的这种效果就很感兴趣，然后群里也有朋友问我怎么实现类似“知乎”这个应用的滑动切换的效果，我也特意去下了一个“知乎”，在之前的实现中我遇到了一些瓶颈，没有实现出来就搁置了在那里，今天无意中看到给Activity设置透明的背景，于是乎我恍然大悟，真是灵感来源于瞬间，不能强求啊，然后自己就将此效果实现了出来，给大家分享一下，希望给有此需求的你一点点帮助。\u003c/p\u003e\n\u003cp\u003e不知道大家对Scroller这个类以及View的scrollBy() 和scrollTo()的使用熟悉不？我之前介绍了Scroller类的滑动实现原理\u003ca href=\"http://blog.csdn.net/xiaanming/article/details/17483273\"\u003eAndroid 带你从源码的角度解析Scroller的滚动实现原理\u003c/a\u003e，在那里面也介绍了scrollBy() 和scrollTo()方法，不明白的同学可以去看看，这对实现此效果有很大的帮助，了解scrollBy() 和scrollTo()的朋友应该知道，如果想对某个View（例如Button）就行滚动,我们直接调用该View(Button)的scrollBy()方法，并不是该View(Button)进行滚动，而是该View里面的内容（Button上面的文字）进行滚动，所以我们假如要让View整体滚动就需要对其View的父布局调用scrollBy()方法，回到这篇文章来，假如我们想要对一个Activity进行滚动，我们就需求对这个Activity布局文件的顶层布局的父布局进行滚动\u003c/p\u003e\n\u003cp\u003e例如下面的XML布局文件\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/20934541#)[copy](http://blog.csdn.net/xiaanming/article/details/20934541#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/232806)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/232806/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e如果我们对LinearLayout进行滚动，并不能实现我们想要的效果，而只能对LinearLayout里面的内容或者说是子View进行滚动，所以我们需要获取利用LinearLayout的getParent()方法获取父布局，其实Android系统会对我们的布局文件的最外层套一个FrameLayout，所以我们其实就是对FrameLayout进行滚动就行了\u003c/p\u003e\n\u003cp\u003e了解了实现的原理之后，我们就来编写代码吧，首先新建一个android工程，取名SildingFinish\u003c/p\u003e","title":"Android 向右滑动销毁（finish）Activity, 随着手势的滑动而滑动的效果"},{"content":"转载（http://blog.csdn.net/xiaanming/article/details/20481185）\n大家好！过完年回来到现在差不多一个月没写文章了，一是觉得不知道写哪些方面的文章，没有好的题材来写，二是因为自己的一些私事给耽误了，所以过完年的第一篇文章到现在才发表出来，2014年我还是会继续在CSDN上面更新我的博客，欢迎大家关注一下，今天这篇文章主要的是介绍下开源库StickyGridHeaders的使用，StickyGridHeaders是一个自定义GridView带sections和headers的Android库，sections就是GridView item之间的分隔，headers就是固定在GridView顶部的标题，类似一些Android手机联系人的效果，StickyGridHeaders的介绍在https://github.com/TonicArtos/StickyGridHeaders，与此对应也有一个相同效果的自定义ListView带sections和headers的开源库https://github.com/emilsjolander/StickyListHeaders，大家有兴趣的可以去看下，我这里介绍的是StickyGridHeaders的使用，我在Android应用方面看到使用StickyGridHeaders的不是很多，而是在Iphone上看到相册采用的是这种效果，于是我就使用StickyGridHeaders来仿照Iphone按照日期分隔显示本地图片\n我们先新建一个Android项目StickyHeaderGridView，去https://github.com/TonicArtos/StickyGridHeaders下载开源库，为了方便浏览源码我直接将源码拷到我的工程中了\ncom.tonicartos.widget.stickygridheaders这个包就是我放StickyGridHeaders开源库的源码，com.example.stickyheadergridview这个包是我实现此功能的代码，类看起来还蛮多的，下面我就一一来介绍了\nGridItem用来封装StickyGridHeadersGridView 每个Item的数据，里面有本地图片的路径，图片加入手机系统的时间和headerId\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; GridItem { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 图片的路径\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String path; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 图片加入手机中的时间，只取了年月日\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String time; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 每个Item对应的HeaderId\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; headerId; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; GridItem(String path, String time) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.path = path; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.time = time; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getPath() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; path; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setPath(String path) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.path = path; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getTime() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; time; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setTime(String time) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.time = time; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getHeaderId() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; headerId; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setHeaderId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; headerId) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.headerId = headerId; - } - - - } 图片的路径path和图片加入的时间time 我们直接可以通过ContentProvider获取，但是headerId需要我们根据逻辑来生成。\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.ContentResolver; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.database.Cursor; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.net.Uri; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Environment; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.provider.MediaStore; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 图片扫描器\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ImageScanner { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context mContext; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ImageScanner(Context context){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mContext = context; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 利用ContentProvider扫描手机中的图片，将扫描的Cursor回调到ScanCompleteCallBack\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 接口的scanComplete方法中，此方法在运行在子线程中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scanImages(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; ScanCompleteCallBack callback) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Handler mHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.handleMessage(msg); - callback.scanComplete((Cursor)msg.obj); - } - }; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Thread(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//先发送广播扫描下整个sd卡\u0026lt;/span\u0026gt; - mContext.sendBroadcast(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent( - Intent.ACTION_MEDIA_MOUNTED, - Uri.parse(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;file://\u0026amp;#8221;\u0026lt;/span\u0026gt; + Environment.getExternalStorageDirectory()))); - - Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; - ContentResolver mContentResolver = mContext.getContentResolver(); - - Cursor mCursor = mContentResolver.query(mImageUri, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, MediaStore.Images.Media.DATE_ADDED); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//利用Handler通知调用线程\u0026lt;/span\u0026gt; - Message msg = mHandler.obtainMessage(); - msg.obj = mCursor; - mHandler.sendMessage(msg); - } - }).start(); - - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 扫描完成之后的回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; ScanCompleteCallBack{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scanComplete(Cursor cursor); - } - - - } ImageScanner是一个图片的扫描器类，该类使用ContentProvider扫描手机中的图片，我们通过调用scanImages()方法就能对手机中的图片进行扫描，将扫描的Cursor回调到ScanCompleteCallBack 接口的scanComplete方法中，由于考虑到扫描图片属于耗时操作，所以该操作运行在子线程中，在我们扫描图片之前我们需要先发送广播来扫描外部媒体库，为什么要这么做呢，假如我们新增加一张图片到sd卡，图片确实已经添加了进去，但是我们此时的媒体库还没有同步更新，若不同步媒体库我们就看不到新增加的图片，当然我们可以通过重新启动系统来更新媒体库，但是这样不可取，所以我们直接发送广播就可以同步媒体库了。\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.concurrent.ExecutorService; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.concurrent.Executors; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.BitmapFactory; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Point; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v4.util.LruCache; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 本地图片加载器,采用的是异步解析本地图片，单例模式利用getInstance()获取NativeImageLoader实例\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 调用loadNativeImage()方法加载本地图片，此类可作为一个加载本地图片的工具类\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; NativeImageLoader { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = NativeImageLoader.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getSimpleName(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; NativeImageLoader mInstance = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; NativeImageLoader(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; LruCache\u0026lt;String, Bitmap\u0026gt; mMemoryCache; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ExecutorService mImageThreadPool = Executors.newFixedThreadPool(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; NativeImageLoader(){ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取应用程序的最大内存\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; maxMemory = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (Runtime.getRuntime().maxMemory()); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//用最大内存的1/8来存储图片\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cacheSize = maxMemory / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; - mMemoryCache = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LruCache\u0026lt;String, Bitmap\u0026gt;(cacheSize) { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取每张图片的bytes\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; sizeOf(String key, Bitmap bitmap) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; bitmap.getRowBytes() * bitmap.getHeight(); - } - - }; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 通过此方法来获取NativeImageLoader的实例\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; NativeImageLoader getInstance(){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mInstance; - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 加载本地图片，对图片不进行裁剪\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param path\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param mCallBack\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Bitmap loadNativeImage(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String path, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; NativeImageCallBack mCallBack){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.loadNativeImage(path, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, mCallBack); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 此方法来加载本地图片，这里的mPoint是用来封装ImageView的宽和高，我们会根据ImageView控件的大小来裁剪Bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 如果你不想裁剪图片，调用loadNativeImage(final String path, final NativeImageCallBack mCallBack)来加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param path\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param mPoint\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param mCallBack\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Bitmap loadNativeImage(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String path, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Point mPoint, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; NativeImageCallBack mCallBack){ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//先获取内存中的Bitmap\u0026lt;/span\u0026gt; - Bitmap bitmap = getBitmapFromMemCache(path); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Handler mHander = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler(){ - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.handleMessage(msg); - mCallBack.onImageLoader((Bitmap)msg.obj, path); - } - - }; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//若该Bitmap不在内存缓存中，则启用线程去加载本地的图片，并将Bitmap加入到mMemoryCache中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(bitmap == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - mImageThreadPool.execute(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//先获取图片的缩略图\u0026lt;/span\u0026gt; - Bitmap mBitmap = decodeThumbBitmapForFile(path, mPoint == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; ? \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;: mPoint.x, mPoint == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; ? \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;: mPoint.y); - Message msg = mHander.obtainMessage(); - msg.obj = mBitmap; - mHander.sendMessage(msg); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将图片加入到内存缓存\u0026lt;/span\u0026gt; - addBitmapToMemoryCache(path, mBitmap); - } - }); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; bitmap; - - } - - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 往内存缓存中添加Bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param key\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; addBitmapToMemoryCache(String key, Bitmap bitmap) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getBitmapFromMemCache(key) == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; bitmap != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mMemoryCache.put(key, bitmap); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 根据key来获取内存中的图片\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param key\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap getBitmapFromMemCache(String key) { - Bitmap bitmap = mMemoryCache.get(key); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(bitmap != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;get image for LRUCache , path = \u0026amp;#8220;\u0026lt;/span\u0026gt; + key); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; bitmap; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 清除LruCache中的bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; trimMemCache(){ - mMemoryCache.evictAll(); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 根据View(主要是ImageView)的宽和高来获取图片的缩略图\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param path\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param viewWidth\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param viewHeight\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap decodeThumbBitmapForFile(String path, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewWidth, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewHeight){ - BitmapFactory.Options options = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BitmapFactory.Options(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置为true,表示解析Bitmap对象，该对象不占内存\u0026lt;/span\u0026gt; - options.inJustDecodeBounds = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - BitmapFactory.decodeFile(path, options); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置缩放比例\u0026lt;/span\u0026gt; - options.inSampleSize = computeScale(options, viewWidth, viewHeight); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置为false,解析Bitmap对象加入到内存中\u0026lt;/span\u0026gt; - options.inJustDecodeBounds = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - - - Log.e(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;get Iamge form file, path = \u0026amp;#8220;\u0026lt;/span\u0026gt; + path); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; BitmapFactory.decodeFile(path, options); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 根据View(主要是ImageView)的宽和高来计算Bitmap缩放比例。默认不缩放\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param options\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param width\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param height\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; computeScale(BitmapFactory.Options options, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewWidth, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewHeight){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; inSampleSize = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(viewWidth == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; || viewWidth == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; inSampleSize; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bitmapWidth = options.outWidth; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bitmapHeight = options.outHeight; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//假如Bitmap的宽度或高度大于我们设定图片的View的宽高，则计算缩放比例\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(bitmapWidth \u0026gt; viewWidth || bitmapHeight \u0026gt; viewWidth){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthScale = Math.round((\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) bitmapWidth / (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) viewWidth); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightScale = Math.round((\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) bitmapHeight / (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) viewWidth); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//为了保证图片不缩放变形，我们取宽高比例最小的那个\u0026lt;/span\u0026gt; - inSampleSize = widthScale \u0026lt; heightScale ? widthScale : heightScale; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; inSampleSize; - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 加载本地图片的回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; NativeImageCallBack{ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 当子线程加载完了本地的图片，将Bitmap和图片路径回调在此方法中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param path\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onImageLoader(Bitmap bitmap, String path); - } - } NativeImageLoader该类是一个单例类，提供了本地图片加载，内存缓存，裁剪等逻辑，该类在加载本地图片的时候采用的是异步加载的方式，对于大图片的加载也是比较耗时的，所以采用子线程的方式去加载，对于图片的缓存机制使用的是LruCache，我们使用手机分配给应用程序内存的1/8用来缓存图片，给图片缓存的内存不宜太大，太大也可能会发生OOM，该类是用我之前写的文章Android 使用ContentProvider扫描手机中的图片，仿微信显示本地图片效果，在这里我就不做过多的介绍，有兴趣的可以去看看那篇文章，不过这里新增了一个方法trimMemCache(),，用来清空LruCache使用的内存\n我们看主界面的布局代码，里面只有一个自定义的StickyGridHeadersGridView控件\n**[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.tonicartos.widget.stickygridheaders.StickyGridHeadersGridView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/asset_grid\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:clipToPadding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:columnWidth\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;90dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:horizontalSpacing\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;3dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:numColumns\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;auto_fit\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:verticalSpacing\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;3dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; 在看主界面的代码之前我们先看StickyGridAdapter的代码\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Point; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.BaseAdapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.stickyheadergridview.MyImageView.OnMeasureListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.stickyheadergridview.NativeImageLoader.NativeImageCallBack; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.tonicartos.widget.stickygridheaders.StickyGridHeadersSimpleAdapter; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * StickyHeaderGridView的适配器，除了要继承BaseAdapter之外还需要\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 实现StickyGridHeadersSimpleAdapter接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; StickyGridAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; BaseAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; - StickyGridHeadersSimpleAdapter { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;GridItem\u0026gt; hasHeaderIdList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LayoutInflater mInflater; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GridView mGridView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Point mPoint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Point(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//用来封装ImageView的宽和高的对象 \u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; StickyGridAdapter(Context context, List\u0026lt;GridItem\u0026gt; hasHeaderIdList, - GridView mGridView) { - mInflater = LayoutInflater.from(context); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mGridView = mGridView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.hasHeaderIdList = hasHeaderIdList; - } - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; hasHeaderIdList.size(); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object getItem(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; hasHeaderIdList.get(position); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getItemId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; position; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) { - ViewHolder mViewHolder; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (convertView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mViewHolder = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewHolder(); - convertView = mInflater.inflate(R.layout.grid_item, parent, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); - mViewHolder.mImageView = (MyImageView) convertView - .findViewById(R.id.grid_item); - convertView.setTag(mViewHolder); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//用来监听ImageView的宽和高 \u0026lt;/span\u0026gt; - mViewHolder.mImageView.setOnMeasureListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnMeasureListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasureSize(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height) { - mPoint.set(width, height); - } - }); - - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - mViewHolder = (ViewHolder) convertView.getTag(); - } - - String path = hasHeaderIdList.get(position).getPath(); - mViewHolder.mImageView.setTag(path); - - Bitmap bitmap = NativeImageLoader.getInstance().loadNativeImage(path, mPoint, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; NativeImageCallBack() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onImageLoader(Bitmap bitmap, String path) { - ImageView mImageView = (ImageView) mGridView - .findViewWithTag(path); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (bitmap != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mImageView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mImageView.setImageBitmap(bitmap); - } - } - }); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (bitmap != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mViewHolder.mImageView.setImageBitmap(bitmap); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - mViewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; convertView; - } - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getHeaderView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) { - HeaderViewHolder mHeaderHolder; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (convertView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mHeaderHolder = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HeaderViewHolder(); - convertView = mInflater.inflate(R.layout.header, parent, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); - mHeaderHolder.mTextView = (TextView) convertView - .findViewById(R.id.header); - convertView.setTag(mHeaderHolder); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - mHeaderHolder = (HeaderViewHolder) convertView.getTag(); - } - mHeaderHolder.mTextView.setText(hasHeaderIdList.get(position).getTime()); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; convertView; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 获取HeaderId, 只要HeaderId不相等就添加一个Header\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getHeaderId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; hasHeaderIdList.get(position).getHeaderId(); - } - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ViewHolder { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyImageView mImageView; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; HeaderViewHolder { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; TextView mTextView; - } - - - - } 除了要继承BaseAdapter之外还需要实现StickyGridHeadersSimpleAdapter接口，继承BaseAdapter需要实现getCount()，getItem(int position)， getItemId(int position)，getView(int position, View convertView, ViewGroup parent)这四个方法，这几个方法的实现跟我们平常实现的方式一样，主要是看一下getView()方法，我们将每个item的图片路径设置Tag到该ImageView上面，然后利用NativeImageLoader来加载本地图片，在这里使用的ImageView依然是自定义的MyImageView，该自定义ImageView主要实现当MyImageView测量完毕之后，就会将测量的宽和高回调到onMeasureSize()中，然后我们可以根据MyImageView的大小来裁剪图片\n另外我们需要实现StickyGridHeadersSimpleAdapter接口的getHeaderId(int position)和getHeaderView(int position, View convertView, ViewGroup parent)，getHeaderId(int position)方法返回每个Item的headerId，getHeaderView()方法是生成sections和headers的，如果某个item的headerId跟他下一个item的HeaderId不同，则会调用getHeaderView方法生成一个sections用来区分不同的组，还会根据firstVisibleItem的headerId来生成一个位于顶部的headers，所以如何生成每个Item的headerId才是关键，生成headerId的方法在MainActivity中\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.text.SimpleDateFormat; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Collections; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Date; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.HashMap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ListIterator; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Map; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.TimeZone; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.ProgressDialog; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.database.Cursor; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.provider.MediaStore; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.stickyheadergridview.ImageScanner.ScanCompleteCallBack; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ProgressDialog mProgressDialog; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 图片扫描器\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageScanner mScanner; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GridView mGridView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 没有HeaderId的List\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;GridItem\u0026gt; nonHeaderIdList = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;GridItem\u0026gt;(); - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - mGridView = (GridView) findViewById(R.id.asset_grid); - mScanner = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageScanner(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - - mScanner.scanImages(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ScanCompleteCallBack() { - { - mProgressDialog = ProgressDialog.show(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;正在加载\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scanComplete(Cursor cursor) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 关闭进度条\u0026lt;/span\u0026gt; - mProgressDialog.dismiss(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(cursor == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt; (cursor.moveToNext()) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获取图片的路径\u0026lt;/span\u0026gt; - String path = cursor.getString(cursor - .getColumnIndex(MediaStore.Images.Media.DATA)); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取图片的添加到系统的毫秒数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; times = cursor.getLong(cursor - .getColumnIndex(MediaStore.Images.Media.DATE_ADDED)); - - GridItem mGridItem = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GridItem(path, paserTimeToYMD(times, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;yyyy年MM月dd日\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - nonHeaderIdList.add(mGridItem); - - } - cursor.close(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//给GridView的item的数据生成HeaderId\u0026lt;/span\u0026gt; - List\u0026lt;GridItem\u0026gt; hasHeaderIdList = generateHeaderId(nonHeaderIdList); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//排序\u0026lt;/span\u0026gt; - Collections.sort(hasHeaderIdList, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; YMDComparator()); - mGridView.setAdapter(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StickyGridAdapter(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, hasHeaderIdList, mGridView)); - - } - }); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 对GridView的Item生成HeaderId, 根据图片的添加时间的年、月、日来生成HeaderId\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 年、月、日相等HeaderId就相同\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param nonHeaderIdList\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;GridItem\u0026gt; generateHeaderId(List\u0026lt;GridItem\u0026gt; nonHeaderIdList) { - Map\u0026lt;String, Integer\u0026gt; mHeaderIdMap = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;String, Integer\u0026gt;(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mHeaderId = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - List\u0026lt;GridItem\u0026gt; hasHeaderIdList; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(ListIterator\u0026lt;GridItem\u0026gt; it = nonHeaderIdList.listIterator(); it.hasNext();){ - GridItem mGridItem = it.next(); - String ymd = mGridItem.getTime(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!mHeaderIdMap.containsKey(ymd)){ - mGridItem.setHeaderId(mHeaderId); - mHeaderIdMap.put(ymd, mHeaderId); - mHeaderId ++; - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - mGridItem.setHeaderId(mHeaderIdMap.get(ymd)); - } - } - hasHeaderIdList = nonHeaderIdList; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; hasHeaderIdList; - } - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDestroy() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDestroy(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//退出页面清除LRUCache中的Bitmap占用的内存\u0026lt;/span\u0026gt; - NativeImageLoader.getInstance().trimMemCache(); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 将毫秒数装换成pattern这个格式，我这里是转换成年月日\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param time\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param pattern\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String paserTimeToYMD(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; time, String pattern ) { - System.setProperty(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;user.timezone\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Asia/Shanghai\u0026amp;#8221;\u0026lt;/span\u0026gt;); - TimeZone tz = TimeZone.getTimeZone(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Asia/Shanghai\u0026amp;#8221;\u0026lt;/span\u0026gt;); - TimeZone.setDefault(tz); - SimpleDateFormat format = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SimpleDateFormat(pattern); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; format.format(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Date(time * 1000L)); - } - - } 主界面的代码主要是组装StickyGridHeadersGridView的数据，我们将扫描出来的图片的路径，时间的毫秒数解析成年月日的格式封装到GridItem中，然后将GridItem加入到List中，此时每个Item还没有生成headerId，我们需要调用generateHeaderId()，该方法主要是将同一天加入的系统的图片生成相同的HeaderId,这样子同一天加入的图片就在一个组中，当然你要改成同一个月的图片在一起，修改paserTimeToYMD（）方法的第二个参数就行了，当Activity finish之后，我们利用NativeImageLoader.getInstance().trimMemCache()释放内存，当然我们还需要对GridView的数据进行排序，比如说headerId相同的item不连续，headerId相同的item就会生成多个sections(即多个分组)，所以我们要利用YMDComparator使得在同一天加入的图片在一起，YMDComparator的代码如下\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Comparator; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; YMDComparator \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Comparator\u0026lt;GridItem\u0026gt; { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; compare(GridItem o1, GridItem o2) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; o1.getTime().compareTo(o2.getTime()); - } - - } 当然这篇文章不使用YMDComparator也是可以的，因为我在利用ContentProvider获取图片的时候，就是根据加入系统的时间排序的，排序只是针对一般的数据来说的。\n接下来我们运行下程序看看效果如何\n今天的文章就到这里结束了，感谢大家的观看，上面还有一个类和一些资源文件没有贴出来，大家有兴趣研究下就直接下载项目源码，记住采用LruCache缓存图片的时候，cacheSize不要设置得过大，不然产生OOM的概率就更大些，我利用上面的程序测试显示600多张图片来回滑动，没有产生OOM,有问题不明白的同学可以在下面留言！\n项目源码，点击下载\n","permalink":"https://blog.zdltech.com/posts/android-%E4%BD%BF%E7%94%A8%E5%BC%80%E6%BA%90%E5%BA%93stickygridheaders%E6%9D%A5%E5%AE%9E%E7%8E%B0%E5%B8%A6sections%E5%92%8Cheaders%E7%9A%84gridview%E6%98%BE%E7%A4%BA%E6%9C%AC%E5%9C%B0%E5%9B%BE-2/","summary":"\u003cp\u003e转载（\u003ca href=\"http://blog.csdn.net/xiaanming/article/details/20481185\"\u003ehttp://blog.csdn.net/xiaanming/article/details/20481185\u003c/a\u003e）\u003c/p\u003e\n\u003cp\u003e大家好！过完年回来到现在差不多一个月没写文章了，一是觉得不知道写哪些方面的文章，没有好的题材来写，二是因为自己的一些私事给耽误了，所以过完年的第一篇文章到现在才发表出来，2014年我还是会继续在CSDN上面更新我的博客，欢迎大家关注一下，今天这篇文章主要的是介绍下开源库StickyGridHeaders的使用，StickyGridHeaders是一个自定义GridView带sections和headers的Android库，sections就是GridView item之间的分隔，headers就是固定在GridView顶部的标题，类似一些Android手机联系人的效果，StickyGridHeaders的介绍在\u003ca href=\"https://github.com/TonicArtos/StickyGridHeaders\"\u003ehttps://github.com/TonicArtos/StickyGridHeaders\u003c/a\u003e，与此对应也有一个相同效果的自定义ListView带sections和headers的开源库\u003ca href=\"https://github.com/emilsjolander/StickyListHeaders\"\u003ehttps://github.com/emilsjolander/StickyListHeaders\u003c/a\u003e，大家有兴趣的可以去看下，我这里介绍的是StickyGridHeaders的使用，我在Android应用方面看到使用StickyGridHeaders的不是很多，而是在Iphone上看到相册采用的是这种效果，于是我就使用StickyGridHeaders来仿照Iphone按照日期分隔显示本地图片\u003c/p\u003e\n\u003cp\u003e我们先新建一个Android项目StickyHeaderGridView，去\u003ca href=\"https://github.com/TonicArtos/StickyGridHeaders\"\u003ehttps://github.com/TonicArtos/StickyGridHeaders\u003c/a\u003e下载开源库，为了方便浏览源码我直接将源码拷到我的工程中了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140305103135687?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhYW5taW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003ecom.tonicartos.widget.stickygridheaders这个包就是我放StickyGridHeaders开源库的源码，com.example.stickyheadergridview这个包是我实现此功能的代码，类看起来还蛮多的，下面我就一一来介绍了\u003c/p\u003e\n\u003cp\u003eGridItem用来封装StickyGridHeadersGridView 每个Item的数据，里面有本地图片的路径，图片加入手机系统的时间和headerId\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; GridItem {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 图片的路径\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String path;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 图片加入手机中的时间，只取了年月日\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String time;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 每个Item对应的HeaderId\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; headerId;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; GridItem(String path, String time) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.path = path;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.time = time;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getPath() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; path;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setPath(String path) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.path = path;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getTime() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; time;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setTime(String time) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.time = time;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getHeaderId() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; headerId;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setHeaderId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; headerId) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.headerId = headerId;\n\n- }\n\n- \n- \n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e图片的路径path和图片加入的时间time 我们直接可以通过ContentProvider获取，但是headerId需要我们根据逻辑来生成。\u003c/p\u003e","title":"Android 使用开源库StickyGridHeaders来实现带sections和headers的GridView显示本地图片效果"},{"content":"转载：http://blog.csdn.net/xiaanming/article/details/18730223\n写这篇文章之前，先简单说几句，首先是先恭喜下自己获得了2013年的博客之星称号，很意外也很开心，自己是从2013年开始写博客，那时候也不知道怎么写，我从小就不喜欢写日记，作文什么的，所以刚开始都是贴代码，也没有人看，后面慢慢的，写的文章被推荐博客首页和CSDN首页（这里也要小小的感谢下小编MM），访问量逐渐的多了起来，有更多的人看我的文章，这也使自己有了继续写文章的动力，也希望我写的东西对大家有点帮助吧，在2014年我会继续在CSDN上面写博客，然后是感谢博客之星给我投票支持我的朋友们，谢谢你们支持我的每一票，最后就是2014春节马上就到了，提前祝福大家新年快乐，工作顺利，事事顺心！\n回到主题，之前群里面有朋友问我，有没有关于本地图片选择的Demo，类似微信的效果，他说网上没有这方面的Demo，问我能不能写一篇关于这个效果的Demo，于是我研究了下微信的本地图片选择的Demo，自己仿照的写了下分享给大家，希望对以后有这样子需求的朋友有一点帮助吧，主要使用的是ContentProvider扫描手机中的图片，并用GridView将图片显示出来，关于GridView和ListView显示图片的问题，一直是一个很头疼的问题，因为我们手机的内存有限，手机给每个应用程序分配的内存也有限，所以图片多的情况下很容易伴随着OOM的发生，不过现在也有很多的开源的图片显示框架，对显示很多图片进行了优化，大家有兴趣的可以去了解了解，今天我的这篇文章使用的是LruCache这个类（之前写了一篇使用LruCache加载网络图片的Android 异步加载图片，使用LruCache和SD卡或手机缓存，效果非常的流畅）以及对图片进行相对应的裁剪，这样也可以尽量的避免OOM的发生，我们先看下微信的效果吧\n接下来我们就来实现这些效果吧，首先我们新建一个项目，取名ImageScan\n首先我们先看第一个界面吧，使用将手机中的图片扫描出来，然后根据图片的所在的文件夹将其分类出来，并显示所在文件夹里面的一张图片和文件夹中图片个数，我们根据界面元素（文件夹名， 文件夹图片个数，文件夹中的一张图片）使用一个实体对象ImageBean来封装这三个属性\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18730223#)[copy](http://blog.csdn.net/xiaanming/article/details/18730223#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/169891)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/169891/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.imagescan; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * GridView的每个item的数据对象\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author len\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ImageBean{ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 文件夹的第一张图片路径\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String topImagePath; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 文件夹名\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String folderName; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 文件夹中的图片数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; imageCounts; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getTopImagePath() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; topImagePath; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setTopImagePath(String topImagePath) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.topImagePath = topImagePath; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getFolderName() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; folderName; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setFolderName(String folderName) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.folderName = folderName; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getImageCounts() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; imageCounts; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setImageCounts(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; imageCounts) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.imageCounts = imageCounts; - } - - } 接下来就是主界面的布局啦，上面的导航栏我没有加进去，只有下面的GridView，所以说主界面布局中只有一个GridView\n**[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/18730223#)[copy](http://blog.csdn.net/xiaanming/article/details/18730223#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/169891)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/169891/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;GridView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/main_grid\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:listSelector\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/transparent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:cacheColorHint\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/transparent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:stretchMode\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;columnWidth\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:horizontalSpacing\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:verticalSpacing\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:columnWidth\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;90dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:numColumns\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;2\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;GridView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 接下来就是GridView的Item的布局，看上面的图也行你会认为他的效果是2张图片添加的效果，其实不是，后面的叠加效果只是一张背景图片而已，代码先贴上来\n**[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/18730223#)[copy](http://blog.csdn.net/xiaanming/article/details/18730223#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/169891)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/169891/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;UTF-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;FrameLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/framelayout\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.imagescan.MyImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/group_image\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/albums_bg\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/friends_sends_pictures_no\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;18dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;30dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scaleType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fitXY\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;150dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/group_count\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/albums_icon_bg\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;bottom|center_horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;FrameLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/group_title\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_below\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/framelayout\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerHorizontal\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:ellipsize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;end\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:singleLine\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;Camera\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;16sp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 看到上面的布局代码，也行你已经发现了，上面使用的是自定义的MyImageView，我先不说这个自定义MyImageView的作用，待会再给大家说，我们继续看代码\n第一个界面的主要代码\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18730223#)[copy](http://blog.csdn.net/xiaanming/article/details/18730223#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/169891)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/169891/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.imagescan; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.File; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.HashMap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Iterator; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Map; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.ProgressDialog; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.ContentResolver; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.database.Cursor; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.net.Uri; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.provider.MediaStore; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView.OnItemClickListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; HashMap\u0026lt;String, List\u0026lt;String\u0026gt;\u0026gt; mGruopMap = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;String, List\u0026lt;String\u0026gt;\u0026gt;(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;ImageBean\u0026gt; list = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;ImageBean\u0026gt;(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; SCAN_OK = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ProgressDialog mProgressDialog; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GroupAdapter adapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GridView mGroupGridView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler mHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler(){ - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.handleMessage(msg); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (msg.what) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; SCAN_OK: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//关闭进度条\u0026lt;/span\u0026gt; - mProgressDialog.dismiss(); - - adapter = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GroupAdapter(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, list = subGroupOfImage(mGruopMap), mGroupGridView); - mGroupGridView.setAdapter(adapter); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - - }; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - mGroupGridView = (GridView) findViewById(R.id.main_grid); - - getImages(); - - mGroupGridView.setOnItemClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnItemClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onItemClick(AdapterView\u0026lt;?\u0026gt; parent, View view, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; id) { - List\u0026lt;String\u0026gt; childList = mGruopMap.get(list.get(position).getFolderName()); - - Intent mIntent = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, ShowImageActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); - mIntent.putStringArrayListExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;data\u0026amp;#8221;\u0026lt;/span\u0026gt;, (ArrayList\u0026lt;String\u0026gt;)childList); - startActivity(mIntent); - - } - }); - - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 利用ContentProvider扫描手机中的图片，此方法在运行在子线程中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; getImages() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//显示进度条\u0026lt;/span\u0026gt; - mProgressDialog = ProgressDialog.show(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;正在加载\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Thread(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; - ContentResolver mContentResolver = MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getContentResolver(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//只查询jpeg和png的图片\u0026lt;/span\u0026gt; - Cursor mCursor = mContentResolver.query(mImageUri, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, - MediaStore.Images.Media.MIME_TYPE + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;=? or \u0026amp;#8220;\u0026lt;/span\u0026gt; - + MediaStore.Images.Media.MIME_TYPE + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;=?\u0026amp;#8221;\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; String[] { \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;image/jpeg\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;image/png\u0026amp;#8221;\u0026lt;/span\u0026gt; }, MediaStore.Images.Media.DATE_MODIFIED); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mCursor == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt; (mCursor.moveToNext()) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取图片的路径\u0026lt;/span\u0026gt; - String path = mCursor.getString(mCursor - .getColumnIndex(MediaStore.Images.Media.DATA)); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取该图片的父路径名\u0026lt;/span\u0026gt; - String parentName = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; File(path).getParentFile().getName(); - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//根据父路径名将图片放入到mGruopMap中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!mGruopMap.containsKey(parentName)) { - List\u0026lt;String\u0026gt; chileList = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;String\u0026gt;(); - chileList.add(path); - mGruopMap.put(parentName, chileList); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - mGruopMap.get(parentName).add(path); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//通知Handler扫描图片完成\u0026lt;/span\u0026gt; - mHandler.sendEmptyMessage(SCAN_OK); - mCursor.close(); - } - }).start(); - - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 组装分组界面GridView的数据源，因为我们扫描手机的时候将图片信息放在HashMap中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 所以需要遍历HashMap将数据组装成List\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param mGruopMap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;ImageBean\u0026gt; subGroupOfImage(HashMap\u0026lt;String, List\u0026lt;String\u0026gt;\u0026gt; mGruopMap){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mGruopMap.size() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - List\u0026lt;ImageBean\u0026gt; list = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;ImageBean\u0026gt;(); - - Iterator\u0026lt;Map.Entry\u0026lt;String, List\u0026lt;String\u0026gt;\u0026gt;\u0026gt; it = mGruopMap.entrySet().iterator(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt; (it.hasNext()) { - Map.Entry\u0026lt;String, List\u0026lt;String\u0026gt;\u0026gt; entry = it.next(); - ImageBean mImageBean = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageBean(); - String key = entry.getKey(); - List\u0026lt;String\u0026gt; value = entry.getValue(); - - mImageBean.setFolderName(key); - mImageBean.setImageCounts(value.size()); - mImageBean.setTopImagePath(value.get(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;));\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取该组的第一张图片\u0026lt;/span\u0026gt; - - list.add(mImageBean); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; list; - - } - - - } 首先看getImages()这个方法，该方法是使用ContentProvider将手机中的图片扫描出来，我这里只扫描了手机的外部存储中的图片，由于手机中可能存在很多的图片，扫描图片又比较耗时，所以我们在这里开启了子线程去获取图片，扫描的图片都存放在Cursor中，我们先要将图片按照文件夹进行分类,我们使用了HashMap来进行分类并将结果存储到mGruopMap（Key是文件夹名，Value是文件夹中的图片路径的List）中，分类完了关闭Cursor并利用Handler来通知主线程 然后是subGroupOfImage()方法，改方法是将mGruopMap的数据组装到List中，在List中存放GridView中的每个item的数据对象ImageBean, 遍历HashMap对象，具体的逻辑看代码，之后就是给GridView设置Adapter。 设置item点击事件，点击文件夹跳转到展示文件夹图片的Activity, 我们需要传递每个文件夹中的图片的路径的集合 看GroupAdapter的代码之前，我们先看一个比较重要的类，本地图片加载器NativeImageLoader\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18730223#)[copy](http://blog.csdn.net/xiaanming/article/details/18730223#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/169891)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/169891/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.imagescan; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.concurrent.ExecutorService; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.concurrent.Executors; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.BitmapFactory; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Point; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v4.util.LruCache; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 本地图片加载器,采用的是异步解析本地图片，单例模式利用getInstance()获取NativeImageLoader实例\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 调用loadNativeImage()方法加载本地图片，此类可作为一个加载本地图片的工具类\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; NativeImageLoader { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LruCache\u0026lt;String, Bitmap\u0026gt; mMemoryCache; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; NativeImageLoader mInstance = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; NativeImageLoader(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ExecutorService mImageThreadPool = Executors.newFixedThreadPool(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; NativeImageLoader(){ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取应用程序的最大内存\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; maxMemory = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (Runtime.getRuntime().maxMemory() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1024\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//用最大内存的1/4来存储图片\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cacheSize = maxMemory / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;; - mMemoryCache = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LruCache\u0026lt;String, Bitmap\u0026gt;(cacheSize) { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取每张图片的大小\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; sizeOf(String key, Bitmap bitmap) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; bitmap.getRowBytes() * bitmap.getHeight() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1024\u0026lt;/span\u0026gt;; - } - }; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 通过此方法来获取NativeImageLoader的实例\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; NativeImageLoader getInstance(){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mInstance; - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 加载本地图片，对图片不进行裁剪\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param path\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param mCallBack\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Bitmap loadNativeImage(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String path, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; NativeImageCallBack mCallBack){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.loadNativeImage(path, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, mCallBack); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 此方法来加载本地图片，这里的mPoint是用来封装ImageView的宽和高，我们会根据ImageView控件的大小来裁剪Bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 如果你不想裁剪图片，调用loadNativeImage(final String path, final NativeImageCallBack mCallBack)来加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param path\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param mPoint\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param mCallBack\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Bitmap loadNativeImage(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String path, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Point mPoint, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; NativeImageCallBack mCallBack){ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//先获取内存中的Bitmap\u0026lt;/span\u0026gt; - Bitmap bitmap = getBitmapFromMemCache(path); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Handler mHander = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler(){ - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.handleMessage(msg); - mCallBack.onImageLoader((Bitmap)msg.obj, path); - } - - }; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//若该Bitmap不在内存缓存中，则启用线程去加载本地的图片，并将Bitmap加入到mMemoryCache中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(bitmap == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - mImageThreadPool.execute(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//先获取图片的缩略图\u0026lt;/span\u0026gt; - Bitmap mBitmap = decodeThumbBitmapForFile(path, mPoint == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; ? \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;: mPoint.x, mPoint == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; ? \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;: mPoint.y); - Message msg = mHander.obtainMessage(); - msg.obj = mBitmap; - mHander.sendMessage(msg); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将图片加入到内存缓存\u0026lt;/span\u0026gt; - addBitmapToMemoryCache(path, mBitmap); - } - }); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; bitmap; - - } - - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 往内存缓存中添加Bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param key\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; addBitmapToMemoryCache(String key, Bitmap bitmap) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getBitmapFromMemCache(key) == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; bitmap != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mMemoryCache.put(key, bitmap); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 根据key来获取内存中的图片\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param key\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap getBitmapFromMemCache(String key) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mMemoryCache.get(key); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 根据View(主要是ImageView)的宽和高来获取图片的缩略图\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param path\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param viewWidth\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param viewHeight\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap decodeThumbBitmapForFile(String path, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewWidth, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewHeight){ - BitmapFactory.Options options = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BitmapFactory.Options(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置为true,表示解析Bitmap对象，该对象不占内存\u0026lt;/span\u0026gt; - options.inJustDecodeBounds = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - BitmapFactory.decodeFile(path, options); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置缩放比例\u0026lt;/span\u0026gt; - options.inSampleSize = computeScale(options, viewWidth, viewHeight); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置为false,解析Bitmap对象加入到内存中\u0026lt;/span\u0026gt; - options.inJustDecodeBounds = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; BitmapFactory.decodeFile(path, options); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 根据View(主要是ImageView)的宽和高来计算Bitmap缩放比例。默认不缩放\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param options\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param width\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param height\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; computeScale(BitmapFactory.Options options, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewWidth, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewHeight){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; inSampleSize = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(viewWidth == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; || viewWidth == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; inSampleSize; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bitmapWidth = options.outWidth; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bitmapHeight = options.outHeight; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//假如Bitmap的宽度或高度大于我们设定图片的View的宽高，则计算缩放比例\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(bitmapWidth \u0026gt; viewWidth || bitmapHeight \u0026gt; viewWidth){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthScale = Math.round((\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) bitmapWidth / (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) viewWidth); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightScale = Math.round((\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) bitmapHeight / (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) viewWidth); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//为了保证图片不缩放变形，我们取宽高比例最小的那个\u0026lt;/span\u0026gt; - inSampleSize = widthScale \u0026lt; heightScale ? widthScale : heightScale; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; inSampleSize; - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 加载本地图片的回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; NativeImageCallBack{ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 当子线程加载完了本地的图片，将Bitmap和图片路径回调在此方法中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param path\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onImageLoader(Bitmap bitmap, String path); - } - } 该类是一个单例类，提供了本地图片加载，内存缓存，裁剪等逻辑，该类在加载本地图片的时候采用的是异步加载的方式，对于大图片的加载也是比较耗时的，所以采用子线程的方式去加载，对于图片的缓存机制使用的是LruCache，使用手机分配给应用程序内存的1/4用来缓存图片，除了使用LruCache缓存图片之外，还对图片进行了裁剪，举个很简单的例子，假如我们的控件大小是100 * 100， 而我们的图片是400*400，我们加载这么大的图片需要很多的内存，所以我们采用了图片裁剪，根据控件的大小来确定图片的裁剪比例，从而减小内存的消耗，提高GridView滑动的流畅度，介绍里面几个比较重要的方法\ncomputeScale()计算图片需要裁剪的比例，根据控件的大小和图片的大小确定比例，如果图片比控件大，我们就进行裁剪，否则不需要。 decodeThumbBitmapForFile()方法是根据计算好了图片裁剪的比例之后从文件中加载图片，我们先设置options.inJustDecodeBounds = true表示解析不占用内存，但是我们能获取图片的具体大小，利用computeScale()计算好比例，在将options.inJustDecodeBounds=false,再次解析Bitmap，这样子就对图片进行了裁剪。 loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack)我们在客户端只需要调用该方法就能获取到Bitmap对象，里面的具体逻辑是先判断内存缓存LruCache中是否存在该Bitmap，不存在就开启子线程去读取，为了方便管理加载本地图片线程，这里使用了线程池，池中只能容纳一个线程，读取完了本地图片先将Bitmap加入到LruCache中，保存的Key为图片路径，然后再使用Handler通知主线程图片加载好了，之后将Bitmap和路径回调到方法onImageLoader(Bitmap bitmap, String path)中，该方法的mPoint是用来封装控件的宽和高的对象 如果不对图片进行裁剪直接这个方法的重载方法loadNativeImage(final String path, final NativeImageCallBack mCallBack) 就行了，逻辑是一样的，只是这个方法不对图片进行裁剪 接下来就是GridView的Adapter类的代码\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18730223#)[copy](http://blog.csdn.net/xiaanming/article/details/18730223#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/169891)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/169891/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.imagescan; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Point; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.BaseAdapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.imagescan.MyImageView.OnMeasureListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.imagescan.NativeImageLoader.NativeImageCallBack; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; GroupAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; BaseAdapter{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;ImageBean\u0026gt; list; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Point mPoint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Point(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//用来封装ImageView的宽和高的对象\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GridView mGridView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; LayoutInflater mInflater; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; list.size(); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object getItem(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; list.get(position); - } - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getItemId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; position; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; GroupAdapter(Context context, List\u0026lt;ImageBean\u0026gt; list, GridView mGridView){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.list = list; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mGridView = mGridView; - mInflater = LayoutInflater.from(context); - } - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; ViewHolder viewHolder; - ImageBean mImageBean = list.get(position); - String path = mImageBean.getTopImagePath(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(convertView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - viewHolder = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewHolder(); - convertView = mInflater.inflate(R.layout.grid_group_item, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - viewHolder.mImageView = (MyImageView) convertView.findViewById(R.id.group_image); - viewHolder.mTextViewTitle = (TextView) convertView.findViewById(R.id.group_title); - viewHolder.mTextViewCounts = (TextView) convertView.findViewById(R.id.group_count); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//用来监听ImageView的宽和高\u0026lt;/span\u0026gt; - viewHolder.mImageView.setOnMeasureListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnMeasureListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasureSize(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height) { - mPoint.set(width, height); - } - }); - - convertView.setTag(viewHolder); - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - viewHolder = (ViewHolder) convertView.getTag(); - viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no); - } - - viewHolder.mTextViewTitle.setText(mImageBean.getFolderName()); - viewHolder.mTextViewCounts.setText(Integer.toString(mImageBean.getImageCounts())); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//给ImageView设置路径Tag,这是异步加载图片的小技巧\u0026lt;/span\u0026gt; - viewHolder.mImageView.setTag(path); - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//利用NativeImageLoader类加载本地图片\u0026lt;/span\u0026gt; - Bitmap bitmap = NativeImageLoader.getInstance().loadNativeImage(path, mPoint, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; NativeImageCallBack() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onImageLoader(Bitmap bitmap, String path) { - ImageView mImageView = (ImageView) mGridView.findViewWithTag(path); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(bitmap != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mImageView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - mImageView.setImageBitmap(bitmap); - } - } - }); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(bitmap != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - viewHolder.mImageView.setImageBitmap(bitmap); - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no); - } - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; convertView; - } - - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ViewHolder{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyImageView mImageView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; TextView mTextViewTitle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; TextView mTextViewCounts; - } - - - } 首先我们将每个item的图片路径设置Tag到该ImageView上面，然后利用NativeImageLoader来加载本地图片，但是我们显示的图片的宽和高可能远大于GirdView item中ImageView的大小，于是为了节省内存，我们需要对图片进行裁剪，需要对图片裁剪我们利用loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack)方法,我们就必须要获取ImageView的宽和高了\n但是我们想在getView()中获取ImageView的宽和高存在问题，在getView()里面刚开始显示item的时候利用ImageView.getWidth() 获取的都是0，为什么刚开始获取不到宽和高呢，因为我们使用LayoutInflater来将XML布局文件Inflater()成View的时候,View并没有显示在界面上面，表明并没有对View进行onMeasure(), onLayout(), onDraw()等操作，必须等到retrue convertView的时候，表示该item对应的View已经绘制在ListView的位置上了， 此时才对item对应的View进行onMeasure(), onLayout(), onDraw()等操作，这时候才能获取到Item的宽和高，于是我想到了自定义ImageView，在onMeasure()中利用回调的模式主动通知我ImageView测量的宽和高，但是这有一个小小的问题，就是显示GridView的第一个item的时候，获取的宽和高还是0，第二个就能正常获取了，第一个宽和高为0，表示我们不对第一张图片进行裁剪而已，在效率上也没啥问题，不知道大家有没有好的方法，可以在getView()中获取Item中某个控件的宽和高。\n自定义MyImageView的代码，我们只需要设置OnMeasureListener监听，当MyImageView测量完毕之后，就会将测量的宽和高回调到onMeasureSize()中，然后我们可以根据MyImageView的大小来裁剪图片\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18730223#)[copy](http://blog.csdn.net/xiaanming/article/details/18730223#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/169891)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/169891/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.imagescan; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyImageView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ImageView { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnMeasureListener onMeasureListener; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnMeasureListener(OnMeasureListener onMeasureListener) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onMeasureListener = onMeasureListener; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyImageView(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyImageView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMeasure(widthMeasureSpec, heightMeasureSpec); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将图片测量的大小回调到onMeasureSize()方法中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(onMeasureListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - onMeasureListener.onMeasureSize(getMeasuredWidth(), getMeasuredHeight()); - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnMeasureListener{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasureSize(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height); - } - - } 上面这些代码就完成了第一个界面的功能了，接下来就是点击GridView的item跳转另一个界面来显示该文件夹下面的所有图片，功能跟第一个界面差不多，也是使用GridView来显示图片，第二个界面的布局代码我就不贴了，直接贴上界面的代码\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18730223#)[copy](http://blog.csdn.net/xiaanming/article/details/18730223#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/169891)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/169891/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.imagescan; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ShowImageActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GridView mGridView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;String\u0026gt; list; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ChildAdapter adapter; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.show_image_activity); - - mGridView = (GridView) findViewById(R.id.child_grid); - list = getIntent().getStringArrayListExtra(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;data\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - adapter = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ChildAdapter(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, list, mGridView); - mGridView.setAdapter(adapter); - - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onBackPressed() { - Toast.makeText(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;选中 \u0026amp;#8220;\u0026lt;/span\u0026gt; + adapter.getSelectItems().size() + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; item\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_LONG).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onBackPressed(); - } - - - } GridView的item上面一个我们自定义的MyImageView用来显示图片，另外还有一个CheckBox来记录我们选中情况，Adapter的代码如下\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18730223#)[copy](http://blog.csdn.net/xiaanming/article/details/18730223#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/169891)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/169891/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.imagescan; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.HashMap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Iterator; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Map; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Point; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.BaseAdapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.CheckBox; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.CompoundButton; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.CompoundButton.OnCheckedChangeListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.imagescan.MyImageView.OnMeasureListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.imagescan.NativeImageLoader.NativeImageCallBack; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.nineoldandroids.animation.AnimatorSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.nineoldandroids.animation.ObjectAnimator; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ChildAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; BaseAdapter { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Point mPoint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Point(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//用来封装ImageView的宽和高的对象\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 用来存储图片的选中情况\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; HashMap\u0026lt;Integer, Boolean\u0026gt; mSelectMap = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;Integer, Boolean\u0026gt;(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GridView mGridView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;String\u0026gt; list; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; LayoutInflater mInflater; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ChildAdapter(Context context, List\u0026lt;String\u0026gt; list, GridView mGridView) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.list = list; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mGridView = mGridView; - mInflater = LayoutInflater.from(context); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; list.size(); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object getItem(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; list.get(position); - } - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getItemId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; position; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; ViewHolder viewHolder; - String path = list.get(position); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(convertView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - convertView = mInflater.inflate(R.layout.grid_child_item, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - viewHolder = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewHolder(); - viewHolder.mImageView = (MyImageView) convertView.findViewById(R.id.child_image); - viewHolder.mCheckBox = (CheckBox) convertView.findViewById(R.id.child_checkbox); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//用来监听ImageView的宽和高\u0026lt;/span\u0026gt; - viewHolder.mImageView.setOnMeasureListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnMeasureListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasureSize(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height) { - mPoint.set(width, height); - } - }); - - convertView.setTag(viewHolder); - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - viewHolder = (ViewHolder) convertView.getTag(); - viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no); - } - viewHolder.mImageView.setTag(path); - viewHolder.mCheckBox.setOnCheckedChangeListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnCheckedChangeListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCheckedChanged(CompoundButton buttonView, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isChecked) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//如果是未选中的CheckBox,则添加动画\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!mSelectMap.containsKey(position) || !mSelectMap.get(position)){ - addAnimation(viewHolder.mCheckBox); - } - mSelectMap.put(position, isChecked); - } - }); - - viewHolder.mCheckBox.setChecked(mSelectMap.containsKey(position) ? mSelectMap.get(position) : \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//利用NativeImageLoader类加载本地图片\u0026lt;/span\u0026gt; - Bitmap bitmap = NativeImageLoader.getInstance().loadNativeImage(path, mPoint, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; NativeImageCallBack() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onImageLoader(Bitmap bitmap, String path) { - ImageView mImageView = (ImageView) mGridView.findViewWithTag(path); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(bitmap != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mImageView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - mImageView.setImageBitmap(bitmap); - } - } - }); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(bitmap != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - viewHolder.mImageView.setImageBitmap(bitmap); - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - viewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; convertView; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 给CheckBox加点击动画，利用开源库nineoldandroids设置动画 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param view\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; addAnimation(View view){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; [] vaules = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[]{\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.5f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.6f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.7f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.8f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.9f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.1f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.2f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.3f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.25f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.2f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.15f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.1f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f}; - AnimatorSet set = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorSet(); - set.playTogether(ObjectAnimator.ofFloat(view, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;scaleX\u0026amp;#8221;\u0026lt;/span\u0026gt;, vaules), - ObjectAnimator.ofFloat(view, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;scaleY\u0026amp;#8221;\u0026lt;/span\u0026gt;, vaules)); - set.setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;150\u0026lt;/span\u0026gt;); - set.start(); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 获取选中的Item的position\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; List\u0026lt;Integer\u0026gt; getSelectItems(){ - List\u0026lt;Integer\u0026gt; list = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;Integer\u0026gt;(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(Iterator\u0026lt;Map.Entry\u0026lt;Integer, Boolean\u0026gt;\u0026gt; it = mSelectMap.entrySet().iterator(); it.hasNext();){ - Map.Entry\u0026lt;Integer, Boolean\u0026gt; entry = it.next(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(entry.getValue()){ - list.add(entry.getKey()); - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; list; - } - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ViewHolder{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyImageView mImageView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; CheckBox mCheckBox; - } - - - } 第二个界面的Adapter跟第一个界面差不多，无非多了一个CheckBox用来记录图片选择情况，我们只需要对CheckBox设置setOnCheckedChangeListener监听，微信的选中之后CheckBox有一个动画效果，所以我利用nineoldandroids动画库也给CheckBox加了一个动画效果，直接调用addAnimation()方法就能添加了，getSelectItems()方法就能获取我们选中的item的position了，知道了选中的position，其他的信息就都知道了，微信有对图片进行预览的功能，我这里就不添加了，如果有这个需求可以自行添加，给大家推荐一个https://github.com/chrisbanes/PhotoView\n运行项目，效果如下\n看起来还不错吧，采用的是异步读取图片，对图片进行了缓存和裁剪，使得在显示本地图片方面比较流畅，GridView滑动也挺流畅的，也有效的避免OOM的产生，工程中有些东西还没有贴完全，有兴趣的朋友可以下载Demo来运行一下，好了，今天的讲解到这里结束了，感谢大家观看，有疑问的朋友可以在下面留言，我会为大家解答的！\n项目源码，点击下载\n","permalink":"https://blog.zdltech.com/posts/android-%E4%BD%BF%E7%94%A8contentprovider%E6%89%AB%E6%8F%8F%E6%89%8B%E6%9C%BA%E4%B8%AD%E7%9A%84%E5%9B%BE%E7%89%87%E4%BB%BF%E5%BE%AE%E4%BF%A1%E6%98%BE%E7%A4%BA%E6%9C%AC%E5%9C%B0%E5%9B%BE/","summary":"\u003cp\u003e转载：\u003ca href=\"http://blog.csdn.net/xiaanming/article/details/18730223\"\u003ehttp://blog.csdn.net/xiaanming/article/details/18730223\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e写这篇文章之前，先简单说几句，首先是先恭喜下自己获得了2013年的博客之星称号，很意外也很开心，自己是从2013年开始写博客，那时候也不知道怎么写，我从小就不喜欢写日记，作文什么的，所以刚开始都是贴代码，也没有人看，后面慢慢的，写的文章被推荐博客首页和CSDN首页（这里也要小小的感谢下小编MM），访问量逐渐的多了起来，有更多的人看我的文章，这也使自己有了继续写文章的动力，也希望我写的东西对大家有点帮助吧，在2014年我会继续在CSDN上面写博客，然后是感谢博客之星给我投票支持我的朋友们，谢谢你们支持我的每一票，最后就是2014春节马上就到了，提前祝福大家新年快乐，工作顺利，事事顺心！\u003c/p\u003e\n\u003cp\u003e回到主题，之前群里面有朋友问我，有没有关于本地图片选择的Demo，类似微信的效果，他说网上没有这方面的Demo，问我能不能写一篇关于这个效果的Demo，于是我研究了下微信的本地图片选择的Demo，自己仿照的写了下分享给大家，希望对以后有这样子需求的朋友有一点帮助吧，主要使用的是ContentProvider扫描手机中的图片，并用GridView将图片显示出来，关于GridView和ListView显示图片的问题，一直是一个很头疼的问题，因为我们手机的内存有限，手机给每个应用程序分配的内存也有限，所以图片多的情况下很容易伴随着OOM的发生，不过现在也有很多的开源的图片显示框架，对显示很多图片进行了优化，大家有兴趣的可以去了解了解，今天我的这篇文章使用的是LruCache这个类（之前写了一篇使用LruCache加载网络图片的\u003ca href=\"http://blog.csdn.net/xiaanming/article/details/9825113\"\u003eAndroid 异步加载图片，使用LruCache和SD卡或手机缓存，效果非常的流畅\u003c/a\u003e）以及对图片进行相对应的裁剪，这样也可以尽量的避免OOM的发生，我们先看下微信的效果吧\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140124115941500?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhYW5taW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140124120013718?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhYW5taW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来我们就来实现这些效果吧，首先我们新建一个项目，取名ImageScan\u003c/p\u003e\n\u003cp\u003e首先我们先看第一个界面吧，使用将手机中的图片扫描出来，然后根据图片的所在的文件夹将其分类出来，并显示所在文件夹里面的一张图片和文件夹中图片个数，我们根据界面元素（文件夹名， 文件夹图片个数，文件夹中的一张图片）使用一个实体对象ImageBean来封装这三个属性\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18730223#)[copy](http://blog.csdn.net/xiaanming/article/details/18730223#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/169891)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/169891/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.imagescan;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * GridView的每个item的数据对象\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author len\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ImageBean{\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 文件夹的第一张图片路径\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String topImagePath;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 文件夹名\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String folderName;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 文件夹中的图片数\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; imageCounts;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getTopImagePath() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; topImagePath;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setTopImagePath(String topImagePath) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.topImagePath = topImagePath;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getFolderName() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; folderName;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setFolderName(String folderName) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.folderName = folderName;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getImageCounts() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; imageCounts;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setImageCounts(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; imageCounts) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.imageCounts = imageCounts;\n\n- }\n\n- \n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e接下来就是主界面的布局啦，上面的导航栏我没有加进去，只有下面的GridView，所以说主界面布局中只有一个GridView\u003c/p\u003e","title":"Android 使用ContentProvider扫描手机中的图片，仿微信显示本地图片效果"},{"content":"转载（http://blog.csdn.net/xiaanming/article/details/18311877）\n今天还是给大家带来自定义控件的编写，自定义一个ListView的左右滑动删除Item的效果，这个效果之前已经实现过了，有兴趣的可以看下Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果，之前使用的是滑动类Scroller来实现的，但是看了下通知栏的左右滑动删除效果，确实很棒，当我们滑动Item超过一半的时候，item的透明度就变成了0，我们就知道抬起手指的时候item就被删除了，当item的透明度不为0的时候，我们抬起手指Item会回到起始位置，这样我们就知道拖动到什么位置item会删除，什么位置Item不删除，用户体验更好了，还有一个效果，就是我们滑动删除了item的时候，ListView的其他item会出现向上或者向下滚动的效果，感觉效果很棒，所以在GitHub上面搜索了下，发现很多开源库都有这个效果，比如ListViewAnimations, android-swipelistview等等，我看了下实现原理，使用的是Jake Wharton的动画开源库NineOldAndroids，这个库究竟是干嘛的呢？在API3.0（Honeycomb）, SDK新增了一个android.animation包，里面的类是实现动画效果相关的类，通过Honeycomb API，能够实现非常复杂的动画效果，但是如果开发者想在3.0以下使用这一套API, 则需要使用开源框架Nine Old Androids，在这个库中会根据我们运行的机器判断其SDK版本，如果是API3.0以上则使用Android自带的动画类，否则就使用Nine Old Androids库中，这是一个兼容库，接下来我们就来看看这个效果的具体实现吧\n实现该效果的主要思路\n先根据手指触摸的点来获取点击的是ListView的哪一个Item 当手指在屏幕上面滑动的时候，我们要使得Item跟随手指的滑动而滑动 当我们抬起手指的时候，我们根据滑动的距离或者手指在屏幕上面的速度来判断Item是滑出屏幕还是滑动至其实位置 Item滑出屏幕时，使ListView的其他item产生向上挤压或者向下挤压的效果 大致的思路这是这四步，其中的一些细节接下来我会一一为大家解答的，接下来我们就用代码来实现这种效果吧\n首先我们新建一个工程，叫Swipedismisslistview,我们需要将Nine Old Androids这个库引入到工程，大家可以去https://github.com/JakeWharton/NineOldAndroids下载,可以使用Jar包，也可以使用工程库的形式引入到我们自己的工程，我们还需要自定义一个ListView，我们先看代码然后给大家讲解下具体的功能实现\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18311877#)[copy](http://blog.csdn.net/xiaanming/article/details/18311877#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/159353)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/159353/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.swipedismisslistview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; com.nineoldandroids.view.ViewHelper.setAlpha; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; com.nineoldandroids.view.ViewHelper.setTranslationX; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.VelocityTracker; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewConfiguration; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.nineoldandroids.animation.Animator; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.nineoldandroids.animation.AnimatorListenerAdapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.nineoldandroids.animation.ValueAnimator; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.nineoldandroids.view.ViewHelper; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.nineoldandroids.view.ViewPropertyAnimator; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SwipeDismissListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ListView { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 认为是用户滑动的最小距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mSlop; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 滑动的最小速度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMinFlingVelocity; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 滑动的最大速度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMaxFlingVelocity; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 执行动画的时间\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; mAnimationTime = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;150\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 用来标记用户是否正在滑动中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; mSwiping; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 滑动速度检测类\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; VelocityTracker mVelocityTracker; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 手指按下的position\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDownPosition; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 按下的item对应的View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View mDownView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mDownX; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mDownY; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * item的宽度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mViewWidth; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 当ListView的Item滑出界面回调的接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnDismissCallback onDismissCallback; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 设置动画时间\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param mAnimationTime\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setmAnimationTime(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; mAnimationTime) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mAnimationTime = mAnimationTime; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 设置删除回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param onDismissCallback\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnDismissCallback(OnDismissCallback onDismissCallback) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onDismissCallback = onDismissCallback; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SwipeDismissListView(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SwipeDismissListView(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, attrs, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SwipeDismissListView(Context context, AttributeSet attrs, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - - ViewConfiguration vc = ViewConfiguration.get(context); - mSlop = vc.getScaledTouchSlop(); - mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取滑动的最小速度\u0026lt;/span\u0026gt; - mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取滑动的最大速度\u0026lt;/span\u0026gt; - } - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent ev) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (ev.getAction()) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: - handleActionDown(ev); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; handleActionMove(ev); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - handleActionUp(ev); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 按下事件处理\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param ev\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleActionDown(MotionEvent ev) { - mDownX = ev.getX(); - mDownY = ev.getY(); - - mDownPosition = pointToPosition((\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) mDownX, (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) mDownY); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mDownPosition == AdapterView.INVALID_POSITION) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - } - - mDownView = getChildAt(mDownPosition \u0026amp;#8211; getFirstVisiblePosition()); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mDownView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mViewWidth = mDownView.getWidth(); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//加入速度检测\u0026lt;/span\u0026gt; - mVelocityTracker = VelocityTracker.obtain(); - mVelocityTracker.addMovement(ev); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 处理手指滑动的方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param ev\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; handleActionMove(MotionEvent ev) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mVelocityTracker == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || mDownView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获取X方向滑动的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; deltaX = ev.getX() \u0026amp;#8211; mDownX; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; deltaY = ev.getY() \u0026amp;#8211; mDownY; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// X方向滑动的距离大于mSlop并且Y方向滑动的距离小于mSlop，表示可以滑动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (Math.abs(deltaX) \u0026gt; mSlop \u0026amp;\u0026amp; Math.abs(deltaY) \u0026lt; mSlop) { - mSwiping = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//当手指滑动item,取消item的点击事件，不然我们滑动Item也伴随着item点击事件的发生\u0026lt;/span\u0026gt; - MotionEvent cancelEvent = MotionEvent.obtain(ev); - cancelEvent.setAction(MotionEvent.ACTION_CANCEL | - (ev.getActionIndex()\u0026lt;\u0026lt; MotionEvent.ACTION_POINTER_INDEX_SHIFT)); - onTouchEvent(cancelEvent); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mSwiping) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 跟谁手指移动item\u0026lt;/span\u0026gt; - ViewHelper.setTranslationX(mDownView, deltaX); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 透明度渐变\u0026lt;/span\u0026gt; - ViewHelper.setAlpha(mDownView, Math.max(0f, Math.min(1f, 1f \u0026amp;#8211; 2f * Math.abs(deltaX)/ mViewWidth))); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 手指滑动的时候,返回true，表示SwipeDismissListView自己处理onTouchEvent,其他的就交给父类来处理\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev); - - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 手指抬起的事件处理\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param ev\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleActionUp(MotionEvent ev) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mVelocityTracker == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || mDownView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;|| !mSwiping) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; deltaX = ev.getX() \u0026amp;#8211; mDownX; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//通过滑动的距离计算出X,Y方向的速度\u0026lt;/span\u0026gt; - mVelocityTracker.computeCurrentVelocity(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityX = Math.abs(mVelocityTracker.getXVelocity()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityY = Math.abs(mVelocityTracker.getYVelocity()); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dismiss = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//item是否要滑出屏幕\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dismissRight = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//是否往右边删除\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//当拖动item的距离大于item的一半，item滑出屏幕\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (Math.abs(deltaX) \u0026gt; mViewWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;) { - dismiss = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - dismissRight = deltaX \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//手指在屏幕滑动的速度在某个范围内，也使得item滑出屏幕\u0026lt;/span\u0026gt; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMinFlingVelocity \u0026lt;= velocityX - \u0026amp;\u0026amp; velocityX \u0026lt;= mMaxFlingVelocity \u0026amp;\u0026amp; velocityY \u0026lt; velocityX) { - dismiss = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - dismissRight = mVelocityTracker.getXVelocity() \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (dismiss) { - ViewPropertyAnimator.animate(mDownView) - .translationX(dismissRight ? mViewWidth : -mViewWidth)\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//X轴方向的移动距离\u0026lt;/span\u0026gt; - .alpha(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - .setDuration(mAnimationTime) - .setListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorListenerAdapter() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationEnd(Animator animation) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Item滑出界面之后执行删除\u0026lt;/span\u0026gt; - performDismiss(mDownView, mDownPosition); - } - }); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将item滑动至开始位置\u0026lt;/span\u0026gt; - ViewPropertyAnimator.animate(mDownView) - .translationX(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - .alpha(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) - .setDuration(mAnimationTime).setListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//移除速度检测\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mVelocityTracker != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - mVelocityTracker.recycle(); - mVelocityTracker = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - - mSwiping = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 在此方法中执行item删除之后，其他的item向上或者向下滚动的动画，并且将position回调到方法onDismiss()中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param dismissView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param dismissPosition\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; performDismiss(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View dismissView, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dismissPosition) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; ViewGroup.LayoutParams lp = dismissView.getLayoutParams();\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取item的布局参数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; originalHeight = dismissView.getHeight();\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//item的高度\u0026lt;/span\u0026gt; - - ValueAnimator animator = ValueAnimator.ofInt(originalHeight, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).setDuration(mAnimationTime); - animator.start(); - - animator.addListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorListenerAdapter() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationEnd(Animator animation) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (onDismissCallback != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - onDismissCallback.onDismiss(dismissPosition); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//这段代码很重要，因为我们并没有将item从ListView中移除，而是将item的高度设置为0\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//所以我们在动画执行完毕之后将item设置回来\u0026lt;/span\u0026gt; - ViewHelper.setAlpha(dismissView, 1f); - ViewHelper.setTranslationX(dismissView, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - ViewGroup.LayoutParams lp = dismissView.getLayoutParams(); - lp.height = originalHeight; - dismissView.setLayoutParams(lp); - - } - }); - - animator.addUpdateListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ValueAnimator.AnimatorUpdateListener() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationUpdate(ValueAnimator valueAnimator) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//这段代码的效果是ListView删除某item之后，其他的item向上滑动的效果\u0026lt;/span\u0026gt; - lp.height = (Integer) valueAnimator.getAnimatedValue(); - dismissView.setLayoutParams(lp); - } - }); - - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 删除的回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnDismissCallback { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDismiss(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dismissPosition); - } - - } 看过Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果你会发现，这个自定义的SwipeDismissListView只重写了onTouchEvent()方法，其实我们重写这一个方法就能实现我们需要的效果\n我们先看手指按下屏幕的处理方法handleActionDown();该方法里面根据我们手指按下的点根据pointToPosition()方法来获取我们点击的position,然后利用getChildAt()来获取我们按下的item的View对象，并且加入手指在屏幕滑动的速度检查，这一步相对来说还是比较简单\n接下来就是手指在屏幕上面滑动的处理方法handleActionMove(),这个方法就稍微的复杂些，我们需要根据手指在X轴的滑动距离和Y轴的滑动距离来判断是ListView item的水平滑动还是ListView的上下滑动，当满足Math.abs(deltaX) \u0026gt; mSlop \u0026amp;\u0026amp; Math.abs(deltaY) \u0026lt; mSlop这个条件时候，我们用一个布尔值mSwiping来标记Item现在处于水平滑动的状态，这时候我们需要处理Item跟随手指的滑动而滑动的逻辑，我们使用ViewHelper来处理Item的滑动逻辑，这个类会根据机器的SDK版本来判断使用Android系统的API还是NineOldandroids中自己实现的API使得View滑动的效果，NineOldandroids中主要使用Camera（可以实现各种复杂动画效果的类），我们直接使用ViewHelper的setTranslationX()和setAlpha()就实现了item滑动和透明度渐变的效果，为了使得我们在滑动item的时候，ListView不上下滚动，我们必须返回true来屏蔽ListView的上下滚动，这里需要我们要非常熟悉Android的事件分发机制，这里我就不说明了，大家不了解的去网上找找相关的文章看看\n还有一个问题，就是当我们滑动ListView的item的时候，会伴随着item的点击事件，这不是我们想要的效果，所以当Item滑动的时候我们需要取消ListView Item的点击事件\n在看手指抬起的时候的处理方法handleActionUp(),这里面需要根据手指的滑动速度或者Item移动的距离来判断Item是滑出屏幕还是滑动至起始位置，并且要判断item向左还是向右滑出屏幕等等逻辑，具体的逻辑可以看代码，相信大家都看得懂.\n我这里要说说ViewPropertyAnimator类,这个类能更好的实现一个View同时进行多个动画的功能，当然我们也可以使用ObjectAnimator利用AnimatorSet来实现一个View上的多个同时进行的动画效果，例如我们可以将\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18311877#)[copy](http://blog.csdn.net/xiaanming/article/details/18311877#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/159353)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/159353/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - ViewPropertyAnimator.animate(mDownView) - .translationX(dismissRight ? mViewWidth : -mViewWidth)\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//X轴方向的移动距离\u0026lt;/span\u0026gt; - .alpha(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - .setDuration(mAnimationTime) - .setListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorListenerAdapter() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationEnd(Animator animation) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Item滑出界面之后执行删除\u0026lt;/span\u0026gt; - performDismiss(mDownView, mDownPosition); - } - }); 替换成\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18311877#)[copy](http://blog.csdn.net/xiaanming/article/details/18311877#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/159353)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/159353/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - AnimatorSet set = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorSet(); - set.playTogether(ObjectAnimator.ofFloat(mDownView, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;translationX\u0026amp;#8221;\u0026lt;/span\u0026gt;, dismissRight ? mViewWidth : -mViewWidth), - ObjectAnimator.ofFloat(mDownView, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;alpha\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)); - set.setDuration(mAnimationTime).start(); - set.addListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorListenerAdapter() { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationEnd(Animator animation) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Item滑出界面之后执行删除\u0026lt;/span\u0026gt; - performDismiss(mDownView, mDownPosition); - } - }); 在效果上面是一样的，但是ViewPropertyAnimator在性能上要比使用ObjectAnimator来实现多个同时进行的动画要高的多，举个例子，假如要对View使用移动和透明度的动画，使用ViewPropertyAnimator的话，某个时间点上我们只需要调用一次invalidate()方法刷新界面就行了，而使用ObjectAnimator的话，移动的动画需要调用invalidate(),透明度的动画也需要调用invalidate()方法，在性能上使用AnimationSet比ViewPropertyAnimator要低，但是有的时候我们还是需要使用ObjectAnimator，比如，在某个时间内，我们需要将View先变大在变小在变大等复杂情况，这时候ObjectAnimator就派上用场了，例如\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18311877#)[copy](http://blog.csdn.net/xiaanming/article/details/18311877#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/159353)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/159353/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - ObjectAnimator.ofInt(mDownView, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;scaleX\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; ,\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt; ,\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;).setDuration(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;).start() 通过上面的几步我们就实现了ListView的左右滑动删除item的效果啦，但是还有一个效果，item删除之后，ListView的其他item向上或者向下缓缓滑动的效果，实现这个也很容易，就是动态设置item的高度，item高度逐渐变小，这样其他的item就会出现向上或者向下挤压的效果啦!\n这里我们使用的是ValueAnimator这个类，这个类并不是针对View作用的动画，而是对某个值作用的动画，他默认使用的Interpolator(插补器)是AccelerateDecelerateInterpolator(开始和结束的时候慢，中间快) ， 举个很简单的例子，我们在10秒内使用ValueAnimator将某个值从0变化到100，如果使用LinearInterpolator（线性插补器，匀速变化）在第2秒的时候，这个值变成了20，而是用AccelerateDecelerateInterpolator，可能在第二秒的时候这个值为15或者13，所以我们在ValueAnimator变化的时候设置值动画变化的监听器AnimatorUpdateListener就知道某个时间这个值变成了多少，从而对View的某个属性进行设置（例如大小），所以ValueAnimator是间接的对View设置动画的 了解了ValueAnimator的使用原理，我们就可以现实上面的动画效果了，我们使用ValueAnimator将item的高度变成0,设置ValueAnimator变化的监听，我们在回调函数onAnimationUpdate()中动态的设置item的高度， 然后添加AnimatorListener监听动画的状态（例如动画开始，结束，重复等）监听，在动画结束的回调函数onAnimationEnd()中删除该item的数据，调用notifyDataSetChanged刷新ListView,看看下面这段代码\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18311877#)[copy](http://blog.csdn.net/xiaanming/article/details/18311877#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/159353)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/159353/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - ViewHelper.setAlpha(dismissView, 1f); - ViewHelper.setTranslationX(dismissView, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - ViewGroup.LayoutParams lp = dismissView.getLayoutParams(); - lp.height = originalHeight; - dismissView.setLayoutParams(lp); 我们使用动画只是将item移动出了屏幕，并且将item的高度设置为了0，并没有将item的View从ListView中Remove掉，况且ListView也不能直接Remove掉Item的，只能将数据源删除，在调用notifyDataSetChanged()刷新，所以我们需要将刚刚滑出屏幕高度设置为0的Item恢复回来\n自定义控件的代码我们已经编写完了，接下来我们就要使用它了，先看界面的布局代码\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18311877#)[copy](http://blog.csdn.net/xiaanming/article/details/18311877#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/159353)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/159353/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;RelativeLayout xmlns:android=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - xmlns:tools=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; - - \u0026lt;com.example.swipedismisslistview.SwipeDismissListView - android:id=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@+id/swipeDismissListView\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:listSelector=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/transparent\u0026amp;#8221;\u0026lt;/span\u0026gt; - android:cacheColorHint=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/transparent\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; - \u0026lt;/com.example.swipedismisslistview.SwipeDismissListView\u0026gt; - - \u0026lt;/RelativeLayout\u0026gt; 很简单，一个RelativeLayout包裹我们自定义的ListView控件，接下来就是主界面的代码编写，跟平常的ListView使用一样，但是我们需要设置OnDismissCallback()监听，在\nonDismiss()中删除该位置对于的数据，刷新ListView\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18311877#)[copy](http://blog.csdn.net/xiaanming/article/details/18311877#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/159353)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/159353/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.swipedismisslistview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView.OnItemClickListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ArrayAdapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.swipedismisslistview.SwipeDismissListView.OnDismissCallback; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SwipeActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; SwipeDismissListView swipeDismissListView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ArrayAdapter\u0026lt;String\u0026gt; adapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;String\u0026gt; dataSourceList = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;String\u0026gt;(); - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_swipe); - init(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; init() { - swipeDismissListView = (SwipeDismissListView) findViewById(R.id.swipeDismissListView); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;; i++) { - dataSourceList.add(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;滑动删除\u0026amp;#8221;\u0026lt;/span\u0026gt; + i); - } - - adapter = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayAdapter\u0026lt;String\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, - android.R.layout.simple_list_item_1, - android.R.id.text1, dataSourceList); - - swipeDismissListView.setAdapter(adapter); - - swipeDismissListView.setOnDismissCallback(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnDismissCallback() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDismiss(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dismissPosition) { - adapter.remove(adapter.getItem(dismissPosition)); - } - }); - - - swipeDismissListView.setOnItemClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnItemClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onItemClick(AdapterView\u0026lt;?\u0026gt; parent, View view, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; id) { - Toast.makeText(SwipeActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, adapter.getItem(position), Toast.LENGTH_SHORT).show(); - } - }); - - } - - } 所有的代码都已经编写完毕了，接下来就是运行工程，看看具体的效果是不是我们想要的\n好了，今天的讲解到这里结束了，有了NineOldAndroids我们可以在2.x的手机上面实现许多复杂的动画效果，文章也介绍了关于开源库NineOldAndroids使用的一些知识，文章有点长，希望读者还是先将文章看下，然后自己看看能不能自己实现出来，有什么不明白的地方请在下面留言，我会为大家解答的！\n项目源码，点击下载\nps： 下载源码的时候运行出错，是因为我加入了NineOldAndroids的Jar包，然后又加入了NineOldAndroids工程库，主要是我写DEMO的时候为了方便看源码就导入了NineOldAndroids工程库，大家删除一个JAR包或者NineOldAndroids工程库 就能解决了\n","permalink":"https://blog.zdltech.com/posts/android-%E4%BD%BF%E7%94%A8nineoldandroids%E5%AE%9E%E7%8E%B0%E7%BB%9A%E4%B8%BD%E7%9A%84listview%E5%B7%A6%E5%8F%B3%E6%BB%91%E5%8A%A8%E5%88%A0%E9%99%A4item%E6%95%88%E6%9E%9C/","summary":"\u003cp\u003e转载（\u003ca href=\"http://blog.csdn.net/xiaanming/article/details/18311877\"\u003ehttp://blog.csdn.net/xiaanming/article/details/18311877\u003c/a\u003e）\u003c/p\u003e\n\u003cp\u003e今天还是给大家带来自定义控件的编写，自定义一个ListView的左右滑动删除Item的效果，这个效果之前已经实现过了，有兴趣的可以看下\u003ca href=\"http://blog.csdn.net/xiaanming/article/details/17539199\"\u003eAndroid 使用Scroller实现绚丽的ListView左右滑动删除Item效果\u003c/a\u003e，之前使用的是滑动类Scroller来实现的，但是看了下通知栏的左右滑动删除效果，确实很棒，当我们滑动Item超过一半的时候，item的透明度就变成了0，我们就知道抬起手指的时候item就被删除了，当item的透明度不为0的时候，我们抬起手指Item会回到起始位置，这样我们就知道拖动到什么位置item会删除，什么位置Item不删除，用户体验更好了，还有一个效果，就是我们滑动删除了item的时候，ListView的其他item会出现向上或者向下滚动的效果，感觉效果很棒，所以在GitHub上面搜索了下，发现很多开源库都有这个效果，比如\u003ca href=\"https://github.com/nhaarman/ListViewAnimations\"\u003eListViewAnimations\u003c/a\u003e, \u003ca href=\"https://github.com/47deg/android-swipelistview\"\u003eandroid-swipelistview\u003c/a\u003e等等，我看了下实现原理，使用的是Jake Wharton的动画开源库\u003ca href=\"https://github.com/JakeWharton/NineOldAndroids\"\u003eNineOldAndroids\u003c/a\u003e，这个库究竟是干嘛的呢？在API3.0（Honeycomb）, SDK新增了一个android.animation包，里面的类是实现动画效果相关的类，通过Honeycomb API，能够实现非常复杂的动画效果，但是如果开发者想在3.0以下使用这一套API, 则需要使用开源框架Nine Old Androids，在这个库中会根据我们运行的机器判断其SDK版本，如果是API3.0以上则使用Android自带的动画类，否则就使用Nine Old Androids库中，这是一个兼容库，接下来我们就来看看这个效果的具体实现吧\u003c/p\u003e\n\u003cp\u003e实现该效果的主要思路\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e先根据手指触摸的点来获取点击的是ListView的哪一个Item\u003c/li\u003e\n\u003cli\u003e当手指在屏幕上面滑动的时候，我们要使得Item跟随手指的滑动而滑动\u003c/li\u003e\n\u003cli\u003e当我们抬起手指的时候，我们根据滑动的距离或者手指在屏幕上面的速度来判断Item是滑出屏幕还是滑动至其实位置\u003c/li\u003e\n\u003cli\u003eItem滑出屏幕时，使ListView的其他item产生向上挤压或者向下挤压的效果\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e大致的思路这是这四步，其中的一些细节接下来我会一一为大家解答的，接下来我们就用代码来实现这种效果吧\u003c/p\u003e\n\u003cp\u003e首先我们新建一个工程，叫Swipedismisslistview,我们需要将Nine Old Androids这个库引入到工程，大家可以去\u003ca href=\"https://github.com/JakeWharton/NineOldAndroids\"\u003ehttps://github.com/JakeWharton/NineOldAndroids\u003c/a\u003e下载,可以使用Jar包，也可以使用工程库的形式引入到我们自己的工程，我们还需要自定义一个ListView，我们先看代码然后给大家讲解下具体的功能实现\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18311877#)[copy](http://blog.csdn.net/xiaanming/article/details/18311877#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/159353)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/159353/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.swipedismisslistview;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; com.nineoldandroids.view.ViewHelper.setAlpha;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; com.nineoldandroids.view.ViewHelper.setTranslationX;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.VelocityTracker;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewConfiguration;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.nineoldandroids.animation.Animator;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.nineoldandroids.animation.AnimatorListenerAdapter;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.nineoldandroids.animation.ValueAnimator;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.nineoldandroids.view.ViewHelper;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.nineoldandroids.view.ViewPropertyAnimator;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SwipeDismissListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ListView {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 认为是用户滑动的最小距离\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mSlop;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 滑动的最小速度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMinFlingVelocity;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 滑动的最大速度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMaxFlingVelocity;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 执行动画的时间\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; mAnimationTime = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;150\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 用来标记用户是否正在滑动中\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; mSwiping;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 滑动速度检测类\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; VelocityTracker mVelocityTracker;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 手指按下的position\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDownPosition;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 按下的item对应的View\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View mDownView;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mDownX;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mDownY;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * item的宽度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mViewWidth;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 当ListView的Item滑出界面回调的接口\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnDismissCallback onDismissCallback;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 设置动画时间\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param mAnimationTime\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setmAnimationTime(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; mAnimationTime) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mAnimationTime = mAnimationTime;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 设置删除回调接口\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param onDismissCallback\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnDismissCallback(OnDismissCallback onDismissCallback) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onDismissCallback = onDismissCallback;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SwipeDismissListView(Context context) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SwipeDismissListView(Context context, AttributeSet attrs) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, attrs, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SwipeDismissListView(Context context, AttributeSet attrs,\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle);\n\n- \n- ViewConfiguration vc = ViewConfiguration.get(context);\n\n- mSlop = vc.getScaledTouchSlop();\n\n- mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取滑动的最小速度\u0026lt;/span\u0026gt;\n\n- mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();  \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取滑动的最大速度\u0026lt;/span\u0026gt;\n\n- }\n\n- \n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent ev) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (ev.getAction()) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN:\n\n- handleActionDown(ev);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE:\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; handleActionMove(ev);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP:\n\n- handleActionUp(ev);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 按下事件处理\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param ev\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleActionDown(MotionEvent ev) {\n\n- mDownX = ev.getX();\n\n- mDownY = ev.getY();\n\n- \n- mDownPosition = pointToPosition((\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) mDownX, (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) mDownY);\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mDownPosition == AdapterView.INVALID_POSITION) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- mDownView = getChildAt(mDownPosition \u0026amp;#8211; getFirstVisiblePosition());\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mDownView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n\n- mViewWidth = mDownView.getWidth();\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//加入速度检测\u0026lt;/span\u0026gt;\n\n- mVelocityTracker = VelocityTracker.obtain();\n\n- mVelocityTracker.addMovement(ev);\n\n- }\n\n- \n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 处理手指滑动的方法\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param ev\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; handleActionMove(MotionEvent ev) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mVelocityTracker == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || mDownView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获取X方向滑动的距离\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; deltaX = ev.getX() \u0026amp;#8211; mDownX;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; deltaY = ev.getY() \u0026amp;#8211; mDownY;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// X方向滑动的距离大于mSlop并且Y方向滑动的距离小于mSlop，表示可以滑动\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (Math.abs(deltaX) \u0026gt; mSlop \u0026amp;\u0026amp; Math.abs(deltaY) \u0026lt; mSlop) {\n\n- mSwiping = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//当手指滑动item,取消item的点击事件，不然我们滑动Item也伴随着item点击事件的发生\u0026lt;/span\u0026gt;\n\n- MotionEvent cancelEvent = MotionEvent.obtain(ev);\n\n- cancelEvent.setAction(MotionEvent.ACTION_CANCEL |\n\n- (ev.getActionIndex()\u0026lt;\u0026lt; MotionEvent.ACTION_POINTER_INDEX_SHIFT));\n\n- onTouchEvent(cancelEvent);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mSwiping) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 跟谁手指移动item\u0026lt;/span\u0026gt;\n\n- ViewHelper.setTranslationX(mDownView, deltaX);\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 透明度渐变\u0026lt;/span\u0026gt;\n\n- ViewHelper.setAlpha(mDownView, Math.max(0f, Math.min(1f, 1f \u0026amp;#8211; 2f * Math.abs(deltaX)/ mViewWidth)));\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 手指滑动的时候,返回true，表示SwipeDismissListView自己处理onTouchEvent,其他的就交给父类来处理\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev);\n\n- \n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 手指抬起的事件处理\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param ev\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleActionUp(MotionEvent ev) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mVelocityTracker == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || mDownView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;|| !mSwiping) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; deltaX = ev.getX() \u0026amp;#8211; mDownX;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//通过滑动的距离计算出X,Y方向的速度\u0026lt;/span\u0026gt;\n\n- mVelocityTracker.computeCurrentVelocity(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityX = Math.abs(mVelocityTracker.getXVelocity());\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityY = Math.abs(mVelocityTracker.getYVelocity());\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dismiss = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//item是否要滑出屏幕\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dismissRight = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//是否往右边删除\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//当拖动item的距离大于item的一半，item滑出屏幕\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (Math.abs(deltaX) \u0026gt; mViewWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;) {\n\n- dismiss = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- dismissRight = deltaX \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//手指在屏幕滑动的速度在某个范围内，也使得item滑出屏幕\u0026lt;/span\u0026gt;\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMinFlingVelocity \u0026lt;= velocityX\n\n- \u0026amp;\u0026amp; velocityX \u0026lt;= mMaxFlingVelocity \u0026amp;\u0026amp; velocityY \u0026lt; velocityX) {\n\n- dismiss = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- dismissRight = mVelocityTracker.getXVelocity() \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (dismiss) {\n\n- ViewPropertyAnimator.animate(mDownView)\n\n- .translationX(dismissRight ? mViewWidth : -mViewWidth)\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//X轴方向的移动距离\u0026lt;/span\u0026gt;\n\n- .alpha(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n\n- .setDuration(mAnimationTime)\n\n- .setListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorListenerAdapter() {\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationEnd(Animator animation) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Item滑出界面之后执行删除\u0026lt;/span\u0026gt;\n\n- performDismiss(mDownView, mDownPosition);\n\n- }\n\n- });\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将item滑动至开始位置\u0026lt;/span\u0026gt;\n\n- ViewPropertyAnimator.animate(mDownView)\n\n- .translationX(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n\n- .alpha(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;)\n\n- .setDuration(mAnimationTime).setListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//移除速度检测\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mVelocityTracker != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){\n\n- mVelocityTracker.recycle();\n\n- mVelocityTracker = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- mSwiping = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 在此方法中执行item删除之后，其他的item向上或者向下滚动的动画，并且将position回调到方法onDismiss()中\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param dismissView\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param dismissPosition\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; performDismiss(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View dismissView, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dismissPosition) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; ViewGroup.LayoutParams lp = dismissView.getLayoutParams();\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取item的布局参数\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; originalHeight = dismissView.getHeight();\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//item的高度\u0026lt;/span\u0026gt;\n\n- \n- ValueAnimator animator = ValueAnimator.ofInt(originalHeight, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).setDuration(mAnimationTime);\n\n- animator.start();\n\n- \n- animator.addListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; AnimatorListenerAdapter() {\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationEnd(Animator animation) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (onDismissCallback != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n\n- onDismissCallback.onDismiss(dismissPosition);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//这段代码很重要，因为我们并没有将item从ListView中移除，而是将item的高度设置为0\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//所以我们在动画执行完毕之后将item设置回来\u0026lt;/span\u0026gt;\n\n- ViewHelper.setAlpha(dismissView, 1f);\n\n- ViewHelper.setTranslationX(dismissView, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- ViewGroup.LayoutParams lp = dismissView.getLayoutParams();\n\n- lp.height = originalHeight;\n\n- dismissView.setLayoutParams(lp);\n\n- \n- }\n\n- });\n\n- \n- animator.addUpdateListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ValueAnimator.AnimatorUpdateListener() {\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onAnimationUpdate(ValueAnimator valueAnimator) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//这段代码的效果是ListView删除某item之后，其他的item向上滑动的效果\u0026lt;/span\u0026gt;\n\n- lp.height = (Integer) valueAnimator.getAnimatedValue();\n\n- dismissView.setLayoutParams(lp);\n\n- }\n\n- });\n\n- \n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 删除的回调接口\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @author xiaanming\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnDismissCallback {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDismiss(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dismissPosition);\n\n- }\n\n- \n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e看过\u003ca href=\"http://blog.csdn.net/xiaanming/article/details/17539199\"\u003eAndroid 使用Scroller实现绚丽的ListView左右滑动删除Item效果\u003c/a\u003e你会发现，这个自定义的SwipeDismissListView只重写了onTouchEvent()方法，其实我们重写这一个方法就能实现我们需要的效果\u003c/p\u003e","title":"Android 使用NineOldAndroids实现绚丽的ListView左右滑动删除Item效果"},{"content":"实现思路\n1.使用http://nineoldandroids.com/动画库\nhttps://github.com/JakeWharton/NineOldAndroids\nhttps://github.com/jfeinstein10/JazzyViewPager\n2.使用3.0以上直接使用\n3.自定义Viewpage\n","permalink":"https://blog.zdltech.com/posts/android-viewpage%E5%8A%A8%E7%94%BB%E5%AE%9E%E7%8E%B0/","summary":"\u003cp\u003e实现思路\u003c/p\u003e\n\u003cp\u003e1.使用http://nineoldandroids.com/动画库\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/JakeWharton/NineOldAndroids\"\u003ehttps://github.com/JakeWharton/NineOldAndroids\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/jfeinstein10/JazzyViewPager\"\u003ehttps://github.com/jfeinstein10/JazzyViewPager\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e2.使用3.0以上直接使用\u003c/p\u003e\n\u003cp\u003e3.自定义Viewpage\u003c/p\u003e","title":"android ViewPage动画实现"},{"content":" **21. [drag-sort-listview](https://github.com/bauerca/drag-sort-listview)** DragSortListView（DSLV）是Android ListView的一个扩展，支持拖拽排序和左右滑动删除功能。重写了TouchInterceptor（TI）类来提供更加优美的拖拽动画效果。 [![](http://cms.csdnimg.cn/article/201305/06/5187781b64cbe_middle.jpg)](http://cms.csdnimg.cn/article/201305/06/5187781b64cbe.jpg) [![](http://cms.csdnimg.cn/article/201305/06/5187782519829_middle.jpg)](http://cms.csdnimg.cn/article/201305/06/5187782519829.jpg) DSLV主要特性： - 完美的拖拽支持； - 在拖动时提供更平滑的滚动列表滚动； - 支持每个ListItem高度的多样性 - 公开startDrag()和stopDrag()方法； - 有公开的接口可以自定义拖动的View。 DragSortListView适用于带有任何优先级的列表：收藏夹、播放列表及清单等，算得上是目前Android开源实现拖动排序操作最完美的方案。 **22. [c-geo-opensource](https://github.com/cgeo/c-geo-opensource)** c:geo是Android设备上一个简单而又强大的非官方地理寻宝客户端。与其他类似应用不同的是，c:geo不需要Web浏览器，也不需要文件输出。你可以在毫无准备的情况下，毫无后顾之忧地带上你的智能手机去进行地理寻宝。当然，你也不需要付钱，因为它是免费的。 [![](http://cms.csdnimg.cn/article/201305/07/518894ed23ed2_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/518894ed23ed2.jpg) c-geo-opensource包含了c:geo所有开源代码。 详情请参考：[**c:geo**](http://www.cgeo.org/) **23. [NineOldAndroids](https://github.com/JakeWharton/NineOldAndroids)** 自Android 3.0以上的版本，SDK新增了一个android.animation包，里面的类都是跟动画效果实现相关的，通过Honeycomb API，能够实现非常复杂的动画效果。但如果开发者想在3.0以下的版本中也能使用到这套API，那么Nine Old Androids就会是你最好的选择，该API和Honeycomb API完全一样，只是改变了你使用com.nineoldandroids.XXX的入口。 [![](http://cms.csdnimg.cn/article/201305/07/51889435c4f33_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51889435c4f33.jpg) 该项目包含两个工程，一个是Library，即为动画效果的实现库，另一个则是Sample，是对如何使用该API的演示。开发者可以直接登陆Google Play下载安装[**Nine Old Androids Sample**](https://play.google.com/store/apps/details?id=com.jakewharton.nineoldandroids.sample)，查看演示。 详情请参考：[**Nine Old Androids**](http://nineoldandroids.com/) **24. [ppsspp](https://github.com/hrydgard/ppsspp)** PPSSPP是由GC/Wii模拟器[**Dolphin**](http://dolphin-emu.org/)联合创始人之一Henrik Rydgård开发的一款免费的跨平台开源模拟器，支持Windows、Linux、Mac、Android、iOS、BlackBerry 10等主流计算机与移动操作系统，可直接工作在x86、x64、ARM等CPU平台上，以GNU GPLv2许可协议发布，主要使用C++编写以提高效率和可移植性。 [![](http://cms.csdnimg.cn/article/201305/06/518779953e825_middle.jpg)](http://cms.csdnimg.cn/article/201305/06/518779953e825.jpg) 只要支持OpenGL ES 2.0，PPSSPP就可以在相当低规格的硬件设备上运行，包括基于ARM的手机及平板电脑。 详情请参考：[**PPSSPP**](http://www.ppsspp.org/) **25. [androidquery](https://github.com/androidquery/androidquery)** Android-Query（AQuery）是一个轻量级的开发包，用于实现Android上的异步任务和操作UI元素，可让Android应用开发更简单、更容易，也更有趣。 **26. [droid-fu](https://github.com/mttkay/droid-fu)** Droid-Fu是一个开源的通用Android应用库，其主要目的是为了让Android开发更容易，包含有许多工具类，还有非常易用的Android组件。 Droid-Fu提供支持的领域包括： - Android应用的生命周期帮助 - 支持处理Intents和diagnostics类 - 后台任务支持 - HTTP消息处理 - 对象、HTTP响应及远程图像高速缓存 - 定制各种Adapter及View [![](http://cms.csdnimg.cn/article/201305/07/518897f7199f4_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/518897f7199f4.jpg) Droid-Fu最大的优势在于它的应用生命周期帮助类，如果你正在开发一款Android应用，而它的主要任务是运行后台任务，比如从Web上抓取数据，那么，你一定会使用到Droid-Fu，不过，目前该项目在GitHub上已经停止更新维护。 详情请参考：[**droid-fu**](https://github.com/mttkay/droid-fu/wiki) **27. [TextSecure](https://github.com/WhisperSystems/TextSecure)** TextSecure是Whisper Systems团队开发的一个Android上的加密信息客户端，旨在增强用户和企业通信的安全性，其源代码于2011年被Twitter发布在GitHub开源数据库中。 [![](http://cms.csdnimg.cn/article/201305/07/51889740c3bd3_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51889740c3bd3.jpg) 该软件允许用户将在Android设备上所有发送和接收的短信内容进行加密，还可以将加密信息发送给另一个TextSecure用户。 **28. [XobotOS](https://github.com/xamarin/XobotOS)** XobotOS是Xamarin的一个研究项目，用于将Android 4.0从Java/Dalvik移植到C#，并对移植后的性能及内存占用情况进行检测。 [![](http://cms.csdnimg.cn/article/201305/06/518779fcb89b9_middle.jpg)](http://cms.csdnimg.cn/article/201305/06/518779fcb89b9.jpg) **29. [ignition](https://github.com/mttkay/ignition)** 在编写Android应用时，通过提供即用组件和包含许多样板文件的实用类，ignition可以让你的Android应用快速起步。ignition涵盖的区域包括： - Widget、Adapter、Dialog等UI组件； - 允许编写简单却强大的网络代码的HTTP Wrapper库； - 加载远程Web图像并进行缓存的类； - 简单但有效的缓存框架（将对所有对象树做出响应的HTTP缓存到内存或硬盘中）； - Intents、diagnostics等几个能让API级别更容易向后兼容的帮助类； - 更友好、更强大的AsyncTask实现。 [![](http://cms.csdnimg.cn/article/201305/07/51889448dd732_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51889448dd732.jpg) ignition包括三个子项目： - ignition-core——是一个可以直接编译到App中的Android库项目。 - ignition-support——一个标准的Java库项目，被部署为一个普通的JAR，包含了大部分实用工具类。开发者可以独立使用该工程的核心模块。 - ignition-location——一个可以直接编译到应用程序中的Android AspectJ库项目。能够让定位应用在不需要Activity位置更新处理的情况下获取到最新的位置信息。 详情请参考：[**ignition Sample applications**](https://github.com/mttkay/ignition/wiki/Sample-applications) **30. [android_page_curl](https://github.com/harism/android_page_curl)** android_page_curl是一个在Android上使用OpenGL ES实现类似书本翻页效果的示例程序。（点击链接查看[**视频演示**](http://www.youtube.com/watch?v=iwu7P5PCpsw)） [![](http://cms.csdnimg.cn/article/201305/07/51889b43ec9e9_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51889b43ec9e9.jpg) **31. [asmack](https://github.com/Flowdalic/asmack)** 说到aSmack，自然要先提提Smack。Smack API是一个完整的实现了XMPP协议的开源API库，而aSmack则是Smack在Android上的构建版本，于2013年2月初迁移到GitHub上，该资源库并不包含太多的代码，只是一个构建环境。开发者可以利用该API进行基于XMPP协议的即时消息应用程序开发。 详情请参考：[**asmack**](https://code.google.com/p/asmack/) **32. [AndroidBillingLibrary](https://github.com/robotmedia/AndroidBillingLibrary)** In-app Billing是一项Google Play服务，能够让你在应用内进行数字内容销售，可销售的数字内容范围非常广，包括媒体文件、照片等下载内容，还包括游戏级别、药剂、增值服务和功能等虚拟内容。Android Billing Library可以实现In-app Billing的所有规范，并提供更高级的类来进行使用。 [![](http://cms.csdnimg.cn/article/201305/07/5188ae278fb5a_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188ae278fb5a.jpg) Google于2012年底正式发布了v3版Android In-app Billing，但截至目前，GitHub上的Android Billing Library还只能支持到v2版，据悉Google将于2013年初对它进行更新。 详情请参考：[**Google Play In-app Billing**](http://developer.android.com/google/play/billing/index.html) **33. [Crouton](https://github.com/keyboardsurfer/Crouton)** Crouton是Android上的一个可以让开发者对环境中的Toast进行替换的类，以一个应用程序窗口的方式显示，而其显示位置则由开发者自己决定。 [![](http://cms.csdnimg.cn/article/201305/07/5188b6491fd81_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188b6491fd81.jpg) 开发者可以直接登陆Google Play下载安装[**Crouton Demo**](https://play.google.com/store/apps/details?id=de.keyboardsurfer.app.demo.crouton)，查看应用演示。 **34. [cwac-endless](https://github.com/commonsguy/cwac-endless)** CommonsWare Android Components（CWAC）是一个开源的Android组件库，用来解决Android开发中各个方面的常见问题，每个 CWAC组件打包成一个独立的jar文件，其中就包含cwac-endless。 [![](http://cms.csdnimg.cn/article/201305/07/5188ca3020955_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188ca3020955.jpg) cwac-endless提供一个EndlessAdapter，这是一个自动分页的List，当用户浏览到List最后一行时自动请求新的数据。 详情请参考：[**Commons Ware**](http://commonsware.com/cwac) **35. [DiskLruCache](https://github.com/JakeWharton/DiskLruCache)** 在Android应用开发中，为了提高UI的流畅性、响应速度，提供更高的用户体验，开发者常常会绞尽脑汁地思考如何实现高效加载图片，而DiskLruCache实现正是开发者常用的图片缓存技术之一。Disk LRU Cache，顾名思义，硬件缓存，就是一个在文件系统中使用有限空间进行高速缓存。每个缓存项都有一个字符串键和一个固定大小的值。 [![](http://cms.csdnimg.cn/article/201305/07/5188fc60a7729_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188fc60a7729.jpg) 点击链接[**下载**](http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy\u0026amp;g=com.jakewharton\u0026amp;a=disklrucache\u0026amp;v=LATEST)该库项目。 **36. [Android-SlideExpandableListView](https://github.com/tjerkw/Android-SlideExpandableListView)** 如果你对Android提供的Android ExpandableListView并不满意，一心想要实现诸如Spotify应用那般的效果，那么SlideExpandableListView绝对是你最好的选择。该库允许你自定义每个列表项目中的ListView，一旦用户点击某个按钮，即可实现该列表项目区域滑动。 [![](http://cms.csdnimg.cn/article/201305/07/5188ff9b1a21b_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188ff9b1a21b.jpg) **37. [gauges-android](https://github.com/github/gauges-android)** Gaug.es for Android是由[**gaug.es**](http://get.gaug.es/)推出的一款在Android设备上对网站流量数据进行实时统计的应用。gauges-android包含了该应用的源代码，开发者可以直接登陆[**Google Play**](https://play.google.com/store/apps/details?id=com.github.mobile.gauges)下载安装该应用。 [![](http://cms.csdnimg.cn/article/201305/07/5189035ebf373_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5189035ebf373.jpg) **38. [acra](https://github.com/ACRA/acra)** ACRA是一个能够让Android应用自动将崩溃报告以谷歌文档电子表的形式进行发送的库，旨在当应用发生崩溃或出现错误行为时，开发者可以获取到相关数据。 [![](http://cms.csdnimg.cn/article/201305/07/5189057f9195e_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5189057f9195e.jpg) **39. [roboguice](https://github.com/roboguice/roboguice)** RoboGuice是Android平台上基于Google Guice开发的一个库，可以大大简化Android应用开发的代码及一些繁琐重复的代码。给Android带来了简单、易用的依赖注入，如果你使用过Spring或Guice的话，你就会知道这种编程方式是多么的便捷。 [![](http://cms.csdnimg.cn/article/201305/07/518906ff6405e_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/518906ff6405e.jpg) **40. [otto](https://github.com/square/otto)** Otto是由Square发布的一个着重于Android支持的基于Guava的强大的事件总线，在对应用程序不同部分进行解耦之后，仍然允许它们进行有效的沟通。 [![](http://cms.csdnimg.cn/article/201305/07/51890a97dcfc6_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51890a97dcfc6.jpg) 详情请参考：**[Otto](http://square.github.io/otto/)** - [直接拿来用！最火的Android开源项目（完结篇）](http://www.csdn.net/article/1970-01-01/2815370) - [直接拿来用！最火的iOS开源项目（二）](http://www.csdn.net/article/1970-01-01/2815806) - [直接拿来用！最火的iOS开源项目（三）](http://www.csdn.net/article/1970-01-01/2816230) - [直接拿来用！最火的iOS开源项目（一）](http://www.csdn.net/article/1970-01-01/2815530) - [直接拿来用！Facebook移动开源项目大合集](http://www.csdn.net/article/1970-01-01/2819435) \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/%E7%9B%B4%E6%8E%A5%E6%8B%BF%E6%9D%A5%E7%94%A8%E6%9C%80%E7%81%AB%E7%9A%84android%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/","summary":"\u003cp\u003e \u003c/p\u003e\n\u003cdiv class=\"con news_content\"\u003e\n\u003cpre\u003e\u003ccode\u003e**21. [drag-sort-listview](https://github.com/bauerca/drag-sort-listview)**\n\n\n\n\n\nDragSortListView（DSLV）是Android ListView的一个扩展，支持拖拽排序和左右滑动删除功能。重写了TouchInterceptor（TI）类来提供更加优美的拖拽动画效果。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/06/5187781b64cbe_middle.jpg)](http://cms.csdnimg.cn/article/201305/06/5187781b64cbe.jpg) [![](http://cms.csdnimg.cn/article/201305/06/5187782519829_middle.jpg)](http://cms.csdnimg.cn/article/201305/06/5187782519829.jpg)\n\n\n\n\n\nDSLV主要特性：\n\n\n\n\n- 完美的拖拽支持；\n\n- 在拖动时提供更平滑的滚动列表滚动；\n\n- 支持每个ListItem高度的多样性\n\n- 公开startDrag()和stopDrag()方法；\n\n- 有公开的接口可以自定义拖动的View。\n\n\n\n\n\nDragSortListView适用于带有任何优先级的列表：收藏夹、播放列表及清单等，算得上是目前Android开源实现拖动排序操作最完美的方案。\n\n\n\n\n\n**22. [c-geo-opensource](https://github.com/cgeo/c-geo-opensource)**\n\n\n\n\n\nc:geo是Android设备上一个简单而又强大的非官方地理寻宝客户端。与其他类似应用不同的是，c:geo不需要Web浏览器，也不需要文件输出。你可以在毫无准备的情况下，毫无后顾之忧地带上你的智能手机去进行地理寻宝。当然，你也不需要付钱，因为它是免费的。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/518894ed23ed2_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/518894ed23ed2.jpg)\n\n\n\n\n\nc-geo-opensource包含了c:geo所有开源代码。\n\n\n\n\n\n详情请参考：[**c:geo**](http://www.cgeo.org/)\n\n\n\n\n\n**23. [NineOldAndroids](https://github.com/JakeWharton/NineOldAndroids)**\n\n\n\n\n\n自Android 3.0以上的版本，SDK新增了一个android.animation包，里面的类都是跟动画效果实现相关的，通过Honeycomb API，能够实现非常复杂的动画效果。但如果开发者想在3.0以下的版本中也能使用到这套API，那么Nine Old Androids就会是你最好的选择，该API和Honeycomb API完全一样，只是改变了你使用com.nineoldandroids.XXX的入口。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/51889435c4f33_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51889435c4f33.jpg)\n\n\n\n\n\n该项目包含两个工程，一个是Library，即为动画效果的实现库，另一个则是Sample，是对如何使用该API的演示。开发者可以直接登陆Google Play下载安装[**Nine Old Androids Sample**](https://play.google.com/store/apps/details?id=com.jakewharton.nineoldandroids.sample)，查看演示。\n\n\n\n\n\n详情请参考：[**Nine Old Androids**](http://nineoldandroids.com/)\n\n\n\n\n\n**24. [ppsspp](https://github.com/hrydgard/ppsspp)**\n\n\n\n\n\nPPSSPP是由GC/Wii模拟器[**Dolphin**](http://dolphin-emu.org/)联合创始人之一Henrik Rydgård开发的一款免费的跨平台开源模拟器，支持Windows、Linux、Mac、Android、iOS、BlackBerry 10等主流计算机与移动操作系统，可直接工作在x86、x64、ARM等CPU平台上，以GNU GPLv2许可协议发布，主要使用C++编写以提高效率和可移植性。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/06/518779953e825_middle.jpg)](http://cms.csdnimg.cn/article/201305/06/518779953e825.jpg)\n\n\n\n\n\n只要支持OpenGL ES 2.0，PPSSPP就可以在相当低规格的硬件设备上运行，包括基于ARM的手机及平板电脑。\n\n\n\n\n\n详情请参考：[**PPSSPP**](http://www.ppsspp.org/)\n\n\n\n\n\n**25. [androidquery](https://github.com/androidquery/androidquery)**\n\n\n\n\n\nAndroid-Query（AQuery）是一个轻量级的开发包，用于实现Android上的异步任务和操作UI元素，可让Android应用开发更简单、更容易，也更有趣。\n\n\n\n\n\n**26. [droid-fu](https://github.com/mttkay/droid-fu)**\n\n\n\n\n\nDroid-Fu是一个开源的通用Android应用库，其主要目的是为了让Android开发更容易，包含有许多工具类，还有非常易用的Android组件。\n\n\n\n\n\nDroid-Fu提供支持的领域包括：\n\n\n\n\n- Android应用的生命周期帮助\n\n- 支持处理Intents和diagnostics类\n\n- 后台任务支持\n\n- HTTP消息处理\n\n- 对象、HTTP响应及远程图像高速缓存\n\n- 定制各种Adapter及View\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/518897f7199f4_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/518897f7199f4.jpg)\n\n\n\n\n\nDroid-Fu最大的优势在于它的应用生命周期帮助类，如果你正在开发一款Android应用，而它的主要任务是运行后台任务，比如从Web上抓取数据，那么，你一定会使用到Droid-Fu，不过，目前该项目在GitHub上已经停止更新维护。\n\n\n\n\n\n详情请参考：[**droid-fu**](https://github.com/mttkay/droid-fu/wiki)\n\n\n\n\n\n**27. [TextSecure](https://github.com/WhisperSystems/TextSecure)**\n\n\n\n\n\nTextSecure是Whisper Systems团队开发的一个Android上的加密信息客户端，旨在增强用户和企业通信的安全性，其源代码于2011年被Twitter发布在GitHub开源数据库中。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/51889740c3bd3_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51889740c3bd3.jpg)\n\n\n\n\n\n该软件允许用户将在Android设备上所有发送和接收的短信内容进行加密，还可以将加密信息发送给另一个TextSecure用户。\n\n\n\n\n\n**28. [XobotOS](https://github.com/xamarin/XobotOS)**\n\n\n\n\n\nXobotOS是Xamarin的一个研究项目，用于将Android 4.0从Java/Dalvik移植到C#，并对移植后的性能及内存占用情况进行检测。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/06/518779fcb89b9_middle.jpg)](http://cms.csdnimg.cn/article/201305/06/518779fcb89b9.jpg)\n\n\n\n\n\n**29. [ignition](https://github.com/mttkay/ignition)**\n\n\n\n\n\n在编写Android应用时，通过提供即用组件和包含许多样板文件的实用类，ignition可以让你的Android应用快速起步。ignition涵盖的区域包括：\n\n\n\n\n- Widget、Adapter、Dialog等UI组件；\n\n- 允许编写简单却强大的网络代码的HTTP Wrapper库；\n\n- 加载远程Web图像并进行缓存的类；\n\n- 简单但有效的缓存框架（将对所有对象树做出响应的HTTP缓存到内存或硬盘中）；\n\n- Intents、diagnostics等几个能让API级别更容易向后兼容的帮助类；\n\n- 更友好、更强大的AsyncTask实现。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/51889448dd732_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51889448dd732.jpg)\n\n\n\n\n\nignition包括三个子项目：\n\n\n\n\n- ignition-core——是一个可以直接编译到App中的Android库项目。\n\n- ignition-support——一个标准的Java库项目，被部署为一个普通的JAR，包含了大部分实用工具类。开发者可以独立使用该工程的核心模块。\n\n- ignition-location——一个可以直接编译到应用程序中的Android AspectJ库项目。能够让定位应用在不需要Activity位置更新处理的情况下获取到最新的位置信息。\n\n\n\n\n\n详情请参考：[**ignition Sample applications**](https://github.com/mttkay/ignition/wiki/Sample-applications)\n\n\n\n\n\n**30. [android_page_curl](https://github.com/harism/android_page_curl)**\n\n\n\n\n\nandroid_page_curl是一个在Android上使用OpenGL ES实现类似书本翻页效果的示例程序。（点击链接查看[**视频演示**](http://www.youtube.com/watch?v=iwu7P5PCpsw)）\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/51889b43ec9e9_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51889b43ec9e9.jpg)\n\n\n\n\n\n**31. [asmack](https://github.com/Flowdalic/asmack)**\n\n\n\n\n\n说到aSmack，自然要先提提Smack。Smack API是一个完整的实现了XMPP协议的开源API库，而aSmack则是Smack在Android上的构建版本，于2013年2月初迁移到GitHub上，该资源库并不包含太多的代码，只是一个构建环境。开发者可以利用该API进行基于XMPP协议的即时消息应用程序开发。\n\n\n\n\n\n详情请参考：[**asmack**](https://code.google.com/p/asmack/)\n\n\n\n\n\n**32. [AndroidBillingLibrary](https://github.com/robotmedia/AndroidBillingLibrary)**\n\n\n\n\n\nIn-app Billing是一项Google Play服务，能够让你在应用内进行数字内容销售，可销售的数字内容范围非常广，包括媒体文件、照片等下载内容，还包括游戏级别、药剂、增值服务和功能等虚拟内容。Android Billing Library可以实现In-app Billing的所有规范，并提供更高级的类来进行使用。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/5188ae278fb5a_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188ae278fb5a.jpg)\n\n\n\n\n\nGoogle于2012年底正式发布了v3版Android In-app Billing，但截至目前，GitHub上的Android Billing Library还只能支持到v2版，据悉Google将于2013年初对它进行更新。\n\n\n\n\n\n详情请参考：[**Google Play In-app Billing**](http://developer.android.com/google/play/billing/index.html)\n\n\n\n\n\n**33. [Crouton](https://github.com/keyboardsurfer/Crouton)**\n\n\n\n\n\nCrouton是Android上的一个可以让开发者对环境中的Toast进行替换的类，以一个应用程序窗口的方式显示，而其显示位置则由开发者自己决定。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/5188b6491fd81_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188b6491fd81.jpg)\n\n\n\n\n\n开发者可以直接登陆Google Play下载安装[**Crouton Demo**](https://play.google.com/store/apps/details?id=de.keyboardsurfer.app.demo.crouton)，查看应用演示。\n\n\n\n\n\n**34. [cwac-endless](https://github.com/commonsguy/cwac-endless)**\n\n\n\n\n\nCommonsWare Android Components（CWAC）是一个开源的Android组件库，用来解决Android开发中各个方面的常见问题，每个 CWAC组件打包成一个独立的jar文件，其中就包含cwac-endless。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/5188ca3020955_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188ca3020955.jpg)\n\n\n\n\n\ncwac-endless提供一个EndlessAdapter，这是一个自动分页的List，当用户浏览到List最后一行时自动请求新的数据。\n\n\n\n\n\n详情请参考：[**Commons Ware**](http://commonsware.com/cwac)\n\n\n\n\n\n**35. [DiskLruCache](https://github.com/JakeWharton/DiskLruCache)**\n\n\n\n\n\n在Android应用开发中，为了提高UI的流畅性、响应速度，提供更高的用户体验，开发者常常会绞尽脑汁地思考如何实现高效加载图片，而DiskLruCache实现正是开发者常用的图片缓存技术之一。Disk LRU Cache，顾名思义，硬件缓存，就是一个在文件系统中使用有限空间进行高速缓存。每个缓存项都有一个字符串键和一个固定大小的值。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/5188fc60a7729_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188fc60a7729.jpg)\n\n\n\n\n\n点击链接[**下载**](http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy\u0026amp;g=com.jakewharton\u0026amp;a=disklrucache\u0026amp;v=LATEST)该库项目。\n\n\n\n\n\n**36. [Android-SlideExpandableListView](https://github.com/tjerkw/Android-SlideExpandableListView)**\n\n\n\n\n\n如果你对Android提供的Android ExpandableListView并不满意，一心想要实现诸如Spotify应用那般的效果，那么SlideExpandableListView绝对是你最好的选择。该库允许你自定义每个列表项目中的ListView，一旦用户点击某个按钮，即可实现该列表项目区域滑动。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/5188ff9b1a21b_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188ff9b1a21b.jpg)\n\n\n\n\n\n**37. [gauges-android](https://github.com/github/gauges-android)**\n\n\n\n\n\nGaug.es for Android是由[**gaug.es**](http://get.gaug.es/)推出的一款在Android设备上对网站流量数据进行实时统计的应用。gauges-android包含了该应用的源代码，开发者可以直接登陆[**Google Play**](https://play.google.com/store/apps/details?id=com.github.mobile.gauges)下载安装该应用。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/5189035ebf373_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5189035ebf373.jpg)\n\n\n\n\n\n**38. [acra](https://github.com/ACRA/acra)**\n\n\n\n\n\nACRA是一个能够让Android应用自动将崩溃报告以谷歌文档电子表的形式进行发送的库，旨在当应用发生崩溃或出现错误行为时，开发者可以获取到相关数据。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/5189057f9195e_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5189057f9195e.jpg)\n\n\n\n\n\n**39. [roboguice](https://github.com/roboguice/roboguice)**\n\n\n\n\n\nRoboGuice是Android平台上基于Google Guice开发的一个库，可以大大简化Android应用开发的代码及一些繁琐重复的代码。给Android带来了简单、易用的依赖注入，如果你使用过Spring或Guice的话，你就会知道这种编程方式是多么的便捷。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/518906ff6405e_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/518906ff6405e.jpg)\n\n\n\n\n\n**40. [otto](https://github.com/square/otto)**\n\n\n\n\n\nOtto是由Square发布的一个着重于Android支持的基于Guava的强大的事件总线，在对应用程序不同部分进行解耦之后，仍然允许它们进行有效的沟通。\n\n\n\n\n\n[![](http://cms.csdnimg.cn/article/201305/07/51890a97dcfc6_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51890a97dcfc6.jpg)\n\n\n\n\n\n详情请参考：**[Otto](http://square.github.io/otto/)**\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv id=\"Tab3\" class=\"relational\"\u003e\n  \u003cdiv class=\"con Contentbox\"\u003e\n    \u003cdiv id=\"con_three_1\" class=\"hover\"\u003e\n\u003cpre\u003e\u003ccode\u003e    - [直接拿来用！最火的Android开源项目（完结篇）](http://www.csdn.net/article/1970-01-01/2815370)\n    \n    - [直接拿来用！最火的iOS开源项目（二）](http://www.csdn.net/article/1970-01-01/2815806)\n    \n    - [直接拿来用！最火的iOS开源项目（三）](http://www.csdn.net/article/1970-01-01/2816230)\n    \n    - [直接拿来用！最火的iOS开源项目（一）](http://www.csdn.net/article/1970-01-01/2815530)\n    \n    - [直接拿来用！Facebook移动开源项目大合集](http://www.csdn.net/article/1970-01-01/2819435)\n    \n  \n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e","title":"直接拿来用！最火的Android开源项目"},{"content":"回弹的ScrollView 网上看到的通常是ElasticScrollView，\n有一个Bug：点击子控件滑动时，滑动无效，\n所以针对此问题，我对ElasticScrollView做了改进。\n原理图 代码 我在注释中做了详细的说明\n\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Rect; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.Animation; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.DecelerateInterpolator; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.TranslateAnimation; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ScrollView; \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/** * Created by Tindle Wei. */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-class\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;ElasticScrollView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;ScrollView\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/** * 手指抖动误差 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; SHAKE_MOVE_VALUE = \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/** * Scrollview内部的view */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View innerView; \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/** * 记录innerView最初的Y位置 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; startY; \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/** * 记录原始innerView的大小位置 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Rect outRect = \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect(); \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; animationFinish = \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;ElasticScrollView\u0026lt;/span\u0026gt;(Context context) { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); } \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;ElasticScrollView\u0026lt;/span\u0026gt;(Context context, AttributeSet attrs) { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); } \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/** * 继承自View * 在xml的所有布局加载完之后执行 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onFinishInflate\u0026lt;/span\u0026gt;() { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getChildCount() \u0026gt; \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;) { innerView = getChildAt(\u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;); } } \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/** * 继承自ViewGroup * 返回true, 截取触摸事件 * 返回false, 将事件传递给onTouchEvent()和子控件的dispatchTouchEvent() */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onInterceptTouchEvent\u0026lt;/span\u0026gt;(MotionEvent ev) { \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 判断 点击子控件 or 按住子控件滑动\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 如果点击子控件，则返回 false, 子控件响应点击事件\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 如果按住子控件滑动，则返回 true, 滑动布局\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (ev.getAction()) { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: { startY = ev.getY(); \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; currentY = ev.getY(); \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; scrollY = currentY - startY; \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 是否返回 true\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; Math.abs(scrollY) \u0026gt; SHAKE_MOVE_VALUE; } } \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 默认返回 false\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onInterceptTouchEvent(ev); } \u0026lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onTouchEvent\u0026lt;/span\u0026gt;(MotionEvent ev) { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (innerView == \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev); } \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { myTouchEvent(ev); } \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev); } \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;myTouchEvent\u0026lt;/span\u0026gt;(MotionEvent ev) { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (animationFinish) { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (ev.getAction()) { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: startY = ev.getY(); \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev); \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: startY = \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isNeedAnimation()) { animation(); } \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev); \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; preY = startY == \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt; ? ev.getY() : startY; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; nowY = ev.getY(); \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; deltaY = (\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (preY - nowY); startY = nowY; \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 当滚动到最上或者最下时就不会再滚动，这时移动布局\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isNeedMove()) { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (outRect.isEmpty()) { \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 保存正常的布局位置\u0026lt;/span\u0026gt; outRect.set(innerView .getLeft(), innerView.getTop(), innerView.getRight(), innerView.getBottom()); } \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 移动布局\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 这里 deltaY/2 为了操作体验更好\u0026lt;/span\u0026gt; innerView.layout(innerView.getLeft(), innerView.getTop() - deltaY / \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, innerView.getRight(), innerView.getBottom() - deltaY / \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); } \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev); } \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; } } } \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/** * 开启移动动画 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;animation\u0026lt;/span\u0026gt;() { TranslateAnimation ta = \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TranslateAnimation(\u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;, outRect.top - innerView.getTop()); ta.setDuration(\u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;400\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 减速变化 为了用户体验更好\u0026lt;/span\u0026gt; ta.setInterpolator(\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DecelerateInterpolator()); ta.setAnimationListener(\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Animation.AnimationListener() { \u0026lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onAnimationStart\u0026lt;/span\u0026gt;(Animation animation) { animationFinish = \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onAnimationRepeat\u0026lt;/span\u0026gt;(Animation animation) { } \u0026lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onAnimationEnd\u0026lt;/span\u0026gt;(Animation animation) { innerView.clearAnimation(); \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 设置innerView回到正常的布局位置\u0026lt;/span\u0026gt; innerView.layout(outRect.left, outRect.top, outRect.right, outRect.bottom); outRect.setEmpty(); animationFinish = \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; } }); innerView.startAnimation(ta); } \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/** * 是否需要开启动画 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;isNeedAnimation\u0026lt;/span\u0026gt;() { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; !outRect.isEmpty(); } \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/** * 是否需要移动布局 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;isNeedMove\u0026lt;/span\u0026gt;() { \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; offset = innerView.getMeasuredHeight() - getHeight(); offset = (offset \u0026lt; \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;) ? \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;: offset; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollY = getScrollY(); \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (offset == \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt; || scrollY == offset); } } 其他说明 下面是继承关系：\nElasticScrollView extends ScrollView\nScrollView extends FrameLayout\nFrameLayout extends ViewGroup\nViewGroup extends View 解决子控件 截取滑动监听的代码在onInterceptTouchEvent() ,\n通过监听Y的变化，来判断是点击子控件还是上拉下拉 getMeasuredHeight()返回的是原始测量高度，与屏幕无关，\ngetHeight()返回的是在屏幕上显示的高度。\n实际上在当屏幕可以包裹内容的时候，他们的值是相等的，只有当view超出屏幕后，才能看出他们的区别。当超出屏幕后，getMeasuredHeight()等于getHeight()加上屏幕之外没有显示的高度。 getScrollY() 返回的是滑动View显示部分的顶部 转自：http://www.hotpost.co/8699.html\n","permalink":"https://blog.zdltech.com/posts/android%E5%8E%9F%E7%90%86-%E5%9B%9E%E5%BC%B9scrollview/","summary":"\u003ch3 id=\"回弹的scrollview\"\u003e回弹的ScrollView\u003c/h3\u003e\n\u003cp\u003e网上看到的通常是\u003ccode\u003eElasticScrollView\u003c/code\u003e，\u003cbr\u003e\n有一个Bug：点击子控件滑动时，滑动无效，\u003cbr\u003e\n所以针对此问题，我对\u003ccode\u003eElasticScrollView\u003c/code\u003e做了改进。\u003c/p\u003e\n\u003ch3 id=\"原理图\"\u003e原理图\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"Android原理——回弹ScrollView\" loading=\"lazy\" src=\"http://static.hotpost.co/images/2015/02/20150217_54e353a561c7e.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Android原理——回弹ScrollView\" loading=\"lazy\" src=\"http://static.hotpost.co/images/2015/02/20150217_54e353a58d5ce.png\"\u003e\u003c/p\u003e\n\u003ch3 id=\"代码\"\u003e代码\u003c/h3\u003e\n\u003cp\u003e我在注释中做了详细的说明\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Rect;\n\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent;\n\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\n\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.Animation;\n\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.DecelerateInterpolator;\n\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.TranslateAnimation;\n\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ScrollView;\n\n\u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\n * Created by Tindle Wei.\n */\u0026lt;/span\u0026gt;\n\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-class\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;ElasticScrollView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;ScrollView\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt;\n\n    \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\n     * 手指抖动误差\n     */\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; SHAKE_MOVE_VALUE = \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;;\n    \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\n     * Scrollview内部的view\n     */\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View innerView;\n    \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\n     * 记录innerView最初的Y位置\n     */\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; startY;\n    \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\n     * 记录原始innerView的大小位置\n     */\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Rect outRect = \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect();\n\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; animationFinish = \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;ElasticScrollView\u0026lt;/span\u0026gt;(Context context) {\n        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context);\n    }\n\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;ElasticScrollView\u0026lt;/span\u0026gt;(Context context, AttributeSet attrs) {\n        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);\n    }\n\n    \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\n     * 继承自View\n     * 在xml的所有布局加载完之后执行\n     */\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onFinishInflate\u0026lt;/span\u0026gt;() {\n        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getChildCount() \u0026gt; \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;) {\n            innerView = getChildAt(\u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;);\n        }\n    }\n\n    \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\n     * 继承自ViewGroup\n     * 返回true, 截取触摸事件\n     * 返回false, 将事件传递给onTouchEvent()和子控件的dispatchTouchEvent()\n     */\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onInterceptTouchEvent\u0026lt;/span\u0026gt;(MotionEvent ev) {\n\n        \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 判断 点击子控件 or 按住子控件滑动\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 如果点击子控件，则返回 false, 子控件响应点击事件\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 如果按住子控件滑动，则返回 true, 滑动布局\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (ev.getAction()) {\n            \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: {\n                startY = ev.getY();\n                \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n            }\n            \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: {\n                \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; currentY = ev.getY();\n                \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; scrollY = currentY - startY;\n\n                \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 是否返回 true\u0026lt;/span\u0026gt;\n                \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; Math.abs(scrollY) \u0026gt; SHAKE_MOVE_VALUE;\n            }\n        }\n        \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 默认返回 false\u0026lt;/span\u0026gt;\n        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onInterceptTouchEvent(ev);\n    }\n\n    \u0026lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onTouchEvent\u0026lt;/span\u0026gt;(MotionEvent ev) {\n        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (innerView == \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n            \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev);\n        } \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n            myTouchEvent(ev);\n        }\n        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev);\n    }\n\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;myTouchEvent\u0026lt;/span\u0026gt;(MotionEvent ev) {\n        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (animationFinish) {\n\n            \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (ev.getAction()) {\n                \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN:\n                    startY = ev.getY();\n                    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev);\n                    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n                \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP:\n                    startY = \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;;\n                    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isNeedAnimation()) {\n                        animation();\n                    }\n                    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev);\n                    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n                \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE:\n                    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; preY = \n                          startY == \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt; ? ev.getY() : startY;\n                    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; nowY = ev.getY();\n                    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; deltaY = (\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (preY - nowY);\n                    startY = nowY;\n\n                    \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 当滚动到最上或者最下时就不会再滚动，这时移动布局\u0026lt;/span\u0026gt;\n                    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isNeedMove()) {\n                        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (outRect.isEmpty()) {\n                            \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 保存正常的布局位置\u0026lt;/span\u0026gt;\n                            outRect.set(innerView\n                            .getLeft(),  innerView.getTop(), \n                            innerView.getRight(), \n                            innerView.getBottom());\n                        }\n                        \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 移动布局\u0026lt;/span\u0026gt;\n                        \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 这里 deltaY/2 为了操作体验更好\u0026lt;/span\u0026gt;\n                        innerView.layout(innerView.getLeft(),  \n                        innerView.getTop() - deltaY / \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;,  \n                        innerView.getRight(),  \n                        innerView.getBottom() - deltaY / \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;);\n                    } \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n                        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev);\n                    }\n                    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n                \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;:\n                    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n            }\n        }\n    }\n\n    \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\n     * 开启移动动画\n     */\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;animation\u0026lt;/span\u0026gt;() {\n        TranslateAnimation ta = \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TranslateAnimation(\u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;, outRect.top - innerView.getTop());\n        ta.setDuration(\u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;400\u0026lt;/span\u0026gt;);\n        \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 减速变化 为了用户体验更好\u0026lt;/span\u0026gt;\n        ta.setInterpolator(\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DecelerateInterpolator());\n        ta.setAnimationListener(\u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Animation.AnimationListener() {\n            \u0026lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n            \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onAnimationStart\u0026lt;/span\u0026gt;(Animation animation) {\n                animationFinish = \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n            }\n\n            \u0026lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n            \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onAnimationRepeat\u0026lt;/span\u0026gt;(Animation animation) {\n            }\n\n            \u0026lt;span class=\u0026quot;hljs-annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n            \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;onAnimationEnd\u0026lt;/span\u0026gt;(Animation animation) {\n                innerView.clearAnimation();\n                \u0026lt;span class=\u0026quot;hljs-comment\u0026quot;\u0026gt;// 设置innerView回到正常的布局位置\u0026lt;/span\u0026gt;\n                innerView.layout(outRect.left, \n                outRect.top, outRect.right, outRect.bottom);\n                outRect.setEmpty();\n                animationFinish = \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n            }\n        });\n        innerView.startAnimation(ta);\n    }\n\n    \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\n     * 是否需要开启动画\n     */\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;isNeedAnimation\u0026lt;/span\u0026gt;() {\n        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; !outRect.isEmpty();\n    }\n\n    \u0026lt;span class=\u0026quot;hljs-javadoc\u0026quot;\u0026gt;/**\n     * 是否需要移动布局\n     */\u0026lt;/span\u0026gt;\n    \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;hljs-title\u0026quot;\u0026gt;isNeedMove\u0026lt;/span\u0026gt;() {\n        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; offset = innerView.getMeasuredHeight() - getHeight();\n        offset = (offset \u0026lt; \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;) ? \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt;: offset;\n        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollY = getScrollY();\n        \u0026lt;span class=\u0026quot;hljs-keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (offset == \u0026lt;span class=\u0026quot;hljs-number\u0026quot;\u0026gt;0\u0026lt;/span\u0026gt; || scrollY == offset);\n    }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3 id=\"其他说明\"\u003e其他说明\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e下面是继承关系：\u003cbr\u003e\n\u003ccode\u003eElasticScrollView extends ScrollView\u003c/code\u003e\u003cbr\u003e\n\u003ccode\u003eScrollView extends FrameLayout\u003c/code\u003e\u003cbr\u003e\n\u003ccode\u003eFrameLayout extends ViewGroup\u003c/code\u003e\u003cbr\u003e\n\u003ccode\u003eViewGroup extends View\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e解决子控件 截取滑动监听的代码在\u003ccode\u003eonInterceptTouchEvent()\u003c/code\u003e ,\u003cbr\u003e\n通过监听Y的变化，来判断是点击子控件还是上拉下拉\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egetMeasuredHeight()\u003c/code\u003e返回的是原始测量高度，与屏幕无关，\u003cbr\u003e\n\u003ccode\u003egetHeight()\u003c/code\u003e返回的是在屏幕上显示的高度。\u003cbr\u003e\n实际上在当屏幕可以包裹内容的时候，他们的值是相等的，只有当\u003ccode\u003eview\u003c/code\u003e超出屏幕后，才能看出他们的区别。当超出屏幕后，\u003ccode\u003egetMeasuredHeight()\u003c/code\u003e等于\u003ccode\u003egetHeight()\u003c/code\u003e加上屏幕之外没有显示的高度。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003egetScrollY()\u003c/code\u003e 返回的是滑动View显示部分的顶部\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e转自：http://www.hotpost.co/8699.html\u003c/p\u003e","title":"Android原理——回弹ScrollView"},{"content":"文件夹 PATH 列表\n卷序列号为 000A-8F50\nE:.\n│ javaapk.com文件列表生成工具.bat\n│ 使用说明.txt\n│ 免费下载更多源码.url\n│ 目录列表.txt\n│\n├─android web应用\n│ jqmDemo_static.zip\n│ jqmMobileDemo-master.zip\n│ jqmMobileDemo1_1-master.zip\n│ Location1014.rar\n│\n├─anko\n│ anko服务端和客户端源码.rar\n│\n├─Bmob\n│ Bmob云后端数据库开发个失物招领的简单案例.zip\n│ 结合IM_SDK项目源码.zip\n│\n├─Button按钮\n│ 动态添加RadioGroup的RadioButton.zip\n│ 带有进度条的button.rar\n│ 自定义组件实现可滑动的ToggleButton的功能..rar\n│\n├─Dialog对话框\n│ android 自定义对话框.rar\n│ android-styled-dialogs 可自定义样式的dialog.zip\n│ Android中实现Iphone样式的AlertDialog.zip\n│ Android实现Windows风格的Dialog.zip\n│ HerilyAlertDialog完全自定义的Dialog.zip\n│ 仿QQ的头像选择弹出的对话框，酷似！.zip\n│ 基本的对话框.rar\n│ 自定义列表选择Dialog，适用网络请求数据.rar\n│ 自定义单选、多选对话框及popwindow窗口实例源码.rar\n│ 自定义彩色Toast.rar\n│\n├─dlan\n│ dlna库源代码包.zip\n│\n├─EditText输入框\n│ 前面部分可以编辑后面部分不可编辑的EditText.zip\n│\n├─Emoji表情\n│ 在项目中使用Emoji表情【源代码】.rar\n│\n├─Fragment\u0026amp;Tab选项卡\n│ Android ViewPager Fragment实现选项卡.rar\n│ ExpandTabView.zip\n│ Fragment实现TabHost效果.rar\n│ Fragment实现tab实例 代码.zip\n│ SYBViewPager(自定义下划线标题的ViewPager).zip\n│ Tab+Viewpage+Fragment实现导航.zip\n│ TabActivityDemo.rar\n│ Tab控件使用的最简纯净Demo.zip\n│ viewpager+Fragment.zip\n│ ViewPager仿微信分页导航，多Activity载入.rar\n│ ViewPager和Tabhost结合，可滑动的tabhost.rar\n│ 仿lol应用的布局 fragment的嵌套.zip\n│ 基于Fragment实现Tab的切换，滑出侧边栏.zip\n│ 封装的一个tabhost框架.zip\n│ 简单实现 一条线 跟随 viewpager 滚动.rar\n│ 页卡滑动， 标题跟着滑动，页卡所在标题始终显示在最显眼位置.rar\n│ 页卡滑动，标题固定位置，以标题颜色与下划线表示当前页卡所在位置.rar\n│ 高仿网易新闻抽屉效果+横向菜单+页面滑动.zip\n│ 高仿蘑菇街 主界面，fragment实现首页tab切换.zip\n│\n├─GIF\n│ android gif模式和图片展现模式 图片展现神器.zip\n│ android 经典帧动画源码.rar\n│ GiF完美运行！！！！.rar\n│ 序列帧动画,开始,结束监听的解决.zip\n│\n├─gridview相关\n│ gridview分页效果.zip\n│ gridview最新版本.rar\n│ GridView添加图片DeleteGridView0.2.rar\n│ Listview,Gridview空数据处理.zip\n│ 单排显示gridview并从解析JSON读取数据加载项目.zip\n│ 横向GridView显示图片（增强版）.rar\n│ 类似表格，可拖动，查询信息，也可添加信息.rar\n│\n├─HOME键\n│ 捕获Home键.rar\n│\n├─IOS风格\n│ 仿IOS的圆角设置界面。直接可用，单选多选等ATable_Demo(iOS风格设置).zip\n│\n├─IPCamera\n│ android播放IPCamera的rtsp连接.rar\n│\n├─JBox2D相关\n│ 基于JBox2D的Android游戏开发全源码.zip\n│\n├─Launcher 桌面\n│ Android Launcher 桌面分页滑动代码.rar\n│ Android Launcher 源码修改可编译.rar\n│ 创建桌面快捷方式源代码.rar\n│ 安卓桌面应用EyeRoom.zip\n│\n├─listview相关\n│ android 仿path 下拉图片放大，放开回弹 ListView.rar\n│ android-swipelistview-支持左右滑动.rar\n│ HorizontalListViewDemo 横向滑动的ListView.zip\n│ HorizontalListView仿微信发起群聊.zip\n│ listview 的各种动画效果.rar\n│ listview 适配器 优化 重用.rar\n│ ListView+CheckBox UI 完美版。实现 全选 、 全不选 、 删除等功能.rar\n│ Listview,Gridview空数据处理.zip\n│ ListView停止滚动开启下载图片.zip\n│ Listview分页加载数据.rar\n│ ListView多级展示，item由对象Leaf提供数据，可设置多个控件.zip\n│ Listview实现三级菜单列表.rar\n│ listview实现图片的异步加载.rar\n│ listview快速滑动，修改默认的滑动条.rar\n│ ListView滚动气泡提示.rar\n│ listview获取网络图片缓存优化.zip\n│ 一个ExpandableListView的例子，实现多级菜单分类展示.rar\n│ 三种ListView下拉刷新的样式.rar\n│ 仿QQ listView的item划动删除+上下拉刷新.rar\n│ 仿QQ消息列表(ListView)滑动删除效果源码.rar\n│ 仿UC删除窗口列表动画.rar\n│ 仿照新浪微博Android客户端个人中心的ScrollView.rar\n│ 分享一个自定义列表.rar\n│ 双列关联listview.rar\n│ 实现列表多选的DEMO.zip\n│ 带有拼音首字母排序的listview.rar\n│ 改编自XListView的更强大的ListView.zip\n│ 显示在一个半圆列表项，一个不错的鱼眼效果.zip\n│ 横向ListView的完整实现(包含基于横向listview做的一个小相册demo).rar\n│ 横竖都能滑动的 listview 嵌套在一起的.zip\n│ 滑动 删除 ListView.zip\n│ 管理图书分类 通过listview来显示有关图书资源信息.zip\n│ 自己做的手风琴效果 没有用折叠list 每个选项中 显示的是不同的list.rar\n│\n├─NFC\n│ MyNFCDemon.rar\n│\n├─OAuth\n│ OAuth认证以及使用网易微博开放平台实现聊天功能.rar\n│ 基于author2.0的新浪微博.rar\n│\n├─OCR图像识别\n│ 图像字符识别（android OCR）.zip\n│ 最全的OCR图像识别技术源码内有说明.zip\n│\n├─P2P\n│ Android-Sip2Peer-1.0 实现p2p.zip\n│\n├─popupwindow\n│ PopupWindow模仿UC底部Menu.rar\n│ 从下方弹出的popupwindow拍照裁剪.rar\n│ 仿微信popupwindow.zip\n│ 博客里各个pop的源码，包括布局文件,popmenu,DefaultPop,和GridPop.rar\n│ 类似google+的侧滑效果以及仿微信的dropdown菜单.rar\n│\n├─SD卡\n│ 判断双SD卡_CheckDoubleSDCard.rar\n│\n├─SQLite\n│ Android 操作数据库实例.zip\n│ AndroidInject增加sqlite3数据库映射注解(ORM).zip\n│ android个人消费记录软件-拖控件作品.zip\n│ Android学习之数据存储.rar\n│ Android轻量级sqlite orm框架.zip\n│ sqlite的一些基本操作，包括数据库创建、数据库版本升级、创建表、数据的增删改查.zip\n│ 一个简单的英汉词典，点击按钮切换汉译英，主要是外部数据库的导入解析！.rar\n│ 带密码登陆的密码保险箱.zip\n│ 超简单的SQLite的使用.rar\n│\n├─SQLSEVER\u0026amp;安卓\n│ android 通过jdts.jar 连接SQLSEVER2008.zip\n│\n├─textView\n│ textView显示图片的例子_TextImage.rar\n│ textView根据长度自动换行.rar\n│\n├─UI布局\n│ Android_系统UI设计规则.docx\n│ android多分辨率适配 ，判断平板还是手机，等比例缩小图片.zip\n│ android模仿易信UI布局效果源码.zip\n│ 仿安卓美团界面.rar\n│ 动态交叉布局demo.zip\n│ 标签式布局吧.zip\n│ 模仿乐动力介绍页面第一屏动画效果.zip\n│ 高仿网易客户端UI（tabhost）.rar\n│\n├─UPnP\n│ UPnP Android代码实现.zip\n│\n├─Widget小组件\n│ android Widget小组件开发.zip\n│ Android小部件AppWidget.rar\n│\n├─wifi蓝牙\n│ android 4.3 版本的蓝牙4.0 扫描、连接等操作。.rar\n│ Android 开启指定名称和密码的 Wifi热点 demo .zip\n│ android,wifi,静态IP,设置.rar\n│ android蓝牙连接打印机.rar\n│ Android通过蓝牙与设备连接，解决数据报文分段（通过时间控制）。动态修改动画.zip\n│ samsung android 蓝牙4.0开发工具包和BLE例子.rar\n│ WIFIHostDemo.zip\n│ wifi信息扫描和rssi值检测.rar\n│ 一个蓝牙4.0BLE安卓开发的小例子,适合新手入门学习.rar\n│ 安卓蓝牙对战demo实例.rar\n│ 很基本的android 通过wifi传输文件的例子，带有基本UI，类似茄子快传的原理.rar\n│ 蓝牙调试助手.zip\n│ 蓝牙项目有注释BluetoothComm.rar\n│\n├─win8风格\n│ win8界面风格扁平化设计点击动画效果.rar\n│\n├─XMPP\n│ 【仿微信即时聊天】xmpp4Android 第一期.rar\n│\n├─下拉上拉刷新\n│ Google官方下拉刷新组件SwipeRefreshLayout(Google最新控件).rar\n│ LearnPullToRefreshControls.zip\n│ listview上拉刷新.zip\n│ listview上拉和下拉刷新项目包.zip\n│ listView下拉刷新上拉刷新带阻尼效果.rar\n│ PullToRefresh下拉刷新详细注释版.rar\n│ SwipeRefreshLayoutSample.zip\n│ ViewPager中嵌套ListView实现了下拉刷新和上拉更多，解决了冲突的问题。.zip\n│ XListview实现上拉刷新下拉加载功能.rar\n│ 下拉刷新2.zip\n│ 仿网易新闻listview加header图片滚动，上拉下拉刷新.zip\n│\n├─串口\u0026amp;Socket通讯USB驱动\u0026amp;jni\n│ andorid串口编程.rar\n│ android 局域网数据传输(基于热点局域网).rar\n│ Android例子源码Socket实现粗略的聊天室功能.rar\n│ Android应用源码安卓与PC的Socket通信项目C#版+Java版.rar\n│ Android应用源码安卓与PC的Socket通信项目java版.rar\n│ Android系统访问串口设备源码.rar\n│ exarusbdriver.rar\n│ 串口开发的demo，里面包含JNI文件.rar\n│ 串口编程资料.rar\n│ 安卓JNIdemo.zip\n│\n├─人脸识别\n│ 人脸检测的API例子.zip\n│\n├─代码安全\n│ Android软件安全与逆向分析PDF+随书源码.rar\n│ java 对apk 文件进行伪加密，然后进行字节码变换的工具，可运行的源代码，其中的apk的目录，需要自己修改成，你的自己的目录。.zip\n│ 这是一个文件文件加密的安卓源代码，此功能在很多场合都有用到，分享给大家.zip\n│\n├─仪表盘效果\n│ android仪表盘.zip\n│ Circle.rar\n│ thermometer_android仪表盘.zip\n│\n├─其他\n│ 100多个Android 实例集合.rar\n│ 9GAG网站客户端.rar\n│ Android 4.4.2 简单的人品测试.zip\n│ Android 北京地铁导航源码.rar\n│ android 豆瓣网客户端.rar\n│ android小插件tab标签大合集.zip\n│ Android经典开发—豆瓣网移动客户端+讲解+源代码.rar\n│ Android重力感应跑步测速应用.zip\n│ BMI健康计算器.rar\n│ google 官方AIPDEMO.rar\n│ NameCardRec.rar\n│ ViewPager+ViewFillper+ViewFlow的使用方法.zip\n│ 人脸识别Camera_face.rar\n│ 仿快按钮 360智键 米键.rar\n│ 健身助手Android应用代码.zip\n│ 北京工商大学上网登陆Android版源码.rar\n│ 后台保持运行，开机后自动启动设定好的APK的DEMO.zip\n│ 基于MQTT的安卓消息推送php服务端源码+安卓端源码.rar\n│ 手机远程监控.rar\n│ 桌面图标，点击进入相应的网站。（仿移动门户10086）.zip\n│ 桌面快捷键消息数目提醒.zip\n│ 植物大战僵尸源码.7z\n│ 植物大战僵尸源码.rar\n│ 网易新闻.zip\n│ 软件管理器.rar\n│\n├─切换动画\n│ Activity切换动画–模糊、水波纹、折叠效果.zip\n│ 各种Activity切换效果.rar\n│\n├─刮刮乐\n│ android刮奖效果.rar\n│ 刮刮乐开奖.rar\n│\n├─动态布局\n│ android动态添加表格行.rar\n│ java代码动态生成控件.zip\n│ 根据内容自动布局.rar\n│\n├─动画效果\n│ activity切换特效.rar\n│ Android Layout UI 首页加载过渡动画，星期变化动画.rar\n│ android 仿真翻页效果.rar\n│ Android 烟花效果源码.zip\n│ android-flip 类似Flipboard翻转动画的实现.zip\n│ Android仿苹果的上下翻页效果.rar\n│ Android使用SurfaceView实现墨迹天气的风车效果.zip\n│ android抽屉效果.rar\n│ animation的结合蝴蝶飞的动画，使用动画里面的几种类型.zip\n│ BackgroundViewPager实现桌面launch移动.zip\n│ ViewFlow,一个滑动效果库.rar\n│ 乐动力的酷黑旋转引导动画.rar\n│ 仿淘宝购买商品，主页后缩.rar\n│ 多个按钮左右相互挤压效果demo.zip\n│ 幸运大转盘源码.rar\n│ 摇色子效果.rar\n│ 水果忍者点击屏幕效果.rar\n│ 翻翻乐–抢答–转盘.rar\n│ 自定义视图实现水波从中心扩散效果.rar\n│ 雪花飘落效果，代码很简单！！！！！.zip\n│ 高仿墨迹天气背景动画效果-云，风，雪等.rar\n│\n├─医疗相关\n│ Android版预约挂号部分版.rar\n│\n├─后台服务\n│ android杀不死服务一种实现，能过保证第三方软件和系统杀不死他，很好用哦.zip\n│\n├─启动退出\u0026amp;网络判断\n│ 3G和wifi的切换监听.zip\n│ Activity启动和退出动画.zip\n│ android 启动页 引导页 到主界面，含有检查应用更新。.rar\n│ android监听网络状态Demo.zip\n│ ViewPager+Fragment侧滑选项卡，浏览器控件，两次退出.rar\n│ 从注册流程 分析如何安全退出多个Activity 多种方式.rar\n│ 判断是否联网.rar\n│ 快捷图标的创建与移除.rar\n│ 网络判断，界面启动.zip\n│ 网络连接状态检测.rar\n│ 返回键退出程序的两种方式.rar\n│ 闪屏加退出提示应用.zip\n│ 隐藏安装包图标使用其他应用启动本应用.rar\n│\n├─图片剪裁\n│ android图片中部裁剪.zip\n│ Android图片的旋转，缩放，剪切，存储.rar\n│\n├─图片加载缓存\n│ afinal框架实现图片的简单异步缓存加载.rar\n│ andengine中直接加载多张小图片合成一张大图片生成动画精灵.rar\n│ Android 图片缓存、加载器.zip\n│ Android-异步图片加载器.zip\n│ Android9妹工具(9Patch).rar\n│ android相册系统(用Matrix实现).zip\n│ android端用于异步加载图片，内存缓存，文件缓存，imageview显示图片时增加淡入淡出动画。.zip\n│ 优化增强的缓存机制(SimpleCache).rar\n│ 加载本地图片，绝对不会出现OOM.rar\n│ 图片加载器.rar\n│ 图片浏览器+缓存+viewpager.rar\n│ 安卓图片旋转放大缩写透明度调整例子.rar\n│ 扫描手机中的图片，仿微信显示本地图片效果.rar\n│ 演化理解 Android 异步加载图片.rar\n│ 自己在用的网络图片加载代码.zip\n│ （Android平台）可以根据手势简单缩放图片.rar\n│\n├─图片圆角\n│ Android创建抗锯齿透明背景圆角图像.zip\n│ ImageView 自定义控件，实现圆角控件图片功能.zip\n│ 圆形，圆角图片，已经封装好的方法，直接调用！.zip\n│ 带自定义编辑功能的圆形头像.rar\n│ 很多项目中用到了用户头像，但是系统的ImageView 是四方形的 ，自己写了个处理的方法， 把bitmap处理成圆角的 。很方便.rar\n│\n├─图片处理\n│ 各种Android模糊毛玻璃效果的源代码.zip\n│\n├─图片多选\n│ 最近在做关于上传多张图片的项目，需要选择多张图片，所以就做了个demo，仅供大家参考.rar\n│ 自定义本地相册的功能，可以多选图片用.rar\n│ 自定义相册支持多选.rar\n│ 选择多张照片上传.rar\n│\n├─图片画廊图库\n│ 360全景查看demo.rar\n│ Android 图片浏览全屏缩放.zip\n│ android 安卓画廊 照片转换器.zip\n│ android_PageFlipper.zip\n│ Android利用Gallery和ImageSwitcher实现在线相册图片预览功能（异步加载图片）.rar\n│ Android实现左右滑动查看图片效果.rar\n│ Android高级图片滚动控件，3D版的图片轮播器Demo.rar\n│ CoversFlow.rar\n│ drawable(图片).zip\n│ Gallery+ImageSwitcher+ViewFlipper实现手机查看壁纸效果.rar\n│ Gallery3D.rar\n│ GalleryDemo.rar\n│ Gallery相册浏览.zip\n│ Grallery3D.zip\n│ MyCoversFlow完整代码（无图片）.zip\n│ MyWorkText.zip\n│ ViewFlowTest 完美实现gallry轮训效果！！！.rar\n│ 安卓3D相册 带有阴影立体浏览.rar\n│ 照片墙（不规则）.zip\n│ 类似于系统图库的Demo.zip\n│ 通过异步加载网络图片并在自定义的gallery中实现轮播图展示.rar\n│\n├─图片轮播\n│ 仿优酷Android客户端图片左右滑动.rar\n│ 分享一个自己做的 Slider 库.zip\n│ 图片左右滑动 点击放大.zip\n│ 图片轮播（Viwepager）+(读取网络图片)+点击图片(WebView）展示.rar\n│ 广告轮播图自动循环滚动和点击事件.rar\n│\n├─图表报表\n│ Android 多种统计图表源码.zip\n│ Android多维报表.zip\n│ 仿随手记的炫酷饼图.rar\n│ 使用ChartEngine实现折现图表格.rar\n│ 安卓画曲线图代码.rar\n│ 折线统计图.rar\n│ 简单用canvas实现一个圆锥漏斗，按照比例分成不同颜色显示。用来做统计。.zip\n│ 自定义View实现折线图.zip\n│ 自定义的柱状图控件，欢迎大家下载学习，我的博客空间是httpblog.csdn.netls1110924viewmode=contents.zip\n│ 自定义表格自动刷新数据.zip\n│ 里面有曲线图 折线图 双曲线图 柱形图 饼图，在achartengine 的基础上 更改了一些颜色 .zip\n│\n├─地图\u0026amp;导航\u0026amp;定位\u0026amp;指南\n│ AMap_Android_API_Demo_V2.0.4(Location_API_V1.0.2).zip\n│ Android 4.0下指南针开发源码,可在Nexus 4上完美运行.zip\n│ Android GPS 开发client端代码分享.zip\n│ Android SDK-高德地图API.pdf\n│ Android 百度地图API-定位周边搜索POI源码.zip\n│ Android 百度地图API源码.zip\n│ Android 百度地图之自定义公交路线源码.rar\n│ android 获取精度纬度.rar\n│ androidGPS及WIFI基站定位坐标源码.rar\n│ android程序的自动更新 和 基于GPS定位的轨迹存储.zip\n│ android获取当前经纬度.rar\n│ BaiduMap_AndroidSDK_v2.1.2_All.zip\n│ BaiduMap_AndroidSDK_v2.1.2_Sample.zip\n│ Baidu定位截图Demo.rar\n│ BMapRoutePlan.rar\n│ Test_Map.zip\n│ 上传百度地图的基本定位操作应用.rar\n│ 两个GPS导航定位源码.rar\n│ 基于百度地图实现的定位功能.rar\n│ 安卓调用百度地图，实现定位和搜索功能.rar\n│ 指南针安卓端源码.rar\n│ 百度地图定位，显示周围的人，类似于E代驾的首页效果.zip\n│ 百度地图点击标注，弹出窗口.rar\n│ 百度地图移动获取位置，自动定位.zip\n│ 百度快速定位locSDK_3.3_Demo.zip\n│ 监控别人的行踪.rar\n│ 调用GoogleMap源码，点击事件在注释里面.rar\n│ 高德地图Marker拖动圆环范围.zip\n│ 高德地图图层效果.zip\n│ 高德地图标注 路线规划.zip\n│\n├─声波通讯\n│ 声波支付例子SinVoice-master.rar\n│ 声波通信改进版.zip\n│\n├─多点触控\u0026amp;手势操作\n│ 一个最最基础的图形程序，圆可以拖动，两点触控是删除圆，3点触控是添加一个圆.rar\n│ 做了四个界面的滑动功能，设置了每个界面的移动动画操作.rar\n│ 在android学习中，动作交互是软件中重要的一部分，其中的Scroller就是提供了拖动效果的类，在网上，比如说一些Launcher实现滑屏都可以通过这个类去实现。这个就是Scroller类学习的后的实践了，效果很棒哦。你可以去博客里面查看如何实现以及效果图。对应的博文地址：httpblog.csdn.netvipzjyno1articledetails24664161.rar\n│ 多点触控控制字体大小,源码中有详细注释，简单Demo.rar\n│ 实现类似地图标签的拖拽缩放.rar\n│ 手势检测.rar\n│ 移动开发触摸控制实现代码.rar\n│ 通过手势实现的缩放处理 .rar\n│ 通过手势对图片进行任意放大绽放旋转.rar\n│\n├─夜间模式\n│ 白天黑夜切换实例.rar\n│\n├─天气日历\u0026amp;时间选择\n│ android-times-square Android日历部件.zip\n│ Android日期时间倒计时（可设置提醒）.zip\n│ Android时间日期滚动控件（附件版）.zip\n│ Android系统日历日程操作.zip\n│ datetimepicker实现挺不错的时间选择器，分为日期选择器和时钟选择器。.zip\n│ 可拖拽View，仿墨迹天气城市管理.rar\n│ 携程、去哪儿日历源码.rar\n│ 支持农历的精美日历项目源码.zip\n│ 日历源码（自带农历 节气 以及 节日）.zip\n│ 最全日历.rar\n│ 模仿Iphone时间滚轮.rar\n│ 活动限时抢购倒计时案例.rar\n│ 简易日历中心.rar\n│ 简洁天气项目源码.zip\n│ 精确计算农历二十四节气.zip\n│\n├─字母排序\n│ Android字母排序 类似通讯录字母检索.rar\n│ 按字母索引滑动.zip\n│ 获取手机联系人并按字母排序，且可根据字母右侧A~Z检索.rar\n│\n├─安装\u0026amp;卸载\n│ Android中禁止某软件的安装.zip\n│ 监听自身应用卸载，并在卸载之后，使用libcurl三方库进行一次三方请求，或者启动网页的实例工程。.rar\n│ 监听自身被卸载.zip\n│\n├─富文本编辑器\n│ Android富文本编辑器源码+服务端.rar\n│\n├─对讲机\u0026amp;录音机\n│ Andorid录音+变声+转mp3.rar\n│ Android电子麦克风.zip\n│ 仿微信录音的功能.zip\n│ 仿微信的录音功能.zip\n│ 使用MedioRecord录音根据声音大小图片显示波动.rar\n│ 对讲机参考资料.rar\n│ 开心网语音发送模块的录音功能.zip\n│ 录音，播放和音频格式转换，（pcm-bin,bin-pcm,pcm-wav）.zip\n│ 按住说话，开始录音，停止录音，显示到列表，点击列表项播放。.rar\n│ 神聊对讲机源码.rar\n│ 简易录音机.rar\n│ 语音压缩，android开发语音功能较多使用的时候，压缩大小50%.rar\n│\n├─导航菜单分类\n│ Android仿大众点评、美团下拉菜单.zip\n│ Android双向滑动菜单带按钮版.zip\n│ Android圆形旋转菜单CircleMenu.rar\n│ Android实现菜单、弹出框、Activity带值例子.rar\n│ android自定义控件-侧滑菜单.zip\n│ ContextMenu 上下文选项菜单，长按后跳出菜单.zip\n│ Fragment例子.rar\n│ NavigationDrawer完整代码.rar\n│ QQ空间底部菜单.rar\n│ SlidingMenu 侧滑菜单 简化版.zip\n│ SlidingMenu实现侧滑栏菜单.rar\n│ SlidingMenu左右宽度可调节菜单.rar\n│ 一个ExpandableListView的例子，实现多级菜单分类展示.rar\n│ 以圆心散开的半圆菜单.zip\n│ 仿 网易新闻客户端 滑动导航.zip\n│ 仿google play侧滑菜单.zip\n│ 仿slidingmune的app左滑菜单效果.rar\n│ 仿照360手机助手，网易新闻客户端 实现 侧滑.zip\n│ 仿米赚带两侧slidingmenu和自动banner的一个应用.rar\n│ 仿美团弹出分类选择框.rar\n│ 关于Frangment 的实现 仿网易.zip\n│ 原来PATH的菜单效果如此简单。布局+TranslateAnimation搞定.zip\n│ 完美！SlidingMenu jar包版demo！不用导包！兼容2.2.zip\n│ 开源侧滑效果实现.rar\n│ 新手侧滑菜单例子.rar\n│ 模仿什么值得买的demo fragment很强大.rar\n│ 水平方向伸缩的path按钮菜单，非弧形.rar\n│ 级联菜单，两级菜单自定义实现提供多种方式PopWindow，Fragment引用..rar\n│ 自动判断位置的弹出菜单.zip\n│ 菜单动画(类似QQ空间)Demo.zip\n│ 菜单类似QQ的设置面板的侧滑菜单布局.zip\n│ 高仿网易新闻抽屉效果+横向菜单+页面滑动.zip\n│\n├─工具\u0026amp;文档\n│ 14天学会安卓开发_(完整版).pdf\n│ 安卓伪加密工具.7z\n│\n├─广告展示\n│ Android高仿广告条用ViewPager实现左右完美无限滑动.zip\n│ ViewPager使用不错的代码.rar\n│ 广告自动滚屏播放应用.zip\n│ 用ViewPager实现手动切换，用Timer + Handler实现自动切换，左右完美无限滑动效果非常平滑.zip\n│\n├─应用信息\n│ 获取手机应用信息.rar\n│\n├─应用更新\n│ android 在线更新示例代码.rar\n│ android程序的自动更新 和 基于GPS定位的轨迹存储.zip\n│ app更新，实现service下载.rar\n│ 【手机安全卫士02】连接服务器获取更新信息.rar\n│\n├─开关效果\n│ 仿ios的SwitchButton 非图片实现.zip\n│\n├─开发框架\n│ AndBase框架.rar\n│ Android 极速开发框架 dhroid.zip\n│ AndroidAppCodeFramework-master.zip\n│ TreeCore Android应用框架.rar\n│\n├─引导页面\n│ Activity进场 切换动画 （仿QQ）.zip\n│ android启动及欢迎界面.rar\n│ Android应用源码高仿墨迹天气引导界面.rar\n│ [安卓开源]GuideViewDemo(超炫丽用户引导).rar\n│ 仿赶集生活android客户端的介绍动画界面.rar\n│ 在android 软件第一次使用的时候，一般会在当前的界面上做一个灰色的蒙版，上面有显示的一些提醒性质的教学文字或者图案。我想的是当前界面上蒙上一个 Fragment 把提示信息也放在Fragment上。博客地址httpblog.csdn.netu012565107articledetails24727251.zip\n│ 完美！ 闪屏+引导页 功能全面！源码详细注释！.rar\n│ 引导界面viewPager.zip\n│ 引导界面仿人人网.zip\n│ 引导界面仿微信.zip\n│ 欢迎引导页面.zip\n│ 超炫丽viewpager用户引导.zip\n│ 闪屏及第一次进入的介绍界面.rar\n│ 项目启动的时候，弹出的悬浮带有关闭按钮的dialog.rar\n│\n├─悬浮窗\n│ Android 天天动听悬浮歌词源码.zip\n│ android 悬浮窗.rar\n│ android桌面悬浮窗效果进阶 仿360手机卫士、淘宝手机助手.rar\n│ 仿360桌面悬浮窗效果，支持拖到指定位置删除.zip\n│ 实现桌面悬浮窗，并可随手指移动,代码只实现一个button，可自行修改悬浮窗样式.rar\n│ 悬浮窗 仿qq小火箭的实现源码，可运行，可作为桌面动态图的例子.rar\n│ 悬浮窗口和半透明实现效果.rar\n│ 浮动窗口播放器.rar\n│\n├─截屏\n│ 简单的截屏应用.rar\n│\n├─抽屉效果\n│ 简单可以滑动的抽屉效果.zip\n│\n├─拍照\u0026amp;录像\n│ android 使用javacv进行录像[模仿vine].zip\n│ Android-拍照、打开本地相册.zip\n│ camera应用，修改过可以在4.0系统上运行。.zip\n│ 基于Android2.2照相机Demo,可以直接放到项目里使用.rar\n│ 手机拍照.rar\n│\n├─拍照\u0026amp;文件上传\u0026amp;录像\u0026amp;监控\n│ android 调用系统相机图库裁剪-图片上传-客服端(测试可用).rar\n│ android录音上传到服务器，上传使用AsyncTask异步任务.rar\n│ android拍摄视频并上传到PHP服务器.zip\n│ 图片拍照上传.rar\n│ 基于android手机的远程视频监控系统.rar\n│ 安卓图片上传和文件上传带jsp服务端源码.rar\n│ 实现录音的AAC格式，并上传到服务器，然后下载播放.rar\n│ 实现网络摄像头功能.zip\n│ 拍照上传源码.zip\n│ 拍照，完美尺寸保存SD卡.zip\n│ 自定义相机（选择曝光度）源码.rar\n│\n├─换肤\n│ “摇一摇”动态更换皮肤完美实现！.zip\n│ 更换软件主题（apk方式）.rar\n│ 更换软件主题（zip方式）.rar\n│\n├─搜索相关\n│ Android关键字飞入飞出的动画，类似应用宝那样的搜索关键字的动画.zip\n│ 快速选择条件进行结果检索的实现.rar\n│\n├─摇一摇\u0026amp;重力传感器\n│ Android加速度传感器源代码.zip\n│ android姿态传感器源代码.zip\n│ Android摇一摇功能示例源码.zip\n│ android摇一摇监听，伴随震动，注释很强，代码清晰，绝对可以运行。.rar\n│ Vibrator手机震动服务 – 小小程序员 – 博客频道 – CSDN.pdf\n│ “摇一摇”动态更换皮肤完美实现！.zip\n│ 加速度传感器.rar\n│ 对三个方向的加速度进行测量并实时绘制图像.rar\n│ 手机摇一摇DEMO代码，实现摇一摇执行特定程序.zip\n│\n├─支付例子\n│ 2.0新版技术开发包.zip\n│ android应用内购买 google app veding billing.rar\n│ BlogForZFB.zip\n│ NetPayClient用户手册.doc\n│ NetPayClinet2.5 for java.rar\n│ WS_SECURE_PAY.zip\n│ 客户端文档及demo_Android(20130328).zip\n│ 手机类似拉卡拉音频刷卡器分析.pdf\n│ 手机银行支付规范.rar\n│ 支付SDK.zip\n│ 支付宝_安卓苹果_快捷支付_文档_代码例子.rar\n│ 支付宝无线支付官方的例子和资料.zip\n│ 银联支付Demo.zip\n│\n├─文件下载上传\n│ Android 在线下载压缩包并解压到指定目录.rar\n│ Android快速框架+多线程下载框架的技术(Android + Afinal+gson).zip\n│ Android断点下载.rar\n│ 一个支持暂停下载断点续传的源码 .rar\n│ 下载网络图片 (整合多线程、内存缓存、本地文件缓存~） .zip\n│ 从网络上获取图片.rar\n│ 仿360MyDownload.zip\n│ 图片下载以及内存处理防OOM.rar\n│ 在Listview显示多任务下载效果。可以中途停止类似360手机助手.rar\n│ 多线程网络下载.rar\n│ 自己写的应用下载自动安装demo.zip\n│\n├─文件管理\n│ Android 文件操作 列表显示 进入 退出 删除 复制 粘贴 新建文件等等.rar\n│ 很实用的源码，包含文件管理器的基本实现思路和原理，及其方式一、首先得到手机SDCard跟目录及所有文件对象二、将这些文件目录信息包装进Adapter三、将Adapter数据设置给ListView控件显示.zip\n│ 文件夹的创建将raw中文件放到SD卡中将assets中文件保存到SD卡中压缩包的解压文件的删除功能.rar\n│ 文件浏览返回路径.zip\n│ 文件选择器.zip\n│ 自己做的一个android数据库复制到sdcard和一个简单的角标使用，demo很简陋.zip\n│\n├─文档操作\n│ android 读取展示office2007.rar\n│ 安卓读取Excel文件获取表格数据.zip\n│ 解析word文档，过程详细，易懂，代码可直接复用.zip\n│\n├─日志分析\n│ android java 通用代码，关于用properties存储打印的Log.zip\n│ Android开发的日记打印工具类Log4jForAndroid和LogUtil.rar\n│ 日志记录，开源项目使用方法见说明.zip\n│\n├─时间轴\n│ Android 时间轴样式.zip\n│ ListView\u0026amp;时间轴.zip\n│ 时间轴 TimeLine.rar\n│\n├─机顶盒\n│ 基于安卓机顶盒上的launcher开发，这是所有应用的一部分，里面有卸载等等其他功能。.rar\n│ 应用在机顶盒上的我的应用，类似于市场上流行的飞看盒子，小米盒子的我的应用的代码实现.rar\n│ 机顶盒应用的demo.rar\n│\n├─条码扫描\u0026amp;二维码\n│ android 二维码 识别基本代码.zip\n│ android 实现竖屏二维码扫描.zip\n│ android二维码扫描，很好用的资源.rar\n│ android二维码的生成和解析.rar\n│ zxing 生成二维码名片.zip\n│ 二维码 水印相机.zip\n│ 二维码.rar\n│ 二维码扫描和生成亲测可用版BarCodeDemo.rar\n│ 二维码扫描案例.rar\n│ 二维码扫描的实现.rar\n│ 二维码扫描的源代码Demo.rar\n│ 仿360扫描模块.rar\n│ 在网上找的例子,但没有做二维码中添加图片和保存的,自己改了改,发给大家共享一下,直接可以用到项目中.zip\n│ 支持竖屏、平板和只有前置摄像头的android二维码扫描demo（修复后）.zip\n│ 详细注释！二维码条码扫描源码，使用Zxing core2.3.rar\n│ 项目中应用到的条码识别代码.rar\n│ 高仿支付宝扫描.zip\n│\n├─标签云\n│ 标签云（词云）.zip\n│\n├─浏览器\u0026amp;WebView\u0026amp;JS\u0026amp;HTML5\n│ Android webView和js交互的Demo.zip\n│ Android下读取网页，显示进度条.rar\n│ Android调用JavaScript.rar\n│ android通过js调用安卓系统功能.rar\n│ ViewPager+Fragment侧滑选项卡，浏览器控件，两次退出.rar\n│ WebViewDemo.rar\n│ webview支持html5视频播放实例.rar\n│ webview重载使用.rar\n│ 一个简单基于Android平台的网页浏览器，实现了网页浏览的基本功能.rar\n│ 使用html5得到手机设备信息的.zip\n│ 浏览器的源码 .rar\n│ 自定义WebView，自带加载动画.zip\n│\n├─涂鸦绘图\u0026amp;图片处理\u0026amp;手写\n│ android 吸管取色功能.zip\n│ Android截图,圆形,Canvas.rar\n│ android手绘操作demo和经典绘图源码Pretty-Painter-master.zip\n│ android的手写功能.zip\n│ DrawPanel双缓冲实现画板.rar\n│ 一个涂鸦还有画矩形 圆形的小Demo.zip\n│ 仿qq实现图文混排以及涂鸦等功能.rar\n│ 仿美图秀秀拼图功能使用代码的时候，请修改2014-03big文件放到mntsdcardclothe目录下。.zip\n│ 可以任意对本地图片进行添加画笔标示，有保存，删除，调整画笔粗细等功能.zip\n│ 橡皮擦与画笔的demo.rar\n│ 相册选择、拍照、缩放、裁减》–源码.rar\n│\n├─消息推送通知栏\n│ NotificationTest 消息推送的简单demo.rar\n│ 实现Notification的通知栏常驻.zip\n│ 消息推送完美demo.rar\n│ 消息推送最新demo +服务器.rar\n│ 激光推送客户端demo.zip\n│ 状态栏通知小图标，notification通知.rar\n│ 通知栏框架（Notificaiton）的全面学习.rar\n│\n├─游戏源码\n│ Android 游戏开发入门随书光盘的代码.rar\n│ android蓝牙tank大战（有错误）.zip\n│ 中国象棋（有错误）.rar\n│ 安卓冒险游戏源码可直接运行类似于精灵快跑这种可做毕业设计.rar\n│ 安卓游戏2048源代码.zip\n│ 安卓飞机游戏.rar\n│ 完美版的Android 拼图游戏APK和工程源码.rar\n│ 微信打灰机源码.rar\n│ 捕鱼达人源代码.rar\n│ 最强手指 (Typing It).zip\n│ 猜拳游戏.rar\n│ 用的libgdx引擎写的ACE 弹幕射击游戏设计与开发.rar\n│ 类似冰雪奇缘一类的三消游戏，用quick-x实现的，简单的demo.rar\n│ 连连看.rar\n│\n├─瀑布流\n│ android平台仿pinterest瀑布流展现方式实现.zip\n│ Android瀑布流加载图片效果Demo.rar\n│ Android瀑布流照片墙实现，体验不规则排列的美感.rar\n│ waterfall瀑布流.zip\n│ 瀑布流PhotoWallFallsDemo.rar\n│\n├─电量管理\n│ 手机电量测试.zip\n│\n├─登录注册\n│ Android 仿 窗帘效果 和 登录界面拖动效果 （Scroller类的应用）.rar\n│ android记住密码自动登录.zip\n│ tablelogin（登陆界面）.rar\n│ 一个登陆和注册界面.rar\n│ 一个简单注册界面.rar\n│ 一个简单登录的DEMO.rar\n│ 仿QQ代码，实现了登入注册的聊天功能.zip\n│ 仿QQ微信登录页面.rar\n│ 实现登陆注册的Login.rar\n│ 用户注册，登录的简单实现.zip\n│ 登录界面设计.zip\n│ 自动清空edittext.rar\n│ 通过Android客户端访问web服务器，实现一个登录功能,服务端+数据库+安卓端.rar\n│\n├─省市联动\u0026amp;多级联动\n│ android(三级联动)全国省市县下拉地址选择源码.zip\n│ Spinner多级联动.zip\n│ 中国地区选择.zip\n│ 仿苹果的滚轮-城市选择.rar\n│ 全国省市县下拉地址选择源码.zip\n│ 安卓省市联动.rar\n│ 省市区城市选择.zip\n│ 自己做的安卓开发关于两个spinner联动的实例.rar\n│ 选择城市列表，配本地数据库，可以直接应用到项目.zip\n│\n├─短信彩信相关\n│ android模拟短信插入和接收.rar\n│ 一个短信应用源码.rar\n│ 后台转发短信到指定邮件箱，有一个测试界面，是别人的程序我组合一起，部分原创.rar\n│ 安卓手机定时发送短信 ，多条短信同时发布.zip\n│ 广播监听短信并获取短信内容.rar\n│ 点对点发送彩信源码.rar\n│\n├─短信验证\n│ android仿淘宝，自动获取短信验证码 demo.zip\n│\n├─社会化分享第三方登录\n│ SharedSDK实现一键分享.rar\n│ 使用ShareSDK完成一键分享.rar\n│ 微信分享Demo.zip\n│ 新浪微博+九宫格快捷分享.rar\n│ 第三方登录(QQ空间+新浪微博).rar\n│ 第三方登录（新浪，腾讯。人人网）.zip\n│\n├─窗口抖动\n│ 实现抖动窗口.rar\n│ 窗口抖动（源码）.rar\n│\n├─编程知识\n│ 模拟Activity进出栈.zip\n│ 用Roboguice实现依赖注入-.zip\n│\n├─网站交互\u0026amp;JSON\u0026amp;xml\n│ Android 解析json_dome.rar\n│ Android与.net交互（含post提交使用的Soap）.rar\n│ android与asp.net中的一般处理程序ashx进行交互.zip\n│ android使用JSON进行网络数据交换(服务端、客户端)的实现.zip\n│ android机票查询源码webservice实现.rar\n│ Android解析服务端XML.zip\n│ 利用JSON，通过Android客户端访问web服务器，实现一个登录功能.zip\n│ 基于ssl(安全套接层)的安全传输，信任X。509证书。.zip\n│ 客户端与服务端的json交互的小例子.zip\n│ 比较通用的xml解析方法.rar\n│ 网上选课管理系统（手机端）.zip\n│ 获取每周电影票房列表.rar\n│ 通过httpclient获取到JSON数据，展示到ListView.zip\n│\n├─聊天通讯\n│ 仿QQ聊天界面，可发png，gif，图文混排.rar\n│ 仿微信聊天软件，Socket实现.zip\n│ 安卓局域网视频聊天.zip\n│ 百度推聊应用.zip\n│ 简易微信客户端和服务器源码.rar\n│\n├─自定义控件\n│ androd自定义有进度的圆形进度条.zip\n│ Android 4.0风格中文滚动输入.zip\n│ Android Form EditText 验证输入合法性的编辑框.zip\n│ Android 自定义头部控件,简单易用.rar\n│ android-gif-drawable 支持fig显示的view.zip\n│ AndroidWheel Android Wheel支持城市、多种日期时间、密码、图片.zip\n│ Android滑动选择控件WheelView，双级联动，有图有真相.rar\n│ Android自定义控件知识 – 博客园.pdf\n│ Crouton 丰富样式的Toast.zip\n│ ImageViewEx 支持Gif显示的ImageView.zip\n│ ProgressWheel 支持进度显示的圆形ProgressBar.zip\n│ UITableView ios风格控件.zip\n│ ViewFlipper水平滑动.rar\n│ 一个Demo搞定30个控件.rar\n│ 不规则点击区域 三角形点击区域.zip\n│ 五种不同的Toast效果.rar\n│ 五种效果的Toast.rar\n│ 自动换行并且对换行后的子控件间隙进行平均分配.rar\n│ 自定义控件入门级demo.zip\n│ 高仿iOS ActionSheet控件.rar\n│\n├─自适应\n│ 计算自己手机的屏幕宽高，density值，px 宽高，dp 的宽高，及px 和dp互转的科普.rar\n│\n├─视图效果\n│ Activity实现透明的最简洁Demo.zip\n│ BadgeView实现在控件上显示小标签.rar\n│ MetroUI.rar\n│ 仿 [Tidy相册] 背景模糊效果.zip\n│ 仿微信标题栏右上角PopupWindow.rar\n│ 使用代码绘制一个电池 (非图片).rar\n│ 各种侧滑界面的实现(圆点指示_标签指示).rar\n│ 带暂停功能倒计时TimeCountDown盒子适用.rar\n│ 来电弹屏实例代码，带关闭按钮.rar\n│ 树形主键.rar\n│ 漂亮的自定义圆形进度条.zip\n│ 简单实用的抽屉效果.zip\n│ 高仿乐动力体重设置.zip\n│\n├─视图注入库\n│ 模仿butter knife，实现 两个基本的功能.zip\n│\n├─视频播放\u0026amp;流媒体\n│ android上实现mp4文件的高效率切割。.rar\n│ Red5+Android 直播系统的架构服务端的直播流工程.zip\n│ SeeJoPlayer（视频播放器）.rar\n│ 使用Vitamio打造自己的Android万能播放器.pdf\n│ 安卓视音频播放测试工程.zip\n│ 完整版android视频播放器.zip\n│ 手势实现播放器的进度和音量调节.zip\n│ 调用系统默认播放器，RTSP流媒体。.rar\n│\n├─计算器\n│ 计算器的源码.zip\n│\n├─记事本备忘录\n│ 初初级记事本程序，直接写文件.zip\n│\n├─语音识别\u0026amp;文本朗读\n│ Android平台使用PocketSphinx做离线语音识别，小范围语音99%识别率.zip\n│ data.zip\n│ PocketSphinxAndroidDemo.zip\n│ 三个android语音识别例程mystt.rar\n│ 语音合成和语音听写，科大讯飞，代码有详细注释.rar\n│ 语音识别，根据语音，执行对应操作.rar\n│ 调用安卓自带文本朗读.rar\n│\n├─课程表\n│ Android课表视图.zip\n│\n├─跑马灯\n│ 跑马灯效果.rar\n│ 跑马灯效果MarqueTextView textview 循环 跑马灯效果.rar\n│\n├─运营商\n│ 获取手机号码\u0026amp;\u0026amp;获取手机运营商.zip\n│\n├─进度条\n│ Android seekbar滑动按钮源码.rar\n│ 仿知乎的横线直线progressbar.rar\n│ 垂直SeekBar（拖动条）.zip\n│ 环形的调节条，用于工程中特殊的调值控件，拟物控件的制作.rar\n│ 自定义进度条效果.rar\n│\n├─通讯录\u0026amp;联系人\u0026amp;打电话\u0026amp;归属地\n│ Android导入导出txt通讯录工具.rar\n│ android手机号码归属地查询源码内附SQlite数据库，并且有查询示例。.zip\n│ Android手机的通讯录联系人信息.zip\n│ android手机通讯录.rar\n│ android打电话源码.rar\n│ Android简易通讯录程序.rar\n│ 一个漂亮的T9拨号面板.zip\n│ 仿qq通讯录联系人.rar\n│ 名片夹_搜索排序.rar\n│ 根据手机号查询通话记录和短信记录.rar\n│ 通讯录+备份还原.rar\n│\n├─邮件相关\n│ Android调用谷歌STMP发送邮件 MailDemo.zip\n│\n├─锁屏\n│ Android4.2原生锁屏GlowPadView.zip\n│ Android滑动解锁.zip\n│ 安卓锁屏和恢复出厂设置功能.rar\n│ 按下电源键，再次按下时，弹出自定义界面。Activity+service+receiver.zip\n│\n├─锁屏\u0026amp;九宫格锁屏\u0026amp;解锁\n│ android 滑动解锁实现源代码.zip\n│ android一键锁屏源代码，android4.2工作正常.zip\n│ 一键锁屏功能源码.zip\n│ 九宫格滑动解锁例子.rar\n│ 智能UI锁屏.zip\n│\n├─键盘输入\n│ android全屏模式下计算键盘的大小.rar\n│ 仿淘宝自定义键盘.rar\n│ 最简单的输入法.rar\n│ 注释过的谷歌输入法PinyinIME源码.rar\n│ 自定义键盘.zip\n│\n├─闪光灯\n│ 闪光灯的简单控制.rar\n│\n├─闹钟\n│ Android一个小闹钟例子.zip\n│ 倒计时闹钟，用timetasker每秒执行一次并且按照时间显示常规减去分或秒.rar\n│ 安卓调用系统闹钟及获取所有软件信息.zip\n│\n├─音乐播放器\n│ Android多线程断点续传下载+在线播放音乐.zip\n│ GL音乐播放器.rar\n│ 利用contentprovider扫描内存卡上所有的音频文件，扫描速度一般是300首歌需要50毫秒以内.rar\n│ 基于SDL、FFmpeg的android播放器源码.zip\n│ 简单实用的音乐播放器.rar\n│ 简单音乐播放器，实现了播放器基本功能，使用service后台播放音乐，并使用异步线程加载音乐图片.rar\n│ 边下载边播music.rar\n│ 音乐播放器 (2).zip\n│ 音乐播放器.zip\n│ 音乐播放器消息通知栏切歌栏效果（Notification+BroadcastReceiver）.zip\n│ 音乐播放器源码.rar\n│\n├─音乐相关\n│ Android 音乐频谱分析，把时域上连续的信号(波形)强度转换成离散的频域信号(频谱)。.rar\n│\n├─飞行模式\n│ Android定时进入飞行模式.zip\n│\n└─验证码\nAndroid随机验证码.rar\n查看本栏目更多精彩内容：http://www.bianceng.cn/OS/extra/\nandroid验证码的整个实现过程和所有的代码，功能比较的简单，大家可以好好参考学习一下.rar\n360网盘下载地址：http://yunpan.cn/QTptFRNMIJpeQ 访问密码 3814\n百度网盘链接: http://pan.baidu.com/s/1qWjW8Q4 密码: up35\n转自：http://m.bianceng.cn/OS/extra/201409/45127.htm\n","permalink":"https://blog.zdltech.com/posts/android%E6%BA%90%E7%A0%81%E5%A4%A7%E6%94%BE%E9%80%81%E5%AE%9E%E6%88%98%E5%BC%80%E5%8F%91%E5%BF%85%E5%A4%87/","summary":"\u003cp\u003e文件夹 PATH 列表\u003c/p\u003e\n\u003cp\u003e卷序列号为 000A-8F50\u003c/p\u003e\n\u003cp\u003eE:.\u003c/p\u003e\n\u003cp\u003e│  javaapk.com文件列表生成工具.bat\u003c/p\u003e\n\u003cp\u003e│  使用说明.txt\u003c/p\u003e\n\u003cp\u003e│  免费下载更多源码.url\u003c/p\u003e\n\u003cp\u003e│  目录列表.txt\u003c/p\u003e\n\u003cp\u003e│\u003c/p\u003e\n\u003cp\u003e├─android web应用\u003c/p\u003e\n\u003cp\u003e│      jqmDemo_static.zip\u003c/p\u003e\n\u003cp\u003e│      jqmMobileDemo-master.zip\u003c/p\u003e\n\u003cp\u003e│      jqmMobileDemo1_1-master.zip\u003c/p\u003e\n\u003cp\u003e│      Location1014.rar\u003c/p\u003e\n\u003cp\u003e│\u003c/p\u003e\n\u003cp\u003e├─anko\u003c/p\u003e\n\u003cp\u003e│      anko服务端和客户端源码.rar\u003c/p\u003e\n\u003cp\u003e│\u003c/p\u003e\n\u003cp\u003e├─Bmob\u003c/p\u003e\n\u003cp\u003e│      Bmob云后端数据库开发个失物招领的简单案例.zip\u003c/p\u003e\n\u003cp\u003e│      结合IM_SDK项目源码.zip\u003c/p\u003e\n\u003cp\u003e│\u003c/p\u003e\n\u003cp\u003e├─Button按钮\u003c/p\u003e\n\u003cp\u003e│      动态添加RadioGroup的RadioButton.zip\u003c/p\u003e\n\u003cp\u003e│      带有进度条的button.rar\u003c/p\u003e\n\u003cp\u003e│      自定义组件实现可滑动的ToggleButton的功能..rar\u003c/p\u003e\n\u003cp\u003e│\u003c/p\u003e\n\u003cp\u003e├─Dialog对话框\u003c/p\u003e\n\u003cp\u003e│      android 自定义对话框.rar\u003c/p\u003e\n\u003cp\u003e│      android-styled-dialogs 可自定义样式的dialog.zip\u003c/p\u003e\n\u003cp\u003e│      Android中实现Iphone样式的AlertDialog.zip\u003c/p\u003e\n\u003cp\u003e│      Android实现Windows风格的Dialog.zip\u003c/p\u003e\n\u003cp\u003e│      HerilyAlertDialog完全自定义的Dialog.zip\u003c/p\u003e\n\u003cp\u003e│      仿QQ的头像选择弹出的对话框，酷似！.zip\u003c/p\u003e\n\u003cp\u003e│      基本的对话框.rar\u003c/p\u003e\n\u003cp\u003e│      自定义列表选择Dialog，适用网络请求数据.rar\u003c/p\u003e\n\u003cp\u003e│      自定义单选、多选对话框及popwindow窗口实例源码.rar\u003c/p\u003e\n\u003cp\u003e│      自定义彩色Toast.rar\u003c/p\u003e\n\u003cp\u003e│\u003c/p\u003e\n\u003cp\u003e├─dlan\u003c/p\u003e\n\u003cp\u003e│      dlna库源代码包.zip\u003c/p\u003e\n\u003cp\u003e│\u003c/p\u003e\n\u003cp\u003e├─EditText输入框\u003c/p\u003e\n\u003cp\u003e│      前面部分可以编辑后面部分不可编辑的EditText.zip\u003c/p\u003e\n\u003cp\u003e│\u003c/p\u003e\n\u003cp\u003e├─Emoji表情\u003c/p\u003e\n\u003cp\u003e│      在项目中使用Emoji表情【源代码】.rar\u003c/p\u003e","title":"android源码大放送（实战开发必备）"},{"content":"在很多应用中，看到这样的listview：listview滑动过程中分组标题固定在上方，当第二个组滑上来时，第一个组才跟着上滑，下一个组固定，直到该组也滑出上边缘。世上无难事只怕有心人，在github上就有人做出来了，而且效果很好（后来发现安卓自带应用中联系人应用就是这样的，估计github的作者也是仿照着联系人做出来的吧）。\n先看截图：\nPinnedSectionListView继承自listview，众所周知listview的每个子view都是按顺序跟着滚动的，要实现联系人listview的效果还真的找不到思路。看了PinnedSectionListView之后，感觉要改造一个现有的控件，一般都是通过重绘子view来实现的。ViewGroup（ListView继承自它）重绘子view的方法是dispatchDraw。\n看看PinnedSectionListView在dispatchDraw中有那些特别的处理：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `protected void dispatchDraw(Canvas canvas) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``super``.dispatchDraw(canvas);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``if` `(mPinnedSection != ``null``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``// prepare variables` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``int pLeft = getListPaddingLeft();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``int pTop = getListPaddingTop();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``View view = mPinnedSection.view;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``// draw child` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``canvas.save();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``int clipHeight = view.getHeight() +` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``(mShadowDrawable == ``null` `? 0 : Math.min(mShadowHeight, mSectionsDistanceY));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``canvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``canvas.translate(pLeft, pTop + mTranslateY);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``drawChild(canvas, mPinnedSection.view, getDrawingTime());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``if` `(mShadowDrawable != ``null` `\u0026amp;\u0026amp; mSectionsDistanceY \u0026amp;gt; 0) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``mShadowDrawable.setBounds(mPinnedSection.view.getLeft(),` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``mPinnedSection.view.getBottom(),` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``mPinnedSection.view.getRight(),` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``mPinnedSection.view.getBottom() + mShadowHeight);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``mShadowDrawable.draw(canvas);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``canvas.restore();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 关键在于```canvas.translate(pLeft, pTop + mTranslateY);意思是在绘制mPinnedSection的时候，listview滑动了多长的距离，就将canvas移动多少的距离，使mPinnedSection`始终在可见的范围内固定不变。\n使用方法：\n1.在xml布局文件中将ListView替换成PinnedSectionListView\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;com.hb.views.PinnedSectionListView` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:id=``\u0026quot;@android:id/list\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 2.让你的ListAdapter继承PinnedSectionListAdapter接口，最简单的做法是只增加isItemViewTypePinned方法，该方法必须在item为pinned的情况下返回true。\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `// Our adapter class implements 'PinnedSectionListAdapter' interface` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `class MyPinnedSectionListAdapter extends BaseAdapter implements PinnedSectionListAdapter {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``...` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``// We implement this method to return 'true' for all view types we want to pin` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``public boolean isItemViewTypePinned(int viewType) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``return` `viewType == \u0026amp;lt;type to be pinned\u0026amp;gt;;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 项目地址：https://github.com/beworker/pinned-section-listview\n","permalink":"https://blog.zdltech.com/posts/github%E6%BA%90%E7%A0%81%E5%88%86%E4%BA%ABpinnedsectionlistview%E5%88%86%E7%BB%84%E7%9A%84listview%E6%BB%91%E5%8A%A8%E4%B8%AD%E5%9B%BA%E5%AE%9A%E7%BB%84%E6%A0%87%E9%A2%98%E7%9A%84%E5%AE%9E/","summary":"\u003cp\u003e在很多应用中，看到这样的listview：listview滑动过程中分组标题固定在上方，当第二个组滑上来时，第一个组才跟着上滑，下一个组固定，直到该组也滑出上边缘。世上无难事只怕有心人，在github上就有人做出来了，而且效果很好（后来发现安卓自带应用中联系人应用就是这样的，估计github的作者也是仿照着联系人做出来的吧）。\u003c/p\u003e\n\u003cp\u003e先看截图：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://www.jcodecraeer.com/uploads/20140307/13941224949560.png\"\u003e  \u003cimg loading=\"lazy\" src=\"http://www.jcodecraeer.com/uploads/20140307/13941224944294.png\"\u003e  \u003cimg loading=\"lazy\" src=\"http://www.jcodecraeer.com/uploads/20140307/13941224952328.png\"\u003e\u003c/p\u003e\n\u003cp\u003ePinnedSectionListView继承自listview，众所周知listview的每个子view都是按顺序跟着滚动的，要实现联系人listview的效果还真的找不到思路。看了PinnedSectionListView之后，感觉要改造一个现有的控件，一般都是通过重绘子view来实现的。ViewGroup（ListView继承自它）重绘子view的方法是dispatchDraw。\u003c/p\u003e\n\u003cp\u003e看看PinnedSectionListView在dispatchDraw中有那些特别的处理：\u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_148167\" class=\"syntaxhighlighter  js\"\u003e\n    \u003ctable border=\"0\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n      \u003ctr\u003e\n        \u003ctd class=\"gutter\"\u003e\n          \u003cdiv class=\"line number1 index0 alt2\"\u003e\n            1\n          \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        2\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n        3\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n        4\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n        5\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n        6\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n        7\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n        8\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n        9\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n        10\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n        11\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n        12\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n        13\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n        14\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n        15\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n        16\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n        17\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n        18\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n        19\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n        20\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n        21\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n        22\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n        23\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n        24\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n        25\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          `protected void dispatchDraw(Canvas canvas) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `    ``super``.dispatchDraw(canvas);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          `    ``if` `(mPinnedSection != ``null``) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          `        ``// prepare variables`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n          `        ``int pLeft = getListPaddingLeft();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n          `        ``int pTop = getListPaddingTop();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n          `        ``View view = mPinnedSection.view;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n          `        ``// draw child`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n          `        ``canvas.save();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n          `        ``int clipHeight = view.getHeight() +`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n          `                ``(mShadowDrawable == ``null` `? 0 : Math.min(mShadowHeight, mSectionsDistanceY));`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n          `        ``canvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n          `        ``canvas.translate(pLeft, pTop + mTranslateY);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n          `        ``drawChild(canvas, mPinnedSection.view, getDrawingTime());`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n          `        ``if` `(mShadowDrawable != ``null` `\u0026amp;\u0026amp; mSectionsDistanceY \u0026amp;gt; 0) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n          `            ``mShadowDrawable.setBounds(mPinnedSection.view.getLeft(),`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n          `                    ``mPinnedSection.view.getBottom(),`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n          `                    ``mPinnedSection.view.getRight(),`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n          `                    ``mPinnedSection.view.getBottom() + mShadowHeight);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n          `            ``mShadowDrawable.draw(canvas);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n          `        ``canvas.restore();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e关键在于```canvas.translate(pLeft, pTop + mTranslateY);\u003ccode\u003e意思是在绘制\u003c/code\u003emPinnedSection\u003ccode\u003e的时候，listview滑动了多长的距离，就将canvas移动多少的距离，使\u003c/code\u003emPinnedSection`始终在可见的范围内固定不变。\u003c/p\u003e","title":"github源码分享PinnedSectionListView：分组的listView滑动中固定组标题的实现"},{"content":"转帖请注明本文出自xiaanming的博客（http://blog.csdn.net/xiaanming），请尊重他人的辛勤劳动成果，谢谢！\n随着移动互联网的快速发展，它已经和我们的生活息息相关了，在公交地铁里面都能看到很多人的人低头看着自己的手机屏幕，从此“低头族”一词就产生了，作为一名移动行业的开发人员，我自己也是一名“低头族”，上下班时间在公交地铁上看看新闻来打发下时间，有时候也会看看那些受欢迎的App的一些界面效果，为什么人家的app那么受欢迎？跟用户体验跟UI设计也有直接的关系，最近在美团和大众点评的App看到如下效果，我感觉用户好，很人性化，所以自己也尝试着实现了下，接下来就讲解下实现思路！\n如上图(2)我们看到了，当立即抢购布局向上滑动到导航栏布局的时候，立即抢购布局就贴在导航栏布局下面，下面的其他的布局还是可以滑动，当我们向下滑动的时候，立即抢购的布局又随着往下滑动了，看似有点复杂，但是一说思路可能你就顿时恍然大悟了。\n当我们向上滑动过程中，我们判断立即抢购的布局是否滑到导航栏布局下面，如果立即抢购的上面顶到了导航栏，我们新建一个立即抢购的悬浮框来显示在导航栏下面，这样子就实现了立即抢购贴在导航栏下面的效果啦，而当我们向下滑动的时候，当立即抢购布局的下面刚好到了刚刚新建的立即抢购悬浮框的下面的时候，我们就移除立即抢购悬浮框，可能说的有点拗口，既然知道了思路，接下来我们就来实现效果。\n新建一个Android项目，取名MeiTuanDemo,先看立即抢购（buy_layout.xml）的布局，这里为了方便我直接从美团上面截去了图片\n**[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/17374599#)[copy](http://blog.csdn.net/xiaanming/article/details/17374599#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/120124)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/120124/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;UTF-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/buy_layout\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/buy\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 立即抢购的布局实现了，接下来实现主界面的布局，上面是导航栏布局，为了方便还是直接从美团截取的图片，然后下面的ViewPager布局，立即抢购布局，其他布局 放在ScrollView里面，界面还是很简单的\n**[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/17374599#)[copy](http://blog.csdn.net/xiaanming/article/details/17374599#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/120124)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/120124/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/imageView1\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scaleType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;centerCrop\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;45dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/navigation_bar\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.meituandemo.MyScrollView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/scrollView\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/iamge\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/pic\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scaleType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;centerCrop\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;include\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/buy\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;layout\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@layout/buy_layout\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/one\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scaleType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;centerCrop\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/one\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scaleType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;centerCrop\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/one\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scaleType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;centerCrop\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.meituandemo.MyScrollView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 你会发现上面的主界面布局中并不是ScrollView,而是自定义的一个MyScrollView,接下来就看看MyScrollView类中的代码\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17374599#)[copy](http://blog.csdn.net/xiaanming/article/details/17374599#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/120124)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/120124/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.meituandemo; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ScrollView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 博客地址:http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyScrollView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ScrollView { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnScrollListener onScrollListener; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 主要是用在用户手指离开MyScrollView，MyScrollView还在继续滑动，我们用来保存Y的距离，然后做比较\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; lastScrollY; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyScrollView(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyScrollView(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, attrs, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyScrollView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 设置滚动接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param onScrollListener\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnScrollListener(OnScrollListener onScrollListener) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onScrollListener = onScrollListener; - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 用于用户手指离开MyScrollView的时候获取MyScrollView滚动的Y距离，然后回调给onScroll方法中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(android.os.Message msg) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollY = MyScrollView.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getScrollY(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//此时的距离和记录下的距离不相等，在隔5毫秒给handler发送消息\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(lastScrollY != scrollY){ - lastScrollY = scrollY; - handler.sendMessageDelayed(handler.obtainMessage(), \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(onScrollListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - onScrollListener.onScroll(scrollY); - } - - }; - - }; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 重写onTouchEvent， 当用户的手在MyScrollView上面的时候，\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 直接将MyScrollView滑动的Y方向距离回调给onScroll方法中，当用户抬起手的时候，\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * MyScrollView可能还在滑动，所以当用户抬起手我们隔5毫秒给handler发送消息，在handler处理\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * MyScrollView滑动的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent ev) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(onScrollListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - onScrollListener.onScroll(lastScrollY = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getScrollY()); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt;(ev.getAction()){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - handler.sendMessageDelayed(handler.obtainMessage(), \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 滚动的回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnScrollListener{ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 回调方法， 返回MyScrollView滑动的Y方向距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param scrollY\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 、\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onScroll(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollY); - } - - - - } 一看代码你也许明白了，就是对ScrollView的滚动Y值进行监听，我们知道ScrollView并没有实现滚动监听，所以我们必须自行实现对ScrollView的监听，我们很自然的想到在onTouchEvent()方法中实现对滚动Y轴进行监听，可是你会发现，我们在滑动ScrollView的时候，当我们手指离开ScrollView。它可能还会继续滑动一段距离，所以我们选择在用户手指离开的时候每隔5毫秒来判断ScrollView是否停止滑动，并将ScrollView的滚动Y值回调给OnScrollListener接口的onScroll(int scrollY)方法中，我们只需要对ScrollView调用我们只需要对ScrollView调用setOnScrollListener方法就能监听到滚动的Y值。\n实现了对ScrollView滚动的Y值进行监听，接下来就简单了，我们只需要显示立即抢购悬浮框和移除悬浮框了，接下来看看主界面Activity的代码编写\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17374599#)[copy](http://blog.csdn.net/xiaanming/article/details/17374599#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/120124)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/120124/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.meituandemo; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.PixelFormat; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Gravity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.WindowManager; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.WindowManager.LayoutParams; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.meituandemo.MyScrollView.OnScrollListener; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 博客地址:http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnScrollListener{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyScrollView myScrollView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LinearLayout mBuyLayout; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; WindowManager mWindowManager; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 手机屏幕宽度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; screenWidth; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 悬浮框View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; View suspendView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 悬浮框的参数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; WindowManager.LayoutParams suspendLayoutParams; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 购买布局的高度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; buyLayoutHeight; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * myScrollView与其父类布局的顶部距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; myScrollViewTop; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 购买布局与其父类布局的顶部距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; buyLayoutTop; - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - myScrollView = (MyScrollView) findViewById(R.id.scrollView); - mBuyLayout = (LinearLayout) findViewById(R.id.buy); - - myScrollView.setOnScrollListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); - screenWidth = mWindowManager.getDefaultDisplay().getWidth(); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 窗口有焦点的时候，即所有的布局绘制完毕的时候，我们来获取购买布局的高度和myScrollView距离父类布局的顶部位置\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onWindowFocusChanged(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; hasFocus) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onWindowFocusChanged(hasFocus); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(hasFocus){ - buyLayoutHeight = mBuyLayout.getHeight(); - buyLayoutTop = mBuyLayout.getTop(); - - myScrollViewTop = myScrollView.getTop(); - } - } - - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 滚动的回调方法，当滚动的Y距离大于或者等于 购买布局距离父类布局顶部的位置，就显示购买的悬浮框\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 当滚动的Y的距离小于 购买布局距离父类布局顶部的位置加上购买布局的高度就移除购买的悬浮框\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onScroll(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollY) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(scrollY \u0026gt;= buyLayoutTop){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(suspendView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - showSuspend(); - } - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(scrollY \u0026lt;= buyLayoutTop + buyLayoutHeight){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(suspendView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - removeSuspend(); - } - } - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 显示购买的悬浮框\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; showSuspend(){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(suspendView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - suspendView = LayoutInflater.from(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;).inflate(R.layout.buy_layout, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(suspendLayoutParams == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - suspendLayoutParams = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(); - suspendLayoutParams.type = LayoutParams.TYPE_PHONE; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//悬浮窗的类型，一般设为2002，表示在所有应用程序之上，但在状态栏之下 \u0026lt;/span\u0026gt; - suspendLayoutParams.format = PixelFormat.RGBA_8888; - suspendLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL - | LayoutParams.FLAG_NOT_FOCUSABLE; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//悬浮窗的行为，比如说不可聚焦，非模态对话框等等 \u0026lt;/span\u0026gt; - suspendLayoutParams.gravity = Gravity.TOP; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//悬浮窗的对齐方式\u0026lt;/span\u0026gt; - suspendLayoutParams.width = screenWidth; - suspendLayoutParams.height = buyLayoutHeight; - suspendLayoutParams.x = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//悬浮窗X的位置\u0026lt;/span\u0026gt; - suspendLayoutParams.y = myScrollViewTop; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;////悬浮窗Y的位置\u0026lt;/span\u0026gt; - } - } - - mWindowManager.addView(suspendView, suspendLayoutParams); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 移除购买的悬浮框\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; removeSuspend(){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(suspendView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - mWindowManager.removeView(suspendView); - suspendView = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - } - - } 上面的代码比较简单，根据ScrollView滑动的距离来判断显示和移除悬浮框，悬浮框的实现主要是通过WindowManager这个类来实现的，调用这个类的addView方法用于添加一个悬浮框，removeView用于移除悬浮框。\n通过上述代码就实现了美团，大众点评的这种效果，在运行项目之前我们必须在AndroidManifest.xml中加入\n我们运行下项目看下效果吧\n好了，今天的讲解到此结束，有疑问的朋友请在下面留言\n项目源码，点击下载\nPS:大家有兴趣的话可以看看Android 仿美团网,大众点评购买框悬浮效果之修改版\n","permalink":"https://blog.zdltech.com/posts/android-%E5%AF%B9scrollview%E6%BB%9A%E5%8A%A8%E7%9B%91%E5%90%AC%E5%AE%9E%E7%8E%B0%E7%BE%8E%E5%9B%A2%E5%A4%A7%E4%BC%97%E7%82%B9%E8%AF%84%E7%9A%84%E8%B4%AD%E4%B9%B0%E6%82%AC%E6%B5%AE-2/","summary":"\u003cp\u003e转帖请注明本文出自xiaanming的博客（\u003ca href=\"http://blog.csdn.net/xiaanming\"\u003ehttp://blog.csdn.net/xiaanming\u003c/a\u003e），请尊重他人的辛勤劳动成果，谢谢！\u003c/p\u003e\n\u003cp\u003e随着移动互联网的快速发展，它已经和我们的生活息息相关了，在公交地铁里面都能看到很多人的人低头看着自己的手机屏幕，从此“低头族”一词就产生了，作为一名移动行业的开发人员，我自己也是一名“低头族”，上下班时间在公交地铁上看看新闻来打发下时间，有时候也会看看那些受欢迎的App的一些界面效果，为什么人家的app那么受欢迎？跟用户体验跟UI设计也有直接的关系，最近在美团和大众点评的App看到如下效果，我感觉用户好，很人性化，所以自己也尝试着实现了下，接下来就讲解下实现思路！\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20131217133443078\"\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20131217141615875?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhYW5taW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e如上图(2)我们看到了，当立即抢购布局向上滑动到导航栏布局的时候，立即抢购布局就贴在导航栏布局下面，下面的其他的布局还是可以滑动，当我们向下滑动的时候，立即抢购的布局又随着往下滑动了，看似有点复杂，但是一说思路可能你就顿时恍然大悟了。\u003c/p\u003e\n\u003cp\u003e当我们向上滑动过程中，我们判断立即抢购的布局是否滑到导航栏布局下面，如果立即抢购的上面顶到了导航栏，我们新建一个立即抢购的悬浮框来显示在导航栏下面，这样子就实现了立即抢购贴在导航栏下面的效果啦，而当我们向下滑动的时候，当立即抢购布局的下面刚好到了刚刚新建的立即抢购悬浮框的下面的时候，我们就移除立即抢购悬浮框，可能说的有点拗口，既然知道了思路，接下来我们就来实现效果。\u003c/p\u003e\n\u003cp\u003e新建一个Android项目，取名MeiTuanDemo,先看立即抢购（buy_layout.xml）的布局，这里为了方便我直接从美团上面截去了图片\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/17374599#)[copy](http://blog.csdn.net/xiaanming/article/details/17374599#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/120124)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/120124/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;UTF-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/buy_layout\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/buy\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e立即抢购的布局实现了，接下来实现主界面的布局，上面是导航栏布局，为了方便还是直接从美团截取的图片，然后下面的ViewPager布局，立即抢购布局，其他布局 放在ScrollView里面，界面还是很简单的\u003c/p\u003e","title":"Android 对ScrollView滚动监听，实现美团、大众点评的购买悬浮效果"},{"content":"转帖请注明本文出自xiaanming的博客（http://blog.csdn.net/xiaanming/article/details/17483273），请尊重他人的辛勤劳动成果，谢谢！\n今天给大家讲解的是Scroller类的滚动实现原理，可能很多朋友不太了解该类是用来干嘛的，但是研究Launcher的朋友应该对他很熟悉，Scroller类是滚动的一个封装类，可以实现View的平滑滚动效果，什么是实现View的平滑滚动效果呢，举个简单的例子，一个View从在我们指定的时间内从一个位置滚动到另外一个位置，我们利用Scroller类可以实现匀速滚动，可以先加速后减速，可以先减速后加速等等效果，而不是瞬间的移动的效果，所以Scroller可以帮我们实现很多滑动的效果。\n在介绍Scroller类之前，我们先去了解View的scrollBy() 和scrollTo()方法的区别，在区分这两个方法的之前，我们要先理解View 里面的两个成员变量mScrollX， mScrollY，X轴方向的偏移量和Y轴方向的偏移量，这个是一个相对距离，相对的不是屏幕的原点，而是View的左边缘，举个通俗易懂的例子，一列火车从吉安到深圳，途中经过赣州，那么原点就是赣州，偏移量就是 负的吉安到赣州的距离，大家从getScrollX()方法中的注释中就能看出答案来\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17483273#)[copy](http://blog.csdn.net/xiaanming/article/details/17483273#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/129807)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/129807/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Return the scrolled left position of this view. This is the left edge of\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * the displayed part of your view. You do not need to draw any pixels\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * farther left, since those are outside of the frame of your view on\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * screen.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return The left edge of the displayed part of your view, in pixels.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getScrollX() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mScrollX; - } 现在我们知道了向右滑动 mScrollX就为负数，向左滑动mScrollX为正数，接下来我们先来看看 scrollTo()方法的源码\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17483273#)[copy](http://blog.csdn.net/xiaanming/article/details/17483273#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/129807)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/129807/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Set the scrolled position of your view. This will cause a call to\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * {@link #onScrollChanged(int, int, int, int)} and the view will be\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * invalidated.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param x the x position to scroll to\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param y the y position to scroll to\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scrollTo(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mScrollX != x || mScrollY != y) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldX = mScrollX; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldY = mScrollY; - mScrollX = x; - mScrollY = y; - onScrollChanged(mScrollX, mScrollY, oldX, oldY); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!awakenScrollBars()) { - invalidate(); - } - } - } 从该方法中我们可以看出，先判断传进来的(x, y)值是否和View的X, Y偏移量相等，如果不相等，就调用onScrollChanged()方法来通知界面发生改变，然后重绘界面，所以这样子就实现了移动效果啦， 现在我们知道了scrollTo()方法是滚动到(x, y)这个偏移量的点，他是相对于View的开始位置来滚动的。在看看scrollBy()这个方法的代码\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17483273#)[copy](http://blog.csdn.net/xiaanming/article/details/17483273#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/129807)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/129807/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Move the scrolled position of your view. This will cause a call to\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * {@link #onScrollChanged(int, int, int, int)} and the view will be\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * invalidated.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param x the amount of pixels to scroll by horizontally\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param y the amount of pixels to scroll by vertically\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scrollBy(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y) { - scrollTo(mScrollX + x, mScrollY + y); - } 原来他里面调用了scrollTo()方法，那就好办了，他就是相对于View上一个位置根据(x, y)来进行滚动，可能大家脑海中对这两个方法还有点模糊，没关系，还是举个通俗的例子帮大家理解下，假如一个View,调用两次scrollTo(-10, 0)，第一次向右滚动10，第二次就不滚动了，因为mScrollX和x相等了，当我们调用两次scrollBy(-10, 0),第一次向右滚动10，第二次再向右滚动10，他是相对View的上一个位置来滚动的。\n对于scrollTo()和scrollBy()方法还有一点需要注意，这点也很重要，假如你给一个LinearLayout调用scrollTo()方法，并不是LinearLayout滚动，而是LinearLayout里面的内容进行滚动，比如你想对一个按钮进行滚动，直接用Button调用scrollTo()一定达不到你的需求，大家可以试一试，如果真要对某个按钮进行scrollTo()滚动的话，我们可以在Button外面包裹一层Layout，然后对Layout调用scrollTo()方法。\n了解了scrollTo()和scrollBy()方法之后我们就了解下Scroller类了，先看其构造方法\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17483273#)[copy](http://blog.csdn.net/xiaanming/article/details/17483273#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/129807)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/129807/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Create a Scroller with the default duration and interpolator.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Scroller(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Create a Scroller with the specified interpolator. If the interpolator is\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * null, the default (viscous) interpolator will be used.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Scroller(Context context, Interpolator interpolator) { - mFinished = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - mInterpolator = interpolator; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; ppi = context.getResources().getDisplayMetrics().density * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;160\u0026lt;/span\u0026gt;.0f; - mDeceleration = SensorManager.GRAVITY_EARTH \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// g (m/s^2)\u0026lt;/span\u0026gt; - * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;39\u0026lt;/span\u0026gt;.37f \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// inch/meter\u0026lt;/span\u0026gt; - * ppi \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// pixels per inch\u0026lt;/span\u0026gt; - * ViewConfiguration.getScrollFriction(); - } 只有两个构造方法，第一个只有一个Context参数，第二个构造方法中指定了Interpolator，什么Interpolator呢？中文意思插补器，了解Android动画的朋友都应该熟悉\nInterpolator，他指定了动画的变化率，比如说匀速变化，先加速后减速，正弦变化等等，不同的Interpolator可以做出不同的效果出来，第一个使用默认的Interpolator(viscous)\n接下来我们就要在Scroller类里面找滚动的方法，我们从名字上面可以看出startScroll()应该是个滚动的方法，我们来看看其源码吧\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17483273#)[copy](http://blog.csdn.net/xiaanming/article/details/17483273#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/129807)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/129807/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; startScroll(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startX, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startY, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dy, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; duration) { - mMode = SCROLL_MODE; - mFinished = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - mDuration = duration; - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mStartX = startX; - mStartY = startY; - mFinalX = startX + dx; - mFinalY = startY + dy; - mDeltaX = dx; - mDeltaY = dy; - mDurationReciprocal = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f / (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) mDuration; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// This controls the viscous fluid effect (how much of it)\u0026lt;/span\u0026gt; - mViscousFluidScale = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;.0f; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// must be set to 1.0 (used in viscousFluid())\u0026lt;/span\u0026gt; - mViscousFluidNormalize = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f; - mViscousFluidNormalize = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f / viscousFluid(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f); - } 在这个方法中我们只看到了对一些滚动的基本设置动作，比如设置滚动模式，开始时间，持续时间等等，并没有任何对View的滚动操作，也许你正纳闷，不是滚动的方法干嘛还叫做startScroll(),稍安勿躁，既然叫开始滚动，那就是对滚动的滚动之前的基本设置咯。\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17483273#)[copy](http://blog.csdn.net/xiaanming/article/details/17483273#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/129807)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/129807/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Call this when you want to know the new location. If it returns true,\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * the animation is not yet finished. loc will be altered to provide the\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * new location.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; computeScrollOffset() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mFinished) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; timePassed = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)(AnimationUtils.currentAnimationTimeMillis() \u0026amp;#8211; mStartTime); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (timePassed \u0026lt; mDuration) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (mMode) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; SCROLL_MODE: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;)timePassed * mDurationReciprocal; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mInterpolator == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - x = viscousFluid(x); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - x = mInterpolator.getInterpolation(x); - - mCurrX = mStartX + Math.round(x * mDeltaX); - mCurrY = mStartY + Math.round(x * mDeltaY); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; FLING_MODE: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; timePassedSeconds = timePassed / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;.0f; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distance = (mVelocity * timePassedSeconds) - \u0026amp;#8211; (mDeceleration * timePassedSeconds * timePassedSeconds / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;.0f); - - mCurrX = mStartX + Math.round(distance * mCoeffX); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Pin to mMinX \u0026lt;= mCurrX \u0026lt;= mMaxX\u0026lt;/span\u0026gt; - mCurrX = Math.min(mCurrX, mMaxX); - mCurrX = Math.max(mCurrX, mMinX); - - mCurrY = mStartY + Math.round(distance * mCoeffY); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Pin to mMinY \u0026lt;= mCurrY \u0026lt;= mMaxY\u0026lt;/span\u0026gt; - mCurrY = Math.min(mCurrY, mMaxY); - mCurrY = Math.max(mCurrY, mMinY); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - mCurrX = mFinalX; - mCurrY = mFinalY; - mFinished = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } 我们在startScroll()方法的时候获取了当前的动画毫秒赋值给了mStartTime，在computeScrollOffset()中再一次调用AnimationUtils.currentAnimationTimeMillis()来获取动画\n毫秒减去mStartTime就是持续时间了，然后进去if判断，如果动画持续时间小于我们设置的滚动持续时间mDuration，进去switch的SCROLL_MODE，然后根据Interpolator来计算出在该时间段里面移动的距离，赋值给mCurrX， mCurrY， 所以该方法的作用是，计算在0到mDuration时间段内滚动的偏移量，并且判断滚动是否结束，true代表还没结束，false则表示滚动介绍了，Scroller类的其他的方法我就不提了，大都是一些get(), set()方法。\n看了这么多，到底要怎么才能触发滚动，你心里肯定有很多疑惑，在说滚动之前我要先提另外一个方法computeScroll()，该方法是滑动的控制方法，在绘制View时，会在draw()过程调用该方法。我们先看看computeScroll()的源码\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17483273#)[copy](http://blog.csdn.net/xiaanming/article/details/17483273#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/129807)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/129807/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Called by a parent to request that a child update its values for mScrollX\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * and mScrollY if necessary. This will typically be done if the child is\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * animating a scroll using a {@link android.widget.Scroller Scroller}\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * object.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll() { - } 没错，他是一个空的方法，需要子类去重写该方法来实现逻辑，到底该方法在哪里被触发呢。我们继续看看View的绘制方法draw()\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17483273#)[copy](http://blog.csdn.net/xiaanming/article/details/17483273#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/129807)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/129807/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; draw(Canvas canvas) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; privateFlags = mPrivateFlags; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dirtyOpaque = (privateFlags \u0026amp; PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE \u0026amp;\u0026amp; - (mAttachInfo == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || !mAttachInfo.mIgnoreDirtyState); - mPrivateFlags = (privateFlags \u0026amp; ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Draw traversal performs several drawing steps which must be executed\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * in the appropriate order:\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 1. Draw the background\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 2. If necessary, save the canvas\u0026amp;#8217; layers to prepare for fading\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 3. Draw view\u0026amp;#8217;s content\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 4. Draw children\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 5. If necessary, draw the fading edges and restore layers\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 6. Draw decorations (scrollbars for instance)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Step 1, draw the background, if needed\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; saveCount; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!dirtyOpaque) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Drawable background = mBackground; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (background != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollX = mScrollX; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollY = mScrollY; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mBackgroundSizeChanged) { - background.setBounds(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, mRight \u0026amp;#8211; mLeft, mBottom \u0026amp;#8211; mTop); - mBackgroundSizeChanged = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((scrollX | scrollY) == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - background.draw(canvas); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - canvas.translate(scrollX, scrollY); - background.draw(canvas); - canvas.translate(-scrollX, -scrollY); - } - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// skip step 2 \u0026amp; 5 if possible (common case)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewFlags = mViewFlags; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; horizontalEdges = (viewFlags \u0026amp; FADING_EDGE_HORIZONTAL) != \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; verticalEdges = (viewFlags \u0026amp; FADING_EDGE_VERTICAL) != \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!verticalEdges \u0026amp;\u0026amp; !horizontalEdges) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Step 3, draw the content\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!dirtyOpaque) onDraw(canvas); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Step 4, draw the children\u0026lt;/span\u0026gt; - dispatchDraw(canvas); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Step 6, draw decorations (scrollbars)\u0026lt;/span\u0026gt; - onDrawScrollBars(canvas); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// we\u0026amp;#8217;re done\u0026amp;#8230;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - } - - \u0026amp;#8230;\u0026amp;#8230; - \u0026amp;#8230;\u0026amp;#8230; - \u0026amp;#8230;\u0026amp;#8230; 我们只截取了draw()的部分代码，这上面11-16行为我们写出了绘制一个View的几个步骤，我们看看第四步绘制孩子的时候会触发dispatchDraw()这个方法，来看看源码是什么内容\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17483273#)[copy](http://blog.csdn.net/xiaanming/article/details/17483273#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/129807)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/129807/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Called by draw to draw the child views. This may be overridden\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * by derived classes to gain control just before its children are drawn\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * (but after its own view has been drawn).\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param canvas the canvas on which to draw the view\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; dispatchDraw(Canvas canvas) { - - } 好吧，又是定义的一个空方法，给子类来重写的方法,所以我们找到View的子类ViewGroup来看看该方法的具体实现逻辑\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17483273#)[copy](http://blog.csdn.net/xiaanming/article/details/17483273#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/129807)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/129807/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_10\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_10\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; dispatchDraw(Canvas canvas) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; count = mChildrenCount; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View[] children = mChildren; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; flags = mGroupFlags; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((flags \u0026amp; FLAG_RUN_ANIMATION) != \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; canAnimate()) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; cache = (mGroupFlags \u0026amp; FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; buildCache = !isHardwareAccelerated(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; count; i++) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View child = children[i]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((child.mViewFlags \u0026amp; VISIBILITY_MASK) == VISIBLE) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; LayoutParams params = child.getLayoutParams(); - attachLayoutAnimationParameters(child, params, i, count); - bindLayoutAnimation(child); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (cache) { - child.setDrawingCacheEnabled(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (buildCache) { - child.buildDrawingCache(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - } - } - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; LayoutAnimationController controller = mLayoutAnimationController; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (controller.willOverlap()) { - mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE; - } - - controller.start(); - - mGroupFlags \u0026amp;= ~FLAG_RUN_ANIMATION; - mGroupFlags \u0026amp;= ~FLAG_ANIMATION_DONE; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (cache) { - mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mAnimationListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mAnimationListener.onAnimationStart(controller.getAnimation()); - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; saveCount = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; clipToPadding = (flags \u0026amp; CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (clipToPadding) { - saveCount = canvas.save(); - canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop, - mScrollX + mRight \u0026amp;#8211; mLeft \u0026amp;#8211; mPaddingRight, - mScrollY + mBottom \u0026amp;#8211; mTop \u0026amp;#8211; mPaddingBottom); - - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// We will draw our child\u0026amp;#8217;s animation, let\u0026amp;#8217;s reset the flag\u0026lt;/span\u0026gt; - mPrivateFlags \u0026amp;= ~PFLAG_DRAW_ANIMATION; - mGroupFlags \u0026amp;= ~FLAG_INVALIDATE_REQUIRED; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; more = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; drawingTime = getDrawingTime(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((flags \u0026amp; FLAG_USE_CHILD_DRAWING_ORDER) == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; count; i++) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View child = children[i]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((child.mViewFlags \u0026amp; VISIBILITY_MASK) == VISIBLE || child.getAnimation() != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - more |= drawChild(canvas, child, drawingTime); - } - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; count; i++) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View child = children[getChildDrawingOrder(count, i)]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((child.mViewFlags \u0026amp; VISIBILITY_MASK) == VISIBLE || child.getAnimation() != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - more |= drawChild(canvas, child, drawingTime); - } - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Draw any disappearing views that have animations\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mDisappearingChildren != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; ArrayList\u0026lt;View\u0026gt; disappearingChildren = mDisappearingChildren; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; disappearingCount = disappearingChildren.size() \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Go backwards \u0026amp;#8212; we may delete as animations finish\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = disappearingCount; i \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i\u0026amp;#8211;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View child = disappearingChildren.get(i); - more |= drawChild(canvas, child, drawingTime); - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (debugDraw()) { - onDebugDraw(canvas); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (clipToPadding) { - canvas.restoreToCount(saveCount); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// mGroupFlags might have been updated by drawChild()\u0026lt;/span\u0026gt; - flags = mGroupFlags; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((flags \u0026amp; FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) { - invalidate(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((flags \u0026amp; FLAG_ANIMATION_DONE) == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; (flags \u0026amp; FLAG_NOTIFY_ANIMATION_LISTENER) == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; - mLayoutAnimationController.isDone() \u0026amp;\u0026amp; !more) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// We want to erase the drawing cache and notify the listener after the\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// next frame is drawn because one extra invalidate() is caused by\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// drawChild() after the animation is over\u0026lt;/span\u0026gt; - mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Runnable end = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - notifyAnimationListener(); - } - }; - post(end); - } - } 这个方法代码有点多，但是我们还是挑重点看吧，从65-79行可以看出 在dispatchDraw()里面会对ViewGroup里面的子View调用drawChild()来进行绘制，接下来我们来看看drawChild()方法的代码\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17483273#)[copy](http://blog.csdn.net/xiaanming/article/details/17483273#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/129807)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/129807/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_11\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_11\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; drawChild(Canvas canvas, View child, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; drawingTime) { - \u0026amp;#8230;\u0026amp;#8230; - \u0026amp;#8230;\u0026amp;#8230; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!concatMatrix \u0026amp;\u0026amp; canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) \u0026amp;\u0026amp; - (child.mPrivateFlags \u0026amp; DRAW_ANIMATION) == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; more; - } - - child.computeScroll(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; sx = child.mScrollX; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; sy = child.mScrollY; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; scalingRequired = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - Bitmap cache = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - - \u0026amp;#8230;\u0026amp;#8230; - \u0026amp;#8230;\u0026amp;#8230; - - } 只截取了部分代码，看到child.computeScroll()你大概明白什么了吧，转了老半天终于找到了computeScroll()方法被触发，就是ViewGroup在分发绘制自己的孩子的时候，会对其子View调用computeScroll()方法\n整理下思路，来看看View滚动的实现原理，我们先调用Scroller的startScroll()方法来进行一些滚动的初始化设置，然后迫使View进行绘制，我们调用View的invalidate()或postInvalidate()就可以重新绘制View，绘制View的时候会触发computeScroll()方法，我们重写computeScroll()，在computeScroll()里面先调用Scroller的computeScrollOffset()方法来判断滚动有没有结束，如果滚动没有结束我们就调用scrollTo()方法来进行滚动，该scrollTo()方法虽然会重新绘制View,但是我们还是要手动调用下invalidate()或者postInvalidate()来触发界面重绘，重新绘制View又触发computeScroll()，所以就进入一个循环阶段，这样子就实现了在某个时间段里面滚动某段距离的一个平滑的滚动效果\n也许有人会问，干嘛还要调用来调用去最后在调用scrollTo()方法，还不如直接调用scrollTo()方法来实现滚动，其实直接调用是可以，只不过scrollTo()是瞬间滚动的，给人的用户体验不太好，所以Android提供了Scroller类实现平滑滚动的效果。为了方面大家理解，我画了一个简单的调用示意图\n好了，讲到这里就已经讲完了Scroller类的滚动实现原理啦，不知道大家理解了没有，Scroller能实现很多滚动的效果，由于考虑到这篇文章的篇幅有点长，所以这篇文章就不带领大家来使用Scroller类了，我将在下一篇文章将会带来Scroller类的使用，希望大家到时候关注下，有疑问的同学在下面留言，我会为大家解答的！\n","permalink":"https://blog.zdltech.com/posts/android-%E5%AF%B9scrollview%E6%BB%9A%E5%8A%A8%E7%9B%91%E5%90%AC%E5%AE%9E%E7%8E%B0%E7%BE%8E%E5%9B%A2%E5%A4%A7%E4%BC%97%E7%82%B9%E8%AF%84%E7%9A%84%E8%B4%AD%E4%B9%B0%E6%82%AC%E6%B5%AE/","summary":"\u003cp\u003e转帖请注明本文出自xiaanming的博客（\u003ca href=\"http://blog.csdn.net/xiaanming/article/details/17483273\"\u003ehttp://blog.csdn.net/xiaanming/article/details/17483273\u003c/a\u003e），请尊重他人的辛勤劳动成果，谢谢！\u003c/p\u003e\n\u003cp\u003e今天给大家讲解的是Scroller类的滚动实现原理，可能很多朋友不太了解该类是用来干嘛的，但是研究Launcher的朋友应该对他很熟悉，Scroller类是滚动的一个封装类，可以实现View的平滑滚动效果，什么是实现View的平滑滚动效果呢，举个简单的例子，一个View从在我们指定的时间内从一个位置滚动到另外一个位置，我们利用Scroller类可以实现匀速滚动，可以先加速后减速，可以先减速后加速等等效果，而不是瞬间的移动的效果，所以Scroller可以帮我们实现很多滑动的效果。\u003c/p\u003e\n\u003cp\u003e在介绍Scroller类之前，我们先去了解View的scrollBy() 和scrollTo()方法的区别，在区分这两个方法的之前，我们要先理解View 里面的两个成员变量mScrollX， mScrollY，X轴方向的偏移量和Y轴方向的偏移量，这个是一个相对距离，相对的不是屏幕的原点，而是View的左边缘，举个通俗易懂的例子，一列火车从吉安到深圳，途中经过赣州，那么原点就是赣州，偏移量就是 负的吉安到赣州的距离，大家从getScrollX()方法中的注释中就能看出答案来\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17483273#)[copy](http://blog.csdn.net/xiaanming/article/details/17483273#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/129807)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/129807/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;    * Return the scrolled left position of this view. This is the left edge of\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;    * the displayed part of your view. You do not need to draw any pixels\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;    * farther left, since those are outside of the frame of your view on\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;    * screen.\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;    *\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;    * @return The left edge of the displayed part of your view, in pixels.\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;    */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getScrollX() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mScrollX;\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e现在我们知道了向右滑动 mScrollX就为负数，向左滑动mScrollX为正数，接下来我们先来看看 scrollTo()方法的源码\u003c/p\u003e","title":"Android 带你从源码的角度解析Scroller的滚动实现原理"},{"content":"转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/38868463\n前面写过一篇关于下拉刷新控件的博客下拉刷新控件终结者：PullToRefreshLayout，后来看到好多人还有上拉加载更多的需求，于是就在前面下拉刷新控件的基础上进行了改进，加了上拉加载的功能。不仅如此，我已经把它改成了对所有View都通用！可以随心所欲使用这两个功能~~\n我做了一个大集合的demo，实现了ListView、GridView、ExpandableListView、ScrollView、WebView、ImageView、TextView的下拉刷新和上拉加载。后面会提供demo的下载地址。（csdn上的demo有小bug，最新代码已上传到github：https://github.com/jingchenUSTC/PullToRefreshAndLoad)\n依照惯例，下面将会是一大波效果图：\ndemo首页也是可下拉的ListView，在底下可以加入table：\nListView：\nGridView：\nExpandableListView：\nScrollView：\nWebView：\nImageView：\nTextView：\n很不错吧？最后的ImageView和TextView是最简单的，直接在下面的接口方法里返回true。\n增加上拉加载很简单，和管理下拉头一样，再多管理一个上拉头，也不费事；至于把它改成通用的就需要统一一下View的行为了，为此，我定义了这样一个接口：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; Pullable - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 判断是否可以下拉，如果不需要下拉功能可以直接return false\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return true如果可以下拉否则返回false\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 判断是否可以上拉，如果不需要上拉功能可以直接return false\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return true如果可以上拉否则返回false\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp(); - } 从接口名就可以看出它是一个提供判断是否可拉的方法的接口。这个接口的两个方法，canPullDown()是判断何时可以下拉的方法，canPullUp()则是判断何时可以上拉，我在demo中的判断是滑到顶部的时候可以下拉，滑到底部的时候可以上拉。所有需要上拉和下拉的View都需要实现这个接口。后面会给出一些View的实现。先来看看改进后的自定义的布局PullToRefreshLayout，增加了一个上拉头，下拉头和上拉头之间的View是实现了Pullable接口的pullableView。相比前面的版本，这里有改动的需要注意的地方如下：\n1、增加了上拉头，相应的也增加了控制变量。\n2、拉动时消除content_view事件防止误触发不再使用反射，直接设置 event.setAction(MotionEvent.ACTION_CANCEL)。\n3、消除了拉动过程中的多点触碰导致的剧变。\n4、不再设置content_view的onTouListener，让使用者可以更加自由的设置监听器。\n这个PullToRefreshLayout只负责管理三个控件，如果一个View需要有上拉下拉功能则只需实现接口就行了。下面看PullToRefreshLayout的代码，注释写了好多：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Timer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.TimerTask; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.LinearGradient; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint.Style; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.RectF; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Shader.TileMode; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.AnimationUtils; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.LinearInterpolator; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.animation.RotateAnimation; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.RelativeLayout; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview.Pullable; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 自定义的布局，用来管理三个子控件，其中一个是下拉头，一个是包含内容的pullableView（可以是实现Pullable接口的的任何View），\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 还有一个上拉头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author 陈靖\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullToRefreshLayout \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; RelativeLayout - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;PullToRefreshLayout\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; INIT = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; RELEASE_TO_REFRESH = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; REFRESHING = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; RELEASE_TO_LOAD = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; LOADING = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 操作完毕\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; DONE = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 当前状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; state = INIT; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnRefreshListener mListener; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新成功\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; SUCCEED = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; FAIL = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 按下Y坐标，上一个事件点Y坐标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; downY, lastY; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉的距离。注意：pullDownY和pullUpY不可能同时不为0\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; pullDownY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; pullUpY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放刷新的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; refreshDist = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放加载的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; loadmoreDist = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTimer timer; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 回滚速度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; MOVE_SPEED = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 第一次执行布局\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isLayout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 在刷新过程中滑动操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 手指滑动距离与下拉头的滑动距离比，中间会随正切函数变化\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; radio = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉箭头的转180°动画\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; RotateAnimation rotateAnimation; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 均匀旋转动画\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; RotateAnimation refreshingAnimation; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View refreshView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉的箭头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View pullView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新的图标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View refreshingView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果图标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View refreshStateImageView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果：成功或失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView refreshStateTextView; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View loadmoreView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉的箭头\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View pullUpView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载的图标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View loadingView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载结果图标\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View loadStateImageView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载结果：成功或失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView loadStateTextView; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 实现了Pullable接口的View\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View pullableView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 过滤多点触碰\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mEvents; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这两个变量用来控制pull的方向，如果不加控制，当情况满足可上拉又可下拉时没法下拉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 执行自动回滚的handler\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - Handler updateHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 回弹速度随下拉距离moveDeltaY增大而增大\u0026lt;/span\u0026gt; - MOVE_SPEED = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt; * Math.tan(Math.PI / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; - / getMeasuredHeight() * (pullDownY + Math.abs(pullUpY)))); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isTouch) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新，且没有往上推的话则悬停，显示\u0026amp;#8221;正在刷新\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == REFRESHING \u0026amp;\u0026amp; pullDownY \u0026lt;= refreshDist) - { - pullDownY = refreshDist; - timer.cancel(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == LOADING \u0026amp;\u0026amp; -pullUpY \u0026lt;= loadmoreDist) - { - pullUpY = -loadmoreDist; - timer.cancel(); - } - - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - pullDownY -= MOVE_SPEED; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - pullUpY += MOVE_SPEED; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 已完成回弹\u0026lt;/span\u0026gt; - pullDownY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - pullView.clearAnimation(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 隐藏下拉头时有可能还在刷新，只有当前状态不是正在刷新时才改变状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state != REFRESHING \u0026amp;\u0026amp; state != LOADING) - changeState(INIT); - timer.cancel(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 已完成回弹\u0026lt;/span\u0026gt; - pullUpY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - pullUpView.clearAnimation(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 隐藏下拉头时有可能还在刷新，只有当前状态不是正在刷新时才改变状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state != REFRESHING \u0026amp;\u0026amp; state != LOADING) - changeState(INIT); - timer.cancel(); - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新布局,会自动调用onLayout\u0026lt;/span\u0026gt; - requestLayout(); - } - - }; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnRefreshListener(OnRefreshListener listener) - { - mListener = listener; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullToRefreshLayout(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - initView(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullToRefreshLayout(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - initView(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullToRefreshLayout(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - initView(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView(Context context) - { - timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTimer(updateHandler); - rotateAnimation = (RotateAnimation) AnimationUtils.loadAnimation( - context, R.anim.reverse_anim); - refreshingAnimation = (RotateAnimation) AnimationUtils.loadAnimation( - context, R.anim.rotating); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 添加匀速转动动画\u0026lt;/span\u0026gt; - LinearInterpolator lir = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearInterpolator(); - rotateAnimation.setInterpolator(lir); - refreshingAnimation.setInterpolator(lir); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; hide() - { - timer.schedule(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 完成刷新操作，显示刷新结果。注意：刷新完成后一定要调用这个方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param refreshResult\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * PullToRefreshLayout.SUCCEED代表成功，PullToRefreshLayout.FAIL代表失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; refreshFinish(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; refreshResult) - { - refreshingView.clearAnimation(); - refreshingView.setVisibility(View.GONE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (refreshResult) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; SUCCEED: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新成功\u0026lt;/span\u0026gt; - refreshStateImageView.setVisibility(View.VISIBLE); - refreshStateTextView.setText(R.string.refresh_succeed); - refreshStateImageView - .setBackgroundResource(R.drawable.refresh_succeed); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; FAIL: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新失败\u0026lt;/span\u0026gt; - refreshStateImageView.setVisibility(View.VISIBLE); - refreshStateTextView.setText(R.string.refresh_fail); - refreshStateImageView - .setBackgroundResource(R.drawable.refresh_failed); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果停留1秒\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() - { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) - { - changeState(DONE); - hide(); - } - }.sendEmptyMessageDelayed(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 加载完毕，显示加载结果。注意：加载完成后一定要调用这个方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param refreshResult\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * PullToRefreshLayout.SUCCEED代表成功，PullToRefreshLayout.FAIL代表失败\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; loadmoreFinish(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; refreshResult) - { - loadingView.clearAnimation(); - loadingView.setVisibility(View.GONE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (refreshResult) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; SUCCEED: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载成功\u0026lt;/span\u0026gt; - loadStateImageView.setVisibility(View.VISIBLE); - loadStateTextView.setText(R.string.load_succeed); - loadStateImageView.setBackgroundResource(R.drawable.load_succeed); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; FAIL: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载失败\u0026lt;/span\u0026gt; - loadStateImageView.setVisibility(View.VISIBLE); - loadStateTextView.setText(R.string.load_fail); - loadStateImageView.setBackgroundResource(R.drawable.load_failed); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新结果停留1秒\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() - { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) - { - changeState(DONE); - hide(); - } - }.sendEmptyMessageDelayed(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; changeState(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; to) - { - state = to; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (state) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; INIT: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下拉布局初始状态\u0026lt;/span\u0026gt; - refreshStateImageView.setVisibility(View.GONE); - refreshStateTextView.setText(R.string.pull_to_refresh); - pullView.clearAnimation(); - pullView.setVisibility(View.VISIBLE); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 上拉布局初始状态\u0026lt;/span\u0026gt; - loadStateImageView.setVisibility(View.GONE); - loadStateTextView.setText(R.string.pullup_to_load); - pullUpView.clearAnimation(); - pullUpView.setVisibility(View.VISIBLE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; RELEASE_TO_REFRESH: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放刷新状态\u0026lt;/span\u0026gt; - refreshStateTextView.setText(R.string.release_to_refresh); - pullView.startAnimation(rotateAnimation); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; REFRESHING: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新状态\u0026lt;/span\u0026gt; - pullView.clearAnimation(); - refreshingView.setVisibility(View.VISIBLE); - pullView.setVisibility(View.INVISIBLE); - refreshingView.startAnimation(refreshingAnimation); - refreshStateTextView.setText(R.string.refreshing); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; RELEASE_TO_LOAD: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 释放加载状态\u0026lt;/span\u0026gt; - loadStateTextView.setText(R.string.release_to_load); - pullUpView.startAnimation(rotateAnimation); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; LOADING: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载状态\u0026lt;/span\u0026gt; - pullUpView.clearAnimation(); - loadingView.setVisibility(View.VISIBLE); - pullUpView.setVisibility(View.INVISIBLE); - loadingView.startAnimation(refreshingAnimation); - loadStateTextView.setText(R.string.loading); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; DONE: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新或加载完毕，啥都不做\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 不限制上拉或下拉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; releasePull() - { - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * （非 Javadoc）由父控件决定是否分发事件，防止事件冲突\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (ev.getActionMasked()) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: - downY = ev.getY(); - lastY = downY; - timer.cancel(); - mEvents = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - releasePull(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_DOWN: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_UP: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 过滤多点触碰\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mEvents == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (((Pullable) pullableView).canPullDown() \u0026amp;\u0026amp; canPullDown - \u0026amp;\u0026amp; state != LOADING) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 可以下拉，正在加载时不能下拉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 对实际滑动距离做缩小，造成用力拉的感觉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - pullDownY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt; getMeasuredHeight()) - pullDownY = getMeasuredHeight(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == REFRESHING) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新的时候触摸移动\u0026lt;/span\u0026gt; - isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (((Pullable) pullableView).canPullUp() \u0026amp;\u0026amp; canPullUp - \u0026amp;\u0026amp; state != REFRESHING) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 可以上拉，正在刷新时不能上拉\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - pullUpY = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullUpY \u0026lt; -getMeasuredHeight()) - pullUpY = -getMeasuredHeight(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == LOADING) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在加载的时候触摸移动\u0026lt;/span\u0026gt; - isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - releasePull(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - mEvents = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - lastY = ev.getY(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 根据下拉距离改变比例\u0026lt;/span\u0026gt; - radio = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; * Math.tan(Math.PI / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; / getMeasuredHeight() - * (pullDownY + Math.abs(pullUpY)))); - requestLayout(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026lt;= refreshDist - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026amp;\u0026amp; (state == RELEASE_TO_REFRESH || state == DONE)) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果下拉距离没达到刷新的距离且当前状态是释放刷新，改变状态为下拉刷新\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;changeState(INIT); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt;= refreshDist \u0026amp;\u0026amp; (state == INIT || state == DONE)) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 如果下拉距离达到刷新的距离且当前状态是初始状态刷新，改变状态为释放刷新\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;changeState(RELEASE_TO_REFRESH); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 下面是判断上拉加载的，同上，注意pullUpY是负值\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (-pullUpY \u0026lt;= loadmoreDist - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026amp;\u0026amp; (state == RELEASE_TO_LOAD || state == DONE)) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;changeState(INIT); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (-pullUpY \u0026gt;= loadmoreDist \u0026amp;\u0026amp; (state == INIT || state == DONE)) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;changeState(RELEASE_TO_LOAD); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 因为刷新和加载操作不能同时进行，所以pullDownY和pullUpY不会同时不为0，因此这里用(pullDownY +\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Math.abs(pullUpY))就可以不对当前状态作区分了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((pullDownY + Math.abs(pullUpY)) \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止下拉过程中误触发长按事件和点击事件\u0026lt;/span\u0026gt; - ev.setAction(MotionEvent.ACTION_CANCEL); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pullDownY \u0026gt; refreshDist || -pullUpY \u0026gt; loadmoreDist) - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在刷新时往下拉（正在加载时往上拉），释放后下拉头（上拉头）不隐藏\u0026lt;/span\u0026gt; - isTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == RELEASE_TO_REFRESH) - { - changeState(REFRESHING); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 刷新操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - mListener.onRefresh(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == RELEASE_TO_LOAD) - { - changeState(LOADING); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 加载操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mListener != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - mListener.onLoadMore(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - } - hide(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 事件分发交给父类\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(ev); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始化下拉布局\u0026lt;/span\u0026gt; - pullView = refreshView.findViewById(R.id.pull_icon); - refreshStateTextView = (TextView) refreshView - .findViewById(R.id.state_tv); - refreshingView = refreshView.findViewById(R.id.refreshing_icon); - refreshStateImageView = refreshView.findViewById(R.id.state_iv); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始化上拉布局\u0026lt;/span\u0026gt; - pullUpView = loadmoreView.findViewById(R.id.pullup_icon); - loadStateTextView = (TextView) loadmoreView - .findViewById(R.id.loadstate_tv); - loadingView = loadmoreView.findViewById(R.id.loading_icon); - loadStateImageView = loadmoreView.findViewById(R.id.loadstate_iv); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isLayout) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这里是第一次进来的时候做一些初始化\u0026lt;/span\u0026gt; - refreshView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - pullableView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - loadmoreView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); - isLayout = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - initView(); - refreshDist = ((ViewGroup) refreshView).getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - .getMeasuredHeight(); - loadmoreDist = ((ViewGroup) loadmoreView).getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - .getMeasuredHeight(); - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 改变子控件的布局，这里直接用(pullDownY + pullUpY)作为偏移量，这样就可以不对当前状态作区分\u0026lt;/span\u0026gt; - refreshView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, - refreshView.getMeasuredWidth(), (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY)); - pullableView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY), - pullableView.getMeasuredWidth(), (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY) - + pullableView.getMeasuredHeight()); - loadmoreView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, - (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY) + pullableView.getMeasuredHeight(), - loadmoreView.getMeasuredWidth(), - (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (pullDownY + pullUpY) + pullableView.getMeasuredHeight() - + loadmoreView.getMeasuredHeight()); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTimer - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Timer timer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTask mTask; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTimer(Handler handler) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler; - timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Timer(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; schedule(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; period) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - mTask.cancel(); - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTask(handler); - timer.schedule(mTask, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, period); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; cancel() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - mTask.cancel(); - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTask \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; TimerTask - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTask(Handler handler) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() - { - handler.obtainMessage().sendToTarget(); - } - - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 刷新加载回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author chenjing\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnRefreshListener - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 刷新操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onRefresh(PullToRefreshLayout pullToRefreshLayout); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 加载操作\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLoadMore(PullToRefreshLayout pullToRefreshLayout); - } - - } 上面就是整个布局的代码，并不是很难。\n下面看各个View对Pullable接口的实现，ListView和GridView还有ExpandableListView的判断方法是一样的：\nPullableListView：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableListView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableListView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableListView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以下拉刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getFirstVisiblePosition() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getTop() \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到ListView的顶部了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以上拉加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到底部了\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt( - getLastVisiblePosition() - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } PullableExpandableListView：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ExpandableListView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableExpandableListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ExpandableListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; - Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableExpandableListView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableExpandableListView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableExpandableListView(Context context, AttributeSet attrs, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以下拉刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getFirstVisiblePosition() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getTop() \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到顶部了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以上拉加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到底部了\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt( - getLastVisiblePosition() - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - } PullableGridView：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableGridView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; GridView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableGridView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableGridView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableGridView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以下拉刷新\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getFirstVisiblePosition() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getTop() \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到顶部了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getCount() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 没有item的时候也可以上拉加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑到底部了\u0026lt;/span\u0026gt; - \u0026amp;\u0026amp; getChildAt( - getLastVisiblePosition() - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - } PullableScrollView：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ScrollView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableScrollView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ScrollView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableScrollView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableScrollView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableScrollView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollY() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - } PullableWebView：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.webkit.WebView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PullableWebView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; WebView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Pullable - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableWebView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableWebView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; PullableWebView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollY() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getScrollY() \u0026gt;= getContentHeight() * getScale() - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } ImageView和TextView就不贴了，我直接在方法里返回了true。\nOK了，整个demo的代码有点多，就不贴了。\n源码下载\n","permalink":"https://blog.zdltech.com/posts/android%E4%B8%8B%E6%8B%89%E5%88%B7%E6%96%B0%E4%B8%8A%E6%8B%89%E5%8A%A0%E8%BD%BD%E6%8E%A7%E4%BB%B6%E5%AF%B9%E6%89%80%E6%9C%89view%E9%80%9A%E7%94%A8/","summary":"\u003cp\u003e转载请声明出处\u003ca href=\"http://blog.csdn.net/zhongkejingwang/article/details/38868463\"\u003ehttp://blog.csdn.net/zhongkejingwang/article/details/38868463\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e前面写过一篇关于下拉刷新控件的博客\u003ca href=\"http://blog.csdn.net/zhongkejingwang/article/details/38340701\"\u003e下拉刷新控件终结者：PullToRefreshLayout\u003c/a\u003e，后来看到好多人还有上拉加载更多的需求，于是就在前面下拉刷新控件的基础上进行了改进，加了上拉加载的功能。不仅如此，我已经把它改成了对所有View都通用！可以随心所欲使用这两个功能~~\u003c/p\u003e\n\u003cp\u003e我做了一个大集合的demo，实现了ListView、GridView、ExpandableListView、ScrollView、WebView、ImageView、TextView的下拉刷新和上拉加载。后面会提供demo的下载地址。（csdn上的demo有小bug，最新代码已上传到github：\u003ca href=\"https://github.com/jingchenUSTC/PullToRefreshAndLoad\"\u003ehttps://github.com/jingchenUSTC/PullToRefreshAndLoad\u003c/a\u003e)\u003c/p\u003e\n\u003cp\u003e依照惯例，下面将会是一大波效果图：\u003c/p\u003e\n\u003cp\u003edemo首页也是可下拉的ListView，在底下可以加入table：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827132732390?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eListView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827133113883?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eGridView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827133157922?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eExpandableListView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827133245580?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eScrollView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827134146109?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eWebView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827134443946?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eImageView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827135142900?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eTextView：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140827135212228?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e很不错吧？最后的ImageView和TextView是最简单的，直接在下面的接口方法里返回true。\u003c/p\u003e\n\u003cp\u003e增加上拉加载很简单，和管理下拉头一样，再多管理一个上拉头，也不费事；至于把它改成通用的就需要统一一下View的行为了，为此，我定义了这样一个接口：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pulltorefresh.pullableview;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; Pullable\n\n- {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 判断是否可以下拉，如果不需要下拉功能可以直接return false\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return true如果可以下拉否则返回false\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown();\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 判断是否可以上拉，如果不需要上拉功能可以直接return false\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return true如果可以上拉否则返回false\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp();\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e从接口名就可以看出它是一个提供判断是否可拉的方法的接口。这个接口的两个方法，canPullDown()是判断何时可以下拉的方法，canPullUp()则是判断何时可以上拉，我在demo中的判断是滑到顶部的时候可以下拉，滑到底部的时候可以上拉。所有需要上拉和下拉的View都需要实现这个接口。后面会给出一些View的实现。先来看看改进后的自定义的布局PullToRefreshLayout，增加了一个上拉头，下拉头和上拉头之间的View是实现了Pullable接口的pullableView。相比前面的版本，这里有改动的需要注意的地方如下：\u003c/p\u003e","title":"Android下拉刷新上拉加载控件，对所有View通用！"},{"content":"转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/38728119\n之前自己做的一个APP需要用到翻页阅读，网上看过立体翻页效果，不过bug太多了还不兼容。看了一下多看阅读翻页是采用平移翻页的，于是就仿写了一个平移翻页的控件。效果如下：\n在翻页时页面右边缘绘制了阴影，效果还不错。要实现这种平移翻页控件并不难，只需要定义一个布局管理页面就可以了。具体实现上有以下难点：\n1、循环翻页，页面的重复利用。\n2、在翻页时过滤掉多点触碰。\n3、采用setAdapter的方式设置页面布局和数据。\n下面就来一一解决这几个难点。首先看循环翻页问题，怎么样能采用较少的页面实现这种翻页呢？由于屏幕上每次只能显示一张完整的页面，翻过去的页面也看不到，所以可以把翻过去的页面拿来重复利用，不必每次都new一个页面，所以，我只用了三张页面实现循环翻页。要想重复利用页面，首先要知道页面在布局中序号和对应的层次关系，比如一个父控件的子view的序号越大就位于越上层。循环利用页面的原理图如下：\n向右翻页时状态图是这样的，只用了0、1、2三张页面，页面序号为2的位于最上层，我把它隐藏在左边，所以看到的只有页面1，页面0在1下面挡着也看不到，向右翻页时，页面2被滑到屏幕中，这时候把页面0的内容替换成页面2的前一页内容，把它放到之前页面2的位置，这时，状态又回到了初始状态，又可以继续向右翻页了！\n向左翻页时是这样的，初始状态还是一样，当页面1被往左翻过时，看到的是页面0，这时候页面0下面已经没有页面了，而页面2已经用不到了，这时候把页面2放到页面0下面，这时候状态又回到了初始状态，就可以继续往左翻页了。\n类似于这种循环效果的实现我一直用的解决方案都是将选中的置于最中间，比如原理图中的页面1，每次翻页完成后可见的都是页面1。在滚动选择器PickerView中也是同样的方案。这就解决了页面的重复利用问题了。\n解决难点2 翻页时过滤多点触碰这个问题在仿淘宝商品浏览界面中已经解决过了，就是用一个控制变量mEvents过滤掉pointer down或up后到来的第一个move事件。\n解决难点3 采用adapter方式设置页面的布局和数据。这个在Android的AdapterView里用到的，但是我没有看它的adapter机制，太复杂了，我就搞了个简单的adapter，如下：\nPageAdapter.java：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pagerdemo; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PageAdapter - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return 页面view\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; View getView(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 将内容添加到view中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param view\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 包含内容的view\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param position\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 第position页\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; addContent(View view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position); - } 这是一个抽象类，getView()用于返回页面的布局，getCount()返回数据总共需要多少页，addContent(View view, int position)这个是每翻过一页后将会被调用来请求页面数据的，参数view就是页面，position是表明第几页。待会儿会在自定义布局中定义setAdapter方法设置设配器。\nOK，难点都解决了，自定义一个布局叫ScanView继承自RelativeLayout：\nScanView.java：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pagerdemo; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Timer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.TimerTask; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.LinearGradient; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint.Style; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.RectF; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Shader.TileMode; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.VelocityTracker; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.RelativeLayout; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author chenjing\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ScanView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; RelativeLayout - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;ScanView\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isInit = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑动的时候存在两页可滑动，要判断是哪一页在滑动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isPreMoving = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;, isCurrMoving = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 当前是第几页\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; index; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; lastX; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 前一页，当前页，下一页的左边位置\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; prePageLeft = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, currPageLeft = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, nextPageLeft = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 三张页面\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View prePage, currPage, nextPage; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 页面状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; STATE_MOVE = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; STATE_STOP = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑动的页面，只有前一页和当前页可滑\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; PRE = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; CURR = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; state = STATE_STOP; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 正在滑动的页面右边位置，用于绘制阴影\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; right; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 手指滑动的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; moveLenght; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 页面宽高\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mWidth, mHeight; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获取滑动速度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; VelocityTracker vt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止抖动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; speed_shake = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 当前滑动速度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; speed; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Timer timer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTimerTask mTask; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 滑动动画的移动速度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; MOVE_SPEED = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 页面适配器\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; PageAdapter adapter; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 过滤多点触碰的控制变量\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mEvents; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setAdapter(ScanViewAdapter adapter) - { - removeAllViews(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.adapter = adapter; - prePage = adapter.getView(); - addView(prePage, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT)); - adapter.addContent(prePage, index \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - - currPage = adapter.getView(); - addView(currPage, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT)); - adapter.addContent(currPage, index); - - nextPage = adapter.getView(); - addView(nextPage, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT)); - adapter.addContent(nextPage, index + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 向左滑。注意可以滑动的页面只有当前页和前一页\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param which\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; moveLeft(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; which) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (which) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; PRE: - prePageLeft -= MOVE_SPEED; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (prePageLeft \u0026lt; -mWidth) - prePageLeft = -mWidth; - right = mWidth + prePageLeft; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; CURR: - currPageLeft -= MOVE_SPEED; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (currPageLeft \u0026lt; -mWidth) - currPageLeft = -mWidth; - right = mWidth + currPageLeft; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 向右滑。注意可以滑动的页面只有当前页和前一页\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param which\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; moveRight(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; which) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (which) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; PRE: - prePageLeft += MOVE_SPEED; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (prePageLeft \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - prePageLeft = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - right = mWidth + prePageLeft; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; CURR: - currPageLeft += MOVE_SPEED; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (currPageLeft \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - currPageLeft = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - right = mWidth + currPageLeft; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 当往回翻过一页时添加前一页在最左边\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; addPrePage() - { - removeView(nextPage); - addView(nextPage, \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT)); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 从适配器获取前一页内容\u0026lt;/span\u0026gt; - adapter.addContent(nextPage, index \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 交换顺序\u0026lt;/span\u0026gt; - View temp = nextPage; - nextPage = currPage; - currPage = prePage; - prePage = temp; - prePageLeft = -mWidth; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 当往前翻过一页时，添加一页在最底下\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; addNextPage() - { - removeView(prePage); - addView(prePage, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT)); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 从适配器获取后一页内容\u0026lt;/span\u0026gt; - adapter.addContent(prePage, index + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 交换顺序\u0026lt;/span\u0026gt; - View temp = currPage; - currPage = nextPage; - nextPage = prePage; - prePage = temp; - currPageLeft = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - } - - Handler updateHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state != STATE_MOVE) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 移动页面\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 翻回，先判断当前哪一页处于未返回状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (prePageLeft \u0026gt; -mWidth \u0026amp;\u0026amp; speed \u0026lt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 前一页处于未返回状态\u0026lt;/span\u0026gt; - moveLeft(PRE); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (currPageLeft \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; speed \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 当前页处于未返回状态\u0026lt;/span\u0026gt; - moveRight(CURR); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (speed \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; index \u0026lt; adapter.getCount()) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 向左翻，翻动的是当前页\u0026lt;/span\u0026gt; - moveLeft(CURR); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (currPageLeft == (-mWidth)) - { - index++; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 翻过一页，在底下添加一页，把最上层页面移除\u0026lt;/span\u0026gt; - addNextPage(); - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (speed \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; index \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 向右翻，翻动的是前一页\u0026lt;/span\u0026gt; - moveRight(PRE); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (prePageLeft == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - index\u0026amp;#8211;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 翻回一页，添加一页在最上层，隐藏在最左边\u0026lt;/span\u0026gt; - addPrePage(); - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (right == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; || right == mWidth) - { - releaseMoving(); - state = STATE_STOP; - quitMove(); - } - ScanView.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.requestLayout(); - } - - }; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ScanView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - init(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ScanView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - init(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ScanView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - init(); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 退出动画翻页\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; quitMove() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - mTask.cancel(); - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; init() - { - index = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Timer(); - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTimerTask(updateHandler); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 释放动作，不限制手滑动方向\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; releaseMoving() - { - isPreMoving = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - isCurrMoving = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent event) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (adapter != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (event.getActionMasked()) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: - lastX = event.getX(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (vt == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - vt = VelocityTracker.obtain(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - { - vt.clear(); - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) - { - e.printStackTrace(); - } - vt.addMovement(event); - mEvents = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_DOWN: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_UP: - mEvents = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 取消动画\u0026lt;/span\u0026gt; - quitMove(); - Log.d(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;index\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;mEvents = \u0026amp;#8220;\u0026lt;/span\u0026gt; + mEvents + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;, isPreMoving = \u0026amp;#8220;\u0026lt;/span\u0026gt; - + isPreMoving + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;, isCurrMoving = \u0026amp;#8220;\u0026lt;/span\u0026gt; + isCurrMoving); - vt.addMovement(event); - vt.computeCurrentVelocity(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt;); - speed = vt.getXVelocity(); - moveLenght = event.getX() \u0026amp;#8211; lastX; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((moveLenght \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; || !isCurrMoving) \u0026amp;\u0026amp; isPreMoving - \u0026amp;\u0026amp; mEvents == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - isPreMoving = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - isCurrMoving = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (index == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 第一页不能再往右翻，跳转到前一个activity\u0026lt;/span\u0026gt; - state = STATE_MOVE; - releaseMoving(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 非第一页\u0026lt;/span\u0026gt; - prePageLeft += (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) moveLenght; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止滑过边界\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (prePageLeft \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - prePageLeft = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (prePageLeft \u0026lt; -mWidth) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 边界判断，释放动作，防止来回滑动导致滑动前一页时当前页无法滑动\u0026lt;/span\u0026gt; - prePageLeft = -mWidth; - releaseMoving(); - } - right = mWidth + prePageLeft; - state = STATE_MOVE; - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((moveLenght \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; || !isPreMoving) \u0026amp;\u0026amp; isCurrMoving - \u0026amp;\u0026amp; mEvents == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - isPreMoving = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - isCurrMoving = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (index == adapter.getCount()) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 最后一页不能再往左翻\u0026lt;/span\u0026gt; - state = STATE_STOP; - releaseMoving(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - { - currPageLeft += (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) moveLenght; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止滑过边界\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (currPageLeft \u0026lt; -mWidth) - currPageLeft = -mWidth; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (currPageLeft \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 边界判断，释放动作，防止来回滑动导致滑动当前页是前一页无法滑动\u0026lt;/span\u0026gt; - currPageLeft = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - releaseMoving(); - } - right = mWidth + currPageLeft; - state = STATE_MOVE; - } - - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - mEvents = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - lastX = event.getX(); - requestLayout(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (Math.abs(speed) \u0026lt; speed_shake) - speed = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - quitMove(); - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTimerTask(updateHandler); - timer.schedule(mTask, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; - { - vt.clear(); - vt.recycle(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) - { - e.printStackTrace(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(event); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * （非 Javadoc） 在这里绘制翻页阴影效果\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @see android.view.ViewGroup#dispatchDraw(android.graphics.Canvas)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; dispatchDraw(Canvas canvas) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchDraw(canvas); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (right == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; || right == mWidth) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - RectF rectF = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; RectF(right, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, mWidth, mHeight); - Paint paint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(); - paint.setAntiAlias(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - LinearGradient linearGradient = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearGradient(right, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, - right + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xffbbbbbb\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x00bbbbbb\u0026lt;/span\u0026gt;, TileMode.CLAMP); - paint.setShader(linearGradient); - paint.setStyle(Style.FILL); - canvas.drawRect(rectF, paint); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMeasure(widthMeasureSpec, heightMeasureSpec); - mWidth = getMeasuredWidth(); - mHeight = getMeasuredHeight(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isInit) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 初始状态，一页放在左边隐藏起来，两页叠在一块\u0026lt;/span\u0026gt; - prePageLeft = -mWidth; - currPageLeft = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - nextPageLeft = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - isInit = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (adapter == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - prePage.layout(prePageLeft, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, - prePageLeft + prePage.getMeasuredWidth(), - prePage.getMeasuredHeight()); - currPage.layout(currPageLeft, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, - currPageLeft + currPage.getMeasuredWidth(), - currPage.getMeasuredHeight()); - nextPage.layout(nextPageLeft, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, - nextPageLeft + nextPage.getMeasuredWidth(), - nextPage.getMeasuredHeight()); - invalidate(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTimerTask \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; TimerTask - { - Handler handler; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTimerTask(Handler handler) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() - { - handler.sendMessage(handler.obtainMessage()); - } - - } - } 代码中的注释写的非常多，原理理解了看代码就容易看懂了。写完这个布局后再写一个ScanViewAdapter继承PageAdapter：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pagerdemo; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.res.AssetManager; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Typeface; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ScanViewAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; PageAdapter - { - Context context; - List\u0026lt;String\u0026gt; items; - AssetManager am; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ScanViewAdapter(Context context, List\u0026lt;String\u0026gt; items) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.context = context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.items = items; - am = context.getAssets(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; addContent(View view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) - { - TextView content = (TextView) view.findViewById(R.id.content); - TextView tv = (TextView) view.findViewById(R.id.index); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((position \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; || (position \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) \u0026gt;= getCount()) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - content.setText(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; 双峰叠障，过天风海雨，无边空碧。月姊年年应好在，玉阙琼宫愁寂。谁唤痴云，一杯未尽，夜气寒无色。碧城凝望，高楼缥缈西北。\\n\\n 肠断桂冷蟾孤，佳期如梦，又把阑干拍。雾鬓风虔相借问，浮世几回今夕。圆缺睛明，古今同恨，我更长为客。蝉娟明夜，尊前谁念南陌。\u0026amp;#8221;\u0026lt;/span\u0026gt;); - tv.setText(items.get(position \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;)); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; items.size(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getView() - { - View view = LayoutInflater.from(context).inflate(R.layout.page_layout, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; view; - } - } 这里只是我的demo里写的Adapter，也可以写成带更多内容的Adapter。addContent里带的参数view就是getView里面返回的view，这样就可以根据inflate的布局设置内容了，getView返回的布局page_layout.xml如下：\n**[html]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/cover\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerHorizontal\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;60dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:padding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#000000\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;22sp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/index\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_alignParentBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerHorizontal\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;60dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#000000\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;30sp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 只包含了两个TextView，所以在adapter中可以根据id查找到这两个TextView再给它设置内容。\nOK了，MainActivity的布局如下：\n**[html]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.jingchen.pagerdemo.ScanView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/scanview\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 很简单，只包含了ScanView。\nMainActivity的代码：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pagerdemo; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Menu; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity - { - ScanView scanview; - ScanViewAdapter adapter; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - scanview = (ScanView) findViewById(R.id.scanview); - List\u0026lt;String\u0026gt; items = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;String\u0026gt;(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; i++) - items.add(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;第 \u0026amp;#8220;\u0026lt;/span\u0026gt; + (i + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; 页\u0026amp;#8221;\u0026lt;/span\u0026gt;); - adapter = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ScanViewAdapter(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, items); - scanview.setAdapter(adapter); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onCreateOptionsMenu(Menu menu) - { - getMenuInflater().inflate(R.menu.main, menu); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - } 给ScanView设置Adapter就可以了。\n好啦，仿多看的平移翻页就完成了~\n源码下载\n","permalink":"https://blog.zdltech.com/posts/android%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6%E5%AE%9E%E6%88%98-%E4%BB%BF%E5%A4%9A%E7%9C%8B%E9%98%85%E8%AF%BB%E5%B9%B3%E7%A7%BB%E7%BF%BB%E9%A1%B5/","summary":"\u003cp\u003e转载请声明出处\u003ca href=\"http://blog.csdn.net/zhongkejingwang/article/details/38728119\"\u003ehttp://blog.csdn.net/zhongkejingwang/article/details/38728119\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e之前自己做的一个APP需要用到翻页阅读，网上看过立体翻页效果，不过bug太多了还不兼容。看了一下多看阅读翻页是采用平移翻页的，于是就仿写了一个平移翻页的控件。效果如下：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140821123816920?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e在翻页时页面右边缘绘制了阴影，效果还不错。要实现这种平移翻页控件并不难，只需要定义一个布局管理页面就可以了。具体实现上有以下难点：\u003c/p\u003e\n\u003cp\u003e1、循环翻页，页面的重复利用。\u003c/p\u003e\n\u003cp\u003e2、在翻页时过滤掉多点触碰。\u003c/p\u003e\n\u003cp\u003e3、采用setAdapter的方式设置页面布局和数据。\u003c/p\u003e\n\u003cp\u003e下面就来一一解决这几个难点。首先看循环翻页问题，怎么样能采用较少的页面实现这种翻页呢？由于屏幕上每次只能显示一张完整的页面，翻过去的页面也看不到，所以可以把翻过去的页面拿来重复利用，不必每次都new一个页面，所以，我只用了三张页面实现循环翻页。要想重复利用页面，首先要知道页面在布局中序号和对应的层次关系，比如一个父控件的子view的序号越大就位于越上层。循环利用页面的原理图如下：\u003c/p\u003e\n\u003cp\u003e向右翻页时状态图是这样的，只用了0、1、2三张页面，页面序号为2的位于最上层，我把它隐藏在左边，所以看到的只有页面1，页面0在1下面挡着也看不到，向右翻页时，页面2被滑到屏幕中，这时候把页面0的内容替换成页面2的前一页内容，把它放到之前页面2的位置，这时，状态又回到了初始状态，又可以继续向右翻页了！\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140821125739808?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e向左翻页时是这样的，初始状态还是一样，当页面1被往左翻过时，看到的是页面0，这时候页面0下面已经没有页面了，而页面2已经用不到了，这时候把页面2放到页面0下面，这时候状态又回到了初始状态，就可以继续往左翻页了。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140821130648570?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e类似于这种循环效果的实现我一直用的解决方案都是将选中的置于最中间，比如原理图中的页面1，每次翻页完成后可见的都是页面1。在\u003ca href=\"http://blog.csdn.net/zhongkejingwang/article/details/38513301\"\u003e滚动选择器PickerView\u003c/a\u003e中也是同样的方案。这就解决了页面的重复利用问题了。\u003c/p\u003e\n\u003cp\u003e解决难点2 翻页时过滤多点触碰这个问题在\u003ca href=\"http://blog.csdn.net/zhongkejingwang/article/details/38656929\"\u003e仿淘宝商品浏览界面\u003c/a\u003e中已经解决过了，就是用一个控制变量mEvents过滤掉pointer down或up后到来的第一个move事件。\u003c/p\u003e\n\u003cp\u003e解决难点3 采用adapter方式设置页面的布局和数据。这个在Android的AdapterView里用到的，但是我没有看它的adapter机制，太复杂了，我就搞了个简单的adapter，如下：\u003c/p\u003e\n\u003cp\u003ePageAdapter.java：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.pagerdemo;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PageAdapter\n\n- {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @return 页面view\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; View getView();\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount();\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 将内容添加到view中\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param view\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     *            包含内容的view\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * @param position\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     *            第position页\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; addContent(View view, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position);\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e这是一个抽象类，getView()用于返回页面的布局，getCount()返回数据总共需要多少页，addContent(View view, int position)这个是每翻过一页后将会被调用来请求页面数据的，参数view就是页面，position是表明第几页。待会儿会在自定义布局中定义setAdapter方法设置设配器。\u003c/p\u003e","title":"Android自定义控件实战——仿多看阅读平移翻页"},{"content":"转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/38556891\n水流波动的波形都是三角波，曲线是正余弦曲线，但是Android中没有提供绘制正余弦曲线的API，好在Path类有个绘制贝塞尔曲线的方法quadTo，绘制出来的是2阶的贝塞尔曲线，要想实现波动效果，只能用它来绘制Path曲线。待会儿再讲解2阶的贝塞尔曲线是怎么回事，先来看实现的效果：\n这个波长比较短，还看不到起伏，只是荡漾，把波长拉长再看一下：\n已经可以看到起伏很明显了，再拉长看一下：\n这个的起伏感就比较强了。利用这个波动效果，可以用在绘制水位线的时候使用到，还可以做一个波动的进度条WaveUpProgress，比如这样：\n是不是很动感？\n那这样的波动效果是怎么做的呢？前面讲到的贝塞尔曲线到底是什么呢？下面一一讲解。想要用好贝塞尔曲线就得先理解它的表达式，为了形象描述，我从网上盗了些动图。\n首先看1阶贝塞尔曲线的表达式：\n随着t的变化，它实际是一条P0到P1的直线段：\nAndroid中Path的quadTo是3点的2阶贝塞尔曲线，那么2阶的表达式是这样的：\n看起来很复杂，我把它拆分开来看：\n然后再合并成这样：\n看到什么了吧？如果看不出来再替换成这样：\nB0和B1分别是P0到P1和P1到P2的1阶贝塞尔曲线。而2阶贝塞尔曲线B就是B0到B1的1阶贝塞尔曲线。显然，它的动态图表示出来就不难理解了：\n红色点的运动轨迹就是B的轨迹，这就是2阶贝塞尔曲线了。当P1位于P0和P2的垂直平分线上时，B就是开口向上或向下的抛物线了。而在WaveView中就是用的开口向上和向下的抛物线模拟水波。在Android里用Path的方法，首先path.moveTo(P0)，然后path.quadTo(P1, P2)，canvas.drawPath(path, paint)曲线就出来了，如果想要绘制多个贝塞尔曲线就不断的quadTo吧。\n讲完贝塞尔曲线后就要开始讲水波动的效果是怎么来的了，首先要理解，机械波的传输就是通过介质的震动把波形往传输方向平移，每震动一个周期波形刚好平移一个波长，所有介质点又回到一个周期前的状态。所以要实现水波动效果只需要把波形平移就可以了。\n那么WaveView的实现原理是这样的：\n首先在View上根据View宽计算可以容纳几个完整波形，不够一个的算一个，然后在View的不可见处预留一个完整的波形；然后波动开始的时候将所有点同时在x方向上移动相同的距离，这样隐藏的波形就会被平移出来，当平移距离达到一个波长时，这时候将所有点的x坐标又恢复到平移前的值，这样就可以一个波形一个波形地往外传输。用草图表示如下：\nWaveView的原理在上图很直观的看出来了，P[2n+1]，n\u0026gt;=0都是贝塞尔曲线的控制点，红线为水位线。\n知道原理以后可以看代码了：\nWaveView.java：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38556891#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38556891#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.waveview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Timer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.TimerTask; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Color; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint.Align; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint.Style; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Region.Op; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Path; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.RectF; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 水流波动控件\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author chenjing\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; WaveView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; View - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mViewWidth; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mViewHeight; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 水位线\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mLevelLine; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 波浪起伏幅度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mWaveHeight = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;80\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 波长\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mWaveWidth = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 被隐藏的最左边的波形\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mLeftSide; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mMoveLen; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 水波平移速度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; SPEED = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.7f; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;Point\u0026gt; mPointsList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Paint mPaint; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Paint mTextPaint; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Path mWavePath; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isMeasured = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Timer timer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTimerTask mTask; - Handler updateHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 记录平移总位移\u0026lt;/span\u0026gt; - mMoveLen += SPEED; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 水位上升\u0026lt;/span\u0026gt; - mLevelLine -= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.1f; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mLevelLine \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - mLevelLine = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - mLeftSide += SPEED; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 波形平移\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; mPointsList.size(); i++) - { - mPointsList.get(i).setX(mPointsList.get(i).getX() + SPEED); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (i % \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;: - mPointsList.get(i).setY(mLevelLine); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;: - mPointsList.get(i).setY(mLevelLine + mWaveHeight); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;: - mPointsList.get(i).setY(mLevelLine \u0026amp;#8211; mWaveHeight); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026gt;= mWaveWidth) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 波形平移超过一个完整波形后复位\u0026lt;/span\u0026gt; - mMoveLen = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - resetPoints(); - } - invalidate(); - } - - }; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 所有点的x坐标都还原到初始状态，也就是一个周期前的状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; resetPoints() - { - mLeftSide = -mWaveWidth; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; mPointsList.size(); i++) - { - mPointsList.get(i).setX(i * mWaveWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt; \u0026amp;#8211; mWaveWidth); - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; WaveView(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - init(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; WaveView(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - init(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; WaveView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - init(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; init() - { - mPointsList = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;Point\u0026gt;(); - timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Timer(); - - mPaint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(); - mPaint.setAntiAlias(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - mPaint.setStyle(Style.FILL); - mPaint.setColor(Color.BLUE); - - mTextPaint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(); - mTextPaint.setColor(Color.WHITE); - mTextPaint.setTextAlign(Align.CENTER); - mTextPaint.setTextSize(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;30\u0026lt;/span\u0026gt;); - - mWavePath = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Path(); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onWindowFocusChanged(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; hasWindowFocus) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onWindowFocusChanged(hasWindowFocus); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 开始波动\u0026lt;/span\u0026gt; - start(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; start() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - { - mTask.cancel(); - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTimerTask(updateHandler); - timer.schedule(mTask, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMeasure(widthMeasureSpec, heightMeasureSpec); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isMeasured) - { - isMeasured = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - mViewHeight = getMeasuredHeight(); - mViewWidth = getMeasuredWidth(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 水位线从最底下开始上升\u0026lt;/span\u0026gt; - mLevelLine = mViewHeight; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 根据View宽度计算波形峰值\u0026lt;/span\u0026gt; - mWaveHeight = mViewWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;.5f; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 波长等于四倍View宽度也就是View中只能看到四分之一个波形，这样可以使起伏更明显\u0026lt;/span\u0026gt; - mWaveWidth = mViewWidth * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 左边隐藏的距离预留一个波形\u0026lt;/span\u0026gt; - mLeftSide = -mWaveWidth; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这里计算在可见的View宽度中能容纳几个波形，注意n上取整\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; n = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) Math.round(mViewWidth / mWaveWidth + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0.5\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// n个波形需要4n+1个点，但是我们要预留一个波形在左边隐藏区域，所以需要4n+5个点\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt; * n + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;); i++) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 从P0开始初始化到P4n+4，总共4n+5个点\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x = i * mWaveWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt; \u0026amp;#8211; mWaveWidth; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (i % \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 零点位于水位线上\u0026lt;/span\u0026gt; - y = mLevelLine; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 往下波动的控制点\u0026lt;/span\u0026gt; - y = mLevelLine + mWaveHeight; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 往上波动的控制点\u0026lt;/span\u0026gt; - y = mLevelLine \u0026amp;#8211; mWaveHeight; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - mPointsList.add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Point(x, y)); - } - } - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) - { - - mWavePath.reset(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - mWavePath.moveTo(mPointsList.get(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getX(), mPointsList.get(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getY()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (; i \u0026lt; mPointsList.size() \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; i = i + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;) - { - mWavePath.quadTo(mPointsList.get(i + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;).getX(), - mPointsList.get(i + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;).getY(), mPointsList.get(i + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;) - .getX(), mPointsList.get(i + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;).getY()); - } - mWavePath.lineTo(mPointsList.get(i).getX(), mViewHeight); - mWavePath.lineTo(mLeftSide, mViewHeight); - mWavePath.close(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// mPaint的Style是FILL，会填充整个Path区域\u0026lt;/span\u0026gt; - canvas.drawPath(mWavePath, mPaint); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 绘制百分比\u0026lt;/span\u0026gt; - canvas.drawText(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt; + ((\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) ((\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; \u0026amp;#8211; mLevelLine / mViewHeight) * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;)) - + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;%\u0026amp;#8221;\u0026lt;/span\u0026gt;, mViewWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, mLevelLine + mWaveHeight - + (mViewHeight \u0026amp;#8211; mLevelLine \u0026amp;#8211; mWaveHeight) / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, mTextPaint); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTimerTask \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; TimerTask - { - Handler handler; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTimerTask(Handler handler) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() - { - handler.sendMessage(handler.obtainMessage()); - } - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; Point - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; getX() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; x; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setX(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.x = x; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; getY() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; y; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setY(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.y = y; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Point(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.x = x; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.y = y; - } - - } - - } 代码中注释写的很多，不难看懂。\nDemo的布局：\n**[html]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38556891#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38556891#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#000000\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.jingchen.waveview.WaveView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;100dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#ffffff\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerInParent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; MainActivity的代码：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38556891#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38556891#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.waveview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Menu; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onCreateOptionsMenu(Menu menu) - { - getMenuInflater().inflate(R.menu.main, menu); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - } 代码量很少。这样就可以很简单的做出水波效果啦~\n源码下载\n","permalink":"https://blog.zdltech.com/posts/android%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6%E5%AE%9E%E6%88%98-%E6%B0%B4%E6%B5%81%E6%B3%A2%E5%8A%A8%E6%95%88%E6%9E%9C%E7%9A%84%E5%AE%9E%E7%8E%B0waveview/","summary":"\u003cp\u003e转载请声明出处\u003ca href=\"http://blog.csdn.net/zhongkejingwang/article/details/38556891\"\u003ehttp://blog.csdn.net/zhongkejingwang/article/details/38556891\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e水流波动的波形都是三角波，曲线是正余弦曲线，但是Android中没有提供绘制正余弦曲线的API，好在Path类有个绘制贝塞尔曲线的方法quadTo，绘制出来的是2阶的贝塞尔曲线，要想实现波动效果，只能用它来绘制Path曲线。待会儿再讲解2阶的贝塞尔曲线是怎么回事，先来看实现的效果：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814123448732?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e这个波长比较短，还看不到起伏，只是荡漾，把波长拉长再看一下：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814123613206?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e已经可以看到起伏很明显了，再拉长看一下：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814123526843?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e这个的起伏感就比较强了。利用这个波动效果，可以用在绘制水位线的时候使用到，还可以做一个波动的进度条WaveUpProgress，比如这样：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814123825609?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e是不是很动感？\u003c/p\u003e\n\u003cp\u003e那这样的波动效果是怎么做的呢？前面讲到的贝塞尔曲线到底是什么呢？下面一一讲解。想要用好贝塞尔曲线就得先理解它的表达式，为了形象描述，我从网上盗了些动图。\u003c/p\u003e\n\u003cp\u003e首先看1阶贝塞尔曲线的表达式：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814130656771\"\u003e\u003c/p\u003e\n\u003cp\u003e随着t的变化，它实际是一条P0到P1的直线段：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814130802728\"\u003e\u003c/p\u003e\n\u003cp\u003eAndroid中Path的quadTo是3点的2阶贝塞尔曲线，那么2阶的表达式是这样的：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814130738218\"\u003e\u003c/p\u003e\n\u003cp\u003e看起来很复杂，我把它拆分开来看：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814130856750\"\u003e\u003c/p\u003e\n\u003cp\u003e然后再合并成这样：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814131350062\"\u003e\u003c/p\u003e\n\u003cp\u003e看到什么了吧？如果看不出来再替换成这样：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814131156213\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814131503757\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814131315015\"\u003e\u003c/p\u003e\n\u003cp\u003eB0和B1分别是P0到P1和P1到P2的1阶贝塞尔曲线。而2阶贝塞尔曲线B就是B0到B1的1阶贝塞尔曲线。显然，它的动态图表示出来就不难理解了：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814131810021\"\u003e\u003c/p\u003e\n\u003cp\u003e红色点的运动轨迹就是B的轨迹，这就是2阶贝塞尔曲线了。当P1位于P0和P2的垂直平分线上时，B就是开口向上或向下的抛物线了。而在WaveView中就是用的开口向上和向下的抛物线模拟水波。在Android里用Path的方法，首先path.moveTo(P0)，然后path.quadTo(P1, P2)，canvas.drawPath(path, paint)曲线就出来了，如果想要绘制多个贝塞尔曲线就不断的quadTo吧。\u003c/p\u003e\n\u003cp\u003e讲完贝塞尔曲线后就要开始讲水波动的效果是怎么来的了，首先要理解，机械波的传输就是通过介质的震动把波形往传输方向平移，每震动一个周期波形刚好平移一个波长，所有介质点又回到一个周期前的状态。所以要实现水波动效果只需要把波形平移就可以了。\u003c/p\u003e\n\u003cp\u003e那么WaveView的实现原理是这样的：\u003c/p\u003e\n\u003cp\u003e首先在View上根据View宽计算可以容纳几个完整波形，不够一个的算一个，然后在View的不可见处预留一个完整的波形；然后波动开始的时候将所有点同时在x方向上移动相同的距离，这样隐藏的波形就会被平移出来，当平移距离达到一个波长时，这时候将所有点的x坐标又恢复到平移前的值，这样就可以一个波形一个波形地往外传输。用草图表示如下：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140814140553375?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eWaveView的原理在上图很直观的看出来了，P[2n+1]，n\u0026gt;=0都是贝塞尔曲线的控制点，红线为水位线。\u003c/p\u003e\n\u003cp\u003e知道原理以后可以看代码了：\u003c/p\u003e\n\u003cp\u003eWaveView.java：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38556891#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38556891#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.waveview;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Timer;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.TimerTask;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Color;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint.Align;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint.Style;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Region.Op;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Path;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.RectF;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 水流波动控件\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author chenjing\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; WaveView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; View\n\n- {\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mViewWidth;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mViewHeight;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 水位线\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mLevelLine;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 波浪起伏幅度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mWaveHeight = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;80\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 波长\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mWaveWidth = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;200\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 被隐藏的最左边的波形\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mLeftSide;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mMoveLen;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 水波平移速度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; SPEED = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.7f;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;Point\u0026gt; mPointsList;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Paint mPaint;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Paint mTextPaint;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Path mWavePath;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isMeasured = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Timer timer;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTimerTask mTask;\n\n- Handler updateHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler()\n\n- {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg)\n\n- {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 记录平移总位移\u0026lt;/span\u0026gt;\n\n- mMoveLen += SPEED;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 水位上升\u0026lt;/span\u0026gt;\n\n- mLevelLine -= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.1f;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mLevelLine \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n\n- mLevelLine = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- mLeftSide += SPEED;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 波形平移\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; mPointsList.size(); i++)\n\n- {\n\n- mPointsList.get(i).setX(mPointsList.get(i).getX() + SPEED);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (i % \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;:\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;:\n\n- mPointsList.get(i).setY(mLevelLine);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;:\n\n- mPointsList.get(i).setY(mLevelLine + mWaveHeight);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;:\n\n- mPointsList.get(i).setY(mLevelLine \u0026amp;#8211; mWaveHeight);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- }\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026gt;= mWaveWidth)\n\n- {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 波形平移超过一个完整波形后复位\u0026lt;/span\u0026gt;\n\n- mMoveLen = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- resetPoints();\n\n- }\n\n- invalidate();\n\n- }\n\n- \n- };\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 所有点的x坐标都还原到初始状态，也就是一个周期前的状态\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; resetPoints()\n\n- {\n\n- mLeftSide = -mWaveWidth;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; mPointsList.size(); i++)\n\n- {\n\n- mPointsList.get(i).setX(i * mWaveWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt; \u0026amp;#8211; mWaveWidth);\n\n- }\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; WaveView(Context context)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context);\n\n- init();\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; WaveView(Context context, AttributeSet attrs)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);\n\n- init();\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; WaveView(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle);\n\n- init();\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; init()\n\n- {\n\n- mPointsList = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;Point\u0026gt;();\n\n- timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Timer();\n\n- \n- mPaint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint();\n\n- mPaint.setAntiAlias(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\n\n- mPaint.setStyle(Style.FILL);\n\n- mPaint.setColor(Color.BLUE);\n\n- \n- mTextPaint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint();\n\n- mTextPaint.setColor(Color.WHITE);\n\n- mTextPaint.setTextAlign(Align.CENTER);\n\n- mTextPaint.setTextSize(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;30\u0026lt;/span\u0026gt;);\n\n- \n- mWavePath = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Path();\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onWindowFocusChanged(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; hasWindowFocus)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onWindowFocusChanged(hasWindowFocus);\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 开始波动\u0026lt;/span\u0026gt;\n\n- start();\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; start()\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)\n\n- {\n\n- mTask.cancel();\n\n- mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n- }\n\n- mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTimerTask(updateHandler);\n\n- timer.schedule(mTask, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isMeasured)\n\n- {\n\n- isMeasured = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- mViewHeight = getMeasuredHeight();\n\n- mViewWidth = getMeasuredWidth();\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 水位线从最底下开始上升\u0026lt;/span\u0026gt;\n\n- mLevelLine = mViewHeight;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 根据View宽度计算波形峰值\u0026lt;/span\u0026gt;\n\n- mWaveHeight = mViewWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;.5f;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 波长等于四倍View宽度也就是View中只能看到四分之一个波形，这样可以使起伏更明显\u0026lt;/span\u0026gt;\n\n- mWaveWidth = mViewWidth * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 左边隐藏的距离预留一个波形\u0026lt;/span\u0026gt;\n\n- mLeftSide = -mWaveWidth;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 这里计算在可见的View宽度中能容纳几个波形，注意n上取整\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; n = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) Math.round(mViewWidth / mWaveWidth + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0.5\u0026lt;/span\u0026gt;);\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// n个波形需要4n+1个点，但是我们要预留一个波形在左边隐藏区域，所以需要4n+5个点\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt; * n + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;); i++)\n\n- {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 从P0开始初始化到P4n+4，总共4n+5个点\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x = i * mWaveWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt; \u0026amp;#8211; mWaveWidth;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (i % \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;:\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;:\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 零点位于水位线上\u0026lt;/span\u0026gt;\n\n- y = mLevelLine;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;:\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 往下波动的控制点\u0026lt;/span\u0026gt;\n\n- y = mLevelLine + mWaveHeight;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;:\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 往上波动的控制点\u0026lt;/span\u0026gt;\n\n- y = mLevelLine \u0026amp;#8211; mWaveHeight;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- }\n\n- mPointsList.add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Point(x, y));\n\n- }\n\n- }\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas)\n\n- {\n\n- \n- mWavePath.reset();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- mWavePath.moveTo(mPointsList.get(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getX(), mPointsList.get(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getY());\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (; i \u0026lt; mPointsList.size() \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; i = i + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;)\n\n- {\n\n- mWavePath.quadTo(mPointsList.get(i + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;).getX(),\n\n- mPointsList.get(i + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;).getY(), mPointsList.get(i + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;)\n\n- .getX(), mPointsList.get(i + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;).getY());\n\n- }\n\n- mWavePath.lineTo(mPointsList.get(i).getX(), mViewHeight);\n\n- mWavePath.lineTo(mLeftSide, mViewHeight);\n\n- mWavePath.close();\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// mPaint的Style是FILL，会填充整个Path区域\u0026lt;/span\u0026gt;\n\n- canvas.drawPath(mWavePath, mPaint);\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 绘制百分比\u0026lt;/span\u0026gt;\n\n- canvas.drawText(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt; + ((\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) ((\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; \u0026amp;#8211; mLevelLine / mViewHeight) * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;))\n\n- + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;%\u0026amp;#8221;\u0026lt;/span\u0026gt;, mViewWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, mLevelLine + mWaveHeight\n\n- + (mViewHeight \u0026amp;#8211; mLevelLine \u0026amp;#8211; mWaveHeight) / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, mTextPaint);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTimerTask \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; TimerTask\n\n- {\n\n- Handler handler;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTimerTask(Handler handler)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run()\n\n- {\n\n- handler.sendMessage(handler.obtainMessage());\n\n- }\n\n- \n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; Point\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; getX()\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; x;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setX(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.x = x;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; getY()\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; y;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setY(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.y = y;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Point(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.x = x;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.y = y;\n\n- }\n\n- \n- }\n\n- \n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e代码中注释写的很多，不难看懂。\u003c/p\u003e","title":"Android自定义控件实战——水流波动效果的实现WaveView"},{"content":"转载出处http://blog.csdn.net/zhongkejingwang/article/details/38656929\n用手机淘宝浏览商品详情时，商品图片是放在后面的，在第一个ScrollView滚动到最底下时会有提示，继续拖动才能浏览图片。仿照这个效果写一个出来并不难，只要定义一个Layout管理两个ScrollView就行了，当第一个ScrollView滑到底部时，再次向上滑动进入第二个ScrollView。效果如下：\n需要注意的地方是：\n1、如果是手动滑到底部需要再次按下才能继续往下滑，自动滚动到底部则不需要\n2、在由上一个ScrollView滑动到下一个ScrollView的过程中多只手指相继拖动也不会导致布局的剧变，也就是多个pointer的滑动不会导致move距离的剧变。\n这个Layout的实现思路是：\n在布局中放置两个ScrollView，并为其设置OnTouchListener，时刻判断ScrollView的滚动距离，一旦第一个ScrollView滚动到底部，则标识改为可向上拖动，此时开始记录滑动距离mMoveLen，根据mMoveLen重新layout两个ScrollView；同理，监听第二个ScrollView是否滚动到顶部，以往下拖动。\nOK，明白了原理之后可以看代码了：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38656929#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38656929#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.tbviewer; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Timer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.TimerTask; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.VelocityTracker; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.RelativeLayout; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ScrollView; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 包含两个ScrollView的容器\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author chenjing\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ScrollViewContainer \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; RelativeLayout { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 自动上滑\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; AUTO_UP = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 自动下滑\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; AUTO_DOWN = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 动画完成\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; DONE = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 动画速度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; SPEED = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;6\u0026lt;/span\u0026gt;.5f; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isMeasured = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 用于计算手滑动的速度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; VelocityTracker vt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mViewHeight; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mViewWidth; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View topView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View bottomView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; state = DONE; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 记录当前展示的是哪个view，0是topView，1是bottomView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 手滑动距离，这个是控制布局的主要变量\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mMoveLen; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTimer mTimer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mLastY; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 用于控制是否变动布局的另一个条件，mEvents==0时布局可以拖拽了，mEvents==-1时可以舍弃将要到来的第一个move事件，\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 这点是去除多点拖动剧变的关键\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mEvents; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen != \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == AUTO_UP) { - mMoveLen -= SPEED; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026lt;= -mViewHeight) { - mMoveLen = -mViewHeight; - state = DONE; - mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == AUTO_DOWN) { - mMoveLen += SPEED; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - mMoveLen = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - state = DONE; - mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - mTimer.cancel(); - } - } - requestLayout(); - } - - }; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ScrollViewContainer(Context context) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); - init(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ScrollViewContainer(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - init(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ScrollViewContainer(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - init(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; init() { - mTimer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTimer(handler); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (ev.getActionMasked()) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (vt == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) - vt = VelocityTracker.obtain(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - vt.clear(); - mLastY = ev.getY(); - vt.addMovement(ev); - mEvents = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_DOWN: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_UP: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 多一只手指按下或抬起时舍弃将要到来的第一个事件move，防止多点拖拽的bug\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE: - vt.addMovement(ev); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (canPullUp \u0026amp;\u0026amp; mCurrentViewIndex == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mEvents == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止上下越界\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - mMoveLen = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026lt; -mViewHeight) { - mMoveLen = -mViewHeight; - mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止事件冲突\u0026lt;/span\u0026gt; - ev.setAction(MotionEvent.ACTION_CANCEL); - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (canPullDown \u0026amp;\u0026amp; mCurrentViewIndex == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mEvents == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止上下越界\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026lt; -mViewHeight) { - mMoveLen = -mViewHeight; - mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - mMoveLen = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止事件冲突\u0026lt;/span\u0026gt; - ev.setAction(MotionEvent.ACTION_CANCEL); - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - mEvents++; - mLastY = ev.getY(); - requestLayout(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - mLastY = ev.getY(); - vt.addMovement(ev); - vt.computeCurrentVelocity(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;700\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获取Y方向的速度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mYV = vt.getYVelocity(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; || mMoveLen == -mViewHeight) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (Math.abs(mYV) \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 速度小于一定值的时候当作静止释放，这时候两个View往哪移动取决于滑动的距离\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026lt;= -mViewHeight / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;) { - state = AUTO_UP; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026gt; -mViewHeight / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;) { - state = AUTO_DOWN; - } - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 抬起手指时速度方向决定两个View往哪移动\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mYV \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - state = AUTO_UP; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - state = AUTO_DOWN; - } - mTimer.schedule(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - vt.recycle(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) { - e.printStackTrace(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(ev); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b) { - topView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) mMoveLen, mViewWidth, - topView.getMeasuredHeight() + (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) mMoveLen); - bottomView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, topView.getMeasuredHeight() + (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) mMoveLen, - mViewWidth, topView.getMeasuredHeight() + (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) mMoveLen - + bottomView.getMeasuredHeight()); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMeasure(widthMeasureSpec, heightMeasureSpec); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isMeasured) { - isMeasured = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - - mViewHeight = getMeasuredHeight(); - mViewWidth = getMeasuredWidth(); - - topView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - bottomView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - - bottomView.setOnTouchListener(bottomViewTouchListener); - topView.setOnTouchListener(topViewTouchListener); - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnTouchListener topViewTouchListener = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnTouchListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) { - ScrollView sv = (ScrollView) v; - .getMeasuredHeight()) \u0026amp;\u0026amp; mCurrentViewIndex == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - }; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnTouchListener bottomViewTouchListener = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnTouchListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) { - ScrollView sv = (ScrollView) v; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (sv.getScrollY() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mCurrentViewIndex == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - }; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTimer { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Timer timer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTask mTask; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTimer(Handler handler) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler; - timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Timer(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; schedule(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; period) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mTask.cancel(); - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTask(handler); - timer.schedule(mTask, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, period); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; cancel() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mTask.cancel(); - mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTask \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; TimerTask { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTask(Handler handler) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - handler.obtainMessage().sendToTarget(); - } - - } - } - - } 注释写的很清楚了，有几个关键点需要讲一下：\n1、由于这里为两个ScrollView设置了OnTouchListener，所以在其他地方不能再设置了，否则就白搭了。\n2、两个ScrollView的layout参数统一由mMoveLen决定。\n3、变量mEvents有两个作用：一是防止手动滑到底部或顶部时继续滑动而改变布局，必须再次按下才能继续滑动；二是在新的pointer down或up时把mEvents设置成-1可以舍弃将要到来的第一个move事件，防止mMoveLen出现剧变。为什么会出现剧变呢？因为假设一开始只有一只手指在滑动，记录的坐标值是这个pointer的事件坐标点，这时候另一只手指按下了导致事件又多了一个pointer，这时候到来的move事件的坐标可能就变成了新的pointer的坐标，这时计算与上一次坐标的差值就会出现剧变，变化的距离就是两个pointer间的距离。所以要把这个move事件舍弃掉，让mLastY值记录这个pointer的坐标再开始计算mMoveLen。pointer up的时候也一样。\n理解了这几点，看起来就没什么难度了，代码量也很小。\nMainActivity的布局：\n**[html]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38656929#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38656929#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.jingchen.tbviewer.ScrollViewContainer\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ScrollView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/imagesLayout\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/h\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/i\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/j\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/k\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/l\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/m\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;60dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_below\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/imagesLayout\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#eeeeee\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;继续拖动，查看更多美女\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20sp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ScrollView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ScrollView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#000000\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/a\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/b\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/c\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/d\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/e\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/f\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/g\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ScrollView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.jingchen.tbviewer.ScrollViewContainer\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 在ScrollView中放了几张图片而已。\nMainActivity的代码：\n**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38656929#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38656929#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.tbviewer; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Menu; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity - { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onCreateOptionsMenu(Menu menu) - { - getMenuInflater().inflate(R.menu.main, menu); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - } 啥也没有……\n好了，到此结束~\n源码下载\n","permalink":"https://blog.zdltech.com/posts/android%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6%E5%AE%9E%E6%88%98-%E4%BB%BF%E6%B7%98%E5%AE%9D%E5%95%86%E5%93%81%E6%B5%8F%E8%A7%88%E7%95%8C%E9%9D%A2/","summary":"\u003cp\u003e转载出处\u003ca href=\"http://blog.csdn.net/zhongkejingwang/article/details/38656929\"\u003ehttp://blog.csdn.net/zhongkejingwang/article/details/38656929\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e用手机淘宝浏览商品详情时，商品图片是放在后面的，在第一个ScrollView滚动到最底下时会有提示，继续拖动才能浏览图片。仿照这个效果写一个出来并不难，只要定义一个Layout管理两个ScrollView就行了，当第一个ScrollView滑到底部时，再次向上滑动进入第二个ScrollView。效果如下：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140818121207234?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhvbmdrZWppbmd3YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e需要注意的地方是：\u003c/p\u003e\n\u003cp\u003e1、如果是手动滑到底部需要再次按下才能继续往下滑，自动滚动到底部则不需要\u003c/p\u003e\n\u003cp\u003e2、在由上一个ScrollView滑动到下一个ScrollView的过程中多只手指相继拖动也不会导致布局的剧变，也就是多个pointer的滑动不会导致move距离的剧变。\u003c/p\u003e\n\u003cp\u003e这个Layout的实现思路是：\u003c/p\u003e\n\u003cp\u003e在布局中放置两个ScrollView，并为其设置OnTouchListener，时刻判断ScrollView的滚动距离，一旦第一个ScrollView滚动到底部，则标识改为可向上拖动，此时开始记录滑动距离mMoveLen，根据mMoveLen重新layout两个ScrollView；同理，监听第二个ScrollView是否滚动到顶部，以往下拖动。\u003c/p\u003e\n\u003cp\u003eOK，明白了原理之后可以看代码了：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38656929#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38656929#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.jingchen.tbviewer;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Timer;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.TimerTask;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.VelocityTracker;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.RelativeLayout;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ScrollView;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 包含两个ScrollView的容器\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author chenjing\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ScrollViewContainer \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; RelativeLayout {\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 自动上滑\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; AUTO_UP = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 自动下滑\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; AUTO_DOWN = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 动画完成\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; DONE = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 动画速度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; SPEED = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;6\u0026lt;/span\u0026gt;.5f;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isMeasured = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 用于计算手滑动的速度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; VelocityTracker vt;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mViewHeight;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mViewWidth;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View topView;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; View bottomView;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullDown;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; canPullUp;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; state = DONE;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 记录当前展示的是哪个view，0是topView，1是bottomView\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 手滑动距离，这个是控制布局的主要变量\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mMoveLen;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTimer mTimer;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mLastY;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 用于控制是否变动布局的另一个条件，mEvents==0时布局可以拖拽了，mEvents==-1时可以舍弃将要到来的第一个move事件，\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 这点是去除多点拖动剧变的关键\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mEvents;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen != \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == AUTO_UP) {\n\n- mMoveLen -= SPEED;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026lt;= -mViewHeight) {\n\n- mMoveLen = -mViewHeight;\n\n- state = DONE;\n\n- mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n\n- }\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (state == AUTO_DOWN) {\n\n- mMoveLen += SPEED;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {\n\n- mMoveLen = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- state = DONE;\n\n- mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- }\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n\n- mTimer.cancel();\n\n- }\n\n- }\n\n- requestLayout();\n\n- }\n\n- \n- };\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ScrollViewContainer(Context context) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context);\n\n- init();\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ScrollViewContainer(Context context, AttributeSet attrs) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);\n\n- init();\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ScrollViewContainer(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle);\n\n- init();\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; init() {\n\n- mTimer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTimer(handler);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (ev.getActionMasked()) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_DOWN:\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (vt == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)\n\n- vt = VelocityTracker.obtain();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n\n- vt.clear();\n\n- mLastY = ev.getY();\n\n- vt.addMovement(ev);\n\n- mEvents = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_DOWN:\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_POINTER_UP:\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 多一只手指按下或抬起时舍弃将要到来的第一个事件move，防止多点拖拽的bug\u0026lt;/span\u0026gt;\n\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_MOVE:\n\n- vt.addMovement(ev);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (canPullUp \u0026amp;\u0026amp; mCurrentViewIndex == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mEvents == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {\n\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止上下越界\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {\n\n- mMoveLen = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026lt; -mViewHeight) {\n\n- mMoveLen = -mViewHeight;\n\n- mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n\n- \n- }\n\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止事件冲突\u0026lt;/span\u0026gt;\n\n- ev.setAction(MotionEvent.ACTION_CANCEL);\n\n- }\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (canPullDown \u0026amp;\u0026amp; mCurrentViewIndex == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mEvents == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {\n\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止上下越界\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026lt; -mViewHeight) {\n\n- mMoveLen = -mViewHeight;\n\n- mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {\n\n- mMoveLen = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- mCurrentViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- }\n\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 防止事件冲突\u0026lt;/span\u0026gt;\n\n- ev.setAction(MotionEvent.ACTION_CANCEL);\n\n- }\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n\n- mEvents++;\n\n- mLastY = ev.getY();\n\n- requestLayout();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP:\n\n- mLastY = ev.getY();\n\n- vt.addMovement(ev);\n\n- vt.computeCurrentVelocity(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;700\u0026lt;/span\u0026gt;);\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获取Y方向的速度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mYV = vt.getYVelocity();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; || mMoveLen == -mViewHeight)\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (Math.abs(mYV) \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt;) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 速度小于一定值的时候当作静止释放，这时候两个View往哪移动取决于滑动的距离\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026lt;= -mViewHeight / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;) {\n\n- state = AUTO_UP;\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMoveLen \u0026gt; -mViewHeight / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;) {\n\n- state = AUTO_DOWN;\n\n- }\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 抬起手指时速度方向决定两个View往哪移动\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mYV \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n\n- state = AUTO_UP;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n\n- state = AUTO_DOWN;\n\n- }\n\n- mTimer.schedule(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\n- vt.recycle();\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) {\n\n- e.printStackTrace();\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- \n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(ev);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b) {\n\n- topView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) mMoveLen, mViewWidth,\n\n- topView.getMeasuredHeight() + (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) mMoveLen);\n\n- bottomView.layout(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, topView.getMeasuredHeight() + (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) mMoveLen,\n\n- mViewWidth, topView.getMeasuredHeight() + (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) mMoveLen\n\n- + bottomView.getMeasuredHeight());\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!isMeasured) {\n\n- isMeasured = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- \n- mViewHeight = getMeasuredHeight();\n\n- mViewWidth = getMeasuredWidth();\n\n- \n- topView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- bottomView = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);\n\n- \n- bottomView.setOnTouchListener(bottomViewTouchListener);\n\n- topView.setOnTouchListener(topViewTouchListener);\n\n- }\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnTouchListener topViewTouchListener = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnTouchListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) {\n\n- ScrollView sv = (ScrollView) v;\n\n\n- .getMeasuredHeight()) \u0026amp;\u0026amp; mCurrentViewIndex == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)\n\n- canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n\n- canPullUp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- };\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnTouchListener bottomViewTouchListener = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnTouchListener() {\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) {\n\n- ScrollView sv = (ScrollView) v;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (sv.getScrollY() == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mCurrentViewIndex == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;)\n\n- canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n\n- canPullDown = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- };\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTimer {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Timer timer;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyTask mTask;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTimer(Handler handler) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler;\n\n- timer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Timer();\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; schedule(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; period) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n\n- mTask.cancel();\n\n- mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n- }\n\n- mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyTask(handler);\n\n- timer.schedule(mTask, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, period);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; cancel() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTask != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n\n- mTask.cancel();\n\n- mTask = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n- }\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyTask \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; TimerTask {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler handler;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyTask(Handler handler) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.handler = handler;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() {\n\n- handler.obtainMessage().sendToTarget();\n\n- }\n\n- \n- }\n\n- }\n\n- \n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e注释写的很清楚了，有几个关键点需要讲一下：\u003c/p\u003e","title":"Android自定义控件实战——仿淘宝商品浏览界面"},{"content":" 滑动置顶标题在QQ中的好友列表、Android的通讯录中可以见到，用户在滑动的时候可以随时看到当前的内容的标题。 这个效果的实现，思路是在Android的Listview的顶部动态的生成一个与标题等高等宽的View，并且实时监听Listview滑动的状态，当Listview滑动到第一项和第二项的标题不一致的时候，动态的重画View，让它有一种向上滑动的效果，当完全滑出以后再重画生成新的标题。\n\u0026amp;nbsp; 话不多说，上干货 - 下载：http://www.etongwl.com/images/2015/03/b69c13c0-75c3-3160-97c8-8691ddfe9501.zip 转自：http://ygydaiaq-gmail-com.iteye.com/blog/1778844 ","permalink":"https://blog.zdltech.com/posts/%E6%8E%A2%E7%B4%A2android-%E6%BB%91%E5%8A%A8%E7%BD%AE%E9%A1%B6%E6%A0%87%E9%A2%98%E7%9A%84%E5%AE%9E%E7%8E%B0/","summary":"\u003cdiv id=\"blog_content\" class=\"blog_content\"\u003e\n  \u003cdiv class=\"iteye-blog-content-contain\"\u003e\n\u003cpre\u003e\u003ccode\u003e  滑动置顶标题在QQ中的好友列表、Android的通讯录中可以见到，用户在滑动的时候可以随时看到当前的内容的标题。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://dl.iteye.com/upload/attachment/0079/9992/9ff401f9-1e96-3d01-9989-07a70e4a7b53.png\"\u003e\n这个效果的实现，思路是在Android的Listview的顶部动态的生成一个与标题等高等宽的View，并且实时监听Listview滑动的状态，当Listview滑动到第一项和第二项的标题不一致的时候，动态的重画View，让它有一种向上滑动的效果，当完全滑出以后再重画生成新的标题。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026amp;nbsp;\n\n\n\n\n\n  话不多说，上干货\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"attachments\"\u003e\n\u003cpre\u003e\u003ccode\u003e- 下载：http://www.etongwl.com/images/2015/03/b69c13c0-75c3-3160-97c8-8691ddfe9501.zip\n\n\n\n\n\n转自：http://ygydaiaq-gmail-com.iteye.com/blog/1778844\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"探索Android 滑动置顶标题的实现"},{"content":"GLSurfaceView是 OpenGL中的一个类，也是可以预览Camera的，而且在预览Camera上有其独到之处。独到之处在哪？当使用Surfaceview无能为力、痛 不欲生时就只有使用GLSurfaceView了，它能够真正做到让Camera的数据和显示分离，所以搞明白了这个，像Camera只开预览不显示这都 是小菜，妥妥的。Android4.0的自带Camera源码是用SurfaceView预览的，但到了4.2就换成了GLSurfaceView来预 览。如今到了4.4又用了自家的TextureView，所以从中可以窥探出新增TextureView的用意。\n虽 说Android4.2的Camera源码是用GLSurfaceView预览的，但是进行了大量的封装又封装的，由于是OpenGL小白，真是看的不知 所云。俺滴要求不高，只想弄个可拍照的摸清GLSurfaceView在预览Camera上的使用流程。经过一番百度一无所获，后来翻出去Google一 大圈也没发现可用的。倒是很多人都在用GLSurfaceView和Surfaceview同时预览Camera，Surfaceview用来预览数据， 在上面又铺了一层GLSurfaceView绘制一些信息。无奈自己摸索，整出来的是能拍照也能得到数据，但是界面上不是一块白板就是一块黑板啥都不显 示。后来在stackoverflow终于找到了一个可用的链接，哈哈，苍天啊，终于柳暗花明了！参考此链接，自己又改改摸索了一天才彻底搞定。之所以费这么多时间是不明白OpenGL ES2.0的绘制基本流程，跟简单的OpenGL的绘制还是稍有区别。下面上源码:\n一、CameraGLSurfaceView.java 此类继承GLSurfaceView，并实现了两个接口\n**[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[copy](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[print](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[?](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/402612)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/402612/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;24\u0026quot; height=\u0026quot;13\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.camera.preview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; javax.microedition.khronos.egl.EGLConfig; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; javax.microedition.khronos.opengles.GL10; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.camera.CameraInterface; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.SurfaceTexture; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLES11Ext; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLES20; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLSurfaceView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLSurfaceView.Renderer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; CameraGLSurfaceView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; GLSurfaceView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Renderer, SurfaceTexture.OnFrameAvailableListener { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;yanzi\u0026amp;#8221;\u0026lt;/span\u0026gt;; - Context mContext; - SurfaceTexture mSurface; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mTextureID = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - DirectDrawer mDirectDrawer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; CameraGLSurfaceView(Context context, AttributeSet attrs) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated constructor stub\u0026lt;/span\u0026gt; - mContext = context; - setEGLContextClientVersion(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); - setRenderer(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - setRenderMode(RENDERMODE_WHEN_DIRTY); - } - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSurfaceCreated(GL10 gl, EGLConfig config) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSurfaceCreated\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); - mTextureID = createTextureID(); - mSurface = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SurfaceTexture(mTextureID); - mSurface.setOnFrameAvailableListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - mDirectDrawer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DirectDrawer(mTextureID); - CameraInterface.getInstance().doOpenCamera(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - - } - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSurfaceChanged(GL10 gl, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSurfaceChanged\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); - GLES20.glViewport(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, width, height); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!CameraInterface.getInstance().isPreviewing()){ - CameraInterface.getInstance().doStartPreview(mSurface, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.33f); - } - - - } - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDrawFrame(GL10 gl) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDrawFrame\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); - GLES20.glClearColor(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f); - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); - mSurface.updateTexImage(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] mtx = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;]; - mSurface.getTransformMatrix(mtx); - mDirectDrawer.draw(mtx); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onPause() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onPause(); - CameraInterface.getInstance().doStopCamera(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; createTextureID() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] texture = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - - GLES20.glGenTextures(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, texture, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]); - GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, - GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR); - GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, - GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); - GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, - GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); - GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, - GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; texture[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SurfaceTexture _getSurfaceTexture(){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mSurface; - } - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onFrameAvailable(SurfaceTexture surfaceTexture) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onFrameAvailable\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.requestRender(); - } - - } - \u0026lt;/span\u0026gt; 关于这个类进行简单说明:\n1、 Renderer这个接口里有三个回调: onSurfaceCreated() onSurfaceChanged() onDrawFrame(), 在onSurfaceCreated里设置了GLSurfaceView的版本: setEGLContextClientVersion(2); 如果没这个设置是啥都画不出来了，因为Android支持OpenGL ES1.1和2.0及最新的3.0，而且版本间差别很大。不告诉他版本他不知道用哪个版本的api渲染。在设置setRenderer(this);后， 再设置它的模式为RENDERMODE_WHEN_DIRTY。这个也很关键，看api：\nWhen renderMode is RENDERMODE_CONTINUOUSLY, the renderer is called repeatedly to re-render the scene. When renderMode is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface is created, or when [requestRender](http://blog.csdn.net/huiguixian/article/details/36900865) is called. Defaults to RENDERMODE_CONTINUOUSLY.\nUsing RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance by allowing the GPU and CPU to idle when the view does not need to be updated.\n大意是 RENDERMODE_CONTINUOUSLY模式就会一直Render，如果设置成RENDERMODE_WHEN_DIRTY，就是当有数据时才 rendered或者主动调用了GLSurfaceView的requestRender.默认是连续模式，很显然Camera适合脏模式，一秒30帧， 当有数据来时再渲染。\n2、 正因是RENDERMODE_WHEN_DIRTY所以就要告诉GLSurfaceView什么时候Render，也就是啥时候进到 onDrawFrame()这个函数里。SurfaceTexture.OnFrameAvailableListener这个接口就干了这么一件事，当 有数据上来后会进到\npublic void onFrameAvailable(SurfaceTexture surfaceTexture) {\n// TODO Auto-generated method stub\nLog.i(TAG, “onFrameAvailable…”);\nthis.requestRender();\n}\n这里，然后执行requestRender()。\n3、网上有一些OpenGL ES的示例是在Activity里实现了SurfaceTexture.OnFrameAvailableListener此接口，其实这个无所谓。无论是被谁实现，关键看在回调里干了什么事。\n4、与TextureView里对比可知，TextureView预览时因为实现了SurfaceTextureListener会自动创建SurfaceTexture。但在GLSurfaceView里则要手动创建同时绑定一个纹理ID。\n5、 本文在onSurfaceCreated()里打开Camera，在onSurfaceChanged()里开启预览，默认1.33的比例。原因是相比前 两种预览，此处SurfaceTexture创建需要一定时间。如果想要开预览时由Activity发起，则要GLSurfaceView利用 Handler将创建的SurfaceTexture传递给Activity。\n二、DirectDrawer.java 此类非常关键，负责将SurfaceTexture内容绘制到屏幕上\n**[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[copy](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[print](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[?](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/402612)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/402612/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;24\u0026quot; height=\u0026quot;13\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.camera.preview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.nio.ByteBuffer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.nio.ByteOrder; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.nio.FloatBuffer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.nio.ShortBuffer; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLES11Ext; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLES20; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.Matrix; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; DirectDrawer { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String vertexShaderCode = - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;attribute vec4 vPosition;\u0026amp;#8221;\u0026lt;/span\u0026gt; + - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;attribute vec2 inputTextureCoordinate;\u0026amp;#8221;\u0026lt;/span\u0026gt; + - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;varying vec2 textureCoordinate;\u0026amp;#8221;\u0026lt;/span\u0026gt; + - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;void main()\u0026amp;#8221;\u0026lt;/span\u0026gt; + - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;{\u0026amp;#8220;\u0026lt;/span\u0026gt;+ - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;gl_Position = vPosition;\u0026amp;#8221;\u0026lt;/span\u0026gt;+ - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;textureCoordinate = inputTextureCoordinate;\u0026amp;#8221;\u0026lt;/span\u0026gt; + - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;}\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String fragmentShaderCode = - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;#extension GL_OES_EGL_image_external : require\\n\u0026amp;#8221;\u0026lt;/span\u0026gt;+ - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;precision mediump float;\u0026amp;#8221;\u0026lt;/span\u0026gt; + - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;varying vec2 textureCoordinate;\\n\u0026amp;#8221;\u0026lt;/span\u0026gt; + - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;uniform samplerExternalOES s_texture;\\n\u0026amp;#8221;\u0026lt;/span\u0026gt; + - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;void main() {\u0026amp;#8220;\u0026lt;/span\u0026gt; + - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8221; gl_FragColor = texture2D( s_texture, textureCoordinate );\\n\u0026amp;#8221;\u0026lt;/span\u0026gt; + - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;}\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; FloatBuffer vertexBuffer, textureVerticesBuffer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ShortBuffer drawListBuffer; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mProgram; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mPositionHandle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mTextureCoordHandle; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;short\u0026lt;/span\u0026gt; drawOrder[] = { \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt; }; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// order to draw vertices\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// number of coordinates per vertex in this array\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; COORDS_PER_VERTEX = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; vertexStride = COORDS_PER_VERTEX * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 4 bytes per vertex\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; squareCoords[] = { - \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, - \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, - }; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; textureVertices[] = { - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0f, - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0f, - }; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; texture; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; DirectDrawer(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; texture) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.texture = texture; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// initialize vertex byte buffer for shape coordinates\u0026lt;/span\u0026gt; - ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;); - bb.order(ByteOrder.nativeOrder()); - vertexBuffer = bb.asFloatBuffer(); - vertexBuffer.put(squareCoords); - vertexBuffer.position(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// initialize byte buffer for the draw list\u0026lt;/span\u0026gt; - ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); - dlb.order(ByteOrder.nativeOrder()); - drawListBuffer = dlb.asShortBuffer(); - drawListBuffer.put(drawOrder); - drawListBuffer.position(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - - ByteBuffer bb2 = ByteBuffer.allocateDirect(textureVertices.length * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;); - bb2.order(ByteOrder.nativeOrder()); - textureVerticesBuffer = bb2.asFloatBuffer(); - textureVerticesBuffer.put(textureVertices); - textureVerticesBuffer.position(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); - - mProgram = GLES20.glCreateProgram(); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// create empty OpenGL ES Program\u0026lt;/span\u0026gt; - GLES20.glAttachShader(mProgram, vertexShader); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// add the vertex shader to program\u0026lt;/span\u0026gt; - GLES20.glAttachShader(mProgram, fragmentShader); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// add the fragment shader to program\u0026lt;/span\u0026gt; - GLES20.glLinkProgram(mProgram); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// creates OpenGL ES program executables\u0026lt;/span\u0026gt; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; draw(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] mtx) - { - GLES20.glUseProgram(mProgram); - - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// get handle to vertex shader\u0026amp;#8217;s vPosition member\u0026lt;/span\u0026gt; - mPositionHandle = GLES20.glGetAttribLocation(mProgram, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;vPosition\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Enable a handle to the triangle vertices\u0026lt;/span\u0026gt; - GLES20.glEnableVertexAttribArray(mPositionHandle); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Prepare the \u0026lt;insert shape here\u0026gt; coordinate data\u0026lt;/span\u0026gt; - GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, vertexStride, vertexBuffer); - - mTextureCoordHandle = GLES20.glGetAttribLocation(mProgram, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;inputTextureCoordinate\u0026amp;#8221;\u0026lt;/span\u0026gt;); - GLES20.glEnableVertexAttribArray(mTextureCoordHandle); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// textureVerticesBuffer.clear();\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// textureVerticesBuffer.put( transformTextureCoordinates( textureVertices, mtx ));\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// textureVerticesBuffer.position(0);\u0026lt;/span\u0026gt; - GLES20.glVertexAttribPointer(mTextureCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, vertexStride, textureVerticesBuffer); - - GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Disable vertex array\u0026lt;/span\u0026gt; - GLES20.glDisableVertexAttribArray(mPositionHandle); - GLES20.glDisableVertexAttribArray(mTextureCoordHandle); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; loadShader(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; type, String shaderCode){ - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// create a vertex shader type (GLES20.GL_VERTEX_SHADER)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; shader = GLES20.glCreateShader(type); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// add the source code to the shader and compile it\u0026lt;/span\u0026gt; - GLES20.glShaderSource(shader, shaderCode); - GLES20.glCompileShader(shader); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; shader; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] transformTextureCoordinates( \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] coords, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] matrix) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] result = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[ coords.length ]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] vt = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;]; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; ( \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; ; i \u0026lt; coords.length ; i += \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; ) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] v = { coords[i], coords[i+\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;], \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; , \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; }; - Matrix.multiplyMV(vt, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, matrix, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, v, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - result[i] = vt[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; - result[i+\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;] = vt[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; result; - } - } - \u0026lt;/span\u0026gt; 三、有了上面两个类就完成95%的工作，可以将GLSurfaceView看成是有生命周期的。在onPause里进行关闭Camera，在Activity里复写两个方法:\n**[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[copy](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[print](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[?](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/402612)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/402612/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;24\u0026quot; height=\u0026quot;13\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onResume() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onResume(); - glSurfaceView.bringToFront(); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onPause() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onPause(); - glSurfaceView.onPause(); - }\u0026lt;/span\u0026gt; 这个glSurfaceView.bringToFront();其实不写也中。在布局里写入自定义的GLSurfaceView就ok了:\n**[html]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[copy](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[print](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[?](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/402612)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/402612/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;24\u0026quot; height=\u0026quot;13\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;FrameLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;org.yanzi.camera.preview.CameraGLSurfaceView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/camera_textureview\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;FrameLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; CameraActivity里只负责UI部分，CameraGLSurfaceView负责开Camera、预览，并调用DirectDrawer里的draw()进行绘制。其他代码就不上了。\n注意事项:\n1、**在onDrawFrame()里，如果不调用mDirectDrawer.draw(mtx);是啥都显示不出来的！！！**这是GLSurfaceView的特别之处。为啥呢？因为GLSurfaceView不是Android亲生的，而Surfaceview和TextureView是。所以得自己按照OpenGL ES的流程画。\n2、究竟 mDirectDrawer.draw(mtx)里在哪获取的Buffer目前杂家还么看太明白，貌似么有请求buffer，而是根据 GLSurfaceView里创建的SurfaceTexture之前，生成的有个纹理ID。这个纹理ID一方面跟SurfaceTexture是绑定在 一起的，另一方面跟DirectDrawer绑定，而SurfaceTexture作渲染载体。\n3、参考链接里有,有人为了解决问题，给出了下面三段代码:\n@Override public void onDrawFrame(GL10 gl) { float[] mtx = new float[16]; mSurface.updateTexImage(); mSurface.getTransformMatrix(mtx); mDirectVideo.draw(mtx); } private float[] transformTextureCoordinates( float[] coords, float[] matrix) { float[] result = new float[ coords.length ]; float[] vt = new float[4]; for ( int i = 0 ; i \u0026lt; coords.length ; i += 2 ) { float[] v = { coords[i], coords[i+1], 0 , 1 }; Matrix.multiplyMV(vt, 0, matrix, 0, v, 0); result[i] = vt[0]; result[i+1] = vt[1]; } return result; } textureVerticesBuffer.clear(); textureVerticesBuffer.put( transformTextureCoordinates( textureVertices, mtx )); textureVerticesBuffer.position(0); 我已经把代码都融入到了此demo，只不过在draw()方法里么有使用。原因是使用之后，得到的预览画面反而是变形的，而不用的话是ok的。上面的代码是得到SurfaceTexture的变换矩阵：mSurface.getTransformMatrix\n然后将此矩阵传递给draw()，在draw的时候对textureVerticesBuffer作一个变化，然后再画。\n下图是未加这个矩阵变换效果时:\n下图为使用了变换矩阵，划片扭曲的还真说不上来咋扭曲的，但足以说明OpenGL ES在渲染效果上的强大，就是设置了个矩阵，不用一帧帧处理，就能得到不一样显示效果。\n—————————–本文系原创，转载请注明作者yanzi1225627\n版本号:PlayCamera_V3.0.0[2014-6-22].zip\nCSDN下载链接:http://download.csdn.net/detail/yanzi1225627/7547263\n百度云盘:\n附个OpenGL ES简明教程：http://www.apkbus.com/android-20427-1-1.html\n转自：\nhttp://blog.csdn.net/yanzi1225627/article/details/33339965\n","permalink":"https://blog.zdltech.com/posts/android-surfacetexture%E5%92%8Cglsurfaceview%E5%81%9Acamera%E9%A2%84%E8%A7%88/","summary":"\u003cp\u003eGLSurfaceView是 OpenGL中的一个类，也是可以预览Camera的，而且在预览Camera上有其独到之处。独到之处在哪？当使用Surfaceview无能为力、痛 不欲生时就只有使用GLSurfaceView了，它能够真正做到让Camera的数据和显示分离，所以搞明白了这个，像Camera只开预览不显示这都 是小菜，妥妥的。Android4.0的自带Camera源码是用SurfaceView预览的，但到了4.2就换成了GLSurfaceView来预 览。如今到了4.4又用了自家的TextureView，所以从中可以窥探出新增TextureView的用意。\u003c/p\u003e\n\u003cp\u003e虽 说Android4.2的Camera源码是用GLSurfaceView预览的，但是进行了大量的封装又封装的，由于是OpenGL小白，真是看的不知 所云。俺滴要求不高，只想弄个可拍照的摸清GLSurfaceView在预览Camera上的使用流程。经过一番百度一无所获，后来翻出去Google一 大圈也没发现可用的。倒是很多人都在用GLSurfaceView和Surfaceview同时预览Camera，Surfaceview用来预览数据， 在上面又铺了一层GLSurfaceView绘制一些信息。无奈自己摸索，整出来的是能拍照也能得到数据，但是界面上不是一块白板就是一块黑板啥都不显 示。后来在stackoverflow终于找到了一个可用的\u003ca href=\"http://stackoverflow.com/questions/19852680/android-opengl-camera-preview-issue\"\u003e链接\u003c/a\u003e，哈哈，苍天啊，终于柳暗花明了！参考此链接，自己又改改摸索了一天才彻底搞定。之所以费这么多时间是不明白OpenGL ES2.0的绘制基本流程，跟简单的OpenGL的绘制还是稍有区别。下面上源码:\u003c/p\u003e\n\u003cp\u003e一、CameraGLSurfaceView.java 此类继承GLSurfaceView，并实现了两个接口\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[copy](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[print](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[?](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/402612)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/402612/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;24\u0026quot; height=\u0026quot;13\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.camera.preview;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; javax.microedition.khronos.egl.EGLConfig;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; javax.microedition.khronos.opengles.GL10;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.camera.CameraInterface;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.SurfaceTexture;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLES11Ext;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLES20;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLSurfaceView;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLSurfaceView.Renderer;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; CameraGLSurfaceView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; GLSurfaceView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Renderer, SurfaceTexture.OnFrameAvailableListener {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;yanzi\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n\n- Context mContext;\n\n- SurfaceTexture mSurface;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mTextureID = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;\n\n- DirectDrawer mDirectDrawer;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; CameraGLSurfaceView(Context context, AttributeSet attrs) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated constructor stub\u0026lt;/span\u0026gt;\n\n- mContext = context;\n\n- setEGLContextClientVersion(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;);\n\n- setRenderer(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);\n\n- setRenderMode(RENDERMODE_WHEN_DIRTY);\n\n- }\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSurfaceCreated(GL10 gl, EGLConfig config) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSurfaceCreated\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- mTextureID = createTextureID();\n\n- mSurface = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SurfaceTexture(mTextureID);\n\n- mSurface.setOnFrameAvailableListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);\n\n- mDirectDrawer = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DirectDrawer(mTextureID);\n\n- CameraInterface.getInstance().doOpenCamera(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;);\n\n- \n- }\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSurfaceChanged(GL10 gl, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onSurfaceChanged\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- GLES20.glViewport(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, width, height);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!CameraInterface.getInstance().isPreviewing()){\n\n- CameraInterface.getInstance().doStartPreview(mSurface, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.33f);\n\n- }\n\n- \n- \n- }\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDrawFrame(GL10 gl) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onDrawFrame\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- GLES20.glClearColor(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f);\n\n- GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);\n\n- mSurface.updateTexImage();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] mtx = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;];\n\n- mSurface.getTransformMatrix(mtx);\n\n- mDirectDrawer.draw(mtx);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onPause() {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onPause();\n\n- CameraInterface.getInstance().doStopCamera();\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; createTextureID()\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] texture = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];\n\n- \n- GLES20.glGenTextures(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, texture, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]);\n\n- GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,\n\n- GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR);\n\n- GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,\n\n- GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);\n\n- GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,\n\n- GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);\n\n- GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,\n\n- GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; texture[\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SurfaceTexture _getSurfaceTexture(){\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mSurface;\n\n- }\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onFrameAvailable(SurfaceTexture surfaceTexture) {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;\n\n- Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;onFrameAvailable\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.requestRender();\n\n- }\n\n- \n- }\n\n- \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e关于这个类进行简单说明:\u003c/p\u003e","title":"Android SurfaceTexture和GLSurfaceView做Camera预览"},{"content":" github上类似项目 https://github.com/jfeinstein10/SlidingMenu https://github.com/yueyueniao2012/SlidingMenu *转自：* [http://blog.csdn.net/jj120522/article/details/8075249](http://blog.csdn.net/jj120522/article/details/8075249?utm_source=tuicool) 首先我们看下面视图： ![](http://img1.tuicool.com/yyqeQv.png) ![](http://img0.tuicool.com/mYVFFr.png) 这种效果大家都不陌生，网上好多都说是仿人人网的，估计人家牛逼出来的早吧，我也参考了一一些例子，实现起来有三种方法，我下面简单介绍下： 方法一： 其实就是对GestureDetector手势的应用及布局文件的设计 . 布局文件main.xml 采用RelativeLayout布局. ``` \u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;utf-8\u0026rdquo;?\u0026gt; \u0026lt;RelativeLayout xmlns:android=\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot; android:layout_width=\u0026ldquo;fill_parent\u0026rdquo; android:layout_height=\u0026ldquo;fill_parent\u0026rdquo; android:orientation=\u0026ldquo;vertical\u0026rdquo; \u0026gt;\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;LinearLayout android:id=\u0026rdquo;@+id/layout_right\u0026quot; android:layout_width=\u0026ldquo;fill_parent\u0026rdquo; android:layout_height=\u0026ldquo;fill_parent\u0026rdquo; android:layout_marginLeft=\u0026ldquo;50dp\u0026rdquo; android:orientation=\u0026ldquo;vertical\u0026rdquo; \u0026gt;\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;AbsoluteLayout android:layout_width=\u0026ldquo;fill_parent\u0026rdquo; android:layout_height=\u0026ldquo;wrap_content\u0026rdquo; android:background=\u0026quot;@color/grey21\u0026quot; android:padding=\u0026ldquo;10dp\u0026rdquo; \u0026gt;\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;TextView android:layout_width=\u0026ldquo;wrap_content\u0026rdquo; android:layout_height=\u0026ldquo;wrap_content\u0026rdquo; android:text=\u0026ldquo;设置\u0026rdquo; android:textColor=\u0026quot;@android:color/background_light\u0026quot; android:textSize=\u0026ldquo;20sp\u0026rdquo; /\u0026gt; \u0026lt;/AbsoluteLayout\u0026gt;\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;ListView android:id=\u0026quot;@+id/lv_set\u0026quot; android:layout_width=\u0026ldquo;fill_parent\u0026rdquo; android:layout_height=\u0026ldquo;fill_parent\u0026rdquo; android:layout_weight=\u0026ldquo;1\u0026rdquo; \u0026gt; \u0026lt;/ListView\u0026gt; \u0026lt;/LinearLayout\u0026gt;\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;LinearLayout android:id=\u0026quot;@+id/layout_left\u0026quot; android:layout_width=\u0026ldquo;fill_parent\u0026rdquo; android:layout_height=\u0026ldquo;fill_parent\u0026rdquo; android:background=\u0026quot;@color/white\u0026quot; android:orientation=\u0026ldquo;vertical\u0026rdquo; \u0026gt;\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;RelativeLayout android:layout_width=\u0026ldquo;fill_parent\u0026rdquo; android:layout_height=\u0026ldquo;wrap_content\u0026rdquo; android:background=\u0026quot;@drawable/nav_bg\u0026quot; \u0026gt;\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;ImageView android:id=\u0026quot;@+id/iv_set\u0026quot; android:layout_width=\u0026ldquo;wrap_content\u0026rdquo; android:layout_height=\u0026ldquo;wrap_content\u0026rdquo; android:layout_alignParentRight=\u0026ldquo;true\u0026rdquo; android:layout_alignParentTop=\u0026ldquo;true\u0026rdquo; android:src=\u0026quot;@drawable/nav_setting\u0026quot; /\u0026gt;\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;TextView android:layout_width=\u0026ldquo;wrap_content\u0026rdquo; android:layout_height=\u0026ldquo;wrap_content\u0026rdquo; android:layout_centerInParent=\u0026ldquo;true\u0026rdquo; android:text=\u0026ldquo;我\u0026rdquo; android:textColor=\u0026quot;@android:color/background_light\u0026quot; android:textSize=\u0026ldquo;20sp\u0026rdquo; /\u0026gt; \u0026lt;/RelativeLayout\u0026gt;\n\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;ImageView android:id=\u0026quot;@+id/iv_set\u0026quot; android:layout_width=\u0026ldquo;fill_parent\u0026rdquo; android:layout_height=\u0026ldquo;fill_parent\u0026rdquo; android:scaleType=\u0026ldquo;fitXY\u0026rdquo; android:src=\u0026quot;@drawable/bg_guide_5\u0026quot; /\u0026gt; \u0026lt;/LinearLayout\u0026gt;\n\u0026lt;/RelativeLayout\u0026gt;\n![](http://img0.tuicool.com/QfYjYf.png)layout_right ：这个大布局文件， layout_left:距离左边50dp像素.(我们要移动的是 layout_left ). 看到这个图我想大家都很清晰了吧，其实: 我们就是把layout_left这个布局控件整理向左移动，至于移动多少，就要看layout_right有多宽了。layout_left移动到距离左边的边距就是layout_right的宽及-MAX_WIDTH.相信大家都理解. 布局文件就介绍到这里，下面看代码. ``` \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/*** * 初始化view */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; InitView() { layout_left = (LinearLayout) findViewById(R.id.layout_left); layout_right = (LinearLayout) findViewById(R.id.layout_right); iv_set = (ImageView) findViewById(R.id.iv_set); lv_set = (ListView) findViewById(R.id.lv_set); lv_set.setAdapter(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; ArrayAdapter\u0026amp;lt;String\u0026amp;gt;(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;, R.layout.item, R.id.tv_item, title)); lv_set.setOnItemClickListener(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; OnItemClickListener() { \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onItemClick(AdapterView\u0026amp;lt;?\u0026amp;gt; parent, View view, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; position, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;long\u0026lt;/span\u0026gt; id) { Toast.makeText(MainActivity.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;, title[position], \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;).show(); } }); layout_left.setOnTouchListener(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;); iv_set.setOnTouchListener(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;); mGestureDetector = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 禁用长按监听\u0026lt;/span\u0026gt; mGestureDetector.setIsLongpressEnabled(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); getMAX_WIDTH(); } 这里要对手势进行监听，我想大家都知道怎么做，在这里我要说明一个方法： ``` /***\n获取移动距离 移动的距离其实就是layout_left的宽度 */ void getMAX_WIDTH() { ViewTreeObserver viewTreeObserver = layout_left.getViewTreeObserver(); // 获取控件宽度 viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() { @Override public boolean onPreDraw() { if (!hasMeasured) { window_width = getWindowManager().getDefaultDisplay() .getWidth(); RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left .getLayoutParams(); layoutParams.width = window_width; layout_left.setLayoutParams(layoutParams); MAX_WIDTH = layout_right.getWidth(); Log.v(TAG, \u0026ldquo;MAX_WIDTH=\u0026quot; + MAX_WIDTH + \u0026ldquo;width=\u0026quot; + window_width); hasMeasured = true; } return true; } }); }\n在这里我们要获取屏幕的宽度，并将屏幕宽度设置给layout_left这个控件，为什么要这么做呢 ， 因为如果不把该控件宽度写死的话，那么系统将认为layout_left会根据不同环境宽度自动适应，也就是说我们通过layout_left.getLayoutParams动态移动该控件的时候，该控件会伸缩而不是移动。 描述的有点模糊，大家请看下面示意图就明白了. 我们不为 layout_left定义死宽度效果： ![](http://img1.tuicool.com/ziAjIr.png) ![](http://img0.tuicool.com/VrqI32.png) getLayoutParams可以很清楚看到， layout_left被向左拉伸了，并不是我们要的效果. 还有一种解决办法就是我们在配置文件中直接把 layout_left宽度写死，不过这样不利于开发，因为分辨率的问题.因此就用 ViewTreeObserver进行对 layout_left设置宽度. ViewTreeObserver,这个类主要用于对布局文件的监听.强烈建议同学们参考这篇文章 [android ViewTreeObserver详细讲解](http://blog.csdn.net/jj120522/article/details/8097133)，相信让你对ViewTreeObserver有更一步的了解.其他的就是对 GestureDetector手势的应用，下面我把代码贴出来： ``` \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;package\u0026lt;/span\u0026gt; com.jj.slidingmenu; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.os.AsyncTask; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.GestureDetector; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.KeyEvent; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewTreeObserver; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewTreeObserver.OnPreDrawListener; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnTouchListener; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView.OnItemClickListener; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ArrayAdapter; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.RelativeLayout; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout.LayoutParams; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/*** * 滑动菜单 * * \u0026lt;span class=\u0026#34;javadoctag\u0026#34;\u0026gt;@author\u0026lt;/span\u0026gt; jjhappyforever... * */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;MainActivity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Activity\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;OnTouchListener\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;GestureDetector\u0026lt;/span\u0026gt;.\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;OnGestureListener\u0026lt;/span\u0026gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; hasMeasured = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 是否Measured.\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; LinearLayout layout_left; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; LinearLayout layout_right; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; ImageView iv_set; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; ListView lv_set; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 每次自动展开/收缩的范围 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; MAX_WIDTH = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** 每次自动展开/收缩的速度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; SPEED = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; GestureDetector mGestureDetector;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 手势\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; isScrolling = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; mScrollX; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 滑块滑动距离\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; window_width;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 屏幕的宽度\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;jj\u0026#34;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; String title[] = { \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;待发送队列\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;同步分享设置\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;编辑我的资料\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;找朋友\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;告诉朋友\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;节省流量\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;推送设置\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;版本更新\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;意见反馈\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;积分兑换\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;精品应用\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;常见问题\u0026#34;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;退出当前帐号\u0026#34;\u0026lt;/span\u0026gt; }; \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/*** * 初始化view */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; InitView() { layout_left = (LinearLayout) findViewById(R.id.layout_left); layout_right = (LinearLayout) findViewById(R.id.layout_right); iv_set = (ImageView) findViewById(R.id.iv_set); lv_set = (ListView) findViewById(R.id.lv_set); lv_set.setAdapter(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; ArrayAdapter\u0026amp;lt;String\u0026amp;gt;(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;, R.layout.item, R.id.tv_item, title)); lv_set.setOnItemClickListener(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; OnItemClickListener() { \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onItemClick(AdapterView\u0026amp;lt;?\u0026amp;gt; parent, View view, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; position, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;long\u0026lt;/span\u0026gt; id) { Toast.makeText(MainActivity.\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;, title[position], \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;).show(); } }); layout_left.setOnTouchListener(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;); iv_set.setOnTouchListener(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;); mGestureDetector = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 禁用长按监听\u0026lt;/span\u0026gt; mGestureDetector.setIsLongpressEnabled(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;); getMAX_WIDTH(); } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/*** * 获取移动距离 移动的距离其实就是layout_left的宽度 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; getMAX_WIDTH() { ViewTreeObserver viewTreeObserver = layout_left.getViewTreeObserver(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 获取控件宽度\u0026lt;/span\u0026gt; viewTreeObserver.addOnPreDrawListener(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; OnPreDrawListener() { \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onPreDraw() { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (!hasMeasured) { window_width = getWindowManager().getDefaultDisplay() .getWidth(); RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left .getLayoutParams(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// layoutParams.width = window_width;\u0026lt;/span\u0026gt; layout_left.setLayoutParams(layoutParams); MAX_WIDTH = layout_right.getWidth(); Log.v(TAG, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;MAX_WIDTH=\u0026#34;\u0026lt;/span\u0026gt; + MAX_WIDTH + \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;width=\u0026#34;\u0026lt;/span\u0026gt; + window_width); hasMeasured = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } }); } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.main); InitView(); } \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 返回键\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onKeyDown(\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; keyCode, KeyEvent event) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (KeyEvent.KEYCODE_BACK == keyCode \u0026amp;\u0026amp; event.getRepeatCount() == \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left .getLayoutParams(); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (layoutParams.leftMargin \u0026amp;lt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; AsynMove().execute(SPEED); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;; } } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;.onKeyDown(keyCode, event); } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 松开的时候要判断，如果不到半屏幕位子则缩回去，\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (MotionEvent.ACTION_UP == event.getAction() \u0026amp;\u0026amp; isScrolling == \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;) { RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left .getLayoutParams(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 缩回去\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (layoutParams.leftMargin \u0026amp;lt; -window_width / \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; AsynMove().execute(-SPEED); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; AsynMove().execute(SPEED); } } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; mGestureDetector.onTouchEvent(event); } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onDown(MotionEvent e) { mScrollX = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; isScrolling = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 将之改为true，不然事件不会向下传递.\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onShowPress(MotionEvent e) { } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/*** * 点击松开执行 */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onSingleTapUp(MotionEvent e) { RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left .getLayoutParams(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 左移动\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (layoutParams.leftMargin \u0026amp;gt;= \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; AsynMove().execute(-SPEED); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 右移动\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; AsynMove().execute(SPEED); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/*** * e1 是起点，e2是终点，如果distanceX=e1.x-e2.x\u0026amp;gt;0说明向左滑动。反之亦如此. */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onScroll(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; distanceX, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; distanceY) { isScrolling = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;; mScrollX += distanceX;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// distanceX:向左为正，右为负\u0026lt;/span\u0026gt; RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left .getLayoutParams(); layoutParams.leftMargin -= mScrollX; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (layoutParams.leftMargin \u0026amp;gt;= \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { isScrolling = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 拖过头了不需要再执行AsynMove了\u0026lt;/span\u0026gt; layoutParams.leftMargin = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (layoutParams.leftMargin \u0026amp;lt;= -MAX_WIDTH) { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 拖过头了不需要再执行AsynMove了\u0026lt;/span\u0026gt; isScrolling = \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;; layoutParams.leftMargin = -MAX_WIDTH; } layout_left.setLayoutParams(layoutParams); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onLongPress(MotionEvent e) { } \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; velocityX, \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;class\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;AsynMove\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;AsyncTask\u0026lt;/span\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Integer\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Integer\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;title\u0026#34;\u0026gt;Void\u0026lt;/span\u0026gt;\u0026amp;gt; {\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; Void doInBackground(Integer... params) { \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; times = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (MAX_WIDTH % Math.abs(params[\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;]) == \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;)\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 整除\u0026lt;/span\u0026gt; times = MAX_WIDTH / Math.abs(params[\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;]); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; times = MAX_WIDTH / Math.abs(params[\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;]) + \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;;\u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 有余数\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026amp;lt; times; i++) { publishProgress(params[\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;]); \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;try\u0026lt;/span\u0026gt; { Thread.sleep(Math.abs(params[\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;])); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;catch\u0026lt;/span\u0026gt; (InterruptedException e) { e.printStackTrace(); } } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; } \u0026lt;span class=\u0026#34;javadoc\u0026#34;\u0026gt;/** * update UI */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onProgressUpdate(Integer... values) { RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left .getLayoutParams(); \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 右移动\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (values[\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;] \u0026amp;gt; \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;) { layoutParams.leftMargin = Math.min(layoutParams.leftMargin + values[\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;], \u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;); Log.v(TAG, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;移动右\u0026#34;\u0026lt;/span\u0026gt; + layoutParams.rightMargin); } \u0026lt;span class=\u0026#34;keyword\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span class=\u0026#34;comment\u0026#34;\u0026gt;// 左移动\u0026lt;/span\u0026gt; layoutParams.leftMargin = Math.max(layoutParams.leftMargin + values[\u0026lt;span class=\u0026#34;number\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;], -MAX_WIDTH); Log.v(TAG, \u0026lt;span class=\u0026#34;string\u0026#34;\u0026gt;\u0026#34;移动左\u0026#34;\u0026lt;/span\u0026gt; + layoutParams.rightMargin); } layout_left.setLayoutParams(layoutParams); } } } 上面代码注释已经很明确，相信大家都看的明白，我就不过多解释了。效果图： 截屏出来有点卡，不过在手机虚拟机上是不卡的. ![](http://img0.tuicool.com/ziuuUn.gif) [源码下载](http://download.csdn.net/detail/jj120522/4670568) 怎么样，看着还行吧，我们在看下面一个示例： ![](http://img1.tuicool.com/vaYRbe.png) 简单说明一下，当你滑动的时候左边会跟着右边一起滑动，这个效果比上面那个酷吧，上面那个有点死板，其实实现起来也比较容易，只需要把我们上面那个稍微修改下，对layout_right也进行时时更新，这样就实现了这个效果了，如果上面那个理解了，这个很轻松就解决了，在这里我又遇到一个问题： 此时的listview的item监听不到手势，意思就是我左右滑动listview他没有进行滑动。 本人对touch众多事件监听拦截等熟悉度不够，因此这里我用到自己写的方法，也许比较麻烦，如果有更好的解决办法，请大家一定要分享哦，再次 thanks for you 了. 具体解决办法：我们重写listview,对此listview进行手势监听， 我们自定义一个接口来实现 ，具体代码如下： ``` package com.jj.slidingmenu;\nimport android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.GestureDetector.OnGestureListener; import android.view.View; import android.widget.ListView; import android.widget.Toast;\npublic class MyListView extends ListView implements OnGestureListener {\nprivate GestureDetector gd; // 事件状态 public static final char FLING_CLICK = ; public static final char FLING_LEFT = 1; public static final char FLING_RIGHT = 2; public static char flingState = FLING_CLICK;\nprivate float distanceX;// 水平滑动的距离\nprivate MyListViewFling myListViewFling;\npublic static boolean isClick = false;// 是否可以点击\npublic void setMyListViewFling(MyListViewFling myListViewFling) { this.myListViewFling = myListViewFling; }\npublic float getDistanceX() { return distanceX; }\npublic char getFlingState() { return flingState; }\nprivate Context context;\npublic MyListView(Context context) { super(context);\n}\npublic MyListView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; gd = new GestureDetector(this); }\n/**\n覆写此方法，以解决ListView滑动被屏蔽问题 */ @Override public boolean dispatchTouchEvent(MotionEvent event) { myListViewFling.doFlingOver(event);// 回调执行完毕. this.gd.onTouchEvent(event); \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(event); }\n@Override public boolean onTouchEvent(MotionEvent ev) { /*** * 当移动的时候 */ if (ev.getAction() == MotionEvent.ACTION_DOWN) isClick = true; if (ev.getAction() == MotionEvent.ACTION_MOVE) isClick = false; return super.onTouchEvent(ev); }\n@Override public boolean onDown(MotionEvent e) { int position = pointToPosition((int) e.getX(), (int) e.getY()); if (position != ListView.INVALID_POSITION) { View child = getChildAt(position - getFirstVisiblePosition()); } return true; }\n@Override public void onShowPress(MotionEvent e) {\n}\n@Override public boolean onSingleTapUp(MotionEvent e) {\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; }\n@Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // 左滑动 if (distanceX \u0026gt; ) { flingState = FLING_RIGHT; Log.v(\u0026ldquo;jj\u0026rdquo;, \u0026ldquo;左distanceX=\u0026quot; + distanceX); myListViewFling.doFlingLeft(distanceX);// 回调 // 右滑动. } else if (distanceX \u0026lt; ) { flingState = FLING_LEFT; Log.v(\u0026ldquo;jj\u0026rdquo;, \u0026ldquo;右distanceX=\u0026quot; + distanceX); myListViewFling.doFlingRight(distanceX);// 回调 }\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; }\n/***\n上下文菜单 */ @Override public void onLongPress(MotionEvent e) { // System.out.println(\u0026ldquo;Listview long press\u0026rdquo;); // int position = pointToPosition((int) e.getX(), (int) e.getY()); // if (position != ListView.INVALID_POSITION) { // View child = getChildAt(position - getFirstVisiblePosition()); // if (child != null) { // showContextMenuForChild(child); // this.requestFocusFromTouch(); // } // // } } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; }\n/***\n回调接口 @author jjhappyforever\u0026hellip; */ interface MyListViewFling { void doFlingLeft(float distanceX);// 左滑动执行\n\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; doFlingRight(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceX);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 右滑动执行\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; doFlingOver(MotionEvent event);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 拖拽松开时执行\u0026lt;/span\u0026gt; }\n}\n而在MainActivity.java里面实现该接口,我这么一说，我想有的同学们都明白了，具体实现起来代码有点多，我把代码上传到网上，大家可以下载后 用心看 ，我想大家都能够明白的.（在这里我鄙视一下自己，肯定通过对手势监听拦截实现对listview的左右滑动，但是自己学业不经，再次再说一下，如有好的解决方案，请一定要分享我一下哦.） 另外有一个问题：当listivew超出一屏的时候， 此时的listview滑动的时候可以上下左右一起滑动,在此没有解决这个问题，如有解决请分享我哦. 效果图： ![](http://img1.tuicool.com/A3iARj.gif) [源码下载](http://download.csdn.net/detail/jj120522/4671132) 由于篇符较长，先说到这里，其实android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu也可以实现.具体参考下一篇文章： 先写到这里，有不足的地方请指出， 如果对您有帮助的话请记得赞一个哦. thanks for you。 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-%E6%BB%91%E5%8A%A8%E8%8F%9C%E5%8D%95slidingmenu%E7%9A%84%E5%AE%9E%E7%8E%B0/","summary":"\u003cdiv class=\"article_meta\"\u003e\n  github上类似项目\n\u003c/div\u003e\n\u003cdiv class=\"article_meta\"\u003e\n  https://github.com/jfeinstein10/SlidingMenu\n\u003c/div\u003e\n\u003cdiv class=\"article_meta\"\u003e\n  https://github.com/yueyueniao2012/SlidingMenu\n\u003c/div\u003e\n\u003cdiv class=\"article_meta\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"article_meta\"\u003e\n  \u003cspan class=\"source\"\u003e*转自：*  [http://blog.csdn.net/jj120522/article/details/8075249](http://blog.csdn.net/jj120522/article/details/8075249?utm_source=tuicool)\u003c/span\u003e\n\u003c/div\u003e\n\u003cdiv id=\"nei\" class=\"article_body\"\u003e\n  \u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e  首先我们看下面视图：\n\n\n\n\n\n  ![](http://img1.tuicool.com/yyqeQv.png)      ![](http://img0.tuicool.com/mYVFFr.png)\n\n\n\n\n\n  这种效果大家都不陌生，网上好多都说是仿人人网的，估计人家牛逼出来的早吧，我也参考了一一些例子，实现起来有三种方法，我下面简单介绍下：\n\n\n\n\n\n  方法一： 其实就是对GestureDetector手势的应用及布局文件的设计 .\n\n\n\n\n\n  布局文件main.xml    采用RelativeLayout布局.\n\n\n\n```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cspan class=\"pi\"\u003e\u0026lt;?xml version=\u0026ldquo;1.0\u0026rdquo; encoding=\u0026ldquo;utf-8\u0026rdquo;?\u0026gt;\u003c/span\u003e\n\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"title\"\u003eRelativeLayout\u003c/span\u003e \u003cspan class=\"attribute\"\u003exmlns:android\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;\u003ca href=\"http://schemas.android.com/apk/res/android%22\"\u003ehttp://schemas.android.com/apk/res/android\u0026quot;\u003c/a\u003e\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_width\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;fill_parent\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_height\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;fill_parent\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:orientation\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;vertical\u0026rdquo;\u003c/span\u003e \u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;LinearLayout\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003c/span\u003e        \u003cspan class=\"attribute\"\u003eandroid:id\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026rdquo;@+id/layout_right\u0026quot;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_width\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;fill_parent\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_height\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;fill_parent\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_marginLeft\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;50dp\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:orientation\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;vertical\u0026rdquo;\u003c/span\u003e \u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;AbsoluteLayout\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003c/span\u003e            \u003cspan class=\"attribute\"\u003eandroid:layout_width\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;fill_parent\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_height\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;wrap_content\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:background\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026quot;@color/grey21\u0026quot;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:padding\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;10dp\u0026rdquo;\u003c/span\u003e \u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e        \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;TextView\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003c/span\u003e                \u003cspan class=\"attribute\"\u003eandroid:layout_width\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;wrap_content\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_height\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;wrap_content\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:text\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;设置\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:textColor\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026quot;@android:color/background_light\u0026quot;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:textSize\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;20sp\u0026rdquo;\u003c/span\u003e /\u0026gt;\u003c/span\u003e\n\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"title\"\u003eAbsoluteLayout\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;ListView\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003c/span\u003e            \u003cspan class=\"attribute\"\u003eandroid:id\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026quot;@+id/lv_set\u0026quot;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_width\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;fill_parent\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_height\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;fill_parent\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_weight\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;1\u0026rdquo;\u003c/span\u003e \u0026gt;\u003c/span\u003e\n\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"title\"\u003eListView\u003c/span\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"title\"\u003eLinearLayout\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;LinearLayout\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003c/span\u003e        \u003cspan class=\"attribute\"\u003eandroid:id\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026quot;@+id/layout_left\u0026quot;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_width\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;fill_parent\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_height\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;fill_parent\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:background\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026quot;@color/white\u0026quot;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:orientation\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;vertical\u0026rdquo;\u003c/span\u003e \u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;RelativeLayout\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003c/span\u003e            \u003cspan class=\"attribute\"\u003eandroid:layout_width\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;fill_parent\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_height\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;wrap_content\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:background\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026quot;@drawable/nav_bg\u0026quot;\u003c/span\u003e \u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e        \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;ImageView\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003c/span\u003e                \u003cspan class=\"attribute\"\u003eandroid:id\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026quot;@+id/iv_set\u0026quot;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_width\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;wrap_content\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_height\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;wrap_content\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_alignParentRight\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;true\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_alignParentTop\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;true\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:src\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026quot;@drawable/nav_setting\u0026quot;\u003c/span\u003e /\u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e        \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026amp;lt;\u0026lt;span class=\u0026quot;title\u0026quot;\u0026gt;TextView\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003c/span\u003e                \u003cspan class=\"attribute\"\u003eandroid:layout_width\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;wrap_content\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_height\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;wrap_content\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:layout_centerInParent\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;true\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:text\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;我\u0026rdquo;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:textColor\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026quot;@android:color/background_light\u0026quot;\u003c/span\u003e\n\u003cspan class=\"attribute\"\u003eandroid:textSize\u003c/span\u003e=\u003cspan class=\"value\"\u003e\u0026ldquo;20sp\u0026rdquo;\u003c/span\u003e /\u0026gt;\u003c/span\u003e\n\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"title\"\u003eRelativeLayout\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/p\u003e","title":"android 滑动菜单SlidingMenu的实现"},{"content":"转载出处：http://blog.csdn.net/lmj623565791/article/details/41531475\n1、概述 之前写了一个Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭 ，恰逢QQ5.2又加了一个右侧菜单，刚好看了下DrawerLayout，一方面官方的东西，我都比较感兴趣；另一方面，这玩意用起来的确方便，于是简单写了个demo，高仿QQ5.2双向侧滑，分享给大家。\n首先看看效果图：\nDrawerLayout用起来真的很方便，下面一起看看用法~\n2、DrawerLayout的使用 直接将DrawerLayout作为根布局，然后其内部第一个View为内容区域，第二个View为左侧菜单，第三个View为右侧侧滑菜单，当前第三个是可选的。\n第一个View的宽高应当设置为match_parent，当然了，这也理所当然。\n第二、三个View需要设置android:layout_gravity=”left”，和android:layout_gravity=”right”且一搬高度设置为match_parent，宽度为固定值，即侧滑菜单的宽度。\n按照上面的描述写个布局文件，然后设置给Activity就添加好了左右侧滑了，是不是很简单~~~\n比如我们的布局文件：\n**[html]** [view plain](http://blog.csdn.net/lmj623565791/article/details/41531475#)[copy](http://blog.csdn.net/lmj623565791/article/details/41531475#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;android.support.v4.widget.DrawerLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/id_drawerLayout\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/img_frame_background\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/qq\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;40dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;30dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_alignParentRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/youce\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;OpenRightMenu\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;fragment\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/id_left_menu\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;com.zhy.demo_zhy_17_drawerlayout.MenuLeftFragment\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;200dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;left\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:tag\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;LEFT\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;fragment\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/id_right_menu\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;com.zhy.demo_zhy_17_drawerlayout.MenuRightFragment\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;100dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;right\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:tag\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;RIGHT\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;android.support.v4.widget.DrawerLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 这里我们的主内容区域为RelativeLayout\n菜单用的两个Fragment，左侧为200dp，右侧为100dp；\n好了，看了我们的布局文件，接下来看下我们的详细代码。\n3、代码是最好的老师 1、MenuLeftFragment **[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/41531475#)[copy](http://blog.csdn.net/lmj623565791/article/details/41531475#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/534306)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/534306/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.demo_zhy_17_drawerlayout; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v4.app.Fragment; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MenuLeftFragment \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Fragment - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; inflater.inflate(R.layout.layout_menu, container, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); - } - } 对应的布局文件：\n**[html]** [view plain](http://blog.csdn.net/lmj623565791/article/details/41531475#)[copy](http://blog.csdn.net/lmj623565791/article/details/41531475#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/534306)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/534306/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#00000000\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/one\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/img_1\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_toRightOf\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/one\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;第1个Item\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#f0f0f0\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20sp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/two\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/img_2\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_toRightOf\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/two\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;第2个Item\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#f0f0f0\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20sp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/three\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/img_3\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_toRightOf\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/three\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;第3个Item\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#f0f0f0\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20sp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/four\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/img_4\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_toRightOf\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/four\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;第4个Item\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#f0f0f0\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20sp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/five\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/img_5\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_toRightOf\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@id/five\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;第5个Item\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#f0f0f0\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20sp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 其实就是堆出来的布局~~没撒意思~\n2、MenuRightFragment **[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/41531475#)[copy](http://blog.csdn.net/lmj623565791/article/details/41531475#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/534306)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/534306/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.demo_zhy_17_drawerlayout; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v4.app.Fragment; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MenuRightFragment \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Fragment - { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; inflater.inflate(R.layout.menu_layout_right, container, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); - } - } 对应布局文件：\n**[html]** [view plain](http://blog.csdn.net/lmj623565791/article/details/41531475#)[copy](http://blog.csdn.net/lmj623565791/article/details/41531475#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/534306)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/534306/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;60dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;60dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/wode\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;扫一扫\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#ffffff\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;60dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;60dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/saoma\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;讨论组\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#ffffff\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;60dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;60dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/wode\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;扫一扫\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#ffffff\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;60dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;60dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/saoma\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;讨论组\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#ffffff\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 依旧很简单，除了图标比较难找以外~~\n3、MainActivity MainActivity的布局文件已经贴过了~~\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/41531475#)[copy](http://blog.csdn.net/lmj623565791/article/details/41531475#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/534306)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/534306/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.demo_zhy_17_drawerlayout; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v4.app.FragmentActivity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v4.widget.DrawerLayout; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v4.widget.DrawerLayout.DrawerListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Gravity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.nineoldandroids.view.ViewHelper; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; FragmentActivity - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; DrawerLayout mDrawerLayout; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.activity_main); - - initView(); - initEvents(); - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; OpenRightMenu(View view) - { - mDrawerLayout.openDrawer(Gravity.RIGHT); - mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, - Gravity.RIGHT); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initEvents() - { - mDrawerLayout.setDrawerListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DrawerListener() - { - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDrawerStateChanged(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; newState) - { - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDrawerSlide(View drawerView, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; slideOffset) - { - View mContent = mDrawerLayout.getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - View mMenu = drawerView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; scale = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; \u0026amp;#8211; slideOffset; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; rightScale = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.8f + scale * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.2f; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (drawerView.getTag().equals(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;LEFT\u0026amp;#8221;\u0026lt;/span\u0026gt;)) - { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; leftScale = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.3f * scale; - - ViewHelper.setScaleX(mMenu, leftScale); - ViewHelper.setScaleY(mMenu, leftScale); - ViewHelper.setAlpha(mMenu, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.6f + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.4f * (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; \u0026amp;#8211; scale)); - ViewHelper.setTranslationX(mContent, - mMenu.getMeasuredWidth() * (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; \u0026amp;#8211; scale)); - ViewHelper.setPivotX(mContent, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - ViewHelper.setPivotY(mContent, - mContent.getMeasuredHeight() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); - mContent.invalidate(); - ViewHelper.setScaleX(mContent, rightScale); - ViewHelper.setScaleY(mContent, rightScale); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - { - ViewHelper.setTranslationX(mContent, - -mMenu.getMeasuredWidth() * slideOffset); - ViewHelper.setPivotX(mContent, mContent.getMeasuredWidth()); - ViewHelper.setPivotY(mContent, - mContent.getMeasuredHeight() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); - mContent.invalidate(); - ViewHelper.setScaleX(mContent, rightScale); - ViewHelper.setScaleY(mContent, rightScale); - } - - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDrawerOpened(View drawerView) - { - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDrawerClosed(View drawerView) - { - mDrawerLayout.setDrawerLockMode( - DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.RIGHT); - } - }); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() - { - mDrawerLayout = (DrawerLayout) findViewById(R.id.id_drawerLayout); - mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, - Gravity.RIGHT); - } - - } 嗯，代码基本没什么注释~~维撒呢？是因为的确没什么好注释的。\n提几点：\n1、为了模拟QQ的右侧菜单需要点击才能出现，所以在初始化DrawerLayout的时候，使用了mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED,Gravity.RIGHT);意思是只有编程才能将其弹出。\n然后在弹出以后，需要让手势可以滑动回去，所以在OpenRightMenu中又编写了：\nmDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED,Gravity.RIGHT); UNLOCK了一下。\n最后在onDrawerClosed回调中，继续设置mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED,Gravity.RIGHT)；\n2、动画效果\n动画用了nineoldandroids，关于动画各种偏移量、缩放比例的计算请参考Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭 基本是一致的，唯一的不同的地方，给Content设置了ViewHelper.setTranslationX(mContent, mMenu.getMeasuredWidth() * (1 – scale));让Content在菜单的右侧，默认情况下Menu在菜单之上，所以我们根据菜单划出的距离给Content设置X方向的偏移量。\n好了，其实看到可以这么做，基本上任何的侧滑菜单效果都能写出来了。有兴趣的话，可以拿DrawerLayout实现这篇博客的所有效果：Android 实现形态各异的双向侧滑菜单 自定义控件来袭 。\n3、setDrawerListener\n通过代码也能看出来，可以使用setDrawerListener监听菜单的打开与关闭等等。这里对于当前操作是哪个菜单的判断是通过TAG判断的，我觉得使用gravity应该也能判断出来~~\n好了，没撒了，由于DrawerLayout默认只能从边界划出菜单，但是QQ划出菜单的手势区域比较大，大家有兴趣，可以重写Activity的onTouchEvent，在里面判断，如果是左右滑动手势神马的，弹出菜单，应该不麻烦~~~\n源码点击下载\n我建了一个QQ群，方便大家交流。群号：55032675\n———————————————————————————————————-\n博主部分视频已经上线，如果你不喜欢枯燥的文本，请猛戳（初录，期待您的支持）：\n1、Android 自定义控件实战 电商活动中的刮刮卡\n2、Android自定义控件实战 打造Android流式布局和热门标签\n3、Android智能机器人“小慕”的实现\n4、高仿QQ5.0侧滑\n5、高仿微信5.2.1主界面及消息提醒\n","permalink":"https://blog.zdltech.com/posts/android-drawerlayout-%E9%AB%98%E4%BB%BFqq5-2%E5%8F%8C%E5%90%91%E4%BE%A7%E6%BB%91%E8%8F%9C%E5%8D%95/","summary":"\u003cp\u003e转载出处：\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/41531475\"\u003ehttp://blog.csdn.net/lmj623565791/article/details/41531475\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"1概述\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003e1、概述\u003c/h1\u003e\n\u003cp\u003e之前写了一个\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/39257409\"\u003eAndroid 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭\u003c/a\u003e ，恰逢QQ5.2又加了一个右侧菜单，刚好看了下DrawerLayout，一方面官方的东西，我都比较感兴趣；另一方面，这玩意用起来的确方便，于是简单写了个demo，高仿QQ5.2双向侧滑，分享给大家。\u003c/p\u003e\n\u003cp\u003e首先看看效果图：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20141127010522656\"\u003e\u003c/p\u003e\n\u003cp\u003eDrawerLayout用起来真的很方便，下面一起看看用法~\u003c/p\u003e\n\u003ch1 id=\"2drawerlayout的使用\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e2、DrawerLayout的使用\u003c/h1\u003e\n\u003cp\u003e直接将DrawerLayout作为根布局，然后其内部第一个View为内容区域，第二个View为左侧菜单，第三个View为右侧侧滑菜单，当前第三个是可选的。\u003c/p\u003e\n\u003cp\u003e第一个View的宽高应当设置为match_parent，当然了，这也理所当然。\u003c/p\u003e\n\u003cp\u003e第二、三个View需要设置android:layout_gravity=”left”，和android:layout_gravity=”right”且一搬高度设置为match_parent，宽度为固定值，即侧滑菜单的宽度。\u003c/p\u003e\n\u003cp\u003e按照上面的描述写个布局文件，然后设置给Activity就添加好了左右侧滑了，是不是很简单~~~\u003c/p\u003e\n\u003cp\u003e比如我们的布局文件：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/lmj623565791/article/details/41531475#)[copy](http://blog.csdn.net/lmj623565791/article/details/41531475#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;android.support.v4.widget.DrawerLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/id_drawerLayout\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/img_frame_background\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/qq\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;40dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;30dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_marginTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_alignParentRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/youce\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;OpenRightMenu\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;fragment\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/id_left_menu\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;com.zhy.demo_zhy_17_drawerlayout.MenuLeftFragment\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;200dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;left\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:tag\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;LEFT\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;fragment\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/id_right_menu\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;com.zhy.demo_zhy_17_drawerlayout.MenuRightFragment\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;100dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;right\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:tag\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;RIGHT\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;android.support.v4.widget.DrawerLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e这里我们的主内容区域为RelativeLayout\u003c/p\u003e","title":"Android DrawerLayout 高仿QQ5.2双向侧滑菜单"},{"content":"AndroidResideMenu\n![](http://www.2cto.com/uploadfile/Collfiles/20140911/20140911091421122.gif)\n先看看如何使用：\n把项目源码下载下来导入工程，可以看到\n![](http://www.2cto.com/uploadfile/Collfiles/20140911/20140911091422123.jpg)\nResideMenu为引用工程，再看看如何使用这个引用工程来构建出ResideMenu，\n1.先new一个ResideMenu对象\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `resideMenu = ``new` `ResideMenu(``this``);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 2.设置它的背景图片\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `resideMenu.setBackground(R.drawable.menu_background);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 3.绑定当前Activity\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `resideMenu.attachToActivity(``this``);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 4.设置监听\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `resideMenu.setMenuListener(menuListener);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 可以监听菜单打开和关闭状态\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `private` `ResideMenu.OnMenuListener menuListener = ``new` `ResideMenu.OnMenuListener() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``public` `void` `openMenu() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``Toast.makeText(mContext, Menu is opened!, Toast.LENGTH_SHORT).show();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``public` `void` `closeMenu() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``Toast.makeText(mContext, Menu is closed!, Toast.LENGTH_SHORT).show();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; `};` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 5.设置内容缩放比例（0.1~1f）\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `//valid scale factor is between 0.0f and 1.0f. leftmenu'width is 150dip. ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``resideMenu.setScaleValue(````.6f);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 6.创建子菜单\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `// create menu items;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``itemHome = ``new` `ResideMenuItem(``this``, R.drawable.icon_home, Home);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``itemProfile = ``new` `ResideMenuItem(``this``, R.drawable.icon_profile, Profile);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``itemCalendar = ``new` `ResideMenuItem(``this``, R.drawable.icon_calendar, Calendar);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``itemSettings = ``new` `ResideMenuItem(``this``, R.drawable.icon_settings, Settings);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 7.设置点击事件及将刚创建的子菜单添加到侧换菜单中（可以看到它是通过常量来控制子菜单的添加位置）\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `itemHome.setOnClickListener(``this``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``itemProfile.setOnClickListener(``this``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``itemCalendar.setOnClickListener(``this``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``itemSettings.setOnClickListener(``this``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``resideMenu.addMenuItem(itemHome, ResideMenu.DIRECTION_LEFT);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``resideMenu.addMenuItem(itemProfile, ResideMenu.DIRECTION_LEFT);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``resideMenu.addMenuItem(itemCalendar, ResideMenu.DIRECTION_RIGHT);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``resideMenu.addMenuItem(itemSettings, ResideMenu.DIRECTION_RIGHT);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 8.设置title按钮的点击事件，设置左右菜单的开关\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `// You can disable a direction by setting -\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``// resideMenu.setSwipeDirectionDisable(ResideMenu.DIRECTION_RIGHT);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``findViewById(R.id.title_bar_left_menu).setOnClickListener(``new` `View.OnClickListener() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``public` `void` `onClick(View view) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``resideMenu.openMenu(ResideMenu.DIRECTION_LEFT);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``});` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``findViewById(R.id.title_bar_right_menu).setOnClickListener(``new` `View.OnClickListener() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``public` `void` `onClick(View view) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``resideMenu.openMenu(ResideMenu.DIRECTION_RIGHT);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``});` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 9.还重写了dispatchTouchEvent\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``public` `boolean` `dispatchTouchEvent(MotionEvent ev) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``return` `resideMenu.dispatchTouchEvent(ev);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 10.菜单关闭方法\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `resideMenu.closeMenu();` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 11.屏蔽菜单方法\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `// You can disable a direction by setting -\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``// resideMenu.setSwipeDirectionDisable(ResideMenu.DIRECTION_RIGHT);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 使用方法已经说完了，接下来，看看它的源码,先看看源码的项目结构。\n![](http://www.2cto.com/uploadfile/Collfiles/20140911/20140911091422126.jpg)\n很多人初学者都曾纠结，看源码，如何从何看起，我个人建议从上面使用的顺序看起，并且在看的时候要带个问题去看去思考，这样更容易理解。\n上面的第一步是，创建ResideMenu对象，我们就看看ResideMenu的构造。\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `ResideMenu(Context context) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``super``(context);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``initViews(context);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 从上面代码，看到构造里面就一个初始化view，思考问题：如何初始化view及初始化了什么view。\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `private` `void` `initViews(Context context){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``LayoutInflater inflater = (LayoutInflater)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``inflater.inflate(R.layout.residemenu, ``this``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``scrollViewLeftMenu = (ScrollView) findViewById(R.id.sv_left_menu);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``scrollViewRightMenu = (ScrollView) findViewById(R.id.sv_right_menu);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``imageViewShadow = (ImageView) findViewById(R.id.iv_shadow);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``layoutLeftMenu = (LinearLayout) findViewById(R.id.layout_left_menu);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``layoutRightMenu = (LinearLayout) findViewById(R.id.layout_right_menu);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``imageViewBackground = (ImageView) findViewById(R.id.iv_background);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 原理分析：从上面的代码可以看到，加载了一个residemenu的布局,先看布局\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;!--?xml version=``1.0` `encoding=utf-``8``?--\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `\u0026amp;lt;framelayout android:layout_height=``\u0026quot;match_parent\u0026quot;` `android:layout_width=``\u0026quot;match_parent\u0026quot;` `xmlns:android=``\u0026quot;\u0026amp;lt;a href=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;\u0026gt;http://schemas.android.com/apk/res/android\u0026amp;lt;/a\u0026gt;\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;imageview android:adjustviewbounds=``\u0026quot;true\u0026quot;` `android:id=``\u0026quot;@+id/iv_background\u0026quot;` `android:layout_height=``\u0026quot;match_parent/\u0026quot;` `android:layout_width=``\u0026quot;match_parent\u0026quot;` `android:scaletype=``\u0026quot;centerCrop\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;imageview android:background=``\u0026quot;@drawable/shadow\u0026quot;` `android:id=``\u0026quot;@+id/iv_shadow\u0026quot;` `android:layout_height=``\u0026quot;fill_parent\u0026quot;` `android:layout_width=``\u0026quot;fill_parent\u0026quot;` `android:scaletype=``\u0026quot;fitXY/\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;scrollview android:id=``\u0026quot;@+id/sv_left_menu\u0026quot;` `android:layout_height=``\u0026quot;fill_parent\u0026quot;` `android:layout_width=``\u0026quot;150dp\u0026quot;` `android:paddingleft=``\u0026quot;30dp\u0026quot;` `android:scrollbars=``\u0026quot;none\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;linearlayout android:id=``\u0026quot;@+id/layout_left_menu\u0026quot;` `android:layout_gravity=``\u0026quot;center_vertical\u0026quot;` `android:layout_height=``\u0026quot;wrap_content\u0026quot;` `android:layout_width=``\u0026quot;wrap_content\u0026quot;` `android:orientation=``\u0026quot;vertical\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;/linearlayout\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;/scrollview\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;scrollview android:id=``\u0026quot;@+id/sv_right_menu\u0026quot;` `android:layout_gravity=``\u0026quot;right\u0026quot;` `android:layout_height=``\u0026quot;fill_parent\u0026quot;` `android:layout_width=``\u0026quot;150dp\u0026quot;` `android:paddingright=``\u0026quot;30dp\u0026quot;` `android:scrollbars=``\u0026quot;none\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;linearlayout android:gravity=``\u0026quot;right\u0026quot;` `android:id=``\u0026quot;@+id/layout_right_menu\u0026quot;` `android:layout_gravity=``\u0026quot;center_vertical\u0026quot;` `android:layout_height=``\u0026quot;wrap_content\u0026quot;` `android:layout_width=``\u0026quot;wrap_content\u0026quot;` `android:orientation=``\u0026quot;vertical\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;/linearlayout\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;/scrollview\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; `\u0026amp;lt;/imageview\u0026amp;gt;\u0026amp;lt;/imageview\u0026amp;gt;\u0026amp;lt;/framelayout\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 布局显示效果\n![](http://www.2cto.com/uploadfile/Collfiles/20140911/20140911091423127.png)\n从布局文件，以及显示效果我们可以看到，它是一个帧布局，第一个ImageView是背景，第二个ImageView是.9的阴影效果的图片（看下面的图），\n两个（ScrollView包裹着一个LinerLayout），可以从上面图看到结构分别是左菜单和右菜单\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 1.初始化布局以及布局文件分析完毕，2.接下来是设置背景图，初始化view的时候就已经拿到了背景控件，所以设置背景图也是非常好实现的事情了。\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `void` `setBackground(``int` `imageResrouce){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``imageViewBackground.setImageResource(imageResrouce);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 3.绑定activity，思考问题：它做了什么？\n[?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``* use the method to set up the activity which residemenu need to show;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``* @param activity` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``public` `void` `attachToActivity(Activity activity){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``initValue(activity);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``setShadowAdjustScaleXByOrientation();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``viewDecor.addView(``this``, ````);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``setViewPadding();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 原理分析：绑定activity做了4件事情，分别是： \u0026amp;nbsp; 1.初始化参数: \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_491650\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `private` `void` `initValue(Activity activity){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``this``.activity = activity;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``leftMenuItems = ``new` `ArrayList\u0026amp;lt;residemenuitem\u0026amp;gt;();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``rightMenuItems = ``new` `ArrayList\u0026amp;lt;residemenuitem\u0026amp;gt;();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``ignoredViews = ``new` `ArrayList\u0026amp;lt;view\u0026amp;gt;();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``viewDecor = (ViewGroup) activity.getWindow().getDecorView();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``viewActivity = ``new` `TouchDisableView(``this``.activity);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``View mContent = viewDecor.getChildAt(````);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``viewDecor.removeViewAt(````);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``viewActivity.setContent(mContent);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``addView(viewActivity);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``ViewGroup parent = (ViewGroup) scrollViewLeftMenu.getParent();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``parent.removeView(scrollViewLeftMenu);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``parent.removeView(scrollViewRightMenu);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; `}\u0026amp;lt;/view\u0026amp;gt;\u0026amp;lt;/residemenuitem\u0026amp;gt;\u0026amp;lt;/residemenuitem\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; 2.正对横竖屏缩放比例进行调整 \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_875164\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `private` `void` `setShadowAdjustScaleXByOrientation(){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``int` `orientation = getResources().getConfiguration().orientation;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``if` `(orientation == Configuration.ORIENTATION_LANDSCAPE) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``shadowAdjustScaleX = ````.034f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``shadowAdjustScaleY = ````.12f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``} ``else` `if` `(orientation == Configuration.ORIENTATION_PORTRAIT) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``shadowAdjustScaleX = ````.06f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``shadowAdjustScaleY = ````.07f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; 3.添加当前view \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_800309\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `viewDecor.addView(``this``, ````);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; 4.设置view边距 \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_276247\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``* we need the call the method before the menu show, because the` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``* padding of activity can't get at the moment of onCreateView();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``private` `void` `setViewPadding(){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``this``.setPadding(viewActivity.getPaddingLeft(),` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``viewActivity.getPaddingTop(),` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``viewActivity.getPaddingRight(),` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``viewActivity.getPaddingBottom());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 4.设置监听，思考问题：它什么时候调用监听，原理分析：动画监听开始执行动画掉哦那个openMenu动画结束调用closeMenu，从此我们可以想到，但它调用openMenu(int direction)和closeMenu()都会设置这个监听。 \u0026amp;nbsp; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_50179\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `private` `Animator.AnimatorListener animationListener = ``new` `Animator.AnimatorListener() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``public` `void` `onAnimationStart(Animator animation) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``if` `(isOpened()){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``showScrollViewMenu();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``if` `(menuListener != ``null``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``menuListener.openMenu();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``public` `void` `onAnimationEnd(Animator animation) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``// reset the view;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``if``(isOpened()){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``viewActivity.setTouchDisable(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``viewActivity.setOnClickListener(viewActivityOnClickListener);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``}``else``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``viewActivity.setTouchDisable(``false``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``viewActivity.setOnClickListener(``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``hideScrollViewMenu();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``if` `(menuListener != ``null``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``menuListener.closeMenu();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``public` `void` `onAnimationCancel(Animator animation) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ``public` `void` `onAnimationRepeat(Animator animation) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``};` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 5.设置内容缩放比例（0.1~1f），细心的同学会发现在当缩完成后还可以在往里面拉到更小，有种弹性的感觉，挺有趣的。但是有些人的需求不想要有这种弹性效果，我们可以通过修改源码修改这个弹性效果，找到getTargetScale这个方法，修改下面0.5这个数值。使用时设置了0.6的缩放比例，默认下面的弹性参数是0.5所以我们当缩完成后还可以在往里面拉0.1的比例。 \u0026amp;nbsp; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_849856\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `private` `float` `getTargetScale(``float` `currentRawX){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``float` `scaleFloatX = ((currentRawX - lastRawX) / getScreenWidth()) * ````.75f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``scaleFloatX = scaleDirection == DIRECTION_RIGHT ? - scaleFloatX : scaleFloatX;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``float` `targetScale = ViewHelper.getScaleX(viewActivity) - scaleFloatX;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``targetScale = targetScale \u0026amp;gt; ``1``.0f ? ``1``.0f : targetScale;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``targetScale = targetScale \u0026amp;lt; ````.5f ? ````.5f : targetScale;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``return` `targetScale;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; 默认缩放比例： \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_387269\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `//valid scale factor is between 0.0f and 1.0f.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``private` `float` `mScaleValue = ````.5f;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_786345\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `AnimatorSet scaleDown_activity = buildScaleDownAnimation(viewActivity, mScaleValue, mScaleValue);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_737569\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``* a helper method to build scale down animation;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``* @param target` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``* @param targetScaleX` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``* @param targetScaleY` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``* @return` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``private` `AnimatorSet buildScaleDownAnimation(View target,``float` `targetScaleX,``float` `targetScaleY){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``AnimatorSet scaleDown = ``new` `AnimatorSet();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``scaleDown.playTogether(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``ObjectAnimator.ofFloat(target, scaleX, targetScaleX),` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``ObjectAnimator.ofFloat(target, scaleY, targetScaleY)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``scaleDown.setInterpolator(AnimationUtils.loadInterpolator(activity,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``android.R.anim.decelerate_interpolator));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``scaleDown.setDuration(``250``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``return` `scaleDown;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 6.创建子菜单，看下子菜单的构造，我们通过上面的学习，原理分析：我们可以猜测到，无非就是加载布局设置内容 \u0026amp;nbsp; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_727811\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `ResideMenuItem(Context context, ``int` `icon, String title) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``super``(context);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``initViews(context);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``iv_icon.setImageResource(icon);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``tv_title.setText(title);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``private` `void` `initViews(Context context){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``LayoutInflater inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``inflater.inflate(R.layout.residemenu_item, ``this``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``iv_icon = (ImageView) findViewById(R.id.iv_icon);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``tv_title = (TextView) findViewById(R.id.tv_title);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 布局文件： \u0026amp;nbsp; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_266937\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;!--?xml version=``1.0` `encoding=utf-``8``?--\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `\u0026amp;lt;linearlayout android:gravity=``\u0026quot;center_vertical\u0026quot;` `android:layout_height=``\u0026quot;wrap_content\u0026quot;` `android:layout_width=``\u0026quot;match_parent\u0026quot;` `android:orientation=``\u0026quot;horizontal\u0026quot;` `android:paddingtop=``\u0026quot;30dp\u0026quot;` `xmlns:android=``\u0026quot;\u0026amp;lt;a href=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;\u0026gt;http://schemas.android.com/apk/res/android\u0026amp;lt;/a\u0026gt;\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;imageview android:id=``\u0026quot;@+id/iv_icon/\u0026quot;` `android:layout_height=``\u0026quot;30dp\u0026quot;` `android:layout_width=``\u0026quot;30dp\u0026quot;` `android:scaletype=``\u0026quot;centerCrop\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;textview android:id=``\u0026quot;@+id/tv_title/\u0026quot;` `android:layout_height=``\u0026quot;wrap_content\u0026quot;` `android:layout_marginleft=``\u0026quot;10dp\u0026quot;` `android:layout_width=``\u0026quot;match_parent\u0026quot;` `android:textcolor=``\u0026quot;@android:color/white\u0026quot;` `android:textsize=``\u0026quot;18sp\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; `\u0026amp;lt;/textview\u0026amp;gt;\u0026amp;lt;/imageview\u0026amp;gt;\u0026amp;lt;/linearlayout\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; 显示效果图： ![\\](http://www.2cto.com/uploadfile/Collfiles/20140911/20140911091424130.png) 7.子菜单添加到侧换菜单中（可以看到它是通过常量来控制子菜单的添加位置）原理分析：根据不同的常量来区分添加不同菜单的子菜单 \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_947418\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``* add a single items;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``* @param menuItem` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``* @param direction` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``public` `void` `addMenuItem(ResideMenuItem menuItem, ``int` `direction){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``if` `(direction == DIRECTION_LEFT){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``this``.leftMenuItems.add(menuItem);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``layoutLeftMenu.addView(menuItem);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``}``else``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``this``.rightMenuItems.add(menuItem);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``layoutRightMenu.addView(menuItem);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 8.设置title按钮的点击事件，设置左右菜单的开关，原理分析：先设置了缩放方向然后在设置动画，正如我们上面想的一样还设置了动画监听。 \u0026amp;nbsp; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_968606\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``* show the reside menu;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `public` `void` `openMenu(``int` `direction){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``setScaleDirection(direction);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``isOpened = ``true``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``AnimatorSet scaleDown_activity = buildScaleDownAnimation(viewActivity, mScaleValue, mScaleValue);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``AnimatorSet scaleDown_shadow = buildScaleDownAnimation(imageViewShadow,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``mScaleValue + shadowAdjustScaleX, mScaleValue + shadowAdjustScaleY);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``AnimatorSet alpha_menu = buildMenuAnimation(scrollViewMenu, ``1``.0f);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``scaleDown_shadow.addListener(animationListener);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``scaleDown_activity.playTogether(scaleDown_shadow);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``scaleDown_activity.playTogether(alpha_menu);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``scaleDown_activity.start();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 设置缩放方向及计算x，y轴位置。 \u0026amp;nbsp; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_444663\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `private` `void` `setScaleDirection(``int` `direction){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``int` `screenWidth = getScreenWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``float` `pivotX;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``float` `pivotY = getScreenHeight() * ````.5f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``if` `(direction == DIRECTION_LEFT){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``scrollViewMenu = scrollViewLeftMenu;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``pivotX = screenWidth * ``1``.5f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``}``else``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``scrollViewMenu = scrollViewRightMenu;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``pivotX = screenWidth * -````.5f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``ViewHelper.setPivotX(viewActivity, pivotX);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``ViewHelper.setPivotY(viewActivity, pivotY);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``ViewHelper.setPivotX(imageViewShadow, pivotX);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``ViewHelper.setPivotY(imageViewShadow, pivotY);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``scaleDirection = direction;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 9.重写dispatchTouchEvent，问题思考：如何到根据手指滑动自动缩放 \u0026amp;nbsp; 如果还不了解，dispatchTouchEvent这个函数如何调用？什么时候调用？请先看看http://blog.csdn.net/cym492224103/article/details/39179311 \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_475966\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; 51 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; 52 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; 53 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; 54 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; 55 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; 56 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; 57 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; 58 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; 59 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; 60 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; 61 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; 62 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; 63 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; 64 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; 65 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; 66 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; 67 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; 68 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; 69 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; 70 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; 71 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; 72 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; 73 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; 74 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; 75 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; 76 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `public` `boolean` `dispatchTouchEvent(MotionEvent ev) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``float` `currentActivityScaleX = ViewHelper.getScaleX(viewActivity);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``if` `(currentActivityScaleX == ``1``.0f)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``setScaleDirectionByRawX(ev.getRawX());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``switch` `(ev.getAction()){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``case` `MotionEvent.ACTION_DOWN:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``lastActionDownX = ev.getX();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``lastActionDownY = ev.getY();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``isInIgnoredView = isInIgnoredView(ev) \u0026amp;\u0026amp; !isOpened();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``pressedState = PRESSED_DOWN;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``case` `MotionEvent.ACTION_MOVE:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``if` `(isInIgnoredView || isInDisableDirection(scaleDirection))` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``if``(pressedState != PRESSED_DOWN \u0026amp;\u0026amp;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``pressedState != PRESSED_MOVE_HORIZANTAL)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``int` `xOffset = (``int``) (ev.getX() - lastActionDownX);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``int` `yOffset = (``int``) (ev.getY() - lastActionDownY);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``if``(pressedState == PRESSED_DOWN) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``if``(yOffset \u0026amp;gt; ``25` `|| yOffset \u0026amp;lt; -``25``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ``pressedState = PRESSED_MOVE_VERTICAL;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``if``(xOffset \u0026amp;lt; -``50` `|| xOffset \u0026amp;gt; ``50``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ``pressedState = PRESSED_MOVE_HORIZANTAL;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ``ev.setAction(MotionEvent.ACTION_CANCEL);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``} ``else` `if``(pressedState == PRESSED_MOVE_HORIZANTAL) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; ` ``if` `(currentActivityScaleX \u0026amp;lt; ``0.95``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; ` ``showScrollViewMenu();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; ` ``float` `targetScale = getTargetScale(ev.getRawX());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; ` ``ViewHelper.setScaleX(viewActivity, targetScale);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; ` ``ViewHelper.setScaleY(viewActivity, targetScale);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; ` ``ViewHelper.setScaleX(imageViewShadow, targetScale + shadowAdjustScaleX);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; ` ``ViewHelper.setScaleY(imageViewShadow, targetScale + shadowAdjustScaleY);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; ` ``ViewHelper.setAlpha(scrollViewMenu, (``1` `- targetScale) * ``2``.0f);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; ` ``lastRawX = ev.getRawX();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; ` ``return` `true``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; ` ``case` `MotionEvent.ACTION_UP:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; ` ``if` `(isInIgnoredView) ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; ` ``if` `(pressedState != PRESSED_MOVE_HORIZANTAL) ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; ` ``pressedState = PRESSED_DONE;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; ` ``if` `(isOpened()){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; ` ``if` `(currentActivityScaleX \u0026amp;gt; ````.56f)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; ` ``closeMenu();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; ` ``else` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; ` ``openMenu(scaleDirection);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; ` ``}``else``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; ` ``if` `(currentActivityScaleX \u0026amp;lt; ````.94f){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; ` ``openMenu(scaleDirection);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; ` ``}``else``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; ` ``closeMenu();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; ` ``lastRawX = ev.getRawX();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; ` ``return` `super``.dispatchTouchEvent(ev);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 上面代码量有点多，看上去有点晕，接下来我们来分别从按下、移动、放开、来原理分析： \u0026amp;nbsp; MotionEvent.ACTION_DOWN: 记录了X，Y轴的坐标点，判断是否打开，设置了按下的状态为PRESSED_DOWN MotionEvent.ACTION_MOVE: 拿到当前X,Y减去DOWN下记录下来的X,Y，这样得到了移动的X,Y， 然后判断如果如果移动的X,Y大于25或者小于-25就改变按下状态为PRESSED_MOVE_VERTICAL 如果移动的X,Y大于50或者小于-50就改变状态为PRESSED_MOVE_HORIZANTAL 状态为PRESSED_MOVE_HORIZANTAL就改变菜单主视图内容以及阴影图片大小，在改变的同时还设置了当前菜单的透明度。 MotionEvent.ACTION_UP: 判断是否菜单是否打开状态，在获取当前缩放的X比例， 判断比例小于0.56f,则关闭菜单，反正开启菜单。 看完后，我们在回去看看代码，就会发现其实也不过如此~！ 10.菜单关闭方法，同样也设置了动画监听之前的想法也是成立的。 \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_197589\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``* close the reslide menu;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``public` `void` `closeMenu(){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``isOpened = ``false``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``AnimatorSet scaleUp_activity = buildScaleUpAnimation(viewActivity, ``1``.0f, ``1``.0f);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``AnimatorSet scaleUp_shadow = buildScaleUpAnimation(imageViewShadow, ``1``.0f, ``1``.0f);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``AnimatorSet alpha_menu = buildMenuAnimation(scrollViewMenu, ````.0f);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``scaleUp_activity.addListener(animationListener);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``scaleUp_activity.playTogether(scaleUp_shadow);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``scaleUp_activity.playTogether(alpha_menu);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``scaleUp_activity.start();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 11.屏蔽菜单方法 \u0026amp;nbsp; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_622781\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `void` `setSwipeDirectionDisable(``int` `direction){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``disabledSwipeDirection.add(direction);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_971803\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `private` `boolean` `isInDisableDirection(``int` `direction){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``return` `disabledSwipeDirection.contains(direction);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 原理分析：在重写dispatchTouchEvent的时候，细心的同学应该会看到，ACTION_MOVE下面有个判断 \u0026amp;nbsp; \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_907157\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `if` `(isInIgnoredView || isInDisableDirection(scaleDirection))` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 如果这个方向的菜单被屏蔽了，就滑不出来了。 \u0026amp;nbsp; 最后我们会发现我们一直都没说到TouchDisableView，其实initValue的时候就初始化了，它就是viewActivity，是我们的内容视图。 ![\\](http://www.2cto.com/uploadfile/Collfiles/20140911/20140911091424131.png) 我们来看看它做了什么？ \u0026lt;div\u0026gt; \u0026lt;div id=\u0026quot;highlighter_627811\u0026quot; class=\u0026quot;syntaxhighlighter java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;toolbar\u0026quot;\u0026gt; [?](http://www.2cto.com/kf/201409/332224.html#) \u0026lt;/div\u0026gt; \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``protected` `void` `onMeasure(``int` `widthMeasureSpec, ``int` `heightMeasureSpec) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``int` `width = getDefaultSize(````, widthMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``int` `height = getDefaultSize(````, heightMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``setMeasuredDimension(width, height);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``final` `int` `contentWidth = getChildMeasureSpec(widthMeasureSpec, ````, width);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``final` `int` `contentHeight = getChildMeasureSpec(heightMeasureSpec, ````, height);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``mContent.measure(contentWidth, contentHeight);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``protected` `void` `onLayout(``boolean` `changed, ``int` `l, ``int` `t, ``int` `r, ``int` `b) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``final` `int` `width = r - l;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``final` `int` `height = b - t;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``mContent.layout(````, ````, width, height);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``public` `boolean` `onInterceptTouchEvent(MotionEvent ev) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``return` `mTouchDisabled;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``void` `setTouchDisable(``boolean` `disableTouch) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``mTouchDisabled = disableTouch;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``boolean` `isTouchDisabled() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ``return` `mTouchDisabled;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 动态设置宽高，设置事件是否传递下去的flag。 \u0026amp;nbsp; ","permalink":"https://blog.zdltech.com/posts/ym-android%E4%BB%BFqq5-0%E4%BE%A7%E6%BB%91%E8%8F%9C%E5%8D%95residemenu%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/","summary":"\u003cp\u003eAndroidResideMenu\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e![](http://www.2cto.com/uploadfile/Collfiles/20140911/20140911091421122.gif)\u003c/p\u003e\n\u003cp\u003e先看看如何使用：\u003c/p\u003e\n\u003cp\u003e把项目源码\u003ca href=\"http://www.2cto.com/soft\"\u003e下载\u003c/a\u003e下来导入工程，可以看到\u003c/p\u003e\n\u003cp\u003e![](http://www.2cto.com/uploadfile/Collfiles/20140911/20140911091422123.jpg)\u003c/p\u003e\n\u003cp\u003eResideMenu为引用工程，再看看如何使用这个引用工程来构建出ResideMenu，\u003c/p\u003e\n\u003cp\u003e1.先new一个ResideMenu对象\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_117755\" class=\"syntaxhighlighter  java\"\u003e\n    \u003cdiv class=\"toolbar\"\u003e\n      [?](http://www.2cto.com/kf/201409/332224.html#)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n  \u0026lt;tr\u0026gt;\n    \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n        1\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `resideMenu = ``new` `ResideMenu(``this``);`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e2.设置它的背景图片\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_863755\" class=\"syntaxhighlighter  java\"\u003e\n    \u003cdiv class=\"toolbar\"\u003e\n      [?](http://www.2cto.com/kf/201409/332224.html#)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n  \u0026lt;tr\u0026gt;\n    \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n        1\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `resideMenu.setBackground(R.drawable.menu_background);`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e3.绑定当前Activity\u003c/p\u003e","title":"ym——Android仿QQ5.0侧滑菜单ResideMenu源码分析"},{"content":"转载出处：http://blog.csdn.net/lmj623565791/article/details/39185641\n侧滑菜单在很多应用中都会见到，最近QQ5.0侧滑还玩了点花样对于侧滑菜单，一般大家都会自定义ViewGroup，然后隐藏菜单栏，当手指滑动时，通过Scroller或者不断的改变leftMargin等实现；多少都有点复杂，完成以后还需要对滑动冲突等进行处理今天给大家带来一个简单的实现，史上最简单有点夸张，但是的确是我目前遇到过的最简单的一种实现~~~\n1、原理分析 既然是侧滑，无非就是在巴掌大的屏幕，塞入大概两巴掌大的布局，需要滑动可以出现另一个，既然这样，大家为啥不考虑使用Android提供的HorizontalScrollView呢~\n如果使用HorizontalScrollView，还需要在ACTION_DOWN , ACTION_MOVE里面去监听，判断，不断改变控件位置了么? NO！！！HorizontalScrollView本身就带了滑动的功能~~\n还需要自己的手动处理各种冲突么？NO！！！当然了，还是需要了解下事件分发机制的~~~\n2、效果图 嗯，主界面搞了QQ一张图片，左边盗用了一兄弟的布局文件罪过 谁有好看的布局、图片、图标神马的，可以给我发点，感激~\n3、布局文件 **[html]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39185641#)[copy](http://blog.csdn.net/lmj623565791/article/details/39185641#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.zhy_slidingmenu.SlidingMenu\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scrollbars\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;none\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;include\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;layout\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@layout/layout_menu\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/qq\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.zhy_slidingmenu.SlidingMenu\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 首先是我们的自定义View，里面一个方向水平的LinearLayout，然后就是一个是菜单的布局，一个是主布局了~\n4、自定义SlidingMenu 接下来就是我们最核心的代码了~\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39185641#)[copy](http://blog.csdn.net/lmj623565791/article/details/39185641#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.zhy_slidingmenu; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.TypedValue; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.HorizontalScrollView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.utils.ScreenUtils; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SlidingMenu \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; HorizontalScrollView - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 屏幕宽度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mScreenWidth; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * dp\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMenuRightPadding = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;50\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 菜单的宽度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMenuWidth; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mHalfMenuWidth; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; once; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SlidingMenu(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); - mScreenWidth = ScreenUtils.getScreenWidth(context); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 显示的设置一个宽度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!once) - { - LinearLayout wrapper = (LinearLayout) getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - ViewGroup menu = (ViewGroup) wrapper.getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - ViewGroup content = (ViewGroup) wrapper.getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// dp to px\u0026lt;/span\u0026gt; - mMenuRightPadding = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, mMenuRightPadding, content - .getResources().getDisplayMetrics()); - - mHalfMenuWidth = mMenuWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - menu.getLayoutParams().width = mMenuWidth; - content.getLayoutParams().width = mScreenWidth; - - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMeasure(widthMeasureSpec, heightMeasureSpec); - - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onLayout(changed, l, t, r, b); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (changed) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 将菜单隐藏\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.scrollTo(mMenuWidth, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - once = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent ev) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; action = ev.getAction(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (action) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Up时，进行判断，如果显示区域大于菜单宽度一半则完全显示，否则隐藏\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollX = getScrollX(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (scrollX \u0026gt; mHalfMenuWidth) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(mMenuWidth, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev); - } - - } 哈哈，完工~上面的演示图，就用到这么点代码~~\n代码怎么样，短不短除了设置宽度这些杂七杂八的代码正在处理滑动的代码不过10行~~我说史上最简单不为过吧~\n嗯，由于代码过于短，就不解释了，大家自己看下注释~\n5、扩展 嗯，就下来，我们完善下程序，我准备首先把菜单布局里面改成ListView来证明我们是没有冲突的；然后添加一个属性让用户配置菜单距离右边的边距的值；再对外公布一个方法，点击自动打开菜单，供用户点击某个按钮，菜单慢慢滑出来~\n1、添加自定义属性 a、首先在values文件夹下新建一个attr.xml，写入以下内容：\n**[html]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39185641#)[copy](http://blog.csdn.net/lmj623565791/article/details/39185641#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;attr\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;rightPadding\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;format\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;dimension\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;declare-styleable\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;SlidingMenu\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;attr\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;rightPadding\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;declare-styleable\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; b、在布局中声明命名空间和使用属性\n定义完了，肯定要使用么。\n**[html]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39185641#)[copy](http://blog.csdn.net/lmj623565791/article/details/39185641#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.zhy_slidingmenu.SlidingMenu\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:zhy\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/com.example.zhy_slidingmenu\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scrollbars\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;none\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;zhy:rightPadding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;100dp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 可以看到我们的命名空间：xmlns:zhy=”http://schemas.android.com/apk/res/com.example.zhy_slidingmenu” 是http://schemas.android.com/apk/res/加上我们的包名；\n我们的属性：zhy:rightPadding=”100dp”这里我设置了100dp；\n注：很多人问我，没有提示咋办，这样，你clean下项目，如果你运气好，就有提示了，嗯，运气好~\nc、在我们自定义类中获得属性\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39185641#)[copy](http://blog.csdn.net/lmj623565791/article/details/39185641#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SlidingMenu(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - mScreenWidth = ScreenUtils.getScreenWidth(context); - - TypedArray a = context.getTheme().obtainStyledAttributes(attrs, - R.styleable.SlidingMenu, defStyle, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; n = a.getIndexCount(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; n; i++) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; attr = a.getIndex(i); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (attr) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.styleable.SlidingMenu_rightPadding: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 默认50\u0026lt;/span\u0026gt; - mMenuRightPadding = a.getDimensionPixelSize(attr, - (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, 50f, - getResources().getDisplayMetrics()));\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 默认为10DP\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - a.recycle(); - } 在三个参数的构造方法中，通过TypeArray获取就行了~\n好了，这样就行了~如果你又很多自定义属性，按照上面的步骤来就行了~~\n2、对外公布一个打开菜单的方法 首先定义一个boolean isOpen变量，用来标识我们当前菜单的状态~~然后记得在ACTION_UP的时候改变下状态：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39185641#)[copy](http://blog.csdn.net/lmj623565791/article/details/39185641#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollX = getScrollX(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (scrollX \u0026gt; mHalfMenuWidth) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(mMenuWidth, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - isOpen = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - isOpen = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } 下面开始添加方法：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39185641#)[copy](http://blog.csdn.net/lmj623565791/article/details/39185641#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 打开菜单\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; openMenu() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isOpen) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - isOpen = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 关闭菜单\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; closeMenu() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isOpen) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(mMenuWidth, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - isOpen = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 切换菜单状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; toggle() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isOpen) - { - closeMenu(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - { - openMenu(); - } - } 顺手多添加了两个。。。\n下面，我们挑一个进行测试：\n主布局多添加一个按钮，用于触发toggleMenu（）方法\n主Activity\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39185641#)[copy](http://blog.csdn.net/lmj623565791/article/details/39185641#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; SlidingMenu mMenu ; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.activity_main); - mMenu = (SlidingMenu) findViewById(R.id.id_menu); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; toggleMenu(View view) - { - mMenu.toggle(); - } - } 好了，看下现在的效果图：\n我们把padding改成了100dp~\n然后点击我们的按钮，看哈效果~~\n3、添加ListView测试 好了ListView也测试完了大家可以根据自己的需求各种修改~~\n对了，今天测试用QQ的目的是为了，下次我要拿上面的代码，改造和QQ5.0一模一样的效果，大家有兴趣可以提前试一试，QQ的菜单好像是隐藏在主界面下面一样，给人感觉不是划出来的，我们这个例子也能做出那样的效果，拭目以待吧；剩下就是各种缩放，透明度的动画了~~~\n源码点击下载\n如果觉得不错，评价下哈\n———————————————————————————————————-\n博主部分视频已经上线，如果你不喜欢枯燥的文本，请猛戳（初录，期待您的支持）：\n1、高仿微信5.2.1主界面及消息提醒\n2、高仿QQ5.0侧滑\n3、Android智能机器人“小慕”的实现\n4、Android自定义控件 打造Android流式布局和热门标签\n","permalink":"https://blog.zdltech.com/posts/android-%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6%E6%89%93%E9%80%A0%E5%8F%B2%E4%B8%8A%E6%9C%80%E7%AE%80%E5%8D%95%E7%9A%84%E4%BE%A7%E6%BB%91%E8%8F%9C%E5%8D%95/","summary":"\u003cp\u003e转载出处：\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/39185641\"\u003ehttp://blog.csdn.net/lmj623565791/article/details/39185641\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e侧滑菜单在很多应用中都会见到，最近QQ5.0侧滑还玩了点花样\u003cdel\u003e对于侧滑菜单，一般大家都会自定义ViewGroup，然后隐藏菜单栏，当手指滑动时，通过Scroller或者不断的改变leftMargin等实现；多少都有点复杂，完成以后还需要对滑动冲突等进行处理\u003c/del\u003e今天给大家带来一个简单的实现，史上最简单有点夸张，但是的确是我目前遇到过的最简单的一种实现~~~\u003c/p\u003e\n\u003ch1 id=\"1原理分析\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003e1、原理分析\u003c/h1\u003e\n\u003cp\u003e既然是侧滑，无非就是在巴掌大的屏幕，塞入大概两巴掌大的布局，需要滑动可以出现另一个，既然这样，大家为啥不考虑使用Android提供的HorizontalScrollView呢~\u003c/p\u003e\n\u003cp\u003e如果使用HorizontalScrollView，还需要在ACTION_DOWN , ACTION_MOVE里面去监听，判断，不断改变控件位置了么? NO！！！HorizontalScrollView本身就带了滑动的功能~~\u003c/p\u003e\n\u003cp\u003e还需要自己的手动处理各种冲突么？NO！！！当然了，还是需要了解下事件分发机制的~~~\u003c/p\u003e\n\u003ch1 id=\"2效果图\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e2、效果图\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.my.csdn.net/uploads/201409/10/1410354714_6322.gif\"\u003e\u003c/p\u003e\n\u003cp\u003e嗯，主界面搞了QQ一张图片，左边盗用了一兄弟的布局文件\u003cdel\u003e罪过\u003c/del\u003e 谁有好看的布局、图片、图标神马的，可以给我发点，感激~\u003c/p\u003e\n\u003ch1 id=\"3布局文件\"\u003e\u003ca name=\"t2\"\u003e\u003c/a\u003e3、布局文件\u003c/h1\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39185641#)[copy](http://blog.csdn.net/lmj623565791/article/details/39185641#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.zhy_slidingmenu.SlidingMenu\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scrollbars\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;none\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;include\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;layout\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@layout/layout_menu\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/qq\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.example.zhy_slidingmenu.SlidingMenu\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e首先是我们的自定义View，里面一个方向水平的LinearLayout，然后就是一个是菜单的布局，一个是主布局了~\u003c/p\u003e","title":"Android 自定义控件打造史上最简单的侧滑菜单"},{"content":"转载出处：http://blog.csdn.net/lmj623565791/article/details/39257409\n上一篇博客带大家实现了：Android 自定义控件打造史上最简单的侧滑菜单 ，有兄弟看了以后说，你这滑动菜单过时了呀~QQ5.0的效果还不错嗯，的确，上一篇也承诺过，稍微修改上一篇的代码，实现QQ5.0侧滑菜单好了，下面就开始为大家展示写一个类QQ的侧滑有多easy ~!\n1、原理分析 首先对比一下我们上篇的实现距离QQ的效果还有多远：\n差距还是蛮大的\n区别1、QQ的内容区域会伴随菜单的出现而缩小\n区别2、QQ的侧滑菜单给人的感觉是隐藏在内容的后面，而不是拖出来的感觉\n区别3、QQ的侧滑菜单有一个缩放以及透明度的效果~\n那么我们如何能做到呢：\n对于区别1：这个好办，我们可以在滑动的时候，不断的改变内容区域的大小；如何改变呢？我们在菜单出现的整个过程中，不断记录菜单显示的宽度与其总宽度的比值，是个从0到1的过程，然后把01转化为10.7（假设内容区域缩小至0.7)；不断去缩小内容区域；\n对于区别3：也比较好办，上面已经可以得到0到1的这个值了，那么缩放和透明度的动画就不在话下了；\n对于区别2：我们使用的HorizontalScrollView，然后水平放置了菜单和内容，如何让菜单可以隐藏到内容的后面呢？其实也比较简单，在菜单出现的过程中，不断设置菜单的x方向的偏移量；0的时候完全隐藏，0.3的时候，隐藏x方向偏移量为0.7个宽度，类推~~~\n好了，分析完毕，那么对于这些动画用什么实现最好呢？\n想都不用想，属性动画哈，如果你对属性动画不了解，可以参：Android 属性动画（Property Animation） 完全解析 （上）和Android 属性动画（Property Animation） 完全解析 （下）\n2、实现 1、初步的代码 布局文件神马的，都和上一篇一模一样，这里就不重复贴代码了，不了解的，先看下上一篇；\n先看一下上一篇我们已经实现的完整代码：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39257409#)[copy](http://blog.csdn.net/lmj623565791/article/details/39257409#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/468874)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/468874/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.zhy_slidingmenu; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.res.TypedArray; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.TypedValue; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.HorizontalScrollView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.utils.ScreenUtils; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SlidingMenu \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; HorizontalScrollView - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 屏幕宽度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mScreenWidth; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * dp\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMenuRightPadding; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 菜单的宽度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMenuWidth; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mHalfMenuWidth; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isOpen; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; once; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SlidingMenu(Context context, AttributeSet attrs) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, attrs, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SlidingMenu(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); - mScreenWidth = ScreenUtils.getScreenWidth(context); - - TypedArray a = context.getTheme().obtainStyledAttributes(attrs, - R.styleable.SlidingMenu, defStyle, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; n = a.getIndexCount(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; n; i++) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; attr = a.getIndex(i); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (attr) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.styleable.SlidingMenu_rightPadding: - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 默认50\u0026lt;/span\u0026gt; - mMenuRightPadding = a.getDimensionPixelSize(attr, - (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, 50f, - getResources().getDisplayMetrics()));\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 默认为10DP\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - a.recycle(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SlidingMenu(Context context) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 显示的设置一个宽度\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!once) - { - LinearLayout wrapper = (LinearLayout) getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - ViewGroup menu = (ViewGroup) wrapper.getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - ViewGroup content = (ViewGroup) wrapper.getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - - mMenuWidth = mScreenWidth \u0026amp;#8211; mMenuRightPadding; - mHalfMenuWidth = mMenuWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - menu.getLayoutParams().width = mMenuWidth; - content.getLayoutParams().width = mScreenWidth; - - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMeasure(widthMeasureSpec, heightMeasureSpec); - - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onLayout(changed, l, t, r, b); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (changed) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 将菜单隐藏\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.scrollTo(mMenuWidth, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - once = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent ev) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; action = ev.getAction(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (action) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Up时，进行判断，如果显示区域大于菜单宽度一半则完全显示，否则隐藏\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollX = getScrollX(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (scrollX \u0026gt; mHalfMenuWidth) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(mMenuWidth, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - isOpen = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - isOpen = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 打开菜单\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; openMenu() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isOpen) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - isOpen = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 关闭菜单\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; closeMenu() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isOpen) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(mMenuWidth, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - isOpen = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 切换菜单状态\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; toggle() - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isOpen) - { - closeMenu(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - { - openMenu(); - } - } - - - - } 利用HorizontalScrollView，监听了ACTION_UP的事件，当用户抬起手指时，根据当前菜单显示的宽度值，判断是缩回还是完全展开；给用户提供了一个rightPadding属性，用于设置菜单离右屏幕的距离；以及对外提供了打开，关闭，切换的几个方法；具体的讲解看下上篇博客了；\n2、实现的思路 现在我们开始解决那3个区别，已经选择了使用属性动画，现在决定动画效果应该加在哪儿？\n不用说，我用大腿想一想都应该是在ACTION_MOVE中，是的，ACTION_MOVE中的确可以，不断获取当前的getScrollX / mMenuWidth，不断改变菜单的透明度，缩放，X方向的偏移量；不断改变内容区域的宽度和高度；\n说一下，起初我也是在MOVE中这么做的，但是呢，出现两个问题：\n1、动画效果并不是很流畅，特别是菜单，有抖动的效果；\n2、用户抬起后，还需要在UP里面，继续未完成的动画，就是说，你的透明度、缩放神马的，当用户抬起以后就需要自动变化了；\n于是乎，我就开始换了个方向，既然是SrollView，肯定有一个ScrollChanged方法，功夫不负有心人，真心这么个方法：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39257409#)[copy](http://blog.csdn.net/lmj623565791/article/details/39257409#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/468874)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/468874/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onScrollChanged(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldl, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldt) - { - - } 这个方法只要scrollChanged就会触发，l就是我们需要的scrollX，太赞了~~~\n3、动画比例的计算 我们在onScrollChanged里面，拿到 l 也就是个getScrollX，即菜单已经显示的宽度值；\n**[html]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39257409#)[copy](http://blog.csdn.net/lmj623565791/article/details/39257409#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/468874)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/468874/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;scale\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;l\u0026lt;/span\u0026gt; * 1.0f / mMenuWidth; 与菜单的宽度做除法运算，在菜单隐藏到显示整个过程，会得到1.0~0.0这么个变化的区间；\n有了这个区间，就可以根据这个区间设置动画了；\n1、首先是内容区域的缩放比例计算：\n我们准备让在菜单出现的过程中，让内容区域从1.0~0.8进行变化~~\n那么怎么把1.00.0转化为1.00.8呢，其实很简单了：\nfloat rightScale = 0.8f + scale * 0.2f; （scale 从1到0 ），是不是哦了~\n接下来还有3个动画：\n2、菜单的缩放比例计算\n仔细观察了下QQ，菜单大概缩放变化是0.7~1.0\nfloat leftScale = 1 – 0.3f * scale;\n3、菜单的透明度比例：\n我们设置为0.6~1.0；即：0.6f + 0.4f * (1 – scale)\n4、菜单的x方向偏移量：\n看一下QQ，并非完全从被内容区域覆盖，还是有一点拖出的感觉，所以我们的偏移量这么设置：\ntranlateX = mMenuWidth * scale * 0.6f ；刚开始还是让它隐藏一点点~~~\n4、完整的实现 说了这么多，其实到上一篇史上最简单的侧滑，到QQ5.0的效果的转变，只需要几行代码~~\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39257409#)[copy](http://blog.csdn.net/lmj623565791/article/details/39257409#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/468874)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/468874/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onScrollChanged(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldl, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldt) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onScrollChanged(l, t, oldl, oldt); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; scale = l * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f / mMenuWidth; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; leftScale = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.3f * scale; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; rightScale = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.8f + scale * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.2f; - - ViewHelper.setScaleX(mMenu, leftScale); - ViewHelper.setScaleY(mMenu, leftScale); - ViewHelper.setAlpha(mMenu, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.6f + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.4f * (\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; \u0026amp;#8211; scale)); - ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.6f); - - ViewHelper.setPivotX(mContent, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - ViewHelper.setPivotY(mContent, mContent.getHeight() / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); - ViewHelper.setScaleX(mContent, rightScale); - ViewHelper.setScaleY(mContent, rightScale); - - } 就这么几行。这里属性动画用的nineoldandroids为了保持向下的兼容；主要就是设置了各种动画，上面都详细说了~~~\n然后，记得把我们的菜单和内容的布局，单独声明出来为我们的mMenu ,mContent 没了，就改了这么几行\n3、效果图 是骡子是马，拉出来溜溜\n菜单栏需要ListView的拖动也是不会冲突了，上篇已经测试了；\n关于动画属性的范围：上面介绍的特别清楚，比如内容我们是最小显示0.8，你要是喜欢0.6，自己去修改一下；包括偏移量，透明度等范围；\n因为上一篇已经写了如何把属性抽取成自定义的属性；所以这里就没有抽取了，不然总觉得是在重复~\n嗯，最近还有写APP的侧滑，是这样的，就是菜单栏完全隐藏在内容区域下面，如果需要这样需求的：\n其实我还满喜欢这样效果的。\n实现呢，注释几行代码就实现了：\n**[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39257409#)[copy](http://blog.csdn.net/lmj623565791/article/details/39257409#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/468874)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/468874/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onScrollChanged(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldl, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldt) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onScrollChanged(l, t, oldl, oldt); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; scale = l * \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f / mMenuWidth; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// float leftScale = 1 \u0026amp;#8211; 0.3f * scale;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// float rightScale = 0.8f + scale * 0.2f;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// ViewHelper.setScaleX(mMenu, leftScale);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// ViewHelper.setScaleY(mMenu, leftScale);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// ViewHelper.setAlpha(mMenu, 0.6f + 0.4f * (1 \u0026amp;#8211; scale));\u0026lt;/span\u0026gt; - ViewHelper.setTranslationX(mMenu, mMenuWidth * scale ); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// ViewHelper.setPivotX(mContent, 0);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// ViewHelper.setScaleX(mContent, rightScale);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// ViewHelper.setScaleY(mContent, rightScale);\u0026lt;/span\u0026gt; - - } 好了，虽说最终的实现看起来还是很简单的，看起来，嗯但是从无到有的这个过程还是不容易的各种尝试，我能说我连蹲坑都在滑QQ的菜单观察么哈，见笑了；博客中也写出了过程中失败的尝试，希望能够更好的让大家在里面学到些有用的东西~~YEAH!! 就到这，没事就留个言~~~再不留言，我就来个源码请留下邮箱，嘿嘿，开个玩笑\n源码点击下载\n最后，我建了一个QQ群，方便大家交流。群号：55032675\n—————————————————————————————————————————————\n本博客内容视频版，已经上线，如果你不喜欢枯燥的文本，请猛戳：\n1、高仿微信5.2.1主界面及消息提醒\n2、高仿QQ5.0侧滑\n3、Android智能机器人“小慕”的实现\n4、Android自定义控件 打造Android流式布局和热门标签\n","permalink":"https://blog.zdltech.com/posts/android-%E9%AB%98%E4%BB%BF-qq-%E4%BE%A7%E6%BB%91%E8%8F%9C%E5%8D%95%E6%95%88%E6%9E%9C-%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6%E6%9D%A5%E8%A2%AD/","summary":"\u003cp\u003e转载出处：\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/39257409\"\u003ehttp://blog.csdn.net/lmj623565791/article/details/39257409\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e上一篇博客带大家实现了：\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/39185641\"\u003eAndroid 自定义控件打造史上最简单的侧滑菜单\u003c/a\u003e ，有兄弟看了以后说，你这滑动菜单过时了呀~QQ5.0的效果还不错\u003cdel\u003e嗯，的确，上一篇也承诺过，稍微修改上一篇的代码，实现QQ5.0侧滑菜单\u003c/del\u003e好了，下面就开始为大家展示写一个类QQ的侧滑有多easy ~!\u003c/p\u003e\n\u003ch1 id=\"1原理分析\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003e1、原理分析\u003c/h1\u003e\n\u003cp\u003e首先对比一下我们上篇的实现距离QQ的效果还有多远：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140913233249734?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG1qNjIzNTY1Nzkx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.my.csdn.net/uploads/201409/10/1410354714_6322.gif\"\u003e\u003c/p\u003e\n\u003cp\u003e差距还是蛮大的\u003c/p\u003e\n\u003cp\u003e区别1、QQ的内容区域会伴随菜单的出现而缩小\u003c/p\u003e\n\u003cp\u003e区别2、QQ的侧滑菜单给人的感觉是隐藏在内容的后面，而不是拖出来的感觉\u003c/p\u003e\n\u003cp\u003e区别3、QQ的侧滑菜单有一个缩放以及透明度的效果~\u003c/p\u003e\n\u003cp\u003e那么我们如何能做到呢：\u003c/p\u003e\n\u003cp\u003e对于区别1：这个好办，我们可以在滑动的时候，不断的改变内容区域的大小；如何改变呢？我们在菜单出现的整个过程中，不断记录菜单显示的宽度与其总宽度的比值，是个从0到1的过程，然后把0\u003cdel\u003e1转化为1\u003c/del\u003e0.7（假设内容区域缩小至0.7)；不断去缩小内容区域；\u003c/p\u003e\n\u003cp\u003e对于区别3：也比较好办，上面已经可以得到0到1的这个值了，那么缩放和透明度的动画就不在话下了；\u003c/p\u003e\n\u003cp\u003e对于区别2：我们使用的HorizontalScrollView，然后水平放置了菜单和内容，如何让菜单可以隐藏到内容的后面呢？其实也比较简单，在菜单出现的过程中，不断设置菜单的x方向的偏移量；0的时候完全隐藏，0.3的时候，隐藏x方向偏移量为0.7个宽度，类推~~~\u003c/p\u003e\n\u003cp\u003e好了，分析完毕，那么对于这些动画用什么实现最好呢？\u003c/p\u003e\n\u003cp\u003e想都不用想，属性动画哈，如果你对属性动画不了解，可以参：\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/38067475\"\u003eAndroid 属性动画（Property Animation） 完全解析 （上）\u003c/a\u003e和\u003ca href=\"http://blog.csdn.net/lmj623565791/article/details/38092093\"\u003eAndroid 属性动画（Property Animation） 完全解析 （下）\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"2实现\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e2、实现\u003c/h1\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch2 id=\"1初步的代码\"\u003e\u003ca name=\"t2\"\u003e\u003c/a\u003e1、初步的代码\u003c/h2\u003e\n\u003cp\u003e布局文件神马的，都和上一篇一模一样，这里就不重复贴代码了，不了解的，先看下上一篇；\u003c/p\u003e\n\u003cp\u003e先看一下上一篇我们已经实现的完整代码：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39257409#)[copy](http://blog.csdn.net/lmj623565791/article/details/39257409#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/468874)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/468874/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.zhy_slidingmenu;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.res.TypedArray;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.TypedValue;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.HorizontalScrollView;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.zhy.utils.ScreenUtils;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SlidingMenu \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; HorizontalScrollView\n\n- {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 屏幕宽度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mScreenWidth;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * dp\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMenuRightPadding;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 菜单的宽度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMenuWidth;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mHalfMenuWidth;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isOpen;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; once;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SlidingMenu(Context context, AttributeSet attrs)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, attrs, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- \n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SlidingMenu(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle);\n\n- mScreenWidth = ScreenUtils.getScreenWidth(context);\n\n- \n- TypedArray a = context.getTheme().obtainStyledAttributes(attrs,\n\n- R.styleable.SlidingMenu, defStyle, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; n = a.getIndexCount();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; n; i++)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; attr = a.getIndex(i);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (attr)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.styleable.SlidingMenu_rightPadding:\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 默认50\u0026lt;/span\u0026gt;\n\n- mMenuRightPadding = a.getDimensionPixelSize(attr,\n\n- (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) TypedValue.applyDimension(\n\n- TypedValue.COMPLEX_UNIT_DIP, 50f,\n\n- getResources().getDisplayMetrics()));\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 默认为10DP\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;\n\n- }\n\n- }\n\n- a.recycle();\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SlidingMenu(Context context)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;(context, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasure(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthMeasureSpec, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightMeasureSpec)\n\n- {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         * 显示的设置一个宽度\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!once)\n\n- {\n\n- LinearLayout wrapper = (LinearLayout) getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- ViewGroup menu = (ViewGroup) wrapper.getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- ViewGroup content = (ViewGroup) wrapper.getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);\n\n- \n- mMenuWidth = mScreenWidth \u0026amp;#8211; mMenuRightPadding;\n\n- mHalfMenuWidth = mMenuWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;;\n\n- menu.getLayoutParams().width = mMenuWidth;\n\n- content.getLayoutParams().width = mScreenWidth;\n\n- \n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n- \n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onLayout(changed, l, t, r, b);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (changed)\n\n- {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 将菜单隐藏\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.scrollTo(mMenuWidth, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- once = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouchEvent(MotionEvent ev)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; action = ev.getAction();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (action)\n\n- {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// Up时，进行判断，如果显示区域大于菜单宽度一半则完全显示，否则隐藏\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP:\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollX = getScrollX();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (scrollX \u0026gt; mHalfMenuWidth)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(mMenuWidth, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- isOpen = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- isOpen = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(ev);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 打开菜单\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; openMenu()\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isOpen)\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- isOpen = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 关闭菜单\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; closeMenu()\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isOpen)\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.smoothScrollTo(mMenuWidth, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- isOpen = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;\n\n- }\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 切换菜单状态\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; toggle()\n\n- {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isOpen)\n\n- {\n\n- closeMenu();\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;\n\n- {\n\n- openMenu();\n\n- }\n\n- }\n\n- \n- \n- \n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e利用HorizontalScrollView，监听了ACTION_UP的事件，当用户抬起手指时，根据当前菜单显示的宽度值，判断是缩回还是完全展开；给用户提供了一个rightPadding属性，用于设置菜单离右屏幕的距离；以及对外提供了打开，关闭，切换的几个方法；具体的讲解看下上篇博客了；\u003c/p\u003e","title":"Android 高仿 QQ 侧滑菜单效果 自定义控件来袭"},{"content":"参考GitHub 中\nRESideMenu https://github.com/romaonthego/RESideMenu\nhttps://github.com/kyze8439690/ResideLayout\nhttps://github.com/SpecialCyCi/AndroidResideMenu\nAndroid仿QQ5.0侧滑菜单ResideMenu 最近项目要做一个QQ5.0的侧滑菜单效果，和传统的侧滑菜单存在着一些差异。想必大家都已经见识过了。\n为了不重复发明轮子，先去github上面搜索了一番。\n发现了几个类似的，但是还是有一些不同。\n下面是搜索到的类似的开源项目。\nRESideMenu（ios项目）\nhttps://github.com/romaonthego/RESideMenu\nAndroidResideMenu\nhttps://github.com/SpecialCyCi/AndroidResideMenu\nResideLayout\nhttps://github.com/kyze8439690/ResideLayout\n研究了一下这些开源项目的源代码。感觉并不是特别适用于我们自己的项目。所以，我自己又研究了一下。最后的效果如下。当然了，还有很多可以优化的地方，后续再慢慢优化。\n我是基于SlidingMenu库进行的二次修改，增加了一些转场动画。\n大家对这个库应该比较熟悉，下面是SlidingMenu的github地址。非常感谢Jeremy Feinstein提供的这个库，让广大Android Developers省去了非常多的麻烦。\nhttps://github.com/jfeinstein10/SlidingMenu\n备注：SlidingMenu使用了SherlockActionBar这个库，配置起来会比较麻烦，在文章的最后我会把demo上传，供大家下载，减去了大家自己配置项目的麻烦。\n我主要修改了2个类，SlidingMenu.java和CustonViewAbove.java，只是增加了一些功能，并没有修改原本的功能。\n做了修改的地方，我做了中文注释，其实实现很简单，几行代码而已。推荐大家下载Demo，然后自己调试一下。Demo的下载地址在文章的末尾。\n废话不多说，直接上代码，略微有点长。\n[?](http://www.open-open.com/lib/view/open1411269966859.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; 51 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; 52 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; 53 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; 54 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; 55 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; 56 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; 57 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; 58 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; 59 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; 60 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; 61 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; 62 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; 63 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; 64 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; 65 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; 66 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; 67 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; 68 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; 69 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; 70 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; 71 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; 72 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; 73 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; 74 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; 75 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; 76 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; 77 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; 78 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; 79 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; 80 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; 81 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; 82 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; 83 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; 84 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; 85 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; 86 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; 87 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; 88 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; 89 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; 90 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; 91 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt; 92 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt; 93 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt; 94 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt; 95 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt; 96 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt; 97 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt; 98 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt; 99 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt; 100 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number101 index100 alt2\u0026quot;\u0026gt; 101 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number102 index101 alt1\u0026quot;\u0026gt; 102 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number103 index102 alt2\u0026quot;\u0026gt; 103 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number104 index103 alt1\u0026quot;\u0026gt; 104 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number105 index104 alt2\u0026quot;\u0026gt; 105 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number106 index105 alt1\u0026quot;\u0026gt; 106 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number107 index106 alt2\u0026quot;\u0026gt; 107 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number108 index107 alt1\u0026quot;\u0026gt; 108 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number109 index108 alt2\u0026quot;\u0026gt; 109 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number110 index109 alt1\u0026quot;\u0026gt; 110 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number111 index110 alt2\u0026quot;\u0026gt; 111 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number112 index111 alt1\u0026quot;\u0026gt; 112 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number113 index112 alt2\u0026quot;\u0026gt; 113 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number114 index113 alt1\u0026quot;\u0026gt; 114 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number115 index114 alt2\u0026quot;\u0026gt; 115 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number116 index115 alt1\u0026quot;\u0026gt; 116 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number117 index116 alt2\u0026quot;\u0026gt; 117 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number118 index117 alt1\u0026quot;\u0026gt; 118 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number119 index118 alt2\u0026quot;\u0026gt; 119 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number120 index119 alt1\u0026quot;\u0026gt; 120 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number121 index120 alt2\u0026quot;\u0026gt; 121 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number122 index121 alt1\u0026quot;\u0026gt; 122 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number123 index122 alt2\u0026quot;\u0026gt; 123 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number124 index123 alt1\u0026quot;\u0026gt; 124 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number125 index124 alt2\u0026quot;\u0026gt; 125 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number126 index125 alt1\u0026quot;\u0026gt; 126 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number127 index126 alt2\u0026quot;\u0026gt; 127 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number128 index127 alt1\u0026quot;\u0026gt; 128 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number129 index128 alt2\u0026quot;\u0026gt; 129 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number130 index129 alt1\u0026quot;\u0026gt; 130 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number131 index130 alt2\u0026quot;\u0026gt; 131 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number132 index131 alt1\u0026quot;\u0026gt; 132 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number133 index132 alt2\u0026quot;\u0026gt; 133 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number134 index133 alt1\u0026quot;\u0026gt; 134 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number135 index134 alt2\u0026quot;\u0026gt; 135 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number136 index135 alt1\u0026quot;\u0026gt; 136 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number137 index136 alt2\u0026quot;\u0026gt; 137 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number138 index137 alt1\u0026quot;\u0026gt; 138 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number139 index138 alt2\u0026quot;\u0026gt; 139 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number140 index139 alt1\u0026quot;\u0026gt; 140 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number141 index140 alt2\u0026quot;\u0026gt; 141 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number142 index141 alt1\u0026quot;\u0026gt; 142 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number143 index142 alt2\u0026quot;\u0026gt; 143 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number144 index143 alt1\u0026quot;\u0026gt; 144 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number145 index144 alt2\u0026quot;\u0026gt; 145 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number146 index145 alt1\u0026quot;\u0026gt; 146 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number147 index146 alt2\u0026quot;\u0026gt; 147 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number148 index147 alt1\u0026quot;\u0026gt; 148 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number149 index148 alt2\u0026quot;\u0026gt; 149 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number150 index149 alt1\u0026quot;\u0026gt; 150 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number151 index150 alt2\u0026quot;\u0026gt; 151 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number152 index151 alt1\u0026quot;\u0026gt; 152 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number153 index152 alt2\u0026quot;\u0026gt; 153 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number154 index153 alt1\u0026quot;\u0026gt; 154 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number155 index154 alt2\u0026quot;\u0026gt; 155 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number156 index155 alt1\u0026quot;\u0026gt; 156 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number157 index156 alt2\u0026quot;\u0026gt; 157 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number158 index157 alt1\u0026quot;\u0026gt; 158 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number159 index158 alt2\u0026quot;\u0026gt; 159 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number160 index159 alt1\u0026quot;\u0026gt; 160 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number161 index160 alt2\u0026quot;\u0026gt; 161 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number162 index161 alt1\u0026quot;\u0026gt; 162 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number163 index162 alt2\u0026quot;\u0026gt; 163 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number164 index163 alt1\u0026quot;\u0026gt; 164 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number165 index164 alt2\u0026quot;\u0026gt; 165 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number166 index165 alt1\u0026quot;\u0026gt; 166 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number167 index166 alt2\u0026quot;\u0026gt; 167 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number168 index167 alt1\u0026quot;\u0026gt; 168 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number169 index168 alt2\u0026quot;\u0026gt; 169 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number170 index169 alt1\u0026quot;\u0026gt; 170 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number171 index170 alt2\u0026quot;\u0026gt; 171 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number172 index171 alt1\u0026quot;\u0026gt; 172 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number173 index172 alt2\u0026quot;\u0026gt; 173 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number174 index173 alt1\u0026quot;\u0026gt; 174 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number175 index174 alt2\u0026quot;\u0026gt; 175 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number176 index175 alt1\u0026quot;\u0026gt; 176 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number177 index176 alt2\u0026quot;\u0026gt; 177 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number178 index177 alt1\u0026quot;\u0026gt; 178 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number179 index178 alt2\u0026quot;\u0026gt; 179 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number180 index179 alt1\u0026quot;\u0026gt; 180 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number181 index180 alt2\u0026quot;\u0026gt; 181 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number182 index181 alt1\u0026quot;\u0026gt; 182 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number183 index182 alt2\u0026quot;\u0026gt; 183 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number184 index183 alt1\u0026quot;\u0026gt; 184 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number185 index184 alt2\u0026quot;\u0026gt; 185 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number186 index185 alt1\u0026quot;\u0026gt; 186 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number187 index186 alt2\u0026quot;\u0026gt; 187 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number188 index187 alt1\u0026quot;\u0026gt; 188 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number189 index188 alt2\u0026quot;\u0026gt; 189 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number190 index189 alt1\u0026quot;\u0026gt; 190 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number191 index190 alt2\u0026quot;\u0026gt; 191 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number192 index191 alt1\u0026quot;\u0026gt; 192 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number193 index192 alt2\u0026quot;\u0026gt; 193 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number194 index193 alt1\u0026quot;\u0026gt; 194 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number195 index194 alt2\u0026quot;\u0026gt; 195 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number196 index195 alt1\u0026quot;\u0026gt; 196 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number197 index196 alt2\u0026quot;\u0026gt; 197 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number198 index197 alt1\u0026quot;\u0026gt; 198 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number199 index198 alt2\u0026quot;\u0026gt; 199 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number200 index199 alt1\u0026quot;\u0026gt; 200 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number201 index200 alt2\u0026quot;\u0026gt; 201 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number202 index201 alt1\u0026quot;\u0026gt; 202 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number203 index202 alt2\u0026quot;\u0026gt; 203 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number204 index203 alt1\u0026quot;\u0026gt; 204 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number205 index204 alt2\u0026quot;\u0026gt; 205 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number206 index205 alt1\u0026quot;\u0026gt; 206 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number207 index206 alt2\u0026quot;\u0026gt; 207 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number208 index207 alt1\u0026quot;\u0026gt; 208 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number209 index208 alt2\u0026quot;\u0026gt; 209 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number210 index209 alt1\u0026quot;\u0026gt; 210 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number211 index210 alt2\u0026quot;\u0026gt; 211 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number212 index211 alt1\u0026quot;\u0026gt; 212 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number213 index212 alt2\u0026quot;\u0026gt; 213 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number214 index213 alt1\u0026quot;\u0026gt; 214 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number215 index214 alt2\u0026quot;\u0026gt; 215 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number216 index215 alt1\u0026quot;\u0026gt; 216 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number217 index216 alt2\u0026quot;\u0026gt; 217 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number218 index217 alt1\u0026quot;\u0026gt; 218 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number219 index218 alt2\u0026quot;\u0026gt; 219 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number220 index219 alt1\u0026quot;\u0026gt; 220 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number221 index220 alt2\u0026quot;\u0026gt; 221 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number222 index221 alt1\u0026quot;\u0026gt; 222 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number223 index222 alt2\u0026quot;\u0026gt; 223 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number224 index223 alt1\u0026quot;\u0026gt; 224 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number225 index224 alt2\u0026quot;\u0026gt; 225 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number226 index225 alt1\u0026quot;\u0026gt; 226 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number227 index226 alt2\u0026quot;\u0026gt; 227 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number228 index227 alt1\u0026quot;\u0026gt; 228 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number229 index228 alt2\u0026quot;\u0026gt; 229 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number230 index229 alt1\u0026quot;\u0026gt; 230 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number231 index230 alt2\u0026quot;\u0026gt; 231 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number232 index231 alt1\u0026quot;\u0026gt; 232 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number233 index232 alt2\u0026quot;\u0026gt; 233 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number234 index233 alt1\u0026quot;\u0026gt; 234 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number235 index234 alt2\u0026quot;\u0026gt; 235 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number236 index235 alt1\u0026quot;\u0026gt; 236 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number237 index236 alt2\u0026quot;\u0026gt; 237 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number238 index237 alt1\u0026quot;\u0026gt; 238 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number239 index238 alt2\u0026quot;\u0026gt; 239 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number240 index239 alt1\u0026quot;\u0026gt; 240 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number241 index240 alt2\u0026quot;\u0026gt; 241 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number242 index241 alt1\u0026quot;\u0026gt; 242 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number243 index242 alt2\u0026quot;\u0026gt; 243 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number244 index243 alt1\u0026quot;\u0026gt; 244 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number245 index244 alt2\u0026quot;\u0026gt; 245 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number246 index245 alt1\u0026quot;\u0026gt; 246 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number247 index246 alt2\u0026quot;\u0026gt; 247 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number248 index247 alt1\u0026quot;\u0026gt; 248 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number249 index248 alt2\u0026quot;\u0026gt; 249 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number250 index249 alt1\u0026quot;\u0026gt; 250 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number251 index250 alt2\u0026quot;\u0026gt; 251 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number252 index251 alt1\u0026quot;\u0026gt; 252 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number253 index252 alt2\u0026quot;\u0026gt; 253 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number254 index253 alt1\u0026quot;\u0026gt; 254 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number255 index254 alt2\u0026quot;\u0026gt; 255 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number256 index255 alt1\u0026quot;\u0026gt; 256 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number257 index256 alt2\u0026quot;\u0026gt; 257 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number258 index257 alt1\u0026quot;\u0026gt; 258 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number259 index258 alt2\u0026quot;\u0026gt; 259 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number260 index259 alt1\u0026quot;\u0026gt; 260 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number261 index260 alt2\u0026quot;\u0026gt; 261 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number262 index261 alt1\u0026quot;\u0026gt; 262 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number263 index262 alt2\u0026quot;\u0026gt; 263 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number264 index263 alt1\u0026quot;\u0026gt; 264 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number265 index264 alt2\u0026quot;\u0026gt; 265 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number266 index265 alt1\u0026quot;\u0026gt; 266 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number267 index266 alt2\u0026quot;\u0026gt; 267 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number268 index267 alt1\u0026quot;\u0026gt; 268 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number269 index268 alt2\u0026quot;\u0026gt; 269 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number270 index269 alt1\u0026quot;\u0026gt; 270 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number271 index270 alt2\u0026quot;\u0026gt; 271 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number272 index271 alt1\u0026quot;\u0026gt; 272 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number273 index272 alt2\u0026quot;\u0026gt; 273 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number274 index273 alt1\u0026quot;\u0026gt; 274 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number275 index274 alt2\u0026quot;\u0026gt; 275 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number276 index275 alt1\u0026quot;\u0026gt; 276 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number277 index276 alt2\u0026quot;\u0026gt; 277 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number278 index277 alt1\u0026quot;\u0026gt; 278 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number279 index278 alt2\u0026quot;\u0026gt; 279 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number280 index279 alt1\u0026quot;\u0026gt; 280 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number281 index280 alt2\u0026quot;\u0026gt; 281 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number282 index281 alt1\u0026quot;\u0026gt; 282 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number283 index282 alt2\u0026quot;\u0026gt; 283 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number284 index283 alt1\u0026quot;\u0026gt; 284 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number285 index284 alt2\u0026quot;\u0026gt; 285 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number286 index285 alt1\u0026quot;\u0026gt; 286 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number287 index286 alt2\u0026quot;\u0026gt; 287 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number288 index287 alt1\u0026quot;\u0026gt; 288 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number289 index288 alt2\u0026quot;\u0026gt; 289 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number290 index289 alt1\u0026quot;\u0026gt; 290 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number291 index290 alt2\u0026quot;\u0026gt; 291 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number292 index291 alt1\u0026quot;\u0026gt; 292 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number293 index292 alt2\u0026quot;\u0026gt; 293 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number294 index293 alt1\u0026quot;\u0026gt; 294 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number295 index294 alt2\u0026quot;\u0026gt; 295 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number296 index295 alt1\u0026quot;\u0026gt; 296 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number297 index296 alt2\u0026quot;\u0026gt; 297 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number298 index297 alt1\u0026quot;\u0026gt; 298 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number299 index298 alt2\u0026quot;\u0026gt; 299 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number300 index299 alt1\u0026quot;\u0026gt; 300 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number301 index300 alt2\u0026quot;\u0026gt; 301 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number302 index301 alt1\u0026quot;\u0026gt; 302 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number303 index302 alt2\u0026quot;\u0026gt; 303 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number304 index303 alt1\u0026quot;\u0026gt; 304 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number305 index304 alt2\u0026quot;\u0026gt; 305 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number306 index305 alt1\u0026quot;\u0026gt; 306 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number307 index306 alt2\u0026quot;\u0026gt; 307 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number308 index307 alt1\u0026quot;\u0026gt; 308 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number309 index308 alt2\u0026quot;\u0026gt; 309 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number310 index309 alt1\u0026quot;\u0026gt; 310 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number311 index310 alt2\u0026quot;\u0026gt; 311 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number312 index311 alt1\u0026quot;\u0026gt; 312 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number313 index312 alt2\u0026quot;\u0026gt; 313 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number314 index313 alt1\u0026quot;\u0026gt; 314 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number315 index314 alt2\u0026quot;\u0026gt; 315 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number316 index315 alt1\u0026quot;\u0026gt; 316 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number317 index316 alt2\u0026quot;\u0026gt; 317 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number318 index317 alt1\u0026quot;\u0026gt; 318 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number319 index318 alt2\u0026quot;\u0026gt; 319 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number320 index319 alt1\u0026quot;\u0026gt; 320 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number321 index320 alt2\u0026quot;\u0026gt; 321 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number322 index321 alt1\u0026quot;\u0026gt; 322 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number323 index322 alt2\u0026quot;\u0026gt; 323 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number324 index323 alt1\u0026quot;\u0026gt; 324 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number325 index324 alt2\u0026quot;\u0026gt; 325 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number326 index325 alt1\u0026quot;\u0026gt; 326 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number327 index326 alt2\u0026quot;\u0026gt; 327 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number328 index327 alt1\u0026quot;\u0026gt; 328 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number329 index328 alt2\u0026quot;\u0026gt; 329 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number330 index329 alt1\u0026quot;\u0026gt; 330 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number331 index330 alt2\u0026quot;\u0026gt; 331 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number332 index331 alt1\u0026quot;\u0026gt; 332 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number333 index332 alt2\u0026quot;\u0026gt; 333 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number334 index333 alt1\u0026quot;\u0026gt; 334 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number335 index334 alt2\u0026quot;\u0026gt; 335 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number336 index335 alt1\u0026quot;\u0026gt; 336 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number337 index336 alt2\u0026quot;\u0026gt; 337 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number338 index337 alt1\u0026quot;\u0026gt; 338 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number339 index338 alt2\u0026quot;\u0026gt; 339 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number340 index339 alt1\u0026quot;\u0026gt; 340 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number341 index340 alt2\u0026quot;\u0026gt; 341 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number342 index341 alt1\u0026quot;\u0026gt; 342 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number343 index342 alt2\u0026quot;\u0026gt; 343 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number344 index343 alt1\u0026quot;\u0026gt; 344 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number345 index344 alt2\u0026quot;\u0026gt; 345 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number346 index345 alt1\u0026quot;\u0026gt; 346 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number347 index346 alt2\u0026quot;\u0026gt; 347 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number348 index347 alt1\u0026quot;\u0026gt; 348 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number349 index348 alt2\u0026quot;\u0026gt; 349 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number350 index349 alt1\u0026quot;\u0026gt; 350 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number351 index350 alt2\u0026quot;\u0026gt; 351 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number352 index351 alt1\u0026quot;\u0026gt; 352 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number353 index352 alt2\u0026quot;\u0026gt; 353 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number354 index353 alt1\u0026quot;\u0026gt; 354 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number355 index354 alt2\u0026quot;\u0026gt; 355 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number356 index355 alt1\u0026quot;\u0026gt; 356 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number357 index356 alt2\u0026quot;\u0026gt; 357 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number358 index357 alt1\u0026quot;\u0026gt; 358 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number359 index358 alt2\u0026quot;\u0026gt; 359 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number360 index359 alt1\u0026quot;\u0026gt; 360 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number361 index360 alt2\u0026quot;\u0026gt; 361 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number362 index361 alt1\u0026quot;\u0026gt; 362 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number363 index362 alt2\u0026quot;\u0026gt; 363 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number364 index363 alt1\u0026quot;\u0026gt; 364 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number365 index364 alt2\u0026quot;\u0026gt; 365 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number366 index365 alt1\u0026quot;\u0026gt; 366 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number367 index366 alt2\u0026quot;\u0026gt; 367 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number368 index367 alt1\u0026quot;\u0026gt; 368 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number369 index368 alt2\u0026quot;\u0026gt; 369 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number370 index369 alt1\u0026quot;\u0026gt; 370 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number371 index370 alt2\u0026quot;\u0026gt; 371 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number372 index371 alt1\u0026quot;\u0026gt; 372 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number373 index372 alt2\u0026quot;\u0026gt; 373 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number374 index373 alt1\u0026quot;\u0026gt; 374 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number375 index374 alt2\u0026quot;\u0026gt; 375 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number376 index375 alt1\u0026quot;\u0026gt; 376 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number377 index376 alt2\u0026quot;\u0026gt; 377 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number378 index377 alt1\u0026quot;\u0026gt; 378 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number379 index378 alt2\u0026quot;\u0026gt; 379 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number380 index379 alt1\u0026quot;\u0026gt; 380 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number381 index380 alt2\u0026quot;\u0026gt; 381 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number382 index381 alt1\u0026quot;\u0026gt; 382 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number383 index382 alt2\u0026quot;\u0026gt; 383 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number384 index383 alt1\u0026quot;\u0026gt; 384 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number385 index384 alt2\u0026quot;\u0026gt; 385 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number386 index385 alt1\u0026quot;\u0026gt; 386 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number387 index386 alt2\u0026quot;\u0026gt; 387 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number388 index387 alt1\u0026quot;\u0026gt; 388 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number389 index388 alt2\u0026quot;\u0026gt; 389 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number390 index389 alt1\u0026quot;\u0026gt; 390 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number391 index390 alt2\u0026quot;\u0026gt; 391 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number392 index391 alt1\u0026quot;\u0026gt; 392 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number393 index392 alt2\u0026quot;\u0026gt; 393 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number394 index393 alt1\u0026quot;\u0026gt; 394 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number395 index394 alt2\u0026quot;\u0026gt; 395 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number396 index395 alt1\u0026quot;\u0026gt; 396 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number397 index396 alt2\u0026quot;\u0026gt; 397 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number398 index397 alt1\u0026quot;\u0026gt; 398 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number399 index398 alt2\u0026quot;\u0026gt; 399 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number400 index399 alt1\u0026quot;\u0026gt; 400 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number401 index400 alt2\u0026quot;\u0026gt; 401 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number402 index401 alt1\u0026quot;\u0026gt; 402 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number403 index402 alt2\u0026quot;\u0026gt; 403 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number404 index403 alt1\u0026quot;\u0026gt; 404 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number405 index404 alt2\u0026quot;\u0026gt; 405 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number406 index405 alt1\u0026quot;\u0026gt; 406 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number407 index406 alt2\u0026quot;\u0026gt; 407 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number408 index407 alt1\u0026quot;\u0026gt; 408 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number409 index408 alt2\u0026quot;\u0026gt; 409 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number410 index409 alt1\u0026quot;\u0026gt; 410 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number411 index410 alt2\u0026quot;\u0026gt; 411 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number412 index411 alt1\u0026quot;\u0026gt; 412 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number413 index412 alt2\u0026quot;\u0026gt; 413 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number414 index413 alt1\u0026quot;\u0026gt; 414 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number415 index414 alt2\u0026quot;\u0026gt; 415 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number416 index415 alt1\u0026quot;\u0026gt; 416 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number417 index416 alt2\u0026quot;\u0026gt; 417 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number418 index417 alt1\u0026quot;\u0026gt; 418 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number419 index418 alt2\u0026quot;\u0026gt; 419 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number420 index419 alt1\u0026quot;\u0026gt; 420 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number421 index420 alt2\u0026quot;\u0026gt; 421 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number422 index421 alt1\u0026quot;\u0026gt; 422 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number423 index422 alt2\u0026quot;\u0026gt; 423 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number424 index423 alt1\u0026quot;\u0026gt; 424 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number425 index424 alt2\u0026quot;\u0026gt; 425 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number426 index425 alt1\u0026quot;\u0026gt; 426 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number427 index426 alt2\u0026quot;\u0026gt; 427 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number428 index427 alt1\u0026quot;\u0026gt; 428 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number429 index428 alt2\u0026quot;\u0026gt; 429 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number430 index429 alt1\u0026quot;\u0026gt; 430 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number431 index430 alt2\u0026quot;\u0026gt; 431 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number432 index431 alt1\u0026quot;\u0026gt; 432 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number433 index432 alt2\u0026quot;\u0026gt; 433 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number434 index433 alt1\u0026quot;\u0026gt; 434 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number435 index434 alt2\u0026quot;\u0026gt; 435 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number436 index435 alt1\u0026quot;\u0026gt; 436 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number437 index436 alt2\u0026quot;\u0026gt; 437 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number438 index437 alt1\u0026quot;\u0026gt; 438 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number439 index438 alt2\u0026quot;\u0026gt; 439 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number440 index439 alt1\u0026quot;\u0026gt; 440 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number441 index440 alt2\u0026quot;\u0026gt; 441 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number442 index441 alt1\u0026quot;\u0026gt; 442 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number443 index442 alt2\u0026quot;\u0026gt; 443 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number444 index443 alt1\u0026quot;\u0026gt; 444 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number445 index444 alt2\u0026quot;\u0026gt; 445 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number446 index445 alt1\u0026quot;\u0026gt; 446 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number447 index446 alt2\u0026quot;\u0026gt; 447 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number448 index447 alt1\u0026quot;\u0026gt; 448 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number449 index448 alt2\u0026quot;\u0026gt; 449 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number450 index449 alt1\u0026quot;\u0026gt; 450 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number451 index450 alt2\u0026quot;\u0026gt; 451 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number452 index451 alt1\u0026quot;\u0026gt; 452 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number453 index452 alt2\u0026quot;\u0026gt; 453 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number454 index453 alt1\u0026quot;\u0026gt; 454 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number455 index454 alt2\u0026quot;\u0026gt; 455 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number456 index455 alt1\u0026quot;\u0026gt; 456 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number457 index456 alt2\u0026quot;\u0026gt; 457 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number458 index457 alt1\u0026quot;\u0026gt; 458 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number459 index458 alt2\u0026quot;\u0026gt; 459 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number460 index459 alt1\u0026quot;\u0026gt; 460 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number461 index460 alt2\u0026quot;\u0026gt; 461 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number462 index461 alt1\u0026quot;\u0026gt; 462 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number463 index462 alt2\u0026quot;\u0026gt; 463 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number464 index463 alt1\u0026quot;\u0026gt; 464 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number465 index464 alt2\u0026quot;\u0026gt; 465 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number466 index465 alt1\u0026quot;\u0026gt; 466 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number467 index466 alt2\u0026quot;\u0026gt; 467 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number468 index467 alt1\u0026quot;\u0026gt; 468 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number469 index468 alt2\u0026quot;\u0026gt; 469 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number470 index469 alt1\u0026quot;\u0026gt; 470 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number471 index470 alt2\u0026quot;\u0026gt; 471 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number472 index471 alt1\u0026quot;\u0026gt; 472 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number473 index472 alt2\u0026quot;\u0026gt; 473 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number474 index473 alt1\u0026quot;\u0026gt; 474 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number475 index474 alt2\u0026quot;\u0026gt; 475 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number476 index475 alt1\u0026quot;\u0026gt; 476 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number477 index476 alt2\u0026quot;\u0026gt; 477 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number478 index477 alt1\u0026quot;\u0026gt; 478 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number479 index478 alt2\u0026quot;\u0026gt; 479 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number480 index479 alt1\u0026quot;\u0026gt; 480 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number481 index480 alt2\u0026quot;\u0026gt; 481 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number482 index481 alt1\u0026quot;\u0026gt; 482 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number483 index482 alt2\u0026quot;\u0026gt; 483 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number484 index483 alt1\u0026quot;\u0026gt; 484 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number485 index484 alt2\u0026quot;\u0026gt; 485 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number486 index485 alt1\u0026quot;\u0026gt; 486 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number487 index486 alt2\u0026quot;\u0026gt; 487 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number488 index487 alt1\u0026quot;\u0026gt; 488 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number489 index488 alt2\u0026quot;\u0026gt; 489 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number490 index489 alt1\u0026quot;\u0026gt; 490 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number491 index490 alt2\u0026quot;\u0026gt; 491 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number492 index491 alt1\u0026quot;\u0026gt; 492 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number493 index492 alt2\u0026quot;\u0026gt; 493 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number494 index493 alt1\u0026quot;\u0026gt; 494 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number495 index494 alt2\u0026quot;\u0026gt; 495 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number496 index495 alt1\u0026quot;\u0026gt; 496 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number497 index496 alt2\u0026quot;\u0026gt; 497 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number498 index497 alt1\u0026quot;\u0026gt; 498 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number499 index498 alt2\u0026quot;\u0026gt; 499 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number500 index499 alt1\u0026quot;\u0026gt; 500 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number501 index500 alt2\u0026quot;\u0026gt; 501 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number502 index501 alt1\u0026quot;\u0026gt; 502 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number503 index502 alt2\u0026quot;\u0026gt; 503 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number504 index503 alt1\u0026quot;\u0026gt; 504 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number505 index504 alt2\u0026quot;\u0026gt; 505 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number506 index505 alt1\u0026quot;\u0026gt; 506 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number507 index506 alt2\u0026quot;\u0026gt; 507 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number508 index507 alt1\u0026quot;\u0026gt; 508 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number509 index508 alt2\u0026quot;\u0026gt; 509 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number510 index509 alt1\u0026quot;\u0026gt; 510 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number511 index510 alt2\u0026quot;\u0026gt; 511 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number512 index511 alt1\u0026quot;\u0026gt; 512 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number513 index512 alt2\u0026quot;\u0026gt; 513 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number514 index513 alt1\u0026quot;\u0026gt; 514 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number515 index514 alt2\u0026quot;\u0026gt; 515 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number516 index515 alt1\u0026quot;\u0026gt; 516 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number517 index516 alt2\u0026quot;\u0026gt; 517 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number518 index517 alt1\u0026quot;\u0026gt; 518 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number519 index518 alt2\u0026quot;\u0026gt; 519 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number520 index519 alt1\u0026quot;\u0026gt; 520 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number521 index520 alt2\u0026quot;\u0026gt; 521 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number522 index521 alt1\u0026quot;\u0026gt; 522 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number523 index522 alt2\u0026quot;\u0026gt; 523 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number524 index523 alt1\u0026quot;\u0026gt; 524 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number525 index524 alt2\u0026quot;\u0026gt; 525 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number526 index525 alt1\u0026quot;\u0026gt; 526 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number527 index526 alt2\u0026quot;\u0026gt; 527 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number528 index527 alt1\u0026quot;\u0026gt; 528 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number529 index528 alt2\u0026quot;\u0026gt; 529 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number530 index529 alt1\u0026quot;\u0026gt; 530 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number531 index530 alt2\u0026quot;\u0026gt; 531 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number532 index531 alt1\u0026quot;\u0026gt; 532 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number533 index532 alt2\u0026quot;\u0026gt; 533 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number534 index533 alt1\u0026quot;\u0026gt; 534 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number535 index534 alt2\u0026quot;\u0026gt; 535 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number536 index535 alt1\u0026quot;\u0026gt; 536 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number537 index536 alt2\u0026quot;\u0026gt; 537 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number538 index537 alt1\u0026quot;\u0026gt; 538 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number539 index538 alt2\u0026quot;\u0026gt; 539 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number540 index539 alt1\u0026quot;\u0026gt; 540 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number541 index540 alt2\u0026quot;\u0026gt; 541 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number542 index541 alt1\u0026quot;\u0026gt; 542 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number543 index542 alt2\u0026quot;\u0026gt; 543 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number544 index543 alt1\u0026quot;\u0026gt; 544 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number545 index544 alt2\u0026quot;\u0026gt; 545 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number546 index545 alt1\u0026quot;\u0026gt; 546 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number547 index546 alt2\u0026quot;\u0026gt; 547 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number548 index547 alt1\u0026quot;\u0026gt; 548 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number549 index548 alt2\u0026quot;\u0026gt; 549 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number550 index549 alt1\u0026quot;\u0026gt; 550 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number551 index550 alt2\u0026quot;\u0026gt; 551 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number552 index551 alt1\u0026quot;\u0026gt; 552 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number553 index552 alt2\u0026quot;\u0026gt; 553 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number554 index553 alt1\u0026quot;\u0026gt; 554 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number555 index554 alt2\u0026quot;\u0026gt; 555 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number556 index555 alt1\u0026quot;\u0026gt; 556 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number557 index556 alt2\u0026quot;\u0026gt; 557 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number558 index557 alt1\u0026quot;\u0026gt; 558 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number559 index558 alt2\u0026quot;\u0026gt; 559 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number560 index559 alt1\u0026quot;\u0026gt; 560 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number561 index560 alt2\u0026quot;\u0026gt; 561 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number562 index561 alt1\u0026quot;\u0026gt; 562 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number563 index562 alt2\u0026quot;\u0026gt; 563 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number564 index563 alt1\u0026quot;\u0026gt; 564 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number565 index564 alt2\u0026quot;\u0026gt; 565 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number566 index565 alt1\u0026quot;\u0026gt; 566 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number567 index566 alt2\u0026quot;\u0026gt; 567 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number568 index567 alt1\u0026quot;\u0026gt; 568 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number569 index568 alt2\u0026quot;\u0026gt; 569 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number570 index569 alt1\u0026quot;\u0026gt; 570 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number571 index570 alt2\u0026quot;\u0026gt; 571 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number572 index571 alt1\u0026quot;\u0026gt; 572 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number573 index572 alt2\u0026quot;\u0026gt; 573 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number574 index573 alt1\u0026quot;\u0026gt; 574 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number575 index574 alt2\u0026quot;\u0026gt; 575 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number576 index575 alt1\u0026quot;\u0026gt; 576 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number577 index576 alt2\u0026quot;\u0026gt; 577 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number578 index577 alt1\u0026quot;\u0026gt; 578 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number579 index578 alt2\u0026quot;\u0026gt; 579 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number580 index579 alt1\u0026quot;\u0026gt; 580 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number581 index580 alt2\u0026quot;\u0026gt; 581 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number582 index581 alt1\u0026quot;\u0026gt; 582 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number583 index582 alt2\u0026quot;\u0026gt; 583 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number584 index583 alt1\u0026quot;\u0026gt; 584 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number585 index584 alt2\u0026quot;\u0026gt; 585 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number586 index585 alt1\u0026quot;\u0026gt; 586 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number587 index586 alt2\u0026quot;\u0026gt; 587 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number588 index587 alt1\u0026quot;\u0026gt; 588 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number589 index588 alt2\u0026quot;\u0026gt; 589 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number590 index589 alt1\u0026quot;\u0026gt; 590 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number591 index590 alt2\u0026quot;\u0026gt; 591 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number592 index591 alt1\u0026quot;\u0026gt; 592 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number593 index592 alt2\u0026quot;\u0026gt; 593 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number594 index593 alt1\u0026quot;\u0026gt; 594 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number595 index594 alt2\u0026quot;\u0026gt; 595 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number596 index595 alt1\u0026quot;\u0026gt; 596 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number597 index596 alt2\u0026quot;\u0026gt; 597 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number598 index597 alt1\u0026quot;\u0026gt; 598 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number599 index598 alt2\u0026quot;\u0026gt; 599 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number600 index599 alt1\u0026quot;\u0026gt; 600 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number601 index600 alt2\u0026quot;\u0026gt; 601 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number602 index601 alt1\u0026quot;\u0026gt; 602 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number603 index602 alt2\u0026quot;\u0026gt; 603 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number604 index603 alt1\u0026quot;\u0026gt; 604 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number605 index604 alt2\u0026quot;\u0026gt; 605 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number606 index605 alt1\u0026quot;\u0026gt; 606 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number607 index606 alt2\u0026quot;\u0026gt; 607 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number608 index607 alt1\u0026quot;\u0026gt; 608 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number609 index608 alt2\u0026quot;\u0026gt; 609 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number610 index609 alt1\u0026quot;\u0026gt; 610 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number611 index610 alt2\u0026quot;\u0026gt; 611 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number612 index611 alt1\u0026quot;\u0026gt; 612 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number613 index612 alt2\u0026quot;\u0026gt; 613 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number614 index613 alt1\u0026quot;\u0026gt; 614 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number615 index614 alt2\u0026quot;\u0026gt; 615 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number616 index615 alt1\u0026quot;\u0026gt; 616 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number617 index616 alt2\u0026quot;\u0026gt; 617 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number618 index617 alt1\u0026quot;\u0026gt; 618 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number619 index618 alt2\u0026quot;\u0026gt; 619 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number620 index619 alt1\u0026quot;\u0026gt; 620 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number621 index620 alt2\u0026quot;\u0026gt; 621 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number622 index621 alt1\u0026quot;\u0026gt; 622 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number623 index622 alt2\u0026quot;\u0026gt; 623 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number624 index623 alt1\u0026quot;\u0026gt; 624 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number625 index624 alt2\u0026quot;\u0026gt; 625 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number626 index625 alt1\u0026quot;\u0026gt; 626 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number627 index626 alt2\u0026quot;\u0026gt; 627 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number628 index627 alt1\u0026quot;\u0026gt; 628 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number629 index628 alt2\u0026quot;\u0026gt; 629 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number630 index629 alt1\u0026quot;\u0026gt; 630 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number631 index630 alt2\u0026quot;\u0026gt; 631 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number632 index631 alt1\u0026quot;\u0026gt; 632 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number633 index632 alt2\u0026quot;\u0026gt; 633 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number634 index633 alt1\u0026quot;\u0026gt; 634 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number635 index634 alt2\u0026quot;\u0026gt; 635 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number636 index635 alt1\u0026quot;\u0026gt; 636 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number637 index636 alt2\u0026quot;\u0026gt; 637 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number638 index637 alt1\u0026quot;\u0026gt; 638 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number639 index638 alt2\u0026quot;\u0026gt; 639 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number640 index639 alt1\u0026quot;\u0026gt; 640 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number641 index640 alt2\u0026quot;\u0026gt; 641 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number642 index641 alt1\u0026quot;\u0026gt; 642 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number643 index642 alt2\u0026quot;\u0026gt; 643 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number644 index643 alt1\u0026quot;\u0026gt; 644 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number645 index644 alt2\u0026quot;\u0026gt; 645 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number646 index645 alt1\u0026quot;\u0026gt; 646 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number647 index646 alt2\u0026quot;\u0026gt; 647 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number648 index647 alt1\u0026quot;\u0026gt; 648 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number649 index648 alt2\u0026quot;\u0026gt; 649 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number650 index649 alt1\u0026quot;\u0026gt; 650 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number651 index650 alt2\u0026quot;\u0026gt; 651 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number652 index651 alt1\u0026quot;\u0026gt; 652 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number653 index652 alt2\u0026quot;\u0026gt; 653 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number654 index653 alt1\u0026quot;\u0026gt; 654 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number655 index654 alt2\u0026quot;\u0026gt; 655 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number656 index655 alt1\u0026quot;\u0026gt; 656 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number657 index656 alt2\u0026quot;\u0026gt; 657 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number658 index657 alt1\u0026quot;\u0026gt; 658 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number659 index658 alt2\u0026quot;\u0026gt; 659 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number660 index659 alt1\u0026quot;\u0026gt; 660 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number661 index660 alt2\u0026quot;\u0026gt; 661 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number662 index661 alt1\u0026quot;\u0026gt; 662 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number663 index662 alt2\u0026quot;\u0026gt; 663 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number664 index663 alt1\u0026quot;\u0026gt; 664 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number665 index664 alt2\u0026quot;\u0026gt; 665 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number666 index665 alt1\u0026quot;\u0026gt; 666 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number667 index666 alt2\u0026quot;\u0026gt; 667 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number668 index667 alt1\u0026quot;\u0026gt; 668 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number669 index668 alt2\u0026quot;\u0026gt; 669 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number670 index669 alt1\u0026quot;\u0026gt; 670 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number671 index670 alt2\u0026quot;\u0026gt; 671 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number672 index671 alt1\u0026quot;\u0026gt; 672 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number673 index672 alt2\u0026quot;\u0026gt; 673 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number674 index673 alt1\u0026quot;\u0026gt; 674 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number675 index674 alt2\u0026quot;\u0026gt; 675 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number676 index675 alt1\u0026quot;\u0026gt; 676 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number677 index676 alt2\u0026quot;\u0026gt; 677 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number678 index677 alt1\u0026quot;\u0026gt; 678 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number679 index678 alt2\u0026quot;\u0026gt; 679 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number680 index679 alt1\u0026quot;\u0026gt; 680 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number681 index680 alt2\u0026quot;\u0026gt; 681 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number682 index681 alt1\u0026quot;\u0026gt; 682 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number683 index682 alt2\u0026quot;\u0026gt; 683 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number684 index683 alt1\u0026quot;\u0026gt; 684 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number685 index684 alt2\u0026quot;\u0026gt; 685 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number686 index685 alt1\u0026quot;\u0026gt; 686 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number687 index686 alt2\u0026quot;\u0026gt; 687 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number688 index687 alt1\u0026quot;\u0026gt; 688 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number689 index688 alt2\u0026quot;\u0026gt; 689 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number690 index689 alt1\u0026quot;\u0026gt; 690 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number691 index690 alt2\u0026quot;\u0026gt; 691 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number692 index691 alt1\u0026quot;\u0026gt; 692 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number693 index692 alt2\u0026quot;\u0026gt; 693 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number694 index693 alt1\u0026quot;\u0026gt; 694 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number695 index694 alt2\u0026quot;\u0026gt; 695 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number696 index695 alt1\u0026quot;\u0026gt; 696 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number697 index696 alt2\u0026quot;\u0026gt; 697 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number698 index697 alt1\u0026quot;\u0026gt; 698 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number699 index698 alt2\u0026quot;\u0026gt; 699 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number700 index699 alt1\u0026quot;\u0026gt; 700 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number701 index700 alt2\u0026quot;\u0026gt; 701 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number702 index701 alt1\u0026quot;\u0026gt; 702 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number703 index702 alt2\u0026quot;\u0026gt; 703 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number704 index703 alt1\u0026quot;\u0026gt; 704 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number705 index704 alt2\u0026quot;\u0026gt; 705 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number706 index705 alt1\u0026quot;\u0026gt; 706 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number707 index706 alt2\u0026quot;\u0026gt; 707 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number708 index707 alt1\u0026quot;\u0026gt; 708 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number709 index708 alt2\u0026quot;\u0026gt; 709 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number710 index709 alt1\u0026quot;\u0026gt; 710 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number711 index710 alt2\u0026quot;\u0026gt; 711 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number712 index711 alt1\u0026quot;\u0026gt; 712 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number713 index712 alt2\u0026quot;\u0026gt; 713 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number714 index713 alt1\u0026quot;\u0026gt; 714 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number715 index714 alt2\u0026quot;\u0026gt; 715 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number716 index715 alt1\u0026quot;\u0026gt; 716 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number717 index716 alt2\u0026quot;\u0026gt; 717 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number718 index717 alt1\u0026quot;\u0026gt; 718 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number719 index718 alt2\u0026quot;\u0026gt; 719 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number720 index719 alt1\u0026quot;\u0026gt; 720 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number721 index720 alt2\u0026quot;\u0026gt; 721 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number722 index721 alt1\u0026quot;\u0026gt; 722 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number723 index722 alt2\u0026quot;\u0026gt; 723 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number724 index723 alt1\u0026quot;\u0026gt; 724 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number725 index724 alt2\u0026quot;\u0026gt; 725 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number726 index725 alt1\u0026quot;\u0026gt; 726 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number727 index726 alt2\u0026quot;\u0026gt; 727 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number728 index727 alt1\u0026quot;\u0026gt; 728 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number729 index728 alt2\u0026quot;\u0026gt; 729 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number730 index729 alt1\u0026quot;\u0026gt; 730 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number731 index730 alt2\u0026quot;\u0026gt; 731 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number732 index731 alt1\u0026quot;\u0026gt; 732 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number733 index732 alt2\u0026quot;\u0026gt; 733 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number734 index733 alt1\u0026quot;\u0026gt; 734 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number735 index734 alt2\u0026quot;\u0026gt; 735 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number736 index735 alt1\u0026quot;\u0026gt; 736 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number737 index736 alt2\u0026quot;\u0026gt; 737 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number738 index737 alt1\u0026quot;\u0026gt; 738 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number739 index738 alt2\u0026quot;\u0026gt; 739 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number740 index739 alt1\u0026quot;\u0026gt; 740 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number741 index740 alt2\u0026quot;\u0026gt; 741 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number742 index741 alt1\u0026quot;\u0026gt; 742 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number743 index742 alt2\u0026quot;\u0026gt; 743 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number744 index743 alt1\u0026quot;\u0026gt; 744 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number745 index744 alt2\u0026quot;\u0026gt; 745 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number746 index745 alt1\u0026quot;\u0026gt; 746 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number747 index746 alt2\u0026quot;\u0026gt; 747 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number748 index747 alt1\u0026quot;\u0026gt; 748 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number749 index748 alt2\u0026quot;\u0026gt; 749 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number750 index749 alt1\u0026quot;\u0026gt; 750 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number751 index750 alt2\u0026quot;\u0026gt; 751 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number752 index751 alt1\u0026quot;\u0026gt; 752 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number753 index752 alt2\u0026quot;\u0026gt; 753 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number754 index753 alt1\u0026quot;\u0026gt; 754 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number755 index754 alt2\u0026quot;\u0026gt; 755 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number756 index755 alt1\u0026quot;\u0026gt; 756 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number757 index756 alt2\u0026quot;\u0026gt; 757 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number758 index757 alt1\u0026quot;\u0026gt; 758 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number759 index758 alt2\u0026quot;\u0026gt; 759 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number760 index759 alt1\u0026quot;\u0026gt; 760 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number761 index760 alt2\u0026quot;\u0026gt; 761 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number762 index761 alt1\u0026quot;\u0026gt; 762 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number763 index762 alt2\u0026quot;\u0026gt; 763 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number764 index763 alt1\u0026quot;\u0026gt; 764 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number765 index764 alt2\u0026quot;\u0026gt; 765 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number766 index765 alt1\u0026quot;\u0026gt; 766 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number767 index766 alt2\u0026quot;\u0026gt; 767 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number768 index767 alt1\u0026quot;\u0026gt; 768 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number769 index768 alt2\u0026quot;\u0026gt; 769 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number770 index769 alt1\u0026quot;\u0026gt; 770 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number771 index770 alt2\u0026quot;\u0026gt; 771 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number772 index771 alt1\u0026quot;\u0026gt; 772 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number773 index772 alt2\u0026quot;\u0026gt; 773 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number774 index773 alt1\u0026quot;\u0026gt; 774 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number775 index774 alt2\u0026quot;\u0026gt; 775 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number776 index775 alt1\u0026quot;\u0026gt; 776 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number777 index776 alt2\u0026quot;\u0026gt; 777 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number778 index777 alt1\u0026quot;\u0026gt; 778 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number779 index778 alt2\u0026quot;\u0026gt; 779 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number780 index779 alt1\u0026quot;\u0026gt; 780 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number781 index780 alt2\u0026quot;\u0026gt; 781 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number782 index781 alt1\u0026quot;\u0026gt; 782 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number783 index782 alt2\u0026quot;\u0026gt; 783 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number784 index783 alt1\u0026quot;\u0026gt; 784 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number785 index784 alt2\u0026quot;\u0026gt; 785 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number786 index785 alt1\u0026quot;\u0026gt; 786 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number787 index786 alt2\u0026quot;\u0026gt; 787 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number788 index787 alt1\u0026quot;\u0026gt; 788 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number789 index788 alt2\u0026quot;\u0026gt; 789 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number790 index789 alt1\u0026quot;\u0026gt; 790 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number791 index790 alt2\u0026quot;\u0026gt; 791 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number792 index791 alt1\u0026quot;\u0026gt; 792 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number793 index792 alt2\u0026quot;\u0026gt; 793 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number794 index793 alt1\u0026quot;\u0026gt; 794 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number795 index794 alt2\u0026quot;\u0026gt; 795 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number796 index795 alt1\u0026quot;\u0026gt; 796 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number797 index796 alt2\u0026quot;\u0026gt; 797 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number798 index797 alt1\u0026quot;\u0026gt; 798 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number799 index798 alt2\u0026quot;\u0026gt; 799 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number800 index799 alt1\u0026quot;\u0026gt; 800 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number801 index800 alt2\u0026quot;\u0026gt; 801 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number802 index801 alt1\u0026quot;\u0026gt; 802 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number803 index802 alt2\u0026quot;\u0026gt; 803 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number804 index803 alt1\u0026quot;\u0026gt; 804 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number805 index804 alt2\u0026quot;\u0026gt; 805 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number806 index805 alt1\u0026quot;\u0026gt; 806 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number807 index806 alt2\u0026quot;\u0026gt; 807 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number808 index807 alt1\u0026quot;\u0026gt; 808 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number809 index808 alt2\u0026quot;\u0026gt; 809 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number810 index809 alt1\u0026quot;\u0026gt; 810 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number811 index810 alt2\u0026quot;\u0026gt; 811 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number812 index811 alt1\u0026quot;\u0026gt; 812 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number813 index812 alt2\u0026quot;\u0026gt; 813 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number814 index813 alt1\u0026quot;\u0026gt; 814 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number815 index814 alt2\u0026quot;\u0026gt; 815 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number816 index815 alt1\u0026quot;\u0026gt; 816 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number817 index816 alt2\u0026quot;\u0026gt; 817 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number818 index817 alt1\u0026quot;\u0026gt; 818 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number819 index818 alt2\u0026quot;\u0026gt; 819 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number820 index819 alt1\u0026quot;\u0026gt; 820 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number821 index820 alt2\u0026quot;\u0026gt; 821 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number822 index821 alt1\u0026quot;\u0026gt; 822 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number823 index822 alt2\u0026quot;\u0026gt; 823 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number824 index823 alt1\u0026quot;\u0026gt; 824 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number825 index824 alt2\u0026quot;\u0026gt; 825 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number826 index825 alt1\u0026quot;\u0026gt; 826 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number827 index826 alt2\u0026quot;\u0026gt; 827 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number828 index827 alt1\u0026quot;\u0026gt; 828 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number829 index828 alt2\u0026quot;\u0026gt; 829 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number830 index829 alt1\u0026quot;\u0026gt; 830 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number831 index830 alt2\u0026quot;\u0026gt; 831 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number832 index831 alt1\u0026quot;\u0026gt; 832 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number833 index832 alt2\u0026quot;\u0026gt; 833 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number834 index833 alt1\u0026quot;\u0026gt; 834 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number835 index834 alt2\u0026quot;\u0026gt; 835 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number836 index835 alt1\u0026quot;\u0026gt; 836 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number837 index836 alt2\u0026quot;\u0026gt; 837 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number838 index837 alt1\u0026quot;\u0026gt; 838 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number839 index838 alt2\u0026quot;\u0026gt; 839 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number840 index839 alt1\u0026quot;\u0026gt; 840 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number841 index840 alt2\u0026quot;\u0026gt; 841 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number842 index841 alt1\u0026quot;\u0026gt; 842 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number843 index842 alt2\u0026quot;\u0026gt; 843 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number844 index843 alt1\u0026quot;\u0026gt; 844 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number845 index844 alt2\u0026quot;\u0026gt; 845 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number846 index845 alt1\u0026quot;\u0026gt; 846 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number847 index846 alt2\u0026quot;\u0026gt; 847 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number848 index847 alt1\u0026quot;\u0026gt; 848 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number849 index848 alt2\u0026quot;\u0026gt; 849 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number850 index849 alt1\u0026quot;\u0026gt; 850 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number851 index850 alt2\u0026quot;\u0026gt; 851 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number852 index851 alt1\u0026quot;\u0026gt; 852 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number853 index852 alt2\u0026quot;\u0026gt; 853 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number854 index853 alt1\u0026quot;\u0026gt; 854 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number855 index854 alt2\u0026quot;\u0026gt; 855 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number856 index855 alt1\u0026quot;\u0026gt; 856 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number857 index856 alt2\u0026quot;\u0026gt; 857 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number858 index857 alt1\u0026quot;\u0026gt; 858 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number859 index858 alt2\u0026quot;\u0026gt; 859 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number860 index859 alt1\u0026quot;\u0026gt; 860 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number861 index860 alt2\u0026quot;\u0026gt; 861 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number862 index861 alt1\u0026quot;\u0026gt; 862 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number863 index862 alt2\u0026quot;\u0026gt; 863 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number864 index863 alt1\u0026quot;\u0026gt; 864 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number865 index864 alt2\u0026quot;\u0026gt; 865 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number866 index865 alt1\u0026quot;\u0026gt; 866 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number867 index866 alt2\u0026quot;\u0026gt; 867 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number868 index867 alt1\u0026quot;\u0026gt; 868 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number869 index868 alt2\u0026quot;\u0026gt; 869 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number870 index869 alt1\u0026quot;\u0026gt; 870 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number871 index870 alt2\u0026quot;\u0026gt; 871 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number872 index871 alt1\u0026quot;\u0026gt; 872 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number873 index872 alt2\u0026quot;\u0026gt; 873 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number874 index873 alt1\u0026quot;\u0026gt; 874 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number875 index874 alt2\u0026quot;\u0026gt; 875 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number876 index875 alt1\u0026quot;\u0026gt; 876 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number877 index876 alt2\u0026quot;\u0026gt; 877 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number878 index877 alt1\u0026quot;\u0026gt; 878 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number879 index878 alt2\u0026quot;\u0026gt; 879 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number880 index879 alt1\u0026quot;\u0026gt; 880 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number881 index880 alt2\u0026quot;\u0026gt; 881 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number882 index881 alt1\u0026quot;\u0026gt; 882 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number883 index882 alt2\u0026quot;\u0026gt; 883 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number884 index883 alt1\u0026quot;\u0026gt; 884 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number885 index884 alt2\u0026quot;\u0026gt; 885 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number886 index885 alt1\u0026quot;\u0026gt; 886 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number887 index886 alt2\u0026quot;\u0026gt; 887 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number888 index887 alt1\u0026quot;\u0026gt; 888 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number889 index888 alt2\u0026quot;\u0026gt; 889 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number890 index889 alt1\u0026quot;\u0026gt; 890 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number891 index890 alt2\u0026quot;\u0026gt; 891 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number892 index891 alt1\u0026quot;\u0026gt; 892 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number893 index892 alt2\u0026quot;\u0026gt; 893 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number894 index893 alt1\u0026quot;\u0026gt; 894 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number895 index894 alt2\u0026quot;\u0026gt; 895 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number896 index895 alt1\u0026quot;\u0026gt; 896 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number897 index896 alt2\u0026quot;\u0026gt; 897 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number898 index897 alt1\u0026quot;\u0026gt; 898 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number899 index898 alt2\u0026quot;\u0026gt; 899 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number900 index899 alt1\u0026quot;\u0026gt; 900 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number901 index900 alt2\u0026quot;\u0026gt; 901 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number902 index901 alt1\u0026quot;\u0026gt; 902 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number903 index902 alt2\u0026quot;\u0026gt; 903 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number904 index903 alt1\u0026quot;\u0026gt; 904 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number905 index904 alt2\u0026quot;\u0026gt; 905 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number906 index905 alt1\u0026quot;\u0026gt; 906 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number907 index906 alt2\u0026quot;\u0026gt; 907 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number908 index907 alt1\u0026quot;\u0026gt; 908 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number909 index908 alt2\u0026quot;\u0026gt; 909 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number910 index909 alt1\u0026quot;\u0026gt; 910 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number911 index910 alt2\u0026quot;\u0026gt; 911 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number912 index911 alt1\u0026quot;\u0026gt; 912 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number913 index912 alt2\u0026quot;\u0026gt; 913 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number914 index913 alt1\u0026quot;\u0026gt; 914 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number915 index914 alt2\u0026quot;\u0026gt; 915 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number916 index915 alt1\u0026quot;\u0026gt; 916 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number917 index916 alt2\u0026quot;\u0026gt; 917 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number918 index917 alt1\u0026quot;\u0026gt; 918 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number919 index918 alt2\u0026quot;\u0026gt; 919 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number920 index919 alt1\u0026quot;\u0026gt; 920 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number921 index920 alt2\u0026quot;\u0026gt; 921 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number922 index921 alt1\u0026quot;\u0026gt; 922 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number923 index922 alt2\u0026quot;\u0026gt; 923 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number924 index923 alt1\u0026quot;\u0026gt; 924 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number925 index924 alt2\u0026quot;\u0026gt; 925 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number926 index925 alt1\u0026quot;\u0026gt; 926 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number927 index926 alt2\u0026quot;\u0026gt; 927 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number928 index927 alt1\u0026quot;\u0026gt; 928 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number929 index928 alt2\u0026quot;\u0026gt; 929 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number930 index929 alt1\u0026quot;\u0026gt; 930 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number931 index930 alt2\u0026quot;\u0026gt; 931 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number932 index931 alt1\u0026quot;\u0026gt; 932 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number933 index932 alt2\u0026quot;\u0026gt; 933 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number934 index933 alt1\u0026quot;\u0026gt; 934 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number935 index934 alt2\u0026quot;\u0026gt; 935 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number936 index935 alt1\u0026quot;\u0026gt; 936 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number937 index936 alt2\u0026quot;\u0026gt; 937 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number938 index937 alt1\u0026quot;\u0026gt; 938 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number939 index938 alt2\u0026quot;\u0026gt; 939 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number940 index939 alt1\u0026quot;\u0026gt; 940 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number941 index940 alt2\u0026quot;\u0026gt; 941 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number942 index941 alt1\u0026quot;\u0026gt; 942 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number943 index942 alt2\u0026quot;\u0026gt; 943 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number944 index943 alt1\u0026quot;\u0026gt; 944 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number945 index944 alt2\u0026quot;\u0026gt; 945 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number946 index945 alt1\u0026quot;\u0026gt; 946 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number947 index946 alt2\u0026quot;\u0026gt; 947 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number948 index947 alt1\u0026quot;\u0026gt; 948 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number949 index948 alt2\u0026quot;\u0026gt; 949 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number950 index949 alt1\u0026quot;\u0026gt; 950 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number951 index950 alt2\u0026quot;\u0026gt; 951 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number952 index951 alt1\u0026quot;\u0026gt; 952 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number953 index952 alt2\u0026quot;\u0026gt; 953 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number954 index953 alt1\u0026quot;\u0026gt; 954 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number955 index954 alt2\u0026quot;\u0026gt; 955 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number956 index955 alt1\u0026quot;\u0026gt; 956 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number957 index956 alt2\u0026quot;\u0026gt; 957 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number958 index957 alt1\u0026quot;\u0026gt; 958 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number959 index958 alt2\u0026quot;\u0026gt; 959 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number960 index959 alt1\u0026quot;\u0026gt; 960 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number961 index960 alt2\u0026quot;\u0026gt; 961 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number962 index961 alt1\u0026quot;\u0026gt; 962 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number963 index962 alt2\u0026quot;\u0026gt; 963 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number964 index963 alt1\u0026quot;\u0026gt; 964 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number965 index964 alt2\u0026quot;\u0026gt; 965 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number966 index965 alt1\u0026quot;\u0026gt; 966 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number967 index966 alt2\u0026quot;\u0026gt; 967 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number968 index967 alt1\u0026quot;\u0026gt; 968 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number969 index968 alt2\u0026quot;\u0026gt; 969 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number970 index969 alt1\u0026quot;\u0026gt; 970 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number971 index970 alt2\u0026quot;\u0026gt; 971 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number972 index971 alt1\u0026quot;\u0026gt; 972 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number973 index972 alt2\u0026quot;\u0026gt; 973 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number974 index973 alt1\u0026quot;\u0026gt; 974 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number975 index974 alt2\u0026quot;\u0026gt; 975 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number976 index975 alt1\u0026quot;\u0026gt; 976 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number977 index976 alt2\u0026quot;\u0026gt; 977 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number978 index977 alt1\u0026quot;\u0026gt; 978 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number979 index978 alt2\u0026quot;\u0026gt; 979 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number980 index979 alt1\u0026quot;\u0026gt; 980 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number981 index980 alt2\u0026quot;\u0026gt; 981 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number982 index981 alt1\u0026quot;\u0026gt; 982 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number983 index982 alt2\u0026quot;\u0026gt; 983 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number984 index983 alt1\u0026quot;\u0026gt; 984 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number985 index984 alt2\u0026quot;\u0026gt; 985 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number986 index985 alt1\u0026quot;\u0026gt; 986 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number987 index986 alt2\u0026quot;\u0026gt; 987 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number988 index987 alt1\u0026quot;\u0026gt; 988 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number989 index988 alt2\u0026quot;\u0026gt; 989 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number990 index989 alt1\u0026quot;\u0026gt; 990 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number991 index990 alt2\u0026quot;\u0026gt; 991 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number992 index991 alt1\u0026quot;\u0026gt; 992 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number993 index992 alt2\u0026quot;\u0026gt; 993 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number994 index993 alt1\u0026quot;\u0026gt; 994 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number995 index994 alt2\u0026quot;\u0026gt; 995 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number996 index995 alt1\u0026quot;\u0026gt; 996 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number997 index996 alt2\u0026quot;\u0026gt; 997 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number998 index997 alt1\u0026quot;\u0026gt; 998 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number999 index998 alt2\u0026quot;\u0026gt; 999 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1000 index999 alt1\u0026quot;\u0026gt; 1000 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1001 index1000 alt2\u0026quot;\u0026gt; 1001 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1002 index1001 alt1\u0026quot;\u0026gt; 1002 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1003 index1002 alt2\u0026quot;\u0026gt; 1003 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1004 index1003 alt1\u0026quot;\u0026gt; 1004 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1005 index1004 alt2\u0026quot;\u0026gt; 1005 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1006 index1005 alt1\u0026quot;\u0026gt; 1006 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1007 index1006 alt2\u0026quot;\u0026gt; 1007 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1008 index1007 alt1\u0026quot;\u0026gt; 1008 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1009 index1008 alt2\u0026quot;\u0026gt; 1009 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1010 index1009 alt1\u0026quot;\u0026gt; 1010 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1011 index1010 alt2\u0026quot;\u0026gt; 1011 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1012 index1011 alt1\u0026quot;\u0026gt; 1012 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1013 index1012 alt2\u0026quot;\u0026gt; 1013 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1014 index1013 alt1\u0026quot;\u0026gt; 1014 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1015 index1014 alt2\u0026quot;\u0026gt; 1015 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1016 index1015 alt1\u0026quot;\u0026gt; 1016 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1017 index1016 alt2\u0026quot;\u0026gt; 1017 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1018 index1017 alt1\u0026quot;\u0026gt; 1018 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1019 index1018 alt2\u0026quot;\u0026gt; 1019 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1020 index1019 alt1\u0026quot;\u0026gt; 1020 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1021 index1020 alt2\u0026quot;\u0026gt; 1021 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1022 index1021 alt1\u0026quot;\u0026gt; 1022 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1023 index1022 alt2\u0026quot;\u0026gt; 1023 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1024 index1023 alt1\u0026quot;\u0026gt; 1024 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1025 index1024 alt2\u0026quot;\u0026gt; 1025 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1026 index1025 alt1\u0026quot;\u0026gt; 1026 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1027 index1026 alt2\u0026quot;\u0026gt; 1027 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1028 index1027 alt1\u0026quot;\u0026gt; 1028 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1029 index1028 alt2\u0026quot;\u0026gt; 1029 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1030 index1029 alt1\u0026quot;\u0026gt; 1030 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1031 index1030 alt2\u0026quot;\u0026gt; 1031 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1032 index1031 alt1\u0026quot;\u0026gt; 1032 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1033 index1032 alt2\u0026quot;\u0026gt; 1033 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1034 index1033 alt1\u0026quot;\u0026gt; 1034 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1035 index1034 alt2\u0026quot;\u0026gt; 1035 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1036 index1035 alt1\u0026quot;\u0026gt; 1036 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1037 index1036 alt2\u0026quot;\u0026gt; 1037 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1038 index1037 alt1\u0026quot;\u0026gt; 1038 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1039 index1038 alt2\u0026quot;\u0026gt; 1039 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1040 index1039 alt1\u0026quot;\u0026gt; 1040 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1041 index1040 alt2\u0026quot;\u0026gt; 1041 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1042 index1041 alt1\u0026quot;\u0026gt; 1042 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1043 index1042 alt2\u0026quot;\u0026gt; 1043 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1044 index1043 alt1\u0026quot;\u0026gt; 1044 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1045 index1044 alt2\u0026quot;\u0026gt; 1045 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1046 index1045 alt1\u0026quot;\u0026gt; 1046 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1047 index1046 alt2\u0026quot;\u0026gt; 1047 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1048 index1047 alt1\u0026quot;\u0026gt; 1048 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1049 index1048 alt2\u0026quot;\u0026gt; 1049 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1050 index1049 alt1\u0026quot;\u0026gt; 1050 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1051 index1050 alt2\u0026quot;\u0026gt; 1051 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1052 index1051 alt1\u0026quot;\u0026gt; 1052 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1053 index1052 alt2\u0026quot;\u0026gt; 1053 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1054 index1053 alt1\u0026quot;\u0026gt; 1054 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1055 index1054 alt2\u0026quot;\u0026gt; 1055 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1056 index1055 alt1\u0026quot;\u0026gt; 1056 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1057 index1056 alt2\u0026quot;\u0026gt; 1057 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1058 index1057 alt1\u0026quot;\u0026gt; 1058 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1059 index1058 alt2\u0026quot;\u0026gt; 1059 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1060 index1059 alt1\u0026quot;\u0026gt; 1060 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1061 index1060 alt2\u0026quot;\u0026gt; 1061 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1062 index1061 alt1\u0026quot;\u0026gt; 1062 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1063 index1062 alt2\u0026quot;\u0026gt; 1063 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1064 index1063 alt1\u0026quot;\u0026gt; 1064 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1065 index1064 alt2\u0026quot;\u0026gt; 1065 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1066 index1065 alt1\u0026quot;\u0026gt; 1066 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1067 index1066 alt2\u0026quot;\u0026gt; 1067 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1068 index1067 alt1\u0026quot;\u0026gt; 1068 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1069 index1068 alt2\u0026quot;\u0026gt; 1069 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1070 index1069 alt1\u0026quot;\u0026gt; 1070 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1071 index1070 alt2\u0026quot;\u0026gt; 1071 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1072 index1071 alt1\u0026quot;\u0026gt; 1072 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1073 index1072 alt2\u0026quot;\u0026gt; 1073 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1074 index1073 alt1\u0026quot;\u0026gt; 1074 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1075 index1074 alt2\u0026quot;\u0026gt; 1075 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1076 index1075 alt1\u0026quot;\u0026gt; 1076 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1077 index1076 alt2\u0026quot;\u0026gt; 1077 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1078 index1077 alt1\u0026quot;\u0026gt; 1078 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1079 index1078 alt2\u0026quot;\u0026gt; 1079 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1080 index1079 alt1\u0026quot;\u0026gt; 1080 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1081 index1080 alt2\u0026quot;\u0026gt; 1081 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1082 index1081 alt1\u0026quot;\u0026gt; 1082 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1083 index1082 alt2\u0026quot;\u0026gt; 1083 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1084 index1083 alt1\u0026quot;\u0026gt; 1084 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1085 index1084 alt2\u0026quot;\u0026gt; 1085 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1086 index1085 alt1\u0026quot;\u0026gt; 1086 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1087 index1086 alt2\u0026quot;\u0026gt; 1087 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1088 index1087 alt1\u0026quot;\u0026gt; 1088 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1089 index1088 alt2\u0026quot;\u0026gt; 1089 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1090 index1089 alt1\u0026quot;\u0026gt; 1090 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1091 index1090 alt2\u0026quot;\u0026gt; 1091 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1092 index1091 alt1\u0026quot;\u0026gt; 1092 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1093 index1092 alt2\u0026quot;\u0026gt; 1093 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1094 index1093 alt1\u0026quot;\u0026gt; 1094 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1095 index1094 alt2\u0026quot;\u0026gt; 1095 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1096 index1095 alt1\u0026quot;\u0026gt; 1096 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1097 index1096 alt2\u0026quot;\u0026gt; 1097 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1098 index1097 alt1\u0026quot;\u0026gt; 1098 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1099 index1098 alt2\u0026quot;\u0026gt; 1099 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1100 index1099 alt1\u0026quot;\u0026gt; 1100 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1101 index1100 alt2\u0026quot;\u0026gt; 1101 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1102 index1101 alt1\u0026quot;\u0026gt; 1102 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1103 index1102 alt2\u0026quot;\u0026gt; 1103 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1104 index1103 alt1\u0026quot;\u0026gt; 1104 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1105 index1104 alt2\u0026quot;\u0026gt; 1105 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1106 index1105 alt1\u0026quot;\u0026gt; 1106 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1107 index1106 alt2\u0026quot;\u0026gt; 1107 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1108 index1107 alt1\u0026quot;\u0026gt; 1108 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1109 index1108 alt2\u0026quot;\u0026gt; 1109 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1110 index1109 alt1\u0026quot;\u0026gt; 1110 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1111 index1110 alt2\u0026quot;\u0026gt; 1111 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1112 index1111 alt1\u0026quot;\u0026gt; 1112 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1113 index1112 alt2\u0026quot;\u0026gt; 1113 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1114 index1113 alt1\u0026quot;\u0026gt; 1114 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1115 index1114 alt2\u0026quot;\u0026gt; 1115 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1116 index1115 alt1\u0026quot;\u0026gt; 1116 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1117 index1116 alt2\u0026quot;\u0026gt; 1117 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1118 index1117 alt1\u0026quot;\u0026gt; 1118 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1119 index1118 alt2\u0026quot;\u0026gt; 1119 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1120 index1119 alt1\u0026quot;\u0026gt; 1120 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1121 index1120 alt2\u0026quot;\u0026gt; 1121 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1122 index1121 alt1\u0026quot;\u0026gt; 1122 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1123 index1122 alt2\u0026quot;\u0026gt; 1123 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1124 index1123 alt1\u0026quot;\u0026gt; 1124 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1125 index1124 alt2\u0026quot;\u0026gt; 1125 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1126 index1125 alt1\u0026quot;\u0026gt; 1126 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1127 index1126 alt2\u0026quot;\u0026gt; 1127 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1128 index1127 alt1\u0026quot;\u0026gt; 1128 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1129 index1128 alt2\u0026quot;\u0026gt; 1129 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1130 index1129 alt1\u0026quot;\u0026gt; 1130 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1131 index1130 alt2\u0026quot;\u0026gt; 1131 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1132 index1131 alt1\u0026quot;\u0026gt; 1132 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1133 index1132 alt2\u0026quot;\u0026gt; 1133 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1134 index1133 alt1\u0026quot;\u0026gt; 1134 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1135 index1134 alt2\u0026quot;\u0026gt; 1135 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1136 index1135 alt1\u0026quot;\u0026gt; 1136 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1137 index1136 alt2\u0026quot;\u0026gt; 1137 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1138 index1137 alt1\u0026quot;\u0026gt; 1138 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1139 index1138 alt2\u0026quot;\u0026gt; 1139 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1140 index1139 alt1\u0026quot;\u0026gt; 1140 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1141 index1140 alt2\u0026quot;\u0026gt; 1141 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1142 index1141 alt1\u0026quot;\u0026gt; 1142 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1143 index1142 alt2\u0026quot;\u0026gt; 1143 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1144 index1143 alt1\u0026quot;\u0026gt; 1144 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `SlidingMenu ``extends` `RelativeLayout {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``private` `static` `final` `String TAG = SlidingMenu.``class``.getSimpleName();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``public` `static` `final` `int` `SLIDING_WINDOW = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``public` `static` `final` `int` `SLIDING_CONTENT = ``1``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``private` `boolean` `mActionbarOverlay = ``false``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``* Constant value for use with setTouchModeAbove(). Allows the SlidingMenu` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``* to be opened with a swipe gesture on the screen's margin` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``public` `static` `final` `int` `TOUCHMODE_MARGIN = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``* Constant value for use with setTouchModeAbove(). Allows the SlidingMenu` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``* to be opened with a swipe gesture anywhere on the screen` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``public` `static` `final` `int` `TOUCHMODE_FULLSCREEN = ``1``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``* Constant value for use with setTouchModeAbove(). Denies the SlidingMenu` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``* to be opened with a swipe gesture` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``public` `static` `final` `int` `TOUCHMODE_NONE = ``2``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ``* Constant value for use with setMode(). Puts the menu to the left of the` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``* content.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``public` `static` `final` `int` `LEFT = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ``* Constant value for use with setMode(). Puts the menu to the right of the` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``* content.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; ` ``public` `static` `final` `int` `RIGHT = ``1``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; ` ``* Constant value for use with setMode(). Puts menus to the left and right` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; ` ``* of the content.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; ` ``public` `static` `final` `int` `LEFT_RIGHT = ``2``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; ` ``private` `CustomViewAbove mViewAbove;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; ` ``private` `CustomViewBehind mViewBehind;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; ` ``/** 整体的背景，用一个ImageView代替 */` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; ` ``private` `ImageView mViewBackground;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; ` ``private` `OnOpenListener mOpenListener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; ` ``private` `OnOpenListener mSecondaryOpenListner;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; ` ``private` `OnCloseListener mCloseListener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; ` ``* The listener interface for receiving onOpen events. The class that is` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; ` ``* interested in processing a onOpen event implements this interface, and` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; ` ``* the object created with that class is registered with a component using` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; ` ``* the component's \u0026amp;lt;code\u0026amp;gt;addOnOpenListener\u0026amp;lt;code\u0026amp;gt; method. When` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; ` ``* the onOpen event occurs, that object's appropriate` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; ` ``* method is invoked` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; ` ``public` `interface` `OnOpenListener {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; ` ``* On open.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; ` ``public` `void` `onOpen();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; ` ``* The listener interface for receiving onOpened events. The class that is` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; ` ``* interested in processing a onOpened event implements this interface, and` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; ` ``* the object created with that class is registered with a component using` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; ` ``* the component's \u0026amp;lt;code\u0026amp;gt;addOnOpenedListener\u0026amp;lt;code\u0026amp;gt; method. When` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; ` ``* the onOpened event occurs, that object's appropriate` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; ` ``* method is invoked.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; ` ``* @see OnOpenedEvent` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; ` ``public` `interface` `OnOpenedListener {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; ` ``* On opened.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; ` ``public` `void` `onOpened();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt; ` ``* The listener interface for receiving onClose events. The class that is` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt; ` ``* interested in processing a onClose event implements this interface, and` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt; ` ``* the object created with that class is registered with a component using` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt; ` ``* the component's \u0026amp;lt;code\u0026amp;gt;addOnCloseListener\u0026amp;lt;code\u0026amp;gt; method. When` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt; ` ``* the onClose event occurs, that object's appropriate` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt; ` ``* method is invoked.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt; ` ``* @see OnCloseEvent` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number101 index100 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number102 index101 alt1\u0026quot;\u0026gt; ` ``public` `interface` `OnCloseListener {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number103 index102 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number104 index103 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number105 index104 alt2\u0026quot;\u0026gt; ` ``* On close.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number106 index105 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number107 index106 alt2\u0026quot;\u0026gt; ` ``public` `void` `onClose();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number108 index107 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number109 index108 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number110 index109 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number111 index110 alt2\u0026quot;\u0026gt; ` ``* The listener interface for receiving onClosed events. The class that is` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number112 index111 alt1\u0026quot;\u0026gt; ` ``* interested in processing a onClosed event implements this interface, and` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number113 index112 alt2\u0026quot;\u0026gt; ` ``* the object created with that class is registered with a component using` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number114 index113 alt1\u0026quot;\u0026gt; ` ``* the component's \u0026amp;lt;code\u0026amp;gt;addOnClosedListener\u0026amp;lt;code\u0026amp;gt; method. When` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number115 index114 alt2\u0026quot;\u0026gt; ` ``* the onClosed event occurs, that object's appropriate` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number116 index115 alt1\u0026quot;\u0026gt; ` ``* method is invoked.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number117 index116 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number118 index117 alt1\u0026quot;\u0026gt; ` ``* @see OnClosedEvent` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number119 index118 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number120 index119 alt1\u0026quot;\u0026gt; ` ``public` `interface` `OnClosedListener {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number121 index120 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number122 index121 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number123 index122 alt2\u0026quot;\u0026gt; ` ``* On closed.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number124 index123 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number125 index124 alt2\u0026quot;\u0026gt; ` ``public` `void` `onClosed();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number126 index125 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number127 index126 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number128 index127 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number129 index128 alt2\u0026quot;\u0026gt; ` ``* The Interface CanvasTransformer.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number130 index129 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number131 index130 alt2\u0026quot;\u0026gt; ` ``public` `interface` `CanvasTransformer {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number132 index131 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number133 index132 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number134 index133 alt1\u0026quot;\u0026gt; ` ``* Transform canvas.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number135 index134 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number136 index135 alt1\u0026quot;\u0026gt; ` ``* @param canvas` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number137 index136 alt2\u0026quot;\u0026gt; ` ``* the canvas` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number138 index137 alt1\u0026quot;\u0026gt; ` ``* @param percentOpen` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number139 index138 alt2\u0026quot;\u0026gt; ` ``* the percent open` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number140 index139 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number141 index140 alt2\u0026quot;\u0026gt; ` ``public` `void` `transformCanvas(Canvas canvas, ``float` `percentOpen);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number142 index141 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number143 index142 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number144 index143 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number145 index144 alt2\u0026quot;\u0026gt; ` ``* Instantiates a new SlidingMenu.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number146 index145 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number147 index146 alt2\u0026quot;\u0026gt; ` ``* @param context` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number148 index147 alt1\u0026quot;\u0026gt; ` ``* the associated Context` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number149 index148 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number150 index149 alt1\u0026quot;\u0026gt; ` ``public` `SlidingMenu(Context context) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number151 index150 alt2\u0026quot;\u0026gt; ` ``this``(context, ``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number152 index151 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number153 index152 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number154 index153 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number155 index154 alt2\u0026quot;\u0026gt; ` ``* Instantiates a new SlidingMenu and attach to Activity.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number156 index155 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number157 index156 alt2\u0026quot;\u0026gt; ` ``* @param activity` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number158 index157 alt1\u0026quot;\u0026gt; ` ``* the activity to attach slidingmenu` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number159 index158 alt2\u0026quot;\u0026gt; ` ``* @param slideStyle` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number160 index159 alt1\u0026quot;\u0026gt; ` ``* the slidingmenu style` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number161 index160 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number162 index161 alt1\u0026quot;\u0026gt; ` ``public` `SlidingMenu(Activity activity, ``int` `slideStyle) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number163 index162 alt2\u0026quot;\u0026gt; ` ``this``(activity, ``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number164 index163 alt1\u0026quot;\u0026gt; ` ``this``.attachToActivity(activity, slideStyle);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number165 index164 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number166 index165 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number167 index166 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number168 index167 alt1\u0026quot;\u0026gt; ` ``* Instantiates a new SlidingMenu.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number169 index168 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number170 index169 alt1\u0026quot;\u0026gt; ` ``* @param context` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number171 index170 alt2\u0026quot;\u0026gt; ` ``* the associated Context` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number172 index171 alt1\u0026quot;\u0026gt; ` ``* @param attrs` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number173 index172 alt2\u0026quot;\u0026gt; ` ``* the attrs` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number174 index173 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number175 index174 alt2\u0026quot;\u0026gt; ` ``public` `SlidingMenu(Context context, AttributeSet attrs) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number176 index175 alt1\u0026quot;\u0026gt; ` ``this``(context, attrs, ````);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number177 index176 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number178 index177 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number179 index178 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number180 index179 alt1\u0026quot;\u0026gt; ` ``* Instantiates a new SlidingMenu.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number181 index180 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number182 index181 alt1\u0026quot;\u0026gt; ` ``* @param context` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number183 index182 alt2\u0026quot;\u0026gt; ` ``* the associated Context` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number184 index183 alt1\u0026quot;\u0026gt; ` ``* @param attrs` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number185 index184 alt2\u0026quot;\u0026gt; ` ``* the attrs` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number186 index185 alt1\u0026quot;\u0026gt; ` ``* @param defStyle` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number187 index186 alt2\u0026quot;\u0026gt; ` ``* the def style` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number188 index187 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number189 index188 alt2\u0026quot;\u0026gt; ` ``public` `SlidingMenu(Context context, AttributeSet attrs, ``int` `defStyle) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number190 index189 alt1\u0026quot;\u0026gt; ` ``super``(context, attrs, defStyle);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number191 index190 alt2\u0026quot;\u0026gt; ` ``/** SlidingMenu是一个RelativeLayout，这里把背景图ImageView添加到RelativeLayout的最底层。*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number192 index191 alt1\u0026quot;\u0026gt; ` ``LayoutParams backgroundParams = ``new` `LayoutParams(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number193 index192 alt2\u0026quot;\u0026gt; ` ``LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number194 index193 alt1\u0026quot;\u0026gt; ` ``mViewBackground = ``new` `ImageView(context);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number195 index194 alt2\u0026quot;\u0026gt; ` ``mViewBackground.setScaleType(ImageView.ScaleType.CENTER_CROP);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number196 index195 alt1\u0026quot;\u0026gt; ` ``addView(mViewBackground, backgroundParams);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number197 index196 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number198 index197 alt1\u0026quot;\u0026gt; ` ``LayoutParams behindParams = ``new` `LayoutParams(LayoutParams.MATCH_PARENT,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number199 index198 alt2\u0026quot;\u0026gt; ` ``LayoutParams.MATCH_PARENT);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number200 index199 alt1\u0026quot;\u0026gt; ` ``mViewBehind = ``new` `CustomViewBehind(context);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number201 index200 alt2\u0026quot;\u0026gt; ` ``addView(mViewBehind, behindParams);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number202 index201 alt1\u0026quot;\u0026gt; ` ``LayoutParams aboveParams = ``new` `LayoutParams(LayoutParams.MATCH_PARENT,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number203 index202 alt2\u0026quot;\u0026gt; ` ``LayoutParams.MATCH_PARENT);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number204 index203 alt1\u0026quot;\u0026gt; ` ``mViewAbove = ``new` `CustomViewAbove(context);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number205 index204 alt2\u0026quot;\u0026gt; ` ``addView(mViewAbove, aboveParams);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number206 index205 alt1\u0026quot;\u0026gt; ` ``// register the CustomViewBehind with the CustomViewAbove` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number207 index206 alt2\u0026quot;\u0026gt; ` ``mViewAbove.setCustomViewBehind(mViewBehind);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number208 index207 alt1\u0026quot;\u0026gt; ` ``mViewBehind.setCustomViewAbove(mViewAbove);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number209 index208 alt2\u0026quot;\u0026gt; ` ``mViewAbove.setOnPageChangeListener(``new` `OnPageChangeListener() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number210 index209 alt1\u0026quot;\u0026gt; ` ``public` `static` `final` `int` `POSITION_OPEN = ````;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number211 index210 alt2\u0026quot;\u0026gt; ` ``public` `static` `final` `int` `POSITION_CLOSE = ``1``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number212 index211 alt1\u0026quot;\u0026gt; ` ``public` `static` `final` `int` `POSITION_SECONDARY_OPEN = ``2``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number213 index212 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number214 index213 alt1\u0026quot;\u0026gt; ` ``public` `void` `onPageScrolled(``int` `position, ``float` `positionOffset,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number215 index214 alt2\u0026quot;\u0026gt; ` ``int` `positionOffsetPixels) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number216 index215 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number217 index216 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number218 index217 alt1\u0026quot;\u0026gt; ` ``public` `void` `onPageSelected(``int` `position) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number219 index218 alt2\u0026quot;\u0026gt; ` ``if` `(position == POSITION_OPEN \u0026amp;\u0026amp; mOpenListener != ``null``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number220 index219 alt1\u0026quot;\u0026gt; ` ``mOpenListener.onOpen();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number221 index220 alt2\u0026quot;\u0026gt; ` ``} ``else` `if` `(position == POSITION_CLOSE \u0026amp;\u0026amp; mCloseListener != ``null``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number222 index221 alt1\u0026quot;\u0026gt; ` ``mCloseListener.onClose();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number223 index222 alt2\u0026quot;\u0026gt; ` ``} ``else` `if` `(position == POSITION_SECONDARY_OPEN` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number224 index223 alt1\u0026quot;\u0026gt; ` ``\u0026amp;\u0026amp; mSecondaryOpenListner != ``null``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number225 index224 alt2\u0026quot;\u0026gt; ` ``mSecondaryOpenListner.onOpen();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number226 index225 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number227 index226 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number228 index227 alt1\u0026quot;\u0026gt; ` ``});` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number229 index228 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number230 index229 alt1\u0026quot;\u0026gt; ` ``// now style everything!` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number231 index230 alt2\u0026quot;\u0026gt; ` ``TypedArray ta = context.obtainStyledAttributes(attrs,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number232 index231 alt1\u0026quot;\u0026gt; ` ``R.styleable.SlidingMenu);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number233 index232 alt2\u0026quot;\u0026gt; ` ``// set the above and behind views if defined in xml` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number234 index233 alt1\u0026quot;\u0026gt; ` ``int` `mode = ta.getInt(R.styleable.SlidingMenu_mode, LEFT);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number235 index234 alt2\u0026quot;\u0026gt; ` ``setMode(mode);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number236 index235 alt1\u0026quot;\u0026gt; ` ``int` `viewAbove = ta.getResourceId(R.styleable.SlidingMenu_viewAbove, -``1``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number237 index236 alt2\u0026quot;\u0026gt; ` ``if` `(viewAbove != -``1``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number238 index237 alt1\u0026quot;\u0026gt; ` ``setContent(viewAbove);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number239 index238 alt2\u0026quot;\u0026gt; ` ``} ``else` `{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number240 index239 alt1\u0026quot;\u0026gt; ` ``setContent(``new` `FrameLayout(context));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number241 index240 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number242 index241 alt1\u0026quot;\u0026gt; ` ``int` `viewBehind = ta.getResourceId(R.styleable.SlidingMenu_viewBehind,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number243 index242 alt2\u0026quot;\u0026gt; ` ``-``1``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number244 index243 alt1\u0026quot;\u0026gt; ` ``if` `(viewBehind != -``1``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number245 index244 alt2\u0026quot;\u0026gt; ` ``setMenu(viewBehind);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number246 index245 alt1\u0026quot;\u0026gt; ` ``} ``else` `{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number247 index246 alt2\u0026quot;\u0026gt; ` ``setMenu(``new` `FrameLayout(context));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number248 index247 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number249 index248 alt2\u0026quot;\u0026gt; ` ``int` `touchModeAbove = ta.getInt(R.styleable.SlidingMenu_touchModeAbove,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number250 index249 alt1\u0026quot;\u0026gt; ` ``TOUCHMODE_MARGIN);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number251 index250 alt2\u0026quot;\u0026gt; ` ``setTouchModeAbove(touchModeAbove);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number252 index251 alt1\u0026quot;\u0026gt; ` ``int` `touchModeBehind = ta.getInt(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number253 index252 alt2\u0026quot;\u0026gt; ` ``R.styleable.SlidingMenu_touchModeBehind, TOUCHMODE_MARGIN);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number254 index253 alt1\u0026quot;\u0026gt; ` ``setTouchModeBehind(touchModeBehind);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number255 index254 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number256 index255 alt1\u0026quot;\u0026gt; ` ``int` `offsetBehind = (``int``) ta.getDimension(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number257 index256 alt2\u0026quot;\u0026gt; ` ``R.styleable.SlidingMenu_behindOffset, -``1``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number258 index257 alt1\u0026quot;\u0026gt; ` ``int` `widthBehind = (``int``) ta.getDimension(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number259 index258 alt2\u0026quot;\u0026gt; ` ``R.styleable.SlidingMenu_behindWidth, -``1``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number260 index259 alt1\u0026quot;\u0026gt; ` ``if` `(offsetBehind != -``1` `\u0026amp;\u0026amp; widthBehind != -``1``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number261 index260 alt2\u0026quot;\u0026gt; ` ``throw` `new` `IllegalStateException(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number262 index261 alt1\u0026quot;\u0026gt; ` ``\u0026quot;Cannot set both behindOffset and behindWidth for a SlidingMenu\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number263 index262 alt2\u0026quot;\u0026gt; ` ``else` `if` `(offsetBehind != -``1``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number264 index263 alt1\u0026quot;\u0026gt; ` ``setBehindOffset(offsetBehind);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number265 index264 alt2\u0026quot;\u0026gt; ` ``else` `if` `(widthBehind != -``1``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number266 index265 alt1\u0026quot;\u0026gt; ` ``setBehindWidth(widthBehind);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number267 index266 alt2\u0026quot;\u0026gt; ` ``else` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number268 index267 alt1\u0026quot;\u0026gt; ` ``setBehindOffset(````);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number269 index268 alt2\u0026quot;\u0026gt; ` ``float` `scrollOffsetBehind = ta.getFloat(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number270 index269 alt1\u0026quot;\u0026gt; ` ``R.styleable.SlidingMenu_behindScrollScale, ````.33f);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number271 index270 alt2\u0026quot;\u0026gt; ` ``setBehindScrollScale(scrollOffsetBehind);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number272 index271 alt1\u0026quot;\u0026gt; ` ``int` `shadowRes = ta.getResourceId(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number273 index272 alt2\u0026quot;\u0026gt; ` ``R.styleable.SlidingMenu_shadowDrawable, -``1``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number274 index273 alt1\u0026quot;\u0026gt; ` ``if` `(shadowRes != -``1``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number275 index274 alt2\u0026quot;\u0026gt; ` ``setShadowDrawable(shadowRes);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number276 index275 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number277 index276 alt2\u0026quot;\u0026gt; ` ``int` `shadowWidth = (``int``) ta.getDimension(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number278 index277 alt1\u0026quot;\u0026gt; ` ``R.styleable.SlidingMenu_shadowWidth, ````);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number279 index278 alt2\u0026quot;\u0026gt; ` ``setShadowWidth(shadowWidth);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number280 index279 alt1\u0026quot;\u0026gt; ` ``boolean` `fadeEnabled = ta.getBoolean(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number281 index280 alt2\u0026quot;\u0026gt; ` ``R.styleable.SlidingMenu_fadeEnabled, ``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number282 index281 alt1\u0026quot;\u0026gt; ` ``setFadeEnabled(fadeEnabled);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number283 index282 alt2\u0026quot;\u0026gt; ` ``float` `fadeDeg = ta.getFloat(R.styleable.SlidingMenu_fadeDegree, ````.33f);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number284 index283 alt1\u0026quot;\u0026gt; ` ``setFadeDegree(fadeDeg);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number285 index284 alt2\u0026quot;\u0026gt; ` ``boolean` `selectorEnabled = ta.getBoolean(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number286 index285 alt1\u0026quot;\u0026gt; ` ``R.styleable.SlidingMenu_selectorEnabled, ``false``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number287 index286 alt2\u0026quot;\u0026gt; ` ``setSelectorEnabled(selectorEnabled);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number288 index287 alt1\u0026quot;\u0026gt; ` ``int` `selectorRes = ta.getResourceId(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number289 index288 alt2\u0026quot;\u0026gt; ` ``R.styleable.SlidingMenu_selectorDrawable, -``1``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number290 index289 alt1\u0026quot;\u0026gt; ` ``if` `(selectorRes != -``1``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number291 index290 alt2\u0026quot;\u0026gt; ` ``setSelectorDrawable(selectorRes);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number292 index291 alt1\u0026quot;\u0026gt; ` ``ta.recycle();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number293 index292 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number294 index293 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number295 index294 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number296 index295 alt1\u0026quot;\u0026gt; ` ``* Attaches the SlidingMenu to an entire Activity` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number297 index296 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number298 index297 alt1\u0026quot;\u0026gt; ` ``* @param activity` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number299 index298 alt2\u0026quot;\u0026gt; ` ``* the Activity` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number300 index299 alt1\u0026quot;\u0026gt; ` ``* @param slideStyle` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number301 index300 alt2\u0026quot;\u0026gt; ` ``* either SLIDING_CONTENT or SLIDING_WINDOW` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number302 index301 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number303 index302 alt2\u0026quot;\u0026gt; ` ``public` `void` `attachToActivity(Activity activity, ``int` `slideStyle) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number304 index303 alt1\u0026quot;\u0026gt; ` ``attachToActivity(activity, slideStyle, ``false``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number305 index304 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number306 index305 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number307 index306 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number308 index307 alt1\u0026quot;\u0026gt; ` ``* Attaches the SlidingMenu to an entire Activity` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number309 index308 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number310 index309 alt1\u0026quot;\u0026gt; ` ``* @param activity` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number311 index310 alt2\u0026quot;\u0026gt; ` ``* the Activity` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number312 index311 alt1\u0026quot;\u0026gt; ` ``* @param slideStyle` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number313 index312 alt2\u0026quot;\u0026gt; ` ``* either SLIDING_CONTENT or SLIDING_WINDOW` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number314 index313 alt1\u0026quot;\u0026gt; ` ``* @param actionbarOverlay` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number315 index314 alt2\u0026quot;\u0026gt; ` ``* whether or not the ActionBar is overlaid` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number316 index315 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number317 index316 alt2\u0026quot;\u0026gt; ` ``public` `void` `attachToActivity(Activity activity, ``int` `slideStyle,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number318 index317 alt1\u0026quot;\u0026gt; ` ``boolean` `actionbarOverlay) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number319 index318 alt2\u0026quot;\u0026gt; ` ``if` `(slideStyle != SLIDING_WINDOW \u0026amp;\u0026amp; slideStyle != SLIDING_CONTENT)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number320 index319 alt1\u0026quot;\u0026gt; ` ``throw` `new` `IllegalArgumentException(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number321 index320 alt2\u0026quot;\u0026gt; ` ``\u0026quot;slideStyle must be either SLIDING_WINDOW or SLIDING_CONTENT\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number322 index321 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number323 index322 alt2\u0026quot;\u0026gt; ` ``if` `(getParent() != ``null``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number324 index323 alt1\u0026quot;\u0026gt; ` ``throw` `new` `IllegalStateException(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number325 index324 alt2\u0026quot;\u0026gt; ` ``\u0026quot;This SlidingMenu appears to already be attached\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number326 index325 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number327 index326 alt2\u0026quot;\u0026gt; ` ``// get the window background` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number328 index327 alt1\u0026quot;\u0026gt; ` ``TypedArray a = activity.getTheme().obtainStyledAttributes(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number329 index328 alt2\u0026quot;\u0026gt; ` ``new` `int``[] { android.R.attr.windowBackground });` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number330 index329 alt1\u0026quot;\u0026gt; ` ``int` `background = a.getResourceId(````, ````);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number331 index330 alt2\u0026quot;\u0026gt; ` ``a.recycle();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number332 index331 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number333 index332 alt2\u0026quot;\u0026gt; ` ``switch` `(slideStyle) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number334 index333 alt1\u0026quot;\u0026gt; ` ``case` `SLIDING_WINDOW:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number335 index334 alt2\u0026quot;\u0026gt; ` ``mActionbarOverlay = ``false``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number336 index335 alt1\u0026quot;\u0026gt; ` ``ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number337 index336 alt2\u0026quot;\u0026gt; ` ``ViewGroup decorChild = (ViewGroup) decor.getChildAt(````);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number338 index337 alt1\u0026quot;\u0026gt; ` ``// save ActionBar themes that have transparent assets` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number339 index338 alt2\u0026quot;\u0026gt; ` ``decorChild.setBackgroundResource(background);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number340 index339 alt1\u0026quot;\u0026gt; ` ``decor.removeView(decorChild);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number341 index340 alt2\u0026quot;\u0026gt; ` ``decor.addView(``this``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number342 index341 alt1\u0026quot;\u0026gt; ` ``setContent(decorChild);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number343 index342 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number344 index343 alt1\u0026quot;\u0026gt; ` ``case` `SLIDING_CONTENT:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number345 index344 alt2\u0026quot;\u0026gt; ` ``mActionbarOverlay = actionbarOverlay;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number346 index345 alt1\u0026quot;\u0026gt; ` ``// take the above view out of` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number347 index346 alt2\u0026quot;\u0026gt; ` ``ViewGroup contentParent = (ViewGroup) activity` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number348 index347 alt1\u0026quot;\u0026gt; ` ``.findViewById(android.R.id.content);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number349 index348 alt2\u0026quot;\u0026gt; ` ``View content = contentParent.getChildAt(````);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number350 index349 alt1\u0026quot;\u0026gt; ` ``contentParent.removeView(content);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number351 index350 alt2\u0026quot;\u0026gt; ` ``contentParent.addView(``this``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number352 index351 alt1\u0026quot;\u0026gt; ` ``setContent(content);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number353 index352 alt2\u0026quot;\u0026gt; ` ``// save people from having transparent backgrounds` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number354 index353 alt1\u0026quot;\u0026gt; ` ``if` `(content.getBackground() == ``null``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number355 index354 alt2\u0026quot;\u0026gt; ` ``content.setBackgroundResource(background);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number356 index355 alt1\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number357 index356 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number358 index357 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number359 index358 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number360 index359 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number361 index360 alt2\u0026quot;\u0026gt; ` ``* Set the above view content from a layout resource. The resource will be` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number362 index361 alt1\u0026quot;\u0026gt; ` ``* inflated, adding all top-level views to the above view.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number363 index362 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number364 index363 alt1\u0026quot;\u0026gt; ` ``* @param res` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number365 index364 alt2\u0026quot;\u0026gt; ` ``* the new content` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number366 index365 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number367 index366 alt2\u0026quot;\u0026gt; ` ``public` `void` `setContent(``int` `res) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number368 index367 alt1\u0026quot;\u0026gt; ` ``setContent(LayoutInflater.from(getContext()).inflate(res, ``null``));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number369 index368 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number370 index369 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number371 index370 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number372 index371 alt1\u0026quot;\u0026gt; ` ``* Set the above view content to the given View.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number373 index372 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number374 index373 alt1\u0026quot;\u0026gt; ` ``* @param view` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number375 index374 alt2\u0026quot;\u0026gt; ` ``* The desired content to display.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number376 index375 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number377 index376 alt2\u0026quot;\u0026gt; ` ``public` `void` `setContent(View view) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number378 index377 alt1\u0026quot;\u0026gt; ` ``mViewAbove.setContent(view);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number379 index378 alt2\u0026quot;\u0026gt; ` ``showContent();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number380 index379 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number381 index380 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number382 index381 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number383 index382 alt2\u0026quot;\u0026gt; ` ``* 设置背景图片` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number384 index383 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number385 index384 alt2\u0026quot;\u0026gt; ` ``* @param resid` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number386 index385 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number387 index386 alt2\u0026quot;\u0026gt; ` ``public` `void` `setBackgroundImage(``int` `resid) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number388 index387 alt1\u0026quot;\u0026gt; ` ``mViewBackground.setBackgroundResource(resid);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number389 index388 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number390 index389 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number391 index390 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number392 index391 alt1\u0026quot;\u0026gt; ` ``* Retrieves the current content.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number393 index392 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number394 index393 alt1\u0026quot;\u0026gt; ` ``* @return the current content` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number395 index394 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number396 index395 alt1\u0026quot;\u0026gt; ` ``public` `View getContent() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number397 index396 alt2\u0026quot;\u0026gt; ` ``return` `mViewAbove.getContent();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number398 index397 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number399 index398 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number400 index399 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number401 index400 alt2\u0026quot;\u0026gt; ` ``* Set the behind view (menu) content from a layout resource. The resource` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number402 index401 alt1\u0026quot;\u0026gt; ` ``* will be inflated, adding all top-level views to the behind view.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number403 index402 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number404 index403 alt1\u0026quot;\u0026gt; ` ``* @param res` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number405 index404 alt2\u0026quot;\u0026gt; ` ``* the new content` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number406 index405 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number407 index406 alt2\u0026quot;\u0026gt; ` ``public` `void` `setMenu(``int` `res) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number408 index407 alt1\u0026quot;\u0026gt; ` ``setMenu(LayoutInflater.from(getContext()).inflate(res, ``null``));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number409 index408 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number410 index409 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number411 index410 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number412 index411 alt1\u0026quot;\u0026gt; ` ``* Set the behind view (menu) content to the given View.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number413 index412 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number414 index413 alt1\u0026quot;\u0026gt; ` ``* @param view` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number415 index414 alt2\u0026quot;\u0026gt; ` ``* The desired content to display.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number416 index415 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number417 index416 alt2\u0026quot;\u0026gt; ` ``public` `void` `setMenu(View v) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number418 index417 alt1\u0026quot;\u0026gt; ` ``mViewBehind.setContent(v);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number419 index418 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number420 index419 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number421 index420 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number422 index421 alt1\u0026quot;\u0026gt; ` ``* Retrieves the main menu.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number423 index422 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number424 index423 alt1\u0026quot;\u0026gt; ` ``* @return the main menu` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number425 index424 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number426 index425 alt1\u0026quot;\u0026gt; ` ``public` `View getMenu() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number427 index426 alt2\u0026quot;\u0026gt; ` ``return` `mViewBehind.getContent();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number428 index427 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number429 index428 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number430 index429 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number431 index430 alt2\u0026quot;\u0026gt; ` ``* Set the secondary behind view (right menu) content from a layout` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number432 index431 alt1\u0026quot;\u0026gt; ` ``* resource. The resource will be inflated, adding all top-level views to` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number433 index432 alt2\u0026quot;\u0026gt; ` ``* the behind view.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number434 index433 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number435 index434 alt2\u0026quot;\u0026gt; ` ``* @param res` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number436 index435 alt1\u0026quot;\u0026gt; ` ``* the new content` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number437 index436 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number438 index437 alt1\u0026quot;\u0026gt; ` ``public` `void` `setSecondaryMenu(``int` `res) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number439 index438 alt2\u0026quot;\u0026gt; ` ``setSecondaryMenu(LayoutInflater.from(getContext()).inflate(res, ``null``));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number440 index439 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number441 index440 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number442 index441 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number443 index442 alt2\u0026quot;\u0026gt; ` ``* Set the secondary behind view (right menu) content to the given View.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number444 index443 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number445 index444 alt2\u0026quot;\u0026gt; ` ``* @param view` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number446 index445 alt1\u0026quot;\u0026gt; ` ``* The desired content to display.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number447 index446 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number448 index447 alt1\u0026quot;\u0026gt; ` ``public` `void` `setSecondaryMenu(View v) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number449 index448 alt2\u0026quot;\u0026gt; ` ``mViewBehind.setSecondaryContent(v);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number450 index449 alt1\u0026quot;\u0026gt; ` ``// mViewBehind.invalidate();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number451 index450 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number452 index451 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number453 index452 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number454 index453 alt1\u0026quot;\u0026gt; ` ``* Retrieves the current secondary menu (right).` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number455 index454 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number456 index455 alt1\u0026quot;\u0026gt; ` ``* @return the current menu` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number457 index456 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number458 index457 alt1\u0026quot;\u0026gt; ` ``public` `View getSecondaryMenu() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number459 index458 alt2\u0026quot;\u0026gt; ` ``return` `mViewBehind.getSecondaryContent();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number460 index459 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number461 index460 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number462 index461 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number463 index462 alt2\u0026quot;\u0026gt; ` ``* Sets the sliding enabled.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number464 index463 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number465 index464 alt2\u0026quot;\u0026gt; ` ``* @param b` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number466 index465 alt1\u0026quot;\u0026gt; ` ``* true to enable sliding, false to disable it.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number467 index466 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number468 index467 alt1\u0026quot;\u0026gt; ` ``public` `void` `setSlidingEnabled(``boolean` `b) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number469 index468 alt2\u0026quot;\u0026gt; ` ``mViewAbove.setSlidingEnabled(b);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number470 index469 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number471 index470 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number472 index471 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number473 index472 alt2\u0026quot;\u0026gt; ` ``* Checks if is sliding enabled.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number474 index473 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number475 index474 alt2\u0026quot;\u0026gt; ` ``* @return true, if is sliding enabled` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number476 index475 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number477 index476 alt2\u0026quot;\u0026gt; ` ``public` `boolean` `isSlidingEnabled() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number478 index477 alt1\u0026quot;\u0026gt; ` ``return` `mViewAbove.isSlidingEnabled();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number479 index478 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number480 index479 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number481 index480 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number482 index481 alt1\u0026quot;\u0026gt; ` ``* Sets which side the SlidingMenu should appear on.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number483 index482 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number484 index483 alt1\u0026quot;\u0026gt; ` ``* @param mode` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number485 index484 alt2\u0026quot;\u0026gt; ` ``* must be either SlidingMenu.LEFT or SlidingMenu.RIGHT` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number486 index485 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number487 index486 alt2\u0026quot;\u0026gt; ` ``public` `void` `setMode(``int` `mode) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number488 index487 alt1\u0026quot;\u0026gt; ` ``if` `(mode != LEFT \u0026amp;\u0026amp; mode != RIGHT \u0026amp;\u0026amp; mode != LEFT_RIGHT) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number489 index488 alt2\u0026quot;\u0026gt; ` ``throw` `new` `IllegalStateException(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number490 index489 alt1\u0026quot;\u0026gt; ` ``\u0026quot;SlidingMenu mode must be LEFT, RIGHT, or LEFT_RIGHT\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number491 index490 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number492 index491 alt1\u0026quot;\u0026gt; ` ``mViewBehind.setMode(mode);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number493 index492 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number494 index493 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number495 index494 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number496 index495 alt1\u0026quot;\u0026gt; ` ``* Returns the current side that the SlidingMenu is on.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number497 index496 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number498 index497 alt1\u0026quot;\u0026gt; ` ``* @return the current mode, either SlidingMenu.LEFT or SlidingMenu.RIGHT` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number499 index498 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number500 index499 alt1\u0026quot;\u0026gt; ` ``public` `int` `getMode() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number501 index500 alt2\u0026quot;\u0026gt; ` ``return` `mViewBehind.getMode();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number502 index501 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number503 index502 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number504 index503 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number505 index504 alt2\u0026quot;\u0026gt; ` ``* Sets whether or not the SlidingMenu is in static mode (i.e. nothing is` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number506 index505 alt1\u0026quot;\u0026gt; ` ``* moving and everything is showing)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number507 index506 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number508 index507 alt1\u0026quot;\u0026gt; ` ``* @param b` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number509 index508 alt2\u0026quot;\u0026gt; ` ``* true to set static mode, false to disable static mode.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number510 index509 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number511 index510 alt2\u0026quot;\u0026gt; ` ``public` `void` `setStatic(``boolean` `b) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number512 index511 alt1\u0026quot;\u0026gt; ` ``if` `(b) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number513 index512 alt2\u0026quot;\u0026gt; ` ``setSlidingEnabled(``false``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number514 index513 alt1\u0026quot;\u0026gt; ` ``mViewAbove.setCustomViewBehind(``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number515 index514 alt2\u0026quot;\u0026gt; ` ``mViewAbove.setCurrentItem(``1``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number516 index515 alt1\u0026quot;\u0026gt; ` ``// mViewBehind.setCurrentItem(0);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number517 index516 alt2\u0026quot;\u0026gt; ` ``} ``else` `{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number518 index517 alt1\u0026quot;\u0026gt; ` ``mViewAbove.setCurrentItem(``1``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number519 index518 alt2\u0026quot;\u0026gt; ` ``// mViewBehind.setCurrentItem(1);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number520 index519 alt1\u0026quot;\u0026gt; ` ``mViewAbove.setCustomViewBehind(mViewBehind);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number521 index520 alt2\u0026quot;\u0026gt; ` ``setSlidingEnabled(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number522 index521 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number523 index522 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number524 index523 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number525 index524 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number526 index525 alt1\u0026quot;\u0026gt; ` ``* Opens the menu and shows the menu view.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number527 index526 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number528 index527 alt1\u0026quot;\u0026gt; ` ``public` `void` `showMenu() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number529 index528 alt2\u0026quot;\u0026gt; ` ``showMenu(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number530 index529 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number531 index530 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number532 index531 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number533 index532 alt2\u0026quot;\u0026gt; ` ``* Opens the menu and shows the menu view.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number534 index533 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number535 index534 alt2\u0026quot;\u0026gt; ` ``* @param animate` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number536 index535 alt1\u0026quot;\u0026gt; ` ``* true to animate the transition, false to ignore animation` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number537 index536 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number538 index537 alt1\u0026quot;\u0026gt; ` ``public` `void` `showMenu(``boolean` `animate) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number539 index538 alt2\u0026quot;\u0026gt; ` ``mViewAbove.setCurrentItem(````, animate);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number540 index539 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number541 index540 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number542 index541 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number543 index542 alt2\u0026quot;\u0026gt; ` ``* Opens the menu and shows the secondary menu view. Will default to the` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number544 index543 alt1\u0026quot;\u0026gt; ` ``* regular menu if there is only one.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number545 index544 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number546 index545 alt1\u0026quot;\u0026gt; ` ``public` `void` `showSecondaryMenu() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number547 index546 alt2\u0026quot;\u0026gt; ` ``showSecondaryMenu(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number548 index547 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number549 index548 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number550 index549 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number551 index550 alt2\u0026quot;\u0026gt; ` ``* Opens the menu and shows the secondary (right) menu view. Will default to` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number552 index551 alt1\u0026quot;\u0026gt; ` ``* the regular menu if there is only one.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number553 index552 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number554 index553 alt1\u0026quot;\u0026gt; ` ``* @param animate` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number555 index554 alt2\u0026quot;\u0026gt; ` ``* true to animate the transition, false to ignore animation` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number556 index555 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number557 index556 alt2\u0026quot;\u0026gt; ` ``public` `void` `showSecondaryMenu(``boolean` `animate) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number558 index557 alt1\u0026quot;\u0026gt; ` ``mViewAbove.setCurrentItem(``2``, animate);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number559 index558 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number560 index559 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number561 index560 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number562 index561 alt1\u0026quot;\u0026gt; ` ``* Closes the menu and shows the above view.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number563 index562 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number564 index563 alt1\u0026quot;\u0026gt; ` ``public` `void` `showContent() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number565 index564 alt2\u0026quot;\u0026gt; ` ``showContent(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number566 index565 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number567 index566 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number568 index567 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number569 index568 alt2\u0026quot;\u0026gt; ` ``* Closes the menu and shows the above view.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number570 index569 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number571 index570 alt2\u0026quot;\u0026gt; ` ``* @param animate` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number572 index571 alt1\u0026quot;\u0026gt; ` ``* true to animate the transition, false to ignore animation` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number573 index572 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number574 index573 alt1\u0026quot;\u0026gt; ` ``public` `void` `showContent(``boolean` `animate) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number575 index574 alt2\u0026quot;\u0026gt; ` ``mViewAbove.setCurrentItem(``1``, animate);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number576 index575 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number577 index576 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number578 index577 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number579 index578 alt2\u0026quot;\u0026gt; ` ``* Toggle the SlidingMenu. If it is open, it will be closed, and vice versa.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number580 index579 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number581 index580 alt2\u0026quot;\u0026gt; ` ``public` `void` `toggle() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number582 index581 alt1\u0026quot;\u0026gt; ` ``toggle(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number583 index582 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number584 index583 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number585 index584 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number586 index585 alt1\u0026quot;\u0026gt; ` ``* Toggle the SlidingMenu. If it is open, it will be closed, and vice versa.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number587 index586 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number588 index587 alt1\u0026quot;\u0026gt; ` ``* @param animate` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number589 index588 alt2\u0026quot;\u0026gt; ` ``* true to animate the transition, false to ignore animation` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number590 index589 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number591 index590 alt2\u0026quot;\u0026gt; ` ``public` `void` `toggle(``boolean` `animate) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number592 index591 alt1\u0026quot;\u0026gt; ` ``if` `(isMenuShowing()) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number593 index592 alt2\u0026quot;\u0026gt; ` ``showContent(animate);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number594 index593 alt1\u0026quot;\u0026gt; ` ``} ``else` `{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number595 index594 alt2\u0026quot;\u0026gt; ` ``showMenu(animate);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number596 index595 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number597 index596 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number598 index597 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number599 index598 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number600 index599 alt1\u0026quot;\u0026gt; ` ``* Checks if is the behind view showing.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number601 index600 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number602 index601 alt1\u0026quot;\u0026gt; ` ``* @return Whether or not the behind view is showing` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number603 index602 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number604 index603 alt1\u0026quot;\u0026gt; ` ``public` `boolean` `isMenuShowing() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number605 index604 alt2\u0026quot;\u0026gt; ` ``return` `mViewAbove.getCurrentItem() == ``` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number606 index605 alt1\u0026quot;\u0026gt; ` ``|| mViewAbove.getCurrentItem() == ``2``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number607 index606 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number608 index607 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number609 index608 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number610 index609 alt1\u0026quot;\u0026gt; ` ``* Checks if is the behind view showing.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number611 index610 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number612 index611 alt1\u0026quot;\u0026gt; ` ``* @return Whether or not the behind view is showing` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number613 index612 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number614 index613 alt1\u0026quot;\u0026gt; ` ``public` `boolean` `isSecondaryMenuShowing() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number615 index614 alt2\u0026quot;\u0026gt; ` ``return` `mViewAbove.getCurrentItem() == ``2``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number616 index615 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number617 index616 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number618 index617 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number619 index618 alt2\u0026quot;\u0026gt; ` ``* Gets the behind offset.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number620 index619 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number621 index620 alt2\u0026quot;\u0026gt; ` ``* @return The margin on the right of the screen that the behind view` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number622 index621 alt1\u0026quot;\u0026gt; ` ``* scrolls to` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number623 index622 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number624 index623 alt1\u0026quot;\u0026gt; ` ``public` `int` `getBehindOffset() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number625 index624 alt2\u0026quot;\u0026gt; ` ``return` `((RelativeLayout.LayoutParams) mViewBehind.getLayoutParams()).rightMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number626 index625 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number627 index626 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number628 index627 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number629 index628 alt2\u0026quot;\u0026gt; ` ``* Sets the behind offset.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number630 index629 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number631 index630 alt2\u0026quot;\u0026gt; ` ``* @param i` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number632 index631 alt1\u0026quot;\u0026gt; ` ``* The margin, in pixels, on the right of the screen that the` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number633 index632 alt2\u0026quot;\u0026gt; ` ``* behind view scrolls to.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number634 index633 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number635 index634 alt2\u0026quot;\u0026gt; ` ``public` `void` `setBehindOffset(``int` `i) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number636 index635 alt1\u0026quot;\u0026gt; ` ``// RelativeLayout.LayoutParams params =` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number637 index636 alt2\u0026quot;\u0026gt; ` ``// ((RelativeLayout.LayoutParams)mViewBehind.getLayoutParams());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number638 index637 alt1\u0026quot;\u0026gt; ` ``// int bottom = params.bottomMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number639 index638 alt2\u0026quot;\u0026gt; ` ``// int top = params.topMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number640 index639 alt1\u0026quot;\u0026gt; ` ``// int left = params.leftMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number641 index640 alt2\u0026quot;\u0026gt; ` ``// params.setMargins(left, top, i, bottom);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number642 index641 alt1\u0026quot;\u0026gt; ` ``mViewBehind.setWidthOffset(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number643 index642 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number644 index643 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number645 index644 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number646 index645 alt1\u0026quot;\u0026gt; ` ``* Sets the behind offset.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number647 index646 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number648 index647 alt1\u0026quot;\u0026gt; ` ``* @param resID` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number649 index648 alt2\u0026quot;\u0026gt; ` ``* The dimension resource id to be set as the behind offset. The` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number650 index649 alt1\u0026quot;\u0026gt; ` ``* menu, when open, will leave this width margin on the right of` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number651 index650 alt2\u0026quot;\u0026gt; ` ``* the screen.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number652 index651 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number653 index652 alt2\u0026quot;\u0026gt; ` ``public` `void` `setBehindOffsetRes(``int` `resID) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number654 index653 alt1\u0026quot;\u0026gt; ` ``int` `i = (``int``) getContext().getResources().getDimension(resID);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number655 index654 alt2\u0026quot;\u0026gt; ` ``setBehindOffset(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number656 index655 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number657 index656 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number658 index657 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number659 index658 alt2\u0026quot;\u0026gt; ` ``* Sets the above offset.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number660 index659 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number661 index660 alt2\u0026quot;\u0026gt; ` ``* @param i` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number662 index661 alt1\u0026quot;\u0026gt; ` ``* the new above offset, in pixels` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number663 index662 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number664 index663 alt1\u0026quot;\u0026gt; ` ``public` `void` `setAboveOffset(``int` `i) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number665 index664 alt2\u0026quot;\u0026gt; ` ``mViewAbove.setAboveOffset(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number666 index665 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number667 index666 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number668 index667 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number669 index668 alt2\u0026quot;\u0026gt; ` ``* Sets the above offset.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number670 index669 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number671 index670 alt2\u0026quot;\u0026gt; ` ``* @param resID` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number672 index671 alt1\u0026quot;\u0026gt; ` ``* The dimension resource id to be set as the above offset.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number673 index672 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number674 index673 alt1\u0026quot;\u0026gt; ` ``public` `void` `setAboveOffsetRes(``int` `resID) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number675 index674 alt2\u0026quot;\u0026gt; ` ``int` `i = (``int``) getContext().getResources().getDimension(resID);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number676 index675 alt1\u0026quot;\u0026gt; ` ``setAboveOffset(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number677 index676 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number678 index677 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number679 index678 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number680 index679 alt1\u0026quot;\u0026gt; ` ``* Sets the behind width.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number681 index680 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number682 index681 alt1\u0026quot;\u0026gt; ` ``* @param i` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number683 index682 alt2\u0026quot;\u0026gt; ` ``* The width the Sliding Menu will open to, in pixels` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number684 index683 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number685 index684 alt2\u0026quot;\u0026gt; ` ``@SuppressWarnings``(``\u0026quot;deprecation\u0026quot;``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number686 index685 alt1\u0026quot;\u0026gt; ` ``public` `void` `setBehindWidth(``int` `i) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number687 index686 alt2\u0026quot;\u0026gt; ` ``int` `width;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number688 index687 alt1\u0026quot;\u0026gt; ` ``Display display = ((WindowManager) getContext().getSystemService(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number689 index688 alt2\u0026quot;\u0026gt; ` ``Context.WINDOW_SERVICE)).getDefaultDisplay();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number690 index689 alt1\u0026quot;\u0026gt; ` ``try` `{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number691 index690 alt2\u0026quot;\u0026gt; ` ``Class\u0026amp;lt;?\u0026amp;gt; cls = Display.``class``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number692 index691 alt1\u0026quot;\u0026gt; ` ``Class\u0026amp;lt;?\u0026amp;gt;[] parameterTypes = { Point.``class` `};` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number693 index692 alt2\u0026quot;\u0026gt; ` ``Point parameter = ``new` `Point();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number694 index693 alt1\u0026quot;\u0026gt; ` ``Method method = cls.getMethod(``\u0026quot;getSize\u0026quot;``, parameterTypes);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number695 index694 alt2\u0026quot;\u0026gt; ` ``method.invoke(display, parameter);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number696 index695 alt1\u0026quot;\u0026gt; ` ``width = parameter.x;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number697 index696 alt2\u0026quot;\u0026gt; ` ``} ``catch` `(Exception e) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number698 index697 alt1\u0026quot;\u0026gt; ` ``width = display.getWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number699 index698 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number700 index699 alt1\u0026quot;\u0026gt; ` ``setBehindOffset(width - i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number701 index700 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number702 index701 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number703 index702 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number704 index703 alt1\u0026quot;\u0026gt; ` ``* Sets the behind width.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number705 index704 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number706 index705 alt1\u0026quot;\u0026gt; ` ``* @param res` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number707 index706 alt2\u0026quot;\u0026gt; ` ``* The dimension resource id to be set as the behind width` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number708 index707 alt1\u0026quot;\u0026gt; ` ``* offset. The menu, when open, will open this wide.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number709 index708 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number710 index709 alt1\u0026quot;\u0026gt; ` ``public` `void` `setBehindWidthRes(``int` `res) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number711 index710 alt2\u0026quot;\u0026gt; ` ``int` `i = (``int``) getContext().getResources().getDimension(res);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number712 index711 alt1\u0026quot;\u0026gt; ` ``setBehindWidth(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number713 index712 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number714 index713 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number715 index714 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number716 index715 alt1\u0026quot;\u0026gt; ` ``* Gets the behind scroll scale.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number717 index716 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number718 index717 alt1\u0026quot;\u0026gt; ` ``* @return The scale of the parallax scroll` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number719 index718 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number720 index719 alt1\u0026quot;\u0026gt; ` ``public` `float` `getBehindScrollScale() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number721 index720 alt2\u0026quot;\u0026gt; ` ``return` `mViewBehind.getScrollScale();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number722 index721 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number723 index722 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number724 index723 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number725 index724 alt2\u0026quot;\u0026gt; ` ``* Gets the touch mode margin threshold` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number726 index725 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number727 index726 alt2\u0026quot;\u0026gt; ` ``* @return the touch mode margin threshold` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number728 index727 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number729 index728 alt2\u0026quot;\u0026gt; ` ``public` `int` `getTouchmodeMarginThreshold() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number730 index729 alt1\u0026quot;\u0026gt; ` ``return` `mViewBehind.getMarginThreshold();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number731 index730 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number732 index731 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number733 index732 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number734 index733 alt1\u0026quot;\u0026gt; ` ``* Set the touch mode margin threshold` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number735 index734 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number736 index735 alt1\u0026quot;\u0026gt; ` ``* @param touchmodeMarginThreshold` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number737 index736 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number738 index737 alt1\u0026quot;\u0026gt; ` ``public` `void` `setTouchmodeMarginThreshold(``int` `touchmodeMarginThreshold) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number739 index738 alt2\u0026quot;\u0026gt; ` ``mViewBehind.setMarginThreshold(touchmodeMarginThreshold);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number740 index739 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number741 index740 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number742 index741 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number743 index742 alt2\u0026quot;\u0026gt; ` ``* Sets the behind scroll scale.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number744 index743 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number745 index744 alt2\u0026quot;\u0026gt; ` ``* @param f` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number746 index745 alt1\u0026quot;\u0026gt; ` ``* The scale of the parallax scroll (i.e. 1.0f scrolls 1 pixel` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number747 index746 alt2\u0026quot;\u0026gt; ` ``* for every 1 pixel that the above view scrolls and 0.0f scrolls` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number748 index747 alt1\u0026quot;\u0026gt; ` ``* 0 pixels)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number749 index748 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number750 index749 alt1\u0026quot;\u0026gt; ` ``public` `void` `setBehindScrollScale(``float` `f) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number751 index750 alt2\u0026quot;\u0026gt; ` ``if` `(f \u0026amp;lt; ``` `\u0026amp;\u0026amp; f \u0026amp;gt; ``1``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number752 index751 alt1\u0026quot;\u0026gt; ` ``throw` `new` `IllegalStateException(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number753 index752 alt2\u0026quot;\u0026gt; ` ``\u0026quot;ScrollScale must be between 0 and 1\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number754 index753 alt1\u0026quot;\u0026gt; ` ``mViewBehind.setScrollScale(f);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number755 index754 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number756 index755 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number757 index756 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number758 index757 alt1\u0026quot;\u0026gt; ` ``* Sets the behind canvas transformer.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number759 index758 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number760 index759 alt1\u0026quot;\u0026gt; ` ``* @param t` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number761 index760 alt2\u0026quot;\u0026gt; ` ``* the new behind canvas transformer` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number762 index761 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number763 index762 alt2\u0026quot;\u0026gt; ` ``public` `void` `setBehindCanvasTransformer(CanvasTransformer t) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number764 index763 alt1\u0026quot;\u0026gt; ` ``mViewBehind.setCanvasTransformer(t);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number765 index764 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number766 index765 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number767 index766 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number768 index767 alt1\u0026quot;\u0026gt; ` ``* 设置右侧视图的转场动画` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number769 index768 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number770 index769 alt1\u0026quot;\u0026gt; ` ``* @param t` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number771 index770 alt2\u0026quot;\u0026gt; ` ``* the new above canvas transformer` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number772 index771 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number773 index772 alt2\u0026quot;\u0026gt; ` ``public` `void` `setAboveCanvasTransformer(CanvasTransformer t) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number774 index773 alt1\u0026quot;\u0026gt; ` ``mViewAbove.setCanvasTransformer(t);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number775 index774 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number776 index775 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number777 index776 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number778 index777 alt1\u0026quot;\u0026gt; ` ``* Gets the touch mode above.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number779 index778 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number780 index779 alt1\u0026quot;\u0026gt; ` ``* @return the touch mode above` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number781 index780 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number782 index781 alt1\u0026quot;\u0026gt; ` ``public` `int` `getTouchModeAbove() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number783 index782 alt2\u0026quot;\u0026gt; ` ``return` `mViewAbove.getTouchMode();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number784 index783 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number785 index784 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number786 index785 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number787 index786 alt2\u0026quot;\u0026gt; ` ``* Controls whether the SlidingMenu can be opened with a swipe gesture.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number788 index787 alt1\u0026quot;\u0026gt; ` ``* Options are {@link #TOUCHMODE_MARGIN TOUCHMODE_MARGIN},` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number789 index788 alt2\u0026quot;\u0026gt; ` ``* {@link #TOUCHMODE_FULLSCREEN TOUCHMODE_FULLSCREEN}, or` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number790 index789 alt1\u0026quot;\u0026gt; ` ``* {@link #TOUCHMODE_NONE TOUCHMODE_NONE}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number791 index790 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number792 index791 alt1\u0026quot;\u0026gt; ` ``* @param i` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number793 index792 alt2\u0026quot;\u0026gt; ` ``* the new touch mode` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number794 index793 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number795 index794 alt2\u0026quot;\u0026gt; ` ``public` `void` `setTouchModeAbove(``int` `i) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number796 index795 alt1\u0026quot;\u0026gt; ` ``if` `(i != TOUCHMODE_FULLSCREEN \u0026amp;\u0026amp; i != TOUCHMODE_MARGIN` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number797 index796 alt2\u0026quot;\u0026gt; ` ``\u0026amp;\u0026amp; i != TOUCHMODE_NONE) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number798 index797 alt1\u0026quot;\u0026gt; ` ``throw` `new` `IllegalStateException(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number799 index798 alt2\u0026quot;\u0026gt; ` ``\u0026quot;TouchMode must be set to either\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number800 index799 alt1\u0026quot;\u0026gt; ` ``+ ``\u0026quot;TOUCHMODE_FULLSCREEN or TOUCHMODE_MARGIN or TOUCHMODE_NONE.\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number801 index800 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number802 index801 alt1\u0026quot;\u0026gt; ` ``mViewAbove.setTouchMode(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number803 index802 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number804 index803 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number805 index804 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number806 index805 alt1\u0026quot;\u0026gt; ` ``* Controls whether the SlidingMenu can be opened with a swipe gesture.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number807 index806 alt2\u0026quot;\u0026gt; ` ``* Options are {@link #TOUCHMODE_MARGIN TOUCHMODE_MARGIN},` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number808 index807 alt1\u0026quot;\u0026gt; ` ``* {@link #TOUCHMODE_FULLSCREEN TOUCHMODE_FULLSCREEN}, or` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number809 index808 alt2\u0026quot;\u0026gt; ` ``* {@link #TOUCHMODE_NONE TOUCHMODE_NONE}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number810 index809 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number811 index810 alt2\u0026quot;\u0026gt; ` ``* @param i` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number812 index811 alt1\u0026quot;\u0026gt; ` ``* the new touch mode` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number813 index812 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number814 index813 alt1\u0026quot;\u0026gt; ` ``public` `void` `setTouchModeBehind(``int` `i) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number815 index814 alt2\u0026quot;\u0026gt; ` ``if` `(i != TOUCHMODE_FULLSCREEN \u0026amp;\u0026amp; i != TOUCHMODE_MARGIN` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number816 index815 alt1\u0026quot;\u0026gt; ` ``\u0026amp;\u0026amp; i != TOUCHMODE_NONE) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number817 index816 alt2\u0026quot;\u0026gt; ` ``throw` `new` `IllegalStateException(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number818 index817 alt1\u0026quot;\u0026gt; ` ``\u0026quot;TouchMode must be set to either\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number819 index818 alt2\u0026quot;\u0026gt; ` ``+ ``\u0026quot;TOUCHMODE_FULLSCREEN or TOUCHMODE_MARGIN or TOUCHMODE_NONE.\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number820 index819 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number821 index820 alt2\u0026quot;\u0026gt; ` ``mViewBehind.setTouchMode(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number822 index821 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number823 index822 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number824 index823 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number825 index824 alt2\u0026quot;\u0026gt; ` ``* Sets the shadow drawable.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number826 index825 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number827 index826 alt2\u0026quot;\u0026gt; ` ``* @param resId` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number828 index827 alt1\u0026quot;\u0026gt; ` ``* the resource ID of the new shadow drawable` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number829 index828 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number830 index829 alt1\u0026quot;\u0026gt; ` ``public` `void` `setShadowDrawable(``int` `resId) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number831 index830 alt2\u0026quot;\u0026gt; ` ``setShadowDrawable(getContext().getResources().getDrawable(resId));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number832 index831 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number833 index832 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number834 index833 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number835 index834 alt2\u0026quot;\u0026gt; ` ``* Sets the shadow drawable.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number836 index835 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number837 index836 alt2\u0026quot;\u0026gt; ` ``* @param d` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number838 index837 alt1\u0026quot;\u0026gt; ` ``* the new shadow drawable` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number839 index838 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number840 index839 alt1\u0026quot;\u0026gt; ` ``public` `void` `setShadowDrawable(Drawable d) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number841 index840 alt2\u0026quot;\u0026gt; ` ``mViewBehind.setShadowDrawable(d);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number842 index841 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number843 index842 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number844 index843 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number845 index844 alt2\u0026quot;\u0026gt; ` ``* Sets the secondary (right) shadow drawable.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number846 index845 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number847 index846 alt2\u0026quot;\u0026gt; ` ``* @param resId` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number848 index847 alt1\u0026quot;\u0026gt; ` ``* the resource ID of the new shadow drawable` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number849 index848 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number850 index849 alt1\u0026quot;\u0026gt; ` ``public` `void` `setSecondaryShadowDrawable(``int` `resId) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number851 index850 alt2\u0026quot;\u0026gt; ` ``setSecondaryShadowDrawable(getContext().getResources().getDrawable(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number852 index851 alt1\u0026quot;\u0026gt; ` ``resId));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number853 index852 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number854 index853 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number855 index854 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number856 index855 alt1\u0026quot;\u0026gt; ` ``* Sets the secondary (right) shadow drawable.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number857 index856 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number858 index857 alt1\u0026quot;\u0026gt; ` ``* @param d` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number859 index858 alt2\u0026quot;\u0026gt; ` ``* the new shadow drawable` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number860 index859 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number861 index860 alt2\u0026quot;\u0026gt; ` ``public` `void` `setSecondaryShadowDrawable(Drawable d) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number862 index861 alt1\u0026quot;\u0026gt; ` ``mViewBehind.setSecondaryShadowDrawable(d);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number863 index862 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number864 index863 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number865 index864 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number866 index865 alt1\u0026quot;\u0026gt; ` ``* Sets the shadow width.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number867 index866 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number868 index867 alt1\u0026quot;\u0026gt; ` ``* @param resId` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number869 index868 alt2\u0026quot;\u0026gt; ` ``* The dimension resource id to be set as the shadow width.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number870 index869 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number871 index870 alt2\u0026quot;\u0026gt; ` ``public` `void` `setShadowWidthRes(``int` `resId) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number872 index871 alt1\u0026quot;\u0026gt; ` ``setShadowWidth((``int``) getResources().getDimension(resId));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number873 index872 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number874 index873 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number875 index874 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number876 index875 alt1\u0026quot;\u0026gt; ` ``* Sets the shadow width.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number877 index876 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number878 index877 alt1\u0026quot;\u0026gt; ` ``* @param pixels` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number879 index878 alt2\u0026quot;\u0026gt; ` ``* the new shadow width, in pixels` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number880 index879 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number881 index880 alt2\u0026quot;\u0026gt; ` ``public` `void` `setShadowWidth(``int` `pixels) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number882 index881 alt1\u0026quot;\u0026gt; ` ``mViewBehind.setShadowWidth(pixels);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number883 index882 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number884 index883 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number885 index884 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number886 index885 alt1\u0026quot;\u0026gt; ` ``* Enables or disables the SlidingMenu's fade in and out` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number887 index886 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number888 index887 alt1\u0026quot;\u0026gt; ` ``* @param b` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number889 index888 alt2\u0026quot;\u0026gt; ` ``* true to enable fade, false to disable it` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number890 index889 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number891 index890 alt2\u0026quot;\u0026gt; ` ``public` `void` `setFadeEnabled(``boolean` `b) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number892 index891 alt1\u0026quot;\u0026gt; ` ``mViewBehind.setFadeEnabled(b);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number893 index892 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number894 index893 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number895 index894 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number896 index895 alt1\u0026quot;\u0026gt; ` ``* Sets how much the SlidingMenu fades in and out. Fade must be enabled, see` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number897 index896 alt2\u0026quot;\u0026gt; ` ``* {@link #setFadeEnabled(boolean) setFadeEnabled(boolean)}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number898 index897 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number899 index898 alt2\u0026quot;\u0026gt; ` ``* @param f` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number900 index899 alt1\u0026quot;\u0026gt; ` ``* the new fade degree, between 0.0f and 1.0f` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number901 index900 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number902 index901 alt1\u0026quot;\u0026gt; ` ``public` `void` `setFadeDegree(``float` `f) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number903 index902 alt2\u0026quot;\u0026gt; ` ``mViewBehind.setFadeDegree(f);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number904 index903 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number905 index904 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number906 index905 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number907 index906 alt2\u0026quot;\u0026gt; ` ``* Enables or disables whether the selector is drawn` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number908 index907 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number909 index908 alt2\u0026quot;\u0026gt; ` ``* @param b` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number910 index909 alt1\u0026quot;\u0026gt; ` ``* true to draw the selector, false to not draw the selector` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number911 index910 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number912 index911 alt1\u0026quot;\u0026gt; ` ``public` `void` `setSelectorEnabled(``boolean` `b) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number913 index912 alt2\u0026quot;\u0026gt; ` ``mViewBehind.setSelectorEnabled(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number914 index913 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number915 index914 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number916 index915 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number917 index916 alt2\u0026quot;\u0026gt; ` ``* Sets the selected view. The selector will be drawn here` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number918 index917 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number919 index918 alt2\u0026quot;\u0026gt; ` ``* @param v` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number920 index919 alt1\u0026quot;\u0026gt; ` ``* the new selected view` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number921 index920 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number922 index921 alt1\u0026quot;\u0026gt; ` ``public` `void` `setSelectedView(View v) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number923 index922 alt2\u0026quot;\u0026gt; ` ``mViewBehind.setSelectedView(v);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number924 index923 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number925 index924 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number926 index925 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number927 index926 alt2\u0026quot;\u0026gt; ` ``* Sets the selector drawable.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number928 index927 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number929 index928 alt2\u0026quot;\u0026gt; ` ``* @param res` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number930 index929 alt1\u0026quot;\u0026gt; ` ``* a resource ID for the selector drawable` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number931 index930 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number932 index931 alt1\u0026quot;\u0026gt; ` ``public` `void` `setSelectorDrawable(``int` `res) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number933 index932 alt2\u0026quot;\u0026gt; ` ``mViewBehind.setSelectorBitmap(BitmapFactory.decodeResource(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number934 index933 alt1\u0026quot;\u0026gt; ` ``getResources(), res));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number935 index934 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number936 index935 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number937 index936 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number938 index937 alt1\u0026quot;\u0026gt; ` ``* Sets the selector drawable.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number939 index938 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number940 index939 alt1\u0026quot;\u0026gt; ` ``* @param b` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number941 index940 alt2\u0026quot;\u0026gt; ` ``* the new selector bitmap` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number942 index941 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number943 index942 alt2\u0026quot;\u0026gt; ` ``public` `void` `setSelectorBitmap(Bitmap b) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number944 index943 alt1\u0026quot;\u0026gt; ` ``mViewBehind.setSelectorBitmap(b);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number945 index944 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number946 index945 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number947 index946 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number948 index947 alt1\u0026quot;\u0026gt; ` ``* Add a View ignored by the Touch Down event when mode is Fullscreen` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number949 index948 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number950 index949 alt1\u0026quot;\u0026gt; ` ``* @param v` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number951 index950 alt2\u0026quot;\u0026gt; ` ``* a view to be ignored` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number952 index951 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number953 index952 alt2\u0026quot;\u0026gt; ` ``public` `void` `addIgnoredView(View v) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number954 index953 alt1\u0026quot;\u0026gt; ` ``mViewAbove.addIgnoredView(v);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number955 index954 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number956 index955 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number957 index956 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number958 index957 alt1\u0026quot;\u0026gt; ` ``* Remove a View ignored by the Touch Down event when mode is Fullscreen` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number959 index958 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number960 index959 alt1\u0026quot;\u0026gt; ` ``* @param v` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number961 index960 alt2\u0026quot;\u0026gt; ` ``* a view not wanted to be ignored anymore` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number962 index961 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number963 index962 alt2\u0026quot;\u0026gt; ` ``public` `void` `removeIgnoredView(View v) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number964 index963 alt1\u0026quot;\u0026gt; ` ``mViewAbove.removeIgnoredView(v);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number965 index964 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number966 index965 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number967 index966 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number968 index967 alt1\u0026quot;\u0026gt; ` ``* Clear the list of Views ignored by the Touch Down event when mode is` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number969 index968 alt2\u0026quot;\u0026gt; ` ``* Fullscreen` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number970 index969 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number971 index970 alt2\u0026quot;\u0026gt; ` ``public` `void` `clearIgnoredViews() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number972 index971 alt1\u0026quot;\u0026gt; ` ``mViewAbove.clearIgnoredViews();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number973 index972 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number974 index973 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number975 index974 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number976 index975 alt1\u0026quot;\u0026gt; ` ``* Sets the OnOpenListener. {@link OnOpenListener#onOpen()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number977 index976 alt2\u0026quot;\u0026gt; ` ``* OnOpenListener.onOpen()} will be called when the SlidingMenu is opened` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number978 index977 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number979 index978 alt2\u0026quot;\u0026gt; ` ``* @param listener` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number980 index979 alt1\u0026quot;\u0026gt; ` ``* the new OnOpenListener` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number981 index980 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number982 index981 alt1\u0026quot;\u0026gt; ` ``public` `void` `setOnOpenListener(OnOpenListener listener) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number983 index982 alt2\u0026quot;\u0026gt; ` ``// mViewAbove.setOnOpenListener(listener);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number984 index983 alt1\u0026quot;\u0026gt; ` ``mOpenListener = listener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number985 index984 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number986 index985 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number987 index986 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number988 index987 alt1\u0026quot;\u0026gt; ` ``* Sets the OnOpenListner for secondary menu {@link OnOpenListener#onOpen()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number989 index988 alt2\u0026quot;\u0026gt; ` ``* OnOpenListener.onOpen()} will be called when the secondary SlidingMenu is` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number990 index989 alt1\u0026quot;\u0026gt; ` ``* opened` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number991 index990 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number992 index991 alt1\u0026quot;\u0026gt; ` ``* @param listener` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number993 index992 alt2\u0026quot;\u0026gt; ` ``* the new OnOpenListener` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number994 index993 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number995 index994 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number996 index995 alt1\u0026quot;\u0026gt; ` ``public` `void` `setSecondaryOnOpenListner(OnOpenListener listener) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number997 index996 alt2\u0026quot;\u0026gt; ` ``mSecondaryOpenListner = listener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number998 index997 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number999 index998 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1000 index999 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1001 index1000 alt2\u0026quot;\u0026gt; ` ``* Sets the OnCloseListener. {@link OnCloseListener#onClose()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1002 index1001 alt1\u0026quot;\u0026gt; ` ``* OnCloseListener.onClose()} will be called when any one of the SlidingMenu` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1003 index1002 alt2\u0026quot;\u0026gt; ` ``* is closed` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1004 index1003 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1005 index1004 alt2\u0026quot;\u0026gt; ` ``* @param listener` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1006 index1005 alt1\u0026quot;\u0026gt; ` ``* the new setOnCloseListener` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1007 index1006 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1008 index1007 alt1\u0026quot;\u0026gt; ` ``public` `void` `setOnCloseListener(OnCloseListener listener) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1009 index1008 alt2\u0026quot;\u0026gt; ` ``// mViewAbove.setOnCloseListener(listener);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1010 index1009 alt1\u0026quot;\u0026gt; ` ``mCloseListener = listener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1011 index1010 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1012 index1011 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1013 index1012 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1014 index1013 alt1\u0026quot;\u0026gt; ` ``* Sets the OnOpenedListener. {@link OnOpenedListener#onOpened()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1015 index1014 alt2\u0026quot;\u0026gt; ` ``* OnOpenedListener.onOpened()} will be called after the SlidingMenu is` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1016 index1015 alt1\u0026quot;\u0026gt; ` ``* opened` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1017 index1016 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1018 index1017 alt1\u0026quot;\u0026gt; ` ``* @param listener` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1019 index1018 alt2\u0026quot;\u0026gt; ` ``* the new OnOpenedListener` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1020 index1019 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1021 index1020 alt2\u0026quot;\u0026gt; ` ``public` `void` `setOnOpenedListener(OnOpenedListener listener) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1022 index1021 alt1\u0026quot;\u0026gt; ` ``mViewAbove.setOnOpenedListener(listener);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1023 index1022 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1024 index1023 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1025 index1024 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1026 index1025 alt1\u0026quot;\u0026gt; ` ``* Sets the OnClosedListener. {@link OnClosedListener#onClosed()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1027 index1026 alt2\u0026quot;\u0026gt; ` ``* OnClosedListener.onClosed()} will be called after the SlidingMenu is` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1028 index1027 alt1\u0026quot;\u0026gt; ` ``* closed` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1029 index1028 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1030 index1029 alt1\u0026quot;\u0026gt; ` ``* @param listener` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1031 index1030 alt2\u0026quot;\u0026gt; ` ``* the new OnClosedListener` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1032 index1031 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1033 index1032 alt2\u0026quot;\u0026gt; ` ``public` `void` `setOnClosedListener(OnClosedListener listener) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1034 index1033 alt1\u0026quot;\u0026gt; ` ``mViewAbove.setOnClosedListener(listener);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1035 index1034 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1036 index1035 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1037 index1036 alt2\u0026quot;\u0026gt; ` ``public` `static` `class` `SavedState ``extends` `BaseSavedState {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1038 index1037 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1039 index1038 alt2\u0026quot;\u0026gt; ` ``private` `final` `int` `mItem;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1040 index1039 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1041 index1040 alt2\u0026quot;\u0026gt; ` ``public` `SavedState(Parcelable superState, ``int` `item) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1042 index1041 alt1\u0026quot;\u0026gt; ` ``super``(superState);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1043 index1042 alt2\u0026quot;\u0026gt; ` ``mItem = item;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1044 index1043 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1045 index1044 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1046 index1045 alt1\u0026quot;\u0026gt; ` ``private` `SavedState(Parcel in) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1047 index1046 alt2\u0026quot;\u0026gt; ` ``super``(in);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1048 index1047 alt1\u0026quot;\u0026gt; ` ``mItem = in.readInt();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1049 index1048 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1050 index1049 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1051 index1050 alt2\u0026quot;\u0026gt; ` ``public` `int` `getItem() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1052 index1051 alt1\u0026quot;\u0026gt; ` ``return` `mItem;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1053 index1052 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1054 index1053 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1055 index1054 alt2\u0026quot;\u0026gt; ` ``/*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1056 index1055 alt1\u0026quot;\u0026gt; ` ``* (non-Javadoc)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1057 index1056 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1058 index1057 alt1\u0026quot;\u0026gt; ` ``* @see android.view.AbsSavedState#writeToParcel(android.os.Parcel, int)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1059 index1058 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1060 index1059 alt1\u0026quot;\u0026gt; ` ``public void writeToParcel(Parcel out, int flags) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1061 index1060 alt2\u0026quot;\u0026gt; ` ``super.writeToParcel(out, flags);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1062 index1061 alt1\u0026quot;\u0026gt; ` ``out.writeInt(mItem);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1063 index1062 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1064 index1063 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1065 index1064 alt2\u0026quot;\u0026gt; ` ``public static final Parcelable.Creator\u0026amp;lt;SavedState\u0026amp;gt; CREATOR = new Parcelable.Creator\u0026amp;lt;SavedState\u0026amp;gt;() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1066 index1065 alt1\u0026quot;\u0026gt; ` ``public SavedState createFromParcel(Parcel in) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1067 index1066 alt2\u0026quot;\u0026gt; ` ``return new SavedState(in);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1068 index1067 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1069 index1068 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1070 index1069 alt1\u0026quot;\u0026gt; ` ``public SavedState[] newArray(int size) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1071 index1070 alt2\u0026quot;\u0026gt; ` ``return new SavedState[size];` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1072 index1071 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1073 index1072 alt2\u0026quot;\u0026gt; ` ``};` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1074 index1073 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1075 index1074 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1076 index1075 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1077 index1076 alt2\u0026quot;\u0026gt; ` ``/*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1078 index1077 alt1\u0026quot;\u0026gt; ` ``* (non-Javadoc)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1079 index1078 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1080 index1079 alt1\u0026quot;\u0026gt; ` ``* @see android.view.View#onSaveInstanceState()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1081 index1080 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1082 index1081 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1083 index1082 alt2\u0026quot;\u0026gt; ` ``protected Parcelable onSaveInstanceState() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1084 index1083 alt1\u0026quot;\u0026gt; ` ``Parcelable superState = super.onSaveInstanceState();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1085 index1084 alt2\u0026quot;\u0026gt; ` ``SavedState ss = new SavedState(superState, mViewAbove.getCurrentItem());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1086 index1085 alt1\u0026quot;\u0026gt; ` ``return ss;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1087 index1086 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1088 index1087 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1089 index1088 alt2\u0026quot;\u0026gt; ` ``/*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1090 index1089 alt1\u0026quot;\u0026gt; ` ``* (non-Javadoc)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1091 index1090 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1092 index1091 alt1\u0026quot;\u0026gt; ` ``* @see android.view.View#onRestoreInstanceState(android.os.Parcelable)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1093 index1092 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1094 index1093 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1095 index1094 alt2\u0026quot;\u0026gt; ` ``protected void onRestoreInstanceState(Parcelable state) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1096 index1095 alt1\u0026quot;\u0026gt; ` ``SavedState ss = (SavedState) state;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1097 index1096 alt2\u0026quot;\u0026gt; ` ``super.onRestoreInstanceState(ss.getSuperState());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1098 index1097 alt1\u0026quot;\u0026gt; ` ``mViewAbove.setCurrentItem(ss.getItem());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1099 index1098 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1100 index1099 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1101 index1100 alt2\u0026quot;\u0026gt; ` ``/*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1102 index1101 alt1\u0026quot;\u0026gt; ` ``* (non-Javadoc)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1103 index1102 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1104 index1103 alt1\u0026quot;\u0026gt; ` ``* @see android.view.ViewGroup#fitSystemWindows(android.graphics.Rect)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1105 index1104 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1106 index1105 alt1\u0026quot;\u0026gt; ` ``@SuppressLint``(``\u0026quot;NewApi\u0026quot;``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1107 index1106 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1108 index1107 alt1\u0026quot;\u0026gt; ` ``protected` `boolean` `fitSystemWindows(Rect insets) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1109 index1108 alt2\u0026quot;\u0026gt; ` ``int` `leftPadding = insets.left;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1110 index1109 alt1\u0026quot;\u0026gt; ` ``int` `rightPadding = insets.right;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1111 index1110 alt2\u0026quot;\u0026gt; ` ``int` `topPadding = insets.top;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1112 index1111 alt1\u0026quot;\u0026gt; ` ``int` `bottomPadding = insets.bottom;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1113 index1112 alt2\u0026quot;\u0026gt; ` ``if` `(!mActionbarOverlay) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1114 index1113 alt1\u0026quot;\u0026gt; ` ``Log.v(TAG, ``\u0026quot;setting padding!\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1115 index1114 alt2\u0026quot;\u0026gt; ` ``setPadding(leftPadding, topPadding, rightPadding, bottomPadding);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1116 index1115 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1117 index1116 alt2\u0026quot;\u0026gt; ` ``return` `true``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1118 index1117 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1119 index1118 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1120 index1119 alt1\u0026quot;\u0026gt; ` ``@TargetApi``(Build.VERSION_CODES.HONEYCOMB)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1121 index1120 alt2\u0026quot;\u0026gt; ` ``public` `void` `manageLayers(``float` `percentOpen) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1122 index1121 alt1\u0026quot;\u0026gt; ` ``if` `(Build.VERSION.SDK_INT \u0026amp;lt; ``11``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1123 index1122 alt2\u0026quot;\u0026gt; ` ``return``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1124 index1123 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1125 index1124 alt2\u0026quot;\u0026gt; ` ``boolean` `layer = percentOpen \u0026amp;gt; ````.0f \u0026amp;\u0026amp; percentOpen \u0026amp;lt; ``1``.0f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1126 index1125 alt1\u0026quot;\u0026gt; ` ``final` `int` `layerType = layer ? View.LAYER_TYPE_HARDWARE` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1127 index1126 alt2\u0026quot;\u0026gt; ` ``: View.LAYER_TYPE_NONE;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1128 index1127 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1129 index1128 alt2\u0026quot;\u0026gt; ` ``if` `(layerType != getContent().getLayerType()) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1130 index1129 alt1\u0026quot;\u0026gt; ` ``getHandler().post(``new` `Runnable() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1131 index1130 alt2\u0026quot;\u0026gt; ` ``public` `void` `run() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1132 index1131 alt1\u0026quot;\u0026gt; ` ``Log.v(TAG, ``\u0026quot;changing layerType. hardware? \u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1133 index1132 alt2\u0026quot;\u0026gt; ` ``+ (layerType == View.LAYER_TYPE_HARDWARE));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1134 index1133 alt1\u0026quot;\u0026gt; ` ``getContent().setLayerType(layerType, ``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1135 index1134 alt2\u0026quot;\u0026gt; ` ``getMenu().setLayerType(layerType, ``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1136 index1135 alt1\u0026quot;\u0026gt; ` ``if` `(getSecondaryMenu() != ``null``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1137 index1136 alt2\u0026quot;\u0026gt; ` ``getSecondaryMenu().setLayerType(layerType, ``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1138 index1137 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1139 index1138 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1140 index1139 alt1\u0026quot;\u0026gt; ` ``});` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1141 index1140 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1142 index1141 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1143 index1142 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number1144 index1143 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; [?](http://www.open-open.com/lib/view/open1411269966859.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; 51 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; 52 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; 53 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; 54 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; 55 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; 56 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; 57 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; 58 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; 59 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; 60 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; 61 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; 62 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; 63 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; 64 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; 65 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; 66 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; 67 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; 68 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; 69 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; 70 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; 71 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; 72 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; 73 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; 74 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; 75 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; 76 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; 77 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; 78 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; 79 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; 80 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; 81 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; 82 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; 83 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; 84 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; 85 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; 86 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; 87 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; 88 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; 89 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; 90 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; 91 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt; 92 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt; 93 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt; 94 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt; 95 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt; 96 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt; 97 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt; 98 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt; 99 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt; 100 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number101 index100 alt2\u0026quot;\u0026gt; 101 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number102 index101 alt1\u0026quot;\u0026gt; 102 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number103 index102 alt2\u0026quot;\u0026gt; 103 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number104 index103 alt1\u0026quot;\u0026gt; 104 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number105 index104 alt2\u0026quot;\u0026gt; 105 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number106 index105 alt1\u0026quot;\u0026gt; 106 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number107 index106 alt2\u0026quot;\u0026gt; 107 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number108 index107 alt1\u0026quot;\u0026gt; 108 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number109 index108 alt2\u0026quot;\u0026gt; 109 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number110 index109 alt1\u0026quot;\u0026gt; 110 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number111 index110 alt2\u0026quot;\u0026gt; 111 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number112 index111 alt1\u0026quot;\u0026gt; 112 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number113 index112 alt2\u0026quot;\u0026gt; 113 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number114 index113 alt1\u0026quot;\u0026gt; 114 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number115 index114 alt2\u0026quot;\u0026gt; 115 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number116 index115 alt1\u0026quot;\u0026gt; 116 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number117 index116 alt2\u0026quot;\u0026gt; 117 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number118 index117 alt1\u0026quot;\u0026gt; 118 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number119 index118 alt2\u0026quot;\u0026gt; 119 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number120 index119 alt1\u0026quot;\u0026gt; 120 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number121 index120 alt2\u0026quot;\u0026gt; 121 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number122 index121 alt1\u0026quot;\u0026gt; 122 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number123 index122 alt2\u0026quot;\u0026gt; 123 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number124 index123 alt1\u0026quot;\u0026gt; 124 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number125 index124 alt2\u0026quot;\u0026gt; 125 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number126 index125 alt1\u0026quot;\u0026gt; 126 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number127 index126 alt2\u0026quot;\u0026gt; 127 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number128 index127 alt1\u0026quot;\u0026gt; 128 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number129 index128 alt2\u0026quot;\u0026gt; 129 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number130 index129 alt1\u0026quot;\u0026gt; 130 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number131 index130 alt2\u0026quot;\u0026gt; 131 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number132 index131 alt1\u0026quot;\u0026gt; 132 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number133 index132 alt2\u0026quot;\u0026gt; 133 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number134 index133 alt1\u0026quot;\u0026gt; 134 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number135 index134 alt2\u0026quot;\u0026gt; 135 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number136 index135 alt1\u0026quot;\u0026gt; 136 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number137 index136 alt2\u0026quot;\u0026gt; 137 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number138 index137 alt1\u0026quot;\u0026gt; 138 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number139 index138 alt2\u0026quot;\u0026gt; 139 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number140 index139 alt1\u0026quot;\u0026gt; 140 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number141 index140 alt2\u0026quot;\u0026gt; 141 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number142 index141 alt1\u0026quot;\u0026gt; 142 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number143 index142 alt2\u0026quot;\u0026gt; 143 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number144 index143 alt1\u0026quot;\u0026gt; 144 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number145 index144 alt2\u0026quot;\u0026gt; 145 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number146 index145 alt1\u0026quot;\u0026gt; 146 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number147 index146 alt2\u0026quot;\u0026gt; 147 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number148 index147 alt1\u0026quot;\u0026gt; 148 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number149 index148 alt2\u0026quot;\u0026gt; 149 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number150 index149 alt1\u0026quot;\u0026gt; 150 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number151 index150 alt2\u0026quot;\u0026gt; 151 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number152 index151 alt1\u0026quot;\u0026gt; 152 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number153 index152 alt2\u0026quot;\u0026gt; 153 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number154 index153 alt1\u0026quot;\u0026gt; 154 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number155 index154 alt2\u0026quot;\u0026gt; 155 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number156 index155 alt1\u0026quot;\u0026gt; 156 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number157 index156 alt2\u0026quot;\u0026gt; 157 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number158 index157 alt1\u0026quot;\u0026gt; 158 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number159 index158 alt2\u0026quot;\u0026gt; 159 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number160 index159 alt1\u0026quot;\u0026gt; 160 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number161 index160 alt2\u0026quot;\u0026gt; 161 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number162 index161 alt1\u0026quot;\u0026gt; 162 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number163 index162 alt2\u0026quot;\u0026gt; 163 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number164 index163 alt1\u0026quot;\u0026gt; 164 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number165 index164 alt2\u0026quot;\u0026gt; 165 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number166 index165 alt1\u0026quot;\u0026gt; 166 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number167 index166 alt2\u0026quot;\u0026gt; 167 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number168 index167 alt1\u0026quot;\u0026gt; 168 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number169 index168 alt2\u0026quot;\u0026gt; 169 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number170 index169 alt1\u0026quot;\u0026gt; 170 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number171 index170 alt2\u0026quot;\u0026gt; 171 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number172 index171 alt1\u0026quot;\u0026gt; 172 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number173 index172 alt2\u0026quot;\u0026gt; 173 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number174 index173 alt1\u0026quot;\u0026gt; 174 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number175 index174 alt2\u0026quot;\u0026gt; 175 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number176 index175 alt1\u0026quot;\u0026gt; 176 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number177 index176 alt2\u0026quot;\u0026gt; 177 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number178 index177 alt1\u0026quot;\u0026gt; 178 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number179 index178 alt2\u0026quot;\u0026gt; 179 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number180 index179 alt1\u0026quot;\u0026gt; 180 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number181 index180 alt2\u0026quot;\u0026gt; 181 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number182 index181 alt1\u0026quot;\u0026gt; 182 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number183 index182 alt2\u0026quot;\u0026gt; 183 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number184 index183 alt1\u0026quot;\u0026gt; 184 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number185 index184 alt2\u0026quot;\u0026gt; 185 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number186 index185 alt1\u0026quot;\u0026gt; 186 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number187 index186 alt2\u0026quot;\u0026gt; 187 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number188 index187 alt1\u0026quot;\u0026gt; 188 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number189 index188 alt2\u0026quot;\u0026gt; 189 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number190 index189 alt1\u0026quot;\u0026gt; 190 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number191 index190 alt2\u0026quot;\u0026gt; 191 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number192 index191 alt1\u0026quot;\u0026gt; 192 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number193 index192 alt2\u0026quot;\u0026gt; 193 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number194 index193 alt1\u0026quot;\u0026gt; 194 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number195 index194 alt2\u0026quot;\u0026gt; 195 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number196 index195 alt1\u0026quot;\u0026gt; 196 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number197 index196 alt2\u0026quot;\u0026gt; 197 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number198 index197 alt1\u0026quot;\u0026gt; 198 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number199 index198 alt2\u0026quot;\u0026gt; 199 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number200 index199 alt1\u0026quot;\u0026gt; 200 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number201 index200 alt2\u0026quot;\u0026gt; 201 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number202 index201 alt1\u0026quot;\u0026gt; 202 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number203 index202 alt2\u0026quot;\u0026gt; 203 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number204 index203 alt1\u0026quot;\u0026gt; 204 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number205 index204 alt2\u0026quot;\u0026gt; 205 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number206 index205 alt1\u0026quot;\u0026gt; 206 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number207 index206 alt2\u0026quot;\u0026gt; 207 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number208 index207 alt1\u0026quot;\u0026gt; 208 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number209 index208 alt2\u0026quot;\u0026gt; 209 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number210 index209 alt1\u0026quot;\u0026gt; 210 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number211 index210 alt2\u0026quot;\u0026gt; 211 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number212 index211 alt1\u0026quot;\u0026gt; 212 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number213 index212 alt2\u0026quot;\u0026gt; 213 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number214 index213 alt1\u0026quot;\u0026gt; 214 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number215 index214 alt2\u0026quot;\u0026gt; 215 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number216 index215 alt1\u0026quot;\u0026gt; 216 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number217 index216 alt2\u0026quot;\u0026gt; 217 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number218 index217 alt1\u0026quot;\u0026gt; 218 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number219 index218 alt2\u0026quot;\u0026gt; 219 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number220 index219 alt1\u0026quot;\u0026gt; 220 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number221 index220 alt2\u0026quot;\u0026gt; 221 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number222 index221 alt1\u0026quot;\u0026gt; 222 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number223 index222 alt2\u0026quot;\u0026gt; 223 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number224 index223 alt1\u0026quot;\u0026gt; 224 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number225 index224 alt2\u0026quot;\u0026gt; 225 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number226 index225 alt1\u0026quot;\u0026gt; 226 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number227 index226 alt2\u0026quot;\u0026gt; 227 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number228 index227 alt1\u0026quot;\u0026gt; 228 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number229 index228 alt2\u0026quot;\u0026gt; 229 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number230 index229 alt1\u0026quot;\u0026gt; 230 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number231 index230 alt2\u0026quot;\u0026gt; 231 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number232 index231 alt1\u0026quot;\u0026gt; 232 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number233 index232 alt2\u0026quot;\u0026gt; 233 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number234 index233 alt1\u0026quot;\u0026gt; 234 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number235 index234 alt2\u0026quot;\u0026gt; 235 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number236 index235 alt1\u0026quot;\u0026gt; 236 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number237 index236 alt2\u0026quot;\u0026gt; 237 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number238 index237 alt1\u0026quot;\u0026gt; 238 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number239 index238 alt2\u0026quot;\u0026gt; 239 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number240 index239 alt1\u0026quot;\u0026gt; 240 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number241 index240 alt2\u0026quot;\u0026gt; 241 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number242 index241 alt1\u0026quot;\u0026gt; 242 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number243 index242 alt2\u0026quot;\u0026gt; 243 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number244 index243 alt1\u0026quot;\u0026gt; 244 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number245 index244 alt2\u0026quot;\u0026gt; 245 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number246 index245 alt1\u0026quot;\u0026gt; 246 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number247 index246 alt2\u0026quot;\u0026gt; 247 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number248 index247 alt1\u0026quot;\u0026gt; 248 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number249 index248 alt2\u0026quot;\u0026gt; 249 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number250 index249 alt1\u0026quot;\u0026gt; 250 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number251 index250 alt2\u0026quot;\u0026gt; 251 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number252 index251 alt1\u0026quot;\u0026gt; 252 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number253 index252 alt2\u0026quot;\u0026gt; 253 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number254 index253 alt1\u0026quot;\u0026gt; 254 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number255 index254 alt2\u0026quot;\u0026gt; 255 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number256 index255 alt1\u0026quot;\u0026gt; 256 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number257 index256 alt2\u0026quot;\u0026gt; 257 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number258 index257 alt1\u0026quot;\u0026gt; 258 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number259 index258 alt2\u0026quot;\u0026gt; 259 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number260 index259 alt1\u0026quot;\u0026gt; 260 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number261 index260 alt2\u0026quot;\u0026gt; 261 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number262 index261 alt1\u0026quot;\u0026gt; 262 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number263 index262 alt2\u0026quot;\u0026gt; 263 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number264 index263 alt1\u0026quot;\u0026gt; 264 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number265 index264 alt2\u0026quot;\u0026gt; 265 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number266 index265 alt1\u0026quot;\u0026gt; 266 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number267 index266 alt2\u0026quot;\u0026gt; 267 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number268 index267 alt1\u0026quot;\u0026gt; 268 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number269 index268 alt2\u0026quot;\u0026gt; 269 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number270 index269 alt1\u0026quot;\u0026gt; 270 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number271 index270 alt2\u0026quot;\u0026gt; 271 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number272 index271 alt1\u0026quot;\u0026gt; 272 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number273 index272 alt2\u0026quot;\u0026gt; 273 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number274 index273 alt1\u0026quot;\u0026gt; 274 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number275 index274 alt2\u0026quot;\u0026gt; 275 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number276 index275 alt1\u0026quot;\u0026gt; 276 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number277 index276 alt2\u0026quot;\u0026gt; 277 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number278 index277 alt1\u0026quot;\u0026gt; 278 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number279 index278 alt2\u0026quot;\u0026gt; 279 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number280 index279 alt1\u0026quot;\u0026gt; 280 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number281 index280 alt2\u0026quot;\u0026gt; 281 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number282 index281 alt1\u0026quot;\u0026gt; 282 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number283 index282 alt2\u0026quot;\u0026gt; 283 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number284 index283 alt1\u0026quot;\u0026gt; 284 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number285 index284 alt2\u0026quot;\u0026gt; 285 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number286 index285 alt1\u0026quot;\u0026gt; 286 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number287 index286 alt2\u0026quot;\u0026gt; 287 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number288 index287 alt1\u0026quot;\u0026gt; 288 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number289 index288 alt2\u0026quot;\u0026gt; 289 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number290 index289 alt1\u0026quot;\u0026gt; 290 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number291 index290 alt2\u0026quot;\u0026gt; 291 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number292 index291 alt1\u0026quot;\u0026gt; 292 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number293 index292 alt2\u0026quot;\u0026gt; 293 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number294 index293 alt1\u0026quot;\u0026gt; 294 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number295 index294 alt2\u0026quot;\u0026gt; 295 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number296 index295 alt1\u0026quot;\u0026gt; 296 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number297 index296 alt2\u0026quot;\u0026gt; 297 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number298 index297 alt1\u0026quot;\u0026gt; 298 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number299 index298 alt2\u0026quot;\u0026gt; 299 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number300 index299 alt1\u0026quot;\u0026gt; 300 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number301 index300 alt2\u0026quot;\u0026gt; 301 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number302 index301 alt1\u0026quot;\u0026gt; 302 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number303 index302 alt2\u0026quot;\u0026gt; 303 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number304 index303 alt1\u0026quot;\u0026gt; 304 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number305 index304 alt2\u0026quot;\u0026gt; 305 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number306 index305 alt1\u0026quot;\u0026gt; 306 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number307 index306 alt2\u0026quot;\u0026gt; 307 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number308 index307 alt1\u0026quot;\u0026gt; 308 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number309 index308 alt2\u0026quot;\u0026gt; 309 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number310 index309 alt1\u0026quot;\u0026gt; 310 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number311 index310 alt2\u0026quot;\u0026gt; 311 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number312 index311 alt1\u0026quot;\u0026gt; 312 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number313 index312 alt2\u0026quot;\u0026gt; 313 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number314 index313 alt1\u0026quot;\u0026gt; 314 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number315 index314 alt2\u0026quot;\u0026gt; 315 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number316 index315 alt1\u0026quot;\u0026gt; 316 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number317 index316 alt2\u0026quot;\u0026gt; 317 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number318 index317 alt1\u0026quot;\u0026gt; 318 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number319 index318 alt2\u0026quot;\u0026gt; 319 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number320 index319 alt1\u0026quot;\u0026gt; 320 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number321 index320 alt2\u0026quot;\u0026gt; 321 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number322 index321 alt1\u0026quot;\u0026gt; 322 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number323 index322 alt2\u0026quot;\u0026gt; 323 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number324 index323 alt1\u0026quot;\u0026gt; 324 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number325 index324 alt2\u0026quot;\u0026gt; 325 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number326 index325 alt1\u0026quot;\u0026gt; 326 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number327 index326 alt2\u0026quot;\u0026gt; 327 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number328 index327 alt1\u0026quot;\u0026gt; 328 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number329 index328 alt2\u0026quot;\u0026gt; 329 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number330 index329 alt1\u0026quot;\u0026gt; 330 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number331 index330 alt2\u0026quot;\u0026gt; 331 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number332 index331 alt1\u0026quot;\u0026gt; 332 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number333 index332 alt2\u0026quot;\u0026gt; 333 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number334 index333 alt1\u0026quot;\u0026gt; 334 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number335 index334 alt2\u0026quot;\u0026gt; 335 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number336 index335 alt1\u0026quot;\u0026gt; 336 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number337 index336 alt2\u0026quot;\u0026gt; 337 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number338 index337 alt1\u0026quot;\u0026gt; 338 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number339 index338 alt2\u0026quot;\u0026gt; 339 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number340 index339 alt1\u0026quot;\u0026gt; 340 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number341 index340 alt2\u0026quot;\u0026gt; 341 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number342 index341 alt1\u0026quot;\u0026gt; 342 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number343 index342 alt2\u0026quot;\u0026gt; 343 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number344 index343 alt1\u0026quot;\u0026gt; 344 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number345 index344 alt2\u0026quot;\u0026gt; 345 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number346 index345 alt1\u0026quot;\u0026gt; 346 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number347 index346 alt2\u0026quot;\u0026gt; 347 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number348 index347 alt1\u0026quot;\u0026gt; 348 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number349 index348 alt2\u0026quot;\u0026gt; 349 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number350 index349 alt1\u0026quot;\u0026gt; 350 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number351 index350 alt2\u0026quot;\u0026gt; 351 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number352 index351 alt1\u0026quot;\u0026gt; 352 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number353 index352 alt2\u0026quot;\u0026gt; 353 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number354 index353 alt1\u0026quot;\u0026gt; 354 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number355 index354 alt2\u0026quot;\u0026gt; 355 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number356 index355 alt1\u0026quot;\u0026gt; 356 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number357 index356 alt2\u0026quot;\u0026gt; 357 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number358 index357 alt1\u0026quot;\u0026gt; 358 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number359 index358 alt2\u0026quot;\u0026gt; 359 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number360 index359 alt1\u0026quot;\u0026gt; 360 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number361 index360 alt2\u0026quot;\u0026gt; 361 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number362 index361 alt1\u0026quot;\u0026gt; 362 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number363 index362 alt2\u0026quot;\u0026gt; 363 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number364 index363 alt1\u0026quot;\u0026gt; 364 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number365 index364 alt2\u0026quot;\u0026gt; 365 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number366 index365 alt1\u0026quot;\u0026gt; 366 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number367 index366 alt2\u0026quot;\u0026gt; 367 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number368 index367 alt1\u0026quot;\u0026gt; 368 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number369 index368 alt2\u0026quot;\u0026gt; 369 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number370 index369 alt1\u0026quot;\u0026gt; 370 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number371 index370 alt2\u0026quot;\u0026gt; 371 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number372 index371 alt1\u0026quot;\u0026gt; 372 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number373 index372 alt2\u0026quot;\u0026gt; 373 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number374 index373 alt1\u0026quot;\u0026gt; 374 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number375 index374 alt2\u0026quot;\u0026gt; 375 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number376 index375 alt1\u0026quot;\u0026gt; 376 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number377 index376 alt2\u0026quot;\u0026gt; 377 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number378 index377 alt1\u0026quot;\u0026gt; 378 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number379 index378 alt2\u0026quot;\u0026gt; 379 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number380 index379 alt1\u0026quot;\u0026gt; 380 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number381 index380 alt2\u0026quot;\u0026gt; 381 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number382 index381 alt1\u0026quot;\u0026gt; 382 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number383 index382 alt2\u0026quot;\u0026gt; 383 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number384 index383 alt1\u0026quot;\u0026gt; 384 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number385 index384 alt2\u0026quot;\u0026gt; 385 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number386 index385 alt1\u0026quot;\u0026gt; 386 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number387 index386 alt2\u0026quot;\u0026gt; 387 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number388 index387 alt1\u0026quot;\u0026gt; 388 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number389 index388 alt2\u0026quot;\u0026gt; 389 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number390 index389 alt1\u0026quot;\u0026gt; 390 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number391 index390 alt2\u0026quot;\u0026gt; 391 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number392 index391 alt1\u0026quot;\u0026gt; 392 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number393 index392 alt2\u0026quot;\u0026gt; 393 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number394 index393 alt1\u0026quot;\u0026gt; 394 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number395 index394 alt2\u0026quot;\u0026gt; 395 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number396 index395 alt1\u0026quot;\u0026gt; 396 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number397 index396 alt2\u0026quot;\u0026gt; 397 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number398 index397 alt1\u0026quot;\u0026gt; 398 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number399 index398 alt2\u0026quot;\u0026gt; 399 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number400 index399 alt1\u0026quot;\u0026gt; 400 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number401 index400 alt2\u0026quot;\u0026gt; 401 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number402 index401 alt1\u0026quot;\u0026gt; 402 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number403 index402 alt2\u0026quot;\u0026gt; 403 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number404 index403 alt1\u0026quot;\u0026gt; 404 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number405 index404 alt2\u0026quot;\u0026gt; 405 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number406 index405 alt1\u0026quot;\u0026gt; 406 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number407 index406 alt2\u0026quot;\u0026gt; 407 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number408 index407 alt1\u0026quot;\u0026gt; 408 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number409 index408 alt2\u0026quot;\u0026gt; 409 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number410 index409 alt1\u0026quot;\u0026gt; 410 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number411 index410 alt2\u0026quot;\u0026gt; 411 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number412 index411 alt1\u0026quot;\u0026gt; 412 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number413 index412 alt2\u0026quot;\u0026gt; 413 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number414 index413 alt1\u0026quot;\u0026gt; 414 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number415 index414 alt2\u0026quot;\u0026gt; 415 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number416 index415 alt1\u0026quot;\u0026gt; 416 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number417 index416 alt2\u0026quot;\u0026gt; 417 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number418 index417 alt1\u0026quot;\u0026gt; 418 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number419 index418 alt2\u0026quot;\u0026gt; 419 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number420 index419 alt1\u0026quot;\u0026gt; 420 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number421 index420 alt2\u0026quot;\u0026gt; 421 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number422 index421 alt1\u0026quot;\u0026gt; 422 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number423 index422 alt2\u0026quot;\u0026gt; 423 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number424 index423 alt1\u0026quot;\u0026gt; 424 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number425 index424 alt2\u0026quot;\u0026gt; 425 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number426 index425 alt1\u0026quot;\u0026gt; 426 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number427 index426 alt2\u0026quot;\u0026gt; 427 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number428 index427 alt1\u0026quot;\u0026gt; 428 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number429 index428 alt2\u0026quot;\u0026gt; 429 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number430 index429 alt1\u0026quot;\u0026gt; 430 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number431 index430 alt2\u0026quot;\u0026gt; 431 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number432 index431 alt1\u0026quot;\u0026gt; 432 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number433 index432 alt2\u0026quot;\u0026gt; 433 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number434 index433 alt1\u0026quot;\u0026gt; 434 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number435 index434 alt2\u0026quot;\u0026gt; 435 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number436 index435 alt1\u0026quot;\u0026gt; 436 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number437 index436 alt2\u0026quot;\u0026gt; 437 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number438 index437 alt1\u0026quot;\u0026gt; 438 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number439 index438 alt2\u0026quot;\u0026gt; 439 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number440 index439 alt1\u0026quot;\u0026gt; 440 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number441 index440 alt2\u0026quot;\u0026gt; 441 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number442 index441 alt1\u0026quot;\u0026gt; 442 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number443 index442 alt2\u0026quot;\u0026gt; 443 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number444 index443 alt1\u0026quot;\u0026gt; 444 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number445 index444 alt2\u0026quot;\u0026gt; 445 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number446 index445 alt1\u0026quot;\u0026gt; 446 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number447 index446 alt2\u0026quot;\u0026gt; 447 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number448 index447 alt1\u0026quot;\u0026gt; 448 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number449 index448 alt2\u0026quot;\u0026gt; 449 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number450 index449 alt1\u0026quot;\u0026gt; 450 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number451 index450 alt2\u0026quot;\u0026gt; 451 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number452 index451 alt1\u0026quot;\u0026gt; 452 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number453 index452 alt2\u0026quot;\u0026gt; 453 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number454 index453 alt1\u0026quot;\u0026gt; 454 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number455 index454 alt2\u0026quot;\u0026gt; 455 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number456 index455 alt1\u0026quot;\u0026gt; 456 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number457 index456 alt2\u0026quot;\u0026gt; 457 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number458 index457 alt1\u0026quot;\u0026gt; 458 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number459 index458 alt2\u0026quot;\u0026gt; 459 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number460 index459 alt1\u0026quot;\u0026gt; 460 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number461 index460 alt2\u0026quot;\u0026gt; 461 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number462 index461 alt1\u0026quot;\u0026gt; 462 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number463 index462 alt2\u0026quot;\u0026gt; 463 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number464 index463 alt1\u0026quot;\u0026gt; 464 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number465 index464 alt2\u0026quot;\u0026gt; 465 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number466 index465 alt1\u0026quot;\u0026gt; 466 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number467 index466 alt2\u0026quot;\u0026gt; 467 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number468 index467 alt1\u0026quot;\u0026gt; 468 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number469 index468 alt2\u0026quot;\u0026gt; 469 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number470 index469 alt1\u0026quot;\u0026gt; 470 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number471 index470 alt2\u0026quot;\u0026gt; 471 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number472 index471 alt1\u0026quot;\u0026gt; 472 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number473 index472 alt2\u0026quot;\u0026gt; 473 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number474 index473 alt1\u0026quot;\u0026gt; 474 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number475 index474 alt2\u0026quot;\u0026gt; 475 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number476 index475 alt1\u0026quot;\u0026gt; 476 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number477 index476 alt2\u0026quot;\u0026gt; 477 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number478 index477 alt1\u0026quot;\u0026gt; 478 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number479 index478 alt2\u0026quot;\u0026gt; 479 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number480 index479 alt1\u0026quot;\u0026gt; 480 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number481 index480 alt2\u0026quot;\u0026gt; 481 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number482 index481 alt1\u0026quot;\u0026gt; 482 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number483 index482 alt2\u0026quot;\u0026gt; 483 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number484 index483 alt1\u0026quot;\u0026gt; 484 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number485 index484 alt2\u0026quot;\u0026gt; 485 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number486 index485 alt1\u0026quot;\u0026gt; 486 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number487 index486 alt2\u0026quot;\u0026gt; 487 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number488 index487 alt1\u0026quot;\u0026gt; 488 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number489 index488 alt2\u0026quot;\u0026gt; 489 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number490 index489 alt1\u0026quot;\u0026gt; 490 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number491 index490 alt2\u0026quot;\u0026gt; 491 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number492 index491 alt1\u0026quot;\u0026gt; 492 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number493 index492 alt2\u0026quot;\u0026gt; 493 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number494 index493 alt1\u0026quot;\u0026gt; 494 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number495 index494 alt2\u0026quot;\u0026gt; 495 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number496 index495 alt1\u0026quot;\u0026gt; 496 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number497 index496 alt2\u0026quot;\u0026gt; 497 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number498 index497 alt1\u0026quot;\u0026gt; 498 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number499 index498 alt2\u0026quot;\u0026gt; 499 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number500 index499 alt1\u0026quot;\u0026gt; 500 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number501 index500 alt2\u0026quot;\u0026gt; 501 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number502 index501 alt1\u0026quot;\u0026gt; 502 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number503 index502 alt2\u0026quot;\u0026gt; 503 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number504 index503 alt1\u0026quot;\u0026gt; 504 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number505 index504 alt2\u0026quot;\u0026gt; 505 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number506 index505 alt1\u0026quot;\u0026gt; 506 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number507 index506 alt2\u0026quot;\u0026gt; 507 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number508 index507 alt1\u0026quot;\u0026gt; 508 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number509 index508 alt2\u0026quot;\u0026gt; 509 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number510 index509 alt1\u0026quot;\u0026gt; 510 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number511 index510 alt2\u0026quot;\u0026gt; 511 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number512 index511 alt1\u0026quot;\u0026gt; 512 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number513 index512 alt2\u0026quot;\u0026gt; 513 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number514 index513 alt1\u0026quot;\u0026gt; 514 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number515 index514 alt2\u0026quot;\u0026gt; 515 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number516 index515 alt1\u0026quot;\u0026gt; 516 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number517 index516 alt2\u0026quot;\u0026gt; 517 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number518 index517 alt1\u0026quot;\u0026gt; 518 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number519 index518 alt2\u0026quot;\u0026gt; 519 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number520 index519 alt1\u0026quot;\u0026gt; 520 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number521 index520 alt2\u0026quot;\u0026gt; 521 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number522 index521 alt1\u0026quot;\u0026gt; 522 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number523 index522 alt2\u0026quot;\u0026gt; 523 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number524 index523 alt1\u0026quot;\u0026gt; 524 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number525 index524 alt2\u0026quot;\u0026gt; 525 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number526 index525 alt1\u0026quot;\u0026gt; 526 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number527 index526 alt2\u0026quot;\u0026gt; 527 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number528 index527 alt1\u0026quot;\u0026gt; 528 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number529 index528 alt2\u0026quot;\u0026gt; 529 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number530 index529 alt1\u0026quot;\u0026gt; 530 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number531 index530 alt2\u0026quot;\u0026gt; 531 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number532 index531 alt1\u0026quot;\u0026gt; 532 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number533 index532 alt2\u0026quot;\u0026gt; 533 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number534 index533 alt1\u0026quot;\u0026gt; 534 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number535 index534 alt2\u0026quot;\u0026gt; 535 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number536 index535 alt1\u0026quot;\u0026gt; 536 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number537 index536 alt2\u0026quot;\u0026gt; 537 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number538 index537 alt1\u0026quot;\u0026gt; 538 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number539 index538 alt2\u0026quot;\u0026gt; 539 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number540 index539 alt1\u0026quot;\u0026gt; 540 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number541 index540 alt2\u0026quot;\u0026gt; 541 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number542 index541 alt1\u0026quot;\u0026gt; 542 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number543 index542 alt2\u0026quot;\u0026gt; 543 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number544 index543 alt1\u0026quot;\u0026gt; 544 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number545 index544 alt2\u0026quot;\u0026gt; 545 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number546 index545 alt1\u0026quot;\u0026gt; 546 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number547 index546 alt2\u0026quot;\u0026gt; 547 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number548 index547 alt1\u0026quot;\u0026gt; 548 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number549 index548 alt2\u0026quot;\u0026gt; 549 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number550 index549 alt1\u0026quot;\u0026gt; 550 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number551 index550 alt2\u0026quot;\u0026gt; 551 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number552 index551 alt1\u0026quot;\u0026gt; 552 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number553 index552 alt2\u0026quot;\u0026gt; 553 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number554 index553 alt1\u0026quot;\u0026gt; 554 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number555 index554 alt2\u0026quot;\u0026gt; 555 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number556 index555 alt1\u0026quot;\u0026gt; 556 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number557 index556 alt2\u0026quot;\u0026gt; 557 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number558 index557 alt1\u0026quot;\u0026gt; 558 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number559 index558 alt2\u0026quot;\u0026gt; 559 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number560 index559 alt1\u0026quot;\u0026gt; 560 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number561 index560 alt2\u0026quot;\u0026gt; 561 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number562 index561 alt1\u0026quot;\u0026gt; 562 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number563 index562 alt2\u0026quot;\u0026gt; 563 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number564 index563 alt1\u0026quot;\u0026gt; 564 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number565 index564 alt2\u0026quot;\u0026gt; 565 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number566 index565 alt1\u0026quot;\u0026gt; 566 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number567 index566 alt2\u0026quot;\u0026gt; 567 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number568 index567 alt1\u0026quot;\u0026gt; 568 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number569 index568 alt2\u0026quot;\u0026gt; 569 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number570 index569 alt1\u0026quot;\u0026gt; 570 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number571 index570 alt2\u0026quot;\u0026gt; 571 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number572 index571 alt1\u0026quot;\u0026gt; 572 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number573 index572 alt2\u0026quot;\u0026gt; 573 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number574 index573 alt1\u0026quot;\u0026gt; 574 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number575 index574 alt2\u0026quot;\u0026gt; 575 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number576 index575 alt1\u0026quot;\u0026gt; 576 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number577 index576 alt2\u0026quot;\u0026gt; 577 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number578 index577 alt1\u0026quot;\u0026gt; 578 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number579 index578 alt2\u0026quot;\u0026gt; 579 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number580 index579 alt1\u0026quot;\u0026gt; 580 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number581 index580 alt2\u0026quot;\u0026gt; 581 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number582 index581 alt1\u0026quot;\u0026gt; 582 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number583 index582 alt2\u0026quot;\u0026gt; 583 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number584 index583 alt1\u0026quot;\u0026gt; 584 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number585 index584 alt2\u0026quot;\u0026gt; 585 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number586 index585 alt1\u0026quot;\u0026gt; 586 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number587 index586 alt2\u0026quot;\u0026gt; 587 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number588 index587 alt1\u0026quot;\u0026gt; 588 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number589 index588 alt2\u0026quot;\u0026gt; 589 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number590 index589 alt1\u0026quot;\u0026gt; 590 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number591 index590 alt2\u0026quot;\u0026gt; 591 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number592 index591 alt1\u0026quot;\u0026gt; 592 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number593 index592 alt2\u0026quot;\u0026gt; 593 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number594 index593 alt1\u0026quot;\u0026gt; 594 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number595 index594 alt2\u0026quot;\u0026gt; 595 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number596 index595 alt1\u0026quot;\u0026gt; 596 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number597 index596 alt2\u0026quot;\u0026gt; 597 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number598 index597 alt1\u0026quot;\u0026gt; 598 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number599 index598 alt2\u0026quot;\u0026gt; 599 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number600 index599 alt1\u0026quot;\u0026gt; 600 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number601 index600 alt2\u0026quot;\u0026gt; 601 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number602 index601 alt1\u0026quot;\u0026gt; 602 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number603 index602 alt2\u0026quot;\u0026gt; 603 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number604 index603 alt1\u0026quot;\u0026gt; 604 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number605 index604 alt2\u0026quot;\u0026gt; 605 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number606 index605 alt1\u0026quot;\u0026gt; 606 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number607 index606 alt2\u0026quot;\u0026gt; 607 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number608 index607 alt1\u0026quot;\u0026gt; 608 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number609 index608 alt2\u0026quot;\u0026gt; 609 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number610 index609 alt1\u0026quot;\u0026gt; 610 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number611 index610 alt2\u0026quot;\u0026gt; 611 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number612 index611 alt1\u0026quot;\u0026gt; 612 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number613 index612 alt2\u0026quot;\u0026gt; 613 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number614 index613 alt1\u0026quot;\u0026gt; 614 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number615 index614 alt2\u0026quot;\u0026gt; 615 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number616 index615 alt1\u0026quot;\u0026gt; 616 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number617 index616 alt2\u0026quot;\u0026gt; 617 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number618 index617 alt1\u0026quot;\u0026gt; 618 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number619 index618 alt2\u0026quot;\u0026gt; 619 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number620 index619 alt1\u0026quot;\u0026gt; 620 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number621 index620 alt2\u0026quot;\u0026gt; 621 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number622 index621 alt1\u0026quot;\u0026gt; 622 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number623 index622 alt2\u0026quot;\u0026gt; 623 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number624 index623 alt1\u0026quot;\u0026gt; 624 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number625 index624 alt2\u0026quot;\u0026gt; 625 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number626 index625 alt1\u0026quot;\u0026gt; 626 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number627 index626 alt2\u0026quot;\u0026gt; 627 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number628 index627 alt1\u0026quot;\u0026gt; 628 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number629 index628 alt2\u0026quot;\u0026gt; 629 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number630 index629 alt1\u0026quot;\u0026gt; 630 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number631 index630 alt2\u0026quot;\u0026gt; 631 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number632 index631 alt1\u0026quot;\u0026gt; 632 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number633 index632 alt2\u0026quot;\u0026gt; 633 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number634 index633 alt1\u0026quot;\u0026gt; 634 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number635 index634 alt2\u0026quot;\u0026gt; 635 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number636 index635 alt1\u0026quot;\u0026gt; 636 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number637 index636 alt2\u0026quot;\u0026gt; 637 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number638 index637 alt1\u0026quot;\u0026gt; 638 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number639 index638 alt2\u0026quot;\u0026gt; 639 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number640 index639 alt1\u0026quot;\u0026gt; 640 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number641 index640 alt2\u0026quot;\u0026gt; 641 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number642 index641 alt1\u0026quot;\u0026gt; 642 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number643 index642 alt2\u0026quot;\u0026gt; 643 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number644 index643 alt1\u0026quot;\u0026gt; 644 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number645 index644 alt2\u0026quot;\u0026gt; 645 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number646 index645 alt1\u0026quot;\u0026gt; 646 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number647 index646 alt2\u0026quot;\u0026gt; 647 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number648 index647 alt1\u0026quot;\u0026gt; 648 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number649 index648 alt2\u0026quot;\u0026gt; 649 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number650 index649 alt1\u0026quot;\u0026gt; 650 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number651 index650 alt2\u0026quot;\u0026gt; 651 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number652 index651 alt1\u0026quot;\u0026gt; 652 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number653 index652 alt2\u0026quot;\u0026gt; 653 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number654 index653 alt1\u0026quot;\u0026gt; 654 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number655 index654 alt2\u0026quot;\u0026gt; 655 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number656 index655 alt1\u0026quot;\u0026gt; 656 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number657 index656 alt2\u0026quot;\u0026gt; 657 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number658 index657 alt1\u0026quot;\u0026gt; 658 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number659 index658 alt2\u0026quot;\u0026gt; 659 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number660 index659 alt1\u0026quot;\u0026gt; 660 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number661 index660 alt2\u0026quot;\u0026gt; 661 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number662 index661 alt1\u0026quot;\u0026gt; 662 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number663 index662 alt2\u0026quot;\u0026gt; 663 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number664 index663 alt1\u0026quot;\u0026gt; 664 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number665 index664 alt2\u0026quot;\u0026gt; 665 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number666 index665 alt1\u0026quot;\u0026gt; 666 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number667 index666 alt2\u0026quot;\u0026gt; 667 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number668 index667 alt1\u0026quot;\u0026gt; 668 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number669 index668 alt2\u0026quot;\u0026gt; 669 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number670 index669 alt1\u0026quot;\u0026gt; 670 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number671 index670 alt2\u0026quot;\u0026gt; 671 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number672 index671 alt1\u0026quot;\u0026gt; 672 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number673 index672 alt2\u0026quot;\u0026gt; 673 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number674 index673 alt1\u0026quot;\u0026gt; 674 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number675 index674 alt2\u0026quot;\u0026gt; 675 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number676 index675 alt1\u0026quot;\u0026gt; 676 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number677 index676 alt2\u0026quot;\u0026gt; 677 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number678 index677 alt1\u0026quot;\u0026gt; 678 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number679 index678 alt2\u0026quot;\u0026gt; 679 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number680 index679 alt1\u0026quot;\u0026gt; 680 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number681 index680 alt2\u0026quot;\u0026gt; 681 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number682 index681 alt1\u0026quot;\u0026gt; 682 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number683 index682 alt2\u0026quot;\u0026gt; 683 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number684 index683 alt1\u0026quot;\u0026gt; 684 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number685 index684 alt2\u0026quot;\u0026gt; 685 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number686 index685 alt1\u0026quot;\u0026gt; 686 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number687 index686 alt2\u0026quot;\u0026gt; 687 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number688 index687 alt1\u0026quot;\u0026gt; 688 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number689 index688 alt2\u0026quot;\u0026gt; 689 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number690 index689 alt1\u0026quot;\u0026gt; 690 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number691 index690 alt2\u0026quot;\u0026gt; 691 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number692 index691 alt1\u0026quot;\u0026gt; 692 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number693 index692 alt2\u0026quot;\u0026gt; 693 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number694 index693 alt1\u0026quot;\u0026gt; 694 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number695 index694 alt2\u0026quot;\u0026gt; 695 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number696 index695 alt1\u0026quot;\u0026gt; 696 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number697 index696 alt2\u0026quot;\u0026gt; 697 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number698 index697 alt1\u0026quot;\u0026gt; 698 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number699 index698 alt2\u0026quot;\u0026gt; 699 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number700 index699 alt1\u0026quot;\u0026gt; 700 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number701 index700 alt2\u0026quot;\u0026gt; 701 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number702 index701 alt1\u0026quot;\u0026gt; 702 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number703 index702 alt2\u0026quot;\u0026gt; 703 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number704 index703 alt1\u0026quot;\u0026gt; 704 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number705 index704 alt2\u0026quot;\u0026gt; 705 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number706 index705 alt1\u0026quot;\u0026gt; 706 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number707 index706 alt2\u0026quot;\u0026gt; 707 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number708 index707 alt1\u0026quot;\u0026gt; 708 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number709 index708 alt2\u0026quot;\u0026gt; 709 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number710 index709 alt1\u0026quot;\u0026gt; 710 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number711 index710 alt2\u0026quot;\u0026gt; 711 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number712 index711 alt1\u0026quot;\u0026gt; 712 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number713 index712 alt2\u0026quot;\u0026gt; 713 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number714 index713 alt1\u0026quot;\u0026gt; 714 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number715 index714 alt2\u0026quot;\u0026gt; 715 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number716 index715 alt1\u0026quot;\u0026gt; 716 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number717 index716 alt2\u0026quot;\u0026gt; 717 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number718 index717 alt1\u0026quot;\u0026gt; 718 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number719 index718 alt2\u0026quot;\u0026gt; 719 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number720 index719 alt1\u0026quot;\u0026gt; 720 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number721 index720 alt2\u0026quot;\u0026gt; 721 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number722 index721 alt1\u0026quot;\u0026gt; 722 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number723 index722 alt2\u0026quot;\u0026gt; 723 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number724 index723 alt1\u0026quot;\u0026gt; 724 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number725 index724 alt2\u0026quot;\u0026gt; 725 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number726 index725 alt1\u0026quot;\u0026gt; 726 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number727 index726 alt2\u0026quot;\u0026gt; 727 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number728 index727 alt1\u0026quot;\u0026gt; 728 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number729 index728 alt2\u0026quot;\u0026gt; 729 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number730 index729 alt1\u0026quot;\u0026gt; 730 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number731 index730 alt2\u0026quot;\u0026gt; 731 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number732 index731 alt1\u0026quot;\u0026gt; 732 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number733 index732 alt2\u0026quot;\u0026gt; 733 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number734 index733 alt1\u0026quot;\u0026gt; 734 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number735 index734 alt2\u0026quot;\u0026gt; 735 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number736 index735 alt1\u0026quot;\u0026gt; 736 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number737 index736 alt2\u0026quot;\u0026gt; 737 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number738 index737 alt1\u0026quot;\u0026gt; 738 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number739 index738 alt2\u0026quot;\u0026gt; 739 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number740 index739 alt1\u0026quot;\u0026gt; 740 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number741 index740 alt2\u0026quot;\u0026gt; 741 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number742 index741 alt1\u0026quot;\u0026gt; 742 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number743 index742 alt2\u0026quot;\u0026gt; 743 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number744 index743 alt1\u0026quot;\u0026gt; 744 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number745 index744 alt2\u0026quot;\u0026gt; 745 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number746 index745 alt1\u0026quot;\u0026gt; 746 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number747 index746 alt2\u0026quot;\u0026gt; 747 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number748 index747 alt1\u0026quot;\u0026gt; 748 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number749 index748 alt2\u0026quot;\u0026gt; 749 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number750 index749 alt1\u0026quot;\u0026gt; 750 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number751 index750 alt2\u0026quot;\u0026gt; 751 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number752 index751 alt1\u0026quot;\u0026gt; 752 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number753 index752 alt2\u0026quot;\u0026gt; 753 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number754 index753 alt1\u0026quot;\u0026gt; 754 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number755 index754 alt2\u0026quot;\u0026gt; 755 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number756 index755 alt1\u0026quot;\u0026gt; 756 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number757 index756 alt2\u0026quot;\u0026gt; 757 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number758 index757 alt1\u0026quot;\u0026gt; 758 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number759 index758 alt2\u0026quot;\u0026gt; 759 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number760 index759 alt1\u0026quot;\u0026gt; 760 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number761 index760 alt2\u0026quot;\u0026gt; 761 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number762 index761 alt1\u0026quot;\u0026gt; 762 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number763 index762 alt2\u0026quot;\u0026gt; 763 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number764 index763 alt1\u0026quot;\u0026gt; 764 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number765 index764 alt2\u0026quot;\u0026gt; 765 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number766 index765 alt1\u0026quot;\u0026gt; 766 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number767 index766 alt2\u0026quot;\u0026gt; 767 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number768 index767 alt1\u0026quot;\u0026gt; 768 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number769 index768 alt2\u0026quot;\u0026gt; 769 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number770 index769 alt1\u0026quot;\u0026gt; 770 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number771 index770 alt2\u0026quot;\u0026gt; 771 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number772 index771 alt1\u0026quot;\u0026gt; 772 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number773 index772 alt2\u0026quot;\u0026gt; 773 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number774 index773 alt1\u0026quot;\u0026gt; 774 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number775 index774 alt2\u0026quot;\u0026gt; 775 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number776 index775 alt1\u0026quot;\u0026gt; 776 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number777 index776 alt2\u0026quot;\u0026gt; 777 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number778 index777 alt1\u0026quot;\u0026gt; 778 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number779 index778 alt2\u0026quot;\u0026gt; 779 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number780 index779 alt1\u0026quot;\u0026gt; 780 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number781 index780 alt2\u0026quot;\u0026gt; 781 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number782 index781 alt1\u0026quot;\u0026gt; 782 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number783 index782 alt2\u0026quot;\u0026gt; 783 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number784 index783 alt1\u0026quot;\u0026gt; 784 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number785 index784 alt2\u0026quot;\u0026gt; 785 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number786 index785 alt1\u0026quot;\u0026gt; 786 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number787 index786 alt2\u0026quot;\u0026gt; 787 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number788 index787 alt1\u0026quot;\u0026gt; 788 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number789 index788 alt2\u0026quot;\u0026gt; 789 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number790 index789 alt1\u0026quot;\u0026gt; 790 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number791 index790 alt2\u0026quot;\u0026gt; 791 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number792 index791 alt1\u0026quot;\u0026gt; 792 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number793 index792 alt2\u0026quot;\u0026gt; 793 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number794 index793 alt1\u0026quot;\u0026gt; 794 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number795 index794 alt2\u0026quot;\u0026gt; 795 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number796 index795 alt1\u0026quot;\u0026gt; 796 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number797 index796 alt2\u0026quot;\u0026gt; 797 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number798 index797 alt1\u0026quot;\u0026gt; 798 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number799 index798 alt2\u0026quot;\u0026gt; 799 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number800 index799 alt1\u0026quot;\u0026gt; 800 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number801 index800 alt2\u0026quot;\u0026gt; 801 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number802 index801 alt1\u0026quot;\u0026gt; 802 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number803 index802 alt2\u0026quot;\u0026gt; 803 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number804 index803 alt1\u0026quot;\u0026gt; 804 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number805 index804 alt2\u0026quot;\u0026gt; 805 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number806 index805 alt1\u0026quot;\u0026gt; 806 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number807 index806 alt2\u0026quot;\u0026gt; 807 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number808 index807 alt1\u0026quot;\u0026gt; 808 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number809 index808 alt2\u0026quot;\u0026gt; 809 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number810 index809 alt1\u0026quot;\u0026gt; 810 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number811 index810 alt2\u0026quot;\u0026gt; 811 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number812 index811 alt1\u0026quot;\u0026gt; 812 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number813 index812 alt2\u0026quot;\u0026gt; 813 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number814 index813 alt1\u0026quot;\u0026gt; 814 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number815 index814 alt2\u0026quot;\u0026gt; 815 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number816 index815 alt1\u0026quot;\u0026gt; 816 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number817 index816 alt2\u0026quot;\u0026gt; 817 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number818 index817 alt1\u0026quot;\u0026gt; 818 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number819 index818 alt2\u0026quot;\u0026gt; 819 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number820 index819 alt1\u0026quot;\u0026gt; 820 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number821 index820 alt2\u0026quot;\u0026gt; 821 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number822 index821 alt1\u0026quot;\u0026gt; 822 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number823 index822 alt2\u0026quot;\u0026gt; 823 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number824 index823 alt1\u0026quot;\u0026gt; 824 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number825 index824 alt2\u0026quot;\u0026gt; 825 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number826 index825 alt1\u0026quot;\u0026gt; 826 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number827 index826 alt2\u0026quot;\u0026gt; 827 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number828 index827 alt1\u0026quot;\u0026gt; 828 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number829 index828 alt2\u0026quot;\u0026gt; 829 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number830 index829 alt1\u0026quot;\u0026gt; 830 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number831 index830 alt2\u0026quot;\u0026gt; 831 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number832 index831 alt1\u0026quot;\u0026gt; 832 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number833 index832 alt2\u0026quot;\u0026gt; 833 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number834 index833 alt1\u0026quot;\u0026gt; 834 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number835 index834 alt2\u0026quot;\u0026gt; 835 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number836 index835 alt1\u0026quot;\u0026gt; 836 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number837 index836 alt2\u0026quot;\u0026gt; 837 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number838 index837 alt1\u0026quot;\u0026gt; 838 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number839 index838 alt2\u0026quot;\u0026gt; 839 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number840 index839 alt1\u0026quot;\u0026gt; 840 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number841 index840 alt2\u0026quot;\u0026gt; 841 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number842 index841 alt1\u0026quot;\u0026gt; 842 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number843 index842 alt2\u0026quot;\u0026gt; 843 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number844 index843 alt1\u0026quot;\u0026gt; 844 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number845 index844 alt2\u0026quot;\u0026gt; 845 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number846 index845 alt1\u0026quot;\u0026gt; 846 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number847 index846 alt2\u0026quot;\u0026gt; 847 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number848 index847 alt1\u0026quot;\u0026gt; 848 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number849 index848 alt2\u0026quot;\u0026gt; 849 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number850 index849 alt1\u0026quot;\u0026gt; 850 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number851 index850 alt2\u0026quot;\u0026gt; 851 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number852 index851 alt1\u0026quot;\u0026gt; 852 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number853 index852 alt2\u0026quot;\u0026gt; 853 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number854 index853 alt1\u0026quot;\u0026gt; 854 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number855 index854 alt2\u0026quot;\u0026gt; 855 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number856 index855 alt1\u0026quot;\u0026gt; 856 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number857 index856 alt2\u0026quot;\u0026gt; 857 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number858 index857 alt1\u0026quot;\u0026gt; 858 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number859 index858 alt2\u0026quot;\u0026gt; 859 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number860 index859 alt1\u0026quot;\u0026gt; 860 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number861 index860 alt2\u0026quot;\u0026gt; 861 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number862 index861 alt1\u0026quot;\u0026gt; 862 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number863 index862 alt2\u0026quot;\u0026gt; 863 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number864 index863 alt1\u0026quot;\u0026gt; 864 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number865 index864 alt2\u0026quot;\u0026gt; 865 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number866 index865 alt1\u0026quot;\u0026gt; 866 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number867 index866 alt2\u0026quot;\u0026gt; 867 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number868 index867 alt1\u0026quot;\u0026gt; 868 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number869 index868 alt2\u0026quot;\u0026gt; 869 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number870 index869 alt1\u0026quot;\u0026gt; 870 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number871 index870 alt2\u0026quot;\u0026gt; 871 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number872 index871 alt1\u0026quot;\u0026gt; 872 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number873 index872 alt2\u0026quot;\u0026gt; 873 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number874 index873 alt1\u0026quot;\u0026gt; 874 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number875 index874 alt2\u0026quot;\u0026gt; 875 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number876 index875 alt1\u0026quot;\u0026gt; 876 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number877 index876 alt2\u0026quot;\u0026gt; 877 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number878 index877 alt1\u0026quot;\u0026gt; 878 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number879 index878 alt2\u0026quot;\u0026gt; 879 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number880 index879 alt1\u0026quot;\u0026gt; 880 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number881 index880 alt2\u0026quot;\u0026gt; 881 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number882 index881 alt1\u0026quot;\u0026gt; 882 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number883 index882 alt2\u0026quot;\u0026gt; 883 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number884 index883 alt1\u0026quot;\u0026gt; 884 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number885 index884 alt2\u0026quot;\u0026gt; 885 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number886 index885 alt1\u0026quot;\u0026gt; 886 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number887 index886 alt2\u0026quot;\u0026gt; 887 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number888 index887 alt1\u0026quot;\u0026gt; 888 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number889 index888 alt2\u0026quot;\u0026gt; 889 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number890 index889 alt1\u0026quot;\u0026gt; 890 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number891 index890 alt2\u0026quot;\u0026gt; 891 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number892 index891 alt1\u0026quot;\u0026gt; 892 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number893 index892 alt2\u0026quot;\u0026gt; 893 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number894 index893 alt1\u0026quot;\u0026gt; 894 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number895 index894 alt2\u0026quot;\u0026gt; 895 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number896 index895 alt1\u0026quot;\u0026gt; 896 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number897 index896 alt2\u0026quot;\u0026gt; 897 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number898 index897 alt1\u0026quot;\u0026gt; 898 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number899 index898 alt2\u0026quot;\u0026gt; 899 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number900 index899 alt1\u0026quot;\u0026gt; 900 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number901 index900 alt2\u0026quot;\u0026gt; 901 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number902 index901 alt1\u0026quot;\u0026gt; 902 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number903 index902 alt2\u0026quot;\u0026gt; 903 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number904 index903 alt1\u0026quot;\u0026gt; 904 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number905 index904 alt2\u0026quot;\u0026gt; 905 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number906 index905 alt1\u0026quot;\u0026gt; 906 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number907 index906 alt2\u0026quot;\u0026gt; 907 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number908 index907 alt1\u0026quot;\u0026gt; 908 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number909 index908 alt2\u0026quot;\u0026gt; 909 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number910 index909 alt1\u0026quot;\u0026gt; 910 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number911 index910 alt2\u0026quot;\u0026gt; 911 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number912 index911 alt1\u0026quot;\u0026gt; 912 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number913 index912 alt2\u0026quot;\u0026gt; 913 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number914 index913 alt1\u0026quot;\u0026gt; 914 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number915 index914 alt2\u0026quot;\u0026gt; 915 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number916 index915 alt1\u0026quot;\u0026gt; 916 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number917 index916 alt2\u0026quot;\u0026gt; 917 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number918 index917 alt1\u0026quot;\u0026gt; 918 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number919 index918 alt2\u0026quot;\u0026gt; 919 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number920 index919 alt1\u0026quot;\u0026gt; 920 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number921 index920 alt2\u0026quot;\u0026gt; 921 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number922 index921 alt1\u0026quot;\u0026gt; 922 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number923 index922 alt2\u0026quot;\u0026gt; 923 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number924 index923 alt1\u0026quot;\u0026gt; 924 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number925 index924 alt2\u0026quot;\u0026gt; 925 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number926 index925 alt1\u0026quot;\u0026gt; 926 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number927 index926 alt2\u0026quot;\u0026gt; 927 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number928 index927 alt1\u0026quot;\u0026gt; 928 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number929 index928 alt2\u0026quot;\u0026gt; 929 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number930 index929 alt1\u0026quot;\u0026gt; 930 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number931 index930 alt2\u0026quot;\u0026gt; 931 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number932 index931 alt1\u0026quot;\u0026gt; 932 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number933 index932 alt2\u0026quot;\u0026gt; 933 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number934 index933 alt1\u0026quot;\u0026gt; 934 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number935 index934 alt2\u0026quot;\u0026gt; 935 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number936 index935 alt1\u0026quot;\u0026gt; 936 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number937 index936 alt2\u0026quot;\u0026gt; 937 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number938 index937 alt1\u0026quot;\u0026gt; 938 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number939 index938 alt2\u0026quot;\u0026gt; 939 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number940 index939 alt1\u0026quot;\u0026gt; 940 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number941 index940 alt2\u0026quot;\u0026gt; 941 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number942 index941 alt1\u0026quot;\u0026gt; 942 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number943 index942 alt2\u0026quot;\u0026gt; 943 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number944 index943 alt1\u0026quot;\u0026gt; 944 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number945 index944 alt2\u0026quot;\u0026gt; 945 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number946 index945 alt1\u0026quot;\u0026gt; 946 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number947 index946 alt2\u0026quot;\u0026gt; 947 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number948 index947 alt1\u0026quot;\u0026gt; 948 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number949 index948 alt2\u0026quot;\u0026gt; 949 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number950 index949 alt1\u0026quot;\u0026gt; 950 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number951 index950 alt2\u0026quot;\u0026gt; 951 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number952 index951 alt1\u0026quot;\u0026gt; 952 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number953 index952 alt2\u0026quot;\u0026gt; 953 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number954 index953 alt1\u0026quot;\u0026gt; 954 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number955 index954 alt2\u0026quot;\u0026gt; 955 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number956 index955 alt1\u0026quot;\u0026gt; 956 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number957 index956 alt2\u0026quot;\u0026gt; 957 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number958 index957 alt1\u0026quot;\u0026gt; 958 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number959 index958 alt2\u0026quot;\u0026gt; 959 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number960 index959 alt1\u0026quot;\u0026gt; 960 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number961 index960 alt2\u0026quot;\u0026gt; 961 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number962 index961 alt1\u0026quot;\u0026gt; 962 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number963 index962 alt2\u0026quot;\u0026gt; 963 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number964 index963 alt1\u0026quot;\u0026gt; 964 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number965 index964 alt2\u0026quot;\u0026gt; 965 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number966 index965 alt1\u0026quot;\u0026gt; 966 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number967 index966 alt2\u0026quot;\u0026gt; 967 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number968 index967 alt1\u0026quot;\u0026gt; 968 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number969 index968 alt2\u0026quot;\u0026gt; 969 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number970 index969 alt1\u0026quot;\u0026gt; 970 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number971 index970 alt2\u0026quot;\u0026gt; 971 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number972 index971 alt1\u0026quot;\u0026gt; 972 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number973 index972 alt2\u0026quot;\u0026gt; 973 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number974 index973 alt1\u0026quot;\u0026gt; 974 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number975 index974 alt2\u0026quot;\u0026gt; 975 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number976 index975 alt1\u0026quot;\u0026gt; 976 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number977 index976 alt2\u0026quot;\u0026gt; 977 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number978 index977 alt1\u0026quot;\u0026gt; 978 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number979 index978 alt2\u0026quot;\u0026gt; 979 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number980 index979 alt1\u0026quot;\u0026gt; 980 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number981 index980 alt2\u0026quot;\u0026gt; 981 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number982 index981 alt1\u0026quot;\u0026gt; 982 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number983 index982 alt2\u0026quot;\u0026gt; 983 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number984 index983 alt1\u0026quot;\u0026gt; 984 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number985 index984 alt2\u0026quot;\u0026gt; 985 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number986 index985 alt1\u0026quot;\u0026gt; 986 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number987 index986 alt2\u0026quot;\u0026gt; 987 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number988 index987 alt1\u0026quot;\u0026gt; 988 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number989 index988 alt2\u0026quot;\u0026gt; 989 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number990 index989 alt1\u0026quot;\u0026gt; 990 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number991 index990 alt2\u0026quot;\u0026gt; 991 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `CustomViewAbove ``extends` `ViewGroup {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``private` `static` `final` `String TAG = ``\u0026quot;CustomViewAbove\u0026quot;``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``private` `static` `final` `boolean` `DEBUG = ``false``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``private` `static` `final` `boolean` `USE_CACHE = ``false``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``private` `static` `final` `int` `MAX_SETTLE_DURATION = ``600``; ``// ms` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``private` `static` `final` `int` `MIN_DISTANCE_FOR_FLING = ``25``; ``// dips` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``private` `static` `final` `Interpolator sInterpolator = ``new` `Interpolator() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``public` `float` `getInterpolation(``float` `t) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``t -= ``1``.0f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``return` `t * t * t * t * t + ``1``.0f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``};` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``private` `View mContent;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``private` `int` `mCurItem;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``private` `Scroller mScroller;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``private` `boolean` `mScrollingCacheEnabled;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``private` `boolean` `mScrolling;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``private` `boolean` `mIsBeingDragged;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ``private` `boolean` `mIsUnableToDrag;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``private` `int` `mTouchSlop;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ``private` `float` `mInitialMotionX;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ``* Position of the last motion event.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ``private` `float` `mLastMotionX;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``private` `float` `mLastMotionY;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; ` ``* ID of the active pointer. This is used to retain consistency during` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; ` ``* drags/flings if multiple pointers are used.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; ` ``protected` `int` `mActivePointerId = INVALID_POINTER;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; ` ``* Sentinel value for no current active pointer.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; ` ``* Used by {@link #mActivePointerId}.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; ` ``private` `static` `final` `int` `INVALID_POINTER = -``1``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; ` ``/** 保存转场动画的变量*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; ` ``private` `CanvasTransformer mTransformer;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; ` ``* Determines speed during touch scrolling` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; ` ``protected` `VelocityTracker mVelocityTracker;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; ` ``private` `int` `mMinimumVelocity;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; ` ``protected` `int` `mMaximumVelocity;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; ` ``private` `int` `mFlingDistance;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; ` ``private` `CustomViewBehind mViewBehind;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; ` ``// private int mMode;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; ` ``private` `boolean` `mEnabled = ``true``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; ` ``private` `OnPageChangeListener mOnPageChangeListener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; ` ``private` `OnPageChangeListener mInternalPageChangeListener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; ` ``// private OnCloseListener mCloseListener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; ` ``// private OnOpenListener mOpenListener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; ` ``private` `OnClosedListener mClosedListener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; ` ``private` `OnOpenedListener mOpenedListener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; ` ``private` `List\u0026amp;lt;View\u0026amp;gt; mIgnoredViews = ``new` `ArrayList\u0026amp;lt;View\u0026amp;gt;();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; ` ``// private int mScrollState = SCROLL_STATE_IDLE;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; ` ``* Callback interface for responding to changing state of the selected page.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; ` ``public` `interface` `OnPageChangeListener {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; ` ``* This method will be invoked when the current page is scrolled, either as part` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; ` ``* of a programmatically initiated smooth scroll or a user initiated touch scroll.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; ` ``* @param position Position index of the first page currently being displayed.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; ` ``* Page position+1 will be visible if positionOffset is nonzero.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; ` ``* @param positionOffset Value from [0, 1) indicating the offset from the page at position.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; ` ``* @param positionOffsetPixels Value in pixels indicating the offset from position.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; ` ``public` `void` `onPageScrolled(``int` `position, ``float` `positionOffset, ``int` `positionOffsetPixels);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; ` ``* This method will be invoked when a new page becomes selected. Animation is not` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; ` ``* necessarily complete.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt; ` ``* @param position Position index of the new selected page.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt; ` ``public` `void` `onPageSelected(``int` `position);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt; ` ``* Simple implementation of the {@link OnPageChangeListener} interface with stub` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number101 index100 alt2\u0026quot;\u0026gt; ` ``* implementations of each method. Extend this if you do not intend to override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number102 index101 alt1\u0026quot;\u0026gt; ` ``* every method of {@link OnPageChangeListener}.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number103 index102 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number104 index103 alt1\u0026quot;\u0026gt; ` ``public` `static` `class` `SimpleOnPageChangeListener ``implements` `OnPageChangeListener {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number105 index104 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number106 index105 alt1\u0026quot;\u0026gt; ` ``public` `void` `onPageScrolled(``int` `position, ``float` `positionOffset, ``int` `positionOffsetPixels) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number107 index106 alt2\u0026quot;\u0026gt; ` ``// This space for rent` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number108 index107 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number109 index108 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number110 index109 alt1\u0026quot;\u0026gt; ` ``public` `void` `onPageSelected(``int` `position) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number111 index110 alt2\u0026quot;\u0026gt; ` ``// This space for rent` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number112 index111 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number113 index112 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number114 index113 alt1\u0026quot;\u0026gt; ` ``public` `void` `onPageScrollStateChanged(``int` `state) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number115 index114 alt2\u0026quot;\u0026gt; ` ``// This space for rent` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number116 index115 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number117 index116 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number118 index117 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number119 index118 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number120 index119 alt1\u0026quot;\u0026gt; ` ``public` `CustomViewAbove(Context context) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number121 index120 alt2\u0026quot;\u0026gt; ` ``this``(context, ``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number122 index121 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number123 index122 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number124 index123 alt1\u0026quot;\u0026gt; ` ``public` `CustomViewAbove(Context context, AttributeSet attrs) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number125 index124 alt2\u0026quot;\u0026gt; ` ``super``(context, attrs);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number126 index125 alt1\u0026quot;\u0026gt; ` ``initCustomViewAbove();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number127 index126 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number128 index127 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number129 index128 alt2\u0026quot;\u0026gt; ` ``void` `initCustomViewAbove() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number130 index129 alt1\u0026quot;\u0026gt; ` ``setWillNotDraw(``false``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number131 index130 alt2\u0026quot;\u0026gt; ` ``setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number132 index131 alt1\u0026quot;\u0026gt; ` ``setFocusable(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number133 index132 alt2\u0026quot;\u0026gt; ` ``final` `Context context = getContext();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number134 index133 alt1\u0026quot;\u0026gt; ` ``mScroller = ``new` `Scroller(context, sInterpolator);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number135 index134 alt2\u0026quot;\u0026gt; ` ``final` `ViewConfiguration configuration = ViewConfiguration.get(context);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number136 index135 alt1\u0026quot;\u0026gt; ` ``mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number137 index136 alt2\u0026quot;\u0026gt; ` ``mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number138 index137 alt1\u0026quot;\u0026gt; ` ``mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number139 index138 alt2\u0026quot;\u0026gt; ` ``setInternalPageChangeListener(``new` `SimpleOnPageChangeListener() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number140 index139 alt1\u0026quot;\u0026gt; ` ``public` `void` `onPageSelected(``int` `position) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number141 index140 alt2\u0026quot;\u0026gt; ` ``if` `(mViewBehind != ``null``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number142 index141 alt1\u0026quot;\u0026gt; ` ``switch` `(position) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number143 index142 alt2\u0026quot;\u0026gt; ` ``case` ```:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number144 index143 alt1\u0026quot;\u0026gt; ` ``case` `2``:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number145 index144 alt2\u0026quot;\u0026gt; ` ``mViewBehind.setChildrenEnabled(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number146 index145 alt1\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number147 index146 alt2\u0026quot;\u0026gt; ` ``case` `1``:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number148 index147 alt1\u0026quot;\u0026gt; ` ``mViewBehind.setChildrenEnabled(``false``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number149 index148 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number150 index149 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number151 index150 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number152 index151 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number153 index152 alt2\u0026quot;\u0026gt; ` ``});` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number154 index153 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number155 index154 alt2\u0026quot;\u0026gt; ` ``final` `float` `density = context.getResources().getDisplayMetrics().density;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number156 index155 alt1\u0026quot;\u0026gt; ` ``mFlingDistance = (``int``) (MIN_DISTANCE_FOR_FLING * density);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number157 index156 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number158 index157 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number159 index158 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number160 index159 alt1\u0026quot;\u0026gt; ` ``* Set the currently selected page. If the CustomViewPager has already been through its first` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number161 index160 alt2\u0026quot;\u0026gt; ` ``* layout there will be a smooth animated transition between the current item and the` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number162 index161 alt1\u0026quot;\u0026gt; ` ``* specified item.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number163 index162 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number164 index163 alt1\u0026quot;\u0026gt; ` ``* @param item Item index to select` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number165 index164 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number166 index165 alt1\u0026quot;\u0026gt; ` ``public` `void` `setCurrentItem(``int` `item) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number167 index166 alt2\u0026quot;\u0026gt; ` ``setCurrentItemInternal(item, ``true``, ``false``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number168 index167 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number169 index168 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number170 index169 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number171 index170 alt2\u0026quot;\u0026gt; ` ``* Set the currently selected page.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number172 index171 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number173 index172 alt2\u0026quot;\u0026gt; ` ``* @param item Item index to select` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number174 index173 alt1\u0026quot;\u0026gt; ` ``* @param smoothScroll True to smoothly scroll to the new item, false to transition immediately` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number175 index174 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number176 index175 alt1\u0026quot;\u0026gt; ` ``public` `void` `setCurrentItem(``int` `item, ``boolean` `smoothScroll) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number177 index176 alt2\u0026quot;\u0026gt; ` ``setCurrentItemInternal(item, smoothScroll, ``false``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number178 index177 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number179 index178 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number180 index179 alt1\u0026quot;\u0026gt; ` ``public` `int` `getCurrentItem() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number181 index180 alt2\u0026quot;\u0026gt; ` ``return` `mCurItem;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number182 index181 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number183 index182 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number184 index183 alt1\u0026quot;\u0026gt; ` ``void` `setCurrentItemInternal(``int` `item, ``boolean` `smoothScroll, ``boolean` `always) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number185 index184 alt2\u0026quot;\u0026gt; ` ``setCurrentItemInternal(item, smoothScroll, always, ````);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number186 index185 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number187 index186 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number188 index187 alt1\u0026quot;\u0026gt; ` ``void` `setCurrentItemInternal(``int` `item, ``boolean` `smoothScroll, ``boolean` `always, ``int` `velocity) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number189 index188 alt2\u0026quot;\u0026gt; ` ``if` `(!always \u0026amp;\u0026amp; mCurItem == item) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number190 index189 alt1\u0026quot;\u0026gt; ` ``setScrollingCacheEnabled(``false``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number191 index190 alt2\u0026quot;\u0026gt; ` ``return``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number192 index191 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number193 index192 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number194 index193 alt1\u0026quot;\u0026gt; ` ``item = mViewBehind.getMenuPage(item);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number195 index194 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number196 index195 alt1\u0026quot;\u0026gt; ` ``final` `boolean` `dispatchSelected = mCurItem != item;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number197 index196 alt2\u0026quot;\u0026gt; ` ``mCurItem = item;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number198 index197 alt1\u0026quot;\u0026gt; ` ``final` `int` `destX = getDestScrollX(mCurItem);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number199 index198 alt2\u0026quot;\u0026gt; ` ``if` `(dispatchSelected \u0026amp;\u0026amp; mOnPageChangeListener != ``null``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number200 index199 alt1\u0026quot;\u0026gt; ` ``mOnPageChangeListener.onPageSelected(item);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number201 index200 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number202 index201 alt1\u0026quot;\u0026gt; ` ``if` `(dispatchSelected \u0026amp;\u0026amp; mInternalPageChangeListener != ``null``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number203 index202 alt2\u0026quot;\u0026gt; ` ``mInternalPageChangeListener.onPageSelected(item);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number204 index203 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number205 index204 alt2\u0026quot;\u0026gt; ` ``if` `(smoothScroll) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number206 index205 alt1\u0026quot;\u0026gt; ` ``smoothScrollTo(destX, ````, velocity);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number207 index206 alt2\u0026quot;\u0026gt; ` ``} ``else` `{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number208 index207 alt1\u0026quot;\u0026gt; ` ``completeScroll();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number209 index208 alt2\u0026quot;\u0026gt; ` ``scrollTo(destX, ````);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number210 index209 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number211 index210 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number212 index211 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number213 index212 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number214 index213 alt1\u0026quot;\u0026gt; ` ``* Set a listener that will be invoked whenever the page changes or is incrementally` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number215 index214 alt2\u0026quot;\u0026gt; ` ``* scrolled. See {@link OnPageChangeListener}.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number216 index215 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number217 index216 alt2\u0026quot;\u0026gt; ` ``* @param listener Listener to set` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number218 index217 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number219 index218 alt2\u0026quot;\u0026gt; ` ``public` `void` `setOnPageChangeListener(OnPageChangeListener listener) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number220 index219 alt1\u0026quot;\u0026gt; ` ``mOnPageChangeListener = listener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number221 index220 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number222 index221 alt1\u0026quot;\u0026gt; ` ``/*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number223 index222 alt2\u0026quot;\u0026gt; ` ``public void setOnOpenListener(OnOpenListener l) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number224 index223 alt1\u0026quot;\u0026gt; ` ``mOpenListener = l;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number225 index224 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number226 index225 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number227 index226 alt2\u0026quot;\u0026gt; ` ``public void setOnCloseListener(OnCloseListener l) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number228 index227 alt1\u0026quot;\u0026gt; ` ``mCloseListener = l;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number229 index228 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number230 index229 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number231 index230 alt2\u0026quot;\u0026gt; ` ``public void setOnOpenedListener(OnOpenedListener l) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number232 index231 alt1\u0026quot;\u0026gt; ` ``mOpenedListener = l;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number233 index232 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number234 index233 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number235 index234 alt2\u0026quot;\u0026gt; ` ``public void setOnClosedListener(OnClosedListener l) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number236 index235 alt1\u0026quot;\u0026gt; ` ``mClosedListener = l;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number237 index236 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number238 index237 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number239 index238 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number240 index239 alt1\u0026quot;\u0026gt; ` ``* Set a separate OnPageChangeListener for internal use by the support library.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number241 index240 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number242 index241 alt1\u0026quot;\u0026gt; ` ``* @param listener Listener to set` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number243 index242 alt2\u0026quot;\u0026gt; ` ``* @return The old listener that was set, if any.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number244 index243 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number245 index244 alt2\u0026quot;\u0026gt; ` ``OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number246 index245 alt1\u0026quot;\u0026gt; ` ``OnPageChangeListener oldListener = mInternalPageChangeListener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number247 index246 alt2\u0026quot;\u0026gt; ` ``mInternalPageChangeListener = listener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number248 index247 alt1\u0026quot;\u0026gt; ` ``return oldListener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number249 index248 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number250 index249 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number251 index250 alt2\u0026quot;\u0026gt; ` ``public void addIgnoredView(View v) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number252 index251 alt1\u0026quot;\u0026gt; ` ``if (!mIgnoredViews.contains(v)) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number253 index252 alt2\u0026quot;\u0026gt; ` ``mIgnoredViews.add(v);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number254 index253 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number255 index254 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number256 index255 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number257 index256 alt2\u0026quot;\u0026gt; ` ``public void removeIgnoredView(View v) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number258 index257 alt1\u0026quot;\u0026gt; ` ``mIgnoredViews.remove(v);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number259 index258 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number260 index259 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number261 index260 alt2\u0026quot;\u0026gt; ` ``public void clearIgnoredViews() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number262 index261 alt1\u0026quot;\u0026gt; ` ``mIgnoredViews.clear();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number263 index262 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number264 index263 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number265 index264 alt2\u0026quot;\u0026gt; ` ``// We want the duration of the page snap animation to be influenced by the distance that` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number266 index265 alt1\u0026quot;\u0026gt; ` ``// the screen has to travel, however, we don't want this duration to be effected in a` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number267 index266 alt2\u0026quot;\u0026gt; ` ``// purely linear fashion. Instead, we use this method to moderate the effect that the distance` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number268 index267 alt1\u0026quot;\u0026gt; ` ``// of travel has on the overall snap duration.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number269 index268 alt2\u0026quot;\u0026gt; ` ``float distanceInfluenceForSnapDuration(float f) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number270 index269 alt1\u0026quot;\u0026gt; ` ``f -= 0.5f; // center the values about 0.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number271 index270 alt2\u0026quot;\u0026gt; ` ``f *= 0.3f * Math.PI / 2.0f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number272 index271 alt1\u0026quot;\u0026gt; ` ``return (float) FloatMath.sin(f);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number273 index272 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number274 index273 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number275 index274 alt2\u0026quot;\u0026gt; ` ``public int getDestScrollX(int page) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number276 index275 alt1\u0026quot;\u0026gt; ` ``switch (page) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number277 index276 alt2\u0026quot;\u0026gt; ` ``case 0:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number278 index277 alt1\u0026quot;\u0026gt; ` ``case 2:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number279 index278 alt2\u0026quot;\u0026gt; ` ``return mViewBehind.getMenuLeft(mContent, page);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number280 index279 alt1\u0026quot;\u0026gt; ` ``case 1:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number281 index280 alt2\u0026quot;\u0026gt; ` ``return mContent.getLeft();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number282 index281 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number283 index282 alt2\u0026quot;\u0026gt; ` ``return 0;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number284 index283 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number285 index284 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number286 index285 alt1\u0026quot;\u0026gt; ` ``private int getLeftBound() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number287 index286 alt2\u0026quot;\u0026gt; ` ``return mViewBehind.getAbsLeftBound(mContent);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number288 index287 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number289 index288 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number290 index289 alt1\u0026quot;\u0026gt; ` ``private int getRightBound() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number291 index290 alt2\u0026quot;\u0026gt; ` ``return mViewBehind.getAbsRightBound(mContent);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number292 index291 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number293 index292 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number294 index293 alt1\u0026quot;\u0026gt; ` ``public int getContentLeft() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number295 index294 alt2\u0026quot;\u0026gt; ` ``return mContent.getLeft() + mContent.getPaddingLeft();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number296 index295 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number297 index296 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number298 index297 alt1\u0026quot;\u0026gt; ` ``public boolean isMenuOpen() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number299 index298 alt2\u0026quot;\u0026gt; ` ``return mCurItem == 0 || mCurItem == 2;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number300 index299 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number301 index300 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number302 index301 alt1\u0026quot;\u0026gt; ` ``private boolean isInIgnoredView(MotionEvent ev) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number303 index302 alt2\u0026quot;\u0026gt; ` ``Rect rect = new Rect();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number304 index303 alt1\u0026quot;\u0026gt; ` ``for (View v : mIgnoredViews) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number305 index304 alt2\u0026quot;\u0026gt; ` ``v.getHitRect(rect);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number306 index305 alt1\u0026quot;\u0026gt; ` ``if (rect.contains((int)ev.getX(), (int)ev.getY())) return true;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number307 index306 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number308 index307 alt1\u0026quot;\u0026gt; ` ``return false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number309 index308 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number310 index309 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number311 index310 alt2\u0026quot;\u0026gt; ` ``public int getBehindWidth() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number312 index311 alt1\u0026quot;\u0026gt; ` ``if (mViewBehind == null) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number313 index312 alt2\u0026quot;\u0026gt; ` ``return 0;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number314 index313 alt1\u0026quot;\u0026gt; ` ``} else {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number315 index314 alt2\u0026quot;\u0026gt; ` ``return mViewBehind.getBehindWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number316 index315 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number317 index316 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number318 index317 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number319 index318 alt2\u0026quot;\u0026gt; ` ``public int getChildWidth(int i) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number320 index319 alt1\u0026quot;\u0026gt; ` ``switch (i) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number321 index320 alt2\u0026quot;\u0026gt; ` ``case 0:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number322 index321 alt1\u0026quot;\u0026gt; ` ``return getBehindWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number323 index322 alt2\u0026quot;\u0026gt; ` ``case 1:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number324 index323 alt1\u0026quot;\u0026gt; ` ``return mContent.getWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number325 index324 alt2\u0026quot;\u0026gt; ` ``default:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number326 index325 alt1\u0026quot;\u0026gt; ` ``return 0;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number327 index326 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number328 index327 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number329 index328 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number330 index329 alt1\u0026quot;\u0026gt; ` ``public boolean isSlidingEnabled() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number331 index330 alt2\u0026quot;\u0026gt; ` ``return mEnabled;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number332 index331 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number333 index332 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number334 index333 alt1\u0026quot;\u0026gt; ` ``public void setSlidingEnabled(boolean b) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number335 index334 alt2\u0026quot;\u0026gt; ` ``mEnabled = b;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number336 index335 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number337 index336 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number338 index337 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number339 index338 alt2\u0026quot;\u0026gt; ` ``* Like {@link View#scrollBy}, but scroll smoothly instead of immediately.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number340 index339 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number341 index340 alt2\u0026quot;\u0026gt; ` ``* @param x the number of pixels to scroll by on the X axis` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number342 index341 alt1\u0026quot;\u0026gt; ` ``* @param y the number of pixels to scroll by on the Y axis` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number343 index342 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number344 index343 alt1\u0026quot;\u0026gt; ` ``void smoothScrollTo(int x, int y) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number345 index344 alt2\u0026quot;\u0026gt; ` ``smoothScrollTo(x, y, 0);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number346 index345 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number347 index346 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number348 index347 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number349 index348 alt2\u0026quot;\u0026gt; ` ``* Like {@link View#scrollBy}, but scroll smoothly instead of immediately.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number350 index349 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number351 index350 alt2\u0026quot;\u0026gt; ` ``* @param x the number of pixels to scroll by on the X axis` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number352 index351 alt1\u0026quot;\u0026gt; ` ``* @param y the number of pixels to scroll by on the Y axis` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number353 index352 alt2\u0026quot;\u0026gt; ` ``* @param velocity the velocity associated with a fling, if applicable. (0 otherwise)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number354 index353 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number355 index354 alt2\u0026quot;\u0026gt; ` ``void smoothScrollTo(int x, int y, int velocity) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number356 index355 alt1\u0026quot;\u0026gt; ` ``if (getChildCount() == 0) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number357 index356 alt2\u0026quot;\u0026gt; ` ``// Nothing to do.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number358 index357 alt1\u0026quot;\u0026gt; ` ``setScrollingCacheEnabled(false);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number359 index358 alt2\u0026quot;\u0026gt; ` ``return;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number360 index359 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number361 index360 alt2\u0026quot;\u0026gt; ` ``int sx = getScrollX();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number362 index361 alt1\u0026quot;\u0026gt; ` ``int sy = getScrollY();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number363 index362 alt2\u0026quot;\u0026gt; ` ``int dx = x - sx;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number364 index363 alt1\u0026quot;\u0026gt; ` ``int dy = y - sy;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number365 index364 alt2\u0026quot;\u0026gt; ` ``if (dx == 0 \u0026amp;\u0026amp; dy == 0) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number366 index365 alt1\u0026quot;\u0026gt; ` ``completeScroll();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number367 index366 alt2\u0026quot;\u0026gt; ` ``if (isMenuOpen()) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number368 index367 alt1\u0026quot;\u0026gt; ` ``if (mOpenedListener != null)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number369 index368 alt2\u0026quot;\u0026gt; ` ``mOpenedListener.onOpened();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number370 index369 alt1\u0026quot;\u0026gt; ` ``} else {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number371 index370 alt2\u0026quot;\u0026gt; ` ``if (mClosedListener != null)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number372 index371 alt1\u0026quot;\u0026gt; ` ``mClosedListener.onClosed();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number373 index372 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number374 index373 alt1\u0026quot;\u0026gt; ` ``return;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number375 index374 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number376 index375 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number377 index376 alt2\u0026quot;\u0026gt; ` ``setScrollingCacheEnabled(true);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number378 index377 alt1\u0026quot;\u0026gt; ` ``mScrolling = true;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number379 index378 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number380 index379 alt1\u0026quot;\u0026gt; ` ``final int width = getBehindWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number381 index380 alt2\u0026quot;\u0026gt; ` ``final int halfWidth = width / 2;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number382 index381 alt1\u0026quot;\u0026gt; ` ``final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number383 index382 alt2\u0026quot;\u0026gt; ` ``final float distance = halfWidth + halfWidth *` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number384 index383 alt1\u0026quot;\u0026gt; ` ``distanceInfluenceForSnapDuration(distanceRatio);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number385 index384 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number386 index385 alt1\u0026quot;\u0026gt; ` ``int duration = 0;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number387 index386 alt2\u0026quot;\u0026gt; ` ``velocity = Math.abs(velocity);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number388 index387 alt1\u0026quot;\u0026gt; ` ``if (velocity \u0026amp;gt; 0) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number389 index388 alt2\u0026quot;\u0026gt; ` ``duration = 4 * Math.round(1000 * Math.abs(distance / velocity));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number390 index389 alt1\u0026quot;\u0026gt; ` ``} else {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number391 index390 alt2\u0026quot;\u0026gt; ` ``final float pageDelta = (float) Math.abs(dx) / width;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number392 index391 alt1\u0026quot;\u0026gt; ` ``duration = (int) ((pageDelta + 1) * 100);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number393 index392 alt2\u0026quot;\u0026gt; ` ``duration = MAX_SETTLE_DURATION;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number394 index393 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number395 index394 alt2\u0026quot;\u0026gt; ` ``duration = Math.min(duration, MAX_SETTLE_DURATION);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number396 index395 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number397 index396 alt2\u0026quot;\u0026gt; ` ``mScroller.startScroll(sx, sy, dx, dy, duration);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number398 index397 alt1\u0026quot;\u0026gt; ` ``invalidate();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number399 index398 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number400 index399 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number401 index400 alt2\u0026quot;\u0026gt; ` ``public void setContent(View v) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number402 index401 alt1\u0026quot;\u0026gt; ` ``if (mContent != null)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number403 index402 alt2\u0026quot;\u0026gt; ` ``this.removeView(mContent);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number404 index403 alt1\u0026quot;\u0026gt; ` ``mContent = v;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number405 index404 alt2\u0026quot;\u0026gt; ` ``addView(mContent);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number406 index405 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number407 index406 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number408 index407 alt1\u0026quot;\u0026gt; ` ``public View getContent() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number409 index408 alt2\u0026quot;\u0026gt; ` ``return mContent;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number410 index409 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number411 index410 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number412 index411 alt1\u0026quot;\u0026gt; ` ``public void setCustomViewBehind(CustomViewBehind cvb) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number413 index412 alt2\u0026quot;\u0026gt; ` ``mViewBehind = cvb;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number414 index413 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number415 index414 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number416 index415 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number417 index416 alt2\u0026quot;\u0026gt; ` ``protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number418 index417 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number419 index418 alt2\u0026quot;\u0026gt; ` ``int width = getDefaultSize(0, widthMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number420 index419 alt1\u0026quot;\u0026gt; ` ``int height = getDefaultSize(0, heightMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number421 index420 alt2\u0026quot;\u0026gt; ` ``setMeasuredDimension(width, height);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number422 index421 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number423 index422 alt2\u0026quot;\u0026gt; ` ``final int contentWidth = getChildMeasureSpec(widthMeasureSpec, 0, width);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number424 index423 alt1\u0026quot;\u0026gt; ` ``final int contentHeight = getChildMeasureSpec(heightMeasureSpec, 0, height);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number425 index424 alt2\u0026quot;\u0026gt; ` ``mContent.measure(contentWidth, contentHeight);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number426 index425 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number427 index426 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number428 index427 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number429 index428 alt2\u0026quot;\u0026gt; ` ``protected void onSizeChanged(int w, int h, int oldw, int oldh) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number430 index429 alt1\u0026quot;\u0026gt; ` ``super.onSizeChanged(w, h, oldw, oldh);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number431 index430 alt2\u0026quot;\u0026gt; ` ``// Make sure scroll position is set correctly.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number432 index431 alt1\u0026quot;\u0026gt; ` ``if (w != oldw) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number433 index432 alt2\u0026quot;\u0026gt; ` ``// [ChrisJ] - This fixes the onConfiguration change for orientation issue..` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number434 index433 alt1\u0026quot;\u0026gt; ` ``// maybe worth having a look why the recomputeScroll pos is screwing` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number435 index434 alt2\u0026quot;\u0026gt; ` ``// up?` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number436 index435 alt1\u0026quot;\u0026gt; ` ``completeScroll();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number437 index436 alt2\u0026quot;\u0026gt; ` ``scrollTo(getDestScrollX(mCurItem), getScrollY());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number438 index437 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number439 index438 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number440 index439 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number441 index440 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number442 index441 alt1\u0026quot;\u0026gt; ` ``protected void onLayout(boolean changed, int l, int t, int r, int b) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number443 index442 alt2\u0026quot;\u0026gt; ` ``final int width = r - l;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number444 index443 alt1\u0026quot;\u0026gt; ` ``final int height = b - t;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number445 index444 alt2\u0026quot;\u0026gt; ` ``mContent.layout(0, 0, width, height);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number446 index445 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number447 index446 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number448 index447 alt1\u0026quot;\u0026gt; ` ``public void setAboveOffset(int i) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number449 index448 alt2\u0026quot;\u0026gt; ` ``// RelativeLayout.LayoutParams params = ((RelativeLayout.LayoutParams)mContent.getLayoutParams());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number450 index449 alt1\u0026quot;\u0026gt; ` ``// params.setMargins(i, params.topMargin, params.rightMargin, params.bottomMargin);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number451 index450 alt2\u0026quot;\u0026gt; ` ``mContent.setPadding(i, mContent.getPaddingTop(),` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number452 index451 alt1\u0026quot;\u0026gt; ` ``mContent.getPaddingRight(), mContent.getPaddingBottom());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number453 index452 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number454 index453 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number455 index454 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number456 index455 alt1\u0026quot;\u0026gt; ` ``public void computeScroll() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number457 index456 alt2\u0026quot;\u0026gt; ` ``if (!mScroller.isFinished()) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number458 index457 alt1\u0026quot;\u0026gt; ` ``if (mScroller.computeScrollOffset()) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number459 index458 alt2\u0026quot;\u0026gt; ` ``int oldX = getScrollX();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number460 index459 alt1\u0026quot;\u0026gt; ` ``int oldY = getScrollY();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number461 index460 alt2\u0026quot;\u0026gt; ` ``int x = mScroller.getCurrX();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number462 index461 alt1\u0026quot;\u0026gt; ` ``int y = mScroller.getCurrY();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number463 index462 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number464 index463 alt1\u0026quot;\u0026gt; ` ``if (oldX != x || oldY != y) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number465 index464 alt2\u0026quot;\u0026gt; ` ``scrollTo(x, y);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number466 index465 alt1\u0026quot;\u0026gt; ` ``pageScrolled(x);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number467 index466 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number468 index467 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number469 index468 alt2\u0026quot;\u0026gt; ` ``// Keep on drawing until the animation has finished.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number470 index469 alt1\u0026quot;\u0026gt; ` ``invalidate();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number471 index470 alt2\u0026quot;\u0026gt; ` ``return;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number472 index471 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number473 index472 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number474 index473 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number475 index474 alt2\u0026quot;\u0026gt; ` ``// Done with scroll, clean up state.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number476 index475 alt1\u0026quot;\u0026gt; ` ``completeScroll();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number477 index476 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number478 index477 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number479 index478 alt2\u0026quot;\u0026gt; ` ``private void pageScrolled(int xpos) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number480 index479 alt1\u0026quot;\u0026gt; ` ``final int widthWithMargin = getWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number481 index480 alt2\u0026quot;\u0026gt; ` ``final int position = xpos / widthWithMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number482 index481 alt1\u0026quot;\u0026gt; ` ``final int offsetPixels = xpos % widthWithMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number483 index482 alt2\u0026quot;\u0026gt; ` ``final float offset = (float) offsetPixels / widthWithMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number484 index483 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number485 index484 alt2\u0026quot;\u0026gt; ` ``onPageScrolled(position, offset, offsetPixels);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number486 index485 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number487 index486 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number488 index487 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number489 index488 alt2\u0026quot;\u0026gt; ` ``* This method will be invoked when the current page is scrolled, either as part` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number490 index489 alt1\u0026quot;\u0026gt; ` ``* of a programmatically initiated smooth scroll or a user initiated touch scroll.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number491 index490 alt2\u0026quot;\u0026gt; ` ``* If you override this method you must call through to the superclass implementation` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number492 index491 alt1\u0026quot;\u0026gt; ` ``* (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number493 index492 alt2\u0026quot;\u0026gt; ` ``* returns.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number494 index493 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number495 index494 alt2\u0026quot;\u0026gt; ` ``* @param position Position index of the first page currently being displayed.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number496 index495 alt1\u0026quot;\u0026gt; ` ``* Page position+1 will be visible if positionOffset is nonzero.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number497 index496 alt2\u0026quot;\u0026gt; ` ``* @param offset Value from [0, 1) indicating the offset from the page at position.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number498 index497 alt1\u0026quot;\u0026gt; ` ``* @param offsetPixels Value in pixels indicating the offset from position.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number499 index498 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number500 index499 alt1\u0026quot;\u0026gt; ` ``protected void onPageScrolled(int position, float offset, int offsetPixels) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number501 index500 alt2\u0026quot;\u0026gt; ` ``if (mOnPageChangeListener != null) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number502 index501 alt1\u0026quot;\u0026gt; ` ``mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number503 index502 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number504 index503 alt1\u0026quot;\u0026gt; ` ``if (mInternalPageChangeListener != null) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number505 index504 alt2\u0026quot;\u0026gt; ` ``mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number506 index505 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number507 index506 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number508 index507 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number509 index508 alt2\u0026quot;\u0026gt; ` ``private void completeScroll() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number510 index509 alt1\u0026quot;\u0026gt; ` ``boolean needPopulate = mScrolling;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number511 index510 alt2\u0026quot;\u0026gt; ` ``if (needPopulate) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number512 index511 alt1\u0026quot;\u0026gt; ` ``// Done with scroll, no longer want to cache view drawing.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number513 index512 alt2\u0026quot;\u0026gt; ` ``setScrollingCacheEnabled(false);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number514 index513 alt1\u0026quot;\u0026gt; ` ``mScroller.abortAnimation();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number515 index514 alt2\u0026quot;\u0026gt; ` ``int oldX = getScrollX();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number516 index515 alt1\u0026quot;\u0026gt; ` ``int oldY = getScrollY();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number517 index516 alt2\u0026quot;\u0026gt; ` ``int x = mScroller.getCurrX();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number518 index517 alt1\u0026quot;\u0026gt; ` ``int y = mScroller.getCurrY();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number519 index518 alt2\u0026quot;\u0026gt; ` ``if (oldX != x || oldY != y) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number520 index519 alt1\u0026quot;\u0026gt; ` ``scrollTo(x, y);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number521 index520 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number522 index521 alt1\u0026quot;\u0026gt; ` ``if (isMenuOpen()) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number523 index522 alt2\u0026quot;\u0026gt; ` ``if (mOpenedListener != null)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number524 index523 alt1\u0026quot;\u0026gt; ` ``mOpenedListener.onOpened();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number525 index524 alt2\u0026quot;\u0026gt; ` ``} else {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number526 index525 alt1\u0026quot;\u0026gt; ` ``if (mClosedListener != null)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number527 index526 alt2\u0026quot;\u0026gt; ` ``mClosedListener.onClosed();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number528 index527 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number529 index528 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number530 index529 alt1\u0026quot;\u0026gt; ` ``mScrolling = false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number531 index530 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number532 index531 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number533 index532 alt2\u0026quot;\u0026gt; ` ``protected int mTouchMode = SlidingMenu.TOUCHMODE_MARGIN;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number534 index533 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number535 index534 alt2\u0026quot;\u0026gt; ` ``public void setTouchMode(int i) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number536 index535 alt1\u0026quot;\u0026gt; ` ``mTouchMode = i;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number537 index536 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number538 index537 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number539 index538 alt2\u0026quot;\u0026gt; ` ``public int getTouchMode() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number540 index539 alt1\u0026quot;\u0026gt; ` ``return mTouchMode;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number541 index540 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number542 index541 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number543 index542 alt2\u0026quot;\u0026gt; ` ``private boolean thisTouchAllowed(MotionEvent ev) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number544 index543 alt1\u0026quot;\u0026gt; ` ``int x = (int) (ev.getX() + mScrollX);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number545 index544 alt2\u0026quot;\u0026gt; ` ``if (isMenuOpen()) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number546 index545 alt1\u0026quot;\u0026gt; ` ``return mViewBehind.menuOpenTouchAllowed(mContent, mCurItem, x);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number547 index546 alt2\u0026quot;\u0026gt; ` ``} else {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number548 index547 alt1\u0026quot;\u0026gt; ` ``switch (mTouchMode) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number549 index548 alt2\u0026quot;\u0026gt; ` ``case SlidingMenu.TOUCHMODE_FULLSCREEN:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number550 index549 alt1\u0026quot;\u0026gt; ` ``return !isInIgnoredView(ev);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number551 index550 alt2\u0026quot;\u0026gt; ` ``case SlidingMenu.TOUCHMODE_NONE:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number552 index551 alt1\u0026quot;\u0026gt; ` ``return false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number553 index552 alt2\u0026quot;\u0026gt; ` ``case SlidingMenu.TOUCHMODE_MARGIN:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number554 index553 alt1\u0026quot;\u0026gt; ` ``return mViewBehind.marginTouchAllowed(mContent, x);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number555 index554 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number556 index555 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number557 index556 alt2\u0026quot;\u0026gt; ` ``return false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number558 index557 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number559 index558 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number560 index559 alt1\u0026quot;\u0026gt; ` ``private boolean thisSlideAllowed(float dx) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number561 index560 alt2\u0026quot;\u0026gt; ` ``boolean allowed = false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number562 index561 alt1\u0026quot;\u0026gt; ` ``if (isMenuOpen()) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number563 index562 alt2\u0026quot;\u0026gt; ` ``allowed = mViewBehind.menuOpenSlideAllowed(dx);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number564 index563 alt1\u0026quot;\u0026gt; ` ``} else {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number565 index564 alt2\u0026quot;\u0026gt; ` ``allowed = mViewBehind.menuClosedSlideAllowed(dx);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number566 index565 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number567 index566 alt2\u0026quot;\u0026gt; ` ``if (DEBUG)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number568 index567 alt1\u0026quot;\u0026gt; ` ``Log.v(TAG, \u0026quot;this slide allowed \u0026quot; + allowed + \u0026quot; dx: \u0026quot; + dx);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number569 index568 alt2\u0026quot;\u0026gt; ` ``return allowed;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number570 index569 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number571 index570 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number572 index571 alt1\u0026quot;\u0026gt; ` ``private int getPointerIndex(MotionEvent ev, int id) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number573 index572 alt2\u0026quot;\u0026gt; ` ``int activePointerIndex = MotionEventCompat.findPointerIndex(ev, id);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number574 index573 alt1\u0026quot;\u0026gt; ` ``if (activePointerIndex == -1)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number575 index574 alt2\u0026quot;\u0026gt; ` ``mActivePointerId = INVALID_POINTER;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number576 index575 alt1\u0026quot;\u0026gt; ` ``return activePointerIndex;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number577 index576 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number578 index577 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number579 index578 alt2\u0026quot;\u0026gt; ` ``private boolean mQuickReturn = false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number580 index579 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number581 index580 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number582 index581 alt1\u0026quot;\u0026gt; ` ``public boolean onInterceptTouchEvent(MotionEvent ev) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number583 index582 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number584 index583 alt1\u0026quot;\u0026gt; ` ``if (!mEnabled)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number585 index584 alt2\u0026quot;\u0026gt; ` ``return false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number586 index585 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number587 index586 alt2\u0026quot;\u0026gt; ` ``final int action = ev.getAction() \u0026amp; MotionEventCompat.ACTION_MASK;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number588 index587 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number589 index588 alt2\u0026quot;\u0026gt; ` ``if (DEBUG)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number590 index589 alt1\u0026quot;\u0026gt; ` ``if (action == MotionEvent.ACTION_DOWN)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number591 index590 alt2\u0026quot;\u0026gt; ` ``Log.v(TAG, \u0026quot;Received ACTION_DOWN\u0026quot;);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number592 index591 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number593 index592 alt2\u0026quot;\u0026gt; ` ``if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number594 index593 alt1\u0026quot;\u0026gt; ` ``|| (action != MotionEvent.ACTION_DOWN \u0026amp;\u0026amp; mIsUnableToDrag)) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number595 index594 alt2\u0026quot;\u0026gt; ` ``endDrag();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number596 index595 alt1\u0026quot;\u0026gt; ` ``return false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number597 index596 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number598 index597 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number599 index598 alt2\u0026quot;\u0026gt; ` ``switch (action) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number600 index599 alt1\u0026quot;\u0026gt; ` ``case MotionEvent.ACTION_MOVE:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number601 index600 alt2\u0026quot;\u0026gt; ` ``determineDrag(ev);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number602 index601 alt1\u0026quot;\u0026gt; ` ``break;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number603 index602 alt2\u0026quot;\u0026gt; ` ``case MotionEvent.ACTION_DOWN:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number604 index603 alt1\u0026quot;\u0026gt; ` ``int index = MotionEventCompat.getActionIndex(ev);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number605 index604 alt2\u0026quot;\u0026gt; ` ``mActivePointerId = MotionEventCompat.getPointerId(ev, index);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number606 index605 alt1\u0026quot;\u0026gt; ` ``if (mActivePointerId == INVALID_POINTER)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number607 index606 alt2\u0026quot;\u0026gt; ` ``break;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number608 index607 alt1\u0026quot;\u0026gt; ` ``mLastMotionX = mInitialMotionX = MotionEventCompat.getX(ev, index);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number609 index608 alt2\u0026quot;\u0026gt; ` ``mLastMotionY = MotionEventCompat.getY(ev, index);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number610 index609 alt1\u0026quot;\u0026gt; ` ``if (thisTouchAllowed(ev)) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number611 index610 alt2\u0026quot;\u0026gt; ` ``mIsBeingDragged = false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number612 index611 alt1\u0026quot;\u0026gt; ` ``mIsUnableToDrag = false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number613 index612 alt2\u0026quot;\u0026gt; ` ``if (isMenuOpen() \u0026amp;\u0026amp; mViewBehind.menuTouchInQuickReturn(mContent, mCurItem, ev.getX() + mScrollX)) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number614 index613 alt1\u0026quot;\u0026gt; ` ``mQuickReturn = true;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number615 index614 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number616 index615 alt1\u0026quot;\u0026gt; ` ``} else {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number617 index616 alt2\u0026quot;\u0026gt; ` ``mIsUnableToDrag = true;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number618 index617 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number619 index618 alt2\u0026quot;\u0026gt; ` ``break;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number620 index619 alt1\u0026quot;\u0026gt; ` ``case MotionEventCompat.ACTION_POINTER_UP:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number621 index620 alt2\u0026quot;\u0026gt; ` ``onSecondaryPointerUp(ev);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number622 index621 alt1\u0026quot;\u0026gt; ` ``break;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number623 index622 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number624 index623 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number625 index624 alt2\u0026quot;\u0026gt; ` ``if (!mIsBeingDragged) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number626 index625 alt1\u0026quot;\u0026gt; ` ``if (mVelocityTracker == null) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number627 index626 alt2\u0026quot;\u0026gt; ` ``mVelocityTracker = VelocityTracker.obtain();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number628 index627 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number629 index628 alt2\u0026quot;\u0026gt; ` ``mVelocityTracker.addMovement(ev);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number630 index629 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number631 index630 alt2\u0026quot;\u0026gt; ` ``return mIsBeingDragged || mQuickReturn;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number632 index631 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number633 index632 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number634 index633 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number635 index634 alt2\u0026quot;\u0026gt; ` ``public boolean onTouchEvent(MotionEvent ev) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number636 index635 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number637 index636 alt2\u0026quot;\u0026gt; ` ``if (!mEnabled)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number638 index637 alt1\u0026quot;\u0026gt; ` ``return false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number639 index638 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number640 index639 alt1\u0026quot;\u0026gt; ` ``if (!mIsBeingDragged \u0026amp;\u0026amp; !thisTouchAllowed(ev))` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number641 index640 alt2\u0026quot;\u0026gt; ` ``return false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number642 index641 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number643 index642 alt2\u0026quot;\u0026gt; ` ``// if (!mIsBeingDragged \u0026amp;\u0026amp; !mQuickReturn)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number644 index643 alt1\u0026quot;\u0026gt; ` ``// return false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number645 index644 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number646 index645 alt1\u0026quot;\u0026gt; ` ``final int action = ev.getAction();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number647 index646 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number648 index647 alt1\u0026quot;\u0026gt; ` ``if (mVelocityTracker == null) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number649 index648 alt2\u0026quot;\u0026gt; ` ``mVelocityTracker = VelocityTracker.obtain();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number650 index649 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number651 index650 alt2\u0026quot;\u0026gt; ` ``mVelocityTracker.addMovement(ev);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number652 index651 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number653 index652 alt2\u0026quot;\u0026gt; ` ``switch (action \u0026amp; MotionEventCompat.ACTION_MASK) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number654 index653 alt1\u0026quot;\u0026gt; ` ``case MotionEvent.ACTION_DOWN:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number655 index654 alt2\u0026quot;\u0026gt; ` ``/*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number656 index655 alt1\u0026quot;\u0026gt; ` ``* If being flinged and user touches, stop the fling. isFinished` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number657 index656 alt2\u0026quot;\u0026gt; ` ``* will be false if being flinged.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number658 index657 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number659 index658 alt2\u0026quot;\u0026gt; ` ``completeScroll();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number660 index659 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number661 index660 alt2\u0026quot;\u0026gt; ` ``// Remember where the motion event started` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number662 index661 alt1\u0026quot;\u0026gt; ` ``int index = MotionEventCompat.getActionIndex(ev);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number663 index662 alt2\u0026quot;\u0026gt; ` ``mActivePointerId = MotionEventCompat.getPointerId(ev, index);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number664 index663 alt1\u0026quot;\u0026gt; ` ``mLastMotionX = mInitialMotionX = ev.getX();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number665 index664 alt2\u0026quot;\u0026gt; ` ``break;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number666 index665 alt1\u0026quot;\u0026gt; ` ``case MotionEvent.ACTION_MOVE:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number667 index666 alt2\u0026quot;\u0026gt; ` ``if (!mIsBeingDragged) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number668 index667 alt1\u0026quot;\u0026gt; ` ``determineDrag(ev);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number669 index668 alt2\u0026quot;\u0026gt; ` ``if (mIsUnableToDrag)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number670 index669 alt1\u0026quot;\u0026gt; ` ``return false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number671 index670 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number672 index671 alt1\u0026quot;\u0026gt; ` ``if (mIsBeingDragged) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number673 index672 alt2\u0026quot;\u0026gt; ` ``// Scroll to follow the motion event` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number674 index673 alt1\u0026quot;\u0026gt; ` ``final int activePointerIndex = getPointerIndex(ev, mActivePointerId);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number675 index674 alt2\u0026quot;\u0026gt; ` ``if (mActivePointerId == INVALID_POINTER)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number676 index675 alt1\u0026quot;\u0026gt; ` ``break;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number677 index676 alt2\u0026quot;\u0026gt; ` ``final float x = MotionEventCompat.getX(ev, activePointerIndex);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number678 index677 alt1\u0026quot;\u0026gt; ` ``final float deltaX = mLastMotionX - x;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number679 index678 alt2\u0026quot;\u0026gt; ` ``mLastMotionX = x;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number680 index679 alt1\u0026quot;\u0026gt; ` ``float oldScrollX = getScrollX();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number681 index680 alt2\u0026quot;\u0026gt; ` ``float scrollX = oldScrollX + deltaX;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number682 index681 alt1\u0026quot;\u0026gt; ` ``final float leftBound = getLeftBound();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number683 index682 alt2\u0026quot;\u0026gt; ` ``final float rightBound = getRightBound();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number684 index683 alt1\u0026quot;\u0026gt; ` ``if (scrollX \u0026amp;lt; leftBound) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number685 index684 alt2\u0026quot;\u0026gt; ` ``scrollX = leftBound;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number686 index685 alt1\u0026quot;\u0026gt; ` ``} else if (scrollX \u0026amp;gt; rightBound) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number687 index686 alt2\u0026quot;\u0026gt; ` ``scrollX = rightBound;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number688 index687 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number689 index688 alt2\u0026quot;\u0026gt; ` ``// Don't lose the rounded component` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number690 index689 alt1\u0026quot;\u0026gt; ` ``mLastMotionX += scrollX - (int) scrollX;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number691 index690 alt2\u0026quot;\u0026gt; ` ``scrollTo((int) scrollX, getScrollY());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number692 index691 alt1\u0026quot;\u0026gt; ` ``pageScrolled((int) scrollX);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number693 index692 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number694 index693 alt1\u0026quot;\u0026gt; ` ``break;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number695 index694 alt2\u0026quot;\u0026gt; ` ``case MotionEvent.ACTION_UP:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number696 index695 alt1\u0026quot;\u0026gt; ` ``if (mIsBeingDragged) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number697 index696 alt2\u0026quot;\u0026gt; ` ``final VelocityTracker velocityTracker = mVelocityTracker;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number698 index697 alt1\u0026quot;\u0026gt; ` ``velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number699 index698 alt2\u0026quot;\u0026gt; ` ``int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number700 index699 alt1\u0026quot;\u0026gt; ` ``velocityTracker, mActivePointerId);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number701 index700 alt2\u0026quot;\u0026gt; ` ``final int scrollX = getScrollX();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number702 index701 alt1\u0026quot;\u0026gt; ` ``final float pageOffset = (float) (scrollX - getDestScrollX(mCurItem)) / getBehindWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number703 index702 alt2\u0026quot;\u0026gt; ` ``final int activePointerIndex = getPointerIndex(ev, mActivePointerId);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number704 index703 alt1\u0026quot;\u0026gt; ` ``if (mActivePointerId != INVALID_POINTER) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number705 index704 alt2\u0026quot;\u0026gt; ` ``final float x = MotionEventCompat.getX(ev, activePointerIndex);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number706 index705 alt1\u0026quot;\u0026gt; ` ``final int totalDelta = (int) (x - mInitialMotionX);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number707 index706 alt2\u0026quot;\u0026gt; ` ``int nextPage = determineTargetPage(pageOffset, initialVelocity, totalDelta);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number708 index707 alt1\u0026quot;\u0026gt; ` ``setCurrentItemInternal(nextPage, true, true, initialVelocity);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number709 index708 alt2\u0026quot;\u0026gt; ` ``} else { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number710 index709 alt1\u0026quot;\u0026gt; ` ``setCurrentItemInternal(mCurItem, true, true, initialVelocity);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number711 index710 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number712 index711 alt1\u0026quot;\u0026gt; ` ``mActivePointerId = INVALID_POINTER;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number713 index712 alt2\u0026quot;\u0026gt; ` ``endDrag();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number714 index713 alt1\u0026quot;\u0026gt; ` ``} else if (mQuickReturn \u0026amp;\u0026amp; mViewBehind.menuTouchInQuickReturn(mContent, mCurItem, ev.getX() + mScrollX)) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number715 index714 alt2\u0026quot;\u0026gt; ` ``// close the menu` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number716 index715 alt1\u0026quot;\u0026gt; ` ``setCurrentItem(1);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number717 index716 alt2\u0026quot;\u0026gt; ` ``endDrag();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number718 index717 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number719 index718 alt2\u0026quot;\u0026gt; ` ``break;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number720 index719 alt1\u0026quot;\u0026gt; ` ``case MotionEvent.ACTION_CANCEL:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number721 index720 alt2\u0026quot;\u0026gt; ` ``if (mIsBeingDragged) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number722 index721 alt1\u0026quot;\u0026gt; ` ``setCurrentItemInternal(mCurItem, true, true);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number723 index722 alt2\u0026quot;\u0026gt; ` ``mActivePointerId = INVALID_POINTER;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number724 index723 alt1\u0026quot;\u0026gt; ` ``endDrag();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number725 index724 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number726 index725 alt1\u0026quot;\u0026gt; ` ``break;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number727 index726 alt2\u0026quot;\u0026gt; ` ``case MotionEventCompat.ACTION_POINTER_DOWN: {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number728 index727 alt1\u0026quot;\u0026gt; ` ``final int indexx = MotionEventCompat.getActionIndex(ev);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number729 index728 alt2\u0026quot;\u0026gt; ` ``mLastMotionX = MotionEventCompat.getX(ev, indexx);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number730 index729 alt1\u0026quot;\u0026gt; ` ``mActivePointerId = MotionEventCompat.getPointerId(ev, indexx);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number731 index730 alt2\u0026quot;\u0026gt; ` ``break;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number732 index731 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number733 index732 alt2\u0026quot;\u0026gt; ` ``case MotionEventCompat.ACTION_POINTER_UP:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number734 index733 alt1\u0026quot;\u0026gt; ` ``onSecondaryPointerUp(ev);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number735 index734 alt2\u0026quot;\u0026gt; ` ``int pointerIndex = getPointerIndex(ev, mActivePointerId);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number736 index735 alt1\u0026quot;\u0026gt; ` ``if (mActivePointerId == INVALID_POINTER)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number737 index736 alt2\u0026quot;\u0026gt; ` ``break;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number738 index737 alt1\u0026quot;\u0026gt; ` ``mLastMotionX = MotionEventCompat.getX(ev, pointerIndex);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number739 index738 alt2\u0026quot;\u0026gt; ` ``break;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number740 index739 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number741 index740 alt2\u0026quot;\u0026gt; ` ``return true;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number742 index741 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number743 index742 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number744 index743 alt1\u0026quot;\u0026gt; ` ``private void determineDrag(MotionEvent ev) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number745 index744 alt2\u0026quot;\u0026gt; ` ``final int activePointerId = mActivePointerId;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number746 index745 alt1\u0026quot;\u0026gt; ` ``final int pointerIndex = getPointerIndex(ev, activePointerId);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number747 index746 alt2\u0026quot;\u0026gt; ` ``if (activePointerId == INVALID_POINTER || pointerIndex == INVALID_POINTER)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number748 index747 alt1\u0026quot;\u0026gt; ` ``return;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number749 index748 alt2\u0026quot;\u0026gt; ` ``final float x = MotionEventCompat.getX(ev, pointerIndex);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number750 index749 alt1\u0026quot;\u0026gt; ` ``final float dx = x - mLastMotionX;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number751 index750 alt2\u0026quot;\u0026gt; ` ``final float xDiff = Math.abs(dx);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number752 index751 alt1\u0026quot;\u0026gt; ` ``final float y = MotionEventCompat.getY(ev, pointerIndex);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number753 index752 alt2\u0026quot;\u0026gt; ` ``final float dy = y - mLastMotionY;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number754 index753 alt1\u0026quot;\u0026gt; ` ``final float yDiff = Math.abs(dy);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number755 index754 alt2\u0026quot;\u0026gt; ` ``if (xDiff \u0026amp;gt; (isMenuOpen()?mTouchSlop/2:mTouchSlop) \u0026amp;\u0026amp; xDiff \u0026amp;gt; yDiff \u0026amp;\u0026amp; thisSlideAllowed(dx)) { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number756 index755 alt1\u0026quot;\u0026gt; ` ``startDrag();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number757 index756 alt2\u0026quot;\u0026gt; ` ``mLastMotionX = x;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number758 index757 alt1\u0026quot;\u0026gt; ` ``mLastMotionY = y;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number759 index758 alt2\u0026quot;\u0026gt; ` ``setScrollingCacheEnabled(true);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number760 index759 alt1\u0026quot;\u0026gt; ` ``// TODO add back in touch slop check` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number761 index760 alt2\u0026quot;\u0026gt; ` ``} else if (xDiff \u0026amp;gt; mTouchSlop) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number762 index761 alt1\u0026quot;\u0026gt; ` ``mIsUnableToDrag = true;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number763 index762 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number764 index763 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number765 index764 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number766 index765 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number767 index766 alt2\u0026quot;\u0026gt; ` ``public void scrollTo(int x, int y) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number768 index767 alt1\u0026quot;\u0026gt; ` ``super.scrollTo(x, y);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number769 index768 alt2\u0026quot;\u0026gt; ` ``mScrollX = x;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number770 index769 alt1\u0026quot;\u0026gt; ` ``mViewBehind.scrollBehindTo(mContent, x, y);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number771 index770 alt2\u0026quot;\u0026gt; ` ``((SlidingMenu)getParent()).manageLayers(getPercentOpen());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number772 index771 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number773 index772 alt2\u0026quot;\u0026gt; ` ``if (mTransformer != null) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number774 index773 alt1\u0026quot;\u0026gt; ` ``invalidate();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number775 index774 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number776 index775 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number777 index776 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number778 index777 alt1\u0026quot;\u0026gt; ` ``private int determineTargetPage(float pageOffset, int velocity, int deltaX) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number779 index778 alt2\u0026quot;\u0026gt; ` ``int targetPage = mCurItem;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number780 index779 alt1\u0026quot;\u0026gt; ` ``if (Math.abs(deltaX) \u0026amp;gt; mFlingDistance \u0026amp;\u0026amp; Math.abs(velocity) \u0026amp;gt; mMinimumVelocity) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number781 index780 alt2\u0026quot;\u0026gt; ` ``if (velocity \u0026amp;gt; 0 \u0026amp;\u0026amp; deltaX \u0026amp;gt; 0) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number782 index781 alt1\u0026quot;\u0026gt; ` ``targetPage -= 1;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number783 index782 alt2\u0026quot;\u0026gt; ` ``} else if (velocity \u0026amp;lt; 0 \u0026amp;\u0026amp; deltaX \u0026amp;lt; 0){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number784 index783 alt1\u0026quot;\u0026gt; ` ``targetPage += 1;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number785 index784 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number786 index785 alt1\u0026quot;\u0026gt; ` ``} else {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number787 index786 alt2\u0026quot;\u0026gt; ` ``targetPage = (int) Math.round(mCurItem + pageOffset);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number788 index787 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number789 index788 alt2\u0026quot;\u0026gt; ` ``return targetPage;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number790 index789 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number791 index790 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number792 index791 alt1\u0026quot;\u0026gt; ` ``protected float getPercentOpen() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number793 index792 alt2\u0026quot;\u0026gt; ` ``return Math.abs(mScrollX-mContent.getLeft()) / getBehindWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number794 index793 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number795 index794 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number796 index795 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number797 index796 alt2\u0026quot;\u0026gt; ` ``protected void dispatchDraw(Canvas canvas) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number798 index797 alt1\u0026quot;\u0026gt; ` ``// 这句要注释掉，否则会出现2个右侧的视图，一个有转场动画，一个没有转场动画` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number799 index798 alt2\u0026quot;\u0026gt; ` ``// super.dispatchDraw(canvas);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number800 index799 alt1\u0026quot;\u0026gt; ` ``// Draw the margin drawable if needed.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number801 index800 alt2\u0026quot;\u0026gt; ` ``mViewBehind.drawShadow(mContent, canvas);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number802 index801 alt1\u0026quot;\u0026gt; ` ``mViewBehind.drawFade(mContent, canvas, getPercentOpen());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number803 index802 alt2\u0026quot;\u0026gt; ` ``mViewBehind.drawSelector(mContent, canvas, getPercentOpen());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number804 index803 alt1\u0026quot;\u0026gt; ` ``// 设置右侧视图的转场效果，主要是修改Canvas。` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number805 index804 alt2\u0026quot;\u0026gt; ` ``if (mTransformer != null) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number806 index805 alt1\u0026quot;\u0026gt; ` ``canvas.save();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number807 index806 alt2\u0026quot;\u0026gt; ` ``mTransformer.transformCanvas(canvas, getPercentOpen());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number808 index807 alt1\u0026quot;\u0026gt; ` ``super.dispatchDraw(canvas);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number809 index808 alt2\u0026quot;\u0026gt; ` ``canvas.restore();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number810 index809 alt1\u0026quot;\u0026gt; ` ``} else {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number811 index810 alt2\u0026quot;\u0026gt; ` ``super.dispatchDraw(canvas);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number812 index811 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number813 index812 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number814 index813 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number815 index814 alt2\u0026quot;\u0026gt; ` ``// variables for drawing` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number816 index815 alt1\u0026quot;\u0026gt; ` ``private float mScrollX = 0.0f;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number817 index816 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number818 index817 alt1\u0026quot;\u0026gt; ` ``private void onSecondaryPointerUp(MotionEvent ev) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number819 index818 alt2\u0026quot;\u0026gt; ` ``if (DEBUG) Log.v(TAG, \u0026quot;onSecondaryPointerUp called\u0026quot;);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number820 index819 alt1\u0026quot;\u0026gt; ` ``final int pointerIndex = MotionEventCompat.getActionIndex(ev);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number821 index820 alt2\u0026quot;\u0026gt; ` ``final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number822 index821 alt1\u0026quot;\u0026gt; ` ``if (pointerId == mActivePointerId) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number823 index822 alt2\u0026quot;\u0026gt; ` ``// This was our active pointer going up. Choose a new` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number824 index823 alt1\u0026quot;\u0026gt; ` ``// active pointer and adjust accordingly.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number825 index824 alt2\u0026quot;\u0026gt; ` ``final int newPointerIndex = pointerIndex == 0 ? 1 : 0;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number826 index825 alt1\u0026quot;\u0026gt; ` ``mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number827 index826 alt2\u0026quot;\u0026gt; ` ``mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number828 index827 alt1\u0026quot;\u0026gt; ` ``if (mVelocityTracker != null) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number829 index828 alt2\u0026quot;\u0026gt; ` ``mVelocityTracker.clear();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number830 index829 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number831 index830 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number832 index831 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number833 index832 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number834 index833 alt1\u0026quot;\u0026gt; ` ``private void startDrag() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number835 index834 alt2\u0026quot;\u0026gt; ` ``mIsBeingDragged = true;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number836 index835 alt1\u0026quot;\u0026gt; ` ``mQuickReturn = false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number837 index836 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number838 index837 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number839 index838 alt2\u0026quot;\u0026gt; ` ``private void endDrag() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number840 index839 alt1\u0026quot;\u0026gt; ` ``mQuickReturn = false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number841 index840 alt2\u0026quot;\u0026gt; ` ``mIsBeingDragged = false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number842 index841 alt1\u0026quot;\u0026gt; ` ``mIsUnableToDrag = false;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number843 index842 alt2\u0026quot;\u0026gt; ` ``mActivePointerId = INVALID_POINTER;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number844 index843 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number845 index844 alt2\u0026quot;\u0026gt; ` ``if (mVelocityTracker != null) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number846 index845 alt1\u0026quot;\u0026gt; ` ``mVelocityTracker.recycle();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number847 index846 alt2\u0026quot;\u0026gt; ` ``mVelocityTracker = null;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number848 index847 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number849 index848 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number850 index849 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number851 index850 alt2\u0026quot;\u0026gt; ` ``private void setScrollingCacheEnabled(boolean enabled) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number852 index851 alt1\u0026quot;\u0026gt; ` ``if (mScrollingCacheEnabled != enabled) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number853 index852 alt2\u0026quot;\u0026gt; ` ``mScrollingCacheEnabled = enabled;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number854 index853 alt1\u0026quot;\u0026gt; ` ``if (USE_CACHE) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number855 index854 alt2\u0026quot;\u0026gt; ` ``final int size = getChildCount();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number856 index855 alt1\u0026quot;\u0026gt; ` ``for (int i = 0; i \u0026amp;lt; size; ++i) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number857 index856 alt2\u0026quot;\u0026gt; ` ``final View child = getChildAt(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number858 index857 alt1\u0026quot;\u0026gt; ` ``if (child.getVisibility() != GONE) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number859 index858 alt2\u0026quot;\u0026gt; ` ``child.setDrawingCacheEnabled(enabled);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number860 index859 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number861 index860 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number862 index861 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number863 index862 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number864 index863 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number865 index864 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number866 index865 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number867 index866 alt2\u0026quot;\u0026gt; ` ``* Tests scrollability within child views of v given a delta of dx.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number868 index867 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number869 index868 alt2\u0026quot;\u0026gt; ` ``* @param v View to test for horizontal scrollability` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number870 index869 alt1\u0026quot;\u0026gt; ` ``* @param checkV Whether the view v passed should itself be checked for scrollability (true),` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number871 index870 alt2\u0026quot;\u0026gt; ` ``* or just its children (false).` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number872 index871 alt1\u0026quot;\u0026gt; ` ``* @param dx Delta scrolled in pixels` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number873 index872 alt2\u0026quot;\u0026gt; ` ``* @param x X coordinate of the active touch point` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number874 index873 alt1\u0026quot;\u0026gt; ` ``* @param y Y coordinate of the active touch point` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number875 index874 alt2\u0026quot;\u0026gt; ` ``* @return true if child views of v can be scrolled by delta of dx.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number876 index875 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number877 index876 alt2\u0026quot;\u0026gt; ` ``protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number878 index877 alt1\u0026quot;\u0026gt; ` ``if (v instanceof ViewGroup) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number879 index878 alt2\u0026quot;\u0026gt; ` ``final ViewGroup group = (ViewGroup) v;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number880 index879 alt1\u0026quot;\u0026gt; ` ``final int scrollX = v.getScrollX();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number881 index880 alt2\u0026quot;\u0026gt; ` ``final int scrollY = v.getScrollY();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number882 index881 alt1\u0026quot;\u0026gt; ` ``final int count = group.getChildCount();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number883 index882 alt2\u0026quot;\u0026gt; ` ``// Count backwards - let topmost views consume scroll distance first.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number884 index883 alt1\u0026quot;\u0026gt; ` ``for (int i = count - 1; i \u0026amp;gt;= 0; i--) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number885 index884 alt2\u0026quot;\u0026gt; ` ``final View child = group.getChildAt(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number886 index885 alt1\u0026quot;\u0026gt; ` ``if (x + scrollX \u0026amp;gt;= child.getLeft() \u0026amp;\u0026amp; x + scrollX \u0026amp;lt; child.getRight() \u0026amp;\u0026amp;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number887 index886 alt2\u0026quot;\u0026gt; ` ``y + scrollY \u0026amp;gt;= child.getTop() \u0026amp;\u0026amp; y + scrollY \u0026amp;lt; child.getBottom() \u0026amp;\u0026amp;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number888 index887 alt1\u0026quot;\u0026gt; ` ``canScroll(child, true, dx, x + scrollX - child.getLeft(),` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number889 index888 alt2\u0026quot;\u0026gt; ` ``y + scrollY - child.getTop())) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number890 index889 alt1\u0026quot;\u0026gt; ` ``return true;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number891 index890 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number892 index891 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number893 index892 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number894 index893 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number895 index894 alt2\u0026quot;\u0026gt; ` ``return checkV \u0026amp;\u0026amp; ViewCompat.canScrollHorizontally(v, -dx);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number896 index895 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number897 index896 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number898 index897 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number899 index898 alt2\u0026quot;\u0026gt; ` ``public boolean dispatchKeyEvent(KeyEvent event) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number900 index899 alt1\u0026quot;\u0026gt; ` ``// Let the focused view and/or our descendants get the key first` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number901 index900 alt2\u0026quot;\u0026gt; ` ``return super.dispatchKeyEvent(event) || executeKeyEvent(event);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number902 index901 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number903 index902 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number904 index903 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number905 index904 alt2\u0026quot;\u0026gt; ` ``* You can call this function yourself to have the scroll view perform` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number906 index905 alt1\u0026quot;\u0026gt; ` ``* scrolling from a key event, just as if the event had been dispatched to` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number907 index906 alt2\u0026quot;\u0026gt; ` ``* it by the view hierarchy.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number908 index907 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number909 index908 alt2\u0026quot;\u0026gt; ` ``* @param event The key event to execute.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number910 index909 alt1\u0026quot;\u0026gt; ` ``* @return Return true if the event was handled, else false.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number911 index910 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number912 index911 alt1\u0026quot;\u0026gt; ` ``public` `boolean` `executeKeyEvent(KeyEvent event) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number913 index912 alt2\u0026quot;\u0026gt; ` ``boolean` `handled = ``false``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number914 index913 alt1\u0026quot;\u0026gt; ` ``if` `(event.getAction() == KeyEvent.ACTION_DOWN) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number915 index914 alt2\u0026quot;\u0026gt; ` ``switch` `(event.getKeyCode()) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number916 index915 alt1\u0026quot;\u0026gt; ` ``case` `KeyEvent.KEYCODE_DPAD_LEFT:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number917 index916 alt2\u0026quot;\u0026gt; ` ``handled = arrowScroll(FOCUS_LEFT);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number918 index917 alt1\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number919 index918 alt2\u0026quot;\u0026gt; ` ``case` `KeyEvent.KEYCODE_DPAD_RIGHT:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number920 index919 alt1\u0026quot;\u0026gt; ` ``handled = arrowScroll(FOCUS_RIGHT);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number921 index920 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number922 index921 alt1\u0026quot;\u0026gt; ` ``case` `KeyEvent.KEYCODE_TAB:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number923 index922 alt2\u0026quot;\u0026gt; ` ``if` `(Build.VERSION.SDK_INT \u0026amp;gt;= ``11``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number924 index923 alt1\u0026quot;\u0026gt; ` ``// The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number925 index924 alt2\u0026quot;\u0026gt; ` ``// before Android 3.0. Ignore the tab key on those devices.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number926 index925 alt1\u0026quot;\u0026gt; ` ``if` `(KeyEventCompat.hasNoModifiers(event)) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number927 index926 alt2\u0026quot;\u0026gt; ` ``handled = arrowScroll(FOCUS_FORWARD);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number928 index927 alt1\u0026quot;\u0026gt; ` ``} ``else` `if` `(KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number929 index928 alt2\u0026quot;\u0026gt; ` ``handled = arrowScroll(FOCUS_BACKWARD);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number930 index929 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number931 index930 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number932 index931 alt1\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number933 index932 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number934 index933 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number935 index934 alt2\u0026quot;\u0026gt; ` ``return` `handled;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number936 index935 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number937 index936 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number938 index937 alt1\u0026quot;\u0026gt; ` ``public` `boolean` `arrowScroll(``int` `direction) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number939 index938 alt2\u0026quot;\u0026gt; ` ``View currentFocused = findFocus();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number940 index939 alt1\u0026quot;\u0026gt; ` ``if` `(currentFocused == ``this``) currentFocused = ``null``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number941 index940 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number942 index941 alt1\u0026quot;\u0026gt; ` ``boolean` `handled = ``false``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number943 index942 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number944 index943 alt1\u0026quot;\u0026gt; ` ``View nextFocused = FocusFinder.getInstance().findNextFocus(``this``, currentFocused,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number945 index944 alt2\u0026quot;\u0026gt; ` ``direction);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number946 index945 alt1\u0026quot;\u0026gt; ` ``if` `(nextFocused != ``null` `\u0026amp;\u0026amp; nextFocused != currentFocused) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number947 index946 alt2\u0026quot;\u0026gt; ` ``if` `(direction == View.FOCUS_LEFT) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number948 index947 alt1\u0026quot;\u0026gt; ` ``handled = nextFocused.requestFocus();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number949 index948 alt2\u0026quot;\u0026gt; ` ``} ``else` `if` `(direction == View.FOCUS_RIGHT) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number950 index949 alt1\u0026quot;\u0026gt; ` ``// If there is nothing to the right, or this is causing us to` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number951 index950 alt2\u0026quot;\u0026gt; ` ``// jump to the left, then what we really want to do is page right.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number952 index951 alt1\u0026quot;\u0026gt; ` ``if` `(currentFocused != ``null` `\u0026amp;\u0026amp; nextFocused.getLeft() \u0026amp;lt;= currentFocused.getLeft()) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number953 index952 alt2\u0026quot;\u0026gt; ` ``handled = pageRight();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number954 index953 alt1\u0026quot;\u0026gt; ` ``} ``else` `{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number955 index954 alt2\u0026quot;\u0026gt; ` ``handled = nextFocused.requestFocus();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number956 index955 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number957 index956 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number958 index957 alt1\u0026quot;\u0026gt; ` ``} ``else` `if` `(direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number959 index958 alt2\u0026quot;\u0026gt; ` ``// Trying to move left and nothing there; try to page.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number960 index959 alt1\u0026quot;\u0026gt; ` ``handled = pageLeft();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number961 index960 alt2\u0026quot;\u0026gt; ` ``} ``else` `if` `(direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number962 index961 alt1\u0026quot;\u0026gt; ` ``// Trying to move right and nothing there; try to page.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number963 index962 alt2\u0026quot;\u0026gt; ` ``handled = pageRight();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number964 index963 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number965 index964 alt2\u0026quot;\u0026gt; ` ``if` `(handled) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number966 index965 alt1\u0026quot;\u0026gt; ` ``playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number967 index966 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number968 index967 alt1\u0026quot;\u0026gt; ` ``return` `handled;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number969 index968 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number970 index969 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number971 index970 alt2\u0026quot;\u0026gt; ` ``boolean` `pageLeft() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number972 index971 alt1\u0026quot;\u0026gt; ` ``if` `(mCurItem \u0026amp;gt; ````) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number973 index972 alt2\u0026quot;\u0026gt; ` ``setCurrentItem(mCurItem-``1``, ``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number974 index973 alt1\u0026quot;\u0026gt; ` ``return` `true``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number975 index974 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number976 index975 alt1\u0026quot;\u0026gt; ` ``return` `false``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number977 index976 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number978 index977 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number979 index978 alt2\u0026quot;\u0026gt; ` ``boolean` `pageRight() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number980 index979 alt1\u0026quot;\u0026gt; ` ``if` `(mCurItem \u0026amp;lt; ``1``) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number981 index980 alt2\u0026quot;\u0026gt; ` ``setCurrentItem(mCurItem+``1``, ``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number982 index981 alt1\u0026quot;\u0026gt; ` ``return` `true``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number983 index982 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number984 index983 alt1\u0026quot;\u0026gt; ` ``return` `false``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number985 index984 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number986 index985 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number987 index986 alt2\u0026quot;\u0026gt; ` ``public` `void` `setCanvasTransformer(CanvasTransformer t) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number988 index987 alt1\u0026quot;\u0026gt; ` ``mTransformer = t;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number989 index988 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number990 index989 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number991 index990 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 如果想要使用这个侧滑菜单的动画效果，直接替换这两个类即可。同时，并不会影响SlidingMenu的固有功能。\n下面看看如何配置SlidingMenu实例。\n[?](http://www.open-open.com/lib/view/open1411269966859.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; ` ``SlidingMenu sm = getSlidingMenu();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``sm.setBehindOffsetRes(R.dimen.slidingmenu_offset);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``sm.setFadeEnabled(``false``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``sm.setBehindScrollScale(````.25f);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``sm.setFadeDegree(````.25f);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``// 配置背景图片` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``sm.setBackgroundImage(R.drawable.img_frame_background);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``// 设置专场动画效果` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``sm.setBehindCanvasTransformer(``new` `SlidingMenu.CanvasTransformer() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``public` `void` `transformCanvas(Canvas canvas, ``float` `percentOpen) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``float` `scale = (``float``) (percentOpen * ``0.25` `+ ``0.75``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``canvas.scale(scale, scale, -canvas.getWidth() / ``2``,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``canvas.getHeight() / ``2``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``});` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``sm.setAboveCanvasTransformer(``new` `SlidingMenu.CanvasTransformer() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``public` `void` `transformCanvas(Canvas canvas, ``float` `percentOpen) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``float` `scale = (``float``) (``1` `- percentOpen * ``0.25``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``canvas.scale(scale, scale, ````, canvas.getHeight() / ``2``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``});` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 大功告成！\n最后，附上Demo的下载地址。\n百度网盘 http://pan.baidu.com/s/1jGrASui\n转自：http://www.open-open.com/lib/view/open1411269966859.html\n","permalink":"https://blog.zdltech.com/posts/android-residemenu%E4%BE%A7%E6%BB%91%E8%8F%9C%E5%8D%95/","summary":"\u003cp\u003e参考GitHub 中\u003c/p\u003e\n\u003ch1 class=\"entry-title.public\" id=\"residemenu\"\u003eRESideMenu\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/romaonthego/RESideMenu\"\u003ehttps://github.com/romaonthego/RESideMenu\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/kyze8439690/ResideLayout\"\u003ehttps://github.com/kyze8439690/ResideLayout\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/SpecialCyCi/AndroidResideMenu\"\u003ehttps://github.com/SpecialCyCi/AndroidResideMenu\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"android仿qq50侧滑菜单residemenu\"\u003eAndroid仿QQ5.0侧滑菜单ResideMenu\u003c/h3\u003e\n\u003cp\u003e最近项目要做一个QQ5.0的侧滑菜单效果，和传统的侧滑菜单存在着一些差异。想必大家都已经见识过了。\u003c/p\u003e\n\u003cp\u003e为了不重复发明轮子，先去github上面搜索了一番。\u003c/p\u003e\n\u003cp\u003e发现了几个类似的，但是还是有一些不同。\u003c/p\u003e\n\u003cp\u003e下面是搜索到的类似的开源项目。\u003c/p\u003e\n\u003cp\u003eRESideMenu（ios项目）\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/romaonthego/RESideMenu\"\u003ehttps://github.com/romaonthego/RESideMenu\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140902223053218?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFub2Vs/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eAndroidResideMenu\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/SpecialCyCi/AndroidResideMenu\"\u003ehttps://github.com/SpecialCyCi/AndroidResideMenu\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140902223213773?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFub2Vs/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003eResideLayout\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/kyze8439690/ResideLayout\"\u003ehttps://github.com/kyze8439690/ResideLayout\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140902223059096?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFub2Vs/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e研究了一下这些开源项目的源代码。感觉并不是特别适用于我们自己的项目。所以，我自己又研究了一下。最后的效果如下。当然了，还有很多可以优化的地方，后续再慢慢优化。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140902225149282?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFub2Vs/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e我是基于SlidingMenu库进行的二次修改，增加了一些转场动画。\u003c/p\u003e\n\u003cp\u003e大家对这个库应该比较熟悉，下面是SlidingMenu的github地址。\u003cstrong\u003e非常感谢Jeremy Feinstein提供的这个库，让广大Android Developers省去了非常多的麻烦。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/jfeinstein10/SlidingMenu\"\u003ehttps://github.com/jfeinstein10/SlidingMenu\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e备注：SlidingMenu使用了SherlockActionBar这个库，配置起来会比较麻烦，在文章的最后我会把demo上传，供大家下载，减去了大家自己配置项目的麻烦。\u003c/p\u003e\n\u003cp\u003e我主要修改了2个类，SlidingMenu.java和CustonViewAbove.java，只是增加了一些功能，并没有修改原本的功能。\u003c/p\u003e\n\u003cp\u003e做了修改的地方，我做了中文注释，其实实现很简单，几行代码而已。推荐大家下载Demo，然后自己调试一下。Demo的下载地址在文章的末尾。\u003c/p\u003e\n\u003cp\u003e废话不多说，直接上代码，略微有点长。\u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_916125\" class=\"syntaxhighlighter  java\"\u003e\n    \u003cdiv class=\"toolbar\"\u003e\n      [?](http://www.open-open.com/lib/view/open1411269966859.html#)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n  \u0026lt;tr\u0026gt;\n    \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n        1\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        2\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n        3\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n        4\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n        5\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n        6\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n        7\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n        8\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n        9\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n        10\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n        11\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n        12\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n        13\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n        14\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n        15\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n        16\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n        17\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n        18\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n        19\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n        20\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n        21\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n        22\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n        23\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n        24\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n        25\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n        26\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n        27\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n        28\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n        29\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n        30\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n        31\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n        32\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n        33\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt;\n        34\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt;\n        35\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt;\n        36\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt;\n        37\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt;\n        38\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt;\n        39\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt;\n        40\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt;\n        41\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt;\n        42\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt;\n        43\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt;\n        44\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt;\n        45\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt;\n        46\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt;\n        47\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt;\n        48\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt;\n        49\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt;\n        50\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt;\n        51\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt;\n        52\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt;\n        53\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt;\n        54\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt;\n        55\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt;\n        56\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt;\n        57\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt;\n        58\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt;\n        59\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt;\n        60\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt;\n        61\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt;\n        62\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt;\n        63\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt;\n        64\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt;\n        65\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt;\n        66\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt;\n        67\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt;\n        68\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt;\n        69\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt;\n        70\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt;\n        71\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt;\n        72\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt;\n        73\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt;\n        74\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt;\n        75\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt;\n        76\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt;\n        77\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt;\n        78\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt;\n        79\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt;\n        80\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt;\n        81\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt;\n        82\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt;\n        83\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt;\n        84\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt;\n        85\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt;\n        86\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt;\n        87\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt;\n        88\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt;\n        89\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt;\n        90\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt;\n        91\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt;\n        92\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt;\n        93\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt;\n        94\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt;\n        95\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt;\n        96\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt;\n        97\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt;\n        98\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt;\n        99\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt;\n        100\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number101 index100 alt2\u0026quot;\u0026gt;\n        101\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number102 index101 alt1\u0026quot;\u0026gt;\n        102\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number103 index102 alt2\u0026quot;\u0026gt;\n        103\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number104 index103 alt1\u0026quot;\u0026gt;\n        104\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number105 index104 alt2\u0026quot;\u0026gt;\n        105\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number106 index105 alt1\u0026quot;\u0026gt;\n        106\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number107 index106 alt2\u0026quot;\u0026gt;\n        107\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number108 index107 alt1\u0026quot;\u0026gt;\n        108\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number109 index108 alt2\u0026quot;\u0026gt;\n        109\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number110 index109 alt1\u0026quot;\u0026gt;\n        110\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number111 index110 alt2\u0026quot;\u0026gt;\n        111\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number112 index111 alt1\u0026quot;\u0026gt;\n        112\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number113 index112 alt2\u0026quot;\u0026gt;\n        113\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number114 index113 alt1\u0026quot;\u0026gt;\n        114\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number115 index114 alt2\u0026quot;\u0026gt;\n        115\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number116 index115 alt1\u0026quot;\u0026gt;\n        116\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number117 index116 alt2\u0026quot;\u0026gt;\n        117\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number118 index117 alt1\u0026quot;\u0026gt;\n        118\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number119 index118 alt2\u0026quot;\u0026gt;\n        119\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number120 index119 alt1\u0026quot;\u0026gt;\n        120\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number121 index120 alt2\u0026quot;\u0026gt;\n        121\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number122 index121 alt1\u0026quot;\u0026gt;\n        122\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number123 index122 alt2\u0026quot;\u0026gt;\n        123\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number124 index123 alt1\u0026quot;\u0026gt;\n        124\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number125 index124 alt2\u0026quot;\u0026gt;\n        125\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number126 index125 alt1\u0026quot;\u0026gt;\n        126\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number127 index126 alt2\u0026quot;\u0026gt;\n        127\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number128 index127 alt1\u0026quot;\u0026gt;\n        128\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number129 index128 alt2\u0026quot;\u0026gt;\n        129\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number130 index129 alt1\u0026quot;\u0026gt;\n        130\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number131 index130 alt2\u0026quot;\u0026gt;\n        131\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number132 index131 alt1\u0026quot;\u0026gt;\n        132\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number133 index132 alt2\u0026quot;\u0026gt;\n        133\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number134 index133 alt1\u0026quot;\u0026gt;\n        134\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number135 index134 alt2\u0026quot;\u0026gt;\n        135\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number136 index135 alt1\u0026quot;\u0026gt;\n        136\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number137 index136 alt2\u0026quot;\u0026gt;\n        137\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number138 index137 alt1\u0026quot;\u0026gt;\n        138\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number139 index138 alt2\u0026quot;\u0026gt;\n        139\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number140 index139 alt1\u0026quot;\u0026gt;\n        140\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number141 index140 alt2\u0026quot;\u0026gt;\n        141\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number142 index141 alt1\u0026quot;\u0026gt;\n        142\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number143 index142 alt2\u0026quot;\u0026gt;\n        143\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number144 index143 alt1\u0026quot;\u0026gt;\n        144\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number145 index144 alt2\u0026quot;\u0026gt;\n        145\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number146 index145 alt1\u0026quot;\u0026gt;\n        146\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number147 index146 alt2\u0026quot;\u0026gt;\n        147\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number148 index147 alt1\u0026quot;\u0026gt;\n        148\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number149 index148 alt2\u0026quot;\u0026gt;\n        149\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number150 index149 alt1\u0026quot;\u0026gt;\n        150\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number151 index150 alt2\u0026quot;\u0026gt;\n        151\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number152 index151 alt1\u0026quot;\u0026gt;\n        152\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number153 index152 alt2\u0026quot;\u0026gt;\n        153\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number154 index153 alt1\u0026quot;\u0026gt;\n        154\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number155 index154 alt2\u0026quot;\u0026gt;\n        155\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number156 index155 alt1\u0026quot;\u0026gt;\n        156\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number157 index156 alt2\u0026quot;\u0026gt;\n        157\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number158 index157 alt1\u0026quot;\u0026gt;\n        158\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number159 index158 alt2\u0026quot;\u0026gt;\n        159\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number160 index159 alt1\u0026quot;\u0026gt;\n        160\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number161 index160 alt2\u0026quot;\u0026gt;\n        161\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number162 index161 alt1\u0026quot;\u0026gt;\n        162\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number163 index162 alt2\u0026quot;\u0026gt;\n        163\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number164 index163 alt1\u0026quot;\u0026gt;\n        164\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number165 index164 alt2\u0026quot;\u0026gt;\n        165\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number166 index165 alt1\u0026quot;\u0026gt;\n        166\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number167 index166 alt2\u0026quot;\u0026gt;\n        167\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number168 index167 alt1\u0026quot;\u0026gt;\n        168\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number169 index168 alt2\u0026quot;\u0026gt;\n        169\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number170 index169 alt1\u0026quot;\u0026gt;\n        170\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number171 index170 alt2\u0026quot;\u0026gt;\n        171\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number172 index171 alt1\u0026quot;\u0026gt;\n        172\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number173 index172 alt2\u0026quot;\u0026gt;\n        173\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number174 index173 alt1\u0026quot;\u0026gt;\n        174\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number175 index174 alt2\u0026quot;\u0026gt;\n        175\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number176 index175 alt1\u0026quot;\u0026gt;\n        176\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number177 index176 alt2\u0026quot;\u0026gt;\n        177\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number178 index177 alt1\u0026quot;\u0026gt;\n        178\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number179 index178 alt2\u0026quot;\u0026gt;\n        179\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number180 index179 alt1\u0026quot;\u0026gt;\n        180\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number181 index180 alt2\u0026quot;\u0026gt;\n        181\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number182 index181 alt1\u0026quot;\u0026gt;\n        182\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number183 index182 alt2\u0026quot;\u0026gt;\n        183\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number184 index183 alt1\u0026quot;\u0026gt;\n        184\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number185 index184 alt2\u0026quot;\u0026gt;\n        185\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number186 index185 alt1\u0026quot;\u0026gt;\n        186\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number187 index186 alt2\u0026quot;\u0026gt;\n        187\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number188 index187 alt1\u0026quot;\u0026gt;\n        188\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number189 index188 alt2\u0026quot;\u0026gt;\n        189\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number190 index189 alt1\u0026quot;\u0026gt;\n        190\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number191 index190 alt2\u0026quot;\u0026gt;\n        191\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number192 index191 alt1\u0026quot;\u0026gt;\n        192\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number193 index192 alt2\u0026quot;\u0026gt;\n        193\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number194 index193 alt1\u0026quot;\u0026gt;\n        194\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number195 index194 alt2\u0026quot;\u0026gt;\n        195\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number196 index195 alt1\u0026quot;\u0026gt;\n        196\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number197 index196 alt2\u0026quot;\u0026gt;\n        197\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number198 index197 alt1\u0026quot;\u0026gt;\n        198\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number199 index198 alt2\u0026quot;\u0026gt;\n        199\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number200 index199 alt1\u0026quot;\u0026gt;\n        200\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number201 index200 alt2\u0026quot;\u0026gt;\n        201\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number202 index201 alt1\u0026quot;\u0026gt;\n        202\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number203 index202 alt2\u0026quot;\u0026gt;\n        203\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number204 index203 alt1\u0026quot;\u0026gt;\n        204\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number205 index204 alt2\u0026quot;\u0026gt;\n        205\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number206 index205 alt1\u0026quot;\u0026gt;\n        206\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number207 index206 alt2\u0026quot;\u0026gt;\n        207\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number208 index207 alt1\u0026quot;\u0026gt;\n        208\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number209 index208 alt2\u0026quot;\u0026gt;\n        209\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number210 index209 alt1\u0026quot;\u0026gt;\n        210\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number211 index210 alt2\u0026quot;\u0026gt;\n        211\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number212 index211 alt1\u0026quot;\u0026gt;\n        212\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number213 index212 alt2\u0026quot;\u0026gt;\n        213\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number214 index213 alt1\u0026quot;\u0026gt;\n        214\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number215 index214 alt2\u0026quot;\u0026gt;\n        215\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number216 index215 alt1\u0026quot;\u0026gt;\n        216\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number217 index216 alt2\u0026quot;\u0026gt;\n        217\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number218 index217 alt1\u0026quot;\u0026gt;\n        218\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number219 index218 alt2\u0026quot;\u0026gt;\n        219\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number220 index219 alt1\u0026quot;\u0026gt;\n        220\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number221 index220 alt2\u0026quot;\u0026gt;\n        221\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number222 index221 alt1\u0026quot;\u0026gt;\n        222\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number223 index222 alt2\u0026quot;\u0026gt;\n        223\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number224 index223 alt1\u0026quot;\u0026gt;\n        224\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number225 index224 alt2\u0026quot;\u0026gt;\n        225\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number226 index225 alt1\u0026quot;\u0026gt;\n        226\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number227 index226 alt2\u0026quot;\u0026gt;\n        227\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number228 index227 alt1\u0026quot;\u0026gt;\n        228\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number229 index228 alt2\u0026quot;\u0026gt;\n        229\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number230 index229 alt1\u0026quot;\u0026gt;\n        230\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number231 index230 alt2\u0026quot;\u0026gt;\n        231\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number232 index231 alt1\u0026quot;\u0026gt;\n        232\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number233 index232 alt2\u0026quot;\u0026gt;\n        233\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number234 index233 alt1\u0026quot;\u0026gt;\n        234\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number235 index234 alt2\u0026quot;\u0026gt;\n        235\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number236 index235 alt1\u0026quot;\u0026gt;\n        236\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number237 index236 alt2\u0026quot;\u0026gt;\n        237\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number238 index237 alt1\u0026quot;\u0026gt;\n        238\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number239 index238 alt2\u0026quot;\u0026gt;\n        239\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number240 index239 alt1\u0026quot;\u0026gt;\n        240\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number241 index240 alt2\u0026quot;\u0026gt;\n        241\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number242 index241 alt1\u0026quot;\u0026gt;\n        242\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number243 index242 alt2\u0026quot;\u0026gt;\n        243\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number244 index243 alt1\u0026quot;\u0026gt;\n        244\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number245 index244 alt2\u0026quot;\u0026gt;\n        245\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number246 index245 alt1\u0026quot;\u0026gt;\n        246\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number247 index246 alt2\u0026quot;\u0026gt;\n        247\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number248 index247 alt1\u0026quot;\u0026gt;\n        248\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number249 index248 alt2\u0026quot;\u0026gt;\n        249\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number250 index249 alt1\u0026quot;\u0026gt;\n        250\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number251 index250 alt2\u0026quot;\u0026gt;\n        251\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number252 index251 alt1\u0026quot;\u0026gt;\n        252\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number253 index252 alt2\u0026quot;\u0026gt;\n        253\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number254 index253 alt1\u0026quot;\u0026gt;\n        254\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number255 index254 alt2\u0026quot;\u0026gt;\n        255\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number256 index255 alt1\u0026quot;\u0026gt;\n        256\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number257 index256 alt2\u0026quot;\u0026gt;\n        257\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number258 index257 alt1\u0026quot;\u0026gt;\n        258\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number259 index258 alt2\u0026quot;\u0026gt;\n        259\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number260 index259 alt1\u0026quot;\u0026gt;\n        260\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number261 index260 alt2\u0026quot;\u0026gt;\n        261\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number262 index261 alt1\u0026quot;\u0026gt;\n        262\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number263 index262 alt2\u0026quot;\u0026gt;\n        263\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number264 index263 alt1\u0026quot;\u0026gt;\n        264\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number265 index264 alt2\u0026quot;\u0026gt;\n        265\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number266 index265 alt1\u0026quot;\u0026gt;\n        266\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number267 index266 alt2\u0026quot;\u0026gt;\n        267\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number268 index267 alt1\u0026quot;\u0026gt;\n        268\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number269 index268 alt2\u0026quot;\u0026gt;\n        269\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number270 index269 alt1\u0026quot;\u0026gt;\n        270\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number271 index270 alt2\u0026quot;\u0026gt;\n        271\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number272 index271 alt1\u0026quot;\u0026gt;\n        272\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number273 index272 alt2\u0026quot;\u0026gt;\n        273\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number274 index273 alt1\u0026quot;\u0026gt;\n        274\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number275 index274 alt2\u0026quot;\u0026gt;\n        275\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number276 index275 alt1\u0026quot;\u0026gt;\n        276\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number277 index276 alt2\u0026quot;\u0026gt;\n        277\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number278 index277 alt1\u0026quot;\u0026gt;\n        278\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number279 index278 alt2\u0026quot;\u0026gt;\n        279\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number280 index279 alt1\u0026quot;\u0026gt;\n        280\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number281 index280 alt2\u0026quot;\u0026gt;\n        281\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number282 index281 alt1\u0026quot;\u0026gt;\n        282\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number283 index282 alt2\u0026quot;\u0026gt;\n        283\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number284 index283 alt1\u0026quot;\u0026gt;\n        284\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number285 index284 alt2\u0026quot;\u0026gt;\n        285\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number286 index285 alt1\u0026quot;\u0026gt;\n        286\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number287 index286 alt2\u0026quot;\u0026gt;\n        287\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number288 index287 alt1\u0026quot;\u0026gt;\n        288\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number289 index288 alt2\u0026quot;\u0026gt;\n        289\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number290 index289 alt1\u0026quot;\u0026gt;\n        290\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number291 index290 alt2\u0026quot;\u0026gt;\n        291\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number292 index291 alt1\u0026quot;\u0026gt;\n        292\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number293 index292 alt2\u0026quot;\u0026gt;\n        293\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number294 index293 alt1\u0026quot;\u0026gt;\n        294\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number295 index294 alt2\u0026quot;\u0026gt;\n        295\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number296 index295 alt1\u0026quot;\u0026gt;\n        296\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number297 index296 alt2\u0026quot;\u0026gt;\n        297\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number298 index297 alt1\u0026quot;\u0026gt;\n        298\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number299 index298 alt2\u0026quot;\u0026gt;\n        299\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number300 index299 alt1\u0026quot;\u0026gt;\n        300\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number301 index300 alt2\u0026quot;\u0026gt;\n        301\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number302 index301 alt1\u0026quot;\u0026gt;\n        302\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number303 index302 alt2\u0026quot;\u0026gt;\n        303\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number304 index303 alt1\u0026quot;\u0026gt;\n        304\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number305 index304 alt2\u0026quot;\u0026gt;\n        305\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number306 index305 alt1\u0026quot;\u0026gt;\n        306\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number307 index306 alt2\u0026quot;\u0026gt;\n        307\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number308 index307 alt1\u0026quot;\u0026gt;\n        308\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number309 index308 alt2\u0026quot;\u0026gt;\n        309\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number310 index309 alt1\u0026quot;\u0026gt;\n        310\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number311 index310 alt2\u0026quot;\u0026gt;\n        311\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number312 index311 alt1\u0026quot;\u0026gt;\n        312\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number313 index312 alt2\u0026quot;\u0026gt;\n        313\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number314 index313 alt1\u0026quot;\u0026gt;\n        314\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number315 index314 alt2\u0026quot;\u0026gt;\n        315\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number316 index315 alt1\u0026quot;\u0026gt;\n        316\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number317 index316 alt2\u0026quot;\u0026gt;\n        317\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number318 index317 alt1\u0026quot;\u0026gt;\n        318\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number319 index318 alt2\u0026quot;\u0026gt;\n        319\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number320 index319 alt1\u0026quot;\u0026gt;\n        320\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number321 index320 alt2\u0026quot;\u0026gt;\n        321\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number322 index321 alt1\u0026quot;\u0026gt;\n        322\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number323 index322 alt2\u0026quot;\u0026gt;\n        323\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number324 index323 alt1\u0026quot;\u0026gt;\n        324\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number325 index324 alt2\u0026quot;\u0026gt;\n        325\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number326 index325 alt1\u0026quot;\u0026gt;\n        326\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number327 index326 alt2\u0026quot;\u0026gt;\n        327\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number328 index327 alt1\u0026quot;\u0026gt;\n        328\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number329 index328 alt2\u0026quot;\u0026gt;\n        329\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number330 index329 alt1\u0026quot;\u0026gt;\n        330\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number331 index330 alt2\u0026quot;\u0026gt;\n        331\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number332 index331 alt1\u0026quot;\u0026gt;\n        332\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number333 index332 alt2\u0026quot;\u0026gt;\n        333\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number334 index333 alt1\u0026quot;\u0026gt;\n        334\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number335 index334 alt2\u0026quot;\u0026gt;\n        335\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number336 index335 alt1\u0026quot;\u0026gt;\n        336\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number337 index336 alt2\u0026quot;\u0026gt;\n        337\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number338 index337 alt1\u0026quot;\u0026gt;\n        338\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number339 index338 alt2\u0026quot;\u0026gt;\n        339\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number340 index339 alt1\u0026quot;\u0026gt;\n        340\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number341 index340 alt2\u0026quot;\u0026gt;\n        341\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number342 index341 alt1\u0026quot;\u0026gt;\n        342\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number343 index342 alt2\u0026quot;\u0026gt;\n        343\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number344 index343 alt1\u0026quot;\u0026gt;\n        344\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number345 index344 alt2\u0026quot;\u0026gt;\n        345\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number346 index345 alt1\u0026quot;\u0026gt;\n        346\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number347 index346 alt2\u0026quot;\u0026gt;\n        347\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number348 index347 alt1\u0026quot;\u0026gt;\n        348\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number349 index348 alt2\u0026quot;\u0026gt;\n        349\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number350 index349 alt1\u0026quot;\u0026gt;\n        350\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number351 index350 alt2\u0026quot;\u0026gt;\n        351\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number352 index351 alt1\u0026quot;\u0026gt;\n        352\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number353 index352 alt2\u0026quot;\u0026gt;\n        353\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number354 index353 alt1\u0026quot;\u0026gt;\n        354\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number355 index354 alt2\u0026quot;\u0026gt;\n        355\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number356 index355 alt1\u0026quot;\u0026gt;\n        356\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number357 index356 alt2\u0026quot;\u0026gt;\n        357\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number358 index357 alt1\u0026quot;\u0026gt;\n        358\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number359 index358 alt2\u0026quot;\u0026gt;\n        359\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number360 index359 alt1\u0026quot;\u0026gt;\n        360\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number361 index360 alt2\u0026quot;\u0026gt;\n        361\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number362 index361 alt1\u0026quot;\u0026gt;\n        362\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number363 index362 alt2\u0026quot;\u0026gt;\n        363\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number364 index363 alt1\u0026quot;\u0026gt;\n        364\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number365 index364 alt2\u0026quot;\u0026gt;\n        365\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number366 index365 alt1\u0026quot;\u0026gt;\n        366\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number367 index366 alt2\u0026quot;\u0026gt;\n        367\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number368 index367 alt1\u0026quot;\u0026gt;\n        368\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number369 index368 alt2\u0026quot;\u0026gt;\n        369\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number370 index369 alt1\u0026quot;\u0026gt;\n        370\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number371 index370 alt2\u0026quot;\u0026gt;\n        371\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number372 index371 alt1\u0026quot;\u0026gt;\n        372\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number373 index372 alt2\u0026quot;\u0026gt;\n        373\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number374 index373 alt1\u0026quot;\u0026gt;\n        374\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number375 index374 alt2\u0026quot;\u0026gt;\n        375\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number376 index375 alt1\u0026quot;\u0026gt;\n        376\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number377 index376 alt2\u0026quot;\u0026gt;\n        377\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number378 index377 alt1\u0026quot;\u0026gt;\n        378\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number379 index378 alt2\u0026quot;\u0026gt;\n        379\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number380 index379 alt1\u0026quot;\u0026gt;\n        380\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number381 index380 alt2\u0026quot;\u0026gt;\n        381\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number382 index381 alt1\u0026quot;\u0026gt;\n        382\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number383 index382 alt2\u0026quot;\u0026gt;\n        383\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number384 index383 alt1\u0026quot;\u0026gt;\n        384\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number385 index384 alt2\u0026quot;\u0026gt;\n        385\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number386 index385 alt1\u0026quot;\u0026gt;\n        386\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number387 index386 alt2\u0026quot;\u0026gt;\n        387\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number388 index387 alt1\u0026quot;\u0026gt;\n        388\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number389 index388 alt2\u0026quot;\u0026gt;\n        389\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number390 index389 alt1\u0026quot;\u0026gt;\n        390\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number391 index390 alt2\u0026quot;\u0026gt;\n        391\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number392 index391 alt1\u0026quot;\u0026gt;\n        392\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number393 index392 alt2\u0026quot;\u0026gt;\n        393\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number394 index393 alt1\u0026quot;\u0026gt;\n        394\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number395 index394 alt2\u0026quot;\u0026gt;\n        395\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number396 index395 alt1\u0026quot;\u0026gt;\n        396\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number397 index396 alt2\u0026quot;\u0026gt;\n        397\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number398 index397 alt1\u0026quot;\u0026gt;\n        398\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number399 index398 alt2\u0026quot;\u0026gt;\n        399\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number400 index399 alt1\u0026quot;\u0026gt;\n        400\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number401 index400 alt2\u0026quot;\u0026gt;\n        401\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number402 index401 alt1\u0026quot;\u0026gt;\n        402\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number403 index402 alt2\u0026quot;\u0026gt;\n        403\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number404 index403 alt1\u0026quot;\u0026gt;\n        404\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number405 index404 alt2\u0026quot;\u0026gt;\n        405\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number406 index405 alt1\u0026quot;\u0026gt;\n        406\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number407 index406 alt2\u0026quot;\u0026gt;\n        407\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number408 index407 alt1\u0026quot;\u0026gt;\n        408\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number409 index408 alt2\u0026quot;\u0026gt;\n        409\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number410 index409 alt1\u0026quot;\u0026gt;\n        410\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number411 index410 alt2\u0026quot;\u0026gt;\n        411\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number412 index411 alt1\u0026quot;\u0026gt;\n        412\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number413 index412 alt2\u0026quot;\u0026gt;\n        413\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number414 index413 alt1\u0026quot;\u0026gt;\n        414\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number415 index414 alt2\u0026quot;\u0026gt;\n        415\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number416 index415 alt1\u0026quot;\u0026gt;\n        416\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number417 index416 alt2\u0026quot;\u0026gt;\n        417\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number418 index417 alt1\u0026quot;\u0026gt;\n        418\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number419 index418 alt2\u0026quot;\u0026gt;\n        419\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number420 index419 alt1\u0026quot;\u0026gt;\n        420\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number421 index420 alt2\u0026quot;\u0026gt;\n        421\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number422 index421 alt1\u0026quot;\u0026gt;\n        422\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number423 index422 alt2\u0026quot;\u0026gt;\n        423\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number424 index423 alt1\u0026quot;\u0026gt;\n        424\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number425 index424 alt2\u0026quot;\u0026gt;\n        425\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number426 index425 alt1\u0026quot;\u0026gt;\n        426\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number427 index426 alt2\u0026quot;\u0026gt;\n        427\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number428 index427 alt1\u0026quot;\u0026gt;\n        428\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number429 index428 alt2\u0026quot;\u0026gt;\n        429\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number430 index429 alt1\u0026quot;\u0026gt;\n        430\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number431 index430 alt2\u0026quot;\u0026gt;\n        431\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number432 index431 alt1\u0026quot;\u0026gt;\n        432\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number433 index432 alt2\u0026quot;\u0026gt;\n        433\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number434 index433 alt1\u0026quot;\u0026gt;\n        434\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number435 index434 alt2\u0026quot;\u0026gt;\n        435\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number436 index435 alt1\u0026quot;\u0026gt;\n        436\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number437 index436 alt2\u0026quot;\u0026gt;\n        437\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number438 index437 alt1\u0026quot;\u0026gt;\n        438\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number439 index438 alt2\u0026quot;\u0026gt;\n        439\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number440 index439 alt1\u0026quot;\u0026gt;\n        440\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number441 index440 alt2\u0026quot;\u0026gt;\n        441\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number442 index441 alt1\u0026quot;\u0026gt;\n        442\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number443 index442 alt2\u0026quot;\u0026gt;\n        443\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number444 index443 alt1\u0026quot;\u0026gt;\n        444\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number445 index444 alt2\u0026quot;\u0026gt;\n        445\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number446 index445 alt1\u0026quot;\u0026gt;\n        446\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number447 index446 alt2\u0026quot;\u0026gt;\n        447\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number448 index447 alt1\u0026quot;\u0026gt;\n        448\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number449 index448 alt2\u0026quot;\u0026gt;\n        449\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number450 index449 alt1\u0026quot;\u0026gt;\n        450\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number451 index450 alt2\u0026quot;\u0026gt;\n        451\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number452 index451 alt1\u0026quot;\u0026gt;\n        452\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number453 index452 alt2\u0026quot;\u0026gt;\n        453\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number454 index453 alt1\u0026quot;\u0026gt;\n        454\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number455 index454 alt2\u0026quot;\u0026gt;\n        455\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number456 index455 alt1\u0026quot;\u0026gt;\n        456\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number457 index456 alt2\u0026quot;\u0026gt;\n        457\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number458 index457 alt1\u0026quot;\u0026gt;\n        458\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number459 index458 alt2\u0026quot;\u0026gt;\n        459\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number460 index459 alt1\u0026quot;\u0026gt;\n        460\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number461 index460 alt2\u0026quot;\u0026gt;\n        461\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number462 index461 alt1\u0026quot;\u0026gt;\n        462\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number463 index462 alt2\u0026quot;\u0026gt;\n        463\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number464 index463 alt1\u0026quot;\u0026gt;\n        464\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number465 index464 alt2\u0026quot;\u0026gt;\n        465\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number466 index465 alt1\u0026quot;\u0026gt;\n        466\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number467 index466 alt2\u0026quot;\u0026gt;\n        467\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number468 index467 alt1\u0026quot;\u0026gt;\n        468\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number469 index468 alt2\u0026quot;\u0026gt;\n        469\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number470 index469 alt1\u0026quot;\u0026gt;\n        470\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number471 index470 alt2\u0026quot;\u0026gt;\n        471\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number472 index471 alt1\u0026quot;\u0026gt;\n        472\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number473 index472 alt2\u0026quot;\u0026gt;\n        473\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number474 index473 alt1\u0026quot;\u0026gt;\n        474\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number475 index474 alt2\u0026quot;\u0026gt;\n        475\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number476 index475 alt1\u0026quot;\u0026gt;\n        476\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number477 index476 alt2\u0026quot;\u0026gt;\n        477\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number478 index477 alt1\u0026quot;\u0026gt;\n        478\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number479 index478 alt2\u0026quot;\u0026gt;\n        479\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number480 index479 alt1\u0026quot;\u0026gt;\n        480\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number481 index480 alt2\u0026quot;\u0026gt;\n        481\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number482 index481 alt1\u0026quot;\u0026gt;\n        482\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number483 index482 alt2\u0026quot;\u0026gt;\n        483\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number484 index483 alt1\u0026quot;\u0026gt;\n        484\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number485 index484 alt2\u0026quot;\u0026gt;\n        485\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number486 index485 alt1\u0026quot;\u0026gt;\n        486\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number487 index486 alt2\u0026quot;\u0026gt;\n        487\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number488 index487 alt1\u0026quot;\u0026gt;\n        488\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number489 index488 alt2\u0026quot;\u0026gt;\n        489\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number490 index489 alt1\u0026quot;\u0026gt;\n        490\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number491 index490 alt2\u0026quot;\u0026gt;\n        491\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number492 index491 alt1\u0026quot;\u0026gt;\n        492\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number493 index492 alt2\u0026quot;\u0026gt;\n        493\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number494 index493 alt1\u0026quot;\u0026gt;\n        494\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number495 index494 alt2\u0026quot;\u0026gt;\n        495\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number496 index495 alt1\u0026quot;\u0026gt;\n        496\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number497 index496 alt2\u0026quot;\u0026gt;\n        497\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number498 index497 alt1\u0026quot;\u0026gt;\n        498\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number499 index498 alt2\u0026quot;\u0026gt;\n        499\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number500 index499 alt1\u0026quot;\u0026gt;\n        500\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number501 index500 alt2\u0026quot;\u0026gt;\n        501\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number502 index501 alt1\u0026quot;\u0026gt;\n        502\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number503 index502 alt2\u0026quot;\u0026gt;\n        503\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number504 index503 alt1\u0026quot;\u0026gt;\n        504\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number505 index504 alt2\u0026quot;\u0026gt;\n        505\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number506 index505 alt1\u0026quot;\u0026gt;\n        506\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number507 index506 alt2\u0026quot;\u0026gt;\n        507\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number508 index507 alt1\u0026quot;\u0026gt;\n        508\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number509 index508 alt2\u0026quot;\u0026gt;\n        509\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number510 index509 alt1\u0026quot;\u0026gt;\n        510\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number511 index510 alt2\u0026quot;\u0026gt;\n        511\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number512 index511 alt1\u0026quot;\u0026gt;\n        512\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number513 index512 alt2\u0026quot;\u0026gt;\n        513\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number514 index513 alt1\u0026quot;\u0026gt;\n        514\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number515 index514 alt2\u0026quot;\u0026gt;\n        515\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number516 index515 alt1\u0026quot;\u0026gt;\n        516\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number517 index516 alt2\u0026quot;\u0026gt;\n        517\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number518 index517 alt1\u0026quot;\u0026gt;\n        518\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number519 index518 alt2\u0026quot;\u0026gt;\n        519\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number520 index519 alt1\u0026quot;\u0026gt;\n        520\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number521 index520 alt2\u0026quot;\u0026gt;\n        521\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number522 index521 alt1\u0026quot;\u0026gt;\n        522\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number523 index522 alt2\u0026quot;\u0026gt;\n        523\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number524 index523 alt1\u0026quot;\u0026gt;\n        524\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number525 index524 alt2\u0026quot;\u0026gt;\n        525\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number526 index525 alt1\u0026quot;\u0026gt;\n        526\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number527 index526 alt2\u0026quot;\u0026gt;\n        527\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number528 index527 alt1\u0026quot;\u0026gt;\n        528\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number529 index528 alt2\u0026quot;\u0026gt;\n        529\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number530 index529 alt1\u0026quot;\u0026gt;\n        530\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number531 index530 alt2\u0026quot;\u0026gt;\n        531\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number532 index531 alt1\u0026quot;\u0026gt;\n        532\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number533 index532 alt2\u0026quot;\u0026gt;\n        533\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number534 index533 alt1\u0026quot;\u0026gt;\n        534\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number535 index534 alt2\u0026quot;\u0026gt;\n        535\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number536 index535 alt1\u0026quot;\u0026gt;\n        536\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number537 index536 alt2\u0026quot;\u0026gt;\n        537\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number538 index537 alt1\u0026quot;\u0026gt;\n        538\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number539 index538 alt2\u0026quot;\u0026gt;\n        539\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number540 index539 alt1\u0026quot;\u0026gt;\n        540\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number541 index540 alt2\u0026quot;\u0026gt;\n        541\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number542 index541 alt1\u0026quot;\u0026gt;\n        542\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number543 index542 alt2\u0026quot;\u0026gt;\n        543\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number544 index543 alt1\u0026quot;\u0026gt;\n        544\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number545 index544 alt2\u0026quot;\u0026gt;\n        545\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number546 index545 alt1\u0026quot;\u0026gt;\n        546\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number547 index546 alt2\u0026quot;\u0026gt;\n        547\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number548 index547 alt1\u0026quot;\u0026gt;\n        548\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number549 index548 alt2\u0026quot;\u0026gt;\n        549\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number550 index549 alt1\u0026quot;\u0026gt;\n        550\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number551 index550 alt2\u0026quot;\u0026gt;\n        551\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number552 index551 alt1\u0026quot;\u0026gt;\n        552\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number553 index552 alt2\u0026quot;\u0026gt;\n        553\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number554 index553 alt1\u0026quot;\u0026gt;\n        554\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number555 index554 alt2\u0026quot;\u0026gt;\n        555\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number556 index555 alt1\u0026quot;\u0026gt;\n        556\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number557 index556 alt2\u0026quot;\u0026gt;\n        557\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number558 index557 alt1\u0026quot;\u0026gt;\n        558\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number559 index558 alt2\u0026quot;\u0026gt;\n        559\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number560 index559 alt1\u0026quot;\u0026gt;\n        560\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number561 index560 alt2\u0026quot;\u0026gt;\n        561\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number562 index561 alt1\u0026quot;\u0026gt;\n        562\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number563 index562 alt2\u0026quot;\u0026gt;\n        563\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number564 index563 alt1\u0026quot;\u0026gt;\n        564\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number565 index564 alt2\u0026quot;\u0026gt;\n        565\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number566 index565 alt1\u0026quot;\u0026gt;\n        566\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number567 index566 alt2\u0026quot;\u0026gt;\n        567\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number568 index567 alt1\u0026quot;\u0026gt;\n        568\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number569 index568 alt2\u0026quot;\u0026gt;\n        569\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number570 index569 alt1\u0026quot;\u0026gt;\n        570\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number571 index570 alt2\u0026quot;\u0026gt;\n        571\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number572 index571 alt1\u0026quot;\u0026gt;\n        572\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number573 index572 alt2\u0026quot;\u0026gt;\n        573\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number574 index573 alt1\u0026quot;\u0026gt;\n        574\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number575 index574 alt2\u0026quot;\u0026gt;\n        575\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number576 index575 alt1\u0026quot;\u0026gt;\n        576\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number577 index576 alt2\u0026quot;\u0026gt;\n        577\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number578 index577 alt1\u0026quot;\u0026gt;\n        578\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number579 index578 alt2\u0026quot;\u0026gt;\n        579\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number580 index579 alt1\u0026quot;\u0026gt;\n        580\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number581 index580 alt2\u0026quot;\u0026gt;\n        581\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number582 index581 alt1\u0026quot;\u0026gt;\n        582\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number583 index582 alt2\u0026quot;\u0026gt;\n        583\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number584 index583 alt1\u0026quot;\u0026gt;\n        584\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number585 index584 alt2\u0026quot;\u0026gt;\n        585\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number586 index585 alt1\u0026quot;\u0026gt;\n        586\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number587 index586 alt2\u0026quot;\u0026gt;\n        587\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number588 index587 alt1\u0026quot;\u0026gt;\n        588\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number589 index588 alt2\u0026quot;\u0026gt;\n        589\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number590 index589 alt1\u0026quot;\u0026gt;\n        590\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number591 index590 alt2\u0026quot;\u0026gt;\n        591\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number592 index591 alt1\u0026quot;\u0026gt;\n        592\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number593 index592 alt2\u0026quot;\u0026gt;\n        593\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number594 index593 alt1\u0026quot;\u0026gt;\n        594\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number595 index594 alt2\u0026quot;\u0026gt;\n        595\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number596 index595 alt1\u0026quot;\u0026gt;\n        596\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number597 index596 alt2\u0026quot;\u0026gt;\n        597\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number598 index597 alt1\u0026quot;\u0026gt;\n        598\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number599 index598 alt2\u0026quot;\u0026gt;\n        599\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number600 index599 alt1\u0026quot;\u0026gt;\n        600\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number601 index600 alt2\u0026quot;\u0026gt;\n        601\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number602 index601 alt1\u0026quot;\u0026gt;\n        602\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number603 index602 alt2\u0026quot;\u0026gt;\n        603\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number604 index603 alt1\u0026quot;\u0026gt;\n        604\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number605 index604 alt2\u0026quot;\u0026gt;\n        605\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number606 index605 alt1\u0026quot;\u0026gt;\n        606\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number607 index606 alt2\u0026quot;\u0026gt;\n        607\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number608 index607 alt1\u0026quot;\u0026gt;\n        608\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number609 index608 alt2\u0026quot;\u0026gt;\n        609\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number610 index609 alt1\u0026quot;\u0026gt;\n        610\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number611 index610 alt2\u0026quot;\u0026gt;\n        611\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number612 index611 alt1\u0026quot;\u0026gt;\n        612\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number613 index612 alt2\u0026quot;\u0026gt;\n        613\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number614 index613 alt1\u0026quot;\u0026gt;\n        614\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number615 index614 alt2\u0026quot;\u0026gt;\n        615\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number616 index615 alt1\u0026quot;\u0026gt;\n        616\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number617 index616 alt2\u0026quot;\u0026gt;\n        617\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number618 index617 alt1\u0026quot;\u0026gt;\n        618\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number619 index618 alt2\u0026quot;\u0026gt;\n        619\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number620 index619 alt1\u0026quot;\u0026gt;\n        620\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number621 index620 alt2\u0026quot;\u0026gt;\n        621\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number622 index621 alt1\u0026quot;\u0026gt;\n        622\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number623 index622 alt2\u0026quot;\u0026gt;\n        623\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number624 index623 alt1\u0026quot;\u0026gt;\n        624\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number625 index624 alt2\u0026quot;\u0026gt;\n        625\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number626 index625 alt1\u0026quot;\u0026gt;\n        626\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number627 index626 alt2\u0026quot;\u0026gt;\n        627\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number628 index627 alt1\u0026quot;\u0026gt;\n        628\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number629 index628 alt2\u0026quot;\u0026gt;\n        629\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number630 index629 alt1\u0026quot;\u0026gt;\n        630\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number631 index630 alt2\u0026quot;\u0026gt;\n        631\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number632 index631 alt1\u0026quot;\u0026gt;\n        632\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number633 index632 alt2\u0026quot;\u0026gt;\n        633\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number634 index633 alt1\u0026quot;\u0026gt;\n        634\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number635 index634 alt2\u0026quot;\u0026gt;\n        635\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number636 index635 alt1\u0026quot;\u0026gt;\n        636\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number637 index636 alt2\u0026quot;\u0026gt;\n        637\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number638 index637 alt1\u0026quot;\u0026gt;\n        638\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number639 index638 alt2\u0026quot;\u0026gt;\n        639\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number640 index639 alt1\u0026quot;\u0026gt;\n        640\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number641 index640 alt2\u0026quot;\u0026gt;\n        641\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number642 index641 alt1\u0026quot;\u0026gt;\n        642\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number643 index642 alt2\u0026quot;\u0026gt;\n        643\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number644 index643 alt1\u0026quot;\u0026gt;\n        644\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number645 index644 alt2\u0026quot;\u0026gt;\n        645\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number646 index645 alt1\u0026quot;\u0026gt;\n        646\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number647 index646 alt2\u0026quot;\u0026gt;\n        647\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number648 index647 alt1\u0026quot;\u0026gt;\n        648\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number649 index648 alt2\u0026quot;\u0026gt;\n        649\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number650 index649 alt1\u0026quot;\u0026gt;\n        650\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number651 index650 alt2\u0026quot;\u0026gt;\n        651\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number652 index651 alt1\u0026quot;\u0026gt;\n        652\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number653 index652 alt2\u0026quot;\u0026gt;\n        653\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number654 index653 alt1\u0026quot;\u0026gt;\n        654\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number655 index654 alt2\u0026quot;\u0026gt;\n        655\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number656 index655 alt1\u0026quot;\u0026gt;\n        656\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number657 index656 alt2\u0026quot;\u0026gt;\n        657\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number658 index657 alt1\u0026quot;\u0026gt;\n        658\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number659 index658 alt2\u0026quot;\u0026gt;\n        659\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number660 index659 alt1\u0026quot;\u0026gt;\n        660\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number661 index660 alt2\u0026quot;\u0026gt;\n        661\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number662 index661 alt1\u0026quot;\u0026gt;\n        662\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number663 index662 alt2\u0026quot;\u0026gt;\n        663\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number664 index663 alt1\u0026quot;\u0026gt;\n        664\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number665 index664 alt2\u0026quot;\u0026gt;\n        665\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number666 index665 alt1\u0026quot;\u0026gt;\n        666\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number667 index666 alt2\u0026quot;\u0026gt;\n        667\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number668 index667 alt1\u0026quot;\u0026gt;\n        668\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number669 index668 alt2\u0026quot;\u0026gt;\n        669\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number670 index669 alt1\u0026quot;\u0026gt;\n        670\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number671 index670 alt2\u0026quot;\u0026gt;\n        671\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number672 index671 alt1\u0026quot;\u0026gt;\n        672\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number673 index672 alt2\u0026quot;\u0026gt;\n        673\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number674 index673 alt1\u0026quot;\u0026gt;\n        674\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number675 index674 alt2\u0026quot;\u0026gt;\n        675\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number676 index675 alt1\u0026quot;\u0026gt;\n        676\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number677 index676 alt2\u0026quot;\u0026gt;\n        677\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number678 index677 alt1\u0026quot;\u0026gt;\n        678\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number679 index678 alt2\u0026quot;\u0026gt;\n        679\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number680 index679 alt1\u0026quot;\u0026gt;\n        680\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number681 index680 alt2\u0026quot;\u0026gt;\n        681\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number682 index681 alt1\u0026quot;\u0026gt;\n        682\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number683 index682 alt2\u0026quot;\u0026gt;\n        683\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number684 index683 alt1\u0026quot;\u0026gt;\n        684\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number685 index684 alt2\u0026quot;\u0026gt;\n        685\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number686 index685 alt1\u0026quot;\u0026gt;\n        686\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number687 index686 alt2\u0026quot;\u0026gt;\n        687\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number688 index687 alt1\u0026quot;\u0026gt;\n        688\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number689 index688 alt2\u0026quot;\u0026gt;\n        689\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number690 index689 alt1\u0026quot;\u0026gt;\n        690\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number691 index690 alt2\u0026quot;\u0026gt;\n        691\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number692 index691 alt1\u0026quot;\u0026gt;\n        692\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number693 index692 alt2\u0026quot;\u0026gt;\n        693\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number694 index693 alt1\u0026quot;\u0026gt;\n        694\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number695 index694 alt2\u0026quot;\u0026gt;\n        695\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number696 index695 alt1\u0026quot;\u0026gt;\n        696\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number697 index696 alt2\u0026quot;\u0026gt;\n        697\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number698 index697 alt1\u0026quot;\u0026gt;\n        698\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number699 index698 alt2\u0026quot;\u0026gt;\n        699\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number700 index699 alt1\u0026quot;\u0026gt;\n        700\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number701 index700 alt2\u0026quot;\u0026gt;\n        701\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number702 index701 alt1\u0026quot;\u0026gt;\n        702\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number703 index702 alt2\u0026quot;\u0026gt;\n        703\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number704 index703 alt1\u0026quot;\u0026gt;\n        704\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number705 index704 alt2\u0026quot;\u0026gt;\n        705\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number706 index705 alt1\u0026quot;\u0026gt;\n        706\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number707 index706 alt2\u0026quot;\u0026gt;\n        707\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number708 index707 alt1\u0026quot;\u0026gt;\n        708\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number709 index708 alt2\u0026quot;\u0026gt;\n        709\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number710 index709 alt1\u0026quot;\u0026gt;\n        710\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number711 index710 alt2\u0026quot;\u0026gt;\n        711\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number712 index711 alt1\u0026quot;\u0026gt;\n        712\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number713 index712 alt2\u0026quot;\u0026gt;\n        713\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number714 index713 alt1\u0026quot;\u0026gt;\n        714\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number715 index714 alt2\u0026quot;\u0026gt;\n        715\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number716 index715 alt1\u0026quot;\u0026gt;\n        716\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number717 index716 alt2\u0026quot;\u0026gt;\n        717\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number718 index717 alt1\u0026quot;\u0026gt;\n        718\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number719 index718 alt2\u0026quot;\u0026gt;\n        719\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number720 index719 alt1\u0026quot;\u0026gt;\n        720\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number721 index720 alt2\u0026quot;\u0026gt;\n        721\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number722 index721 alt1\u0026quot;\u0026gt;\n        722\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number723 index722 alt2\u0026quot;\u0026gt;\n        723\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number724 index723 alt1\u0026quot;\u0026gt;\n        724\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number725 index724 alt2\u0026quot;\u0026gt;\n        725\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number726 index725 alt1\u0026quot;\u0026gt;\n        726\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number727 index726 alt2\u0026quot;\u0026gt;\n        727\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number728 index727 alt1\u0026quot;\u0026gt;\n        728\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number729 index728 alt2\u0026quot;\u0026gt;\n        729\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number730 index729 alt1\u0026quot;\u0026gt;\n        730\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number731 index730 alt2\u0026quot;\u0026gt;\n        731\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number732 index731 alt1\u0026quot;\u0026gt;\n        732\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number733 index732 alt2\u0026quot;\u0026gt;\n        733\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number734 index733 alt1\u0026quot;\u0026gt;\n        734\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number735 index734 alt2\u0026quot;\u0026gt;\n        735\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number736 index735 alt1\u0026quot;\u0026gt;\n        736\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number737 index736 alt2\u0026quot;\u0026gt;\n        737\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number738 index737 alt1\u0026quot;\u0026gt;\n        738\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number739 index738 alt2\u0026quot;\u0026gt;\n        739\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number740 index739 alt1\u0026quot;\u0026gt;\n        740\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number741 index740 alt2\u0026quot;\u0026gt;\n        741\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number742 index741 alt1\u0026quot;\u0026gt;\n        742\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number743 index742 alt2\u0026quot;\u0026gt;\n        743\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number744 index743 alt1\u0026quot;\u0026gt;\n        744\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number745 index744 alt2\u0026quot;\u0026gt;\n        745\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number746 index745 alt1\u0026quot;\u0026gt;\n        746\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number747 index746 alt2\u0026quot;\u0026gt;\n        747\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number748 index747 alt1\u0026quot;\u0026gt;\n        748\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number749 index748 alt2\u0026quot;\u0026gt;\n        749\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number750 index749 alt1\u0026quot;\u0026gt;\n        750\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number751 index750 alt2\u0026quot;\u0026gt;\n        751\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number752 index751 alt1\u0026quot;\u0026gt;\n        752\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number753 index752 alt2\u0026quot;\u0026gt;\n        753\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number754 index753 alt1\u0026quot;\u0026gt;\n        754\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number755 index754 alt2\u0026quot;\u0026gt;\n        755\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number756 index755 alt1\u0026quot;\u0026gt;\n        756\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number757 index756 alt2\u0026quot;\u0026gt;\n        757\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number758 index757 alt1\u0026quot;\u0026gt;\n        758\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number759 index758 alt2\u0026quot;\u0026gt;\n        759\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number760 index759 alt1\u0026quot;\u0026gt;\n        760\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number761 index760 alt2\u0026quot;\u0026gt;\n        761\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number762 index761 alt1\u0026quot;\u0026gt;\n        762\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number763 index762 alt2\u0026quot;\u0026gt;\n        763\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number764 index763 alt1\u0026quot;\u0026gt;\n        764\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number765 index764 alt2\u0026quot;\u0026gt;\n        765\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number766 index765 alt1\u0026quot;\u0026gt;\n        766\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number767 index766 alt2\u0026quot;\u0026gt;\n        767\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number768 index767 alt1\u0026quot;\u0026gt;\n        768\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number769 index768 alt2\u0026quot;\u0026gt;\n        769\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number770 index769 alt1\u0026quot;\u0026gt;\n        770\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number771 index770 alt2\u0026quot;\u0026gt;\n        771\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number772 index771 alt1\u0026quot;\u0026gt;\n        772\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number773 index772 alt2\u0026quot;\u0026gt;\n        773\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number774 index773 alt1\u0026quot;\u0026gt;\n        774\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number775 index774 alt2\u0026quot;\u0026gt;\n        775\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number776 index775 alt1\u0026quot;\u0026gt;\n        776\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number777 index776 alt2\u0026quot;\u0026gt;\n        777\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number778 index777 alt1\u0026quot;\u0026gt;\n        778\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number779 index778 alt2\u0026quot;\u0026gt;\n        779\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number780 index779 alt1\u0026quot;\u0026gt;\n        780\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number781 index780 alt2\u0026quot;\u0026gt;\n        781\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number782 index781 alt1\u0026quot;\u0026gt;\n        782\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number783 index782 alt2\u0026quot;\u0026gt;\n        783\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number784 index783 alt1\u0026quot;\u0026gt;\n        784\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number785 index784 alt2\u0026quot;\u0026gt;\n        785\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number786 index785 alt1\u0026quot;\u0026gt;\n        786\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number787 index786 alt2\u0026quot;\u0026gt;\n        787\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number788 index787 alt1\u0026quot;\u0026gt;\n        788\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number789 index788 alt2\u0026quot;\u0026gt;\n        789\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number790 index789 alt1\u0026quot;\u0026gt;\n        790\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number791 index790 alt2\u0026quot;\u0026gt;\n        791\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number792 index791 alt1\u0026quot;\u0026gt;\n        792\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number793 index792 alt2\u0026quot;\u0026gt;\n        793\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number794 index793 alt1\u0026quot;\u0026gt;\n        794\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number795 index794 alt2\u0026quot;\u0026gt;\n        795\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number796 index795 alt1\u0026quot;\u0026gt;\n        796\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number797 index796 alt2\u0026quot;\u0026gt;\n        797\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number798 index797 alt1\u0026quot;\u0026gt;\n        798\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number799 index798 alt2\u0026quot;\u0026gt;\n        799\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number800 index799 alt1\u0026quot;\u0026gt;\n        800\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number801 index800 alt2\u0026quot;\u0026gt;\n        801\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number802 index801 alt1\u0026quot;\u0026gt;\n        802\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number803 index802 alt2\u0026quot;\u0026gt;\n        803\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number804 index803 alt1\u0026quot;\u0026gt;\n        804\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number805 index804 alt2\u0026quot;\u0026gt;\n        805\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number806 index805 alt1\u0026quot;\u0026gt;\n        806\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number807 index806 alt2\u0026quot;\u0026gt;\n        807\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number808 index807 alt1\u0026quot;\u0026gt;\n        808\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number809 index808 alt2\u0026quot;\u0026gt;\n        809\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number810 index809 alt1\u0026quot;\u0026gt;\n        810\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number811 index810 alt2\u0026quot;\u0026gt;\n        811\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number812 index811 alt1\u0026quot;\u0026gt;\n        812\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number813 index812 alt2\u0026quot;\u0026gt;\n        813\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number814 index813 alt1\u0026quot;\u0026gt;\n        814\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number815 index814 alt2\u0026quot;\u0026gt;\n        815\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number816 index815 alt1\u0026quot;\u0026gt;\n        816\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number817 index816 alt2\u0026quot;\u0026gt;\n        817\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number818 index817 alt1\u0026quot;\u0026gt;\n        818\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number819 index818 alt2\u0026quot;\u0026gt;\n        819\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number820 index819 alt1\u0026quot;\u0026gt;\n        820\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number821 index820 alt2\u0026quot;\u0026gt;\n        821\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number822 index821 alt1\u0026quot;\u0026gt;\n        822\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number823 index822 alt2\u0026quot;\u0026gt;\n        823\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number824 index823 alt1\u0026quot;\u0026gt;\n        824\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number825 index824 alt2\u0026quot;\u0026gt;\n        825\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number826 index825 alt1\u0026quot;\u0026gt;\n        826\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number827 index826 alt2\u0026quot;\u0026gt;\n        827\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number828 index827 alt1\u0026quot;\u0026gt;\n        828\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number829 index828 alt2\u0026quot;\u0026gt;\n        829\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number830 index829 alt1\u0026quot;\u0026gt;\n        830\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number831 index830 alt2\u0026quot;\u0026gt;\n        831\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number832 index831 alt1\u0026quot;\u0026gt;\n        832\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number833 index832 alt2\u0026quot;\u0026gt;\n        833\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number834 index833 alt1\u0026quot;\u0026gt;\n        834\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number835 index834 alt2\u0026quot;\u0026gt;\n        835\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number836 index835 alt1\u0026quot;\u0026gt;\n        836\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number837 index836 alt2\u0026quot;\u0026gt;\n        837\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number838 index837 alt1\u0026quot;\u0026gt;\n        838\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number839 index838 alt2\u0026quot;\u0026gt;\n        839\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number840 index839 alt1\u0026quot;\u0026gt;\n        840\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number841 index840 alt2\u0026quot;\u0026gt;\n        841\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number842 index841 alt1\u0026quot;\u0026gt;\n        842\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number843 index842 alt2\u0026quot;\u0026gt;\n        843\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number844 index843 alt1\u0026quot;\u0026gt;\n        844\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number845 index844 alt2\u0026quot;\u0026gt;\n        845\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number846 index845 alt1\u0026quot;\u0026gt;\n        846\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number847 index846 alt2\u0026quot;\u0026gt;\n        847\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number848 index847 alt1\u0026quot;\u0026gt;\n        848\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number849 index848 alt2\u0026quot;\u0026gt;\n        849\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number850 index849 alt1\u0026quot;\u0026gt;\n        850\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number851 index850 alt2\u0026quot;\u0026gt;\n        851\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number852 index851 alt1\u0026quot;\u0026gt;\n        852\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number853 index852 alt2\u0026quot;\u0026gt;\n        853\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number854 index853 alt1\u0026quot;\u0026gt;\n        854\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number855 index854 alt2\u0026quot;\u0026gt;\n        855\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number856 index855 alt1\u0026quot;\u0026gt;\n        856\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number857 index856 alt2\u0026quot;\u0026gt;\n        857\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number858 index857 alt1\u0026quot;\u0026gt;\n        858\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number859 index858 alt2\u0026quot;\u0026gt;\n        859\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number860 index859 alt1\u0026quot;\u0026gt;\n        860\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number861 index860 alt2\u0026quot;\u0026gt;\n        861\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number862 index861 alt1\u0026quot;\u0026gt;\n        862\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number863 index862 alt2\u0026quot;\u0026gt;\n        863\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number864 index863 alt1\u0026quot;\u0026gt;\n        864\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number865 index864 alt2\u0026quot;\u0026gt;\n        865\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number866 index865 alt1\u0026quot;\u0026gt;\n        866\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number867 index866 alt2\u0026quot;\u0026gt;\n        867\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number868 index867 alt1\u0026quot;\u0026gt;\n        868\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number869 index868 alt2\u0026quot;\u0026gt;\n        869\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number870 index869 alt1\u0026quot;\u0026gt;\n        870\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number871 index870 alt2\u0026quot;\u0026gt;\n        871\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number872 index871 alt1\u0026quot;\u0026gt;\n        872\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number873 index872 alt2\u0026quot;\u0026gt;\n        873\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number874 index873 alt1\u0026quot;\u0026gt;\n        874\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number875 index874 alt2\u0026quot;\u0026gt;\n        875\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number876 index875 alt1\u0026quot;\u0026gt;\n        876\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number877 index876 alt2\u0026quot;\u0026gt;\n        877\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number878 index877 alt1\u0026quot;\u0026gt;\n        878\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number879 index878 alt2\u0026quot;\u0026gt;\n        879\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number880 index879 alt1\u0026quot;\u0026gt;\n        880\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number881 index880 alt2\u0026quot;\u0026gt;\n        881\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number882 index881 alt1\u0026quot;\u0026gt;\n        882\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number883 index882 alt2\u0026quot;\u0026gt;\n        883\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number884 index883 alt1\u0026quot;\u0026gt;\n        884\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number885 index884 alt2\u0026quot;\u0026gt;\n        885\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number886 index885 alt1\u0026quot;\u0026gt;\n        886\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number887 index886 alt2\u0026quot;\u0026gt;\n        887\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number888 index887 alt1\u0026quot;\u0026gt;\n        888\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number889 index888 alt2\u0026quot;\u0026gt;\n        889\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number890 index889 alt1\u0026quot;\u0026gt;\n        890\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number891 index890 alt2\u0026quot;\u0026gt;\n        891\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number892 index891 alt1\u0026quot;\u0026gt;\n        892\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number893 index892 alt2\u0026quot;\u0026gt;\n        893\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number894 index893 alt1\u0026quot;\u0026gt;\n        894\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number895 index894 alt2\u0026quot;\u0026gt;\n        895\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number896 index895 alt1\u0026quot;\u0026gt;\n        896\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number897 index896 alt2\u0026quot;\u0026gt;\n        897\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number898 index897 alt1\u0026quot;\u0026gt;\n        898\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number899 index898 alt2\u0026quot;\u0026gt;\n        899\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number900 index899 alt1\u0026quot;\u0026gt;\n        900\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number901 index900 alt2\u0026quot;\u0026gt;\n        901\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number902 index901 alt1\u0026quot;\u0026gt;\n        902\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number903 index902 alt2\u0026quot;\u0026gt;\n        903\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number904 index903 alt1\u0026quot;\u0026gt;\n        904\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number905 index904 alt2\u0026quot;\u0026gt;\n        905\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number906 index905 alt1\u0026quot;\u0026gt;\n        906\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number907 index906 alt2\u0026quot;\u0026gt;\n        907\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number908 index907 alt1\u0026quot;\u0026gt;\n        908\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number909 index908 alt2\u0026quot;\u0026gt;\n        909\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number910 index909 alt1\u0026quot;\u0026gt;\n        910\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number911 index910 alt2\u0026quot;\u0026gt;\n        911\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number912 index911 alt1\u0026quot;\u0026gt;\n        912\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number913 index912 alt2\u0026quot;\u0026gt;\n        913\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number914 index913 alt1\u0026quot;\u0026gt;\n        914\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number915 index914 alt2\u0026quot;\u0026gt;\n        915\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number916 index915 alt1\u0026quot;\u0026gt;\n        916\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number917 index916 alt2\u0026quot;\u0026gt;\n        917\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number918 index917 alt1\u0026quot;\u0026gt;\n        918\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number919 index918 alt2\u0026quot;\u0026gt;\n        919\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number920 index919 alt1\u0026quot;\u0026gt;\n        920\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number921 index920 alt2\u0026quot;\u0026gt;\n        921\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number922 index921 alt1\u0026quot;\u0026gt;\n        922\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number923 index922 alt2\u0026quot;\u0026gt;\n        923\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number924 index923 alt1\u0026quot;\u0026gt;\n        924\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number925 index924 alt2\u0026quot;\u0026gt;\n        925\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number926 index925 alt1\u0026quot;\u0026gt;\n        926\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number927 index926 alt2\u0026quot;\u0026gt;\n        927\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number928 index927 alt1\u0026quot;\u0026gt;\n        928\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number929 index928 alt2\u0026quot;\u0026gt;\n        929\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number930 index929 alt1\u0026quot;\u0026gt;\n        930\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number931 index930 alt2\u0026quot;\u0026gt;\n        931\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number932 index931 alt1\u0026quot;\u0026gt;\n        932\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number933 index932 alt2\u0026quot;\u0026gt;\n        933\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number934 index933 alt1\u0026quot;\u0026gt;\n        934\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number935 index934 alt2\u0026quot;\u0026gt;\n        935\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number936 index935 alt1\u0026quot;\u0026gt;\n        936\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number937 index936 alt2\u0026quot;\u0026gt;\n        937\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number938 index937 alt1\u0026quot;\u0026gt;\n        938\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number939 index938 alt2\u0026quot;\u0026gt;\n        939\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number940 index939 alt1\u0026quot;\u0026gt;\n        940\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number941 index940 alt2\u0026quot;\u0026gt;\n        941\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number942 index941 alt1\u0026quot;\u0026gt;\n        942\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number943 index942 alt2\u0026quot;\u0026gt;\n        943\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number944 index943 alt1\u0026quot;\u0026gt;\n        944\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number945 index944 alt2\u0026quot;\u0026gt;\n        945\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number946 index945 alt1\u0026quot;\u0026gt;\n        946\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number947 index946 alt2\u0026quot;\u0026gt;\n        947\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number948 index947 alt1\u0026quot;\u0026gt;\n        948\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number949 index948 alt2\u0026quot;\u0026gt;\n        949\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number950 index949 alt1\u0026quot;\u0026gt;\n        950\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number951 index950 alt2\u0026quot;\u0026gt;\n        951\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number952 index951 alt1\u0026quot;\u0026gt;\n        952\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number953 index952 alt2\u0026quot;\u0026gt;\n        953\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number954 index953 alt1\u0026quot;\u0026gt;\n        954\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number955 index954 alt2\u0026quot;\u0026gt;\n        955\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number956 index955 alt1\u0026quot;\u0026gt;\n        956\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number957 index956 alt2\u0026quot;\u0026gt;\n        957\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number958 index957 alt1\u0026quot;\u0026gt;\n        958\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number959 index958 alt2\u0026quot;\u0026gt;\n        959\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number960 index959 alt1\u0026quot;\u0026gt;\n        960\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number961 index960 alt2\u0026quot;\u0026gt;\n        961\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number962 index961 alt1\u0026quot;\u0026gt;\n        962\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number963 index962 alt2\u0026quot;\u0026gt;\n        963\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number964 index963 alt1\u0026quot;\u0026gt;\n        964\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number965 index964 alt2\u0026quot;\u0026gt;\n        965\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number966 index965 alt1\u0026quot;\u0026gt;\n        966\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number967 index966 alt2\u0026quot;\u0026gt;\n        967\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number968 index967 alt1\u0026quot;\u0026gt;\n        968\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number969 index968 alt2\u0026quot;\u0026gt;\n        969\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number970 index969 alt1\u0026quot;\u0026gt;\n        970\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number971 index970 alt2\u0026quot;\u0026gt;\n        971\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number972 index971 alt1\u0026quot;\u0026gt;\n        972\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number973 index972 alt2\u0026quot;\u0026gt;\n        973\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number974 index973 alt1\u0026quot;\u0026gt;\n        974\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number975 index974 alt2\u0026quot;\u0026gt;\n        975\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number976 index975 alt1\u0026quot;\u0026gt;\n        976\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number977 index976 alt2\u0026quot;\u0026gt;\n        977\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number978 index977 alt1\u0026quot;\u0026gt;\n        978\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number979 index978 alt2\u0026quot;\u0026gt;\n        979\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number980 index979 alt1\u0026quot;\u0026gt;\n        980\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number981 index980 alt2\u0026quot;\u0026gt;\n        981\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number982 index981 alt1\u0026quot;\u0026gt;\n        982\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number983 index982 alt2\u0026quot;\u0026gt;\n        983\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number984 index983 alt1\u0026quot;\u0026gt;\n        984\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number985 index984 alt2\u0026quot;\u0026gt;\n        985\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number986 index985 alt1\u0026quot;\u0026gt;\n        986\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number987 index986 alt2\u0026quot;\u0026gt;\n        987\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number988 index987 alt1\u0026quot;\u0026gt;\n        988\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number989 index988 alt2\u0026quot;\u0026gt;\n        989\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number990 index989 alt1\u0026quot;\u0026gt;\n        990\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number991 index990 alt2\u0026quot;\u0026gt;\n        991\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number992 index991 alt1\u0026quot;\u0026gt;\n        992\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number993 index992 alt2\u0026quot;\u0026gt;\n        993\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number994 index993 alt1\u0026quot;\u0026gt;\n        994\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number995 index994 alt2\u0026quot;\u0026gt;\n        995\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number996 index995 alt1\u0026quot;\u0026gt;\n        996\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number997 index996 alt2\u0026quot;\u0026gt;\n        997\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number998 index997 alt1\u0026quot;\u0026gt;\n        998\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number999 index998 alt2\u0026quot;\u0026gt;\n        999\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1000 index999 alt1\u0026quot;\u0026gt;\n        1000\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1001 index1000 alt2\u0026quot;\u0026gt;\n        1001\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1002 index1001 alt1\u0026quot;\u0026gt;\n        1002\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1003 index1002 alt2\u0026quot;\u0026gt;\n        1003\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1004 index1003 alt1\u0026quot;\u0026gt;\n        1004\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1005 index1004 alt2\u0026quot;\u0026gt;\n        1005\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1006 index1005 alt1\u0026quot;\u0026gt;\n        1006\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1007 index1006 alt2\u0026quot;\u0026gt;\n        1007\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1008 index1007 alt1\u0026quot;\u0026gt;\n        1008\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1009 index1008 alt2\u0026quot;\u0026gt;\n        1009\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1010 index1009 alt1\u0026quot;\u0026gt;\n        1010\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1011 index1010 alt2\u0026quot;\u0026gt;\n        1011\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1012 index1011 alt1\u0026quot;\u0026gt;\n        1012\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1013 index1012 alt2\u0026quot;\u0026gt;\n        1013\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1014 index1013 alt1\u0026quot;\u0026gt;\n        1014\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1015 index1014 alt2\u0026quot;\u0026gt;\n        1015\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1016 index1015 alt1\u0026quot;\u0026gt;\n        1016\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1017 index1016 alt2\u0026quot;\u0026gt;\n        1017\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1018 index1017 alt1\u0026quot;\u0026gt;\n        1018\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1019 index1018 alt2\u0026quot;\u0026gt;\n        1019\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1020 index1019 alt1\u0026quot;\u0026gt;\n        1020\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1021 index1020 alt2\u0026quot;\u0026gt;\n        1021\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1022 index1021 alt1\u0026quot;\u0026gt;\n        1022\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1023 index1022 alt2\u0026quot;\u0026gt;\n        1023\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1024 index1023 alt1\u0026quot;\u0026gt;\n        1024\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1025 index1024 alt2\u0026quot;\u0026gt;\n        1025\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1026 index1025 alt1\u0026quot;\u0026gt;\n        1026\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1027 index1026 alt2\u0026quot;\u0026gt;\n        1027\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1028 index1027 alt1\u0026quot;\u0026gt;\n        1028\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1029 index1028 alt2\u0026quot;\u0026gt;\n        1029\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1030 index1029 alt1\u0026quot;\u0026gt;\n        1030\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1031 index1030 alt2\u0026quot;\u0026gt;\n        1031\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1032 index1031 alt1\u0026quot;\u0026gt;\n        1032\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1033 index1032 alt2\u0026quot;\u0026gt;\n        1033\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1034 index1033 alt1\u0026quot;\u0026gt;\n        1034\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1035 index1034 alt2\u0026quot;\u0026gt;\n        1035\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1036 index1035 alt1\u0026quot;\u0026gt;\n        1036\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1037 index1036 alt2\u0026quot;\u0026gt;\n        1037\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1038 index1037 alt1\u0026quot;\u0026gt;\n        1038\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1039 index1038 alt2\u0026quot;\u0026gt;\n        1039\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1040 index1039 alt1\u0026quot;\u0026gt;\n        1040\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1041 index1040 alt2\u0026quot;\u0026gt;\n        1041\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1042 index1041 alt1\u0026quot;\u0026gt;\n        1042\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1043 index1042 alt2\u0026quot;\u0026gt;\n        1043\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1044 index1043 alt1\u0026quot;\u0026gt;\n        1044\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1045 index1044 alt2\u0026quot;\u0026gt;\n        1045\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1046 index1045 alt1\u0026quot;\u0026gt;\n        1046\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1047 index1046 alt2\u0026quot;\u0026gt;\n        1047\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1048 index1047 alt1\u0026quot;\u0026gt;\n        1048\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1049 index1048 alt2\u0026quot;\u0026gt;\n        1049\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1050 index1049 alt1\u0026quot;\u0026gt;\n        1050\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1051 index1050 alt2\u0026quot;\u0026gt;\n        1051\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1052 index1051 alt1\u0026quot;\u0026gt;\n        1052\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1053 index1052 alt2\u0026quot;\u0026gt;\n        1053\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1054 index1053 alt1\u0026quot;\u0026gt;\n        1054\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1055 index1054 alt2\u0026quot;\u0026gt;\n        1055\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1056 index1055 alt1\u0026quot;\u0026gt;\n        1056\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1057 index1056 alt2\u0026quot;\u0026gt;\n        1057\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1058 index1057 alt1\u0026quot;\u0026gt;\n        1058\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1059 index1058 alt2\u0026quot;\u0026gt;\n        1059\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1060 index1059 alt1\u0026quot;\u0026gt;\n        1060\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1061 index1060 alt2\u0026quot;\u0026gt;\n        1061\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1062 index1061 alt1\u0026quot;\u0026gt;\n        1062\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1063 index1062 alt2\u0026quot;\u0026gt;\n        1063\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1064 index1063 alt1\u0026quot;\u0026gt;\n        1064\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1065 index1064 alt2\u0026quot;\u0026gt;\n        1065\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1066 index1065 alt1\u0026quot;\u0026gt;\n        1066\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1067 index1066 alt2\u0026quot;\u0026gt;\n        1067\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1068 index1067 alt1\u0026quot;\u0026gt;\n        1068\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1069 index1068 alt2\u0026quot;\u0026gt;\n        1069\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1070 index1069 alt1\u0026quot;\u0026gt;\n        1070\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1071 index1070 alt2\u0026quot;\u0026gt;\n        1071\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1072 index1071 alt1\u0026quot;\u0026gt;\n        1072\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1073 index1072 alt2\u0026quot;\u0026gt;\n        1073\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1074 index1073 alt1\u0026quot;\u0026gt;\n        1074\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1075 index1074 alt2\u0026quot;\u0026gt;\n        1075\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1076 index1075 alt1\u0026quot;\u0026gt;\n        1076\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1077 index1076 alt2\u0026quot;\u0026gt;\n        1077\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1078 index1077 alt1\u0026quot;\u0026gt;\n        1078\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1079 index1078 alt2\u0026quot;\u0026gt;\n        1079\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1080 index1079 alt1\u0026quot;\u0026gt;\n        1080\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1081 index1080 alt2\u0026quot;\u0026gt;\n        1081\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1082 index1081 alt1\u0026quot;\u0026gt;\n        1082\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1083 index1082 alt2\u0026quot;\u0026gt;\n        1083\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1084 index1083 alt1\u0026quot;\u0026gt;\n        1084\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1085 index1084 alt2\u0026quot;\u0026gt;\n        1085\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1086 index1085 alt1\u0026quot;\u0026gt;\n        1086\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1087 index1086 alt2\u0026quot;\u0026gt;\n        1087\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1088 index1087 alt1\u0026quot;\u0026gt;\n        1088\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1089 index1088 alt2\u0026quot;\u0026gt;\n        1089\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1090 index1089 alt1\u0026quot;\u0026gt;\n        1090\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1091 index1090 alt2\u0026quot;\u0026gt;\n        1091\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1092 index1091 alt1\u0026quot;\u0026gt;\n        1092\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1093 index1092 alt2\u0026quot;\u0026gt;\n        1093\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1094 index1093 alt1\u0026quot;\u0026gt;\n        1094\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1095 index1094 alt2\u0026quot;\u0026gt;\n        1095\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1096 index1095 alt1\u0026quot;\u0026gt;\n        1096\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1097 index1096 alt2\u0026quot;\u0026gt;\n        1097\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1098 index1097 alt1\u0026quot;\u0026gt;\n        1098\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1099 index1098 alt2\u0026quot;\u0026gt;\n        1099\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1100 index1099 alt1\u0026quot;\u0026gt;\n        1100\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1101 index1100 alt2\u0026quot;\u0026gt;\n        1101\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1102 index1101 alt1\u0026quot;\u0026gt;\n        1102\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1103 index1102 alt2\u0026quot;\u0026gt;\n        1103\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1104 index1103 alt1\u0026quot;\u0026gt;\n        1104\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1105 index1104 alt2\u0026quot;\u0026gt;\n        1105\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1106 index1105 alt1\u0026quot;\u0026gt;\n        1106\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1107 index1106 alt2\u0026quot;\u0026gt;\n        1107\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1108 index1107 alt1\u0026quot;\u0026gt;\n        1108\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1109 index1108 alt2\u0026quot;\u0026gt;\n        1109\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1110 index1109 alt1\u0026quot;\u0026gt;\n        1110\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1111 index1110 alt2\u0026quot;\u0026gt;\n        1111\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1112 index1111 alt1\u0026quot;\u0026gt;\n        1112\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1113 index1112 alt2\u0026quot;\u0026gt;\n        1113\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1114 index1113 alt1\u0026quot;\u0026gt;\n        1114\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1115 index1114 alt2\u0026quot;\u0026gt;\n        1115\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1116 index1115 alt1\u0026quot;\u0026gt;\n        1116\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1117 index1116 alt2\u0026quot;\u0026gt;\n        1117\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1118 index1117 alt1\u0026quot;\u0026gt;\n        1118\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1119 index1118 alt2\u0026quot;\u0026gt;\n        1119\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1120 index1119 alt1\u0026quot;\u0026gt;\n        1120\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1121 index1120 alt2\u0026quot;\u0026gt;\n        1121\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1122 index1121 alt1\u0026quot;\u0026gt;\n        1122\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1123 index1122 alt2\u0026quot;\u0026gt;\n        1123\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1124 index1123 alt1\u0026quot;\u0026gt;\n        1124\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1125 index1124 alt2\u0026quot;\u0026gt;\n        1125\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1126 index1125 alt1\u0026quot;\u0026gt;\n        1126\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1127 index1126 alt2\u0026quot;\u0026gt;\n        1127\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1128 index1127 alt1\u0026quot;\u0026gt;\n        1128\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1129 index1128 alt2\u0026quot;\u0026gt;\n        1129\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1130 index1129 alt1\u0026quot;\u0026gt;\n        1130\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1131 index1130 alt2\u0026quot;\u0026gt;\n        1131\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1132 index1131 alt1\u0026quot;\u0026gt;\n        1132\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1133 index1132 alt2\u0026quot;\u0026gt;\n        1133\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1134 index1133 alt1\u0026quot;\u0026gt;\n        1134\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1135 index1134 alt2\u0026quot;\u0026gt;\n        1135\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1136 index1135 alt1\u0026quot;\u0026gt;\n        1136\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1137 index1136 alt2\u0026quot;\u0026gt;\n        1137\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1138 index1137 alt1\u0026quot;\u0026gt;\n        1138\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1139 index1138 alt2\u0026quot;\u0026gt;\n        1139\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1140 index1139 alt1\u0026quot;\u0026gt;\n        1140\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1141 index1140 alt2\u0026quot;\u0026gt;\n        1141\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1142 index1141 alt1\u0026quot;\u0026gt;\n        1142\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1143 index1142 alt2\u0026quot;\u0026gt;\n        1143\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number1144 index1143 alt1\u0026quot;\u0026gt;\n        1144\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `public` `class` `SlidingMenu ``extends` `RelativeLayout {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `    ``private` `static` `final` `String TAG = SlidingMenu.``class``.getSimpleName();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          `    ``public` `static` `final` `int` `SLIDING_WINDOW = ````;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n          `    ``public` `static` `final` `int` `SLIDING_CONTENT = ``1``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n          `    ``private` `boolean` `mActionbarOverlay = ``false``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n          `     ``* Constant value for use with setTouchModeAbove(). Allows the SlidingMenu`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n          `     ``* to be opened with a swipe gesture on the screen's margin`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n          `    ``public` `static` `final` `int` `TOUCHMODE_MARGIN = ````;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n          `     ``* Constant value for use with setTouchModeAbove(). Allows the SlidingMenu`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n          `     ``* to be opened with a swipe gesture anywhere on the screen`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n          `    ``public` `static` `final` `int` `TOUCHMODE_FULLSCREEN = ``1``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n          `     ``* Constant value for use with setTouchModeAbove(). Denies the SlidingMenu`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n          `     ``* to be opened with a swipe gesture`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n          `    ``public` `static` `final` `int` `TOUCHMODE_NONE = ``2``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n          `     ``* Constant value for use with setMode(). Puts the menu to the left of the`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n          `     ``* content.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n          `    ``public` `static` `final` `int` `LEFT = ````;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt;\n          `     ``* Constant value for use with setMode(). Puts the menu to the right of the`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt;\n          `     ``* content.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt;\n          `    ``public` `static` `final` `int` `RIGHT = ``1``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt;\n          `     ``* Constant value for use with setMode(). Puts menus to the left and right`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt;\n          `     ``* of the content.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt;\n          `    ``public` `static` `final` `int` `LEFT_RIGHT = ``2``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt;\n          `    ``private` `CustomViewAbove mViewAbove;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt;\n          `    ``private` `CustomViewBehind mViewBehind;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt;\n          `        ``/** 整体的背景，用一个ImageView代替 */`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt;\n          `    ``private` `ImageView mViewBackground;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt;\n          `    ``private` `OnOpenListener mOpenListener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt;\n          `    ``private` `OnOpenListener mSecondaryOpenListner;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt;\n          `    ``private` `OnCloseListener mCloseListener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt;\n          `     ``* The listener interface for receiving onOpen events. The class that is`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt;\n          `     ``* interested in processing a onOpen event implements this interface, and`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt;\n          `     ``* the object created with that class is registered with a component using`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt;\n          `     ``* the component's \u0026amp;lt;code\u0026amp;gt;addOnOpenListener\u0026amp;lt;code\u0026amp;gt; method. When`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt;\n          `     ``* the onOpen event occurs, that object's appropriate`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt;\n          `     ``* method is invoked`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt;\n          `    ``public` `interface` `OnOpenListener {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt;\n          `        ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt;\n          `         ``* On open.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt;\n          `         ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt;\n          `        ``public` `void` `onOpen();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt;\n          `     ``* The listener interface for receiving onOpened events. The class that is`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt;\n          `     ``* interested in processing a onOpened event implements this interface, and`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt;\n          `     ``* the object created with that class is registered with a component using`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt;\n          `     ``* the component's \u0026amp;lt;code\u0026amp;gt;addOnOpenedListener\u0026amp;lt;code\u0026amp;gt; method. When`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt;\n          `     ``* the onOpened event occurs, that object's appropriate`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt;\n          `     ``* method is invoked.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt;\n          `     ``* @see OnOpenedEvent`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt;\n          `    ``public` `interface` `OnOpenedListener {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt;\n          `        ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt;\n          `         ``* On opened.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt;\n          `         ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt;\n          `        ``public` `void` `onOpened();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt;\n          `     ``* The listener interface for receiving onClose events. The class that is`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt;\n          `     ``* interested in processing a onClose event implements this interface, and`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt;\n          `     ``* the object created with that class is registered with a component using`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt;\n          `     ``* the component's \u0026amp;lt;code\u0026amp;gt;addOnCloseListener\u0026amp;lt;code\u0026amp;gt; method. When`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt;\n          `     ``* the onClose event occurs, that object's appropriate`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt;\n          `     ``* method is invoked.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt;\n          `     ``* @see OnCloseEvent`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number101 index100 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number102 index101 alt1\u0026quot;\u0026gt;\n          `    ``public` `interface` `OnCloseListener {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number103 index102 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number104 index103 alt1\u0026quot;\u0026gt;\n          `        ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number105 index104 alt2\u0026quot;\u0026gt;\n          `         ``* On close.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number106 index105 alt1\u0026quot;\u0026gt;\n          `         ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number107 index106 alt2\u0026quot;\u0026gt;\n          `        ``public` `void` `onClose();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number108 index107 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number109 index108 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number110 index109 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number111 index110 alt2\u0026quot;\u0026gt;\n          `     ``* The listener interface for receiving onClosed events. The class that is`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number112 index111 alt1\u0026quot;\u0026gt;\n          `     ``* interested in processing a onClosed event implements this interface, and`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number113 index112 alt2\u0026quot;\u0026gt;\n          `     ``* the object created with that class is registered with a component using`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number114 index113 alt1\u0026quot;\u0026gt;\n          `     ``* the component's \u0026amp;lt;code\u0026amp;gt;addOnClosedListener\u0026amp;lt;code\u0026amp;gt; method. When`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number115 index114 alt2\u0026quot;\u0026gt;\n          `     ``* the onClosed event occurs, that object's appropriate`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number116 index115 alt1\u0026quot;\u0026gt;\n          `     ``* method is invoked.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number117 index116 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number118 index117 alt1\u0026quot;\u0026gt;\n          `     ``* @see OnClosedEvent`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number119 index118 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number120 index119 alt1\u0026quot;\u0026gt;\n          `    ``public` `interface` `OnClosedListener {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number121 index120 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number122 index121 alt1\u0026quot;\u0026gt;\n          `        ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number123 index122 alt2\u0026quot;\u0026gt;\n          `         ``* On closed.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number124 index123 alt1\u0026quot;\u0026gt;\n          `         ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number125 index124 alt2\u0026quot;\u0026gt;\n          `        ``public` `void` `onClosed();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number126 index125 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number127 index126 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number128 index127 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number129 index128 alt2\u0026quot;\u0026gt;\n          `     ``* The Interface CanvasTransformer.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number130 index129 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number131 index130 alt2\u0026quot;\u0026gt;\n          `    ``public` `interface` `CanvasTransformer {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number132 index131 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number133 index132 alt2\u0026quot;\u0026gt;\n          `        ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number134 index133 alt1\u0026quot;\u0026gt;\n          `         ``* Transform canvas.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number135 index134 alt2\u0026quot;\u0026gt;\n          `         ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number136 index135 alt1\u0026quot;\u0026gt;\n          `         ``* @param canvas`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number137 index136 alt2\u0026quot;\u0026gt;\n          `         ``*            the canvas`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number138 index137 alt1\u0026quot;\u0026gt;\n          `         ``* @param percentOpen`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number139 index138 alt2\u0026quot;\u0026gt;\n          `         ``*            the percent open`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number140 index139 alt1\u0026quot;\u0026gt;\n          `         ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number141 index140 alt2\u0026quot;\u0026gt;\n          `        ``public` `void` `transformCanvas(Canvas canvas, ``float` `percentOpen);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number142 index141 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number143 index142 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number144 index143 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number145 index144 alt2\u0026quot;\u0026gt;\n          `     ``* Instantiates a new SlidingMenu.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number146 index145 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number147 index146 alt2\u0026quot;\u0026gt;\n          `     ``* @param context`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number148 index147 alt1\u0026quot;\u0026gt;\n          `     ``*            the associated Context`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number149 index148 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number150 index149 alt1\u0026quot;\u0026gt;\n          `    ``public` `SlidingMenu(Context context) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number151 index150 alt2\u0026quot;\u0026gt;\n          `        ``this``(context, ``null``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number152 index151 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number153 index152 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number154 index153 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number155 index154 alt2\u0026quot;\u0026gt;\n          `     ``* Instantiates a new SlidingMenu and attach to Activity.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number156 index155 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number157 index156 alt2\u0026quot;\u0026gt;\n          `     ``* @param activity`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number158 index157 alt1\u0026quot;\u0026gt;\n          `     ``*            the activity to attach slidingmenu`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number159 index158 alt2\u0026quot;\u0026gt;\n          `     ``* @param slideStyle`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number160 index159 alt1\u0026quot;\u0026gt;\n          `     ``*            the slidingmenu style`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number161 index160 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number162 index161 alt1\u0026quot;\u0026gt;\n          `    ``public` `SlidingMenu(Activity activity, ``int` `slideStyle) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number163 index162 alt2\u0026quot;\u0026gt;\n          `        ``this``(activity, ``null``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number164 index163 alt1\u0026quot;\u0026gt;\n          `        ``this``.attachToActivity(activity, slideStyle);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number165 index164 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number166 index165 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number167 index166 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number168 index167 alt1\u0026quot;\u0026gt;\n          `     ``* Instantiates a new SlidingMenu.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number169 index168 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number170 index169 alt1\u0026quot;\u0026gt;\n          `     ``* @param context`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number171 index170 alt2\u0026quot;\u0026gt;\n          `     ``*            the associated Context`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number172 index171 alt1\u0026quot;\u0026gt;\n          `     ``* @param attrs`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number173 index172 alt2\u0026quot;\u0026gt;\n          `     ``*            the attrs`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number174 index173 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number175 index174 alt2\u0026quot;\u0026gt;\n          `    ``public` `SlidingMenu(Context context, AttributeSet attrs) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number176 index175 alt1\u0026quot;\u0026gt;\n          `        ``this``(context, attrs, ````);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number177 index176 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number178 index177 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number179 index178 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number180 index179 alt1\u0026quot;\u0026gt;\n          `     ``* Instantiates a new SlidingMenu.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number181 index180 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number182 index181 alt1\u0026quot;\u0026gt;\n          `     ``* @param context`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number183 index182 alt2\u0026quot;\u0026gt;\n          `     ``*            the associated Context`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number184 index183 alt1\u0026quot;\u0026gt;\n          `     ``* @param attrs`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number185 index184 alt2\u0026quot;\u0026gt;\n          `     ``*            the attrs`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number186 index185 alt1\u0026quot;\u0026gt;\n          `     ``* @param defStyle`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number187 index186 alt2\u0026quot;\u0026gt;\n          `     ``*            the def style`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number188 index187 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number189 index188 alt2\u0026quot;\u0026gt;\n          `    ``public` `SlidingMenu(Context context, AttributeSet attrs, ``int` `defStyle) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number190 index189 alt1\u0026quot;\u0026gt;\n          `        ``super``(context, attrs, defStyle);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number191 index190 alt2\u0026quot;\u0026gt;\n          `                ``/** SlidingMenu是一个RelativeLayout，这里把背景图ImageView添加到RelativeLayout的最底层。*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number192 index191 alt1\u0026quot;\u0026gt;\n          `        ``LayoutParams backgroundParams = ``new` `LayoutParams(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number193 index192 alt2\u0026quot;\u0026gt;\n          `                ``LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number194 index193 alt1\u0026quot;\u0026gt;\n          `        ``mViewBackground = ``new` `ImageView(context);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number195 index194 alt2\u0026quot;\u0026gt;\n          `        ``mViewBackground.setScaleType(ImageView.ScaleType.CENTER_CROP);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number196 index195 alt1\u0026quot;\u0026gt;\n          `        ``addView(mViewBackground, backgroundParams);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number197 index196 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number198 index197 alt1\u0026quot;\u0026gt;\n          `                ``LayoutParams behindParams = ``new` `LayoutParams(LayoutParams.MATCH_PARENT,`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number199 index198 alt2\u0026quot;\u0026gt;\n          `                ``LayoutParams.MATCH_PARENT);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number200 index199 alt1\u0026quot;\u0026gt;\n          `        ``mViewBehind = ``new` `CustomViewBehind(context);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number201 index200 alt2\u0026quot;\u0026gt;\n          `        ``addView(mViewBehind, behindParams);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number202 index201 alt1\u0026quot;\u0026gt;\n          `        ``LayoutParams aboveParams = ``new` `LayoutParams(LayoutParams.MATCH_PARENT,`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number203 index202 alt2\u0026quot;\u0026gt;\n          `                ``LayoutParams.MATCH_PARENT);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number204 index203 alt1\u0026quot;\u0026gt;\n          `        ``mViewAbove = ``new` `CustomViewAbove(context);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number205 index204 alt2\u0026quot;\u0026gt;\n          `        ``addView(mViewAbove, aboveParams);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number206 index205 alt1\u0026quot;\u0026gt;\n          `        ``// register the CustomViewBehind with the CustomViewAbove`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number207 index206 alt2\u0026quot;\u0026gt;\n          `        ``mViewAbove.setCustomViewBehind(mViewBehind);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number208 index207 alt1\u0026quot;\u0026gt;\n          `        ``mViewBehind.setCustomViewAbove(mViewAbove);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number209 index208 alt2\u0026quot;\u0026gt;\n          `        ``mViewAbove.setOnPageChangeListener(``new` `OnPageChangeListener() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number210 index209 alt1\u0026quot;\u0026gt;\n          `            ``public` `static` `final` `int` `POSITION_OPEN = ````;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number211 index210 alt2\u0026quot;\u0026gt;\n          `            ``public` `static` `final` `int` `POSITION_CLOSE = ``1``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number212 index211 alt1\u0026quot;\u0026gt;\n          `            ``public` `static` `final` `int` `POSITION_SECONDARY_OPEN = ``2``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number213 index212 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number214 index213 alt1\u0026quot;\u0026gt;\n          `            ``public` `void` `onPageScrolled(``int` `position, ``float` `positionOffset,`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number215 index214 alt2\u0026quot;\u0026gt;\n          `                    ``int` `positionOffsetPixels) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number216 index215 alt1\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number217 index216 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number218 index217 alt1\u0026quot;\u0026gt;\n          `            ``public` `void` `onPageSelected(``int` `position) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number219 index218 alt2\u0026quot;\u0026gt;\n          `                ``if` `(position == POSITION_OPEN \u0026amp;\u0026amp; mOpenListener != ``null``) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number220 index219 alt1\u0026quot;\u0026gt;\n          `                    ``mOpenListener.onOpen();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number221 index220 alt2\u0026quot;\u0026gt;\n          `                ``} ``else` `if` `(position == POSITION_CLOSE \u0026amp;\u0026amp; mCloseListener != ``null``) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number222 index221 alt1\u0026quot;\u0026gt;\n          `                    ``mCloseListener.onClose();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number223 index222 alt2\u0026quot;\u0026gt;\n          `                ``} ``else` `if` `(position == POSITION_SECONDARY_OPEN`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number224 index223 alt1\u0026quot;\u0026gt;\n          `                        ``\u0026amp;\u0026amp; mSecondaryOpenListner != ``null``) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number225 index224 alt2\u0026quot;\u0026gt;\n          `                    ``mSecondaryOpenListner.onOpen();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number226 index225 alt1\u0026quot;\u0026gt;\n          `                ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number227 index226 alt2\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number228 index227 alt1\u0026quot;\u0026gt;\n          `        ``});`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number229 index228 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number230 index229 alt1\u0026quot;\u0026gt;\n          `        ``// now style everything!`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number231 index230 alt2\u0026quot;\u0026gt;\n          `        ``TypedArray ta = context.obtainStyledAttributes(attrs,`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number232 index231 alt1\u0026quot;\u0026gt;\n          `                ``R.styleable.SlidingMenu);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number233 index232 alt2\u0026quot;\u0026gt;\n          `        ``// set the above and behind views if defined in xml`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number234 index233 alt1\u0026quot;\u0026gt;\n          `        ``int` `mode = ta.getInt(R.styleable.SlidingMenu_mode, LEFT);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number235 index234 alt2\u0026quot;\u0026gt;\n          `        ``setMode(mode);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number236 index235 alt1\u0026quot;\u0026gt;\n          `        ``int` `viewAbove = ta.getResourceId(R.styleable.SlidingMenu_viewAbove, -``1``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number237 index236 alt2\u0026quot;\u0026gt;\n          `        ``if` `(viewAbove != -``1``) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number238 index237 alt1\u0026quot;\u0026gt;\n          `            ``setContent(viewAbove);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number239 index238 alt2\u0026quot;\u0026gt;\n          `        ``} ``else` `{`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number240 index239 alt1\u0026quot;\u0026gt;\n          `            ``setContent(``new` `FrameLayout(context));`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number241 index240 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number242 index241 alt1\u0026quot;\u0026gt;\n          `        ``int` `viewBehind = ta.getResourceId(R.styleable.SlidingMenu_viewBehind,`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number243 index242 alt2\u0026quot;\u0026gt;\n          `                ``-``1``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number244 index243 alt1\u0026quot;\u0026gt;\n          `        ``if` `(viewBehind != -``1``) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number245 index244 alt2\u0026quot;\u0026gt;\n          `            ``setMenu(viewBehind);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number246 index245 alt1\u0026quot;\u0026gt;\n          `        ``} ``else` `{`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number247 index246 alt2\u0026quot;\u0026gt;\n          `            ``setMenu(``new` `FrameLayout(context));`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number248 index247 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number249 index248 alt2\u0026quot;\u0026gt;\n          `        ``int` `touchModeAbove = ta.getInt(R.styleable.SlidingMenu_touchModeAbove,`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number250 index249 alt1\u0026quot;\u0026gt;\n          `                ``TOUCHMODE_MARGIN);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number251 index250 alt2\u0026quot;\u0026gt;\n          `        ``setTouchModeAbove(touchModeAbove);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number252 index251 alt1\u0026quot;\u0026gt;\n          `        ``int` `touchModeBehind = ta.getInt(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number253 index252 alt2\u0026quot;\u0026gt;\n          `                ``R.styleable.SlidingMenu_touchModeBehind, TOUCHMODE_MARGIN);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number254 index253 alt1\u0026quot;\u0026gt;\n          `        ``setTouchModeBehind(touchModeBehind);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number255 index254 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number256 index255 alt1\u0026quot;\u0026gt;\n          `        ``int` `offsetBehind = (``int``) ta.getDimension(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number257 index256 alt2\u0026quot;\u0026gt;\n          `                ``R.styleable.SlidingMenu_behindOffset, -``1``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number258 index257 alt1\u0026quot;\u0026gt;\n          `        ``int` `widthBehind = (``int``) ta.getDimension(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number259 index258 alt2\u0026quot;\u0026gt;\n          `                ``R.styleable.SlidingMenu_behindWidth, -``1``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number260 index259 alt1\u0026quot;\u0026gt;\n          `        ``if` `(offsetBehind != -``1` `\u0026amp;\u0026amp; widthBehind != -``1``)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number261 index260 alt2\u0026quot;\u0026gt;\n          `            ``throw` `new` `IllegalStateException(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number262 index261 alt1\u0026quot;\u0026gt;\n          `                    ``\u0026quot;Cannot set both behindOffset and behindWidth for a SlidingMenu\u0026quot;``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number263 index262 alt2\u0026quot;\u0026gt;\n          `        ``else` `if` `(offsetBehind != -``1``)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number264 index263 alt1\u0026quot;\u0026gt;\n          `            ``setBehindOffset(offsetBehind);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number265 index264 alt2\u0026quot;\u0026gt;\n          `        ``else` `if` `(widthBehind != -``1``)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number266 index265 alt1\u0026quot;\u0026gt;\n          `            ``setBehindWidth(widthBehind);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number267 index266 alt2\u0026quot;\u0026gt;\n          `        ``else`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number268 index267 alt1\u0026quot;\u0026gt;\n          `            ``setBehindOffset(````);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number269 index268 alt2\u0026quot;\u0026gt;\n          `        ``float` `scrollOffsetBehind = ta.getFloat(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number270 index269 alt1\u0026quot;\u0026gt;\n          `                ``R.styleable.SlidingMenu_behindScrollScale, ````.33f);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number271 index270 alt2\u0026quot;\u0026gt;\n          `        ``setBehindScrollScale(scrollOffsetBehind);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number272 index271 alt1\u0026quot;\u0026gt;\n          `        ``int` `shadowRes = ta.getResourceId(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number273 index272 alt2\u0026quot;\u0026gt;\n          `                ``R.styleable.SlidingMenu_shadowDrawable, -``1``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number274 index273 alt1\u0026quot;\u0026gt;\n          `        ``if` `(shadowRes != -``1``) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number275 index274 alt2\u0026quot;\u0026gt;\n          `            ``setShadowDrawable(shadowRes);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number276 index275 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number277 index276 alt2\u0026quot;\u0026gt;\n          `        ``int` `shadowWidth = (``int``) ta.getDimension(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number278 index277 alt1\u0026quot;\u0026gt;\n          `                ``R.styleable.SlidingMenu_shadowWidth, ````);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number279 index278 alt2\u0026quot;\u0026gt;\n          `        ``setShadowWidth(shadowWidth);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number280 index279 alt1\u0026quot;\u0026gt;\n          `        ``boolean` `fadeEnabled = ta.getBoolean(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number281 index280 alt2\u0026quot;\u0026gt;\n          `                ``R.styleable.SlidingMenu_fadeEnabled, ``true``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number282 index281 alt1\u0026quot;\u0026gt;\n          `        ``setFadeEnabled(fadeEnabled);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number283 index282 alt2\u0026quot;\u0026gt;\n          `        ``float` `fadeDeg = ta.getFloat(R.styleable.SlidingMenu_fadeDegree, ````.33f);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number284 index283 alt1\u0026quot;\u0026gt;\n          `        ``setFadeDegree(fadeDeg);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number285 index284 alt2\u0026quot;\u0026gt;\n          `        ``boolean` `selectorEnabled = ta.getBoolean(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number286 index285 alt1\u0026quot;\u0026gt;\n          `                ``R.styleable.SlidingMenu_selectorEnabled, ``false``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number287 index286 alt2\u0026quot;\u0026gt;\n          `        ``setSelectorEnabled(selectorEnabled);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number288 index287 alt1\u0026quot;\u0026gt;\n          `        ``int` `selectorRes = ta.getResourceId(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number289 index288 alt2\u0026quot;\u0026gt;\n          `                ``R.styleable.SlidingMenu_selectorDrawable, -``1``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number290 index289 alt1\u0026quot;\u0026gt;\n          `        ``if` `(selectorRes != -``1``)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number291 index290 alt2\u0026quot;\u0026gt;\n          `            ``setSelectorDrawable(selectorRes);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number292 index291 alt1\u0026quot;\u0026gt;\n          `        ``ta.recycle();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number293 index292 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number294 index293 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number295 index294 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number296 index295 alt1\u0026quot;\u0026gt;\n          `     ``* Attaches the SlidingMenu to an entire Activity`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number297 index296 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number298 index297 alt1\u0026quot;\u0026gt;\n          `     ``* @param activity`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number299 index298 alt2\u0026quot;\u0026gt;\n          `     ``*            the Activity`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number300 index299 alt1\u0026quot;\u0026gt;\n          `     ``* @param slideStyle`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number301 index300 alt2\u0026quot;\u0026gt;\n          `     ``*            either SLIDING_CONTENT or SLIDING_WINDOW`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number302 index301 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number303 index302 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `attachToActivity(Activity activity, ``int` `slideStyle) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number304 index303 alt1\u0026quot;\u0026gt;\n          `        ``attachToActivity(activity, slideStyle, ``false``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number305 index304 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number306 index305 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number307 index306 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number308 index307 alt1\u0026quot;\u0026gt;\n          `     ``* Attaches the SlidingMenu to an entire Activity`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number309 index308 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number310 index309 alt1\u0026quot;\u0026gt;\n          `     ``* @param activity`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number311 index310 alt2\u0026quot;\u0026gt;\n          `     ``*            the Activity`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number312 index311 alt1\u0026quot;\u0026gt;\n          `     ``* @param slideStyle`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number313 index312 alt2\u0026quot;\u0026gt;\n          `     ``*            either SLIDING_CONTENT or SLIDING_WINDOW`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number314 index313 alt1\u0026quot;\u0026gt;\n          `     ``* @param actionbarOverlay`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number315 index314 alt2\u0026quot;\u0026gt;\n          `     ``*            whether or not the ActionBar is overlaid`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number316 index315 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number317 index316 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `attachToActivity(Activity activity, ``int` `slideStyle,`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number318 index317 alt1\u0026quot;\u0026gt;\n          `            ``boolean` `actionbarOverlay) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number319 index318 alt2\u0026quot;\u0026gt;\n          `        ``if` `(slideStyle != SLIDING_WINDOW \u0026amp;\u0026amp; slideStyle != SLIDING_CONTENT)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number320 index319 alt1\u0026quot;\u0026gt;\n          `            ``throw` `new` `IllegalArgumentException(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number321 index320 alt2\u0026quot;\u0026gt;\n          `                    ``\u0026quot;slideStyle must be either SLIDING_WINDOW or SLIDING_CONTENT\u0026quot;``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number322 index321 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number323 index322 alt2\u0026quot;\u0026gt;\n          `        ``if` `(getParent() != ``null``)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number324 index323 alt1\u0026quot;\u0026gt;\n          `            ``throw` `new` `IllegalStateException(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number325 index324 alt2\u0026quot;\u0026gt;\n          `                    ``\u0026quot;This SlidingMenu appears to already be attached\u0026quot;``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number326 index325 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number327 index326 alt2\u0026quot;\u0026gt;\n          `        ``// get the window background`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number328 index327 alt1\u0026quot;\u0026gt;\n          `        ``TypedArray a = activity.getTheme().obtainStyledAttributes(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number329 index328 alt2\u0026quot;\u0026gt;\n          `                ``new` `int``[] { android.R.attr.windowBackground });`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number330 index329 alt1\u0026quot;\u0026gt;\n          `        ``int` `background = a.getResourceId(````, ````);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number331 index330 alt2\u0026quot;\u0026gt;\n          `        ``a.recycle();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number332 index331 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number333 index332 alt2\u0026quot;\u0026gt;\n          `        ``switch` `(slideStyle) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number334 index333 alt1\u0026quot;\u0026gt;\n          `        ``case` `SLIDING_WINDOW:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number335 index334 alt2\u0026quot;\u0026gt;\n          `            ``mActionbarOverlay = ``false``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number336 index335 alt1\u0026quot;\u0026gt;\n          `            ``ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number337 index336 alt2\u0026quot;\u0026gt;\n          `            ``ViewGroup decorChild = (ViewGroup) decor.getChildAt(````);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number338 index337 alt1\u0026quot;\u0026gt;\n          `            ``// save ActionBar themes that have transparent assets`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number339 index338 alt2\u0026quot;\u0026gt;\n          `            ``decorChild.setBackgroundResource(background);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number340 index339 alt1\u0026quot;\u0026gt;\n          `            ``decor.removeView(decorChild);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number341 index340 alt2\u0026quot;\u0026gt;\n          `            ``decor.addView(``this``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number342 index341 alt1\u0026quot;\u0026gt;\n          `            ``setContent(decorChild);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number343 index342 alt2\u0026quot;\u0026gt;\n          `            ``break``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number344 index343 alt1\u0026quot;\u0026gt;\n          `        ``case` `SLIDING_CONTENT:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number345 index344 alt2\u0026quot;\u0026gt;\n          `            ``mActionbarOverlay = actionbarOverlay;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number346 index345 alt1\u0026quot;\u0026gt;\n          `            ``// take the above view out of`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number347 index346 alt2\u0026quot;\u0026gt;\n          `            ``ViewGroup contentParent = (ViewGroup) activity`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number348 index347 alt1\u0026quot;\u0026gt;\n          `                    ``.findViewById(android.R.id.content);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number349 index348 alt2\u0026quot;\u0026gt;\n          `            ``View content = contentParent.getChildAt(````);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number350 index349 alt1\u0026quot;\u0026gt;\n          `            ``contentParent.removeView(content);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number351 index350 alt2\u0026quot;\u0026gt;\n          `            ``contentParent.addView(``this``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number352 index351 alt1\u0026quot;\u0026gt;\n          `            ``setContent(content);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number353 index352 alt2\u0026quot;\u0026gt;\n          `            ``// save people from having transparent backgrounds`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number354 index353 alt1\u0026quot;\u0026gt;\n          `            ``if` `(content.getBackground() == ``null``)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number355 index354 alt2\u0026quot;\u0026gt;\n          `                ``content.setBackgroundResource(background);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number356 index355 alt1\u0026quot;\u0026gt;\n          `            ``break``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number357 index356 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number358 index357 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number359 index358 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number360 index359 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number361 index360 alt2\u0026quot;\u0026gt;\n          `     ``* Set the above view content from a layout resource. The resource will be`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number362 index361 alt1\u0026quot;\u0026gt;\n          `     ``* inflated, adding all top-level views to the above view.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number363 index362 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number364 index363 alt1\u0026quot;\u0026gt;\n          `     ``* @param res`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number365 index364 alt2\u0026quot;\u0026gt;\n          `     ``*            the new content`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number366 index365 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number367 index366 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setContent(``int` `res) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number368 index367 alt1\u0026quot;\u0026gt;\n          `        ``setContent(LayoutInflater.from(getContext()).inflate(res, ``null``));`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number369 index368 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number370 index369 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number371 index370 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number372 index371 alt1\u0026quot;\u0026gt;\n          `     ``* Set the above view content to the given View.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number373 index372 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number374 index373 alt1\u0026quot;\u0026gt;\n          `     ``* @param view`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number375 index374 alt2\u0026quot;\u0026gt;\n          `     ``*            The desired content to display.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number376 index375 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number377 index376 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setContent(View view) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number378 index377 alt1\u0026quot;\u0026gt;\n          `        ``mViewAbove.setContent(view);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number379 index378 alt2\u0026quot;\u0026gt;\n          `        ``showContent();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number380 index379 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number381 index380 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number382 index381 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number383 index382 alt2\u0026quot;\u0026gt;\n          `     ``* 设置背景图片`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number384 index383 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number385 index384 alt2\u0026quot;\u0026gt;\n          `     ``* @param resid`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number386 index385 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number387 index386 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setBackgroundImage(``int` `resid) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number388 index387 alt1\u0026quot;\u0026gt;\n          `        ``mViewBackground.setBackgroundResource(resid);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number389 index388 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number390 index389 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number391 index390 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number392 index391 alt1\u0026quot;\u0026gt;\n          `     ``* Retrieves the current content.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number393 index392 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number394 index393 alt1\u0026quot;\u0026gt;\n          `     ``* @return the current content`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number395 index394 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number396 index395 alt1\u0026quot;\u0026gt;\n          `    ``public` `View getContent() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number397 index396 alt2\u0026quot;\u0026gt;\n          `        ``return` `mViewAbove.getContent();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number398 index397 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number399 index398 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number400 index399 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number401 index400 alt2\u0026quot;\u0026gt;\n          `     ``* Set the behind view (menu) content from a layout resource. The resource`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number402 index401 alt1\u0026quot;\u0026gt;\n          `     ``* will be inflated, adding all top-level views to the behind view.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number403 index402 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number404 index403 alt1\u0026quot;\u0026gt;\n          `     ``* @param res`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number405 index404 alt2\u0026quot;\u0026gt;\n          `     ``*            the new content`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number406 index405 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number407 index406 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setMenu(``int` `res) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number408 index407 alt1\u0026quot;\u0026gt;\n          `        ``setMenu(LayoutInflater.from(getContext()).inflate(res, ``null``));`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number409 index408 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number410 index409 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number411 index410 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number412 index411 alt1\u0026quot;\u0026gt;\n          `     ``* Set the behind view (menu) content to the given View.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number413 index412 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number414 index413 alt1\u0026quot;\u0026gt;\n          `     ``* @param view`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number415 index414 alt2\u0026quot;\u0026gt;\n          `     ``*            The desired content to display.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number416 index415 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number417 index416 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setMenu(View v) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number418 index417 alt1\u0026quot;\u0026gt;\n          `        ``mViewBehind.setContent(v);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number419 index418 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number420 index419 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number421 index420 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number422 index421 alt1\u0026quot;\u0026gt;\n          `     ``* Retrieves the main menu.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number423 index422 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number424 index423 alt1\u0026quot;\u0026gt;\n          `     ``* @return the main menu`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number425 index424 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number426 index425 alt1\u0026quot;\u0026gt;\n          `    ``public` `View getMenu() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number427 index426 alt2\u0026quot;\u0026gt;\n          `        ``return` `mViewBehind.getContent();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number428 index427 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number429 index428 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number430 index429 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number431 index430 alt2\u0026quot;\u0026gt;\n          `     ``* Set the secondary behind view (right menu) content from a layout`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number432 index431 alt1\u0026quot;\u0026gt;\n          `     ``* resource. The resource will be inflated, adding all top-level views to`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number433 index432 alt2\u0026quot;\u0026gt;\n          `     ``* the behind view.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number434 index433 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number435 index434 alt2\u0026quot;\u0026gt;\n          `     ``* @param res`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number436 index435 alt1\u0026quot;\u0026gt;\n          `     ``*            the new content`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number437 index436 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number438 index437 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setSecondaryMenu(``int` `res) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number439 index438 alt2\u0026quot;\u0026gt;\n          `        ``setSecondaryMenu(LayoutInflater.from(getContext()).inflate(res, ``null``));`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number440 index439 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number441 index440 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number442 index441 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number443 index442 alt2\u0026quot;\u0026gt;\n          `     ``* Set the secondary behind view (right menu) content to the given View.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number444 index443 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number445 index444 alt2\u0026quot;\u0026gt;\n          `     ``* @param view`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number446 index445 alt1\u0026quot;\u0026gt;\n          `     ``*            The desired content to display.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number447 index446 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number448 index447 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setSecondaryMenu(View v) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number449 index448 alt2\u0026quot;\u0026gt;\n          `        ``mViewBehind.setSecondaryContent(v);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number450 index449 alt1\u0026quot;\u0026gt;\n          `        ``// mViewBehind.invalidate();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number451 index450 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number452 index451 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number453 index452 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number454 index453 alt1\u0026quot;\u0026gt;\n          `     ``* Retrieves the current secondary menu (right).`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number455 index454 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number456 index455 alt1\u0026quot;\u0026gt;\n          `     ``* @return the current menu`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number457 index456 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number458 index457 alt1\u0026quot;\u0026gt;\n          `    ``public` `View getSecondaryMenu() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number459 index458 alt2\u0026quot;\u0026gt;\n          `        ``return` `mViewBehind.getSecondaryContent();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number460 index459 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number461 index460 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number462 index461 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number463 index462 alt2\u0026quot;\u0026gt;\n          `     ``* Sets the sliding enabled.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number464 index463 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number465 index464 alt2\u0026quot;\u0026gt;\n          `     ``* @param b`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number466 index465 alt1\u0026quot;\u0026gt;\n          `     ``*            true to enable sliding, false to disable it.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number467 index466 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number468 index467 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setSlidingEnabled(``boolean` `b) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number469 index468 alt2\u0026quot;\u0026gt;\n          `        ``mViewAbove.setSlidingEnabled(b);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number470 index469 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number471 index470 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number472 index471 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number473 index472 alt2\u0026quot;\u0026gt;\n          `     ``* Checks if is sliding enabled.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number474 index473 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number475 index474 alt2\u0026quot;\u0026gt;\n          `     ``* @return true, if is sliding enabled`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number476 index475 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number477 index476 alt2\u0026quot;\u0026gt;\n          `    ``public` `boolean` `isSlidingEnabled() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number478 index477 alt1\u0026quot;\u0026gt;\n          `        ``return` `mViewAbove.isSlidingEnabled();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number479 index478 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number480 index479 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number481 index480 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number482 index481 alt1\u0026quot;\u0026gt;\n          `     ``* Sets which side the SlidingMenu should appear on.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number483 index482 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number484 index483 alt1\u0026quot;\u0026gt;\n          `     ``* @param mode`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number485 index484 alt2\u0026quot;\u0026gt;\n          `     ``*            must be either SlidingMenu.LEFT or SlidingMenu.RIGHT`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number486 index485 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number487 index486 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setMode(``int` `mode) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number488 index487 alt1\u0026quot;\u0026gt;\n          `        ``if` `(mode != LEFT \u0026amp;\u0026amp; mode != RIGHT \u0026amp;\u0026amp; mode != LEFT_RIGHT) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number489 index488 alt2\u0026quot;\u0026gt;\n          `            ``throw` `new` `IllegalStateException(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number490 index489 alt1\u0026quot;\u0026gt;\n          `                    ``\u0026quot;SlidingMenu mode must be LEFT, RIGHT, or LEFT_RIGHT\u0026quot;``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number491 index490 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number492 index491 alt1\u0026quot;\u0026gt;\n          `        ``mViewBehind.setMode(mode);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number493 index492 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number494 index493 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number495 index494 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number496 index495 alt1\u0026quot;\u0026gt;\n          `     ``* Returns the current side that the SlidingMenu is on.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number497 index496 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number498 index497 alt1\u0026quot;\u0026gt;\n          `     ``* @return the current mode, either SlidingMenu.LEFT or SlidingMenu.RIGHT`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number499 index498 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number500 index499 alt1\u0026quot;\u0026gt;\n          `    ``public` `int` `getMode() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number501 index500 alt2\u0026quot;\u0026gt;\n          `        ``return` `mViewBehind.getMode();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number502 index501 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number503 index502 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number504 index503 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number505 index504 alt2\u0026quot;\u0026gt;\n          `     ``* Sets whether or not the SlidingMenu is in static mode (i.e. nothing is`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number506 index505 alt1\u0026quot;\u0026gt;\n          `     ``* moving and everything is showing)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number507 index506 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number508 index507 alt1\u0026quot;\u0026gt;\n          `     ``* @param b`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number509 index508 alt2\u0026quot;\u0026gt;\n          `     ``*            true to set static mode, false to disable static mode.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number510 index509 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number511 index510 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setStatic(``boolean` `b) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number512 index511 alt1\u0026quot;\u0026gt;\n          `        ``if` `(b) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number513 index512 alt2\u0026quot;\u0026gt;\n          `            ``setSlidingEnabled(``false``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number514 index513 alt1\u0026quot;\u0026gt;\n          `            ``mViewAbove.setCustomViewBehind(``null``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number515 index514 alt2\u0026quot;\u0026gt;\n          `            ``mViewAbove.setCurrentItem(``1``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number516 index515 alt1\u0026quot;\u0026gt;\n          `            ``// mViewBehind.setCurrentItem(0);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number517 index516 alt2\u0026quot;\u0026gt;\n          `        ``} ``else` `{`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number518 index517 alt1\u0026quot;\u0026gt;\n          `            ``mViewAbove.setCurrentItem(``1``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number519 index518 alt2\u0026quot;\u0026gt;\n          `            ``// mViewBehind.setCurrentItem(1);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number520 index519 alt1\u0026quot;\u0026gt;\n          `            ``mViewAbove.setCustomViewBehind(mViewBehind);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number521 index520 alt2\u0026quot;\u0026gt;\n          `            ``setSlidingEnabled(``true``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number522 index521 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number523 index522 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number524 index523 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number525 index524 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number526 index525 alt1\u0026quot;\u0026gt;\n          `     ``* Opens the menu and shows the menu view.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number527 index526 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number528 index527 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `showMenu() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number529 index528 alt2\u0026quot;\u0026gt;\n          `        ``showMenu(``true``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number530 index529 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number531 index530 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number532 index531 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number533 index532 alt2\u0026quot;\u0026gt;\n          `     ``* Opens the menu and shows the menu view.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number534 index533 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number535 index534 alt2\u0026quot;\u0026gt;\n          `     ``* @param animate`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number536 index535 alt1\u0026quot;\u0026gt;\n          `     ``*            true to animate the transition, false to ignore animation`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number537 index536 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number538 index537 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `showMenu(``boolean` `animate) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number539 index538 alt2\u0026quot;\u0026gt;\n          `        ``mViewAbove.setCurrentItem(````, animate);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number540 index539 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number541 index540 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number542 index541 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number543 index542 alt2\u0026quot;\u0026gt;\n          `     ``* Opens the menu and shows the secondary menu view. Will default to the`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number544 index543 alt1\u0026quot;\u0026gt;\n          `     ``* regular menu if there is only one.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number545 index544 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number546 index545 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `showSecondaryMenu() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number547 index546 alt2\u0026quot;\u0026gt;\n          `        ``showSecondaryMenu(``true``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number548 index547 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number549 index548 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number550 index549 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number551 index550 alt2\u0026quot;\u0026gt;\n          `     ``* Opens the menu and shows the secondary (right) menu view. Will default to`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number552 index551 alt1\u0026quot;\u0026gt;\n          `     ``* the regular menu if there is only one.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number553 index552 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number554 index553 alt1\u0026quot;\u0026gt;\n          `     ``* @param animate`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number555 index554 alt2\u0026quot;\u0026gt;\n          `     ``*            true to animate the transition, false to ignore animation`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number556 index555 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number557 index556 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `showSecondaryMenu(``boolean` `animate) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number558 index557 alt1\u0026quot;\u0026gt;\n          `        ``mViewAbove.setCurrentItem(``2``, animate);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number559 index558 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number560 index559 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number561 index560 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number562 index561 alt1\u0026quot;\u0026gt;\n          `     ``* Closes the menu and shows the above view.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number563 index562 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number564 index563 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `showContent() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number565 index564 alt2\u0026quot;\u0026gt;\n          `        ``showContent(``true``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number566 index565 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number567 index566 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number568 index567 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number569 index568 alt2\u0026quot;\u0026gt;\n          `     ``* Closes the menu and shows the above view.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number570 index569 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number571 index570 alt2\u0026quot;\u0026gt;\n          `     ``* @param animate`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number572 index571 alt1\u0026quot;\u0026gt;\n          `     ``*            true to animate the transition, false to ignore animation`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number573 index572 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number574 index573 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `showContent(``boolean` `animate) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number575 index574 alt2\u0026quot;\u0026gt;\n          `        ``mViewAbove.setCurrentItem(``1``, animate);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number576 index575 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number577 index576 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number578 index577 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number579 index578 alt2\u0026quot;\u0026gt;\n          `     ``* Toggle the SlidingMenu. If it is open, it will be closed, and vice versa.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number580 index579 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number581 index580 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `toggle() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number582 index581 alt1\u0026quot;\u0026gt;\n          `        ``toggle(``true``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number583 index582 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number584 index583 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number585 index584 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number586 index585 alt1\u0026quot;\u0026gt;\n          `     ``* Toggle the SlidingMenu. If it is open, it will be closed, and vice versa.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number587 index586 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number588 index587 alt1\u0026quot;\u0026gt;\n          `     ``* @param animate`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number589 index588 alt2\u0026quot;\u0026gt;\n          `     ``*            true to animate the transition, false to ignore animation`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number590 index589 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number591 index590 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `toggle(``boolean` `animate) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number592 index591 alt1\u0026quot;\u0026gt;\n          `        ``if` `(isMenuShowing()) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number593 index592 alt2\u0026quot;\u0026gt;\n          `            ``showContent(animate);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number594 index593 alt1\u0026quot;\u0026gt;\n          `        ``} ``else` `{`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number595 index594 alt2\u0026quot;\u0026gt;\n          `            ``showMenu(animate);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number596 index595 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number597 index596 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number598 index597 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number599 index598 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number600 index599 alt1\u0026quot;\u0026gt;\n          `     ``* Checks if is the behind view showing.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number601 index600 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number602 index601 alt1\u0026quot;\u0026gt;\n          `     ``* @return Whether or not the behind view is showing`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number603 index602 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number604 index603 alt1\u0026quot;\u0026gt;\n          `    ``public` `boolean` `isMenuShowing() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number605 index604 alt2\u0026quot;\u0026gt;\n          `        ``return` `mViewAbove.getCurrentItem() == ```\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number606 index605 alt1\u0026quot;\u0026gt;\n          `                ``|| mViewAbove.getCurrentItem() == ``2``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number607 index606 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number608 index607 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number609 index608 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number610 index609 alt1\u0026quot;\u0026gt;\n          `     ``* Checks if is the behind view showing.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number611 index610 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number612 index611 alt1\u0026quot;\u0026gt;\n          `     ``* @return Whether or not the behind view is showing`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number613 index612 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number614 index613 alt1\u0026quot;\u0026gt;\n          `    ``public` `boolean` `isSecondaryMenuShowing() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number615 index614 alt2\u0026quot;\u0026gt;\n          `        ``return` `mViewAbove.getCurrentItem() == ``2``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number616 index615 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number617 index616 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number618 index617 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number619 index618 alt2\u0026quot;\u0026gt;\n          `     ``* Gets the behind offset.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number620 index619 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number621 index620 alt2\u0026quot;\u0026gt;\n          `     ``* @return The margin on the right of the screen that the behind view`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number622 index621 alt1\u0026quot;\u0026gt;\n          `     ``*         scrolls to`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number623 index622 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number624 index623 alt1\u0026quot;\u0026gt;\n          `    ``public` `int` `getBehindOffset() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number625 index624 alt2\u0026quot;\u0026gt;\n          `        ``return` `((RelativeLayout.LayoutParams) mViewBehind.getLayoutParams()).rightMargin;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number626 index625 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number627 index626 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number628 index627 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number629 index628 alt2\u0026quot;\u0026gt;\n          `     ``* Sets the behind offset.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number630 index629 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number631 index630 alt2\u0026quot;\u0026gt;\n          `     ``* @param i`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number632 index631 alt1\u0026quot;\u0026gt;\n          `     ``*            The margin, in pixels, on the right of the screen that the`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number633 index632 alt2\u0026quot;\u0026gt;\n          `     ``*            behind view scrolls to.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number634 index633 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number635 index634 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setBehindOffset(``int` `i) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number636 index635 alt1\u0026quot;\u0026gt;\n          `        ``// RelativeLayout.LayoutParams params =`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number637 index636 alt2\u0026quot;\u0026gt;\n          `        ``// ((RelativeLayout.LayoutParams)mViewBehind.getLayoutParams());`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number638 index637 alt1\u0026quot;\u0026gt;\n          `        ``// int bottom = params.bottomMargin;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number639 index638 alt2\u0026quot;\u0026gt;\n          `        ``// int top = params.topMargin;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number640 index639 alt1\u0026quot;\u0026gt;\n          `        ``// int left = params.leftMargin;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number641 index640 alt2\u0026quot;\u0026gt;\n          `        ``// params.setMargins(left, top, i, bottom);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number642 index641 alt1\u0026quot;\u0026gt;\n          `        ``mViewBehind.setWidthOffset(i);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number643 index642 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number644 index643 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number645 index644 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number646 index645 alt1\u0026quot;\u0026gt;\n          `     ``* Sets the behind offset.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number647 index646 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number648 index647 alt1\u0026quot;\u0026gt;\n          `     ``* @param resID`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number649 index648 alt2\u0026quot;\u0026gt;\n          `     ``*            The dimension resource id to be set as the behind offset. The`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number650 index649 alt1\u0026quot;\u0026gt;\n          `     ``*            menu, when open, will leave this width margin on the right of`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number651 index650 alt2\u0026quot;\u0026gt;\n          `     ``*            the screen.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number652 index651 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number653 index652 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setBehindOffsetRes(``int` `resID) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number654 index653 alt1\u0026quot;\u0026gt;\n          `        ``int` `i = (``int``) getContext().getResources().getDimension(resID);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number655 index654 alt2\u0026quot;\u0026gt;\n          `        ``setBehindOffset(i);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number656 index655 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number657 index656 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number658 index657 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number659 index658 alt2\u0026quot;\u0026gt;\n          `     ``* Sets the above offset.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number660 index659 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number661 index660 alt2\u0026quot;\u0026gt;\n          `     ``* @param i`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number662 index661 alt1\u0026quot;\u0026gt;\n          `     ``*            the new above offset, in pixels`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number663 index662 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number664 index663 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setAboveOffset(``int` `i) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number665 index664 alt2\u0026quot;\u0026gt;\n          `        ``mViewAbove.setAboveOffset(i);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number666 index665 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number667 index666 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number668 index667 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number669 index668 alt2\u0026quot;\u0026gt;\n          `     ``* Sets the above offset.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number670 index669 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number671 index670 alt2\u0026quot;\u0026gt;\n          `     ``* @param resID`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number672 index671 alt1\u0026quot;\u0026gt;\n          `     ``*            The dimension resource id to be set as the above offset.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number673 index672 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number674 index673 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setAboveOffsetRes(``int` `resID) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number675 index674 alt2\u0026quot;\u0026gt;\n          `        ``int` `i = (``int``) getContext().getResources().getDimension(resID);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number676 index675 alt1\u0026quot;\u0026gt;\n          `        ``setAboveOffset(i);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number677 index676 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number678 index677 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number679 index678 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number680 index679 alt1\u0026quot;\u0026gt;\n          `     ``* Sets the behind width.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number681 index680 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number682 index681 alt1\u0026quot;\u0026gt;\n          `     ``* @param i`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number683 index682 alt2\u0026quot;\u0026gt;\n          `     ``*            The width the Sliding Menu will open to, in pixels`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number684 index683 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number685 index684 alt2\u0026quot;\u0026gt;\n          `    ``@SuppressWarnings``(``\u0026quot;deprecation\u0026quot;``)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number686 index685 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setBehindWidth(``int` `i) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number687 index686 alt2\u0026quot;\u0026gt;\n          `        ``int` `width;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number688 index687 alt1\u0026quot;\u0026gt;\n          `        ``Display display = ((WindowManager) getContext().getSystemService(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number689 index688 alt2\u0026quot;\u0026gt;\n          `                ``Context.WINDOW_SERVICE)).getDefaultDisplay();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number690 index689 alt1\u0026quot;\u0026gt;\n          `        ``try` `{`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number691 index690 alt2\u0026quot;\u0026gt;\n          `            ``Class\u0026amp;lt;?\u0026amp;gt; cls = Display.``class``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number692 index691 alt1\u0026quot;\u0026gt;\n          `            ``Class\u0026amp;lt;?\u0026amp;gt;[] parameterTypes = { Point.``class` `};`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number693 index692 alt2\u0026quot;\u0026gt;\n          `            ``Point parameter = ``new` `Point();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number694 index693 alt1\u0026quot;\u0026gt;\n          `            ``Method method = cls.getMethod(``\u0026quot;getSize\u0026quot;``, parameterTypes);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number695 index694 alt2\u0026quot;\u0026gt;\n          `            ``method.invoke(display, parameter);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number696 index695 alt1\u0026quot;\u0026gt;\n          `            ``width = parameter.x;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number697 index696 alt2\u0026quot;\u0026gt;\n          `        ``} ``catch` `(Exception e) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number698 index697 alt1\u0026quot;\u0026gt;\n          `            ``width = display.getWidth();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number699 index698 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number700 index699 alt1\u0026quot;\u0026gt;\n          `        ``setBehindOffset(width - i);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number701 index700 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number702 index701 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number703 index702 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number704 index703 alt1\u0026quot;\u0026gt;\n          `     ``* Sets the behind width.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number705 index704 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number706 index705 alt1\u0026quot;\u0026gt;\n          `     ``* @param res`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number707 index706 alt2\u0026quot;\u0026gt;\n          `     ``*            The dimension resource id to be set as the behind width`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number708 index707 alt1\u0026quot;\u0026gt;\n          `     ``*            offset. The menu, when open, will open this wide.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number709 index708 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number710 index709 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setBehindWidthRes(``int` `res) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number711 index710 alt2\u0026quot;\u0026gt;\n          `        ``int` `i = (``int``) getContext().getResources().getDimension(res);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number712 index711 alt1\u0026quot;\u0026gt;\n          `        ``setBehindWidth(i);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number713 index712 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number714 index713 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number715 index714 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number716 index715 alt1\u0026quot;\u0026gt;\n          `     ``* Gets the behind scroll scale.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number717 index716 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number718 index717 alt1\u0026quot;\u0026gt;\n          `     ``* @return The scale of the parallax scroll`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number719 index718 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number720 index719 alt1\u0026quot;\u0026gt;\n          `    ``public` `float` `getBehindScrollScale() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number721 index720 alt2\u0026quot;\u0026gt;\n          `        ``return` `mViewBehind.getScrollScale();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number722 index721 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number723 index722 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number724 index723 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number725 index724 alt2\u0026quot;\u0026gt;\n          `     ``* Gets the touch mode margin threshold`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number726 index725 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number727 index726 alt2\u0026quot;\u0026gt;\n          `     ``* @return the touch mode margin threshold`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number728 index727 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number729 index728 alt2\u0026quot;\u0026gt;\n          `    ``public` `int` `getTouchmodeMarginThreshold() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number730 index729 alt1\u0026quot;\u0026gt;\n          `        ``return` `mViewBehind.getMarginThreshold();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number731 index730 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number732 index731 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number733 index732 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number734 index733 alt1\u0026quot;\u0026gt;\n          `     ``* Set the touch mode margin threshold`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number735 index734 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number736 index735 alt1\u0026quot;\u0026gt;\n          `     ``* @param touchmodeMarginThreshold`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number737 index736 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number738 index737 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setTouchmodeMarginThreshold(``int` `touchmodeMarginThreshold) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number739 index738 alt2\u0026quot;\u0026gt;\n          `        ``mViewBehind.setMarginThreshold(touchmodeMarginThreshold);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number740 index739 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number741 index740 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number742 index741 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number743 index742 alt2\u0026quot;\u0026gt;\n          `     ``* Sets the behind scroll scale.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number744 index743 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number745 index744 alt2\u0026quot;\u0026gt;\n          `     ``* @param f`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number746 index745 alt1\u0026quot;\u0026gt;\n          `     ``*            The scale of the parallax scroll (i.e. 1.0f scrolls 1 pixel`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number747 index746 alt2\u0026quot;\u0026gt;\n          `     ``*            for every 1 pixel that the above view scrolls and 0.0f scrolls`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number748 index747 alt1\u0026quot;\u0026gt;\n          `     ``*            0 pixels)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number749 index748 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number750 index749 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setBehindScrollScale(``float` `f) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number751 index750 alt2\u0026quot;\u0026gt;\n          `        ``if` `(f \u0026amp;lt; ``` `\u0026amp;\u0026amp; f \u0026amp;gt; ``1``)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number752 index751 alt1\u0026quot;\u0026gt;\n          `            ``throw` `new` `IllegalStateException(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number753 index752 alt2\u0026quot;\u0026gt;\n          `                    ``\u0026quot;ScrollScale must be between 0 and 1\u0026quot;``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number754 index753 alt1\u0026quot;\u0026gt;\n          `        ``mViewBehind.setScrollScale(f);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number755 index754 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number756 index755 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number757 index756 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number758 index757 alt1\u0026quot;\u0026gt;\n          `     ``* Sets the behind canvas transformer.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number759 index758 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number760 index759 alt1\u0026quot;\u0026gt;\n          `     ``* @param t`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number761 index760 alt2\u0026quot;\u0026gt;\n          `     ``*            the new behind canvas transformer`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number762 index761 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number763 index762 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setBehindCanvasTransformer(CanvasTransformer t) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number764 index763 alt1\u0026quot;\u0026gt;\n          `        ``mViewBehind.setCanvasTransformer(t);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number765 index764 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number766 index765 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number767 index766 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number768 index767 alt1\u0026quot;\u0026gt;\n          `     ``* 设置右侧视图的转场动画`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number769 index768 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number770 index769 alt1\u0026quot;\u0026gt;\n          `     ``* @param t`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number771 index770 alt2\u0026quot;\u0026gt;\n          `     ``*            the new above canvas transformer`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number772 index771 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number773 index772 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setAboveCanvasTransformer(CanvasTransformer t) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number774 index773 alt1\u0026quot;\u0026gt;\n          `        ``mViewAbove.setCanvasTransformer(t);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number775 index774 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number776 index775 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number777 index776 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number778 index777 alt1\u0026quot;\u0026gt;\n          `     ``* Gets the touch mode above.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number779 index778 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number780 index779 alt1\u0026quot;\u0026gt;\n          `     ``* @return the touch mode above`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number781 index780 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number782 index781 alt1\u0026quot;\u0026gt;\n          `    ``public` `int` `getTouchModeAbove() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number783 index782 alt2\u0026quot;\u0026gt;\n          `        ``return` `mViewAbove.getTouchMode();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number784 index783 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number785 index784 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number786 index785 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number787 index786 alt2\u0026quot;\u0026gt;\n          `     ``* Controls whether the SlidingMenu can be opened with a swipe gesture.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number788 index787 alt1\u0026quot;\u0026gt;\n          `     ``* Options are {@link #TOUCHMODE_MARGIN TOUCHMODE_MARGIN},`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number789 index788 alt2\u0026quot;\u0026gt;\n          `     ``* {@link #TOUCHMODE_FULLSCREEN TOUCHMODE_FULLSCREEN}, or`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number790 index789 alt1\u0026quot;\u0026gt;\n          `     ``* {@link #TOUCHMODE_NONE TOUCHMODE_NONE}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number791 index790 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number792 index791 alt1\u0026quot;\u0026gt;\n          `     ``* @param i`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number793 index792 alt2\u0026quot;\u0026gt;\n          `     ``*            the new touch mode`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number794 index793 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number795 index794 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setTouchModeAbove(``int` `i) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number796 index795 alt1\u0026quot;\u0026gt;\n          `        ``if` `(i != TOUCHMODE_FULLSCREEN \u0026amp;\u0026amp; i != TOUCHMODE_MARGIN`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number797 index796 alt2\u0026quot;\u0026gt;\n          `                ``\u0026amp;\u0026amp; i != TOUCHMODE_NONE) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number798 index797 alt1\u0026quot;\u0026gt;\n          `            ``throw` `new` `IllegalStateException(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number799 index798 alt2\u0026quot;\u0026gt;\n          `                    ``\u0026quot;TouchMode must be set to either\u0026quot;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number800 index799 alt1\u0026quot;\u0026gt;\n          `                            ``+ ``\u0026quot;TOUCHMODE_FULLSCREEN or TOUCHMODE_MARGIN or TOUCHMODE_NONE.\u0026quot;``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number801 index800 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number802 index801 alt1\u0026quot;\u0026gt;\n          `        ``mViewAbove.setTouchMode(i);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number803 index802 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number804 index803 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number805 index804 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number806 index805 alt1\u0026quot;\u0026gt;\n          `     ``* Controls whether the SlidingMenu can be opened with a swipe gesture.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number807 index806 alt2\u0026quot;\u0026gt;\n          `     ``* Options are {@link #TOUCHMODE_MARGIN TOUCHMODE_MARGIN},`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number808 index807 alt1\u0026quot;\u0026gt;\n          `     ``* {@link #TOUCHMODE_FULLSCREEN TOUCHMODE_FULLSCREEN}, or`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number809 index808 alt2\u0026quot;\u0026gt;\n          `     ``* {@link #TOUCHMODE_NONE TOUCHMODE_NONE}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number810 index809 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number811 index810 alt2\u0026quot;\u0026gt;\n          `     ``* @param i`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number812 index811 alt1\u0026quot;\u0026gt;\n          `     ``*            the new touch mode`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number813 index812 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number814 index813 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setTouchModeBehind(``int` `i) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number815 index814 alt2\u0026quot;\u0026gt;\n          `        ``if` `(i != TOUCHMODE_FULLSCREEN \u0026amp;\u0026amp; i != TOUCHMODE_MARGIN`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number816 index815 alt1\u0026quot;\u0026gt;\n          `                ``\u0026amp;\u0026amp; i != TOUCHMODE_NONE) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number817 index816 alt2\u0026quot;\u0026gt;\n          `            ``throw` `new` `IllegalStateException(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number818 index817 alt1\u0026quot;\u0026gt;\n          `                    ``\u0026quot;TouchMode must be set to either\u0026quot;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number819 index818 alt2\u0026quot;\u0026gt;\n          `                            ``+ ``\u0026quot;TOUCHMODE_FULLSCREEN or TOUCHMODE_MARGIN or TOUCHMODE_NONE.\u0026quot;``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number820 index819 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number821 index820 alt2\u0026quot;\u0026gt;\n          `        ``mViewBehind.setTouchMode(i);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number822 index821 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number823 index822 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number824 index823 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number825 index824 alt2\u0026quot;\u0026gt;\n          `     ``* Sets the shadow drawable.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number826 index825 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number827 index826 alt2\u0026quot;\u0026gt;\n          `     ``* @param resId`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number828 index827 alt1\u0026quot;\u0026gt;\n          `     ``*            the resource ID of the new shadow drawable`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number829 index828 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number830 index829 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setShadowDrawable(``int` `resId) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number831 index830 alt2\u0026quot;\u0026gt;\n          `        ``setShadowDrawable(getContext().getResources().getDrawable(resId));`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number832 index831 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number833 index832 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number834 index833 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number835 index834 alt2\u0026quot;\u0026gt;\n          `     ``* Sets the shadow drawable.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number836 index835 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number837 index836 alt2\u0026quot;\u0026gt;\n          `     ``* @param d`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number838 index837 alt1\u0026quot;\u0026gt;\n          `     ``*            the new shadow drawable`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number839 index838 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number840 index839 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setShadowDrawable(Drawable d) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number841 index840 alt2\u0026quot;\u0026gt;\n          `        ``mViewBehind.setShadowDrawable(d);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number842 index841 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number843 index842 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number844 index843 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number845 index844 alt2\u0026quot;\u0026gt;\n          `     ``* Sets the secondary (right) shadow drawable.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number846 index845 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number847 index846 alt2\u0026quot;\u0026gt;\n          `     ``* @param resId`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number848 index847 alt1\u0026quot;\u0026gt;\n          `     ``*            the resource ID of the new shadow drawable`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number849 index848 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number850 index849 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setSecondaryShadowDrawable(``int` `resId) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number851 index850 alt2\u0026quot;\u0026gt;\n          `        ``setSecondaryShadowDrawable(getContext().getResources().getDrawable(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number852 index851 alt1\u0026quot;\u0026gt;\n          `                ``resId));`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number853 index852 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number854 index853 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number855 index854 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number856 index855 alt1\u0026quot;\u0026gt;\n          `     ``* Sets the secondary (right) shadow drawable.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number857 index856 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number858 index857 alt1\u0026quot;\u0026gt;\n          `     ``* @param d`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number859 index858 alt2\u0026quot;\u0026gt;\n          `     ``*            the new shadow drawable`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number860 index859 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number861 index860 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setSecondaryShadowDrawable(Drawable d) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number862 index861 alt1\u0026quot;\u0026gt;\n          `        ``mViewBehind.setSecondaryShadowDrawable(d);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number863 index862 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number864 index863 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number865 index864 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number866 index865 alt1\u0026quot;\u0026gt;\n          `     ``* Sets the shadow width.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number867 index866 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number868 index867 alt1\u0026quot;\u0026gt;\n          `     ``* @param resId`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number869 index868 alt2\u0026quot;\u0026gt;\n          `     ``*            The dimension resource id to be set as the shadow width.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number870 index869 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number871 index870 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setShadowWidthRes(``int` `resId) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number872 index871 alt1\u0026quot;\u0026gt;\n          `        ``setShadowWidth((``int``) getResources().getDimension(resId));`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number873 index872 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number874 index873 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number875 index874 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number876 index875 alt1\u0026quot;\u0026gt;\n          `     ``* Sets the shadow width.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number877 index876 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number878 index877 alt1\u0026quot;\u0026gt;\n          `     ``* @param pixels`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number879 index878 alt2\u0026quot;\u0026gt;\n          `     ``*            the new shadow width, in pixels`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number880 index879 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number881 index880 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setShadowWidth(``int` `pixels) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number882 index881 alt1\u0026quot;\u0026gt;\n          `        ``mViewBehind.setShadowWidth(pixels);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number883 index882 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number884 index883 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number885 index884 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number886 index885 alt1\u0026quot;\u0026gt;\n          `     ``* Enables or disables the SlidingMenu's fade in and out`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number887 index886 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number888 index887 alt1\u0026quot;\u0026gt;\n          `     ``* @param b`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number889 index888 alt2\u0026quot;\u0026gt;\n          `     ``*            true to enable fade, false to disable it`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number890 index889 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number891 index890 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setFadeEnabled(``boolean` `b) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number892 index891 alt1\u0026quot;\u0026gt;\n          `        ``mViewBehind.setFadeEnabled(b);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number893 index892 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number894 index893 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number895 index894 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number896 index895 alt1\u0026quot;\u0026gt;\n          `     ``* Sets how much the SlidingMenu fades in and out. Fade must be enabled, see`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number897 index896 alt2\u0026quot;\u0026gt;\n          `     ``* {@link #setFadeEnabled(boolean) setFadeEnabled(boolean)}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number898 index897 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number899 index898 alt2\u0026quot;\u0026gt;\n          `     ``* @param f`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number900 index899 alt1\u0026quot;\u0026gt;\n          `     ``*            the new fade degree, between 0.0f and 1.0f`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number901 index900 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number902 index901 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setFadeDegree(``float` `f) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number903 index902 alt2\u0026quot;\u0026gt;\n          `        ``mViewBehind.setFadeDegree(f);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number904 index903 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number905 index904 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number906 index905 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number907 index906 alt2\u0026quot;\u0026gt;\n          `     ``* Enables or disables whether the selector is drawn`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number908 index907 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number909 index908 alt2\u0026quot;\u0026gt;\n          `     ``* @param b`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number910 index909 alt1\u0026quot;\u0026gt;\n          `     ``*            true to draw the selector, false to not draw the selector`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number911 index910 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number912 index911 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setSelectorEnabled(``boolean` `b) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number913 index912 alt2\u0026quot;\u0026gt;\n          `        ``mViewBehind.setSelectorEnabled(``true``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number914 index913 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number915 index914 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number916 index915 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number917 index916 alt2\u0026quot;\u0026gt;\n          `     ``* Sets the selected view. The selector will be drawn here`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number918 index917 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number919 index918 alt2\u0026quot;\u0026gt;\n          `     ``* @param v`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number920 index919 alt1\u0026quot;\u0026gt;\n          `     ``*            the new selected view`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number921 index920 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number922 index921 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setSelectedView(View v) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number923 index922 alt2\u0026quot;\u0026gt;\n          `        ``mViewBehind.setSelectedView(v);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number924 index923 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number925 index924 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number926 index925 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number927 index926 alt2\u0026quot;\u0026gt;\n          `     ``* Sets the selector drawable.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number928 index927 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number929 index928 alt2\u0026quot;\u0026gt;\n          `     ``* @param res`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number930 index929 alt1\u0026quot;\u0026gt;\n          `     ``*            a resource ID for the selector drawable`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number931 index930 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number932 index931 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setSelectorDrawable(``int` `res) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number933 index932 alt2\u0026quot;\u0026gt;\n          `        ``mViewBehind.setSelectorBitmap(BitmapFactory.decodeResource(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number934 index933 alt1\u0026quot;\u0026gt;\n          `                ``getResources(), res));`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number935 index934 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number936 index935 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number937 index936 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number938 index937 alt1\u0026quot;\u0026gt;\n          `     ``* Sets the selector drawable.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number939 index938 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number940 index939 alt1\u0026quot;\u0026gt;\n          `     ``* @param b`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number941 index940 alt2\u0026quot;\u0026gt;\n          `     ``*            the new selector bitmap`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number942 index941 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number943 index942 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setSelectorBitmap(Bitmap b) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number944 index943 alt1\u0026quot;\u0026gt;\n          `        ``mViewBehind.setSelectorBitmap(b);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number945 index944 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number946 index945 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number947 index946 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number948 index947 alt1\u0026quot;\u0026gt;\n          `     ``* Add a View ignored by the Touch Down event when mode is Fullscreen`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number949 index948 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number950 index949 alt1\u0026quot;\u0026gt;\n          `     ``* @param v`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number951 index950 alt2\u0026quot;\u0026gt;\n          `     ``*            a view to be ignored`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number952 index951 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number953 index952 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `addIgnoredView(View v) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number954 index953 alt1\u0026quot;\u0026gt;\n          `        ``mViewAbove.addIgnoredView(v);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number955 index954 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number956 index955 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number957 index956 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number958 index957 alt1\u0026quot;\u0026gt;\n          `     ``* Remove a View ignored by the Touch Down event when mode is Fullscreen`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number959 index958 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number960 index959 alt1\u0026quot;\u0026gt;\n          `     ``* @param v`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number961 index960 alt2\u0026quot;\u0026gt;\n          `     ``*            a view not wanted to be ignored anymore`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number962 index961 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number963 index962 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `removeIgnoredView(View v) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number964 index963 alt1\u0026quot;\u0026gt;\n          `        ``mViewAbove.removeIgnoredView(v);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number965 index964 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number966 index965 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number967 index966 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number968 index967 alt1\u0026quot;\u0026gt;\n          `     ``* Clear the list of Views ignored by the Touch Down event when mode is`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number969 index968 alt2\u0026quot;\u0026gt;\n          `     ``* Fullscreen`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number970 index969 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number971 index970 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `clearIgnoredViews() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number972 index971 alt1\u0026quot;\u0026gt;\n          `        ``mViewAbove.clearIgnoredViews();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number973 index972 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number974 index973 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number975 index974 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number976 index975 alt1\u0026quot;\u0026gt;\n          `     ``* Sets the OnOpenListener. {@link OnOpenListener#onOpen()`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number977 index976 alt2\u0026quot;\u0026gt;\n          `     ``* OnOpenListener.onOpen()} will be called when the SlidingMenu is opened`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number978 index977 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number979 index978 alt2\u0026quot;\u0026gt;\n          `     ``* @param listener`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number980 index979 alt1\u0026quot;\u0026gt;\n          `     ``*            the new OnOpenListener`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number981 index980 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number982 index981 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setOnOpenListener(OnOpenListener listener) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number983 index982 alt2\u0026quot;\u0026gt;\n          `        ``// mViewAbove.setOnOpenListener(listener);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number984 index983 alt1\u0026quot;\u0026gt;\n          `        ``mOpenListener = listener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number985 index984 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number986 index985 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number987 index986 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number988 index987 alt1\u0026quot;\u0026gt;\n          `     ``* Sets the OnOpenListner for secondary menu {@link OnOpenListener#onOpen()`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number989 index988 alt2\u0026quot;\u0026gt;\n          `     ``* OnOpenListener.onOpen()} will be called when the secondary SlidingMenu is`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number990 index989 alt1\u0026quot;\u0026gt;\n          `     ``* opened`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number991 index990 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number992 index991 alt1\u0026quot;\u0026gt;\n          `     ``* @param listener`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number993 index992 alt2\u0026quot;\u0026gt;\n          `     ``*            the new OnOpenListener`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number994 index993 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number995 index994 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number996 index995 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setSecondaryOnOpenListner(OnOpenListener listener) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number997 index996 alt2\u0026quot;\u0026gt;\n          `        ``mSecondaryOpenListner = listener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number998 index997 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number999 index998 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1000 index999 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1001 index1000 alt2\u0026quot;\u0026gt;\n          `     ``* Sets the OnCloseListener. {@link OnCloseListener#onClose()`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1002 index1001 alt1\u0026quot;\u0026gt;\n          `     ``* OnCloseListener.onClose()} will be called when any one of the SlidingMenu`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1003 index1002 alt2\u0026quot;\u0026gt;\n          `     ``* is closed`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1004 index1003 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1005 index1004 alt2\u0026quot;\u0026gt;\n          `     ``* @param listener`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1006 index1005 alt1\u0026quot;\u0026gt;\n          `     ``*            the new setOnCloseListener`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1007 index1006 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1008 index1007 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setOnCloseListener(OnCloseListener listener) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1009 index1008 alt2\u0026quot;\u0026gt;\n          `        ``// mViewAbove.setOnCloseListener(listener);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1010 index1009 alt1\u0026quot;\u0026gt;\n          `        ``mCloseListener = listener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1011 index1010 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1012 index1011 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1013 index1012 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1014 index1013 alt1\u0026quot;\u0026gt;\n          `     ``* Sets the OnOpenedListener. {@link OnOpenedListener#onOpened()`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1015 index1014 alt2\u0026quot;\u0026gt;\n          `     ``* OnOpenedListener.onOpened()} will be called after the SlidingMenu is`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1016 index1015 alt1\u0026quot;\u0026gt;\n          `     ``* opened`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1017 index1016 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1018 index1017 alt1\u0026quot;\u0026gt;\n          `     ``* @param listener`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1019 index1018 alt2\u0026quot;\u0026gt;\n          `     ``*            the new OnOpenedListener`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1020 index1019 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1021 index1020 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setOnOpenedListener(OnOpenedListener listener) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1022 index1021 alt1\u0026quot;\u0026gt;\n          `        ``mViewAbove.setOnOpenedListener(listener);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1023 index1022 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1024 index1023 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1025 index1024 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1026 index1025 alt1\u0026quot;\u0026gt;\n          `     ``* Sets the OnClosedListener. {@link OnClosedListener#onClosed()`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1027 index1026 alt2\u0026quot;\u0026gt;\n          `     ``* OnClosedListener.onClosed()} will be called after the SlidingMenu is`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1028 index1027 alt1\u0026quot;\u0026gt;\n          `     ``* closed`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1029 index1028 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1030 index1029 alt1\u0026quot;\u0026gt;\n          `     ``* @param listener`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1031 index1030 alt2\u0026quot;\u0026gt;\n          `     ``*            the new OnClosedListener`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1032 index1031 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1033 index1032 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setOnClosedListener(OnClosedListener listener) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1034 index1033 alt1\u0026quot;\u0026gt;\n          `        ``mViewAbove.setOnClosedListener(listener);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1035 index1034 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1036 index1035 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1037 index1036 alt2\u0026quot;\u0026gt;\n          `    ``public` `static` `class` `SavedState ``extends` `BaseSavedState {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1038 index1037 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1039 index1038 alt2\u0026quot;\u0026gt;\n          `        ``private` `final` `int` `mItem;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1040 index1039 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1041 index1040 alt2\u0026quot;\u0026gt;\n          `        ``public` `SavedState(Parcelable superState, ``int` `item) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1042 index1041 alt1\u0026quot;\u0026gt;\n          `            ``super``(superState);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1043 index1042 alt2\u0026quot;\u0026gt;\n          `            ``mItem = item;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1044 index1043 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1045 index1044 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1046 index1045 alt1\u0026quot;\u0026gt;\n          `        ``private` `SavedState(Parcel in) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1047 index1046 alt2\u0026quot;\u0026gt;\n          `            ``super``(in);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1048 index1047 alt1\u0026quot;\u0026gt;\n          `            ``mItem = in.readInt();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1049 index1048 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1050 index1049 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1051 index1050 alt2\u0026quot;\u0026gt;\n          `        ``public` `int` `getItem() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1052 index1051 alt1\u0026quot;\u0026gt;\n          `            ``return` `mItem;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1053 index1052 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1054 index1053 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1055 index1054 alt2\u0026quot;\u0026gt;\n          `        ``/*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1056 index1055 alt1\u0026quot;\u0026gt;\n          `         ``* (non-Javadoc)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1057 index1056 alt2\u0026quot;\u0026gt;\n          `         ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1058 index1057 alt1\u0026quot;\u0026gt;\n          `         ``* @see android.view.AbsSavedState#writeToParcel(android.os.Parcel, int)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1059 index1058 alt2\u0026quot;\u0026gt;\n          `         ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1060 index1059 alt1\u0026quot;\u0026gt;\n          `        ``public void writeToParcel(Parcel out, int flags) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1061 index1060 alt2\u0026quot;\u0026gt;\n          `            ``super.writeToParcel(out, flags);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1062 index1061 alt1\u0026quot;\u0026gt;\n          `            ``out.writeInt(mItem);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1063 index1062 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1064 index1063 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1065 index1064 alt2\u0026quot;\u0026gt;\n          `        ``public static final Parcelable.Creator\u0026amp;lt;SavedState\u0026amp;gt; CREATOR = new Parcelable.Creator\u0026amp;lt;SavedState\u0026amp;gt;() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1066 index1065 alt1\u0026quot;\u0026gt;\n          `            ``public SavedState createFromParcel(Parcel in) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1067 index1066 alt2\u0026quot;\u0026gt;\n          `                ``return new SavedState(in);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1068 index1067 alt1\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1069 index1068 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1070 index1069 alt1\u0026quot;\u0026gt;\n          `            ``public SavedState[] newArray(int size) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1071 index1070 alt2\u0026quot;\u0026gt;\n          `                ``return new SavedState[size];`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1072 index1071 alt1\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1073 index1072 alt2\u0026quot;\u0026gt;\n          `        ``};`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1074 index1073 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1075 index1074 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1076 index1075 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1077 index1076 alt2\u0026quot;\u0026gt;\n          `    ``/*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1078 index1077 alt1\u0026quot;\u0026gt;\n          `     ``* (non-Javadoc)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1079 index1078 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1080 index1079 alt1\u0026quot;\u0026gt;\n          `     ``* @see android.view.View#onSaveInstanceState()`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1081 index1080 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1082 index1081 alt1\u0026quot;\u0026gt;\n          `    ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1083 index1082 alt2\u0026quot;\u0026gt;\n          `    ``protected Parcelable onSaveInstanceState() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1084 index1083 alt1\u0026quot;\u0026gt;\n          `        ``Parcelable superState = super.onSaveInstanceState();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1085 index1084 alt2\u0026quot;\u0026gt;\n          `        ``SavedState ss = new SavedState(superState, mViewAbove.getCurrentItem());`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1086 index1085 alt1\u0026quot;\u0026gt;\n          `        ``return ss;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1087 index1086 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1088 index1087 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1089 index1088 alt2\u0026quot;\u0026gt;\n          `    ``/*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1090 index1089 alt1\u0026quot;\u0026gt;\n          `     ``* (non-Javadoc)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1091 index1090 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1092 index1091 alt1\u0026quot;\u0026gt;\n          `     ``* @see android.view.View#onRestoreInstanceState(android.os.Parcelable)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1093 index1092 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1094 index1093 alt1\u0026quot;\u0026gt;\n          `    ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1095 index1094 alt2\u0026quot;\u0026gt;\n          `    ``protected void onRestoreInstanceState(Parcelable state) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1096 index1095 alt1\u0026quot;\u0026gt;\n          `        ``SavedState ss = (SavedState) state;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1097 index1096 alt2\u0026quot;\u0026gt;\n          `        ``super.onRestoreInstanceState(ss.getSuperState());`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1098 index1097 alt1\u0026quot;\u0026gt;\n          `        ``mViewAbove.setCurrentItem(ss.getItem());`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1099 index1098 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1100 index1099 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1101 index1100 alt2\u0026quot;\u0026gt;\n          `    ``/*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1102 index1101 alt1\u0026quot;\u0026gt;\n          `     ``* (non-Javadoc)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1103 index1102 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1104 index1103 alt1\u0026quot;\u0026gt;\n          `     ``* @see android.view.ViewGroup#fitSystemWindows(android.graphics.Rect)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1105 index1104 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1106 index1105 alt1\u0026quot;\u0026gt;\n          `    ``@SuppressLint``(``\u0026quot;NewApi\u0026quot;``)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1107 index1106 alt2\u0026quot;\u0026gt;\n          `    ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1108 index1107 alt1\u0026quot;\u0026gt;\n          `    ``protected` `boolean` `fitSystemWindows(Rect insets) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1109 index1108 alt2\u0026quot;\u0026gt;\n          `        ``int` `leftPadding = insets.left;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1110 index1109 alt1\u0026quot;\u0026gt;\n          `        ``int` `rightPadding = insets.right;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1111 index1110 alt2\u0026quot;\u0026gt;\n          `        ``int` `topPadding = insets.top;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1112 index1111 alt1\u0026quot;\u0026gt;\n          `        ``int` `bottomPadding = insets.bottom;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1113 index1112 alt2\u0026quot;\u0026gt;\n          `        ``if` `(!mActionbarOverlay) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1114 index1113 alt1\u0026quot;\u0026gt;\n          `            ``Log.v(TAG, ``\u0026quot;setting padding!\u0026quot;``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1115 index1114 alt2\u0026quot;\u0026gt;\n          `            ``setPadding(leftPadding, topPadding, rightPadding, bottomPadding);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1116 index1115 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1117 index1116 alt2\u0026quot;\u0026gt;\n          `        ``return` `true``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1118 index1117 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1119 index1118 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1120 index1119 alt1\u0026quot;\u0026gt;\n          `    ``@TargetApi``(Build.VERSION_CODES.HONEYCOMB)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1121 index1120 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `manageLayers(``float` `percentOpen) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1122 index1121 alt1\u0026quot;\u0026gt;\n          `        ``if` `(Build.VERSION.SDK_INT \u0026amp;lt; ``11``)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1123 index1122 alt2\u0026quot;\u0026gt;\n          `            ``return``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1124 index1123 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1125 index1124 alt2\u0026quot;\u0026gt;\n          `        ``boolean` `layer = percentOpen \u0026amp;gt; ````.0f \u0026amp;\u0026amp; percentOpen \u0026amp;lt; ``1``.0f;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1126 index1125 alt1\u0026quot;\u0026gt;\n          `        ``final` `int` `layerType = layer ? View.LAYER_TYPE_HARDWARE`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1127 index1126 alt2\u0026quot;\u0026gt;\n          `                ``: View.LAYER_TYPE_NONE;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1128 index1127 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1129 index1128 alt2\u0026quot;\u0026gt;\n          `        ``if` `(layerType != getContent().getLayerType()) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1130 index1129 alt1\u0026quot;\u0026gt;\n          `            ``getHandler().post(``new` `Runnable() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1131 index1130 alt2\u0026quot;\u0026gt;\n          `                ``public` `void` `run() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1132 index1131 alt1\u0026quot;\u0026gt;\n          `                    ``Log.v(TAG, ``\u0026quot;changing layerType. hardware? \u0026quot;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1133 index1132 alt2\u0026quot;\u0026gt;\n          `                            ``+ (layerType == View.LAYER_TYPE_HARDWARE));`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1134 index1133 alt1\u0026quot;\u0026gt;\n          `                    ``getContent().setLayerType(layerType, ``null``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1135 index1134 alt2\u0026quot;\u0026gt;\n          `                    ``getMenu().setLayerType(layerType, ``null``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1136 index1135 alt1\u0026quot;\u0026gt;\n          `                    ``if` `(getSecondaryMenu() != ``null``) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1137 index1136 alt2\u0026quot;\u0026gt;\n          `                        ``getSecondaryMenu().setLayerType(layerType, ``null``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1138 index1137 alt1\u0026quot;\u0026gt;\n          `                    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1139 index1138 alt2\u0026quot;\u0026gt;\n          `                ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1140 index1139 alt1\u0026quot;\u0026gt;\n          `            ``});`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1141 index1140 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1142 index1141 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1143 index1142 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number1144 index1143 alt1\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_572363\" class=\"syntaxhighlighter  java\"\u003e\n    \u003cdiv class=\"toolbar\"\u003e\n      [?](http://www.open-open.com/lib/view/open1411269966859.html#)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n  \u0026lt;tr\u0026gt;\n    \u0026lt;td class=\u0026quot;gutter\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n        1\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        2\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n        3\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n        4\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n        5\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n        6\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n        7\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n        8\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n        9\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n        10\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n        11\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n        12\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n        13\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n        14\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n        15\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n        16\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n        17\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n        18\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n        19\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n        20\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n        21\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n        22\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n        23\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n        24\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n        25\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n        26\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n        27\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n        28\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n        29\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n        30\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n        31\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n        32\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n        33\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt;\n        34\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt;\n        35\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt;\n        36\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt;\n        37\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt;\n        38\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt;\n        39\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt;\n        40\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt;\n        41\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt;\n        42\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt;\n        43\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt;\n        44\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt;\n        45\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt;\n        46\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt;\n        47\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt;\n        48\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt;\n        49\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt;\n        50\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt;\n        51\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt;\n        52\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt;\n        53\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt;\n        54\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt;\n        55\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt;\n        56\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt;\n        57\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt;\n        58\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt;\n        59\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt;\n        60\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt;\n        61\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt;\n        62\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt;\n        63\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt;\n        64\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt;\n        65\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt;\n        66\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt;\n        67\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt;\n        68\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt;\n        69\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt;\n        70\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt;\n        71\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt;\n        72\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt;\n        73\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt;\n        74\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt;\n        75\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt;\n        76\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt;\n        77\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt;\n        78\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt;\n        79\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt;\n        80\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt;\n        81\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt;\n        82\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt;\n        83\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt;\n        84\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt;\n        85\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt;\n        86\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt;\n        87\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt;\n        88\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt;\n        89\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt;\n        90\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt;\n        91\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt;\n        92\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt;\n        93\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt;\n        94\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt;\n        95\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt;\n        96\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt;\n        97\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt;\n        98\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt;\n        99\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt;\n        100\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number101 index100 alt2\u0026quot;\u0026gt;\n        101\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number102 index101 alt1\u0026quot;\u0026gt;\n        102\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number103 index102 alt2\u0026quot;\u0026gt;\n        103\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number104 index103 alt1\u0026quot;\u0026gt;\n        104\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number105 index104 alt2\u0026quot;\u0026gt;\n        105\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number106 index105 alt1\u0026quot;\u0026gt;\n        106\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number107 index106 alt2\u0026quot;\u0026gt;\n        107\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number108 index107 alt1\u0026quot;\u0026gt;\n        108\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number109 index108 alt2\u0026quot;\u0026gt;\n        109\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number110 index109 alt1\u0026quot;\u0026gt;\n        110\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number111 index110 alt2\u0026quot;\u0026gt;\n        111\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number112 index111 alt1\u0026quot;\u0026gt;\n        112\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number113 index112 alt2\u0026quot;\u0026gt;\n        113\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number114 index113 alt1\u0026quot;\u0026gt;\n        114\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number115 index114 alt2\u0026quot;\u0026gt;\n        115\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number116 index115 alt1\u0026quot;\u0026gt;\n        116\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number117 index116 alt2\u0026quot;\u0026gt;\n        117\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number118 index117 alt1\u0026quot;\u0026gt;\n        118\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number119 index118 alt2\u0026quot;\u0026gt;\n        119\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number120 index119 alt1\u0026quot;\u0026gt;\n        120\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number121 index120 alt2\u0026quot;\u0026gt;\n        121\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number122 index121 alt1\u0026quot;\u0026gt;\n        122\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number123 index122 alt2\u0026quot;\u0026gt;\n        123\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number124 index123 alt1\u0026quot;\u0026gt;\n        124\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number125 index124 alt2\u0026quot;\u0026gt;\n        125\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number126 index125 alt1\u0026quot;\u0026gt;\n        126\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number127 index126 alt2\u0026quot;\u0026gt;\n        127\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number128 index127 alt1\u0026quot;\u0026gt;\n        128\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number129 index128 alt2\u0026quot;\u0026gt;\n        129\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number130 index129 alt1\u0026quot;\u0026gt;\n        130\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number131 index130 alt2\u0026quot;\u0026gt;\n        131\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number132 index131 alt1\u0026quot;\u0026gt;\n        132\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number133 index132 alt2\u0026quot;\u0026gt;\n        133\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number134 index133 alt1\u0026quot;\u0026gt;\n        134\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number135 index134 alt2\u0026quot;\u0026gt;\n        135\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number136 index135 alt1\u0026quot;\u0026gt;\n        136\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number137 index136 alt2\u0026quot;\u0026gt;\n        137\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number138 index137 alt1\u0026quot;\u0026gt;\n        138\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number139 index138 alt2\u0026quot;\u0026gt;\n        139\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number140 index139 alt1\u0026quot;\u0026gt;\n        140\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number141 index140 alt2\u0026quot;\u0026gt;\n        141\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number142 index141 alt1\u0026quot;\u0026gt;\n        142\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number143 index142 alt2\u0026quot;\u0026gt;\n        143\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number144 index143 alt1\u0026quot;\u0026gt;\n        144\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number145 index144 alt2\u0026quot;\u0026gt;\n        145\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number146 index145 alt1\u0026quot;\u0026gt;\n        146\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number147 index146 alt2\u0026quot;\u0026gt;\n        147\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number148 index147 alt1\u0026quot;\u0026gt;\n        148\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number149 index148 alt2\u0026quot;\u0026gt;\n        149\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number150 index149 alt1\u0026quot;\u0026gt;\n        150\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number151 index150 alt2\u0026quot;\u0026gt;\n        151\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number152 index151 alt1\u0026quot;\u0026gt;\n        152\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number153 index152 alt2\u0026quot;\u0026gt;\n        153\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number154 index153 alt1\u0026quot;\u0026gt;\n        154\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number155 index154 alt2\u0026quot;\u0026gt;\n        155\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number156 index155 alt1\u0026quot;\u0026gt;\n        156\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number157 index156 alt2\u0026quot;\u0026gt;\n        157\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number158 index157 alt1\u0026quot;\u0026gt;\n        158\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number159 index158 alt2\u0026quot;\u0026gt;\n        159\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number160 index159 alt1\u0026quot;\u0026gt;\n        160\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number161 index160 alt2\u0026quot;\u0026gt;\n        161\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number162 index161 alt1\u0026quot;\u0026gt;\n        162\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number163 index162 alt2\u0026quot;\u0026gt;\n        163\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number164 index163 alt1\u0026quot;\u0026gt;\n        164\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number165 index164 alt2\u0026quot;\u0026gt;\n        165\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number166 index165 alt1\u0026quot;\u0026gt;\n        166\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number167 index166 alt2\u0026quot;\u0026gt;\n        167\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number168 index167 alt1\u0026quot;\u0026gt;\n        168\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number169 index168 alt2\u0026quot;\u0026gt;\n        169\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number170 index169 alt1\u0026quot;\u0026gt;\n        170\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number171 index170 alt2\u0026quot;\u0026gt;\n        171\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number172 index171 alt1\u0026quot;\u0026gt;\n        172\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number173 index172 alt2\u0026quot;\u0026gt;\n        173\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number174 index173 alt1\u0026quot;\u0026gt;\n        174\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number175 index174 alt2\u0026quot;\u0026gt;\n        175\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number176 index175 alt1\u0026quot;\u0026gt;\n        176\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number177 index176 alt2\u0026quot;\u0026gt;\n        177\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number178 index177 alt1\u0026quot;\u0026gt;\n        178\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number179 index178 alt2\u0026quot;\u0026gt;\n        179\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number180 index179 alt1\u0026quot;\u0026gt;\n        180\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number181 index180 alt2\u0026quot;\u0026gt;\n        181\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number182 index181 alt1\u0026quot;\u0026gt;\n        182\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number183 index182 alt2\u0026quot;\u0026gt;\n        183\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number184 index183 alt1\u0026quot;\u0026gt;\n        184\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number185 index184 alt2\u0026quot;\u0026gt;\n        185\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number186 index185 alt1\u0026quot;\u0026gt;\n        186\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number187 index186 alt2\u0026quot;\u0026gt;\n        187\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number188 index187 alt1\u0026quot;\u0026gt;\n        188\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number189 index188 alt2\u0026quot;\u0026gt;\n        189\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number190 index189 alt1\u0026quot;\u0026gt;\n        190\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number191 index190 alt2\u0026quot;\u0026gt;\n        191\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number192 index191 alt1\u0026quot;\u0026gt;\n        192\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number193 index192 alt2\u0026quot;\u0026gt;\n        193\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number194 index193 alt1\u0026quot;\u0026gt;\n        194\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number195 index194 alt2\u0026quot;\u0026gt;\n        195\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number196 index195 alt1\u0026quot;\u0026gt;\n        196\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number197 index196 alt2\u0026quot;\u0026gt;\n        197\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number198 index197 alt1\u0026quot;\u0026gt;\n        198\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number199 index198 alt2\u0026quot;\u0026gt;\n        199\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number200 index199 alt1\u0026quot;\u0026gt;\n        200\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number201 index200 alt2\u0026quot;\u0026gt;\n        201\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number202 index201 alt1\u0026quot;\u0026gt;\n        202\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number203 index202 alt2\u0026quot;\u0026gt;\n        203\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number204 index203 alt1\u0026quot;\u0026gt;\n        204\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number205 index204 alt2\u0026quot;\u0026gt;\n        205\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number206 index205 alt1\u0026quot;\u0026gt;\n        206\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number207 index206 alt2\u0026quot;\u0026gt;\n        207\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number208 index207 alt1\u0026quot;\u0026gt;\n        208\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number209 index208 alt2\u0026quot;\u0026gt;\n        209\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number210 index209 alt1\u0026quot;\u0026gt;\n        210\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number211 index210 alt2\u0026quot;\u0026gt;\n        211\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number212 index211 alt1\u0026quot;\u0026gt;\n        212\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number213 index212 alt2\u0026quot;\u0026gt;\n        213\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number214 index213 alt1\u0026quot;\u0026gt;\n        214\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number215 index214 alt2\u0026quot;\u0026gt;\n        215\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number216 index215 alt1\u0026quot;\u0026gt;\n        216\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number217 index216 alt2\u0026quot;\u0026gt;\n        217\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number218 index217 alt1\u0026quot;\u0026gt;\n        218\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number219 index218 alt2\u0026quot;\u0026gt;\n        219\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number220 index219 alt1\u0026quot;\u0026gt;\n        220\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number221 index220 alt2\u0026quot;\u0026gt;\n        221\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number222 index221 alt1\u0026quot;\u0026gt;\n        222\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number223 index222 alt2\u0026quot;\u0026gt;\n        223\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number224 index223 alt1\u0026quot;\u0026gt;\n        224\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number225 index224 alt2\u0026quot;\u0026gt;\n        225\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number226 index225 alt1\u0026quot;\u0026gt;\n        226\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number227 index226 alt2\u0026quot;\u0026gt;\n        227\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number228 index227 alt1\u0026quot;\u0026gt;\n        228\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number229 index228 alt2\u0026quot;\u0026gt;\n        229\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number230 index229 alt1\u0026quot;\u0026gt;\n        230\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number231 index230 alt2\u0026quot;\u0026gt;\n        231\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number232 index231 alt1\u0026quot;\u0026gt;\n        232\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number233 index232 alt2\u0026quot;\u0026gt;\n        233\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number234 index233 alt1\u0026quot;\u0026gt;\n        234\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number235 index234 alt2\u0026quot;\u0026gt;\n        235\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number236 index235 alt1\u0026quot;\u0026gt;\n        236\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number237 index236 alt2\u0026quot;\u0026gt;\n        237\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number238 index237 alt1\u0026quot;\u0026gt;\n        238\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number239 index238 alt2\u0026quot;\u0026gt;\n        239\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number240 index239 alt1\u0026quot;\u0026gt;\n        240\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number241 index240 alt2\u0026quot;\u0026gt;\n        241\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number242 index241 alt1\u0026quot;\u0026gt;\n        242\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number243 index242 alt2\u0026quot;\u0026gt;\n        243\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number244 index243 alt1\u0026quot;\u0026gt;\n        244\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number245 index244 alt2\u0026quot;\u0026gt;\n        245\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number246 index245 alt1\u0026quot;\u0026gt;\n        246\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number247 index246 alt2\u0026quot;\u0026gt;\n        247\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number248 index247 alt1\u0026quot;\u0026gt;\n        248\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number249 index248 alt2\u0026quot;\u0026gt;\n        249\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number250 index249 alt1\u0026quot;\u0026gt;\n        250\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number251 index250 alt2\u0026quot;\u0026gt;\n        251\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number252 index251 alt1\u0026quot;\u0026gt;\n        252\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number253 index252 alt2\u0026quot;\u0026gt;\n        253\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number254 index253 alt1\u0026quot;\u0026gt;\n        254\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number255 index254 alt2\u0026quot;\u0026gt;\n        255\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number256 index255 alt1\u0026quot;\u0026gt;\n        256\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number257 index256 alt2\u0026quot;\u0026gt;\n        257\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number258 index257 alt1\u0026quot;\u0026gt;\n        258\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number259 index258 alt2\u0026quot;\u0026gt;\n        259\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number260 index259 alt1\u0026quot;\u0026gt;\n        260\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number261 index260 alt2\u0026quot;\u0026gt;\n        261\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number262 index261 alt1\u0026quot;\u0026gt;\n        262\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number263 index262 alt2\u0026quot;\u0026gt;\n        263\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number264 index263 alt1\u0026quot;\u0026gt;\n        264\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number265 index264 alt2\u0026quot;\u0026gt;\n        265\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number266 index265 alt1\u0026quot;\u0026gt;\n        266\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number267 index266 alt2\u0026quot;\u0026gt;\n        267\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number268 index267 alt1\u0026quot;\u0026gt;\n        268\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number269 index268 alt2\u0026quot;\u0026gt;\n        269\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number270 index269 alt1\u0026quot;\u0026gt;\n        270\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number271 index270 alt2\u0026quot;\u0026gt;\n        271\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number272 index271 alt1\u0026quot;\u0026gt;\n        272\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number273 index272 alt2\u0026quot;\u0026gt;\n        273\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number274 index273 alt1\u0026quot;\u0026gt;\n        274\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number275 index274 alt2\u0026quot;\u0026gt;\n        275\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number276 index275 alt1\u0026quot;\u0026gt;\n        276\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number277 index276 alt2\u0026quot;\u0026gt;\n        277\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number278 index277 alt1\u0026quot;\u0026gt;\n        278\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number279 index278 alt2\u0026quot;\u0026gt;\n        279\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number280 index279 alt1\u0026quot;\u0026gt;\n        280\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number281 index280 alt2\u0026quot;\u0026gt;\n        281\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number282 index281 alt1\u0026quot;\u0026gt;\n        282\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number283 index282 alt2\u0026quot;\u0026gt;\n        283\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number284 index283 alt1\u0026quot;\u0026gt;\n        284\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number285 index284 alt2\u0026quot;\u0026gt;\n        285\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number286 index285 alt1\u0026quot;\u0026gt;\n        286\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number287 index286 alt2\u0026quot;\u0026gt;\n        287\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number288 index287 alt1\u0026quot;\u0026gt;\n        288\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number289 index288 alt2\u0026quot;\u0026gt;\n        289\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number290 index289 alt1\u0026quot;\u0026gt;\n        290\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number291 index290 alt2\u0026quot;\u0026gt;\n        291\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number292 index291 alt1\u0026quot;\u0026gt;\n        292\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number293 index292 alt2\u0026quot;\u0026gt;\n        293\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number294 index293 alt1\u0026quot;\u0026gt;\n        294\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number295 index294 alt2\u0026quot;\u0026gt;\n        295\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number296 index295 alt1\u0026quot;\u0026gt;\n        296\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number297 index296 alt2\u0026quot;\u0026gt;\n        297\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number298 index297 alt1\u0026quot;\u0026gt;\n        298\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number299 index298 alt2\u0026quot;\u0026gt;\n        299\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number300 index299 alt1\u0026quot;\u0026gt;\n        300\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number301 index300 alt2\u0026quot;\u0026gt;\n        301\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number302 index301 alt1\u0026quot;\u0026gt;\n        302\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number303 index302 alt2\u0026quot;\u0026gt;\n        303\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number304 index303 alt1\u0026quot;\u0026gt;\n        304\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number305 index304 alt2\u0026quot;\u0026gt;\n        305\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number306 index305 alt1\u0026quot;\u0026gt;\n        306\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number307 index306 alt2\u0026quot;\u0026gt;\n        307\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number308 index307 alt1\u0026quot;\u0026gt;\n        308\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number309 index308 alt2\u0026quot;\u0026gt;\n        309\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number310 index309 alt1\u0026quot;\u0026gt;\n        310\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number311 index310 alt2\u0026quot;\u0026gt;\n        311\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number312 index311 alt1\u0026quot;\u0026gt;\n        312\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number313 index312 alt2\u0026quot;\u0026gt;\n        313\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number314 index313 alt1\u0026quot;\u0026gt;\n        314\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number315 index314 alt2\u0026quot;\u0026gt;\n        315\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number316 index315 alt1\u0026quot;\u0026gt;\n        316\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number317 index316 alt2\u0026quot;\u0026gt;\n        317\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number318 index317 alt1\u0026quot;\u0026gt;\n        318\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number319 index318 alt2\u0026quot;\u0026gt;\n        319\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number320 index319 alt1\u0026quot;\u0026gt;\n        320\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number321 index320 alt2\u0026quot;\u0026gt;\n        321\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number322 index321 alt1\u0026quot;\u0026gt;\n        322\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number323 index322 alt2\u0026quot;\u0026gt;\n        323\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number324 index323 alt1\u0026quot;\u0026gt;\n        324\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number325 index324 alt2\u0026quot;\u0026gt;\n        325\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number326 index325 alt1\u0026quot;\u0026gt;\n        326\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number327 index326 alt2\u0026quot;\u0026gt;\n        327\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number328 index327 alt1\u0026quot;\u0026gt;\n        328\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number329 index328 alt2\u0026quot;\u0026gt;\n        329\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number330 index329 alt1\u0026quot;\u0026gt;\n        330\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number331 index330 alt2\u0026quot;\u0026gt;\n        331\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number332 index331 alt1\u0026quot;\u0026gt;\n        332\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number333 index332 alt2\u0026quot;\u0026gt;\n        333\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number334 index333 alt1\u0026quot;\u0026gt;\n        334\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number335 index334 alt2\u0026quot;\u0026gt;\n        335\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number336 index335 alt1\u0026quot;\u0026gt;\n        336\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number337 index336 alt2\u0026quot;\u0026gt;\n        337\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number338 index337 alt1\u0026quot;\u0026gt;\n        338\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number339 index338 alt2\u0026quot;\u0026gt;\n        339\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number340 index339 alt1\u0026quot;\u0026gt;\n        340\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number341 index340 alt2\u0026quot;\u0026gt;\n        341\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number342 index341 alt1\u0026quot;\u0026gt;\n        342\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number343 index342 alt2\u0026quot;\u0026gt;\n        343\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number344 index343 alt1\u0026quot;\u0026gt;\n        344\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number345 index344 alt2\u0026quot;\u0026gt;\n        345\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number346 index345 alt1\u0026quot;\u0026gt;\n        346\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number347 index346 alt2\u0026quot;\u0026gt;\n        347\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number348 index347 alt1\u0026quot;\u0026gt;\n        348\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number349 index348 alt2\u0026quot;\u0026gt;\n        349\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number350 index349 alt1\u0026quot;\u0026gt;\n        350\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number351 index350 alt2\u0026quot;\u0026gt;\n        351\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number352 index351 alt1\u0026quot;\u0026gt;\n        352\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number353 index352 alt2\u0026quot;\u0026gt;\n        353\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number354 index353 alt1\u0026quot;\u0026gt;\n        354\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number355 index354 alt2\u0026quot;\u0026gt;\n        355\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number356 index355 alt1\u0026quot;\u0026gt;\n        356\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number357 index356 alt2\u0026quot;\u0026gt;\n        357\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number358 index357 alt1\u0026quot;\u0026gt;\n        358\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number359 index358 alt2\u0026quot;\u0026gt;\n        359\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number360 index359 alt1\u0026quot;\u0026gt;\n        360\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number361 index360 alt2\u0026quot;\u0026gt;\n        361\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number362 index361 alt1\u0026quot;\u0026gt;\n        362\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number363 index362 alt2\u0026quot;\u0026gt;\n        363\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number364 index363 alt1\u0026quot;\u0026gt;\n        364\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number365 index364 alt2\u0026quot;\u0026gt;\n        365\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number366 index365 alt1\u0026quot;\u0026gt;\n        366\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number367 index366 alt2\u0026quot;\u0026gt;\n        367\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number368 index367 alt1\u0026quot;\u0026gt;\n        368\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number369 index368 alt2\u0026quot;\u0026gt;\n        369\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number370 index369 alt1\u0026quot;\u0026gt;\n        370\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number371 index370 alt2\u0026quot;\u0026gt;\n        371\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number372 index371 alt1\u0026quot;\u0026gt;\n        372\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number373 index372 alt2\u0026quot;\u0026gt;\n        373\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number374 index373 alt1\u0026quot;\u0026gt;\n        374\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number375 index374 alt2\u0026quot;\u0026gt;\n        375\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number376 index375 alt1\u0026quot;\u0026gt;\n        376\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number377 index376 alt2\u0026quot;\u0026gt;\n        377\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number378 index377 alt1\u0026quot;\u0026gt;\n        378\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number379 index378 alt2\u0026quot;\u0026gt;\n        379\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number380 index379 alt1\u0026quot;\u0026gt;\n        380\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number381 index380 alt2\u0026quot;\u0026gt;\n        381\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number382 index381 alt1\u0026quot;\u0026gt;\n        382\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number383 index382 alt2\u0026quot;\u0026gt;\n        383\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number384 index383 alt1\u0026quot;\u0026gt;\n        384\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number385 index384 alt2\u0026quot;\u0026gt;\n        385\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number386 index385 alt1\u0026quot;\u0026gt;\n        386\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number387 index386 alt2\u0026quot;\u0026gt;\n        387\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number388 index387 alt1\u0026quot;\u0026gt;\n        388\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number389 index388 alt2\u0026quot;\u0026gt;\n        389\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number390 index389 alt1\u0026quot;\u0026gt;\n        390\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number391 index390 alt2\u0026quot;\u0026gt;\n        391\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number392 index391 alt1\u0026quot;\u0026gt;\n        392\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number393 index392 alt2\u0026quot;\u0026gt;\n        393\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number394 index393 alt1\u0026quot;\u0026gt;\n        394\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number395 index394 alt2\u0026quot;\u0026gt;\n        395\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number396 index395 alt1\u0026quot;\u0026gt;\n        396\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number397 index396 alt2\u0026quot;\u0026gt;\n        397\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number398 index397 alt1\u0026quot;\u0026gt;\n        398\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number399 index398 alt2\u0026quot;\u0026gt;\n        399\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number400 index399 alt1\u0026quot;\u0026gt;\n        400\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number401 index400 alt2\u0026quot;\u0026gt;\n        401\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number402 index401 alt1\u0026quot;\u0026gt;\n        402\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number403 index402 alt2\u0026quot;\u0026gt;\n        403\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number404 index403 alt1\u0026quot;\u0026gt;\n        404\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number405 index404 alt2\u0026quot;\u0026gt;\n        405\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number406 index405 alt1\u0026quot;\u0026gt;\n        406\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number407 index406 alt2\u0026quot;\u0026gt;\n        407\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number408 index407 alt1\u0026quot;\u0026gt;\n        408\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number409 index408 alt2\u0026quot;\u0026gt;\n        409\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number410 index409 alt1\u0026quot;\u0026gt;\n        410\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number411 index410 alt2\u0026quot;\u0026gt;\n        411\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number412 index411 alt1\u0026quot;\u0026gt;\n        412\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number413 index412 alt2\u0026quot;\u0026gt;\n        413\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number414 index413 alt1\u0026quot;\u0026gt;\n        414\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number415 index414 alt2\u0026quot;\u0026gt;\n        415\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number416 index415 alt1\u0026quot;\u0026gt;\n        416\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number417 index416 alt2\u0026quot;\u0026gt;\n        417\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number418 index417 alt1\u0026quot;\u0026gt;\n        418\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number419 index418 alt2\u0026quot;\u0026gt;\n        419\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number420 index419 alt1\u0026quot;\u0026gt;\n        420\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number421 index420 alt2\u0026quot;\u0026gt;\n        421\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number422 index421 alt1\u0026quot;\u0026gt;\n        422\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number423 index422 alt2\u0026quot;\u0026gt;\n        423\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number424 index423 alt1\u0026quot;\u0026gt;\n        424\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number425 index424 alt2\u0026quot;\u0026gt;\n        425\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number426 index425 alt1\u0026quot;\u0026gt;\n        426\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number427 index426 alt2\u0026quot;\u0026gt;\n        427\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number428 index427 alt1\u0026quot;\u0026gt;\n        428\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number429 index428 alt2\u0026quot;\u0026gt;\n        429\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number430 index429 alt1\u0026quot;\u0026gt;\n        430\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number431 index430 alt2\u0026quot;\u0026gt;\n        431\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number432 index431 alt1\u0026quot;\u0026gt;\n        432\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number433 index432 alt2\u0026quot;\u0026gt;\n        433\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number434 index433 alt1\u0026quot;\u0026gt;\n        434\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number435 index434 alt2\u0026quot;\u0026gt;\n        435\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number436 index435 alt1\u0026quot;\u0026gt;\n        436\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number437 index436 alt2\u0026quot;\u0026gt;\n        437\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number438 index437 alt1\u0026quot;\u0026gt;\n        438\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number439 index438 alt2\u0026quot;\u0026gt;\n        439\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number440 index439 alt1\u0026quot;\u0026gt;\n        440\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number441 index440 alt2\u0026quot;\u0026gt;\n        441\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number442 index441 alt1\u0026quot;\u0026gt;\n        442\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number443 index442 alt2\u0026quot;\u0026gt;\n        443\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number444 index443 alt1\u0026quot;\u0026gt;\n        444\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number445 index444 alt2\u0026quot;\u0026gt;\n        445\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number446 index445 alt1\u0026quot;\u0026gt;\n        446\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number447 index446 alt2\u0026quot;\u0026gt;\n        447\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number448 index447 alt1\u0026quot;\u0026gt;\n        448\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number449 index448 alt2\u0026quot;\u0026gt;\n        449\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number450 index449 alt1\u0026quot;\u0026gt;\n        450\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number451 index450 alt2\u0026quot;\u0026gt;\n        451\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number452 index451 alt1\u0026quot;\u0026gt;\n        452\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number453 index452 alt2\u0026quot;\u0026gt;\n        453\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number454 index453 alt1\u0026quot;\u0026gt;\n        454\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number455 index454 alt2\u0026quot;\u0026gt;\n        455\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number456 index455 alt1\u0026quot;\u0026gt;\n        456\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number457 index456 alt2\u0026quot;\u0026gt;\n        457\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number458 index457 alt1\u0026quot;\u0026gt;\n        458\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number459 index458 alt2\u0026quot;\u0026gt;\n        459\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number460 index459 alt1\u0026quot;\u0026gt;\n        460\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number461 index460 alt2\u0026quot;\u0026gt;\n        461\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number462 index461 alt1\u0026quot;\u0026gt;\n        462\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number463 index462 alt2\u0026quot;\u0026gt;\n        463\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number464 index463 alt1\u0026quot;\u0026gt;\n        464\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number465 index464 alt2\u0026quot;\u0026gt;\n        465\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number466 index465 alt1\u0026quot;\u0026gt;\n        466\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number467 index466 alt2\u0026quot;\u0026gt;\n        467\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number468 index467 alt1\u0026quot;\u0026gt;\n        468\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number469 index468 alt2\u0026quot;\u0026gt;\n        469\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number470 index469 alt1\u0026quot;\u0026gt;\n        470\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number471 index470 alt2\u0026quot;\u0026gt;\n        471\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number472 index471 alt1\u0026quot;\u0026gt;\n        472\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number473 index472 alt2\u0026quot;\u0026gt;\n        473\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number474 index473 alt1\u0026quot;\u0026gt;\n        474\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number475 index474 alt2\u0026quot;\u0026gt;\n        475\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number476 index475 alt1\u0026quot;\u0026gt;\n        476\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number477 index476 alt2\u0026quot;\u0026gt;\n        477\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number478 index477 alt1\u0026quot;\u0026gt;\n        478\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number479 index478 alt2\u0026quot;\u0026gt;\n        479\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number480 index479 alt1\u0026quot;\u0026gt;\n        480\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number481 index480 alt2\u0026quot;\u0026gt;\n        481\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number482 index481 alt1\u0026quot;\u0026gt;\n        482\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number483 index482 alt2\u0026quot;\u0026gt;\n        483\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number484 index483 alt1\u0026quot;\u0026gt;\n        484\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number485 index484 alt2\u0026quot;\u0026gt;\n        485\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number486 index485 alt1\u0026quot;\u0026gt;\n        486\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number487 index486 alt2\u0026quot;\u0026gt;\n        487\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number488 index487 alt1\u0026quot;\u0026gt;\n        488\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number489 index488 alt2\u0026quot;\u0026gt;\n        489\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number490 index489 alt1\u0026quot;\u0026gt;\n        490\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number491 index490 alt2\u0026quot;\u0026gt;\n        491\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number492 index491 alt1\u0026quot;\u0026gt;\n        492\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number493 index492 alt2\u0026quot;\u0026gt;\n        493\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number494 index493 alt1\u0026quot;\u0026gt;\n        494\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number495 index494 alt2\u0026quot;\u0026gt;\n        495\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number496 index495 alt1\u0026quot;\u0026gt;\n        496\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number497 index496 alt2\u0026quot;\u0026gt;\n        497\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number498 index497 alt1\u0026quot;\u0026gt;\n        498\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number499 index498 alt2\u0026quot;\u0026gt;\n        499\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number500 index499 alt1\u0026quot;\u0026gt;\n        500\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number501 index500 alt2\u0026quot;\u0026gt;\n        501\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number502 index501 alt1\u0026quot;\u0026gt;\n        502\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number503 index502 alt2\u0026quot;\u0026gt;\n        503\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number504 index503 alt1\u0026quot;\u0026gt;\n        504\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number505 index504 alt2\u0026quot;\u0026gt;\n        505\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number506 index505 alt1\u0026quot;\u0026gt;\n        506\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number507 index506 alt2\u0026quot;\u0026gt;\n        507\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number508 index507 alt1\u0026quot;\u0026gt;\n        508\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number509 index508 alt2\u0026quot;\u0026gt;\n        509\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number510 index509 alt1\u0026quot;\u0026gt;\n        510\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number511 index510 alt2\u0026quot;\u0026gt;\n        511\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number512 index511 alt1\u0026quot;\u0026gt;\n        512\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number513 index512 alt2\u0026quot;\u0026gt;\n        513\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number514 index513 alt1\u0026quot;\u0026gt;\n        514\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number515 index514 alt2\u0026quot;\u0026gt;\n        515\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number516 index515 alt1\u0026quot;\u0026gt;\n        516\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number517 index516 alt2\u0026quot;\u0026gt;\n        517\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number518 index517 alt1\u0026quot;\u0026gt;\n        518\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number519 index518 alt2\u0026quot;\u0026gt;\n        519\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number520 index519 alt1\u0026quot;\u0026gt;\n        520\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number521 index520 alt2\u0026quot;\u0026gt;\n        521\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number522 index521 alt1\u0026quot;\u0026gt;\n        522\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number523 index522 alt2\u0026quot;\u0026gt;\n        523\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number524 index523 alt1\u0026quot;\u0026gt;\n        524\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number525 index524 alt2\u0026quot;\u0026gt;\n        525\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number526 index525 alt1\u0026quot;\u0026gt;\n        526\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number527 index526 alt2\u0026quot;\u0026gt;\n        527\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number528 index527 alt1\u0026quot;\u0026gt;\n        528\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number529 index528 alt2\u0026quot;\u0026gt;\n        529\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number530 index529 alt1\u0026quot;\u0026gt;\n        530\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number531 index530 alt2\u0026quot;\u0026gt;\n        531\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number532 index531 alt1\u0026quot;\u0026gt;\n        532\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number533 index532 alt2\u0026quot;\u0026gt;\n        533\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number534 index533 alt1\u0026quot;\u0026gt;\n        534\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number535 index534 alt2\u0026quot;\u0026gt;\n        535\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number536 index535 alt1\u0026quot;\u0026gt;\n        536\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number537 index536 alt2\u0026quot;\u0026gt;\n        537\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number538 index537 alt1\u0026quot;\u0026gt;\n        538\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number539 index538 alt2\u0026quot;\u0026gt;\n        539\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number540 index539 alt1\u0026quot;\u0026gt;\n        540\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number541 index540 alt2\u0026quot;\u0026gt;\n        541\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number542 index541 alt1\u0026quot;\u0026gt;\n        542\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number543 index542 alt2\u0026quot;\u0026gt;\n        543\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number544 index543 alt1\u0026quot;\u0026gt;\n        544\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number545 index544 alt2\u0026quot;\u0026gt;\n        545\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number546 index545 alt1\u0026quot;\u0026gt;\n        546\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number547 index546 alt2\u0026quot;\u0026gt;\n        547\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number548 index547 alt1\u0026quot;\u0026gt;\n        548\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number549 index548 alt2\u0026quot;\u0026gt;\n        549\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number550 index549 alt1\u0026quot;\u0026gt;\n        550\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number551 index550 alt2\u0026quot;\u0026gt;\n        551\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number552 index551 alt1\u0026quot;\u0026gt;\n        552\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number553 index552 alt2\u0026quot;\u0026gt;\n        553\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number554 index553 alt1\u0026quot;\u0026gt;\n        554\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number555 index554 alt2\u0026quot;\u0026gt;\n        555\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number556 index555 alt1\u0026quot;\u0026gt;\n        556\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number557 index556 alt2\u0026quot;\u0026gt;\n        557\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number558 index557 alt1\u0026quot;\u0026gt;\n        558\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number559 index558 alt2\u0026quot;\u0026gt;\n        559\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number560 index559 alt1\u0026quot;\u0026gt;\n        560\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number561 index560 alt2\u0026quot;\u0026gt;\n        561\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number562 index561 alt1\u0026quot;\u0026gt;\n        562\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number563 index562 alt2\u0026quot;\u0026gt;\n        563\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number564 index563 alt1\u0026quot;\u0026gt;\n        564\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number565 index564 alt2\u0026quot;\u0026gt;\n        565\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number566 index565 alt1\u0026quot;\u0026gt;\n        566\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number567 index566 alt2\u0026quot;\u0026gt;\n        567\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number568 index567 alt1\u0026quot;\u0026gt;\n        568\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number569 index568 alt2\u0026quot;\u0026gt;\n        569\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number570 index569 alt1\u0026quot;\u0026gt;\n        570\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number571 index570 alt2\u0026quot;\u0026gt;\n        571\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number572 index571 alt1\u0026quot;\u0026gt;\n        572\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number573 index572 alt2\u0026quot;\u0026gt;\n        573\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number574 index573 alt1\u0026quot;\u0026gt;\n        574\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number575 index574 alt2\u0026quot;\u0026gt;\n        575\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number576 index575 alt1\u0026quot;\u0026gt;\n        576\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number577 index576 alt2\u0026quot;\u0026gt;\n        577\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number578 index577 alt1\u0026quot;\u0026gt;\n        578\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number579 index578 alt2\u0026quot;\u0026gt;\n        579\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number580 index579 alt1\u0026quot;\u0026gt;\n        580\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number581 index580 alt2\u0026quot;\u0026gt;\n        581\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number582 index581 alt1\u0026quot;\u0026gt;\n        582\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number583 index582 alt2\u0026quot;\u0026gt;\n        583\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number584 index583 alt1\u0026quot;\u0026gt;\n        584\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number585 index584 alt2\u0026quot;\u0026gt;\n        585\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number586 index585 alt1\u0026quot;\u0026gt;\n        586\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number587 index586 alt2\u0026quot;\u0026gt;\n        587\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number588 index587 alt1\u0026quot;\u0026gt;\n        588\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number589 index588 alt2\u0026quot;\u0026gt;\n        589\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number590 index589 alt1\u0026quot;\u0026gt;\n        590\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number591 index590 alt2\u0026quot;\u0026gt;\n        591\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number592 index591 alt1\u0026quot;\u0026gt;\n        592\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number593 index592 alt2\u0026quot;\u0026gt;\n        593\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number594 index593 alt1\u0026quot;\u0026gt;\n        594\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number595 index594 alt2\u0026quot;\u0026gt;\n        595\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number596 index595 alt1\u0026quot;\u0026gt;\n        596\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number597 index596 alt2\u0026quot;\u0026gt;\n        597\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number598 index597 alt1\u0026quot;\u0026gt;\n        598\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number599 index598 alt2\u0026quot;\u0026gt;\n        599\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number600 index599 alt1\u0026quot;\u0026gt;\n        600\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number601 index600 alt2\u0026quot;\u0026gt;\n        601\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number602 index601 alt1\u0026quot;\u0026gt;\n        602\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number603 index602 alt2\u0026quot;\u0026gt;\n        603\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number604 index603 alt1\u0026quot;\u0026gt;\n        604\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number605 index604 alt2\u0026quot;\u0026gt;\n        605\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number606 index605 alt1\u0026quot;\u0026gt;\n        606\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number607 index606 alt2\u0026quot;\u0026gt;\n        607\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number608 index607 alt1\u0026quot;\u0026gt;\n        608\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number609 index608 alt2\u0026quot;\u0026gt;\n        609\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number610 index609 alt1\u0026quot;\u0026gt;\n        610\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number611 index610 alt2\u0026quot;\u0026gt;\n        611\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number612 index611 alt1\u0026quot;\u0026gt;\n        612\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number613 index612 alt2\u0026quot;\u0026gt;\n        613\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number614 index613 alt1\u0026quot;\u0026gt;\n        614\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number615 index614 alt2\u0026quot;\u0026gt;\n        615\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number616 index615 alt1\u0026quot;\u0026gt;\n        616\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number617 index616 alt2\u0026quot;\u0026gt;\n        617\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number618 index617 alt1\u0026quot;\u0026gt;\n        618\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number619 index618 alt2\u0026quot;\u0026gt;\n        619\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number620 index619 alt1\u0026quot;\u0026gt;\n        620\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number621 index620 alt2\u0026quot;\u0026gt;\n        621\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number622 index621 alt1\u0026quot;\u0026gt;\n        622\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number623 index622 alt2\u0026quot;\u0026gt;\n        623\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number624 index623 alt1\u0026quot;\u0026gt;\n        624\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number625 index624 alt2\u0026quot;\u0026gt;\n        625\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number626 index625 alt1\u0026quot;\u0026gt;\n        626\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number627 index626 alt2\u0026quot;\u0026gt;\n        627\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number628 index627 alt1\u0026quot;\u0026gt;\n        628\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number629 index628 alt2\u0026quot;\u0026gt;\n        629\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number630 index629 alt1\u0026quot;\u0026gt;\n        630\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number631 index630 alt2\u0026quot;\u0026gt;\n        631\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number632 index631 alt1\u0026quot;\u0026gt;\n        632\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number633 index632 alt2\u0026quot;\u0026gt;\n        633\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number634 index633 alt1\u0026quot;\u0026gt;\n        634\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number635 index634 alt2\u0026quot;\u0026gt;\n        635\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number636 index635 alt1\u0026quot;\u0026gt;\n        636\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number637 index636 alt2\u0026quot;\u0026gt;\n        637\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number638 index637 alt1\u0026quot;\u0026gt;\n        638\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number639 index638 alt2\u0026quot;\u0026gt;\n        639\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number640 index639 alt1\u0026quot;\u0026gt;\n        640\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number641 index640 alt2\u0026quot;\u0026gt;\n        641\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number642 index641 alt1\u0026quot;\u0026gt;\n        642\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number643 index642 alt2\u0026quot;\u0026gt;\n        643\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number644 index643 alt1\u0026quot;\u0026gt;\n        644\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number645 index644 alt2\u0026quot;\u0026gt;\n        645\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number646 index645 alt1\u0026quot;\u0026gt;\n        646\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number647 index646 alt2\u0026quot;\u0026gt;\n        647\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number648 index647 alt1\u0026quot;\u0026gt;\n        648\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number649 index648 alt2\u0026quot;\u0026gt;\n        649\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number650 index649 alt1\u0026quot;\u0026gt;\n        650\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number651 index650 alt2\u0026quot;\u0026gt;\n        651\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number652 index651 alt1\u0026quot;\u0026gt;\n        652\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number653 index652 alt2\u0026quot;\u0026gt;\n        653\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number654 index653 alt1\u0026quot;\u0026gt;\n        654\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number655 index654 alt2\u0026quot;\u0026gt;\n        655\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number656 index655 alt1\u0026quot;\u0026gt;\n        656\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number657 index656 alt2\u0026quot;\u0026gt;\n        657\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number658 index657 alt1\u0026quot;\u0026gt;\n        658\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number659 index658 alt2\u0026quot;\u0026gt;\n        659\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number660 index659 alt1\u0026quot;\u0026gt;\n        660\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number661 index660 alt2\u0026quot;\u0026gt;\n        661\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number662 index661 alt1\u0026quot;\u0026gt;\n        662\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number663 index662 alt2\u0026quot;\u0026gt;\n        663\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number664 index663 alt1\u0026quot;\u0026gt;\n        664\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number665 index664 alt2\u0026quot;\u0026gt;\n        665\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number666 index665 alt1\u0026quot;\u0026gt;\n        666\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number667 index666 alt2\u0026quot;\u0026gt;\n        667\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number668 index667 alt1\u0026quot;\u0026gt;\n        668\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number669 index668 alt2\u0026quot;\u0026gt;\n        669\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number670 index669 alt1\u0026quot;\u0026gt;\n        670\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number671 index670 alt2\u0026quot;\u0026gt;\n        671\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number672 index671 alt1\u0026quot;\u0026gt;\n        672\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number673 index672 alt2\u0026quot;\u0026gt;\n        673\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number674 index673 alt1\u0026quot;\u0026gt;\n        674\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number675 index674 alt2\u0026quot;\u0026gt;\n        675\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number676 index675 alt1\u0026quot;\u0026gt;\n        676\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number677 index676 alt2\u0026quot;\u0026gt;\n        677\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number678 index677 alt1\u0026quot;\u0026gt;\n        678\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number679 index678 alt2\u0026quot;\u0026gt;\n        679\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number680 index679 alt1\u0026quot;\u0026gt;\n        680\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number681 index680 alt2\u0026quot;\u0026gt;\n        681\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number682 index681 alt1\u0026quot;\u0026gt;\n        682\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number683 index682 alt2\u0026quot;\u0026gt;\n        683\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number684 index683 alt1\u0026quot;\u0026gt;\n        684\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number685 index684 alt2\u0026quot;\u0026gt;\n        685\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number686 index685 alt1\u0026quot;\u0026gt;\n        686\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number687 index686 alt2\u0026quot;\u0026gt;\n        687\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number688 index687 alt1\u0026quot;\u0026gt;\n        688\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number689 index688 alt2\u0026quot;\u0026gt;\n        689\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number690 index689 alt1\u0026quot;\u0026gt;\n        690\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number691 index690 alt2\u0026quot;\u0026gt;\n        691\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number692 index691 alt1\u0026quot;\u0026gt;\n        692\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number693 index692 alt2\u0026quot;\u0026gt;\n        693\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number694 index693 alt1\u0026quot;\u0026gt;\n        694\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number695 index694 alt2\u0026quot;\u0026gt;\n        695\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number696 index695 alt1\u0026quot;\u0026gt;\n        696\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number697 index696 alt2\u0026quot;\u0026gt;\n        697\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number698 index697 alt1\u0026quot;\u0026gt;\n        698\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number699 index698 alt2\u0026quot;\u0026gt;\n        699\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number700 index699 alt1\u0026quot;\u0026gt;\n        700\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number701 index700 alt2\u0026quot;\u0026gt;\n        701\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number702 index701 alt1\u0026quot;\u0026gt;\n        702\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number703 index702 alt2\u0026quot;\u0026gt;\n        703\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number704 index703 alt1\u0026quot;\u0026gt;\n        704\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number705 index704 alt2\u0026quot;\u0026gt;\n        705\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number706 index705 alt1\u0026quot;\u0026gt;\n        706\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number707 index706 alt2\u0026quot;\u0026gt;\n        707\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number708 index707 alt1\u0026quot;\u0026gt;\n        708\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number709 index708 alt2\u0026quot;\u0026gt;\n        709\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number710 index709 alt1\u0026quot;\u0026gt;\n        710\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number711 index710 alt2\u0026quot;\u0026gt;\n        711\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number712 index711 alt1\u0026quot;\u0026gt;\n        712\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number713 index712 alt2\u0026quot;\u0026gt;\n        713\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number714 index713 alt1\u0026quot;\u0026gt;\n        714\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number715 index714 alt2\u0026quot;\u0026gt;\n        715\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number716 index715 alt1\u0026quot;\u0026gt;\n        716\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number717 index716 alt2\u0026quot;\u0026gt;\n        717\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number718 index717 alt1\u0026quot;\u0026gt;\n        718\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number719 index718 alt2\u0026quot;\u0026gt;\n        719\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number720 index719 alt1\u0026quot;\u0026gt;\n        720\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number721 index720 alt2\u0026quot;\u0026gt;\n        721\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number722 index721 alt1\u0026quot;\u0026gt;\n        722\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number723 index722 alt2\u0026quot;\u0026gt;\n        723\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number724 index723 alt1\u0026quot;\u0026gt;\n        724\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number725 index724 alt2\u0026quot;\u0026gt;\n        725\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number726 index725 alt1\u0026quot;\u0026gt;\n        726\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number727 index726 alt2\u0026quot;\u0026gt;\n        727\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number728 index727 alt1\u0026quot;\u0026gt;\n        728\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number729 index728 alt2\u0026quot;\u0026gt;\n        729\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number730 index729 alt1\u0026quot;\u0026gt;\n        730\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number731 index730 alt2\u0026quot;\u0026gt;\n        731\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number732 index731 alt1\u0026quot;\u0026gt;\n        732\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number733 index732 alt2\u0026quot;\u0026gt;\n        733\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number734 index733 alt1\u0026quot;\u0026gt;\n        734\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number735 index734 alt2\u0026quot;\u0026gt;\n        735\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number736 index735 alt1\u0026quot;\u0026gt;\n        736\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number737 index736 alt2\u0026quot;\u0026gt;\n        737\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number738 index737 alt1\u0026quot;\u0026gt;\n        738\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number739 index738 alt2\u0026quot;\u0026gt;\n        739\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number740 index739 alt1\u0026quot;\u0026gt;\n        740\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number741 index740 alt2\u0026quot;\u0026gt;\n        741\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number742 index741 alt1\u0026quot;\u0026gt;\n        742\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number743 index742 alt2\u0026quot;\u0026gt;\n        743\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number744 index743 alt1\u0026quot;\u0026gt;\n        744\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number745 index744 alt2\u0026quot;\u0026gt;\n        745\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number746 index745 alt1\u0026quot;\u0026gt;\n        746\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number747 index746 alt2\u0026quot;\u0026gt;\n        747\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number748 index747 alt1\u0026quot;\u0026gt;\n        748\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number749 index748 alt2\u0026quot;\u0026gt;\n        749\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number750 index749 alt1\u0026quot;\u0026gt;\n        750\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number751 index750 alt2\u0026quot;\u0026gt;\n        751\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number752 index751 alt1\u0026quot;\u0026gt;\n        752\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number753 index752 alt2\u0026quot;\u0026gt;\n        753\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number754 index753 alt1\u0026quot;\u0026gt;\n        754\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number755 index754 alt2\u0026quot;\u0026gt;\n        755\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number756 index755 alt1\u0026quot;\u0026gt;\n        756\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number757 index756 alt2\u0026quot;\u0026gt;\n        757\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number758 index757 alt1\u0026quot;\u0026gt;\n        758\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number759 index758 alt2\u0026quot;\u0026gt;\n        759\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number760 index759 alt1\u0026quot;\u0026gt;\n        760\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number761 index760 alt2\u0026quot;\u0026gt;\n        761\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number762 index761 alt1\u0026quot;\u0026gt;\n        762\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number763 index762 alt2\u0026quot;\u0026gt;\n        763\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number764 index763 alt1\u0026quot;\u0026gt;\n        764\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number765 index764 alt2\u0026quot;\u0026gt;\n        765\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number766 index765 alt1\u0026quot;\u0026gt;\n        766\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number767 index766 alt2\u0026quot;\u0026gt;\n        767\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number768 index767 alt1\u0026quot;\u0026gt;\n        768\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number769 index768 alt2\u0026quot;\u0026gt;\n        769\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number770 index769 alt1\u0026quot;\u0026gt;\n        770\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number771 index770 alt2\u0026quot;\u0026gt;\n        771\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number772 index771 alt1\u0026quot;\u0026gt;\n        772\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number773 index772 alt2\u0026quot;\u0026gt;\n        773\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number774 index773 alt1\u0026quot;\u0026gt;\n        774\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number775 index774 alt2\u0026quot;\u0026gt;\n        775\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number776 index775 alt1\u0026quot;\u0026gt;\n        776\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number777 index776 alt2\u0026quot;\u0026gt;\n        777\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number778 index777 alt1\u0026quot;\u0026gt;\n        778\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number779 index778 alt2\u0026quot;\u0026gt;\n        779\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number780 index779 alt1\u0026quot;\u0026gt;\n        780\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number781 index780 alt2\u0026quot;\u0026gt;\n        781\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number782 index781 alt1\u0026quot;\u0026gt;\n        782\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number783 index782 alt2\u0026quot;\u0026gt;\n        783\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number784 index783 alt1\u0026quot;\u0026gt;\n        784\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number785 index784 alt2\u0026quot;\u0026gt;\n        785\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number786 index785 alt1\u0026quot;\u0026gt;\n        786\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number787 index786 alt2\u0026quot;\u0026gt;\n        787\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number788 index787 alt1\u0026quot;\u0026gt;\n        788\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number789 index788 alt2\u0026quot;\u0026gt;\n        789\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number790 index789 alt1\u0026quot;\u0026gt;\n        790\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number791 index790 alt2\u0026quot;\u0026gt;\n        791\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number792 index791 alt1\u0026quot;\u0026gt;\n        792\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number793 index792 alt2\u0026quot;\u0026gt;\n        793\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number794 index793 alt1\u0026quot;\u0026gt;\n        794\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number795 index794 alt2\u0026quot;\u0026gt;\n        795\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number796 index795 alt1\u0026quot;\u0026gt;\n        796\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number797 index796 alt2\u0026quot;\u0026gt;\n        797\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number798 index797 alt1\u0026quot;\u0026gt;\n        798\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number799 index798 alt2\u0026quot;\u0026gt;\n        799\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number800 index799 alt1\u0026quot;\u0026gt;\n        800\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number801 index800 alt2\u0026quot;\u0026gt;\n        801\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number802 index801 alt1\u0026quot;\u0026gt;\n        802\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number803 index802 alt2\u0026quot;\u0026gt;\n        803\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number804 index803 alt1\u0026quot;\u0026gt;\n        804\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number805 index804 alt2\u0026quot;\u0026gt;\n        805\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number806 index805 alt1\u0026quot;\u0026gt;\n        806\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number807 index806 alt2\u0026quot;\u0026gt;\n        807\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number808 index807 alt1\u0026quot;\u0026gt;\n        808\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number809 index808 alt2\u0026quot;\u0026gt;\n        809\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number810 index809 alt1\u0026quot;\u0026gt;\n        810\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number811 index810 alt2\u0026quot;\u0026gt;\n        811\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number812 index811 alt1\u0026quot;\u0026gt;\n        812\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number813 index812 alt2\u0026quot;\u0026gt;\n        813\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number814 index813 alt1\u0026quot;\u0026gt;\n        814\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number815 index814 alt2\u0026quot;\u0026gt;\n        815\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number816 index815 alt1\u0026quot;\u0026gt;\n        816\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number817 index816 alt2\u0026quot;\u0026gt;\n        817\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number818 index817 alt1\u0026quot;\u0026gt;\n        818\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number819 index818 alt2\u0026quot;\u0026gt;\n        819\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number820 index819 alt1\u0026quot;\u0026gt;\n        820\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number821 index820 alt2\u0026quot;\u0026gt;\n        821\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number822 index821 alt1\u0026quot;\u0026gt;\n        822\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number823 index822 alt2\u0026quot;\u0026gt;\n        823\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number824 index823 alt1\u0026quot;\u0026gt;\n        824\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number825 index824 alt2\u0026quot;\u0026gt;\n        825\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number826 index825 alt1\u0026quot;\u0026gt;\n        826\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number827 index826 alt2\u0026quot;\u0026gt;\n        827\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number828 index827 alt1\u0026quot;\u0026gt;\n        828\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number829 index828 alt2\u0026quot;\u0026gt;\n        829\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number830 index829 alt1\u0026quot;\u0026gt;\n        830\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number831 index830 alt2\u0026quot;\u0026gt;\n        831\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number832 index831 alt1\u0026quot;\u0026gt;\n        832\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number833 index832 alt2\u0026quot;\u0026gt;\n        833\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number834 index833 alt1\u0026quot;\u0026gt;\n        834\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number835 index834 alt2\u0026quot;\u0026gt;\n        835\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number836 index835 alt1\u0026quot;\u0026gt;\n        836\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number837 index836 alt2\u0026quot;\u0026gt;\n        837\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number838 index837 alt1\u0026quot;\u0026gt;\n        838\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number839 index838 alt2\u0026quot;\u0026gt;\n        839\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number840 index839 alt1\u0026quot;\u0026gt;\n        840\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number841 index840 alt2\u0026quot;\u0026gt;\n        841\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number842 index841 alt1\u0026quot;\u0026gt;\n        842\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number843 index842 alt2\u0026quot;\u0026gt;\n        843\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number844 index843 alt1\u0026quot;\u0026gt;\n        844\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number845 index844 alt2\u0026quot;\u0026gt;\n        845\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number846 index845 alt1\u0026quot;\u0026gt;\n        846\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number847 index846 alt2\u0026quot;\u0026gt;\n        847\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number848 index847 alt1\u0026quot;\u0026gt;\n        848\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number849 index848 alt2\u0026quot;\u0026gt;\n        849\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number850 index849 alt1\u0026quot;\u0026gt;\n        850\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number851 index850 alt2\u0026quot;\u0026gt;\n        851\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number852 index851 alt1\u0026quot;\u0026gt;\n        852\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number853 index852 alt2\u0026quot;\u0026gt;\n        853\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number854 index853 alt1\u0026quot;\u0026gt;\n        854\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number855 index854 alt2\u0026quot;\u0026gt;\n        855\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number856 index855 alt1\u0026quot;\u0026gt;\n        856\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number857 index856 alt2\u0026quot;\u0026gt;\n        857\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number858 index857 alt1\u0026quot;\u0026gt;\n        858\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number859 index858 alt2\u0026quot;\u0026gt;\n        859\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number860 index859 alt1\u0026quot;\u0026gt;\n        860\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number861 index860 alt2\u0026quot;\u0026gt;\n        861\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number862 index861 alt1\u0026quot;\u0026gt;\n        862\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number863 index862 alt2\u0026quot;\u0026gt;\n        863\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number864 index863 alt1\u0026quot;\u0026gt;\n        864\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number865 index864 alt2\u0026quot;\u0026gt;\n        865\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number866 index865 alt1\u0026quot;\u0026gt;\n        866\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number867 index866 alt2\u0026quot;\u0026gt;\n        867\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number868 index867 alt1\u0026quot;\u0026gt;\n        868\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number869 index868 alt2\u0026quot;\u0026gt;\n        869\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number870 index869 alt1\u0026quot;\u0026gt;\n        870\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number871 index870 alt2\u0026quot;\u0026gt;\n        871\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number872 index871 alt1\u0026quot;\u0026gt;\n        872\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number873 index872 alt2\u0026quot;\u0026gt;\n        873\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number874 index873 alt1\u0026quot;\u0026gt;\n        874\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number875 index874 alt2\u0026quot;\u0026gt;\n        875\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number876 index875 alt1\u0026quot;\u0026gt;\n        876\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number877 index876 alt2\u0026quot;\u0026gt;\n        877\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number878 index877 alt1\u0026quot;\u0026gt;\n        878\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number879 index878 alt2\u0026quot;\u0026gt;\n        879\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number880 index879 alt1\u0026quot;\u0026gt;\n        880\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number881 index880 alt2\u0026quot;\u0026gt;\n        881\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number882 index881 alt1\u0026quot;\u0026gt;\n        882\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number883 index882 alt2\u0026quot;\u0026gt;\n        883\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number884 index883 alt1\u0026quot;\u0026gt;\n        884\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number885 index884 alt2\u0026quot;\u0026gt;\n        885\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number886 index885 alt1\u0026quot;\u0026gt;\n        886\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number887 index886 alt2\u0026quot;\u0026gt;\n        887\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number888 index887 alt1\u0026quot;\u0026gt;\n        888\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number889 index888 alt2\u0026quot;\u0026gt;\n        889\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number890 index889 alt1\u0026quot;\u0026gt;\n        890\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number891 index890 alt2\u0026quot;\u0026gt;\n        891\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number892 index891 alt1\u0026quot;\u0026gt;\n        892\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number893 index892 alt2\u0026quot;\u0026gt;\n        893\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number894 index893 alt1\u0026quot;\u0026gt;\n        894\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number895 index894 alt2\u0026quot;\u0026gt;\n        895\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number896 index895 alt1\u0026quot;\u0026gt;\n        896\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number897 index896 alt2\u0026quot;\u0026gt;\n        897\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number898 index897 alt1\u0026quot;\u0026gt;\n        898\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number899 index898 alt2\u0026quot;\u0026gt;\n        899\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number900 index899 alt1\u0026quot;\u0026gt;\n        900\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number901 index900 alt2\u0026quot;\u0026gt;\n        901\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number902 index901 alt1\u0026quot;\u0026gt;\n        902\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number903 index902 alt2\u0026quot;\u0026gt;\n        903\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number904 index903 alt1\u0026quot;\u0026gt;\n        904\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number905 index904 alt2\u0026quot;\u0026gt;\n        905\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number906 index905 alt1\u0026quot;\u0026gt;\n        906\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number907 index906 alt2\u0026quot;\u0026gt;\n        907\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number908 index907 alt1\u0026quot;\u0026gt;\n        908\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number909 index908 alt2\u0026quot;\u0026gt;\n        909\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number910 index909 alt1\u0026quot;\u0026gt;\n        910\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number911 index910 alt2\u0026quot;\u0026gt;\n        911\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number912 index911 alt1\u0026quot;\u0026gt;\n        912\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number913 index912 alt2\u0026quot;\u0026gt;\n        913\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number914 index913 alt1\u0026quot;\u0026gt;\n        914\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number915 index914 alt2\u0026quot;\u0026gt;\n        915\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number916 index915 alt1\u0026quot;\u0026gt;\n        916\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number917 index916 alt2\u0026quot;\u0026gt;\n        917\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number918 index917 alt1\u0026quot;\u0026gt;\n        918\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number919 index918 alt2\u0026quot;\u0026gt;\n        919\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number920 index919 alt1\u0026quot;\u0026gt;\n        920\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number921 index920 alt2\u0026quot;\u0026gt;\n        921\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number922 index921 alt1\u0026quot;\u0026gt;\n        922\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number923 index922 alt2\u0026quot;\u0026gt;\n        923\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number924 index923 alt1\u0026quot;\u0026gt;\n        924\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number925 index924 alt2\u0026quot;\u0026gt;\n        925\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number926 index925 alt1\u0026quot;\u0026gt;\n        926\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number927 index926 alt2\u0026quot;\u0026gt;\n        927\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number928 index927 alt1\u0026quot;\u0026gt;\n        928\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number929 index928 alt2\u0026quot;\u0026gt;\n        929\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number930 index929 alt1\u0026quot;\u0026gt;\n        930\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number931 index930 alt2\u0026quot;\u0026gt;\n        931\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number932 index931 alt1\u0026quot;\u0026gt;\n        932\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number933 index932 alt2\u0026quot;\u0026gt;\n        933\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number934 index933 alt1\u0026quot;\u0026gt;\n        934\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number935 index934 alt2\u0026quot;\u0026gt;\n        935\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number936 index935 alt1\u0026quot;\u0026gt;\n        936\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number937 index936 alt2\u0026quot;\u0026gt;\n        937\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number938 index937 alt1\u0026quot;\u0026gt;\n        938\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number939 index938 alt2\u0026quot;\u0026gt;\n        939\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number940 index939 alt1\u0026quot;\u0026gt;\n        940\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number941 index940 alt2\u0026quot;\u0026gt;\n        941\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number942 index941 alt1\u0026quot;\u0026gt;\n        942\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number943 index942 alt2\u0026quot;\u0026gt;\n        943\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number944 index943 alt1\u0026quot;\u0026gt;\n        944\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number945 index944 alt2\u0026quot;\u0026gt;\n        945\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number946 index945 alt1\u0026quot;\u0026gt;\n        946\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number947 index946 alt2\u0026quot;\u0026gt;\n        947\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number948 index947 alt1\u0026quot;\u0026gt;\n        948\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number949 index948 alt2\u0026quot;\u0026gt;\n        949\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number950 index949 alt1\u0026quot;\u0026gt;\n        950\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number951 index950 alt2\u0026quot;\u0026gt;\n        951\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number952 index951 alt1\u0026quot;\u0026gt;\n        952\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number953 index952 alt2\u0026quot;\u0026gt;\n        953\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number954 index953 alt1\u0026quot;\u0026gt;\n        954\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number955 index954 alt2\u0026quot;\u0026gt;\n        955\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number956 index955 alt1\u0026quot;\u0026gt;\n        956\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number957 index956 alt2\u0026quot;\u0026gt;\n        957\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number958 index957 alt1\u0026quot;\u0026gt;\n        958\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number959 index958 alt2\u0026quot;\u0026gt;\n        959\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number960 index959 alt1\u0026quot;\u0026gt;\n        960\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number961 index960 alt2\u0026quot;\u0026gt;\n        961\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number962 index961 alt1\u0026quot;\u0026gt;\n        962\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number963 index962 alt2\u0026quot;\u0026gt;\n        963\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number964 index963 alt1\u0026quot;\u0026gt;\n        964\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number965 index964 alt2\u0026quot;\u0026gt;\n        965\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number966 index965 alt1\u0026quot;\u0026gt;\n        966\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number967 index966 alt2\u0026quot;\u0026gt;\n        967\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number968 index967 alt1\u0026quot;\u0026gt;\n        968\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number969 index968 alt2\u0026quot;\u0026gt;\n        969\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number970 index969 alt1\u0026quot;\u0026gt;\n        970\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number971 index970 alt2\u0026quot;\u0026gt;\n        971\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number972 index971 alt1\u0026quot;\u0026gt;\n        972\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number973 index972 alt2\u0026quot;\u0026gt;\n        973\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number974 index973 alt1\u0026quot;\u0026gt;\n        974\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number975 index974 alt2\u0026quot;\u0026gt;\n        975\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number976 index975 alt1\u0026quot;\u0026gt;\n        976\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number977 index976 alt2\u0026quot;\u0026gt;\n        977\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number978 index977 alt1\u0026quot;\u0026gt;\n        978\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number979 index978 alt2\u0026quot;\u0026gt;\n        979\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number980 index979 alt1\u0026quot;\u0026gt;\n        980\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number981 index980 alt2\u0026quot;\u0026gt;\n        981\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number982 index981 alt1\u0026quot;\u0026gt;\n        982\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number983 index982 alt2\u0026quot;\u0026gt;\n        983\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number984 index983 alt1\u0026quot;\u0026gt;\n        984\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number985 index984 alt2\u0026quot;\u0026gt;\n        985\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number986 index985 alt1\u0026quot;\u0026gt;\n        986\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number987 index986 alt2\u0026quot;\u0026gt;\n        987\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number988 index987 alt1\u0026quot;\u0026gt;\n        988\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number989 index988 alt2\u0026quot;\u0026gt;\n        989\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number990 index989 alt1\u0026quot;\u0026gt;\n        990\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number991 index990 alt2\u0026quot;\u0026gt;\n        991\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `public` `class` `CustomViewAbove ``extends` `ViewGroup {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `    ``private` `static` `final` `String TAG = ``\u0026quot;CustomViewAbove\u0026quot;``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          `    ``private` `static` `final` `boolean` `DEBUG = ``false``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n          `    ``private` `static` `final` `boolean` `USE_CACHE = ``false``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n          `    ``private` `static` `final` `int` `MAX_SETTLE_DURATION = ``600``; ``// ms`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n          `    ``private` `static` `final` `int` `MIN_DISTANCE_FOR_FLING = ``25``; ``// dips`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n          `    ``private` `static` `final` `Interpolator sInterpolator = ``new` `Interpolator() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n          `        ``public` `float` `getInterpolation(``float` `t) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n          `            ``t -= ``1``.0f;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n          `            ``return` `t * t * t * t * t + ``1``.0f;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n          `    ``};`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n          `    ``private` `View mContent;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n          `    ``private` `int` `mCurItem;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n          `    ``private` `Scroller mScroller;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n          `    ``private` `boolean` `mScrollingCacheEnabled;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n          `    ``private` `boolean` `mScrolling;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n          `    ``private` `boolean` `mIsBeingDragged;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n          `    ``private` `boolean` `mIsUnableToDrag;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n          `    ``private` `int` `mTouchSlop;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n          `    ``private` `float` `mInitialMotionX;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n          `     ``* Position of the last motion event.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt;\n          `    ``private` `float` `mLastMotionX;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt;\n          `    ``private` `float` `mLastMotionY;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt;\n          `     ``* ID of the active pointer. This is used to retain consistency during`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt;\n          `     ``* drags/flings if multiple pointers are used.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt;\n          `    ``protected` `int` `mActivePointerId = INVALID_POINTER;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt;\n          `     ``* Sentinel value for no current active pointer.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt;\n          `     ``* Used by {@link #mActivePointerId}.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt;\n          `    ``private` `static` `final` `int` `INVALID_POINTER = -``1``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt;\n          `        ``/** 保存转场动画的变量*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt;\n          `    ``private` `CanvasTransformer mTransformer;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt;\n          `     ``* Determines speed during touch scrolling`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt;\n          `    ``protected` `VelocityTracker mVelocityTracker;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt;\n          `    ``private` `int` `mMinimumVelocity;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt;\n          `    ``protected` `int` `mMaximumVelocity;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt;\n          `    ``private` `int` `mFlingDistance;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt;\n          `    ``private` `CustomViewBehind mViewBehind;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt;\n          `    ``//  private int mMode;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt;\n          `    ``private` `boolean` `mEnabled = ``true``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt;\n          `    ``private` `OnPageChangeListener mOnPageChangeListener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt;\n          `    ``private` `OnPageChangeListener mInternalPageChangeListener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt;\n          `    ``//  private OnCloseListener mCloseListener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt;\n          `    ``//  private OnOpenListener mOpenListener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt;\n          `    ``private` `OnClosedListener mClosedListener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt;\n          `    ``private` `OnOpenedListener mOpenedListener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt;\n          `    ``private` `List\u0026amp;lt;View\u0026amp;gt; mIgnoredViews = ``new` `ArrayList\u0026amp;lt;View\u0026amp;gt;();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt;\n          `    ``//  private int mScrollState = SCROLL_STATE_IDLE;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt;\n          `     ``* Callback interface for responding to changing state of the selected page.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt;\n          `    ``public` `interface` `OnPageChangeListener {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt;\n          `        ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt;\n          `         ``* This method will be invoked when the current page is scrolled, either as part`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt;\n          `         ``* of a programmatically initiated smooth scroll or a user initiated touch scroll.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt;\n          `         ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt;\n          `         ``* @param position Position index of the first page currently being displayed.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt;\n          `         ``*                 Page position+1 will be visible if positionOffset is nonzero.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt;\n          `         ``* @param positionOffset Value from [0, 1) indicating the offset from the page at position.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt;\n          `         ``* @param positionOffsetPixels Value in pixels indicating the offset from position.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt;\n          `         ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt;\n          `        ``public` `void` `onPageScrolled(``int` `position, ``float` `positionOffset, ``int` `positionOffsetPixels);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt;\n          `        ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt;\n          `         ``* This method will be invoked when a new page becomes selected. Animation is not`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt;\n          `         ``* necessarily complete.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt;\n          `         ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt;\n          `         ``* @param position Position index of the new selected page.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt;\n          `         ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt;\n          `        ``public` `void` `onPageSelected(``int` `position);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt;\n          `     ``* Simple implementation of the {@link OnPageChangeListener} interface with stub`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number101 index100 alt2\u0026quot;\u0026gt;\n          `     ``* implementations of each method. Extend this if you do not intend to override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number102 index101 alt1\u0026quot;\u0026gt;\n          `     ``* every method of {@link OnPageChangeListener}.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number103 index102 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number104 index103 alt1\u0026quot;\u0026gt;\n          `    ``public` `static` `class` `SimpleOnPageChangeListener ``implements` `OnPageChangeListener {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number105 index104 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number106 index105 alt1\u0026quot;\u0026gt;\n          `        ``public` `void` `onPageScrolled(``int` `position, ``float` `positionOffset, ``int` `positionOffsetPixels) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number107 index106 alt2\u0026quot;\u0026gt;\n          `            ``// This space for rent`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number108 index107 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number109 index108 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number110 index109 alt1\u0026quot;\u0026gt;\n          `        ``public` `void` `onPageSelected(``int` `position) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number111 index110 alt2\u0026quot;\u0026gt;\n          `            ``// This space for rent`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number112 index111 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number113 index112 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number114 index113 alt1\u0026quot;\u0026gt;\n          `        ``public` `void` `onPageScrollStateChanged(``int` `state) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number115 index114 alt2\u0026quot;\u0026gt;\n          `            ``// This space for rent`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number116 index115 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number117 index116 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number118 index117 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number119 index118 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number120 index119 alt1\u0026quot;\u0026gt;\n          `    ``public` `CustomViewAbove(Context context) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number121 index120 alt2\u0026quot;\u0026gt;\n          `        ``this``(context, ``null``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number122 index121 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number123 index122 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number124 index123 alt1\u0026quot;\u0026gt;\n          `    ``public` `CustomViewAbove(Context context, AttributeSet attrs) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number125 index124 alt2\u0026quot;\u0026gt;\n          `        ``super``(context, attrs);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number126 index125 alt1\u0026quot;\u0026gt;\n          `        ``initCustomViewAbove();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number127 index126 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number128 index127 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number129 index128 alt2\u0026quot;\u0026gt;\n          `    ``void` `initCustomViewAbove() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number130 index129 alt1\u0026quot;\u0026gt;\n          `        ``setWillNotDraw(``false``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number131 index130 alt2\u0026quot;\u0026gt;\n          `        ``setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number132 index131 alt1\u0026quot;\u0026gt;\n          `        ``setFocusable(``true``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number133 index132 alt2\u0026quot;\u0026gt;\n          `        ``final` `Context context = getContext();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number134 index133 alt1\u0026quot;\u0026gt;\n          `        ``mScroller = ``new` `Scroller(context, sInterpolator);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number135 index134 alt2\u0026quot;\u0026gt;\n          `        ``final` `ViewConfiguration configuration = ViewConfiguration.get(context);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number136 index135 alt1\u0026quot;\u0026gt;\n          `        ``mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number137 index136 alt2\u0026quot;\u0026gt;\n          `        ``mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number138 index137 alt1\u0026quot;\u0026gt;\n          `        ``mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number139 index138 alt2\u0026quot;\u0026gt;\n          `        ``setInternalPageChangeListener(``new` `SimpleOnPageChangeListener() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number140 index139 alt1\u0026quot;\u0026gt;\n          `            ``public` `void` `onPageSelected(``int` `position) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number141 index140 alt2\u0026quot;\u0026gt;\n          `                ``if` `(mViewBehind != ``null``) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number142 index141 alt1\u0026quot;\u0026gt;\n          `                    ``switch` `(position) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number143 index142 alt2\u0026quot;\u0026gt;\n          `                    ``case` ```:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number144 index143 alt1\u0026quot;\u0026gt;\n          `                    ``case` `2``:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number145 index144 alt2\u0026quot;\u0026gt;\n          `                        ``mViewBehind.setChildrenEnabled(``true``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number146 index145 alt1\u0026quot;\u0026gt;\n          `                        ``break``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number147 index146 alt2\u0026quot;\u0026gt;\n          `                    ``case` `1``:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number148 index147 alt1\u0026quot;\u0026gt;\n          `                        ``mViewBehind.setChildrenEnabled(``false``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number149 index148 alt2\u0026quot;\u0026gt;\n          `                        ``break``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number150 index149 alt1\u0026quot;\u0026gt;\n          `                    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number151 index150 alt2\u0026quot;\u0026gt;\n          `                ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number152 index151 alt1\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number153 index152 alt2\u0026quot;\u0026gt;\n          `        ``});`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number154 index153 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number155 index154 alt2\u0026quot;\u0026gt;\n          `        ``final` `float` `density = context.getResources().getDisplayMetrics().density;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number156 index155 alt1\u0026quot;\u0026gt;\n          `        ``mFlingDistance = (``int``) (MIN_DISTANCE_FOR_FLING * density);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number157 index156 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number158 index157 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number159 index158 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number160 index159 alt1\u0026quot;\u0026gt;\n          `     ``* Set the currently selected page. If the CustomViewPager has already been through its first`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number161 index160 alt2\u0026quot;\u0026gt;\n          `     ``* layout there will be a smooth animated transition between the current item and the`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number162 index161 alt1\u0026quot;\u0026gt;\n          `     ``* specified item.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number163 index162 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number164 index163 alt1\u0026quot;\u0026gt;\n          `     ``* @param item Item index to select`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number165 index164 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number166 index165 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setCurrentItem(``int` `item) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number167 index166 alt2\u0026quot;\u0026gt;\n          `        ``setCurrentItemInternal(item, ``true``, ``false``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number168 index167 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number169 index168 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number170 index169 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number171 index170 alt2\u0026quot;\u0026gt;\n          `     ``* Set the currently selected page.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number172 index171 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number173 index172 alt2\u0026quot;\u0026gt;\n          `     ``* @param item Item index to select`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number174 index173 alt1\u0026quot;\u0026gt;\n          `     ``* @param smoothScroll True to smoothly scroll to the new item, false to transition immediately`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number175 index174 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number176 index175 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `setCurrentItem(``int` `item, ``boolean` `smoothScroll) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number177 index176 alt2\u0026quot;\u0026gt;\n          `        ``setCurrentItemInternal(item, smoothScroll, ``false``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number178 index177 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number179 index178 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number180 index179 alt1\u0026quot;\u0026gt;\n          `    ``public` `int` `getCurrentItem() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number181 index180 alt2\u0026quot;\u0026gt;\n          `        ``return` `mCurItem;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number182 index181 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number183 index182 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number184 index183 alt1\u0026quot;\u0026gt;\n          `    ``void` `setCurrentItemInternal(``int` `item, ``boolean` `smoothScroll, ``boolean` `always) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number185 index184 alt2\u0026quot;\u0026gt;\n          `        ``setCurrentItemInternal(item, smoothScroll, always, ````);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number186 index185 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number187 index186 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number188 index187 alt1\u0026quot;\u0026gt;\n          `    ``void` `setCurrentItemInternal(``int` `item, ``boolean` `smoothScroll, ``boolean` `always, ``int` `velocity) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number189 index188 alt2\u0026quot;\u0026gt;\n          `        ``if` `(!always \u0026amp;\u0026amp; mCurItem == item) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number190 index189 alt1\u0026quot;\u0026gt;\n          `            ``setScrollingCacheEnabled(``false``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number191 index190 alt2\u0026quot;\u0026gt;\n          `            ``return``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number192 index191 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number193 index192 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number194 index193 alt1\u0026quot;\u0026gt;\n          `        ``item = mViewBehind.getMenuPage(item);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number195 index194 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number196 index195 alt1\u0026quot;\u0026gt;\n          `        ``final` `boolean` `dispatchSelected = mCurItem != item;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number197 index196 alt2\u0026quot;\u0026gt;\n          `        ``mCurItem = item;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number198 index197 alt1\u0026quot;\u0026gt;\n          `        ``final` `int` `destX = getDestScrollX(mCurItem);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number199 index198 alt2\u0026quot;\u0026gt;\n          `        ``if` `(dispatchSelected \u0026amp;\u0026amp; mOnPageChangeListener != ``null``) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number200 index199 alt1\u0026quot;\u0026gt;\n          `            ``mOnPageChangeListener.onPageSelected(item);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number201 index200 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number202 index201 alt1\u0026quot;\u0026gt;\n          `        ``if` `(dispatchSelected \u0026amp;\u0026amp; mInternalPageChangeListener != ``null``) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number203 index202 alt2\u0026quot;\u0026gt;\n          `            ``mInternalPageChangeListener.onPageSelected(item);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number204 index203 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number205 index204 alt2\u0026quot;\u0026gt;\n          `        ``if` `(smoothScroll) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number206 index205 alt1\u0026quot;\u0026gt;\n          `            ``smoothScrollTo(destX, ````, velocity);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number207 index206 alt2\u0026quot;\u0026gt;\n          `        ``} ``else` `{`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number208 index207 alt1\u0026quot;\u0026gt;\n          `            ``completeScroll();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number209 index208 alt2\u0026quot;\u0026gt;\n          `            ``scrollTo(destX, ````);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number210 index209 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number211 index210 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number212 index211 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number213 index212 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number214 index213 alt1\u0026quot;\u0026gt;\n          `     ``* Set a listener that will be invoked whenever the page changes or is incrementally`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number215 index214 alt2\u0026quot;\u0026gt;\n          `     ``* scrolled. See {@link OnPageChangeListener}.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number216 index215 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number217 index216 alt2\u0026quot;\u0026gt;\n          `     ``* @param listener Listener to set`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number218 index217 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number219 index218 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setOnPageChangeListener(OnPageChangeListener listener) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number220 index219 alt1\u0026quot;\u0026gt;\n          `        ``mOnPageChangeListener = listener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number221 index220 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number222 index221 alt1\u0026quot;\u0026gt;\n          `    ``/*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number223 index222 alt2\u0026quot;\u0026gt;\n          `    ``public void setOnOpenListener(OnOpenListener l) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number224 index223 alt1\u0026quot;\u0026gt;\n          `        ``mOpenListener = l;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number225 index224 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number226 index225 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number227 index226 alt2\u0026quot;\u0026gt;\n          `    ``public void setOnCloseListener(OnCloseListener l) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number228 index227 alt1\u0026quot;\u0026gt;\n          `        ``mCloseListener = l;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number229 index228 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number230 index229 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number231 index230 alt2\u0026quot;\u0026gt;\n          `    ``public void setOnOpenedListener(OnOpenedListener l) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number232 index231 alt1\u0026quot;\u0026gt;\n          `        ``mOpenedListener = l;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number233 index232 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number234 index233 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number235 index234 alt2\u0026quot;\u0026gt;\n          `    ``public void setOnClosedListener(OnClosedListener l) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number236 index235 alt1\u0026quot;\u0026gt;\n          `        ``mClosedListener = l;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number237 index236 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number238 index237 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number239 index238 alt2\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number240 index239 alt1\u0026quot;\u0026gt;\n          `     ``* Set a separate OnPageChangeListener for internal use by the support library.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number241 index240 alt2\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number242 index241 alt1\u0026quot;\u0026gt;\n          `     ``* @param listener Listener to set`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number243 index242 alt2\u0026quot;\u0026gt;\n          `     ``* @return The old listener that was set, if any.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number244 index243 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number245 index244 alt2\u0026quot;\u0026gt;\n          `    ``OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number246 index245 alt1\u0026quot;\u0026gt;\n          `        ``OnPageChangeListener oldListener = mInternalPageChangeListener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number247 index246 alt2\u0026quot;\u0026gt;\n          `        ``mInternalPageChangeListener = listener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number248 index247 alt1\u0026quot;\u0026gt;\n          `        ``return oldListener;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number249 index248 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number250 index249 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number251 index250 alt2\u0026quot;\u0026gt;\n          `    ``public void addIgnoredView(View v) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number252 index251 alt1\u0026quot;\u0026gt;\n          `        ``if (!mIgnoredViews.contains(v)) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number253 index252 alt2\u0026quot;\u0026gt;\n          `            ``mIgnoredViews.add(v);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number254 index253 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number255 index254 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number256 index255 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number257 index256 alt2\u0026quot;\u0026gt;\n          `    ``public void removeIgnoredView(View v) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number258 index257 alt1\u0026quot;\u0026gt;\n          `        ``mIgnoredViews.remove(v);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number259 index258 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number260 index259 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number261 index260 alt2\u0026quot;\u0026gt;\n          `    ``public void clearIgnoredViews() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number262 index261 alt1\u0026quot;\u0026gt;\n          `        ``mIgnoredViews.clear();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number263 index262 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number264 index263 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number265 index264 alt2\u0026quot;\u0026gt;\n          `    ``// We want the duration of the page snap animation to be influenced by the distance that`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number266 index265 alt1\u0026quot;\u0026gt;\n          `    ``// the screen has to travel, however, we don't want this duration to be effected in a`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number267 index266 alt2\u0026quot;\u0026gt;\n          `    ``// purely linear fashion. Instead, we use this method to moderate the effect that the distance`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number268 index267 alt1\u0026quot;\u0026gt;\n          `    ``// of travel has on the overall snap duration.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number269 index268 alt2\u0026quot;\u0026gt;\n          `    ``float distanceInfluenceForSnapDuration(float f) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number270 index269 alt1\u0026quot;\u0026gt;\n          `        ``f -= 0.5f; // center the values about 0.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number271 index270 alt2\u0026quot;\u0026gt;\n          `        ``f *= 0.3f * Math.PI / 2.0f;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number272 index271 alt1\u0026quot;\u0026gt;\n          `        ``return (float) FloatMath.sin(f);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number273 index272 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number274 index273 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number275 index274 alt2\u0026quot;\u0026gt;\n          `    ``public int getDestScrollX(int page) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number276 index275 alt1\u0026quot;\u0026gt;\n          `        ``switch (page) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number277 index276 alt2\u0026quot;\u0026gt;\n          `        ``case 0:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number278 index277 alt1\u0026quot;\u0026gt;\n          `        ``case 2:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number279 index278 alt2\u0026quot;\u0026gt;\n          `            ``return mViewBehind.getMenuLeft(mContent, page);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number280 index279 alt1\u0026quot;\u0026gt;\n          `        ``case 1:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number281 index280 alt2\u0026quot;\u0026gt;\n          `            ``return mContent.getLeft();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number282 index281 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number283 index282 alt2\u0026quot;\u0026gt;\n          `        ``return 0;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number284 index283 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number285 index284 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number286 index285 alt1\u0026quot;\u0026gt;\n          `    ``private int getLeftBound() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number287 index286 alt2\u0026quot;\u0026gt;\n          `        ``return mViewBehind.getAbsLeftBound(mContent);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number288 index287 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number289 index288 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number290 index289 alt1\u0026quot;\u0026gt;\n          `    ``private int getRightBound() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number291 index290 alt2\u0026quot;\u0026gt;\n          `        ``return mViewBehind.getAbsRightBound(mContent);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number292 index291 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number293 index292 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number294 index293 alt1\u0026quot;\u0026gt;\n          `    ``public int getContentLeft() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number295 index294 alt2\u0026quot;\u0026gt;\n          `        ``return mContent.getLeft() + mContent.getPaddingLeft();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number296 index295 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number297 index296 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number298 index297 alt1\u0026quot;\u0026gt;\n          `    ``public boolean isMenuOpen() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number299 index298 alt2\u0026quot;\u0026gt;\n          `        ``return mCurItem == 0 || mCurItem == 2;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number300 index299 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number301 index300 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number302 index301 alt1\u0026quot;\u0026gt;\n          `    ``private boolean isInIgnoredView(MotionEvent ev) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number303 index302 alt2\u0026quot;\u0026gt;\n          `        ``Rect rect = new Rect();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number304 index303 alt1\u0026quot;\u0026gt;\n          `        ``for (View v : mIgnoredViews) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number305 index304 alt2\u0026quot;\u0026gt;\n          `            ``v.getHitRect(rect);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number306 index305 alt1\u0026quot;\u0026gt;\n          `            ``if (rect.contains((int)ev.getX(), (int)ev.getY())) return true;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number307 index306 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number308 index307 alt1\u0026quot;\u0026gt;\n          `        ``return false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number309 index308 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number310 index309 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number311 index310 alt2\u0026quot;\u0026gt;\n          `    ``public int getBehindWidth() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number312 index311 alt1\u0026quot;\u0026gt;\n          `        ``if (mViewBehind == null) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number313 index312 alt2\u0026quot;\u0026gt;\n          `            ``return 0;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number314 index313 alt1\u0026quot;\u0026gt;\n          `        ``} else {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number315 index314 alt2\u0026quot;\u0026gt;\n          `            ``return mViewBehind.getBehindWidth();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number316 index315 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number317 index316 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number318 index317 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number319 index318 alt2\u0026quot;\u0026gt;\n          `    ``public int getChildWidth(int i) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number320 index319 alt1\u0026quot;\u0026gt;\n          `        ``switch (i) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number321 index320 alt2\u0026quot;\u0026gt;\n          `        ``case 0:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number322 index321 alt1\u0026quot;\u0026gt;\n          `            ``return getBehindWidth();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number323 index322 alt2\u0026quot;\u0026gt;\n          `        ``case 1:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number324 index323 alt1\u0026quot;\u0026gt;\n          `            ``return mContent.getWidth();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number325 index324 alt2\u0026quot;\u0026gt;\n          `        ``default:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number326 index325 alt1\u0026quot;\u0026gt;\n          `            ``return 0;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number327 index326 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number328 index327 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number329 index328 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number330 index329 alt1\u0026quot;\u0026gt;\n          `    ``public boolean isSlidingEnabled() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number331 index330 alt2\u0026quot;\u0026gt;\n          `        ``return mEnabled;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number332 index331 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number333 index332 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number334 index333 alt1\u0026quot;\u0026gt;\n          `    ``public void setSlidingEnabled(boolean b) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number335 index334 alt2\u0026quot;\u0026gt;\n          `        ``mEnabled = b;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number336 index335 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number337 index336 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number338 index337 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number339 index338 alt2\u0026quot;\u0026gt;\n          `     ``* Like {@link View#scrollBy}, but scroll smoothly instead of immediately.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number340 index339 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number341 index340 alt2\u0026quot;\u0026gt;\n          `     ``* @param x the number of pixels to scroll by on the X axis`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number342 index341 alt1\u0026quot;\u0026gt;\n          `     ``* @param y the number of pixels to scroll by on the Y axis`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number343 index342 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number344 index343 alt1\u0026quot;\u0026gt;\n          `    ``void smoothScrollTo(int x, int y) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number345 index344 alt2\u0026quot;\u0026gt;\n          `        ``smoothScrollTo(x, y, 0);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number346 index345 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number347 index346 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number348 index347 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number349 index348 alt2\u0026quot;\u0026gt;\n          `     ``* Like {@link View#scrollBy}, but scroll smoothly instead of immediately.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number350 index349 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number351 index350 alt2\u0026quot;\u0026gt;\n          `     ``* @param x the number of pixels to scroll by on the X axis`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number352 index351 alt1\u0026quot;\u0026gt;\n          `     ``* @param y the number of pixels to scroll by on the Y axis`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number353 index352 alt2\u0026quot;\u0026gt;\n          `     ``* @param velocity the velocity associated with a fling, if applicable. (0 otherwise)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number354 index353 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number355 index354 alt2\u0026quot;\u0026gt;\n          `    ``void smoothScrollTo(int x, int y, int velocity) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number356 index355 alt1\u0026quot;\u0026gt;\n          `        ``if (getChildCount() == 0) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number357 index356 alt2\u0026quot;\u0026gt;\n          `            ``// Nothing to do.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number358 index357 alt1\u0026quot;\u0026gt;\n          `            ``setScrollingCacheEnabled(false);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number359 index358 alt2\u0026quot;\u0026gt;\n          `            ``return;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number360 index359 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number361 index360 alt2\u0026quot;\u0026gt;\n          `        ``int sx = getScrollX();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number362 index361 alt1\u0026quot;\u0026gt;\n          `        ``int sy = getScrollY();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number363 index362 alt2\u0026quot;\u0026gt;\n          `        ``int dx = x - sx;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number364 index363 alt1\u0026quot;\u0026gt;\n          `        ``int dy = y - sy;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number365 index364 alt2\u0026quot;\u0026gt;\n          `        ``if (dx == 0 \u0026amp;\u0026amp; dy == 0) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number366 index365 alt1\u0026quot;\u0026gt;\n          `            ``completeScroll();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number367 index366 alt2\u0026quot;\u0026gt;\n          `            ``if (isMenuOpen()) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number368 index367 alt1\u0026quot;\u0026gt;\n          `                ``if (mOpenedListener != null)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number369 index368 alt2\u0026quot;\u0026gt;\n          `                    ``mOpenedListener.onOpened();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number370 index369 alt1\u0026quot;\u0026gt;\n          `            ``} else {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number371 index370 alt2\u0026quot;\u0026gt;\n          `                ``if (mClosedListener != null)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number372 index371 alt1\u0026quot;\u0026gt;\n          `                    ``mClosedListener.onClosed();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number373 index372 alt2\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number374 index373 alt1\u0026quot;\u0026gt;\n          `            ``return;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number375 index374 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number376 index375 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number377 index376 alt2\u0026quot;\u0026gt;\n          `        ``setScrollingCacheEnabled(true);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number378 index377 alt1\u0026quot;\u0026gt;\n          `        ``mScrolling = true;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number379 index378 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number380 index379 alt1\u0026quot;\u0026gt;\n          `        ``final int width = getBehindWidth();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number381 index380 alt2\u0026quot;\u0026gt;\n          `        ``final int halfWidth = width / 2;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number382 index381 alt1\u0026quot;\u0026gt;\n          `        ``final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number383 index382 alt2\u0026quot;\u0026gt;\n          `        ``final float distance = halfWidth + halfWidth *`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number384 index383 alt1\u0026quot;\u0026gt;\n          `                ``distanceInfluenceForSnapDuration(distanceRatio);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number385 index384 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number386 index385 alt1\u0026quot;\u0026gt;\n          `        ``int duration = 0;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number387 index386 alt2\u0026quot;\u0026gt;\n          `        ``velocity = Math.abs(velocity);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number388 index387 alt1\u0026quot;\u0026gt;\n          `        ``if (velocity \u0026amp;gt; 0) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number389 index388 alt2\u0026quot;\u0026gt;\n          `            ``duration = 4 * Math.round(1000 * Math.abs(distance / velocity));`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number390 index389 alt1\u0026quot;\u0026gt;\n          `        ``} else {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number391 index390 alt2\u0026quot;\u0026gt;\n          `            ``final float pageDelta = (float) Math.abs(dx) / width;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number392 index391 alt1\u0026quot;\u0026gt;\n          `            ``duration = (int) ((pageDelta + 1) * 100);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number393 index392 alt2\u0026quot;\u0026gt;\n          `            ``duration = MAX_SETTLE_DURATION;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number394 index393 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number395 index394 alt2\u0026quot;\u0026gt;\n          `        ``duration = Math.min(duration, MAX_SETTLE_DURATION);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number396 index395 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number397 index396 alt2\u0026quot;\u0026gt;\n          `        ``mScroller.startScroll(sx, sy, dx, dy, duration);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number398 index397 alt1\u0026quot;\u0026gt;\n          `        ``invalidate();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number399 index398 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number400 index399 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number401 index400 alt2\u0026quot;\u0026gt;\n          `    ``public void setContent(View v) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number402 index401 alt1\u0026quot;\u0026gt;\n          `        ``if (mContent != null)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number403 index402 alt2\u0026quot;\u0026gt;\n          `            ``this.removeView(mContent);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number404 index403 alt1\u0026quot;\u0026gt;\n          `        ``mContent = v;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number405 index404 alt2\u0026quot;\u0026gt;\n          `        ``addView(mContent);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number406 index405 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number407 index406 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number408 index407 alt1\u0026quot;\u0026gt;\n          `    ``public View getContent() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number409 index408 alt2\u0026quot;\u0026gt;\n          `        ``return mContent;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number410 index409 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number411 index410 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number412 index411 alt1\u0026quot;\u0026gt;\n          `    ``public void setCustomViewBehind(CustomViewBehind cvb) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number413 index412 alt2\u0026quot;\u0026gt;\n          `        ``mViewBehind = cvb;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number414 index413 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number415 index414 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number416 index415 alt1\u0026quot;\u0026gt;\n          `    ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number417 index416 alt2\u0026quot;\u0026gt;\n          `    ``protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number418 index417 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number419 index418 alt2\u0026quot;\u0026gt;\n          `        ``int width = getDefaultSize(0, widthMeasureSpec);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number420 index419 alt1\u0026quot;\u0026gt;\n          `        ``int height = getDefaultSize(0, heightMeasureSpec);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number421 index420 alt2\u0026quot;\u0026gt;\n          `        ``setMeasuredDimension(width, height);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number422 index421 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number423 index422 alt2\u0026quot;\u0026gt;\n          `        ``final int contentWidth = getChildMeasureSpec(widthMeasureSpec, 0, width);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number424 index423 alt1\u0026quot;\u0026gt;\n          `        ``final int contentHeight = getChildMeasureSpec(heightMeasureSpec, 0, height);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number425 index424 alt2\u0026quot;\u0026gt;\n          `        ``mContent.measure(contentWidth, contentHeight);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number426 index425 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number427 index426 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number428 index427 alt1\u0026quot;\u0026gt;\n          `    ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number429 index428 alt2\u0026quot;\u0026gt;\n          `    ``protected void onSizeChanged(int w, int h, int oldw, int oldh) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number430 index429 alt1\u0026quot;\u0026gt;\n          `        ``super.onSizeChanged(w, h, oldw, oldh);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number431 index430 alt2\u0026quot;\u0026gt;\n          `        ``// Make sure scroll position is set correctly.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number432 index431 alt1\u0026quot;\u0026gt;\n          `        ``if (w != oldw) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number433 index432 alt2\u0026quot;\u0026gt;\n          `            ``// [ChrisJ] - This fixes the onConfiguration change for orientation issue..`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number434 index433 alt1\u0026quot;\u0026gt;\n          `            ``// maybe worth having a look why the recomputeScroll pos is screwing`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number435 index434 alt2\u0026quot;\u0026gt;\n          `            ``// up?`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number436 index435 alt1\u0026quot;\u0026gt;\n          `            ``completeScroll();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number437 index436 alt2\u0026quot;\u0026gt;\n          `            ``scrollTo(getDestScrollX(mCurItem), getScrollY());`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number438 index437 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number439 index438 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number440 index439 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number441 index440 alt2\u0026quot;\u0026gt;\n          `    ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number442 index441 alt1\u0026quot;\u0026gt;\n          `    ``protected void onLayout(boolean changed, int l, int t, int r, int b) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number443 index442 alt2\u0026quot;\u0026gt;\n          `        ``final int width = r - l;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number444 index443 alt1\u0026quot;\u0026gt;\n          `        ``final int height = b - t;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number445 index444 alt2\u0026quot;\u0026gt;\n          `        ``mContent.layout(0, 0, width, height);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number446 index445 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number447 index446 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number448 index447 alt1\u0026quot;\u0026gt;\n          `    ``public void setAboveOffset(int i) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number449 index448 alt2\u0026quot;\u0026gt;\n          `        ``//      RelativeLayout.LayoutParams params = ((RelativeLayout.LayoutParams)mContent.getLayoutParams());`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number450 index449 alt1\u0026quot;\u0026gt;\n          `        ``//      params.setMargins(i, params.topMargin, params.rightMargin, params.bottomMargin);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number451 index450 alt2\u0026quot;\u0026gt;\n          `        ``mContent.setPadding(i, mContent.getPaddingTop(),`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number452 index451 alt1\u0026quot;\u0026gt;\n          `                ``mContent.getPaddingRight(), mContent.getPaddingBottom());`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number453 index452 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number454 index453 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number455 index454 alt2\u0026quot;\u0026gt;\n          `    ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number456 index455 alt1\u0026quot;\u0026gt;\n          `    ``public void computeScroll() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number457 index456 alt2\u0026quot;\u0026gt;\n          `        ``if (!mScroller.isFinished()) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number458 index457 alt1\u0026quot;\u0026gt;\n          `            ``if (mScroller.computeScrollOffset()) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number459 index458 alt2\u0026quot;\u0026gt;\n          `                ``int oldX = getScrollX();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number460 index459 alt1\u0026quot;\u0026gt;\n          `                ``int oldY = getScrollY();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number461 index460 alt2\u0026quot;\u0026gt;\n          `                ``int x = mScroller.getCurrX();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number462 index461 alt1\u0026quot;\u0026gt;\n          `                ``int y = mScroller.getCurrY();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number463 index462 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number464 index463 alt1\u0026quot;\u0026gt;\n          `                ``if (oldX != x || oldY != y) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number465 index464 alt2\u0026quot;\u0026gt;\n          `                    ``scrollTo(x, y);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number466 index465 alt1\u0026quot;\u0026gt;\n          `                    ``pageScrolled(x);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number467 index466 alt2\u0026quot;\u0026gt;\n          `                ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number468 index467 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number469 index468 alt2\u0026quot;\u0026gt;\n          `                ``// Keep on drawing until the animation has finished.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number470 index469 alt1\u0026quot;\u0026gt;\n          `                ``invalidate();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number471 index470 alt2\u0026quot;\u0026gt;\n          `                ``return;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number472 index471 alt1\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number473 index472 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number474 index473 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number475 index474 alt2\u0026quot;\u0026gt;\n          `        ``// Done with scroll, clean up state.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number476 index475 alt1\u0026quot;\u0026gt;\n          `        ``completeScroll();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number477 index476 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number478 index477 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number479 index478 alt2\u0026quot;\u0026gt;\n          `    ``private void pageScrolled(int xpos) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number480 index479 alt1\u0026quot;\u0026gt;\n          `        ``final int widthWithMargin = getWidth();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number481 index480 alt2\u0026quot;\u0026gt;\n          `        ``final int position = xpos / widthWithMargin;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number482 index481 alt1\u0026quot;\u0026gt;\n          `        ``final int offsetPixels = xpos % widthWithMargin;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number483 index482 alt2\u0026quot;\u0026gt;\n          `        ``final float offset = (float) offsetPixels / widthWithMargin;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number484 index483 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number485 index484 alt2\u0026quot;\u0026gt;\n          `        ``onPageScrolled(position, offset, offsetPixels);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number486 index485 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number487 index486 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number488 index487 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number489 index488 alt2\u0026quot;\u0026gt;\n          `     ``* This method will be invoked when the current page is scrolled, either as part`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number490 index489 alt1\u0026quot;\u0026gt;\n          `     ``* of a programmatically initiated smooth scroll or a user initiated touch scroll.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number491 index490 alt2\u0026quot;\u0026gt;\n          `     ``* If you override this method you must call through to the superclass implementation`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number492 index491 alt1\u0026quot;\u0026gt;\n          `     ``* (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number493 index492 alt2\u0026quot;\u0026gt;\n          `     ``* returns.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number494 index493 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number495 index494 alt2\u0026quot;\u0026gt;\n          `     ``* @param position Position index of the first page currently being displayed.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number496 index495 alt1\u0026quot;\u0026gt;\n          `     ``*                 Page position+1 will be visible if positionOffset is nonzero.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number497 index496 alt2\u0026quot;\u0026gt;\n          `     ``* @param offset Value from [0, 1) indicating the offset from the page at position.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number498 index497 alt1\u0026quot;\u0026gt;\n          `     ``* @param offsetPixels Value in pixels indicating the offset from position.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number499 index498 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number500 index499 alt1\u0026quot;\u0026gt;\n          `    ``protected void onPageScrolled(int position, float offset, int offsetPixels) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number501 index500 alt2\u0026quot;\u0026gt;\n          `        ``if (mOnPageChangeListener != null) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number502 index501 alt1\u0026quot;\u0026gt;\n          `            ``mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number503 index502 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number504 index503 alt1\u0026quot;\u0026gt;\n          `        ``if (mInternalPageChangeListener != null) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number505 index504 alt2\u0026quot;\u0026gt;\n          `            ``mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number506 index505 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number507 index506 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number508 index507 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number509 index508 alt2\u0026quot;\u0026gt;\n          `    ``private void completeScroll() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number510 index509 alt1\u0026quot;\u0026gt;\n          `        ``boolean needPopulate = mScrolling;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number511 index510 alt2\u0026quot;\u0026gt;\n          `        ``if (needPopulate) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number512 index511 alt1\u0026quot;\u0026gt;\n          `            ``// Done with scroll, no longer want to cache view drawing.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number513 index512 alt2\u0026quot;\u0026gt;\n          `            ``setScrollingCacheEnabled(false);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number514 index513 alt1\u0026quot;\u0026gt;\n          `            ``mScroller.abortAnimation();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number515 index514 alt2\u0026quot;\u0026gt;\n          `            ``int oldX = getScrollX();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number516 index515 alt1\u0026quot;\u0026gt;\n          `            ``int oldY = getScrollY();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number517 index516 alt2\u0026quot;\u0026gt;\n          `            ``int x = mScroller.getCurrX();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number518 index517 alt1\u0026quot;\u0026gt;\n          `            ``int y = mScroller.getCurrY();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number519 index518 alt2\u0026quot;\u0026gt;\n          `            ``if (oldX != x || oldY != y) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number520 index519 alt1\u0026quot;\u0026gt;\n          `                ``scrollTo(x, y);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number521 index520 alt2\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number522 index521 alt1\u0026quot;\u0026gt;\n          `            ``if (isMenuOpen()) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number523 index522 alt2\u0026quot;\u0026gt;\n          `                ``if (mOpenedListener != null)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number524 index523 alt1\u0026quot;\u0026gt;\n          `                    ``mOpenedListener.onOpened();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number525 index524 alt2\u0026quot;\u0026gt;\n          `            ``} else {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number526 index525 alt1\u0026quot;\u0026gt;\n          `                ``if (mClosedListener != null)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number527 index526 alt2\u0026quot;\u0026gt;\n          `                    ``mClosedListener.onClosed();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number528 index527 alt1\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number529 index528 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number530 index529 alt1\u0026quot;\u0026gt;\n          `        ``mScrolling = false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number531 index530 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number532 index531 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number533 index532 alt2\u0026quot;\u0026gt;\n          `    ``protected int mTouchMode = SlidingMenu.TOUCHMODE_MARGIN;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number534 index533 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number535 index534 alt2\u0026quot;\u0026gt;\n          `    ``public void setTouchMode(int i) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number536 index535 alt1\u0026quot;\u0026gt;\n          `        ``mTouchMode = i;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number537 index536 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number538 index537 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number539 index538 alt2\u0026quot;\u0026gt;\n          `    ``public int getTouchMode() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number540 index539 alt1\u0026quot;\u0026gt;\n          `        ``return mTouchMode;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number541 index540 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number542 index541 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number543 index542 alt2\u0026quot;\u0026gt;\n          `    ``private boolean thisTouchAllowed(MotionEvent ev) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number544 index543 alt1\u0026quot;\u0026gt;\n          `        ``int x = (int) (ev.getX() + mScrollX);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number545 index544 alt2\u0026quot;\u0026gt;\n          `        ``if (isMenuOpen()) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number546 index545 alt1\u0026quot;\u0026gt;\n          `            ``return mViewBehind.menuOpenTouchAllowed(mContent, mCurItem, x);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number547 index546 alt2\u0026quot;\u0026gt;\n          `        ``} else {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number548 index547 alt1\u0026quot;\u0026gt;\n          `            ``switch (mTouchMode) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number549 index548 alt2\u0026quot;\u0026gt;\n          `            ``case SlidingMenu.TOUCHMODE_FULLSCREEN:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number550 index549 alt1\u0026quot;\u0026gt;\n          `                ``return !isInIgnoredView(ev);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number551 index550 alt2\u0026quot;\u0026gt;\n          `            ``case SlidingMenu.TOUCHMODE_NONE:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number552 index551 alt1\u0026quot;\u0026gt;\n          `                ``return false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number553 index552 alt2\u0026quot;\u0026gt;\n          `            ``case SlidingMenu.TOUCHMODE_MARGIN:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number554 index553 alt1\u0026quot;\u0026gt;\n          `                ``return mViewBehind.marginTouchAllowed(mContent, x);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number555 index554 alt2\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number556 index555 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number557 index556 alt2\u0026quot;\u0026gt;\n          `        ``return false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number558 index557 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number559 index558 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number560 index559 alt1\u0026quot;\u0026gt;\n          `    ``private boolean thisSlideAllowed(float dx) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number561 index560 alt2\u0026quot;\u0026gt;\n          `        ``boolean allowed = false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number562 index561 alt1\u0026quot;\u0026gt;\n          `        ``if (isMenuOpen()) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number563 index562 alt2\u0026quot;\u0026gt;\n          `            ``allowed = mViewBehind.menuOpenSlideAllowed(dx);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number564 index563 alt1\u0026quot;\u0026gt;\n          `        ``} else {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number565 index564 alt2\u0026quot;\u0026gt;\n          `            ``allowed = mViewBehind.menuClosedSlideAllowed(dx);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number566 index565 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number567 index566 alt2\u0026quot;\u0026gt;\n          `        ``if (DEBUG)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number568 index567 alt1\u0026quot;\u0026gt;\n          `            ``Log.v(TAG, \u0026quot;this slide allowed \u0026quot; + allowed + \u0026quot; dx: \u0026quot; + dx);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number569 index568 alt2\u0026quot;\u0026gt;\n          `        ``return allowed;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number570 index569 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number571 index570 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number572 index571 alt1\u0026quot;\u0026gt;\n          `    ``private int getPointerIndex(MotionEvent ev, int id) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number573 index572 alt2\u0026quot;\u0026gt;\n          `        ``int activePointerIndex = MotionEventCompat.findPointerIndex(ev, id);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number574 index573 alt1\u0026quot;\u0026gt;\n          `        ``if (activePointerIndex == -1)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number575 index574 alt2\u0026quot;\u0026gt;\n          `            ``mActivePointerId = INVALID_POINTER;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number576 index575 alt1\u0026quot;\u0026gt;\n          `        ``return activePointerIndex;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number577 index576 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number578 index577 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number579 index578 alt2\u0026quot;\u0026gt;\n          `    ``private boolean mQuickReturn = false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number580 index579 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number581 index580 alt2\u0026quot;\u0026gt;\n          `    ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number582 index581 alt1\u0026quot;\u0026gt;\n          `    ``public boolean onInterceptTouchEvent(MotionEvent ev) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number583 index582 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number584 index583 alt1\u0026quot;\u0026gt;\n          `        ``if (!mEnabled)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number585 index584 alt2\u0026quot;\u0026gt;\n          `            ``return false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number586 index585 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number587 index586 alt2\u0026quot;\u0026gt;\n          `        ``final int action = ev.getAction() \u0026amp; MotionEventCompat.ACTION_MASK;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number588 index587 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number589 index588 alt2\u0026quot;\u0026gt;\n          `        ``if (DEBUG)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number590 index589 alt1\u0026quot;\u0026gt;\n          `            ``if (action == MotionEvent.ACTION_DOWN)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number591 index590 alt2\u0026quot;\u0026gt;\n          `                ``Log.v(TAG, \u0026quot;Received ACTION_DOWN\u0026quot;);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number592 index591 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number593 index592 alt2\u0026quot;\u0026gt;\n          `        ``if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number594 index593 alt1\u0026quot;\u0026gt;\n          `                ``|| (action != MotionEvent.ACTION_DOWN \u0026amp;\u0026amp; mIsUnableToDrag)) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number595 index594 alt2\u0026quot;\u0026gt;\n          `            ``endDrag();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number596 index595 alt1\u0026quot;\u0026gt;\n          `            ``return false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number597 index596 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number598 index597 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number599 index598 alt2\u0026quot;\u0026gt;\n          `        ``switch (action) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number600 index599 alt1\u0026quot;\u0026gt;\n          `        ``case MotionEvent.ACTION_MOVE:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number601 index600 alt2\u0026quot;\u0026gt;\n          `            ``determineDrag(ev);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number602 index601 alt1\u0026quot;\u0026gt;\n          `            ``break;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number603 index602 alt2\u0026quot;\u0026gt;\n          `        ``case MotionEvent.ACTION_DOWN:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number604 index603 alt1\u0026quot;\u0026gt;\n          `            ``int index = MotionEventCompat.getActionIndex(ev);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number605 index604 alt2\u0026quot;\u0026gt;\n          `            ``mActivePointerId = MotionEventCompat.getPointerId(ev, index);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number606 index605 alt1\u0026quot;\u0026gt;\n          `            ``if (mActivePointerId == INVALID_POINTER)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number607 index606 alt2\u0026quot;\u0026gt;\n          `                ``break;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number608 index607 alt1\u0026quot;\u0026gt;\n          `            ``mLastMotionX = mInitialMotionX = MotionEventCompat.getX(ev, index);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number609 index608 alt2\u0026quot;\u0026gt;\n          `            ``mLastMotionY = MotionEventCompat.getY(ev, index);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number610 index609 alt1\u0026quot;\u0026gt;\n          `            ``if (thisTouchAllowed(ev)) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number611 index610 alt2\u0026quot;\u0026gt;\n          `                ``mIsBeingDragged = false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number612 index611 alt1\u0026quot;\u0026gt;\n          `                ``mIsUnableToDrag = false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number613 index612 alt2\u0026quot;\u0026gt;\n          `                ``if (isMenuOpen() \u0026amp;\u0026amp; mViewBehind.menuTouchInQuickReturn(mContent, mCurItem, ev.getX() + mScrollX)) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number614 index613 alt1\u0026quot;\u0026gt;\n          `                    ``mQuickReturn = true;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number615 index614 alt2\u0026quot;\u0026gt;\n          `                ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number616 index615 alt1\u0026quot;\u0026gt;\n          `            ``} else {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number617 index616 alt2\u0026quot;\u0026gt;\n          `                ``mIsUnableToDrag = true;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number618 index617 alt1\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number619 index618 alt2\u0026quot;\u0026gt;\n          `            ``break;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number620 index619 alt1\u0026quot;\u0026gt;\n          `        ``case MotionEventCompat.ACTION_POINTER_UP:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number621 index620 alt2\u0026quot;\u0026gt;\n          `            ``onSecondaryPointerUp(ev);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number622 index621 alt1\u0026quot;\u0026gt;\n          `            ``break;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number623 index622 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number624 index623 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number625 index624 alt2\u0026quot;\u0026gt;\n          `        ``if (!mIsBeingDragged) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number626 index625 alt1\u0026quot;\u0026gt;\n          `            ``if (mVelocityTracker == null) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number627 index626 alt2\u0026quot;\u0026gt;\n          `                ``mVelocityTracker = VelocityTracker.obtain();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number628 index627 alt1\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number629 index628 alt2\u0026quot;\u0026gt;\n          `            ``mVelocityTracker.addMovement(ev);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number630 index629 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number631 index630 alt2\u0026quot;\u0026gt;\n          `        ``return mIsBeingDragged || mQuickReturn;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number632 index631 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number633 index632 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number634 index633 alt1\u0026quot;\u0026gt;\n          `    ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number635 index634 alt2\u0026quot;\u0026gt;\n          `    ``public boolean onTouchEvent(MotionEvent ev) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number636 index635 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number637 index636 alt2\u0026quot;\u0026gt;\n          `        ``if (!mEnabled)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number638 index637 alt1\u0026quot;\u0026gt;\n          `            ``return false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number639 index638 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number640 index639 alt1\u0026quot;\u0026gt;\n          `        ``if (!mIsBeingDragged \u0026amp;\u0026amp; !thisTouchAllowed(ev))`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number641 index640 alt2\u0026quot;\u0026gt;\n          `            ``return false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number642 index641 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number643 index642 alt2\u0026quot;\u0026gt;\n          `        ``//      if (!mIsBeingDragged \u0026amp;\u0026amp; !mQuickReturn)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number644 index643 alt1\u0026quot;\u0026gt;\n          `        ``//          return false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number645 index644 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number646 index645 alt1\u0026quot;\u0026gt;\n          `        ``final int action = ev.getAction();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number647 index646 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number648 index647 alt1\u0026quot;\u0026gt;\n          `        ``if (mVelocityTracker == null) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number649 index648 alt2\u0026quot;\u0026gt;\n          `            ``mVelocityTracker = VelocityTracker.obtain();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number650 index649 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number651 index650 alt2\u0026quot;\u0026gt;\n          `        ``mVelocityTracker.addMovement(ev);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number652 index651 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number653 index652 alt2\u0026quot;\u0026gt;\n          `        ``switch (action \u0026amp; MotionEventCompat.ACTION_MASK) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number654 index653 alt1\u0026quot;\u0026gt;\n          `        ``case MotionEvent.ACTION_DOWN:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number655 index654 alt2\u0026quot;\u0026gt;\n          `            ``/*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number656 index655 alt1\u0026quot;\u0026gt;\n          `             ``* If being flinged and user touches, stop the fling. isFinished`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number657 index656 alt2\u0026quot;\u0026gt;\n          `             ``* will be false if being flinged.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number658 index657 alt1\u0026quot;\u0026gt;\n          `             ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number659 index658 alt2\u0026quot;\u0026gt;\n          `            ``completeScroll();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number660 index659 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number661 index660 alt2\u0026quot;\u0026gt;\n          `            ``// Remember where the motion event started`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number662 index661 alt1\u0026quot;\u0026gt;\n          `            ``int index = MotionEventCompat.getActionIndex(ev);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number663 index662 alt2\u0026quot;\u0026gt;\n          `            ``mActivePointerId = MotionEventCompat.getPointerId(ev, index);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number664 index663 alt1\u0026quot;\u0026gt;\n          `            ``mLastMotionX = mInitialMotionX = ev.getX();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number665 index664 alt2\u0026quot;\u0026gt;\n          `            ``break;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number666 index665 alt1\u0026quot;\u0026gt;\n          `        ``case MotionEvent.ACTION_MOVE:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number667 index666 alt2\u0026quot;\u0026gt;\n          `            ``if (!mIsBeingDragged) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number668 index667 alt1\u0026quot;\u0026gt;\n          `                ``determineDrag(ev);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number669 index668 alt2\u0026quot;\u0026gt;\n          `                ``if (mIsUnableToDrag)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number670 index669 alt1\u0026quot;\u0026gt;\n          `                    ``return false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number671 index670 alt2\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number672 index671 alt1\u0026quot;\u0026gt;\n          `            ``if (mIsBeingDragged) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number673 index672 alt2\u0026quot;\u0026gt;\n          `                ``// Scroll to follow the motion event`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number674 index673 alt1\u0026quot;\u0026gt;\n          `                ``final int activePointerIndex = getPointerIndex(ev, mActivePointerId);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number675 index674 alt2\u0026quot;\u0026gt;\n          `                ``if (mActivePointerId == INVALID_POINTER)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number676 index675 alt1\u0026quot;\u0026gt;\n          `                    ``break;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number677 index676 alt2\u0026quot;\u0026gt;\n          `                ``final float x = MotionEventCompat.getX(ev, activePointerIndex);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number678 index677 alt1\u0026quot;\u0026gt;\n          `                ``final float deltaX = mLastMotionX - x;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number679 index678 alt2\u0026quot;\u0026gt;\n          `                ``mLastMotionX = x;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number680 index679 alt1\u0026quot;\u0026gt;\n          `                ``float oldScrollX = getScrollX();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number681 index680 alt2\u0026quot;\u0026gt;\n          `                ``float scrollX = oldScrollX + deltaX;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number682 index681 alt1\u0026quot;\u0026gt;\n          `                ``final float leftBound = getLeftBound();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number683 index682 alt2\u0026quot;\u0026gt;\n          `                ``final float rightBound = getRightBound();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number684 index683 alt1\u0026quot;\u0026gt;\n          `                ``if (scrollX \u0026amp;lt; leftBound) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number685 index684 alt2\u0026quot;\u0026gt;\n          `                    ``scrollX = leftBound;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number686 index685 alt1\u0026quot;\u0026gt;\n          `                ``} else if (scrollX \u0026amp;gt; rightBound) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number687 index686 alt2\u0026quot;\u0026gt;\n          `                    ``scrollX = rightBound;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number688 index687 alt1\u0026quot;\u0026gt;\n          `                ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number689 index688 alt2\u0026quot;\u0026gt;\n          `                ``// Don't lose the rounded component`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number690 index689 alt1\u0026quot;\u0026gt;\n          `                ``mLastMotionX += scrollX - (int) scrollX;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number691 index690 alt2\u0026quot;\u0026gt;\n          `                ``scrollTo((int) scrollX, getScrollY());`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number692 index691 alt1\u0026quot;\u0026gt;\n          `                ``pageScrolled((int) scrollX);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number693 index692 alt2\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number694 index693 alt1\u0026quot;\u0026gt;\n          `            ``break;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number695 index694 alt2\u0026quot;\u0026gt;\n          `        ``case MotionEvent.ACTION_UP:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number696 index695 alt1\u0026quot;\u0026gt;\n          `            ``if (mIsBeingDragged) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number697 index696 alt2\u0026quot;\u0026gt;\n          `                ``final VelocityTracker velocityTracker = mVelocityTracker;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number698 index697 alt1\u0026quot;\u0026gt;\n          `                ``velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number699 index698 alt2\u0026quot;\u0026gt;\n          `                ``int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number700 index699 alt1\u0026quot;\u0026gt;\n          `                        ``velocityTracker, mActivePointerId);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number701 index700 alt2\u0026quot;\u0026gt;\n          `                ``final int scrollX = getScrollX();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number702 index701 alt1\u0026quot;\u0026gt;\n          `                ``final float pageOffset = (float) (scrollX - getDestScrollX(mCurItem)) / getBehindWidth();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number703 index702 alt2\u0026quot;\u0026gt;\n          `                ``final int activePointerIndex = getPointerIndex(ev, mActivePointerId);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number704 index703 alt1\u0026quot;\u0026gt;\n          `                ``if (mActivePointerId != INVALID_POINTER) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number705 index704 alt2\u0026quot;\u0026gt;\n          `                    ``final float x = MotionEventCompat.getX(ev, activePointerIndex);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number706 index705 alt1\u0026quot;\u0026gt;\n          `                    ``final int totalDelta = (int) (x - mInitialMotionX);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number707 index706 alt2\u0026quot;\u0026gt;\n          `                    ``int nextPage = determineTargetPage(pageOffset, initialVelocity, totalDelta);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number708 index707 alt1\u0026quot;\u0026gt;\n          `                    ``setCurrentItemInternal(nextPage, true, true, initialVelocity);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number709 index708 alt2\u0026quot;\u0026gt;\n          `                ``} else {   `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number710 index709 alt1\u0026quot;\u0026gt;\n          `                    ``setCurrentItemInternal(mCurItem, true, true, initialVelocity);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number711 index710 alt2\u0026quot;\u0026gt;\n          `                ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number712 index711 alt1\u0026quot;\u0026gt;\n          `                ``mActivePointerId = INVALID_POINTER;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number713 index712 alt2\u0026quot;\u0026gt;\n          `                ``endDrag();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number714 index713 alt1\u0026quot;\u0026gt;\n          `            ``} else if (mQuickReturn \u0026amp;\u0026amp; mViewBehind.menuTouchInQuickReturn(mContent, mCurItem, ev.getX() + mScrollX)) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number715 index714 alt2\u0026quot;\u0026gt;\n          `                ``// close the menu`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number716 index715 alt1\u0026quot;\u0026gt;\n          `                ``setCurrentItem(1);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number717 index716 alt2\u0026quot;\u0026gt;\n          `                ``endDrag();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number718 index717 alt1\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number719 index718 alt2\u0026quot;\u0026gt;\n          `            ``break;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number720 index719 alt1\u0026quot;\u0026gt;\n          `        ``case MotionEvent.ACTION_CANCEL:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number721 index720 alt2\u0026quot;\u0026gt;\n          `            ``if (mIsBeingDragged) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number722 index721 alt1\u0026quot;\u0026gt;\n          `                ``setCurrentItemInternal(mCurItem, true, true);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number723 index722 alt2\u0026quot;\u0026gt;\n          `                ``mActivePointerId = INVALID_POINTER;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number724 index723 alt1\u0026quot;\u0026gt;\n          `                ``endDrag();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number725 index724 alt2\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number726 index725 alt1\u0026quot;\u0026gt;\n          `            ``break;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number727 index726 alt2\u0026quot;\u0026gt;\n          `        ``case MotionEventCompat.ACTION_POINTER_DOWN: {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number728 index727 alt1\u0026quot;\u0026gt;\n          `            ``final int indexx = MotionEventCompat.getActionIndex(ev);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number729 index728 alt2\u0026quot;\u0026gt;\n          `            ``mLastMotionX = MotionEventCompat.getX(ev, indexx);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number730 index729 alt1\u0026quot;\u0026gt;\n          `            ``mActivePointerId = MotionEventCompat.getPointerId(ev, indexx);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number731 index730 alt2\u0026quot;\u0026gt;\n          `            ``break;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number732 index731 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number733 index732 alt2\u0026quot;\u0026gt;\n          `        ``case MotionEventCompat.ACTION_POINTER_UP:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number734 index733 alt1\u0026quot;\u0026gt;\n          `            ``onSecondaryPointerUp(ev);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number735 index734 alt2\u0026quot;\u0026gt;\n          `            ``int pointerIndex = getPointerIndex(ev, mActivePointerId);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number736 index735 alt1\u0026quot;\u0026gt;\n          `            ``if (mActivePointerId == INVALID_POINTER)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number737 index736 alt2\u0026quot;\u0026gt;\n          `                ``break;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number738 index737 alt1\u0026quot;\u0026gt;\n          `            ``mLastMotionX = MotionEventCompat.getX(ev, pointerIndex);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number739 index738 alt2\u0026quot;\u0026gt;\n          `            ``break;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number740 index739 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number741 index740 alt2\u0026quot;\u0026gt;\n          `        ``return true;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number742 index741 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number743 index742 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number744 index743 alt1\u0026quot;\u0026gt;\n          `    ``private void determineDrag(MotionEvent ev) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number745 index744 alt2\u0026quot;\u0026gt;\n          `        ``final int activePointerId = mActivePointerId;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number746 index745 alt1\u0026quot;\u0026gt;\n          `        ``final int pointerIndex = getPointerIndex(ev, activePointerId);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number747 index746 alt2\u0026quot;\u0026gt;\n          `        ``if (activePointerId == INVALID_POINTER || pointerIndex == INVALID_POINTER)`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number748 index747 alt1\u0026quot;\u0026gt;\n          `            ``return;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number749 index748 alt2\u0026quot;\u0026gt;\n          `        ``final float x = MotionEventCompat.getX(ev, pointerIndex);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number750 index749 alt1\u0026quot;\u0026gt;\n          `        ``final float dx = x - mLastMotionX;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number751 index750 alt2\u0026quot;\u0026gt;\n          `        ``final float xDiff = Math.abs(dx);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number752 index751 alt1\u0026quot;\u0026gt;\n          `        ``final float y = MotionEventCompat.getY(ev, pointerIndex);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number753 index752 alt2\u0026quot;\u0026gt;\n          `        ``final float dy = y - mLastMotionY;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number754 index753 alt1\u0026quot;\u0026gt;\n          `        ``final float yDiff = Math.abs(dy);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number755 index754 alt2\u0026quot;\u0026gt;\n          `        ``if (xDiff \u0026amp;gt; (isMenuOpen()?mTouchSlop/2:mTouchSlop) \u0026amp;\u0026amp; xDiff \u0026amp;gt; yDiff \u0026amp;\u0026amp; thisSlideAllowed(dx)) {       `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number756 index755 alt1\u0026quot;\u0026gt;\n          `            ``startDrag();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number757 index756 alt2\u0026quot;\u0026gt;\n          `            ``mLastMotionX = x;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number758 index757 alt1\u0026quot;\u0026gt;\n          `            ``mLastMotionY = y;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number759 index758 alt2\u0026quot;\u0026gt;\n          `            ``setScrollingCacheEnabled(true);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number760 index759 alt1\u0026quot;\u0026gt;\n          `            ``// TODO add back in touch slop check`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number761 index760 alt2\u0026quot;\u0026gt;\n          `        ``} else if (xDiff \u0026amp;gt; mTouchSlop) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number762 index761 alt1\u0026quot;\u0026gt;\n          `            ``mIsUnableToDrag = true;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number763 index762 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number764 index763 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number765 index764 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number766 index765 alt1\u0026quot;\u0026gt;\n          `    ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number767 index766 alt2\u0026quot;\u0026gt;\n          `    ``public void scrollTo(int x, int y) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number768 index767 alt1\u0026quot;\u0026gt;\n          `        ``super.scrollTo(x, y);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number769 index768 alt2\u0026quot;\u0026gt;\n          `        ``mScrollX = x;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number770 index769 alt1\u0026quot;\u0026gt;\n          `        ``mViewBehind.scrollBehindTo(mContent, x, y);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number771 index770 alt2\u0026quot;\u0026gt;\n          `       ``((SlidingMenu)getParent()).manageLayers(getPercentOpen());`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number772 index771 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number773 index772 alt2\u0026quot;\u0026gt;\n          `        ``if (mTransformer != null) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number774 index773 alt1\u0026quot;\u0026gt;\n          `            ``invalidate();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number775 index774 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number776 index775 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number777 index776 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number778 index777 alt1\u0026quot;\u0026gt;\n          `    ``private int determineTargetPage(float pageOffset, int velocity, int deltaX) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number779 index778 alt2\u0026quot;\u0026gt;\n          `        ``int targetPage = mCurItem;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number780 index779 alt1\u0026quot;\u0026gt;\n          `        ``if (Math.abs(deltaX) \u0026amp;gt; mFlingDistance \u0026amp;\u0026amp; Math.abs(velocity) \u0026amp;gt; mMinimumVelocity) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number781 index780 alt2\u0026quot;\u0026gt;\n          `            ``if (velocity \u0026amp;gt; 0 \u0026amp;\u0026amp; deltaX \u0026amp;gt; 0) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number782 index781 alt1\u0026quot;\u0026gt;\n          `                ``targetPage -= 1;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number783 index782 alt2\u0026quot;\u0026gt;\n          `            ``} else if (velocity \u0026amp;lt; 0 \u0026amp;\u0026amp; deltaX \u0026amp;lt; 0){`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number784 index783 alt1\u0026quot;\u0026gt;\n          `                ``targetPage += 1;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number785 index784 alt2\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number786 index785 alt1\u0026quot;\u0026gt;\n          `        ``} else {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number787 index786 alt2\u0026quot;\u0026gt;\n          `            ``targetPage = (int) Math.round(mCurItem + pageOffset);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number788 index787 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number789 index788 alt2\u0026quot;\u0026gt;\n          `        ``return targetPage;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number790 index789 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number791 index790 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number792 index791 alt1\u0026quot;\u0026gt;\n          `    ``protected float getPercentOpen() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number793 index792 alt2\u0026quot;\u0026gt;\n          `        ``return Math.abs(mScrollX-mContent.getLeft()) / getBehindWidth();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number794 index793 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number795 index794 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number796 index795 alt1\u0026quot;\u0026gt;\n          `    ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number797 index796 alt2\u0026quot;\u0026gt;\n          `    ``protected void dispatchDraw(Canvas canvas) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number798 index797 alt1\u0026quot;\u0026gt;\n          `        ``// 这句要注释掉，否则会出现2个右侧的视图，一个有转场动画，一个没有转场动画`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number799 index798 alt2\u0026quot;\u0026gt;\n          `                ``// super.dispatchDraw(canvas);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number800 index799 alt1\u0026quot;\u0026gt;\n          `        ``// Draw the margin drawable if needed.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number801 index800 alt2\u0026quot;\u0026gt;\n          `        ``mViewBehind.drawShadow(mContent, canvas);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number802 index801 alt1\u0026quot;\u0026gt;\n          `        ``mViewBehind.drawFade(mContent, canvas, getPercentOpen());`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number803 index802 alt2\u0026quot;\u0026gt;\n          `        ``mViewBehind.drawSelector(mContent, canvas, getPercentOpen());`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number804 index803 alt1\u0026quot;\u0026gt;\n          `        ``// 设置右侧视图的转场效果，主要是修改Canvas。`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number805 index804 alt2\u0026quot;\u0026gt;\n          `        ``if (mTransformer != null) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number806 index805 alt1\u0026quot;\u0026gt;\n          `            ``canvas.save();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number807 index806 alt2\u0026quot;\u0026gt;\n          `            ``mTransformer.transformCanvas(canvas, getPercentOpen());`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number808 index807 alt1\u0026quot;\u0026gt;\n          `            ``super.dispatchDraw(canvas);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number809 index808 alt2\u0026quot;\u0026gt;\n          `            ``canvas.restore();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number810 index809 alt1\u0026quot;\u0026gt;\n          `        ``} else {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number811 index810 alt2\u0026quot;\u0026gt;\n          `            ``super.dispatchDraw(canvas);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number812 index811 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number813 index812 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number814 index813 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number815 index814 alt2\u0026quot;\u0026gt;\n          `    ``// variables for drawing`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number816 index815 alt1\u0026quot;\u0026gt;\n          `    ``private float mScrollX = 0.0f;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number817 index816 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number818 index817 alt1\u0026quot;\u0026gt;\n          `    ``private void onSecondaryPointerUp(MotionEvent ev) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number819 index818 alt2\u0026quot;\u0026gt;\n          `        ``if (DEBUG) Log.v(TAG, \u0026quot;onSecondaryPointerUp called\u0026quot;);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number820 index819 alt1\u0026quot;\u0026gt;\n          `        ``final int pointerIndex = MotionEventCompat.getActionIndex(ev);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number821 index820 alt2\u0026quot;\u0026gt;\n          `        ``final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number822 index821 alt1\u0026quot;\u0026gt;\n          `        ``if (pointerId == mActivePointerId) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number823 index822 alt2\u0026quot;\u0026gt;\n          `            ``// This was our active pointer going up. Choose a new`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number824 index823 alt1\u0026quot;\u0026gt;\n          `            ``// active pointer and adjust accordingly.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number825 index824 alt2\u0026quot;\u0026gt;\n          `            ``final int newPointerIndex = pointerIndex == 0 ? 1 : 0;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number826 index825 alt1\u0026quot;\u0026gt;\n          `            ``mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number827 index826 alt2\u0026quot;\u0026gt;\n          `            ``mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number828 index827 alt1\u0026quot;\u0026gt;\n          `            ``if (mVelocityTracker != null) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number829 index828 alt2\u0026quot;\u0026gt;\n          `                ``mVelocityTracker.clear();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number830 index829 alt1\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number831 index830 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number832 index831 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number833 index832 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number834 index833 alt1\u0026quot;\u0026gt;\n          `    ``private void startDrag() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number835 index834 alt2\u0026quot;\u0026gt;\n          `        ``mIsBeingDragged = true;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number836 index835 alt1\u0026quot;\u0026gt;\n          `        ``mQuickReturn = false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number837 index836 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number838 index837 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number839 index838 alt2\u0026quot;\u0026gt;\n          `    ``private void endDrag() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number840 index839 alt1\u0026quot;\u0026gt;\n          `        ``mQuickReturn = false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number841 index840 alt2\u0026quot;\u0026gt;\n          `        ``mIsBeingDragged = false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number842 index841 alt1\u0026quot;\u0026gt;\n          `        ``mIsUnableToDrag = false;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number843 index842 alt2\u0026quot;\u0026gt;\n          `        ``mActivePointerId = INVALID_POINTER;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number844 index843 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number845 index844 alt2\u0026quot;\u0026gt;\n          `        ``if (mVelocityTracker != null) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number846 index845 alt1\u0026quot;\u0026gt;\n          `            ``mVelocityTracker.recycle();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number847 index846 alt2\u0026quot;\u0026gt;\n          `            ``mVelocityTracker = null;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number848 index847 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number849 index848 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number850 index849 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number851 index850 alt2\u0026quot;\u0026gt;\n          `    ``private void setScrollingCacheEnabled(boolean enabled) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number852 index851 alt1\u0026quot;\u0026gt;\n          `        ``if (mScrollingCacheEnabled != enabled) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number853 index852 alt2\u0026quot;\u0026gt;\n          `            ``mScrollingCacheEnabled = enabled;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number854 index853 alt1\u0026quot;\u0026gt;\n          `            ``if (USE_CACHE) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number855 index854 alt2\u0026quot;\u0026gt;\n          `                ``final int size = getChildCount();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number856 index855 alt1\u0026quot;\u0026gt;\n          `                ``for (int i = 0; i \u0026amp;lt; size; ++i) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number857 index856 alt2\u0026quot;\u0026gt;\n          `                    ``final View child = getChildAt(i);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number858 index857 alt1\u0026quot;\u0026gt;\n          `                    ``if (child.getVisibility() != GONE) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number859 index858 alt2\u0026quot;\u0026gt;\n          `                        ``child.setDrawingCacheEnabled(enabled);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number860 index859 alt1\u0026quot;\u0026gt;\n          `                    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number861 index860 alt2\u0026quot;\u0026gt;\n          `                ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number862 index861 alt1\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number863 index862 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number864 index863 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number865 index864 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number866 index865 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number867 index866 alt2\u0026quot;\u0026gt;\n          `     ``* Tests scrollability within child views of v given a delta of dx.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number868 index867 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number869 index868 alt2\u0026quot;\u0026gt;\n          `     ``* @param v View to test for horizontal scrollability`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number870 index869 alt1\u0026quot;\u0026gt;\n          `     ``* @param checkV Whether the view v passed should itself be checked for scrollability (true),`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number871 index870 alt2\u0026quot;\u0026gt;\n          `     ``*               or just its children (false).`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number872 index871 alt1\u0026quot;\u0026gt;\n          `     ``* @param dx Delta scrolled in pixels`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number873 index872 alt2\u0026quot;\u0026gt;\n          `     ``* @param x X coordinate of the active touch point`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number874 index873 alt1\u0026quot;\u0026gt;\n          `     ``* @param y Y coordinate of the active touch point`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number875 index874 alt2\u0026quot;\u0026gt;\n          `     ``* @return true if child views of v can be scrolled by delta of dx.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number876 index875 alt1\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number877 index876 alt2\u0026quot;\u0026gt;\n          `    ``protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number878 index877 alt1\u0026quot;\u0026gt;\n          `        ``if (v instanceof ViewGroup) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number879 index878 alt2\u0026quot;\u0026gt;\n          `            ``final ViewGroup group = (ViewGroup) v;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number880 index879 alt1\u0026quot;\u0026gt;\n          `            ``final int scrollX = v.getScrollX();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number881 index880 alt2\u0026quot;\u0026gt;\n          `            ``final int scrollY = v.getScrollY();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number882 index881 alt1\u0026quot;\u0026gt;\n          `            ``final int count = group.getChildCount();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number883 index882 alt2\u0026quot;\u0026gt;\n          `            ``// Count backwards - let topmost views consume scroll distance first.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number884 index883 alt1\u0026quot;\u0026gt;\n          `            ``for (int i = count - 1; i \u0026amp;gt;= 0; i--) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number885 index884 alt2\u0026quot;\u0026gt;\n          `                ``final View child = group.getChildAt(i);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number886 index885 alt1\u0026quot;\u0026gt;\n          `                ``if (x + scrollX \u0026amp;gt;= child.getLeft() \u0026amp;\u0026amp; x + scrollX \u0026amp;lt; child.getRight() \u0026amp;\u0026amp;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number887 index886 alt2\u0026quot;\u0026gt;\n          `                        ``y + scrollY \u0026amp;gt;= child.getTop() \u0026amp;\u0026amp; y + scrollY \u0026amp;lt; child.getBottom() \u0026amp;\u0026amp;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number888 index887 alt1\u0026quot;\u0026gt;\n          `                        ``canScroll(child, true, dx, x + scrollX - child.getLeft(),`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number889 index888 alt2\u0026quot;\u0026gt;\n          `                                ``y + scrollY - child.getTop())) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number890 index889 alt1\u0026quot;\u0026gt;\n          `                    ``return true;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number891 index890 alt2\u0026quot;\u0026gt;\n          `                ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number892 index891 alt1\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number893 index892 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number894 index893 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number895 index894 alt2\u0026quot;\u0026gt;\n          `        ``return checkV \u0026amp;\u0026amp; ViewCompat.canScrollHorizontally(v, -dx);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number896 index895 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number897 index896 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number898 index897 alt1\u0026quot;\u0026gt;\n          `    ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number899 index898 alt2\u0026quot;\u0026gt;\n          `    ``public boolean dispatchKeyEvent(KeyEvent event) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number900 index899 alt1\u0026quot;\u0026gt;\n          `        ``// Let the focused view and/or our descendants get the key first`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number901 index900 alt2\u0026quot;\u0026gt;\n          `        ``return super.dispatchKeyEvent(event) || executeKeyEvent(event);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number902 index901 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number903 index902 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number904 index903 alt1\u0026quot;\u0026gt;\n          `    ``/**`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number905 index904 alt2\u0026quot;\u0026gt;\n          `     ``* You can call this function yourself to have the scroll view perform`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number906 index905 alt1\u0026quot;\u0026gt;\n          `     ``* scrolling from a key event, just as if the event had been dispatched to`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number907 index906 alt2\u0026quot;\u0026gt;\n          `     ``* it by the view hierarchy.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number908 index907 alt1\u0026quot;\u0026gt;\n          `     ``*`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number909 index908 alt2\u0026quot;\u0026gt;\n          `     ``* @param event The key event to execute.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number910 index909 alt1\u0026quot;\u0026gt;\n          `     ``* @return Return true if the event was handled, else false.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number911 index910 alt2\u0026quot;\u0026gt;\n          `     ``*/`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number912 index911 alt1\u0026quot;\u0026gt;\n          `    ``public` `boolean` `executeKeyEvent(KeyEvent event) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number913 index912 alt2\u0026quot;\u0026gt;\n          `        ``boolean` `handled = ``false``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number914 index913 alt1\u0026quot;\u0026gt;\n          `        ``if` `(event.getAction() == KeyEvent.ACTION_DOWN) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number915 index914 alt2\u0026quot;\u0026gt;\n          `            ``switch` `(event.getKeyCode()) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number916 index915 alt1\u0026quot;\u0026gt;\n          `            ``case` `KeyEvent.KEYCODE_DPAD_LEFT:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number917 index916 alt2\u0026quot;\u0026gt;\n          `                ``handled = arrowScroll(FOCUS_LEFT);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number918 index917 alt1\u0026quot;\u0026gt;\n          `                ``break``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number919 index918 alt2\u0026quot;\u0026gt;\n          `            ``case` `KeyEvent.KEYCODE_DPAD_RIGHT:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number920 index919 alt1\u0026quot;\u0026gt;\n          `                ``handled = arrowScroll(FOCUS_RIGHT);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number921 index920 alt2\u0026quot;\u0026gt;\n          `                ``break``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number922 index921 alt1\u0026quot;\u0026gt;\n          `            ``case` `KeyEvent.KEYCODE_TAB:`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number923 index922 alt2\u0026quot;\u0026gt;\n          `                ``if` `(Build.VERSION.SDK_INT \u0026amp;gt;= ``11``) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number924 index923 alt1\u0026quot;\u0026gt;\n          `                    ``// The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number925 index924 alt2\u0026quot;\u0026gt;\n          `                    ``// before Android 3.0. Ignore the tab key on those devices.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number926 index925 alt1\u0026quot;\u0026gt;\n          `                    ``if` `(KeyEventCompat.hasNoModifiers(event)) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number927 index926 alt2\u0026quot;\u0026gt;\n          `                        ``handled = arrowScroll(FOCUS_FORWARD);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number928 index927 alt1\u0026quot;\u0026gt;\n          `                    ``} ``else` `if` `(KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number929 index928 alt2\u0026quot;\u0026gt;\n          `                        ``handled = arrowScroll(FOCUS_BACKWARD);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number930 index929 alt1\u0026quot;\u0026gt;\n          `                    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number931 index930 alt2\u0026quot;\u0026gt;\n          `                ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number932 index931 alt1\u0026quot;\u0026gt;\n          `                ``break``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number933 index932 alt2\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number934 index933 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number935 index934 alt2\u0026quot;\u0026gt;\n          `        ``return` `handled;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number936 index935 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number937 index936 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number938 index937 alt1\u0026quot;\u0026gt;\n          `    ``public` `boolean` `arrowScroll(``int` `direction) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number939 index938 alt2\u0026quot;\u0026gt;\n          `        ``View currentFocused = findFocus();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number940 index939 alt1\u0026quot;\u0026gt;\n          `        ``if` `(currentFocused == ``this``) currentFocused = ``null``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number941 index940 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number942 index941 alt1\u0026quot;\u0026gt;\n          `        ``boolean` `handled = ``false``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number943 index942 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number944 index943 alt1\u0026quot;\u0026gt;\n          `        ``View nextFocused = FocusFinder.getInstance().findNextFocus(``this``, currentFocused,`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number945 index944 alt2\u0026quot;\u0026gt;\n          `                ``direction);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number946 index945 alt1\u0026quot;\u0026gt;\n          `        ``if` `(nextFocused != ``null` `\u0026amp;\u0026amp; nextFocused != currentFocused) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number947 index946 alt2\u0026quot;\u0026gt;\n          `            ``if` `(direction == View.FOCUS_LEFT) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number948 index947 alt1\u0026quot;\u0026gt;\n          `                ``handled = nextFocused.requestFocus();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number949 index948 alt2\u0026quot;\u0026gt;\n          `            ``} ``else` `if` `(direction == View.FOCUS_RIGHT) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number950 index949 alt1\u0026quot;\u0026gt;\n          `                ``// If there is nothing to the right, or this is causing us to`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number951 index950 alt2\u0026quot;\u0026gt;\n          `                ``// jump to the left, then what we really want to do is page right.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number952 index951 alt1\u0026quot;\u0026gt;\n          `                ``if` `(currentFocused != ``null` `\u0026amp;\u0026amp; nextFocused.getLeft() \u0026amp;lt;= currentFocused.getLeft()) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number953 index952 alt2\u0026quot;\u0026gt;\n          `                    ``handled = pageRight();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number954 index953 alt1\u0026quot;\u0026gt;\n          `                ``} ``else` `{`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number955 index954 alt2\u0026quot;\u0026gt;\n          `                    ``handled = nextFocused.requestFocus();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number956 index955 alt1\u0026quot;\u0026gt;\n          `                ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number957 index956 alt2\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number958 index957 alt1\u0026quot;\u0026gt;\n          `        ``} ``else` `if` `(direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number959 index958 alt2\u0026quot;\u0026gt;\n          `            ``// Trying to move left and nothing there; try to page.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number960 index959 alt1\u0026quot;\u0026gt;\n          `            ``handled = pageLeft();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number961 index960 alt2\u0026quot;\u0026gt;\n          `        ``} ``else` `if` `(direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number962 index961 alt1\u0026quot;\u0026gt;\n          `            ``// Trying to move right and nothing there; try to page.`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number963 index962 alt2\u0026quot;\u0026gt;\n          `            ``handled = pageRight();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number964 index963 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number965 index964 alt2\u0026quot;\u0026gt;\n          `        ``if` `(handled) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number966 index965 alt1\u0026quot;\u0026gt;\n          `            ``playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number967 index966 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number968 index967 alt1\u0026quot;\u0026gt;\n          `        ``return` `handled;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number969 index968 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number970 index969 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number971 index970 alt2\u0026quot;\u0026gt;\n          `    ``boolean` `pageLeft() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number972 index971 alt1\u0026quot;\u0026gt;\n          `        ``if` `(mCurItem \u0026amp;gt; ````) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number973 index972 alt2\u0026quot;\u0026gt;\n          `            ``setCurrentItem(mCurItem-``1``, ``true``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number974 index973 alt1\u0026quot;\u0026gt;\n          `            ``return` `true``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number975 index974 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number976 index975 alt1\u0026quot;\u0026gt;\n          `        ``return` `false``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number977 index976 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number978 index977 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number979 index978 alt2\u0026quot;\u0026gt;\n          `    ``boolean` `pageRight() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number980 index979 alt1\u0026quot;\u0026gt;\n          `        ``if` `(mCurItem \u0026amp;lt; ``1``) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number981 index980 alt2\u0026quot;\u0026gt;\n          `            ``setCurrentItem(mCurItem+``1``, ``true``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number982 index981 alt1\u0026quot;\u0026gt;\n          `            ``return` `true``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number983 index982 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number984 index983 alt1\u0026quot;\u0026gt;\n          `        ``return` `false``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number985 index984 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number986 index985 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number987 index986 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `setCanvasTransformer(CanvasTransformer t) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number988 index987 alt1\u0026quot;\u0026gt;\n          `        ``mTransformer = t;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number989 index988 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number990 index989 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number991 index990 alt2\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e如果想要使用这个侧滑菜单的动画效果，直接替换这两个类即可。同时，并不会影响SlidingMenu的固有功能。\u003c/p\u003e","title":"Android RESideMenu侧滑菜单"},{"content":"从ueditor.config.js可以看到这些，但是这些修改了，还是不行。\n,compressSide:1 //等比压缩的基准，确定maxImageSideLength参数的参照对象。0为按照最长边，1为按照宽度，2为按照高度 //scaleEnabled //是否可以拉伸长高,默认true(当开启时，自动长高失效) //,scaleEnabled:false UE的js肯定不会修改，所有可以考虑修改样式，由此我们找到如下文件：\nE:\\Camnpr\\www\\modules\\ueditor\\themes\\iframe.css\n从这个文件里，就能看到有这一句：/*可以在这里添加你自己的css*/\n哈哈，接下来，我们写css吧：\n`01` \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `img {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `02` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``max-width``: ``100%``; ``/*图片自适应宽度*/` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `03` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `04` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `body {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `05` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``overflow-y: ``scroll` `!important``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `06` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `07` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `.view {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `08` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``word-break: break-``all``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `09` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `10` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `.vote_area {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `11` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``display``: ``block``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `12` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `13` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `.vote_iframe {` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `14` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``background-color``: ``transparent``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `15` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``border``: ``` `none``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `16` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; ` ``height``: ``100%``;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `17` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `}` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt; `18` \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt; `#edui``1``_imagescale{``display``:``none` `!important``;} ``/*去除点击图片后出现的拉伸边框*/` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 转载：http://camnpr.com/archives/1229.html\n","permalink":"https://blog.zdltech.com/posts/ueditor%E6%8F%92%E5%85%A5%E7%9A%84%E5%9B%BE%E7%89%87%E8%87%AA%E9%80%82%E5%BA%94%E7%BC%96%E8%BE%91%E6%A1%86%E5%A4%A7%E5%B0%8F-%E7%82%B9%E5%87%BB%E5%9B%BE%E7%89%87%E4%B8%8D%E5%87%BA%E7%8E%B0%E6%8B%89/","summary":"\u003cp\u003e从ueditor.config.js可以看到这些，但是这些修改了，还是不行。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e,compressSide:1             //等比压缩的基准，确定maxImageSideLength参数的参照对象。0为按照最长边，1为按照宽度，2为按照高度\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e//scaleEnabled\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e //是否可以拉伸长高,默认true(当开启时，自动长高失效)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e //,scaleEnabled:false\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eUE的js肯定不会修改，所有可以考虑修改样式，由此我们找到如下文件：\u003c/p\u003e\n\u003cp\u003eE:\\Camnpr\\www\\modules\\ueditor\\themes\\iframe.css\u003c/p\u003e\n\u003cp\u003e从这个文件里，就能看到有这一句：/*可以在这里添加你自己的css*/\u003c/p\u003e\n\u003cp\u003e哈哈，接下来，我们写css吧：\u003c/p\u003e\n\u003cdiv id=\"highlighter_871467\" class=\"syntaxhighlighter  \"\u003e\n  \u003cdiv class=\"lines\"\u003e\n    \u003cdiv class=\"line alt1\"\u003e\n      \u003ctable\u003e\n        \u003ctr\u003e\n          \u003ctd class=\"number\"\u003e\n            `01`\n          \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `img {`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `02`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        ` ``max-width``: ``100%``; ``/*图片自适应宽度*/`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `03`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `}`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `04`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `body {`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `05`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        ` ``overflow-y: ``scroll` `!important``;`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `06`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `}`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `07`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `.view {`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `08`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        ` ``word-break: break-``all``;`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `09`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `}`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `10`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `.vote_area {`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `11`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        ` ``display``: ``block``;`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `12`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `}`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `13`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `.vote_iframe {`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `14`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        ` ``background-color``: ``transparent``;`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `15`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        ` ``border``: ``` `none``;`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `16`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        ` ``height``: ``100%``;`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `17`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `}`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;line alt2\u0026quot;\u0026gt;\n  \u0026lt;table\u0026gt;\n    \u0026lt;tr\u0026gt;\n      \u0026lt;td class=\u0026quot;number\u0026quot;\u0026gt;\n        `18`\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;content\u0026quot;\u0026gt;\n        `#edui``1``_imagescale{``display``:``none` `!important``;} ``/*去除点击图片后出现的拉伸边框*/`\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"CB CLEAR\"\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cem\u003e转载：http://camnpr.com/archives/1229.html\u003c/em\u003e\u003c/p\u003e","title":"UEditor插入的图片自适应编辑框大小 点击图片不出现拉伸缩放边框"},{"content":"首先要做一个类似橡皮擦的东西吧，然后才能把纸上的笔迹擦除\n``` /** * FileName: SplashActivity.java * * @desc 橡皮擦功能，类似刮刮乐效果 * @author HTP * @Date 20140311 * @version 1.00 */ public class Text_Rubbler extends TextView { private float TOUCH_TOLERANCE; // 填充距离，使线条更自然，柔和,值越小，越柔和。 // private final int bgColor; // 位图 private Bitmap mBitmap; // 画布 private Canvas mCanvas; // 画笔 private Paint mPaint; private Path mPath; private float mX, mY; private boolean isDraw = false; public Text_Rubbler(Context context) { /** * @param context 上下文 */ super(context); } public Text_Rubbler(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // bgColor = // attrs.getAttributeIntValue(\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;, // \u0026quot;textColor\u0026quot;, 0xFFFFFF); // System.out.println(\u0026quot;Color:\u0026quot;+bgColor); } public Text_Rubbler(Context context, AttributeSet attrs) { super(context, attrs); // bgColor = // attrs.getAttributeIntValue(\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;, // \u0026quot;textColor\u0026quot;, 0xFFFFFF); // System.out.println(bgColor); // System.out.println(attrs.getAttributeValue(\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;, // \u0026quot;layout_width\u0026quot;)); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (isDraw) { mCanvas.drawPath(mPath, mPaint); // mCanvas.drawPoint(mX, mY, mPaint); canvas.drawBitmap(mBitmap, 0, 0, null); } } /** * 开启檫除功能 * * @param bgColor * 覆盖的背景颜色 * @param paintStrokeWidth * 触点（橡皮）宽度 * @param touchTolerance * 填充距离,值越小，越柔和。 */ public void beginRubbler(final int bgColor, final int paintStrokeWidth, float touchTolerance) { TOUCH_TOLERANCE = touchTolerance; // 设置画笔 mPaint = new Paint(); // mPaint.setAlpha(0); // 画笔划过的痕迹就变成透明色了 mPaint.setColor(Color.BLACK); // 此处不能为透明色 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); // 或者 // mPaint.setAlpha(0); // mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); // 前圆角 mPaint.setStrokeCap(Paint.Cap.ROUND); // 后圆角 mPaint.setStrokeWidth(paintStrokeWidth); // 笔宽 // 痕迹 mPath = new Path(); ; // 覆盖 // if (getLayoutParams().width == LayoutParams.FILL_PARENT) { // // } mBitmap = Bitmap.createBitmap(getLayoutParams().width, getLayoutParams().height, Config.ARGB_8888); mCanvas = new Canvas(mBitmap); mCanvas.drawColor(bgColor); isDraw = true; } @Override public boolean onTouchEvent(MotionEvent event) { if (!isDraw) { return true; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 触点按下 // touchDown(event.getRawX(),event.getRawY()); touchDown(event.getX(), event.getY()); invalidate(); break; case MotionEvent.ACTION_MOVE: // 触点移动 touchMove(event.getX(), event.getY()); invalidate(); break; case MotionEvent.ACTION_UP: // 触点弹起 touchUp(event.getX(), event.getY()); invalidate(); break; default: break; } return true; } private void touchDown(float x, float y) { mPath.reset(); mPath.moveTo(x, y); mX = x; mY = y; } private void touchMove(float x, float y) { float dx = Math.abs(x - mX); float dy = Math.abs(y - mY); if (dx \u0026amp;gt;= TOUCH_TOLERANCE || dy \u0026amp;gt;= TOUCH_TOLERANCE) { mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); mX = x; mY = y; } } private void touchUp(float x, float y) { mPath.lineTo(x, y); mCanvas.drawPath(mPath, mPaint); mPath.reset(); } } \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 接下来就是使用橡皮檫擦除了 \u0026lt;div class=\u0026#34;dp-highlighter bg_java\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;tools\u0026#34;\u0026gt; ``` /** * FileName: RubblerAct.java * @Desc 该类通过调用Text_Rubbler这个类将在Activity上显示一片刮一刮的区域，可以出发触摸事件 * @author HTP * @Date 20140312 * @version 1.00 */ public class RubblerAct extends Activity { // 刮开后文字显示 private TextView tv_rubbler; // 得到刮一刮的内容 private Sentence mSentence; // 下一张 private TextView tv_next; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // setContentView(new Rubble(this,\u0026#34;谢谢惠顾\u0026#34;,new Rect(100, 200, // 300,250),2,1f,14)); // ///////////////////////////////////////// setContentView(R.layout.rubbler); // 设置的颜色必须要有透明度。 ((Text_Rubbler) findViewById(R.id.rubbler)).beginRubbler(0xFFFFFFFF, 20, 1f);// 设置橡皮擦的宽度等 mSentence = new Sentence(); // 随机初始化文字 tv_rubbler = (TextView) findViewById(R.id.rubbler); String str = mSentence.getSentence(); tv_rubbler.setText(str); tv_next = (TextView) findViewById(R.id.tv_next); // 点击下一步 tv_next.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub String str = mSentence.getSentence(); tv_rubbler.setText(str); ((Text_Rubbler) findViewById(R.id.rubbler))// 初始化状态 .beginRubbler(0xFFFFFFFF, 20, 1f); } }); } class Rubble extends View { private final int PAINT_STROKE_WIDTH; private final float TOUCH_TOLERANCE; // 填充距离，使线条更自然，柔和,值越小，越柔和。 private final int TEXT_SIZE; private Bitmap mBitmap; // 画布 private Canvas mCanvas; // 画笔 private Paint mPaint; private Path mPath; private float mX, mY; private final int X, Y, W, H; private final Rect touchRect; public Rubble(Context context, String bgText, Rect rect, int paintStrokeWidth, float touchTolerance, int textSize) { super(context); setFocusable(true); touchRect = rect; W = rect.right - rect.left; H = rect.bottom - rect.top; X = rect.left; Y = rect.top; TEXT_SIZE = textSize; PAINT_STROKE_WIDTH = paintStrokeWidth; TOUCH_TOLERANCE = touchTolerance; setBackground(touchRect, bgText); initDrowTools(); } private void setBackground(Rect rect, String bgText) { DisplayMetrics dm = new DisplayMetrics(); dm = this.getResources().getDisplayMetrics(); Bitmap bitmap = Bitmap.createBitmap(dm.widthPixels, dm.heightPixels, Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(); paint.setColor(0x88000000); // paint.setStyle(Style.STROKE); // paint.setTextAlign(Align.CENTER); paint.setTextSize(TEXT_SIZE); // paint.setTextScaleX(1.5f); canvas.drawColor(Color.WHITE); // 画字的坐标不好控制 int x = rect.left + (rect.right - rect.left - bgText.length() * TEXT_SIZE) / 2; int y = rect.top + (rect.bottom - rect.top - TEXT_SIZE) / 2; // int y = 218+25; canvas.drawText(bgText, x, y, paint); Drawable drawable = new BitmapDrawable(bitmap); setBackgroundDrawable(drawable); } private void initDrowTools() { // 设置画笔 mPaint = new Paint(); // mPaint.setAlpha(0); // 画笔划过的痕迹就变成透明色了 mPaint.setColor(Color.BLACK); // 此处不能为透明色 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); // 或者 // mPaint.setAlpha(0); // mPaint.setXfermode(new // PorterDuffXfermode(PorterDuff.Mode.DST_IN)); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); // 前圆角 mPaint.setStrokeCap(Paint.Cap.ROUND); // 后圆角 mPaint.setStrokeWidth(PAINT_STROKE_WIDTH); // 笔宽 // 痕迹 mPath = new Path(); ; // 覆盖 mBitmap = Bitmap.createBitmap(W, H, Config.ARGB_8888); mCanvas = new Canvas(mBitmap); mCanvas.drawColor(0x88000000); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mCanvas.drawPath(mPath, mPaint); // mCanvas.drawPoint(mX, mY, mPaint); canvas.drawBitmap(mBitmap, X, Y, null); } @Override public boolean onTouchEvent(MotionEvent event) { System.out.print(\u0026#34;X--\u0026#34; + event.getX()); System.out.println(\u0026#34;Y--\u0026#34; + event.getY()); if (!touchRect.contains((int) event.getX(), (int) event.getY())) { return false; } switch (event.getAction()) { // 触点按下 case MotionEvent.ACTION_DOWN: { touchDown(event.getRawX(), event.getRawY()); touchDown(event.getX() - touchRect.left, event.getY() - touchRect.top); invalidate(); break; } case MotionEvent.ACTION_MOVE: // 触点移动 touchMove(event.getX() - touchRect.left, event.getY() - touchRect.top); invalidate(); break; case MotionEvent.ACTION_UP: // 触点弹起 touchUp(event.getX() - touchRect.left, event.getY() - touchRect.top); invalidate(); break; default: break; } return true; } private void touchDown(float x, float y) { mPath.reset(); mPath.moveTo(x, y); mX = x; mY = y; } private void touchMove(float x, float y) { float dx = Math.abs(x - mX); float dy = Math.abs(y - mY); if (dx \u0026amp;gt;= TOUCH_TOLERANCE || dy \u0026amp;gt;= TOUCH_TOLERANCE) { mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); mX = x; mY = y; } } private void touchUp(float x, float y) { mPath.lineTo(x, y); mCanvas.drawPath(mPath, mPaint); mPath.reset(); } } /** * 键盘事件，当按下back键的时候询问是否再按一次退出程序 */ // 退出时间 private long exitTime = 0; @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK \u0026amp;\u0026amp; event.getAction() == KeyEvent.ACTION_DOWN) { if ((System.currentTimeMillis() - exitTime) \u0026amp;gt; 2000) { Toast.makeText(getApplicationContext(), \u0026#34;再按一次退出程序\u0026#34;, Toast.LENGTH_SHORT).show(); exitTime = System.currentTimeMillis(); } else { finish(); System.exit(0); } return true; } return super.onKeyDown(keyCode, event); } } \u0026lt;/div\u0026gt; 实现效果如下：\n来自：http://blog.csdn.net/qq544529563/article/details/38795401\n","permalink":"https://blog.zdltech.com/posts/android%E5%AE%9E%E7%8E%B0%E5%88%AE%E5%88%AE%E4%B9%90%E6%95%88%E6%9E%9C/","summary":"\u003cp\u003e首先要做一个类似橡皮擦的东西吧，然后才能把纸上的笔迹擦除\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      ```\n    /** \n     * FileName: SplashActivity.java \n     *  \n     * @desc 橡皮擦功能，类似刮刮乐效果 \n     * @author HTP \n     * @Date 20140311 \n     * @version 1.00 \n     */  \n    public class Text_Rubbler extends TextView {  \n\u003cpre\u003e\u003ccode\u003e    private float TOUCH_TOLERANCE; // 填充距离，使线条更自然，柔和,值越小，越柔和。  \n  \n    // private final int bgColor;  \n    // 位图  \n    private Bitmap mBitmap;  \n    // 画布  \n    private Canvas mCanvas;  \n    // 画笔  \n    private Paint mPaint;  \n    private Path mPath;  \n    private float mX, mY;  \n  \n    private boolean isDraw = false;  \n  \n    public Text_Rubbler(Context context) {  \n        /** \n         * @param context 上下文 \n         */  \n        super(context);  \n  \n    }  \n  \n    public Text_Rubbler(Context context, AttributeSet attrs, int defStyle) {  \n        super(context, attrs, defStyle);  \n        // bgColor =  \n        // attrs.getAttributeIntValue(\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;,  \n        // \u0026quot;textColor\u0026quot;, 0xFFFFFF);  \n        // System.out.println(\u0026quot;Color:\u0026quot;+bgColor);  \n    }  \n  \n    public Text_Rubbler(Context context, AttributeSet attrs) {  \n        super(context, attrs);  \n        // bgColor =  \n        // attrs.getAttributeIntValue(\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;,  \n        // \u0026quot;textColor\u0026quot;, 0xFFFFFF);  \n        // System.out.println(bgColor);  \n        // System.out.println(attrs.getAttributeValue(\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;,  \n        // \u0026quot;layout_width\u0026quot;));  \n    }  \n  \n    @Override  \n    protected void onDraw(Canvas canvas) {  \n        super.onDraw(canvas);  \n        if (isDraw) {  \n  \n            mCanvas.drawPath(mPath, mPaint);  \n            // mCanvas.drawPoint(mX, mY, mPaint);  \n            canvas.drawBitmap(mBitmap, 0, 0, null);  \n        }  \n    }  \n  \n    /** \n     * 开启檫除功能 \n     *  \n     * @param bgColor \n     *            覆盖的背景颜色 \n     * @param paintStrokeWidth \n     *            触点（橡皮）宽度 \n     * @param touchTolerance \n     *            填充距离,值越小，越柔和。 \n     */  \n    public void beginRubbler(final int bgColor, final int paintStrokeWidth,  \n            float touchTolerance) {  \n        TOUCH_TOLERANCE = touchTolerance;  \n        // 设置画笔  \n        mPaint = new Paint();  \n        // mPaint.setAlpha(0);  \n        // 画笔划过的痕迹就变成透明色了  \n        mPaint.setColor(Color.BLACK); // 此处不能为透明色  \n        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));  \n        // 或者  \n        // mPaint.setAlpha(0);  \n        // mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));  \n  \n        mPaint.setAntiAlias(true);  \n        mPaint.setDither(true);  \n        mPaint.setStyle(Paint.Style.STROKE);  \n        mPaint.setStrokeJoin(Paint.Join.ROUND); // 前圆角  \n        mPaint.setStrokeCap(Paint.Cap.ROUND); // 后圆角  \n        mPaint.setStrokeWidth(paintStrokeWidth); // 笔宽  \n  \n        // 痕迹  \n        mPath = new Path();  \n        ;  \n        // 覆盖  \n        // if (getLayoutParams().width == LayoutParams.FILL_PARENT) {  \n        //  \n        // }  \n        mBitmap = Bitmap.createBitmap(getLayoutParams().width,  \n                getLayoutParams().height, Config.ARGB_8888);  \n        mCanvas = new Canvas(mBitmap);  \n  \n        mCanvas.drawColor(bgColor);  \n        isDraw = true;  \n    }  \n  \n    @Override  \n    public boolean onTouchEvent(MotionEvent event) {  \n        if (!isDraw) {  \n            return true;  \n        }  \n        switch (event.getAction()) {  \n        case MotionEvent.ACTION_DOWN: // 触点按下  \n            // touchDown(event.getRawX(),event.getRawY());  \n            touchDown(event.getX(), event.getY());  \n            invalidate();  \n            break;  \n        case MotionEvent.ACTION_MOVE: // 触点移动  \n            touchMove(event.getX(), event.getY());  \n            invalidate();  \n            break;  \n        case MotionEvent.ACTION_UP: // 触点弹起  \n            touchUp(event.getX(), event.getY());  \n            invalidate();  \n            break;  \n        default:  \n            break;  \n        }  \n        return true;  \n    }  \n  \n    private void touchDown(float x, float y) {  \n        mPath.reset();  \n        mPath.moveTo(x, y);  \n        mX = x;  \n        mY = y;  \n    }  \n  \n    private void touchMove(float x, float y) {  \n        float dx = Math.abs(x - mX);  \n        float dy = Math.abs(y - mY);  \n        if (dx \u0026amp;gt;= TOUCH_TOLERANCE || dy \u0026amp;gt;= TOUCH_TOLERANCE) {  \n            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);  \n            mX = x;  \n            mY = y;  \n        }  \n  \n    }  \n  \n    private void touchUp(float x, float y) {  \n        mPath.lineTo(x, y);  \n        mCanvas.drawPath(mPath, mPaint);  \n        mPath.reset();  \n    }  \n  \n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ediv\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ediv\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003ediv\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e接下来就是使用橡皮檫擦除了\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003ediv \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;dp-highlighter bg_java\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003ediv \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;bar\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003ediv \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;tools\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e/**\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e FileName: RubblerAct\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ejava \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @Desc    该类通过调用Text_Rubbler这个类将在Activity上显示一片刮一刮的区域，可以出发触摸事件 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @author  HTP \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @Date    \u003cspan style=\"color:#bd93f9\"\u003e20140312\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @version \u003cspan style=\"color:#bd93f9\"\u003e1.00\u003c/span\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e RubblerAct \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e Activity {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 刮开后文字显示  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        private TextView tv_rubbler;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 得到刮一刮的内容  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        private Sentence mSentence;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 下一张  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        private TextView tv_next;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        @Override  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        public void onCreate(Bundle savedInstanceState) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            super\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonCreate(savedInstanceState);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e setContentView(new Rubble(this,\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;谢谢惠顾\u0026#34;\u003c/span\u003e,new Rect(\u003cspan style=\"color:#bd93f9\"\u003e100\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e200\u003c/span\u003e,  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e300\u003c/span\u003e,\u003cspan style=\"color:#bd93f9\"\u003e250\u003c/span\u003e),\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e,\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003ef,\u003cspan style=\"color:#bd93f9\"\u003e14\u003c/span\u003e));  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e/////////////////////////////////////////\u003c/span\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            setContentView(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elayout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003erubbler);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 设置的颜色必须要有透明度。  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            ((Text_Rubbler) findViewById(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003erubbler))\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ebeginRubbler(\u003cspan style=\"color:#bd93f9\"\u003e0xFFFFFFFF\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e,  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003ef);\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 设置橡皮擦的宽度等  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            mSentence \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new Sentence();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 随机初始化文字  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            tv_rubbler \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (TextView) findViewById(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003erubbler);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            String \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003estr\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e mSentence\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetSentence();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            tv_rubbler\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetText(\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003estr\u003c/span\u003e);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            tv_next \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e (TextView) findViewById(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etv_next);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 点击下一步  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            tv_next\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetOnClickListener(new OnClickListener() {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                @Override  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                public void onClick(View v) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e TODO Auto\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003egenerated method stub  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    String \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003estr\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e mSentence\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetSentence();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    tv_rubbler\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetText(\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003estr\u003c/span\u003e);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    ((Text_Rubbler) findViewById(R\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003erubbler))\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 初始化状态  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            \u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ebeginRubbler(\u003cspan style=\"color:#bd93f9\"\u003e0xFFFFFFFF\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003ef);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            });  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e Rubble \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e View {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private final int PAINT_STROKE_WIDTH;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private final float TOUCH_TOLERANCE; \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 填充距离，使线条更自然，柔和,值越小，越柔和。  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private final int TEXT_SIZE;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private Bitmap mBitmap;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 画布  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private Canvas mCanvas;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 画笔  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private Paint mPaint;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private Path mPath;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private float mX, mY;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private final int X, Y, W, H;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private final Rect touchRect;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            public Rubble(Context context, String bgText, Rect rect,  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    int paintStrokeWidth, float touchTolerance, int textSize) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                super(context);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                setFocusable(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                touchRect \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rect;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                W \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eright \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e rect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eleft;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                H \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ebottom \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e rect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etop;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                X \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eleft;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                Y \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etop;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                TEXT_SIZE \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e textSize;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                PAINT_STROKE_WIDTH \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e paintStrokeWidth;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                TOUCH_TOLERANCE \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e touchTolerance;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                setBackground(touchRect, bgText);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                initDrowTools();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private void setBackground(Rect rect, String bgText) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                DisplayMetrics dm \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new DisplayMetrics();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                dm \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e this\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetResources()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetDisplayMetrics();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                Bitmap bitmap \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Bitmap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecreateBitmap(dm\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidthPixels,  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        dm\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eheightPixels, Config\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eARGB_8888);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                Canvas canvas \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new Canvas(bitmap);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                Paint paint \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new Paint();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                paint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetColor(\u003cspan style=\"color:#bd93f9\"\u003e0x88000000\u003c/span\u003e);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e paint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetStyle(Style\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eSTROKE);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e paint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetTextAlign(Align\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eCENTER);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                paint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetTextSize(TEXT_SIZE);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e paint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetTextScaleX(\u003cspan style=\"color:#bd93f9\"\u003e1.5\u003c/span\u003ef);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                canvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawColor(Color\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eWHITE);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 画字的坐标不好控制  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                int x \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eleft  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e (rect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eright \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e rect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eleft \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e bgText\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elength() \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e TEXT_SIZE)  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                int y \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e rect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etop \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e (rect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ebottom \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e rect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etop \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e TEXT_SIZE) \u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e int y \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e218\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e25\u003c/span\u003e;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                canvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawText(bgText, x, y, paint);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                Drawable drawable \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new BitmapDrawable(bitmap);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                setBackgroundDrawable(drawable);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private void initDrowTools() {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 设置画笔  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPaint \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new Paint();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e mPaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetAlpha(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 画笔划过的痕迹就变成透明色了  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetColor(Color\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBLACK); \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 此处不能为透明色  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetXfermode(new PorterDuffXfermode(PorterDuff\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMode\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eDST_OUT));  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 或者  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e mPaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetAlpha(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e mPaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetXfermode(new  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e PorterDuffXfermode(PorterDuff\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMode\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eDST_IN));  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetAntiAlias(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetDither(\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetStyle(Paint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eStyle\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eSTROKE);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetStrokeJoin(Paint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eJoin\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eROUND); \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 前圆角  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetStrokeCap(Paint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eCap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eROUND); \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 后圆角  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetStrokeWidth(PAINT_STROKE_WIDTH); \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 笔宽  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 痕迹  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPath \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new Path();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                ;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 覆盖  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mBitmap \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Bitmap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecreateBitmap(W, H, Config\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eARGB_8888);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mCanvas \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new Canvas(mBitmap);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mCanvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawColor(\u003cspan style=\"color:#bd93f9\"\u003e0x88000000\u003c/span\u003e);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            @Override  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            protected void onDraw(Canvas canvas) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                super\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonDraw(canvas);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mCanvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawPath(mPath, mPaint);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e mCanvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawPoint(mX, mY, mPaint);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                canvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawBitmap(mBitmap, X, Y, null);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            @Override  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            public boolean onTouchEvent(MotionEvent event) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprint(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;X--\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetX());  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eout\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eprintln(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Y--\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetY());  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#ff79c6\"\u003e!\u003c/span\u003etouchRect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003econtains((int) event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetX(), (int) event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetY())) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003eswitch\u003c/span\u003e (event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetAction()) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 触点按下  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003ecase\u003c/span\u003e MotionEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eACTION_DOWN: {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    touchDown(event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetRawX(), event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetRawY());  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    touchDown(event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetX() \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e touchRect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eleft, event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetY()  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e touchRect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etop);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    invalidate();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003ecase\u003c/span\u003e MotionEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eACTION_MOVE: \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 触点移动  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    touchMove(event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetX() \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e touchRect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eleft, event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetY()  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e touchRect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etop);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    invalidate();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003ecase\u003c/span\u003e MotionEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eACTION_UP: \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 触点弹起  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    touchUp(event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetX() \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e touchRect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eleft, event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetY()  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e touchRect\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etop);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    invalidate();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                default:  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private void touchDown(float x, float y) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPath\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ereset();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPath\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emoveTo(x, y);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mX \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e x;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mY \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e y;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private void touchMove(float x, float y) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                float dx \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Math\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eabs(x \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e mX);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                float dy \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Math\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eabs(y \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e mY);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (dx \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e TOUCH_TOLERANCE \u003cspan style=\"color:#ff79c6\"\u003e||\u003c/span\u003e dy \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e TOUCH_TOLERANCE) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    mPath\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003equadTo(mX, mY, (x \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e mX) \u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e, (y \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e mY) \u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    mX \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e x;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    mY \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e y;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            private void touchUp(float x, float y) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPath\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elineTo(x, y);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mCanvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawPath(mPath, mPaint);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                mPath\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ereset();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e/**\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 键盘事件，当按下back键的时候询问是否再按一次退出程序 \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e 退出时间  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        private long exitTime \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        @Override  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        public boolean onKeyDown(int keyCode, KeyEvent event) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (keyCode \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e KeyEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eKEYCODE_BACK  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetAction() \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e KeyEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eACTION_DOWN) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e ((System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecurrentTimeMillis() \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e exitTime) \u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003egt; \u003cspan style=\"color:#bd93f9\"\u003e2000\u003c/span\u003e) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    Toast\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emakeText(getApplicationContext(), \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;再按一次退出程序\u0026#34;\u003c/span\u003e,  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            Toast\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eLENGTH_SHORT)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eshow();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    exitTime \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecurrentTimeMillis();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                } \u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    finish();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    System\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eexit(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e super\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eonKeyDown(keyCode, event);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android实现刮刮乐效果"},{"content":"XMPP Android基础介绍\n在android中使用到的库为Asmack（下载地址：http://code.google.com/p/asmack/）\nAsmack的相关介绍\n1.ConnectionConfiguration 通过该类设置用于与XMPP服务器建立连接的配置。它能配置连接是否使用TLS、SASL加密等\n2.XMPPConnection 通过该类连接XMPP服务。通过connect()建立连接disconnect（）断开连接\n3.ChatManager 用于监控当前所有Chat，可以使用createChat（String userJID,MessageListener listener）创建一个聊天\n4.Chat 用于监控两个用户间的一系列消息。使用addMessageListener（MessageListener listener），当有任何消息到达时将会触发listener的processMessage（Chat chat,Message msg）方法。\n5.Message 用来表示一个消息包。Message有2个内部类Message.Body表示消息体，Message.Type消息类型\n（1）Message.Type.NORMAL 默认文本消息\n（2）Message.Type.CHAT 典型的短消息，如QQ聊天时一行一行的显示消息\n（3）Message.Type.GROUP_CHAT 群聊消息\n（4）Message.Type.HEADLINE 滚动显示消息\n（5）Message.Type.ERROR 错误消息\n6.Roster 表示存储了一个花名册，其中包含很多RosterEntry。为了易于管理，花名册的项被分配到了各个group中，当建立与XMPP服务的连接后可以使用connection.getRoster()获得Roster对象。别的用户可以使用一个订阅请求（相当于QQ添加好友）尝试订阅目的用户。可以使用Roster.SubscriptionMode的值处理这些请求，accept_all表示接收所有订阅请求，reject_all表示拒绝所有订阅请求，manual表示手工处理订阅请求。\n//创建组的方法\nRosterGroup group=roster.createGroup(“同事”);\n//可以向组中添加RosterEntry对象\ngroup.addEntry(entry);\n7.RosterGroup表示Roster中的每条记录，它包含了用户的JID、用户名、用户分配的昵称。\n8.RosterGroup表示RosterEntry的组。可以使用addEnty(RosterEntry entry)添加，contains(String user)判读某用户是在组中，removeEntry(RosterEnty entry)从组中移除，getEntries()获取所有RosterEntry\n9.Presence表示XMPP状态的packet，每个presence packet都是一个状态，用户枚举类型Presence.Type的值表示。\nPresence.Type值\n（1）available 用户空闲状态\n（2）unavailable 用户没空看消息\n（3）subscribe 请求定义别人，即请求加对方为好友\n（4）subscribed 统一被别人订阅，也就是确认被对方加为好友\n（5）unsubscribe 取消订阅别人，请求删除某好友\n（6）unsubscribed 拒绝被别人订阅，即拒绝对方的添加请求\n（7） error 当前状态packet有错误\n登陆XMPP服务器\n首先创建用户，然后建立与XMPP服务器的连接，最后使用用户登陆到XMPP服务器\n//指定连接到服务器的参数\nConnectionConfiguration mConnectionConfiguration=new ConnectonConfiguration(“192.168.1.105”,5222);\n//初始化XMPPconnection连接\nXMPPConnection mXMPPConnection=new XMPPConnection(mConnectionConfiguration);\n//连接上XMPP服务器\ntry{\nmXMPPConnection.connect();\n//实例化用户管理\nAccountManager mAccountManager=mXMPPConnection.getAccountManager();\n//用指定的用户名和密码创建用户\nmAccountManager.createAccount(‘zhang’,’123456′);\n}catch(XMPPException e){\n}\n登陆之前要和XMPP建立连接。XMPPConnection类用来建立到XMPP服务器的连接。要建立SSL连接使用SSLXMPPConnection\n//建立一个到服务器的连接\nXMPPConnection connl=new XMPPConnection(“hostname”);\n//通过一个特殊的端口建立一个服务器的连接\nXMPPConnection connl=new XMPPConnection(“hostname”,5222);\n//建立一个到服务器的SSL连接\nXMPPConnection connl=new SSLXMPPConnection(“hostname”);\n登陆代码如下：\n//指定连接到服务器的参数\nConnectionConfiguration mConnectionConfiguration=new ConnectonConfiguration(“192.168.1.105”,5222);\n//初始化XMPPconnection连接\nXMPPConnection mXMPPConnection=new XMPPConnection(mConnectionConfiguration);\n//连接上XMPP服务器\ntry{\nmXMPPConnection.connect();\n//使用指定的用户名和密码登录\nmXMPPConnection.login(‘zhang’,’123456′);\n//mXMPPConnection。disconnect()表示下线\n}catch(XMPPException e){\n}\n如果考虑登陆进去，但是显示不在线可以使用\n//Presence类可以设置用户的是否在线的类型属性\nPresence mPresence=new Presence(Presence.Type.unavailable);\n//向服务器提交该属性\nmXMPPConnection.sendPacket(mPresence);\n联系人相关操作\n1.获取联系人列表\nAsmack中的Roster对象能够跟踪其他用户的有效性，联系人列表需要列表引用Roster。一个Roster实例通过XMPPConnection.getRoster()方法获得。需要注意的是只有在成功登陆服务器后才能用该方法。\n在Roster中每个用户用一个RosterEntry表示，它包括了用户的XMPP地址、用户的昵称\n//新建Roster对象\nRoster roster=mXMPPConnection.getRoster();\n//获得联系人列表集合\nCollection rg=roster.getEnteries();\n2.获得联系人状态\n//获取好友状态对象\nPresence presence = roster.getPresence(rosterEntry.getUser());\n//获得好友状态\npressence.getStatus();\n设置状态的方法\n//新建状态\nPresence mPressence=new Presence(Presence.Type.available);\n//设置状态信息\nmPresence.setStatus(“set My Status here”);\n//发送配置包，设置在线状态\nmXMPPConnection.sendPacket(mPresence);\n3.添加和删除联系人\n//新建Roster对象\nRoster roster=mXMPPConn\nection.getRoster();\ntry{\n//添加联系人 3个参数分别问：用户名，昵称，和分组\nroster.createEntry(“zhang@192.168.1.105″,”小伙”,String[]{“friends”});\n//删除联系人\n//roster.removeEntry(roster.getEntry(“zhang@192.168.1.105″));\n}catch(XMPPException e){\n}\n4.监听联系人添加信息\n收到订阅请求时候的XMPP信息如下\n收到被删除订阅的时候的XMPP信息如下： 下面是添加监听的核心代码 //添加监听联系人信息 private static void addListener(){ //新建过滤消息 PacketFilter fileterMessage=new PacketFilter(Presence.class); //创建监听器 PacketListener myListener=new PacketListener(){ public void processPacket(Packet packet){ //消息包赋值给一个新的Presence final Presence mPressence=(Presence)packet; if(mPresence.getType().equals(Presence.Type.subscribe)){ //收到请求订阅的信息，可以在该处处理 }else if(mPresence.getType().equals(Presence.Type.unsubscribe)){ //收到取消订阅的信息，可以在该处处理 } //packet.toXML();可以将接收到是信息转换为XML字符串 } } } 消息处理 发送和接收消息是即时通信的核心地位，类org.jivesoftware.smack.Chat用于在两个联系人之间发送和接收消息 //接收消息 private static void addMessageListener(){ //添加消息监听 mXMPPConnection.getChatManager().addChatListener(new ChatMessageListener(){ //创建消息 public void chatCreated(Chat mChat,boolean createLocally){ //检测消息来源是否为本地发出的 //这里为接收到的消息 if(!createdLocally){ //监听接收到的消息 mChat.addMessageListener(new MessageListener(){ //添加消息处理 public void proceesMessage(Chat mChat,Message mMessage){ //打印接收到的消息 //message.getBody(); } }); } }\n});\n}\n发送消息\n一个chat在两个用户之间创建一个消息线程。\n//新建一个消息线程\nChat chat=mXMPPConnection.getChatManager()\n//指定接收人，并添加消息监听\n.createChat(“user1@stonechen”,new MessageListener(){\n//处理消息\npublic void processMessage(Chat chat,Message message){\n//打印接收的消息 message\n}\n});\n//创建一个新的消息\ntry{\nMessage newMessage=new Message();\n//设置消息内容\nnewMessage.setBody(“hello world”);\n//发送消息\nchat.sendMessage(newMessage);\n}catch(XMPPException e){\n}\n聊天室\nXMPP的xep0045规范给出了多人聊天（MUC,Multi-User Chat）方法,查看MUC协议文本的网址 http://xmpp.org/extensions/xep-0045.html\nXMPP通过Instant room和Reserved rooms创建多人聊天。\n步骤1.创建MultiUserChat实例，聊天室名称通过构造方法创建给要创建的聊天室\n步骤2.调用MultiUserChat的create（String nickName）方法，在这里nickname是用户加入聊天室的用户昵称\n步骤3.创建一个Instant room，调用sendConfigurationFrom（From form）方法，在这里表单是一个空表单，创建一个Reserved room应该首先获得聊天室的配置表单，完成表单将发送回服务器。\n创建Instant room核心代码\n//使用XMPPConnection创建一个MultiUserChat\ntry{\n//初始化MultiUserChat对象\nMultiUserChat muc=new MultiUserChat(mXMPPConnection,”newroom1@confenrence.stonechen”);\n//创建聊天室\nmuc.create(“newroom1″);\n//发送一个空表单配置，这显示我们想要一个Instant room\nmuc.sendConfigurationForm(new Form(Form.TYPE_SUBMIT));\n}catch(XMPPException e){\n}\n创建reserved room\ntry{\n//初始化MultiUserChat对象\nMultiUserChat muc=new MultiUserChat(mXMPPConnection,”newroom2@confenrence.stonechen”);\n//创建聊天室\nmuc.create(“newroom2”);\n//获得聊天室的配置表单\nForm form=muc.getConfigurationForm();\n//根据原始表单穿件一个要提交的新表单\nForm submitForm=form.createAnswerForm();\n//向要提交的表单添加默认答复\nfor(Interator fields=form.getFields();fields.hasNext()){\nFormField field=(FormField) fields.next();\nif(!FormField.TYPE_HIDDEN.equals(fields.getType())\u0026amp;\u0026amp;field.getVariable()!=null){\n//设置默认值作为答复\nsubmitForm.setDefaultAnswer(field.getVariable());\n}\n}\n//设置聊天室的新拥有者\nList oweners=new ArrayList();\noweners.add(“NewUser@stonechen”);\nsubmitForm.setAnswer(“muc#foomconfig_roomowners”,oweners);\n//发送已完成的表单（有默认值）到服务器来配置聊天室\nmuc.sendConfigurationForm(submitForm);\n}catch(XMPPException e){\n}\n注意：更多问题参考官方网站http://community.igniterealtime.org/htread/31118\n加入聊天室\n步骤1.创建一个MultiUserChat的实例，把要加入的聊天室的名称传递给构造方法。\n步骤2.嗲用MultiUserChat的join方法。如果想要加入需啊哟密码才能加入的聊天室使用join(nickname,password);\n//使用XMPPConnection创建一个MultiUserChat\nMultiUserChat muc2=new MultiUserChat(connl,”newroom@conference.stonchen”);\n//加入\nmuc2.join(“user2”);\n//muc2.join(“user2″,password);\n发送和技术消息\ntry{\n//使用XMPPConnection创建一个MultiUserChat\nMultiUserChat muc2=new MultiUserChat(connl,”newroom@conference.stonchen”);\n//用户加入新聊天室，参数为用户的聊天室的昵称\nmuc2.join(“newMucUser”);\nMessage newMessage=muc2.createMessage();\n//设置聊天信息\nnewMessage.setBody(“Hello MUC!”);\n//发送聊天信息\nmuc1.sendMessage(newMessage);\n}catch(XMPPException e){\n}\n接收消息\n//使用XMPPConnection创建一个MultiUserChat\nMultiUserChat muc2=new MultiUserChat(connl,”newroom@conference.stonchen”);\ntry{\n//用户加入新聊天室，参数为用户的聊天室的昵称\nmuc2.join(“newMucUser”);\n}catch(XMPPException e){\n}\n//添加监听\nmuc2.addMessageListener(new PacketListenr(){\npublic void processPacket(Packet packet){\n//此处对收到的消息进行处理\nLog.e(“processPacket message”,packet.toXML());\n}\n}):\n转载注明：http://www.etongwl.com/?p=651\n","permalink":"https://blog.zdltech.com/posts/xmpp-android%E5%9F%BA%E7%A1%80%E4%BB%8B%E7%BB%8D/","summary":"\u003cp\u003eXMPP Android基础介绍\u003c/p\u003e\n\u003cp\u003e在android中使用到的库为Asmack（下载地址：http://code.google.com/p/asmack/）\u003c/p\u003e\n\u003cp\u003eAsmack的相关介绍\u003cbr\u003e\n1.ConnectionConfiguration 通过该类设置用于与XMPP服务器建立连接的配置。它能配置连接是否使用TLS、SASL加密等\u003cbr\u003e\n2.XMPPConnection 通过该类连接XMPP服务。通过connect()建立连接disconnect（）断开连接\u003cbr\u003e\n3.ChatManager 用于监控当前所有Chat，可以使用createChat（String userJID,MessageListener listener）创建一个聊天\u003cbr\u003e\n4.Chat 用于监控两个用户间的一系列消息。使用addMessageListener（MessageListener listener），当有任何消息到达时将会触发listener的processMessage（Chat chat,Message msg）方法。\u003cbr\u003e\n5.Message 用来表示一个消息包。Message有2个内部类Message.Body表示消息体，Message.Type消息类型\u003cbr\u003e\n（1）Message.Type.NORMAL 默认文本消息\u003cbr\u003e\n（2）Message.Type.CHAT 典型的短消息，如QQ聊天时一行一行的显示消息\u003cbr\u003e\n（3）Message.Type.GROUP_CHAT 群聊消息\u003cbr\u003e\n（4）Message.Type.HEADLINE 滚动显示消息\u003cbr\u003e\n（5）Message.Type.ERROR 错误消息\u003cbr\u003e\n6.Roster 表示存储了一个花名册，其中包含很多RosterEntry。为了易于管理，花名册的项被分配到了各个group中，当建立与XMPP服务的连接后可以使用connection.getRoster()获得Roster对象。别的用户可以使用一个订阅请求（相当于QQ添加好友）尝试订阅目的用户。可以使用Roster.SubscriptionMode的值处理这些请求，accept_all表示接收所有订阅请求，reject_all表示拒绝所有订阅请求，manual表示手工处理订阅请求。\u003cbr\u003e\n//创建组的方法\u003cbr\u003e\nRosterGroup group=roster.createGroup(“同事”);\u003cbr\u003e\n//可以向组中添加RosterEntry对象\u003cbr\u003e\ngroup.addEntry(entry);\u003cbr\u003e\n7.RosterGroup表示Roster中的每条记录，它包含了用户的JID、用户名、用户分配的昵称。\u003cbr\u003e\n8.RosterGroup表示RosterEntry的组。可以使用addEnty(RosterEntry entry)添加，contains(String user)判读某用户是在组中，removeEntry(RosterEnty entry)从组中移除，getEntries()获取所有RosterEntry\u003cbr\u003e\n9.Presence表示XMPP状态的packet，每个presence packet都是一个状态，用户枚举类型Presence.Type的值表示。\u003cbr\u003e\nPresence.Type值\u003cbr\u003e\n（1）available 用户空闲状态\u003cbr\u003e\n（2）unavailable 用户没空看消息\u003cbr\u003e\n（3）subscribe 请求定义别人，即请求加对方为好友\u003cbr\u003e\n（4）subscribed 统一被别人订阅，也就是确认被对方加为好友\u003cbr\u003e\n（5）unsubscribe 取消订阅别人，请求删除某好友\u003cbr\u003e\n（6）unsubscribed 拒绝被别人订阅，即拒绝对方的添加请求\u003cbr\u003e\n（7） error 当前状态packet有错误\u003cbr\u003e\n登陆XMPP服务器\u003cbr\u003e\n首先创建用户，然后建立与XMPP服务器的连接，最后使用用户登陆到XMPP服务器\u003cbr\u003e\n//指定连接到服务器的参数\u003cbr\u003e\nConnectionConfiguration mConnectionConfiguration=new ConnectonConfiguration(“192.168.1.105”,5222);\u003cbr\u003e\n//初始化XMPPconnection连接\u003cbr\u003e\nXMPPConnection mXMPPConnection=new XMPPConnection(mConnectionConfiguration);\u003cbr\u003e\n//连接上XMPP服务器\u003cbr\u003e\ntry{\u003cbr\u003e\nmXMPPConnection.connect();\u003cbr\u003e\n//实例化用户管理\u003cbr\u003e\nAccountManager mAccountManager=mXMPPConnection.getAccountManager();\u003cbr\u003e\n//用指定的用户名和密码创建用户\u003cbr\u003e\nmAccountManager.createAccount(‘zhang’,’123456′);\u003cbr\u003e\n}catch(XMPPException e){\u003c/p\u003e","title":"XMPP Android基础介绍"},{"content":"基于SIP协议的VOIP\nSIP（Session Initiation Protocol，会话发起协议）是一个应用层协议，用用建立、修改和终止包括视频、语音、即时通信、在线游戏和虚拟现实等多种多媒体元素在内的交互式用户会话。\n在开发视频会议、即时消息等应用程序的时候可能用户到Android SIP API\nAndroid SIP应用程序必要条件\n1.必须运行在Android2.3以上系统\n2.SIP是通过无线数据连接来运行的，所以设备必须有一个数据连接（wifi或者移动网络）\n3.必须有一个SIP账户。\nSIP服务器搭建\n高效的SIP服务器有很多，这里介绍Brekeke SIP Server下载地址：(国内打不开请翻墙)http://www.brekeke.com/downloads/sip-server.php\n更多服务器参考http://www.officesip.com/、http://www.kamailio.org/\n安装配置大家自己安装不同服务器配置不同，自行配置。(http://wenku.baidu.com/link?url=hUh_ICcJ6C_S0ru9ygE5jzt9CJb9Xs3NHfz2kWsRdunB3ArX3abB-w4YlsIuxWDayM3ZQq8oPqudP4Lk9CoAK6W5wuqK87AQCPgavgCODre)\nSIP程序设置\n主要类android.net.sip包中，其中最重要的是SipManager类\nandroid SIP API中类和接口\n1.SipAudioCall 通过SIP处理网络音频电话\n2.SipAudioCall.Listener 关于SIP电话的事件监听器，比如接到一个电话或者呼出一个电话的时候\n3.SipErrorCode 定义在SIP活动中返回的错误代码\n4.SipManager 为SIP任务提供API，比如初始化一个SIP连接，提供相关SIP服务的访问\n5.SipProfile 定义了SIP相关属性，包括SIP账户、域名和服务器信息\n6.SipProfile.Builder 创建SipProfile的帮助类\n7.SipSession 代表一个SIP会话，跟SIP对话或者一个没有对话框的独立事务相关联\n8.SipSession.Listener 关于SIP会话的事件监听器，比如注册一个会话或者呼出一个电话的时候\n9.SipSession.State 定义SIP会话的声明，比如 注册、呼出电话、打入电话\n10.SipRegisterationListener 一个关于SIP注册事件监听器的接口\nAndroid权限列表\n//访问网络\n//使用SIP连接\n//访问WIFI状态\n//允许程序在手机屏幕关闭后后天进程仍然运行\n//允许通过手机或者耳机的麦克录制声音\n不是所有的设备支持SIP，确保APP只安装在支持SIP的设备上，程序中使用下面代码检测\n//检测当前设备是否支持VOIP通话\nBoolean voipSupported=SipManager.isVoipSupported(this);\n//检测当前设备是否支持SIP的API\nBoolean apiSupport=SipManager.isApiSupported(this);\n添加在Manifest中，不支持SIP的设备在市场过滤掉（Google play）\n在应用Manifest中定义一耳光广播接收器，接收呼叫\n\u0026lt;receiver android:name=”.IncomingCallReceiver” android:lable=”Call Receiver”/\u0026gt;\nSIP初始化通话\n//创建空的SipManager对象\npublic SipManager mSipManager=null;\n//检测当前SipManager是否为空\nif(mSipManager==null){\nmSipManager=SipManager.newInstance(this);\n}\n创建SipProfile\n//创建SipProfile对象\npublic SipProfile mSipProfile=null;\n//使用用户名和服务器地址做为参数\nSipProfile.Builder builder=new SipProfile.Builder(username,domain);\n//给出密码\nbuilder.setPassword(password);\n//实例化SipProfile对象\nmSipProfile=builder.build();\n接下来设置一个标签为android.SipDemo.INCOMING_CALL的意图，这个意图会被一个意图过滤器使用\nIntent intent=new Intent();\nintent.setAction(“android.SipDemo.INCOMING_CALL”);\n//使用PendingIntent对象延后调用\nPendingIntent pendingIntent=PendingIntent.getBroadcast(this,0,intent,Intent.Fill_IN_DATA)；\n//调用方法处理意图\nmSipManager.open(mSipProfile,pendingintent，null);\n在SipManager上设置 一个SipRegisterationListener监听器，这个监听器会跟踪SipProfile，来确定是否成功地注册到SIP服务器\nmSipManager.setRegistrationListener(mSipProfile.getUriString(),new SipRegistrationListener(){\npublic void onRegistrationListener(String localProfileUri){\n//正在和SIP服务器通信\nupdateStatus(“Registering with SIP Server…”);\n}\npublic void onRegistrationDone(String localProfileUri，long expiryTime){\n//在SIP服务器上注册成功\nupdateStatus(“Ready”);\n}\npublic void onRefistrationFailed(String localProfileUri,int errorCode,String errorMessage){\n//在SIP服务器上注册失败\nupdateStatus(“Registration failed,Please check settings.”);\n}\n});\n//注销当前设备\npublic void closeLocalProfile(){\n//检测SipManager对象是否为空\nif(mSipManager==null){//如果为空，则不进行热乎操作，直接返回\nreturn;\n}else{\ntry{\n//不为空的情况\nif(mSipProfile!=null){\n//关闭相关对象\nmSipManager.close(mSipProfile.getUriString());\n}\n}catch(Exception e){\n}\n}\n}\n监听SIP通话\n大部分客户与SIP堆栈的交互都是通过监听器来完成的，所以在拨打SIP语音大户的时候，需要建立一个SipAudioCall.Listener监听器\n//创建一个新的SipAudioCall.Listener监听器\nSipAudioCall.Listener listener=new SipAudioCall.Listener(){\npublic void onCallEstablished(SipAudioCall call){\n//对已经建立的呼叫启动音频\ncall.startAudio();\n//设备设置为扬声器模式\ncall.setSpeakerMode(true);\n//静音切换\ncall.toggleMute();\n}\n//会话终止时候调用\npublic void onCallEnded(SipAudioCall call){\n}\n}\n拨打电话\n一旦创建了SipAudioCall.Listener监听器，就可以拨打电话了，需要用到SipAudioCall的makeAudioCall方法\n//拨打电话\nmakeAudioCall(SipProfile localProfile,SipProfile peerProfile,SipAudioCall.Listener listener,int timeout)\n参数localProfileUri代表本地SIP配置文件（呼叫方），peerProfile为相应的Sip配置文件（被呼叫方）；listener用来监听SipAudioCall发财的呼叫事件，这个参数可以为null，timeout是超时时间，以秒为单位。\ncall=mSipManger.makeAudioCall(mSipProfile.getUriString(),sipAddress,listener,30);\n接收呼叫\n为了接收呼叫，SIP应用程序必须包含一个BroadcastReceiver的子类，这个子类有能力响应一个表明有来电的Intent\n当Android系统接收到一个呼叫的时候，会处理这个SIP呼叫，然后广播一个来的的Intent。\n（详细内容参考：深入理解Android网络编程 技术详解与最佳实践）\n待续。。。\n转载注明：http://www.etongwl.com/?p=648\n","permalink":"https://blog.zdltech.com/posts/%E5%9F%BA%E4%BA%8Esip%E5%8D%8F%E8%AE%AE%E7%9A%84voip/","summary":"\u003cp\u003e基于SIP协议的VOIP\u003cbr\u003e\nSIP（Session Initiation Protocol，会话发起协议）是一个应用层协议，用用建立、修改和终止包括视频、语音、即时通信、在线游戏和虚拟现实等多种多媒体元素在内的交互式用户会话。\u003c/p\u003e\n\u003cp\u003e在开发视频会议、即时消息等应用程序的时候可能用户到Android SIP API\u003c/p\u003e\n\u003cp\u003eAndroid SIP应用程序必要条件\u003cbr\u003e\n1.必须运行在Android2.3以上系统\u003cbr\u003e\n2.SIP是通过无线数据连接来运行的，所以设备必须有一个数据连接（wifi或者移动网络）\u003cbr\u003e\n3.必须有一个SIP账户。\u003cbr\u003e\nSIP服务器搭建\u003cbr\u003e\n高效的SIP服务器有很多，这里介绍Brekeke SIP Server下载地址：(国内打不开请翻墙)http://www.brekeke.com/downloads/sip-server.php\u003cbr\u003e\n更多服务器参考http://www.officesip.com/、http://www.kamailio.org/\u003cbr\u003e\n安装配置大家自己安装不同服务器配置不同，自行配置。(\u003ca href=\"http://wenku.baidu.com/link?url=hUh\"\u003ehttp://wenku.baidu.com/link?url=hUh\u003c/a\u003e_ICcJ6C_S0ru9ygE5jzt9CJb9Xs3NHfz2kWsRdunB3ArX3abB-w4YlsIuxWDayM3ZQq8oPqudP4Lk9CoAK6W5wuqK87AQCPgavgCODre)\u003c/p\u003e\n\u003cp\u003eSIP程序设置\u003cbr\u003e\n主要类android.net.sip包中，其中最重要的是SipManager类\u003c/p\u003e\n\u003cp\u003eandroid SIP API中类和接口\u003cbr\u003e\n1.SipAudioCall 通过SIP处理网络音频电话\u003cbr\u003e\n2.SipAudioCall.Listener 关于SIP电话的事件监听器，比如接到一个电话或者呼出一个电话的时候\u003cbr\u003e\n3.SipErrorCode 定义在SIP活动中返回的错误代码\u003cbr\u003e\n4.SipManager 为SIP任务提供API，比如初始化一个SIP连接，提供相关SIP服务的访问\u003cbr\u003e\n5.SipProfile 定义了SIP相关属性，包括SIP账户、域名和服务器信息\u003cbr\u003e\n6.SipProfile.Builder 创建SipProfile的帮助类\u003cbr\u003e\n7.SipSession 代表一个SIP会话，跟SIP对话或者一个没有对话框的独立事务相关联\u003cbr\u003e\n8.SipSession.Listener 关于SIP会话的事件监听器，比如注册一个会话或者呼出一个电话的时候\u003cbr\u003e\n9.SipSession.State 定义SIP会话的声明，比如 注册、呼出电话、打入电话\u003cbr\u003e\n10.SipRegisterationListener 一个关于SIP注册事件监听器的接口\u003c/p\u003e\n\u003cp\u003eAndroid权限列表\u003cbr\u003e\n//访问网络\u003cbr\u003e\n\u003cuses-permission android:name=\u0026#8221;android.permission.INTERNET\u0026#8221;/\u003e\u003cbr\u003e\n//使用SIP连接\u003cbr\u003e\n\u003cuses-permission android:name=\u0026#8221;android.permission.USE_SIP\u0026#8221;/\u003e\u003cbr\u003e\n//访问WIFI状态\u003cbr\u003e\n\u003cuses-permission android:name=\u0026#8221;android.permission.ACCESS\\_WIFI\\_STATE\u0026#8221;/\u003e\u003cbr\u003e\n//允许程序在手机屏幕关闭后后天进程仍然运行\u003cbr\u003e\n\u003cuses-permission android:name=\u0026#8221;android.permission.WAKE_LOCK\u0026#8221;/\u003e\u003cbr\u003e\n//允许通过手机或者耳机的麦克录制声音\u003cbr\u003e\n\u003cuses-permission android:name=\u0026#8221;android.permission.RECORD_AUDIO\u0026#8221;/\u003e\u003c/p\u003e\n\u003cp\u003e不是所有的设备支持SIP，确保APP只安装在支持SIP的设备上，程序中使用下面代码检测\u003cbr\u003e\n//检测当前设备是否支持VOIP通话\u003cbr\u003e\nBoolean voipSupported=SipManager.isVoipSupported(this);\u003cbr\u003e\n//检测当前设备是否支持SIP的API\u003cbr\u003e\nBoolean apiSupport=SipManager.isApiSupported(this);\u003c/p\u003e\n\u003cp\u003e添加\u003cuses-feature android:name=\u0026#8221;android.hardware.sip.voip\u0026#8221; android:required=\u0026#8221;true\u0026#8221;/\u003e在Manifest中，不支持SIP的设备在市场过滤掉（Google play）\u003c/p\u003e","title":"基于SIP协议的VOIP"},{"content":"Android Wi_Fi编程\nwi-Fi又称802.11b标准\n在android.net.wifi包中提供了一些类管理设备的WiFi功能，主要包括ScanResult、WiFiConfiguration、WiFiInfo和wifiManager\n1.ScanResult类\n主要通过WiFi硬件的扫描来获取一些周边的WiFi热点的信息。（该类包括5个域）\n（1）BSSID 接入点的地址。\n（2）SSID 网络的名字。\n（3）capabilities 网络性能，包括接入点支持的认证、密钥管理、加密机制。\n（4）frequency 以Mhz为单位的接入频率\n（5）level 以dBm为单位的信号强度\n2.wifiConfiguration类\nWiFi的网络配置，包括安全配置等。包括6个子类\n（1）WifiConfiguration.AuthAlgorthm 获取IEEE802.11的加密方法\n（2）Wificonfiguration.GroupCipher 获取组密钥\n（3）wificonfiguration.KeyMgmt 获得密码管理体制\n（4）WiFiConfiguration.PairwiseCipher 获取WPA方式的成对密钥\n（5）WiFiConfiguration.Protocol 获取加密协议\n（6）WiFiConfiguration.Status获取当前网络状态\n3.WifiInfo类\n通过该类可以获得已经建立的或者处于活动状态的WiFi网络的状态信息。\n4.WifiManger类\n管理WiFi连接，其中定义了26个常量和23个方法。WifiManagerLock的作用为：在普通的状态下，如果WiFi的状态处于闲置，那么网络将会暂时中断，但是如果把当前的网络状态锁上，那么WiFi连通将会保持在一定状态，在结束锁定之后，才会恢复常态。\nWiFi直连API\nWifiPpManager类提供了很多方法允许用户通过设备的WiFi模块来进行交互。\nNFC API简介\nandroid对NFC的支持主要在android.nfc包中。包括类NFcAdapter、NdefMessage\n1.NFCAdapter代表设备上的NFC硬件。\n2.NdefMessage代表一个NDEF数据信息，NDEF（NFC Data Exchange Format）是设备与标签传输数据的标准格式。\nandroid NFC基本工作流程如下：\n步骤1：通过android.nfc.NfcAdapter.getDefaultAdapter()取得手机的objNfcAdapter\n步骤2：通过objNfcAdapter.isEnabled()查询手机是否支持NFC\n步骤3：如果手机支持NFC，手机内置的NFC扫描器（相当于NFCAdapter）扫描到电子标签后，就会想程序发送ACTION_TAG_DISCOVERED的Intent，Intent的extras机构中会包含NDEF。\n步骤4：如果接收到ACTION_TAG_DISCOVERED，就提取NdefMessage，并在此基础上进行提取NdefRecord\n在使用NFC API的时候，应用必须在AndroidMinifest.xml中声明获取使用权限最新SDK为10\n申请市场过滤\n转载注明： http://www.etongwl.com/?p=645\n","permalink":"https://blog.zdltech.com/posts/android-wi_fi%E7%BC%96%E7%A8%8B/","summary":"\u003cp\u003eAndroid Wi_Fi编程\u003cbr\u003e\nwi-Fi又称802.11b标准\u003cbr\u003e\n在android.net.wifi包中提供了一些类管理设备的WiFi功能，主要包括ScanResult、WiFiConfiguration、WiFiInfo和wifiManager\u003c/p\u003e\n\u003cp\u003e1.ScanResult类\u003cbr\u003e\n主要通过WiFi硬件的扫描来获取一些周边的WiFi热点的信息。（该类包括5个域）\u003cbr\u003e\n（1）BSSID 接入点的地址。\u003cbr\u003e\n（2）SSID 网络的名字。\u003cbr\u003e\n（3）capabilities 网络性能，包括接入点支持的认证、密钥管理、加密机制。\u003cbr\u003e\n（4）frequency 以Mhz为单位的接入频率\u003cbr\u003e\n（5）level 以dBm为单位的信号强度\u003c/p\u003e\n\u003cp\u003e2.wifiConfiguration类\u003cbr\u003e\nWiFi的网络配置，包括安全配置等。包括6个子类\u003cbr\u003e\n（1）WifiConfiguration.AuthAlgorthm 获取IEEE802.11的加密方法\u003cbr\u003e\n（2）Wificonfiguration.GroupCipher 获取组密钥\u003cbr\u003e\n（3）wificonfiguration.KeyMgmt 获得密码管理体制\u003cbr\u003e\n（4）WiFiConfiguration.PairwiseCipher 获取WPA方式的成对密钥\u003cbr\u003e\n（5）WiFiConfiguration.Protocol 获取加密协议\u003cbr\u003e\n（6）WiFiConfiguration.Status获取当前网络状态\u003c/p\u003e\n\u003cp\u003e3.WifiInfo类\u003cbr\u003e\n通过该类可以获得已经建立的或者处于活动状态的WiFi网络的状态信息。\u003c/p\u003e\n\u003cp\u003e4.WifiManger类\u003cbr\u003e\n管理WiFi连接，其中定义了26个常量和23个方法。WifiManagerLock的作用为：在普通的状态下，如果WiFi的状态处于闲置，那么网络将会暂时中断，但是如果把当前的网络状态锁上，那么WiFi连通将会保持在一定状态，在结束锁定之后，才会恢复常态。\u003c/p\u003e\n\u003cp\u003eWiFi直连API\u003cbr\u003e\nWifiPpManager类提供了很多方法允许用户通过设备的WiFi模块来进行交互。\u003c/p\u003e\n\u003cp\u003eNFC API简介\u003cbr\u003e\nandroid对NFC的支持主要在android.nfc包中。包括类NFcAdapter、NdefMessage\u003cbr\u003e\n1.NFCAdapter代表设备上的NFC硬件。\u003cbr\u003e\n2.NdefMessage代表一个NDEF数据信息，NDEF（NFC Data Exchange Format）是设备与标签传输数据的标准格式。\u003c/p\u003e\n\u003cp\u003eandroid NFC基本工作流程如下：\u003cbr\u003e\n步骤1：通过android.nfc.NfcAdapter.getDefaultAdapter()取得手机的objNfcAdapter\u003cbr\u003e\n步骤2：通过objNfcAdapter.isEnabled()查询手机是否支持NFC\u003cbr\u003e\n步骤3：如果手机支持NFC，手机内置的NFC扫描器（相当于NFCAdapter）扫描到电子标签后，就会想程序发送ACTION_TAG_DISCOVERED的Intent，Intent的extras机构中会包含NDEF。\u003cbr\u003e\n步骤4：如果接收到ACTION_TAG_DISCOVERED，就提取NdefMessage，并在此基础上进行提取NdefRecord\u003c/p\u003e\n\u003cp\u003e在使用NFC API的时候，应用必须在AndroidMinifest.xml中声明获取使用权限\u003cuses-permission android:name=\u0026#8221;android.permission.NFC\u0026#8221;\u003e最新SDK为10\u003cbr\u003e\n申请市场过滤\u003cuses-feature android:name=\u0026#8221;android.hardware.nfc\u0026#8221; android:required=\u0026#8221;true\u0026#8221; \u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e转载注明： \u003cspan id=\"sample-permalink\" tabindex=\"-1\"\u003e\u003ca href=\"http://www.etongwl.com/?p=645\"\u003ehttp://www.etongwl.com/?p=645\u003c/a\u003e\u003c/span\u003e\u003c/p\u003e","title":"Android Wi_Fi编程"},{"content":"USB编程\nUSB编程分为USB HOST(主机模式)和USB Accessory（配件模式）\nUSB相关操作的类都集中在android.hardware.usb命名空间中\n1.USB Accessory API简介\n配件模式中两个重要的类：UsbAccessory和UsbMnanger，其中通过UsbManager可以获得USB状态信息，并负责和USB配件进行通信；UsbAccessory代表一个USB配件并且包含获取配件特定信息的方法。\n定义UsbManager对话和UsbAccessory对象的方法.\n通过Context.USB_SERVICE可以实例化UsbManager对象\nUsbManager manager=（UsbManager）getSystemService(Context.USB_SERVICE);\n通过以下方式获取UsbAccessory对象\nUsbAccessory accessory=(UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);\n2.Android manifest文件配置\n因为不是所有的设备都支持USB accessory API需要在manifest中使用元素声明应用支持它，值为：android.hardware.usb.accessory.支持的最小的api是API Level 12。\n如果希望应用在USB配件连接时能够接收通知，则在主Activity中需要为android.hardware.usb.action.USB_ACCESSORY_ATTACHED这个Intent中指定一对和。\n元素指向里一个xml资源文件，该文件包含希望得到的配件的一些特定信息。\n这个XML资源文件中为希望过滤的配件声明元素。每一个都可以包含“制造商”、“模式”和“版本”这3个属性。资源文件要保存在res/xml/目录下，资源文件的名称必须和在元素中指定的名称相同。\n例如：\nandroid manifest文件\n\u0026lt;manifest ….\u0026gt;\n…\n\u0026lt;activity …\u0026gt;\n…\nres/xml/有个xml文件accessory_filter.xml\n\u003c?xml version=\u0026#8221;1.0\u0026#8243; encoding=\u0026#8221;utf-8\u0026#8243;?\u003e 配件使用\n1.通过一个可以过滤配件附加事件的意图过滤器来找到合适的连接配件，或者枚举所有已连接的配件来找到合适的某个配件\n2.尚未获得许可的用户在与配件通信前需要获得权限\n3.通过合适的端口与配件进行读写通信\n用户可以通过两种方式发现配件：一种是使用Intent过滤器在用户连接配件时对其进行通知，另一种通过枚举已经连接的所有配件。\n意图过滤使用android.hardware.usb.action.USB_ACCESSORY_ATTACHED指定一个意图进行过滤。在这个意图过滤中需要指定一个资源文件来特别说明这个usb配件的属性，例如制造商、模式和版本，当连接的配件和意图过滤条件匹配时，应用会收到一个通知。\n在Activity中可以通过以下方式获得UsbAccessory，它代表了所有连接的配件\nUsbAccessory accessory=(UsbAccessroy) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);\n枚举所有支持的配件\n当应用在运行的时候，可以在应用中枚举所有能够识别的配件。通过getAccessoryList()方法获得一个包含所有已连接USB配件的数组\nUsbManager manager=(UsbManager) getSystemService(Content.USB_SERVICE);\nUsbAccessory[] accessoryList=mamager.getAccessoryList();\n注意：目前一次只能连接一个USB配件，但是这个API设计的在未来可用于支持多个配件\n获得与某个配件通信的权限\n在与某个USB配件通信前，应用必须从用户那里获得权限\n注意：如果应用在连接配件时是通过一个意图过滤器来发现它们，而用户允许应用来处理这个意图时，它将自动获得权限，如果用户不允许，那么久必须在与配件通信前明确的在应用中请求获得权限。\n为了获得权限，首页需要创建一个广播接收器，在调用requestPermission()方法是，这个接收器会监听广播中的意图。通过调用requestPermisson()方法为 用户弹出一个获取权限对话框。\n例子：\n//定义权限字符串\nprivate static final String ACTION_USB_PERMISSION=”com.android.example.USB_PERMISSION”;\n//新建广播接收器\nprivate final BroadcastReceiver mUsbReceiver=new BroadcastReceiver(){\npublic void onReceive(Context context,Intent intent){\n//获得当前Intent的权限字符串\nString action=intent.getAction();\n//判断权限是否和定义的相同\nif(ACTION_USB_PERMISSION.equals(action)){\nsynchroized(this){\n//声明UsbAccessory对象\nUsbAccessory accessory=(UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);\nif(intent.getBooleanExtra(UsbManager.EXTRA_PERAMISSION_GRANTED,false)){\nif(accessory!=null){\n//调用方法建立与某个配件的通信\n}\n}else{\n//没有获取权限\n}\n}\n}\n}\n}\n为了注册广播接收器，需要将下面代码放到activity中的onCreate（）方法中\n//获得系统服务对象\nUsbManager mUsbManage=(UsbManager)getSystemService(Context.USB_SERVICE);\n//定义权限字符串\nprivate static final String ACTION_USB_PERMISSION=”com.android.example.USB_PERMISSION”;\n…\n//稍后处理配件通信事件\nmPermissionIntent=PendingIntent.getBroadcast(this,0,new Intent(ACTION_USB_PERMISSION),0);\n//新建过滤器\nIntentFilter filter=new IntentFilter(ACTION_USB_PERMISSION);\n//注册接收器\nregisterReceiver(mUsbReceiver,filter);\n//当需要弹出获取权限的对话框时，则要调用requestPermission()方法\nUsbAccessory accessory;\n…\nmUsbManager.requestPermission(accessory,mPermissionIntent);\n与配件通信\n可以通过使用UsbManager这个类与配件进行通信，通过这个类可以获得一个文件描述符，然后可以利用该描述符设置输入和输出流来读取和写入数据。这些流用来代表输入和输出的批量端口。最好另外建立一个线程来让设备与配件进行通信，因为这样就可以不需要把主线程锁起来了。\n列如：\n//新建UsbAccessory对象\nUsbAccessory mAccessory；\n//新建ParelFileDescriptor对象\nParcelFileDescriptor mFileDescriptor；\nFileInputStream mInputStream;\nFileOutputStream mOutputStream;\n…\n//打开通信\nprivate void openAccessory(){\n//获取设备文件描述\nmFileDescriptor=mUsbmanager.openAccessory(mAccessory);\n//设备文件描述不为null\nif(mFileDescriptor!=null){\n//获取文件描述\nFileDescriptor fd=mFileDescriptor.getFileDescriptor();\nmInputStream=new FileInputStream(fd);\nmOutputStream=new FileOutputStream(fd);\n//打开新线程\nThread thread=new Thread(null,this,”AccessoryThread”);\n//启动线程\nthread.start();\n}\n}\n在这个线程run（）方法中，可以通过FileInputStream或者FileOutputStream对象来对配件进行读写操作。Android配件协议支持高达16384字节的数据包缓存区，所以设置缓冲字节16384。\n终止与配件的通信\n当完成与配件的通信之后，或则该配件被移除了，通过调用close（）方法来关闭已打开的文件描述符。为了监听分离这样的事件，需要创建广播接收器。\n//新建监听\nBroadcastReceiver mUsbReceiver=new BroadcastReceiver(){\npublic void onReceive(Context context,Intent intent){\n//获取事件字符串\nString action=intent.getAction();\n//对比师父为需要处理的事件权限\nif(UsbMangaer.ACTION_USB_ACCESSORY_DETACHED.equals(action)){\n//新建UsbAccessory对象\nUsbAccessory accessory=（UsbAccessory）intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);\nif(accessory!=null){\n//嗲用方法终止与配件的通信，清理内容\n}\n}\n}\n};\n要在应用中创建这个广播接收器，而不是在manifest文件中创建，且允许应用智能在其运行的时候处理这样的配件分离事件。这样的话，配件分离这个事件就只向在正在运行的应用广播，而不是向所有的应用进行广播。\nUSB Host Mode\n当android设备工作在浙江模式下的时候，Android设备作为主机，为USB总线供电并与USB设备进行通信。同样仅在android3.1以上版本支持这种模式。主机模式使用步骤和配件模式类似。\n相关类 1.UsbManager 2.UsbDevice（代表一个USB设备）3.UsbInterface（usb设备的一个接口） 4.USBEndpoint（代表一个接口的摸个端口类） 5.UsbDeviceConnection（USB连接类，用此连接可以向USB设备传输数据）\n转载注明：http://www.etongwl.com/?p=642\n","permalink":"https://blog.zdltech.com/posts/android-usb%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/","summary":"\u003cp\u003eUSB编程\u003cbr\u003e\nUSB编程分为USB HOST(主机模式)和USB Accessory（配件模式）\u003cbr\u003e\nUSB相关操作的类都集中在android.hardware.usb命名空间中\u003c/p\u003e\n\u003cp\u003e1.USB Accessory API简介\u003cbr\u003e\n配件模式中两个重要的类：UsbAccessory和UsbMnanger，其中通过UsbManager可以获得USB状态信息，并负责和USB配件进行通信；UsbAccessory代表一个USB配件并且包含获取配件特定信息的方法。\u003cbr\u003e\n定义UsbManager对话和UsbAccessory对象的方法.\u003cbr\u003e\n通过Context.USB_SERVICE可以实例化UsbManager对象\u003cbr\u003e\nUsbManager manager=（UsbManager）getSystemService(Context.USB_SERVICE);\u003cbr\u003e\n通过以下方式获取UsbAccessory对象\u003cbr\u003e\nUsbAccessory accessory=(UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);\u003cbr\u003e\n2.Android manifest文件配置\u003cbr\u003e\n因为不是所有的设备都支持USB accessory API需要在manifest中使用\u003cuses-feature\u003e元素声明应用支持它，值为：android.hardware.usb.accessory.支持的最小的api是API Level 12。\u003cbr\u003e\n如果希望应用在USB配件连接时能够接收通知，则在主Activity中需要为android.hardware.usb.action.USB_ACCESSORY_ATTACHED这个Intent中指定一对\u003cintent-filter\u003e和\u003cmeta-data\u003e。\u003cbr\u003e\n\u003cmeta-data\u003e元素指向里一个xml资源文件，该文件包含希望得到的配件的一些特定信息。\u003cbr\u003e\n这个XML资源文件中为希望过滤的配件声明\u003cusb-accessory\u003e元素。每一个\u003cusb-accessory\u003e都可以包含“制造商”、“模式”和“版本”这3个属性。资源文件要保存在res/xml/目录下，资源文件的名称必须和在\u003cmeta-data\u003e元素中指定的名称相同。\u003cbr\u003e\n例如：\u003cbr\u003e\nandroid manifest文件\u003cbr\u003e\n\u0026lt;manifest ….\u0026gt;\u003cbr\u003e\n\u003cuses-feture android:name=\u0026#8221;android.hardware.usb.accessory\u0026#8221;/\u003e\u003cbr\u003e\n\u003cuses-sdk android:minSdkVersion=\u0026#8221;12\u0026#8243;/\u003e\u003cbr\u003e\n…\u003cbr\u003e\n\u003capplication\u003e\u003cbr\u003e\n\u003cuses-library android:name=\u0026#8221;com.android.future.usb.accessory\u0026#8221; /\u003e\u003cbr\u003e\n\u0026lt;activity …\u0026gt;\u003cbr\u003e\n…\u003cbr\u003e\n\u003cintent-filter\u003e\u003cbr\u003e\n\u003caction android:name=\u0026#8221;android.hardware.usb.action.USB\\_ACCESSORY\\_ATTACHED\u0026#8221;/\u003e\u003cbr\u003e\n\u003c/intent-filter\u003e\u003cbr\u003e\n\u003cmeta-data android:name=\u0026#8221;android.hardware.usb.action.USB\\_ACCESSORY\\_ATTACHED\u0026#8221; android:resource=\u0026#8221;@accessory_filter\u0026#8221;/\u003e\u003cbr\u003e\n\u003c/activity\u003e\u003cbr\u003e\n\u003c/application\u003e\u003cbr\u003e\n\u003c/manifest\u003e\u003cbr\u003e\nres/xml/有个xml文件accessory_filter.xml\u003c/p\u003e\n\u003c?xml version=\u0026#8221;1.0\u0026#8243; encoding=\u0026#8221;utf-8\u0026#8243;?\u003e  \n\u003cresources\u003e  \n\u003cusb-accessory model=\u0026#8221;Demokit\u0026#8221; manufacturer=\u0026#8221;Google,Inc.\u0026#8221; version=\u0026#8221;1.0\u0026#8243;/\u003e  \n\u003c/resoutces\u003e\n\u003cp\u003e配件使用\u003cbr\u003e\n1.通过一个可以过滤配件附加事件的意图过滤器来找到合适的连接配件，或者枚举所有已连接的配件来找到合适的某个配件\u003cbr\u003e\n2.尚未获得许可的用户在与配件通信前需要获得权限\u003cbr\u003e\n3.通过合适的端口与配件进行读写通信\u003c/p\u003e\n\u003cp\u003e用户可以通过两种方式发现配件：一种是使用Intent过滤器在用户连接配件时对其进行通知，另一种通过枚举已经连接的所有配件。\u003c/p\u003e\n\u003cp\u003e意图过滤使用android.hardware.usb.action.USB_ACCESSORY_ATTACHED指定一个意图进行过滤。在这个意图过滤中需要指定一个资源文件来特别说明这个usb配件的属性，例如制造商、模式和版本，当连接的配件和意图过滤条件匹配时，应用会收到一个通知。\u003c/p\u003e\n\u003cp\u003e在Activity中可以通过以下方式获得UsbAccessory，它代表了所有连接的配件\u003cbr\u003e\nUsbAccessory accessory=(UsbAccessroy) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);\u003cbr\u003e\n枚举所有支持的配件\u003cbr\u003e\n当应用在运行的时候，可以在应用中枚举所有能够识别的配件。通过getAccessoryList()方法获得一个包含所有已连接USB配件的数组\u003cbr\u003e\nUsbManager manager=(UsbManager) getSystemService(Content.USB_SERVICE);\u003cbr\u003e\nUsbAccessory[] accessoryList=mamager.getAccessoryList();\u003cbr\u003e\n注意：目前一次只能连接一个USB配件，但是这个API设计的在未来可用于支持多个配件\u003c/p\u003e","title":"Android USB编程基础知识"},{"content":"Android Email编程\n1.android自带邮件系统\n//创建Intent\nIntent intent=new Intent();\n//设置对象动作\nintent.setAction(Intent.ACTION_SEND);\n//设置对方邮件地址\nintent.putExtra(Intent.ExTRA_EMAIL,new String[]{‘abc@163.com’,’a@gmail.com’});\n//设置标题内容\nintent.putExtra(Intent.EXTRA_SUBJECT,”test”);\n//设置邮件文本内容\nintent.putExtra(Intent.EXTRA_TEXT,”text_mail”);\n//启动一个新的Activity，‘sending mail…’是在启动这个activity的等待时间时所显示的文字\nstartActivity(Intent.creatChooser(intent,”sending mail…”));\n2.android JavaMail设计\nandroid中使用javamail需要依赖3个包：activation.jar,additionnal.jar,mail.jar\n对于实现邮件的发送，还需要确保发送方能连接到发送方邮件服务器，一般邮件服务器都需要认证，只有通过认证才能连接，从而将邮件发出去。\n以126为例：\n//创建一个身份验证，即定义Authenticator的子类，并重载getPasswordAuthentication（）方法\nclass PuoupAuthenticatior extends Authenticator{\npublic PasswordAuthenication getPasswordAuthentication(){\nString username=”from”;//邮箱登陆账号\nString pwd=””;//登录密码\n//返回PasswrodAuthentication对象\nreturn new PasswordAuthentication(username,pwd);\n}\n}\n//实例化实现对象Properties\nProperties props=new Properties();\n//设置smtp的服务器地址是：smtp.126.com\nprops.put(“mail.smtp.host”,”smtp.126.com”);\nprops.put(“mail.smtp.auth”,”true”);//设置smtp服务器身份验证\nPopupAuthenticator auth=new PopupAuthenticator();//创建身份验证的实例\n//创建会话（Session），用它管理连接\nSession session=Session.getInstance(props,auth);\n//实例化MimeMessage对象\nMimeMessage message=new MimeMessage(session);\n//设置发送方邮件地址\nAddress addressFrom=new InternetAddress(“a@126.com”,”FROM”);\n//设置收件人邮件地址\nAddress addressTo=new InternetAddress(“b@126.com”,”TO”);\n//收件人地址\nAddress addressCopy=new InternetAddress(“abc@gmail.com”,”abc”);\n//创建邮件内容\nmessage.setContent(“hello”,”text/plain”);\n//或者使用message.setText(“Hello”);\nmessage.setSubject(“Title”);\nmessage.setFrom(addressFrom);\nmessage.setRecipient(Message.RecipientType.TO,addressTO);\nmessage.setRecipient(Message.RecipientType.CC,addressCopy);\nmessage.saveChanges();\n//发送邮件\nTransport transport=session.getTransport(“smtp”);//创建连接\ntransport.connect(“smtp.126.com”,”from”,”123456″);\ntransport.send(message);//发送信息\ntransport.close();关闭连接\n","permalink":"https://blog.zdltech.com/posts/android-email%E7%BC%96%E7%A8%8B/","summary":"\u003cp\u003eAndroid Email编程\u003cbr\u003e\n1.android自带邮件系统\u003cbr\u003e\n//创建Intent\u003cbr\u003e\nIntent intent=new Intent();\u003cbr\u003e\n//设置对象动作\u003cbr\u003e\nintent.setAction(Intent.ACTION_SEND);\u003cbr\u003e\n//设置对方邮件地址\u003cbr\u003e\nintent.putExtra(Intent.ExTRA_EMAIL,new String[]{‘abc@163.com’,’a@gmail.com’});\u003cbr\u003e\n//设置标题内容\u003cbr\u003e\nintent.putExtra(Intent.EXTRA_SUBJECT,”test”);\u003cbr\u003e\n//设置邮件文本内容\u003cbr\u003e\nintent.putExtra(Intent.EXTRA_TEXT,”text_mail”);\u003cbr\u003e\n//启动一个新的Activity，‘sending mail…’是在启动这个activity的等待时间时所显示的文字\u003cbr\u003e\nstartActivity(Intent.creatChooser(intent,”sending mail…”));\u003c/p\u003e\n\u003cp\u003e2.android JavaMail设计\u003c/p\u003e\n\u003cp\u003eandroid中使用javamail需要依赖3个包：activation.jar,additionnal.jar,mail.jar\u003cbr\u003e\n对于实现邮件的发送，还需要确保发送方能连接到发送方邮件服务器，一般邮件服务器都需要认证，只有通过认证才能连接，从而将邮件发出去。\u003cbr\u003e\n以126为例：\u003cbr\u003e\n//创建一个身份验证，即定义Authenticator的子类，并重载getPasswordAuthentication（）方法\u003cbr\u003e\nclass PuoupAuthenticatior extends Authenticator{\u003cbr\u003e\npublic PasswordAuthenication getPasswordAuthentication(){\u003cbr\u003e\nString username=”from”;//邮箱登陆账号\u003cbr\u003e\nString pwd=””;//登录密码\u003cbr\u003e\n//返回PasswrodAuthentication对象\u003cbr\u003e\nreturn new PasswordAuthentication(username,pwd);\u003cbr\u003e\n}\u003cbr\u003e\n}\u003cbr\u003e\n//实例化实现对象Properties\u003cbr\u003e\nProperties props=new Properties();\u003cbr\u003e\n//设置smtp的服务器地址是：smtp.126.com\u003cbr\u003e\nprops.put(“mail.smtp.host”,”smtp.126.com”);\u003cbr\u003e\nprops.put(“mail.smtp.auth”,”true”);//设置smtp服务器身份验证\u003cbr\u003e\nPopupAuthenticator auth=new PopupAuthenticator();//创建身份验证的实例\u003cbr\u003e\n//创建会话（Session），用它管理连接\u003cbr\u003e\nSession session=Session.getInstance(props,auth);\u003cbr\u003e\n//实例化MimeMessage对象\u003cbr\u003e\nMimeMessage message=new MimeMessage(session);\u003cbr\u003e\n//设置发送方邮件地址\u003cbr\u003e\nAddress addressFrom=new InternetAddress(“a@126.com”,”FROM”);\u003cbr\u003e\n//设置收件人邮件地址\u003cbr\u003e\nAddress addressTo=new InternetAddress(“b@126.com”,”TO”);\u003cbr\u003e\n//收件人地址\u003cbr\u003e\nAddress addressCopy=new InternetAddress(“abc@gmail.com”,”abc”);\u003cbr\u003e\n//创建邮件内容\u003cbr\u003e\nmessage.setContent(“hello”,”text/plain”);\u003cbr\u003e\n//或者使用message.setText(“Hello”);\u003cbr\u003e\nmessage.setSubject(“Title”);\u003cbr\u003e\nmessage.setFrom(addressFrom);\u003cbr\u003e\nmessage.setRecipient(Message.RecipientType.TO,addressTO);\u003cbr\u003e\nmessage.setRecipient(Message.RecipientType.CC,addressCopy);\u003cbr\u003e\nmessage.saveChanges();\u003cbr\u003e\n//发送邮件\u003cbr\u003e\nTransport transport=session.getTransport(“smtp”);//创建连接\u003cbr\u003e\ntransport.connect(“smtp.126.com”,”from”,”123456″);\u003cbr\u003e\ntransport.send(message);//发送信息\u003cbr\u003e\ntransport.close();关闭连接\u003c/p\u003e","title":"Android Email编程"},{"content":"Androi 加密和解密\n1.DES加密和解密\nimport javax.crypto.Cipher;\nimport javax.crypto.spec.iVparameterSpec;\nimport javax.crypto.spec.SecretKeySpec;\npublic class DES{\n//初始化向量，随便填充\nprivate static byte[] iv={1,2,3,4,5,6,7,8};\n//DES 加密 encryptString为原文 encryptKey为秘钥\npublic static String encryptDes(String encryptString,String encryptKey) throws Exception{\n//实例化IvParameterSpec对象，使用指定的初始化向量\nIvParameterSpec zeroIV=newIvParameterSpec(iv);\n//实例化SecretKeySpec类，根据字节数组来构造SecretKey\nSecretKeySpec key=nnew SecretKeySpec(encryptKey.getBytes(),’DES’);\n//创建密码器\nCipher cipher=Cipher.getInstance(“DES/CBC/PKCE5Padding”);\n//用秘钥初始化Cipher对象\ncipher.init(Cipher.ENCRYPT_MODE,key,zeroIv);\n//执行加密操作\nbyte[] encryptedData=cipher.doFinal(encryptString.getBytes());\n//返回加密后的数据\nreturn Base64.encode(encryptedData);\n}\n//DES解密 decryptString为密文 decryptKey为密钥\npubbic static String decryptDes(String decryptString ,String decryptKey) throws Exception{\n//先使用Base64解密\nbyte[] byteMi=new Base64().decode(decryptString);\n//实例化IvParamterSpec对象，使用指定的初始化向量\nIvparameterSpec zeroIv=newIvParameterSpec(iv);\n//初始化SecretKeySpec类，根据字节数组来构造\nSecretKeySpec key=new SecretKeySpec(decryptKey.getBytes(),”DES”);\n//创建密码器\nClipher cipher=Cipher.getInstance(“DES/CBC/PKCS5Pading”);\n//用秘钥初始化Cipher对象\ncipher.init(Cipher.DECRYPT_MODE,key,zeroIV);\n//获取解密的数据\nbyte decyptedData[] =cipher.doFinal(biytMI);\n//解密数据转换成字符串输出\nreturn new String(decyptedData);\n}\n}\n2.AES加密和解密\nimport java.security.SecureRandom;\nimport javax.crypto.Clipher;\nimport javax.crypto.KeyGenerator;\nimport javax.crypto.SecretKey;\nimport Javax.crypto.spec.SecretKeySpec;\n//AES加密解密的方法\npublic class AES{\n//AES加密 cleartext为需要加密的内容 seed为密钥\npublic static String encrypt(String seed,String cleartext) throws Exception{\n//对密钥进行编码\nbyte[] rawKey=getRawKey(seed.getBytes());\n//加密数据\nbyte[] result=encrypt(rawKey,cleartext.getBytes());\n//将十进制转换为十六进制\nreturn toHex(result);\n}\n//AES解密 encryptd为需要解密的内容 seed为密钥\npublic static String decrypt(String seed,String encrypted) throws Exception{\n//对密钥进行编码\nbyte[] rawKey=getRawKey(seed.getBytes());\nbyte[] enc=toByte(encrypted);\nbyte[] result=decrypt(rawKey,enc);\nreturn new String(result);\n}\n//对密钥进行编码\npublic static byte[] getRawKey(byte[] seed) throws Exception{\n//获取密钥生成器\nKeyGenerator kgen=KeyGenerator.getInstance(“AES”);\nSecureRandom sr=SecureRandom.getInstance(“SHA1PRNG”);\nsr.setSeed(seed);\n//生成128位的AES密码生成器\nkgen.init(128,sr);\n//生成密钥\nSecretKey sKey=kgen.generateKey();\n//编码格式\nbyte[] raw=skey.getEncoded();\nreturn raw;\n}\n//加密\nprivate static byte[] encrypt(byte[] raw,byte][] clear) throws Exception{\n//生成一组扩展密钥，并放入一个数组\nSecretKeySpec skeySpec=new SecretKeySpec(raw,”AES”);\nCipher cipher=Cipher.getInstance(“AES”);\n//用ENCRYPE_MODE模式，用skeySpec密码组，生成AES加密算法\ncipher.init(Cipher.ENCEYPRT_MODE,skeySpec);\n//得到加密数据\nbyte[] encrypted=cipher.doFinal(clear);\nreturn encrypted;\n}\n//解密\nprivate static byte[] decrypt(byte[] raw,byte[] encrypted) throws Exception{\n//生成一组扩展密钥，并放入一个数组之中\nSecretKeySpec skeySpec=newSecretKeySpec(raw,”AES”);\nCipher cipher=Cipher.getInstance(“AES”);\n//用DECRYPT_MODE解密\ncipher.init(Cipher.DECRYPT_MODE,skeySpec);\n//得到解密数据\nbyte[] decrypted=cipher.doFinal(encrypted);\nreturn decrypted;\n}\n//将十进制转换成十六进制\npublic static String toHex(String txt){\nreturn toHex(txt.getBytes());\n}\n//将十六进制转换成十进制\npublic static String fromHex(String hex){\nreturn new String(toByte(hex));\n}\n//将十六进制转换十进制\npublic static byte[] toByte(String hexString){\nint len=hexString.lenth()/2;\nbyte[] result=new byte[len];\nfor(int i=0;i\u0026lt;len;i++){\nresult[i]=Interger.valueOf(hexString.substring(2*i,2*i+2),16).byteValue();\n}\nreturn result;\n}\n//把一个十进制转换成十六进制\npublic static String toHex(byte[] buf){\nif(buf==null){\nreturn “”;\n}\nStringBuffer result=new StringBuffer(2*buf.length);\nfor(int i=0;i\u0026lt;buf.length;i++){\nappendHex(result,buf[i]);\n}\nreturn result.toString();\n}\nprivate final static String HEX=””0123456789ASDFGH;\nprivate static void appendHex(StringBuffer sb,byte b){\nsb.append(HEX.charAt((b\u0026raquo;4)\u0026amp;0x0f)).append(HEX.charAt(b\u0026amp;)0x0f);\n}\n}\n自己设置加密密钥\n调用类中方法就行了\n3.MD5加密\nprivate static String toMD5(byte[] bytes){\ntry{\n//实例化一个指定摘要算法为MD5的MessageDigest对象\nMessageDigest algorithm=MessageDigest.getInstance(“MD5″);\n//重置摘要以供再次使用\nalgorithm.reset();\n//使用bytes更新摘要\nalgorithm。update(bytes);\n//使用指定的byte数组计算\nreturn toHexString(algorithm.digest,””);\n}catch(NoSuchAlgorithmExcetption e){\n}\n}\n//将字符串中的每一个转化成十六进制\nprivate static String toHexString(byte[] bytes,String separator){\nStringBuilder hexString =new StringBuilder();\nfor(byte b:bytes){\nString hex=Integer.toHexString(0xff\u0026amp;b);\nif(hex.length()==1){\nhexString.append(“0”);\n}\nhexString.append(hex).append(separator);\n}\nreturn hexString.toString();\n};\n调用方法如下\nString md5=MD5(“Android developer”.getBytes());\n结果是一个32为的字符串\n","permalink":"https://blog.zdltech.com/posts/androi-%E5%8A%A0%E5%AF%86%E5%92%8C%E8%A7%A3%E5%AF%86/","summary":"\u003cp\u003eAndroi 加密和解密\u003cbr\u003e\n1.DES加密和解密\u003cbr\u003e\nimport javax.crypto.Cipher;\u003cbr\u003e\nimport javax.crypto.spec.iVparameterSpec;\u003cbr\u003e\nimport javax.crypto.spec.SecretKeySpec;\u003cbr\u003e\npublic class DES{\u003cbr\u003e\n//初始化向量，随便填充\u003cbr\u003e\nprivate static byte[] iv={1,2,3,4,5,6,7,8};\u003cbr\u003e\n//DES 加密 encryptString为原文 encryptKey为秘钥\u003cbr\u003e\npublic static String encryptDes(String encryptString,String encryptKey) throws Exception{\u003cbr\u003e\n//实例化IvParameterSpec对象，使用指定的初始化向量\u003cbr\u003e\nIvParameterSpec zeroIV=newIvParameterSpec(iv);\u003cbr\u003e\n//实例化SecretKeySpec类，根据字节数组来构造SecretKey\u003cbr\u003e\nSecretKeySpec key=nnew SecretKeySpec(encryptKey.getBytes(),’DES’);\u003cbr\u003e\n//创建密码器\u003cbr\u003e\nCipher cipher=Cipher.getInstance(“DES/CBC/PKCE5Padding”);\u003cbr\u003e\n//用秘钥初始化Cipher对象\u003cbr\u003e\ncipher.init(Cipher.ENCRYPT_MODE,key,zeroIv);\u003cbr\u003e\n//执行加密操作\u003cbr\u003e\nbyte[] encryptedData=cipher.doFinal(encryptString.getBytes());\u003cbr\u003e\n//返回加密后的数据\u003cbr\u003e\nreturn Base64.encode(encryptedData);\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e//DES解密 decryptString为密文 decryptKey为密钥\u003cbr\u003e\npubbic static String decryptDes(String decryptString ,String decryptKey) throws Exception{\u003cbr\u003e\n//先使用Base64解密\u003cbr\u003e\nbyte[] byteMi=new Base64().decode(decryptString);\u003cbr\u003e\n//实例化IvParamterSpec对象，使用指定的初始化向量\u003cbr\u003e\nIvparameterSpec zeroIv=newIvParameterSpec(iv);\u003cbr\u003e\n//初始化SecretKeySpec类，根据字节数组来构造\u003cbr\u003e\nSecretKeySpec key=new SecretKeySpec(decryptKey.getBytes(),”DES”);\u003cbr\u003e\n//创建密码器\u003cbr\u003e\nClipher cipher=Cipher.getInstance(“DES/CBC/PKCS5Pading”);\u003cbr\u003e\n//用秘钥初始化Cipher对象\u003cbr\u003e\ncipher.init(Cipher.DECRYPT_MODE,key,zeroIV);\u003cbr\u003e\n//获取解密的数据\u003cbr\u003e\nbyte decyptedData[] =cipher.doFinal(biytMI);\u003cbr\u003e\n//解密数据转换成字符串输出\u003cbr\u003e\nreturn new String(decyptedData);\u003cbr\u003e\n}\u003cbr\u003e\n}\u003cbr\u003e\n2.AES加密和解密\u003c/p\u003e","title":"Androi 加密和解密"},{"content":"Android FTP客户端实现\nandroid中使用第三方库来操作FTP，这里使用Apache的包，下载地址为：http://commons.apache.org/proper/commons-net/download_net.cgi\n其文件名称为：commons-net-3.3-bin.zip\n步骤1：在项目中引入包commons-net-3.3.jar，导入需要的FTPClient类；\n步骤2：初始化FTPClient\nmFtp=new FTPClient();\n步骤3：设置登录的地址和端口\nmFtp.connect(ftpUrl,21);\n步骤4：设置登录用户名和密码\nmFtp.login(name,pwd);\n步骤5：设置文件类型和采用被动传输方式\nmFtp.setFileType(FTP.BINARY_FILE_TYPE);\nmFtp.enterLocalPassiveMode();\n步骤6：传输文件\nboolean aRtn=mFtp.storeFile(remoteFileName,aInputStream);//成功返回true\naInputStream.close();\n步骤7：关闭连接\nmFtp.disconnect();\n核心代码：\n//导入需要的FTPClient类\nimport org.apache.commons.net.ftp.FTPClient;\n//初始化FTPClient\nFTPClient ftpClient=new FTPClient();\ntry{\n//连接到指定的FTP服务器\nftpClient.connect(InetAddress.getByName(SERVER));\n//使用用户名和密码登录FTP\nftpClient.login(USERNAME,PASSWORD);\nif(ftpClient.getReplyString().contains(“250”)){\n//设置文件类型\nftpClient.setFileType(//默认使用的是ASCII编码的，这里设置为二进制文件\norg.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE\n);\n//定义一个缓冲区\nBufferedInputStream buffIn=null;\n//将文件加载到缓冲区中\nbuffIn=new BufferedInputStream(new FileInputStream(FULL_PATH_TO_LOCAL_TYPE));\n//设置客户端的PASV模式（客户端主动连服务器：端口用20）\nftpClient.enterLocalPassiveMode();\n//存储文件。返回是否成功\nboolean result=ftpClient.storeFile(localAsset.getFileName,progressInput);\n//关闭缓冲区\nbuffIn.close();\n//登出\nftpClient.logout();\n//断开连接\nftpClient.disconnect();\n}\n}catch(SocketException e){\n}catch(UnKnowHostException e){\n}catch(IOEception ioe){\n}\nTelnet客户端\n实现的远程控制Web服务器。\nandroid使用第三方库Telnet，这里使用Apache的包，下载地址：http://commons.apache.org/proper/commons-net/download_net.cgi\n其文件名称为：commons-net-3.3-bin.zip\n步骤1：在项目中引入包commons-net-3.3.jar，导入需要的TelnetClient类；\n步骤2：初始化TelnetClient\ntc=new TelnetClient();\n步骤3：打开连接\ntc.connect(remoteip,remoteport);\n步骤4：读写数据\ntc.getInputStream(); tc.getOutputStream();\n步骤5：断开Telnet连接\ntc.disconnect();\n核心代码：\n//定义一个TelnetClient\nTelnetClient tc=new TelnetClient();\ntry{\n//连接到指定的FTP服务器\ntc.connect(remoteip,remoteport);\n}catch(IOEception ioe){\nSystem.exit(1);\n}\nIOUtil.readWrite(tc.getInputStream(),tc.getOutputStream(),System.in,System.out);\ntry{\n//断开连接\ntc.disconnect();\n}catch(IOEception ioe){\n}\n其中调用的IOUtil类封装了一些读写操作\npublic final class IOUtil{\npublic staic final void readWrite(final InputStream remoteInput,final OutputStream remoteOutput,final InputStream localInput,final OutputStream localOutput){\n//定义读写的线程\nThread read,writer;\n//定义读线程的具体操作\nreader=new Thread(){\n@Override\npublic void run(){\nint ch;\ntry{\n//判断没被中断的时候\nwhile(!interrupred()\u0026amp;\u0026amp;(ch=localInput.read())!=-1){\n//写自己到远程输入里面\nremoteOutput.write(ch);\n//刷新发送\nremoteOutput.flush();\n}\n}catch(IOException e){\n}\n}\n};\n//定义写线程的具体操作\nreader=new Thread(){\n@Override\npublic void run(){\nint ch;\ntry{\n//把数据从输入流复制到输出流\nUtil.copyStream(remoteInput,localOutput);\n}catch(IOException e){\nSystem.exit(1);\n}\n}\n};\n//设置Writer线程\nwriter.setPriority(Thread.currentThread().getPriority()+1);\n//启动writer线程\nwriter.start();\n//设置reader为后台运行\nreader.setDaemon(true);\n//启动readre线程\nreader.start();\ntry{\n//使得writer线程完成run（）方法后，在执行join（）方法后的代码\nwriter.join();\n//中断reader线程\nreader.interrupt();\n}catch(InterruptedException e){\n}\n};\n}\n","permalink":"https://blog.zdltech.com/posts/android-ftp%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%AE%9E%E7%8E%B0telnet%E5%AE%A2%E6%88%B7%E7%AB%AF/","summary":"\u003cp\u003eAndroid FTP客户端实现\u003c/p\u003e\n\u003cp\u003eandroid中使用第三方库来操作FTP，这里使用Apache的包，下载地址为：http://commons.apache.org/proper/commons-net/download_net.cgi\u003cbr\u003e\n其文件名称为：commons-net-3.3-bin.zip\u003cbr\u003e\n步骤1：在项目中引入包commons-net-3.3.jar，导入需要的FTPClient类；\u003cbr\u003e\n步骤2：初始化FTPClient\u003cbr\u003e\nmFtp=new FTPClient();\u003cbr\u003e\n步骤3：设置登录的地址和端口\u003cbr\u003e\nmFtp.connect(ftpUrl,21);\u003cbr\u003e\n步骤4：设置登录用户名和密码\u003cbr\u003e\nmFtp.login(name,pwd);\u003cbr\u003e\n步骤5：设置文件类型和采用被动传输方式\u003cbr\u003e\nmFtp.setFileType(FTP.BINARY_FILE_TYPE);\u003cbr\u003e\nmFtp.enterLocalPassiveMode();\u003cbr\u003e\n步骤6：传输文件\u003cbr\u003e\nboolean aRtn=mFtp.storeFile(remoteFileName,aInputStream);//成功返回true\u003cbr\u003e\naInputStream.close();\u003cbr\u003e\n步骤7：关闭连接\u003cbr\u003e\nmFtp.disconnect();\u003c/p\u003e\n\u003cp\u003e核心代码：\u003cbr\u003e\n//导入需要的FTPClient类\u003cbr\u003e\nimport org.apache.commons.net.ftp.FTPClient;\u003cbr\u003e\n//初始化FTPClient\u003cbr\u003e\nFTPClient ftpClient=new FTPClient();\u003cbr\u003e\ntry{\u003cbr\u003e\n//连接到指定的FTP服务器\u003cbr\u003e\nftpClient.connect(InetAddress.getByName(SERVER));\u003cbr\u003e\n//使用用户名和密码登录FTP\u003cbr\u003e\nftpClient.login(USERNAME,PASSWORD);\u003cbr\u003e\nif(ftpClient.getReplyString().contains(“250”)){\u003cbr\u003e\n//设置文件类型\u003cbr\u003e\nftpClient.setFileType(//默认使用的是ASCII编码的，这里设置为二进制文件\u003cbr\u003e\norg.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE\u003cbr\u003e\n);\u003cbr\u003e\n//定义一个缓冲区\u003cbr\u003e\nBufferedInputStream buffIn=null;\u003cbr\u003e\n//将文件加载到缓冲区中\u003cbr\u003e\nbuffIn=new BufferedInputStream(new FileInputStream(FULL_PATH_TO_LOCAL_TYPE));\u003cbr\u003e\n//设置客户端的PASV模式（客户端主动连服务器：端口用20）\u003cbr\u003e\nftpClient.enterLocalPassiveMode();\u003cbr\u003e\n//存储文件。返回是否成功\u003cbr\u003e\nboolean result=ftpClient.storeFile(localAsset.getFileName,progressInput);\u003cbr\u003e\n//关闭缓冲区\u003cbr\u003e\nbuffIn.close();\u003cbr\u003e\n//登出\u003cbr\u003e\nftpClient.logout();\u003cbr\u003e\n//断开连接\u003cbr\u003e\nftpClient.disconnect();\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e}catch(SocketException e){\u003c/p\u003e\n\u003cp\u003e}catch(UnKnowHostException e){\u003c/p\u003e\n\u003cp\u003e}catch(IOEception ioe){\u003c/p\u003e\n\u003cp\u003e}\u003cbr\u003e\nTelnet客户端\u003cbr\u003e\n实现的远程控制Web服务器。\u003cbr\u003e\nandroid使用第三方库Telnet，这里使用Apache的包，下载地址：http://commons.apache.org/proper/commons-net/download_net.cgi\u003cbr\u003e\n其文件名称为：commons-net-3.3-bin.zip\u003cbr\u003e\n步骤1：在项目中引入包commons-net-3.3.jar，导入需要的TelnetClient类；\u003cbr\u003e\n步骤2：初始化TelnetClient\u003cbr\u003e\ntc=new TelnetClient();\u003cbr\u003e\n步骤3：打开连接\u003cbr\u003e\ntc.connect(remoteip,remoteport);\u003cbr\u003e\n步骤4：读写数据\u003cbr\u003e\ntc.getInputStream(); tc.getOutputStream();\u003cbr\u003e\n步骤5：断开Telnet连接\u003cbr\u003e\ntc.disconnect();\u003cbr\u003e\n核心代码：\u003cbr\u003e\n//定义一个TelnetClient\u003cbr\u003e\nTelnetClient tc=new TelnetClient();\u003cbr\u003e\ntry{\u003cbr\u003e\n//连接到指定的FTP服务器\u003cbr\u003e\ntc.connect(remoteip,remoteport);\u003cbr\u003e\n}catch(IOEception ioe){\u003cbr\u003e\nSystem.exit(1);\u003cbr\u003e\n}\u003cbr\u003e\nIOUtil.readWrite(tc.getInputStream(),tc.getOutputStream(),System.in,System.out);\u003cbr\u003e\ntry{\u003cbr\u003e\n//断开连接\u003cbr\u003e\ntc.disconnect();\u003cbr\u003e\n}catch(IOEception ioe){\u003c/p\u003e","title":"Android FTP客户端实现、Telnet客户端"},{"content":" Part1: \u0026lt;div\u0026gt; \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt;![jQuery Mobile实现搜索框（图） - 东辰 - 我的博客](http://img1.ph.126.net/HQno7VSqxkMxHqHi__R9Ug==/6608266093561976161.png)\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt;\u0026lt;section id=\u0026amp;#8221;page1\u0026amp;#8243; data-role=\u0026amp;#8221;page\u0026amp;#8221;\u0026gt; \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; # jQuery Mobile\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; \u0026lt;/header\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; \u0026lt;div class=\u0026amp;#8221;content\u0026amp;#8221; data-role=\u0026amp;#8221;content\u0026amp;#8221;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; ### Search Input \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; \u0026lt;div data-role=\u0026amp;#8221;fieldcontain\u0026amp;#8221;\u0026gt; Search Restaurants: \u0026lt;input type=”search” name=”search-restaurants” id=”search-restaurants” /\u0026gt;\n\u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; \u0026lt;/form\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; \u0026lt;footer data-role=\u0026amp;#8221;footer\u0026amp;#8221;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; # O\u0026amp;#8217;Reilly\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; \u0026lt;/footer\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt;\u0026lt;/section\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; Part2: ``` 在列表上方，添加搜索框，只需要添加data-filter=\"true\"就行。 ``` ``` 添加placeholder的方法：data-filter-placeholder=\u0026ldquo;Filter items\u0026hellip;\u0026quot;\n\u0026lt;div\u0026gt; \u0026lt;span style=\u0026#34;font-family: 宋体; font-size: medium;\u0026#34;\u0026gt;![jQuery Mobile实现搜索框（图） - 东辰 - 我的博客](http://img1.ph.126.net/qidW7N5m4gEKWJi6znQCow==/2001287084512884007.png)\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ``` \u0026lt;span style=\u0026#34;font-family: 宋体; font-size: medium;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; ``` \u0026lt;ul data-role=\u0026ldquo;listview\u0026rdquo; data-inset=\u0026ldquo;true\u0026rdquo; data-filter=\u0026ldquo;true\u0026rdquo; data-filter-placeholder=\u0026ldquo;Filter items\u0026hellip;\u0026quot;\u0026gt;\n``` \u0026lt;span style=\u0026#34;font-family: 宋体; font-size: medium;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; ``` 此时，筛选是自动的。\n\u0026lt;div title=\u0026#34;Page 67\u0026#34;\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;span style=\u0026#34;font-family: 宋体; font-size: medium;\u0026#34;\u0026gt;（If you begin typing in the previous field, the list automatically filters out the results\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;font-family: 宋体; font-size: medium;\u0026#34;\u0026gt;as you type）\u0026lt;/span\u0026gt; \u0026lt;div\u0026gt; \u0026lt;span style=\u0026#34;font-family: 宋体; font-size: medium;\u0026#34;\u0026gt;![jQuery Mobile实现搜索框（图） - 东辰 - 我的博客](http://img0.ph.126.net/SRFRofm_Bj6mmEc3pYQtWA==/4852065648638601300.png)\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span style=\u0026#34;font-family: 宋体; font-size: medium;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/jquery-mobile%E5%AE%9E%E7%8E%B0%E6%90%9C%E7%B4%A2%E6%A1%86%E5%9B%BE/","summary":"\u003cdiv title=\"Page 70\"\u003e\n  \u003cdiv\u003e\n    \u003cdiv\u003e\n      \u003cdiv\u003e\n        \u003cspan style=\"font-family: 宋体; font-size: medium;\"\u003ePart1:\u003c/span\u003e\n      \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt;![jQuery Mobile实现搜索框（图） - 东辰 - 我的博客](http://img1.ph.126.net/HQno7VSqxkMxHqHi__R9Ug==/6608266093561976161.png)\u0026lt;/span\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n\n    \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt;\u0026lt;section id=\u0026amp;#8221;page1\u0026amp;#8243; data-role=\u0026amp;#8221;page\u0026amp;#8221;\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n \u003cheader data-role=\u0026#8221;header\u0026#8221;\u003e\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; # jQuery Mobile\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; \u0026lt;/header\u0026gt; \u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; \u0026lt;div class=\u0026amp;#8221;content\u0026amp;#8221; data-role=\u0026amp;#8221;content\u0026amp;#8221;\u0026gt;\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; ### Search Input\n\u003c/code\u003e\u003c/pre\u003e\n \u003cform id=\u0026#8221;myform\u0026#8221; action=\u0026#8221;formprocessor.php\u0026#8221; method=\u0026#8221;post\u0026#8221;\u003e\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;span style=\u0026quot;font-family: 宋体; font-size: medium;\u0026quot;\u0026gt; \u0026lt;div data-role=\u0026amp;#8221;fieldcontain\u0026amp;#8221;\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003clabel for=\u0026#8221;search-restaurants\u0026#8221;\u003eSearch Restaurants:\u003c/label\u003e\n\u0026lt;input \u003cstrong\u003e\u003cspan style=\"color: #ff0000;\"\u003etype=”search”\u003c/span\u003e\u003c/strong\u003e name=”search-restaurants” id=”search-restaurants” /\u0026gt;\u003c/span\u003e\u003c/p\u003e","title":"jQuery Mobile实现搜索框（图） "},{"content":"刚开始项目只是选择了iscroll框架实现滚动翻页，后来和jquery mobile（jqm）框架整合后，界面没法使用\n在网上搜索了很多资料，各种尝试后还是问题很多。最后在老外的网站上发现了jquery-mobile-iscrollview框架，用于整合jquery mobile和iscroll的一个开源框架，处理了很多jquery mobile和iscroll整合中出现的问题。\n1、jquery-mobile-iscrollview下载地址：https://github.com/watusi/jquery-mobile-iscrollview\n解压后的\\jquery-mobile-iscrollview-master\\jquery-mobile-iscrollview-master\\demo\\source路径下是需要引用的js和css文件\n\\jquery-mobile-iscrollview-master\\jquery-mobile-iscrollview-master\\demo\\build路径下是各个jquery mobile版本下的列表和滚动翻页的例子\n在该路径下，我选择了pull_14.html文件，用chrome打开后，发现下面的导航栏变形，将\n去掉后，下面的导航栏正常了\n页面中引用的pull-example.js文件是上拉、下拉事件的处理，只需要将gotPullDownData和gotPullUpData函数修改一下即可实现自己需要加载的数据\n2、直接测试该功能没有什么问题，当把该翻页的页面链接到其他页面上时，通过链接打开该页面，下面的导航栏又出现了问题\n后来发现，这是问题可能是由于jqm的外部页面链接引起的错。jqm在使用外部链接打开另一个页面时，会使用ajax读取需要打开的文件，然后将该文件动态加载到已经打开的页面的后面，jqm只加载文档中取出的第一个页面（第一个带有role=”page”的div），其他内容都将被忽略。\n后来，将列表页面(b.html)所有加载的css和js的标签放到链接该页面的页面(a.html)的标签中。\n\u0026amp;lt;meta http-equiv=\u0026#34;Content-Type\u0026#34; content=\u0026#34;text/html; charset=utf-8\u0026#34; /\u0026amp;gt; \u0026amp;lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no\u0026#34; /\u0026amp;gt; \u0026amp;lt;meta name=\u0026#34;apple-mobile-web-app-capable\u0026#34; content=\u0026#34;yes\u0026#34; /\u0026amp;gt; \u0026amp;lt;meta name=\u0026#34;apple-mobile-web-app-status-bar-style\u0026#34; content=\u0026#34;black\u0026#34; /\u0026amp;gt; \u0026amp;lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;../jquery.mobile-1.4.2.min.css\u0026#34; type=\u0026#34;text/css\u0026#34;\u0026amp;gt; \u0026amp;lt;link href=\u0026#34;../jquery.mobile.iscrollview.css\u0026#34; media=\u0026#34;screen\u0026#34; rel=\u0026#34;stylesheet\u0026#34; type=\u0026#34;text/css\u0026#34; /\u0026amp;gt; \u0026amp;lt;link href=\u0026#34;../jquery.mobile.iscrollview-pull.css\u0026#34; media=\u0026#34;screen\u0026#34; rel=\u0026#34;stylesheet\u0026#34; type=\u0026#34;text/css\u0026#34; /\u0026amp;gt; \u0026amp;lt;script src=\u0026#34;../jquery.js\u0026#34; type=\u0026#34;text/javascript\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;script\u0026amp;gt; \u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(document).bind(\u0026#34;mobileinit\u0026#34;, function(){ //容许ajax跨域访问\u0026lt;/span\u0026gt;.mobile.allowCrossDomainPages = true; }); \u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;script src=\u0026#34;../jquery.mobile-1.4.2.min.js\u0026#34; type=\u0026#34;text/javascript\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;script src=\u0026#34;../javascripts/iscroll.js\u0026#34; type=\u0026#34;text/javascript\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;script src=\u0026#34;../javascripts/jquery.mobile.iscrollview.js\u0026#34; type=\u0026#34;text/javascript\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;script src=\u0026#34;../javascripts/pull-example.js\u0026#34; type=\u0026#34;text/javascript\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt; 当链接打开该页面后，列表页面稳定了\n3、jquery-mobile-iscrollview中引用的jqm框架的版本没有项目中的高，试着将jqm的版本替换为项目中使用的版本后，该功能依旧没有出现问题\n","permalink":"https://blog.zdltech.com/posts/jquery-mobile-iscroll-iscrollview-%E5%BC%80%E5%8F%91%E6%BB%9A%E5%8A%A8%E7%BF%BB%E9%A1%B5%E5%8A%9F%E8%83%BD/","summary":"\u003cp\u003e刚开始项目只是选择了iscroll框架实现滚动翻页，后来和jquery mobile（jqm）框架整合后，界面没法使用\u003c/p\u003e\n\u003cp\u003e在网上搜索了很多资料，各种尝试后还是问题很多。最后在老外的网站上发现了jquery-mobile-iscrollview框架，用于整合jquery mobile和iscroll的一个开源框架，处理了很多jquery mobile和iscroll整合中出现的问题。\u003c/p\u003e\n\u003cp\u003e1、jquery-mobile-iscrollview下载地址：\u003ca href=\"https://github.com/watusi/jquery-mobile-iscrollview\"\u003ehttps://github.com/watusi/jquery-mobile-iscrollview\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e解压后的\\jquery-mobile-iscrollview-master\\jquery-mobile-iscrollview-master\\demo\\source路径下是需要引用的js和css文件\u003c/p\u003e\n\u003cp\u003e\\jquery-mobile-iscrollview-master\\jquery-mobile-iscrollview-master\\demo\\build路径下是各个jquery mobile版本下的列表和滚动翻页的例子\u003c/p\u003e\n\u003cp\u003e在该路径下，我选择了pull_14.html文件，用chrome打开后，发现下面的导航栏变形，将\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cscript src=\u0026#8221;javascripts/demo.js\u0026#8221; type=\u0026#8221;text/javascript\u0026#8221;\u003e\u003c/script\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e去掉后，下面的导航栏正常了\u003c/p\u003e\n\u003cp\u003e页面中引用的pull-example.js文件是上拉、下拉事件的处理，只需要将gotPullDownData和gotPullUpData函数修改一下即可实现自己需要加载的数据\u003c/p\u003e\n\u003cp\u003e2、直接测试该功能没有什么问题，当把该翻页的页面链接到其他页面上时，通过链接打开该页面，下面的导航栏又出现了问题\u003c/p\u003e\n\u003cp\u003e后来发现，这是问题可能是由于jqm的外部页面链接引起的错。jqm在使用外部链接打开另一个页面时，会使用ajax读取需要打开的文件，然后将该文件动态加载到已经打开的页面的后面，jqm只加载文档中取出的第一个页面（第一个带有role=”page”的div），其他内容都将被忽略。\u003c/p\u003e\n\u003cp\u003e后来，将列表页面(b.html)所有加载的css和js的标签放到链接该页面的页面(a.html)的\u003chead\u003e标签中。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;meta http-equiv=\u0026#34;Content-Type\u0026#34; content=\u0026#34;text/html; charset=utf-8\u0026#34; /\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;meta name=\u0026#34;viewport\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tcontent=\u0026#34;width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no\u0026#34; /\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;meta name=\u0026#34;apple-mobile-web-app-capable\u0026#34; content=\u0026#34;yes\u0026#34; /\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;meta name=\u0026#34;apple-mobile-web-app-status-bar-style\u0026#34; content=\u0026#34;black\u0026#34; /\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;../jquery.mobile-1.4.2.min.css\u0026#34; type=\u0026#34;text/css\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;link href=\u0026#34;../jquery.mobile.iscrollview.css\u0026#34; media=\u0026#34;screen\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\trel=\u0026#34;stylesheet\u0026#34; type=\u0026#34;text/css\u0026#34; /\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;link href=\u0026#34;../jquery.mobile.iscrollview-pull.css\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tmedia=\u0026#34;screen\u0026#34; rel=\u0026#34;stylesheet\u0026#34; type=\u0026#34;text/css\u0026#34; /\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;script src=\u0026#34;../jquery.js\u0026#34; type=\u0026#34;text/javascript\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;script\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(document).bind(\u0026#34;mobileinit\u0026#34;, function(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t//容许ajax跨域访问\u0026lt;/span\u0026gt;.mobile.allowCrossDomainPages = true;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/script\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;script src=\u0026#34;../jquery.mobile-1.4.2.min.js\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\ttype=\u0026#34;text/javascript\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;script src=\u0026#34;../javascripts/iscroll.js\u0026#34; type=\u0026#34;text/javascript\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;script src=\u0026#34;../javascripts/jquery.mobile.iscrollview.js\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\ttype=\u0026#34;text/javascript\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;script src=\u0026#34;../javascripts/pull-example.js\u0026#34; type=\u0026#34;text/javascript\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e \u003c/p\u003e","title":"jquery mobile + iscroll + iscrollview 开发滚动翻页功能"},{"content":"http://wenku.baidu.com/link?url=lAOm_kIF29t-JGoUnKAFSY4BhMP6vv-Cvfx9x1_oVSTZ1QDMm6URT7fhRR8ODX7aBVSX8ffOD0LnI-TX4PaRTqzXPWwJdOhBNXMu0lg214O\nhttp://wenku.baidu.com/view/490171b20242a8956bece47d.html?re=view\nhttp://wenku.baidu.com/view/cf48328371fe910ef12df827.html\nhttp://wenku.baidu.com/view/490171b20242a8956bece47d.html?re=view\nhttp://wenku.baidu.com/link?url=lAOm_kIF29t-JGoUnKAFSY4BhMP6vv-Cvfx9x1_oVSTZ1QDMm6URT7fhRR8ODX7aBVSX8ffOD0LnI-TX4PaRTqzXPWwJdOhBNXMu0lg214O\nandroid平台包含了蓝牙网络协议栈的支持，允许android设备与其他蓝牙设备相互传输数据。应用层框架提供了API函数来访问蓝牙模块。使用这些API可以让应用程序连接其他蓝牙设备，实现点对点或多点无线传输。\n运用蓝牙API，可以实现以下功能：\n搜索其他蓝牙设备\n查询本地蓝牙适配器中已经配对好的设备\n建立RFCOMM协议通道\n通过服务端搜索连接到其他设备\n与其他设备互相传输数据\n管理多个连接\n快速阅读\nAndroid蓝牙API可以让应用程序与其他设备传输无线数据。\n关键类\nBluetoothAdapter\nBluetoothDevice\nBluetoothSocket\nBluetoothServerSocket\n相关用例\n蓝牙对讲 http://developer.android.com/resources/samples/BluetoothChat/index.html\n蓝牙医疗设备(Health Device Profile)，比如心率监视器，血压计，温度计等。http://developer.android.com/resources/samples/BluetoothHDP/index.html\n目录 [隐藏]\n1 基本原理\n2 蓝牙权限\n3 配置蓝牙\n4 获取蓝牙设备\n4.1 查询已配对设备\n4.2 搜索设备\n4.3 开启蓝牙可检测性\n5 设备连接\n5.1 作为服务端连接\n5.2 作为客户端连接\n6 连接管理\n7 在蓝牙规范协议下工作\n7.1 Vendor-specific AT commands\n7.2 Health Device Profile\n基本原理\n本文档描述了如何使用蓝牙API来完成蓝牙通讯的四项必要任务：配置蓝牙、搜索附件未配对或可用的蓝牙设备、连接设备、设备间传输数据。\n所有蓝牙API都包含在android.bluetooth包中。以下是建立蓝牙连接需要用到的类和接口的概要：\nBluetoothAdapter (蓝牙适配器)\n表示本地蓝牙适配器(蓝牙收发器). BluetoothAdapter是所有蓝牙活动的起始类. 可用于搜索其他蓝牙设备, 查询已配对设备的列表, 使用MAC地址实例化一个BluetoothDevice对象, 创建BluetoothServerSocket侦听其他设备的连接.\nBluetoothDevice (蓝牙设备)\n表示远程蓝牙设备。可以通过一个BluetoothSocket向它描述的远程设备发起连接，或者该设备的名称、地址、类、连接状态等信息。\nBluetoothSocket (蓝牙套接字)\n表示一个蓝牙套接字(与TCP Socket类似). 它是设备间的连接点，允许应用程序通过InputStream和OutputStream与其他设备进行数据传输。\nBluetoothServerSocket (蓝牙服务端套接字)\n表示一个开放的蓝牙服务器， 用于侦听其他设备发过来的连接请求(与TCP ServerSocket类似). 要将两台设备连接起来, 其中一台必须使用这个类开启一个server socket. 当远程蓝牙设备发起对server的连接请求, 如果连接被接受，BluetoothServerSocket将返回一个连接成功的BluetoothSocket对象.\nBluetoothClass (蓝牙类型)\n描述一个蓝牙设备的规格参数和功能。这是一个只读的属性集，定义了该设备的主要和次要设备种类和服务。它不能完全描述该设备的所有特性和服务，常用于判断设备的类型。\nBluetoothProfile (蓝牙规范协议)\n表示Bluetooth profile的接口. Bluetooth profile是设备间基于蓝牙通讯的接口规范协议。比如Hands-Free(非手持设备) profile。更多关于profiles的说明, 请查看Working with Profiles(在蓝牙规范协议下工作)。\nBluetoothHeadset (蓝牙耳机)\n提供手机使用蓝牙耳机的支持。同时包含了蓝牙耳机和Hands-Free(v1.5)的profiles.\nBluetoothA2dp (蓝牙A2dp)\n定义高质量音频流如何通过蓝牙连接传输到其他设备。”A2DP”是”Advanced Audio Distribution Profile”的缩写，表示高级音频分发规范协议。\nBluetoothHealth (蓝牙医疗设备)\n表示为医疗设备提供蓝牙服务的代理类。\nBluetoothHealthCallback\n这是一个抽象类，用于实现BluetoothHealth的callbacks方法。需要继承此类并实现callback方法才能接收应用程序状态和蓝牙频道状态的变化。\nBluetoothHealthAppConfiguration\n表示蓝牙医疗第三方应用与远程蓝牙医疗设备连接的配置参数。\nBluetoothProfile.ServiceListener (蓝牙规范协议服务侦听)\n一个接口类，当服务连接或断开的时候通知BluetoothProfile IPC 客户端。(这是内部服务运行的一个特殊模式)。\n蓝牙权限\n应用程序要使用手机的蓝牙功能，必须声明以下两种权限中的一种：BLUETOOTH 或 BLUETOOTH_ADMIN。\nBLUETOOTH权限用于进行蓝牙通讯，比如请求连接、接受连接和传输数据。\nBLUETOOTH_ADMIN权限用于初始化设备搜索和进行蓝牙设置。大部分应用只是需要它来搜索附近的蓝牙设备，BLUETOOTH_ADMIN权限赋予的其他能力不需要用到，除非该应用程序是需要修改本机蓝牙设置的电源管理类应用。注意：如果您使用了BLUETOOTH_ADMIN ，必须同时使用BLUETOOTH。\n在你的程序中的manifest文件声明蓝牙权限，例如：\n\u0026lt;manifest … \u0026gt;\n…\n查看 用户权限 这一章节，获得更多关于声明应用程序权限的内容。\n配置蓝牙\n在使用蓝牙之前，首先要确认你的设备带有蓝牙模块，如果有，还要确认蓝牙功能是开启的。\n如果设备不支持蓝牙，应用程序需要禁用所有蓝牙相关的功能。如果设备支持蓝牙，但蓝牙模块是关闭的，可以直接在程序中向用户请求开启蓝牙，不需要离开当前应用。这个过程需要使用BluetoothAdapter，分两步完成。\n1.获取BluetoothAdapter对象\n所有蓝牙活动都需要有一个BluetoothAdapter对象，使用静态方法getDefaultAdapter()可以获取一个BluetoothAdapter对象，表示本设备的蓝牙适配器(蓝牙收发器)。如果整个系统中存在这么一个蓝牙适配器，应用程序就可以通过BluetoothAdapter对象与其相互交流。如果getDefaultAdapter()方法返回null，说明本设备不支持蓝牙，故事结束了。例如：\nBluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();\nif (mBluetoothAdapter == null) {\n// Device does not support Bluetooth\n}\n2.开启蓝牙\n接下来，你需要确认蓝牙模块是否开启。调用isEnabled()检查蓝牙模块是否开启。如果该方法返回false，说明蓝牙模块关闭。需要用ACTION_REQUEST_ENABLE action Intent调用startActivityForResult()请求开启蓝牙。这将通过系统设置发出一个开启蓝牙的请求（无需停止当前应用程序）。例如：\nif (!mBluetoothAdapter.isEnabled()) {\nIntent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);\nstartActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);\n}\n这时会弹出一个对话框，询问用户是否开启蓝牙。如果用户选择“是”，系统将开启蓝牙，并且在完成（或失败）之后，返回到你的应用程序。\n传递给startActivityForResult()的REQUEST_ENABLE_BT常量是一个局部定义的整形（必然大于0），系统会在你实现的onActivityResult()方法中，通过requestCode参数返回这一数值。\n如果开启蓝牙成功，系统会调用你实现的onActivityResult()方法，并得到RESULT_OK的结果码。如果开启失败，或者用户选择“否”，结果码则是RESULT_CANCELED。\n最后是一个可选项，你的程序可以关于ACTION_STATE_CHANGED intent的广播。每当系统蓝牙状态发生变化，系统就会发出该广播。广播中包含了额外的字段EXTRA_STATE 和EXTRA_PREVIOUS_STATE，分别表示新的和旧的蓝牙状态。这些字段可能的值是STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, 和STATE_OFF。侦听广播对程序在运行中检测到蓝牙状态变化非常有用。\n提示：开启蓝牙可检测性会自动开启蓝牙模块，如果你在完成蓝牙活动之前需要一直开启蓝牙可检测性，则可以跳过上面的第二步，看后面的开启蓝牙可检测性。\n获取蓝牙设备\n使用BluetoothAdapter，你可以通过搜寻设备或者查询已配对设备列表来获取其他蓝牙设备。\n搜寻设备是一个搜索附近开启蓝牙的设备并获取设备相关信息的检测过程。 附近的蓝牙设备，必须是开启了蓝牙可检测性，才会被你的设备所检测到。 如果附近一个设备开启了可检测性，它将发送一些信息来回应搜索的请求，比如设备名称、类型以及它的MAC地址。 你的设备可以通过这些信息，初始化一个和被发现设备的连接。\n当与一个从未连接过的设备进行连接的时候，一个蓝牙配对请求会自动呈现给用户。 配对完成后，该设备的基本信息（比如设备名称、类型和MAC地址）就被保存下来并可以使用相关的API函数读取。 使用这个已知的MAC地址，连接就可以随时进行而不再需要进行搜索（前提是该设备在蓝牙范围内）。\n已配对和已连接是不一样的概念，已配对表示两台设备间已经认识了彼此的存在，共享一个用于认证身份的link-key，并能够互相建立加密连接。 已连接表示两台设备当前正在共享一个RFCOMM信道，并能够互相传输数据。 目前Android Bluetooth API要求设备在建立RFCOMM连接之前必须先进行配对。 （当你用蓝牙API初始化一个加密连接时，配对会自动进行。）\n下面的小节讲解如何获得已配对的设备和使用设备搜寻发现新设备。\n注意：安卓蓝牙设备默认是不开启可检测性的。 用户可以通过系统设置将蓝牙可检测性临时打开一段时间， 应用程序也可以向用户请求打开可检测性，而不需要离开当前程序。 后面会说明如何开启可检测性。\n查询已配对设备\n在进行设备搜寻之前，最好先查询一下已配对设备的列表，看看想要连接的设备是否已经配对过了。 调用getBondedDevices()即可。这将返回一个BluetoothDevice对象的set，表示已配对设备的集合。 例如，你可以查询所有已配对设备并显示每个设备的名称，通过使用ArrayAdapter：\nSet pairedDevices = mBluetoothAdapter.getBondedDevices();\n// If there are paired devices\nif (pairedDevices.size() \u0026gt; 0) {\n// Loop through paired devices\nfor (BluetoothDevice device : pairedDevices) {\n// Add the name and address to an array adapter to show in a ListView\nmArrayAdapter.add(device.getName() + “\\n” + device.getAddress());\n}\n}\nBluetoothDevice对象初始化一个连接所需要的唯一信息就是MAC地址。 在这个示例中，MAC地址作为ArrayAdapter的一部分显示出来。后续可用于初始化连接。 更多关于创建连接的信息请查看设备连接。\n搜索设备\n调用startDiscovery()即可开始设备搜寻。搜寻过程是异步的，该方法会立刻返回一个boolean值表示搜寻是否成功开始。 搜寻过程通常是一个十二秒的查询扫描，然后列出一页扫描到的设备的名称。\n应用程序必须注册一个关于ACTION_FOUND Intent的BroadcastReceiver，才能接收每个搜寻到的设备的信息。每搜寻到一个设备，系统都会广播ACTION_FOUND Intent。 Intent里面包含额外的字段EXTRA_DEVICE和EXTRA_CLASS，分部包含一个BluetoothDevice和一个BluetoothClass。 以下代码说明如何注册接收和处理设备被搜寻到的信息：\n// Create a BroadcastReceiver for ACTION_FOUND\nprivate final BroadcastReceiver mReceiver = new BroadcastReceiver() {\npublic void onReceive(Context context, Intent intent) {\nString action = intent.getAction();\n// When discovery finds a device\nif (BluetoothDevice.ACTION_FOUND.equals(action)) {\n// Get the BluetoothDevice object from the Intent\nBluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);\n// Add the name and address to an array adapter to show in a ListView\nmArrayAdapter.add(device.getName() + “\\n” + device.getAddress());\n}\n}\n};\n// Register the BroadcastReceiver\nIntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);\nregisterReceiver(mReceiver, filter); // Don’t forget to unregister during onDestroy\n警告: 进行设备搜寻对于蓝牙适配器来说是一个繁重的过程并会消耗大量资源。 当你搜寻到一个可连接设备时，请确保在尝试连接之前，调用cancelDiscovery()来停止设备搜寻。 并且，当你已经与一个设备建立了连接时，进行设备搜寻会显著降低该连接的可用带宽。所以，在已有连接时，最好不要进行搜寻。\n开启蓝牙可检测性\n如果你想要本设备能被其他蓝牙设备搜寻到，调用startActivityForResult(Intent, int)，Intent为ACTION_REQUEST_DISCOVERABLE action 。 这样会通过系统设置发出一个开启蓝牙可检测性的请求（不需要退出你的应用程序）。 默认情况下，本设备将变为可检测模式，持续120秒。 你可以通过额外添加EXTRA_DISCOVERABLE_DURATION到Intent来定义不同的持续时间。 应用程序能设置的最大持续时间为3600秒，设为0则让设备一直保持可检测状态（任何小于0或大于3600的值，会自动设为120秒）。 例如，以下代码设置持续时间为300秒：\nIntent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);\ndiscoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);\nstartActivity(discoverableIntent);\n在向用户请求开启可检测性时，一个对话框会弹出来。 如果用户选择“是”，设备将在指定的持续时间内开启可检测性。 你的应用程序将接收到onActivityResult()的回调，回调的结果码表示可检测性持续的时间。 如果用户选择“否”或者发生错误，结果码将是RESULT_CANCELED。\n注意如果蓝牙功能没有开启，开启可检测性会自动开启蓝牙功能。\n在预定的时间内，设备会静默地保持可检测性。 如果你想在可检测模式变化时收到相应的通知，可以注册关于ACTION_SCAN_MODE_CHANGED Intent的BroadcastReceiver。 里面包含EXTRA_SCAN_MODE 和 EXTRA_PREVIOUS_SCAN_MODE的额外字段，分别表示新的和旧的状态。 可能的值是SCAN_MODE_CONNECTABLE_DISCOVERABLE, SCAN_MODE_CONNECTABLE, SCAN_MODE_NONE，分别表示设备处于可检测可连接状态， 或者不可检测但可连接，或者不可检测不可连接。\n如果你只想要连接附近的设备，不需要打开可检测性。 只有在你希望应用程序作为蓝牙socket服务端，接收来自其他设备的连接时，才需要打开可检测性。 因为其他设备在发起一个连接前，需要检测到你的设备。\n设备连接\n要在两个设备的应用之间建立连接，必须实现服务端和客户端的机制。 因为其中一个设备必须开启一个server socket，然后另一个设备才能接入进来（通过服务端设备的MAC地址建立连接）。 当服务端和客户端分别得到一个位于相同RFCOMM信道的已连接BluetoothSocket对象时，则说明成功建立连接。 此时，两者都可以获取输入输出流来开始数据传输，这将在连接管理这一节中讨论。 本节描述如何在两个设备间建立连接。\n服务端和客户端获取BluetoothSocket的方式是不一样的， 服务端在接受连接的时候获得一个BluetoothSocket，而客户端是在创建一个连接服务端的RFCOMM信道时获得。\n一个实现的方式是每台设备都自动初始化为服务端，这样每台设备都拥有一个开启的服务端socket用于侦听连接， 任意一个设备都可以作为客户端连接到其他设备。 还有一种方式是其中一台设备作为“主机”，开启一个服务端socket，其他设备只需要连接进来即可。\n注意：如果两个设备之前没有配对过，Android应用框架将在连接过程中自动显示一个配对请求的通知或者一个对话框。 所以在尝试连接时，你的应用程序不需要考虑设备间是否已配对。 你的RFCOMM连接会被阻塞知道用户成功完成配对。如果用户拒绝配对、配对失败或者超时，连接将会失败。\n作为服务端连接\n要在两个设备的应用之间建立连接，其中一台需要作为服务器端，保持一个开启的BluetoothServerSocket。 服务器端socket的目的是侦听接入的连接请求，当连接成功时，生成一个已连接的BluetoothSocket对象。 当BluetoothSocket对象从BluetoothServerSocket获得时，该BluetoothServerSocket可以（也应该）废弃了， 除非你想接受更多的连接。\n1.获得一个BluetoothServerSocket对象，通过调用listenUsingRfcommWithServiceRecord(String, UUID)\nString是你的设备名称，可以自定义。系统会自动将该string写入Service Discovery Protocol (SDP)数据库（设备名称可以随便设定，可以直接使用你的应用名称）。\nUUID也包含在SDP中，作为客户端连接协议的基础。就是客户端尝试连接时，连接信息会带上一个UUID，这个UUID是客户端想要连接的服务端的唯一鉴定标识。 UUID必须与服务端匹配，这样连接才会被接受。\n关于UUID\nUniversally Unique Identifier (UUID)是一个可以标准化为128位格式的字符串，用于唯一标识信息。\nUUID的好处在于它足够大，以至于你选择任意随机信息都不会重复。\n在这里，UUID用于标识应用程序的蓝牙服务端。\n你可以通过互联网上的随机UUID生成器来获得一个UUID字符串，然后用fromString(String)方法，初始化一个UUID用到应用程序中。\n2.调用accept()开始侦听连接请求。\n这是一个阻塞的调用。这个方法在连接成功建立或者错误发生时才会返回。 只有其他设备发送连接请求过来，并且请求中携带的UUID与服务端socket的UUID一致时，连接才会被接受。 当连接成功时，accept()将返回一个已连接的BluetoothSocket对象。\n3.除非想接受更多的连接，否则调用close()\n该方法将释放服务端socket以及它占用的所有资源，但不会关闭在accept()时返回的已连接BluetoothSocket对象。 跟TCP/IP不一样，RFCOMM只允许单个信道中存在一个连接。 所以大部分情况下，在连接建立之后，调用BluetoothServerSocket的close()方法就可以了。\naccept()方法不应在activity的UI线程中调用，因为它是阻塞的，运行时会阻碍程序的其他活动。 通常的做法是应用程序创建一个新线程去完成所有关于BluetoothServerSocket和BluetoothSocket的工作。 如果想中止一个类似accept()这样的阻塞调用，在其他线程调用BluetoothServerSocket (或BluetoothSocket)的close方法，阻塞的调用就会立刻返回。 BluetoothServerSocket和BluetoothSocket的所有方法都是线程安全的。\n示例：\nprivate class AcceptThread extends Thread {\nprivate final BluetoothServerSocket mmServerSocket;\npublic AcceptThread() {\n// Use a temporary object that is later assigned to mmServerSocket,\n// because mmServerSocket is final\nBluetoothServerSocket tmp = null;\ntry {\n// MY_UUID is the app’s UUID string, also used by the client code\ntmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);\n} catch (IOException e) { }\nmmServerSocket = tmp;\n}\npublic void run() {\nBluetoothSocket socket = null;\n// Keep listening until exception occurs or a socket is returned\nwhile (true) {\ntry {\nsocket = mmServerSocket.accept();\n} catch (IOException e) {\nbreak;\n}\n// If a connection was accepted\nif (socket != null) {\n// Do work to manage the connection (in a separate thread)\nmanageConnectedSocket(socket);\nmmServerSocket.close();\nbreak;\n}\n}\n}\n/** Will cancel the listening socket, and cause the thread to finish */\npublic void cancel() {\ntry {\nmmServerSocket.close();\n} catch (IOException e) { }\n}\n}\n在这个示例中，只需要一个接入连接，所以当一个连接被接受并获取到BluetoothSocket对象时，应用程序将BluetoothSocket发送到另一个线程， 关闭了BluetoothServerSocket并停止了while循环。\n需要注意的是，accept()返回的BluetoothSocket对象，内部的socket是已连接的，所以不需要像客户端那样调用connect().\nmanageConnectedSocket()是一个在应用程序中自定义的方法，作用是建立线程传输数据。这将在连接管理这一节中讨论。\n当你完成接入连接的侦听时，应该立刻关闭BluetoothServerSocket。 在示例中，得到BluetoothSocket对象时，立刻调用了close(). 你可以在你的线程中，提供一个public方法，在停止服务端侦听的时候，可以同时关闭私有的BluetoothSocket对象。\n作为客户端连接\n要建立与服务端设备的连接，你必须先获取一个代表该设备的BluetoothDevice对象（获取方式在上面的获取蓝牙设备）。 使用BluetoothDevice来获得一个BluetoothSocket，并建立连接。\n基本步骤如下：\n1.使用BluetoothDevice，调用createRfcommSocketToServiceRecord(UUID)获得一个BluetoothSocket\n这一步初始化一个BluetoothSocket对象用于连接BluetoothDevice。 这里传入的UUID必须与服务端BluetoothServerSocket开启时使用的UUID相匹配(服务端用listenUsingRfcommWithServiceRecord(String, UUID))。 只要同时在服务端和客户端应用程序用相同的UUID字符串硬编码，就可以得到相同的UUID。\n2.调用connect()建立连接\n在调用的过程中，服务端系统会执行一个SDP检查UUID是否匹配。 如果匹配则接受连接，分享RFCOMM信道，connect()就会返回。 该方法是一个阻塞调用。如果连接失败或者conntct()方法超时(大概12秒)或者其他任何原因，则会抛出一个异常。\n因为connect()是阻塞调用，该连接步骤最好放在与主activity线程分离的新线程中执行。\n注意:你必须确保在调用connect()时，设备没有在进行搜寻其他设备的活动。否则连接会明显变得很慢并且很容易失败。\n示例\n这是在一个线程中建立蓝牙连接的基本示例:\nprivate class ConnectThread extends Thread {\nprivate final BluetoothSocket mmSocket;\nprivate final BluetoothDevice mmDevice;\npublic ConnectThread(BluetoothDevice device) {\n// Use a temporary object that is later assigned to mmSocket,\n// because mmSocket is final\nBluetoothSocket tmp = null;\nmmDevice = device;\n// Get a BluetoothSocket to connect with the given BluetoothDevice\ntry {\n// MY_UUID is the app’s UUID string, also used by the server code\ntmp = device.createRfcommSocketToServiceRecord(MY_UUID);\n} catch (IOException e) { }\nmmSocket = tmp;\n}\npublic void run() {\n// Cancel discovery because it will slow down the connection\nmBluetoothAdapter.cancelDiscovery();\ntry {\n// Connect the device through the socket. This will block\n// until it succeeds or throws an exception\nmmSocket.connect();\n} catch (IOException connectException) {\n// Unable to connect; close the socket and get out\ntry {\nmmSocket.close();\n} catch (IOException closeException) { }\nreturn;\n}\n// Do work to manage the connection (in a separate thread)\nmanageConnectedSocket(mmSocket);\n}\n/** Will cancel an in-progress connection, and close the socket */\npublic void cancel() {\ntry {\nmmSocket.close();\n} catch (IOException e) { }\n}\n}\n需要注意的是在连接开始前调用了cancelDiscovery()，你每次连接前都应该这样做， 调用cancelDiscovery()是安全的，不需要检查设备搜寻是否真的在运行(如果你想检查，可以调用isDiscovering())。\nmanageConnectedSocket()是一个在应用程序中自定义的方法，作用是建立线程传输数据。这将在连接管理这一节中讨论。\n当你用BluetoothSocket完成相关工作之后，记得调用close()来释放。 调用该函数将会立刻关闭socket并清除所有内部资源。\n连接管理\n当你成功将两个设备连接起来时，每个设备都拥有一个已连接的BluetoothSocket。 乐趣就从此开始了，因为你可以在两台设备间分享数据。 通过使用BluetoothSocket，传输数据的过程非常简单：\n1.通过socket获取InputStream和OutputStream来操纵传输，分别使用getInputStream()和getOutputStream()即可。\n2.用read(byte[]) 和 write(byte[])在数据流中读写数据。\n就这么简单。\n当然，还有一些实现细节需要考虑。 首先，同时也是最重要的，是使用一个专门的线程来运行所有的数据流读写。 这非常重要，因为read(byte[]) 和 write(byte[])方法都是阻塞的调用。 read(byte[])方法会一直阻塞，直到从数据流上读取到数据。 write(byte[])一般不会阻塞，但是如果对方设备没有及时调用read(byte[])导致临时缓冲区满了的情况下，该方法会阻塞住便于流控制。 所以，你的线程的主循环可以专门用来InputStream读取，然后实现线程的另一个public方法用于OutputStream写入。\n示例\nprivate class ConnectedThread extends Thread {\nprivate final BluetoothSocket mmSocket;\nprivate final InputStream mmInStream;\nprivate final OutputStream mmOutStream;\npublic ConnectedThread(BluetoothSocket socket) {\nmmSocket = socket;\nInputStream tmpIn = null;\nOutputStream tmpOut = null;\n// Get the input and output streams, using temp objects because\n// member streams are final\ntry {\ntmpIn = socket.getInputStream();\ntmpOut = socket.getOutputStream();\n} catch (IOException e) { }\nmmInStream = tmpIn;\nmmOutStream = tmpOut;\n}\npublic void run() {\nbyte[] buffer = new byte[1024]; // buffer store for the stream\nint bytes; // bytes returned from read()\n// Keep listening to the InputStream until an exception occurs\nwhile (true) {\ntry {\n// Read from the InputStream\nbytes = mmInStream.read(buffer);\n// Send the obtained bytes to the UI activity\nmHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)\n.sendToTarget();\n} catch (IOException e) {\nbreak;\n}\n}\n}\n/* Call this from the main activity to send data to the remote device */\npublic void write(byte[] bytes) {\ntry {\nmmOutStream.write(bytes);\n} catch (IOException e) { }\n}\n/* Call this from the main activity to shutdown the connection */\npublic void cancel() {\ntry {\nmmSocket.close();\n} catch (IOException e) { }\n}\n}\n构造函数获取必须的数据流对象，而且一旦执行，线程就会通过InputStream等待数据进入。 当read(byte[])返回数据流上的数据，这些数据就会通过父类的成员Handler被发送到主activity。 然后循环回来继续等待更多数据。\n向外发送数据很简单，只需要在主activity调用write()方法，并在参数中传递需要发送的数据。 该方法直接调用write(byte[])发送数据到对方设备。\n线程的cancel()方法非常重要，这样才能在任何时候通过关闭BluetoothSocket来中断连接。 当你使用完蓝牙连接之后，记得调用cancel()。\n更多关于使用蓝牙API的范例，可以看蓝牙聊天的示例应用. http://developer.android.com/resources/samples/BluetoothChat/index.html\n在蓝牙规范协议下工作\n从Android 3.0开始，蓝牙API就包含了Bluetooth profiles的支持。 Bluetooth profiles是设备间基于蓝牙通讯的无线接口协议描述。 比如免提协议(Hands-Free)，手机如果要与无线耳机连接，两者都要支持免提协议。\n你可以在自己的class中实现BluetoothProfile接口，用于支持特定的Bluetooth profile. Android蓝牙API提供了以下Bluetooth profiles的实现：\n蓝牙耳机： 蓝牙耳机协议提供了蓝牙耳机在手机上使用的支持。Android提供了BluetoothHeadset类， 这是通过IPC(interprocess communication)控制蓝牙耳机服务的代理。 同时包含了蓝牙耳机(Bluetooth Headset)和免提(Hands-Free v1.5)协议。 BluetoothHeadset类还包含了AT命令的支持。更多信息请查看Vendor-specific AT commands。\nA2DP: A2DP(Advanced Audio Distribution Profile),高质量音频分发协议定义了高质量音频的数据流如何通过蓝牙连接从一个设备传输到另一个。 Android提供了BluetoothA2dp类，这是一个通过IPC(interprocess communication)控制蓝牙A2DP服务的代理。\n医疗设备： Android 4.0 (API level 14)引入了HDP(Bluetooth Health Device Profile)的支持。 可以让你的应用程序使用蓝牙连接那些支持蓝牙的医疗设备。 例如心率监视器、血压计、体温计等。 网站www.bluetooth.org的Bluetooth Assigned Numbers记录了关于已支持设备的列表和他们的相关设备数据代码。 这些数值也收录在ISO/IEEE 11073-20601 [7] specification as MDC_DEV_SPEC_PROFILE_* in the Nomenclature Codes Annex. 更多关于HDP的信息请查看Health Device Profile。\n下面是在蓝牙规范协议下工作的基本步骤：\n1.获取默认的适配器，在配置蓝牙这一节中描述过的。\n2.使用getProfileProxy()方法建立到协议相关联的代理对象的连接。\n在下面的示例中，协议代理对象就是一个BluetoothHeadset实例。\n3.创建一个BluetoothProfile.ServiceListener\n这个listener可以侦听BluetoothProfile IPC客户端的连接或断开服务。\n4.在onServiceConnected()中，获得profile代理对象的句柄。\n5.一旦你获得profile proxy对象，你可以用它监视连接状态，还可以执行其他相关的操作。\n下面的代码片段介绍了如何连接一个BluetoothHeadset代理对象，并用来控制Headset协议。\nBluetoothHeadset mBluetoothHeadset;\n// Get the default adapter\nBluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();\n// Establish connection to the proxy.\nmBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);\nprivate BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {\npublic void onServiceConnected(int profile, BluetoothProfile proxy) {\nif (profile == BluetoothProfile.HEADSET) {\nmBluetoothHeadset = (BluetoothHeadset) proxy;\n}\n}\npublic void onServiceDisconnected(int profile) {\nif (profile == BluetoothProfile.HEADSET) {\nmBluetoothHeadset = null;\n}\n}\n};\n// … call functions on mBluetoothHeadset\n// Close proxy connection after use.\nmBluetoothAdapter.closeProfileProxy(mBluetoothHeadset);\nVendor-specific AT commands\n从Android 3.0开始，应用程序就可以注册接收耳机发送的pre-defined vendor-specific AT commands系统广播（类似Plantronics +XEVENT命令）。 例如，一个应用程序可以接收指示已连接设备电量等级的广播，然后通知用户或者采取其他必要的措施。 创建一个ACTION_VENDOR_SPECIFIC_HEADSET_EVENT intent的broadcast receiver，即可处理vendor-specific AT commands。\nHealth Device Profile\n蓝牙对讲 http://developer.android.com/resources/samples/BluetoothChat/index.html\n−\n蓝牙医疗设备(Health Device Profile)，比如心率监视器，血液米，温度计等。http://developer.android.com/resources/samples/BluetoothHDP/index.html\n+\n蓝牙医疗设备(Health Device Profile)，比如心率监视器，血压计，温度计等。http://developer.android.com/resources/samples/BluetoothHDP/index.html\n==基本原理==\n==基本原理==\n第129行： 第129行：\n==获取蓝牙设备==\n==获取蓝牙设备==\n+\n使用BluetoothAdapter，你可以通过搜寻设备或者查询已配对设备列表来获取其他蓝牙设备。\n+\n+\n+\n搜寻设备是一个搜索附近开启蓝牙的设备并获取设备相关信息的检测过程。\n+\n附近的蓝牙设备，必须是开启了蓝牙可检测性，才会被你的设备所检测到。\n+\n如果附近一个设备开启了可检测性，它将发送一些信息来回应搜索的请求，比如设备名称、类型以及它的MAC地址。\n+\n你的设备可以通过这些信息，初始化一个和被发现设备的连接。\n+\n+\n+\n当与一个从未连接过的设备进行连接的时候，一个蓝牙配对请求会自动呈现给用户。\n+\n配对完成后，该设备的基本信息（比如设备名称、类型和MAC地址）就被保存下来并可以使用相关的API函数读取。\n+\n使用这个已知的MAC地址，连接就可以随时进行而不再需要进行搜索（前提是该设备在蓝牙范围内）。\n+\n+\n+\n已配对和已连接是不一样的概念，已配对表示两台设备间已经认识了彼此的存在，共享一个用于认证身份的link-key，并能够互相建立加密连接。\n+\n已连接表示两台设备当前正在共享一个RFCOMM信道，并能够互相传输数据。\n+\n目前Android Bluetooth API要求设备在建立RFCOMM连接之前必须先进行配对。\n+\n（当你用蓝牙API初始化一个加密连接时，配对会自动进行。）\n+\n+\n+\n下面的小节讲解如何获得已配对的设备和使用设备搜寻发现新设备。\n+\n+\n**注意：**安卓蓝牙设备默认是不开启可检测性的。\n+\n用户可以通过系统设置将蓝牙可检测性临时打开一段时间，\n+\n应用程序也可以向用户请求打开可检测性，而不需要离开当前程序。\n+\n后面会说明如何开启可检测性。\n===查询已配对设备===\n===查询已配对设备===\n+\n+\n在进行设备搜寻之前，最好先查询一下已配对设备的列表，看看想要连接的设备是否已经配对过了。\n+\n调用getBondedDevices()即可。这将返回一个BluetoothDevice对象的set，表示已配对设备的集合。\n+\n例如，你可以查询所有已配对设备并显示每个设备的名称，通过使用ArrayAdapter：\n+\nSet pairedDevices = mBluetoothAdapter.getBondedDevices();\n+\n// If there are paired devices\n+\nif (pairedDevices.size() \u0026gt; 0) {\n+\n// Loop through paired devices\n+\nfor (BluetoothDevice device : pairedDevices) {\n+\n// Add the name and address to an array adapter to show in a ListView\n+\nmArrayAdapter.add(device.getName() + “\\n” + device.getAddress());\n+\n}\n+\n}\n+\n+\nBluetoothDevice对象初始化一个连接所需要的唯一信息就是MAC地址。\n+\n在这个示例中，MAC地址作为ArrayAdapter的一部分显示出来。后续可用于初始化连接。\n+\n更多关于创建连接的信息请查看[[#设备连接|设备连接]]。\n===搜索设备===\n===搜索设备===\n+\n调用startDiscovery()即可开始设备搜寻。搜寻过程是异步的，该方法会立刻返回一个boolean值表示搜寻是否成功开始。\n+\n搜寻过程通常是一个十二秒的查询扫描，然后列出一页扫描到的设备的名称。\n+\n+\n+\n应用程序必须注册一个关于ACTION_FOUND Intent的BroadcastReceiver，才能接收每个搜寻到的设备的信息。每搜寻到一个设备，系统都会广播ACTION_FOUND Intent。\n+\nIntent里面包含额外的字段EXTRA_DEVICE和EXTRA_CLASS，分部包含一个BluetoothDevice和一个BluetoothClass。\n+\n以下代码说明如何注册接收和处理设备被搜寻到的信息：\n+\n+\n// Create a BroadcastReceiver for ACTION_FOUND\n+\nprivate final BroadcastReceiver mReceiver = new BroadcastReceiver() {\n+\npublic void onReceive(Context context, Intent intent) {\n+\nString action = intent.getAction();\n+\n// When discovery finds a device\n+\nif (BluetoothDevice.ACTION_FOUND.equals(action)) {\n+\n// Get the BluetoothDevice object from the Intent\n+\nBluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);\n+\n// Add the name and address to an array adapter to show in a ListView\n+\nmArrayAdapter.add(device.getName() + “\\n” + device.getAddress());\n+\n}\n+\n}\n+\n};\n+\n// Register the BroadcastReceiver\n+\nIntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);\n+\nregisterReceiver(mReceiver, filter); // Don’t forget to unregister during onDestroy\n+\n+\n**警告: **进行设备搜寻对于蓝牙适配器来说是一个繁重的过程并会消耗大量资源。\n+\n当你搜寻到一个可连接设备时，请确保在尝试连接之前，调用cancelDiscovery()来停止设备搜寻。\n+\n并且，当你已经与一个设备建立了连接时，进行设备搜寻会显著降低该连接的可用带宽。所以，在已有连接时，最好不要进行搜寻。\n===开启蓝牙可检测性===\n===开启蓝牙可检测性===\n+\n+\n如果你想要本设备能被其他蓝牙设备搜寻到，调用startActivityForResult(Intent, int)，Intent为ACTION_REQUEST_DISCOVERABLE action 。\n+\n这样会通过系统设置发出一个开启蓝牙可检测性的请求（不需要退出你的应用程序）。\n+\n默认情况下，本设备将变为可检测模式，持续120秒。\n+\n你可以通过额外添加EXTRA_DISCOVERABLE_DURATION到Intent来定义不同的持续时间。\n+\n应用程序能设置的最大持续时间为3600秒，设为0则让设备一直保持可检测状态（任何小于0或大于3600的值，会自动设为120秒）。\n+\n例如，以下代码设置持续时间为300秒：\n+\n+\nIntent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);\n+\ndiscoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);\n+\nstartActivity(discoverableIntent);\n+\n+\n在向用户请求开启可检测性时，一个对话框会弹出来。\n+\n如果用户选择“是”，设备将在指定的持续时间内开启可检测性。\n+\n你的应用程序将接收到onActivityResult()的回调，回调的结果码表示可检测性持续的时间。\n+\n如果用户选择“否”或者发生错误，结果码将是RESULT_CANCELED。\n+\n+\n注意如果蓝牙功能没有开启，开启可检测性会自动开启蓝牙功能。\n+\n+\n+\n在预定的时间内，设备会静默地保持可检测性。\n+\n如果你想在可检测模式变化时收到相应的通知，可以注册关于ACTION_SCAN_MODE_CHANGED Intent的BroadcastReceiver。\n+\n里面包含EXTRA_SCAN_MODE 和 EXTRA_PREVIOUS_SCAN_MODE的额外字段，分别表示新的和旧的状态。\n+\n可能的值是SCAN_MODE_CONNECTABLE_DISCOVERABLE, SCAN_MODE_CONNECTABLE, SCAN_MODE_NONE，分别表示设备处于可检测可连接状态，\n+\n或者不可检测但可连接，或者不可检测不可连接。\n+\n+\n+\n如果你只想要连接附近的设备，不需要打开可检测性。\n+\n只有在你希望应用程序作为蓝牙socket服务端，接收来自其他设备的连接时，才需要打开可检测性。\n+\n因为其他设备在发起一个连接前，需要检测到你的设备。\n==设备连接==\n==设备连接==\n+\n要在两个设备的应用之间建立连接，必须实现服务端和客户端的机制。\n+\n因为其中一个设备必须开启一个server socket，然后另一个设备才能接入进来（通过服务端设备的MAC地址建立连接）。\n+\n当服务端和客户端分别得到一个位于相同RFCOMM信道的已连接BluetoothSocket对象时，则说明成功建立连接。\n+\n此时，两者都可以获取输入输出流来开始数据传输，这将在[[#连接管理|连接管理]]这一节中讨论。\n+\n本节描述如何在两个设备间建立连接。\n服务端和客户端获取BluetoothSocket的方式是不一样的，\n+\n服务端在接受连接的时候获得一个BluetoothSocket，而客户端是在创建一个连接服务端的RFCOMM信道时获得。\n+\n+\n一个实现的方式是每台设备都自动初始化为服务端，这样每台设备都拥有一个开启的服务端socket用于侦听连接，\n+\n任意一个设备都可以作为客户端连接到其他设备。\n+\n还有一种方式是其中一台设备作为“主机”，开启一个服务端socket，其他设备只需要连接进来即可。\n+\n+\n**注意：**如果两个设备之前没有配对过，Android应用框架将在连接过程中自动显示一个配对请求的通知或者一个对话框。\n+\n所以在尝试连接时，你的应用程序不需要考虑设备间是否已配对。\n+\n你的RFCOMM连接会被阻塞知道用户成功完成配对。如果用户拒绝配对、配对失败或者超时，连接将会失败。\n===作为服务端连接===\n===作为服务端连接===\n+\n+\n要在两个设备的应用之间建立连接，其中一台需要作为服务器端，保持一个开启的BluetoothServerSocket。\n+\n服务器端socket的目的是侦听接入的连接请求，当连接成功时，生成一个已连接的BluetoothSocket对象。\n+\n当BluetoothSocket对象从BluetoothServerSocket获得时，该BluetoothServerSocket可以（也应该）废弃了，\n+\n除非你想接受更多的连接。\n+\n+\n1.获得一个BluetoothServerSocket对象，通过调用listenUsingRfcommWithServiceRecord(String, UUID)\n+\n+\nString是你的设备名称，可以自定义。系统会自动将该string写入Service Discovery Protocol (SDP)数据库（设备名称可以随便设定，可以直接使用你的应用名称）。\n+\n+\nUUID也包含在SDP中，作为客户端连接协议的基础。就是客户端尝试连接时，连接信息会带上一个UUID，这个UUID是客户端想要连接的服务端的唯一鉴定标识。\n+\nUUID必须与服务端匹配，这样连接才会被接受。\n+\n+\n关于UUID\n+\nUniversally Unique Identifier (UUID)是一个可以标准化为128位格式的字符串，用于唯一标识信息。\n+\nUUID的好处在于它足够大，以至于你选择任意随机信息都不会重复。\n+\n在这里，UUID用于标识应用程序的蓝牙服务端。\n+\n你可以通过互联网上的随机UUID生成器来获得一个UUID字符串，然后用fromString(String)方法，初始化一个UUID用到应用程序中。\n+\n+\n2.调用accept()开始侦听连接请求。\n+\n+\n这是一个阻塞的调用。这个方法在连接成功建立或者错误发生时才会返回。\n+\n只有其他设备发送连接请求过来，并且请求中携带的UUID与服务端socket的UUID一致时，连接才会被接受。\n+\n当连接成功时，accept()将返回一个已连接的BluetoothSocket对象。\n+\n+\n3.除非想接受更多的连接，否则调用close()\n+\n+\n该方法将释放服务端socket以及它占用的所有资源，但不会关闭在accept()时返回的已连接BluetoothSocket对象。\n+\n跟TCP/IP不一样，RFCOMM只允许单个信道中存在一个连接。\n+\n所以大部分情况下，在连接建立之后，调用BluetoothServerSocket的close()方法就可以了。\n+\n+\n+\naccept()方法不应在activity的UI线程中调用，因为它是阻塞的，运行时会阻碍程序的其他活动。\n+\n通常的做法是应用程序创建一个新线程去完成所有关于BluetoothServerSocket和BluetoothSocket的工作。\n+\n如果想中止一个类似accept()这样的阻塞调用，在其他线程调用BluetoothServerSocket (或BluetoothSocket)的close方法，阻塞的调用就会立刻返回。\n+\nBluetoothServerSocket和BluetoothSocket的所有方法都是线程安全的。\n+\n+\n+\n示例：\n+\n+\nprivate class AcceptThread extends Thread {\n+\nprivate final BluetoothServerSocket mmServerSocket;\n+\npublic AcceptThread() {\n+\n// Use a temporary object that is later assigned to mmServerSocket,\n+\n// because mmServerSocket is final\n+\nBluetoothServerSocket tmp = null;\n+\ntry {\n+\n// MY_UUID is the app’s UUID string, also used by the client code\n+\ntmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);\n+\n} catch (IOException e) { }\n+\nmmServerSocket = tmp;\n+\n}\n+\npublic void run() {\n+\nBluetoothSocket socket = null;\n+\n// Keep listening until exception occurs or a socket is returned\n+\nwhile (true) {\n+\ntry {\n+\nsocket = mmServerSocket.accept();\n+\n} catch (IOException e) {\n+\nbreak;\n+\n}\n+\n// If a connection was accepted\n+\nif (socket != null) {\n+\n// Do work to manage the connection (in a separate thread)\n+\nmanageConnectedSocket(socket);\n+\nmmServerSocket.close();\n+\nbreak;\n+\n}\n+\n}\n+\n}\n+\n/** Will cancel the listening socket, and cause the thread to finish */\n+\npublic void cancel() {\n+\ntry {\n+\nmmServerSocket.close();\n+\n} catch (IOException e) { }\n+\n}\n+\n}\n+\n+\n在这个示例中，只需要一个接入连接，所以当一个连接被接受并获取到BluetoothSocket对象时，应用程序将BluetoothSocket发送到另一个线程，\n+\n关闭了BluetoothServerSocket并停止了while循环。\n+\n+\n需要注意的是，accept()返回的BluetoothSocket对象，内部的socket是已连接的，所以不需要像客户端那样调用connect().\n+\n+\nmanageConnectedSocket()是一个在应用程序中自定义的方法，作用是建立线程传输数据。这将在[[#连接管理|连接管理]]这一节中讨论。\n+\n+\n当你完成接入连接的侦听时，应该立刻关闭BluetoothServerSocket。\n+\n在示例中，得到BluetoothSocket对象时，立刻调用了close().\n+\n你可以在你的线程中，提供一个public方法，在停止服务端侦听的时候，可以同时关闭私有的BluetoothSocket对象。\n===作为客户端连接===\n===作为客户端连接===\n+\n+\n要建立与服务端设备的连接，你必须先获取一个代表该设备的BluetoothDevice对象（获取方式在上面的[[#获取蓝牙设备|获取蓝牙设备]]）。\n+\n使用BluetoothDevice来获得一个BluetoothSocket，并建立连接。\n+\n+\n+\n基本步骤如下：\n+\n+\n1.使用BluetoothDevice，调用createRfcommSocketToServiceRecord(UUID)获得一个BluetoothSocket\n+\n+\n这一步初始化一个BluetoothSocket对象用于连接BluetoothDevice。\n+\n这里传入的UUID必须与服务端BluetoothServerSocket开启时使用的UUID相匹配(服务端用listenUsingRfcommWithServiceRecord(String, UUID))。\n+\n只要同时在服务端和客户端应用程序用相同的UUID字符串硬编码，就可以得到相同的UUID。\n+\n+\n2.调用connect()建立连接\n+\n+\n在调用的过程中，服务端系统会执行一个SDP检查UUID是否匹配。\n+\n如果匹配则接受连接，分享RFCOMM信道，connect()就会返回。\n+\n该方法是一个阻塞调用。如果连接失败或者conntct()方法超时(大概12秒)或者其他任何原因，则会抛出一个异常。\n+\n+\n因为connect()是阻塞调用，该连接步骤最好放在与主activity线程分离的新线程中执行。\n+\n+\n**注意:**你必须确保在调用connect()时，设备没有在进行搜寻其他设备的活动。否则连接会明显变得很慢并且很容易失败。\n+\n+\n示例\n+\n+\n这是在一个线程中建立蓝牙连接的基本示例:\n+\n+\nprivate class ConnectThread extends Thread {\n+\nprivate final BluetoothSocket mmSocket;\n+\nprivate final BluetoothDevice mmDevice;\n+\npublic ConnectThread(BluetoothDevice device) {\n+\n// Use a temporary object that is later assigned to mmSocket,\n+\n// because mmSocket is final\n+\nBluetoothSocket tmp = null;\n+\nmmDevice = device;\n+\n// Get a BluetoothSocket to connect with the given BluetoothDevice\n+\ntry {\n+\n// MY_UUID is the app’s UUID string, also used by the server code\n+\ntmp = device.createRfcommSocketToServiceRecord(MY_UUID);\n+\n} catch (IOException e) { }\n+\nmmSocket = tmp;\n+\n}\n+\npublic void run() {\n+\n// Cancel discovery because it will slow down the connection\n+\nmBluetoothAdapter.cancelDiscovery();\n+\ntry {\n+\n// Connect the device through the socket. This will block\n+\n// until it succeeds or throws an exception\n+\nmmSocket.connect();\n+\n} catch (IOException connectException) {\n+\n// Unable to connect; close the socket and get out\n+\ntry {\n+\nmmSocket.close();\n+\n} catch (IOException closeException) { }\n+\nreturn;\n+\n}\n+\n// Do work to manage the connection (in a separate thread)\n+\nmanageConnectedSocket(mmSocket);\n+\n}\n+\n/** Will cancel an in-progress connection, and close the socket */\n+\npublic void cancel() {\n+\ntry {\n+\nmmSocket.close();\n+\n} catch (IOException e) { }\n+\n}\n+\n}\n+\n+\n需要注意的是在连接开始前调用了cancelDiscovery()，你每次连接前都应该这样做，\n+\n调用cancelDiscovery()是安全的，不需要检查设备搜寻是否真的在运行(如果你想检查，可以调用isDiscovering())。\n+\n+\nmanageConnectedSocket()是一个在应用程序中自定义的方法，作用是建立线程传输数据。这将在[[#连接管理|连接管理]]这一节中讨论。\n+\n+\n当你用BluetoothSocket完成相关工作之后，记得调用close()来释放。\n+\n调用该函数将会立刻关闭socket并清除所有内部资源。\n==连接管理==\n==连接管理==\n+\n当你成功将两个设备连接起来时，每个设备都拥有一个已连接的BluetoothSocket。\n+\n乐趣就从此开始了，因为你可以在两台设备间分享数据。\n+\n通过使用BluetoothSocket，传输数据的过程非常简单：\n+\n+\n1.通过socket获取InputStream和OutputStream来操纵传输，分别使用getInputStream()和getOutputStream()即可。\n+\n+\n2.用read(byte[]) 和 write(byte[])在数据流中读写数据。\n+\n+\n就这么简单。\n+\n+\n当然，还有一些实现细节需要考虑。\n+\n首先，同时也是最重要的，是使用一个专门的线程来运行所有的数据流读写。\n+\n这非常重要，因为read(byte[]) 和 write(byte[])方法都是阻塞的调用。\n+\nread(byte[])方法会一直阻塞，直到从数据流上读取到数据。\n+\nwrite(byte[])一般不会阻塞，但是如果对方设备没有及时调用read(byte[])导致临时缓冲区满了的情况下，该方法会阻塞住便于流控制。\n+\n所以，你的线程的主循环可以专门用来InputStream读取，然后实现线程的另一个public方法用于OutputStream写入。\n+\n+\n示例\n+\n+\nprivate class ConnectedThread extends Thread {\n+\nprivate final BluetoothSocket mmSocket;\n+\nprivate final InputStream mmInStream;\n+\nprivate final OutputStream mmOutStream;\n+\npublic ConnectedThread(BluetoothSocket socket) {\n+\nmmSocket = socket;\n+\nInputStream tmpIn = null;\n+\nOutputStream tmpOut = null;\n+\n// Get the input and output streams, using temp objects because\n+\n// member streams are final\n+\ntry {\n+\ntmpIn = socket.getInputStream();\n+\ntmpOut = socket.getOutputStream();\n+\n} catch (IOException e) { }\n+\nmmInStream = tmpIn;\n+\nmmOutStream = tmpOut;\n+\n}\n+\npublic void run() {\n+\nbyte[] buffer = new byte[1024]; // buffer store for the stream\n+\nint bytes; // bytes returned from read()\n+\n// Keep listening to the InputStream until an exception occurs\n+\nwhile (true) {\n+\ntry {\n+\n// Read from the InputStream\n+\nbytes = mmInStream.read(buffer);\n+\n// Send the obtained bytes to the UI activity\n+\nmHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)\n+\n.sendToTarget();\n+\n} catch (IOException e) {\n+\nbreak;\n+\n}\n+\n}\n+\n}\n+\n/* Call this from the main activity to send data to the remote device */\n+\npublic void write(byte[] bytes) {\n+\ntry {\n+\nmmOutStream.write(bytes);\n+\n} catch (IOException e) { }\n+\n}\n+\n/* Call this from the main activity to shutdown the connection */\n+\npublic void cancel() {\n+\ntry {\n+\nmmSocket.close();\n+\n} catch (IOException e) { }\n+\n}\n+\n}\n+\n+\n构造函数获取必须的数据流对象，而且一旦执行，线程就会通过InputStream等待数据进入。\n+\n当read(byte[])返回数据流上的数据，这些数据就会通过父类的成员Handler被发送到主activity。\n+\n然后循环回来继续等待更多数据。\n+\n+\n向外发送数据很简单，只需要在主activity调用write()方法，并在参数中传递需要发送的数据。\n+\n该方法直接调用write(byte[])发送数据到对方设备。\n+\n+\n线程的cancel()方法非常重要，这样才能在任何时候通过关闭BluetoothSocket来中断连接。\n+\n当你使用完蓝牙连接之后，记得调用cancel()。\n+\n+\n更多关于使用蓝牙API的范例，可以看蓝牙聊天的示例应用. http://developer.android.com/resources/samples/BluetoothChat/index.html\n==在蓝牙规范协议下工作==\n==在蓝牙规范协议下工作==\n+\n从Android 3.0开始，蓝牙API就包含了Bluetooth profiles的支持。\n+\nBluetooth profiles是设备间基于蓝牙通讯的无线接口协议描述。\n+\n比如免提协议(Hands-Free)，手机如果要与无线耳机连接，两者都要支持免提协议。\n+\n+\n你可以在自己的class中实现BluetoothProfile接口，用于支持特定的Bluetooth profile.\n+\nAndroid蓝牙API提供了以下Bluetooth profiles的实现：\n+\n+\n蓝牙耳机：\n+\n蓝牙耳机协议提供了蓝牙耳机在手机上使用的支持。Android提供了BluetoothHeadset类，\n+\n这是通过IPC(interprocess communication)控制蓝牙耳机服务的代理。\n+\n同时包含了蓝牙耳机(Bluetooth Headset)和免提(Hands-Free v1.5)协议。\n+\nBluetoothHeadset类还包含了AT命令的支持。更多信息请查看[[#Vendor-specific AT commands|Vendor-specific AT commands]]。\n+\n+\nA2DP:\n+\nA2DP(Advanced Audio Distribution Profile),高质量音频分发协议定义了高质量音频的数据流如何通过蓝牙连接从一个设备传输到另一个。\n+\nAndroid提供了BluetoothA2dp类，这是一个通过IPC(interprocess communication)控制蓝牙A2DP服务的代理。\n+\n+\n医疗设备：\n+\nAndroid 4.0 (API level 14)引入了HDP(Bluetooth Health Device Profile)的支持。\n+\n可以让你的应用程序使用蓝牙连接那些支持蓝牙的医疗设备。\n+\n例如心率监视器、血压计、体温计等。\n+\n网站www.bluetooth.org的Bluetooth Assigned Numbers记录了关于已支持设备的列表和他们的相关设备数据代码。\n+\n这些数值也收录在ISO/IEEE 11073-20601 [7] specification as MDC_DEV_SPEC_PROFILE_* in the Nomenclature Codes Annex.\n+\n更多关于HDP的信息请查看[[#Health Device Profile|Health Device Profile]]。\n+\n+\n下面是在蓝牙规范协议下工作的基本步骤：\n+\n+\n1.获取默认的适配器，在[[#配置蓝牙|配置蓝牙]]这一节中描述过的。\n+\n+\n2.使用getProfileProxy()方法建立到协议相关联的代理对象的连接。\n+\n+\n在下面的示例中，协议代理对象就是一个BluetoothHeadset实例。\n+\n+\n3.创建一个BluetoothProfile.ServiceListener\n+\n+\n这个listener可以侦听BluetoothProfile IPC客户端的连接或断开服务。\n+\n+\n4.在onServiceConnected()中，获得profile代理对象的句柄。\n+\n+\n5.一旦你获得profile proxy对象，你可以用它监视连接状态，还可以执行其他相关的操作。\n+\n+\n下面的代码片段介绍了如何连接一个BluetoothHeadset代理对象，并用来控制Headset协议。\n+\n+\nBluetoothHeadset mBluetoothHeadset;\n+\n// Get the default adapter\n+\nBluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();\n+\n// Establish connection to the proxy.\n+\nmBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);\n+\nprivate BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {\n+\npublic void onServiceConnected(int profile, BluetoothProfile proxy) {\n+\nif (profile == BluetoothProfile.HEADSET) {\n+\nmBluetoothHeadset = (BluetoothHeadset) proxy;\n+\n}\n+\n}\n+\npublic void onServiceDisconnected(int profile) {\n+\nif (profile == BluetoothProfile.HEADSET) {\n+\nmBluetoothHeadset = null;\n+\n}\n+\n}\n+\n};\n+\n// … call functions on mBluetoothHeadset\n+\n// Close proxy connection after use.\n+\nmBluetoothAdapter.closeProfileProxy(mBluetoothHeadset);\n===Vendor-specific AT commands===\n===Vendor-specific AT commands===\n+\n从Android 3.0开始，应用程序就可以注册接收耳机发送的pre-defined vendor-specific AT commands系统广播（类似Plantronics +XEVENT命令）。\n+\n例如，一个应用程序可以接收指示已连接设备电量等级的广播，然后通知用户或者采取其他必要的措施。\n+\n创建一个ACTION_VENDOR_SPECIFIC_HEADSET_EVENT intent的broadcast receiver，即可处理vendor-specific AT commands。\n===Health Device Profile===\n===Health Device Profile===\n","permalink":"https://blog.zdltech.com/posts/android%E8%93%9D%E7%89%99/","summary":"\u003cp\u003e\u003ca href=\"http://wenku.baidu.com/link?url=lAOm\"\u003ehttp://wenku.baidu.com/link?url=lAOm\u003c/a\u003e_kIF29t-JGoUnKAFSY4BhMP6vv-Cvfx9x1_oVSTZ1QDMm6URT7fhRR8ODX7aBVSX8ffOD0LnI-TX4PaRTqzXPWwJdOhBNXMu0lg214O\u003cbr\u003e\n\u003ca href=\"http://wenku.baidu.com/view/490171b20242a8956bece47d.html?re=view\"\u003ehttp://wenku.baidu.com/view/490171b20242a8956bece47d.html?re=view\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"http://wenku.baidu.com/view/cf48328371fe910ef12df827.html\"\u003ehttp://wenku.baidu.com/view/cf48328371fe910ef12df827.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://wenku.baidu.com/view/490171b20242a8956bece47d.html?re=view\"\u003ehttp://wenku.baidu.com/view/490171b20242a8956bece47d.html?re=view\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"http://wenku.baidu.com/link?url=lAOm\"\u003ehttp://wenku.baidu.com/link?url=lAOm\u003c/a\u003e_kIF29t-JGoUnKAFSY4BhMP6vv-Cvfx9x1_oVSTZ1QDMm6URT7fhRR8ODX7aBVSX8ffOD0LnI-TX4PaRTqzXPWwJdOhBNXMu0lg214O\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eandroid平台包含了蓝牙网络协议栈的支持，允许android设备与其他蓝牙设备相互传输数据。应用层框架提供了API函数来访问蓝牙模块。使用这些API可以让应用程序连接其他蓝牙设备，实现点对点或多点无线传输。\u003cbr\u003e\n运用蓝牙API，可以实现以下功能：\u003cbr\u003e\n搜索其他蓝牙设备\u003cbr\u003e\n查询本地蓝牙适配器中已经配对好的设备\u003cbr\u003e\n建立RFCOMM协议通道\u003cbr\u003e\n通过服务端搜索连接到其他设备\u003cbr\u003e\n与其他设备互相传输数据\u003cbr\u003e\n管理多个连接\u003cbr\u003e\n快速阅读\u003cbr\u003e\nAndroid蓝牙API可以让应用程序与其他设备传输无线数据。\u003cbr\u003e\n关键类\u003cbr\u003e\nBluetoothAdapter\u003cbr\u003e\nBluetoothDevice\u003cbr\u003e\nBluetoothSocket\u003cbr\u003e\nBluetoothServerSocket\u003cbr\u003e\n相关用例\u003cbr\u003e\n蓝牙对讲 \u003ca href=\"http://developer.android.com/resources/samples/BluetoothChat/index.html\"\u003ehttp://developer.android.com/resources/samples/BluetoothChat/index.html\u003c/a\u003e\u003cbr\u003e\n蓝牙医疗设备(Health Device Profile)，比如心率监视器，血压计，温度计等。http://developer.android.com/resources/samples/BluetoothHDP/index.html\u003cbr\u003e\n目录 [隐藏]\u003cbr\u003e\n1 基本原理\u003cbr\u003e\n2 蓝牙权限\u003cbr\u003e\n3 配置蓝牙\u003cbr\u003e\n4 获取蓝牙设备\u003cbr\u003e\n4.1 查询已配对设备\u003cbr\u003e\n4.2 搜索设备\u003cbr\u003e\n4.3 开启蓝牙可检测性\u003cbr\u003e\n5 设备连接\u003cbr\u003e\n5.1 作为服务端连接\u003cbr\u003e\n5.2 作为客户端连接\u003cbr\u003e\n6 连接管理\u003cbr\u003e\n7 在蓝牙规范协议下工作\u003cbr\u003e\n7.1 Vendor-specific AT commands\u003cbr\u003e\n7.2 Health Device Profile\u003cbr\u003e\n基本原理\u003c/p\u003e\n\u003cp\u003e本文档描述了如何使用蓝牙API来完成蓝牙通讯的四项必要任务：配置蓝牙、搜索附件未配对或可用的蓝牙设备、连接设备、设备间传输数据。\u003cbr\u003e\n所有蓝牙API都包含在android.bluetooth包中。以下是建立蓝牙连接需要用到的类和接口的概要：\u003cbr\u003e\nBluetoothAdapter (蓝牙适配器)\u003cbr\u003e\n表示本地蓝牙适配器(蓝牙收发器). BluetoothAdapter是所有蓝牙活动的起始类. 可用于搜索其他蓝牙设备, 查询已配对设备的列表, 使用MAC地址实例化一个BluetoothDevice对象, 创建BluetoothServerSocket侦听其他设备的连接.\u003cbr\u003e\nBluetoothDevice (蓝牙设备)\u003cbr\u003e\n表示远程蓝牙设备。可以通过一个BluetoothSocket向它描述的远程设备发起连接，或者该设备的名称、地址、类、连接状态等信息。\u003cbr\u003e\nBluetoothSocket (蓝牙套接字)\u003cbr\u003e\n表示一个蓝牙套接字(与TCP Socket类似). 它是设备间的连接点，允许应用程序通过InputStream和OutputStream与其他设备进行数据传输。\u003cbr\u003e\nBluetoothServerSocket (蓝牙服务端套接字)\u003cbr\u003e\n表示一个开放的蓝牙服务器， 用于侦听其他设备发过来的连接请求(与TCP ServerSocket类似). 要将两台设备连接起来, 其中一台必须使用这个类开启一个server socket. 当远程蓝牙设备发起对server的连接请求, 如果连接被接受，BluetoothServerSocket将返回一个连接成功的BluetoothSocket对象.\u003cbr\u003e\nBluetoothClass (蓝牙类型)\u003cbr\u003e\n描述一个蓝牙设备的规格参数和功能。这是一个只读的属性集，定义了该设备的主要和次要设备种类和服务。它不能完全描述该设备的所有特性和服务，常用于判断设备的类型。\u003cbr\u003e\nBluetoothProfile (蓝牙规范协议)\u003cbr\u003e\n表示Bluetooth profile的接口. Bluetooth profile是设备间基于蓝牙通讯的接口规范协议。比如Hands-Free(非手持设备) profile。更多关于profiles的说明, 请查看Working with Profiles(在蓝牙规范协议下工作)。\u003cbr\u003e\nBluetoothHeadset (蓝牙耳机)\u003cbr\u003e\n提供手机使用蓝牙耳机的支持。同时包含了蓝牙耳机和Hands-Free(v1.5)的profiles.\u003cbr\u003e\nBluetoothA2dp (蓝牙A2dp)\u003cbr\u003e\n定义高质量音频流如何通过蓝牙连接传输到其他设备。”A2DP”是”Advanced Audio Distribution Profile”的缩写，表示高级音频分发规范协议。\u003cbr\u003e\nBluetoothHealth (蓝牙医疗设备)\u003cbr\u003e\n表示为医疗设备提供蓝牙服务的代理类。\u003cbr\u003e\nBluetoothHealthCallback\u003cbr\u003e\n这是一个抽象类，用于实现BluetoothHealth的callbacks方法。需要继承此类并实现callback方法才能接收应用程序状态和蓝牙频道状态的变化。\u003cbr\u003e\nBluetoothHealthAppConfiguration\u003cbr\u003e\n表示蓝牙医疗第三方应用与远程蓝牙医疗设备连接的配置参数。\u003cbr\u003e\nBluetoothProfile.ServiceListener (蓝牙规范协议服务侦听)\u003cbr\u003e\n一个接口类，当服务连接或断开的时候通知BluetoothProfile IPC 客户端。(这是内部服务运行的一个特殊模式)。\u003cbr\u003e\n蓝牙权限\u003c/p\u003e","title":"android蓝牙"},{"content":"https://github.com/search?p=4\u0026amp;q=iHealth\u0026amp;ref=searchresults\u0026amp;type=Repositories\u0026amp;utf8=%E2%9C%93\nhttps://github.com/lfreeman/ihealth\nhttps://github.com/Arunmainthan/iHealth\nhttps://github.com/oyachai/HearthSim/blob/master/docs/DeckFileSpecification.md\nhttps://github.com/house4hack/heartmonitor\nhttps://github.com/phishman3579/android-heart-rate-monitor\nhttp://sandbox.ihealthlabs.com/dev_documentation_openapidoc.htm\niHealth’s\nhttp://developer.ihealthlabs.com/index.htm\nhttp://www.mi.com/ihealth/#overall\nhttp://wenku.baidu.com/link?url=UdozX1eBzPZjrDC2IIbIlvzEi7hS8gXmQkH4RgNBI9FgAorMewSouiEBC9W7RHieklYjQsGaxlRERhtKZpUaxL7j3hctm3PdOKC-SiBxZMG\nhttp://www.leiphone.com/news/201406/qardioarm.html\nhttp://www.mymumu.com/user.php/Change\n爱牵挂老人智能腕表\nhttp://knewone.com/things/ai-qian-gua-lao-ren-zhi-neng-wan-biao-1\nhttp://knewone.com/lists/541baa3631302d2f2c170000\nhttps://github.com/xiaomi\nhttps://github.com/XiaoMi/android_tv_metro\nhttps://github.com/XiaoMi/galaxy-thrift-api\nhttps://github.com/XiaoMi/misound\nhttp://www.etcomm.cn/products_hc-201.html\n技术问题\nhttp://blog.csdn.net/icyfox_bupt/article/details/25487125\nhttp://blog.csdn.net/junbin_fan/article/details/21982509\nhttp://wiki.eoeandroid.com/Bluetooth\n","permalink":"https://blog.zdltech.com/posts/%E7%A7%BB%E5%8A%A8%E5%81%A5%E5%BA%B7%E8%AE%BE%E5%A4%87%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E6%94%B6%E9%9B%86/","summary":"\u003cp\u003e\u003ca href=\"https://github.com/search?p=4\u0026amp;q=iHealth\u0026amp;ref=searchresults\u0026amp;type=Repositories\u0026amp;utf8=%E2%9C%93\"\u003ehttps://github.com/search?p=4\u0026amp;q=iHealth\u0026amp;ref=searchresults\u0026amp;type=Repositories\u0026amp;utf8=%E2%9C%93\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/lfreeman/ihealth\"\u003ehttps://github.com/lfreeman/ihealth\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/Arunmainthan/iHealth\"\u003ehttps://github.com/Arunmainthan/iHealth\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/oyachai/HearthSim/blob/master/docs/DeckFileSpecification.md\"\u003ehttps://github.com/oyachai/HearthSim/blob/master/docs/DeckFileSpecification.md\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/house4hack/heartmonitor\"\u003ehttps://github.com/house4hack/heartmonitor\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/phishman3579/android-heart-rate-monitor\"\u003ehttps://github.com/phishman3579/android-heart-rate-monitor\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://sandbox.ihealthlabs.com/dev\"\u003ehttp://sandbox.ihealthlabs.com/dev\u003c/a\u003e_documentation_openapidoc.htm\u003c/p\u003e\n\u003cp\u003eiHealth’s\u003cbr\u003e\n\u003ca href=\"http://developer.ihealthlabs.com/index.htm\"\u003ehttp://developer.ihealthlabs.com/index.htm\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.mi.com/ihealth/#overall\"\u003ehttp://www.mi.com/ihealth/#overall\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://wenku.baidu.com/link?url=UdozX1eBzPZjrDC2IIbIlvzEi7hS8gXmQkH4RgNBI9FgAorMewSouiEBC9W7RHieklYjQsGaxlRERhtKZpUaxL7j3hctm3PdOKC-SiBxZMG\"\u003ehttp://wenku.baidu.com/link?url=UdozX1eBzPZjrDC2IIbIlvzEi7hS8gXmQkH4RgNBI9FgAorMewSouiEBC9W7RHieklYjQsGaxlRERhtKZpUaxL7j3hctm3PdOKC-SiBxZMG\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"http://www.leiphone.com/news/201406/qardioarm.html\"\u003ehttp://www.leiphone.com/news/201406/qardioarm.html\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"http://www.mymumu.com/user.php/Change\"\u003ehttp://www.mymumu.com/user.php/Change\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e爱牵挂老人智能腕表\u003cbr\u003e\n\u003ca href=\"http://knewone.com/things/ai-qian-gua-lao-ren-zhi-neng-wan-biao-1\"\u003ehttp://knewone.com/things/ai-qian-gua-lao-ren-zhi-neng-wan-biao-1\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://knewone.com/lists/541baa3631302d2f2c170000\"\u003ehttp://knewone.com/lists/541baa3631302d2f2c170000\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"https://github.com/xiaomi\"\u003ehttps://github.com/xiaomi\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"https://github.com/XiaoMi/android\"\u003ehttps://github.com/XiaoMi/android\u003c/a\u003e_tv_metro\u003cbr\u003e\n\u003ca href=\"https://github.com/XiaoMi/galaxy-thrift-api\"\u003ehttps://github.com/XiaoMi/galaxy-thrift-api\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"https://github.com/XiaoMi/misound\"\u003ehttps://github.com/XiaoMi/misound\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.etcomm.cn/products_hc-201.html\"\u003ehttp://www.etcomm.cn/products_hc-201.html\u003c/a\u003e\u003cbr\u003e\n技术问题\u003cbr\u003e\n\u003ca href=\"http://blog.csdn.net/icyfox_bupt/article/details/25487125\"\u003ehttp://blog.csdn.net/icyfox_bupt/article/details/25487125\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"http://blog.csdn.net/junbin_fan/article/details/21982509\"\u003ehttp://blog.csdn.net/junbin_fan/article/details/21982509\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://wiki.eoeandroid.com/Bluetooth\"\u003ehttp://wiki.eoeandroid.com/Bluetooth\u003c/a\u003e\u003c/p\u003e","title":"移动健康设备开源项目收集"},{"content":"保健设备配置文件\nhttps://www.bluetooth.org/zh-cn/specification/assigned-numbers/health-device-profile\n** **\n** **\n上面2个Service对应下面2个服务\n通用属性配置文件(GATT)\n​​​通用属性配置文件(GATT)\nGATT服务 **记忆码** \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; **UUID规格** \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; **UUID** \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;233\u0026quot;\u0026gt; **参考规格** \u0026lt;/td\u0026gt; 《通用访问配置文件》 \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; 0x1800 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;233\u0026quot;\u0026gt; *Bluetooth*®核心规格第3卷C部分第12节 \u0026lt;/td\u0026gt; 《通用属性配置文件》 \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; 0x1801 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;233\u0026quot;\u0026gt; 蓝牙核心规格第3卷G部分第7节 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; （最大值0xFFFF） \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;233\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; 表1： GATT服务\nGATT属性类型 **记忆码** \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; **UUID规格** \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; **UUID** \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;202\u0026quot;\u0026gt; **参考规格** \u0026lt;/td\u0026gt; «主要服务» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; 0x2800 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;202\u0026quot;\u0026gt; 蓝牙核心规格第3卷G部分第3.1节 \u0026lt;/td\u0026gt; «辅助服务» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; 0x2801 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;202\u0026quot;\u0026gt; 蓝牙核心规格第3卷G部分第3.1节 \u0026lt;/td\u0026gt; «包含» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; 0x2802 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;202\u0026quot;\u0026gt; 蓝牙核心规格第3卷G部分第3.2节 \u0026lt;/td\u0026gt; «特征» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; 0x2803 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;202\u0026quot;\u0026gt; 蓝牙核心规格第3卷G部分第3.3节 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; （最大值0xFFFF） \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;202\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; 表2：GATT属性类型\nGATT特征描述符 **记忆码** \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; **UUID规格** \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; **UUID** \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;235\u0026quot;\u0026gt; **参考规格** \u0026lt;/td\u0026gt; «特征扩充属性» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; 0x2900 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;235\u0026quot;\u0026gt; 蓝牙核心规格第3卷G部分第3.3.3.1节 \u0026lt;/td\u0026gt; «特征用户描述» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; 0x2901 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;235\u0026quot;\u0026gt; 蓝牙核心规格第3卷G部分第3.3.3.2节 \u0026lt;/td\u0026gt; «客户特征配置» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; 0x2902 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;235\u0026quot;\u0026gt; 蓝牙核心规格第3卷G部分第3.3.3.3节 \u0026lt;/td\u0026gt; «服务器特征配置» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; 0x2903 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;235\u0026quot;\u0026gt; 蓝牙核心规格第3卷G部分第3.3.3.4节 \u0026lt;/td\u0026gt; «特征格式» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; 0x2904 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;235\u0026quot;\u0026gt; B蓝牙核心规格第3卷G部分第3.3.3.5节 \u0026lt;/td\u0026gt; «特征集成格式» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; 0x2905 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;235\u0026quot;\u0026gt; 蓝牙核心规格第3卷G部分第3.3.3.6节 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt; （最大值0xFFFF） \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;235\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; 表3： GATT特征描述符\nGATT特征类型 **记忆码** \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; **UUID规格** \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;112\u0026quot;\u0026gt; **UUID** \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;208\u0026quot;\u0026gt; **参考规格** \u0026lt;/td\u0026gt; «设备名称» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;112\u0026quot;\u0026gt; 0x2A00 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;208\u0026quot;\u0026gt; 蓝牙核心规格第3卷C部分第12.1节 \u0026lt;/td\u0026gt; «外观» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;112\u0026quot;\u0026gt; 0x2A01 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;208\u0026quot;\u0026gt; 蓝牙核心规格第3卷C部分第12.2节 \u0026lt;/td\u0026gt; «外置设备隐私标志» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;112\u0026quot;\u0026gt; 0x2A02 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;208\u0026quot;\u0026gt; 蓝牙核心规格第3卷C部分第12.3节 \u0026lt;/td\u0026gt; «重新连接地址» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;112\u0026quot;\u0026gt; 0x2A03 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;208\u0026quot;\u0026gt; 蓝牙核心规格第3卷C部分第12.4节 \u0026lt;/td\u0026gt; «外置设备首选连接参数» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;112\u0026quot;\u0026gt; 0x2A04 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;208\u0026quot;\u0026gt; 蓝牙核心规格第3卷C部分第12.5节 \u0026lt;/td\u0026gt; «服务更改» \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; uuid16 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;112\u0026quot;\u0026gt; 0x2A05 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;208\u0026quot;\u0026gt; 蓝牙核心规格第3卷G部分第7.1节 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;112\u0026quot;\u0026gt; （最大值 0xFFFF） \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;208\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; 表4： GATT特征类型\n转载请注明： http://www.etongwl.com/?p=620\n蓝牙提供的服务名称列表\n**SpecificationType** \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; **SpecificationLevel** \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Alert Notification Service](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.alert_notification.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.alert_notification \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1811 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Battery Service](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.battery_service.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.battery_service \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x180F \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Blood Pressure](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.blood_pressure.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.blood_pressure \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1810 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Body Composition](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.body_composition.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.body_composition \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x181B \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Bond Management](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.bond_management.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.bond_management \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x181E \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Continuous Glucose Monitoring](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.continuous_glucose_monitoring.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.continuous_glucose_monitoring \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x181F \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Current Time Service](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.current_time.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.current_time \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1805 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Cycling Power](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.cycling_power.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.cycling_power \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1818 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Cycling Speed and Cadence](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.cycling_speed_and_cadence.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.cycling_speed_and_cadence \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1816 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Device Information](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.device_information.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.device_information \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x180A \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Environmental Sensing](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.environmental_sensing.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.environmental_sensing \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x181A \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Generic Access](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.generic_access.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.generic_access \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1800 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Generic Attribute](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.generic_attribute.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.generic_attribute \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1801 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Glucose](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.glucose.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.glucose \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1808 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Health Thermometer](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.health_thermometer \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1809 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Heart Rate](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.heart_rate.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.heart_rate \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x180D \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Human Interface Device](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.human_interface_device.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.human_interface_device \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1812 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Immediate Alert](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.immediate_alert.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.immediate_alert \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1802 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Internet Protocol Support](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.internet_protocol_support.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.internet_protocol_support \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1820 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Link Loss](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.link_loss.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.link_loss \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1803 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Location and Navigation](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.location_and_navigation.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.location_and_navigation \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1819 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Next DST Change Service](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.next_dst_change.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.next_dst_change \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1807 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Phone Alert Status Service](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.phone_alert_status.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.phone_alert_status \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x180E \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Reference Time Update Service](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.reference_time_update.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.reference_time_update \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1806 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Running Speed and Cadence](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.running_speed_and_cadence.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.running_speed_and_cadence \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1814 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Scan Parameters](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.scan_parameters.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.scan_parameters \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1813 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Tx Power](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.tx_power.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.tx_power \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x1804 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [User Data](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.user_data.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.user_data \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x181C \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;131\u0026quot;\u0026gt; [Weight Scale](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.weight_scale.xml) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;305\u0026quot;\u0026gt; org.bluetooth.service.weight_scale \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;55\u0026quot;\u0026gt; 0x181D \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;60\u0026quot;\u0026gt; Adopted \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026amp;nbsp;\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; \u0026amp;nbsp; \u0026lt;table\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td width=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 聽 \u0026amp;nbsp; ","permalink":"https://blog.zdltech.com/posts/%E8%93%9D%E7%89%99%E6%8F%90%E4%BE%9B%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%E5%88%97%E8%A1%A8/","summary":"\u003cp\u003e\u003cstrong\u003e保健设备配置文件\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://www.bluetooth.org/zh-cn/specification/assigned-numbers/health-device-profile\"\u003ehttps://www.bluetooth.org/zh-cn/specification/assigned-numbers/health-device-profile\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e** **\u003c/p\u003e\n\u003cp\u003e** **\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e上面2个Service对应下面2个服务\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e通用属性配置文件(GATT)\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e​​​通用属性配置文件(GATT)\u003c/p\u003e\n\u003ch2 id=\"gatt服务\"\u003e\u003cstrong\u003eGATT服务\u003c/strong\u003e\u003c/h2\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"130\"\u003e\n      **记忆码**\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt;\n  **UUID规格**\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt;\n  **UUID**\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;233\u0026quot;\u0026gt;\n  **参考规格**\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"130\"\u003e\n      《通用访问配置文件》\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt;\n  uuid16\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt;\n  0x1800\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;233\u0026quot;\u0026gt;\n  *Bluetooth*®核心规格第3卷C部分第12节\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"130\"\u003e\n      《通用属性配置文件》\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt;\n  uuid16\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt;\n  0x1801\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;233\u0026quot;\u0026gt;\n  蓝牙核心规格第3卷G部分第7节\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"130\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt;\n  （最大值0xFFFF）\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;233\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003cp\u003e表1： GATT服务\u003c/p\u003e\n\u003ch2 id=\"gatt属性类型\"\u003e\u003cstrong\u003eGATT属性类型\u003c/strong\u003e\u003c/h2\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"70\"\u003e\n      **记忆码**\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt;\n  **UUID规格**\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt;\n  **UUID**\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;202\u0026quot;\u0026gt;\n  **参考规格**\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"70\"\u003e\n      «主要服务»\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt;\n  uuid16\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt;\n  0x2800\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;202\u0026quot;\u0026gt;\n  蓝牙核心规格第3卷G部分第3.1节\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"70\"\u003e\n      «辅助服务»\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt;\n  uuid16\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt;\n  0x2801\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;202\u0026quot;\u0026gt;\n  蓝牙核心规格第3卷G部分第3.1节\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"70\"\u003e\n      «包含»\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt;\n  uuid16\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt;\n  0x2802\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;202\u0026quot;\u0026gt;\n  蓝牙核心规格第3卷G部分第3.2节\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"70\"\u003e\n      «特征»\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt;\n  uuid16\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt;\n  0x2803\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;202\u0026quot;\u0026gt;\n  蓝牙核心规格第3卷G部分第3.3节\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"70\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td width=\u0026quot;61\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;109\u0026quot;\u0026gt;\n  （最大值0xFFFF）\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td width=\u0026quot;202\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003cp\u003e表2：GATT属性类型\u003c/p\u003e","title":"蓝牙BLE 4.0提供的服务名称列表"},{"content":"Android 4.0 因为项目需要， 要实现屏幕全屏，隐藏虚拟按键，即导航栏\n在Android的API 中\nTo this day, you can hide the status bar on handsets using the [FLAG_FULLSCREEN](http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_FULLSCREEN) flag. In Android 4.0, the APIs that control the system bar’s visibility have been updated to better reflect the behavior of both the system bar and navigation bar:\nThe [SYSTEM_UI_FLAG_LOW_PROFILE](http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_LOW_PROFILE) flag replaces the STATUS_BAR_HIDDEN flag. When set, this flag enables “low profile” mode for the system bar or navigation bar. Navigation buttons dim and other elements in the system bar also hide. Enabling this is useful for creating more immersive games without distraction for the system navigation buttons. The [SYSTEM_UI_FLAG_VISIBLE](http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_VISIBLE) flag replaces the STATUS_BAR_VISIBLE flag to request the system bar or navigation bar be visible. The [SYSTEM_UI_FLAG_HIDE_NAVIGATION](http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_HIDE_NAVIGATION) is a new flag that requests the navigation bar hide completely. Be aware that this works only for the navigation bar used by some handsets (it does not hide the system bar on tablets). The navigation bar returns to view as soon as the system receives user input. As such, this mode is useful primarily for video playback or other cases in which the whole screen is needed but user input is not required `\u0026lt;a href=\"http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_LOW_PROFILE\" target=\"_blank\"\u003eSYSTEM_UI_FLAG_LOW_PROFILE\u0026lt;/a\u003e 相当于隐藏导航栏` [SYSTEM_UI_FLAG_VISIBLE](http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_VISIBLE) 导航栏显示 `\u0026lt;a href=\"http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_HIDE_NAVIGATION\" target=\"_blank\"\u003eSYSTEM_UI_FLAG_HIDE_NAVIGATION\u0026lt;/a\u003e` 要求导航栏完全隐藏\u0026#8211;\u003e但这对部分硬件设备有效 方法一： **[java]** [view plain](http://blog.csdn.net/windownew11/article/details/9427469#)[copy](http://blog.csdn.net/windownew11/article/details/9427469#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.setbutton; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.WindowManager; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - Window window; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** Called when the activity is first created. */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// main = getLayoutInflater().from(this).inflate(R.layout.main, null);\u0026lt;/span\u0026gt; - window = getWindow(); - WindowManager.LayoutParams params = window.getAttributes(); - params.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE; - window.setAttributes(params); - - setContentView(R.layout.main); - } - - } 方法二：\n**[java]** [view plain](http://blog.csdn.net/windownew11/article/details/9427469#)[copy](http://blog.csdn.net/windownew11/article/details/9427469#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.setbutton; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.WindowManager; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Button; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - View main; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Button btn; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** Called when the activity is first created. */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - main = getLayoutInflater().from(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;).inflate(R.layout.main, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - - btn = (Button) main.findViewById(R.id.btn); - btn.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = main.getSystemUiVisibility(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (i == View.SYSTEM_UI_FLAG_VISIBLE) { - main.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); - } - } - }); - - setContentView(main); - - } ","permalink":"https://blog.zdltech.com/posts/android4-0-%E9%9A%90%E8%97%8F%E8%99%9A%E6%8B%9F%E6%8C%89%E9%94%AE-%E5%AE%9E%E7%8E%B0%E5%85%A8%E5%B1%8F/","summary":"\u003cp\u003eAndroid 4.0 因为项目需要， 要实现屏幕全屏，隐藏虚拟按键，即导航栏\u003c/p\u003e\n\u003cp\u003e在Android的API 中\u003c/p\u003e\n\u003cp\u003eTo this day, you can hide the status bar on handsets using the \u003ccode\u003e[FLAG_FULLSCREEN](http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_FULLSCREEN)\u003c/code\u003e flag. In Android 4.0, the APIs that control the system bar’s visibility have been updated to better reflect the behavior of both the system bar and navigation bar:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eThe \u003ccode\u003e[SYSTEM_UI_FLAG_LOW_PROFILE](http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_LOW_PROFILE)\u003c/code\u003e flag replaces the \u003ccode\u003eSTATUS_BAR_HIDDEN\u003c/code\u003e flag. When set, this flag enables “low profile” mode for the system bar or navigation bar. Navigation buttons dim and other elements in the system bar also hide. Enabling this is useful for creating more immersive games without distraction for the system navigation buttons.\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003e[SYSTEM_UI_FLAG_VISIBLE](http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_VISIBLE)\u003c/code\u003e flag replaces the \u003ccode\u003eSTATUS_BAR_VISIBLE\u003c/code\u003e flag to request the system bar or navigation bar be visible.\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003e[SYSTEM_UI_FLAG_HIDE_NAVIGATION](http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_HIDE_NAVIGATION)\u003c/code\u003e is a new flag that requests the navigation bar hide completely. Be aware that this works only for the \u003cem\u003enavigation bar\u003c/em\u003e used by some handsets (it does \u003cstrong\u003enot\u003c/strong\u003e hide the system bar on tablets). The navigation bar returns to view as soon as the system receives user input. As such, this mode is useful primarily for video playback or other cases in which the whole screen is needed but user input is not required\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv\u003e\n   `\u0026lt;a href=\"http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_LOW_PROFILE\" target=\"_blank\"\u003eSYSTEM_UI_FLAG_LOW_PROFILE\u0026lt;/a\u003e 相当于隐藏导航栏`\n\u003c/div\u003e\n\u003cdiv\u003e\n   [SYSTEM_UI_FLAG_VISIBLE](http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_VISIBLE)         导航栏显示\n\u003c/div\u003e\n\u003cdiv\u003e\n   `\u0026lt;a href=\"http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_HIDE_NAVIGATION\" target=\"_blank\"\u003eSYSTEM_UI_FLAG_HIDE_NAVIGATION\u0026lt;/a\u003e` 要求导航栏完全隐藏\u0026#8211;\u003e但这对部分硬件设备有效\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  方法一：\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/windownew11/article/details/9427469#)[copy](http://blog.csdn.net/windownew11/article/details/9427469#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.setbutton;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.WindowManager;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity {\n\n- \n- Window window;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** Called when the activity is first created. */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// main = getLayoutInflater().from(this).inflate(R.layout.main, null);\u0026lt;/span\u0026gt;\n\n- window = getWindow();\n\n- WindowManager.LayoutParams params = window.getAttributes();\n\n- params.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE;\n\n- window.setAttributes(params);\n\n- \n- setContentView(R.layout.main);\n\n- }\n\n- \n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android4.0 隐藏虚拟按键 实现全屏"},{"content":"一、关键概念： **Generic Attribute Profile (GATT)** 通过BLE连接，读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。 **Attribute Protocol (ATT)** GATT是基于ATT Protocol的。ATT针对BLE设备做了专门的优化，具体就是在传输过程中使用尽量少的数据。每个属性都有一个唯一的UUID，属性将以characteristics and services的形式传输。 **Characteristic** Characteristic可以理解为一个数据类型，它包括一个value和0至多个对次value的描述（Descriptor）。 **Descriptor** 对Characteristic的描述，例如范围、计量单位等。 **Service** Characteristic的集合。例如一个service叫做“Heart Rate Monitor”，它可能包含多个Characteristics，其中可能包含一个叫做“heart rate measurement\u0026#8221;的Characteristic。 二、角色和职责： Android设备与BLE设备交互有两组角色： 中心设备和外围设备（Central vs. peripheral）； GATT server vs. GATT client. Central vs. peripheral: 中心设备和外围设备的概念针对的是BLE连接本身。Central角色负责scan advertisement。而peripheral角色负责make advertisement。 GATT server vs. GATT client: 这两种角色取决于BLE连接成功后，两个设备间通信的方式。 举例说明： 现有一个活动追踪的BLE设备和一个支持BLE的Android设备。Android设备支持Central角色，而BLE设备支持peripheral角色。创建一个BLE连接需要这两个角色都存在，都仅支持Central角色或者都仅支持peripheral角色则无法建立连接。 当连接建立后，它们之间就需要传输GATT数据。谁做server，谁做client，则取决于具体数据传输的情况。例如，如果活动追踪的BLE设备需要向Android设备传输sensor数据，则活动追踪器自然成为了server端；而如果活动追踪器需要从Android设备获取更新信息，则Android设备作为server端可能更合适。 三、权限及feature： 和经典蓝牙一样，应用使用蓝牙，需要声明BLUETOOTH权限，如果需要扫描设备或者操作蓝牙设置，则还需要BLUETOOTH_ADMIN权限： 除了蓝牙权限外，如果需要BLE feature则还需要声明uses-feature： 按时required为true时，则应用只能在支持BLE的Android设备上安装运行；required为false时，Android设备均可正常安装运行，需要在代码运行时判断设备是否支持BLE feature： // Use this check to determine whether BLE is supported on the device. Then // you can selectively disable BLE-related features. if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); finish(); } 四、启动蓝牙： 在使用蓝牙BLE之前，需要确认Android设备是否支持BLE feature(required为false时)，另外要需要确认蓝牙是否打开。 如果发现不支持BLE，则不能使用BLE相关的功能。如果支持BLE，但是蓝牙没打开，则需要打开蓝牙。 打开蓝牙的步骤： 1、获取BluetoothAdapter BluetoothAdapter是Android系统中所有蓝牙操作都需要的，它对应本地Android设备的蓝牙模块，在整个系统中BluetoothAdapter是单例的。当你获取到它的示例之后，就能进行相关的蓝牙操作了。 获取BluetoothAdapter代码示例如下： // Initializes Bluetooth adapter. final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); 注：这里通过getSystemService获取BluetoothManager，再通过BluetoothManager获取BluetoothAdapter。BluetoothManager在Android4.3以上支持(API level 18)。 2、判断是否支持蓝牙，并打开蓝牙 获取到BluetoothAdapter之后，还需要判断是否支持蓝牙，以及蓝牙是否打开。 如果没打开，需要让用户打开蓝牙： private BluetoothAdapter mBluetoothAdapter; \u0026#8230; // Ensures Bluetooth is available on the device and it is enabled. If not, // displays a dialog requesting user permission to enable Bluetooth. if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } 五、搜索BLE设备： 通过调用BluetoothAdapter的[startLeScan()](http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback))搜索BLE设备。调用此方法时需要传入 `\u0026lt;a href=\"http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.LeScanCallback.html\"\u003eBluetoothAdapter.LeScanCallback\u0026lt;/a\u003e`参数。 因此你需要实现 `\u0026lt;a href=\"http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.LeScanCallback.html\"\u003eBluetoothAdapter.LeScanCallback\u0026lt;/a\u003e`接口，BLE设备的搜索结果将通过这个callback返回。 由于搜索需要尽量减少功耗，因此在实际使用时需要注意： 1、当找到对应的设备后，立即停止扫描； 2、不要循环搜索设备，为每次搜索设置适合的时间限制。避免设备不在可用范围的时候持续不停扫描，消耗电量。 搜索的示例代码如下： /** * Activity for scanning and displaying available BLE devices. */ public class DeviceScanActivity extends ListActivity { private BluetoothAdapter mBluetoothAdapter; private boolean mScanning; private Handler mHandler;\n// Stops scanning after 10 seconds. private static final long SCAN_PERIOD = 10000; … private void scanLeDevice(final boolean enable) { if (enable) { // Stops scanning after a pre-defined scan period. mHandler.postDelayed(new Runnable() { @Override public void run() { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } }, SCAN_PERIOD);\nmScanning = true; mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } … } … }\n如果你只需要搜索指定UUID的外设，你可以调用 `\u0026lt;a href=\"http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback)\"\u003estartLeScan(UUID[], BluetoothAdapter.LeScanCallback)\u0026lt;/a\u003e`方法。 其中UUID数组指定你的应用程序所支持的GATT Services的UUID。 [BluetoothAdapter.LeScanCallback](http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.LeScanCallback.html)的实现示例如下： private LeDeviceListAdapter mLeDeviceListAdapter; \u0026#8230; // Device scan callback. private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { runOnUiThread(new Runnable() { @Override public void run() { mLeDeviceListAdapter.addDevice(device); mLeDeviceListAdapter.notifyDataSetChanged(); } }); } }; 注意：搜索时，你只能搜索传统蓝牙设备或者BLE设备，两者完全独立，不可同时被搜索。 六、连接GATT Server： 两个设备通过BLE通信，首先需要建立GATT连接。这里我们讲的是Android设备作为client端，连接GATT Server。 连接GATT Server，你需要调用BluetoothDevice的[connectGatt()](http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback))方法。此函数带三个参数：Context、autoConnect(boolean)和[BluetoothGattCallback](http://developer.android.com/reference/android/bluetooth/BluetoothGattCallback.html)对象。调用示例： mBluetoothGatt = device.connectGatt(this, false, mGattCallback); 函数成功，返回[BluetoothGatt](http://developer.android.com/reference/android/bluetooth/BluetoothGatt.html)对象，它是GATT profile的封装。通过这个对象，我们就能进行GATT Client端的相关操作。[BluetoothGattCallback](http://developer.android.com/reference/android/bluetooth/BluetoothGattCallback.html)用于传递一些连接状态及结果。 BluetoothGatt常规用到的几个操作示例: connect() ：连接远程设备。 discoverServices() : 搜索连接设备所支持的service。 disconnect()：断开与远程设备的GATT连接。 close()：关闭GATT Client端。 readCharacteristic(characteristic) ：读取指定的characteristic。 setCharacteristicNotification(characteristic, enabled) ：设置当指定characteristic值变化时，发出通知。 getServices() ：获取远程设备所支持的services。 等等。 注： 1、某些函数调用之间存在先后关系。例如首先需要connect上才能discoverServices。 2、一些函数调用是异步的，需要得到的值不会立即返回，而会在BluetoothGattCallback的回调函数中返回。例如discoverServices与onServicesDiscovered回调，readCharacteristic与onCharacteristicRead回调，setCharacteristicNotification与onCharacteristicChanged回调等。 ","permalink":"https://blog.zdltech.com/posts/android4-3-%E8%93%9D%E7%89%99ble%E5%88%9D%E6%AD%A5/","summary":"\u003ch3 id=\"一关键概念\"\u003e一、关键概念：\u003c/h3\u003e\n\u003cdiv\u003e\n  **Generic Attribute Profile (GATT)**\n\u003c/div\u003e\n\u003cdiv\u003e\n  通过BLE连接，读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  **Attribute Protocol (ATT)**\n\u003c/div\u003e\n\u003cdiv\u003e\n  GATT是基于ATT Protocol的。ATT针对BLE设备做了专门的优化，具体就是在传输过程中使用尽量少的数据。每个属性都有一个唯一的UUID，属性将以characteristics and services的形式传输。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  **Characteristic**\n\u003c/div\u003e\n\u003cdiv\u003e\n  Characteristic可以理解为一个数据类型，它包括一个value和0至多个对次value的描述（Descriptor）。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  **Descriptor**\n\u003c/div\u003e\n\u003cdiv\u003e\n  对Characteristic的描述，例如范围、计量单位等。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  **Service**\n\u003c/div\u003e\n\u003cdiv\u003e\n  Characteristic的集合。例如一个service叫做“Heart Rate Monitor”，它可能包含多个Characteristics，其中可能包含一个叫做“heart rate measurement\u0026#8221;的Characteristic。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch3 id=\"二角色和职责\"\u003e二、角色和职责：\u003c/h3\u003e\n\u003cdiv\u003e\n  Android设备与BLE设备交互有两组角色：\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  中心设备和外围设备（Central vs. peripheral）；\n\u003c/div\u003e\n\u003cdiv\u003e\n  GATT server vs. GATT client.\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  Central vs. peripheral:\n\u003c/div\u003e\n\u003cdiv\u003e\n  中心设备和外围设备的概念针对的是BLE连接本身。Central角色负责scan advertisement。而peripheral角色负责make advertisement。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  GATT server vs. GATT client:\n\u003c/div\u003e\n\u003cdiv\u003e\n  这两种角色取决于BLE连接成功后，两个设备间通信的方式。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  举例说明：\n\u003c/div\u003e\n\u003cdiv\u003e\n  现有一个活动追踪的BLE设备和一个支持BLE的Android设备。Android设备支持Central角色，而BLE设备支持peripheral角色。创建一个BLE连接需要这两个角色都存在，都仅支持Central角色或者都仅支持peripheral角色则无法建立连接。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  当连接建立后，它们之间就需要传输GATT数据。谁做server，谁做client，则取决于具体数据传输的情况。例如，如果活动追踪的BLE设备需要向Android设备传输sensor数据，则活动追踪器自然成为了server端；而如果活动追踪器需要从Android设备获取更新信息，则Android设备作为server端可能更合适。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch3 id=\"三权限及feature\"\u003e三、权限及feature：\u003c/h3\u003e\n\u003cdiv\u003e\n  和经典蓝牙一样，应用使用蓝牙，需要声明BLUETOOTH权限，如果需要扫描设备或者操作蓝牙设置，则还需要BLUETOOTH_ADMIN权限：\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv\u003e\n    \u003cuses-permission android:name=\u0026#8221;android.permission.BLUETOOTH\u0026#8221;/\u003e\n \u003cuses-permission android:name=\u0026#8221;android.permission.BLUETOOTH_ADMIN\u0026#8221;/\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  除了蓝牙权限外，如果需要BLE feature则还需要声明uses-feature：\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv\u003e\n    \u003cuses-feature android:name=\u0026#8221;android.hardware.bluetooth_le\u0026#8221; android:required=\u0026#8221;true\u0026#8221;/\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  按时required为true时，则应用只能在支持BLE的Android设备上安装运行；required为false时，Android设备均可正常安装运行，需要在代码运行时判断设备是否支持BLE feature：\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv\u003e\n    // Use this check to determine whether BLE is supported on the device. Then\n // you can selectively disable BLE-related features.\n if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {\n Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();\n finish();\n }\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch3 id=\"四启动蓝牙\"\u003e四、启动蓝牙：\u003c/h3\u003e\n\u003cdiv\u003e\n  在使用蓝牙BLE之前，需要确认Android设备是否支持BLE feature(required为false时)，另外要需要确认蓝牙是否打开。\n\u003c/div\u003e\n\u003cdiv\u003e\n  如果发现不支持BLE，则不能使用BLE相关的功能。如果支持BLE，但是蓝牙没打开，则需要打开蓝牙。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  打开蓝牙的步骤：\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  1、获取BluetoothAdapter\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  BluetoothAdapter是Android系统中所有蓝牙操作都需要的，它对应本地Android设备的蓝牙模块，在整个系统中BluetoothAdapter是单例的。当你获取到它的示例之后，就能进行相关的蓝牙操作了。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  获取BluetoothAdapter代码示例如下：\n\u003c/div\u003e\n\u003cdiv\u003e\n  // Initializes Bluetooth adapter.\n final BluetoothManager bluetoothManager =\n (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);\n mBluetoothAdapter = bluetoothManager.getAdapter();\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  注：这里通过getSystemService获取BluetoothManager，再通过BluetoothManager获取BluetoothAdapter。BluetoothManager在Android4.3以上支持(API level 18)。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  2、判断是否支持蓝牙，并打开蓝牙\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  获取到BluetoothAdapter之后，还需要判断是否支持蓝牙，以及蓝牙是否打开。\n\u003c/div\u003e\n\u003cdiv\u003e\n  如果没打开，需要让用户打开蓝牙：\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv\u003e\n    private BluetoothAdapter mBluetoothAdapter;\n \u0026#8230;\n // Ensures Bluetooth is available on the device and it is enabled. If not,\n // displays a dialog requesting user permission to enable Bluetooth.\n if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {\n Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);\n startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);\n }\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch3 id=\"五搜索ble设备\"\u003e五、搜索BLE设备：\u003c/h3\u003e\n\u003cdiv\u003e\n  通过调用BluetoothAdapter的[startLeScan()](http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback))搜索BLE设备。调用此方法时需要传入 `\u0026lt;a href=\"http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.LeScanCallback.html\"\u003eBluetoothAdapter.LeScanCallback\u0026lt;/a\u003e`参数。\n\u003c/div\u003e\n\u003cdiv\u003e\n  因此你需要实现 `\u0026lt;a href=\"http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.LeScanCallback.html\"\u003eBluetoothAdapter.LeScanCallback\u0026lt;/a\u003e`接口，BLE设备的搜索结果将通过这个callback返回。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  由于搜索需要尽量减少功耗，因此在实际使用时需要注意：\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  1、当找到对应的设备后，立即停止扫描；\n\u003c/div\u003e\n\u003cdiv\u003e\n  2、不要循环搜索设备，为每次搜索设置适合的时间限制。避免设备不在可用范围的时候持续不停扫描，消耗电量。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  搜索的示例代码如下：\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv\u003e\n    /**\n * Activity for scanning and displaying available BLE devices.\n */\n public class DeviceScanActivity extends ListActivity {\n\u003cpre\u003e\u003ccode\u003e  private BluetoothAdapter mBluetoothAdapter;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eprivate boolean mScanning;\nprivate Handler mHandler;\u003c/p\u003e","title":"Android4.3 蓝牙BLE初步"},{"content":"android平台包含了蓝牙网络协议栈的支持，允许android设备与其他蓝牙设备相互传输数据。应用层框架提供了API函数来访问蓝牙模块。使用这些API可以让应用程序连接其他蓝牙设备，实现点对点或多点无线传输。\n运用蓝牙API，可以实现以下功能：\n搜索其他蓝牙设备\n查询本地蓝牙适配器中已经配对好的设备\n建立RFCOMM协议通道\n通过服务端搜索连接到其他设备\n与其他设备互相传输数据\n管理多个连接\n快速阅读\nAndroid蓝牙API可以让应用程序与其他设备传输无线数据。\n关键类\nBluetoothAdapter\nBluetoothDevice\nBluetoothSocket\nBluetoothServerSocket\n相关用例\n蓝牙对讲 http://developer.android.com/resources/samples/BluetoothChat/index.html\n蓝牙医疗设备(Health Device Profile)，比如心率监视器，血压计，温度计等。http://developer.android.com/resources/samples/BluetoothHDP/index.html\n目录 [隐藏]\n1 基本原理\n2 蓝牙权限\n3 配置蓝牙\n4 获取蓝牙设备\n4.1 查询已配对设备\n4.2 搜索设备\n4.3 开启蓝牙可检测性\n5 设备连接\n5.1 作为服务端连接\n5.2 作为客户端连接\n6 连接管理\n7 在蓝牙规范协议下工作\n7.1 Vendor-specific AT commands\n7.2 Health Device Profile\n基本原理\n本文档描述了如何使用蓝牙API来完成蓝牙通讯的四项必要任务：配置蓝牙、搜索附件未配对或可用的蓝牙设备、连接设备、设备间传输数据。\n所有蓝牙API都包含在android.bluetooth包中。以下是建立蓝牙连接需要用到的类和接口的概要：\nBluetoothAdapter (蓝牙适配器)\n表示本地蓝牙适配器(蓝牙收发器). BluetoothAdapter是所有蓝牙活动的起始类. 可用于搜索其他蓝牙设备, 查询已配对设备的列表, 使用MAC地址实例化一个BluetoothDevice对象, 创建BluetoothServerSocket侦听其他设备的连接.\nBluetoothDevice (蓝牙设备)\n表示远程蓝牙设备。可以通过一个BluetoothSocket向它描述的远程设备发起连接，或者该设备的名称、地址、类、连接状态等信息。\nBluetoothSocket (蓝牙套接字)\n表示一个蓝牙套接字(与TCP Socket类似). 它是设备间的连接点，允许应用程序通过InputStream和OutputStream与其他设备进行数据传输。\nBluetoothServerSocket (蓝牙服务端套接字)\n表示一个开放的蓝牙服务器， 用于侦听其他设备发过来的连接请求(与TCP ServerSocket类似). 要将两台设备连接起来, 其中一台必须使用这个类开启一个server socket. 当远程蓝牙设备发起对server的连接请求, 如果连接被接受，BluetoothServerSocket将返回一个连接成功的BluetoothSocket对象.\nBluetoothClass (蓝牙类型)\n描述一个蓝牙设备的规格参数和功能。这是一个只读的属性集，定义了该设备的主要和次要设备种类和服务。它不能完全描述该设备的所有特性和服务，常用于判断设备的类型。\nBluetoothProfile (蓝牙规范协议)\n表示Bluetooth profile的接口. Bluetooth profile是设备间基于蓝牙通讯的接口规范协议。比如Hands-Free(非手持设备) profile。更多关于profiles的说明, 请查看Working with Profiles(在蓝牙规范协议下工作)。\nBluetoothHeadset (蓝牙耳机)\n提供手机使用蓝牙耳机的支持。同时包含了蓝牙耳机和Hands-Free(v1.5)的profiles.\nBluetoothA2dp (蓝牙A2dp)\n定义高质量音频流如何通过蓝牙连接传输到其他设备。”A2DP”是”Advanced Audio Distribution Profile”的缩写，表示高级音频分发规范协议。\nBluetoothHealth (蓝牙医疗设备)\n表示为医疗设备提供蓝牙服务的代理类。\nBluetoothHealthCallback\n这是一个抽象类，用于实现BluetoothHealth的callbacks方法。需要继承此类并实现callback方法才能接收应用程序状态和蓝牙频道状态的变化。\nBluetoothHealthAppConfiguration\n表示蓝牙医疗第三方应用与远程蓝牙医疗设备连接的配置参数。\nBluetoothProfile.ServiceListener (蓝牙规范协议服务侦听)\n一个接口类，当服务连接或断开的时候通知BluetoothProfile IPC 客户端。(这是内部服务运行的一个特殊模式)。\n蓝牙权限\n应用程序要使用手机的蓝牙功能，必须声明以下两种权限中的一种：BLUETOOTH 或 BLUETOOTH_ADMIN。\nBLUETOOTH权限用于进行蓝牙通讯，比如请求连接、接受连接和传输数据。\nBLUETOOTH_ADMIN权限用于初始化设备搜索和进行蓝牙设置。大部分应用只是需要它来搜索附近的蓝牙设备，BLUETOOTH_ADMIN权限赋予的其他能力不需要用到，除非该应用程序是需要修改本机蓝牙设置的电源管理类应用。注意：如果您使用了BLUETOOTH_ADMIN ，必须同时使用BLUETOOTH。\n在你的程序中的manifest文件声明蓝牙权限，例如：\n\u0026lt;manifest … \u0026gt;\n…\n查看 用户权限 这一章节，获得更多关于声明应用程序权限的内容。\n配置蓝牙\n在使用蓝牙之前，首先要确认你的设备带有蓝牙模块，如果有，还要确认蓝牙功能是开启的。\n如果设备不支持蓝牙，应用程序需要禁用所有蓝牙相关的功能。如果设备支持蓝牙，但蓝牙模块是关闭的，可以直接在程序中向用户请求开启蓝牙，不需要离开当前应用。这个过程需要使用BluetoothAdapter，分两步完成。\n1.获取BluetoothAdapter对象\n所有蓝牙活动都需要有一个BluetoothAdapter对象，使用静态方法getDefaultAdapter()可以获取一个BluetoothAdapter对象，表示本设备的蓝牙适配器(蓝牙收发器)。如果整个系统中存在这么一个蓝牙适配器，应用程序就可以通过BluetoothAdapter对象与其相互交流。如果getDefaultAdapter()方法返回null，说明本设备不支持蓝牙，故事结束了。例如：\nBluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();\nif (mBluetoothAdapter == null) {\n// Device does not support Bluetooth\n}\n2.开启蓝牙\n接下来，你需要确认蓝牙模块是否开启。调用isEnabled()检查蓝牙模块是否开启。如果该方法返回false，说明蓝牙模块关闭。需要用ACTION_REQUEST_ENABLE action Intent调用startActivityForResult()请求开启蓝牙。这将通过系统设置发出一个开启蓝牙的请求（无需停止当前应用程序）。例如：\nif (!mBluetoothAdapter.isEnabled()) {\nIntent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);\nstartActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);\n}\n这时会弹出一个对话框，询问用户是否开启蓝牙。如果用户选择“是”，系统将开启蓝牙，并且在完成（或失败）之后，返回到你的应用程序。\n传递给startActivityForResult()的REQUEST_ENABLE_BT常量是一个局部定义的整形（必然大于0），系统会在你实现的onActivityResult()方法中，通过requestCode参数返回这一数值。\n如果开启蓝牙成功，系统会调用你实现的onActivityResult()方法，并得到RESULT_OK的结果码。如果开启失败，或者用户选择“否”，结果码则是RESULT_CANCELED。\n最后是一个可选项，你的程序可以关于ACTION_STATE_CHANGED intent的广播。每当系统蓝牙状态发生变化，系统就会发出该广播。广播中包含了额外的字段EXTRA_STATE 和EXTRA_PREVIOUS_STATE，分别表示新的和旧的蓝牙状态。这些字段可能的值是STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, 和STATE_OFF。侦听广播对程序在运行中检测到蓝牙状态变化非常有用。\n提示：开启蓝牙可检测性会自动开启蓝牙模块，如果你在完成蓝牙活动之前需要一直开启蓝牙可检测性，则可以跳过上面的第二步，看后面的开启蓝牙可检测性。\n获取蓝牙设备\n使用BluetoothAdapter，你可以通过搜寻设备或者查询已配对设备列表来获取其他蓝牙设备。\n搜寻设备是一个搜索附近开启蓝牙的设备并获取设备相关信息的检测过程。 附近的蓝牙设备，必须是开启了蓝牙可检测性，才会被你的设备所检测到。 如果附近一个设备开启了可检测性，它将发送一些信息来回应搜索的请求，比如设备名称、类型以及它的MAC地址。 你的设备可以通过这些信息，初始化一个和被发现设备的连接。\n当与一个从未连接过的设备进行连接的时候，一个蓝牙配对请求会自动呈现给用户。 配对完成后，该设备的基本信息（比如设备名称、类型和MAC地址）就被保存下来并可以使用相关的API函数读取。 使用这个已知的MAC地址，连接就可以随时进行而不再需要进行搜索（前提是该设备在蓝牙范围内）。\n已配对和已连接是不一样的概念，已配对表示两台设备间已经认识了彼此的存在，共享一个用于认证身份的link-key，并能够互相建立加密连接。 已连接表示两台设备当前正在共享一个RFCOMM信道，并能够互相传输数据。 目前Android Bluetooth API要求设备在建立RFCOMM连接之前必须先进行配对。 （当你用蓝牙API初始化一个加密连接时，配对会自动进行。）\n下面的小节讲解如何获得已配对的设备和使用设备搜寻发现新设备。\n注意：安卓蓝牙设备默认是不开启可检测性的。 用户可以通过系统设置将蓝牙可检测性临时打开一段时间， 应用程序也可以向用户请求打开可检测性，而不需要离开当前程序。 后面会说明如何开启可检测性。\n查询已配对设备\n在进行设备搜寻之前，最好先查询一下已配对设备的列表，看看想要连接的设备是否已经配对过了。 调用getBondedDevices()即可。这将返回一个BluetoothDevice对象的set，表示已配对设备的集合。 例如，你可以查询所有已配对设备并显示每个设备的名称，通过使用ArrayAdapter：\nSet pairedDevices = mBluetoothAdapter.getBondedDevices();\n// If there are paired devices\nif (pairedDevices.size() \u0026gt; 0) {\n// Loop through paired devices\nfor (BluetoothDevice device : pairedDevices) {\n// Add the name and address to an array adapter to show in a ListView\nmArrayAdapter.add(device.getName() + “\\n” + device.getAddress());\n}\n}\nBluetoothDevice对象初始化一个连接所需要的唯一信息就是MAC地址。 在这个示例中，MAC地址作为ArrayAdapter的一部分显示出来。后续可用于初始化连接。 更多关于创建连接的信息请查看设备连接。\n搜索设备\n调用startDiscovery()即可开始设备搜寻。搜寻过程是异步的，该方法会立刻返回一个boolean值表示搜寻是否成功开始。 搜寻过程通常是一个十二秒的查询扫描，然后列出一页扫描到的设备的名称。\n应用程序必须注册一个关于ACTION_FOUND Intent的BroadcastReceiver，才能接收每个搜寻到的设备的信息。每搜寻到一个设备，系统都会广播ACTION_FOUND Intent。 Intent里面包含额外的字段EXTRA_DEVICE和EXTRA_CLASS，分部包含一个BluetoothDevice和一个BluetoothClass。 以下代码说明如何注册接收和处理设备被搜寻到的信息：\n// Create a BroadcastReceiver for ACTION_FOUND\nprivate final BroadcastReceiver mReceiver = new BroadcastReceiver() {\npublic void onReceive(Context context, Intent intent) {\nString action = intent.getAction();\n// When discovery finds a device\nif (BluetoothDevice.ACTION_FOUND.equals(action)) {\n// Get the BluetoothDevice object from the Intent\nBluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);\n// Add the name and address to an array adapter to show in a ListView\nmArrayAdapter.add(device.getName() + “\\n” + device.getAddress());\n}\n}\n};\n// Register the BroadcastReceiver\nIntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);\nregisterReceiver(mReceiver, filter); // Don’t forget to unregister during onDestroy\n警告: 进行设备搜寻对于蓝牙适配器来说是一个繁重的过程并会消耗大量资源。 当你搜寻到一个可连接设备时，请确保在尝试连接之前，调用cancelDiscovery()来停止设备搜寻。 并且，当你已经与一个设备建立了连接时，进行设备搜寻会显著降低该连接的可用带宽。所以，在已有连接时，最好不要进行搜寻。\n开启蓝牙可检测性\n如果你想要本设备能被其他蓝牙设备搜寻到，调用startActivityForResult(Intent, int)，Intent为ACTION_REQUEST_DISCOVERABLE action 。 这样会通过系统设置发出一个开启蓝牙可检测性的请求（不需要退出你的应用程序）。 默认情况下，本设备将变为可检测模式，持续120秒。 你可以通过额外添加EXTRA_DISCOVERABLE_DURATION到Intent来定义不同的持续时间。 应用程序能设置的最大持续时间为3600秒，设为0则让设备一直保持可检测状态（任何小于0或大于3600的值，会自动设为120秒）。 例如，以下代码设置持续时间为300秒：\nIntent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);\ndiscoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);\nstartActivity(discoverableIntent);\n在向用户请求开启可检测性时，一个对话框会弹出来。 如果用户选择“是”，设备将在指定的持续时间内开启可检测性。 你的应用程序将接收到onActivityResult()的回调，回调的结果码表示可检测性持续的时间。 如果用户选择“否”或者发生错误，结果码将是RESULT_CANCELED。\n注意如果蓝牙功能没有开启，开启可检测性会自动开启蓝牙功能。\n在预定的时间内，设备会静默地保持可检测性。 如果你想在可检测模式变化时收到相应的通知，可以注册关于ACTION_SCAN_MODE_CHANGED Intent的BroadcastReceiver。 里面包含EXTRA_SCAN_MODE 和 EXTRA_PREVIOUS_SCAN_MODE的额外字段，分别表示新的和旧的状态。 可能的值是SCAN_MODE_CONNECTABLE_DISCOVERABLE, SCAN_MODE_CONNECTABLE, SCAN_MODE_NONE，分别表示设备处于可检测可连接状态， 或者不可检测但可连接，或者不可检测不可连接。\n如果你只想要连接附近的设备，不需要打开可检测性。 只有在你希望应用程序作为蓝牙socket服务端，接收来自其他设备的连接时，才需要打开可检测性。 因为其他设备在发起一个连接前，需要检测到你的设备。\n设备连接\n要在两个设备的应用之间建立连接，必须实现服务端和客户端的机制。 因为其中一个设备必须开启一个server socket，然后另一个设备才能接入进来（通过服务端设备的MAC地址建立连接）。 当服务端和客户端分别得到一个位于相同RFCOMM信道的已连接BluetoothSocket对象时，则说明成功建立连接。 此时，两者都可以获取输入输出流来开始数据传输，这将在连接管理这一节中讨论。 本节描述如何在两个设备间建立连接。\n服务端和客户端获取BluetoothSocket的方式是不一样的， 服务端在接受连接的时候获得一个BluetoothSocket，而客户端是在创建一个连接服务端的RFCOMM信道时获得。\n一个实现的方式是每台设备都自动初始化为服务端，这样每台设备都拥有一个开启的服务端socket用于侦听连接， 任意一个设备都可以作为客户端连接到其他设备。 还有一种方式是其中一台设备作为“主机”，开启一个服务端socket，其他设备只需要连接进来即可。\n注意：如果两个设备之前没有配对过，Android应用框架将在连接过程中自动显示一个配对请求的通知或者一个对话框。 所以在尝试连接时，你的应用程序不需要考虑设备间是否已配对。 你的RFCOMM连接会被阻塞知道用户成功完成配对。如果用户拒绝配对、配对失败或者超时，连接将会失败。\n作为服务端连接\n要在两个设备的应用之间建立连接，其中一台需要作为服务器端，保持一个开启的BluetoothServerSocket。 服务器端socket的目的是侦听接入的连接请求，当连接成功时，生成一个已连接的BluetoothSocket对象。 当BluetoothSocket对象从BluetoothServerSocket获得时，该BluetoothServerSocket可以（也应该）废弃了， 除非你想接受更多的连接。\n1.获得一个BluetoothServerSocket对象，通过调用listenUsingRfcommWithServiceRecord(String, UUID)\nString是你的设备名称，可以自定义。系统会自动将该string写入Service Discovery Protocol (SDP)数据库（设备名称可以随便设定，可以直接使用你的应用名称）。\nUUID也包含在SDP中，作为客户端连接协议的基础。就是客户端尝试连接时，连接信息会带上一个UUID，这个UUID是客户端想要连接的服务端的唯一鉴定标识。 UUID必须与服务端匹配，这样连接才会被接受。\n关于UUID\nUniversally Unique Identifier (UUID)是一个可以标准化为128位格式的字符串，用于唯一标识信息。\nUUID的好处在于它足够大，以至于你选择任意随机信息都不会重复。\n在这里，UUID用于标识应用程序的蓝牙服务端。\n你可以通过互联网上的随机UUID生成器来获得一个UUID字符串，然后用fromString(String)方法，初始化一个UUID用到应用程序中。\n2.调用accept()开始侦听连接请求。\n这是一个阻塞的调用。这个方法在连接成功建立或者错误发生时才会返回。 只有其他设备发送连接请求过来，并且请求中携带的UUID与服务端socket的UUID一致时，连接才会被接受。 当连接成功时，accept()将返回一个已连接的BluetoothSocket对象。\n3.除非想接受更多的连接，否则调用close()\n该方法将释放服务端socket以及它占用的所有资源，但不会关闭在accept()时返回的已连接BluetoothSocket对象。 跟TCP/IP不一样，RFCOMM只允许单个信道中存在一个连接。 所以大部分情况下，在连接建立之后，调用BluetoothServerSocket的close()方法就可以了。\naccept()方法不应在activity的UI线程中调用，因为它是阻塞的，运行时会阻碍程序的其他活动。 通常的做法是应用程序创建一个新线程去完成所有关于BluetoothServerSocket和BluetoothSocket的工作。 如果想中止一个类似accept()这样的阻塞调用，在其他线程调用BluetoothServerSocket (或BluetoothSocket)的close方法，阻塞的调用就会立刻返回。 BluetoothServerSocket和BluetoothSocket的所有方法都是线程安全的。\n示例：\nprivate class AcceptThread extends Thread {\nprivate final BluetoothServerSocket mmServerSocket;\npublic AcceptThread() {\n// Use a temporary object that is later assigned to mmServerSocket,\n// because mmServerSocket is final\nBluetoothServerSocket tmp = null;\ntry {\n// MY_UUID is the app’s UUID string, also used by the client code\ntmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);\n} catch (IOException e) { }\nmmServerSocket = tmp;\n}\npublic void run() {\nBluetoothSocket socket = null;\n// Keep listening until exception occurs or a socket is returned\nwhile (true) {\ntry {\nsocket = mmServerSocket.accept();\n} catch (IOException e) {\nbreak;\n}\n// If a connection was accepted\nif (socket != null) {\n// Do work to manage the connection (in a separate thread)\nmanageConnectedSocket(socket);\nmmServerSocket.close();\nbreak;\n}\n}\n}\n/** Will cancel the listening socket, and cause the thread to finish */\npublic void cancel() {\ntry {\nmmServerSocket.close();\n} catch (IOException e) { }\n}\n}\n在这个示例中，只需要一个接入连接，所以当一个连接被接受并获取到BluetoothSocket对象时，应用程序将BluetoothSocket发送到另一个线程， 关闭了BluetoothServerSocket并停止了while循环。\n需要注意的是，accept()返回的BluetoothSocket对象，内部的socket是已连接的，所以不需要像客户端那样调用connect().\nmanageConnectedSocket()是一个在应用程序中自定义的方法，作用是建立线程传输数据。这将在连接管理这一节中讨论。\n当你完成接入连接的侦听时，应该立刻关闭BluetoothServerSocket。 在示例中，得到BluetoothSocket对象时，立刻调用了close(). 你可以在你的线程中，提供一个public方法，在停止服务端侦听的时候，可以同时关闭私有的BluetoothSocket对象。\n作为客户端连接\n要建立与服务端设备的连接，你必须先获取一个代表该设备的BluetoothDevice对象（获取方式在上面的获取蓝牙设备）。 使用BluetoothDevice来获得一个BluetoothSocket，并建立连接。\n基本步骤如下：\n1.使用BluetoothDevice，调用createRfcommSocketToServiceRecord(UUID)获得一个BluetoothSocket\n这一步初始化一个BluetoothSocket对象用于连接BluetoothDevice。 这里传入的UUID必须与服务端BluetoothServerSocket开启时使用的UUID相匹配(服务端用listenUsingRfcommWithServiceRecord(String, UUID))。 只要同时在服务端和客户端应用程序用相同的UUID字符串硬编码，就可以得到相同的UUID。\n2.调用connect()建立连接\n在调用的过程中，服务端系统会执行一个SDP检查UUID是否匹配。 如果匹配则接受连接，分享RFCOMM信道，connect()就会返回。 该方法是一个阻塞调用。如果连接失败或者conntct()方法超时(大概12秒)或者其他任何原因，则会抛出一个异常。\n因为connect()是阻塞调用，该连接步骤最好放在与主activity线程分离的新线程中执行。\n注意:你必须确保在调用connect()时，设备没有在进行搜寻其他设备的活动。否则连接会明显变得很慢并且很容易失败。\n示例\n这是在一个线程中建立蓝牙连接的基本示例:\nprivate class ConnectThread extends Thread {\nprivate final BluetoothSocket mmSocket;\nprivate final BluetoothDevice mmDevice;\npublic ConnectThread(BluetoothDevice device) {\n// Use a temporary object that is later assigned to mmSocket,\n// because mmSocket is final\nBluetoothSocket tmp = null;\nmmDevice = device;\n// Get a BluetoothSocket to connect with the given BluetoothDevice\ntry {\n// MY_UUID is the app’s UUID string, also used by the server code\ntmp = device.createRfcommSocketToServiceRecord(MY_UUID);\n} catch (IOException e) { }\nmmSocket = tmp;\n}\npublic void run() {\n// Cancel discovery because it will slow down the connection\nmBluetoothAdapter.cancelDiscovery();\ntry {\n// Connect the device through the socket. This will block\n// until it succeeds or throws an exception\nmmSocket.connect();\n} catch (IOException connectException) {\n// Unable to connect; close the socket and get out\ntry {\nmmSocket.close();\n} catch (IOException closeException) { }\nreturn;\n}\n// Do work to manage the connection (in a separate thread)\nmanageConnectedSocket(mmSocket);\n}\n/** Will cancel an in-progress connection, and close the socket */\npublic void cancel() {\ntry {\nmmSocket.close();\n} catch (IOException e) { }\n}\n}\n需要注意的是在连接开始前调用了cancelDiscovery()，你每次连接前都应该这样做， 调用cancelDiscovery()是安全的，不需要检查设备搜寻是否真的在运行(如果你想检查，可以调用isDiscovering())。\nmanageConnectedSocket()是一个在应用程序中自定义的方法，作用是建立线程传输数据。这将在连接管理这一节中讨论。\n当你用BluetoothSocket完成相关工作之后，记得调用close()来释放。 调用该函数将会立刻关闭socket并清除所有内部资源。\n连接管理\n当你成功将两个设备连接起来时，每个设备都拥有一个已连接的BluetoothSocket。 乐趣就从此开始了，因为你可以在两台设备间分享数据。 通过使用BluetoothSocket，传输数据的过程非常简单：\n1.通过socket获取InputStream和OutputStream来操纵传输，分别使用getInputStream()和getOutputStream()即可。\n2.用read(byte[]) 和 write(byte[])在数据流中读写数据。\n就这么简单。\n当然，还有一些实现细节需要考虑。 首先，同时也是最重要的，是使用一个专门的线程来运行所有的数据流读写。 这非常重要，因为read(byte[]) 和 write(byte[])方法都是阻塞的调用。 read(byte[])方法会一直阻塞，直到从数据流上读取到数据。 write(byte[])一般不会阻塞，但是如果对方设备没有及时调用read(byte[])导致临时缓冲区满了的情况下，该方法会阻塞住便于流控制。 所以，你的线程的主循环可以专门用来InputStream读取，然后实现线程的另一个public方法用于OutputStream写入。\n示例\nprivate class ConnectedThread extends Thread {\nprivate final BluetoothSocket mmSocket;\nprivate final InputStream mmInStream;\nprivate final OutputStream mmOutStream;\npublic ConnectedThread(BluetoothSocket socket) {\nmmSocket = socket;\nInputStream tmpIn = null;\nOutputStream tmpOut = null;\n// Get the input and output streams, using temp objects because\n// member streams are final\ntry {\ntmpIn = socket.getInputStream();\ntmpOut = socket.getOutputStream();\n} catch (IOException e) { }\nmmInStream = tmpIn;\nmmOutStream = tmpOut;\n}\npublic void run() {\nbyte[] buffer = new byte[1024]; // buffer store for the stream\nint bytes; // bytes returned from read()\n// Keep listening to the InputStream until an exception occurs\nwhile (true) {\ntry {\n// Read from the InputStream\nbytes = mmInStream.read(buffer);\n// Send the obtained bytes to the UI activity\nmHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)\n.sendToTarget();\n} catch (IOException e) {\nbreak;\n}\n}\n}\n/* Call this from the main activity to send data to the remote device */\npublic void write(byte[] bytes) {\ntry {\nmmOutStream.write(bytes);\n} catch (IOException e) { }\n}\n/* Call this from the main activity to shutdown the connection */\npublic void cancel() {\ntry {\nmmSocket.close();\n} catch (IOException e) { }\n}\n}\n构造函数获取必须的数据流对象，而且一旦执行，线程就会通过InputStream等待数据进入。 当read(byte[])返回数据流上的数据，这些数据就会通过父类的成员Handler被发送到主activity。 然后循环回来继续等待更多数据。\n向外发送数据很简单，只需要在主activity调用write()方法，并在参数中传递需要发送的数据。 该方法直接调用write(byte[])发送数据到对方设备。\n线程的cancel()方法非常重要，这样才能在任何时候通过关闭BluetoothSocket来中断连接。 当你使用完蓝牙连接之后，记得调用cancel()。\n更多关于使用蓝牙API的范例，可以看蓝牙聊天的示例应用. http://developer.android.com/resources/samples/BluetoothChat/index.html\n在蓝牙规范协议下工作\n从Android 3.0开始，蓝牙API就包含了Bluetooth profiles的支持。 Bluetooth profiles是设备间基于蓝牙通讯的无线接口协议描述。 比如免提协议(Hands-Free)，手机如果要与无线耳机连接，两者都要支持免提协议。\n你可以在自己的class中实现BluetoothProfile接口，用于支持特定的Bluetooth profile. Android蓝牙API提供了以下Bluetooth profiles的实现：\n蓝牙耳机： 蓝牙耳机协议提供了蓝牙耳机在手机上使用的支持。Android提供了BluetoothHeadset类， 这是通过IPC(interprocess communication)控制蓝牙耳机服务的代理。 同时包含了蓝牙耳机(Bluetooth Headset)和免提(Hands-Free v1.5)协议。 BluetoothHeadset类还包含了AT命令的支持。更多信息请查看Vendor-specific AT commands。\nA2DP: A2DP(Advanced Audio Distribution Profile),高质量音频分发协议定义了高质量音频的数据流如何通过蓝牙连接从一个设备传输到另一个。 Android提供了BluetoothA2dp类，这是一个通过IPC(interprocess communication)控制蓝牙A2DP服务的代理。\n医疗设备： Android 4.0 (API level 14)引入了HDP(Bluetooth Health Device Profile)的支持。 可以让你的应用程序使用蓝牙连接那些支持蓝牙的医疗设备。 例如心率监视器、血压计、体温计等。 网站www.bluetooth.org的Bluetooth Assigned Numbers记录了关于已支持设备的列表和他们的相关设备数据代码。 这些数值也收录在ISO/IEEE 11073-20601 [7] specification as MDC_DEV_SPEC_PROFILE_* in the Nomenclature Codes Annex. 更多关于HDP的信息请查看Health Device Profile。\n下面是在蓝牙规范协议下工作的基本步骤：\n1.获取默认的适配器，在配置蓝牙这一节中描述过的。\n2.使用getProfileProxy()方法建立到协议相关联的代理对象的连接。\n在下面的示例中，协议代理对象就是一个BluetoothHeadset实例。\n3.创建一个BluetoothProfile.ServiceListener\n这个listener可以侦听BluetoothProfile IPC客户端的连接或断开服务。\n4.在onServiceConnected()中，获得profile代理对象的句柄。\n5.一旦你获得profile proxy对象，你可以用它监视连接状态，还可以执行其他相关的操作。\n下面的代码片段介绍了如何连接一个BluetoothHeadset代理对象，并用来控制Headset协议。\nBluetoothHeadset mBluetoothHeadset;\n// Get the default adapter\nBluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();\n// Establish connection to the proxy.\nmBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);\nprivate BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {\npublic void onServiceConnected(int profile, BluetoothProfile proxy) {\nif (profile == BluetoothProfile.HEADSET) {\nmBluetoothHeadset = (BluetoothHeadset) proxy;\n}\n}\npublic void onServiceDisconnected(int profile) {\nif (profile == BluetoothProfile.HEADSET) {\nmBluetoothHeadset = null;\n}\n}\n};\n// … call functions on mBluetoothHeadset\n// Close proxy connection after use.\nmBluetoothAdapter.closeProfileProxy(mBluetoothHeadset);\nVendor-specific AT commands\n从Android 3.0开始，应用程序就可以注册接收耳机发送的pre-defined vendor-specific AT commands系统广播（类似Plantronics +XEVENT命令）。 例如，一个应用程序可以接收指示已连接设备电量等级的广播，然后通知用户或者采取其他必要的措施。 创建一个ACTION_VENDOR_SPECIFIC_HEADSET_EVENT intent的broadcast receiver，即可处理vendor-specific AT commands。\nHealth Device Profile\n","permalink":"https://blog.zdltech.com/posts/android-%E8%93%9D%E7%89%99/","summary":"\u003cp\u003eandroid平台包含了蓝牙网络协议栈的支持，允许android设备与其他蓝牙设备相互传输数据。应用层框架提供了API函数来访问蓝牙模块。使用这些API可以让应用程序连接其他蓝牙设备，实现点对点或多点无线传输。\u003cbr\u003e\n运用蓝牙API，可以实现以下功能：\u003cbr\u003e\n搜索其他蓝牙设备\u003cbr\u003e\n查询本地蓝牙适配器中已经配对好的设备\u003cbr\u003e\n建立RFCOMM协议通道\u003cbr\u003e\n通过服务端搜索连接到其他设备\u003cbr\u003e\n与其他设备互相传输数据\u003cbr\u003e\n管理多个连接\u003cbr\u003e\n快速阅读\u003cbr\u003e\nAndroid蓝牙API可以让应用程序与其他设备传输无线数据。\u003cbr\u003e\n关键类\u003cbr\u003e\nBluetoothAdapter\u003cbr\u003e\nBluetoothDevice\u003cbr\u003e\nBluetoothSocket\u003cbr\u003e\nBluetoothServerSocket\u003cbr\u003e\n相关用例\u003cbr\u003e\n蓝牙对讲 \u003ca href=\"http://developer.android.com/resources/samples/BluetoothChat/index.html\"\u003ehttp://developer.android.com/resources/samples/BluetoothChat/index.html\u003c/a\u003e\u003cbr\u003e\n蓝牙医疗设备(Health Device Profile)，比如心率监视器，血压计，温度计等。http://developer.android.com/resources/samples/BluetoothHDP/index.html\u003cbr\u003e\n目录 [隐藏]\u003cbr\u003e\n1 基本原理\u003cbr\u003e\n2 蓝牙权限\u003cbr\u003e\n3 配置蓝牙\u003cbr\u003e\n4 获取蓝牙设备\u003cbr\u003e\n4.1 查询已配对设备\u003cbr\u003e\n4.2 搜索设备\u003cbr\u003e\n4.3 开启蓝牙可检测性\u003cbr\u003e\n5 设备连接\u003cbr\u003e\n5.1 作为服务端连接\u003cbr\u003e\n5.2 作为客户端连接\u003cbr\u003e\n6 连接管理\u003cbr\u003e\n7 在蓝牙规范协议下工作\u003cbr\u003e\n7.1 Vendor-specific AT commands\u003cbr\u003e\n7.2 Health Device Profile\u003cbr\u003e\n基本原理\u003c/p\u003e\n\u003cp\u003e本文档描述了如何使用蓝牙API来完成蓝牙通讯的四项必要任务：配置蓝牙、搜索附件未配对或可用的蓝牙设备、连接设备、设备间传输数据。\u003cbr\u003e\n所有蓝牙API都包含在android.bluetooth包中。以下是建立蓝牙连接需要用到的类和接口的概要：\u003cbr\u003e\nBluetoothAdapter (蓝牙适配器)\u003cbr\u003e\n表示本地蓝牙适配器(蓝牙收发器). BluetoothAdapter是所有蓝牙活动的起始类. 可用于搜索其他蓝牙设备, 查询已配对设备的列表, 使用MAC地址实例化一个BluetoothDevice对象, 创建BluetoothServerSocket侦听其他设备的连接.\u003cbr\u003e\nBluetoothDevice (蓝牙设备)\u003cbr\u003e\n表示远程蓝牙设备。可以通过一个BluetoothSocket向它描述的远程设备发起连接，或者该设备的名称、地址、类、连接状态等信息。\u003cbr\u003e\nBluetoothSocket (蓝牙套接字)\u003cbr\u003e\n表示一个蓝牙套接字(与TCP Socket类似). 它是设备间的连接点，允许应用程序通过InputStream和OutputStream与其他设备进行数据传输。\u003cbr\u003e\nBluetoothServerSocket (蓝牙服务端套接字)\u003cbr\u003e\n表示一个开放的蓝牙服务器， 用于侦听其他设备发过来的连接请求(与TCP ServerSocket类似). 要将两台设备连接起来, 其中一台必须使用这个类开启一个server socket. 当远程蓝牙设备发起对server的连接请求, 如果连接被接受，BluetoothServerSocket将返回一个连接成功的BluetoothSocket对象.\u003cbr\u003e\nBluetoothClass (蓝牙类型)\u003cbr\u003e\n描述一个蓝牙设备的规格参数和功能。这是一个只读的属性集，定义了该设备的主要和次要设备种类和服务。它不能完全描述该设备的所有特性和服务，常用于判断设备的类型。\u003cbr\u003e\nBluetoothProfile (蓝牙规范协议)\u003cbr\u003e\n表示Bluetooth profile的接口. Bluetooth profile是设备间基于蓝牙通讯的接口规范协议。比如Hands-Free(非手持设备) profile。更多关于profiles的说明, 请查看Working with Profiles(在蓝牙规范协议下工作)。\u003cbr\u003e\nBluetoothHeadset (蓝牙耳机)\u003cbr\u003e\n提供手机使用蓝牙耳机的支持。同时包含了蓝牙耳机和Hands-Free(v1.5)的profiles.\u003cbr\u003e\nBluetoothA2dp (蓝牙A2dp)\u003cbr\u003e\n定义高质量音频流如何通过蓝牙连接传输到其他设备。”A2DP”是”Advanced Audio Distribution Profile”的缩写，表示高级音频分发规范协议。\u003cbr\u003e\nBluetoothHealth (蓝牙医疗设备)\u003cbr\u003e\n表示为医疗设备提供蓝牙服务的代理类。\u003cbr\u003e\nBluetoothHealthCallback\u003cbr\u003e\n这是一个抽象类，用于实现BluetoothHealth的callbacks方法。需要继承此类并实现callback方法才能接收应用程序状态和蓝牙频道状态的变化。\u003cbr\u003e\nBluetoothHealthAppConfiguration\u003cbr\u003e\n表示蓝牙医疗第三方应用与远程蓝牙医疗设备连接的配置参数。\u003cbr\u003e\nBluetoothProfile.ServiceListener (蓝牙规范协议服务侦听)\u003cbr\u003e\n一个接口类，当服务连接或断开的时候通知BluetoothProfile IPC 客户端。(这是内部服务运行的一个特殊模式)。\u003cbr\u003e\n蓝牙权限\u003c/p\u003e","title":"android 蓝牙"},{"content":"使用TCP通信服务器步骤\n1、调用ServerSocket(int port) 创建一个ServerSocket，并绑定到指定端口上\n2、调用accept()，监听连接请求，如果客户端请求连接，则接受连接，返回通信套接字\n3、调用Socket的getInputStream（）和getOutputStream（）获得输入和输出流，开始网络数据的发送和接收。\n4、关闭通信套接字。\n例如：\n//创建一个ServerSocket\nServerSocket serverSocket=null;\ntry{\n//TCP_SERVER_PORT为指定的绑定端口，为into类型\nserverSocket=new ServerSocket（TCP_SERVER_PORT）；\n//监听连接请求\nSocket socket=serverSocket.accept();\n//写入读Buffer中\nBufferReader in=new BufferReader(\n//获得输入流\nnew InputStreamReader(socket.getInputStream())\n);\n//放到写Buffer中\nBufferWriter out=new BufferWriter(new OutputStreamWriter(socket.getOutputStream()));\n//读取接收信息，转换为字符串\nString incomingMsg=in.readerLine()+System.getProperty(“line.separator”);\n//生成发送字符串\nString outGoingMsg=”goodbye from port “+TCP_SERVER+PORT+System.getProperty(“line.separator”);\n//将发送字符串写入上面定义的BufferWriter中\nout.write(outGoingMsg);\n//刷新 发送\nout.flush();\n//关闭\nsocket.close();\n}catch(InterruptedIOException e){\n//超时错误\ne.printStackTrace();\n}catch(IOException e){//IO异常\ne.printStackTrace();\n}finally{//判定是否初始化ServerSocket对象，如果初始化则关闭ServerSocket\nif(serverSocket!=null){\ntry{\nserverSocket.close();\n}catch(IOExcetion e){\ne.printStackTrace();\n}\n}\n}\n使用TCP通信客户端步骤\n1、调用Socket（）创建一个Socket（套接字），并绑定到指定服务端口上。\n2、调用Socket的getInputStream（）和getOutputStream（）获得输入和输出流，开始网络数据的发送和接收。\n3、关闭通信套接字。\n例如：\ntry{\n//初始化Socket，TCP_SERVER_PORT为指定的服务器端口（int类型）\nSocket socket=new Socket(“Ip/website”,TCP_SERVER_PORT);\n//获得输入流\nBufferReader in=new BufferReader(new InputStreamReader(socket.getInputStream()));\n//生成输出流\nBufferWriter out=new BufferWriter(new OutputStreamWriter(socket.getOutputStream()));\n//生成发送字符串\nString outGoingMsg=”goodbye from port “+TCP_SERVER+PORT+System.getProperty(“line.separator”);\n//将发送字符串写入上面定义的BufferWriter中\nout.write(outGoingMsg);\n//刷新 发送\nout.flush();\n//读取接收信息，转换为字符串\nString incomingMsg=in.readerLine()+System.getProperty(“line.separator”);\n//关闭\nsocket.close();\n}catch(UnknownHostException e){\n//超时错误\ne.printStackTrace();\n}catch(IOException e){//IO异常\ne.printStackTrace();\n}\n使用UDP通信服务器步骤\n1、调用DatagramSocket(int port) 创建一个数据报套接字，并绑定到指定端口上\n2、调用DatagramPacket(byte[] buf,int length)，建立一个字节数组以接收UDP包。\n3、调用DatagramSocket的receive（），接受UDP包。\n4、关闭数据报套接字。\n例如：\n//接收的字节大小，客户端发送的数据不能超过MAX_UDP_DATAGRAM_LEN\nbyte[] lMsg=new byte[MAX_UDP_DATAGRAM_LEN];\n//实例化一个DatagramPacket\nDatagramPacket dp=new DatagramPacket(lMsg,lMsg.length);\n//创建一个DatagramSocket\nDatagramSocket ds=null;\ntry{\n//UDP_SERVER_PORT为指定的绑定端口，为into类型\nds=new DatagramSocket（UDP_SERVER_PORT）；\n//准备接收数据\nds.receive(dp);\n}catch(SocketException e){\n//超时错误\ne.printStackTrace();\n}catch(IOException e){//IO异常\ne.printStackTrace();\n}finally{//如果ds对象不为空，则关闭ds对象\nif(ds!=null){\nds.close();\n}\n}\n使用UDP通信客户端步骤\n1、调用DatagramSocket（）创建一个数据报套接字。\n2、调用DatagramPacket(byte[] buf,int offset,int length,InetAddress address,int port)，建立要发送的UDP包\n3、调用DatagramSocket的send()发送UDP包\n4、关闭数据报套接字。\n例如：\n//定义要发送的信息\nString udpMsg=”hello world from UDP client “+UDP_SERVER_PORT;\n//新建一个DataGramSocket对象\nDatagramSocket ds=null;\ntry{\n//初始化DatagramSocket\nds=new DatagramSocket();\n//初始化InetAddress 对象\nInetAddress serverAddress=InetAddress.getByName(“127.0.0.1”);\nDatagramPacket dp;\n//初始化DatagramPacket对象\ndp=new DatagramPacket(udpMsg.getBytes(),udpMsg.length(),serverAddress,UDP_SERVER_PORT);\n//发送\nds.send(dp);\n//获得输入流\n}catch(SocketException e){\ne.printStackTrace();\n}catch(UnknownHostException e){\ne.printStackTrace();\n}catch(IOException e){//IO异常\ne.printStackTrace();\n}catch(Exception e){\ne.printStackTrace();\n}finally{\n//如果DatagramSocket已经实例化，需要关闭\nif(ds!=null){\nds.close();\n}\n}\n转发注明来源：http://www.etongwl.com/?p=608\n","permalink":"https://blog.zdltech.com/posts/android-%E4%B8%AD%E4%BD%BF%E7%94%A8tcpudp%E5%8D%8F%E8%AE%AE/","summary":"\u003cp\u003e使用TCP通信服务器步骤\u003cbr\u003e\n1、调用ServerSocket(int port) 创建一个ServerSocket，并绑定到指定端口上\u003cbr\u003e\n2、调用accept()，监听连接请求，如果客户端请求连接，则接受连接，返回通信套接字\u003cbr\u003e\n3、调用Socket的getInputStream（）和getOutputStream（）获得输入和输出流，开始网络数据的发送和接收。\u003cbr\u003e\n4、关闭通信套接字。\u003cbr\u003e\n例如：\u003cbr\u003e\n//创建一个ServerSocket\u003cbr\u003e\nServerSocket serverSocket=null;\u003cbr\u003e\ntry{\u003cbr\u003e\n//TCP_SERVER_PORT为指定的绑定端口，为into类型\u003cbr\u003e\nserverSocket=new ServerSocket（TCP_SERVER_PORT）；\u003cbr\u003e\n//监听连接请求\u003cbr\u003e\nSocket socket=serverSocket.accept();\u003cbr\u003e\n//写入读Buffer中\u003cbr\u003e\nBufferReader in=new BufferReader(\u003cbr\u003e\n//获得输入流\u003cbr\u003e\nnew InputStreamReader(socket.getInputStream())\u003cbr\u003e\n);\u003cbr\u003e\n//放到写Buffer中\u003cbr\u003e\nBufferWriter out=new BufferWriter(new OutputStreamWriter(socket.getOutputStream()));\u003cbr\u003e\n//读取接收信息，转换为字符串\u003cbr\u003e\nString incomingMsg=in.readerLine()+System.getProperty(“line.separator”);\u003cbr\u003e\n//生成发送字符串\u003cbr\u003e\nString outGoingMsg=”goodbye from port “+TCP_SERVER+PORT+System.getProperty(“line.separator”);\u003cbr\u003e\n//将发送字符串写入上面定义的BufferWriter中\u003cbr\u003e\nout.write(outGoingMsg);\u003cbr\u003e\n//刷新 发送\u003cbr\u003e\nout.flush();\u003cbr\u003e\n//关闭\u003cbr\u003e\nsocket.close();\u003cbr\u003e\n}catch(InterruptedIOException e){\u003cbr\u003e\n//超时错误\u003cbr\u003e\ne.printStackTrace();\u003cbr\u003e\n}catch(IOException e){//IO异常\u003cbr\u003e\ne.printStackTrace();\u003cbr\u003e\n}finally{//判定是否初始化ServerSocket对象，如果初始化则关闭ServerSocket\u003cbr\u003e\nif(serverSocket!=null){\u003cbr\u003e\ntry{\u003cbr\u003e\nserverSocket.close();\u003cbr\u003e\n}catch(IOExcetion e){\u003cbr\u003e\ne.printStackTrace();\u003cbr\u003e\n}\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e}\u003cbr\u003e\n使用TCP通信客户端步骤\u003cbr\u003e\n1、调用Socket（）创建一个Socket（套接字），并绑定到指定服务端口上。\u003cbr\u003e\n2、调用Socket的getInputStream（）和getOutputStream（）获得输入和输出流，开始网络数据的发送和接收。\u003cbr\u003e\n3、关闭通信套接字。\u003cbr\u003e\n例如：\u003cbr\u003e\ntry{\u003cbr\u003e\n//初始化Socket，TCP_SERVER_PORT为指定的服务器端口（int类型）\u003cbr\u003e\nSocket socket=new Socket(“Ip/website”,TCP_SERVER_PORT);\u003cbr\u003e\n//获得输入流\u003cbr\u003e\nBufferReader in=new BufferReader(new InputStreamReader(socket.getInputStream()));\u003cbr\u003e\n//生成输出流\u003cbr\u003e\nBufferWriter out=new BufferWriter(new OutputStreamWriter(socket.getOutputStream()));\u003cbr\u003e\n//生成发送字符串\u003cbr\u003e\nString outGoingMsg=”goodbye from port “+TCP_SERVER+PORT+System.getProperty(“line.separator”);\u003cbr\u003e\n//将发送字符串写入上面定义的BufferWriter中\u003cbr\u003e\nout.write(outGoingMsg);\u003cbr\u003e\n//刷新 发送\u003cbr\u003e\nout.flush();\u003cbr\u003e\n//读取接收信息，转换为字符串\u003cbr\u003e\nString incomingMsg=in.readerLine()+System.getProperty(“line.separator”);\u003cbr\u003e\n//关闭\u003cbr\u003e\nsocket.close();\u003cbr\u003e\n}catch(UnknownHostException e){\u003cbr\u003e\n//超时错误\u003cbr\u003e\ne.printStackTrace();\u003cbr\u003e\n}catch(IOException e){//IO异常\u003cbr\u003e\ne.printStackTrace();\u003cbr\u003e\n}\u003cbr\u003e\n使用UDP通信服务器步骤\u003cbr\u003e\n1、调用DatagramSocket(int port) 创建一个数据报套接字，并绑定到指定端口上\u003cbr\u003e\n2、调用DatagramPacket(byte[] buf,int length)，建立一个字节数组以接收UDP包。\u003cbr\u003e\n3、调用DatagramSocket的receive（），接受UDP包。\u003cbr\u003e\n4、关闭数据报套接字。\u003cbr\u003e\n例如：\u003cbr\u003e\n//接收的字节大小，客户端发送的数据不能超过MAX_UDP_DATAGRAM_LEN\u003cbr\u003e\nbyte[] lMsg=new byte[MAX_UDP_DATAGRAM_LEN];\u003cbr\u003e\n//实例化一个DatagramPacket\u003cbr\u003e\nDatagramPacket dp=new DatagramPacket(lMsg,lMsg.length);\u003cbr\u003e\n//创建一个DatagramSocket\u003cbr\u003e\nDatagramSocket ds=null;\u003cbr\u003e\ntry{\u003cbr\u003e\n//UDP_SERVER_PORT为指定的绑定端口，为into类型\u003cbr\u003e\nds=new DatagramSocket（UDP_SERVER_PORT）；\u003cbr\u003e\n//准备接收数据\u003cbr\u003e\nds.receive(dp);\u003cbr\u003e\n}catch(SocketException e){\u003cbr\u003e\n//超时错误\u003cbr\u003e\ne.printStackTrace();\u003cbr\u003e\n}catch(IOException e){//IO异常\u003cbr\u003e\ne.printStackTrace();\u003cbr\u003e\n}finally{//如果ds对象不为空，则关闭ds对象\u003cbr\u003e\nif(ds!=null){\u003cbr\u003e\nds.close();\u003cbr\u003e\n}\u003c/p\u003e","title":"Android 中使用TCP、UDP协议"},{"content":"微信公众平台开发 OAuth2.0网页授权认证 网页授权获取用户基本信息\n作者：方倍工作室\n微信公众平台最近新推出微信认证，认证后可以获得高级接口权限，其中一个是OAuth2.0网页授权，很多朋友在使用这个的时候失败了或者无法理解其内容，希望我出个教程详细讲解一下，于是便有了这篇文章。\n一、什么是OAuth2.0 官方网站：http://oauth.net/ http://oauth.net/2/\n权威定义：OAuth is An open protocol to allow secure authorization in a simple and standard method from web, mobile and desktop applications.\nOAuth是一个开放协议，允许用户让第三方应用以安全且标准的方式获取该用户在某一网站、移动或桌面应用上存储的私密的资源（如用户个人信息、照片、视频、联系人列表），而无需将用户名和密码提供给第三方应用。\nOAuth 2.0是OAuth协议的下一版本，但不向后兼容OAuth 1.0。 OAuth 2.0关注客户端开发者的简易性，同时为Web应用，桌面应用和手机，和起居室设备提供专门的认证流程。\nOAuth允许用户提供一个令牌，而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的网站（例如，视频编辑网站)在特定的时段（例如，接下来的2小时内）内访问特定的资源（例如仅仅是某一相册中的视频）。这样，OAuth允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息，而不需要分享他们的访问许可或他们数据的所有内容。\n新浪微博API目前也使用OAuth 2.0。\n原文：http://www.cnblogs.com/txw1958/p/weixin71-oauth20.html\n二、微信公众平台OAuth2.0授权\n微信公众平台OAuth2.0授权详细步骤如下：\n用户关注微信公众账号。 微信公众账号提供用户请求授权页面URL。 用户点击授权页面URL，将向服务器发起请求 服务器询问用户是否同意授权给微信公众账号(scope为snsapi_base时无此步骤) 用户同意(scope为snsapi_base时无此步骤) 服务器将CODE通过回调传给微信公众账号 微信公众账号获得CODE 微信公众账号通过CODE向服务器请求Access Token 服务器返回Access Token和OpenID给微信公众账号 微信公众账号通过Access Token向服务器请求用户信息(scope为snsapi_base时无此步骤) 服务器将用户信息回送给微信公众账号(scope为snsapi_base时无此步骤) 使用的AppId和AppSecret在开发者中心-开发者ID中，可以找到。\n1. 配置授权回调页面域名\n进入微信公众平台后台后，依次进入开发者中心-权限表，找到网页授权获取用户基本信息，\n点击右侧的修改。原文：http://www.cnblogs.com/txw1958/p/weixin71-oauth20.html\n授权回调域名配置规范为全域名并且不带http，比如需要网页授权的域名为：www.qq.com，配置以后此域名下面的页面http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以进行OAuth2.0鉴权。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com无法进行OAuth2.0鉴权。\n这里我们填写方倍工作室的一个百度应用二级域名为 mascot.duapp.com\n原文：http://www.cnblogs.com/txw1958/p/weixin71-oauth20.html\n如果你的网址没有被列入过黑名单，就会在顶部出现\n然后，域名配置就成功了。\n2. 用户授权并获取code\n在域名根目录下，新建一个文件，命名为oauth2.php，其内容为\n![复制代码](http://common.cnblogs.com/images/copycode.gif) \u0026amp;lt;?php if (isset(\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;_GET[\u0026#39;code\u0026#39;])){ echo\u0026lt;/span\u0026gt;_GET[\u0026#39;code\u0026#39;]; }else{ echo \u0026#34;NO CODE\u0026#34;; } ?\u0026amp;gt; ![复制代码](http://common.cnblogs.com/images/copycode.gif) 先了解下请求授权页面的构造方式：\n``` https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID\u0026redirect_uri=REDIRECT_URI\u0026response_type=code\u0026scope=SCOPE\u0026state=STATE#wechat_redirect ``` 参数说明\n参数 \u0026lt;th\u0026gt; 必须 \u0026lt;/th\u0026gt; \u0026lt;th\u0026gt; 说明 \u0026lt;/th\u0026gt; appid \u0026lt;td\u0026gt; 是 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 公众号的唯一标识 \u0026lt;/td\u0026gt; redirect_uri \u0026lt;td\u0026gt; 是 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 授权后重定向的回调链接地址** ** response_type \u0026lt;td\u0026gt; 是 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 返回类型，请填写code \u0026lt;/td\u0026gt; scope \u0026lt;td\u0026gt; 是 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 应用授权作用域，snsapi_base （不弹出授权页面，直接跳转，只能获取用户openid），snsapi_userinfo （弹出授权页面，可通过openid拿到昵称、性别、所在地。并且，**即使在未关注的情况下，只要用户授权，也能获取其信息**） \u0026lt;/td\u0026gt; state \u0026lt;td\u0026gt; 否 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 重定向后会带上state参数，开发者可以填写任意参数值 \u0026lt;/td\u0026gt; #wechat_redirect \u0026lt;td\u0026gt; 否 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 直接在微信打开链接，可以不填此参数。做页面302重定向时候，必须带此参数 \u0026lt;/td\u0026gt; 应用授权作用域：由于snsapi_base只能获取到openid，意义不大，所以我们使用snsapi_userinfo。\n回调地址：填写为刚才上传后的oauth2.php的文件地址，\nstate参数：随便一个数字，这里填1\n构造请求url如下：\n``` https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx8888888888888888\u0026redirect_uri=http://mascot.duapp.com/oauth2.php\u0026response_type=code\u0026scope=snsapi_userinfo\u0026state=1#wechat_redirect ``` 把这个链接发送到微信中，以便在微信浏览器中打开，这里使用A链接封装如下：\n``` 欢迎关注【近宝】，它能让你更加方便寻找在你附近合你心意的餐饮、服装、百货、美容美发店铺。 \u0026lt;a href=\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx8888888888888888\u0026redirect_uri=http://mascot.duapp.com/oauth2.php\u0026response_type=code\u0026scope=snsapi_userinfo\u0026state=1#wechat_redirect\"\u0026gt;点击这里绑定\u0026lt;/a\u0026gt; 技术支持 方倍工作室 ``` 在微信中显示如下\n点击绑定后，弹出应用授权界面\n选择允许，点击\n跳转到auth2.php页面，执行\n``` echo $_GET['code'] ``` 界面上显示的就是code，这时候通过右上角按钮中的复制链接，得到链接如下：\n``` http://mascot.duapp.com/oauth2.php?code=00b788e3b42043c8459a57a8d8ab5d9f\u0026state=1 ``` 我们成功得到了code了。\n``` 注意：如果在绑定的时候出现这样的界面，就说明参数不对，需要回头检查一下参数 ``` ![](http://images.cnitblog.com/blog/340216/201311/09144149-03e710fa93854bf790ef097eb0557d01.png) ** **\n3. 使用code换取access_token\n换取网页授权access_token页面的构造方式：\n``` https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID\u0026secret=SECRET\u0026code=CODE\u0026grant_type=authorization_code ``` 参数说明\n参数 \u0026lt;th\u0026gt; 是否必须 \u0026lt;/th\u0026gt; \u0026lt;th\u0026gt; 说明 \u0026lt;/th\u0026gt; appid \u0026lt;td\u0026gt; 是 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 公众号的唯一标识 \u0026lt;/td\u0026gt; secret \u0026lt;td\u0026gt; 是 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 公众号的appsecret \u0026lt;/td\u0026gt; code \u0026lt;td\u0026gt; 是 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 填写第一步获取的code参数 \u0026lt;/td\u0026gt; grant_type \u0026lt;td\u0026gt; 是 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 填写为authorization_code \u0026lt;/td\u0026gt; code：在这里填写为上一步获得的值\n构造请求url如下：\n``` https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx8888888888888888\u0026secret=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\u0026code=00b788e3b42043c8459a57a8d8ab5d9f\u0026grant_type=authorization_code ``` 可以在浏览器中直接执行这条语句：\n得到如下json数据:\n![复制代码](http://common.cnblogs.com/images/copycode.gif) { \u0026#34;access_token\u0026#34;: \u0026#34;OezXcEiiBSKSxW0eoylIeAsR0GmYd1awCffdHgb4fhS_KKf2CotGj2cBNUKQQvj-G0ZWEE5-uBjBz941EOPqDQy5sS_GCs2z40dnvU99Y5AI1bw2uqN--2jXoBLIM5d6L9RImvm8Vg8cBAiLpWA8Vw\u0026#34;, \u0026#34;expires_in\u0026#34;: 7200, \u0026#34;refresh_token\u0026#34;: \u0026#34;OezXcEiiBSKSxW0eoylIeAsR0GmYd1awCffdHgb4fhS_KKf2CotGj2cBNUKQQvj-G0ZWEE5-uBjBz941EOPqDQy5sS_GCs2z40dnvU99Y5CZPAwZksiuz_6x_TfkLoXLU7kdKM2232WDXB3Msuzq1A\u0026#34;, \u0026#34;openid\u0026#34;: \u0026#34;oLVPpjqs9BhvzwPj5A-vTYAX3GLc\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;snsapi_userinfo,\u0026#34; } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 数据格式解读如下：\n参数 \u0026lt;th\u0026gt; 描述 \u0026lt;/th\u0026gt; access_token \u0026lt;td\u0026gt; 网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同 \u0026lt;/td\u0026gt; expires_in \u0026lt;td\u0026gt; access_token接口调用凭证超时时间，单位（秒） \u0026lt;/td\u0026gt; refresh_token \u0026lt;td\u0026gt; 用户刷新access_token \u0026lt;/td\u0026gt; openid \u0026lt;td\u0026gt; 用户唯一标识，请注意，在未关注公众号时，用户访问公众号的网页，也会产生一个用户和公众号唯一的OpenID \u0026lt;/td\u0026gt; scope \u0026lt;td\u0026gt; 用户授权的作用域，使用逗号（,）分隔 \u0026lt;/td\u0026gt; 于是，我们成功的通过code换取到了access_token，以及refresh_token。\n![复制代码](http://common.cnblogs.com/images/copycode.gif) **刷新access_token** 官方文档中提到了刷新access_token的功能，但这不是必须要做的，初次使用可以先忽略。 url请求方法如下： ``` https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID\u0026grant_type=refresh_token\u0026refresh_token=REFRESH_TOKEN ``` 参数说明 参数 \u0026lt;th\u0026gt; 是否必须 \u0026lt;/th\u0026gt; \u0026lt;th\u0026gt; 说明 \u0026lt;/th\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; appid \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 是 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 公众号的唯一标识 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; grant_type \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 是 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 填写为refresh_token \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; refresh_token \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 是 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 填写通过access_token获取到的refresh_token参数 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 构造如下： ``` https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=wx8888888888888888\u0026grant_type=refresh_token\u0026refresh_token=OezXcEiiBSKSxW0eoylIeAsR0GmYd1awCffdHgb4fhS_KKf2CotGj2cBNUKQQvj-G0ZWEE5-uBjBz941EOPqDQy5sS_GCs2z40dnvU99Y5CZPAwZksiuz_6x_TfkLoXLU7kdKM2232WDXB3Msuzq1A ``` \u0026lt;span id=\u0026#34;__mceDel\u0026#34;\u0026gt;在浏览器中执行得到前面同样格式的json数据\u0026lt;/span\u0026gt; ![复制代码](http://common.cnblogs.com/images/copycode.gif) 4. 使用access_token获取用户信息\n请求方法：\n``` https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN\u0026openid=OPENID ``` 参数说明\n参数 \u0026lt;th\u0026gt; 描述 \u0026lt;/th\u0026gt; access_token \u0026lt;td\u0026gt; 网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同 \u0026lt;/td\u0026gt; openid \u0026lt;td\u0026gt; 用户的唯一标识 \u0026lt;/td\u0026gt; 构造url如下：\n``` https://api.weixin.qq.com/sns/userinfo?access_token=OezXcEiiBSKSxW0eoylIeAsR0GmYd1awCffdHgb4fhS_KKf2CotGj2cBNUKQQvj-G0ZWEE5-uBjBz941EOPqDQy5sS_GCs2z40dnvU99Y5AI1bw2uqN--2jXoBLIM5d6L9RImvm8Vg8cBAiLpWA8Vw\u0026openid=oLVPpjqs9BhvzwPj5A-vTYAX3GLc ``` 可以在浏览器中直接执行这条语句：\n得到如下json数据:\n![复制代码](http://common.cnblogs.com/images/copycode.gif) { \u0026#34;openid\u0026#34;: \u0026#34;oLVPpjqs9BhvzwPj5A-vTYAX3GLc\u0026#34;, \u0026#34;nickname\u0026#34;: \u0026#34;方倍\u0026#34;, \u0026#34;sex\u0026#34;: 1, \u0026#34;language\u0026#34;: \u0026#34;zh_CN\u0026#34;, \u0026#34;city\u0026#34;: \u0026#34;Shenzhen\u0026#34;, \u0026#34;province\u0026#34;: \u0026#34;Guangdong\u0026#34;, \u0026#34;country\u0026#34;: \u0026#34;CN\u0026#34;, \u0026#34;headimgurl\u0026#34;: \u0026#34;http://wx.qlogo.cn/mmopen/utpKYf69VAbCRDRlbUsPsdQN38DoibCkrU6SAMCSNx558eTaLVM8PyM6jlEGzOrH67hyZibIZPXu4BK1XNWzSXB3Cs4qpBBg18/0\u0026#34;, \u0026#34;privilege\u0026#34;: [] } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 参数解读：\n参数 \u0026lt;th\u0026gt; 描述 \u0026lt;/th\u0026gt; openid \u0026lt;td\u0026gt; 用户的唯一标识 \u0026lt;/td\u0026gt; nickname \u0026lt;td\u0026gt; 用户昵称 \u0026lt;/td\u0026gt; sex \u0026lt;td\u0026gt; 用户的性别，值为1时是男性，值为2时是女性，值为0时是未知 \u0026lt;/td\u0026gt; province \u0026lt;td\u0026gt; 用户个人资料填写的省份 \u0026lt;/td\u0026gt; city \u0026lt;td\u0026gt; 普通用户个人资料填写的城市 \u0026lt;/td\u0026gt; country \u0026lt;td\u0026gt; 国家，如中国为CN \u0026lt;/td\u0026gt; headimgurl \u0026lt;td\u0026gt; 用户头像，最后一个数值代表正方形头像大小（有0、46、64、96、132数值可选，0代表640*640正方形头像），用户没有头像时该项为空 \u0026lt;/td\u0026gt; privilege \u0026lt;td\u0026gt; 用户特权信息，json 数组，如微信沃卡用户为（chinaunicom） \u0026lt;/td\u0026gt; 这与我个人的微信信息是一致的\n至此，在不输入我的账号及密码的情况下，微信公众账号近宝获得了我的个人信息，这些信息包括昵称、性别、国家、省份、城市、个人头像以及特权列表。\n一个完整的OAuth2认证就完成了。\n三、详细演示\n在微信公众账号“方倍工作室”中，回复“授权”。\n弹出获取到的结果\n四、内容更新及源码下载 本节最新的教程说明及源代码已在《微信公众平台开发最佳实践》一书中发布，欢迎购买。\n点此**购买《微信公众平台开发最佳实践》**\n转自：http://www.cnblogs.com/txw1958/p/weixin71-oauth20.html\n","permalink":"https://blog.zdltech.com/posts/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%9171oauth2-0%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83/","summary":"\u003cp\u003e微信公众平台开发 OAuth2.0网页授权认证 网页授权获取用户基本信息\u003cbr\u003e\n作者：\u003ca href=\"http://www.cnblogs.com/txw1958/\"\u003e方倍工作室\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e微信公众平台最近新推出微信认证，认证后可以获得高级接口权限，其中一个是OAuth2.0网页授权，很多朋友在使用这个的时候失败了或者无法理解其内容，希望我出个教程详细讲解一下，于是便有了这篇文章。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch2 id=\"一什么是oauth20\"\u003e\u003cstrong\u003e一、什么是OAuth2.0\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e官方网站：http://oauth.net/   http://oauth.net/2/\u003c/p\u003e\n\u003cp\u003e权威定义：OAuth is An open protocol to allow secure authorization in a simple and standard method from web, mobile and desktop applications.\u003c/p\u003e\n\u003cp\u003eOAuth是一个开放协议，允许用户让第三方应用以安全且标准的方式获取该用户在某一网站、移动或桌面应用上存储的私密的资源（如用户个人信息、照片、视频、联系人列表），而无需将用户名和密码提供给第三方应用。\u003c/p\u003e\n\u003cp\u003eOAuth 2.0是OAuth协议的下一版本，但不向后兼容OAuth 1.0。 OAuth 2.0关注客户端开发者的简易性，同时为Web应用，桌面应用和手机，和起居室设备提供专门的认证流程。\u003c/p\u003e\n\u003cp\u003eOAuth允许用户提供一个令牌，而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的网站（例如，视频编辑网站)在特定的时段（例如，接下来的2小时内）内访问特定的资源（例如仅仅是某一相册中的视频）。这样，OAuth允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息，而不需要分享他们的访问许可或他们数据的所有内容。\u003c/p\u003e\n\u003cp\u003e新浪微博API目前也使用OAuth 2.0。\u003c/p\u003e\n\u003cp\u003e原文：http://www.cnblogs.com/txw1958/p/weixin71-oauth20.html\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e二、微信公众平台OAuth2.0授权\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e微信公众平台OAuth2.0授权详细步骤如下：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e用户关注微信公众账号。\u003c/li\u003e\n\u003cli\u003e微信公众账号提供用户请求授权页面URL。\u003c/li\u003e\n\u003cli\u003e用户点击授权页面URL，将向服务器发起请求\u003c/li\u003e\n\u003cli\u003e服务器询问用户是否同意授权给微信公众账号(scope为snsapi_base时无此步骤)\u003c/li\u003e\n\u003cli\u003e用户同意(scope为snsapi_base时无此步骤)\u003c/li\u003e\n\u003cli\u003e服务器将CODE通过回调传给微信公众账号\u003c/li\u003e\n\u003cli\u003e微信公众账号获得CODE\u003c/li\u003e\n\u003cli\u003e微信公众账号通过CODE向服务器请求Access Token\u003c/li\u003e\n\u003cli\u003e服务器返回Access Token和OpenID给微信公众账号\u003c/li\u003e\n\u003cli\u003e微信公众账号通过Access Token向服务器请求用户信息(scope为snsapi_base时无此步骤)\u003c/li\u003e\n\u003cli\u003e服务器将用户信息回送给微信公众账号(scope为snsapi_base时无此步骤)\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/340216/201401/06193653-6c44fea30bc946238e6940d46ba0f1fc.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e使用的AppId和AppSecret在开发者中心-开发者ID中，可以找到。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/340216/201411/292051020278792.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. 配置授权回调页面域名\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e进入微信公众平台后台后，依次进入开发者中心-权限表，找到网页授权获取用户基本信息，\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/340216/201411/292048235741068.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e点击右侧的修改。原文：http://www.cnblogs.com/txw1958/p/weixin71-oauth20.html\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/340216/201311/09103045-fbd48b2b755646e29cd3b4bf3ea5cd06.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e授权回调域名配置规范为全域名并且不带http，比如需要网页授权的域名为：www.qq.com，配置以后此域名下面的页面http://www.qq.com/music.html 、 \u003ca href=\"http://www.qq.com/login.html\"\u003ehttp://www.qq.com/login.html\u003c/a\u003e 都可以进行OAuth2.0鉴权。但http://pay.qq.com 、 \u003ca href=\"http://music.qq.com\"\u003ehttp://music.qq.com\u003c/a\u003e 、 \u003ca href=\"http://qq.com\"\u003ehttp://qq.com\u003c/a\u003e无法进行OAuth2.0鉴权。\u003c/p\u003e\n\u003cp\u003e这里我们填写方倍工作室的一个百度应用二级域名为 mascot.duapp.com\u003c/p\u003e","title":"微信公众平台开发（71）OAuth2.0网页授权"},{"content":"转载请注明本文出自xiaanming的博客（http://blog.csdn.net/xiaanming/article/details/20481185），请尊重他人的辛勤劳动成果，谢谢！\n大家好！过完年回来到现在差不多一个月没写文章了，一是觉得不知道写哪些方面的文章，没有好的题材来写，二是因为自己的一些私事给耽误了，所以过完年的第一篇文章到现在才发表出来，2014年我还是会继续在CSDN上面更新我的博客，欢迎大家关注一下，今天这篇文章主要的是介绍下开源库StickyGridHeaders的使用，StickyGridHeaders是一个自定义GridView带sections和headers的Android库，sections就是GridView item之间的分隔，headers就是固定在GridView顶部的标题，类似一些Android手机联系人的效果，StickyGridHeaders的介绍在https://github.com/TonicArtos/StickyGridHeaders，与此对应也有一个相同效果的自定义ListView带sections和headers的开源库https://github.com/emilsjolander/StickyListHeaders，大家有兴趣的可以去看下，我这里介绍的是StickyGridHeaders的使用，我在Android应用方面看到使用StickyGridHeaders的不是很多，而是在Iphone上看到相册采用的是这种效果，于是我就使用StickyGridHeaders来仿照Iphone按照日期分隔显示本地图片\n我们先新建一个Android项目StickyHeaderGridView，去https://github.com/TonicArtos/StickyGridHeaders下载开源库，为了方便浏览源码我直接将源码拷到我的工程中了\ncom.tonicartos.widget.stickygridheaders这个包就是我放StickyGridHeaders开源库的源码，com.example.stickyheadergridview这个包是我实现此功能的代码，类看起来还蛮多的，下面我就一一来介绍了\nGridItem用来封装StickyGridHeadersGridView 每个Item的数据，里面有本地图片的路径，图片加入手机系统的时间和headerId\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; GridItem { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 图片的路径\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String path; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 图片加入手机中的时间，只取了年月日\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String time; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 每个Item对应的HeaderId\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; headerId; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; GridItem(String path, String time) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.path = path; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.time = time; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getPath() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; path; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setPath(String path) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.path = path; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getTime() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; time; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setTime(String time) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.time = time; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getHeaderId() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; headerId; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setHeaderId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; headerId) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.headerId = headerId; - } - - - } 图片的路径path和图片加入的时间time 我们直接可以通过ContentProvider获取，但是headerId需要我们根据逻辑来生成。\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.ContentResolver; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.database.Cursor; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.net.Uri; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Environment; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.provider.MediaStore; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 图片扫描器\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ImageScanner { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context mContext; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ImageScanner(Context context){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mContext = context; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 利用ContentProvider扫描手机中的图片，将扫描的Cursor回调到ScanCompleteCallBack\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 接口的scanComplete方法中，此方法在运行在子线程中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scanImages(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; ScanCompleteCallBack callback) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Handler mHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.handleMessage(msg); - callback.scanComplete((Cursor)msg.obj); - } - }; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Thread(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//先发送广播扫描下整个sd卡\u0026lt;/span\u0026gt; - mContext.sendBroadcast(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent( - Intent.ACTION_MEDIA_MOUNTED, - Uri.parse(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;file://\u0026amp;#8221;\u0026lt;/span\u0026gt; + Environment.getExternalStorageDirectory()))); - - Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; - ContentResolver mContentResolver = mContext.getContentResolver(); - - Cursor mCursor = mContentResolver.query(mImageUri, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, MediaStore.Images.Media.DATE_ADDED); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//利用Handler通知调用线程\u0026lt;/span\u0026gt; - Message msg = mHandler.obtainMessage(); - msg.obj = mCursor; - mHandler.sendMessage(msg); - } - }).start(); - - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 扫描完成之后的回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; ScanCompleteCallBack{ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scanComplete(Cursor cursor); - } - - - } ImageScanner是一个图片的扫描器类，该类使用ContentProvider扫描手机中的图片，我们通过调用scanImages()方法就能对手机中的图片进行扫描，将扫描的Cursor回调到ScanCompleteCallBack 接口的scanComplete方法中，由于考虑到扫描图片属于耗时操作，所以该操作运行在子线程中，在我们扫描图片之前我们需要先发送广播来扫描外部媒体库，为什么要这么做呢，假如我们新增加一张图片到sd卡，图片确实已经添加了进去，但是我们此时的媒体库还没有同步更新，若不同步媒体库我们就看不到新增加的图片，当然我们可以通过重新启动系统来更新媒体库，但是这样不可取，所以我们直接发送广播就可以同步媒体库了。\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.concurrent.ExecutorService; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.concurrent.Executors; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.BitmapFactory; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Point; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Message; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v4.util.LruCache; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 本地图片加载器,采用的是异步解析本地图片，单例模式利用getInstance()获取NativeImageLoader实例\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 调用loadNativeImage()方法加载本地图片，此类可作为一个加载本地图片的工具类\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; NativeImageLoader { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = NativeImageLoader.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getSimpleName(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; NativeImageLoader mInstance = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; NativeImageLoader(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; LruCache\u0026lt;String, Bitmap\u0026gt; mMemoryCache; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ExecutorService mImageThreadPool = Executors.newFixedThreadPool(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; NativeImageLoader(){ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取应用程序的最大内存\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; maxMemory = (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (Runtime.getRuntime().maxMemory()); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//用最大内存的1/8来存储图片\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; cacheSize = maxMemory / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;8\u0026lt;/span\u0026gt;; - mMemoryCache = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LruCache\u0026lt;String, Bitmap\u0026gt;(cacheSize) { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取每张图片的bytes\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; sizeOf(String key, Bitmap bitmap) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; bitmap.getRowBytes() * bitmap.getHeight(); - } - - }; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 通过此方法来获取NativeImageLoader的实例\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; NativeImageLoader getInstance(){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mInstance; - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 加载本地图片，对图片不进行裁剪\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param path\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param mCallBack\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Bitmap loadNativeImage(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String path, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; NativeImageCallBack mCallBack){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.loadNativeImage(path, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, mCallBack); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 此方法来加载本地图片，这里的mPoint是用来封装ImageView的宽和高，我们会根据ImageView控件的大小来裁剪Bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 如果你不想裁剪图片，调用loadNativeImage(final String path, final NativeImageCallBack mCallBack)来加载\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param path\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param mPoint\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param mCallBack\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Bitmap loadNativeImage(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String path, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Point mPoint, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; NativeImageCallBack mCallBack){ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//先获取内存中的Bitmap\u0026lt;/span\u0026gt; - Bitmap bitmap = getBitmapFromMemCache(path); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Handler mHander = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler(){ - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(Message msg) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.handleMessage(msg); - mCallBack.onImageLoader((Bitmap)msg.obj, path); - } - - }; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//若该Bitmap不在内存缓存中，则启用线程去加载本地的图片，并将Bitmap加入到mMemoryCache中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(bitmap == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - mImageThreadPool.execute(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//先获取图片的缩略图\u0026lt;/span\u0026gt; - Bitmap mBitmap = decodeThumbBitmapForFile(path, mPoint == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; ? \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;: mPoint.x, mPoint == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; ? \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;: mPoint.y); - Message msg = mHander.obtainMessage(); - msg.obj = mBitmap; - mHander.sendMessage(msg); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将图片加入到内存缓存\u0026lt;/span\u0026gt; - addBitmapToMemoryCache(path, mBitmap); - } - }); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; bitmap; - - } - - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 往内存缓存中添加Bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param key\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; addBitmapToMemoryCache(String key, Bitmap bitmap) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (getBitmapFromMemCache(key) == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; bitmap != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mMemoryCache.put(key, bitmap); - } - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 根据key来获取内存中的图片\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param key\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap getBitmapFromMemCache(String key) { - Bitmap bitmap = mMemoryCache.get(key); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(bitmap != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;get image for LRUCache , path = \u0026amp;#8220;\u0026lt;/span\u0026gt; + key); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; bitmap; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 清除LruCache中的bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; trimMemCache(){ - mMemoryCache.evictAll(); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 根据View(主要是ImageView)的宽和高来获取图片的缩略图\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param path\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param viewWidth\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param viewHeight\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap decodeThumbBitmapForFile(String path, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewWidth, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewHeight){ - BitmapFactory.Options options = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BitmapFactory.Options(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置为true,表示解析Bitmap对象，该对象不占内存\u0026lt;/span\u0026gt; - options.inJustDecodeBounds = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - BitmapFactory.decodeFile(path, options); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置缩放比例\u0026lt;/span\u0026gt; - options.inSampleSize = computeScale(options, viewWidth, viewHeight); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置为false,解析Bitmap对象加入到内存中\u0026lt;/span\u0026gt; - options.inJustDecodeBounds = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - - - Log.e(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;get Iamge form file, path = \u0026amp;#8220;\u0026lt;/span\u0026gt; + path); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; BitmapFactory.decodeFile(path, options); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 根据View(主要是ImageView)的宽和高来计算Bitmap缩放比例。默认不缩放\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param options\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param width\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param height\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; computeScale(BitmapFactory.Options options, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewWidth, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewHeight){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; inSampleSize = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(viewWidth == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; || viewWidth == \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; inSampleSize; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bitmapWidth = options.outWidth; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bitmapHeight = options.outHeight; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//假如Bitmap的宽度或高度大于我们设定图片的View的宽高，则计算缩放比例\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(bitmapWidth \u0026gt; viewWidth || bitmapHeight \u0026gt; viewWidth){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthScale = Math.round((\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) bitmapWidth / (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) viewWidth); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; heightScale = Math.round((\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) bitmapHeight / (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) viewWidth); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//为了保证图片不缩放变形，我们取宽高比例最小的那个\u0026lt;/span\u0026gt; - inSampleSize = widthScale \u0026lt; heightScale ? widthScale : heightScale; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; inSampleSize; - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 加载本地图片的回调接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; NativeImageCallBack{ - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 当子线程加载完了本地的图片，将Bitmap和图片路径回调在此方法中\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param bitmap\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param path\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onImageLoader(Bitmap bitmap, String path); - } - } NativeImageLoader该类是一个单例类，提供了本地图片加载，内存缓存，裁剪等逻辑，该类在加载本地图片的时候采用的是异步加载的方式，对于大图片的加载也是比较耗时的，所以采用子线程的方式去加载，对于图片的缓存机制使用的是LruCache，我们使用手机分配给应用程序内存的1/8用来缓存图片，给图片缓存的内存不宜太大，太大也可能会发生OOM，该类是用我之前写的文章Android 使用ContentProvider扫描手机中的图片，仿微信显示本地图片效果，在这里我就不做过多的介绍，有兴趣的可以去看看那篇文章，不过这里新增了一个方法trimMemCache(),，用来清空LruCache使用的内存\n我们看主界面的布局代码，里面只有一个自定义的StickyGridHeadersGridView控件\n**[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;com.tonicartos.widget.stickygridheaders.StickyGridHeadersGridView\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/asset_grid\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:clipToPadding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:columnWidth\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;90dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:horizontalSpacing\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;3dip\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:numColumns\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;auto_fit\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:verticalSpacing\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;3dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; 在看主界面的代码之前我们先看StickyGridAdapter的代码\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Point; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.BaseAdapter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.stickyheadergridview.MyImageView.OnMeasureListener; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.stickyheadergridview.NativeImageLoader.NativeImageCallBack; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.tonicartos.widget.stickygridheaders.StickyGridHeadersSimpleAdapter; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * StickyHeaderGridView的适配器，除了要继承BaseAdapter之外还需要\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 实现StickyGridHeadersSimpleAdapter接口\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; StickyGridAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; BaseAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; - StickyGridHeadersSimpleAdapter { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;GridItem\u0026gt; hasHeaderIdList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LayoutInflater mInflater; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GridView mGridView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Point mPoint = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Point(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//用来封装ImageView的宽和高的对象 \u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; StickyGridAdapter(Context context, List\u0026lt;GridItem\u0026gt; hasHeaderIdList, - GridView mGridView) { - mInflater = LayoutInflater.from(context); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mGridView = mGridView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.hasHeaderIdList = hasHeaderIdList; - } - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; hasHeaderIdList.size(); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object getItem(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; hasHeaderIdList.get(position); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getItemId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; position; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) { - ViewHolder mViewHolder; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (convertView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mViewHolder = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewHolder(); - convertView = mInflater.inflate(R.layout.grid_item, parent, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); - mViewHolder.mImageView = (MyImageView) convertView - .findViewById(R.id.grid_item); - convertView.setTag(mViewHolder); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//用来监听ImageView的宽和高 \u0026lt;/span\u0026gt; - mViewHolder.mImageView.setOnMeasureListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnMeasureListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onMeasureSize(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height) { - mPoint.set(width, height); - } - }); - - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - mViewHolder = (ViewHolder) convertView.getTag(); - } - - String path = hasHeaderIdList.get(position).getPath(); - mViewHolder.mImageView.setTag(path); - - Bitmap bitmap = NativeImageLoader.getInstance().loadNativeImage(path, mPoint, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; NativeImageCallBack() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onImageLoader(Bitmap bitmap, String path) { - ImageView mImageView = (ImageView) mGridView - .findViewWithTag(path); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (bitmap != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mImageView != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mImageView.setImageBitmap(bitmap); - } - } - }); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (bitmap != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mViewHolder.mImageView.setImageBitmap(bitmap); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - mViewHolder.mImageView.setImageResource(R.drawable.friends_sends_pictures_no); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; convertView; - } - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getHeaderView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) { - HeaderViewHolder mHeaderHolder; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (convertView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - mHeaderHolder = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HeaderViewHolder(); - convertView = mInflater.inflate(R.layout.header, parent, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); - mHeaderHolder.mTextView = (TextView) convertView - .findViewById(R.id.header); - convertView.setTag(mHeaderHolder); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - mHeaderHolder = (HeaderViewHolder) convertView.getTag(); - } - mHeaderHolder.mTextView.setText(hasHeaderIdList.get(position).getTime()); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; convertView; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 获取HeaderId, 只要HeaderId不相等就添加一个Header\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getHeaderId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; hasHeaderIdList.get(position).getHeaderId(); - } - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ViewHolder { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyImageView mImageView; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; HeaderViewHolder { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; TextView mTextView; - } - - - - } 除了要继承BaseAdapter之外还需要实现StickyGridHeadersSimpleAdapter接口，继承BaseAdapter需要实现getCount()，getItem(int position)， getItemId(int position)，getView(int position, View convertView, ViewGroup parent)这四个方法，这几个方法的实现跟我们平常实现的方式一样，主要是看一下getView()方法，我们将每个item的图片路径设置Tag到该ImageView上面，然后利用NativeImageLoader来加载本地图片，在这里使用的ImageView依然是自定义的MyImageView，该自定义ImageView主要实现当MyImageView测量完毕之后，就会将测量的宽和高回调到onMeasureSize()中，然后我们可以根据MyImageView的大小来裁剪图片\n另外我们需要实现StickyGridHeadersSimpleAdapter接口的getHeaderId(int position)和getHeaderView(int position, View convertView, ViewGroup parent)，getHeaderId(int position)方法返回每个Item的headerId，getHeaderView()方法是生成sections和headers的，如果某个item的headerId跟他下一个item的HeaderId不同，则会调用getHeaderView方法生成一个sections用来区分不同的组，还会根据firstVisibleItem的headerId来生成一个位于顶部的headers，所以如何生成每个Item的headerId才是关键，生成headerId的方法在MainActivity中\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.text.SimpleDateFormat; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Collections; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Date; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.HashMap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ListIterator; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Map; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.TimeZone; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.ProgressDialog; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.database.Cursor; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.provider.MediaStore; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.GridView; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.stickyheadergridview.ImageScanner.ScanCompleteCallBack; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ProgressDialog mProgressDialog; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 图片扫描器\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageScanner mScanner; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GridView mGridView; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 没有HeaderId的List\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;GridItem\u0026gt; nonHeaderIdList = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;GridItem\u0026gt;(); - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - mGridView = (GridView) findViewById(R.id.asset_grid); - mScanner = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ImageScanner(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); - - mScanner.scanImages(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ScanCompleteCallBack() { - { - mProgressDialog = ProgressDialog.show(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;正在加载\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scanComplete(Cursor cursor) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 关闭进度条\u0026lt;/span\u0026gt; - mProgressDialog.dismiss(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(cursor == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt; (cursor.moveToNext()) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// 获取图片的路径\u0026lt;/span\u0026gt; - String path = cursor.getString(cursor - .getColumnIndex(MediaStore.Images.Media.DATA)); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取图片的添加到系统的毫秒数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; times = cursor.getLong(cursor - .getColumnIndex(MediaStore.Images.Media.DATE_ADDED)); - - GridItem mGridItem = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GridItem(path, paserTimeToYMD(times, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;yyyy年MM月dd日\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - nonHeaderIdList.add(mGridItem); - - } - cursor.close(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//给GridView的item的数据生成HeaderId\u0026lt;/span\u0026gt; - List\u0026lt;GridItem\u0026gt; hasHeaderIdList = generateHeaderId(nonHeaderIdList); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//排序\u0026lt;/span\u0026gt; - Collections.sort(hasHeaderIdList, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; YMDComparator()); - mGridView.setAdapter(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StickyGridAdapter(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, hasHeaderIdList, mGridView)); - - } - }); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 对GridView的Item生成HeaderId, 根据图片的添加时间的年、月、日来生成HeaderId\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 年、月、日相等HeaderId就相同\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param nonHeaderIdList\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;GridItem\u0026gt; generateHeaderId(List\u0026lt;GridItem\u0026gt; nonHeaderIdList) { - Map\u0026lt;String, Integer\u0026gt; mHeaderIdMap = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;String, Integer\u0026gt;(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mHeaderId = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - List\u0026lt;GridItem\u0026gt; hasHeaderIdList; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(ListIterator\u0026lt;GridItem\u0026gt; it = nonHeaderIdList.listIterator(); it.hasNext();){ - GridItem mGridItem = it.next(); - String ymd = mGridItem.getTime(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!mHeaderIdMap.containsKey(ymd)){ - mGridItem.setHeaderId(mHeaderId); - mHeaderIdMap.put(ymd, mHeaderId); - mHeaderId ++; - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - mGridItem.setHeaderId(mHeaderIdMap.get(ymd)); - } - } - hasHeaderIdList = nonHeaderIdList; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; hasHeaderIdList; - } - - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDestroy() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDestroy(); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//退出页面清除LRUCache中的Bitmap占用的内存\u0026lt;/span\u0026gt; - NativeImageLoader.getInstance().trimMemCache(); - } - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 将毫秒数装换成pattern这个格式，我这里是转换成年月日\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param time\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param pattern\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String paserTimeToYMD(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; time, String pattern ) { - System.setProperty(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;user.timezone\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Asia/Shanghai\u0026amp;#8221;\u0026lt;/span\u0026gt;); - TimeZone tz = TimeZone.getTimeZone(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Asia/Shanghai\u0026amp;#8221;\u0026lt;/span\u0026gt;); - TimeZone.setDefault(tz); - SimpleDateFormat format = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SimpleDateFormat(pattern); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; format.format(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Date(time * 1000L)); - } - - } 主界面的代码主要是组装StickyGridHeadersGridView的数据，我们将扫描出来的图片的路径，时间的毫秒数解析成年月日的格式封装到GridItem中，然后将GridItem加入到List中，此时每个Item还没有生成headerId，我们需要调用generateHeaderId()，该方法主要是将同一天加入的系统的图片生成相同的HeaderId,这样子同一天加入的图片就在一个组中，当然你要改成同一个月的图片在一起，修改paserTimeToYMD（）方法的第二个参数就行了，当Activity finish之后，我们利用NativeImageLoader.getInstance().trimMemCache()释放内存，当然我们还需要对GridView的数据进行排序，比如说headerId相同的item不连续，headerId相同的item就会生成多个sections(即多个分组)，所以我们要利用YMDComparator使得在同一天加入的图片在一起，YMDComparator的代码如下\n**[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Comparator; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; YMDComparator \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Comparator\u0026lt;GridItem\u0026gt; { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; compare(GridItem o1, GridItem o2) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; o1.getTime().compareTo(o2.getTime()); - } - - } 当然这篇文章不使用YMDComparator也是可以的，因为我在利用ContentProvider获取图片的时候，就是根据加入系统的时间排序的，排序只是针对一般的数据来说的。\n接下来我们运行下程序看看效果如何\n今天的文章就到这里结束了，感谢大家的观看，上面还有一个类和一些资源文件没有贴出来，大家有兴趣研究下就直接下载项目源码，记住采用LruCache缓存图片的时候，cacheSize不要设置得过大，不然产生OOM的概率就更大些，我利用上面的程序测试显示600多张图片来回滑动，没有产生OOM,有问题不明白的同学可以在下面留言！\n项目源码，点击下载\n转自：http://blog.csdn.net/xiaanming/article/details/20481185\n使用到的github library地址：https://github.com/emilsjolander/StickyListHeaders\n","permalink":"https://blog.zdltech.com/posts/android-%E4%BD%BF%E7%94%A8%E5%BC%80%E6%BA%90%E5%BA%93stickygridheaders%E6%9D%A5%E5%AE%9E%E7%8E%B0%E5%B8%A6sections%E5%92%8Cheaders%E7%9A%84gridview%E6%98%BE%E7%A4%BA%E6%9C%AC%E5%9C%B0%E5%9B%BE/","summary":"\u003cp\u003e转载请注明本文出自xiaanming的博客（\u003ca href=\"http://blog.csdn.net/xiaanming/article/details/20481185\"\u003ehttp://blog.csdn.net/xiaanming/article/details/20481185\u003c/a\u003e），请尊重他人的辛勤劳动成果，谢谢！\u003c/p\u003e\n\u003cp\u003e大家好！过完年回来到现在差不多一个月没写文章了，一是觉得不知道写哪些方面的文章，没有好的题材来写，二是因为自己的一些私事给耽误了，所以过完年的第一篇文章到现在才发表出来，2014年我还是会继续在CSDN上面更新我的博客，欢迎大家关注一下，今天这篇文章主要的是介绍下开源库StickyGridHeaders的使用，StickyGridHeaders是一个自定义GridView带sections和headers的Android库，sections就是GridView item之间的分隔，headers就是固定在GridView顶部的标题，类似一些Android手机联系人的效果，StickyGridHeaders的介绍在\u003ca href=\"https://github.com/TonicArtos/StickyGridHeaders\"\u003ehttps://github.com/TonicArtos/StickyGridHeaders\u003c/a\u003e，与此对应也有一个相同效果的自定义ListView带sections和headers的开源库\u003ca href=\"https://github.com/emilsjolander/StickyListHeaders\"\u003ehttps://github.com/emilsjolander/StickyListHeaders\u003c/a\u003e，大家有兴趣的可以去看下，我这里介绍的是StickyGridHeaders的使用，我在Android应用方面看到使用StickyGridHeaders的不是很多，而是在Iphone上看到相册采用的是这种效果，于是我就使用StickyGridHeaders来仿照Iphone按照日期分隔显示本地图片\u003c/p\u003e\n\u003cp\u003e我们先新建一个Android项目StickyHeaderGridView，去\u003ca href=\"https://github.com/TonicArtos/StickyGridHeaders\"\u003ehttps://github.com/TonicArtos/StickyGridHeaders\u003c/a\u003e下载开源库，为了方便浏览源码我直接将源码拷到我的工程中了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140305103135687?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhYW5taW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003ecom.tonicartos.widget.stickygridheaders这个包就是我放StickyGridHeaders开源库的源码，com.example.stickyheadergridview这个包是我实现此功能的代码，类看起来还蛮多的，下面我就一一来介绍了\u003c/p\u003e\n\u003cp\u003eGridItem用来封装StickyGridHeadersGridView 每个Item的数据，里面有本地图片的路径，图片加入手机系统的时间和headerId\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.stickyheadergridview;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @blog http://blog.csdn.net/xiaanming\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; GridItem {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 图片的路径\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String path;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 图片加入手机中的时间，只取了年月日\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String time;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     * 每个Item对应的HeaderId\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; headerId;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; GridItem(String path, String time) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.path = path;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.time = time;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getPath() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; path;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setPath(String path) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.path = path;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getTime() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; time;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setTime(String time) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.time = time;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getHeaderId() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; headerId;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setHeaderId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; headerId) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.headerId = headerId;\n\n- }\n\n- \n- \n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e图片的路径path和图片加入的时间time 我们直接可以通过ContentProvider获取，但是headerId需要我们根据逻辑来生成。\u003c/p\u003e","title":"Android 使用开源库StickyGridHeaders来实现带sections和headers的GridView显示本地图片效果"},{"content":"我们知道，Android是靠Binder机制来实现进程间的通信，而上一篇文章中，我们利用AIDL，简单地从代码方面的角度讲解了在服务端中的Binder的存在形式，是以服务的实现存在的，而在客户端，则是以代理的形式，实现存在的只是一个关于服务端的Binder实现的引用。\n理论上的东西我们要去学习掌握，但是也不能忽略了实际的动手能力，对吧。\n今天，我们就一步一步地利用我们所了解地关于AIDL的知识来实现一个跨进程通信的例子。\n在Android的上层应用中，每一个App都是一个单独的进程，所以，要实现跨进程通信，我们需要至少有2个进程，一个代表服务端，一个代表客户端，所以我们会创建2个项目，来分别代表服务端和客户端。\n服务端是提供服务的，得先提供服务，才能让客户端来享受服务，对吧。\n服务端\n我们创建一个服务端的项目，然后创建我们的aidl文件，毕竟只是一个Demo，所以我先从简单入手，方法不要太多，就叫IDemoService.aidl, 如下：\n**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/42835229#)[copy](http://blog.csdn.net/linmiansheng/article/details/42835229#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/582805)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/582805/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.lms.service; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; IDemoService { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; invoke(); - } 我们将其放在com.lms.service的包名目录下，表明其是提供服务的，当我们编译一下项目之后，就会发现在gen目录下面同样的包名下，生成了一个IDemoService.java的文件，如下：\n而其生成的IDemoService.java文件内容如下，跟上一篇文章中所展现的其实一样，就是一个Stub类和一个Proxy类，如下：\n**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/42835229#)[copy](http://blog.csdn.net/linmiansheng/article/details/42835229#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/582805)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/582805/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * This file is auto-generated. DO NOT MODIFY.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Original file: F:\\\\workspace_android\\\\AidlDemoClient\\\\src\\\\com\\\\lms\\\\service\\\\IDemoService.aidl\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.lms.service; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; IDemoService \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; android.os.IInterface { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** Local-side IPC implementation stub class. */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; Stub \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; android.os.Binder \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; - com.lms.service.IDemoService { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; java.lang.String DESCRIPTOR = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.lms.service.IDemoService\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** Construct the stub at attach it to the interface. */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Stub() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.attachInterface(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, DESCRIPTOR); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Cast an IBinder object into an com.lms.service.IDemoService\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * interface, generating a proxy if needed.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; com.lms.service.IDemoService asInterface( - android.os.IBinder obj) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((obj == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (((iin != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) \u0026amp;\u0026amp; (iin \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;instanceof\u0026lt;/span\u0026gt; com.lms.service.IDemoService))) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; ((com.lms.service.IDemoService) iin); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; com.lms.service.IDemoService.Stub.Proxy(obj); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; android.os.IBinder asBinder() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTransact(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; code, android.os.Parcel data, - android.os.Parcel reply, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; flags) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; android.os.RemoteException { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (code) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; INTERFACE_TRANSACTION: { - reply.writeString(DESCRIPTOR); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; TRANSACTION_invoke: { - data.enforceInterface(DESCRIPTOR); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.invoke(); - reply.writeNoException(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTransact(code, data, reply, flags); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; Proxy \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; com.lms.service.IDemoService { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; android.os.IBinder mRemote; - - Proxy(android.os.IBinder remote) { - mRemote = remote; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; android.os.IBinder asBinder() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mRemote; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; java.lang.String getInterfaceDescriptor() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; DESCRIPTOR; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; invoke() \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; android.os.RemoteException { - android.os.Parcel _data = android.os.Parcel.obtain(); - android.os.Parcel _reply = android.os.Parcel.obtain(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_invoke, _data, _reply, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - _reply.readException(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;finally\u0026lt;/span\u0026gt; { - _reply.recycle(); - _data.recycle(); - } - } - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; TRANSACTION_invoke = (android.os.IBinder.FIRST_CALL_TRANSACTION + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; invoke() \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; android.os.RemoteException; - } 既然已经通过aidl生成了这份接口文件，那么根据上一篇文章所讲的，我们接下来就要来实现服务端这边提供的服务了。\n我们可以想到，当我们在使用Android中的服务接口的时候，当其需要与其他模块进行相互通信的时候，我们一般是会通过绑定的形式实现的，而通过此种形式的实现，我们都会实现一个Binder，比如我们之前音乐播放器的实现，如下：\n**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/42835229#)[copy](http://blog.csdn.net/linmiansheng/article/details/42835229#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/582805)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/582805/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; NatureBinder \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Binder{ - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 唱吧，有人想听\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; startPlay(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; currentMusic, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; currentPosition){} - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 别唱了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; stopPlay(){} - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 后一首\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; toNext(){} - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 前一首\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; toPrevious(){} - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 有人改变模式了，我得把它记下来 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; changeMode(){} - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 告诉别人，你现在到底是顺序播放，还是随机乱弹\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * MODE_ONE_LOOP = 1;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * MODE_ALL_LOOP = 2;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * MODE_RANDOM = 3;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * MODE_SEQUENCE = 4; \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCurrentMode(){} - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 告诉调用者，到底有没有在做事。。。\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isPlaying(){} - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 要告诉调用者，当前播哪首歌了，歌多长啊\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; notifyActivity(){} - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 有人拖动Seekbar了，要告诉service去改变播放的位置\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param progress\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; changeProgress(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; progress){} - } 在上面这种情况下，Service是与同一个进程中的其他线程或者模块进行通信的，而在我们这种跨进程的服务中是不是也可以类似自己去实现我们AIDL中的定义的Stub类呢？\n因为Stub类也是继承Binder的，而Binder又是实现了IBinder接口的，所以可以在调用Service的onBinde方法的时候，就返回我们实现的服务呀，对吧。\n所以我们自定义一个服务，就叫做DemoService，如下：\n**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/42835229#)[copy](http://blog.csdn.net/linmiansheng/article/details/42835229#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/582805)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/582805/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.lms.service; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Service; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.IBinder; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; DemoService \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Service{ - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; IBinder onBind(Intent intent) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - - } Service是一个抽象类，继承它必须实现其抽象方法 onBinde，其会返回一个IBinder对象，那么很显然，我们就需要在这个方法里返回我们的Binder了。\n下面，我们先简单实现我们的Binder，如下：\n**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/42835229#)[copy](http://blog.csdn.net/linmiansheng/article/details/42835229#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/582805)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/582805/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; DemoService \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Service { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;DemoService\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; IDemoService.Stub mBinder = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; IDemoService.Stub() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; invoke() \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; RemoteException { - Log.v(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Invoke -\u0026gt; Current Process From Server: \u0026amp;#8220;\u0026lt;/span\u0026gt; + android.os.Process.myPid()); - } - }; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; IBinder onBind(Intent intent) { - Log.v(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Bind -\u0026gt; Current Process From Server: \u0026amp;#8220;\u0026lt;/span\u0026gt; + android.os.Process.myPid()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mBinder; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onUnbind(Intent intent){ - Log.v(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Unbind -\u0026gt; Current Process From Server: \u0026amp;#8220;\u0026lt;/span\u0026gt; + android.os.Process.myPid()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onUnbind(intent); - } - } 最后，在AndroidManifest.xml中注册Service，如下：\n**[html]** [view plain](http://blog.csdn.net/linmiansheng/article/details/42835229#)[copy](http://blog.csdn.net/linmiansheng/article/details/42835229#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/582805)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/582805/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;service\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;com.lms.service.DemoService\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:exported\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:process\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;:remote\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;category\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;android.intent.category.DEFAULT\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;action\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;com.lms.service.DemoService\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;service\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 在这里，我们还需要定义一个intent-filter，以便Android系统在第三方调用的时候，可以通过隐式的intent来匹配到这个服务，同时还要注意两点：\n1）android:process 必须设置值，至于什么值，好像关系并不大，表明可接受远程调用\n2）android:exported设置为true，这表明此组件可供第三方调用，不过对于Service来说，这默认就是true的，所以我们不设也可以。但是对于Activity等来说，其值是默认为false的，这时候，如果我们想让我们的Activity为第三方调用，就要显式设置为true了。通常，在接入第三方插件的时候，我们会用到这个属性。\nOK，到这里为止，我们已经简单地实现了我们的服务端服务了，接下来我们再继续实现我们客户端。\n再创建一个项目，AidlDemoClient，然后将我们在服务端的这份aidl文件，包括包名等，复制到客户端代码中，编译一下，其会生成一份一样的java文件，不过此时，我们不再需要去实现Stub类了，我们只是需要去调用这个类就可以了，如下：\n接着，我们只需要像平常一样调用我们的Service就可以了，所不同的是，由于这服务并不在我们进程内，所以我们必须用隐式的Intent去调用，由系统去匹配服务，从而调起，这也是为什么我们在服务端注册Service的时候，需要设置IntentFilter的原因了。\n**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/42835229#)[copy](http://blog.csdn.net/linmiansheng/article/details/42835229#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/582805)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/582805/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ActionBarActivity { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;DemoService\u0026amp;#8221;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String ACTION_BIND_SERVICE = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.lms.service.DemoService\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; IDemoService mDemoService; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ServiceConnection mServiceConnection = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ServiceConnection() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onServiceDisconnected(ComponentName name) { - mDemoService = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onServiceConnected(ComponentName name, IBinder service) { - mDemoService = IDemoService.Stub.asInterface(service); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { - mDemoService.invoke(); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (RemoteException e) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated catch block\u0026lt;/span\u0026gt; - e.printStackTrace(); - } - } - }; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - Button btnHelloWorld = (Button) findViewById(R.id.btnBind); - btnHelloWorld.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - Intent intentService = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(ACTION_BIND_SERVICE); - intentService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - bindService(intentService, mServiceConnection, BIND_AUTO_CREATE); - Log.v(TAG, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Current Process From Client: \u0026amp;#8220;\u0026lt;/span\u0026gt; + android.os.Process.myPid()); - } - }); - - Button btnUnbind = (Button) findViewById(R.id.btnUnbind); - btnUnbind.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mServiceConnection != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - unbindService(mServiceConnection); - mServiceConnection = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; - } - } - }); - - } 我们定义了两个按钮，当点击的时候，分别通过隐式的intent去启动服务并触发方法和解除绑定，我们可以看到在onServiceConnected中，我们利用了IDemoService.Stub.asInterface() 方法来实例化这个Binder，至于asterface是如何跨进程找到这个binder的，我们上一篇文章中已经简单地讲了一下。\n接下来，我们可以启动这两个应用，来试一下啦。\n从上面的画面中，我们可以看到，点击事件发生的线程ID是685，而真正接受服务和触发Invoke方法的是在进程676上面，于是我们就实现了跨进程通信了。\n当然在这里，我们只是做了一个很简单的调用而已，而实际上我们还能够传递参数和接受返回值，而这些我们都可以在aidl文件中定义，不过要注意的是:\n1）aidl中直接提供的数据类型只支持基本的数据类型和String\n2）如果要支持我们自己的自定义的对象，我们的对象必须也通过aidl来定义，而且实现parceable接口，如下：\n**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/42835229#)[copy](http://blog.csdn.net/linmiansheng/article/details/42835229#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/582805)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/582805/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.lms.aidl; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.lms.aidl.Bean; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; ITestService { - - List\u0026lt;Bean\u0026gt; getBean(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; addBean(in Bean bean); - } 而Bean的aidl文件如下：\n**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/42835229#)[copy](http://blog.csdn.net/linmiansheng/article/details/42835229#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/582805)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/582805/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.lms.aidl; - - parcelable Bean; 其具体实现如下：\n**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/42835229#)[copy](http://blog.csdn.net/linmiansheng/article/details/42835229#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/582805)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/582805/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_10\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_10\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.lms.aidl; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Parcel; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Parcelable; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; Bean \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Parcelable { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String str; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Bean(){ - - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return the i\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getI() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; i; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param i the i to set\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setI(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.i = i; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @return the str\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getStr() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; str; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param str the str to set\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setStr(String str) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.str = str; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Bean(Parcel in) { - readFromParcel(in); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Parcelable.Creator\u0026lt;Bean\u0026gt; CREATOR = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Parcelable.Creator\u0026lt;Bean\u0026gt;() { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Bean createFromParcel(Parcel in) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Bean(in); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Bean[] newArray(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; size) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Bean[size]; - } - - }; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; describeContents() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; writeToParcel(Parcel dest, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; flags) { - dest.writeInt(i); - dest.writeString(str); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; readFromParcel(Parcel in) { - i = in.readInt(); - str = in.readString(); - } - } 而我们可以从其通信的过程中拿到服务端的数据，如下：\n好了，关于aidl的使用，我们就简单地介绍到这里吧，我会把两份Demo的代码都放上来，大家如果有兴趣，可以自己拿去参考一下。\n简单版（只是调用方法）：AidlDemo简单版\n进阶版（进程间通信并且传递自定义对象）：AidlDemo进阶版\n转自：http://blog.csdn.net/linmiansheng/article/details/42835229\n","permalink":"https://blog.zdltech.com/posts/android%E5%AD%A6%E4%B9%A0%E5%B0%8Fdemo23aidl%E5%AE%9E%E7%8E%B0%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1/","summary":"\u003cp\u003e我们知道，Android是靠Binder机制来实现进程间的通信，而上一篇文章中，我们利用AIDL，简单地从代码方面的角度讲解了在服务端中的Binder的存在形式，是以服务的实现存在的，而在客户端，则是以代理的形式，实现存在的只是一个关于服务端的Binder实现的引用。\u003c/p\u003e\n\u003cp\u003e理论上的东西我们要去学习掌握，但是也不能忽略了实际的动手能力，对吧。\u003c/p\u003e\n\u003cp\u003e今天，我们就一步一步地利用我们所了解地关于AIDL的知识来实现一个跨进程通信的例子。\u003c/p\u003e\n\u003cp\u003e在Android的上层应用中，每一个App都是一个单独的进程，所以，要实现跨进程通信，我们需要至少有2个进程，一个代表服务端，一个代表客户端，所以我们会创建2个项目，来分别代表服务端和客户端。\u003c/p\u003e\n\u003cp\u003e服务端是提供服务的，得先提供服务，才能让客户端来享受服务，对吧。\u003c/p\u003e\n\u003cp\u003e服务端\u003c/p\u003e\n\u003cp\u003e我们创建一个服务端的项目，然后创建我们的aidl文件，毕竟只是一个Demo，所以我先从简单入手，方法不要太多，就叫IDemoService.aidl, 如下：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/42835229#)[copy](http://blog.csdn.net/linmiansheng/article/details/42835229#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/582805)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/582805/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.lms.service;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; IDemoService {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; invoke();\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e我们将其放在com.lms.service的包名目录下，表明其是提供服务的，当我们编译一下项目之后，就会发现在gen目录下面同样的包名下，生成了一个IDemoService.java的文件，如下：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20150118135650816?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlubWlhbnNoZW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e而其生成的IDemoService.java文件内容如下，跟上一篇文章中所展现的其实一样，就是一个Stub类和一个Proxy类，如下：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/42835229#)[copy](http://blog.csdn.net/linmiansheng/article/details/42835229#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/582805)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/582805/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * This file is auto-generated.  DO NOT MODIFY.\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Original file: F:\\\\workspace_android\\\\AidlDemoClient\\\\src\\\\com\\\\lms\\\\service\\\\IDemoService.aidl\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.lms.service;\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; IDemoService \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; android.os.IInterface {\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** Local-side IPC implementation stub class. */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;abstract\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; Stub \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; android.os.Binder \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt;\n\n- com.lms.service.IDemoService {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; java.lang.String DESCRIPTOR = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;com.lms.service.IDemoService\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** Construct the stub at attach it to the interface. */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Stub() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.attachInterface(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, DESCRIPTOR);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         * Cast an IBinder object into an com.lms.service.IDemoService\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         * interface, generating a proxy if needed.\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;         */\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; com.lms.service.IDemoService asInterface(\n\n- android.os.IBinder obj) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((obj == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n- }\n\n- android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (((iin != \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) \u0026amp;\u0026amp; (iin \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;instanceof\u0026lt;/span\u0026gt; com.lms.service.IDemoService))) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; ((com.lms.service.IDemoService) iin);\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; com.lms.service.IDemoService.Stub.Proxy(obj);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; android.os.IBinder asBinder() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTransact(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; code, android.os.Parcel data,\n\n- android.os.Parcel reply, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; flags)\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; android.os.RemoteException {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (code) {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; INTERFACE_TRANSACTION: {\n\n- reply.writeString(DESCRIPTOR);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; TRANSACTION_invoke: {\n\n- data.enforceInterface(DESCRIPTOR);\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.invoke();\n\n- reply.writeNoException();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;\n\n- }\n\n- }\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTransact(code, data, reply, flags);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; Proxy \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; com.lms.service.IDemoService {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; android.os.IBinder mRemote;\n\n- \n- Proxy(android.os.IBinder remote) {\n\n- mRemote = remote;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; android.os.IBinder asBinder() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mRemote;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; java.lang.String getInterfaceDescriptor() {\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; DESCRIPTOR;\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; invoke() \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; android.os.RemoteException {\n\n- android.os.Parcel _data = android.os.Parcel.obtain();\n\n- android.os.Parcel _reply = android.os.Parcel.obtain();\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\n- _data.writeInterfaceToken(DESCRIPTOR);\n\n- mRemote.transact(Stub.TRANSACTION_invoke, _data, _reply, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- _reply.readException();\n\n- } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;finally\u0026lt;/span\u0026gt; {\n\n- _reply.recycle();\n\n- _data.recycle();\n\n- }\n\n- }\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; TRANSACTION_invoke = (android.os.IBinder.FIRST_CALL_TRANSACTION + \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);\n\n- }\n\n- \n- \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; invoke() \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; android.os.RemoteException;\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e既然已经通过aidl生成了这份接口文件，那么根据上一篇文章所讲的，我们接下来就要来实现服务端这边提供的服务了。\u003c/p\u003e","title":"Android学习小Demo（23）Aidl实现进程间通信"},{"content":" 很多情况下， 我们想要ListView上面展示的东西是可以分组的，比如联系人列表，国家列表啊，这样看起来数据的展现比较有层次感，而且也有助于我们快速定位到某一个具体的条目上，具体效果请看下图：\n这是前面TodoList小demo的MainActivity，主要是来展现用户添加的任务的，在原来的基础上添加了分组的效果。\n接下来我们具体来讲一下这个效果是怎么实现的。\n这是利用开源库StickyListHeaders(传送门：https://github.com/emilsjolander/StickyListHeaders）来实现的，这个实现的效果是基于ListView的，而其实也有关于GridView而实现的分组的效果，大家可以参考一下xiaanming的博客（他的文章名字都很长。。。）：\nAndroid 使用开源库StickyGridHeaders来实现带sections和headers的GridView显示本地图片效果\n0）关于如何导进开源库，大家请参考：如何导进开源库StickyListHeaders\n1）然后，我们要想清楚一件事情，即分组的ListView，是包含两部分：Header 和 Item，所以相对应的我们也要为其定义两个Layout，如下：\n1.1）task_header.xml\n**[html]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/header_selector\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/tvHeader\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;start|left\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:padding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/white\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;17sp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textStyle\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;bold\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 因为我们在Header上面只是展现一个日期，所以我们只需要一个TextView即可。\n1.2）task_item.xml\n**[html]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;32dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:descendantFocusability\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;blocksDescendants\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:padding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dip\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:padding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_centerVertical\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/ivComplete\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_alignParentLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_alignParentTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:contentDescription\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@string/imageview_contentdesc\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/handdraw_tick\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:visibility\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;gone\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/tvTitle\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_toRightOf\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/ivComplete\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;left|center_vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:padding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;20sp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 在这里面，我们定义了每一个item要展现的布局，跟平常我们经常用的layout其实是一样的，大家接下来自定义的Adapter也就理解了。\n2）第二步，跟平常绑定ListView一样，我们也需要自定义一个Adapter，称之为StickyListTaskAdapter。\n我们来看一下 StickListTaskAdapter 完整的代码，如下：\n**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; StickListTaskAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; BaseAdapter - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; SectionIndexer, StickyListHeadersAdapter{ - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LayoutInflater layoutInflater; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;TodoTask\u0026gt; tasks; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] sectionIndices; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String[] sectionHeaders; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; StickListTaskAdapter(Context context, List\u0026lt;TodoTask\u0026gt; tasks) { - layoutInflater = LayoutInflater.from(context); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.tasks = tasks; - sectionIndices = getSectionIndices(); - sectionHeaders = getSectionHeaders(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; refresh(List\u0026lt;TodoTask\u0026gt; tasks){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.tasks = tasks; - sectionIndices = getSectionIndices(); - sectionHeaders = getSectionHeaders(); - notifyDataSetChanged(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] getSectionIndices() { - List\u0026lt;Integer\u0026gt; sectionIndices = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;Integer\u0026gt;(); - String lastCreateDate = Helper.getFormatDate(tasks.get(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;).getCreateTime()); - sectionIndices.add(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; i \u0026lt; tasks.size(); i++) { - String createDate = Helper.getFormatDate(tasks.get(i).getCreateTime()); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!createDate.equals(lastCreateDate)) { - lastCreateDate = createDate; - sectionIndices.add(i); - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] sections = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[sectionIndices.size()]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; sectionIndices.size(); i++) { - sections[i] = sectionIndices.get(i); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; sections; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String[] getSectionHeaders() { - String[] sectionHeaders = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; String[sectionIndices.length]; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; sectionIndices.length; i++) { - sectionHeaders[i] = Helper.getFormatDate(tasks.get(sectionIndices[i]).getCreateTime()); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; sectionHeaders; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount() { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; tasks.size(); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object getItem(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; tasks.get(position); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getItemId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; tasks.get(position).getId(); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) { - ViewHolder viewHolder; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (convertView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { - viewHolder = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewHolder(); - convertView = layoutInflater.inflate(R.layout.task_item, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - viewHolder.ivComplete = (ImageView)convertView.findViewById(R.id.ivComplete); - viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tvTitle); - viewHolder.tvCreateTime = (TextView) convertView.findViewById(R.id.tvCreateTime); - convertView.setTag(viewHolder); - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - viewHolder = (ViewHolder) convertView.getTag(); - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Y\u0026amp;#8221;\u0026lt;/span\u0026gt;.equals(tasks.get(position).getFlagCompleted())){ - viewHolder.ivComplete.setVisibility(View.VISIBLE); - viewHolder.tvCreateTime.setText(Helper.getFormatDate(tasks.get(position).getCompleteTime())); - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - viewHolder.ivComplete.setVisibility(View.GONE); - viewHolder.tvCreateTime.setText(Helper.getFormatDate(tasks.get(position).getCreateTime())); - } - viewHolder.tvTitle.setText(tasks.get(position).getTitle()); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; convertView; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getHeaderView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) { - HeaderViewHolder hvh; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(convertView == \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ - hvh = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HeaderViewHolder(); - convertView = layoutInflater.inflate(R.layout.task_header, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); - hvh.tvHeader = (TextView) convertView.findViewById(R.id.tvHeader); - convertView.setTag(hvh); - }\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ - hvh = (HeaderViewHolder)convertView.getTag(); - } - hvh.tvHeader.setText(Helper.getFormatDate(tasks.get(position).getCreateTime())); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; convertView; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getHeaderId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; Helper.changeStringDateToLong(Helper.getFormatDate(tasks.get(position).getCreateTime())); - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object[] getSections() { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; sectionHeaders; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getPositionForSection(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; sectionIndex) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (sectionIndex \u0026gt;= sectionIndices.length) { - sectionIndex = sectionIndices.length \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (sectionIndex \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { - sectionIndex = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; sectionIndices[sectionIndex]; - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getSectionForPosition(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; sectionIndices.length; i++) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (position \u0026lt; sectionIndices[i]) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; i \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - } - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; sectionIndices.length \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ViewHolder { - ImageView ivComplete; - TextView tvTitle; - TextView tvCreateTime; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; HeaderViewHolder{ - TextView tvHeader; - } - } 首先我们定义了下面两个数组，并且需要在构造的时候初始化它们： **[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] sectionIndices; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String[] sectionHeaders; 通过构造函数，我们可以发现，我们传到这个Adapter的数据源只有一个ArrayList，因为这才是真正的数据，我们分组也是基于这个数据源的。\n但是我们要展现Header的，那么Header的数据是从哪里来的呢？所以我们在初始化的时候，就要去获得Header的数据。\n大家可以看一下两个getSectionXXX的函数，可以看到在里面做了下面两件事情：\n1）sectionIndices数组用来存放每一轮分组的第一个item的位置。\n2）sectionHeaders数组用来存放每一个分组要展现的数据，因为能够分到同一组的item，它们肯定有一个相同且可以跟其它section区别开来的值，比如在上面，我是利用create_time来分成不同的组的，所以sectionHeaders存放的只是一个create_time。\n不过大家在这里千万要注意：基于某个字段的分组，这个数据源必须是在这个字段上是有序的！\n如果不是有序的，那么属于相同分组的数据就会被拆成几段了，而这个分组就没有意义了。\n所以如果数据源不是有序的，那么我们在初始化获取分组的时候，也需要先将其变成有序的。\n接下来，在我们平常继承BaseAdapter的情况下，我们都要去实现getView等功能，在上面也是一样的，但是我们这个Adapter还必须要实现另外两个接口：\n1）StickyListHeadersAdapter\n2）SectionIndexer\n我们先来看看StickyListHeaderAdapter的定义：\n**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; StickyListHeadersAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ListAdapter { - - View getHeaderView(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getHeaderId(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position); - } 这是开源库提供的接口，因为我们需要添加Header，所以我们必须在Adapter中也返回一个Header的View，这其实跟实现getView是一样的道理的，都挺好理解的。 所以在getHeaderView里面就会用到我们一开始新定义的那个task_header.xml了，同样的，为了实现优化，也会利用一个HeaderViewHolder。\n另外一个接口就是SectionIndexer了，它有三个方法要实现，如下：\n**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; SectionIndexer { - - Object[] getSections(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getPositionForSection(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; sectionIndex); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getSectionForPosition(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position); - } 看代码的实现，可以发现：\ngetSections：返回的其实就是Header上面要展示的数据，在这里其实就是sectionHeaders了，存放的是create_time的数据。\ngetPositionForSection：返回的是这个section数据在List这个基础数据源中的位置，因为section中的数据其实也是从List中获取到的。\ngetSectionForPosition：则是通过在基础数据源List中的位置找出对应的Section中的数据，原因同上。\n那么上面这两个函数的作用在哪？\n大家有没有发现，当同一个分组的数据在滚动的时候，最上面的分组并不会变化，只有当滑到其它分组的时候，这个分组才会被新的分组给替换掉。这个效果实现的原理就在这里了，虽然我没有看过源代码，但是我认为，在每一个item滚动的时候，都会找出其对应的分组，然后显示在最上方，如果都是属于同一个分组的话，那么最上面的显示的当然一直都是这个分组对应的Header了。\n综上所述，为了实现Sticky和分组的效果，我们就要在原来继承BaseAdapter的基础上再实现多两个接口，并实现对应的逻辑。\n那么如何在Activity中使用呢？请看下面的代码：\n在xml中定义：\n**[html]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;se.emilsjolander.stickylistheaders.StickyListHeadersListView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/lvTasks\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/todo_bg\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:clipToPadding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:divider\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#44FFFFFF\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:dividerHeight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:drawSelectorOnTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:fastScrollEnabled\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:overScrollMode\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;never\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:padding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;16dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scrollbarStyle\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;outsideOverlay\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; 在MainActivity中使用：\n**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - lvTasks = (StickyListHeadersListView) findViewById(R.id.lvTasks); - taskAdapter = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StickListTaskAdapter(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, tasks); - lvTasks.setAdapter(taskAdapter); - lvTasks.setDrawingListUnderStickyHeader(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - lvTasks.setAreHeadersSticky(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - lvTasks.setOnItemLongClickListener(onItemLongClickListener); - lvTasks.setOnItemClickListener(onItemClickListener); 而开源库中StickyListHeadersListView还提供了几个接口，可以让我们在Activity中去实现，不过这些就有待大家自己去慢慢学习了。 **[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; StickyListHeadersListView \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; FrameLayout { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnHeaderClickListener { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onHeaderClick(StickyListHeadersListView l, View header, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; itemPosition, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; headerId, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; currentlySticky); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Notifies the listener when the sticky headers top offset has changed.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnStickyHeaderOffsetChangedListener { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param l The view parent\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param header The currently sticky header being offset.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * This header is not guaranteed to have it\u0026amp;#8217;s measurements set.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * It is however guaranteed that this view has been measured,\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * therefor you should user getMeasured* methods instead of\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * get* methods for determining the view\u0026amp;#8217;s size.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param offset The amount the sticky header is offset by towards to top of the screen.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onStickyHeaderOffsetChanged(StickyListHeadersListView l, View header, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; offset); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Notifies the listener when the sticky header has been updated\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnStickyHeaderChangedListener { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param l The view parent\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param header The new sticky header view.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param itemPosition The position of the item within the adapter\u0026amp;#8217;s data set of\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * the item whose header is now sticky.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * @param headerId The id of the new sticky header.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onStickyHeaderChanged(StickyListHeadersListView l, View header, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; itemPosition, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; headerId); - - } 结束。 转自：http://blog.csdn.net/linmiansheng/article/details/20747775\n","permalink":"https://blog.zdltech.com/posts/android%E5%AD%A6%E4%B9%A0%E5%B0%8Fdemo12todolist%E5%AE%9E%E7%8E%B0listview%E7%9A%84%E5%88%86%E7%BB%84%E5%AE%9E%E7%8E%B0/","summary":"\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e很多情况下， 我们想要ListView上面展示的东西是可以分组的，比如联系人列表，国家列表啊，这样看起来数据的展现比较有层次感，而且也有助于我们快速定位到某一个具体的条目上，具体效果请看下图：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140315223318140\"\u003e\u003c/p\u003e\n\u003cp\u003e这是前面TodoList小demo的MainActivity，主要是来展现用户添加的任务的，在原来的基础上添加了分组的效果。\u003c/p\u003e\n\u003cp\u003e接下来我们具体来讲一下这个效果是怎么实现的。\u003c/p\u003e\n\u003cp\u003e这是利用开源库StickyListHeaders(传送门：\u003ca href=\"https://github.com/emilsjolander/StickyListHeaders\"\u003ehttps://github.com/emilsjolander/StickyListHeaders\u003c/a\u003e）来实现的，这个实现的效果是基于ListView的，而其实也有关于GridView而实现的分组的效果，大家可以参考一下xiaanming的博客（他的文章名字都很长。。。）：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/xiaanming/article/details/20481185\"\u003eAndroid 使用开源库StickyGridHeaders来实现带sections和headers的GridView显示本地图片效果\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e0）关于如何导进开源库，大家请参考：\u003ca href=\"http://blog.csdn.net/linmiansheng/article/details/20789569\"\u003e如何导进开源库StickyListHeaders\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e1）然后，我们要想清楚一件事情，即分组的ListView，是包含两部分：Header 和 Item，所以相对应的我们也要为其定义两个Layout，如下：\u003c/p\u003e\n\u003cp\u003e1.1）task_header.xml\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/header_selector\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/tvHeader\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;start|left\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:padding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/white\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textSize\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;17sp\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:textStyle\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;bold\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;\n\n- \n- \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cspan style=\"text-decoration: underline;\"\u003e因为我们在Header上面只是展现一个日期，所以我们只需要一个TextView即可。\u003c/span\u003e\u003c/p\u003e","title":"Android学习小Demo（12）TodoList实现ListView的分组实现"},{"content":"AndroidNDK开发环境介绍\n一.系统和软件需求\n1.AndroidSDK\n一个完整的Android SDK安装(包括所有附件)是必需的\nAndroid 1.5 以上SDK\n2.支持的操作系统\nWindows XP (32-bit) or Vista (32- or 64-bit)\nMac OS X 10.4.8 or later (x86 only)\nLinux (32 or 64-bit; Ubuntu 8.04, or other Linux distributions using GLibc 2.7 or later)\n3.需要的开发工具\n所有开发平台都需要GNU Make3.81以上版本\n需要最新版本的AWK（ GNU Awk 或者Nawk）\n对于Windows，需要Cygwin 1.7以上的版本（注意：Cygwin1.5是不行的）\n4.Android平台兼容性\n创建的本地库Android NDK只能运行特定的最低设备使用Android平台版本，平台所需的最低版本取决于您的目标设备的CPU架构。\n下面的表细节的Android平台版本兼容本地代码开发特定的CPU架构。\nCPU架构 兼容的平台\nARM, ARM-NEON Android 1.5 以上\nx86 Android 2.3 以上\nMIPS Android 2.3 以上\n为了保证平台兼容性需要设置的android:minSdkVersion 例如\nNDK使用OpenGL ES APIs，为了确保平台的兼容性，需要设置的android:minSdkVersion\n下面给出对应关系\nOpenGL ES 版本 兼容平台 需要的最小SDK\nOpenGL ES 1.1 Android 1.6 以上 android:minSdkVersion=”4″\nOpenGL ES 2.0 Android 2.0 以上 android:minSdkVersion=”5″\n另外一个应用使用OpenGL ES，在manifest文件中应该声明的 android:glEsVersion（OpenGL的最小版本）\n例如\nNDK中使用API访问Bitmap相关操作，需要设置Android的最小SDK为8.\n英文原文\nIf you use this NDK to create a native library that uses the API to access Android Bitmap pixel buffers or utilizes native activities, the application containing the library can be deployed only to devices running Android 2.2 (API level 8) or higher. To ensure compatibility, make sure that your application declares attribute value in its manifest.\n二.安装NDK\n1.下载最新的Android SDK或则更新到最新的Android SDK\n2.下载NDK和安装（下面简单不翻译了）\nLinux and Mac OS X (Darwin):\nDownload the appropriate package from this page.\nOpen a terminal window.\nGo to the directory to which you downloaded the package.\nRun chmod a+x on the downloaded package.\nExecute the package. For example:\nndkchmod a+x android-ndk-r10c-darwin-x86_64.bin ndk ./android-ndk-r10c-darwin-x86_64.bin\nThe folder containing the NDK extracts itself.\nNote that you can also use a program like 7z to extract the package.\nOn Windows:\nDownload the appropriate package from this page.\nNavigate to the folder to which you downloaded the package.\nDouble-click the downloaded file. The folder containing the NDK extracts itself.\nWhen uncompressed, the NDK files are contained in a directory called android-ndk-. You can rename the NDK directory if necessary and you can move it to any location on your computer. This documentation refers to the NDK directory as .\nYou are now ready to start working with the NDK.\n注意:在windows上下载的android-ndk-r10d-windows-x86_64.exe这种，点击运行后，发现没有android-ndk-r10d文件夹的话，请放android-ndk-r10d-windows-x86_64.exe在非中文文件目录中或则直接放到硬盘根目录（例如D:）。\n","permalink":"https://blog.zdltech.com/posts/androidndk%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E4%BB%8B%E7%BB%8D/","summary":"\u003cp\u003eAndroidNDK开发环境介绍\u003c/p\u003e\n\u003cp\u003e一.系统和软件需求\u003cbr\u003e\n1.AndroidSDK\u003cbr\u003e\n一个完整的Android SDK安装(包括所有附件)是必需的\u003cbr\u003e\nAndroid 1.5 以上SDK\u003cbr\u003e\n2.支持的操作系统\u003cbr\u003e\nWindows XP (32-bit) or Vista (32- or 64-bit)\u003cbr\u003e\nMac OS X 10.4.8 or later (x86 only)\u003cbr\u003e\nLinux (32 or 64-bit; Ubuntu 8.04, or other Linux distributions using GLibc 2.7 or later)\u003cbr\u003e\n3.需要的开发工具\u003cbr\u003e\n所有开发平台都需要GNU Make3.81以上版本\u003cbr\u003e\n需要最新版本的AWK（ GNU Awk 或者Nawk）\u003cbr\u003e\n对于Windows，需要Cygwin 1.7以上的版本（注意：Cygwin1.5是不行的）\u003cbr\u003e\n4.Android平台兼容性\u003cbr\u003e\n创建的本地库Android NDK只能运行特定的最低设备使用Android平台版本，平台所需的最低版本取决于您的目标设备的CPU架构。\u003cbr\u003e\n下面的表细节的Android平台版本兼容本地代码开发特定的CPU架构。\u003cbr\u003e\nCPU架构 兼容的平台\u003cbr\u003e\nARM, ARM-NEON Android 1.5 以上\u003cbr\u003e\nx86 Android 2.3 以上\u003cbr\u003e\nMIPS Android 2.3 以上\u003cbr\u003e\n为了保证平台兼容性需要设置\u003cuses-sdk\u003e的android:minSdkVersion 例如\u003cuses-sdk android:minSdkVersion=\u0026#8221;3\u0026#8243; /\u003e\u003cbr\u003e\nNDK使用OpenGL ES APIs，为了确保平台的兼容性，需要设置\u003cuses-sdk\u003e的android:minSdkVersion\u003cbr\u003e\n下面给出对应关系\u003cbr\u003e\nOpenGL ES 版本 兼容平台 需要的最小SDK\u003cbr\u003e\nOpenGL ES 1.1 Android 1.6 以上 android:minSdkVersion=”4″\u003cbr\u003e\nOpenGL ES 2.0 Android 2.0 以上 android:minSdkVersion=”5″\u003cbr\u003e\n另外一个应用使用OpenGL ES，在manifest文件中应该声明\u003cuses-feature\u003e的 android:glEsVersion（OpenGL的最小版本）\u003cbr\u003e\n例如\u003cuses-feature android:glEsVersion=\u0026#8221;0x00020000\u0026#8243; /\u003e\u003cbr\u003e\nNDK中使用API访问Bitmap相关操作，需要设置Android的最小SDK为8.\u003cbr\u003e\n英文原文\u003cbr\u003e\nIf you use this NDK to create a native library that uses the API to access Android Bitmap pixel buffers or utilizes native activities, the application containing the library can be deployed only to devices running Android 2.2 (API level 8) or higher. To ensure compatibility, make sure that your application declares \u003cuses-sdk android:minSdkVersion=\u0026#8221;8\u0026#8243; /\u003e attribute value in its manifest.\u003c/p\u003e","title":"AndroidNDK开发环境介绍"},{"content":"NDK项目源码地址 :\n— 第一个JNI示例程序下载 : GitHub – https://github.com/han1202012/NDKHelloworld.git\n— Java传递参数给C语言实例程序 : GitHub – https://github.com/han1202012/NDKParameterPassing.git\n—C语言回调Java方法示例程序 : GitHub – https://github.com/han1202012/NDK_Callback.git\n—分析Log框架层JNI源码所需的Android底层文件 : CSDN – http://download.csdn.net/detail/han1202012/6905507\n开发环境介绍 :\n— eclipse : adt-bundle-windows-x86-20130917\n— sdk : 版本 2.3.3\n— ndk : android-ndk-r9c-windows-x86.zip\n— cygwin : 所需组件 binutils , gcc , gcc-mingw , gdb , make;\n— javah : jdk6.0自带工具\n— javap : jdk6.0自带工具\n**JNI 总结 : **\nJava 调用 C 流程 :\n— a. 定义 Native 方法 : 在 shuliang.han.ndkparameterpassing.DataProvider.java 类中定义 Native 方法 public native int add(int x, int y);\n— b. 生成方法签名 : 进入 AndroidProject/bin/classes 目录, 使用 **javah **shuliang.han.ndkparameterpassing.DataProvider 命令, 便生成了头文件, 该头文件引用了 jni.h, 以及定义好了 对应的 Native 方法, 生成 JNIEXPORT jint JNICALL Java_shuliang_han_ndkparameterpassing_DataProvider_add (JNIEnv *, jobject, jint, jint);\n— c. 编写 Android.mk 文件 :\n**[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - LOCAL_PATH := $(call my-dir) - - include $(CLEAR_VARS) - - LOCAL_MODULE := hello-jni - LOCAL_SRC_FILES := hello-jni.c - - include $(BUILD_SHARED_LIBRARY) — d. 生成 动态库 so 文件 : 进入 Android.mk 所在目录, 在该目录执行 ndk 下的 ndk-build 命令;\n— e. Java代码加载动态库 : 在 Java 代码中调用该类的类前面, 在类的一开始, 不在方法中, 加入 static{ System.loadLibrary(“hello”); } ;\n一. JNI介绍 1. JNI引入 JNI概念 : Java本地接口,Java Native Interface, 它是一个协议, 该协议用来沟通Java代码和外部的本地C/C++代码, 通过该协议 Java代码可以调用外部的本地代码, 外部的C/C++ 代码可以调用Java代码;\nC和Java的侧重 :\n— C语言 : C语言中最重要的是 函数 function;\n— Java语言 : Java中最重要的是 JVM, class类, 以及class中的方法;\nC与Java如何交流 :\n— JNI规范 : C语言与Java语言交流需要一个适配器, 中间件, 即 JNI, JNI提供了一种规范;\n— C语言中调用Java方法 : 可以让我们在C代码中找到Java代码class中的方法, 并且调用该方法;\n— Java语言中调用C语言方法 : 同时也可以在Java代码中, 将一个C语言的方法映射到Java的某个方法上;\n— JNI桥梁作用 : JNI提供了一个桥梁, 打通了C语言和Java语言之间的障碍;\nJNI中的一些概念 :\n— native : Java语言中修饰本地方法的修饰符, 被该修饰符修饰的方法没有方法体;\n— Native方法 : 在Java语言中被native关键字修饰的方法是Native方法;\n— JNI层 : Java声明Native方法的部分;\n— JNI函数 : JNIEnv提供的函数, 这些函数在jni.h中进行定义;\n— JNI方法 : Native方法对应的JNI层实现的 C/C++方法, 即在jni目录中实现的那些C语言代码;\n2. Android中的应用程序框架 正常情况下的Android框架 : 最顶层是Android的应用程序代码, 上层的应用层 和 应用框架层 主要是Java代码, 中间有一层的Framework框架层代码是 C/C++代码, 通过Framework进行系统调用, 调用底层的库 和linux 内核;\n使用JNI时的Android框架 : 绕过Framework提供的调用底层的代码, 直接调用自己写的C代码, 该代码最终会编译成为一个库, 这个库通过JNI提供的一个Stable的ABI 调用linux kernel;ABI是二进制程序接口 application binary interface.\n纽带 : JNI是连接框架层 (Framework – C/C++) 和**应用框架层(Application Framework – Java)**的纽带;\nJNI在Android中作用 : JNI可以调用本地代码库(即C/C++代码), 并通过 Dalvik虚拟机 与应用层 和 应用框架层进行交互, Android中JNI代码主要位于应用层 和 应用框架层;\n— 应用层 : 该层是由JNI开发, 主要使用标准JNI编程模型;\n— 应用框架层 : 使用的是Android中自定义的一套JNI编程模型, 该自定义的JNI编程模型弥补了标准JNI编程模型的不足;\nAndroid中JNI源码位置 : 在应用框架层中, 主要的JNI代码位于 framework/base目录下, 这些模块被编译成共享库之后放在 /system/lib 目录下;\nNDK与JNI区别 :\n— NDK: NDK是Google开发的一套开发和编译工具集, 主要用于Android的JNI开发;\n— JNI : JNI是一套编程接口, 用来实现Java代码与本地的C/C++代码进行交互;\nJNI编程步骤:\n— 声明native方法 : 在Java代码中声明 native method()方法;\n— 实现JNI的C/C++方法 : 在JNI层实现Java中声明的native方法, 这里使用javah工具生成带方法签名的头文件, 该JNI层的C/C++代码将被编译成动态库;\n— 加载动态库 : 在Java代码中的静态代码块中加载JNI编译后的动态共享库;\n.\n3. JNI作用 JNI作用 :\n— 扩展: JNI扩展了JVM能力, 驱动开发, 例如开发一个wifi驱动, 可以将手机设置为无限路由;\n— 高效 : 本地代码效率高, 游戏渲染, 音频视频处理等方面使用JNI调用本地代码, C语言可以灵活操作内存;\n— 复用 : 在文件压缩算法 7zip开源代码库, 机器视觉 openCV开放算法库 等方面可以复用C平台上的代码, 不必在开发一套完整的Java体系, 避免重复发明轮子;\n— 特殊 : 产品的核心技术一般也采用JNI开发, 不易破解;\nJava语言执行流程 :\n— 编译字节码 : Java编译器编译 .java源文件, 获得.class 字节码文件;\n— 装载类库 : 使用类装载器装载平台上的Java类库, 并进行字节码验证;\n— Java虚拟机 : 将字节码加入到JVM中, Java解释器 和 即时编译器 同时处理字节码文件, 将处理后的结果放入运行时系统;\n— 调用JVM所在平台类库 : JVM处理字节码后, 转换成相应平台的操作, 调用本平台底层类库进行相关处理;\nJava一次编译到处执行 : JVM在不同的操作系统都有实现, Java可以一次编译到处运行, 字节码文件一旦编译好了, 可以放在任何平台的虚拟机上运行;\n.\n二. NDK详解 1. 交叉编译库文件 C代码执行 : C代码被编译成库文件之后, 才能执行, 库文件分为动态库 和静态库 两种;\n— 动态库 : unix环境下**.so 后缀的是动态库, windows环境下.dll 后缀**的是动态库; 动态库可以依赖静态库加载一些可执行的C代码;\n— 静态库 :.a 后缀是静态库的扩展名;\n库文件来源 : C代码 进行 编译 链接操作之后, 才会生成库文件, 不同类型的CPU 操作系统 生成的库文件是不一样;\n— CPU分类 : arm结构, 嵌入式设备处理器; x86结构, pc 服务器处理器; 不同的CPU指令集不同;\n— 交叉编译 :windows x86编译出来的库文件可以在arm平台运行的代码;\n— 交叉编译工具链 : Google提供的 NDK 就是交叉编译工具链, 可以在linux环境下编译出在arn平台下执行的二进制库文件;\nNDK作用 : 是Google提供了交叉编译工具链, 能够在linux平台编译出在arm平台下执行的二进制库文件;\nNDK版本介绍 : android-ndk-windows 是在windows系统中的cygwin使用的, android-ndk-linux 是在linux下使用的;\n2. 部署NDK开发环境 (1) 下载Cygwin安装器 下载地址 : http://cygwin.com/setup-x86.exe , 这是下载器, 可以使用该下载器在线安装, 也可以将cygwin下载到本地之后, 在进行安装;\n安装器使用 : Cygwin的下载, 在线安装, 卸载 等操作都有由该安装器进行;\n— 本地文件安装 : 选择安装文件所在的目录, 然后选择所要安装的安装包;\n— 在线安装 : 选择在线安装即可, 然后选择需要的安装包;\n— 卸载 : windows上使用其它软件例如360, 控制面板中是无法卸载Cygwin的, 只能通过安装器来卸载;\n(2) 安装Cygin 双击安装器 setup-x86.exe 下一步 :\n选择安装方式 :\n— 在线安装 : 直接下载, 然后安装;\n— 下载安装文件 : 将安装文件下载下来, 可以随时安装, 注意安装文件也需要安装器来进行安装;\n— 从本地文件安装 : 即使用下载的安装文件进行安装;\n选择Cygwin安装位置 :\n选择下载好安装文件位置 : 之前我下了一个完全版的Cygwin, 包括了所有的Cygwin组件, 全部加起来有5.23G, 下载速度很快, 使用网易的镜像, 基本可以全速下载;\n选择需要安装Cygwin组件 : 这里我们只需要以下组件 : binutils , gcc , gcc-mingw , gdb , make , 不用下全部的组件;\n之后点击下一步等待完成安装即可;\n.\n安装完之后, 打开bash命令窗口, 可以设置下显示的字体, 使用 make -version 查看是否安装成功 :\n(3) Cygwin目录介绍 以下是Cygwin安装目录的情况 : 该安装目录就是所模拟的linux 的根目录;\n对应的linux目录 : 这两个目录进行对比发现, 两个目录是一样的, Cygwin的安装目录就是 linux根目录;\ncygdrive目录 : 该目录是Cygwin模拟出来的windows目录结构, 进入该目录后, 会发现windows的盘符目录, 通过该目录可以访问windows中的文件;\n(4) 下载NDK工具 从Google的Android开发者官网上下载该工具, 注意NDK工具分类 : 下载地址 –http://developer.android.com/tools/sdk/ndk/index.html -;\n— windows版本NDK:android-ndk-r9c-windows-x86.zip (32位),android-ndk-r9c-windows-x86_64.zip (64位) 该版本是用在windows上的Cygwin下, 不能直接在windows上直接运行;\n— linux版本NDK :android-ndk-r9c-linux-x86.tar.bz2(32位) , android-ndk-r9c-linux-x86_64.tar.bz2 (64位) , 该版本直接在linux下执行即可;\n在这里下载windows版本的NDK, 运行在Cygwin上;\n(4) NDK环境介绍 NDK工具的文件结构 :\nndk-build脚本 : NDK build 脚本是 gun-make 的简单封装, gun-make 是编译C语言代码的工具, 该脚本执行的前提是linux环境下必须安装 make 程序;\n**NDK安装在Cygwin中** : 将NDK压缩文件拷贝到Cygwin的根目录中, 解压 : android-ndk-r9c 目录就是NDK目录; **执行以下NDK目录下的 ndk-build 命令** : ./ndk-build ; **执行结果** : **[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026amp;#8221;font-family: \u0026amp;#8216;Courier New\u0026amp;#8217;;\u0026amp;#8221;\u0026gt;Android NDK: Could not find application project directory ! - Android NDK: Please define the NDK_PROJECT_PATH variable to point to it. - /android-ndk-r9c/build/core/build-local.mk:148: *** Android NDK: Aborting 。 停止。\u0026lt;/span\u0026gt; ![](http://img.blog.csdn.net/20140130194048078)\u0026lt;/div\u0026gt; \u0026amp;nbsp; # \u0026lt;a name=\u0026quot;t12\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;三. 开发第一个NDK程序 ## \u0026lt;a name=\u0026quot;t13\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;1. 开发NDK程序流程 #### \u0026lt;a name=\u0026quot;t14\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;a. **创建Android工程**: 首选创建一个Android工程, 在这个工程中进行JNI开发; #### \u0026lt;a name=\u0026quot;t15\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;b. **声明native方法** : 注意方法名使用 native 修饰, 没有方法体 和 参数, eg : public native String helloFromJNI(); #### \u0026lt;a name=\u0026quot;t16\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;c. **创建C文件** : 在 工程根目录下创建 jni 目录, 然后创建一个c语言源文件, 在文件中引入 include \u0026lt;jni.h\u0026gt; , C语言方法声明格式 jstring Java_shuliang.han.ndkhelloworld_MainActivity_helloFromJNI(JNIEnv *env) , jstring 是 Java语言中的String类型, 方法名格式为 : Java_完整包名类名_方法名(); \u0026amp;#8212; **JNIEnv参数** : 代表的是Java环境, 通过这个环境可以调用Java里面的方法; \u0026amp;#8212; **jobject参数** : 调用C语言方法的对象, thiz对象表示当前的对象, 即调用JNI方法所在的类; #### \u0026lt;a name=\u0026quot;t17\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;d. **编写Android.mk文件** : 如何写 查看文档, NDK根目录下有一个 documentation.html 文档, 点击该html文件就可以查看文档, 查看 Android.mk File 文档, 下面是该文档给出的 Android.mk示例 : \u0026lt;div class=\u0026quot;dp-highlighter bg_plain\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - LOCAL_PATH := $(call my-dir) - - include $(CLEAR_VARS) - - LOCAL_MODULE := hello-jni - LOCAL_SRC_FILES := hello-jni.c - - include $(BUILD_SHARED_LIBRARY) \u0026lt;/div\u0026gt; \u0026amp;#8212; **LOCAL_PATH** : 代表mk文件所在的目录; \u0026amp;#8212; **include $(CLEAR_VARS)** : 编译工具函数, 通过该函数可以进行一些初始化操作; \u0026amp;#8212; **LOCAL_MODULE** : 编译后的 .so 后缀文件叫什么名字; \u0026amp;#8212; **LOCAL_SRC_FILES**: 指定编译的源文件名称; \u0026amp;#8212; **include $(BUILD_SHARED_LIBRARY)** : 告诉编译器需要生成动态库; #### \u0026lt;a name=\u0026quot;t18\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;e. **NDK编译生成动态库** : 进入 cygdrive 找到windows目录下对应的文件, 编译完成之后, 会**自动生成so文件并放在libs目录下**, 之后就可以在Java中调用C语言方法了; #### \u0026lt;a name=\u0026quot;t19\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;f. **Java中加载动态库** : 在Java类中的静态代码块中使用System.LoadLibrary()方法加载编译好的 .so 动态库; **NDK平台版本** : NDK脚本随着 android-sdk 版本不同, 执行的脚本也是不同的, 不同平台会引用不同的头文件, 编译的时候一定注意 sdk 与 ndk 版本要一致; **so文件在内存中位置** : apk文件安装到手机上之后, .so动态库文件存在在 data/安装目录/libs 目录下; ## \u0026lt;a name=\u0026quot;t20\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;2. 开发实例 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **按照上面的步骤进行开发** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t21\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(1) 创建Android工程 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Android工程版本** : 创建一个Android工程,**minSdk 为 7 即 android-2.1**, 编译使用的**sdk为 10 即 android-2.3.3** ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;uses-sdk\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:minSdkVersion\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;7\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:targetSdkVersion\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **NDK编译原则** : 编译NDK动态库是**按照最小版本进行编译**, 选择编译的平台的时候, 会选择 NDK 7 平台进行编译; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130221252312) ![](http://img.blog.csdn.net/20140130221301250) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t22\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(2) 声明native方法 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **声明native方法, 注意该方法没有方法体 和 参数, 如下** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 声明一个native方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 这个方法在Java中是没有实现的, 没有方法体\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 该方法需要使用C语言编写\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; String helloFromJNI(); \u0026lt;/div\u0026gt; . **作者** : **万境绝尘 ** **转载请注明出处** : [**http://blog.csdn.net/shulianghan/article/details/18964835**](http://blog.csdn.net/shulianghan/article/details/18964835) . \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t23\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(3) 创建C文件 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **引入头文件**: 首先要包含头文件 jni.h, 该**头文件位置**定义在 android-ndk-r9c\\platforms\\android-5\\arch-arm\\usr\\include目录下的 jni.h, 下面是该头文件中定义的一些方法, 包括本项目中使用的 NewString 方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jstring (*NewString)(JNIEnv*, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; jchar*, jsize); - jsize (*GetStringLength)(JNIEnv*, jstring); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; (*ReleaseStringChars)(JNIEnv*, jstring, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; jchar*); - jstring (*NewStringUTF)(JNIEnv*, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;*); - jsize (*GetStringUTFLength)(JNIEnv*, jstring); \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **调用Java类型** : C中调用Java中的String类型为 jstring; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **C语言方法名规则** : Java_完整包名类名_方法名(JNIEnv *env, jobject thiz), 注意完整的类名包名中包名的点要用 _ 代替; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **参数介绍** : C语言方法中有两个重要的参数, JNIEnv *env, jobject thiz ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNIEnv参数** : 该参数代表Java环境, 通过这个环境可以调用Java中的方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **jobject参数** : 该参数代表调用jni方法的类, 在这里就是MainActivity; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **调用jni.h中的NewStringUTF方法** : 该方法的作用是在C语言中创建一个Java语言中的String类型对象, jni.h中是这样定义的 jstring (*NewStringUTF)(JNIEnv*, const char*), JNIEnv 结构体中包含了 NewStringUTF 函数指针, 通过 JNIEnv 就可以调用这个方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **C语言文件源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;jni.h\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 方法名称规定 : Java_完整包名类名_方法名()\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * JNIEnv 指针\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 参数介绍 :\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * env : 代表Java环境, 通过这个环境可以调用Java中的方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * thiz : 代表调用JNI方法的对象, 即MainActivity对象\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - jstring Java_shuliang_han_ndkhelloworld_MainActivity_helloFromJNI(JNIEnv *env, jobject thiz) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 调用 android-ndk-r9c\\platforms\\android-8\\arch-arm\\usr\\include 中jni.h中的方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * jni.h 中定义的方法 jstring (*NewStringUTF)(JNIEnv*, const char*); \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (*env)-\u0026gt;NewStringUTF(env, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;hello world jni\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t24\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(4) 编写Android.mk文件 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **查询NDK文档** : NDK的文档在NDK工具根目录下, 点击 documentation.html 文件, 就可以在浏览器中打开NDK文档; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **上面的开发流程中详细的介绍了Android.mk 五个参数的详细用处, 这里直接给出源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_plain\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - LOCAL_PATH := $(call my-dir) - - include $(CLEAR_VARS) - - LOCAL_MODULE := hello - LOCAL_SRC_FILES := hello.c - - include $(BUILD_SHARED_LIBRARY) \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t25\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(5) 编译NDK动态库 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **进入Cygwin相应目录** : 从Cygwin中的cygdrive 中进入windows的工程jni目录 ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130223434359) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **编译hello.c文件** : 注意Android.mk文件 与 hello.c 文件在同一目录中; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130224601328) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **编译完成后的情况** : 编译完之后 会成成一个obj文件, 在obj文件中会生成 libhello.so, 系统会**自动将该 so后缀文件放在libs目录下**; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130224720812) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t26\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(6) Java中加载动态库 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **静态代码块中加载** : Java中在静态代码块中加载库文件, 调用 System.loadLibrary(\u0026amp;#8220;hello\u0026amp;#8221;) 方法,**注意 libs中的库文件名称为 libhello.so**,**我们加载的时候 将 lib 去掉**, 只取hello 作为动态库名称, 这是规定的; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//静态代码块加载C语言库文件\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt;{ - System.loadLibrary(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;hello\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t27\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(7) 其它源码 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **MainActivity源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_10\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_10\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; shuliang.han.ndkhelloworld; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//静态代码块加载C语言库文件\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt;{ - System.loadLibrary(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;hello\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 声明一个native方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 这个方法在Java中是没有实现的, 没有方法体\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 该方法需要使用C语言编写\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; String helloFromJNI(); - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - System.out.println(helloFromJNI()); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View view) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//点击按钮显示从jni调用得到的字符串信息\u0026lt;/span\u0026gt; - Toast.makeText(getApplicationContext(), helloFromJNI(), \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;).show(); - } - - } \u0026lt;/div\u0026gt; **XML布局文件** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_11\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_11\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_vertical_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_horizontal_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_horizontal_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_vertical_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/bt\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;显示JNI返回的字符串\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t28\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(8) 将源码上传到GitHub中 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 在上一篇博客 [http://blog.csdn.net/shulianghan/article/details/18812279](http://blog.csdn.net/shulianghan/article/details/18812279) 中对GitHub用法进行了详解; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **在GitHub上创建工程** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **项目地址** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **HTTP**: https://github.com/han1202012/NDKHelloworld.git \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **SSH** : git@github.com:han1202012/NDKHelloworld.git \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **生成的命令** : \u0026lt;div class=\u0026quot;dp-highlighter bg_plain\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_12\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_12\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - touch README.md - git init - git add README.md - git commit -m \u0026amp;#8220;first commit\u0026amp;#8221; - git remote add origin git@github.com:han1202012/NDKHelloworld.git - git push -u origin master \u0026lt;/div\u0026gt; **打开 Git Bash 命令行窗口** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **从GitHub上克隆项目到本地** : git clone git@github.com:han1202012/NDKHelloworld.git , 注意克隆的时候直接在仓库根目录即可, 不用再创建项目根目录 ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130232116609) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **添加文件** : git add ./* , 将目录中所有文件添加; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130232554281) — 查看状态 : git status ; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130232317546) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **提交缓存** : git commit -m \u0026amp;#8216;提交\u0026amp;#8217;; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130232423812) — 提交到远程GitHub仓库 : git push -u origin master ; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130232509203) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **GitHub项目** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130232709500) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t29\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;3. 项目讲解 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t30\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(1) Android.mk文件讲解 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Android.mk文件内容** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_plain\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_13\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_13\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - LOCAL_PATH := $(call my-dir) - - include $(CLEAR_VARS) - - LOCAL_MODULE := hello - LOCAL_SRC_FILES := hello.c - - include $(BUILD_SHARED_LIBRARY) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **获取当前文件内容** : $(call my-dir) 是编译器中的宏方法, 调用该宏方法, 就会**返回前的目录路径**; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **赋值符号** : \u0026amp;#8221; := \u0026amp;#8221; 是**赋值符号**, 第一句话 是 返回当前文件所在的当前目录, 并将这个目录路径赋值给 LOCAL_PATH; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **初始化编译模块参数** : $(CLEAR_VARS) 作用是将编译模块的参数初始化, LOCAL_MODULE LOCAL_SRC_FILES 也是这样的参数; \u0026lt;/div\u0026gt; **指定编译模块** : LOCAL_MODULE := hello , 指定编译后的 so 文件名称, 编译好之后系统会在该名称前面加上 \u0026amp;#8220;lib\u0026amp;#8221;, 后缀加上 \u0026amp;#8220;.so\u0026amp;#8221;;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **指定编译源文件** : LOCAL_SRC_FILES := hello.c 告诉编译系统源文件, 如果有多个文件那么就依次写在后面即可; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **编译成静态库** : include $(BUILD_SHARED_LIBRARY), 作用是高速系统, 编译的结果编译成 .so 后缀的静态库; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **静态库引入** : NDK的platform中有很多 \u0026amp;#8220;.a\u0026amp;#8221; 结尾的动态库, 我们编译动态库的时候, 可以将一些静态库引入进来; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t31\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(2) 自动生成方法签名 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **使用javah工具** : 在C中实现Java调用的jni方法, 方法的签名很复杂, 需要将完整的包名类名方法名都要使用 \u0026amp;#8220;_\u0026amp;#8221; 连接起来, 很麻烦, jdk提供的生成签名方法的工具; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **遗留问题** : 目前查到的方法是 在bin目录下 执行 javah -jni 包名类名 命令, 但是执行不成功, 暂时没找到解决方案; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212;** Android中会自动生成** .class文件吗, 没发现啊, PY人! \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140131220806843) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **解决问题** : 在jni目录下存在classes目录, 但是这个目录在eclipse中不显示, 这里我们要注意; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207202154937) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **在Cygwin中使用 javah 命令即可** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207185534812) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **生成的头文件** : shuliang_han_ndkparameterpassing_DataProvider.h; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_14\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_14\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* DO NOT EDIT THIS FILE \u0026amp;#8211; it is machine generated */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;jni.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* Header for class shuliang_han_ndkparameterpassing_DataProvider */\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifndef _Included_shuliang_han_ndkparameterpassing_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define _Included_shuliang_han_ndkparameterpassing_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifdef __cplusplus\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extern\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;C\u0026amp;#8221;\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Class: shuliang_han_ndkparameterpassing_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Method: add\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Signature: (II)I\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - JNIEXPORT jint JNICALL Java_shuliang_han_ndkparameterpassing_DataProvider_add - (JNIEnv *, jobject, jint, jint); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Class: shuliang_han_ndkparameterpassing_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Method: sayHelloInc\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Signature: (Ljava/lang/String;)Ljava/lang/String;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - JNIEXPORT jstring JNICALL Java_shuliang_han_ndkparameterpassing_DataProvider_sayHelloInc - (JNIEnv *, jobject, jstring); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Class: shuliang_han_ndkparameterpassing_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Method: intMethod\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Signature: ([I)[I\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - JNIEXPORT jintArray JNICALL Java_shuliang_han_ndkparameterpassing_DataProvider_intMethod - (JNIEnv *, jobject, jintArray); - - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifdef __cplusplus\u0026lt;/span\u0026gt; - } - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t32\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(3) NDK开发中乱码问题 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **解决乱码思路** : C语言编译的时候用的是 ISO-8859-1 码表进行编码, 如果我们使用C语言jni开发, 需要进行转码操作; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; 将ISO-8859-1转为UTF-8字符: String string = new String(str.getBytes(\u0026amp;#8220;iso8859-1\u0026amp;#8221;), \u0026amp;#8220;UTF-8\u0026amp;#8221;); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 示例 : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **添加中文jni调用** : 将jni中的hello.c 中返回的字符串修改为中文, 重新编译 .so 静态库文件; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **修改后的hello.c文件如下** : 只改变了返回的字符串, 添加了中文; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_15\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_15\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;jni.h\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 方法名称规定 : Java_完整包名类名_方法名()\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * JNIEnv 指针\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 参数介绍 :\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * env : 代表Java环境, 通过这个环境可以调用Java中的方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * thiz : 代表调用JNI方法的对象, 即MainActivity对象\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - jstring Java_shuliang_han_ndkhelloworld_MainActivity_helloFromJNI(JNIEnv *env, jobject thiz) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 调用 android-ndk-r9c\\platforms\\android-8\\arch-arm\\usr\\include 中jni.h中的方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * jni.h 中定义的方法 jstring (*NewStringUTF)(JNIEnv*, const char*);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (*env)-\u0026gt;NewStringUTF(env, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;hello world jni 中文\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } \u0026lt;/div\u0026gt; **使用NDK重新编译hello.c文件** : 修改了C源码之后, 重新将该c文件编译成so文件;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **编译过程**: 打开cygwin, 进入cygdrive/ 下对应windows中源码项目中的jni目录, 执行 /android-ndk-r9c/ndk-build 命令; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140131223258359) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **运行Android代码报错** : 因为jni中c文件有中文, 中文不能被识别; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_16\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_16\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.803\u0026lt;/span\u0026gt;: W/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): JNI WARNING: illegal continuation \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;byte\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xd0\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.803\u0026lt;/span\u0026gt;: W/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): string: \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;hello world jni ????\u0026amp;#8217;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.803\u0026lt;/span\u0026gt;: W/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): in Lshuliang/han/ndkhelloworld/MainActivity;.helloFromJNI ()Ljava/lang/String; (NewStringUTF) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.834\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;main\u0026amp;#8221;\u0026lt;/span\u0026gt; prio=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt; tid=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; NATIVE - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.834\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): | group=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;main\u0026amp;#8221;\u0026lt;/span\u0026gt; sCount=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; dsCount=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; obj=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0x4001f1a8\u0026lt;/span\u0026gt; self=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;0xce48\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.834\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): | sysTid=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt; nice=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; sched=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;/\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; cgrp=\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt; handle=-\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1345006528\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.844\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): | schedstat=( \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;257006717\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;305462830\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;51\u0026lt;/span\u0026gt; ) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.844\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at shuliang.han.ndkhelloworld.MainActivity.helloFromJNI(Native Method) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.844\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at shuliang.han.ndkhelloworld.MainActivity.onCreate(MainActivity.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;26\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.844\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1047\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.853\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1611\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.853\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1663\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.853\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at android.app.ActivityThread.access$\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1500\u0026lt;/span\u0026gt;(ActivityThread.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;117\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.864\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;931\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.864\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at android.os.Handler.dispatchMessage(Handler.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;99\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.864\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at android.os.Looper.loop(Looper.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;123\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.864\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at android.app.ActivityThread.main(ActivityThread.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3683\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.864\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at java.lang.reflect.Method.invokeNative(Native Method) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.874\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at java.lang.reflect.Method.invoke(Method.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;507\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.874\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;839\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.874\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;597\u0026lt;/span\u0026gt;) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.874\u0026lt;/span\u0026gt;: I/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): at dalvik.system.NativeStart.main(Native Method) - \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;01\u0026lt;/span\u0026gt;\u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;14\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;36\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;04.884\u0026lt;/span\u0026gt;: E/dalvikvm(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;389\u0026lt;/span\u0026gt;): VM aborting \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t33\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;4. JNIEnv 详解 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNIEnv作用** : JNIEnv 是一个指针,**指向了一组JNI函数**, 这些函数可以在jni.h中查询到,**通过这些函数可以实现 Java层 与 JNI层的交互** , 通过JNIEnv 调用JNI函数 可以访问java虚拟机, 操作java对象; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNI线程相关性** : JNIEnv只在当前的线程有效,**JNIEnv不能跨线程传递**, 相同的Java线程调用本地方法, 所使用的JNIEnv是相同的, 一个Native方法不能被不同的Java线程调用; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNIEnv结构体系** : JNIEnv指针**指向一个线程相关的结构**,**线程相关结构指向一个指针数组**,**指针数组中的每个元素最终指向一个JNI函数**. \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t34\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(1) JNIEnv的C/C++声明 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **jni.h中声明JNIEnv** : C语言中定义的JNIEnv 是 JNINativeInterface* , C++中定义的JNIEnv 是 _JNIEnv; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_17\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_17\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;struct\u0026lt;/span\u0026gt; _JNIEnv; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;struct\u0026lt;/span\u0026gt; _JavaVM; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;typedef\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;struct\u0026lt;/span\u0026gt; JNINativeInterface* C_JNIEnv; - - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#if defined(__cplusplus) //为了兼容C 和 C++两种代码 使用该 宏加以区分\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;typedef\u0026lt;/span\u0026gt; _JNIEnv JNIEnv; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//C++ 中的JNIEnv类型\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;typedef\u0026lt;/span\u0026gt; _JavaVM JavaVM; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#else\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;typedef\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;struct\u0026lt;/span\u0026gt; JNINativeInterface* JNIEnv;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//C语言中的JNIEnv类型\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;typedef\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;struct\u0026lt;/span\u0026gt; JNIInvokeInterface* JavaVM; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t35\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(2) C语言中的JNIEnv \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **关于JNIEnv指针调用解析** : C中**JNIEnv就是 const struct JNINativeInterface***, JNIEnv * env**等价于 JNINativeInterface** env**, 因此要得到JNINativeInterface结构体中定义的函数指针, 就必须先获取到 JNINativeInterface的一级指针对象 即 *env , 该**一级指针对象就是 JNINativeInterface* env**, 然后通过该**一级指针对象调用JNI函数 : (*env)-\u0026gt;NewStringUTF(env, \u0026amp;#8220;hello\u0026amp;#8221;)**; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **在JNINativeInterface结构体中定义了一系列的关于Java操作的相关方法** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_18\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_18\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Table of interface function pointers.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;struct\u0026lt;/span\u0026gt; JNINativeInterface { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;* reserved0; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;* reserved1; - - \u0026amp;#8230; \u0026amp;#8230; - - jboolean (*CallStaticBooleanMethodV)(JNIEnv*, jclass, jmethodID, - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jboolean (*CallStaticBooleanMethodA)(JNIEnv*, jclass, jmethodID, - jvalue*); - jbyte (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, \u0026amp;#8230;); - jbyte (*CallStaticByteMethodV)(JNIEnv*, jclass, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - - \u0026amp;#8230; \u0026amp;#8230; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;* (*GetDirectBufferAddress)(JNIEnv*, jobject); - jlong (*GetDirectBufferCapacity)(JNIEnv*, jobject); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* added in JNI 1.6 */\u0026lt;/span\u0026gt; - jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject); - }; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t36\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(3) C++中的JNIEnv \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **C++ 中的JNIEnv**: C++ 中的JNIEnv 就是 _JNIEnv 结构体, 二者是等同的; 因此在调用 JNI函数的时候, 只需要使用 env-\u0026gt;NewStringUTF(env, \u0026amp;#8220;hello\u0026amp;#8221;)方法即可, 不用在进行*运算; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_19\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_19\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * C++ object wrapper.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * This is usually overlaid on a C struct whose first element is a\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * JNINativeInterface*. We rely somewhat on compiler behavior.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;struct\u0026lt;/span\u0026gt; _JNIEnv { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* do not rename this; it does not seem to be entirely opaque */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;struct\u0026lt;/span\u0026gt; JNINativeInterface* functions; - - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#if defined(__cplusplus)\u0026lt;/span\u0026gt; - - jint GetVersion() - { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; functions-\u0026gt;GetVersion(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); } - - jlong GetDirectBufferCapacity(jobject buf) - { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; functions-\u0026gt;GetDirectBufferCapacity(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, buf); } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* added in JNI 1.6 */\u0026lt;/span\u0026gt; - jobjectRefType GetObjectRefType(jobject obj) - { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; functions-\u0026gt;GetObjectRefType(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, obj); } - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif /*__cplusplus*/\u0026lt;/span\u0026gt; - }; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t37\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;5. JNI方法命名规则(标准JNI规范) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNI实现的方法 与 Java中Native方法的映射关系** : 使用方法名进行映射, 可以使用 javah 工具进入 bin/classes 目录下执行命令, 即可生成头文件; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNI方法参数介绍**: \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **参数①** : 第一个参数是JNI接口指针 JNIEnv; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **参数②** : 如果Native方法是非静态的, 那么第二个参数就是对Java对象的引用, 如果Native方法是静态的, 那么第二个参数就是对Java类的Class对象的引用; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNI方法名规范** : 返回值 + Java前缀 + 全路径类名 + 方法名 + 参数① JNIEnv + 参数② jobject + 其它参数; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **注意分隔符** : Java前缀 与 类名 以及类名之间的包名 和 方法名之间 使用 \u0026amp;#8220;_\u0026amp;#8221; 进行分割; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **声明 非静态 方法**: \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **Native方法** : public int hello (String str, int i); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI方法**: jint Java_shuliang_han_Hello_hello(JNIEnv * env, jobject obj, jstring str, jint i); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **声明 静态 方法** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **Native方法** : public static int hello (String str, int i); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212;**JNI方法** : jint Java_shuliang_han_Hello_hello(JNIEnv * env, jobject clazz, jstring str, jint i); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **两种规范** : 以上是Java的标准JNI规范, 在Android中还有一套自定义的规范, 该规范是Android应用框架层 和 框架层交互使用的JNI规范, 依靠方法注册 映射 Native方法 和 JNI方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t38\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;6. JNI方法签名规则 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNI识别Java方法** : **JNI依靠函数名 和 方法签名 识别方法**, 函数名是不能唯一识别一个方法的, 因为方法可以重载, 类型签名代表了 参数 和 返回值; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **签名规则** : (**参数1类型签名参数2类型签名参数3类型签名参数N类型签名**\u0026amp;#8230;)**返回值类型签名**, 注意参数列表中没有任何间隔; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java类型 与 类型签名对照表** : 注意 boolean 与 long 不是大写首字母, 分别是 Z 与 J, 类是L全限定类名, 数组是[元素类型签名; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **类的签名规则** :**L + 全限定名 + ;**三部分, 全限定类名以 / 分割; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;table border=\u0026quot;1\u0026quot; width=\u0026quot;500\u0026quot; cellspacing=\u0026quot;1\u0026quot; cellpadding=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; Java类型 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 类型签名 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; boolean \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; Z \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; byte \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; B \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; char \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; C \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; short \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; S \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; int \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; I \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; long \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; J \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; float \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; F \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; double \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; D \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; 类 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; L全限定类名 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; 数组 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [元素类型签名 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; eg. long function(int n, String str, int[] arr); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **该方法的签名** :**(ILjava/lang/String;[I)J** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; # \u0026lt;a name=\u0026quot;t39\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;四. Java调用JNI法与日志打印 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t40\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;1. JNI数据类型 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java数据类型 C数据类型 JNI数据类型对比** : 32位 与 64位机器可能会有出入; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;table border=\u0026quot;1\u0026quot; width=\u0026quot;600\u0026quot; cellspacing=\u0026quot;1\u0026quot; cellpadding=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; **Java数据类型** \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; **C本地类型** \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; **JNI定义别名** \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; int \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; long \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jint/jsize \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; long \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; __int64 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jlong \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; byte \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; signed char \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jbyte \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; boolean \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; unsigned char \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jboolean \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; char \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; unsigned short \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jchar \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; short \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; short \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jshort \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; float \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; float \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jfloat \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; double \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; doyble \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jdouble \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; object\u0026amp;#8217; \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; _jobject \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jobject \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **数据类型表示方法** : int数组类型 jintArray , boolean数组 jbooleanArray \u0026amp;#8230; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **头文件定义类型** : 这些基本的数据类型在**jni.h 中都有相应的定义** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_20\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_20\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize); - jbyteArray (*NewByteArray)(JNIEnv*, jsize); - jcharArray (*NewCharArray)(JNIEnv*, jsize); - jshortArray (*NewShortArray)(JNIEnv*, jsize); - jintArray (*NewIntArray)(JNIEnv*, jsize); - jlongArray (*NewLongArray)(JNIEnv*, jsize); - jfloatArray (*NewFloatArray)(JNIEnv*, jsize); - jdoubleArray (*NewDoubleArray)(JNIEnv*, jsize); \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t41\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;2. JNI在Java和C语言之间传递int类型 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java中定义的方法** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_21\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_21\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将Java中的两个int值 传给C语言, 进行相加后, 返回java语言 shuliang.han.ndkparameterpassing.DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y); \u0026lt;/div\u0026gt; **C语言中定义的方法** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_22\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_22\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;jni.h\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//方法签名, Java环境 和 调用native方法的类 必不可少, 后面的参数就是native方法的参数\u0026lt;/span\u0026gt; - jint Java_shuliang_han_ndkparameterpassing_DataProvider_add(JNIEnv * env, jobject obj, jint x, jint y) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; x + y; - } \u0026lt;/div\u0026gt; **使用NDK工具变异该c类库** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 在cygwin中进入cygdrive, 然后**进入windows中相应的目录**, 执行 **/android-ndk-r9c/ndk-build** 命令, 即可完成编译; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206151254187) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t42\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;3. NDK中C代码使用LogCat \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t43\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(1) 引入头文件 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **NDK中断点调试** : 断点调试在NDK中实现极其困难, 因此在这里我们一般都是打印日志; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **引入头文件** : 在C代码中引入下面的头文件; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_23\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_23\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;android/log.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOG_TAG \u0026amp;#8220;System.out\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOGD(\u0026amp;#8230;) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOGI(\u0026amp;#8230;) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; **头文件介绍** : log.h 是关于调用 LogCat日志文件;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **log.h头文件路径** : android-ndk-r9c\\platforms\\android-9\\arch-arm\\usr\\include\\android\\log.h; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **主要方法** : __android_log_write, 下面有该方法的解析, 传入参数 日志等级 日志标签 日志内容; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **宏定义** : __android_log_write 方法太麻烦, 这里做出一个映射, LOGD(\u0026amp;#8230;) 输出debug级别的日志, LOGI(\u0026amp;#8230;) 输出Info级别的日志; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212;**LogCat日志级别** : verbose \u0026lt; debug \u0026lt; info \u0026lt; warn \u0026lt; error \u0026lt; assert; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **使用到的log.h文件内容解析** : __android_log_write 方法中的日志等级参数就使用 枚举中的内容 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_24\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_24\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Android log priority values, in ascending priority order. 日志等级\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;typedef\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;enum\u0026lt;/span\u0026gt; android_LogPriority { - ANDROID_LOG_UNKNOWN = 0, - ANDROID_LOG_DEFAULT, \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* only for SetMinPriority() */\u0026lt;/span\u0026gt; - ANDROID_LOG_VERBOSE, - ANDROID_LOG_DEBUG, - ANDROID_LOG_INFO, - ANDROID_LOG_WARN, - ANDROID_LOG_ERROR, - ANDROID_LOG_FATAL, - ANDROID_LOG_SILENT, \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* only for SetMinPriority(); must be last */\u0026lt;/span\u0026gt; - } android_LogPriority; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Send a simple string to the log. 向LogCat中输出日志 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; 参数介绍: 日志优先级 , 日志标签 , 日志内容\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; __android_log_write(\u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; prio, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; *tag, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; *text); \u0026lt;/div\u0026gt; **C语言中输入输出函数占位符介绍** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;table border=\u0026quot;1\u0026quot; width=\u0026quot;200\u0026quot; cellspacing=\u0026quot;1\u0026quot; cellpadding=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; 占位符 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 数据类型 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %d \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; int \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %ld \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; long int \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %c \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; char \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %f \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; float \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; \u0026amp;lf \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; double \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %x \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 十六进制 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %O \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 八进制 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %s \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 字符串 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t44\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(2) Android.mk增加liblog.so动态库 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **在该make配置文件中, 增加一行** : LOCAL_LDLIBS += -llog , 该语句添加在 LOCAL_SRC_FILES 语句下面一行; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **完整的Android.mk文件** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_plain\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_25\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_25\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - LOCAL_PATH := $(call my-dir) - - include $(CLEAR_VARS) - - LOCAL_MODULE := DataProvider - LOCAL_SRC_FILES := DataProvider.c - #增加log函数对应的函数库 liblog.so libthread_db.a - LOCAL_LDLIBS += -llog -lthread_db - include $(BUILD_SHARED_LIBRARY) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **函数库位置** : android-ndk-r9c\\platforms\\android-9\\arch-arm\\usr\\lib; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **函数库截图** : 从该目录下的 liglog.so可以看出, 存在该库; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206154355906) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **引入函数库方法** : 使用 LOCAL_LDLIBS += -l函数库名, 注意**函数库名不带lib前缀** 和**.so 后缀**, 同时可以添加多个库, 使用 -l库1 -l库2 -库3 ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t45\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(3) 编译执行 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **根据(1) 中的占位符, 编写打印日志代码**: \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_26\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_26\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Java中的int对应的是C语言中的long类型, 对应JNI中的jint类型, C语言中\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;JNI_日志 : x = %ld , y = %ld\u0026amp;#8221;\u0026lt;/span\u0026gt; , x , y); \u0026lt;/div\u0026gt; **最终的包含打印日志的完整代码** : 注意, 这里有一处可能错误, 如果是32位机器, int类型占位符使用 %d 即可;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_27\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_27\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;jni.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;android/log.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOG_TAG \u0026amp;#8220;System.out\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOGD(\u0026amp;#8230;) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOGI(\u0026amp;#8230;) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)\u0026lt;/span\u0026gt; - - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//方法签名, Java环境 和 调用native方法的类 必不可少, 后面的参数就是native方法的参数\u0026lt;/span\u0026gt; - jint Java_shuliang_han_ndkparameterpassing_DataProvider_add(JNIEnv * env, jobject obj, jint x, jint y) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Java中的int对应的是C语言中的long类型, 对应JNI中的jint类型, C语言中\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;JNI_日志 : x = %ld , y = %ld\u0026amp;#8221;\u0026lt;/span\u0026gt; , x , y); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; x + y; - } \u0026lt;/div\u0026gt; **重新编译C文件** : 执行 **/android-ndk-r9c/ndk-build**命令;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **第一次编译** : 出现警告, long int占位符行不通, 注意区分机器位长, 64位 与 32位不同, 这样编译出现的结果就不会打印日志; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206155158937) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **第二次编译** : 将占位符改为 %d ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206160147875) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **执行按钮之后打印的日志** : 虽然有乱码, 不过显示出来了; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206160218625) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206184130671) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t46\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;4. 字符串处理 \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java中的String转为C语言中的char字符串** : 下面的工具方法可以在C程序中解决这个问题; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_28\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_28\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// java中的jstring, 转化为c的一个字符数组\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* Jstring2CStr(JNIEnv* env, jstring jstr) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//声明了一个字符串变量 rtn\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* rtn = NULL; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//找到Java中的String的Class对象\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;jclass clsstring = (*env)-\u0026gt;FindClass(env, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;java/lang/String\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//创建一个Java中的字符串 \u0026amp;#8220;GB2312\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;jstring strencode = (*env)-\u0026gt;NewStringUTF(env, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;GB2312\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026lt;span style=\u0026amp;#8221;white-space:pre\u0026amp;#8221;\u0026gt; \u0026lt;/span\u0026gt; * 获取String中定义的方法 getBytes(), 该方法的参数是 String类型的, 返回值是 byte[]数组\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026lt;span style=\u0026amp;#8221;white-space:pre\u0026amp;#8221;\u0026gt; \u0026lt;/span\u0026gt; * \u0026amp;#8220;(Ljava/lang/String;)[B\u0026amp;#8221; 方法前面解析 :\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026lt;span style=\u0026amp;#8221;white-space:pre\u0026amp;#8221;\u0026gt; \u0026lt;/span\u0026gt; * \u0026amp;#8212; Ljava/lang/String; 表示参数是String字符串\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026lt;span style=\u0026amp;#8221;white-space:pre\u0026amp;#8221;\u0026gt; \u0026lt;/span\u0026gt; * \u0026amp;#8212; [B : 中括号表示这是一个数组, B代表byte类型, 返回值是一个byte数组\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026lt;span style=\u0026amp;#8221;white-space:pre\u0026amp;#8221;\u0026gt; \u0026lt;/span\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;jmethodID mid = (*env)-\u0026gt;GetMethodID(env, clsstring, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;getBytes\u0026amp;#8221;\u0026lt;/span\u0026gt;, - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;(Ljava/lang/String;)[B\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用Java中的getBytes方法, 传入参数介绍 参数②表示调用该方法的对象, 参数③表示方法id , 参数④表示方法参数\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;jbyteArray barr = (jbyteArray)(*env)-\u0026gt;CallObjectMethod(env, jstr, mid, - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;strencode); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// String .getByte(\u0026amp;#8220;GB2312\u0026amp;#8221;);\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取数组的长度\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;jsize alen = (*env)-\u0026gt;GetArrayLength(env, barr); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取数组中的所有的元素 , 存放在 jbyte*数组中\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;jbyte* ba = (*env)-\u0026gt;GetByteArrayElements(env, barr, JNI_FALSE); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将Java数组中所有元素拷贝到C的char*数组中, 注意C语言数组结尾要加一个 \u0026amp;#8216;\\0\u0026amp;#8217;\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (alen \u0026gt; 0) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;rtn = (\u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;*) malloc(alen + 1); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//new char[alen+1]; \u0026amp;#8220;\\0\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;memcpy(rtn, ba, alen); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;rtn[alen] = 0; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;(*env)-\u0026gt;ReleaseByteArrayElements(env, barr, ba, 0); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//释放内存\u0026lt;/span\u0026gt; - - - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; rtn; - } \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Jstring2CStr方法讲解** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; a. **获取Java中String类型的class对象** : 参数 : 上下文环境 env, String类完整路径 ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_29\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_29\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jclass clsstring = (*env)-\u0026gt;FindClass(env, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;java/lang/String\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; b.**创建Java字符串** : 使用 NewStringUTF 方法;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_30\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_30\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jstring strencode = (*env)-\u0026gt;NewStringUTF(env, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;GB2312\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; c.**获取String中的getBytes()方法** : 参数介绍 ① env 上下文环境 ② 完整的类路径 ③ 方法名 ④ 方法签名, 方法签名 Ljava/lang/String; 代表参数是String字符串, [B 中括号表示这是一个数组, B代表byte类型, 返回值是一个byte数组;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_31\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_31\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jmethodID mid = (*env)-\u0026gt;GetMethodID(env, clsstring, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;getBytes\u0026amp;#8221;\u0026lt;/span\u0026gt;, - \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;(Ljava/lang/String;)[B\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; d. **获取数组的长度** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_32\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_32\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jsize alen = (*env)-\u0026gt;GetArrayLength(env, barr); \u0026lt;/div\u0026gt; e. 获取数组元素 : 获取数组中的所有的元素 , 存放在 jbyte*数组中; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_33\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_33\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jbyte* ba = (*env)-\u0026gt;GetByteArrayElements(env, barr, JNI_FALSE); \u0026lt;/div\u0026gt; f.**数组拷贝**: 将Java数组中所有元素拷贝到C的char*数组中, 注意C语言数组结尾要加一个 \u0026amp;#8216;\\0\u0026amp;#8217;;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_34\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_34\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (alen \u0026gt; 0) { - rtn = (\u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;*) malloc(alen + 1); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//new char[alen+1]; \u0026amp;#8220;\\0\u0026amp;#8221;\u0026lt;/span\u0026gt; - memcpy(rtn, ba, alen); - rtn[alen] = 0; - } \u0026lt;/div\u0026gt; g.**释放内存** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_35\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_35\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - (*env)-\u0026gt;ReleaseByteArrayElements(env, barr, ba, 0); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//释放内存\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . **作者** : **万境绝尘 ** **转载请注明出处** : [**http://blog.csdn.net/shulianghan/article/details/18964835**](http://blog.csdn.net/shulianghan/article/details/18964835) . \u0026lt;/div\u0026gt; **C语言方法** : 注意调用Jstring2CStr方法之后要强转, 否则会出错, Jstring2CStr方法要定义在该方法的前面, C语言中的方法要先声明才能使用;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_36\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_36\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jstring Java_shuliang_han_ndkparameterpassing_DataProvider_sayHelloInc(JNIEnv *env, jobject obj, jstring str) - { - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; *p = (\u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;*)Jstring2CStr(env, str); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//打印Java传递过来的数据 \u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Java JNI string parameter is : %s\u0026amp;#8221;\u0026lt;/span\u0026gt;, p); - - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; *append = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;append\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//strcat(dest, source) 函数可以将source字符串 添加到dest字符串后面 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (*env)-\u0026gt;NewStringUTF(env, strcat(p, append)); - } \u0026lt;/div\u0026gt; \u0026amp;#8212; **如果没有强转会出现下面的错误** : char *p = Jstring2CStr(env, str); \u0026amp;#8212; **将Jstring2CStr方法定义在主方法下面会出现下面错误** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206183825406) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_37\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_37\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.sayHelloInc: - Toast.makeText(getApplicationContext(), dataProvider.sayHelloInc(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Hello\u0026amp;#8221;\u0026lt;/span\u0026gt;), Toast.LENGTH_LONG).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; **编译之后运行结果** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206184007406) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206184042125) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t47\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;5. 开发JNI程序流程 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; a. **C语言类库接口** : 存在C语言类库, 调用接口为login_server(char* address, char* username, char* password); b. Java定义本地方法 : public native void LoginServer(String address, String user, String pwd); \u0026lt;div\u0026gt; c. **C语言JNI代码** : Java_包名_类名_LoginServer(JNIEnv* env, jobject obj, jstring address, jstring user, jstring pwd){\u0026amp;#8230;调C接口}; **注意跨语言字符串转换**: JNI方法中, 要将Java的String字符串转为C中的char*字符串; **首先验证C码农提供的代码是否可用** : 验证该api是否可用, 在一个 int main() 函数中进行测试, 根据该测试代码查看方法执行相关的情况;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t48\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;6. 数组参数处理 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **模块讲解** : 在该模块中, Java语言传递一个int数组参数给C语言, C语言将这一组参数读取出来, 并且输出到Android的LogCat中, 这里涉及到了两个重要的JNI方法, 一个数**获取数组长度方法**, 一个是**获取数组中每个元素的方法**; **获取数组长度方法** : jni中定义 \u0026amp;#8211; jsize (*GetArrayLength)(JNIEnv*, jarray); 创建数组相关方法 :\n\u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_38\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_38\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize); - jbyteArray (*NewByteArray)(JNIEnv*, jsize); - jcharArray (*NewCharArray)(JNIEnv*, jsize); - jshortArray (*NewShortArray)(JNIEnv*, jsize); - jintArray (*NewIntArray)(JNIEnv*, jsize); - jlongArray (*NewLongArray)(JNIEnv*, jsize); - jfloatArray (*NewFloatArray)(JNIEnv*, jsize); - jdoubleArray (*NewDoubleArray)(JNIEnv*, jsize); \u0026lt;/div\u0026gt; **获取数组元素相关方法** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_39\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_39\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jboolean* (*GetBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*); - jbyte* (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*); - jchar* (*GetCharArrayElements)(JNIEnv*, jcharArray, jboolean*); - jshort* (*GetShortArrayElements)(JNIEnv*, jshortArray, jboolean*); - jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*); - jlong* (*GetLongArrayElements)(JNIEnv*, jlongArray, jboolean*); - jfloat* (*GetFloatArrayElements)(JNIEnv*, jfloatArray, jboolean*); - jdouble* (*GetDoubleArrayElements)(JNIEnv*, jdoubleArray, jboolean*); \u0026lt;/div\u0026gt; **C语言代码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_40\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_40\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jintArray Java_shuliang_han_ndkparameterpassing_DataProvider_intMethod(JNIEnv *env, jobject obj, jintArray arr) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取arr大小 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; len = (*env)-\u0026gt;GetArrayLength(env, arr); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//在LogCat中打印出arr的大小 \u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;the length of array is %d\u0026amp;#8221;\u0026lt;/span\u0026gt;, len); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//如果长度为0, 返回arr \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(len == 0) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; arr; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//如果长度大于0, 那么获取数组中的每个元素 \u0026lt;/span\u0026gt; - jint* p = (*env)-\u0026gt;GetIntArrayElements(env, arr, 0); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//打印出数组中每个元素的值 \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = 0; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(; i \u0026lt; len; i ++) - { - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;arr[%d] = %d\u0026amp;#8221;\u0026lt;/span\u0026gt;, i, *(p + i)); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; arr; - - } \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java代码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_41\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_41\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.intMethod: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] array = {\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;}; - dataProvider.intMethod(array); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; **执行结果** : 上面的那种LogCat竟然启动失败, 只能将就着用这个了;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207144250609) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t49\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;7. 本程序源码 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **XML布局文件** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_42\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_42\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/add\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;调用 add 本地 方法\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/sayHelloInc\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;调用 sayHelloInc 本地 方法\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/intMethod\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;调用 intMethod 本地 方法\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; **Java源码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **MainActivity源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_43\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_43\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; shuliang.han.ndkparameterpassing; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt;{ - System.loadLibrary(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;DataProvider\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - - DataProvider dataProvider; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - dataProvider = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DataProvider(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View view) { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id = view.getId(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (id) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.add: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; result = dataProvider.add(\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); - Toast.makeText(getApplicationContext(), \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;the add result : \u0026amp;#8220;\u0026lt;/span\u0026gt; + result, Toast.LENGTH_LONG).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.sayHelloInc: - Toast.makeText(getApplicationContext(), dataProvider.sayHelloInc(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Hello\u0026amp;#8221;\u0026lt;/span\u0026gt;), Toast.LENGTH_LONG).show(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.intMethod: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] array = {\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;}; - dataProvider.intMethod(array); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - - } \u0026lt;/div\u0026gt; \u0026amp;#8212;**DataProvider源码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_44\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_44\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; shuliang.han.ndkparameterpassing; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; DataProvider { - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将Java中的两个int值 传给C语言, 进行相加后, 返回java语言 shuliang.han.ndkparameterpassing.DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将Java字符串传递给C语言, C语言处理字符串之后, 将处理结果返回给java\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; String sayHelloInc(String s); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将java中的int数组传递给C语言, C语言为每个元素加10, 返回给Java\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] intMethod(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] nums); - - } \u0026lt;/div\u0026gt; **JNI相关源码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **Android.mk源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_plain\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_45\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_45\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - LOCAL_PATH := $(call my-dir) - - include $(CLEAR_VARS) - - LOCAL_MODULE := DataProvider - LOCAL_SRC_FILES := DataProvider.c - #增加log函数对应的log库 - LOCAL_LDLIBS += -llog - - include $(BUILD_SHARED_LIBRARY) \u0026lt;/div\u0026gt; \u0026amp;#8212;**DataProvider.c 主程序源码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_46\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_46\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;jni.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;string.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;android/log.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOG_TAG \u0026amp;#8220;System.out\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOGD(\u0026amp;#8230;) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOGI(\u0026amp;#8230;) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// java中的jstring, 转化为c的一个字符数组\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* Jstring2CStr(JNIEnv* env, jstring jstr) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//声明了一个字符串变量 rtn\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* rtn = NULL; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//找到Java中的String的Class对象\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;jclass clsstring = (*env)-\u0026gt;FindClass(env, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;java/lang/String\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//创建一个Java中的字符串 \u0026amp;#8220;GB2312\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;jstring strencode = (*env)-\u0026gt;NewStringUTF(env, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;GB2312\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026lt;span style=\u0026amp;#8221;white-space:pre\u0026amp;#8221;\u0026gt; \u0026lt;/span\u0026gt; * 获取String中定义的方法 getBytes(), 该方法的参数是 String类型的, 返回值是 byte[]数组\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026lt;span style=\u0026amp;#8221;white-space:pre\u0026amp;#8221;\u0026gt; \u0026lt;/span\u0026gt; * \u0026amp;#8220;(Ljava/lang/String;)[B\u0026amp;#8221; 方法前面解析 :\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026lt;span style=\u0026amp;#8221;white-space:pre\u0026amp;#8221;\u0026gt; \u0026lt;/span\u0026gt; * \u0026amp;#8212; Ljava/lang/String; 表示参数是String字符串\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026lt;span style=\u0026amp;#8221;white-space:pre\u0026amp;#8221;\u0026gt; \u0026lt;/span\u0026gt; * \u0026amp;#8212; [B : 中括号表示这是一个数组, B代表byte类型, 返回值是一个byte数组\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;\u0026lt;span style=\u0026amp;#8221;white-space:pre\u0026amp;#8221;\u0026gt; \u0026lt;/span\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;jmethodID mid = (*env)-\u0026gt;GetMethodID(env, clsstring, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;getBytes\u0026amp;#8221;\u0026lt;/span\u0026gt;, - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;(Ljava/lang/String;)[B\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用Java中的getBytes方法, 传入参数介绍 参数②表示调用该方法的对象, 参数③表示方法id , 参数④表示方法参数\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;jbyteArray barr = (jbyteArray)(*env)-\u0026gt;CallObjectMethod(env, jstr, mid, - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;strencode); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// String .getByte(\u0026amp;#8220;GB2312\u0026amp;#8221;);\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取数组的长度\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;jsize alen = (*env)-\u0026gt;GetArrayLength(env, barr); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取数组中的所有的元素 , 存放在 jbyte*数组中\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;jbyte* ba = (*env)-\u0026gt;GetByteArrayElements(env, barr, JNI_FALSE); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//将Java数组中所有元素拷贝到C的char*数组中, 注意C语言数组结尾要加一个 \u0026amp;#8216;\\0\u0026amp;#8217;\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (alen \u0026gt; 0) { - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;rtn = (\u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;*) malloc(alen + 1); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//new char[alen+1]; \u0026amp;#8220;\\0\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;memcpy(rtn, ba, alen); - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;rtn[alen] = 0; - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;} - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;(*env)-\u0026gt;ReleaseByteArrayElements(env, barr, ba, 0); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//释放内存\u0026lt;/span\u0026gt; - - - \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;white-space:pre\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; rtn; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//方法签名, Java环境 和 调用native方法的类 必不可少, 后面的参数就是native方法的参数\u0026lt;/span\u0026gt; - jint Java_shuliang_han_ndkparameterpassing_DataProvider_add(JNIEnv * env, jobject obj, jint x, jint y) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Java中的int对应的是C语言中的long类型, 对应JNI中的jint类型, C语言中\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;JNI_log : x = %d , y = %d\u0026amp;#8221;\u0026lt;/span\u0026gt; , x , y); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; x + y; - } - - jstring Java_shuliang_han_ndkparameterpassing_DataProvider_sayHelloInc(JNIEnv *env, jobject obj, jstring str) - { - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; *p = (\u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;*)Jstring2CStr(env, str); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//打印Java传递过来的数据\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Java JNI string parameter is : %s\u0026amp;#8221;\u0026lt;/span\u0026gt;, p); - - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; *append = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;append\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//strcat(dest, source) 函数可以将source字符串 添加到dest字符串后面\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (*env)-\u0026gt;NewStringUTF(env, strcat(p, append)); - } - - jintArray Java_shuliang_han_ndkparameterpassing_DataProvider_intMethod(JNIEnv *env, jobject obj, jintArray arr) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取arr大小\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; len = (*env)-\u0026gt;GetArrayLength(env, arr); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//在LogCat中打印出arr的大小\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;the length of array is %d\u0026amp;#8221;\u0026lt;/span\u0026gt;, len); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//如果长度为0, 返回arr\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(len == 0) - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; arr; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//如果长度大于0, 那么获取数组中的每个元素\u0026lt;/span\u0026gt; - jint* p = (*env)-\u0026gt;GetIntArrayElements(env, arr, 0); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//打印出数组中每个元素的值\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = 0; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(; i \u0026lt; len; i ++) - { - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;arr[%d] = %d\u0026amp;#8221;\u0026lt;/span\u0026gt;, i, *(p + i)); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; arr; - - } \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ## \u0026lt;a name=\u0026quot;t50\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;8. 上传代码到GitHub **创建新项目** : han1202012/NDKParameterPassing ; — SSH地址 : git@github.com:han1202012/NDKParameterPassing.git ; — HTTP地址 : https://github.com/han1202012/NDKParameterPassing.git ;\n\u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; # \u0026lt;a name=\u0026quot;t51\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;五. C语言代码回调Java方法 \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **C语言回调Java方法场景** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **复用方法** : 使用Java对象, 复用Java中的方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **激活Java** : C程序后台运行, 该后台程序一直运行, 某个时间出发后需要启动Java服务, 激活Android中的某个界面, 例如使用Intent启动一个Activity; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t52\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;1. C代码回调Java方法的流程 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t53\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(1) 找到java对应的Class \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 创建一个char*数组, 然后使用jni.h中提供的FindClass方法获取jclass返回值; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_47\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_47\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//DataProvider完整类名 shulaing.han.ndk_callback.DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* classname = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;shulaing/han/ndk_callback/DataProvider\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - - jclass dpclazz = (*env)-\u0026gt;FindClass(env, classname); \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t54\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(2) 找到要调用的方法的methodID \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 使用jni.h中提供的GetMethodID方法, 获取jmethodID, 传入参数 ①JNIEnv指针 ②Class对象 ③ 方法名 ④方法签名, 在这里方法名和方法签名确定一个方法, 方法签名就是方法的返回值 与 参数的唯一标示; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_48\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_48\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method\u0026lt;/span\u0026gt; - jmethodID methodID = (*env)-\u0026gt;GetMethodID(env, dpclazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Add\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;(II)I\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **找到静态方法** : 如果方法是静态的, 就使用GetStaticMethod方法获取 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_49\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_49\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jmethodID GetStaticMethodID(jclass clazz, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* name, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* sig) - { \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; functions-\u0026gt;GetStaticMethodID(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, clazz, name, sig); } \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ### \u0026lt;a name=\u0026quot;t55\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;(3) 在C语言中调用相应方法 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **普通方法** : CallTypeMethod , 其中的Type随着返回值类型的不同而改变; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **参数介绍** : ① JNIEnv指针 ②调用该native方法的对象 ③方法的methodID ④⑤\u0026amp;#8230; 后面是可变参数, 这些参数是 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_50\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_50\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jmethodID (*GetMethodID)(JNIEnv*, jclass, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;*, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;*); - - jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;) __NDK_FPABI__; - jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;) __NDK_FPABI__; - jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; - jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;) __NDK_FPABI__; - jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;) __NDK_FPABI__; - jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); \u0026lt;/div\u0026gt; **静态方法** : CallStaticTypeMethod, 其中的Type随着返回值类型不同而改变;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t56\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;2. 一些基本代码编写 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java代码** : 定义**一个callCcode本地方法**, 以及**三个Java方法**, 在jni中使用本地方法调用Java中的方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_51\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_51\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; shulaing.han.ndk_callback; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; DataProvider { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; callCcode(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//C调用java中空方法 shulaing.han.ndk_callback.DataProvider\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; helloFromJava(){ - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;hello from java\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//C调用java中的带两个int参数的方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; Add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x,\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y){ - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; x + y; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//C调用java中参数为string的方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; printString(String s){ - System.out.println(s); - } - - } \u0026lt;/div\u0026gt; **生成头文件** : 进入 bin/classed目录, 使用 **javah shulaing.han.ndk_callback.DataProvider** 命令, 可以在bin/classes下生成头文件;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207203856375) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **头文件内容** : 文件名 : shulaing_han_ndk_callback_DataProvider.h ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_52\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_52\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* DO NOT EDIT THIS FILE \u0026amp;#8211; it is machine generated */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;jni.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* Header for class shulaing_han_ndk_callback_DataProvider */\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifndef _Included_shulaing_han_ndk_callback_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define _Included_shulaing_han_ndk_callback_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifdef __cplusplus\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extern\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;C\u0026amp;#8221;\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Class: shulaing_han_ndk_callback_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Method: callCcode\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Signature: ()V\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - JNIEXPORT \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode - (JNIEnv *, jobject); - - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifdef __cplusplus\u0026lt;/span\u0026gt; - } - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; **编写Android.mk文件** : 注意将LogCat日志输出系统动态库加入;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_plain\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_53\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_53\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - LOCAL_PATH := $(call my-dir) - - include $(CLEAR_VARS) - - LOCAL_MODULE := jni - LOCAL_SRC_FILES := jni.c - #增加log函数对应的log库 - LOCAL_LDLIBS += -llog - - include $(BUILD_SHARED_LIBRARY) \u0026lt;/div\u0026gt; **编写jni的C代码** : 注意加入LogCat相关导入的包;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_54\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_54\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026amp;#8220;shulaing_han_ndk_callback_DataProvider.h\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;string.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;android/log.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOG_TAG \u0026amp;#8220;System.out\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOGD(\u0026amp;#8230;) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOGI(\u0026amp;#8230;) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t57\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;3. C中回调Java的void返回值方法 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **使用JNIEnv指针获取Class对象** : 在jni.h文件中找到 \u0026amp;#8211; jclass (*FindClass)(JNIEnv*, const char*); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **参数介绍** : 第二个参数是类的路径字符串, 如 \u0026amp;#8220;/shuliang/han/ndk_callback/DataProvider\u0026amp;#8221; ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **获取Java类中定义的method方法** : 在jni.h中找到方法 \u0026amp;#8211; jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **参数介绍** : 第二个参数是 Java类的Class对象, 第三个参数是方法名, 第四个参数是Java方法的签名; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **方法签名生成工具** : javap , 使用javap -s 命令即可生成方法签名; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207210214562) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **进入bin/classed目录下** : 执行 javap -s shulaing.han.ndk_callback.DataProvider 命令, 即可显示出每个方法的签名; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_plain\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_55\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_55\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - $ javap -s shulaing.han.ndk_callback.DataProvider - Compiled from \u0026amp;#8220;DataProvider.java\u0026amp;#8221; - public class shulaing.han.ndk_callback.DataProvider extends java.lang.Object{ - public shulaing.han.ndk_callback.DataProvider(); - Signature: ()V - public native void callCcode(); - Signature: ()V - public void helloFromJava(); - Signature: ()V - public int Add(int, int); - Signature: (II)I - public void printString(java.lang.String); - Signature: (Ljava/lang/String;)V - } \u0026lt;/div\u0026gt; **截图** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207210837125) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **方法签名介绍** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **返回值null, 参数null** : void helloFromJava() 方法的签名是 \u0026amp;#8220;()V\u0026amp;#8221;, 括号里什么都没有代表参数为null, V代表返回值是void; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **返回值int, 参数两个int** : int Add(int x,int y) 方法的签名是 \u0026amp;#8220;(II)I\u0026amp;#8221;, 括号中II表示两个int类型参数, 右边括号外的I代表返回值是int类型; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **返回值null, 参数String** : void printString(String s) 方法签名是 \u0026amp;#8220;(Ljava/lang/String;)V\u0026amp;#8221;, 括号中的Ljava/lang/String; 表示参数是String类型, V表示返回值是void; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **jni.h中定义的回调Java方法的相关函数** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_56\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_56\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - jmethodID (*GetMethodID)(JNIEnv*, jclass, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;*, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;*); - - jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); - jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;) __NDK_FPABI__; - jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;) __NDK_FPABI__; - jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; - jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;) __NDK_FPABI__; - jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;) __NDK_FPABI__; - jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;va_list\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; **C语言代码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_57\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_57\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026amp;#8220;shulaing_han_ndk_callback_DataProvider.h\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;string.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;android/log.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOG_TAG \u0026amp;#8220;System.out\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOGD(\u0026amp;#8230;) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOGI(\u0026amp;#8230;) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)\u0026lt;/span\u0026gt; - - JNIEXPORT \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode - (JNIEnv * env, jobject obj) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用DataProvider对象中的helloFromJava()方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取到某个对象, 获取对象中的方法, 调用获取到的方法\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;in code\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//DataProvider完整类名 shulaing.han.ndk_callback.DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* classname = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;shulaing/han/ndk_callback/DataProvider\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - - jclass dpclazz = (*env)-\u0026gt;FindClass(env, classname); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(dpclazz == 0) - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;class not find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;class find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method\u0026lt;/span\u0026gt; - jmethodID methodID = (*env)-\u0026gt;GetMethodID(env, dpclazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;helloFromJava\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;()V\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(methodID == 0) - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;method not find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;method find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 参数介绍 : 后面的 \u0026amp;#8230; 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;before call method\u0026amp;#8221;\u0026lt;/span\u0026gt;); - (*env)-\u0026gt;CallVoidMethod(env, obj, methodID); - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;after call method\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - } \u0026lt;/div\u0026gt; **Java代码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212;**XML布局文件代码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_58\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_58\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_vertical_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_horizontal_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_horizontal_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_vertical_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/call_void_method\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;C语言回调Java中的空方法\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;#8212;**MainActivity代码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_59\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_59\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; shulaing.han.ndk_callback; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt;{ - System.loadLibrary(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;jni\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - DataProvider dp; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - dp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DataProvider(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View view) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id = view.getId(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (id) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.call_void_method: - dp.callCcode(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - - } \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; **执行结果** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207215815265) . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t58\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;4. C代码回调Java中带String参数的方法 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **在DataProvider中添加两个native方法** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_60\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_60\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; callCcode(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; callCcode1(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; callCcode2(); \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **进入bin/classes目录, 使用 javah -jni shulaing.han.ndk_callback.DataProvider 命令生成头文件** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_61\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_61\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* DO NOT EDIT THIS FILE \u0026amp;#8211; it is machine generated */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;jni.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* Header for class shulaing_han_ndk_callback_DataProvider */\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifndef _Included_shulaing_han_ndk_callback_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define _Included_shulaing_han_ndk_callback_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifdef __cplusplus\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extern\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;C\u0026amp;#8221;\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Class: shulaing_han_ndk_callback_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Method: callCcode\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Signature: ()V\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - JNIEXPORT \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode - (JNIEnv *, jobject); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Class: shulaing_han_ndk_callback_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Method: callCcode1\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Signature: ()V\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - JNIEXPORT \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode1 - (JNIEnv *, jobject); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Class: shulaing_han_ndk_callback_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Method: callCcode2\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Signature: ()V\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - JNIEXPORT \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode2 - (JNIEnv *, jobject); - - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifdef __cplusplus\u0026lt;/span\u0026gt; - } - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **jni C语言代码** : 这里只需要修改两处, 方法名, 获取方法id中的参数, 调用方法中最后加上一个Java参数; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_62\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_62\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - JNIEXPORT \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode1 - (JNIEnv *env, jobject obj) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用DataProvider对象中的helloFromJava()方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取到某个对象, 获取对象中的方法, 调用获取到的方法\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;in code\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//DataProvider完整类名 shulaing.han.ndk_callback.DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* classname = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;shulaing/han/ndk_callback/DataProvider\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - - jclass dpclazz = (*env)-\u0026gt;FindClass(env, classname); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(dpclazz == 0) - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;class not find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;class find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method\u0026lt;/span\u0026gt; - jmethodID methodID = (*env)-\u0026gt;GetMethodID(env, dpclazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;printString\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;(Ljava/lang/String;)V\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(methodID == 0) - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;method not find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;method find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 参数介绍 : 后面的 \u0026amp;#8230; 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;before call method\u0026amp;#8221;\u0026lt;/span\u0026gt;); - (*env)-\u0026gt;CallVoidMethod(env, obj, methodID, (*env)-\u0026gt;NewStringUTF(env, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;printString method callback success!!\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;after call method\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } \u0026lt;/div\u0026gt; **执行后的结果** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140208144212640) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t59\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;5. C代码中回调带两个int类型的参数的方法 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **按照上面的流程, 不同之处就是jni中获取方法 和 方法id , 调用方法的jni函数不同** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_63\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_63\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - JNIEXPORT \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode2 - (JNIEnv *env, jobject obj) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用DataProvider对象中的helloFromJava()方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取到某个对象, 获取对象中的方法, 调用获取到的方法\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;in code\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//DataProvider完整类名 shulaing.han.ndk_callback.DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* classname = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;shulaing/han/ndk_callback/DataProvider\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - - jclass dpclazz = (*env)-\u0026gt;FindClass(env, classname); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(dpclazz == 0) - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;class not find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;class find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method\u0026lt;/span\u0026gt; - jmethodID methodID = (*env)-\u0026gt;GetMethodID(env, dpclazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Add\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;(II)I\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(methodID == 0) - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;method not find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;method find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 参数介绍 : 后面的 \u0026amp;#8230; 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;before call method\u0026amp;#8221;\u0026lt;/span\u0026gt;); - (*env)-\u0026gt;CallIntMethod(env, obj, methodID, 3, 5); - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;after call method\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - } \u0026lt;/div\u0026gt; **Java代码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_64\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_64\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.call_int_parameter_method: - dp.callCcode2(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **执行结果** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140208171145750) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . **作者** : **万境绝尘 ** **转载请注明出处** : [**http://blog.csdn.net/shulianghan/article/details/18964835**](http://blog.csdn.net/shulianghan/article/details/18964835) . \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t60\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;6. 完整源码 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **DataProvider源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_65\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_65\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; shulaing.han.ndk_callback; - - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; DataProvider { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; callCcode(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; callCcode1(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; callCcode2(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//C调用java中空方法 shulaing.han.ndk_callback.DataProvider\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; helloFromJava(){ - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;hello from java\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//C调用java中的带两个int参数的方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; Add(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x,\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y){ - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;the add result is : \u0026amp;#8220;\u0026lt;/span\u0026gt; + (x + y)); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; x + y; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//C调用java中参数为string的方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; printString(String s){ - System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;in java code :\u0026amp;#8221;\u0026lt;/span\u0026gt; + s); - } - - } \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **MainActivity源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_66\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_66\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; shulaing.han.ndk_callback; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt;{ - System.loadLibrary(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;jni\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - DataProvider dp; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - dp = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DataProvider(); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View view) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id = view.getId(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (id) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.call_void_method: - dp.callCcode(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.call_string_parameter_method: - dp.callCcode1(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.call_int_parameter_method: - dp.callCcode2(); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - - } \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **XML布局文件源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_67\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_67\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_vertical_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_horizontal_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_horizontal_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_vertical_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/call_void_method\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;C语言回调Java中的空方法\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/call_string_parameter_method\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;C语言回调Java中的String参数方法\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/call_int_parameter_method\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;C语言回调Java中的int参数方法\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **jni源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **头文件源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_68\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_68\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* DO NOT EDIT THIS FILE \u0026amp;#8211; it is machine generated */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;jni.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* Header for class shulaing_han_ndk_callback_DataProvider */\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifndef _Included_shulaing_han_ndk_callback_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define _Included_shulaing_han_ndk_callback_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifdef __cplusplus\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extern\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;C\u0026amp;#8221;\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Class: shulaing_han_ndk_callback_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Method: callCcode\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Signature: ()V\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - JNIEXPORT \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode - (JNIEnv *, jobject); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Class: shulaing_han_ndk_callback_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Method: callCcode1\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Signature: ()V\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - JNIEXPORT \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode1 - (JNIEnv *, jobject); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Class: shulaing_han_ndk_callback_DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Method: callCcode2\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Signature: ()V\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - JNIEXPORT \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode2 - (JNIEnv *, jobject); - - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifdef __cplusplus\u0026lt;/span\u0026gt; - } - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **Android.mk源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_plain\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_69\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_69\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - LOCAL_PATH := $(call my-dir) - - include $(CLEAR_VARS) - - LOCAL_MODULE := jni - LOCAL_SRC_FILES := jni.c - #增加log函数对应的log库 - LOCAL_LDLIBS += -llog - - include $(BUILD_SHARED_LIBRARY) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **jni主程序源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_70\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_70\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026amp;#8220;shulaing_han_ndk_callback_DataProvider.h\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026amp;#8220;first.h\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;string.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;android/log.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOG_TAG \u0026amp;#8220;System.out\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOGD(\u0026amp;#8230;) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOGI(\u0026amp;#8230;) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)\u0026lt;/span\u0026gt; - - JNIEXPORT \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode - (JNIEnv * env, jobject obj) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用DataProvider对象中的helloFromJava()方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取到某个对象, 获取对象中的方法, 调用获取到的方法\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;in code\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//DataProvider完整类名 shulaing.han.ndk_callback.DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* classname = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;shulaing/han/ndk_callback/DataProvider\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - - jclass dpclazz = (*env)-\u0026gt;FindClass(env, classname); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(dpclazz == 0) - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;class not find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;class find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method\u0026lt;/span\u0026gt; - jmethodID methodID = (*env)-\u0026gt;GetMethodID(env, dpclazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;helloFromJava\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;()V\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(methodID == 0) - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;method not find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;method find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 参数介绍 : 后面的 \u0026amp;#8230; 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;before call method\u0026amp;#8221;\u0026lt;/span\u0026gt;); - (*env)-\u0026gt;CallVoidMethod(env, obj, methodID); - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;after call method\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - } - - JNIEXPORT \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode1 - (JNIEnv *env, jobject obj) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用DataProvider对象中的helloFromJava()方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取到某个对象, 获取对象中的方法, 调用获取到的方法\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;in code\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//DataProvider完整类名 shulaing.han.ndk_callback.DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* classname = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;shulaing/han/ndk_callback/DataProvider\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - - jclass dpclazz = (*env)-\u0026gt;FindClass(env, classname); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(dpclazz == 0) - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;class not find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;class find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method\u0026lt;/span\u0026gt; - jmethodID methodID = (*env)-\u0026gt;GetMethodID(env, dpclazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;printString\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;(Ljava/lang/String;)V\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(methodID == 0) - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;method not find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;method find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 参数介绍 : 后面的 \u0026amp;#8230; 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;before call method\u0026amp;#8221;\u0026lt;/span\u0026gt;); - (*env)-\u0026gt;CallVoidMethod(env, obj, methodID, (*env)-\u0026gt;NewStringUTF(env, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;printString method callback success!!\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;after call method\u0026amp;#8221;\u0026lt;/span\u0026gt;); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 实际开发的情况\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * C代码工程师给我们 first.h first.c , 我们只需要将first.h引入, 然后就可以使用其中的方法了\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - JNIEXPORT \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode2 - (JNIEnv *env, jobject obj) - { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用DataProvider对象中的helloFromJava()方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取到某个对象, 获取对象中的方法, 调用获取到的方法\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;in code\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//DataProvider完整类名 shulaing.han.ndk_callback.DataProvider\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* classname = \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;shulaing/han/ndk_callback/DataProvider\u0026amp;#8221;\u0026lt;/span\u0026gt;; - - - jclass dpclazz = (*env)-\u0026gt;FindClass(env, classname); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(dpclazz == 0) - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;class not find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;class find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method\u0026lt;/span\u0026gt; - jmethodID methodID = (*env)-\u0026gt;GetMethodID(env, dpclazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Add\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;(II)I\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(methodID == 0) - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;method not find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;method find !!!\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, \u0026amp;#8230;);\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * 参数介绍 : 后面的 \u0026amp;#8230; 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;before call method\u0026amp;#8221;\u0026lt;/span\u0026gt;); - (*env)-\u0026gt;CallIntMethod(env, obj, methodID, 3, 5); - LOGI(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;after call method\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - } \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t61\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;7. 将程序上传到GitHub中 \u0026lt;div\u0026gt; GitHub地址 : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; SSH : git@github.com:han1202012/NDK_Callback.git \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; HTTP : https://github.com/han1202012/NDK_Callback.git \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; # \u0026lt;a name=\u0026quot;t62\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;六. 实际开发中的环境 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **这里举一个简单的小例子** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **在实际开发中, C工程师会给我们c文件如下** : first.h first.c, 一个C主程序, 一个头文件, 我们只需要将这个头文件引入到jni中的C代码中即可, 在我们自定义生成的签名函数中调用 first.h中的方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **first.h源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_71\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_71\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifndef FIRST_H\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define FIRST_H\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extern\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; first(\u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y); - - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif /* FIRST_H */\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; **first.c源码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_72\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_72\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026amp;#8220;first.h\u0026amp;#8221;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; first(\u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; x + y; - } \u0026lt;/div\u0026gt; ** 在签名函数中, 直接调用 first()方法即可**;\n\u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; # \u0026lt;a name=\u0026quot;t63\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;七 分析Log日志系统框架的JNI代码 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ** ** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **在这里分析日志输出函数** : Log.i(TAG, \u0026amp;#8220;log\u0026amp;#8221;), 分析该**日志系统的JNI层源码结构**; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **这里使用下载的Android2.3.3源码进行分析** : 在 [http://blog.csdn.net/shulianghan/article/details/17350401](http://blog.csdn.net/shulianghan/article/details/17350401) 中介绍了如何使用repo 和 git 下载Android源码 和 kernel 源码; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **LogJNI调用层次** : android.util.Log.java 中的接口 是**通过JNI调用 本地库** 并最终**调用内核驱动程序 Logger** 将日志信息写到 **内核空间中**. \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **分析的源码文件** : \u0026amp;#8220;\\\u0026amp;#8221; 代表Android源代码的本目录; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **Java代码** : \\frameworks\\base\\core\\java\\android\\util\\Log.java \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI层实现代码** : \\frameworks\\base\\core\\jni\\android_util_Log.cpp \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **下面的是Android自定义的JNI规范相关的源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI规范头文件** : \\dalvik\\libnativehelper\\include\\nativehelper\\jni.h \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI帮助文件** : ① \\dalvik\\libnativehelper\\include\\nativehelper\\JNIHelp.h ② \\dalvik\\libnativehelper\\JNIHelp.c \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI运行时文件** : \\frameworks\\base\\core\\jni\\AndroidRuntime.cpp \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **这里将上面几个文件上传到CSDN资源中, 便于查看** : [http://download.csdn.net/detail/han1202012/6905507](http://download.csdn.net/detail/han1202012/6905507) ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t64\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;1. 分析Log.java源码 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Log.java分析** : 在Log.java文件中,**定义了 isLoggable 和 println_native 两个Native方法**, 在Java方法中, 只需要事先**声明native方法, 不用实现方法体**, 可以直接调用; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Log.java在Android源码中的位置** : \\frameworks\\base\\core\\java\\android\\util\\Log.java \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Log.java内容** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_73\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_73\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; android.util; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.android.internal.os.RuntimeInit; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.PrintWriter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.StringWriter; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; Log { - - \u0026amp;#8230; \u0026amp;#8230; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//打印日志\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; d(String tag, String msg) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; println_native(LOG_ID_MAIN, DEBUG, tag, msg); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//打印日志和异常\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; d(String tag, String msg, Throwable tr) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; println_native(LOG_ID_MAIN, DEBUG, tag, msg + \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;\\n\u0026amp;#8217;\u0026lt;/span\u0026gt; + getStackTraceString(tr)); - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//打印日志\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i(String tag, String msg) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; println_native(LOG_ID_MAIN, INFO, tag, msg); - } - - \u0026amp;#8230; \u0026amp;#8230; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//声明native方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isLoggable(String tag, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; level); - - \u0026amp;#8230; \u0026amp;#8230; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** @hide */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; LOG_ID_MAIN = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** @hide */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; LOG_ID_RADIO = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** @hide */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; LOG_ID_EVENTS = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** @hide */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; LOG_ID_SYSTEM = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//声明native方法\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/** @hide */\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;native\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; println_native(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bufID, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; priority, String tag, String msg); - } \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t65\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;2. 分析Log系统JNI层源码 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNI层方法**: JNI层方法根据一定规则**与Java层声明的Native方法进行映射**, 然后可以通过JNIEnv指针提供的**JNI函数对Java层进行操作**; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Log系统的JNI层文件是** : android_util_Log.cpp, 该文件路径 :\\frameworks\\base\\core\\jni\\android_util_Log.cpp 代码如下 : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_74\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_74\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOG_NAMESPACE \u0026amp;#8220;log.tag.\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#define LOG_TAG \u0026amp;#8220;Log_println\u0026amp;#8221;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;assert.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;cutils/properties.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;utils/Log.h\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026lt;utils/String8.h\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026amp;#8220;jni.h\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026amp;#8220;utils/misc.h\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#include \u0026amp;#8220;android_runtime/AndroidRuntime.h\u0026amp;#8221;\u0026lt;/span\u0026gt; - - \u0026amp;#8230; \u0026amp;#8230; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;namespace\u0026lt;/span\u0026gt; android { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;struct\u0026lt;/span\u0026gt; levels_t { - jint verbose; - jint debug; - jint info; - jint warn; - jint error; - jint assert; - }; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; levels_t levels; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; toLevel(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* value) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (value[0]) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;V\u0026amp;#8217;\u0026lt;/span\u0026gt;: \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; levels.verbose; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;D\u0026amp;#8217;\u0026lt;/span\u0026gt;: \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; levels.debug; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;I\u0026amp;#8217;\u0026lt;/span\u0026gt;: \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; levels.info; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;W\u0026amp;#8217;\u0026lt;/span\u0026gt;: \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; levels.warn; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;E\u0026amp;#8217;\u0026lt;/span\u0026gt;: \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; levels.error; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;A\u0026amp;#8217;\u0026lt;/span\u0026gt;: \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; levels.assert; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8216;S\u0026amp;#8217;\u0026lt;/span\u0026gt;: \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; -1; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// SUPPRESS\u0026lt;/span\u0026gt; - } - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; levels.info; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; 实现Java层声明的 isLoggable 方法, 注意方法名不符合标准JNI规范\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; 标准的JNI规范方法名应该是 Java_包名_类名_方法名\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; 其中传入了JNIEnv 和 jobject 参数, JNIEnv参数是Java运行环境, 可以与JVM进行交互\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; jobject参数是包含Native方法的Java类对象\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; 该方法中可以通过JNIEnv调用本地库进行函数处理, 最后返回给Java层函数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;*/\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level) - { - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#ifndef HAVE_ANDROID_OS\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#else /* HAVE_ANDROID_OS */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; len; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; key[PROPERTY_KEY_MAX]; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; buf[PROPERTY_VALUE_MAX]; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (tag == NULL) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } - - jboolean result = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用了JNI函数\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* chars = env-\u0026gt;GetStringUTFChars(tag, NULL); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((strlen(chars)+\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;sizeof\u0026lt;/span\u0026gt;(LOG_NAMESPACE)) \u0026gt; PROPERTY_KEY_MAX) { - jclass clazz = env-\u0026gt;FindClass(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;java/lang/IllegalArgumentException\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; buf2[200]; - snprintf(buf2, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;sizeof\u0026lt;/span\u0026gt;(buf2), \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Log tag \\\u0026amp;#8221;%s\\\u0026amp;#8221; exceeds limit of %d characters\\n\u0026amp;#8221;\u0026lt;/span\u0026gt;, - chars, PROPERTY_KEY_MAX \u0026amp;#8211; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;sizeof\u0026lt;/span\u0026gt;(LOG_NAMESPACE)); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// release the chars!\u0026lt;/span\u0026gt; - env-\u0026gt;ReleaseStringUTFChars(tag, chars); - - env-\u0026gt;ThrowNew(clazz, buf2); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - } \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { - strncpy(key, LOG_NAMESPACE, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;sizeof\u0026lt;/span\u0026gt;(LOG_NAMESPACE)-1); - strcpy(key + \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;sizeof\u0026lt;/span\u0026gt;(LOG_NAMESPACE) \u0026amp;#8211; 1, chars); - } - - env-\u0026gt;ReleaseStringUTFChars(tag, chars); - - len = property_get(key, buf, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; logLevel = toLevel(buf); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; (logLevel \u0026gt;= 0 \u0026amp;\u0026amp; level \u0026gt;= logLevel) ? \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt; : \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;preprocessor\u0026quot;\u0026gt;#endif /* HAVE_ANDROID_OS */\u0026lt;/span\u0026gt; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * In class android.util.Log:\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * public static native int println_native(int buffer, int priority, String tag, String msg)\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; jint android_util_Log_println_native(JNIEnv* env, jobject clazz, - jint bufID, jint priority, jstring tagObj, jstring msgObj) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* tag = NULL; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* msg = NULL; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (msgObj == NULL) { - jclass npeClazz; - - npeClazz = env-\u0026gt;FindClass(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;java/lang/NullPointerException\u0026amp;#8221;\u0026lt;/span\u0026gt;); - assert(npeClazz != NULL); - - env-\u0026gt;ThrowNew(npeClazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;println needs a message\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; -1; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (bufID \u0026lt; 0 || bufID \u0026gt;= LOG_ID_MAX) { - jclass npeClazz; - - npeClazz = env-\u0026gt;FindClass(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;java/lang/NullPointerException\u0026amp;#8221;\u0026lt;/span\u0026gt;); - assert(npeClazz != NULL); - - env-\u0026gt;ThrowNew(npeClazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;bad bufID\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; -1; - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (tagObj != NULL) - tag = env-\u0026gt;GetStringUTFChars(tagObj, NULL); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用JNI函数\u0026lt;/span\u0026gt; - msg = env-\u0026gt;GetStringUTFChars(msgObj, NULL); - - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (tag != NULL) - env-\u0026gt;ReleaseStringUTFChars(tagObj, tag); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用JNI函数释放资源\u0026lt;/span\u0026gt; - env-\u0026gt;ReleaseStringUTFChars(msgObj, msg); \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//调用JNI函数释放资源\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; res; - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * JNI registration. JNI方法注册\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; JNINativeMethod gMethods[] = { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* name, signature, funcPtr */\u0026lt;/span\u0026gt; - { \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;isLoggable\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;(Ljava/lang/String;I)Z\u0026amp;#8221;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;*) android_util_Log_isLoggable }, - { \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;println_native\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;(IILjava/lang/String;Ljava/lang/String;)I\u0026amp;#8221;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;*) android_util_Log_println_native }, - }; - - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; register_android_util_Log(JNIEnv* env) - { - jclass clazz = env-\u0026gt;FindClass(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;android/util/Log\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (clazz == NULL) { - LOGE(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Can\u0026amp;#8217;t find android/util/Log\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; -1; - } - - levels.verbose = env-\u0026gt;GetStaticIntField(clazz, env-\u0026gt;GetStaticFieldID(clazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;VERBOSE\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - levels.debug = env-\u0026gt;GetStaticIntField(clazz, env-\u0026gt;GetStaticFieldID(clazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;DEBUG\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - levels.info = env-\u0026gt;GetStaticIntField(clazz, env-\u0026gt;GetStaticFieldID(clazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;INFO\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - levels.warn = env-\u0026gt;GetStaticIntField(clazz, env-\u0026gt;GetStaticFieldID(clazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;WARN\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - levels.error = env-\u0026gt;GetStaticIntField(clazz, env-\u0026gt;GetStaticFieldID(clazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;ERROR\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - levels.assert = env-\u0026gt;GetStaticIntField(clazz, env-\u0026gt;GetStaticFieldID(clazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;ASSERT\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; AndroidRuntime::registerNativeMethods(env, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;android/util/Log\u0026amp;#8221;\u0026lt;/span\u0026gt;, gMethods, NELEM(gMethods)); - } - - }; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// namespace android\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t66\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;3. 声明JNI 与 Native 方法的映射关系 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **标准JNI规范** : 在标准的JNI规范中, Java中的Native方法 与 JNI层方法 是通过方法名的对应关系进行映射的, 我们通过 javah 工具生成JNI层头文件, 头文件中定义了规范的JNI层方法名, 这个方法名就与Java Native方法对应; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Android自定义规范** : 在 \\dalvik\\libnativehelper\\include\\nativehelper\\jni.h 中定义了这样的映射关系 : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_75\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_75\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;typedef\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;struct\u0026lt;/span\u0026gt; { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* name; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Java层Native函数方法名\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* signature; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//Java层Native函数的签名\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;* fnPtr; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//JNI层实现的方法\u0026lt;/span\u0026gt; - } JNINativeMethod; \u0026lt;/div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNINativeMethod类型数据** : 在android_util_Log.cpp 中定义了一个该类型的数组 : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_76\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_76\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * JNI registration.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; JNINativeMethod gMethods[] = { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/* name, signature, funcPtr */\u0026lt;/span\u0026gt; - { \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;isLoggable\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;(Ljava/lang/String;I)Z\u0026amp;#8221;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;*) android_util_Log_isLoggable }, - { \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;println_native\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;(IILjava/lang/String;Ljava/lang/String;)I\u0026amp;#8221;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;*) android_util_Log_println_native }, - }; \u0026lt;/div\u0026gt; **JNINativeMethod结构体作用** : JNINativeMethod是一个结构体类型, 声明了Native方法 与 JNI方法 的映射关系;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **解析上面的数组中的元素** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **Native方法** : \u0026amp;#8220;isLoggable\u0026amp;#8221; 是Java中声明的Native方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **方法签名** : \u0026amp;#8220;(Ljava/lang/String;I)Z\u0026amp;#8221; 表示该方法的签名, 参数是String类型 和 int类型, Z 表示 boolean类型; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI方法** : (void*) android_util_Log_isLoggable 表示JNI层实现的方法指针; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t67\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;4. 注册JNI方法到虚拟机中 \u0026lt;div\u0026gt; **映射关系体现到虚拟机中** : 在android_util_Log.cpp 中存在这样的方法 : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_77\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_77\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; register_android_util_Log(JNIEnv* env) - { - jclass clazz = env-\u0026gt;FindClass(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;android/util/Log\u0026amp;#8221;\u0026lt;/span\u0026gt;); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (clazz == NULL) { - LOGE(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Can\u0026amp;#8217;t find android/util/Log\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; -1; - } - - levels.verbose = env-\u0026gt;GetStaticIntField(clazz, env-\u0026gt;GetStaticFieldID(clazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;VERBOSE\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - levels.debug = env-\u0026gt;GetStaticIntField(clazz, env-\u0026gt;GetStaticFieldID(clazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;DEBUG\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - levels.info = env-\u0026gt;GetStaticIntField(clazz, env-\u0026gt;GetStaticFieldID(clazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;INFO\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - levels.warn = env-\u0026gt;GetStaticIntField(clazz, env-\u0026gt;GetStaticFieldID(clazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;WARN\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - levels.error = env-\u0026gt;GetStaticIntField(clazz, env-\u0026gt;GetStaticFieldID(clazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;ERROR\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - levels.assert = env-\u0026gt;GetStaticIntField(clazz, env-\u0026gt;GetStaticFieldID(clazz, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;ASSERT\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;)); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; AndroidRuntime::registerNativeMethods(env, \u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;android/util/Log\u0026amp;#8221;\u0026lt;/span\u0026gt;, gMethods, NELEM(gMethods)); - } - - }; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// namespace android\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; **核心方法** : 该函数调用了 AndroidRuntime::registerNativeMethods(env, \u0026amp;#8220;android/util/Log\u0026amp;#8221;, gMethods, NELEM(gMethods)) 方法注册JNI方法;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **register_android_util_Log调用时机** : 该函数是在Android系统启动的时候, 通过AndroidRuntime.cpp中的register_jni_proocs方法执行, 执行该方法的时候会将 Native方法 与 JNI方法 的函数映射关系注册给 Dalvik 虚拟机; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t68\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;5. 解析registerNativeMethod函数 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **该函数定义在AndroidRuntime.cpp中** : 该文件的路径在 \\frameworks\\base\\core\\jni\\AndroidRuntime.cpp ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_78\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_78\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Register native methods using JNI.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*static*/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; AndroidRuntime::registerNativeMethods(JNIEnv* env, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* className, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; JNINativeMethod* gMethods, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; numMethods) - { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; jniRegisterNativeMethods(env, className, gMethods, numMethods); - } \u0026lt;/div\u0026gt; **registerNativeMethods 方法只是对 jniRegisterNativeMethods 方法的封装, 在JNIHelp.h中找到该方法的声明**:\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_79\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_79\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Register one or more native methods with a particular class.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; jniRegisterNativeMethods(C_JNIEnv* env, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* className, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; JNINativeMethod* gMethods, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; numMethods); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; **在JNIHelp.c 中找到该方法的实现 **: 最终方法中调用了 JNIEnv 的RegisterNatives 函数, 将gMethods中存放的JNINativeMethod结构体(存放Native方法 与 JNI方法关联信息) 传递到java虚拟机;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_cpp\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot;\u0026gt; **[cpp]** [view plain](http://blog.csdn.net/shulianghan/article/details/18964835#)[copy](http://blog.csdn.net/shulianghan/article/details/18964835#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/181707)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/181707/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_80\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_80\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * Register native JNI-callable methods.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; * \u0026amp;#8220;className\u0026amp;#8221; looks like \u0026amp;#8220;java/lang/String\u0026amp;#8221;.\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; jniRegisterNativeMethods(JNIEnv* env, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;* className, - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;const\u0026lt;/span\u0026gt; JNINativeMethod* gMethods, \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; numMethods) - { - jclass clazz; - - LOGV(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Registering %s natives\\n\u0026amp;#8221;\u0026lt;/span\u0026gt;, className); - clazz = (*env)-\u0026gt;FindClass(env, className); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (clazz == NULL) { - LOGE(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;Native registration unable to find class \u0026amp;#8216;%s\u0026amp;#8217;\\n\u0026amp;#8221;\u0026lt;/span\u0026gt;, className); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; -1; - } - - \u0026lt;span class=\u0026quot;datatypes\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; result = 0; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((*env)-\u0026gt;RegisterNatives(env, clazz, gMethods, numMethods) \u0026lt; 0) { - LOGE(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;RegisterNatives failed for \u0026amp;#8216;%s\u0026amp;#8217;\\n\u0026amp;#8221;\u0026lt;/span\u0026gt;, className); - result = -1; - } - - (*env)-\u0026gt;DeleteLocalRef(env, clazz); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; result; - } \u0026lt;/div\u0026gt; ## \u0026lt;a name=\u0026quot;t69\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;6. JNI的规范 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Android中JNI存在两种规范** : 一种是**标准的JNI规范**, 多在**应用层**使用; 另一种是**Android中自定义的规范**, 多使用在**应用框架**层; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI标准规范**: 遵守JNI标准规函数命名方式, JNI中方法命名为 Java_包名_类名_方法名 , 可以使用javah生成签名头文件, 靠这种方式实现 Native方法 与 JNI方法之间的映射关系, 即应用直接与框架层进行交互, 这种规范常用与应用开发; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **函数注册规范** : 这是Android自定义的一种规范, 应用框架层采用该规范, 即应用框架层 与 框架层 进行交互, 底层源码开发多使用该规范; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026amp;nbsp; **转载** : [**http://blog.csdn.net/shulianghan/article/details/18964835**](http://blog.csdn.net/shulianghan/article/details/18964835) \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-%E5%BC%80%E5%8F%91-%E4%B9%8B-jni%E5%85%A5%E9%97%A8-ndk%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A-2/","summary":"\u003cp\u003e\u003cstrong\u003eNDK项目源码地址\u003c/strong\u003e :\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003e第一个JNI示例程序下载\u003c/strong\u003e : \u003cstrong\u003eGitHub\u003c/strong\u003e – \u003ca href=\"https://github.com/han1202012/NDKHelloworld.git\"\u003ehttps://github.com/han1202012/NDKHelloworld.git\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003eJava传递参数给C语言实例程序\u003c/strong\u003e : GitHub – \u003ca href=\"https://github.com/han1202012/NDKParameterPassing.git\"\u003ehttps://github.com/han1202012/NDKParameterPassing.git\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e—\u003cstrong\u003eC语言回调Java方法示例程序\u003c/strong\u003e : GitHub – \u003ca href=\"https://github.com/han1202012/NDK_Callback.git\"\u003ehttps://github.com/han1202012/NDK_Callback.git\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e—\u003cstrong\u003e分析Log框架层JNI源码所需的Android底层文件\u003c/strong\u003e : CSDN – \u003ca href=\"http://download.csdn.net/detail/han1202012/6905507\"\u003ehttp://download.csdn.net/detail/han1202012/6905507\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e开发环境介绍\u003c/strong\u003e :\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003eeclipse\u003c/strong\u003e : adt-bundle-windows-x86-20130917\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003esdk\u003c/strong\u003e : 版本 2.3.3\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003endk\u003c/strong\u003e : android-ndk-r9c-windows-x86.zip\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003ecygwin\u003c/strong\u003e : 所需组件 binutils , gcc , gcc-mingw , gdb , make;\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003ejavah\u003c/strong\u003e : jdk6.0自带工具\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003ejavap\u003c/strong\u003e : jdk6.0自带工具\u003c/p\u003e\n\u003cp\u003e**JNI 总结 : **\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eJava 调用 C 流程\u003c/strong\u003e :\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003ea. 定义 Native 方法\u003c/strong\u003e : 在 \u003cstrong\u003eshuliang.han.ndkparameterpassing.DataProvider.java\u003c/strong\u003e 类中定义 Native 方法 \u003cstrong\u003epublic native int add(int x, int y)\u003c/strong\u003e;\u003c/p\u003e","title":"Android 开发 之 JNI入门 – NDK从入门到精通"},{"content":"Android下的NDK开发是Android开发中不可或缺的一部分，通过Google提供的NDK套件，我们可以使用JNI这座桥梁在Java和C/C++之间建立联系（互相调用）。那么，为什么在Android开发中需要了解NDK开发呢？诚然，这些原因有很多说法，在我总结来是这样的。C/C++是比Java还要古老的编程语言，由于其古老的特性，导致早期有很多优秀的类库出现，譬如处理视频编解码的FFMPEG类库，这些复杂的类库早就被C/C++编写过，我们在处理视频编解码的时候没必要重复“造轮子”，所以能直接拿来用的就直接拿来用，但是这个直接法很难做到，因为Java的编译环境的原理跟C/C++的不同，所以就必须找个中间者为Java和C/C++代码建立关系，这个中间者就是JNI。还有一个重要的原因就是效率问题，Java是跨平台的语言，在不同的平台有不同的JVM实现，Java源码需要首先编译成.class文件，然后让.class文件运行在不同的JVM解释执行上，这样的步骤造成了效率的浪费，而不同的是C/C++，可以直接编译成特定平台的二进制文件，直接运行在特定平台上，效率比Java高效很多，所以在某些特定的环境下，还是需要使用C/C++来解决效率问题，Java只负责处理C/C++返回来的结果就可以，这样的话Java和C/C++互调就显得相当重要了。\n做NDK开发前最好需要了解一下C/C++的语法，通常这部分的代码不需要Android程序员编写，但是Android程序员最好能看懂C/C++源码，这样做会事半功倍一点，关于C/C++语法的学习不是这里的重点，大家感兴趣的话可以直接找资料学习，请从柜底抽出大学教材《C语言程序设计——谭浩强》，拍拍上面的灰尘，随便过一遍^.^\n一、明确一些基本概念 1，JNI Java Native Interface Java 本地开发的接口。JNI 是一个协议,这个协议用来沟通java代码和外部的本地代码(c/c++)。通过这个协议,java代码就可以调用外部的c/c++代码，外部的c/c++代码也可以调用java代码。\n2，CDT C/C++ Develop tools，C/C++开发工具。是Eclipse上的一个插件，主要是让C/C++代码能够高亮显示。这个组件不是必要的，除非你是C/C++高手，喜欢在记事本上写代码，对于一般的程序员还是装一下吧，高亮显示很重要的。\n3，NDK Native Develop Kits，本地开发套件。这个套件是非常重要的，是Google提供给我们的一个在Android上开发JNI程序的工具集，有了它会使得开发高效的多。\n4，cygwin Windows下的Linux模拟器。大家知道Android是基于Linux内核的操作系统，所以在编译C/C++源码的使用得使用Linux环境，将其编译成Linux特定平台的文件.so或者.a。好消息是，NDK高版本中提供了Windows下开发套件的支持，cygwin可以不使用，直接在Windows下平台编译也是可行的，但是为了显示学习，最好还是需要了解一点的。\n二、NDK环境搭建 1，安装CDT 如果是使用的是从Android Develop官网上下载的集成了ADT一整套的IDE的话，请跳过这一步，因为ADT中已经集成好了CDT插件，直接使用就可以了。如果使用的是传统的Eclipse自装插件的方式的话，有两种方式可供安装CDT。 （1）下载CDT插件进行安装。在Eclipse社区官网可以找到下载链接[https://eclipse.org/cdt/](https://eclipse.org/cdt/)。 （2）在线安装。步骤如下： ![](http://img.blog.csdn.net/20141208123341295?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 选择 Helios- http：//download.eclipse.org/release/helios ，等待展开，选择Programing language![](http://img.blog.csdn.net/20141208123356255?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 选择c/c++ 开发工具 ![](http://img.blog.csdn.net/20141208123530245?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 一路next下去，同意licenses。 安装成功会提示是不是确认重启eclipse，重启就完成安装。 2，安装cygwin NDK需要运行在linux环境下，cygwin是windows下模拟linux的一个工具。Cygwin是一个程序，支持很多插件。可以去cygwin的官网上下载[http://www.cygwin.com/](http://www.cygwin.com/)双击安装，也可以从CSDN资源页上下载我上传的资料包，里面包含cygwin的安装程序和安装包，地址是：[**http://download.csdn.net/detail/lee_tianya/8235323**](http://download.csdn.net/detail/lee_tianya/8235323) ![](http://img.blog.csdn.net/20141208123919847?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 选择安装方式请注意了，一般可以选择从Internet上在线安装，不过速度很慢，而且中途不能断开，如果网速不好中途断开了，那么就必须从头开始下载，非常不舒服。第二种方式是本地安装，先下载好安装所需要的文件放在本地磁盘上，然后选择安装目录即可，我这里是本地安装。 ![](http://img.blog.csdn.net/20141208124337699?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 选择安装目录的时候请注意：安装目录不可以出现空格，最好不要出现中文等非英文字符。 ![](http://img.blog.csdn.net/20141208124346984?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) ![](http://img.blog.csdn.net/20141208125609296?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) ![](http://img.blog.csdn.net/20141208124405530?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) ![](http://img.blog.csdn.net/20141208124412300?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 安装完毕后 ,桌面会出现一个快捷图标，双击快捷小图标，打开cygwin。 首先程序会初始化 ![](http://img.blog.csdn.net/20141208130726968?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 敲入命令 Make –v ![](http://img.blog.csdn.net/20141208130742387?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 显示出来 GNU Make 的版本 ,说明我们的cygwin模拟的linux编译环境 模拟成功了. 3，安装NDK 首先翻墙上Google Android Develop的官网去下载NDK，地址是**[http://developer.android.com/tools/sdk/ndk/index.html](http://developer.android.com/tools/sdk/ndk/index.html)** **![](http://img.blog.csdn.net/20141208131837421?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) **\n我这里选用的Windows版本64位的r10d版本的ndk，是当前最新版本，android-ndk-r10d-windows-x86_64.exe，下载完成后点击exe文件，会自定解压到当前目录下，这个过程比较漫长，可见升级造成安装的过大啊，好，解压完毕之后我移动E:/NDK目录下了。 做完上面的一些步骤后，环境基本上是搭建完成了，现在我们使用cygwin模拟Linux环境下，进入Windows路径E:/NDK/android-ndk-r10d下，执行ndk-build脚本。 第一步：进入根目录找到根目录下的cygdrive文件，该文件对应的是Windows下的所有盘符： ![](http://img.blog.csdn.net/20141208134637555?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 第二步：进入ndk所在目录： ![](http://img.blog.csdn.net/20141208135338459?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 第三步：执行ndk-build脚本 ![](http://img.blog.csdn.net/20141208135407671?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 通过上面的步骤，我们就可以使用ndk-build脚本了，但是这样的过程是在是太繁琐了，使用起来是非常的不方便，那么下面我们来使用一下简便的方法吧，配置文件。 为了方便直接在命令行里面使用ndk-build，需要给cygwin的环境变量里面添加ndk的目录 首先 我们在cygwin安装的目录下找到etc/profile文件，这个文件就是cygwin的配置文件，用记事本打开这个文件，找到如下一行： ![](http://img.blog.csdn.net/20141208140248189?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 然后 我们在cygwin的控制台上找到ndk的解压路径 ![](http://img.blog.csdn.net/20141208140340776?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 接下来 我们复制这个路径到Path中，注意Linux环境变量中的路径分割使用英文冒号“:”来区分 ![](http://img.blog.csdn.net/20141208140539093?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 最后 检测是否配置完成，在cygwin控制台下输入“ndk-build”命令 ![](http://img.blog.csdn.net/20141208140637046?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 若命令行显示的是如上图所示的信息，说明配置完成了，可以使用了，若不是这种情况，请根据文章的描述再进行一次配置。 好了，NDK开发中的环境搭建到此就结束了，下面就可以使用NDK环境来开发了，关于NDK开发，后续的文章会慢慢介绍。 转自：http://blog.csdn.net/allen315410/article/details/41800955 ","permalink":"https://blog.zdltech.com/posts/android-ndk%E5%BC%80%E5%8F%91%E4%B8%80-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/","summary":"\u003cp\u003eAndroid下的NDK开发是Android开发中不可或缺的一部分，通过Google提供的NDK套件，我们可以使用JNI这座桥梁在Java和C/C++之间建立联系（互相调用）。那么，为什么在Android开发中需要了解NDK开发呢？诚然，这些原因有很多说法，在我总结来是这样的。C/C++是比Java还要古老的编程语言，由于其古老的特性，导致早期有很多优秀的类库出现，譬如处理视频编解码的FFMPEG类库，这些复杂的类库早就被C/C++编写过，我们在处理视频编解码的时候没必要重复“造轮子”，所以能直接拿来用的就直接拿来用，但是这个直接法很难做到，因为Java的编译环境的原理跟C/C++的不同，所以就必须找个中间者为Java和C/C++代码建立关系，这个中间者就是JNI。还有一个重要的原因就是效率问题，Java是跨平台的语言，在不同的平台有不同的JVM实现，Java源码需要首先编译成.class文件，然后让.class文件运行在不同的JVM解释执行上，这样的步骤造成了效率的浪费，而不同的是C/C++，可以直接编译成特定平台的二进制文件，直接运行在特定平台上，效率比Java高效很多，所以在某些特定的环境下，还是需要使用C/C++来解决效率问题，Java只负责处理C/C++返回来的结果就可以，这样的话Java和C/C++互调就显得相当重要了。\u003c/p\u003e\n\u003cp\u003e做NDK开发前最好需要了解一下C/C++的语法，通常这部分的代码不需要Android程序员编写，但是Android程序员最好能看懂C/C++源码，这样做会事半功倍一点，关于C/C++语法的学习不是这里的重点，大家感兴趣的话可以直接找资料学习，请从柜底抽出大学教材《C语言程序设计——谭浩强》，拍拍上面的灰尘，随便过一遍^.^\u003c/p\u003e\n\u003ch2 id=\"一明确一些基本概念\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003e一、明确一些基本概念\u003c/h2\u003e\n\u003ch4 id=\"1jni\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e1，JNI\u003c/h4\u003e\n\u003cp\u003eJava Native Interface Java 本地开发的接口。JNI 是一个协议,这个协议用来沟通java代码和外部的本地代码(c/c++)。通过这个协议,java代码就可以调用外部的c/c++代码，外部的c/c++代码也可以调用java代码。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20141208112349333?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20141208112426046?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003ch4 id=\"2cdt\"\u003e\u003ca name=\"t2\"\u003e\u003c/a\u003e2，CDT\u003c/h4\u003e\n\u003cp\u003eC/C++ Develop tools，C/C++开发工具。是Eclipse上的一个插件，主要是让C/C++代码能够高亮显示。这个组件不是必要的，除非你是C/C++高手，喜欢在记事本上写代码，对于一般的程序员还是装一下吧，高亮显示很重要的。\u003c/p\u003e\n\u003ch4 id=\"3ndk\"\u003e\u003ca name=\"t3\"\u003e\u003c/a\u003e3，NDK\u003c/h4\u003e\n\u003cp\u003eNative Develop Kits，本地开发套件。这个套件是非常重要的，是Google提供给我们的一个在Android上开发JNI程序的工具集，有了它会使得开发高效的多。\u003c/p\u003e\n\u003ch4 id=\"4cygwin\"\u003e\u003ca name=\"t4\"\u003e\u003c/a\u003e4，cygwin\u003c/h4\u003e\n\u003cp\u003eWindows下的Linux模拟器。大家知道Android是基于Linux内核的操作系统，所以在编译C/C++源码的使用得使用Linux环境，将其编译成Linux特定平台的文件.so或者.a。好消息是，NDK高版本中提供了Windows下开发套件的支持，cygwin可以不使用，直接在Windows下平台编译也是可行的，但是为了显示学习，最好还是需要了解一点的。\u003c/p\u003e\n\u003ch2 id=\"二ndk环境搭建\"\u003e\u003ca name=\"t5\"\u003e\u003c/a\u003e二、NDK环境搭建\u003c/h2\u003e\n\u003ch4 id=\"1安装cdt\"\u003e\u003ca name=\"t6\"\u003e\u003c/a\u003e1，安装CDT\u003c/h4\u003e\n\u003cdiv\u003e\n        如果是使用的是从Android Develop官网上下载的集成了ADT一整套的IDE的话，请跳过这一步，因为ADT中已经集成好了CDT插件，直接使用就可以了。如果使用的是传统的Eclipse自装插件的方式的话，有两种方式可供安装CDT。\n\u003c/div\u003e\n\u003cdiv\u003e\n  （1）下载CDT插件进行安装。在Eclipse社区官网可以找到下载链接[https://eclipse.org/cdt/](https://eclipse.org/cdt/)。\n\u003c/div\u003e\n\u003cdiv\u003e\n  （2）在线安装。步骤如下：\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20141208123341295?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n  选择 Helios- http：//download.eclipse.org/release/helios ，等待展开，选择Programing language![](http://img.blog.csdn.net/20141208123356255?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e选择c/c++ 开发工具\n\n\n\n\n\n![](http://img.blog.csdn.net/20141208123530245?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e一路next下去，同意licenses。\n\n\n\n\n\n安装成功会提示是不是确认重启eclipse，重启就完成安装。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003ch4 id=\"2安装cygwin\"\u003e\u003ca name=\"t7\"\u003e\u003c/a\u003e2，安装cygwin\u003c/h4\u003e\n\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e      NDK需要运行在linux环境下，cygwin是windows下模拟linux的一个工具。Cygwin是一个程序，支持很多插件。可以去cygwin的官网上下载[http://www.cygwin.com/](http://www.cygwin.com/)双击安装，也可以从CSDN资源页上下载我上传的资料包，里面包含cygwin的安装程序和安装包，地址是：[**http://download.csdn.net/detail/lee_tianya/8235323**](http://download.csdn.net/detail/lee_tianya/8235323)\n\n\n\n\n\n![](http://img.blog.csdn.net/20141208123919847?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n          选择安装方式请注意了，一般可以选择从Internet上在线安装，不过速度很慢，而且中途不能断开，如果网速不好中途断开了，那么就必须从头开始下载，非常不舒服。第二种方式是本地安装，先下载好安装所需要的文件放在本地磁盘上，然后选择安装目录即可，我这里是本地安装。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20141208124337699?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  选择安装目录的时候请注意：安装目录不可以出现空格，最好不要出现中文等非英文字符。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20141208124346984?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20141208125609296?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20141208124405530?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20141208124412300?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e安装完毕后 ,桌面会出现一个快捷图标，双击快捷小图标，打开cygwin。\n\n\n\n\n\n首先程序会初始化\n\n\n\n\n\n![](http://img.blog.csdn.net/20141208130726968?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\n\n\n\n\n敲入命令\n\n\n\n\n\nMake –v\n\n\n\n\n\n![](http://img.blog.csdn.net/20141208130742387?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\n\n\n\n\n显示出来 GNU Make 的版本 ,说明我们的cygwin模拟的linux编译环境 模拟成功了.\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4 id=\"3安装ndk\"\u003e\u003ca name=\"t8\"\u003e\u003c/a\u003e3，安装NDK\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e首先翻墙上Google Android Develop的官网去下载NDK，地址是**[http://developer.android.com/tools/sdk/ndk/index.html](http://developer.android.com/tools/sdk/ndk/index.html)**\n\n\n\n\n\n**![](http://img.blog.csdn.net/20141208131837421?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWxsZW4zMTU0MTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e**\u003c/p\u003e","title":"Android NDK开发(一)——环境搭建"},{"content":"This is a custom component for Android intended for use instead of a progress bar. {#user-content-a-complete-walkthrough-of-how-to-use-this-component-in-your-app.anchor}A complete walkthrough of how to use this component in your app XML:\nTo implement the view in your xml layout do the following:\nAdd the following to your attrs.xml file (in res/values): ``` \u0026lt;declare-styleable name=\"ProgressWheel\"\u0026gt; \u0026lt;attr name=\"text\" format=\"string\" /\u0026gt; \u0026lt;attr name=\"textColor\" format=\"color\" /\u0026gt; \u0026lt;attr name=\"textSize\" format=\"dimension\" /\u0026gt; \u0026lt;attr name=\"barColor\" format=\"color\" /\u0026gt; \u0026lt;attr name=\"rimColor\" format=\"color\" /\u0026gt; \u0026lt;attr name=\"rimWidth\" format=\"dimension\" /\u0026gt; \u0026lt;attr name=\"spinSpeed\" format=\"integer\" /\u0026gt; \u0026lt;attr name=\"circleColor\" format=\"color\" /\u0026gt; \u0026lt;attr name=\"radius\" format=\"dimension\" /\u0026gt; \u0026lt;attr name=\"barWidth\" format=\"dimension\" /\u0026gt; \u0026lt;attr name=\"barLength\" format=\"dimension\" /\u0026gt; \u0026lt;attr name=\"delayMillis\" format=\"dimension\"/\u0026gt; \u0026lt;attr name=\"contourColor\" format=\"color\"/\u0026gt; \u0026lt;attr name=\"contourSize\" format=\"float\"/\u0026gt; \u0026lt;/declare-styleable\u0026gt; ``` Add the following code to the root view of your layout:xmlns:ProgressWheel=\u0026quot;http://schemas.android.com/apk/res/com.visualdenim.schooltraq\u0026quot;\nAdd the widget code in the appropriate place in your xml file. Here’s a sample implementation:\n``` \u0026lt;com.todddavies.components.progressbar.ProgressWheel android:id=\"@+id/pw_spinner\" android:layout_width=\"200dp\" android:layout_height=\"200dp\" android:layout_centerInParent=\"true\" ProgressWheel:text=\"Authenticating...\" ProgressWheel:textColor=\"#222\" ProgressWheel:textSize=\"14sp\" ProgressWheel:rimColor=\"#330097D6\" ProgressWheel:barLength=\"60dp\" ProgressWheel:barColor=\"#0097D6\" ProgressWheel:barWidth=\"5dp\" ProgressWheel:rimWidth=\"2dp\" /\u0026gt; ``` Java:\nFirst you need to either get a ProgressWheel from a layout file, or initalise one. Do this by:\nProgressWheel pw = new ProgressWheel(myContext, myAttributes);\nProgressWheel pw = (ProgressWheel) findViewById(R.id.pw_spinner);\nTo spin the progress wheel, you just call .spin() and to stop it spinning, you call .stopSpinning()\nIncrementing the progress wheel is slightly more tricky, you call .incrementProgress(). However, this is out of 360,\n(because a circle has 360 degrees), and will automatically reset once you get past 360. A percentage display is\nautomatically displayed.\n{#user-content-using-as-a-library-project.anchor}Using as a library project To use it as a library in Android Studio, please edit build.gradle.\nModify:\napply plugin: 'android' Into:\napply plugin: 'android-library' Since Android SDK Tools revision 17 (released March 2012), this component can be used as a library project. In this case, you do not need to copy anything into your project’s attrs.xml, and you must use the following namespace URI, instead of the above:\nxmlns:ProgressWheel=\u0026quot;http://schemas.android.com/apk/res-auto\u0026quot;\nOtherwise, usage should be the same.\ngithub：https://github.com/Todd-Davies/ProgressWheel\n","permalink":"https://blog.zdltech.com/posts/%E5%9C%86%E5%BD%A2%E8%BF%9B%E5%BA%A6progresswheel/","summary":"\u003ch1 id=\"this-is-a-custom-component-for-android-intended-for-use-instead-of-a-progress-bar\"\u003eThis is a custom component for Android intended for use instead of a progress bar.\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"http://www.etongwl.com/images/2015/01/sample_image.png\"\u003e\u003cimg alt=\"sample_image\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2015/01/sample_image.png\"\u003e\u003c/a\u003e \u003ca href=\"http://www.etongwl.com/images/2015/01/sample_image_2.png\"\u003e\u003cimg alt=\"sample_image_2\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2015/01/sample_image_2.png\"\u003e\u003c/a\u003e \u003ca href=\"http://www.etongwl.com/images/2015/01/sample_image_3.png\"\u003e\u003cimg alt=\"sample_image_3\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2015/01/sample_image_3.png\"\u003e\u003c/a\u003e \u003ca href=\"http://www.etongwl.com/images/2015/01/sample_image_4.png\"\u003e\u003cimg alt=\"sample_image_4\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2015/01/sample_image_4.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"user-content-a-complete-walkthrough-of-how-to-use-this-component-in-your-appanchora-complete-walkthrough-of-how-to-use-this-component-in-your-app\"\u003e\u003ca href=\"https://github.com/Todd-Davies/ProgressWheel#a-complete-walkthrough-of-how-to-use-this-component-in-your-app\"\u003e\u003c/a\u003e{#user-content-a-complete-walkthrough-of-how-to-use-this-component-in-your-app.anchor}A complete walkthrough of how to use this component in your app\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eXML:\u003c/strong\u003e\u003cbr\u003e\nTo implement the view in your xml layout do the following:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAdd the following to your attrs.xml file (in res/values):\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight highlight-xml\"\u003e\n  ```\n\u0026lt;\u003cspan class=\"pl-ent\"\u003edeclare-styleable\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eProgressWheel\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\u0026gt;   \n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003etext\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003estring\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e /\u0026gt;   \n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003etextColor\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ecolor\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e /\u0026gt;   \n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003etextSize\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003edimension\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e /\u0026gt;   \n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ebarColor\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ecolor\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e /\u0026gt;   \n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003erimColor\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ecolor\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e /\u0026gt;   \n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003erimWidth\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003edimension\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e /\u0026gt;   \n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003espinSpeed\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003einteger\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e /\u0026gt;     \n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ecircleColor\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ecolor\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e /\u0026gt;     \n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eradius\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003edimension\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e /\u0026gt;   \n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ebarWidth\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003edimension\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e /\u0026gt;   \n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ebarLength\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003edimension\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e /\u0026gt;\n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003edelayMillis\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003edimension\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e/\u0026gt;\n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003econtourColor\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ecolor\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e/\u0026gt;\n    \u0026lt;\u003cspan class=\"pl-ent\"\u003eattr\u003c/span\u003e \u003cspan class=\"pl-e\"\u003ename\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003econtourSize\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eformat\u003c/span\u003e=\u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003efloat\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e/\u0026gt;\n\u0026lt;/\u003cspan class=\"pl-ent\"\u003edeclare-styleable\u003c/span\u003e\u0026gt;\n```\n\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eAdd the following code to the root view of your layout:\u003ccode\u003exmlns:ProgressWheel=\u0026quot;http://schemas.android.com/apk/res/com.visualdenim.schooltraq\u0026quot;\u003c/code\u003e\u003c/p\u003e","title":"圆形进度（ProgressWheel）"},{"content":" 一个应用被用户卸载肯定是有理由的，而开发者却未必能得知这一重要的理由，毕竟用户很少会主动反馈建议，多半就是用得不爽就卸，如果能在被卸载后获取到用户的一些反馈，那对开发者进一步改进应用是非常有利的。目前据我所知，国内的Android应用中实现这一功能的只有360手机卫士、360平板卫士，那么如何实现这一功能的？ 我们可以把实现卸载反馈的问题转化为监听自己是否被卸载，只有得知自己被卸载，才可以设计相应的反馈处理流程。以下的列表是我在研究这一问题的思路： 1，注册BroadcastReceiver，监听\u0026amp;#8221;android.intent.action.PACKAGE_REMOVED\u0026amp;#8221;系统广播 结果：NO。未写代码，直接分析，卸载的第一步就是退出当前应用的主进程，而此广播是在已经卸载完成后才发出的，此时主进程都没有了，去哪onReceive()呢？ 2，若能收到\u0026amp;#8221;将要卸载XX包\u0026amp;#8221;的系统广播，在主进程被退出之前就抢先进行反馈处理就好了，可惜没有这样的系统广播，不过经过调研，倒是发现了一个办法，读取系统log，当日志中包含\u0026amp;#8221;android.intent.action.DELETE\u0026amp;#8221;和自己的包名时，意味着自己将要被卸载。 结果：NO。调试时发现此方法有两个缺陷，（1）点击设置中的卸载按钮即发出此Intent，此时用户尚未在弹框中确认卸载；（2）pm命令卸载不出发此Intent，意味着被诸如手机安全管家，豌豆荚等软件卸载时，无法提前得知卸载意图。 3，由于时间点不容易把控，所以干脆不依赖系统广播或log，考虑到卸载过程会删除\u0026amp;#8221;/data/data/包名\u0026amp;#8221;目录，我们可以用线程直接轮询这个目录是否存在，以此为依据判断自己是否被卸载。 结果：NO。同方法1，主进程退出，相应的线程必定退出，线程还没等到判断目录是否存在就已经被销毁了。 4，改用C端进程轮询\u0026amp;#8221;/data/data/包名\u0026amp;#8221;目录是否存在 结果：YES。借助Java端进程fork出来的C端进程在应用被卸载后不会被销毁。 OK，上代码！ Activity启动时fork出C端进程轮询目录： ![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` 1 package main.activity; 2 3 import pym.test.uninstalledmoniter.R; 4 import android.app.Activity; 5 import android.os.Bundle; 6 import android.util.Log; 7 8 /** 9 * @author pengyiming 10 * @note 监听此应用是否被卸载，若被卸载则弹出卸载反馈 11 * 12 / 13 14 public class UninstalledMoniterActivity extends Activity 15 { 16 / 数据段begin / 17 private static final String TAG = \u0026ldquo;UninstalledMoniterActivity\u0026rdquo;; 18 / 数据段end / 19 20 / 函数段begin / 21 private native void init(); 22 static 23 { 24 Log.d(TAG, \u0026ldquo;load libuninstalled_moniter\u0026rdquo;); 25 System.loadLibrary(\u0026ldquo;uninstalled_moniter\u0026rdquo;); 26 } 27 28 @Override 29 public void onCreate(Bundle savedInstanceState) 30 { 31 super.onCreate(savedInstanceState); 32 Log.d(TAG, \u0026ldquo;onCreate\u0026rdquo;); 33 34 setContentView(R.layout.uninstalled_moniter_layout); 35 36 init(); 37 } 38 / 函数段end */ 39 }\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 核心——native方法头文件： \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ``` 1 /* 头文件begin */ 2 #include \u0026amp;lt;jni.h\u0026amp;gt; 3 #include \u0026amp;lt;stdio.h\u0026amp;gt; 4 #include \u0026amp;lt;string.h\u0026amp;gt; 5 #include \u0026amp;lt;android/log.h\u0026amp;gt; 6 #include \u0026amp;lt;unistd.h\u0026amp;gt; 7 /* 头文件end */ 8 9 /* 宏定义begin */ 10 //清0宏 11 #define MEM_ZERO(pDest, destSize) memset(pDest, 0, destSize) 12 13 //LOG宏定义 14 #define LOG_INFO(tag, msg) __android_log_write(ANDROID_LOG_INFO, tag, msg) 15 #define LOG_DEBUG(tag, msg) __android_log_write(ANDROID_LOG_DEBUG, tag, msg) 16 #define LOG_WARN(tag, msg) __android_log_write(ANDROID_LOG_WARN, tag, msg) 17 #define LOG_ERROR(tag, msg) __android_log_write(ANDROID_LOG_ERROR, tag, msg) 18 /* 宏定义end */ 19 20 #ifndef _Included_main_activity_UninstalledMoniterActivity 21 #define _Included_main_activity_UninstalledMoniterActivity 22 #ifdef __cplusplus 23 extern \u0026#34;C\u0026#34; { 24 #endif 25 26 #undef main_activity_UninstalledMoniterActivity_MODE_PRIVATE 27 #define main_activity_UninstalledMoniterActivity_MODE_PRIVATE 0L 28 #undef main_activity_UninstalledMoniterActivity_MODE_WORLD_READABLE 29 #define main_activity_UninstalledMoniterActivity_MODE_WORLD_READABLE 1L 30 #undef main_activity_UninstalledMoniterActivity_MODE_WORLD_WRITEABLE 31 #define main_activity_UninstalledMoniterActivity_MODE_WORLD_WRITEABLE 2L 32 #undef main_activity_UninstalledMoniterActivity_MODE_APPEND 33 #define main_activity_UninstalledMoniterActivity_MODE_APPEND 32768L 34 #undef main_activity_UninstalledMoniterActivity_MODE_MULTI_PROCESS 35 #define main_activity_UninstalledMoniterActivity_MODE_MULTI_PROCESS 4L 36 #undef main_activity_UninstalledMoniterActivity_BIND_AUTO_CREATE 37 #define main_activity_UninstalledMoniterActivity_BIND_AUTO_CREATE 1L 38 #undef main_activity_UninstalledMoniterActivity_BIND_DEBUG_UNBIND 39 #define main_activity_UninstalledMoniterActivity_BIND_DEBUG_UNBIND 2L 40 #undef main_activity_UninstalledMoniterActivity_BIND_NOT_FOREGROUND 41 #define main_activity_UninstalledMoniterActivity_BIND_NOT_FOREGROUND 4L 42 #undef main_activity_UninstalledMoniterActivity_BIND_ABOVE_CLIENT 43 #define main_activity_UninstalledMoniterActivity_BIND_ABOVE_CLIENT 8L 44 #undef main_activity_UninstalledMoniterActivity_BIND_ALLOW_OOM_MANAGEMENT 45 #define main_activity_UninstalledMoniterActivity_BIND_ALLOW_OOM_MANAGEMENT 16L 46 #undef main_activity_UninstalledMoniterActivity_BIND_WAIVE_PRIORITY 47 #define main_activity_UninstalledMoniterActivity_BIND_WAIVE_PRIORITY 32L 48 #undef main_activity_UninstalledMoniterActivity_BIND_IMPORTANT 49 #define main_activity_UninstalledMoniterActivity_BIND_IMPORTANT 64L 50 #undef main_activity_UninstalledMoniterActivity_BIND_ADJUST_WITH_ACTIVITY 51 #define main_activity_UninstalledMoniterActivity_BIND_ADJUST_WITH_ACTIVITY 128L 52 #undef main_activity_UninstalledMoniterActivity_CONTEXT_INCLUDE_CODE 53 #define main_activity_UninstalledMoniterActivity_CONTEXT_INCLUDE_CODE 1L 54 #undef main_activity_UninstalledMoniterActivity_CONTEXT_IGNORE_SECURITY 55 #define main_activity_UninstalledMoniterActivity_CONTEXT_IGNORE_SECURITY 2L 56 #undef main_activity_UninstalledMoniterActivity_CONTEXT_RESTRICTED 57 #define main_activity_UninstalledMoniterActivity_CONTEXT_RESTRICTED 4L 58 #undef main_activity_UninstalledMoniterActivity_RESULT_CANCELED 59 #define main_activity_UninstalledMoniterActivity_RESULT_CANCELED 0L 60 #undef main_activity_UninstalledMoniterActivity_RESULT_OK 61 #define main_activity_UninstalledMoniterActivity_RESULT_OK -1L 62 #undef main_activity_UninstalledMoniterActivity_RESULT_FIRST_USER 63 #define main_activity_UninstalledMoniterActivity_RESULT_FIRST_USER 1L 64 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_DISABLE 65 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_DISABLE 0L 66 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_DIALER 67 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_DIALER 1L 68 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SHORTCUT 69 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SHORTCUT 2L 70 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SEARCH_LOCAL 71 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L 72 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SEARCH_GLOBAL 73 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L 74 75 /* 76 * Class: main_activity_UninstalledMoniterActivity 77 * Method: init 78 * Signature: ()V 79 */ 80 JNIEXPORT void JNICALL Java_main_activity_UninstalledMoniterActivity_init(JNIEnv *, jobject); 81 82 #ifdef __cplusplus 83 } 84 #endif 85 #endif \u0026lt;div class=\u0026quot;cnblogs_code_toolbar\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_copy\u0026quot;\u0026gt;\u0026lt;a title=\u0026quot;复制代码\u0026quot;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 核心——native方法实现： ![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` 1 /* 头文件begin / 2 #include \u0026ldquo;main_activity_UninstalledMoniterActivity.h\u0026rdquo; 3 / 头文件end / 4 5 #ifdef __cplusplus 6 extern \u0026ldquo;C\u0026rdquo; { 7 #endif 8 9 / 内全局变量begin / 10 static char c_TAG[] = \u0026ldquo;UninstalledMoniterActivity.init\u0026rdquo;; 11 static jboolean b_IS_COPY = JNI_TRUE; 12 / 内全局变量 / 13 14 / 15 * Class: main_activity_UninstalledMoniterActivity 16 * Method: init 17 * Signature: ()V 18 */ 19 JNIEXPORT void JNICALL Java_main_activity_UninstalledMoniterActivity_init(JNIEnv *env, jobject obj) 20 { 21 jstring tag = (*env)-\u0026gt;NewStringUTF(env, c_TAG); 22 23 //初始化log 24 LOG_DEBUG((*env)-\u0026gt;GetStringUTFChars(env, tag, \u0026amp;b_IS_COPY) 25 , (*env)-\u0026gt;GetStringUTFChars(env, (*env)-\u0026gt;NewStringUTF(env, \u0026ldquo;init OK\u0026rdquo;), \u0026amp;b_IS_COPY)); 26 27 //fork子进程，以执行轮询任务 28 pid_t pid = fork(); 29 if (pid \u0026lt; 0) 30 { 31 //出错log 32 LOG_ERROR((*env)-\u0026gt;GetStringUTFChars(env, tag, \u0026amp;b_IS_COPY) 33 , (*env)-\u0026gt;GetStringUTFChars(env, (*env)-\u0026gt;NewStringUTF(env, \u0026ldquo;fork error !!!\u0026rdquo;), \u0026amp;b_IS_COPY)); 34 } 35 else if (pid == 0) 36 { 37 //子进程轮询\u0026quot;/data/data/pym.test.uninstalledmoniter\u0026quot;目录是否存在，若不存在则说明已被卸载 38 while (1) 39 { 40 FILE *p_file = fopen(\u0026quot;/data/data/pym.test.uninstalledmoniter\u0026quot;, \u0026ldquo;r\u0026rdquo;); 41 if (p_file != NULL) 42 { 43 fclose(p_file); 44 45 //目录存在log 46 LOG_DEBUG((*env)-\u0026gt;GetStringUTFChars(env, tag, \u0026amp;b_IS_COPY) 47 , (*env)-\u0026gt;GetStringUTFChars(env, (*env)-\u0026gt;NewStringUTF(env, \u0026ldquo;I\u0026rsquo;m OK !!!\u0026rdquo;), \u0026amp;b_IS_COPY)); 48 49 sleep(1); 50 } 51 else 52 { 53 //目录不存在log 54 LOG_DEBUG((*env)-\u0026gt;GetStringUTFChars(env, tag, \u0026amp;b_IS_COPY) 55 , (*env)-\u0026gt;GetStringUTFChars(env, (*env)-\u0026gt;NewStringUTF(env, \u0026ldquo;I\u0026rsquo;m NOT OK !!!\u0026rdquo;), \u0026amp;b_IS_COPY)); 56 57 //执行命令am start -a android.intent.action.VIEW -d http://shouji.360.cn/web/uninstall/uninstall.html 58 execlp(\u0026ldquo;am\u0026rdquo;, \u0026ldquo;am\u0026rdquo;, \u0026ldquo;start\u0026rdquo;, \u0026ldquo;-a\u0026rdquo;, \u0026ldquo;android.intent.action.VIEW\u0026rdquo;, \u0026ldquo;-d\u0026rdquo;, \u0026ldquo;http://shouji.360.cn/web/uninstall/uninstall.html\u0026quot;, (char *)NULL); 59 } 60 } 61 } 62 else 63 { 64 //父进程直接退出，使子进程被init进程领养，以避免子进程僵死 65 } 66 } 67 68 #ifdef __cplusplus 69 } 70 #endif\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 注1：为了调试方便，包含\u0026lt;android/log.h\u0026gt;，使得so在执行过程中也可以像Java端一样方便得打出log。相应的mk文件需要加上以下两句声明 LOCAL_C_INCLUDES := \u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(LOCAL_PATH)/include LOCAL_LDLIBS += -L\u0026lt;/span\u0026gt;(SYSROOT)/usr/lib -llog 注2：代码中引用了360手机卫士的反馈地址，仅供大家学习、测试使用~~~ 转自：http://www.cnblogs.com/zealotrouge/p/3157126.html \u0026amp;nbsp; # [Android应用如何监听自己是否被卸载及卸载反馈功能的实现（第二版）](http://www.cnblogs.com/zealotrouge/p/3159772.html) \u0026amp;nbsp; \u0026lt;div id=\u0026#34;cnblogs_post_body\u0026#34;\u0026gt; 昨天发了一篇有关监听自己是否被卸载和卸载反馈功能实现的博客，地址如下：[http://www.cnblogs.com/zealotrouge/p/3157126.html](http://www.cnblogs.com/zealotrouge/p/3157126.html)，发出去后收到几位热心网友的建议，在此特别感谢@cccode @泡泡糖 @Alexia(minmin) @0x00.pl ，你们的建议就是我前进的动力。 昨天的技术方案有一个硬伤，就是每1s就需要轮询目录是否存在，对资源消耗较大，第二版将会解决这一问题。思路是今天想到了一个Android自API1就有的一个类FileObserver，这个类用于监听某个文件的变化状态，如果是目录，这个类还可以监听其子目录及子目录文件的变化状态，通过阅读FileObserver源码，发现其实现利用了Linux内核中一个重要的机制inotify，它是一个内核用于通知用户空间程序文件系统变化的机制，详情可参考[http://en.wikipedia.org/wiki/Inotify](http://en.wikipedia.org/wiki/Inotify)，里面对inotify有比较详细的说明。 使用inotify的好处就在于不需要每1s的轮询，这样就不会无谓地消耗系统资源，使用inotify时会用read()方法阻塞进程，直到收到IN_DELETE通知，此时进程重新被唤醒，执行反馈处理流程。 由于Activity代码和Android.mk文件和第一版并无实质性区别，这里就不贴代码了，直接贴出C端进程的实现代码吧。 核心——native方法头文件： \u0026amp;nbsp; \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ``` 1 /* 头文件begin */ 2 #include \u0026amp;lt;jni.h\u0026amp;gt; 3 #include \u0026amp;lt;stdlib.h\u0026amp;gt; 4 #include \u0026amp;lt;stdio.h\u0026amp;gt; 5 #include \u0026amp;lt;string.h\u0026amp;gt; 6 #include \u0026amp;lt;android/log.h\u0026amp;gt; 7 #include \u0026amp;lt;unistd.h\u0026amp;gt; 8 #include \u0026amp;lt;sys/inotify.h\u0026amp;gt; 9 #include \u0026amp;lt;fcntl.h\u0026amp;gt; 10 /* 头文件end */ 11 12 /* 宏定义begin */ 13 //清0宏 14 #define MEM_ZERO(pDest, destSize) memset(pDest, 0, destSize) 15 16 //LOG宏定义 17 #define LOG_INFO(tag, msg) __android_log_write(ANDROID_LOG_INFO, tag, msg) 18 #define LOG_DEBUG(tag, msg) __android_log_write(ANDROID_LOG_DEBUG, tag, msg) 19 #define LOG_WARN(tag, msg) __android_log_write(ANDROID_LOG_WARN, tag, msg) 20 #define LOG_ERROR(tag, msg) __android_log_write(ANDROID_LOG_ERROR, tag, msg) 21 /* 宏定义end */ 22 23 #ifndef _Included_main_activity_UninstalledObserverActivity 24 #define _Included_main_activity_UninstalledObserverActivity 25 #ifdef __cplusplus 26 extern \u0026#34;C\u0026#34; { 27 #endif 28 29 #undef main_activity_UninstalledObserverActivity_MODE_PRIVATE 30 #define main_activity_UninstalledObserverActivity_MODE_PRIVATE 0L 31 #undef main_activity_UninstalledObserverActivity_MODE_WORLD_READABLE 32 #define main_activity_UninstalledObserverActivity_MODE_WORLD_READABLE 1L 33 #undef main_activity_UninstalledObserverActivity_MODE_WORLD_WRITEABLE 34 #define main_activity_UninstalledObserverActivity_MODE_WORLD_WRITEABLE 2L 35 #undef main_activity_UninstalledObserverActivity_MODE_APPEND 36 #define main_activity_UninstalledObserverActivity_MODE_APPEND 32768L 37 #undef main_activity_UninstalledObserverActivity_MODE_MULTI_PROCESS 38 #define main_activity_UninstalledObserverActivity_MODE_MULTI_PROCESS 4L 39 #undef main_activity_UninstalledObserverActivity_BIND_AUTO_CREATE 40 #define main_activity_UninstalledObserverActivity_BIND_AUTO_CREATE 1L 41 #undef main_activity_UninstalledObserverActivity_BIND_DEBUG_UNBIND 42 #define main_activity_UninstalledObserverActivity_BIND_DEBUG_UNBIND 2L 43 #undef main_activity_UninstalledObserverActivity_BIND_NOT_FOREGROUND 44 #define main_activity_UninstalledObserverActivity_BIND_NOT_FOREGROUND 4L 45 #undef main_activity_UninstalledObserverActivity_BIND_ABOVE_CLIENT 46 #define main_activity_UninstalledObserverActivity_BIND_ABOVE_CLIENT 8L 47 #undef main_activity_UninstalledObserverActivity_BIND_ALLOW_OOM_MANAGEMENT 48 #define main_activity_UninstalledObserverActivity_BIND_ALLOW_OOM_MANAGEMENT 16L 49 #undef main_activity_UninstalledObserverActivity_BIND_WAIVE_PRIORITY 50 #define main_activity_UninstalledObserverActivity_BIND_WAIVE_PRIORITY 32L 51 #undef main_activity_UninstalledObserverActivity_BIND_IMPORTANT 52 #define main_activity_UninstalledObserverActivity_BIND_IMPORTANT 64L 53 #undef main_activity_UninstalledObserverActivity_BIND_ADJUST_WITH_ACTIVITY 54 #define main_activity_UninstalledObserverActivity_BIND_ADJUST_WITH_ACTIVITY 128L 55 #undef main_activity_UninstalledObserverActivity_CONTEXT_INCLUDE_CODE 56 #define main_activity_UninstalledObserverActivity_CONTEXT_INCLUDE_CODE 1L 57 #undef main_activity_UninstalledObserverActivity_CONTEXT_IGNORE_SECURITY 58 #define main_activity_UninstalledObserverActivity_CONTEXT_IGNORE_SECURITY 2L 59 #undef main_activity_UninstalledObserverActivity_CONTEXT_RESTRICTED 60 #define main_activity_UninstalledObserverActivity_CONTEXT_RESTRICTED 4L 61 #undef main_activity_UninstalledObserverActivity_RESULT_CANCELED 62 #define main_activity_UninstalledObserverActivity_RESULT_CANCELED 0L 63 #undef main_activity_UninstalledObserverActivity_RESULT_OK 64 #define main_activity_UninstalledObserverActivity_RESULT_OK -1L 65 #undef main_activity_UninstalledObserverActivity_RESULT_FIRST_USER 66 #define main_activity_UninstalledObserverActivity_RESULT_FIRST_USER 1L 67 #undef main_activity_UninstalledObserverActivity_DEFAULT_KEYS_DISABLE 68 #define main_activity_UninstalledObserverActivity_DEFAULT_KEYS_DISABLE 0L 69 #undef main_activity_UninstalledObserverActivity_DEFAULT_KEYS_DIALER 70 #define main_activity_UninstalledObserverActivity_DEFAULT_KEYS_DIALER 1L 71 #undef main_activity_UninstalledObserverActivity_DEFAULT_KEYS_SHORTCUT 72 #define main_activity_UninstalledObserverActivity_DEFAULT_KEYS_SHORTCUT 2L 73 #undef main_activity_UninstalledObserverActivity_DEFAULT_KEYS_SEARCH_LOCAL 74 #define main_activity_UninstalledObserverActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L 75 #undef main_activity_UninstalledObserverActivity_DEFAULT_KEYS_SEARCH_GLOBAL 76 #define main_activity_UninstalledObserverActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L 77 78 /* 79 * Class: main_activity_UninstalledObserverActivity 80 * Method: init 81 * Signature: ()V 82 */ 83 JNIEXPORT void JNICALL Java_main_activity_UninstalledObserverActivity_init(JNIEnv *, jobject); 84 85 #ifdef __cplusplus 86 } 87 #endif 88 #endif \u0026lt;div class=\u0026quot;cnblogs_code_toolbar\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_copy\u0026quot;\u0026gt;\u0026lt;a title=\u0026quot;复制代码\u0026quot;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; 核心——native方法实现： \u0026amp;nbsp; \u0026lt;div class=\u0026quot;cnblogs_code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;cnblogs_code_toolbar\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_copy\u0026quot;\u0026gt;\u0026lt;a title=\u0026quot;复制代码\u0026quot;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ``` 1 /* 头文件begin / 2 #include \u0026ldquo;main_activity_UninstalledObserverActivity.h\u0026rdquo; 3 / 头文件end / 4 5 #ifdef __cplusplus 6 extern \u0026ldquo;C\u0026rdquo; { 7 #endif 8 9 / 内全局变量begin / 10 static char c_TAG[] = \u0026ldquo;UninstalledObserverActivity.init\u0026rdquo;; 11 static jboolean b_IS_COPY = JNI_TRUE; 12 / 内全局变量 / 13 14 / 15 * Class: main_activity_UninstalledObserverActivity 16 * Method: init 17 * Signature: ()V 18 */ 19 JNIEXPORT void JNICALL Java_main_activity_UninstalledObserverActivity_init(JNIEnv *env, jobject obj) 20 { 21 jstring tag = (*env)-\u0026gt;NewStringUTF(env, c_TAG); 22 23 //初始化log 24 LOG_DEBUG((*env)-\u0026gt;GetStringUTFChars(env, tag, \u0026amp;b_IS_COPY) 25 , (*env)-\u0026gt;GetStringUTFChars(env, (*env)-\u0026gt;NewStringUTF(env, \u0026ldquo;init OK\u0026rdquo;), \u0026amp;b_IS_COPY)); 26 27 //fork子进程，以执行轮询任务 28 pid_t pid = fork(); 29 if (pid \u0026lt; 0) 30 { 31 //出错log 32 LOG_ERROR((*env)-\u0026gt;GetStringUTFChars(env, tag, \u0026amp;b_IS_COPY) 33 , (*env)-\u0026gt;GetStringUTFChars(env, (*env)-\u0026gt;NewStringUTF(env, \u0026ldquo;fork failed !!!\u0026rdquo;), \u0026amp;b_IS_COPY)); 34 } 35 else if (pid == 0) 36 { 37 //子进程注册\u0026rdquo;/data/data/pym.test.uninstalledobserver\u0026quot;目录监听器 38 int fileDescriptor = inotify_init(); 39 if (fileDescriptor \u0026lt; 0) 40 { 41 LOG_DEBUG((*env)-\u0026gt;GetStringUTFChars(env, tag, \u0026amp;b_IS_COPY) 42 , (*env)-\u0026gt;GetStringUTFChars(env, (*env)-\u0026gt;NewStringUTF(env, \u0026ldquo;inotify_init failed !!!\u0026rdquo;), \u0026amp;b_IS_COPY)); 43 44 exit(1); 45 } 46 47 int watchDescriptor; 48 watchDescriptor = inotify_add_watch(fileDescriptor, \u0026ldquo;/data/data/pym.test.uninstalledobserver\u0026rdquo;, IN_DELETE); 49 if (watchDescriptor \u0026lt; 0) 50 { 51 LOG_DEBUG((*env)-\u0026gt;GetStringUTFChars(env, tag, \u0026amp;b_IS_COPY) 52 , (*env)-\u0026gt;GetStringUTFChars(env, (*env)-\u0026gt;NewStringUTF(env, \u0026ldquo;inotify_add_watch failed !!!\u0026rdquo;), \u0026amp;b_IS_COPY)); 53 54 exit(1); 55 } 56 57 //分配缓存，以便读取event，缓存大小=一个struct inotify_event的大小，这样一次处理一个event 58 void *p_buf = malloc(sizeof(struct inotify_event)); 59 if (p_buf == NULL) 60 { 61 LOG_DEBUG((*env)-\u0026gt;GetStringUTFChars(env, tag, \u0026amp;b_IS_COPY) 62 , (*env)-\u0026gt;GetStringUTFChars(env, (*env)-\u0026gt;NewStringUTF(env, \u0026ldquo;malloc failed !!!\u0026rdquo;), \u0026amp;b_IS_COPY)); 63 64 exit(1); 65 } 66 //开始监听 67 LOG_DEBUG((*env)-\u0026gt;GetStringUTFChars(env, tag, \u0026amp;b_IS_COPY) 68 , (*env)-\u0026gt;GetStringUTFChars(env, (*env)-\u0026gt;NewStringUTF(env, \u0026ldquo;start observer\u0026rdquo;), \u0026amp;b_IS_COPY)); 69 size_t readBytes = read(fileDescriptor, p_buf, sizeof(struct inotify_event)); 70 71 //read会阻塞进程，走到这里说明收到目录被删除的事件，注销监听器 72 free(p_buf); 73 inotify_rm_watch(fileDescriptor, IN_DELETE); 74 75 //目录不存在log 76 LOG_DEBUG((*env)-\u0026gt;GetStringUTFChars(env, tag, \u0026amp;b_IS_COPY) 77 , (*env)-\u0026gt;GetStringUTFChars(env, (*env)-\u0026gt;NewStringUTF(env, \u0026ldquo;uninstalled\u0026rdquo;), \u0026amp;b_IS_COPY)); 78 79 //执行命令am start -a android.intent.action.VIEW -d http://shouji.360.cn/web/uninstall/uninstall.html 80 execlp(\u0026ldquo;am\u0026rdquo;, \u0026ldquo;am\u0026rdquo;, \u0026ldquo;start\u0026rdquo;, \u0026ldquo;-a\u0026rdquo;, \u0026ldquo;android.intent.action.VIEW\u0026rdquo;, \u0026ldquo;-d\u0026rdquo;, \u0026ldquo;http://shouji.360.cn/web/uninstall/uninstall.html\u0026quot;, (char *)NULL); 81 } 82 else 83 { 84 //父进程直接退出，使子进程被init进程领养，以避免子进程僵死 85 } 86 } 87 88 #ifdef __cplusplus 89 } 90 #endif\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 转自：http://www.cnblogs.com/zealotrouge/p/3159772.html \u0026amp;nbsp; 问题： 4.2.2的问题解决了，在4.2.2上运行时会抛异常： Permission Denial: startActivity asks to run as user -2 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL， 然后吧命令修改为： execlp(\u0026amp;#8220;am\u0026amp;#8221;, \u0026amp;#8220;am\u0026amp;#8221;, \u0026amp;#8220;start\u0026amp;#8221;,\u0026amp;#8221;\u0026amp;#8211;user\u0026amp;#8221;, \u0026amp;#8220;0\u0026amp;#8221; ,\u0026amp;#8221;-a\u0026amp;#8221;, \u0026amp;#8220;android.intent.action.VIEW\u0026amp;#8221;, \u0026amp;#8220;-d\u0026amp;#8221;, \u0026amp;#8220;[http://shouji.360.cn/web/uninstall/uninstall.html](http://shouji.360.cn/web/uninstall/uninstall.html)\u0026amp;#8220;, (char *)NULL);这样就可以了。 \u0026amp;nbsp; 你好，已经解决了，只是最近比较忙没有时间写博客，解决方案是加\u0026amp;#8211;user，不过\u0026amp;#8211;user后不一定是0，这个跟google 4.2加入的多用户支持特性有关，等这段时间忙完了我会写篇博客专门分析这个问题，包括如何给\u0026amp;#8211;user传递正确的值。 更多问题参考：http://www.cnblogs.com/zealotrouge/p/3159772.html \u0026amp;nbsp; 最后给出eoe上面的demo地址：http://www.eoeandroid.com/thread-317728-1-1.html 没有eoe的伙伴下载这个[监听自身被卸载](http://www.etongwl.com/images/2015/01/监听自身被卸载.zip) git上有个开源地址：https://github.com/sevenler/Uninstall_Statics \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android%E5%BA%94%E7%94%A8%E5%A6%82%E4%BD%95%E7%9B%91%E5%90%AC%E8%87%AA%E5%B7%B1%E6%98%AF%E5%90%A6%E8%A2%AB%E5%8D%B8%E8%BD%BD%E5%8F%8A%E5%8D%B8%E8%BD%BD%E5%8F%8D%E9%A6%88%E5%8A%9F%E8%83%BD%E7%9A%84/","summary":"\u003cdiv id=\"cnblogs_post_body\"\u003e\n\u003cpre\u003e\u003ccode\u003e一个应用被用户卸载肯定是有理由的，而开发者却未必能得知这一重要的理由，毕竟用户很少会主动反馈建议，多半就是用得不爽就卸，如果能在被卸载后获取到用户的一些反馈，那对开发者进一步改进应用是非常有利的。目前据我所知，国内的Android应用中实现这一功能的只有360手机卫士、360平板卫士，那么如何实现这一功能的？\n\n\n\n\n\n我们可以把实现卸载反馈的问题转化为监听自己是否被卸载，只有得知自己被卸载，才可以设计相应的反馈处理流程。以下的列表是我在研究这一问题的思路：\n\n\n\n\n\n1，注册BroadcastReceiver，监听\u0026amp;#8221;android.intent.action.PACKAGE_REMOVED\u0026amp;#8221;系统广播\n\n\n\n\n\n结果：NO。未写代码，直接分析，卸载的第一步就是退出当前应用的主进程，而此广播是在已经卸载完成后才发出的，此时主进程都没有了，去哪onReceive()呢？\n\n\n\n\n\n2，若能收到\u0026amp;#8221;将要卸载XX包\u0026amp;#8221;的系统广播，在主进程被退出之前就抢先进行反馈处理就好了，可惜没有这样的系统广播，不过经过调研，倒是发现了一个办法，读取系统log，当日志中包含\u0026amp;#8221;android.intent.action.DELETE\u0026amp;#8221;和自己的包名时，意味着自己将要被卸载。\n\n\n\n\n\n结果：NO。调试时发现此方法有两个缺陷，（1）点击设置中的卸载按钮即发出此Intent，此时用户尚未在弹框中确认卸载；（2）pm命令卸载不出发此Intent，意味着被诸如手机安全管家，豌豆荚等软件卸载时，无法提前得知卸载意图。\n\n\n\n\n\n3，由于时间点不容易把控，所以干脆不依赖系统广播或log，考虑到卸载过程会删除\u0026amp;#8221;/data/data/包名\u0026amp;#8221;目录，我们可以用线程直接轮询这个目录是否存在，以此为依据判断自己是否被卸载。\n\n\n\n\n\n结果：NO。同方法1，主进程退出，相应的线程必定退出，线程还没等到判断目录是否存在就已经被销毁了。\n\n\n\n\n\n4，改用C端进程轮询\u0026amp;#8221;/data/data/包名\u0026amp;#8221;目录是否存在\n\n\n\n\n\n结果：YES。借助Java端进程fork出来的C端进程在应用被卸载后不会被销毁。\n\n\n\n\n\nOK，上代码！\n\n\n\n\n\nActivity启动时fork出C端进程轮询目录：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"cnblogs_code\"\u003e\n    \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n      \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e1 package main.activity;\n2\n3 import pym.test.uninstalledmoniter.R;\n4 import android.app.Activity;\n5 import android.os.Bundle;\n6 import android.util.Log;\n7\n8 /**\n9  * @author pengyiming\n10  * @note 监听此应用是否被卸载，若被卸载则弹出卸载反馈\n11  *\n12  \u003cem\u003e/\n13\n14 public class UninstalledMoniterActivity extends Activity\n15 {\n16     /\u003c/em\u003e 数据段begin \u003cem\u003e/\n17     private static final String TAG = \u0026ldquo;UninstalledMoniterActivity\u0026rdquo;;\n18     /\u003c/em\u003e 数据段end \u003cem\u003e/\n19  \u003cbr\u003e\n20     /\u003c/em\u003e 函数段begin \u003cem\u003e/\n21     private native void init();\n22     static\n23     {\n24         Log.d(TAG, \u0026ldquo;load libuninstalled_moniter\u0026rdquo;);\n25         System.loadLibrary(\u0026ldquo;uninstalled_moniter\u0026rdquo;);\n26     }\n27  \u003cbr\u003e\n28     @Override\n29     public void onCreate(Bundle savedInstanceState)\n30     {\n31         super.onCreate(savedInstanceState);\n32         Log.d(TAG, \u0026ldquo;onCreate\u0026rdquo;);\n33      \u003cbr\u003e\n34         setContentView(R.layout.uninstalled_moniter_layout);\n35      \u003cbr\u003e\n36         init();\n37     }\n38     /\u003c/em\u003e 函数段end */\n39 }\u003c/p\u003e","title":"Android应用如何监听自己是否被卸载及卸载反馈功能的实现"},{"content":" android下可以连接远程数据的，不过你远程的数据库服务的要开启远程，具体设置[http://www.ways2u.com/knowledge/?post=142](http://www.ways2u.com/knowledge/?post=142) Java利用JDBC访问数据库的编程步骤 http://www.ways2u.com/?post=76\nandroid 链接mysql数据库实例： package com.hl;\nimport java.sql.DriverManager; import java.sql.ResultSet;\nimport com.mysql.jdbc.Connection; import com.mysql.jdbc.Statement;\nimport android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView;\npublic class AndroidMsql extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button btn=(Button)findViewById(R.id.btn); btn.setOnClickListener(new OnClickListener() {\n@Override public void onClick(View v) { sqlCon(); } });\n} private void mSetText(String str){ TextView txt=(TextView)findViewById(R.id.txt); txt.setText(str); }\nprivate void sqlCon(){ try { Class.forName(“com.mysql.jdbc.Driver”); } catch (Exception e) { e.printStackTrace(); } try { String url =”jdbc:mysql://192.168.142.128:3306/mysql?user=zzfeihua\u0026amp;password=12345\u0026amp;useUnicode=true\u0026amp;characterEncoding=UTF-8″;//链接数据库语句 Connection conn= (Connection) DriverManager.getConnection(url); //链接数据库 Statement stmt=(Statement) conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); String sql=”select * from user”;//查询user表语句 ResultSet rs=stmt.executeQuery(sql);//执行查询 StringBuilder str=new StringBuilder(); while(rs.next()){ str.append(rs.getString(1)+”\\n”); } mSetText(str.toString());\nrs.close(); stmt.close(); conn.close();\n} catch (Exception e) { e.printStackTrace(); }\n} } 不过eclipse老是提示： warning: Ignoring InnerClasses attribute for an anonymous inner class that doesn’t come with an associated EnclosingMethod attribute. (This class was probably produced by a broken compiler.) 不知道谁有解决的办法呢？？\n附件下载： AndroidMsql.rar 785.5KB\n转自：http://www.ways2u.com/?post=197\n","permalink":"https://blog.zdltech.com/posts/android-%E9%93%BE%E6%8E%A5mysql%E6%95%B0%E6%8D%AE%E5%BA%93/","summary":"\u003cdiv class=\"postContent\"\u003e\n\u003cpre\u003e\u003ccode\u003eandroid下可以连接远程数据的，不过你远程的数据库服务的要开启远程，具体设置[http://www.ways2u.com/knowledge/?post=142](http://www.ways2u.com/knowledge/?post=142)\n\n\n\n\n\nJava利用JDBC访问数据库的编程步骤\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"http://www.ways2u.com/?post=76\"\u003ehttp://www.ways2u.com/?post=76\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eandroid 链接mysql数据库实例：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003epackage com.hl;\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eimport java.sql.DriverManager;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eimport java.sql.ResultSet;\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eimport com.mysql.jdbc.Connection;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eimport com.mysql.jdbc.Statement;\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eimport android.app.Activity;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eimport android.os.Bundle;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\nimport android.widget.TextView;\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003epublic class AndroidMsql extends Activity {\n\n\n\n\n\n@Override\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003epublic void onCreate(Bundle savedInstanceState) {\nsuper.onCreate(savedInstanceState);\nsetContentView(R.layout.main);\nButton btn=(Button)findViewById(R.id.btn);\nbtn.setOnClickListener(new OnClickListener() {\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e@Override\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003epublic void onClick(View v) {\nsqlCon();\n}\n});\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e}\n\n\n\n\n\nprivate void mSetText(String str){\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eTextView txt=(TextView)findViewById(R.id.txt);\ntxt.setText(str);\n}\u003c/p\u003e","title":"android 链接mysql数据库"},{"content":"mysql中计算经纬度方法\nselect * ,3956*2*asin(sqrt(power(sin((122.4058-abs(dest.lat))*pi()/180/2),2)+cos(122.4058/180)*cos(abs(dest.lat)*pi()/180)*power(sin((37.7907-dest.lon)*pi()/180/2),2))) as distance from sp_zxcplace dest HAVING distance\u0026lt;10000 order by distance\nMysql根据经纬度算距离返回米\n亲测ok\nSELECT pId,name,lon,lat, ROUND(6378.138*2*ASIN(SQRT(POW(SIN((34.3574030000*PI()/180-lat*PI()/180)/2),2)+COS(34.3574030000*PI()/180)*COS(lat*PI()/180)*POW(SIN((108.9263460000*PI()/180-lon*PI()/180)/2),2)))*1000) AS distance FROM sp_zxcplace HAVING distance\u0026lt;10000 ORDER BY distance\n","permalink":"https://blog.zdltech.com/posts/mysql%E8%AE%A1%E7%AE%97%E7%BB%8F%E7%BA%AC%E5%BA%A6%E8%B7%9D%E7%A6%BB/","summary":"\u003cp\u003emysql中计算经纬度方法\u003c/p\u003e\n\u003cp\u003eselect * ,3956*2*asin(sqrt(power(sin((122.4058-abs(dest.lat))*pi()/180/2),2)+cos(122.4058/180)*cos(abs(dest.lat)*pi()/180)*power(sin((37.7907-dest.lon)*pi()/180/2),2))) as distance from sp_zxcplace dest HAVING distance\u0026lt;10000 order by distance\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.etongwl.com/images/2015/01/A5798FB2-258F-46D5-8BCF-AF0F5BB2E641.jpg\"\u003e\u003cimg alt=\"A5798FB2-258F-46D5-8BCF-AF0F5BB2E641\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2015/01/A5798FB2-258F-46D5-8BCF-AF0F5BB2E641-300x187.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eMysql根据经纬度算距离返回米\u003c/p\u003e\n\u003cp\u003e亲测ok\u003c/p\u003e\n\u003cp\u003eSELECT pId,name,lon,lat, ROUND(6378.138*2*ASIN(SQRT(POW(SIN((34.3574030000*PI()/180-lat*PI()/180)/2),2)+COS(34.3574030000*PI()/180)*COS(lat*PI()/180)*POW(SIN((108.9263460000*PI()/180-lon*PI()/180)/2),2)))*1000) AS distance  FROM sp_zxcplace HAVING distance\u0026lt;10000 ORDER BY distance\u003c/p\u003e","title":"mysql计算经纬度距离"},{"content":"在最近几年里，移动互联网高速发展、市场潜力巨大。继计算机、互联网之后，移动互联网正掀起第三次信息技术革命的浪潮，新技术、新应用不断涌现。今天这篇文章向大家推荐10大优秀的移动Web开发框架，帮助开发者更加高效的开发移动Web应用。\nSencha Touch Framework Sencha Touch 是世界上第一个基于 HTML5 的移动 Web 开发框架，支持最新的 HTML5 和 CSS3 标准，全面兼容 Android 和 Apple iOS 设备，提供了丰富的 WEB UI 组件，可以快速的开发出运行于移动终端的应用程序。\njQuery Mobile jQuery Mobile 框架把“write less, do more”精神提升到更高的层次。jQuery 移动框架可以帮助你设计一个可运行于所有流行智能手机和平板平台的应用程序，而不需要为每种移动终端都开发一个特别的版本。\njQTouch jQTouch 是一款 jQuery 的插件，用于手机上实现动画、列表导航、默认应用样式等各种常见UI效果。支持 iPhone、Android 等手机。\nThe M Project The-M-Project 是一个包含各种UI组件，基于 jQuery 开发 HTML5 应用程序的移动Web应用框架，支持 iOS、Android、Palm webOS和BlackBerry 等平台。\nDHTMLX Touch – HTML5 JavaScript Framework for Mobile DHTMLX Touch 是一个基于 HTML5 的免费 JavaScript 库，用于构建跨平台的移动 Web 应用程序。这不只是一组UI部件，而是一个完整的框架，它允许你为手机等触摸设备创建强大的Web应用程序。\nWebApp.Net WebApp.Net 提供了很多的 API，因此可以帮助你节省很多工作了。不需要花时间去进行 Ajax 调用的编码，因为已经内置了，另外还有很多其它内置功能，提供了详细的文档和应用演示。\nWijmo – jQuery UI Widgets Wijmo 混合了 JavaScript、CSS3、SVG 和 HTML5，拥有30多个组件，是 jQuery UI 的一个扩展。\n960 Grid on jQuery-Mobile jquery-mobile-960 是一个用于移动 Web 开发的网格框架，综合了 960.gs 的灵活性和 jQuery Mobile 的方便性。它的目的是让 jQuery Mobile 布局更加的灵活，使得应用应许在移动终端更加易用。\nSproutCore HTML5 Application Framework SproutCore 是一个 HTML5 移动 Web 开发框架，它的目标是在无需浏览器插件的情况下，在浏览器中位应用程序提供极佳的桌面效果。\nNimbleKit NimbleKit 是为 iOS 设备构建应用程序最快速的方式，你不需要知道 Objective-C 或者 iOS SDK，你只需结合 JavaScript 代码编写 HTML 页面就可以了。\n转自：http://www.cnblogs.com/lhb25/archive/2011/09/07/mobile-web-app-frameworks.html\n","permalink":"https://blog.zdltech.com/posts/10%E5%A4%A7%E4%BC%98%E7%A7%80%E7%9A%84%E7%A7%BB%E5%8A%A8web%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E5%BC%80%E5%8F%91%E6%A1%86%E6%9E%B6%E6%8E%A8%E8%8D%90/","summary":"\u003cp\u003e在最近几年里，移动互联网高速发展、市场潜力巨大。继计算机、互联网之后，移动互联网正掀起第三次信息技术革命的浪潮，新技术、新应用不断涌现。今天这篇文章向大家推荐10大优秀的移动Web开发框架，帮助开发者更加高效的开发移动Web应用。\u003c/p\u003e\n\u003ch3 id=\"sencha-touch-framework\"\u003eSencha Touch Framework\u003c/h3\u003e\n\u003cp\u003eSencha Touch 是世界上第一个基于 HTML5 的移动 Web 开发框架，支持最新的 \u003ca href=\"http://www.cnblogs.com/lhb25/category/146076.html\"\u003eHTML5\u003c/a\u003e 和 \u003ca href=\"http://www.cnblogs.com/lhb25/category/146075.html\"\u003eCSS3\u003c/a\u003e 标准，全面兼容 Android 和 Apple iOS 设备，提供了丰富的 WEB UI 组件，可以快速的开发出运行于移动终端的应用程序。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.yyyweb.com/demo/inner-show/touch.html\"\u003e\u003cimg alt=\"10大优秀的移动Web应用程序开发框架推荐\" loading=\"lazy\" src=\"http://pic002.cnblogs.com/images/2011/36987/2011090414113774.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"jquery-mobile\"\u003ejQuery Mobile\u003c/h3\u003e\n\u003cp\u003ejQuery Mobile 框架把“write less, do more”精神提升到更高的层次。\u003ca href=\"http://www.cnblogs.com/lhb25/category/277997.html\"\u003ejQuery\u003c/a\u003e 移动框架可以帮助你设计一个可运行于所有流行智能手机和平板平台的应用程序，而不需要为每种移动终端都开发一个特别的版本。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.yyyweb.com/demo/inner-show/jq-mobile.html\"\u003e\u003cimg alt=\"10大优秀的移动Web应用程序开发框架推荐\" loading=\"lazy\" src=\"http://pic002.cnblogs.com/images/2011/36987/2011090709292152.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"jqtouch\"\u003ejQTouch\u003c/h3\u003e\n\u003cp\u003ejQTouch 是一款 \u003ca href=\"http://www.cnblogs.com/lhb25/category/277997.html\"\u003ejQuery\u003c/a\u003e 的插件，用于手机上实现动画、列表导航、默认应用样式等各种常见UI效果。支持 iPhone、Android 等手机。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.yyyweb.com/demo/inner-show/jq-touch.html\"\u003e\u003cimg alt=\"10大优秀的移动Web应用程序开发框架推荐\" loading=\"lazy\" src=\"http://pic002.cnblogs.com/images/2011/36987/2011090709300666.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"the-m-project\"\u003eThe M Project\u003c/h3\u003e\n\u003cp\u003eThe-M-Project 是一个包含各种UI组件，基于 \u003ca href=\"http://www.cnblogs.com/lhb25/category/277997.html\"\u003ejQuery\u003c/a\u003e 开发 \u003ca href=\"http://www.cnblogs.com/lhb25/category/146076.html\"\u003eHTML5\u003c/a\u003e 应用程序的移动Web应用框架，支持 iOS、Android、Palm webOS和BlackBerry 等平台。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.yyyweb.com/demo/inner-show/m-project.html\"\u003e\u003cimg alt=\"10大优秀的移动Web应用程序开发框架推荐\" loading=\"lazy\" src=\"http://pic002.cnblogs.com/images/2011/36987/2011090709303721.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"dhtmlx-touch--html5-javascript-framework-for-mobile\"\u003eDHTMLX Touch – HTML5 JavaScript Framework for Mobile\u003c/h3\u003e\n\u003cp\u003eDHTMLX Touch 是一个基于 \u003ca href=\"http://www.cnblogs.com/lhb25/category/146076.html\"\u003eHTML5\u003c/a\u003e 的免费 \u003ca href=\"http://www.cnblogs.com/lhb25/category/146074.html\"\u003eJavaScript\u003c/a\u003e 库，用于构建跨平台的移动 Web 应用程序。这不只是一组UI部件，而是一个完整的框架，它允许你为手机等触摸设备创建强大的Web应用程序。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.yyyweb.com/demo/inner-show/dhtmlx-touch.html\"\u003e\u003cimg alt=\"10大优秀的移动Web应用程序开发框架推荐\" loading=\"lazy\" src=\"http://pic002.cnblogs.com/images/2011/36987/2011090709310138.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"webappnet\"\u003eWebApp.Net\u003c/h3\u003e\n\u003cp\u003eWebApp.Net 提供了很多的 API，因此可以帮助你节省很多工作了。不需要花时间去进行 Ajax 调用的编码，因为已经内置了，另外还有很多其它内置功能，提供了详细的文档和应用演示。\u003c/p\u003e","title":"10大优秀的移动Web应用程序开发框架推荐"},{"content":"在Android应用中，当对图片本身进行操作时，应该尽量不要是使用setImageBitmap、setImageResource、BitmapFactory.decodeResource来设置一张大图，因为这些方法在完成Decode后，最终都是通过java层的createBitmap()方法来完成的，这需要消耗更多的内存。因此，应该先通过BitmapFractory.decodeStream方法创建出一个bitmap，然后再将其设置为imageview的source。decodeStream最大的优点是直接调用JNI–\u0026gt;nativeDecodeAsset()来完成decode，而不需要在使用java层的createBitmap，从而节省了java层的空间。如果在读取图片是加上图片的Config参数，可以更有效的减少加载的内存，从而更有效的阻止抛出内存溢出。另外decodeStream直接用图片来读取字节码，不会根据机器的各种分辨率来自动适应。当使用了decodeStream后，需要在hdpi和mdpi中配置相应的图片资源，否则在不同分辨率的机子上都是同样大小（像素点数量），显示出来的大小就不对了。\n优化Dalvik虚拟机的堆内存分配。对Android平台来说，其托管层使用的时Dalvik Java VM，从目前的表现来看还有很多地方可以优化处理，比如在开发一些大型游戏或者耗资源的应用中可以考虑用手动干预GC处理，使用类dalvik.system.VMRuntime提供的setTargetHeapUtilization可以增强程序堆内存的处理效率。使用方法如下：\nprivate final static float TARGET_HEAP_UTILIZATION=0.75f;\nVMRuntime.getRuntime().setTargetHeapUtilazation(TARGET_HEAP_UTILIZATION);\n另外还可以用如下方法定义堆内存的大小，这样就实现了优化功能。\nprivate final static int CWJ_HEAP_SIZE=6*1024*1024;\nVMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);//设置Heap的最小内存6M。\n","permalink":"https://blog.zdltech.com/posts/android-%E5%9B%BE%E7%89%87%E7%9A%84%E5%86%85%E5%AD%98%E4%BC%98%E5%8C%96/","summary":"\u003cp\u003e在Android应用中，当对图片本身进行操作时，应该尽量不要是使用setImageBitmap、setImageResource、BitmapFactory.decodeResource来设置一张大图，因为这些方法在完成Decode后，最终都是通过java层的createBitmap()方法来完成的，这需要消耗更多的内存。因此，应该先通过BitmapFractory.decodeStream方法创建出一个bitmap，然后再将其设置为imageview的source。decodeStream最大的优点是直接调用JNI–\u0026gt;nativeDecodeAsset()来完成decode，而不需要在使用java层的createBitmap，从而节省了java层的空间。如果在读取图片是加上图片的Config参数，可以更有效的减少加载的内存，从而更有效的阻止抛出内存溢出。另外decodeStream直接用图片来读取字节码，不会根据机器的各种分辨率来自动适应。当使用了decodeStream后，需要在hdpi和mdpi中配置相应的图片资源，否则在不同分辨率的机子上都是同样大小（像素点数量），显示出来的大小就不对了。\u003c/p\u003e\n\u003cp\u003e优化Dalvik虚拟机的堆内存分配。对Android平台来说，其托管层使用的时Dalvik Java VM，从目前的表现来看还有很多地方可以优化处理，比如在开发一些大型游戏或者耗资源的应用中可以考虑用手动干预GC处理，使用类dalvik.system.VMRuntime提供的setTargetHeapUtilization可以增强程序堆内存的处理效率。使用方法如下：\u003c/p\u003e\n\u003cp\u003eprivate final static float TARGET_HEAP_UTILIZATION=0.75f;\u003c/p\u003e\n\u003cp\u003eVMRuntime.getRuntime().setTargetHeapUtilazation(TARGET_HEAP_UTILIZATION);\u003c/p\u003e\n\u003cp\u003e另外还可以用如下方法定义堆内存的大小，这样就实现了优化功能。\u003c/p\u003e\n\u003cp\u003eprivate final static int CWJ_HEAP_SIZE=6*1024*1024;\u003c/p\u003e\n\u003cp\u003eVMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);//设置Heap的最小内存6M。\u003c/p\u003e","title":"Android 图片的内存优化"},{"content":"微信开发值得推荐的开源项目 http://www.csdn.net/article/2014-04-16/2819340\n微信公众平台开发（java)用什么框架最好呢？ http://www.oschina.net/question/1462914_162471\nweixin 1 0 微信开发框架 JAVA版 http://download.csdn.net/detail/april127/7675879\n微信公众平台技术方案- http://wenku.baidu.com/link?url=3JxSgzmrWFZdXAHJ9jf1bqhdO-FyGbhWYWIy7N_fBmqkMJ9MOvEe-sPXL76eeWNDV8w7PJpl21o4GQH6-M8FN8SEPuuhyY8GiWzvxTacObu\nhttp://www.eoeandroid.com/thread-317474-1-1.html\nhttp://tieba.baidu.com/p/3237760264\n微信公众帐号: 【凡尘工作室】的开源代码\nhttps://github.com/ostrichmyself/bae_weichat\n","permalink":"https://blog.zdltech.com/posts/%E5%BE%AE%E4%BF%A1%E5%BC%80%E5%8F%91%E5%80%BC%E5%BE%97%E6%8E%A8%E8%8D%90%E7%9A%84%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE-2/","summary":"\u003ch1 id=\"微信开发值得推荐的开源项目\"\u003e微信开发值得推荐的开源项目\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"http://www.csdn.net/article/2014-04-16/2819340\"\u003ehttp://www.csdn.net/article/2014-04-16/2819340\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 id=\"微信公众平台开发java用什么框架最好呢\"\u003e\u003ca href=\"http://www.oschina.net/question/1462914_162471\"\u003e微信公众平台开发（java)用什么框架最好呢？\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"http://www.oschina.net/question/1462914_162471\"\u003ehttp://www.oschina.net/question/1462914_162471\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch3 id=\"weixin10微信开发框架java版\"\u003e\u003cstrong\u003eweixin 1 0 微信开发框架 JAVA版\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e\u003ca href=\"http://download.csdn.net/detail/april127/7675879\"\u003ehttp://download.csdn.net/detail/april127/7675879\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 id=\"微信公众平台技术方案-\"\u003e微信公众平台技术方案-\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"http://wenku.baidu.com/link?url=3JxSgzmrWFZdXAHJ9jf1bqhdO-FyGbhWYWIy7N_fBmqkMJ9MOvEe-sPXL76eeWNDV8w7PJpl21o4GQH6-M8FN8SEPuuhyY8GiWzvxTacObu\"\u003ehttp://wenku.baidu.com/link?url=3JxSgzmrWFZdXAHJ9jf1bqhdO-FyGbhWYWIy7N_fBmqkMJ9MOvEe-sPXL76eeWNDV8w7PJpl21o4GQH6-M8FN8SEPuuhyY8GiWzvxTacObu\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.eoeandroid.com/thread-317474-1-1.html\"\u003ehttp://www.eoeandroid.com/thread-317474-1-1.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://tieba.baidu.com/p/3237760264\"\u003ehttp://tieba.baidu.com/p/3237760264\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e微信公众帐号: 【凡尘工作室】的开源代码\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/ostrichmyself/bae_weichat\"\u003ehttps://github.com/ostrichmyself/bae_weichat\u003c/a\u003e\u003c/p\u003e","title":"微信开发值得推荐的开源项目"},{"content":"进入谷歌那样的大公司工作是多少程序员的人生梦想！最近，Google Education推荐了一系列计算机相关课程，为想要学习编程的大学生们指明方向，非大学生也可以来学习。\n————————以下内容搬运自Google Education————————\n要成为一名成功的软件工程师，你必须具备扎实的计算机科学基础。本自学指南适用于想要学习编程的大学生们，分为专业方向和非专业方向两个系列。你可以借助这个指南进行自学，但请首先修够你的专业学分，以保证顺利毕业。\n本课程表中的课程不能代替大学课程，但它们能够帮助你进一步学习计算机科学，或者对这个领域建立初步理解。\n关于如何使用本学习指南的4点建议：\n请考虑自己的实际情况进行学习。 如果你还想学习《指南》之外的其他课程，尽管上吧！ 本指南仅供参考，即使学完这上面的所有课程，也不能保证你一定能进入谷歌工作。 本指南不定期更新。你可以在Google +上关注 Google for Students +Page，随时获取更多资讯。 【为进军学术界作准备的课程】\n计算机科学导论课程\n你可以选择提供在线编程工具的计算机导论课程。\n课程推荐：\n学习至少一种面向对象编程语言，如C++，Java 或Python\n入门课程：\nMIT Intro to Programming in Java,\nGoogle’s Python Class,\nPython Open Source E-Book\n中级课程:\nUdacity’s Design of Computer Programs,\n学习其他的编程语言\nTo learn list：Java Script, CSS, HTML, Ruby, PHP, C, Perl, Shell. Lisp, Scheme.\n测试和提高自己的编程能力\n例如：排查故障，创建测试，破解软件\n相关课程:\n学习逻辑推理和离散数学\n相关课程：\nMIT Mathematics for Computer Science,\n深入理解算法和数据结构\n学习基本的数据类型，如堆栈、队列和数据包；\n了解排序演算法，如快速排序，二路归并排序和堆排序；\n了解数据结构，如二叉搜索树，红黑树和哈希表。\n相关课程：\nMIT Introduction to Algorithms,\nCoursera Introduction to Algorithms Part 1 \u0026amp; Part 2,\nList of Algorithms,\nList of Data Structures,\n参考书籍: The Algorithm Design Manual\n深入了解操作系统\n相关课程： UC Berkeley Computer Science 162\n人工智能相关课程\n如何开发一个编译器\n密码学\n相关课程：\n并行编程\n【如果你侧重应用方向】\n项目开发相关课程\n这方面的内容包括创建和维护一个网站，建立自己的服务器，或开发一个机器人。\n相关课程：\nApache List of Projects,\nGoogle Summer of Code,\nGoogle Developer Group\n如果你想了解一个大型系统的一部分（如代码库），阅读和理解代码，或跟踪文档和排查故障，那么你可以到Github上围观和学习别人的代码，并尝试开发自己的项目。\n相关资源：Github, Kiln\n如果你想通过学习提高与程序员合作的能力，那么你可以先尝试和程序员们共同完成一个项目。\n如果你想补充算法知识，练习编程技巧，可以参加CodeJam、ACM举办的国际编程大赛等活动。\n相关资源：CodeJam, ACM ICPC\n如果你通过教学加深自己对计算机的理解，获得软件工程等相关领域的实习经验，那么你可以申请担任相关课程的助教。注意要在实习期开始前提前申请哟！\n在美国，学生通常在五月到九月参加实习，一般需要提前几个月进行申请。\n相关资源-到谷歌的招聘页面看看吧： google.com/jobs\n","permalink":"https://blog.zdltech.com/posts/%E8%B0%B7%E6%AD%8C%E5%85%AC%E5%8F%B8%E5%8F%91%E5%B8%83%E7%A8%8B%E5%BA%8F%E5%91%98%E5%85%BB%E6%88%90%E6%8C%87%E5%8D%97%E6%8E%A8%E8%8D%90%E7%9B%B8%E5%85%B3%E5%9C%A8%E7%BA%BF%E8%AF%BE%E7%A8%8B/","summary":"\u003cp\u003e进入谷歌那样的大公司工作是多少程序员的人生梦想！最近，Google Education推荐了一系列计算机相关课程，为想要学习编程的大学生们指明方向，非大学生也可以来学习。\u003c/p\u003e\n\u003cp\u003e————————以下内容搬运自\u003ca href=\"http://www.google.com/edu/tools-and-solutions/guide-for-technical-development/index.html\"\u003eGoogle Education\u003c/a\u003e————————\u003c/p\u003e\n\u003cp\u003e要成为一名成功的软件工程师，你必须具备扎实的计算机科学基础。本自学指南适用于想要学习编程的大学生们，分为专业方向和非专业方向两个系列。你可以借助这个指南进行自学，但请首先修够你的专业学分，以保证顺利毕业。\u003c/p\u003e\n\u003cp\u003e本课程表中的课程不能代替大学课程，但它们能够帮助你进一步学习计算机科学，或者对这个领域建立初步理解。\u003c/p\u003e\n\u003cp\u003e关于如何使用本学习指南的4点建议：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e请考虑自己的实际情况进行学习。\u003c/li\u003e\n\u003cli\u003e如果你还想学习《指南》之外的其他课程，尽管上吧！\u003c/li\u003e\n\u003cli\u003e本指南仅供参考，即使学完这上面的所有课程，也不能保证你一定能进入谷歌工作。\u003c/li\u003e\n\u003cli\u003e本指南不定期更新。你可以在Google +上关注 \u003ca href=\"https://plus.google.com/u/0/%2BGoogleStudents/posts\"\u003eGoogle for Students +Page\u003c/a\u003e，随时获取更多资讯。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e【为进军学术界作准备的课程】\u003c/p\u003e\n\u003cp\u003e计算机科学导论课程\u003c/p\u003e\n\u003cp\u003e你可以选择提供在线编程工具的计算机导论课程。\u003c/p\u003e\n\u003cp\u003e课程推荐：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e学习至少一种面向对象编程语言，如C++，Java 或Python\u003c/p\u003e\n\u003cp\u003e入门课程：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.google.com/url?q=http%3A%2F%2Focw.mit.edu%2Fcourses%2Felectrical-engineering-and-computer-science%2F6-092-introduction-to-programming-in-java-january-iap-2010%2Findex.htm\u0026amp;sa=D\u0026amp;sntz=1\u0026amp;usg=AFQjCNHfuFmBicr4_Zh4dtfmk_mYq0BtNQ\"\u003eMIT Intro to Programming in Java\u003c/a\u003e,\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://developers.google.com/edu/python/\"\u003eGoogle’s Python Class\u003c/a\u003e,\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.openbookproject.net/thinkcs/python/english2e/\"\u003ePython Open Source E-Book\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e中级课程:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.udacity.com/course/cs212\"\u003eUdacity’s Design of Computer Programs\u003c/a\u003e,\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e学习其他的编程语言\u003c/p\u003e\n\u003cp\u003eTo learn list：Java Script, CSS, HTML, Ruby, PHP, C, Perl, Shell. Lisp, Scheme.\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e测试和提高自己的编程能力\u003c/p\u003e\n\u003cp\u003e例如：排查故障，创建测试，破解软件\u003c/p\u003e\n\u003cp\u003e相关课程:\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e学习逻辑推理和离散数学\u003c/p\u003e\n\u003cp\u003e相关课程：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.google.com/url?q=http%3A%2F%2Focw.mit.edu%2Fcourses%2Felectrical-engineering-and-computer-science%2F6-042j-mathematics-for-computer-science-fall-2010%2Findex.htm\u0026amp;sa=D\u0026amp;sntz=1\u0026amp;usg=AFQjCNEXtF_m9Lj7XMQZFy8Y92633L2EcQ\"\u003eMIT Mathematics for Computer Science\u003c/a\u003e,\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e深入理解算法和数据结构\u003c/p\u003e\n\u003cp\u003e学习基本的数据类型，如堆栈、队列和数据包；\u003c/p\u003e\n\u003cp\u003e了解排序演算法，如快速排序，二路归并排序和堆排序；\u003c/p\u003e\n\u003cp\u003e了解数据结构，如二叉搜索树，红黑树和哈希表。\u003c/p\u003e\n\u003cp\u003e相关课程：\u003c/p\u003e","title":"谷歌公司发布程序员养成指南，推荐相关在线课程"},{"content":"在开发应用过程中，我们可以使用现成的工具来查看内存泄漏的情况。例如DDMS和MAT，MAT是Memory Analyzer Tool的缩写，MAT可以安装eclipse插件（更新地址http://download.eclipse.org/mat/1.4/update-site/），可以使用比插件方便的RCP（下载地址：http://www.eclipse.org/mat/downloads.php）。对于MAT的使用我们暂时不详细讲解，小伙伴们可以去（http://www.eclipse.org/mat/中查看Documentation中查看，里面还有blog可以看）\n。\n查看内容泄漏的方法步骤：\n1.生成.hprof文件（使用DDMS生成，有必要的话，我给小伙伴录制一个视频讲解教程）\n2.使用MAT导入.hprof文件\n3.使用MAT的视图工具分析内存\n备注：由于有文件保存，肯定会用到SD卡，用模拟器的小伙伴不要忘记创建SD卡和让测试应用有读写SD卡的权限。如果真的没有SD卡，小伙伴可以使用android.os.Debug中的方法手动指定.hprof的内存（不是运行时内存，指的是系统的内存存储）位置，例如\nxxxButton.setOnclickListener(new View.OnClickListener(){\nandroid.os.Debug.dumpHprofData(“/data/tem/XXX.hprof”);//文件路径可以是SD卡路径\n});如果使用android.os.Debug.dumpHprofData()方法手动生成的.hprof文件，需要使用Android/Tools/ hprofconv xxx.hprof yyy.hprof把原来的xxx.hprof转换成yyy.hprof文件（这个文件才是MAT分析的文件）。\n目前查看内存分析查找内存泄漏的方法还有以下几种\n1.使用命令查看某个进程的内存。例如创建一个脚本文件xxx.sh.该文件的内容指定程序1秒钟输出某个进程的内存使用情况 代码如下\n#！/bin/bash\nWhile true; do adb shell procrank | grep “进程名称”\nSleep 1\ndone\n2.使用Top命令查看内存\nAdb shell top -m 10//查看使用资源最多的10个进程\nAdb shell top|grep 进程名称 //查看指定进程的内存\n3. free命令\nFree命令用来显示内存使用情况，使用权限是所有用户。格式如下\nFree [-b|-k|-m] [-o] [-s delay] [-t] [-v]\n参数 -b/-k/-m表示以B、KB、MB为单位显示内存使用情况\n参数 -s delay 显示每隔多少秒数来显示一次内存使用情况\n参数 -t 显示内存总和列\n参数 -o 不显示缓冲区调节列\nAndroid 为应用进程分配的内存上限保存在ANDROID_SOURCE/system/core/rootdir/init.rc脚本中。\n","permalink":"https://blog.zdltech.com/posts/android%E5%86%85%E5%AD%98%E6%B3%84%E9%9C%B2%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/","summary":"\u003cp\u003e在开发应用过程中，我们可以使用现成的工具来查看内存泄漏的情况。例如DDMS和MAT，MAT是Memory Analyzer Tool的缩写，MAT可以安装eclipse插件（更新地址http://download.eclipse.org/mat/1.4/update-site/），可以使用比插件方便的RCP（下载地址：http://www.eclipse.org/mat/downloads.php）。对于MAT的使用我们暂时不详细讲解，小伙伴们可以去（http://www.eclipse.org/mat/中查看Documentation中查看，里面还有blog可以看）\u003cbr\u003e\n\u003cimg alt=\"图片2\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2014/12/%E5%9B%BE%E7%89%872-300x160.png\"\u003e 。\u003cbr\u003e\n查看内容泄漏的方法步骤：\u003cbr\u003e\n1.生成.hprof文件（使用DDMS生成，有必要的话，我给小伙伴录制一个视频讲解教程）\u003cbr\u003e\n2.使用MAT导入.hprof文件\u003cbr\u003e\n3.使用MAT的视图工具分析内存\u003cbr\u003e\n备注：由于有文件保存，肯定会用到SD卡，用模拟器的小伙伴不要忘记创建SD卡和让测试应用有读写SD卡的权限。如果真的没有SD卡，小伙伴可以使用android.os.Debug中的方法手动指定.hprof的内存（不是运行时内存，指的是系统的内存存储）位置，例如\u003cbr\u003e\nxxxButton.setOnclickListener(new View.OnClickListener(){\u003cbr\u003e\nandroid.os.Debug.dumpHprofData(“/data/tem/XXX.hprof”);//文件路径可以是SD卡路径\u003cbr\u003e\n});如果使用android.os.Debug.dumpHprofData()方法手动生成的.hprof文件，需要使用Android/Tools/ hprofconv xxx.hprof yyy.hprof把原来的xxx.hprof转换成yyy.hprof文件（这个文件才是MAT分析的文件）。\u003c/p\u003e\n\u003cp\u003e目前查看内存分析查找内存泄漏的方法还有以下几种\u003cbr\u003e\n1.使用命令查看某个进程的内存。例如创建一个脚本文件xxx.sh.该文件的内容指定程序1秒钟输出某个进程的内存使用情况 代码如下\u003cbr\u003e\n#！/bin/bash\u003cbr\u003e\nWhile true; do adb shell procrank | grep “进程名称”\u003cbr\u003e\nSleep 1\u003cbr\u003e\ndone\u003cbr\u003e\n2.使用Top命令查看内存\u003cbr\u003e\nAdb shell top -m 10//查看使用资源最多的10个进程\u003cbr\u003e\nAdb shell top|grep 进程名称 //查看指定进程的内存\u003cbr\u003e\n3. free命令\u003cbr\u003e\nFree命令用来显示内存使用情况，使用权限是所有用户。格式如下\u003cbr\u003e\nFree [-b|-k|-m] [-o] [-s delay] [-t] [-v]\u003cbr\u003e\n参数 -b/-k/-m表示以B、KB、MB为单位显示内存使用情况\u003cbr\u003e\n参数 -s delay 显示每隔多少秒数来显示一次内存使用情况\u003cbr\u003e\n参数 -t 显示内存总和列\u003cbr\u003e\n参数 -o 不显示缓冲区调节列\u003c/p\u003e\n\u003cp\u003eAndroid 为应用进程分配的内存上限保存在ANDROID_SOURCE/system/core/rootdir/init.rc脚本中。\u003c/p\u003e","title":"Android内存泄露相关知识总结"},{"content":"Git是一个分布式的版本控制工具，本篇文章从介绍Git开始，重点在于介绍Git的基本命令和使用技巧，让你尝试使用Git的同时，体验到原来一个版 本控制工具可以对开发产生如此之多的影响，文章分为两部分，第一部分介绍Git的一些常用命令，其中穿插介绍Git的基本概念和原理，第二篇重点介绍 Git的使用技巧，最后会在Git Hub上创建一个开源项目开启你的Git实战之旅\n1、Git是什么 Git在Wikipedia上的定义：它是一个免费的、分布式的版本控制工具，或是一个强调了速度快的源代码管理工具。Git最初被Linus Torvalds开发出来用于管理Linux内核的开发。每一个Git的工作目录都是一个完全独立的代码库，并拥有完整的历史记录和版本追踪能力，不依赖 于网络和中心服务器。\nGit的出现减轻了许多开发者和开源项目对于管理分支代码的压力，由于对分支的良好控制，更鼓励开发者对自己感兴趣的项目做出贡献。其实许多开源项目 包括Linux kernel, Samba, X.org Server, Ruby on Rails，都已经过渡到使用Git作为自己的版本控制工具。对于我们这些喜欢写代码的开发者嘛，有两点最大的好处，我们可以在任何地点(在上班的地铁 上)提交自己的代码和查看代码版本;我们可以开许许多多个分支来实践我们的想法，而合并这些分支的开销几乎可以忽略不计。\n2、Git 1+1 现在进入本篇文章真正的主题，介绍一下Git的基本命令和操作，会从Git的版本库的初始化，基本操作和独有的常用命令三部分着手，让大家能够开始使用Git。\nGit通常有两种方式来进行初始化:\ngit clone: 这是较为简单的一种初始化方式，当你已经有一个远程的Git版本库，只需要在本地克隆一份，例如’git clone git://github.com/someone/some_project.git some_project’命令就是将’git://github.com/someone/some_project.git’这个URL地址的远程版 本库完全克隆到本地some_project目录下面\ngit init和git remote：这种方式稍微复杂一些，当你本地创建了一个工作目录，你可以进入这个目录，使用’git init’命令进行初始化，Git以后就会对该目录下的文件进行版本控制，这时候如果你需要将它放到远程服务器上，可以在远程服务器上创建一个目录，并把 可访问的URL记录下来，此时你就可以利用’git remote add’命令来增加一个远程服务器端，例如’git remote add origin git://github.com/someone/another_project.git’这条命令就会增加URL地址为’git: //github.com/someone/another_project.git’，名称为origin的远程服务器，以后提交代码的时候只需要使用 origin别名即可\n3、Git的基本命令 现在我们有了本地和远程的版本库，让我们来试着用用Git的基本命令吧：\n**git pull：**从其他的版本库(既可以是远程的也可以是本地的)将代码更新到本地，例如：’git pull origin master’就是将origin这个版本库的代码更新到本地的master主枝，该功能类似于SVN的update\n**git add：**是将当前更改或者新增的文件加入到Git的索引中，加入到Git的索引中就表示记入了版本历史中，这也是提交之前所需要执行的一步，例如’git add app/model/user.rb’就会增加app/model/user.rb文件到Git的索引中\n**git rm：**从当前的工作空间中和索引中删除文件，例如’git rm app/model/user.rb’\n**git commit：**提交当前工作空间的修改内容，类似于SVN的commit命令，例如’git commit -m “story #3, add user model”‘，提交的时候必须用-m来输入一条提交信息\n**git push：**将本地commit的代码更新到远程版本库中，例如’git push origin’就会将本地的代码更新到名为orgin的远程版本库中\n**git log：**查看历史日志\n**git revert：**还原一个版本的修改，必须提供一个具体的Git版本号，例如’git revert bbaf6fb5060b4875b18ff9ff637ce118256d6f20’，Git的版本号都是生成的一个哈希值、\n上面的命令几乎都是每个版本控制工具所公有的，下面就开始尝试一下Git独有的一些命令：\n4、Git独有的一些命令 ** git branch**：对分支的增、删、查等操作，例如’git branch new_branch’会从当前的工作版本创建一个叫做new_branch的新分支，’git branch -D new_branch’就会强制删除叫做new_branch的分支，’git branch’就会列出本地所有的分支\ngit checkout：Git的checkout有两个作用，其一是在不同的branch之间进行切换，例如 ‘git checkout new_branch’就会切换到new_branch的分支上去;另一个功能是还原代码的作用，例如’git checkout app/model/user.rb’就会将user.rb文件从上一个已提交的版本中更新回来，未提交的内容全部会回滚\ngit rebase：用下面两幅图解释会比较清楚一些，rebase命令执行后，实际上是将分支点从C移到了G，这样分支也就具有了从C到G的功能\ngit reset：将当前的工作目录完全回滚到指定的版本号，假设如下图，我们有A-G五次提交的版本，其中C 的版本号是 bbaf6fb5060b4875b18ff9ff637ce118256d6f20，我们执行了’git reset bbaf6fb5060b4875b18ff9ff637ce118256d6f20’那么结果就只剩下了A-C三个提交的版本\ngit stash：将当前未提交的工作存入Git工作栈中，时机成熟的时候再应用回来，这里暂时提一下这个命令的用法，后面在技巧篇会重点讲解\ngit config：利用这个命令可以新增、更改Git的各种设置，例如’git config branch.master.remote origin’就将master的远程版本库设置为别名叫做origin版本库，后面在技巧篇会利用这个命令个性化设置你的Git，为你打造独一无二的 Git\ngit tag：可以将某个具体的版本打上一个标签，这样你就不需要记忆复杂的版本号哈希值了，例如你可以使用 ‘git tag revert_version bbaf6fb5060b4875b18ff9ff637ce118256d6f20’来标记这个被你还原的版本，那么以后你想查看该版本时，就可以使用 revert_version标签名，而不是哈希值了\nGit之所以能够提供方便的本地分支等特性，是与它的文件存储机制有关的。Git存储版本控制信息时使用它自己定义的一套文件系统存储机制，在代码根目录下有一个.git文件夹，会有如下这样的目录结构：\n![Git使用基础篇 ](http://static.open-open.com/lib/uploadImg/20120328/20120328111443_875.png) \u0026nbsp; 有几个比较重要的文件和目录需要解释一下：HEAD文件存放根节点的信息，其实目录结构就表示一个树型结构，Git采用这种树形结构来存储版本信息， 那么HEAD就表示根;refs目录存储了你在当前版本控制目录下的各种不同引用(引用指的是你本地和远程所用到的各个树分支的信息)，它有heads、 remotes、stash、tags四个子目录，分别存储对不同的根、远程版本库、Git栈和标签的四种引用，你可以通过命令’git show-ref’更清晰地查看引用信息;logs目录根据不同的引用存储了日志信息。因此，Git只需要代码根目录下的这一个.git目录就可以记录完 整的版本控制信息，而不是像SVN那样根目录和子目录下都有.svn目录。那么下面就来看一下Git与SVN的区别吧\n5、Git与SVN的不同 SVN(Subversion)是当前使用最多的版本控制工具。与它相比较，Git最大的优势在于两点：易于本地增加分支和分布式的特性。\n下面两幅图可以形象的展示Git与SVN的不同之处\n对于易于本地增加分支，图中Git本地和服务器端结构都很灵活，所有版本都存储在一个目录中，你只需要进行分支的切换即可达到在某个分支工作的效果。 而SVN则完全不同，如果你需要在本地试验一些自己的代码，只能本地维护多个不同的拷贝，每个拷贝对应一个SVN服务器地址。举一个实际的例子，以前我所 在的小组使用SVN作为版本控制工具，当我正在试图增强一个模块，工作做到一半，由于会改变原模块的行为导致代码服务器上许多测试的失败，所以并没有提交 代码。这时候上级对我说，现在有一个很紧急的Bug需要处理， 必须在两个小时内完成。我只好将本地的所有修改diff，并输出成为一个patch文件，然后回滚有关当前任务的所有代码，再开始修改Bug的任务，等到 修改好后，在将patch应用回来。前前后后要完成多个繁琐的步骤，这还不计中间代码发生冲突所要进行的工作量。可是如果使用Git， 我们只需要开一个分支或者转回到主分支上，就可以随时开始Bug修改的任务，完成之后，只要切换到原来的分支就可以优雅的继续以前的任务。只要你愿意，每 一个新的任务都可以开一个分支，完成后，再将它合并到主分支上，轻松而优雅。\n分布式对于Git而言，你可以本地提交代码，所以在上面的图中，Git有利于将一个大任务分解，进行本地的多次提交，而SVN只能在本地进行大量的一 次性更改，导致将来合并到主干上造成巨大的风险。Git的代码日志是在本地的，可以随时查看。SVN的日志在服务器上的，每次查看日志需要先从服务器上下 载下来。我工作的小组，代码服务器在美国，每次查看小组几年前所做的工作时，日志下载就需要十分钟，这不能不说是一个痛苦。后来我们迁移到Git上，利用 Git日志在本地的特性，我用Ruby编写了一个Rake脚本，可以查看某个具体任务的所有代码历史，每次只需要几秒钟，大大方便我的工作。当然分布式并 不是说用了Git就不需要一个代码中心服务器，如果你工作在一个团队里，还是需要一个服务器来保存所有的代码的。\n** 总结**\n本篇介绍了Git的基本概念、一些常用命令和原理，大家可以尝试动手体会一下，下一篇会重点介绍Git命令的使用技巧，Git附带的工具，最后会在Git Hub上创建一个开源项目。\n转自：http://www.open-open.com/lib/view/open1332904495999.html\nGit 常用命令详解（二） Git 是一个很强大的分布式版本管理工具，它不但适用于管理大型开源软件的源代码（如：linux kernel），管理私人的文档和源代码也有很多优势（如：wsi-lgame-pro）\nGit 的更多介绍，请参考我的上一篇博客：Git 版本管理工具\n一、 Git 命令初识\n在正式介绍Git命令之前，先介绍一下Git 的基本命令和操作，对Git命令有一个总体的认识\n示例：从Git 版本库的初始化，通常有两种方式：\n1）git clone：这是一种较为简单的初始化方式，当你已经有一个远程的Git版本库，只需要在本地克隆一份\n例如：git clone git://github.com/someone/some_project.git some_project\n上面的命令就是将’git://github.com/someone/some_project.git’这个URL地址的远程版本库，完全克隆到本地some_project目录下\n2）git init 和 git remote：这种方式稍微复杂一些，当你本地创建了一个工作目录，你可以进入这个目录，使用’git init’命令进行初始化；Git以后就会对该目录下的文件进行版本控制，这时候如果你需要将它放到远程服务器上，可以在远程服务器上创建一个目录，并把可访问的URL记录下来，此时你就可以利用’git remote add’命令来增加一个远程服务器端，\n例如：git remote add origin git://github.com/someone/another_project.git\n上面的命令就会增加URL地址为’git: //github.com/someone/another_project.git’，名称为origin的远程服务器，以后提交代码的时候只需要使用 origin别名即可\n**二、 Git 常用命令\n远程仓库相关命令 检出仓库： git clone git://github.com/jquery/jquery.git\n查看远程仓库： git remote -v\n添加远程仓库：git remote add [name] [url]\n删除远程仓库：\u0026lt;/span\u0026gt; git remote rm [name] 拉取远程仓库：\u0026lt;/span\u0026gt; git pull [remoteName] [localBranchName] 推送远程仓库：\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;git push [remoteName] [localBranchName] *如果想把本地的某个分支test提交到远程仓库，并作为远程仓库的master分支，或者作为另外一个名叫test的分支，如下：git push origin test:master // 提交本地test分支作为远程的master分支\n$git push origin test:test // 提交本地test分支作为远程的test分支 **2）分支(branch)操作相关命令** 查看本地分支：\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;git branch 查看远程分支：\u0026lt;/span\u0026gt; git branch -r 创建本地分支：\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;git branch [name] \u0026amp;#8212;-注意新分支创建后不会自动切换为当前分支 切换分支：\u0026lt;/span\u0026gt; git checkout [name] 创建新分支并立即切换到新分支：\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;git checkout -b [name] 删除分支：\u0026lt;/span\u0026gt; git branch -d [name] \u0026amp;#8212;- -d选项只能删除已经参与了合并的分支，对于未有合并的分支是无法删除的。如果想强制删除一个分支，可以使用-D选项 合并分支：\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;git merge [name] \u0026amp;#8212;-将名称为[name]的分支与当前分支合并 创建远程分支(本地分支push到远程)：\u0026lt;/span\u0026gt; git push origin [name] 删除远程分支：\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;git push origin :heads/[name] 或\u0026lt;/span\u0026gt; gitpush origin :[name] *创建空的分支：(执行命令之前记得先提交你当前分支的修改，否则会被强制删干净没得后悔)\n\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;git symbolic-ref HEAD refs/heads/[name]\u0026lt;/span\u0026gt;rm .git/index $git clean -fdx **3）版本(tag)操作相关命令** 查看版本：\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;git tag 创建版本：\u0026lt;/span\u0026gt; git tag [name] 删除版本：\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;git tag -d [name] 查看远程版本：\u0026lt;/span\u0026gt; git tag -r 创建远程版本(本地版本push到远程)：\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;git push origin [name] 删除远程版本：\u0026lt;/span\u0026gt; git push origin :refs/tags/[name] 创建带注释的tag：$ git tag -a [name] -m \u0026amp;#8216;yourMessage\u0026amp;#8217; **4) 子模块(submodule)相关操作命令** 添加子模块：\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;git submodule add [url] [path] 如：\u0026lt;/span\u0026gt;git submodule add git://github.com/soberh/ui-libs.git src/main/webapp/ui-libs 初始化子模块：\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;git submodule init \u0026amp;#8212;-只在首次检出仓库时运行一次就行 更新子模块：\u0026lt;/span\u0026gt; git submodule update \u0026amp;#8212;-每次更新或切换分支后都需要运行一下 \u0026amp;nbsp; 删除子模块：（分4步走哦） 2) 编辑“.gitmodules”文件，将子模块的相关配置节点删除掉 3) 编辑“ .git/config”文件，将子模块的相关配置节点删除掉 4) 手动删除子模块残留的目录 **5）忽略一些文件、文件夹不提交** 在仓库根目录下创建名称为“.gitignore”的文件，写入不需要的文件夹名或文件，每个元素占一行即可，如 target bin *.db **三、 Git 命令详解** 现在我们有了本地和远程的版本库，让我们来试着用用Git的基本命令： **git pull：**从其他的版本库（既可以是远程的也可以是本地的）将代码更新到本地，例如：\u0026amp;#8217;git pull origin master\u0026amp;#8217;就是将origin这个版本库的代码更新到本地的master主枝，该功能类似于SVN的**update** **git add：**是将当前更改或者新增的文件加入到Git的索引中，加入到Git的索引中就表示记入了版本历史中，这也是提交之前所需要执行的一步，例如\u0026amp;#8217;git add app/model/user.rb\u0026amp;#8217;就会增加app/model/user.rb文件到Git的索引中，该功能类似于SVN的**add** **git rm：**从当前的工作空间中和索引中删除文件，例如\u0026amp;#8217;git rm app/model/user.rb\u0026amp;#8217;，该功能类似于SVN的**rm、del** **git commit：**提交当前工作空间的修改内容，类似于SVN的commit命令，例如\u0026amp;#8217;git commit -m story #3, add user model\u0026amp;#8217;，提交的时候必须用-m来输入一条提交信息，该功能类似于SVN的**commit** **git push：**将本地commit的代码更新到远程版本库中，例如\u0026amp;#8217;git push origin\u0026amp;#8217;就会将本地的代码更新到名为orgin的远程版本库中 **git log：**查看历史日志，该功能类似于SVN的**log** **git revert：**还原一个版本的修改，必须提供一个具体的Git版本号，例如\u0026amp;#8217;git revert bbaf6fb5060b4875b18ff9ff637ce118256d6f20\u0026amp;#8217;，Git的版本号都是生成的一个哈希值 \u0026amp;nbsp; 上面的命令几乎都是每个版本控制工具所公有的，下面就开始尝试一下Git独有的一些命令： **git branch：**对分支的增、删、查等操作，例如\u0026amp;#8217;git branch new_branch\u0026amp;#8217;会从当前的工作版本创建一个叫做new_branch的新分支，\u0026amp;#8217;git branch -D new_branch\u0026amp;#8217;就会强制删除叫做new_branch的分支，\u0026amp;#8217;git branch\u0026amp;#8217;就会列出本地所有的分支 **git checkout：**Git的checkout有两个作用，其一是在不同的branch之间进行切换，例如\u0026amp;#8217;git checkout new_branch\u0026amp;#8217;就会切换到new_branch的分支上去；另一个功能是还原代码的作用，例如\u0026amp;#8217;git checkout app/model/user.rb\u0026amp;#8217;就会将user.rb文件从上一个已提交的版本中更新回来，未提交的内容全部会回滚 **git rebase：**用下面两幅图解释会比较清楚一些，rebase命令执行后，实际上是将分支点从C移到了G，这样分支也就具有了从C到G的功能 \u0026amp;nbsp; [![](http://static.oschina.net/uploads/img/201301/06111738_OSuY.png)](http://static.oschina.net/uploads/img/201301/06111738_OSuY.png) **git reset：**将当前的工作目录完全回滚到指定的版本号，假设如下图，我们有A-G五次提交的版本，其中C的版本号是 bbaf6fb5060b4875b18ff9ff637ce118256d6f20，我们执行了\u0026amp;#8217;git reset bbaf6fb5060b4875b18ff9ff637ce118256d6f20\u0026amp;#8217;那么结果就只剩下了A-C三个提交的版本 \u0026amp;nbsp; [![](http://static.oschina.net/uploads/img/201301/06111738_eug0.png)](http://static.oschina.net/uploads/img/201301/06111738_eug0.png) **git stash：**将当前未提交的工作存入Git工作栈中，时机成熟的时候再应用回来，这里暂时提一下这个命令的用法，后面在技巧篇会重点讲解 **git config：**利用这个命令可以新增、更改Git的各种设置，例如\u0026amp;#8217;git config branch.master.remote origin\u0026amp;#8217;就将master的远程版本库设置为别名叫做origin版本库，后面在技巧篇会利用这个命令个性化设置你的Git，为你打造独一无二的 Git **git tag：**可以将某个具体的版本打上一个标签，这样你就不需要记忆复杂的版本号哈希值了，例如你可以使用\u0026amp;#8217;git tag revert_version bbaf6fb5060b4875b18ff9ff637ce118256d6f20\u0026amp;#8217;来标记这个被你还原的版本，那么以后你想查看该版本时，就可以使用 revert_version标签名，而不是哈希值了 Git 之所以能够提供方便的本地分支等特性，是与它的文件存储机制有关的。Git存储版本控制信息时使用它自己定义的一套文件系统存储机制，在代码根目录下有一个.git文件夹，会有如下这样的目录结构： \u0026amp;nbsp; [![](http://static.oschina.net/uploads/img/201301/06111739_Cqas.png)](http://static.oschina.net/uploads/img/201301/06111739_Cqas.png) 有几个比较重要的文件和目录需要解释一下：HEAD文件存放根节点的信息，其实目录结构就表示一个树型结构，Git采用这种树形结构来存储版本信息，那么HEAD就表示根；refs目录存储了你在当前版本控制目录下的各种不同引用（引用指的是你本地和远程所用到的各个树分支的信息），它有heads、remotes、stash、tags四个子目录，分别存储对不同的根、远程版本库、Git栈和标签的四种引用，你可以通过命令’git show-ref’更清晰地查看引用信息；logs目录根据不同的引用存储了日志信息。因此，Git只需要代码根目录下的这一个.git目录就可以记录完整的版本控制信息，而不是像SVN那样根目录和子目录下都有.svn目录。那么下面就来看一下Git与SVN的区别吧\n\u0026amp;nbsp; **四、 Git 与SVN 比较** **SVN**（Subversion）是当前使用最多的版本控制工具。与它相比较，**Git **最大的优势在于两点：易于本地增加分支和分布式的特性。 下面两幅图可以形象的展示Git与SVN的不同之处： \u0026amp;nbsp; [![](http://static.oschina.net/uploads/img/201301/06111739_b04y.png)](http://static.oschina.net/uploads/img/201301/06111739_b04y.png) \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212; [![](http://static.oschina.net/uploads/img/201301/06111739_c2d0.png)](http://static.oschina.net/uploads/img/201301/06111739_c2d0.png) \u0026amp;nbsp; 1）本地增加分支 图中Git本地和服务器端结构都很灵活，所有版本都存储在一个目录中，你只需要进行分支的切换即可达到在某个分支工作的效果 而SVN则完全不同，如果你需要在本地试验一些自己的代码，只能本地维护多个不同的拷贝，每个拷贝对应一个SVN服务器地址 举一个实际的例子： 使用SVN作为版本控制工具，当正在试图增强一个模块，工作做到一半，由于会改变原模块的行为导致代码服务器上许多测试的失败，所以并没有提交代码。 这时候假如现在有一个很紧急的Bug需要处理， 必须在两个小时内完成。我只好将本地的所有修改diff，并输出成为一个patch文件，然后回滚有关当前任务的所有代码，再开始修改Bug的任务，等到修改好后，在将patch应用回来。前前后后要完成多个繁琐的步骤，这还不计中间代码发生冲突所要进行的工作量。 可是如果使用Git， 我们只需要开一个分支或者转回到主分支上，就可以随时开始Bug修改的任务，完成之后，只要切换到原来的分支就可以优雅的继续以前的任务。只要你愿意，每一个新的任务都可以开一个分支，完成后，再将它合并到主分支上，轻松而优雅。 2）分布式提交 Git 可以本地提交代码，所以在上面的图中，Git有利于将一个大任务分解，进行本地的多次提交 而SVN只能在本地进行大量的一次性更改，导致将来合并到主干上造成巨大的风险 3）日志查看 Git 的代码日志是在本地的，可以随时查看 SVN的日志在服务器上的，每次查看日志需要先从服务器上下载下来 例如：代码服务器在美国，当每次查看几年前所做的工作时，日志下载可能需要十分钟，这不能不说是一个痛苦。但是如果迁移到Git上，利用Git日志在本地的特性，查看某个具体任务的所有代码历史，每次只需要几秒钟，大大方便了工作，提高了效率。 当然分布式并不是说用了Git就不需要一个代码中心服务器，如果你工作在一个团队里，还是需要一个服务器来保存所有的代码的。 \u0026amp;nbsp; **五、 总结** 上面简单介绍了Git 的基本概念、一些常用命令和原理，大家也可以尝试动手，在Google Code 或 GitHub 上创建一个自己的开源项目 \u0026amp;nbsp; ","permalink":"https://blog.zdltech.com/posts/git%E4%BD%BF%E7%94%A8%E5%9F%BA%E7%A1%80%E7%AF%87/","summary":"\u003cp\u003eGit是一个分布式的版本控制工具，本篇文章从介绍Git开始，重点在于介绍Git的基本命令和使用技巧，让你尝试使用Git的同时，体验到原来一个版 本控制工具可以对开发产生如此之多的影响，文章分为两部分，第一部分介绍Git的一些常用命令，其中穿插介绍Git的基本概念和原理，第二篇重点介绍 Git的使用技巧，最后会在Git Hub上创建一个开源项目开启你的Git实战之旅\u003c/p\u003e\n\u003ch1 id=\"1git是什么\"\u003e1、Git是什么\u003c/h1\u003e\n\u003cp\u003eGit在Wikipedia上的定义：它是一个免费的、分布式的版本控制工具，或是一个强调了速度快的源代码管理工具。Git最初被Linus Torvalds开发出来用于管理Linux内核的开发。每一个Git的工作目录都是一个完全独立的代码库，并拥有完整的历史记录和版本追踪能力，不依赖 于网络和中心服务器。\u003c/p\u003e\n\u003cp\u003eGit的出现减轻了许多开发者和开源项目对于管理分支代码的压力，由于对分支的良好控制，更鼓励开发者对自己感兴趣的项目做出贡献。其实许多开源项目 包括Linux kernel, Samba, X.org Server, Ruby on Rails，都已经过渡到使用Git作为自己的版本控制工具。对于我们这些喜欢写代码的开发者嘛，有两点最大的好处，我们可以在任何地点(在上班的地铁 上)提交自己的代码和查看代码版本;我们可以开许许多多个分支来实践我们的想法，而合并这些分支的开销几乎可以忽略不计。\u003c/p\u003e\n\u003ch1 id=\"2git-11\"\u003e2、Git 1+1\u003c/h1\u003e\n\u003cp\u003e现在进入本篇文章真正的主题，介绍一下Git的基本命令和操作，会从Git的版本库的初始化，基本操作和独有的常用命令三部分着手，让大家能够开始使用Git。\u003c/p\u003e\n\u003cp\u003eGit通常有两种方式来进行初始化:\u003c/p\u003e\n\u003cp\u003egit clone: 这是较为简单的一种初始化方式，当你已经有一个远程的Git版本库，只需要在本地克隆一份，例如’git clone git://github.com/someone/some_project.git some_project’命令就是将’git://github.com/someone/some_project.git’这个URL地址的远程版 本库完全克隆到本地some_project目录下面\u003c/p\u003e\n\u003cp\u003egit init和git remote：这种方式稍微复杂一些，当你本地创建了一个工作目录，你可以进入这个目录，使用’git init’命令进行初始化，Git以后就会对该目录下的文件进行版本控制，这时候如果你需要将它放到远程服务器上，可以在远程服务器上创建一个目录，并把 可访问的URL记录下来，此时你就可以利用’git remote add’命令来增加一个远程服务器端，例如’git remote add origin git://github.com/someone/another_project.git’这条命令就会增加URL地址为’git: //github.com/someone/another_project.git’，名称为origin的远程服务器，以后提交代码的时候只需要使用 origin别名即可\u003c/p\u003e\n\u003ch1 id=\"3git的基本命令\"\u003e3、Git的基本命令\u003c/h1\u003e\n\u003cp\u003e现在我们有了本地和远程的版本库，让我们来试着用用Git的基本命令吧：\u003c/p\u003e\n\u003cp\u003e**git pull：**从其他的版本库(既可以是远程的也可以是本地的)将代码更新到本地，例如：’git pull origin master’就是将origin这个版本库的代码更新到本地的master主枝，该功能类似于SVN的update\u003c/p\u003e\n\u003cp\u003e**git add：**是将当前更改或者新增的文件加入到Git的索引中，加入到Git的索引中就表示记入了版本历史中，这也是提交之前所需要执行的一步，例如’git add app/model/user.rb’就会增加app/model/user.rb文件到Git的索引中\u003c/p\u003e\n\u003cp\u003e**git rm：**从当前的工作空间中和索引中删除文件，例如’git rm app/model/user.rb’\u003c/p\u003e\n\u003cp\u003e**git commit：**提交当前工作空间的修改内容，类似于SVN的commit命令，例如’git commit -m “story #3, add user model”‘，提交的时候必须用-m来输入一条提交信息\u003c/p\u003e\n\u003cp\u003e**git push：**将本地commit的代码更新到远程版本库中，例如’git push origin’就会将本地的代码更新到名为orgin的远程版本库中\u003c/p\u003e","title":"Git使用基础篇"},{"content":"获取Mac地址实际项目中测试了如下几种方法:\n(1)设备开通Wifi连接，获取到网卡的MAC地址(但是不开通wifi，这种方法获取不到Mac地址，这种方法也是网络上使用的最多的方法)\n``` //根据Wifi信息获取本地Mac public static String getLocalMacAddressFromWifiInfo(Context context){ WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); WifiInfo info = wifi.getConnectionInfo(); return info.getMacAddress(); } ``` (2)调用Linux的busybox，通过linux命令来获取\n[![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) //根据busybox获取本地Mac public static String getLocalMacAddressFromBusybox(){ String result = \u0026#34;\u0026#34;; String Mac = \u0026#34;\u0026#34;; result = callCmd(\u0026#34;busybox ifconfig\u0026#34;,\u0026#34;HWaddr\u0026#34;); //如果返回的result == null，则说明网络不可取 if(result==null){ return \u0026#34;网络出错，请检查网络\u0026#34;; } //对该行数据进行解析 //例如：eth0 Link encap:Ethernet HWaddr 00:16:E8:3E:DF:67 if(result.length()\u0026amp;gt;0 \u0026amp;\u0026amp; result.contains(\u0026#34;HWaddr\u0026#34;)==true){ Mac = result.substring(result.indexOf(\u0026#34;HWaddr\u0026#34;)+6, result.length()-1); Log.i(\u0026#34;test\u0026#34;,\u0026#34;Mac:\u0026#34;+Mac+\u0026#34; Mac.length: \u0026#34;+Mac.length()); /*if(Mac.length()\u0026amp;gt;1){ Mac = Mac.replaceAll(\u0026#34; \u0026#34;, \u0026#34;\u0026#34;); result = \u0026#34;\u0026#34;; String[] tmp = Mac.split(\u0026#34;:\u0026#34;); for(int i = 0;i\u0026amp;lt;tmp.length;++i){ result +=tmp[i]; } }*/ result = Mac; Log.i(\u0026#34;test\u0026#34;,result+\u0026#34; result.length: \u0026#34;+result.length()); } return result; } private static String callCmd(String cmd,String filter) { String result = \u0026#34;\u0026#34;; String line = \u0026#34;\u0026#34;; try { Process proc = Runtime.getRuntime().exec(cmd); InputStreamReader is = new InputStreamReader(proc.getInputStream()); BufferedReader br = new BufferedReader (is); //执行命令cmd，只取结果中含有filter的这一行 while ((line = br.readLine ()) != null \u0026amp;\u0026amp; line.contains(filter)== false) { //result += line; Log.i(\u0026#34;test\u0026#34;,\u0026#34;line: \u0026#34;+line); } result = line; Log.i(\u0026#34;test\u0026#34;,\u0026#34;result: \u0026#34;+result); } catch(Exception e) { e.printStackTrace(); } return result; } [![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) (3)调用android 的API： NetworkInterface. getHardwareAddress ()\n该API的level为9，只有android 2.3以上才有该接口\n[![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) //根据IP获取本地Mac public static String getLocalMacAddressFromIp(Context context) { String mac_s= \u0026#34;\u0026#34;; try { byte[] mac; NetworkInterface ne=NetworkInterface.getByInetAddress(InetAddress.getByName(getLocalIpAddress())); mac = ne.getHardwareAddress(); mac_s = byte2hex(mac); } catch (Exception e) { e.printStackTrace(); } return mac_s; } public static String byte2hex(byte[] b) { StringBuffer hs = new StringBuffer(b.length); String stmp = \u0026#34;\u0026#34;; int len = b.length; for (int n = 0; n \u0026amp;lt; len; n++) { stmp = Integer.toHexString(b[n] \u0026amp; 0xFF); if (stmp.length() == 1) hs = hs.append(\u0026#34;0\u0026#34;).append(stmp); else { hs = hs.append(stmp); } } return String.valueOf(hs); } [![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) 其中getLocalIpAddress是获取本地IP地址\n[![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) //获取本地IP public static String getLocalIpAddress() { try { for (Enumeration\u0026amp;lt;NetworkInterface\u0026amp;gt; en = NetworkInterface .getNetworkInterfaces(); en.hasMoreElements();) { NetworkInterface intf = en.nextElement(); for (Enumeration\u0026amp;lt;InetAddress\u0026amp;gt; enumIpAddr = intf .getInetAddresses(); enumIpAddr.hasMoreElements();) { InetAddress inetAddress = enumIpAddr.nextElement(); if (!inetAddress.isLoopbackAddress()) { return inetAddress.getHostAddress().toString(); } } } } catch (SocketException ex) { Log.e(\u0026#34;WifiPreference IpAddress\u0026#34;, ex.toString()); } return null; } [![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) 获取本地IP地址\n在网络上搜索一下，一般就有如下的代码:\n[![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) //获取本地IP public static String getLocalIpAddress() { try { for (Enumeration\u0026amp;lt;NetworkInterface\u0026amp;gt; en = NetworkInterface .getNetworkInterfaces(); en.hasMoreElements();) { NetworkInterface intf = en.nextElement(); for (Enumeration\u0026amp;lt;InetAddress\u0026amp;gt; enumIpAddr = intf .getInetAddresses(); enumIpAddr.hasMoreElements();) { InetAddress inetAddress = enumIpAddr.nextElement(); if (!inetAddress.isLoopbackAddress()) { return inetAddress.getHostAddress().toString(); } } } } catch (SocketException ex) { Log.e(\u0026#34;WifiPreference IpAddress\u0026#34;, ex.toString()); } return null; } [![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) 但是经过测试该方法在android2.3, 2.2…较老版本有效，但是在android较新版本(例如4.0等)获取的数据不正确。\n获取到了类似fe80::b607:f9ff:fee5:487e..这样的IP地址。经过一番努力，终于找出原因。\n上面的IP地址是IPV6的地址形式（大概这个意思，具体没有太深入研究）。解决方法是，在上面代码中的最内层的for循环的if语句中对inetAddress进行格式判断，只有其是IPV4格式地址时，才返回值。修改后代码如下：(下面的方法也是网络上的方法，没有结果验证)\n[![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) public String getLocalIpAddress() { try { String ipv4; List nilist = Collections.list(NetworkInterface.getNetworkInterfaces()); for (NetworkInterface ni: nilist) { List ialist = Collections.list(ni.getInetAddresses()); for (InetAddress address: ialist){ if (!address.isLoopbackAddress() \u0026amp;\u0026amp; InetAddressUtils.isIPv4Address(ipv4=address.getHostAddress())) { return ipv4; } } } } catch (SocketException ex) { Log.e(LOG_TAG, ex.toString()); } return null; } [![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) 网络上还有一种方法来获取本地IP地址(不过是在wifi状态下)\n通过WifiManager， DhcpInfo获取IP地址以及网关等信息（在android4.0等版本也适用）\n[![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) package com.jason.demo.androidip; import android.content.Context; import android.net.DhcpInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.text.format.Formatter; public class IPAddress { public String getIPAddress(Context ctx){ WifiManager wifi_service = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE); DhcpInfo dhcpInfo = wifi_service.getDhcpInfo(); WifiInfo wifiinfo = wifi_service.getConnectionInfo(); System.out.println(\u0026#34;Wifi info-----\u0026amp;gt;\u0026#34;+wifiinfo.getIpAddress()); System.out.println(\u0026#34;DHCP info gateway-----\u0026amp;gt;\u0026#34;+Formatter.formatIpAddress(dhcpInfo.gateway)); System.out.println(\u0026#34;DHCP info netmask-----\u0026amp;gt;\u0026#34;+Formatter.formatIpAddress(dhcpInfo.netmask)); //DhcpInfo中的ipAddress是一个int型的变量，通过Formatter将其转化为字符串IP地址 return Formatter.formatIpAddress(dhcpInfo.ipAddress); } } [![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) 加入permission\n不过我自己在做项目过程中，用另外一种方法也解决了android4.0获取IP错误的问题:\n[![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) //获取本地IP public static String getLocalIpAddress() { try { for (Enumeration\u0026amp;lt;NetworkInterface\u0026amp;gt; en = NetworkInterface .getNetworkInterfaces(); en.hasMoreElements();) { NetworkInterface intf = en.nextElement(); for (Enumeration\u0026amp;lt;InetAddress\u0026amp;gt; enumIpAddr = intf .getInetAddresses(); enumIpAddr.hasMoreElements();) { InetAddress inetAddress = enumIpAddr.nextElement(); if (!inetAddress.isLoopbackAddress() \u0026amp;\u0026amp; !inetAddress.isLinkLocalAddress()) { return inetAddress.getHostAddress().toString(); } } } } catch (SocketException ex) { Log.e(\u0026#34;WifiPreference IpAddress\u0026#34;, ex.toString()); } return null; } [![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html) 参考博文:\nhttp://www.cnblogs.com/Amandaliu/archive/2011/11/06/2238177.html\nAndroid获取Mac地址\nhttp://blog.csdn.net/ccf0703/article/details/7451274\n解决安卓4.0获取本地IP地址问题。\nhttp://blog.csdn.net/garybook/article/details/7874456\n通过WifiManager,DhcpInfo获取android IP地址及网关等信息(两种方式)\nhttp://blog.csdn.net/lizzydarcymsp/article/details/5623302\n利用InetAddress类确定特殊IP地址 (isLinkLocalAddress,isLoopbackAddress等)\n","permalink":"https://blog.zdltech.com/posts/android%E8%8E%B7%E5%8F%96mac%E5%9C%B0%E5%9D%80%E5%92%8Cip%E5%9C%B0%E5%9D%80/","summary":"\u003cp\u003e获取Mac地址实际项目中测试了如下几种方法:\u003cbr\u003e\n(1)设备开通Wifi连接，获取到网卡的MAC地址(但是不开通wifi，这种方法获取不到Mac地址，这种方法也是网络上使用的最多的方法)\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  ```\n//根据Wifi信息获取本地Mac\n     public static String getLocalMacAddressFromWifiInfo(Context context){\n         WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);  \n         WifiInfo info = wifi.getConnectionInfo();  \n         return info.getMacAddress(); \n     }\n```\n\u003c/div\u003e\n\u003cp\u003e(2)调用Linux的busybox，通过linux命令来获取\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e[![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html)\u003c/span\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e//根据busybox获取本地Mac\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   public static String getLocalMacAddressFromBusybox(){   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       String result = \u0026#34;\u0026#34;;     \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       String Mac = \u0026#34;\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       result = callCmd(\u0026#34;busybox ifconfig\u0026#34;,\u0026#34;HWaddr\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       //如果返回的result == null，则说明网络不可取\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       if(result==null){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           return \u0026#34;网络出错，请检查网络\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       //对该行数据进行解析\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       //例如：eth0      Link encap:Ethernet  HWaddr 00:16:E8:3E:DF:67\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       if(result.length()\u0026amp;gt;0 \u0026amp;\u0026amp; result.contains(\u0026#34;HWaddr\u0026#34;)==true){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           Mac = result.substring(result.indexOf(\u0026#34;HWaddr\u0026#34;)+6, result.length()-1);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           Log.i(\u0026#34;test\u0026#34;,\u0026#34;Mac:\u0026#34;+Mac+\u0026#34; Mac.length: \u0026#34;+Mac.length());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           /*if(Mac.length()\u0026amp;gt;1){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               Mac = Mac.replaceAll(\u0026#34; \u0026#34;, \u0026#34;\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               result = \u0026#34;\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               String[] tmp = Mac.split(\u0026#34;:\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               for(int i = 0;i\u0026amp;lt;tmp.length;++i){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                   result +=tmp[i];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           }*/\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           result = Mac;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           Log.i(\u0026#34;test\u0026#34;,result+\u0026#34; result.length: \u0026#34;+result.length());            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       return result;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   }   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   private static String callCmd(String cmd,String filter) {   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       String result = \u0026#34;\u0026#34;;   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       String line = \u0026#34;\u0026#34;;   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       try {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           Process proc = Runtime.getRuntime().exec(cmd);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           InputStreamReader is = new InputStreamReader(proc.getInputStream());   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           BufferedReader br = new BufferedReader (is);   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           //执行命令cmd，只取结果中含有filter的这一行\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           while ((line = br.readLine ()) != null \u0026amp;\u0026amp; line.contains(filter)== false) {   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               //result += line;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               Log.i(\u0026#34;test\u0026#34;,\u0026#34;line: \u0026#34;+line);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           result = line;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           Log.i(\u0026#34;test\u0026#34;,\u0026#34;result: \u0026#34;+result);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       }   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       catch(Exception e) {   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           e.printStackTrace();   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       }   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e       return result;   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e[![复制代码](http://common.cnblogs.com/images/copycode.gif)](http://www.cnblogs.com/lijunamneg/archive/2013/03/04/2943146.html)\u003c/span\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e(3)调用android 的API： NetworkInterface. getHardwareAddress ()\u003cbr\u003e\n该API的level为9，只有android 2.3以上才有该接口\u003c/p\u003e","title":"android获取Mac地址和IP地址"},{"content":"随着android 5.0 的发布，android 开发已经进入了一个全新的时代，eclipse开发安卓已经有点不合时宜了，在github上80%的android项目都采用android studio开发，而且android studio的中文教程越来越多，还有什么理由不固守这eclipse 呢。\n下面这篇文章对了解android studio 很有帮助，原文如下：\nGoogle在2013的I/O开发者大会上引入的该开发工具。现在已经更新到了0.5.8版本。\n现在github的很多项目都使用了Android Studio开发，所以如果你还用Eclipse，就需要把整个项目拆分，\n然后在工程中include依赖包，是非常费事的，有时候弄了半天还不一定能成功导入。而且Android开发者工具的未来的趋势一定也是转向Android Studio。\n介于种种原因，不得不学习使用Android Studio,Android Studio的项目管理使用了Gradle，所以你需要对Gradle进行简单的理解，可以到官网去看下。\nGradle官网\nhttp://www.gradle.org\n因为Android 是在IntelliJ IDEA的基础上开发的，所以可以参考\nIntelliJ IDEA 的官方帮助地址\nhttp://www.jetbrains.com/idea/webhelp/getting-help.html\n简单引入一些概念：（有些是来自个人的官方翻译有些是copy过来的） ** **\nAndroid Studio 建立系统工具包你用来生成，测试，运行您的应用程序和软件包。构建系统是独立于Android的工作室，所以你可以调用它的Android的工作室或从命令行。在你写你的应用程序，你可以使用编译系统的特点：\n定制，配置，和扩展的建立过程。\n为您的应用程序使用同一项目的不同特点，创建多个应用程序。\n重用代码和资源。\nAndroidStudio构建系统由Gradle构成。Gradle是一种高级的构建工具，用于管理依赖性，允许你定义自定义构建逻辑。\nAndroid插件工具并不依赖于Android Studio，虽然Android Studio由它完全集成。\nGradle的配置包含以下方面 构建变量\n构建系统可以根据不同的配置为同一个项目生成多个APK。当你想建立不同版本的应用程序，而不必为每个人单独的项目，这是很有用的。\n依赖关系\n构建系统管理项目的依赖，并从本地文件系统和远程存储库支持的依赖。这可以防止你不必搜索，下载和复制二进制包为你的依赖到你的项目目录。\n清单条目\n构建系统使您可以指定的值在生成配置清单文件中的某些元素。这些新的值将覆盖在manifest文件中的现有值。如果你想生成多个的\nAPK为您的项目中，他们每个人都有不同的包名，最小的SDK版本，或目标SDK版本，这是很有用的。\n签名\n构建系统使您可以指定生成配置签名设置，它可以在生成过程中签署您的APK。\nProGuard 构建系统使您可以指定一个不同的 ProGuard的规则文件的每个版本变量。构建系统可以运行ProGuard的生成过程来混淆你的类。\n测试\n构建系统生成的项目中的测试源测试APK，所以你不必创建一个单独的测试项目。构建系统可以在生成过程中运行测试。\nGradle构建文件使用Groovy的语法。Groovy是一种动态语言，你可以用它来 定义自定义生成逻辑，并与Android的插件Gradle提供了Android特有的元素进行交互。\n按照惯例建立\nAndroid Studio生成系统假定合理的默认值的项目结构和其他编译选项。\n如果您的项目符合这些约定，你的Gradle构建文件是很简单的。当一些这些公约并不适用于你的项目,使您可以配置生成过程的几乎每一个方面。\n例如，如果您的项目的源位于比默认值不同的目录，你可以在构建文件中指定此位置。\n项目和模块 一个项目代表一个完整的Android应用程序。Android Studio项目包含一个或多个module 。一个module 是您的应用程序的独立组件，\n你可以构建，测试或调试。module 包含您的应用程序的源代码和资源。Android的Studio项目包含三种模块：\nJava库模块\n包含可重用的代码。构建系统生成一个JAR包的Java库模块。\nAndroid库模块\n包含可重复使用的Android特有的代码和资源。构建系统产生AAR（安卓归档）包库模块。\nAndroid应用程序模块\n包含应用程序代码，并可能依赖于库模块，虽然很多Android应用程序只包含一个应用程序的模块。构建系统生成APK包，为应用模块。\nDependencies 依赖关系 Android Studio生成系统管理项目的依赖和支持模块依赖关系，局部二进制依赖，以及远程二进制依赖。\n模块依赖关系\n一个项目模块可以在构建文件中包括的其它模块的列表它依赖于。当你建立这个模块，构建系统组装，包括所需要的模块。\n本地依赖性\n如果你有二进制存档在你的本地文件系统中的一个模块依赖于，例如JAR文件，你可以在构建文件中该模块声明这些依赖关系。\n远程依赖性\n当你的一些依赖关系都可以在一个远程存储库，您不必下载它们，并将它们复制到您的项目。而Android工作室打造的系统支持远程的Maven的依赖关系。的Maven是一个受欢迎的软件项目管理工具，可帮助使用库组织项目的依赖关系。\n许多流行的软件库和工具都可以在公共Maven仓库。对于这些依赖项，您只需要指定自己的Maven坐标，它唯一标识一个远程存储库中的每个元素。在构建系统中使用的Maven坐标的格式是组：名称：版本。例如，Maven的坐标为谷歌番石榴库16.0.1版本是 com.google.guava：番石榴：16.0.1。\n在Maven的中央存储库，广泛用于分发很多库和工具。\nBuild Tasks Android Studio生成系统定义了一系列分层的构建任务：\n顶级任务：用于产生必要的结果的任务。\n构建系统提供项目任务：构建您的应用程序和模块的任务，以建立独立的模块。\nGradle Wrapper Android Studio项目包含的Gradle Wrapper由以下构成：\nA JAR file\nA properties file\nA shell script for Windows platforms\nA shell script for Mac and Linux platforms\n**Note:**你应该提交以上所有的文件到资源控制系统。\n使用Gradle wrapper（而不是本地Gradle安装），确保您始终运行的Gradle在属性文件中定义的版本。要配置您的项目使用Gradle较新版本，\n编辑属性文件并指定新的版本。\nAndroid Studio 会从Gradle Wrapper目录下读取你的配置文件，然后运行改wrapper，因此你可以根据不同版本的Gradle无缝的处理多个项目\nAndroid Studio 不支持Shell脚本，因此你应该在Gradle文件中定义自定义的逻辑来替代。\n下面简单的总结构建工程时遇到的问题 问题1. 如何引入第三方lib ？ http://stackoverflow.com/questions/20744692/android-studio-0-4-0-absherlock-gradle-without-import-module a copy lib 工程到项目下，setting.gradle配置include ‘: yourlib’ ,否则会提示在你的项目下找不到该lib工程。\nb 到整个项目下的build.gradle配置include ‘:actionbarsherlock’\nc 在你的Moudle下，而不是整个Project的build.gradle中添加\ndependencies {\ncompile project(‘:yourlib’)\n}\n在网上查的资料，右键，选择add as library,我的是0.5.8的，没有发现。如果没有作为lib引入，在Sync project with gradle files的时候 .\n就会发现，default config 不支持.这是因为你的lib工程没有build.gradle文件，可以拷贝一个简单的build.gradle，到你添加的lib project 目录下。\n这样就可以正常编译了。当然如果你的lib 项目还引用了一些三方jar包，你需要在dependencies中进行配置。\n文件如下\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `apply plugin: ``'android-library'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``compile fileTree(dir: ``'libs'``, include: ``'*.jar'``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `android {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``compileSdkVersion 17` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``buildToolsVersion ``\u0026quot;19.0.3\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``sourceSets {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``main {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``manifest.srcFile ``'AndroidManifest.xml'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``java.srcDirs = [``'src'``]` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``resources.srcDirs = [``'src'``]` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``aidl.srcDirs = [``'src'``]` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``renderscript.srcDirs = [``'src'``]` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``res.srcDirs = [``'res'``]` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``assets.srcDirs = [``'assets'``]` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``// Move the tests to tests/java, tests/res, etc...` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``instrumentTest.setRoot(``'tests'``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``// Move the build types to build-types/\u0026amp;lt;type\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``// This moves them out of them default location under src/\u0026amp;lt;type\u0026amp;gt;/... which would` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``// conflict with src/ being used by the main source set.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``// Adding new build types or product flavors should be accompanied` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``// by a similar customization.` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``debug.setRoot(``'build-types/debug'``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``release.setRoot(``'build-types/release'``)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 问题2 gradle的配置 在第一次的时候，由于下载比较慢，你可以到gradle官方下载最新版本，解压到android studio 的gradle的路径下。这个不固定，跟SDK配置一样，\n只要在gradle setting中指定好路径即可。然后配置gradle到path，gradle -v 验证是否成功配置\n注意：gradle的配置是在整个Project项目下面的build.gradle文件中。\n编译器报错：仅支持0.9+的gradle版本。\n解决方案：可以在build.gradle 里面配置 0.9+，或者在点击提示，gradle setting中选择以下选项之一\nuse default gradle wrapper（官方推荐，很少出问题）\n会自动下载gradle，确保你的项目使用精确的gradle版本\n另外，如果该选项不可选，灰色，请从其他项目中copy一个gradle文件夹到你的工程中\nUse customizable gradle warpper（1.7版本以上支持）\n这选项总是核对更新你指定的gradle版本，你只需要改变gradle的版本号即可。\nUse local gradle distribution（不建议使用，经常出各种问题，可能个人还不够熟悉）\n会使用本地的gradle去build项目，但是请确保你已经安装并在path中正确配置了该gradle。在命令行中，gradle -v可以验证。\n问题3：sync project时长时间停留在 resolve dependencies ‘:classpath’状态 或者 Error:(1, 0) Cause: org/gradle/api/artifacts/result/ResolvedComponentResult 原因：可能gradle配置不正确或者没有连接代理，无法访问到服务器。\n请确保你的其它lib project中也拥有build.gradle\n请检查gradle/wrapper/gradle-wrapper.properties：\ngradle wrapper distributionUrl=http://services.gradle.org/distributions/gradle-1.11-bin.zip或者更高，当时我下载的工程比较早，所以指向了gradle-0.9\n所以这里建议从github上clone项目，或者下载最新的。防止旧的配置出问题。\n如下：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `distributionUrl=http\\:``//services.gradle.org/distributions/gradle-1.11-bin.zip` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `http:``//stackoverflow.com/questions/22989638/android-studio-gradle-could-not-create-plugin-of-type-libraryplugin` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 建议：从github上clone项目，或者下载最新的。防止以前的工程配置出问题。\n通常希望使用offline的状态，不去连接外网，所以使用local gradle的配置，但是经常会出现各种问题，比如：\nError:No cached version of com.android.tools.build:gradle:0.9.+ available for offline mode.Disable Gradle ‘offline mode’ and sync project\n特别是刚开始对gradle比较模糊的时候，你也不清楚它啥时候需要一些依赖lib，啥时候需要去网站下载。\n建议：\n选择 use default gradle wrapper 该配置，也很少出现问题（请确保代理成功连接，可以在Http Proxy中check connection），以后慢慢的积累了多了，\n使用起来比较熟了，可以再试试。\n问题4 work offline 模式 如果你使用了该模式，但是其dependency 的lib project 没有在本地，那么还是需要联网的，否则会报错。\nhttp://stackoverflow.com/questions/20746071/failed-to-build-android-hello-world-application-in-offline-mode\n每次启动都会有联网检测依赖的各种文件是否是最新版本，导致每次都相当慢。如果确定了你的工程中的jar包或者依赖工程都齐全，也不想去更新最新的，就可以在gradle setting中勾选offline，这样就不会去更新了。但是提一下，如果这种情况下出问题，也不要惊讶，请连接代理。重新sync project，因为很多情况你可能并不清楚build工程所依赖的一些插件等是否已经有了。\n另外提一下，如果你使用了0.9+这样的配置方式（带+号），那么无论你是否选择了offline，都会去检测，而且，如果你没有网络连接的话，编译会报错的。\n0.9+，这种配置方式必须联网。\n所以如果你选择了offline，那么请检测自己的gradle的版本配置，可以直接写成你的gradle的版本，比如我下载并配置好的gradle1.2.\n在有可连接到服务器的网络连接的情况下下面的配置，还是比较建议的。\ndependencies {\nclasspath ‘com.android.tools.build:gradle:0.9.+’\n}\n问题5. com.android.dex.DexException: Multiple dex files define Landroid/support/v4/accessibilityservice **原因：**support v4包多次导入，或者是在不同的build.gradle文件中的dependencies 中无意compile了两次，比如在你的actionbarsherlock中使用了dependencies {\ncompile fileTree(dir: ‘libs’, include: ‘*.jar’)}\n表明编译所有的libs目录下的jar包，已经编译了support v4.jar包,而在项目下的build.gradle中又进行了编译：\ndependencies {\ncompile ‘com.android.support:support-v4:18.0.+’\n}\n所以应把项目下的compile ‘com.android.support:support-v4:18.0.+’ 给干掉\n另外提一点，不仅是support v4包，各种lib甚至各种布局的属性，style,color，都不允许在不用的文件中重复定义，在sync project 的时候会报错，你只需保留一份即可\n问题6. AndroidMainfest.xml问题 **前提：**当时我的activity的label中使用的是中文，activity的label中使用的是中文，\n情景1 Fatal error when parsing: AndroidManifest.xml . Failed to parse XML file: org.xml.sax.SAXParseException: Element type “activity” must be followed by either attribute specifications, “\u0026gt;” or “/\u0026gt;”.\n情景2 unexpected end of block data\n以上两种情景的解决方案：\n把中文label Extr 为String即可\n不过我在编译的时候有一些activity的label是中文的，一个一个activity的排错是比较恶心的。还是建议所有的label都抽取到String.xml文件中。\n我是这么修改的，大家可以试试。\n还有一种情况出现：unexpected end of block data\n在Sync project with gradle files 的时候\n解决方案：\nhttp://stackoverflow.com/questions/23045022/unexpected-end-of-block-data-in-gradle-sync\n如果你使用的是 buildToolsVersion “19.0.0”，那么改成 buildToolsVersion “19.0.3”，重新Sync project即可\n问题7 不同的lib 项目中的AndroidMainfest.xml文件中的targetSDK版本不一致 这个简单，只需要全部改成一致的即可。\n问题8. plugin with id ‘android’ not found http://stackoverflow.com/questions/18153739/android-studio-plugin-with-id-android-library-not-found\n在Project的build.gradle中，添加下面代码\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `buildscript {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``repositories {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `mavenCentral()` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``dependencies {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `classpath ``'com.android.tools.build:gradle:0.5.+'` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 问题9 使用NDK时，NDK not configured http://stackoverflow.com/questions/20674650/how-to-configure-ndk-with-android-gradle-plugin-0-7\n在NDK lib工程下的 build.gradle中添加\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `productFlavors {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``arm {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``ndk {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``abiFilters ``\u0026quot;armeabi\u0026quot;``, ``\u0026quot;armeabi-v7a\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``x86 {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``ndk {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``abiFilter ``\u0026quot;x86\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 或者\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `buildTypes {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``debug {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``ndk {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``abiFilters ``\u0026quot;armeabi\u0026quot;``, ``\u0026quot;armeabi-v7a\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 本人用的是第一种，在build photup项目的时候出现的问题\n简单总结下： 使用的时候最好有代理连接。很多时候需要下载一些插件或者依赖项目，除非你在本地完全拥有所有的依赖工程。但是在刚开始使用的时候，还是建议有代理，因为\n在刚使用Android Studio，需要去下载一些东西，比如，maven repository等，\ngradle配置要准确，保持都是最新的，尽量clone并在使用的时候更新项目，或者下载最新的工程，由于个人以前download 了很多的zip，跑demo用，后来直接导入，有些\n插件已经更新了，但是配置文件还没有更新。所以可能导致resolve dependency classpath长时间停留。\noffline work不可信，请尽量保持gradle的代理连接，很可能需要去下载一些依赖工程，或者其它配置。也许是个人哪里处理的不够好。\n请使用官方推荐的Gradle配置选项：use default gradle wrapper\nAndroid Studio快捷键 ** ** 提示\nCtrl+P方法参数提示\nCtrl+空格代码提示\nCtrl＋Shift＋Space在很多时候都能够给出Smart提示\nCtrl+Alt+Space类名或接口名提示\n查看\nAlt+1快速打开或隐藏工程面板\nCtrl+H查看类结构图\nCtrl＋F12查看当前文件的结构\nCtrl+Q查看注释文档\nCtrl＋P查看参数信息\nAlt＋Q查看当前方法的声明\nCtrl＋Q查看JavaDoc\nCtrl＋W选中单词继而语句继而行继而函数\n查找\nAlt + F1查找代码所在位置\nCtrl + F7查找当前元素在当前文件中的引用，然后按F3可以选择\nAlt + F3快速查找\nCtrl + Shift + F7可以高亮当前元素在当前文件中的使用\nCtrl + Shift+N查找文件\nCtrl + Shift+Alt+N查找类中的方法或变量\nCtrl + B查找打开光标处的类或方法\nCtrl + N快速查找类\nCtrl + F查找文本\nAlt＋F1可以将正在编辑的元素在各个面板中定位\nCtrl＋Shift＋Alt＋N可以快速打开符号 快速打开类/文件/符号时，可以使用通配符，也可以使用缩写\nCtrl＋Alt＋Up /Ctrl＋Alt＋Down可以快速跳转搜索结果\n修复\nShift+F6重构-重命名\nCtrl+X删除行\nCtrl+D复制行\nCtrl+/ 或 Ctrl+Shift+/ 注释（// 或者/*…*/ ）\nAlt＋Insert可以生成构造器/Getter/Setter等\nCtrl+Alt+L格式化代码\nCtrl+R替换文本\nAlt+Enter导入包,自动修正\nCtrl+Alt+O优化导入的类和包\nCtrl+J自动代码\nCtrl+Shift+Space自动补全代码\nCtrl＋Alt＋Space类名自动完成\nCtrl＋Shift＋Insert可以选择剪贴板内容并插入\nCtrl＋Shift＋J可以整合两行\nCtrl＋Alt＋T可以把代码包在一块内，例如try/catch\nCtrl＋Alt＋V可以引入变量。例如把括号内的SQL赋成一个变量\nAlt＋F8计算变量值\nCtrl＋O可以选择父类的方法进行重写\n最近相关\nCtrl+E最近打开的文件 ———-\nCtrl＋Shift＋Backspace可以跳转到上次编辑的地方\nCtrl+Alt+ left/right返回至上次浏览的位置\nCtrl+E或者Alt+Shift+C 最近更改的代码\nAlt+Shift+C对比最近修改的代码\n移动\nCtrl+Shift+Up/Down代码向上/下移动。 —————\nF2 或Shift+F2高亮错误或警告快速定位 ————\nCtrl+Up/Down光标跳转到第一行或最后一行下\nCtrl＋[或]可以跳到大括号的开头结尾\nCtrl+Shift+up/down移动方法\nCtrl+P方法参数提示\nCtrl+空格代码提示\nCtrl＋Shift＋Space在很多时候都能够给出Smart提示\nCtrl+Alt+Space类名或接口名提示\n转自：http://blog.csdn.net/xushuaic/article/details/26097663\n","permalink":"https://blog.zdltech.com/posts/android-studio-%E7%AE%80%E5%8D%95%E4%BB%8B%E7%BB%8D%E5%92%8C%E4%BD%BF%E7%94%A8%E9%97%AE%E9%A2%98%E5%B0%8F%E7%BB%93/","summary":"\u003cp\u003e随着android 5.0 的发布，android 开发已经进入了一个全新的时代，eclipse开发安卓已经有点不合时宜了，在github上80%的android项目都采用android studio开发，而且android studio的中文教程越来越多，还有什么理由不固守这eclipse 呢。\u003c/p\u003e\n\u003cp\u003e下面这篇文章对了解android studio 很有帮助，原文如下：\u003c/p\u003e\n\u003cp\u003eGoogle在2013的I/O开发者大会上引入的该开发工具。现在已经更新到了0.5.8版本。\u003c/p\u003e\n\u003cp\u003e现在github的很多项目都使用了Android Studio开发，所以如果你还用Eclipse，就需要把整个项目拆分，\u003cbr\u003e\n然后在工程中include依赖包，是非常费事的，有时候弄了半天还不一定能成功导入。而且Android开发者工具的未来的趋势一定也是转向Android Studio。\u003cbr\u003e\n介于种种原因，不得不学习使用Android Studio,Android Studio的项目管理使用了Gradle，所以你需要对Gradle进行简单的理解，可以到官网去看下。\u003c/p\u003e\n\u003cp\u003eGradle官网\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.gradle.org/\"\u003ehttp://www.gradle.org\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e因为Android 是在IntelliJ IDEA的基础上开发的，所以可以参考\u003cbr\u003e\nIntelliJ IDEA 的官方帮助地址\u003cbr\u003e\n\u003ca href=\"http://www.jetbrains.com/idea/webhelp/getting-help.html\"\u003ehttp://www.jetbrains.com/idea/webhelp/getting-help.html\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"简单引入一些概念有些是来自个人的官方翻译有些是copy过来的\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003e简单引入一些概念：（有些是来自个人的官方翻译有些是copy过来的）\u003c/h2\u003e\n\u003ch3 id=\"heading\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e**\u003c/h3\u003e\n\u003cp\u003e**\u003c/p\u003e\n\u003ch3 id=\"android-studio\"\u003e\u003ca name=\"t2\"\u003e\u003c/a\u003e\u003cstrong\u003eAndroid Studio\u003c/strong\u003e\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e建立系统工具包你用来生成，测试，运行您的应用程序和软件包。构建系统是独立于Android的工作室，所以你可以调用它的Android的工作室或从命令行。在你写你的应用程序，你可以使用编译系统的特点：\u003cbr\u003e\n定制，配置，和扩展的建立过程。\u003c/p\u003e\n\u003cp\u003e为您的应用程序使用同一项目的不同特点，创建多个应用程序。\u003cbr\u003e\n重用代码和资源。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eAndroidStudio构建系统由Gradle构成。Gradle是一种高级的构建工具，用于管理依赖性，允许你定义自定义构建逻辑。\u003cbr\u003e\nAndroid插件工具并不依赖于Android Studio，虽然Android Studio由它完全集成。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"gradle的配置包含以下方面\"\u003e\u003ca name=\"t3\"\u003e\u003c/a\u003e\u003cstrong\u003eGradle的配置包含以下方面\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e构建变量\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e构建系统可以根据不同的配置为同一个项目生成多个APK。当你想建立不同版本的应用程序，而不必为每个人单独的项目，这是很有用的。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e依赖关系\u003c/strong\u003e\u003cbr\u003e\n构建系统管理项目的依赖，并从本地文件系统和远程存储库支持的依赖。这可以防止你不必搜索，下载和复制二进制包为你的依赖到你的项目目录。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e清单条目\u003c/strong\u003e\u003cbr\u003e\n构建系统使您可以指定的值在生成配置清单文件中的某些元素。这些新的值将覆盖在manifest文件中的现有值。如果你想生成多个的\u003cbr\u003e\nAPK为您的项目中，他们每个人都有不同的包名，最小的SDK版本，或目标SDK版本，这是很有用的。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e签名\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e构建系统使您可以指定生成配置签名设置，它可以在生成过程中签署您的APK。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"proguard\"\u003e\u003ca name=\"t4\"\u003e\u003c/a\u003e\u003cstrong\u003eProGuard\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e构建系统使您可以指定一个不同的 ProGuard的规则文件的每个版本变量。构建系统可以运行ProGuard的生成过程来混淆你的类。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e测试\u003c/strong\u003e\u003cbr\u003e\n构建系统生成的项目中的测试源测试APK，所以你不必创建一个单独的测试项目。构建系统可以在生成过程中运行测试。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eGradle构建文件使用Groovy的语法。Groovy是一种动态语言，你可以用它来 定义自定义生成逻辑，并与Android的插件Gradle提供了Android特有的元素进行交互。\u003cbr\u003e\n\u003cstrong\u003e按照惯例建立\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eAndroid Studio生成系统假定合理的默认值的项目结构和其他编译选项。\u003cbr\u003e\n如果您的项目符合这些约定，你的Gradle构建文件是很简单的。当一些这些公约并不适用于你的项目,使您可以配置生成过程的几乎每一个方面。\u003cbr\u003e\n例如，如果您的项目的源位于比默认值不同的目录，你可以在构建文件中指定此位置。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"项目和模块\"\u003e\u003ca name=\"t5\"\u003e\u003c/a\u003e\u003cstrong\u003e项目和模块\u003c/strong\u003e\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e一个项目代表一个完整的Android应用程序。Android Studio项目包含一个或多个module 。一个module 是您的应用程序的独立组件，\u003cbr\u003e\n你可以构建，测试或调试。module 包含您的应用程序的源代码和资源。Android的Studio项目包含三种模块：\u003c/p\u003e","title":"Android Studio 简单介绍和使用问题小结"},{"content":"Matrix的3*3矩阵：\n**[java]** [view plain](http://blog.csdn.net/lonelyroamer/article/details/7626262#)[copy](http://blog.csdn.net/lonelyroamer/article/details/7626262#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - {MSCALE_X,MSKEW_X,MTRANS_X, - MSKEW_Y,MSCALE_Y,MTRANS_Y, - MPERSP_0,MPERSP_1,MPERSP_2} 一、平移（Translation）变换\nTranslation的变换是通过改变MTRANS_X和MTRANS_Y来实现的，Matrix提供了三个方法\npreTranslate(float dx, float dy)\nsetTranslate(float dx, float dy)\npostTranslate(float dx, float dy)\n平移的变换特别简单，相信学过数学的人都知道，不说了。\n二、扭曲（Skew）变换\nskew变换是通过改变MSKEW_X，和MSKEW_Y来实现的，Matrix提供了下面的几个方法来设置skew\nmatrix.setSkew(kx, ky)\nmatrix.setSkew(kx, ky, px, py)\nmatrix.preSkew(kx, ky)\nmatrix.preSkew(kx, ky, px, py)\nmatrix.postSkew(kx, ky)\nmatrix.postSkew(kx, ky, px, py)\n经过自己测试，发现skew的变换是如下的规律：\n点（x,y）经过skew（kx，ky，px，py）变换之后，坐标为（kx*(y-py)+px，ky*(x-px)+py），如果，px和py没有，则默认为都为0。\n图片变换的效果\n三、旋转（Rotate）的变换\n**[java]** [view plain](http://blog.csdn.net/lonelyroamer/article/details/7626262#)[copy](http://blog.csdn.net/lonelyroamer/article/details/7626262#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - {MSCALE_X,MSKEW_X,MTRANS_X, - MSKEW_Y,MSCALE_Y,MTRANS_Y, - MPERSP_0,MPERSP_1,MPERSP_2} Rotate的变换是通过设置4个值来改变的，MSCALE_X，MSKEW_X，MSKEW_Y，MSCALE_Y来进行变换的，有如下的方法\nmatrix.setRotate(degrees)\nmatrix.setRotate(degrees, px, py)\nmatrix.preRotate(degrees)\nmatrix.preRotate(degrees, px, py)\nmatrix.postRotate(degrees)\nmatrix.postRotate(degrees, px, py)\n这就不用解释了，degrees即我们要旋转的度数，px,py是我们旋转的角度通过这个设置，它会直接改变matrix矩阵里面的值，得到相应的变换矩阵。\n还可以通过具体设置我们想要旋转的sin、cos角度来得到变换\nmatrix.setSinCos(sinValue, cosValue)\nmatrix.setSinCos(sinValue, cosValue, px, py)\n转自：http://blog.csdn.net/lonelyroamer/article/details/7626262\n","permalink":"https://blog.zdltech.com/posts/matrix%E5%AD%A6%E4%B9%A03matrix%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%B8%89%E7%A7%8D%E5%8F%98%E6%8D%A2%E4%B9%8Btranslationskewrotate/","summary":"\u003cp\u003eMatrix的3*3矩阵：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/lonelyroamer/article/details/7626262#)[copy](http://blog.csdn.net/lonelyroamer/article/details/7626262#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- {MSCALE_X,MSKEW_X,MTRANS_X,\n\n- MSKEW_Y,MSCALE_Y,MTRANS_Y,\n\n- MPERSP_0,MPERSP_1,MPERSP_2}\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e一、平移（Translation）变换\u003c/p\u003e\n\u003cp\u003eTranslation的变换是通过改变MTRANS_X和MTRANS_Y来实现的，Matrix提供了三个方法\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"sympad\"\u003e\u003ca\u003epreTranslate\u003c/a\u003e\u003c/span\u003e(float dx, float dy)\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"sympad\"\u003e\u003ca\u003esetTranslate\u003c/a\u003e\u003c/span\u003e(float dx, float dy)\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"sympad\"\u003e\u003ca\u003epostTranslate\u003c/a\u003e\u003c/span\u003e(float dx, float dy)\u003c/p\u003e\n\u003cp\u003e平移的变换特别简单，相信学过数学的人都知道，不说了。\u003c/p\u003e\n\u003cp\u003e二、扭曲（Skew）变换\u003c/p\u003e\n\u003cp\u003eskew变换是通过改变MSKEW_X，和MSKEW_Y来实现的，Matrix提供了下面的几个方法来设置skew\u003c/p\u003e\n\u003cp\u003ematrix.setSkew(kx, ky)\u003cbr\u003e\nmatrix.setSkew(kx, ky, px, py)\u003cbr\u003e\nmatrix.preSkew(kx, ky)\u003cbr\u003e\nmatrix.preSkew(kx, ky, px, py)\u003cbr\u003e\nmatrix.postSkew(kx, ky)\u003cbr\u003e\nmatrix.postSkew(kx, ky, px, py)\u003c/p\u003e\n\u003cp\u003e经过自己测试，发现skew的变换是如下的规律：\u003c/p\u003e\n\u003cp\u003e点（x,y）经过skew（kx，ky，px，py）变换之后，坐标为（kx*(y-py)+px，ky*(x-px)+py），如果，px和py没有，则默认为都为0。\u003c/p\u003e\n\u003cp\u003e图片变换的效果\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://my.csdn.net/uploads/201206/04/1338774193_2373.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://my.csdn.net/uploads/201206/04/1338774269_6700.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e三、旋转（Rotate）的变换\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/lonelyroamer/article/details/7626262#)[copy](http://blog.csdn.net/lonelyroamer/article/details/7626262#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- {MSCALE_X,MSKEW_X,MTRANS_X,\n\n- MSKEW_Y,MSCALE_Y,MTRANS_Y,\n\n- MPERSP_0,MPERSP_1,MPERSP_2}\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003eRotate的变换是通过设置4个值来改变的，MSCALE_X，MSKEW_X，MSKEW_Y，MSCALE_Y来进行变换的，有如下的方法\u003c/p\u003e","title":"Matrix学习3、Matrix的基本三种变换之Translation、Skew、Rotate"},{"content":"反编译工具 : 总结了一下 linux, windows, mac 上的版本, 一起放到 CSDN 上下载;\n— CSDN 下载地址 : http://download.csdn.net/detail/han1202012/8221787\n**[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/41697821#)[copy](http://blog.csdn.net/shulianghan/article/details/41697821#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/541288)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/541288/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - octopus@octopus:~/decompiler$ tree -L 2 - . - ├── linux - │ ├── apktool - │ ├── dex2jar-0.0.9.15 - │ └── jd-gui - ├── mac - │ ├── apktool - │ ├── dex2jar-0.0.9.15 - │ └── jd-gui-0.3.5.osx.i686.dmg - ├── windows - │ ├── apkTool - │ ├── dex2jar-0.0.9.15 - │ └── jd-gui.exe - └── 源码 - └── apktool-source.zip - - 10 directories, 4 files 一. 反编译 至 Java 源码 1. 工具介绍 dex2jar 简介 : 将 .dex 或者 .class 后缀文件转换成 .jar 文件;\n— 最新版本 : 目前最新版本 0.0.9.15;\n— 官方地址 (需要翻墙) : http://code.google.com/p/dex2jar/ ;\n— 下载地址 (需要翻墙) : http://code.google.com/p/dex2jar/downloads/list;\njd-gui 简介 : 使用该工具可以查看 .jar 中的 java 代码;\n— 官网地址 : http://jd.benow.ca/ ;\n2. 反编译过程 (1) Ubuntu 系统反编译 a. 获取 .dex 后缀文件 : 修改 apk 文件后缀, 获取 class.dex 文件;\nb. 执行反编译 : 将 classes.dex 拷贝到 dex2jar 目录下, 执行 ./d2j-dex2jar.sh classes.dex 命令;\n— 执行结果 :\n**[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/41697821#)[copy](http://blog.csdn.net/shulianghan/article/details/41697821#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/541288)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/541288/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - octopus@octopus:~/decompiler/linux/dex2jar-0.0.9.15$ ./d2j-dex2jar.sh classes.dex - dex2jar classes.dex -\u0026gt; classes-dex2jar.jar c. jd-gui 中查看源码 : 将 classes-dex2jar.jar 文件拖入 jd-gui 中, 查看源码;\n3. 混淆代码 注意 : 如果不使用签名文件进行打包的话, 直接从 eclipse 中拷贝的文件是无法混淆的;\n(1) 配置混淆文件 编辑 progard.cfg :\n— 文件内容 :\n**[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/41697821#)[copy](http://blog.csdn.net/shulianghan/article/details/41697821#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/541288)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/541288/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - -optimizationpasses 5 - -dontusemixedcaseclassnames - -dontskipnonpubliclibraryclasses - -dontpreverify - -verbose - -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* - - #组件相关的类不进行混淆, 保留 - -keep public class * extends android.app.Activity - -keep public class * extends android.app.Application - -keep public class * extends android.app.Service - -keep public class * extends android.content.BroadcastReceiver - -keep public class * extends android.content.ContentProvider - -keep public class * extends android.app.backup.BackupAgentHelper - -keep public class * extends android.preference.Preference - -keep public class com.android.vending.licensing.ILicensingService - - # 所有类中的 native 方法不混淆 - -keepclasseswithmembernames class * { - native \u0026lt;methods\u0026gt;; - } - - # 对全部类的指定方法的方法名不进行混淆 - -keepclasseswithmembers class * { - public \u0026lt;init\u0026gt;(android.content.Context, android.util.AttributeSet); - } - - #对全部类的指定方法的方法名不进行混淆 - -keepclasseswithmembers class * { - public \u0026lt;init\u0026gt;(android.content.Context, android.util.AttributeSet, int); - } - - # 保留 Activity 子类 - -keepclassmembers class * extends android.app.Activity { - public void *(android.view.View); - } - - # 对枚举类型enum的全部类的下面指定方法的方法名不进行混淆 - -keepclassmembers enum * { - public static **[] values(); - public static ** valueOf(java.lang.String); - } - - # 实现了 Parcelable 序列化接口的类不混淆 - -keep class * implements android.os.Parcelable { - public static final android.os.Parcelable$Creator *; - } — project.properties 配置混淆文件 :\n**[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/41697821#)[copy](http://blog.csdn.net/shulianghan/article/details/41697821#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/541288)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/541288/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - target=android-19 - proguard.config=proguard.cfg (2) 打包 apk 文件 (创建新的 keystore) b. 创建 keystore : 选择 Create new keystore, 选择一个文件, 然后设置 keystore 的用户名 和 密码;\n— Location : keystore 文件;\n— Password : 密码;\n— Confirm : 确认密码, 重新输入密码;\nc. 输入 keystore 详细信息 :\n— Alias : 别名;\n— Password : 别名密码;\n— Confirm : 确认密码;\n— Validity(years) : 有效期限, 推荐 25 年;\n— First and Last Name : 开发者姓名;\n下面的参数可以不填写\n— Orgnizational Unit : 组织名称;\n— Orgnization : 组织;\n— City or Location : 城市;\n— State or Provience : 省 或者 州;\n— Country Code : 国家;\nd. 选择 apk 文件并打包 : 点击 finish 按钮后打包完毕;\n(3) 打包 apk 文件 (使用现有的 keystore 文件) b. 选择签名文件 : 输入签名文件密码;\nc. 输入别名密码 :\nd. 打包 apk : 选择要打包的 apk 文件 :\n(4) 验证混淆效果 反编译 : 将 apk 文件后缀改为 .zip, 之后取出 classes.dex 文件 到 dex2jar 根目录中, 执行 ./d2j-dex2jar.sh classes.dex 命令;\n**[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/41697821#)[copy](http://blog.csdn.net/shulianghan/article/details/41697821#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/541288)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/541288/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - octopus@octopus:~/decompiler/linux/dex2jar-0.0.9.15$ ./d2j-dex2jar.sh classes.dex - dex2jar classes.dex -\u0026gt; classes-dex2jar.jar 在 jd-gui 中查看 Java 代码 :\n二. Apktools 反编译 1. Apktools 介绍 Apktools 简介 :\n— 最新版本 : 2.0.0 ;\n— 官方网站 (需要翻墙) : https://code.google.com/p/android-apktool/ ;\n— 新版本下载地址 : https://bitbucket.org/iBotPeaches/apktool/downloads ;\n— 老版本下载地址 (需要翻墙) : https://code.google.com/p/android-apktool/downloads/list ;\n需要下载的文件 :\n— apktool jar 包 : apktool1.5.2.tar.bz2\n— apktool 引导工具 (Linux) : apktool-install-linux-r05-ibot.tar.bz2\n— apktool 引导工具 (mac) : apktool-install-macosx-r05-ibot.tar.bz2\n— apktool 引导工具 (wondows) : apktool-install-windows-r05-ibot.tar.bz2\n2. 反编译 将下载的文件放到一个文件中 :\n反编译 : 将 apk 文件放入上面的目录, 执行命令 ./apktool d WheelView.apk ;\n— 反编译过程 :\n**[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/41697821#)[copy](http://blog.csdn.net/shulianghan/article/details/41697821#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/541288)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/541288/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - octopus@octopus:~/decompiler/linux/apktool$ ./apktool d WheelView.apk - I: Baksmaling\u0026amp;#8230; - I: Loading resource table\u0026amp;#8230; - I: Loaded. - I: Decoding AndroidManifest.xml with resources\u0026amp;#8230; - I: Loading resource table from file: /home/octopus/apktool/framework/1.apk - I: Loaded. - I: Regular manifest package\u0026amp;#8230; - I: Decoding file-resources\u0026amp;#8230; - I: Decoding values */* XMLs\u0026amp;#8230; - I: Done. - I: Copying assets and libs\u0026amp;#8230; - octopus@octopus:~/decompiler/linux/apktool$ ls - aapt apktool apktool.jar WheelView WheelView.apk — 反编译结果 : 反编译结果都在 WheelView 目录中, res 中是相关资源文件, smali 中是 smali 汇编文件;\n3. 重新编译 重新编译命令格式 : ./apktool b apk源目录 apk文件名称;\n— 执行命令 : ./apktool b WheelView WheelView1.apk , 可以生成 WheelView1.apk 文件;\n**[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/41697821#)[copy](http://blog.csdn.net/shulianghan/article/details/41697821#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/541288)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/541288/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - octopus@octopus:~/decompiler/linux/apktool$ ls - aapt apktool apktool.jar WheelView WheelView.apk - octopus@octopus:~/decompiler/linux/apktool$ ./apktool b WheelView WheelView1.apk - I: Checking whether sources has changed\u0026amp;#8230; - I: Smaling\u0026amp;#8230; - I: Checking whether resources has changed\u0026amp;#8230; - I: Building resources\u0026amp;#8230; - I: Building apk file\u0026amp;#8230; - octopus@octopus:~/decompiler/linux/apktool$ ls - aapt apktool apktool.jar WheelView WheelView1.apk WheelView.apk ","permalink":"https://blog.zdltech.com/posts/android-%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91-android-apk-%E5%8F%8D%E7%BC%96%E8%AF%91-%E6%B7%B7%E6%B7%86-%E5%8F%8D%E7%BC%96%E8%AF%91%E5%90%8E%E9%87%8D%E7%BC%96%E8%AF%91/","summary":"\u003cp\u003e\u003cstrong\u003e反编译工具\u003c/strong\u003e : 总结了一下 linux, windows, mac 上的版本, 一起放到 CSDN 上下载;\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003eCSDN 下载地址\u003c/strong\u003e : \u003cstrong\u003e\u003ca href=\"http://download.csdn.net/detail/han1202012/8221787\"\u003ehttp://download.csdn.net/detail/han1202012/8221787\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_plain\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[plain]** [view plain](http://blog.csdn.net/shulianghan/article/details/41697821#)[copy](http://blog.csdn.net/shulianghan/article/details/41697821#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/541288)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/541288/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- octopus@octopus:~/decompiler$ tree -L 2\n\n- .\n\n- ├── linux\n\n- │   ├── apktool\n\n- │   ├── dex2jar-0.0.9.15\n\n- │   └── jd-gui\n\n- ├── mac\n\n- │   ├── apktool\n\n- │   ├── dex2jar-0.0.9.15\n\n- │   └── jd-gui-0.3.5.osx.i686.dmg\n\n- ├── windows\n\n- │   ├── apkTool\n\n- │   ├── dex2jar-0.0.9.15\n\n- │   └── jd-gui.exe\n\n- └── 源码\n\n- └── apktool-source.zip\n\n- \n- 10 directories, 4 files\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"【Android 应用开发】 Android APK 反编译 混淆 反编译后重编译"},{"content":"http://www.cnblogs.com/dwinter/archive/2012/01/12/2321082.html\nActivity:\n**[html]** [view plain](http://blog.csdn.net/n70joey/article/details/7993188#)[copy](http://blog.csdn.net/n70joey/article/details/7993188#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - /** - * 图片浏览、缩放、拖动、自动居中 - */ - public class Touch extends Activity implements OnTouchListener { - - Matrix \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;matrix\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Matrix(); - Matrix \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;savedMatrix\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Matrix(); - DisplayMetrics dm; - ImageView imgView; - Bitmap bitmap; - - float minScaleR;// 最小缩放比例 - static final float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;MAX_SCALE\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;4f\u0026lt;/span\u0026gt;;// 最大缩放比例 - - static final int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;NONE\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;// 初始状态 - static final int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;DRAG\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;// 拖动 - static final int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;ZOOM\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;;// 缩放 - int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;NONE\u0026lt;/span\u0026gt;; - - PointF \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;prev\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PointF(); - PointF \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mid\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PointF(); - float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;dist\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;1f\u0026lt;/span\u0026gt;; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.scale); - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;imgView\u0026lt;/span\u0026gt; = (ImageView) findViewById(R.id.imag);// 获取控件 - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;bitmap\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;BitmapFactory\u0026lt;/span\u0026gt;.decodeResource(getResources(), this.getIntent() - .getExtras().getInt(\u0026amp;#8220;IMG\u0026amp;#8221;));// 获取图片资源 - imgView.setImageBitmap(bitmap);// 填充控件 - imgView.setOnTouchListener(this);// 设置触屏监听 - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;dm\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics(dm);// 获取分辨率 - minZoom(); - center(); - imgView.setImageMatrix(matrix); - } - - /** - * 触屏监听 - */ - public boolean onTouch(View v, MotionEvent event) { - - switch (event.getAction() \u0026amp; MotionEvent.ACTION_MASK) { - // 主点按下 - case MotionEvent.ACTION_DOWN: - savedMatrix.set(matrix); - prev.set(event.getX(), event.getY()); - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;DRAG\u0026lt;/span\u0026gt;; - break; - // 副点按下 - case MotionEvent.ACTION_POINTER_DOWN: - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;dist\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;spacing\u0026lt;/span\u0026gt;(event); - // 如果连续两点距离大于10，则判定为多点模式 - if (spacing(event) \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 10f) { - savedMatrix.set(matrix); - midPoint(mid, event); - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;ZOOM\u0026lt;/span\u0026gt;; - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;NONE\u0026lt;/span\u0026gt;; - break; - case MotionEvent.ACTION_MOVE: - if (\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; == DRAG) { - matrix.set(savedMatrix); - matrix.postTranslate(event.getX() \u0026amp;#8211; prev.x, event.getY() - \u0026amp;#8211; prev.y); - } else if (\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; == ZOOM) { - float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;newDist\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;spacing\u0026lt;/span\u0026gt;(event); - if (newDist \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 10f) { - matrix.set(savedMatrix); - float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;tScale\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;newDist\u0026lt;/span\u0026gt; / dist; - matrix.postScale(tScale, tScale, mid.x, mid.y); - } - } - break; - } - imgView.setImageMatrix(matrix); - CheckView(); - return true; - } - - /** - * 限制最大最小缩放比例，自动居中 - */ - private void CheckView() { - float p[] = new float[9]; - matrix.getValues(p); - if (\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; == ZOOM) { - if (p[0] \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;minScaleR\u0026lt;/span\u0026gt;) { - matrix.setScale(minScaleR, minScaleR); - } - if (p[0] \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; MAX_SCALE) { - matrix.set(savedMatrix); - } - } - center(); - } - - /** - * 最小缩放比例，最大为100% - */ - private void minZoom() { - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;minScaleR\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;Math\u0026lt;/span\u0026gt;.min( - (float) dm.widthPixels / (float) bitmap.getWidth(), - (float) dm.heightPixels / (float) bitmap.getHeight()); - if (minScaleR \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;1.0\u0026lt;/span\u0026gt;) { - matrix.postScale(minScaleR, minScaleR); - } - } - - private void center() { - center(true, true); - } - - /** - * 横向、纵向居中 - */ - protected void center(boolean horizontal, boolean vertical) { - - Matrix \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;m\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Matrix(); - m.set(matrix); - RectF \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;rect\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()); - m.mapRect(rect); - - float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;height\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;rect\u0026lt;/span\u0026gt;.height(); - float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;width\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;rect\u0026lt;/span\u0026gt;.width(); - - float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaX\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaY\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - - if (vertical) { - // 图片小于屏幕大小，则居中显示。大于屏幕，上方留空则往上移，下方留空则往下移 - int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;screenHeight\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;dm\u0026lt;/span\u0026gt;.heightPixels; - if (height \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;screenHeight\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaY\u0026lt;/span\u0026gt; = (screenHeight \u0026amp;#8211; height) / 2 \u0026amp;#8211; rect.top; - } else if (rect.top \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 0) { - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaY\u0026lt;/span\u0026gt; = -rect.top; - } else if (rect.bottom \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;screenHeight\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaY\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;imgView\u0026lt;/span\u0026gt;.getHeight() \u0026amp;#8211; rect.bottom; - } - } - - if (horizontal) { - int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;screenWidth\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;dm\u0026lt;/span\u0026gt;.widthPixels; - if (width \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;screenWidth\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaX\u0026lt;/span\u0026gt; = (screenWidth \u0026amp;#8211; width) / 2 \u0026amp;#8211; rect.left; - } else if (rect.left \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 0) { - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaX\u0026lt;/span\u0026gt; = -rect.left; - } else if (rect.right \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;screenWidth\u0026lt;/span\u0026gt;) { - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaX\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;screenWidth\u0026lt;/span\u0026gt; \u0026amp;#8211; rect.right; - } - } - matrix.postTranslate(deltaX, deltaY); - } - - /** - * 两点的距离 - */ - private float spacing(MotionEvent event) { - float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;x\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;event\u0026lt;/span\u0026gt;.getX(0) \u0026amp;#8211; event.getX(1); - float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;y\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;event\u0026lt;/span\u0026gt;.getY(0) \u0026amp;#8211; event.getY(1); - return FloatMath.sqrt(x * x + y * y); - } - - /** - * 两点的中点 - */ - private void midPoint(PointF point, MotionEvent event) { - float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;x\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;event\u0026lt;/span\u0026gt;.getX(0) + event.getX(1); - float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;y\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;event\u0026lt;/span\u0026gt;.getY(0) + event.getY(1); - point.set(x / 2, y / 2); - } - } **[html]** [view plain](http://blog.csdn.net/n70joey/article/details/7993188#)[copy](http://blog.csdn.net/n70joey/article/details/7993188#) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;FrameLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/imag\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scaleType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;matrix\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;FrameLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-%E5%9B%BE%E7%89%87%E7%9A%84%E6%B5%8F%E8%A7%88%E7%BC%A9%E6%94%BE%E6%8B%96%E5%8A%A8%E5%92%8C%E8%87%AA%E5%8A%A8%E5%B1%85%E4%B8%AD/","summary":"\u003cp\u003e\u003ca href=\"http://www.cnblogs.com/dwinter/archive/2012/01/12/2321082.html\"\u003ehttp://www.cnblogs.com/dwinter/archive/2012/01/12/2321082.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eActivity:\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/n70joey/article/details/7993188#)[copy](http://blog.csdn.net/n70joey/article/details/7993188#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt;\n    \u0026lt;/embed\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- /**\n\n- * 图片浏览、缩放、拖动、自动居中\n\n- */\n\n- public class Touch extends Activity implements OnTouchListener {\n\n- \n- Matrix \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;matrix\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Matrix();\n\n- Matrix \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;savedMatrix\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Matrix();\n\n- DisplayMetrics dm;\n\n- ImageView imgView;\n\n- Bitmap bitmap;\n\n- \n- float minScaleR;// 最小缩放比例\n\n- static final float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;MAX_SCALE\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;4f\u0026lt;/span\u0026gt;;// 最大缩放比例\n\n- \n- static final int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;NONE\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;// 初始状态\n\n- static final int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;DRAG\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;// 拖动\n\n- static final int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;ZOOM\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;;// 缩放\n\n- int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;NONE\u0026lt;/span\u0026gt;;\n\n- \n- PointF \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;prev\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PointF();\n\n- PointF \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mid\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PointF();\n\n- float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;dist\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;1f\u0026lt;/span\u0026gt;;\n\n- \n- @Override\n\n- public void onCreate(Bundle savedInstanceState) {\n\n- super.onCreate(savedInstanceState);\n\n- setContentView(R.layout.scale);\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;imgView\u0026lt;/span\u0026gt; = (ImageView) findViewById(R.id.imag);// 获取控件\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;bitmap\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;BitmapFactory\u0026lt;/span\u0026gt;.decodeResource(getResources(), this.getIntent()\n\n- .getExtras().getInt(\u0026amp;#8220;IMG\u0026amp;#8221;));// 获取图片资源\n\n- imgView.setImageBitmap(bitmap);// 填充控件\n\n- imgView.setOnTouchListener(this);// 设置触屏监听\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;dm\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DisplayMetrics();\n\n- getWindowManager().getDefaultDisplay().getMetrics(dm);// 获取分辨率\n\n- minZoom();\n\n- center();\n\n- imgView.setImageMatrix(matrix);\n\n- }\n\n- \n- /**\n\n- * 触屏监听\n\n- */\n\n- public boolean onTouch(View v, MotionEvent event) {\n\n- \n- switch (event.getAction() \u0026amp; MotionEvent.ACTION_MASK) {\n\n- // 主点按下\n\n- case MotionEvent.ACTION_DOWN:\n\n- savedMatrix.set(matrix);\n\n- prev.set(event.getX(), event.getY());\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;DRAG\u0026lt;/span\u0026gt;;\n\n- break;\n\n- // 副点按下\n\n- case MotionEvent.ACTION_POINTER_DOWN:\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;dist\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;spacing\u0026lt;/span\u0026gt;(event);\n\n- // 如果连续两点距离大于10，则判定为多点模式\n\n- if (spacing(event) \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 10f) {\n\n- savedMatrix.set(matrix);\n\n- midPoint(mid, event);\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;ZOOM\u0026lt;/span\u0026gt;;\n\n- }\n\n- break;\n\n- case MotionEvent.ACTION_UP:\n\n- case MotionEvent.ACTION_POINTER_UP:\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;NONE\u0026lt;/span\u0026gt;;\n\n- break;\n\n- case MotionEvent.ACTION_MOVE:\n\n- if (\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; == DRAG) {\n\n- matrix.set(savedMatrix);\n\n- matrix.postTranslate(event.getX() \u0026amp;#8211; prev.x, event.getY()\n\n- \u0026amp;#8211; prev.y);\n\n- } else if (\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; == ZOOM) {\n\n- float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;newDist\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;spacing\u0026lt;/span\u0026gt;(event);\n\n- if (newDist \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 10f) {\n\n- matrix.set(savedMatrix);\n\n- float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;tScale\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;newDist\u0026lt;/span\u0026gt; / dist;\n\n- matrix.postScale(tScale, tScale, mid.x, mid.y);\n\n- }\n\n- }\n\n- break;\n\n- }\n\n- imgView.setImageMatrix(matrix);\n\n- CheckView();\n\n- return true;\n\n- }\n\n- \n- /**\n\n- * 限制最大最小缩放比例，自动居中\n\n- */\n\n- private void CheckView() {\n\n- float p[] = new float[9];\n\n- matrix.getValues(p);\n\n- if (\u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;mode\u0026lt;/span\u0026gt; == ZOOM) {\n\n- if (p[0] \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;minScaleR\u0026lt;/span\u0026gt;) {\n\n- matrix.setScale(minScaleR, minScaleR);\n\n- }\n\n- if (p[0] \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; MAX_SCALE) {\n\n- matrix.set(savedMatrix);\n\n- }\n\n- }\n\n- center();\n\n- }\n\n- \n- /**\n\n- * 最小缩放比例，最大为100%\n\n- */\n\n- private void minZoom() {\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;minScaleR\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;Math\u0026lt;/span\u0026gt;.min(\n\n- (float) dm.widthPixels / (float) bitmap.getWidth(),\n\n- (float) dm.heightPixels / (float) bitmap.getHeight());\n\n- if (minScaleR \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;1.0\u0026lt;/span\u0026gt;) {\n\n- matrix.postScale(minScaleR, minScaleR);\n\n- }\n\n- }\n\n- \n- private void center() {\n\n- center(true, true);\n\n- }\n\n- \n- /**\n\n- * 横向、纵向居中\n\n- */\n\n- protected void center(boolean horizontal, boolean vertical) {\n\n- \n- Matrix \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;m\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Matrix();\n\n- m.set(matrix);\n\n- RectF \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;rect\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());\n\n- m.mapRect(rect);\n\n- \n- float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;height\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;rect\u0026lt;/span\u0026gt;.height();\n\n- float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;width\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;rect\u0026lt;/span\u0026gt;.width();\n\n- \n- float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaX\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaY\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\n\n- \n- if (vertical) {\n\n- // 图片小于屏幕大小，则居中显示。大于屏幕，上方留空则往上移，下方留空则往下移\n\n- int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;screenHeight\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;dm\u0026lt;/span\u0026gt;.heightPixels;\n\n- if (height \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;screenHeight\u0026lt;/span\u0026gt;) {\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaY\u0026lt;/span\u0026gt; = (screenHeight \u0026amp;#8211; height) / 2 \u0026amp;#8211; rect.top;\n\n- } else if (rect.top \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 0) {\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaY\u0026lt;/span\u0026gt; = -rect.top;\n\n- } else if (rect.bottom \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;screenHeight\u0026lt;/span\u0026gt;) {\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaY\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;imgView\u0026lt;/span\u0026gt;.getHeight() \u0026amp;#8211; rect.bottom;\n\n- }\n\n- }\n\n- \n- if (horizontal) {\n\n- int \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;screenWidth\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;dm\u0026lt;/span\u0026gt;.widthPixels;\n\n- if (width \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;screenWidth\u0026lt;/span\u0026gt;) {\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaX\u0026lt;/span\u0026gt; = (screenWidth \u0026amp;#8211; width) / 2 \u0026amp;#8211; rect.left;\n\n- } else if (rect.left \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 0) {\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaX\u0026lt;/span\u0026gt; = -rect.left;\n\n- } else if (rect.right \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;screenWidth\u0026lt;/span\u0026gt;) {\n\n- \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;deltaX\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;screenWidth\u0026lt;/span\u0026gt; \u0026amp;#8211; rect.right;\n\n- }\n\n- }\n\n- matrix.postTranslate(deltaX, deltaY);\n\n- }\n\n- \n- /**\n\n- * 两点的距离\n\n- */\n\n- private float spacing(MotionEvent event) {\n\n- float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;x\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;event\u0026lt;/span\u0026gt;.getX(0) \u0026amp;#8211; event.getX(1);\n\n- float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;y\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;event\u0026lt;/span\u0026gt;.getY(0) \u0026amp;#8211; event.getY(1);\n\n- return FloatMath.sqrt(x * x + y * y);\n\n- }\n\n- \n- /**\n\n- * 两点的中点\n\n- */\n\n- private void midPoint(PointF point, MotionEvent event) {\n\n- float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;x\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;event\u0026lt;/span\u0026gt;.getX(0) + event.getX(1);\n\n- float \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;y\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;event\u0026lt;/span\u0026gt;.getY(0) + event.getY(1);\n\n- point.set(x / 2, y / 2);\n\n- }\n\n- }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android 图片的浏览、缩放、拖动和自动居中"},{"content":"NDK项目源码地址 :\n转载出处 : http://blog.csdn.net/shulianghan/article/details/18964835\n.\n开发环境介绍 :\n— eclipse : adt-bundle-windows-x86-20130917\n— sdk : 版本 2.3.3\n— ndk : android-ndk-r9c-windows-x86.zip\n— cygwin : 所需组件 binutils , gcc , gcc-mingw , gdb , make;\n— javah : jdk6.0自带工具\n— javap : jdk6.0自带工具\n**JNI 总结 : **\nJava 调用 C 流程 :\n— a. 定义 Native 方法 : 在 shuliang.han.ndkparameterpassing.DataProvider.java 类中定义 Native 方法 public native int add(int x, int y);\n— b. 生成方法签名 : 进入 AndroidProject/bin/classes 目录, 使用 **javah **shuliang.han.ndkparameterpassing.DataProvider 命令, 便生成了头文件, 该头文件引用了 jni.h, 以及定义好了 对应的 Native 方法, 生成 JNIEXPORT jint JNICALL Java_shuliang_han_ndkparameterpassing_DataProvider_add (JNIEnv *, jobject, jint, jint);\n— c. 编写 Android.mk 文件 :\nLOCAL_PATH := \u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(call my-dir) include\u0026lt;/span\u0026gt;(CLEAR_VARS) LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c include $(BUILD_SHARED_LIBRARY) — d. 生成 动态库 so 文件 : 进入 Android.mk 所在目录, 在该目录执行 ndk 下的 ndk-build 命令;\n— e. Java代码加载动态库 : 在 Java 代码中调用该类的类前面, 在类的一开始, 不在方法中, 加入 static{ System.loadLibrary(“hello”); } ;\n一. JNI介绍 1. JNI引入 JNI概念 : Java本地接口,Java Native Interface, 它是一个协议, 该协议用来沟通Java代码和外部的本地C/C++代码, 通过该协议 Java代码可以调用外部的本地代码, 外部的C/C++ 代码可以调用Java代码;\nC和Java的侧重 :\n— C语言 : C语言中最重要的是 函数 function;\n— Java语言 : Java中最重要的是 JVM, class类, 以及class中的方法;\nC与Java如何交流 :\n— JNI规范 : C语言与Java语言交流需要一个适配器, 中间件, 即 JNI, JNI提供了一种规范;\n— C语言中调用Java方法 : 可以让我们在C代码中找到Java代码class中的方法, 并且调用该方法;\n— Java语言中调用C语言方法 : 同时也可以在Java代码中, 将一个C语言的方法映射到Java的某个方法上;\n— JNI桥梁作用 : JNI提供了一个桥梁, 打通了C语言和Java语言之间的障碍;\nJNI中的一些概念 :\n— native : Java语言中修饰本地方法的修饰符, 被该修饰符修饰的方法没有方法体;\n— Native方法 : 在Java语言中被native关键字修饰的方法是Native方法;\n— JNI层 : Java声明Native方法的部分;\n— JNI函数 : JNIEnv提供的函数, 这些函数在jni.h中进行定义;\n— JNI方法 : Native方法对应的JNI层实现的 C/C++方法, 即在jni目录中实现的那些C语言代码;\n2. Android中的应用程序框架 正常情况下的Android框架 : 最顶层是Android的应用程序代码, 上层的应用层 和 应用框架层 主要是Java代码, 中间有一层的Framework框架层代码是 C/C++代码, 通过Framework进行系统调用, 调用底层的库 和linux 内核;\n使用JNI时的Android框架 : 绕过Framework提供的调用底层的代码, 直接调用自己写的C代码, 该代码最终会编译成为一个库, 这个库通过JNI提供的一个Stable的ABI 调用linux kernel;ABI是二进制程序接口 application binary interface.\nJNI在Android中作用 : JNI可以调用本地代码库(即C/C++代码), 并通过 Dalvik虚拟机 与应用层 和 应用框架层进行交互, Android中JNI代码主要位于应用层 和 应用框架层;\n— 应用层 : 该层是由JNI开发, 主要使用标准JNI编程模型;\n— 应用框架层 : 使用的是Android中自定义的一套JNI编程模型, 该自定义的JNI编程模型弥补了标准JNI编程模型的不足;\nAndroid中JNI源码位置 : 在应用框架层中, 主要的JNI代码位于 framework/base目录下, 这些模块被编译成共享库之后放在 /system/lib 目录下;\nNDK与JNI区别 :\n— NDK: NDK是Google开发的一套开发和编译工具集, 主要用于Android的JNI开发;\n— JNI : JNI是一套编程接口, 用来实现Java代码与本地的C/C++代码进行交互;\nJNI编程步骤:\n— 声明native方法 : 在Java代码中声明 native method()方法;\n— 实现JNI的C/C++方法 : 在JNI层实现Java中声明的native方法, 这里使用javah工具生成带方法签名的头文件, 该JNI层的C/C++代码将被编译成动态库;\n— 加载动态库 : 在Java代码中的静态代码块中加载JNI编译后的动态共享库;\n.\n3. JNI作用 JNI作用 :\n— 扩展: JNI扩展了JVM能力, 驱动开发, 例如开发一个wifi驱动, 可以将手机设置为无限路由;\n— 高效 : 本地代码效率高, 游戏渲染, 音频视频处理等方面使用JNI调用本地代码, C语言可以灵活操作内存;\n— 复用 : 在文件压缩算法 7zip开源代码库, 机器视觉 openCV开放算法库 等方面可以复用C平台上的代码, 不必在开发一套完整的Java体系, 避免重复发明轮子;\n— 特殊 : 产品的核心技术一般也采用JNI开发, 不易破解;\nJava语言执行流程 :\n— 编译字节码 : Java编译器编译 .java源文件, 获得.class 字节码文件;\n— 装载类库 : 使用类装载器装载平台上的Java类库, 并进行字节码验证;\n— Java虚拟机 : 将字节码加入到JVM中, Java解释器 和 即时编译器 同时处理字节码文件, 将处理后的结果放入运行时系统;\n— 调用JVM所在平台类库 : JVM处理字节码后, 转换成相应平台的操作, 调用本平台底层类库进行相关处理;\nJava一次编译到处执行 : JVM在不同的操作系统都有实现, Java可以一次编译到处运行, 字节码文件一旦编译好了, 可以放在任何平台的虚拟机上运行;\n.\n二. NDK详解 1. 交叉编译库文件 C代码执行 : C代码被编译成库文件之后, 才能执行, 库文件分为动态库 和静态库 两种;\n— 动态库 : unix环境下**.so 后缀的是动态库, windows环境下.dll 后缀**的是动态库; 动态库可以依赖静态库加载一些可执行的C代码;\n— 静态库 :.a 后缀是静态库的扩展名;\n库文件来源 : C代码 进行 编译 链接操作之后, 才会生成库文件, 不同类型的CPU 操作系统 生成的库文件是不一样;\n— CPU分类 : arm结构, 嵌入式设备处理器; x86结构, pc 服务器处理器; 不同的CPU指令集不同;\n— 交叉编译 :windows x86编译出来的库文件可以在arm平台运行的代码;\n— 交叉编译工具链 : Google提供的 NDK 就是交叉编译工具链, 可以在linux环境下编译出在arn平台下执行的二进制库文件;\nNDK作用 : 是Google提供了交叉编译工具链, 能够在linux平台编译出在arm平台下执行的二进制库文件;\nNDK版本介绍 : android-ndk-windows 是在windows系统中的cygwin使用的, android-ndk-linux 是在linux下使用的;\n2. 部署NDK开发环境 (1) 下载Cygwin安装器 下载地址 : http://cygwin.com/setup-x86.exe , 这是下载器, 可以使用该下载器在线安装, 也可以将cygwin下载到本地之后, 在进行安装;\n安装器使用 : Cygwin的下载, 在线安装, 卸载 等操作都有由该安装器进行;\n— 本地文件安装 : 选择安装文件所在的目录, 然后选择所要安装的安装包;\n— 在线安装 : 选择在线安装即可, 然后选择需要的安装包;\n— 卸载 : windows上使用其它软件例如360, 控制面板中是无法卸载Cygwin的, 只能通过安装器来卸载;\n(2) 安装Cygin 双击安装器 setup-x86.exe 下一步 :\n选择安装方式 :\n— 在线安装 : 直接下载, 然后安装;\n— 下载安装文件 : 将安装文件下载下来, 可以随时安装, 注意安装文件也需要安装器来进行安装;\n— 从本地文件安装 : 即使用下载的安装文件进行安装;\n选择Cygwin安装位置 :\n选择下载好安装文件位置 : 之前我下了一个完全版的Cygwin, 包括了所有的Cygwin组件, 全部加起来有5.23G, 下载速度很快, 使用网易的镜像, 基本可以全速下载;\n选择需要安装Cygwin组件 : 这里我们只需要以下组件 : binutils , gcc , gcc-mingw , gdb , make , 不用下全部的组件;\n之后点击下一步等待完成安装即可;\n.\n安装完之后, 打开bash命令窗口, 可以设置下显示的字体, 使用 make -version 查看是否安装成功 :\n(3) Cygwin目录介绍 以下是Cygwin安装目录的情况 : 该安装目录就是所模拟的linux 的根目录;\n对应的linux目录 : 这两个目录进行对比发现, 两个目录是一样的, Cygwin的安装目录就是 linux根目录;\ncygdrive目录 : 该目录是Cygwin模拟出来的windows目录结构, 进入该目录后, 会发现windows的盘符目录, 通过该目录可以访问windows中的文件;\n(4) 下载NDK工具 — windows版本NDK:android-ndk-r9c-windows-x86.zip (32位),android-ndk-r9c-windows-x86_64.zip (64位) 该版本是用在windows上的Cygwin下, 不能直接在windows上直接运行;\n— linux版本NDK :android-ndk-r9c-linux-x86.tar.bz2(32位) , android-ndk-r9c-linux-x86_64.tar.bz2 (64位) , 该版本直接在linux下执行即可;\n在这里下载windows版本的NDK, 运行在Cygwin上;\n(4) NDK环境介绍 NDK工具的文件结构 :\nndk-build脚本 : NDK build 脚本是 gun-make 的简单封装, gun-make 是编译C语言代码的工具, 该脚本执行的前提是linux环境下必须安装 make 程序;\n**NDK安装在Cygwin中** : 将NDK压缩文件拷贝到Cygwin的根目录中, 解压 : android-ndk-r9c 目录就是NDK目录; **执行以下NDK目录下的 ndk-build 命令** : ./ndk-build ; **执行结果** : Android NDK: Could not find application project directory ! Android NDK: Please define the NDK_PROJECT_PATH variable to point to it. /android-ndk-r9c/build/core/build-local.mk:148: *** Android NDK: Aborting 。 停止。 ![](http://img.blog.csdn.net/20140130194048078)\u0026lt;/div\u0026gt; \u0026amp;nbsp; # 三. 开发第一个NDK程序 ## 1. 开发NDK程序流程 #### a. **创建Android工程**: 首选创建一个Android工程, 在这个工程中进行JNI开发; #### b. **声明native方法** : 注意方法名使用 native 修饰, 没有方法体 和 参数, eg : public native String helloFromJNI(); #### c. **创建C文件** : 在工程根目录下创建 jni 目录, 然后创建一个c语言源文件, 在文件中引入 include \u0026lt;jni.h\u0026gt; , C语言方法声明格式 jstring Java_shuliang.han.ndkhelloworld_MainActivity_helloFromJNI(JNIEnv *env) , jstring 是 Java语言中的String类型, 方法名格式为 : Java_完整包名类名_方法名(); \u0026amp;#8212; **JNIEnv参数** : 代表的是Java环境, 通过这个环境可以调用Java里面的方法; \u0026amp;#8212; **jobject参数** : 调用C语言方法的对象, thiz对象表示当前的对象, 即调用JNI方法所在的类; #### d. **编写Android.mk文件** : 如何写 查看文档, NDK根目录下有一个 documentation.html 文档, 点击该html文件就可以查看文档, 查看 Android.mk File 文档, 下面是该文档给出的 Android.mk示例 : ``` LOCAL_PATH := (call my-dir)\ninclude(CLEAR_VARS)\nLOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c\ninclude $(BUILD_SHARED_LIBRARY)\n\u0026amp;#8212; **LOCAL_PATH** : 代表mk文件所在的目录; \u0026amp;#8212; **include $(CLEAR_VARS)** : 编译工具函数, 通过该函数可以进行一些初始化操作; \u0026amp;#8212; **LOCAL_MODULE** : 编译后的 .so 后缀文件叫什么名字; \u0026amp;#8212; **LOCAL_SRC_FILES**: 指定编译的源文件名称; \u0026amp;#8212; **include $(BUILD_SHARED_LIBRARY)** : 告诉编译器需要生成动态库; #### e. **NDK编译生成动态库** : 进入 cygdrive 找到windows目录下对应的文件, 编译完成之后, 会**自动生成so文件并放在libs目录下**, 之后就可以在Java中调用C语言方法了; #### f. **Java中加载动态库** : 在Java类中的静态代码块中使用System.LoadLibrary()方法加载编译好的 .so 动态库; **NDK平台版本** : NDK脚本随着 android-sdk 版本不同, 执行的脚本也是不同的, 不同平台会引用不同的头文件, 编译的时候一定注意 sdk 与 ndk 版本要一致; **so文件在内存中位置** : apk文件安装到手机上之后, .so动态库文件存在在 data/安装目录/libs 目录下; ## 2. 开发实例 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **按照上面的步骤进行开发** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### (1) 创建Android工程 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Android工程版本** : 创建一个Android工程,**minSdk 为 7 即 android-2.1**, 编译使用的**sdk为 10 即 android-2.3.3** ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` \u0026amp;lt;uses-sdk android:minSdkVersion=\u0026#34;7\u0026#34; android:targetSdkVersion=\u0026#34;10\u0026#34; /\u0026amp;gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **NDK编译原则** : 编译NDK动态库是**按照最小版本进行编译**, 选择编译的平台的时候, 会选择 NDK 7 平台进行编译; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130221252312) ![](http://img.blog.csdn.net/20140130221301250) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### (2) 声明native方法 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **声明native方法, 注意该方法没有方法体 和 参数, 如下** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` /* * 声明一个native方法 * 这个方法在Java中是没有实现的, 没有方法体 * 该方法需要使用C语言编写 */ public native String helloFromJNI(); . **作者** : **万境绝尘 ** **转载请注明出处** : [**http://blog.csdn.net/shulianghan/article/details/18964835**](http://blog.csdn.net/shulianghan/article/details/18964835) . \u0026lt;/div\u0026gt; ### (3) 创建C文件 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **引入头文件**: 首先要包含头文件 jni.h, 该**头文件位置**定义在 android-ndk-r9c\\platforms\\android-5\\arch-arm\\usr\\include目录下的 jni.h, 下面是该头文件中定义的一些方法, 包括本项目中使用的 NewString 方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` jstring (*NewString)(JNIEnv*, const jchar*, jsize); jsize (*GetStringLength)(JNIEnv*, jstring); const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*); void (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*); jstring (*NewStringUTF)(JNIEnv*, const char*); jsize (*GetStringUTFLength)(JNIEnv*, jstring); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **调用Java类型** : C中调用Java中的String类型为 jstring; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **C语言方法名规则** : Java_完整包名类名_方法名(JNIEnv *env, jobject thiz), 注意完整的类名包名中包名的点要用 _ 代替; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **参数介绍** : C语言方法中有两个重要的参数, JNIEnv *env, jobject thiz ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNIEnv参数** : 该参数代表Java环境, 通过这个环境可以调用Java中的方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **jobject参数** : 该参数代表调用jni方法的类, 在这里就是MainActivity; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **调用jni.h中的NewStringUTF方法** : 该方法的作用是在C语言中创建一个Java语言中的String类型对象, jni.h中是这样定义的 jstring (*NewStringUTF)(JNIEnv*, const char*), JNIEnv 结构体中包含了 NewStringUTF 函数指针, 通过 JNIEnv 就可以调用这个方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **C语言文件源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` #include \u0026lt;jni.h\u0026gt;\n/*\n方法名称规定 : Java_完整包名类名_方法名() JNIEnv 指针 参数介绍 : env : 代表Java环境, 通过这个环境可以调用Java中的方法 thiz : 代表调用JNI方法的对象, 即MainActivity对象 */ jstring Java_shuliang_han_ndkhelloworld_MainActivity_helloFromJNI(JNIEnv env, jobject thiz) { / 调用 android-ndk-r9c\\platforms\\android-8\\arch-arm\\usr\\include 中jni.h中的方法 jni.h 中定义的方法 jstring (NewStringUTF)(JNIEnv, const char*); */ return (*env)-\u0026gt;NewStringUTF(env, \u0026ldquo;hello world jni\u0026rdquo;); } \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### (4) 编写Android.mk文件 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **查询NDK文档** : NDK的文档在NDK工具根目录下, 点击 documentation.html 文件, 就可以在浏览器中打开NDK文档; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **上面的开发流程中详细的介绍了Android.mk 五个参数的详细用处, 这里直接给出源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` LOCAL_PATH := \u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(call my-dir) include\u0026lt;/span\u0026gt;(CLEAR_VARS) LOCAL_MODULE := hello LOCAL_SRC_FILES := hello.c include $(BUILD_SHARED_LIBRARY) ### (5) 编译NDK动态库 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **进入Cygwin相应目录** : 从Cygwin中的cygdrive 中进入windows的工程jni目录 ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130223434359) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **编译hello.c文件** : 注意Android.mk文件 与 hello.c 文件在同一目录中; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130224601328) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **编译完成后的情况** : 编译完之后 会成成一个obj文件, 在obj文件中会生成 libhello.so, 系统会**自动将该 so后缀文件放在libs目录下**; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130224720812) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### (6) Java中加载动态库 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **静态代码块中加载** : Java中在静态代码块中加载库文件, 调用 System.loadLibrary(\u0026amp;#8220;hello\u0026amp;#8221;) 方法,**注意 libs中的库文件名称为 libhello.so**,**我们加载的时候 将 lib 去掉**, 只取hello 作为动态库名称, 这是规定的; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` //静态代码块加载C语言库文件 static{ System.loadLibrary(\u0026quot;hello\u0026quot;); } \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### (7) 其它源码 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **MainActivity源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` package shuliang.han.ndkhelloworld; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Toast; public class MainActivity extends Activity { //静态代码块加载C语言库文件 static{ System.loadLibrary(\u0026#34;hello\u0026#34;); } /* * 声明一个native方法 * 这个方法在Java中是没有实现的, 没有方法体 * 该方法需要使用C语言编写 */ public native String helloFromJNI(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); System.out.println(helloFromJNI()); } public void onClick(View view) { //点击按钮显示从jni调用得到的字符串信息 Toast.makeText(getApplicationContext(), helloFromJNI(), 1).show(); } } **XML布局文件** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` \u0026lt;RelativeLayout xmlns:android=\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot; xmlns:tools=\u0026ldquo;http://schemas.android.com/tools\u0026quot; android:layout_width=\u0026ldquo;match_parent\u0026rdquo; android:layout_height=\u0026ldquo;match_parent\u0026rdquo; android:paddingBottom=\u0026quot;@dimen/activity_vertical_margin\u0026rdquo; android:paddingLeft=\u0026quot;@dimen/activity_horizontal_margin\u0026rdquo; android:paddingRight=\u0026quot;@dimen/activity_horizontal_margin\u0026quot; android:paddingTop=\u0026quot;@dimen/activity_vertical_margin\u0026quot; tools:context=\u0026quot;.MainActivity\u0026quot; \u0026gt;\n\u0026amp;lt;Button android:id=\u0026quot;@+id/bt\u0026quot; android:layout_width=\u0026quot;wrap_content\u0026quot; android:layout_height=\u0026quot;wrap_content\u0026quot; android:onClick=\u0026quot;onClick\u0026quot; android:text=\u0026quot;显示JNI返回的字符串\u0026quot; /\u0026amp;gt; \u0026lt;/RelativeLayout\u0026gt;\n### (8) 将源码上传到GitHub中 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 在上一篇博客 [http://blog.csdn.net/shulianghan/article/details/18812279](http://blog.csdn.net/shulianghan/article/details/18812279) 中对GitHub用法进行了详解; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **在GitHub上创建工程** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **项目地址** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **HTTP**: https://github.com/han1202012/NDKHelloworld.git \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **SSH** : git@github.com:han1202012/NDKHelloworld.git \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **生成的命令** : ``` touch README.md git init git add README.md git commit -m \u0026#34;first commit\u0026#34; git remote add origin git@github.com:han1202012/NDKHelloworld.git git push -u origin master **打开 Git Bash 命令行窗口** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **从GitHub上克隆项目到本地** : git clone git@github.com:han1202012/NDKHelloworld.git , 注意克隆的时候直接在仓库根目录即可, 不用再创建项目根目录 ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130232116609) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **添加文件** : git add ./* , 将目录中所有文件添加; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130232554281) — 查看状态 : git status ; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130232317546) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **提交缓存** : git commit -m \u0026amp;#8216;提交\u0026amp;#8217;; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130232423812) — 提交到远程GitHub仓库 : git push -u origin master ; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130232509203) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **GitHub项目** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140130232709500) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 3. 项目讲解 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### (1) Android.mk文件讲解 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Android.mk文件内容** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` LOCAL_PATH := (call my-dir)\ninclude(CLEAR_VARS)\nLOCAL_MODULE := hello LOCAL_SRC_FILES := hello.c\ninclude $(BUILD_SHARED_LIBRARY)\n\u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **获取当前文件内容** : $(call my-dir) 是编译器中的宏方法, 调用该宏方法, 就会**返回前的目录路径**; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **赋值符号** : \u0026amp;#8221; := \u0026amp;#8221; 是**赋值符号**, 第一句话 是 返回当前文件所在的当前目录, 并将这个目录路径赋值给 LOCAL_PATH; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **初始化编译模块参数** : $(CLEAR_VARS) 作用是将编译模块的参数初始化, LOCAL_MODULE LOCAL_SRC_FILES 也是这样的参数; \u0026lt;/div\u0026gt; **指定编译模块** : LOCAL_MODULE := hello , 指定编译后的 so 文件名称, 编译好之后系统会在该名称前面加上 \u0026amp;#8220;lib\u0026amp;#8221;, 后缀加上 \u0026amp;#8220;.so\u0026amp;#8221;;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **指定编译源文件** : LOCAL_SRC_FILES := hello.c 告诉编译系统源文件, 如果有多个文件那么就依次写在后面即可; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **编译成静态库** : include $(BUILD_SHARED_LIBRARY), 作用是高速系统, 编译的结果编译成 .so 后缀的静态库; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **静态库引入** : NDK的platform中有很多 \u0026amp;#8220;.a\u0026amp;#8221; 结尾的动态库, 我们编译动态库的时候, 可以将一些静态库引入进来; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### (2) 自动生成方法签名 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **使用javah工具** : 在C中实现Java调用的jni方法, 方法的签名很复杂, 需要将完整的包名类名方法名都要使用 \u0026amp;#8220;_\u0026amp;#8221; 连接起来, 很麻烦, jdk提供的生成签名方法的工具; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **遗留问题** : 目前查到的方法是 在bin目录下 执行 javah -jni 包名类名 命令, 但是执行不成功, 暂时没找到解决方案; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212;** Android中会自动生成** .class文件吗, 没发现啊, PY人! \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140131220806843) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **解决问题** : 在jni目录下存在classes目录, 但是这个目录在eclipse中不显示, 这里我们要注意; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207202154937) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **在Cygwin中使用 javah 命令即可** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207185534812) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **生成的头文件** : shuliang_han_ndkparameterpassing_DataProvider.h; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` /* DO NOT EDIT THIS FILE - it is machine generated */ #include \u0026amp;lt;jni.h\u0026amp;gt; /* Header for class shuliang_han_ndkparameterpassing_DataProvider */ #ifndef _Included_shuliang_han_ndkparameterpassing_DataProvider #define _Included_shuliang_han_ndkparameterpassing_DataProvider #ifdef __cplusplus extern \u0026#34;C\u0026#34; { #endif /* * Class: shuliang_han_ndkparameterpassing_DataProvider * Method: add * Signature: (II)I */ JNIEXPORT jint JNICALL Java_shuliang_han_ndkparameterpassing_DataProvider_add (JNIEnv *, jobject, jint, jint); /* * Class: shuliang_han_ndkparameterpassing_DataProvider * Method: sayHelloInc * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_shuliang_han_ndkparameterpassing_DataProvider_sayHelloInc (JNIEnv *, jobject, jstring); /* * Class: shuliang_han_ndkparameterpassing_DataProvider * Method: intMethod * Signature: ([I)[I */ JNIEXPORT jintArray JNICALL Java_shuliang_han_ndkparameterpassing_DataProvider_intMethod (JNIEnv *, jobject, jintArray); #ifdef __cplusplus } #endif #endif \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### (3) NDK开发中乱码问题 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **解决乱码思路** : C语言编译的时候用的是 ISO-8859-1 码表进行编码, 如果我们使用C语言jni开发, 需要进行转码操作; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; 将ISO-8859-1转为UTF-8字符: String string = new String(str.getBytes(\u0026amp;#8220;iso8859-1\u0026amp;#8221;), \u0026amp;#8220;UTF-8\u0026amp;#8221;); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 示例 : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **添加中文jni调用** : 将jni中的hello.c 中返回的字符串修改为中文, 重新编译 .so 静态库文件; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **修改后的hello.c文件如下** : 只改变了返回的字符串, 添加了中文; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` #include \u0026lt;jni.h\u0026gt;\n/*\n方法名称规定 : Java_完整包名类名_方法名() JNIEnv 指针 参数介绍 : env : 代表Java环境, 通过这个环境可以调用Java中的方法 thiz : 代表调用JNI方法的对象, 即MainActivity对象 */ jstring Java_shuliang_han_ndkhelloworld_MainActivity_helloFromJNI(JNIEnv env, jobject thiz) { / 调用 android-ndk-r9c\\platforms\\android-8\\arch-arm\\usr\\include 中jni.h中的方法 jni.h 中定义的方法 jstring (NewStringUTF)(JNIEnv, const char*); */ return (*env)-\u0026gt;NewStringUTF(env, \u0026ldquo;hello world jni 中文\u0026rdquo;); } **使用NDK重新编译hello.c文件** : 修改了C源码之后, 重新将该c文件编译成so文件;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **编译过程**: 打开cygwin, 进入cygdrive/ 下对应windows中源码项目中的jni目录, 执行 /android-ndk-r9c/ndk-build 命令; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140131223258359) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **运行Android代码报错** : 因为jni中c文件有中文, 中文不能被识别; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` 01-31 14:36:04.803: W/dalvikvm(389): JNI WARNING: illegal continuation byte 0xd0 01-31 14:36:04.803: W/dalvikvm(389): string: \u0026#39;hello world jni ????\u0026#39; 01-31 14:36:04.803: W/dalvikvm(389): in Lshuliang/han/ndkhelloworld/MainActivity;.helloFromJNI ()Ljava/lang/String; (NewStringUTF) 01-31 14:36:04.834: I/dalvikvm(389): \u0026#34;main\u0026#34; prio=5 tid=1 NATIVE 01-31 14:36:04.834: I/dalvikvm(389): | group=\u0026#34;main\u0026#34; sCount=0 dsCount=0 obj=0x4001f1a8 self=0xce48 01-31 14:36:04.834: I/dalvikvm(389): | sysTid=389 nice=0 sched=0/0 cgrp=default handle=-1345006528 01-31 14:36:04.844: I/dalvikvm(389): | schedstat=( 257006717 305462830 51 ) 01-31 14:36:04.844: I/dalvikvm(389): at shuliang.han.ndkhelloworld.MainActivity.helloFromJNI(Native Method) 01-31 14:36:04.844: I/dalvikvm(389): at shuliang.han.ndkhelloworld.MainActivity.onCreate(MainActivity.java:26) 01-31 14:36:04.844: I/dalvikvm(389): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 01-31 14:36:04.853: I/dalvikvm(389): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611) 01-31 14:36:04.853: I/dalvikvm(389): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663) 01-31 14:36:04.853: I/dalvikvm(389): at android.app.ActivityThread.access\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;1500(ActivityThread.java:117) 01-31 14:36:04.864: I/dalvikvm(389): at android.app.ActivityThread\u0026lt;/span\u0026gt;H.handleMessage(ActivityThread.java:931) 01-31 14:36:04.864: I/dalvikvm(389): at android.os.Handler.dispatchMessage(Handler.java:99) 01-31 14:36:04.864: I/dalvikvm(389): at android.os.Looper.loop(Looper.java:123) 01-31 14:36:04.864: I/dalvikvm(389): at android.app.ActivityThread.main(ActivityThread.java:3683) 01-31 14:36:04.864: I/dalvikvm(389): at java.lang.reflect.Method.invokeNative(Native Method) 01-31 14:36:04.874: I/dalvikvm(389): at java.lang.reflect.Method.invoke(Method.java:507) 01-31 14:36:04.874: I/dalvikvm(389): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 01-31 14:36:04.874: I/dalvikvm(389): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 01-31 14:36:04.874: I/dalvikvm(389): at dalvik.system.NativeStart.main(Native Method) 01-31 14:36:04.884: E/dalvikvm(389): VM aborting \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 4. JNIEnv 详解 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNIEnv作用** : JNIEnv 是一个指针,**指向了一组JNI函数**, 这些函数可以在jni.h中查询到,**通过这些函数可以实现 Java层 与 JNI层的交互** , 通过JNIEnv 调用JNI函数 可以访问java虚拟机, 操作java对象; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNI线程相关性** : JNIEnv只在当前的线程有效,**JNIEnv不能跨线程传递**, 相同的Java线程调用本地方法, 所使用的JNIEnv是相同的, 一个Native方法不能被不同的Java线程调用; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNIEnv结构体系** : JNIEnv指针**指向一个线程相关的结构**,**线程相关结构指向一个指针数组**,**指针数组中的每个元素最终指向一个JNI函数**. \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### (1) JNIEnv的C/C++声明 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **jni.h中声明JNIEnv** : C语言中定义的JNIEnv 是 JNINativeInterface* , C++中定义的JNIEnv 是 _JNIEnv; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` struct _JNIEnv; struct _JavaVM; typedef const struct JNINativeInterface* C_JNIEnv;\n#if defined(__cplusplus)\t//为了兼容C 和 C++两种代码 使用该 宏加以区分 typedef _JNIEnv JNIEnv;\t//C++ 中的JNIEnv类型 typedef _JavaVM JavaVM; #else typedef const struct JNINativeInterface* JNIEnv;//C语言中的JNIEnv类型 typedef const struct JNIInvokeInterface* JavaVM; #endif\n### (2) C语言中的JNIEnv \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **关于JNIEnv指针调用解析** : C中**JNIEnv就是 const struct JNINativeInterface***, JNIEnv * env**等价于 JNINativeInterface** env**, 因此要得到JNINativeInterface结构体中定义的函数指针, 就必须先获取到 JNINativeInterface的一级指针对象 即 *env , 该**一级指针对象就是 JNINativeInterface* env**, 然后通过该**一级指针对象调用JNI函数 : (*env)-\u0026gt;NewStringUTF(env, \u0026amp;#8220;hello\u0026amp;#8221;)**; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **在JNINativeInterface结构体中定义了一系列的关于Java操作的相关方法** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` /* * Table of interface function pointers. */ struct JNINativeInterface { void* reserved0; void* reserved1; ... ... jboolean (*CallStaticBooleanMethodV)(JNIEnv*, jclass, jmethodID, va_list); jboolean (*CallStaticBooleanMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jbyte (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, ...); jbyte (*CallStaticByteMethodV)(JNIEnv*, jclass, jmethodID, va_list); ... ... void* (*GetDirectBufferAddress)(JNIEnv*, jobject); jlong (*GetDirectBufferCapacity)(JNIEnv*, jobject); /* added in JNI 1.6 */ jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject); }; ### (3) C++中的JNIEnv \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **C++ 中的JNIEnv**: C++ 中的JNIEnv 就是 _JNIEnv 结构体, 二者是等同的; 因此在调用 JNI函数的时候, 只需要使用 env-\u0026gt;NewStringUTF(env, \u0026amp;#8220;hello\u0026amp;#8221;)方法即可, 不用在进行*运算; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` /*\nC++ object wrapper. This is usually overlaid on a C struct whose first element is a JNINativeInterface*. We rely somewhat on compiler behavior. / struct _JNIEnv { / do not rename this; it does not seem to be entirely opaque / const struct JNINativeInterface functions; #if defined(__cplusplus)\njint GetVersion() { return functions-\u0026amp;gt;GetVersion(this); } jlong GetDirectBufferCapacity(jobject buf) { return functions-\u0026amp;gt;GetDirectBufferCapacity(this, buf); } /* added in JNI 1.6 */ jobjectRefType GetObjectRefType(jobject obj) { return functions-\u0026amp;gt;GetObjectRefType(this, obj); } #endif /__cplusplus/ };\n## 5. JNI方法命名规则(标准JNI规范) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNI实现的方法 与 Java中Native方法的映射关系** : 使用方法名进行映射, 可以使用 javah 工具进入 bin/classes 目录下执行命令, 即可生成头文件; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNI方法参数介绍**: \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **参数①** : 第一个参数是JNI接口指针 JNIEnv; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **参数②** : 如果Native方法是非静态的, 那么第二个参数就是对Java对象的引用, 如果Native方法是静态的, 那么第二个参数就是对Java类的Class对象的引用; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNI方法名规范** : 返回值 + Java前缀 + 全路径类名 + 方法名 + 参数① JNIEnv + 参数② jobject + 其它参数; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **注意分隔符** : Java前缀 与 类名 以及类名之间的包名 和 方法名之间 使用 \u0026amp;#8220;_\u0026amp;#8221; 进行分割; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **声明 非静态 方法**: \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **Native方法** : public int hello (String str, int i); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI方法**: jint Java_shuliang_han_Hello_hello(JNIEnv * env, jobject obj, jstring str, jint i); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **声明 静态 方法** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **Native方法** : public static int hello (String str, int i); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212;**JNI方法** : jint Java_shuliang_han_Hello_hello(JNIEnv * env, jobject clazz, jstring str, jint i); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **两种规范** : 以上是Java的标准JNI规范, 在Android中还有一套自定义的规范, 该规范是Android应用框架层 和 框架层交互使用的JNI规范, 依靠方法注册 映射 Native方法 和 JNI方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 6. JNI方法签名规则 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNI识别Java方法** : **JNI依靠函数名 和 方法签名 识别方法**, 函数名是不能唯一识别一个方法的, 因为方法可以重载, 类型签名代表了 参数 和 返回值; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **签名规则** : (**参数1类型签名参数2类型签名参数3类型签名参数N类型签名**\u0026amp;#8230;)**返回值类型签名**, 注意参数列表中没有任何间隔; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java类型 与 类型签名对照表** : 注意 boolean 与 long 不是大写首字母, 分别是 Z 与 J, 类是L全限定类名, 数组是[元素类型签名; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **类的签名规则** :**L + 全限定名 + ;**三部分, 全限定类名以 / 分割; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;table border=\u0026#34;1\u0026#34; width=\u0026#34;500\u0026#34; cellspacing=\u0026#34;1\u0026#34; cellpadding=\u0026#34;1\u0026#34;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; Java类型 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 类型签名 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; boolean \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; Z \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; byte \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; B \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; char \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; C \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; short \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; S \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; int \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; I \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; long \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; J \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; float \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; F \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; double \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; D \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; 类 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; L全限定类名 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; 数组 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; [元素类型签名 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; eg. long function(int n, String str, int[] arr); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **该方法的签名** :**(ILjava/lang/String;[I)J** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; # 四. Java调用JNI法与日志打印 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 1. JNI数据类型 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java数据类型 C数据类型 JNI数据类型对比** : 32位 与 64位机器可能会有出入; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;table border=\u0026#34;1\u0026#34; width=\u0026#34;600\u0026#34; cellspacing=\u0026#34;1\u0026#34; cellpadding=\u0026#34;1\u0026#34;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; **Java数据类型** \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; **C本地类型** \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; **JNI定义别名** \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; int \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; long \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jint/jsize \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; long \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; __int64 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jlong \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; byte \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; signed char \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jbyte \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; boolean \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; unsigned char \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jboolean \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; char \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; unsigned short \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jchar \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; short \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; short \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jshort \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; float \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; float \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jfloat \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; double \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; doyble \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jdouble \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; object\u0026amp;#8217; \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; _jobject \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; jobject \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **数据类型表示方法** : int数组类型 jintArray , boolean数组 jbooleanArray \u0026amp;#8230; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **头文件定义类型** : 这些基本的数据类型在**jni.h 中都有相应的定义** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...); jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list); jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...); jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list); jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...); jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list); jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...); jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list); jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...); jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list); jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...); jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list); jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize); jbyteArray (*NewByteArray)(JNIEnv*, jsize); jcharArray (*NewCharArray)(JNIEnv*, jsize); jshortArray (*NewShortArray)(JNIEnv*, jsize); jintArray (*NewIntArray)(JNIEnv*, jsize); jlongArray (*NewLongArray)(JNIEnv*, jsize); jfloatArray (*NewFloatArray)(JNIEnv*, jsize); jdoubleArray (*NewDoubleArray)(JNIEnv*, jsize); \u0026lt;/div\u0026gt; ## 2. JNI在Java和C语言之间传递int类型 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java中定义的方法** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` //将Java中的两个int值 传给C语言, 进行相加后, 返回java语言 shuliang.han.ndkparameterpassing.DataProvider public native int add(int x, int y); **C语言中定义的方法** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` #include \u0026amp;lt;jni.h\u0026amp;gt; //方法签名, Java环境 和 调用native方法的类 必不可少, 后面的参数就是native方法的参数 jint Java_shuliang_han_ndkparameterpassing_DataProvider_add(JNIEnv * env, jobject obj, jint x, jint y) { return x + y; } **使用NDK工具变异该c类库** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 在cygwin中进入cygdrive, 然后**进入windows中相应的目录**, 执行 **/android-ndk-r9c/ndk-build** 命令, 即可完成编译; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206151254187) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 3. NDK中C代码使用LogCat \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### (1) 引入头文件 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **NDK中断点调试** : 断点调试在NDK中实现极其困难, 因此在这里我们一般都是打印日志; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **引入头文件** : 在C代码中引入下面的头文件; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` #include \u0026lt;android/log.h\u0026gt; #define LOG_TAG \u0026ldquo;System.out\u0026rdquo; #define LOGD(\u0026hellip;) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, VA_ARGS) #define LOGI(\u0026hellip;) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, VA_ARGS)\n**头文件介绍** : log.h 是关于调用 LogCat日志文件;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **log.h头文件路径** : android-ndk-r9c\\platforms\\android-9\\arch-arm\\usr\\include\\android\\log.h; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **主要方法** : __android_log_write, 下面有该方法的解析, 传入参数 日志等级 日志标签 日志内容; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **宏定义** : __android_log_write 方法太麻烦, 这里做出一个映射, LOGD(\u0026amp;#8230;) 输出debug级别的日志, LOGI(\u0026amp;#8230;) 输出Info级别的日志; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212;**LogCat日志级别** : verbose \u0026lt; debug \u0026lt; info \u0026lt; warn \u0026lt; error \u0026lt; assert; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **使用到的log.h文件内容解析** : __android_log_write 方法中的日志等级参数就使用 枚举中的内容 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` /* * Android log priority values, in ascending priority order. 日志等级 */ typedef enum android_LogPriority { ANDROID_LOG_UNKNOWN = 0, ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */ ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */ } android_LogPriority; /* * Send a simple string to the log. 向LogCat中输出日志 参数介绍: 日志优先级 , 日志标签 , 日志内容 */ int __android_log_write(int prio, const char *tag, const char *text); **C语言中输入输出函数占位符介绍** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;table border=\u0026quot;1\u0026quot; width=\u0026quot;200\u0026quot; cellspacing=\u0026quot;1\u0026quot; cellpadding=\u0026quot;1\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; 占位符 \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 数据类型 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %d \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; int \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %ld \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; long int \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %c \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; char \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %f \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; float \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; \u0026amp;lf \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; double \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %x \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 十六进制 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %O \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 八进制 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td\u0026gt; %s \u0026lt;/td\u0026gt; \u0026lt;td\u0026gt; 字符串 \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### (2) Android.mk增加liblog.so动态库 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **在该make配置文件中, 增加一行** : LOCAL_LDLIBS += -llog , 该语句添加在 LOCAL_SRC_FILES 语句下面一行; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **完整的Android.mk文件** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` LOCAL_PATH := (call my-dir)\ninclude(CLEAR_VARS)\nLOCAL_MODULE := DataProvider LOCAL_SRC_FILES := DataProvider.c #增加log函数对应的函数库 liblog.so libthread_db.a LOCAL_LDLIBS += -llog -lthread_db include $(BUILD_SHARED_LIBRARY)\n\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **函数库位置** : android-ndk-r9c\\platforms\\android-9\\arch-arm\\usr\\lib; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **函数库截图** : 从该目录下的 liglog.so可以看出, 存在该库; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206154355906) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **引入函数库方法** : 使用 LOCAL_LDLIBS += -l函数库名, 注意**函数库名不带lib前缀** 和**.so 后缀**, 同时可以添加多个库, 使用 -l库1 -l库2 -库3 ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### (3) 编译执行 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **根据(1) 中的占位符, 编写打印日志代码**: \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` //Java中的int对应的是C语言中的long类型, 对应JNI中的jint类型, C语言中 LOGI(\u0026#34;JNI_日志 : x = %ld , y = %ld\u0026#34; , x , y); **最终的包含打印日志的完整代码** : 注意, 这里有一处可能错误, 如果是32位机器, int类型占位符使用 %d 即可;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` #include \u0026lt;jni.h\u0026gt; #include \u0026lt;android/log.h\u0026gt; #define LOG_TAG \u0026ldquo;System.out\u0026rdquo; #define LOGD(\u0026hellip;) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, VA_ARGS) #define LOGI(\u0026hellip;) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, VA_ARGS)\n//方法签名, Java环境 和 调用native方法的类 必不可少, 后面的参数就是native方法的参数 jint Java_shuliang_han_ndkparameterpassing_DataProvider_add(JNIEnv * env, jobject obj, jint x, jint y) { //Java中的int对应的是C语言中的long类型, 对应JNI中的jint类型, C语言中 LOGI(\u0026ldquo;JNI_日志 : x = %ld , y = %ld\u0026rdquo; , x , y); return x + y; }\n**重新编译C文件** : 执行 **/android-ndk-r9c/ndk-build**命令;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **第一次编译** : 出现警告, long int占位符行不通, 注意区分机器位长, 64位 与 32位不同, 这样编译出现的结果就不会打印日志; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206155158937) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **第二次编译** : 将占位符改为 %d ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206160147875) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **执行按钮之后打印的日志** : 虽然有乱码, 不过显示出来了; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206160218625) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206184130671) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 4. 字符串处理 \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java中的String转为C语言中的char字符串** : 下面的工具方法可以在C程序中解决这个问题; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` // java中的jstring, 转化为c的一个字符数组 char* Jstring2CStr(JNIEnv* env, jstring jstr) { //声明了一个字符串变量 rtn char* rtn = NULL; //找到Java中的String的Class对象 jclass clsstring = (*env)-\u0026amp;gt;FindClass(env, \u0026#34;java/lang/String\u0026#34;); //创建一个Java中的字符串 \u0026#34;GB2312\u0026#34; jstring strencode = (*env)-\u0026amp;gt;NewStringUTF(env, \u0026#34;GB2312\u0026#34;); /* * 获取String中定义的方法 getBytes(), 该方法的参数是 String类型的, 返回值是 byte[]数组 * \u0026#34;(Ljava/lang/String;)[B\u0026#34; 方法前面解析 : * -- Ljava/lang/String; 表示参数是String字符串 * -- [B : 中括号表示这是一个数组, B代表byte类型, 返回值是一个byte数组 */ jmethodID mid = (*env)-\u0026amp;gt;GetMethodID(env, clsstring, \u0026#34;getBytes\u0026#34;, \u0026#34;(Ljava/lang/String;)[B\u0026#34;); //调用Java中的getBytes方法, 传入参数介绍 参数②表示调用该方法的对象, 参数③表示方法id , 参数④表示方法参数 jbyteArray barr = (jbyteArray)(*env)-\u0026amp;gt;CallObjectMethod(env, jstr, mid, strencode); // String .getByte(\u0026#34;GB2312\u0026#34;); //获取数组的长度 jsize alen = (*env)-\u0026amp;gt;GetArrayLength(env, barr); //获取数组中的所有的元素 , 存放在 jbyte*数组中 jbyte* ba = (*env)-\u0026amp;gt;GetByteArrayElements(env, barr, JNI_FALSE); //将Java数组中所有元素拷贝到C的char*数组中, 注意C语言数组结尾要加一个 \u0026#39;\\0\u0026#39; if (alen \u0026amp;gt; 0) { rtn = (char*) malloc(alen + 1); //new char[alen+1]; \u0026#34;\\0\u0026#34; memcpy(rtn, ba, alen); rtn[alen] = 0; } (*env)-\u0026amp;gt;ReleaseByteArrayElements(env, barr, ba, 0); //释放内存 return rtn; } \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Jstring2CStr方法讲解** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; a. **获取Java中String类型的class对象** : 参数 : 上下文环境 env, String类完整路径 ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` jclass clsstring = (*env)-\u0026gt;FindClass(env, \u0026ldquo;java/lang/String\u0026rdquo;);\nb.**创建Java字符串** : 使用 NewStringUTF 方法;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` jstring strencode = (*env)-\u0026amp;gt;NewStringUTF(env, \u0026#34;GB2312\u0026#34;); c.**获取String中的getBytes()方法** : 参数介绍 ① env 上下文环境 ② 完整的类路径 ③ 方法名 ④ 方法签名, 方法签名 Ljava/lang/String; 代表参数是String字符串, [B 中括号表示这是一个数组, B代表byte类型, 返回值是一个byte数组;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` jmethodID mid = (*env)-\u0026amp;gt;GetMethodID(env, clsstring, \u0026quot;getBytes\u0026quot;, \u0026quot;(Ljava/lang/String;)[B\u0026quot;); d. **获取数组的长度** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` jsize alen = (*env)-\u0026amp;gt;GetArrayLength(env, barr); e. 获取数组元素 : 获取数组中的所有的元素 , 存放在 jbyte*数组中; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` jbyte* ba = (*env)-\u0026gt;GetByteArrayElements(env, barr, JNI_FALSE);\nf.**数组拷贝**: 将Java数组中所有元素拷贝到C的char*数组中, 注意C语言数组结尾要加一个 \u0026amp;#8216;\\0\u0026amp;#8217;;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` if (alen \u0026amp;gt; 0) { rtn = (char*) malloc(alen + 1); //new char[alen+1]; \u0026#34;\\0\u0026#34; memcpy(rtn, ba, alen); rtn[alen] = 0; } g.**释放内存** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` (*env)-\u0026gt;ReleaseByteArrayElements(env, barr, ba, 0); //释放内存\n\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . **作者** : **万境绝尘 ** **转载请注明出处** : [**http://blog.csdn.net/shulianghan/article/details/18964835**](http://blog.csdn.net/shulianghan/article/details/18964835) . \u0026lt;/div\u0026gt; **C语言方法** : 注意调用Jstring2CStr方法之后要强转, 否则会出错, Jstring2CStr方法要定义在该方法的前面, C语言中的方法要先声明才能使用;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` jstring Java_shuliang_han_ndkparameterpassing_DataProvider_sayHelloInc(JNIEnv *env, jobject obj, jstring str) { char *p = (char*)Jstring2CStr(env, str); //打印Java传递过来的数据 LOGI(\u0026#34;Java JNI string parameter is : %s\u0026#34;, p); char *append = \u0026#34;append\u0026#34;; //strcat(dest, source) 函数可以将source字符串 添加到dest字符串后面 return (*env)-\u0026amp;gt;NewStringUTF(env, strcat(p, append)); } \u0026amp;#8212; **如果没有强转会出现下面的错误** : char *p = Jstring2CStr(env, str); \u0026amp;#8212; **将Jstring2CStr方法定义在主方法下面会出现下面错误** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206183825406) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` case R.id.sayHelloInc:\nToast.makeText(getApplicationContext(), dataProvider.sayHelloInc(\u0026ldquo;Hello\u0026rdquo;), Toast.LENGTH_LONG).show();\nbreak;\n**编译之后运行结果** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206184007406) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140206184042125) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 5. 开发JNI程序流程 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; a. **C语言类库接口** : 存在C语言类库, 调用接口为login_server(char* address, char* username, char* password); b. **Java定义本地方法** : public native void LoginServer(String address, String user, String pwd); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; c. **C语言JNI代码** : Java_包名_类名_LoginServer(JNIEnv* env, jobject obj, jstring address, jstring user, jstring pwd){\u0026amp;#8230;调C接口}; **注意跨语言字符串转换**: JNI方法中, 要将Java的String字符串转为C中的char*字符串; **首先验证C码农提供的代码是否可用** : 验证该api是否可用, 在一个 int main() 函数中进行测试, 根据该测试代码查看方法执行相关的情况;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 6. 数组参数处理 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **模块讲解** : 在该模块中, Java语言传递一个int数组参数给C语言, C语言将这一组参数读取出来, 并且输出到Android的LogCat中, 这里涉及到了两个重要的JNI方法, 一个数**获取数组长度方法**, 一个是**获取数组中每个元素的方法**; **创建数组相关方法** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize); jbyteArray (*NewByteArray)(JNIEnv*, jsize); jcharArray (*NewCharArray)(JNIEnv*, jsize); jshortArray (*NewShortArray)(JNIEnv*, jsize); jintArray (*NewIntArray)(JNIEnv*, jsize); jlongArray (*NewLongArray)(JNIEnv*, jsize); jfloatArray (*NewFloatArray)(JNIEnv*, jsize); jdoubleArray (*NewDoubleArray)(JNIEnv*, jsize); **获取数组元素相关方法** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` jboolean* (GetBooleanArrayElements)(JNIEnv, jbooleanArray, jboolean*);\njbyte* (GetByteArrayElements)(JNIEnv, jbyteArray, jboolean*);\njchar* (GetCharArrayElements)(JNIEnv, jcharArray, jboolean*);\njshort* (GetShortArrayElements)(JNIEnv, jshortArray, jboolean*);\njint* (GetIntArrayElements)(JNIEnv, jintArray, jboolean*);\njlong* (GetLongArrayElements)(JNIEnv, jlongArray, jboolean*);\njfloat* (GetFloatArrayElements)(JNIEnv, jfloatArray, jboolean*);\njdouble* (GetDoubleArrayElements)(JNIEnv, jdoubleArray, jboolean*);\n**C语言代码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` jintArray Java_shuliang_han_ndkparameterpassing_DataProvider_intMethod(JNIEnv *env, jobject obj, jintArray arr) { //获取arr大小 int len = (*env)-\u0026amp;gt;GetArrayLength(env, arr); //在LogCat中打印出arr的大小 LOGI(\u0026#34;the length of array is %d\u0026#34;, len); //如果长度为0, 返回arr if(len == 0) return arr; //如果长度大于0, 那么获取数组中的每个元素 jint* p = (*env)-\u0026amp;gt;GetIntArrayElements(env, arr, 0); //打印出数组中每个元素的值 int i = 0; for(; i \u0026amp;lt; len; i ++) { LOGI(\u0026#34;arr[%d] = %d\u0026#34;, i, *(p + i)); } return arr; } \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java代码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` case R.id.intMethod:\nint[] array = {1, 2, 3, 4, 5};\ndataProvider.intMethod(array);\nbreak;\n**执行结果** : 上面的那种LogCat竟然启动失败, 只能将就着用这个了;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207144250609) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 7. 本程序源码 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **XML布局文件** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` \u0026amp;lt;LinearLayout xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34; xmlns:tools=\u0026#34;http://schemas.android.com/tools\u0026#34; android:orientation=\u0026#34;vertical\u0026#34; android:layout_width=\u0026#34;match_parent\u0026#34; android:layout_height=\u0026#34;match_parent\u0026#34; \u0026amp;gt; \u0026amp;lt;Button android:id=\u0026#34;@+id/add\u0026#34; android:layout_width=\u0026#34;wrap_content\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:text=\u0026#34;调用 add 本地 方法\u0026#34; android:onClick=\u0026#34;onClick\u0026#34;/\u0026amp;gt; \u0026amp;lt;Button android:id=\u0026#34;@+id/sayHelloInc\u0026#34; android:layout_width=\u0026#34;wrap_content\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:text=\u0026#34;调用 sayHelloInc 本地 方法\u0026#34; android:onClick=\u0026#34;onClick\u0026#34;/\u0026amp;gt; \u0026amp;lt;Button android:id=\u0026#34;@+id/intMethod\u0026#34; android:layout_width=\u0026#34;wrap_content\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:text=\u0026#34;调用 intMethod 本地 方法\u0026#34; android:onClick=\u0026#34;onClick\u0026#34;/\u0026amp;gt; \u0026amp;lt;/LinearLayout\u0026amp;gt; **Java源码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **MainActivity源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` package shuliang.han.ndkparameterpassing;\nimport android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Toast;\npublic class MainActivity extends Activity {\nstatic{ System.loadLibrary(\u0026quot;DataProvider\u0026quot;); } DataProvider dataProvider; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dataProvider = new DataProvider(); } public void onClick(View view) { int id = view.getId(); switch (id) { case R.id.add: int result = dataProvider.add(1, 2); Toast.makeText(getApplicationContext(), \u0026quot;the add result : \u0026quot; + result, Toast.LENGTH_LONG).show(); break; case R.id.sayHelloInc: Toast.makeText(getApplicationContext(), dataProvider.sayHelloInc(\u0026quot;Hello\u0026quot;), Toast.LENGTH_LONG).show(); break; case R.id.intMethod: int[] array = {1, 2, 3, 4, 5}; dataProvider.intMethod(array); break; default: break; } } }\n\u0026amp;#8212;**DataProvider源码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` package shuliang.han.ndkparameterpassing; public class DataProvider { //将Java中的两个int值 传给C语言, 进行相加后, 返回java语言 shuliang.han.ndkparameterpassing.DataProvider public native int add(int x, int y); //将Java字符串传递给C语言, C语言处理字符串之后, 将处理结果返回给java public native String sayHelloInc(String s); //将java中的int数组传递给C语言, C语言为每个元素加10, 返回给Java public native int[] intMethod(int[] nums); } **JNI相关源码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **Android.mk源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` LOCAL_PATH := (call my-dir)\ninclude(CLEAR_VARS)\nLOCAL_MODULE := DataProvider LOCAL_SRC_FILES := DataProvider.c #增加log函数对应的log库 LOCAL_LDLIBS += -llog\ninclude $(BUILD_SHARED_LIBRARY)\n\u0026amp;#8212;**DataProvider.c 主程序源码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` #include \u0026amp;lt;jni.h\u0026amp;gt; #include \u0026amp;lt;string.h\u0026amp;gt; #include \u0026amp;lt;android/log.h\u0026amp;gt; #define LOG_TAG \u0026#34;System.out\u0026#34; #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) // java中的jstring, 转化为c的一个字符数组 char* Jstring2CStr(JNIEnv* env, jstring jstr) { //声明了一个字符串变量 rtn char* rtn = NULL; //找到Java中的String的Class对象 jclass clsstring = (*env)-\u0026amp;gt;FindClass(env, \u0026#34;java/lang/String\u0026#34;); //创建一个Java中的字符串 \u0026#34;GB2312\u0026#34; jstring strencode = (*env)-\u0026amp;gt;NewStringUTF(env, \u0026#34;GB2312\u0026#34;); /* * 获取String中定义的方法 getBytes(), 该方法的参数是 String类型的, 返回值是 byte[]数组 * \u0026#34;(Ljava/lang/String;)[B\u0026#34; 方法前面解析 : * -- Ljava/lang/String; 表示参数是String字符串 * -- [B : 中括号表示这是一个数组, B代表byte类型, 返回值是一个byte数组 */ jmethodID mid = (*env)-\u0026amp;gt;GetMethodID(env, clsstring, \u0026#34;getBytes\u0026#34;, \u0026#34;(Ljava/lang/String;)[B\u0026#34;); //调用Java中的getBytes方法, 传入参数介绍 参数②表示调用该方法的对象, 参数③表示方法id , 参数④表示方法参数 jbyteArray barr = (jbyteArray)(*env)-\u0026amp;gt;CallObjectMethod(env, jstr, mid, strencode); // String .getByte(\u0026#34;GB2312\u0026#34;); //获取数组的长度 jsize alen = (*env)-\u0026amp;gt;GetArrayLength(env, barr); //获取数组中的所有的元素 , 存放在 jbyte*数组中 jbyte* ba = (*env)-\u0026amp;gt;GetByteArrayElements(env, barr, JNI_FALSE); //将Java数组中所有元素拷贝到C的char*数组中, 注意C语言数组结尾要加一个 \u0026#39;\\0\u0026#39; if (alen \u0026amp;gt; 0) { rtn = (char*) malloc(alen + 1); //new char[alen+1]; \u0026#34;\\0\u0026#34; memcpy(rtn, ba, alen); rtn[alen] = 0; } (*env)-\u0026amp;gt;ReleaseByteArrayElements(env, barr, ba, 0); //释放内存 return rtn; } //方法签名, Java环境 和 调用native方法的类 必不可少, 后面的参数就是native方法的参数 jint Java_shuliang_han_ndkparameterpassing_DataProvider_add(JNIEnv * env, jobject obj, jint x, jint y) { //Java中的int对应的是C语言中的long类型, 对应JNI中的jint类型, C语言中 LOGI(\u0026#34;JNI_log : x = %d , y = %d\u0026#34; , x , y); return x + y; } jstring Java_shuliang_han_ndkparameterpassing_DataProvider_sayHelloInc(JNIEnv *env, jobject obj, jstring str) { char *p = (char*)Jstring2CStr(env, str); //打印Java传递过来的数据 LOGI(\u0026#34;Java JNI string parameter is : %s\u0026#34;, p); char *append = \u0026#34;append\u0026#34;; //strcat(dest, source) 函数可以将source字符串 添加到dest字符串后面 return (*env)-\u0026amp;gt;NewStringUTF(env, strcat(p, append)); } jintArray Java_shuliang_han_ndkparameterpassing_DataProvider_intMethod(JNIEnv *env, jobject obj, jintArray arr) { //获取arr大小 int len = (*env)-\u0026amp;gt;GetArrayLength(env, arr); //在LogCat中打印出arr的大小 LOGI(\u0026#34;the length of array is %d\u0026#34;, len); //如果长度为0, 返回arr if(len == 0) return arr; //如果长度大于0, 那么获取数组中的每个元素 jint* p = (*env)-\u0026amp;gt;GetIntArrayElements(env, arr, 0); //打印出数组中每个元素的值 int i = 0; for(; i \u0026amp;lt; len; i ++) { LOGI(\u0026#34;arr[%d] = %d\u0026#34;, i, *(p + i)); } return arr; } \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ## 8. 上传代码到GitHub **创建新项目** : han1202012/NDKParameterPassing ; — SSH地址 : git@github.com:han1202012/NDKParameterPassing.git ; — HTTP地址 : https://github.com/han1202012/NDKParameterPassing.git ;\n\u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; # 五. C语言代码回调Java方法 \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **C语言回调Java方法场景** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **复用方法** : 使用Java对象, 复用Java中的方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **激活Java** : C程序后台运行, 该后台程序一直运行, 某个时间出发后需要启动Java服务, 激活Android中的某个界面, 例如使用Intent启动一个Activity; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 1. C代码回调Java方法的流程 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ### (1) 找到java对应的Class \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 创建一个char*数组, 然后使用jni.h中提供的FindClass方法获取jclass返回值; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` //DataProvider完整类名 shulaing.han.ndk_callback.DataProvider char* classname = \u0026quot;shulaing/han/ndk_callback/DataProvider\u0026quot;; jclass dpclazz = (*env)-\u0026amp;gt;FindClass(env, classname); ### (2) 找到要调用的方法的methodID \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 使用jni.h中提供的GetMethodID方法, 获取jmethodID, 传入参数 ①JNIEnv指针 ②Class对象 ③ 方法名 ④方法签名, 在这里方法名和方法签名确定一个方法, 方法签名就是方法的返回值 与 参数的唯一标示; ``` //参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method jmethodID methodID = (*env)-\u0026amp;gt;GetMethodID(env, dpclazz, \u0026#34;Add\u0026#34;, \u0026#34;(II)I\u0026#34;); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **找到静态方法** : 如果方法是静态的, 就使用GetStaticMethod方法获取 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; ``` jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig) { return functions-\u0026gt;GetStaticMethodID(this, clazz, name, sig); }\n\u0026lt;/div\u0026gt; ### (3) 在C语言中调用相应方法 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **普通方法** : CallTypeMethod , 其中的Type随着返回值类型的不同而改变; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **参数介绍** : ① JNIEnv指针 ②调用该native方法的对象 ③方法的methodID ④⑤\u0026amp;#8230; 后面是可变参数, 这些参数是 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...); jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list); jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...); jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list); jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...); jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list); jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...); jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list); jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...); jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list); jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...); jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list); jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...); jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list); jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__; jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__; jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__; jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__; jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list); void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); **静态方法** : CallStaticTypeMethod, 其中的Type随着返回值类型不同而改变;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 2. 一些基本代码编写 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java代码** : 定义**一个callCcode本地方法**, 以及**三个Java方法**, 在jni中使用本地方法调用Java中的方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` package shulaing.han.ndk_callback;\npublic class DataProvider {\npublic native void callCcode(); //C调用java中空方法 shulaing.han.ndk_callback.DataProvider public void helloFromJava(){ System.out.println(\u0026quot;hello from java\u0026quot;); } //C调用java中的带两个int参数的方法 public int Add(int x,int y){ return x + y; } //C调用java中参数为string的方法 public void printString(String s){ System.out.println(s); } }\n**生成头文件** : 进入 bin/classed目录, 使用 **javah shulaing.han.ndk_callback.DataProvider** 命令, 可以在bin/classes下生成头文件;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207203856375) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **头文件内容** : 文件名 : shulaing_han_ndk_callback_DataProvider.h ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` /* DO NOT EDIT THIS FILE - it is machine generated */ #include \u0026amp;lt;jni.h\u0026amp;gt; /* Header for class shulaing_han_ndk_callback_DataProvider */ #ifndef _Included_shulaing_han_ndk_callback_DataProvider #define _Included_shulaing_han_ndk_callback_DataProvider #ifdef __cplusplus extern \u0026#34;C\u0026#34; { #endif /* * Class: shulaing_han_ndk_callback_DataProvider * Method: callCcode * Signature: ()V */ JNIEXPORT void JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif **编写Android.mk文件** : 注意将LogCat日志输出系统动态库加入;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` LOCAL_PATH := (call my-dir)\ninclude(CLEAR_VARS)\nLOCAL_MODULE := jni LOCAL_SRC_FILES := jni.c #增加log函数对应的log库 LOCAL_LDLIBS += -llog\ninclude $(BUILD_SHARED_LIBRARY)\n**编写jni的C代码** : 注意加入LogCat相关导入的包;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` #include \u0026#34;shulaing_han_ndk_callback_DataProvider.h\u0026#34; #include \u0026amp;lt;string.h\u0026amp;gt; #include \u0026amp;lt;android/log.h\u0026amp;gt; #define LOG_TAG \u0026#34;System.out\u0026#34; #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) \u0026lt;/div\u0026gt; ## 3. C中回调Java的void返回值方法 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **参数介绍** : 第二个参数是类的路径字符串, 如 \u0026amp;#8220;/shuliang/han/ndk_callback/DataProvider\u0026amp;#8221; ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **参数介绍** : 第二个参数是 Java类的Class对象, 第三个参数是方法名, 第四个参数是Java方法的签名; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **方法签名生成工具** : javap , 使用javap -s 命令即可生成方法签名; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207210214562) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **进入bin/classed目录下** : 执行 javap -s shulaing.han.ndk_callback.DataProvider 命令, 即可显示出每个方法的签名; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` $ javap -s shulaing.han.ndk_callback.DataProvider Compiled from \u0026ldquo;DataProvider.java\u0026rdquo; public class shulaing.han.ndk_callback.DataProvider extends java.lang.Object{ public shulaing.han.ndk_callback.DataProvider(); Signature: ()V public native void callCcode(); Signature: ()V public void helloFromJava(); Signature: ()V public int Add(int, int); Signature: (II)I public void printString(java.lang.String); Signature: (Ljava/lang/String;)V }\n**截图** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207210837125) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **方法签名介绍** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **返回值null, 参数null** : void helloFromJava() 方法的签名是 \u0026amp;#8220;()V\u0026amp;#8221;, 括号里什么都没有代表参数为null, V代表返回值是void; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **返回值int, 参数两个int** : int Add(int x,int y) 方法的签名是 \u0026amp;#8220;(II)I\u0026amp;#8221;, 括号中II表示两个int类型参数, 右边括号外的I代表返回值是int类型; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **返回值null, 参数String** : void printString(String s) 方法签名是 \u0026amp;#8220;(Ljava/lang/String;)V\u0026amp;#8221;, 括号中的Ljava/lang/String; 表示参数是String类型, V表示返回值是void; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **jni.h中定义的回调Java方法的相关函数** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...); jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list); jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...); jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list); jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...); jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list); jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...); jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list); jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...); jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list); jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...); jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list); jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...); jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list); jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__; jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__; jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__; jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__; jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list); void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; **C语言代码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` #include \u0026ldquo;shulaing_han_ndk_callback_DataProvider.h\u0026rdquo; #include \u0026lt;string.h\u0026gt; #include \u0026lt;android/log.h\u0026gt; #define LOG_TAG \u0026ldquo;System.out\u0026rdquo; #define LOGD(\u0026hellip;) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, VA_ARGS) #define LOGI(\u0026hellip;) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, VA_ARGS)\nJNIEXPORT void JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode (JNIEnv * env, jobject obj) { //调用DataProvider对象中的helloFromJava()方法 //获取到某个对象, 获取对象中的方法, 调用获取到的方法 LOGI(\u0026ldquo;in code\u0026rdquo;); //DataProvider完整类名 shulaing.han.ndk_callback.DataProvider char* classname = \u0026ldquo;shulaing/han/ndk_callback/DataProvider\u0026rdquo;;\njclass dpclazz = (*env)-\u0026amp;gt;FindClass(env, classname); if(dpclazz == 0) LOGI(\u0026quot;class not find !!!\u0026quot;); else LOGI(\u0026quot;class find !!!\u0026quot;); //参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method jmethodID methodID = (*env)-\u0026amp;gt;GetMethodID(env, dpclazz, \u0026quot;helloFromJava\u0026quot;, \u0026quot;()V\u0026quot;); if(methodID == 0) LOGI(\u0026quot;method not find !!!\u0026quot;); else LOGI(\u0026quot;method find !!!\u0026quot;); /* * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); * 参数介绍 : 后面的 ... 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列 */ LOGI(\u0026quot;before call method\u0026quot;); (*env)-\u0026amp;gt;CallVoidMethod(env, obj, methodID); LOGI(\u0026quot;after call method\u0026quot;); }\n**Java代码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212;**XML布局文件代码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` \u0026amp;lt;LinearLayout xmlns:android=\u0026#34;http://schemas.android.com/apk/res/android\u0026#34; xmlns:tools=\u0026#34;http://schemas.android.com/tools\u0026#34; android:layout_width=\u0026#34;match_parent\u0026#34; android:layout_height=\u0026#34;match_parent\u0026#34; android:orientation=\u0026#34;vertical\u0026#34; android:paddingBottom=\u0026#34;@dimen/activity_vertical_margin\u0026#34; android:paddingLeft=\u0026#34;@dimen/activity_horizontal_margin\u0026#34; android:paddingRight=\u0026#34;@dimen/activity_horizontal_margin\u0026#34; android:paddingTop=\u0026#34;@dimen/activity_vertical_margin\u0026#34; tools:context=\u0026#34;.MainActivity\u0026#34; \u0026amp;gt; \u0026amp;lt;Button android:id=\u0026#34;@+id/call_void_method\u0026#34; android:layout_width=\u0026#34;wrap_content\u0026#34; android:layout_height=\u0026#34;wrap_content\u0026#34; android:onClick=\u0026#34;onClick\u0026#34; android:text=\u0026#34;C语言回调Java中的空方法\u0026#34; /\u0026amp;gt; \u0026amp;lt;/LinearLayout\u0026amp;gt; \u0026amp;#8212;**MainActivity代码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` package shulaing.han.ndk_callback;\nimport android.app.Activity; import android.os.Bundle; import android.view.View;\npublic class MainActivity extends Activity {\nstatic{ System.loadLibrary(\u0026quot;jni\u0026quot;); } DataProvider dp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dp = new DataProvider(); } public void onClick(View view) { int id = view.getId(); switch (id) { case R.id.call_void_method: dp.callCcode(); break; default: break; } } }\n\u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; **执行结果** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140207215815265) . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 4. C代码回调Java中带String参数的方法 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **在DataProvider中添加两个native方法** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` public native void callCcode(); public native void callCcode1(); public native void callCcode2(); \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **进入bin/classes目录, 使用 javah -jni shulaing.han.ndk_callback.DataProvider 命令生成头文件** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` /* DO NOT EDIT THIS FILE - it is machine generated / #include \u0026lt;jni.h\u0026gt; / Header for class shulaing_han_ndk_callback_DataProvider */\n#ifndef _Included_shulaing_han_ndk_callback_DataProvider #define _Included_shulaing_han_ndk_callback_DataProvider #ifdef __cplusplus extern \u0026ldquo;C\u0026rdquo; { #endif /*\nClass: shulaing_han_ndk_callback_DataProvider Method: callCcode Signature: ()V */ JNIEXPORT void JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode (JNIEnv *, jobject); /*\nClass: shulaing_han_ndk_callback_DataProvider Method: callCcode1 Signature: ()V */ JNIEXPORT void JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode1 (JNIEnv *, jobject); /*\nClass: shulaing_han_ndk_callback_DataProvider Method: callCcode2 Signature: ()V */ JNIEXPORT void JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode2 (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif\n\u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **jni C语言代码** : 这里只需要修改两处, 方法名, 获取方法id中的参数, 调用方法中最后加上一个Java参数; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` JNIEXPORT void JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode1 (JNIEnv *env, jobject obj) { //调用DataProvider对象中的helloFromJava()方法 //获取到某个对象, 获取对象中的方法, 调用获取到的方法 LOGI(\u0026#34;in code\u0026#34;); //DataProvider完整类名 shulaing.han.ndk_callback.DataProvider char* classname = \u0026#34;shulaing/han/ndk_callback/DataProvider\u0026#34;; jclass dpclazz = (*env)-\u0026amp;gt;FindClass(env, classname); if(dpclazz == 0) LOGI(\u0026#34;class not find !!!\u0026#34;); else LOGI(\u0026#34;class find !!!\u0026#34;); //参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method jmethodID methodID = (*env)-\u0026amp;gt;GetMethodID(env, dpclazz, \u0026#34;printString\u0026#34;, \u0026#34;(Ljava/lang/String;)V\u0026#34;); if(methodID == 0) LOGI(\u0026#34;method not find !!!\u0026#34;); else LOGI(\u0026#34;method find !!!\u0026#34;); /* * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); * 参数介绍 : 后面的 ... 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列 */ LOGI(\u0026#34;before call method\u0026#34;); (*env)-\u0026amp;gt;CallVoidMethod(env, obj, methodID, (*env)-\u0026amp;gt;NewStringUTF(env, \u0026#34;printString method callback success!!\u0026#34;)); LOGI(\u0026#34;after call method\u0026#34;); } **执行后的结果** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140208144212640) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 5. C代码中回调带两个int类型的参数的方法 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **按照上面的流程, 不同之处就是jni中获取方法 和 方法id , 调用方法的jni函数不同** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` JNIEXPORT void JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode2 (JNIEnv env, jobject obj) { //调用DataProvider对象中的helloFromJava()方法 //获取到某个对象, 获取对象中的方法, 调用获取到的方法 LOGI(\u0026ldquo;in code\u0026rdquo;); //DataProvider完整类名 shulaing.han.ndk_callback.DataProvider char classname = \u0026ldquo;shulaing/han/ndk_callback/DataProvider\u0026rdquo;;\njclass dpclazz = (*env)-\u0026amp;gt;FindClass(env, classname); if(dpclazz == 0) LOGI(\u0026quot;class not find !!!\u0026quot;); else LOGI(\u0026quot;class find !!!\u0026quot;); //参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method jmethodID methodID = (*env)-\u0026amp;gt;GetMethodID(env, dpclazz, \u0026quot;Add\u0026quot;, \u0026quot;(II)I\u0026quot;); if(methodID == 0) LOGI(\u0026quot;method not find !!!\u0026quot;); else LOGI(\u0026quot;method find !!!\u0026quot;); /* * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); * 参数介绍 : 后面的 ... 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列 */ LOGI(\u0026quot;before call method\u0026quot;); (*env)-\u0026amp;gt;CallIntMethod(env, obj, methodID, 3, 5); LOGI(\u0026quot;after call method\u0026quot;); }\n**Java代码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` case R.id.call_int_parameter_method: dp.callCcode2(); break; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **执行结果** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140208171145750) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . **作者** : **万境绝尘 ** **转载请注明出处** : [**http://blog.csdn.net/shulianghan/article/details/18964835**](http://blog.csdn.net/shulianghan/article/details/18964835) . \u0026lt;/div\u0026gt; ## 6. 完整源码 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Java源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **DataProvider源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` package shulaing.han.ndk_callback;\npublic class DataProvider {\npublic native void callCcode(); public native void callCcode1(); public native void callCcode2(); //C调用java中空方法 shulaing.han.ndk_callback.DataProvider public void helloFromJava(){ System.out.println(\u0026quot;hello from java\u0026quot;); } //C调用java中的带两个int参数的方法 public int Add(int x,int y){ System.out.println(\u0026quot;the add result is : \u0026quot; + (x + y)); return x + y; } //C调用java中参数为string的方法 public void printString(String s){ System.out.println(\u0026quot;in java code :\u0026quot; + s); } }\n\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **MainActivity源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` package shulaing.han.ndk_callback; import android.app.Activity; import android.os.Bundle; import android.view.View; public class MainActivity extends Activity { static{ System.loadLibrary(\u0026#34;jni\u0026#34;); } DataProvider dp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dp = new DataProvider(); } public void onClick(View view) { int id = view.getId(); switch (id) { case R.id.call_void_method: dp.callCcode(); break; case R.id.call_string_parameter_method: dp.callCcode1(); break; case R.id.call_int_parameter_method: dp.callCcode2(); break; default: break; } } } \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **XML布局文件源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` \u0026lt;LinearLayout xmlns:android=\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot; xmlns:tools=\u0026ldquo;http://schemas.android.com/tools\u0026quot; android:layout_width=\u0026ldquo;match_parent\u0026rdquo; android:layout_height=\u0026ldquo;match_parent\u0026rdquo; android:orientation=\u0026ldquo;vertical\u0026rdquo; android:paddingBottom=\u0026quot;@dimen/activity_vertical_margin\u0026rdquo; android:paddingLeft=\u0026quot;@dimen/activity_horizontal_margin\u0026rdquo; android:paddingRight=\u0026quot;@dimen/activity_horizontal_margin\u0026quot; android:paddingTop=\u0026quot;@dimen/activity_vertical_margin\u0026quot; tools:context=\u0026quot;.MainActivity\u0026quot; \u0026gt;\n\u0026amp;lt;Button android:id=\u0026quot;@+id/call_void_method\u0026quot; android:layout_width=\u0026quot;wrap_content\u0026quot; android:layout_height=\u0026quot;wrap_content\u0026quot; android:onClick=\u0026quot;onClick\u0026quot; android:text=\u0026quot;C语言回调Java中的空方法\u0026quot; /\u0026amp;gt; \u0026amp;lt;Button android:id=\u0026quot;@+id/call_string_parameter_method\u0026quot; android:layout_width=\u0026quot;wrap_content\u0026quot; android:layout_height=\u0026quot;wrap_content\u0026quot; android:onClick=\u0026quot;onClick\u0026quot; android:text=\u0026quot;C语言回调Java中的String参数方法\u0026quot; /\u0026amp;gt; \u0026amp;lt;Button android:id=\u0026quot;@+id/call_int_parameter_method\u0026quot; android:layout_width=\u0026quot;wrap_content\u0026quot; android:layout_height=\u0026quot;wrap_content\u0026quot; android:onClick=\u0026quot;onClick\u0026quot; android:text=\u0026quot;C语言回调Java中的int参数方法\u0026quot; /\u0026amp;gt; \u0026lt;/LinearLayout\u0026gt;\n\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **jni源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **头文件源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` /* DO NOT EDIT THIS FILE - it is machine generated */ #include \u0026amp;lt;jni.h\u0026amp;gt; /* Header for class shulaing_han_ndk_callback_DataProvider */ #ifndef _Included_shulaing_han_ndk_callback_DataProvider #define _Included_shulaing_han_ndk_callback_DataProvider #ifdef __cplusplus extern \u0026#34;C\u0026#34; { #endif /* * Class: shulaing_han_ndk_callback_DataProvider * Method: callCcode * Signature: ()V */ JNIEXPORT void JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode (JNIEnv *, jobject); /* * Class: shulaing_han_ndk_callback_DataProvider * Method: callCcode1 * Signature: ()V */ JNIEXPORT void JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode1 (JNIEnv *, jobject); /* * Class: shulaing_han_ndk_callback_DataProvider * Method: callCcode2 * Signature: ()V */ JNIEXPORT void JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode2 (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **Android.mk源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` LOCAL_PATH := (call my-dir)\ninclude(CLEAR_VARS)\nLOCAL_MODULE := jni LOCAL_SRC_FILES := jni.c #增加log函数对应的log库 LOCAL_LDLIBS += -llog\ninclude $(BUILD_SHARED_LIBRARY)\n\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **jni主程序源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` #include \u0026#34;shulaing_han_ndk_callback_DataProvider.h\u0026#34; #include \u0026#34;first.h\u0026#34; #include \u0026amp;lt;string.h\u0026amp;gt; #include \u0026amp;lt;android/log.h\u0026amp;gt; #define LOG_TAG \u0026#34;System.out\u0026#34; #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) JNIEXPORT void JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode (JNIEnv * env, jobject obj) { //调用DataProvider对象中的helloFromJava()方法 //获取到某个对象, 获取对象中的方法, 调用获取到的方法 LOGI(\u0026#34;in code\u0026#34;); //DataProvider完整类名 shulaing.han.ndk_callback.DataProvider char* classname = \u0026#34;shulaing/han/ndk_callback/DataProvider\u0026#34;; jclass dpclazz = (*env)-\u0026amp;gt;FindClass(env, classname); if(dpclazz == 0) LOGI(\u0026#34;class not find !!!\u0026#34;); else LOGI(\u0026#34;class find !!!\u0026#34;); //参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method jmethodID methodID = (*env)-\u0026amp;gt;GetMethodID(env, dpclazz, \u0026#34;helloFromJava\u0026#34;, \u0026#34;()V\u0026#34;); if(methodID == 0) LOGI(\u0026#34;method not find !!!\u0026#34;); else LOGI(\u0026#34;method find !!!\u0026#34;); /* * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); * 参数介绍 : 后面的 ... 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列 */ LOGI(\u0026#34;before call method\u0026#34;); (*env)-\u0026amp;gt;CallVoidMethod(env, obj, methodID); LOGI(\u0026#34;after call method\u0026#34;); } JNIEXPORT void JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode1 (JNIEnv *env, jobject obj) { //调用DataProvider对象中的helloFromJava()方法 //获取到某个对象, 获取对象中的方法, 调用获取到的方法 LOGI(\u0026#34;in code\u0026#34;); //DataProvider完整类名 shulaing.han.ndk_callback.DataProvider char* classname = \u0026#34;shulaing/han/ndk_callback/DataProvider\u0026#34;; jclass dpclazz = (*env)-\u0026amp;gt;FindClass(env, classname); if(dpclazz == 0) LOGI(\u0026#34;class not find !!!\u0026#34;); else LOGI(\u0026#34;class find !!!\u0026#34;); //参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method jmethodID methodID = (*env)-\u0026amp;gt;GetMethodID(env, dpclazz, \u0026#34;printString\u0026#34;, \u0026#34;(Ljava/lang/String;)V\u0026#34;); if(methodID == 0) LOGI(\u0026#34;method not find !!!\u0026#34;); else LOGI(\u0026#34;method find !!!\u0026#34;); /* * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); * 参数介绍 : 后面的 ... 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列 */ LOGI(\u0026#34;before call method\u0026#34;); (*env)-\u0026amp;gt;CallVoidMethod(env, obj, methodID, (*env)-\u0026amp;gt;NewStringUTF(env, \u0026#34;printString method callback success!!\u0026#34;)); LOGI(\u0026#34;after call method\u0026#34;); } /* * 实际开发的情况 * C代码工程师给我们 first.h first.c , 我们只需要将first.h引入, 然后就可以使用其中的方法了 */ JNIEXPORT void JNICALL Java_shulaing_han_ndk_1callback_DataProvider_callCcode2 (JNIEnv *env, jobject obj) { //调用DataProvider对象中的helloFromJava()方法 //获取到某个对象, 获取对象中的方法, 调用获取到的方法 LOGI(\u0026#34;in code\u0026#34;); //DataProvider完整类名 shulaing.han.ndk_callback.DataProvider char* classname = \u0026#34;shulaing/han/ndk_callback/DataProvider\u0026#34;; jclass dpclazz = (*env)-\u0026amp;gt;FindClass(env, classname); if(dpclazz == 0) LOGI(\u0026#34;class not find !!!\u0026#34;); else LOGI(\u0026#34;class find !!!\u0026#34;); //参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的method jmethodID methodID = (*env)-\u0026amp;gt;GetMethodID(env, dpclazz, \u0026#34;Add\u0026#34;, \u0026#34;(II)I\u0026#34;); if(methodID == 0) LOGI(\u0026#34;method not find !!!\u0026#34;); else LOGI(\u0026#34;method find !!!\u0026#34;); /* * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); * 参数介绍 : 后面的 ... 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列 */ LOGI(\u0026#34;before call method\u0026#34;); (*env)-\u0026amp;gt;CallIntMethod(env, obj, methodID, 3, 5); LOGI(\u0026#34;after call method\u0026#34;); } \u0026lt;/div\u0026gt; ## 7. 将程序上传到GitHub中 \u0026lt;div\u0026gt; GitHub地址 : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; SSH : git@github.com:han1202012/NDK_Callback.git \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; HTTP : https://github.com/han1202012/NDK_Callback.git \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; # 六. 实际开发中的环境 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **这里举一个简单的小例子** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **在实际开发中, C工程师会给我们c文件如下** : first.h first.c, 一个C主程序, 一个头文件, 我们只需要将这个头文件引入到jni中的C代码中即可, 在我们自定义生成的签名函数中调用 first.h中的方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **first.h源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` #ifndef FIRST_H #define FIRST_H\nextern int first(int x, int y);\n#endif /* FIRST_H */\n**first.c源码** :\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` #include \u0026#34;first.h\u0026#34; int first(int x, int y) { return x + y; } ** 在签名函数中, 直接调用 first()方法即可**;\n\u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; # 七 分析Log日志系统框架的JNI代码 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ** ** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **在这里分析日志输出函数** : Log.i(TAG, \u0026amp;#8220;log\u0026amp;#8221;), 分析该**日志系统的JNI层源码结构**; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **这里使用下载的Android2.3.3源码进行分析** : 在 [http://blog.csdn.net/shulianghan/article/details/17350401](http://blog.csdn.net/shulianghan/article/details/17350401) 中介绍了如何使用repo 和 git 下载Android源码 和 kernel 源码; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **LogJNI调用层次** : android.util.Log.java 中的接口 是**通过JNI调用 本地库** 并最终**调用内核驱动程序 Logger** 将日志信息写到 **内核空间中**. \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **分析的源码文件** : \u0026amp;#8220;\\\u0026amp;#8221; 代表Android源代码的本目录; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **Java代码** : \\frameworks\\base\\core\\java\\android\\util\\Log.java \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI层实现代码** : \\frameworks\\base\\core\\jni\\android_util_Log.cpp \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **下面的是Android自定义的JNI规范相关的源码** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI规范头文件** : \\dalvik\\libnativehelper\\include\\nativehelper\\jni.h \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI帮助文件** : ① \\dalvik\\libnativehelper\\include\\nativehelper\\JNIHelp.h ② \\dalvik\\libnativehelper\\JNIHelp.c \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI运行时文件** : \\frameworks\\base\\core\\jni\\AndroidRuntime.cpp \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **这里将上面几个文件上传到CSDN资源中, 便于查看** : [http://download.csdn.net/detail/han1202012/6905507](http://download.csdn.net/detail/han1202012/6905507) ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 1. 分析Log.java源码 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Log.java分析** : 在Log.java文件中,**定义了 isLoggable 和 println_native 两个Native方法**, 在Java方法中, 只需要事先**声明native方法, 不用实现方法体**, 可以直接调用; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Log.java在Android源码中的位置** : \\frameworks\\base\\core\\java\\android\\util\\Log.java \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Log.java内容** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` package android.util;\nimport com.android.internal.os.RuntimeInit;\nimport java.io.PrintWriter; import java.io.StringWriter; public final class Log {\n... ... //打印日志 public static int d(String tag, String msg) { return println_native(LOG_ID_MAIN, DEBUG, tag, msg); } //打印日志和异常 public static int d(String tag, String msg, Throwable tr) { return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '\\n' + getStackTraceString(tr)); } //打印日志 public static int i(String tag, String msg) { return println_native(LOG_ID_MAIN, INFO, tag, msg); } ... ... //声明native方法 public static native boolean isLoggable(String tag, int level); ... ... /** @hide */ public static final int LOG_ID_MAIN = 0; /** @hide */ public static final int LOG_ID_RADIO = 1; /** @hide */ public static final int LOG_ID_EVENTS = 2; /** @hide */ public static final int LOG_ID_SYSTEM = 3; //声明native方法 /** @hide */ public static native int println_native(int bufID, int priority, String tag, String msg); }\n\u0026lt;/div\u0026gt; ## 2. 分析Log系统JNI层源码 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNI层方法**: JNI层方法根据一定规则**与Java层声明的Native方法进行映射**, 然后可以通过JNIEnv指针提供的**JNI函数对Java层进行操作**; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Log系统的JNI层文件是** : android_util_Log.cpp, 该文件路径 :\\frameworks\\base\\core\\jni\\android_util_Log.cpp 代码如下 : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` #define LOG_NAMESPACE \u0026#34;log.tag.\u0026#34; #define LOG_TAG \u0026#34;Log_println\u0026#34; #include \u0026amp;lt;assert.h\u0026amp;gt; #include \u0026amp;lt;cutils/properties.h\u0026amp;gt; #include \u0026amp;lt;utils/Log.h\u0026amp;gt; #include \u0026amp;lt;utils/String8.h\u0026amp;gt; #include \u0026#34;jni.h\u0026#34; #include \u0026#34;utils/misc.h\u0026#34; #include \u0026#34;android_runtime/AndroidRuntime.h\u0026#34; ... ... namespace android { struct levels_t { jint verbose; jint debug; jint info; jint warn; jint error; jint assert; }; static levels_t levels; static int toLevel(const char* value) { switch (value[0]) { case \u0026#39;V\u0026#39;: return levels.verbose; case \u0026#39;D\u0026#39;: return levels.debug; case \u0026#39;I\u0026#39;: return levels.info; case \u0026#39;W\u0026#39;: return levels.warn; case \u0026#39;E\u0026#39;: return levels.error; case \u0026#39;A\u0026#39;: return levels.assert; case \u0026#39;S\u0026#39;: return -1; // SUPPRESS } return levels.info; } /* 实现Java层声明的 isLoggable 方法, 注意方法名不符合标准JNI规范 标准的JNI规范方法名应该是 Java_包名_类名_方法名 其中传入了JNIEnv 和 jobject 参数, JNIEnv参数是Java运行环境, 可以与JVM进行交互 jobject参数是包含Native方法的Java类对象 该方法中可以通过JNIEnv调用本地库进行函数处理, 最后返回给Java层函数 */ static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level) { #ifndef HAVE_ANDROID_OS return false; #else /* HAVE_ANDROID_OS */ int len; char key[PROPERTY_KEY_MAX]; char buf[PROPERTY_VALUE_MAX]; if (tag == NULL) { return false; } jboolean result = false; //调用了JNI函数 const char* chars = env-\u0026amp;gt;GetStringUTFChars(tag, NULL); if ((strlen(chars)+sizeof(LOG_NAMESPACE)) \u0026amp;gt; PROPERTY_KEY_MAX) { jclass clazz = env-\u0026amp;gt;FindClass(\u0026#34;java/lang/IllegalArgumentException\u0026#34;); char buf2[200]; snprintf(buf2, sizeof(buf2), \u0026#34;Log tag \\\u0026#34;%s\\\u0026#34; exceeds limit of %d characters\\n\u0026#34;, chars, PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE)); // release the chars! env-\u0026amp;gt;ReleaseStringUTFChars(tag, chars); env-\u0026amp;gt;ThrowNew(clazz, buf2); return false; } else { strncpy(key, LOG_NAMESPACE, sizeof(LOG_NAMESPACE)-1); strcpy(key + sizeof(LOG_NAMESPACE) - 1, chars); } env-\u0026amp;gt;ReleaseStringUTFChars(tag, chars); len = property_get(key, buf, \u0026#34;\u0026#34;); int logLevel = toLevel(buf); return (logLevel \u0026amp;gt;= 0 \u0026amp;\u0026amp; level \u0026amp;gt;= logLevel) ? true : false; #endif /* HAVE_ANDROID_OS */ } /* * In class android.util.Log: * public static native int println_native(int buffer, int priority, String tag, String msg) */ static jint android_util_Log_println_native(JNIEnv* env, jobject clazz, jint bufID, jint priority, jstring tagObj, jstring msgObj) { const char* tag = NULL; const char* msg = NULL; if (msgObj == NULL) { jclass npeClazz; npeClazz = env-\u0026amp;gt;FindClass(\u0026#34;java/lang/NullPointerException\u0026#34;); assert(npeClazz != NULL); env-\u0026amp;gt;ThrowNew(npeClazz, \u0026#34;println needs a message\u0026#34;); return -1; } if (bufID \u0026amp;lt; 0 || bufID \u0026amp;gt;= LOG_ID_MAX) { jclass npeClazz; npeClazz = env-\u0026amp;gt;FindClass(\u0026#34;java/lang/NullPointerException\u0026#34;); assert(npeClazz != NULL); env-\u0026amp;gt;ThrowNew(npeClazz, \u0026#34;bad bufID\u0026#34;); return -1; } if (tagObj != NULL) tag = env-\u0026amp;gt;GetStringUTFChars(tagObj, NULL);\t//调用JNI函数 msg = env-\u0026amp;gt;GetStringUTFChars(msgObj, NULL); int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg); if (tag != NULL) env-\u0026amp;gt;ReleaseStringUTFChars(tagObj, tag);\t//调用JNI函数释放资源 env-\u0026amp;gt;ReleaseStringUTFChars(msgObj, msg);\t//调用JNI函数释放资源 return res; } /* * JNI registration. JNI方法注册 */ static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { \u0026#34;isLoggable\u0026#34;, \u0026#34;(Ljava/lang/String;I)Z\u0026#34;, (void*) android_util_Log_isLoggable }, { \u0026#34;println_native\u0026#34;, \u0026#34;(IILjava/lang/String;Ljava/lang/String;)I\u0026#34;, (void*) android_util_Log_println_native }, }; int register_android_util_Log(JNIEnv* env) { jclass clazz = env-\u0026amp;gt;FindClass(\u0026#34;android/util/Log\u0026#34;); if (clazz == NULL) { LOGE(\u0026#34;Can\u0026#39;t find android/util/Log\u0026#34;); return -1; } levels.verbose = env-\u0026amp;gt;GetStaticIntField(clazz, env-\u0026amp;gt;GetStaticFieldID(clazz, \u0026#34;VERBOSE\u0026#34;, \u0026#34;I\u0026#34;)); levels.debug = env-\u0026amp;gt;GetStaticIntField(clazz, env-\u0026amp;gt;GetStaticFieldID(clazz, \u0026#34;DEBUG\u0026#34;, \u0026#34;I\u0026#34;)); levels.info = env-\u0026amp;gt;GetStaticIntField(clazz, env-\u0026amp;gt;GetStaticFieldID(clazz, \u0026#34;INFO\u0026#34;, \u0026#34;I\u0026#34;)); levels.warn = env-\u0026amp;gt;GetStaticIntField(clazz, env-\u0026amp;gt;GetStaticFieldID(clazz, \u0026#34;WARN\u0026#34;, \u0026#34;I\u0026#34;)); levels.error = env-\u0026amp;gt;GetStaticIntField(clazz, env-\u0026amp;gt;GetStaticFieldID(clazz, \u0026#34;ERROR\u0026#34;, \u0026#34;I\u0026#34;)); levels.assert = env-\u0026amp;gt;GetStaticIntField(clazz, env-\u0026amp;gt;GetStaticFieldID(clazz, \u0026#34;ASSERT\u0026#34;, \u0026#34;I\u0026#34;)); return AndroidRuntime::registerNativeMethods(env, \u0026#34;android/util/Log\u0026#34;, gMethods, NELEM(gMethods)); } }; // namespace android ## 3. 声明JNI 与 Native 方法的映射关系 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **标准JNI规范** : 在标准的JNI规范中, Java中的Native方法 与 JNI层方法 是通过方法名的对应关系进行映射的, 我们通过 javah 工具生成JNI层头文件, 头文件中定义了规范的JNI层方法名, 这个方法名就与Java Native方法对应; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Android自定义规范** : 在 \\dalvik\\libnativehelper\\include\\nativehelper\\jni.h 中定义了这样的映射关系 : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` typedef struct { const char* name;\t//Java层Native函数方法名 const char* signature;\t//Java层Native函数的签名 void* fnPtr;\t//JNI层实现的方法 } JNINativeMethod;\n. \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **JNINativeMethod类型数据** : 在android_util_Log.cpp 中定义了一个该类型的数组 : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` /* * JNI registration. */ static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { \u0026#34;isLoggable\u0026#34;, \u0026#34;(Ljava/lang/String;I)Z\u0026#34;, (void*) android_util_Log_isLoggable }, { \u0026#34;println_native\u0026#34;, \u0026#34;(IILjava/lang/String;Ljava/lang/String;)I\u0026#34;, (void*) android_util_Log_println_native }, }; **JNINativeMethod结构体作用** : JNINativeMethod是一个结构体类型, 声明了Native方法 与 JNI方法 的映射关系;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **解析上面的数组中的元素** : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **Native方法** : \u0026amp;#8220;isLoggable\u0026amp;#8221; 是Java中声明的Native方法; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **方法签名** : \u0026amp;#8220;(Ljava/lang/String;I)Z\u0026amp;#8221; 表示该方法的签名, 参数是String类型 和 int类型, Z 表示 boolean类型; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI方法** : (void*) android_util_Log_isLoggable 表示JNI层实现的方法指针; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 4. 注册JNI方法到虚拟机中 \u0026lt;div\u0026gt; **映射关系体现到虚拟机中** : 在android_util_Log.cpp 中存在这样的方法 : \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` int register_android_util_Log(JNIEnv* env) { jclass clazz = env-\u0026gt;FindClass(\u0026ldquo;android/util/Log\u0026rdquo;);\nif (clazz == NULL) { LOGE(\u0026quot;Can't find android/util/Log\u0026quot;); return -1; } levels.verbose = env-\u0026amp;gt;GetStaticIntField(clazz, env-\u0026amp;gt;GetStaticFieldID(clazz, \u0026quot;VERBOSE\u0026quot;, \u0026quot;I\u0026quot;)); levels.debug = env-\u0026amp;gt;GetStaticIntField(clazz, env-\u0026amp;gt;GetStaticFieldID(clazz, \u0026quot;DEBUG\u0026quot;, \u0026quot;I\u0026quot;)); levels.info = env-\u0026amp;gt;GetStaticIntField(clazz, env-\u0026amp;gt;GetStaticFieldID(clazz, \u0026quot;INFO\u0026quot;, \u0026quot;I\u0026quot;)); levels.warn = env-\u0026amp;gt;GetStaticIntField(clazz, env-\u0026amp;gt;GetStaticFieldID(clazz, \u0026quot;WARN\u0026quot;, \u0026quot;I\u0026quot;)); levels.error = env-\u0026amp;gt;GetStaticIntField(clazz, env-\u0026amp;gt;GetStaticFieldID(clazz, \u0026quot;ERROR\u0026quot;, \u0026quot;I\u0026quot;)); levels.assert = env-\u0026amp;gt;GetStaticIntField(clazz, env-\u0026amp;gt;GetStaticFieldID(clazz, \u0026quot;ASSERT\u0026quot;, \u0026quot;I\u0026quot;)); return AndroidRuntime::registerNativeMethods(env, \u0026quot;android/util/Log\u0026quot;, gMethods, NELEM(gMethods)); }\n}; // namespace android\n**核心方法** : 该函数调用了 AndroidRuntime::registerNativeMethods(env, \u0026amp;#8220;android/util/Log\u0026amp;#8221;, gMethods, NELEM(gMethods)) 方法注册JNI方法;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **register_android_util_Log调用时机** : 该函数是在Android系统启动的时候, 通过AndroidRuntime.cpp中的register_jni_proocs方法执行, 执行该方法的时候会将 Native方法 与 JNI方法 的函数映射关系注册给 Dalvik 虚拟机; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## 5. 解析registerNativeMethod函数 \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **该函数定义在AndroidRuntime.cpp中** : 该文件的路径在 \\frameworks\\base\\core\\jni\\AndroidRuntime.cpp ; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` /* * Register native methods using JNI. */ /*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods) { return jniRegisterNativeMethods(env, className, gMethods, numMethods); } **registerNativeMethods 方法只是对 jniRegisterNativeMethods 方法的封装, 在JNIHelp.h中找到该方法的声明**:\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` /*\nRegister one or more native methods with a particular class. / int jniRegisterNativeMethods(C_JNIEnv env, const char* className, const JNINativeMethod* gMethods, int numMethods); \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; **在JNIHelp.c 中找到该方法的实现 **: 最终方法中调用了 JNIEnv 的RegisterNatives 函数, 将gMethods中存放的JNINativeMethod结构体(存放Native方法 与 JNI方法关联信息) 传递到java虚拟机;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` /* * Register native JNI-callable methods. * * \u0026#34;className\u0026#34; looks like \u0026#34;java/lang/String\u0026#34;. */ int jniRegisterNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods) { jclass clazz; LOGV(\u0026#34;Registering %s natives\\n\u0026#34;, className); clazz = (*env)-\u0026amp;gt;FindClass(env, className); if (clazz == NULL) { LOGE(\u0026#34;Native registration unable to find class \u0026#39;%s\u0026#39;\\n\u0026#34;, className); return -1; } int result = 0; if ((*env)-\u0026amp;gt;RegisterNatives(env, clazz, gMethods, numMethods) \u0026amp;lt; 0) { LOGE(\u0026#34;RegisterNatives failed for \u0026#39;%s\u0026#39;\\n\u0026#34;, className); result = -1; } (*env)-\u0026amp;gt;DeleteLocalRef(env, clazz); return result; } ## 6. JNI的规范 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **Android中JNI存在两种规范** : 一种是**标准的JNI规范**, 多在**应用层**使用; 另一种是**Android中自定义的规范**, 多使用在**应用框架**层; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **JNI标准规范**: 遵守JNI标准规函数命名方式, JNI中方法命名为 Java_包名_类名_方法名 , 可以使用javah生成签名头文件, 靠这种方式实现 Native方法 与 JNI方法之间的映射关系, 即应用直接与框架层进行交互, 这种规范常用与应用开发; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212; **函数注册规范** : 这是Android自定义的一种规范, 应用框架层采用该规范, 即应用框架层 与 框架层 进行交互, 底层源码开发多使用该规范; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; . **转载出处** : [**http://blog.csdn.net/shulianghan/article/details/18964835**](http://blog.csdn.net/shulianghan/article/details/18964835) . \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-%E5%BC%80%E5%8F%91-%E4%B9%8B-jni%E5%85%A5%E9%97%A8-ndk%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A/","summary":"\u003cp\u003e\u003cstrong\u003eNDK项目源码地址\u003c/strong\u003e :\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e转载出处\u003c/strong\u003e : \u003ca href=\"http://blog.csdn.net/shulianghan/article/details/18964835\"\u003e\u003cstrong\u003ehttp://blog.csdn.net/shulianghan/article/details/18964835\u003c/strong\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e开发环境介绍\u003c/strong\u003e :\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003eeclipse\u003c/strong\u003e : adt-bundle-windows-x86-20130917\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003esdk\u003c/strong\u003e : 版本 2.3.3\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003endk\u003c/strong\u003e : android-ndk-r9c-windows-x86.zip\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003ecygwin\u003c/strong\u003e : 所需组件 binutils , gcc , gcc-mingw , gdb , make;\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003ejavah\u003c/strong\u003e : jdk6.0自带工具\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003ejavap\u003c/strong\u003e : jdk6.0自带工具\u003c/p\u003e\n\u003cp\u003e**JNI 总结 : **\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eJava 调用 C 流程\u003c/strong\u003e :\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003ea. 定义 Native 方法\u003c/strong\u003e : 在 \u003cstrong\u003eshuliang.han.ndkparameterpassing.DataProvider.java\u003c/strong\u003e 类中定义 Native 方法 \u003cstrong\u003epublic native int add(int x, int y)\u003c/strong\u003e;\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003eb. 生成方法签名\u003c/strong\u003e : 进入 \u003cstrong\u003eAndroidProject/bin/classes\u003c/strong\u003e 目录, 使用 **javah **\u003cstrong\u003eshuliang.han.ndkparameterpassing.DataProvider\u003c/strong\u003e 命令, 便生成了头文件, 该头文件引用了 jni.h, 以及定义好了 对应的 Native 方法, 生成 \u003cstrong\u003eJNIEXPORT jint JNICALL Java_shuliang_han_ndkparameterpassing_DataProvider_add (JNIEnv *, jobject, jint, jint)\u003c/strong\u003e;\u003c/p\u003e","title":"Android 开发 之 JNI入门 – NDK从入门到精通"},{"content":"图片浏览器效果图 :\n源码下载地址 :\n— CSDN : http://download.csdn.net/detail/han1202012/6875083\n— GitHub : https://github.com/han1202012/AndroidPictureViewer.git\n.\n作者 :**万境绝尘 **\n转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/18964835\n.\n一. 图片浏览器显示界面ImageView介绍 1. ImageView的上下继承结构 下面是API中的结构:\n[java.lang.Object](http://developer.android.com/reference/java/lang/Object.html) ↳ \u0026lt;td class=\u0026quot;jd-inheritance-class-cell\u0026quot; colspan=\u0026quot;2\u0026quot;\u0026gt; [android.view.View](http://developer.android.com/reference/android/view/View.html) \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;jd-inheritance-space\u0026quot;\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;jd-inheritance-class-cell\u0026quot; colspan=\u0026quot;1\u0026quot;\u0026gt; android.widget.ImageView \u0026lt;/td\u0026gt; [![](http://developer.android.com/assets/images/triangle-closed.png)](http://developer.android.com/reference/android/widget/ImageView.html#)Known Direct Subclasses \u0026lt;div id=\u0026quot;subclasses-direct\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;subclasses-direct-list\u0026quot; class=\u0026quot;jd-inheritedlinks\u0026quot;\u0026gt; [ImageButton](http://developer.android.com/reference/android/widget/ImageButton.html), [QuickContactBadge](http://developer.android.com/reference/android/widget/QuickContactBadge.html) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; [![](http://developer.android.com/assets/images/triangle-closed.png)](http://developer.android.com/reference/android/widget/ImageView.html#)Known Indirect Subclasses \u0026lt;div id=\u0026quot;subclasses-indirect\u0026quot;\u0026gt; \u0026lt;div id=\u0026quot;subclasses-indirect-list\u0026quot; class=\u0026quot;jd-inheritedlinks\u0026quot;\u0026gt; [ZoomButton](http://developer.android.com/reference/android/widget/ZoomButton.html) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; 绘制成UML图 :\n通过上面的分析 : ImageView有两个子类 ImageButton 和 QuickContactBadge, ImageButton还有一个子类是 ZoomButton;\n2. XML文件属性 调整边界, 保持长宽比 :android:adjustViewBounds, setAdjustViewBounds(boolean), 是否调整自己的边界, 用来保持图片的长宽比例, 该属性与 android:maxHeight 和 android:maxWidth 属性一起使用才有效果, 单独使用没有效果;\n设置最大宽度, 高度 :android:maxWidth(android:maxHeight), setMaxWidth(int)[setMaxHeight(int)], 该属性需要与android:adjustViewBounds属性一起使用,单独使用无效果;\n— 设置图片固定大小, 同时保持长宽比 : a. 设置android:adjustViewBounds 为 true; b. 设置最大宽度, 高度; c. 设置android:layout_width 与 android:layout_height 值为 warp_content;\n裁剪保留空白 :android:cropToPadding, setCropToPadding(boolean), 是否裁剪, 用来保留ImageView的padding, 该属性与android:scrollY 属性一起使用的时候才有用, 单独使用没有效果; 即 在滚动的时候, 滚动到边界, 边界的padding空白是否显示;\n填充方式 :android:scaleType, setScaleType(ImageView.ScaleType), 设置图片缩放类型以适配ImageView大小, 即填充方式;\n可能的取值 : matrix, fitXY, fitStart, fitCenter, fitEnd, center, centerCrop, centerInside;\n— matrix : 方法中的常量值为 ImageView.ScaleType.MATRIX, 使用矩阵来进行绘图;\n— fitXY : 方法中的常量值为 ImageView.ScaleType.FIT_XY, 在x y 两个方向上缩放, 使图片完全填充整个ImageView 不按照长宽比例缩放;\n— fitStart : 方法中的常量值为 ImageView.ScaleType.FIT_START, 保持长宽比缩放, 直到该图片完全显示在ImageView中, 缩放完成之后该图片在左上角;\n— fitCenter : 方法中的常量值为 ImageView.ScaleType.FIT_CENTER, 保持长宽比缩放, 直到该图片完全显示在ImageView中, 缩放完成之后该图片位于中央;\n— fitEnd : 方法中的常量值为 ImageView.ScaleType.FIT_END, 保持长宽比缩放, 直到该图片完全显示在ImageView中, 缩放完成之后该图片位于右下角;\n— center : 方法中的常量值为 ImageView.ScaleType.CENTER, 将图片放在ImageView的中央, 不进行缩放;\n— centerCrop : 方法中的常量值为 ImageView.ScaleType.CENTER_CROP, 保持长宽比缩放, 使图片完全覆盖ImageView;\n— centerInside : 方法中的常量值为 ImageView.ScaleType.CENTER_INSIDE, 保持长宽比缩放, 是的ImageView完全显示图片;\n实例 :\nXML文件 :\n**[html]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_1\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_1\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/im\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#00FF00\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;300dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;300dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/pic\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;strong\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;android:scaleType\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;strong\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;=\u0026amp;#8221;matrix\u0026amp;#8221;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 修改其中的 android:scaleType属性值, 查看其中的差异 :\n原图 :\nandroid:scaleType 默认情况下 :\nandroid:scaleType = “matrix” : 由下图可以看出, ImageView中的图片宽度与原图一样, 该属性不进行任何缩放,直接将图片放在左上角;\nandroid:scaleType = “fixXY” : 长宽不按比例拉伸, 图片明显变形 :\nandroid:scaleType = “fitStart” , 图片按比例缩放, 宽先达到边界, 图片位于上边; 如果高先达到边界, 图片位于左边;\nandroid:scaleType = “fieCenter” ,长宽按照比例缩放, 宽度先达到边界, 上下有空白; 如果高度先达到边界, 那么左右有空白;\nandroid:scaleType = “fitEnd” , 长宽等比例缩放, 宽度先达到边界, 位于下边; 如果高度先达到边界, 位于右边;\nandroid:scaleType = “center” ,长宽不进行缩放, 图片的中心 与 ImageView 的中心重合;\nandroid:scaleType = “centerCrop” ,长宽等比例缩放, 使图片完全覆盖ImageView, 图片中心与ImageView中心重合, 使图片最短的边能覆盖ImageView边界;\nandroid:scaleType = “centerInside” ,长宽等比例缩放, 如果图片宽高小于等于ImageView宽高, 那么就按照原图大小显示; 如果图片大于ImageView, 那么按照等比例缩小直到能完全显示为止;\n3. ImageView常用方法 设置图片 :\n— 设置位图 : setImageBitmap(bitmap), 为ImageView设置Bitmap位图显示;\n— 设置Drawable : setImageDrawable(drawable), 为ImageView设置Drawable显示;\n— 设置资源 : setImageResource(int), 为ImageView设置资源图片;\n— 设置路径 : setImageUri(uri), 为ImageView设置图片路径, 显示该路径的图片;\n二. 图片浏览器操作介绍 1. 实现左右循环切换图片 图片数组 : 将图片放在数组中, ImageView显示数组中的图片;\n当前显示图片下标索引 : 设置一个int值, 用来表示当前显示图片数组中的图片, 这个值不是int下标, 这个值设置很大设置成Integer.MAXVALUE / 2, 该值与图片数组的长度进行取模运算结果就是当前显示的图片数组下标值;\n翻页操作 : 上一页操作就将当前显示索引自减1, 然后模上 图片数组大小; 下一页就将当前索引自增1, 然后模上 图片数组大小;\n代码示例 :\n**[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_2\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_2\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//设置一个很大的值, 保证前后翻页不会出现异常\u0026lt;/span\u0026gt; - currentImage = Integer.MAX_VALUE / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//为了保证图片能够循环, 这里模运算是关键, 显示图片的下标始终是长度的模\u0026lt;/span\u0026gt; - image_all.setImageResource(images[ ++currentImage % images.length ]); - image_all.setImageResource(images[ \u0026amp;#8211;currentImage % images.length ]); 2. 透明度改变 设置当前透明度 : 设置一个当前透明度值, 初始值为255, 255是不透明, 0为完全透明;\n透明度改变 : 当点击透明度增加按钮的时候, 透明度自增20, 如果结果透明度大于255, 那么改透明度强制设置为255; 当点击透明度见效按钮的时候, 透明度自减20, 当透明度小于0的时候, 透明度强制设置为0;\n代码示例 :\n**[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_3\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_3\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//透明度初始值\u0026lt;/span\u0026gt; - alpha = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;255\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//透明度增加\u0026lt;/span\u0026gt; - alpha += \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(alpha \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;255\u0026lt;/span\u0026gt;) - alpha = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;255\u0026lt;/span\u0026gt;; - image_all.setAlpha(alpha); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//透明度减小\u0026lt;/span\u0026gt; - alpha -= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(alpha \u0026lt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - alpha = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - image_all.setAlpha(alpha); 3. 图片的放大缩小 获取View组件宽高 : 在Activity普通方法中无法获取到view组件的准确值, 如果想要获取view组件的宽高, 可以在 onWindowFocusChanged()方法中获取;\n计算每次自增自减的单位值 : 当按下缩放按钮的时候, 就对ImageView的宽高值进行自增自减单位值操作;\n为ImageView设置宽高 : 即设置LayoutParams, 注意是LinearLayout.LayoutParams对象;\n代码示例 :\n获取宽高 :\n**[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_4\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_4\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onWindowFocusChanged(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; hasFocus) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onWindowFocusChanged(hasFocus); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取ImageView组件的宽高\u0026lt;/span\u0026gt; - imageWidth = image_all.getWidth(); - imageHeight = image_all.getHeight(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//计算每次自增自减的值\u0026lt;/span\u0026gt; - addWidth = imageWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;; - addHeight = imageHeight / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;; - } 缩放图片操作 :\n**[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_5\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_5\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.big: \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//放大图片\u0026lt;/span\u0026gt; - imageWidth += addWidth; - imageHeight += addHeight; - - image_all.setLayoutParams(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearLayout.LayoutParams(imageWidth, imageHeight)); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.small: \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//缩小图片\u0026lt;/span\u0026gt; - imageWidth -= addWidth; - imageHeight -= addHeight; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(imageWidth \u0026lt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; || imageHeight \u0026lt;=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){ - imageWidth += addWidth; - imageHeight += addHeight; - } - - image_all.setLayoutParams(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearLayout.LayoutParams(imageWidth, imageHeight)); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; 4. 旋转图片操作 设置Matrix对象 : 该对象用来存放图像的旋转角度;\n设置旋转角度 : matrix.setRotate(), 即可设置旋转角度;\n创建Bitmap : 创建一个位图, 注意将设置了旋转角度的 matrix 设置上去;\n源码示例 :\n**[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_6\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_6\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - matrix = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Matrix(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//向左旋转进行的操作\u0026lt;/span\u0026gt; - anglel += \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;45\u0026lt;/span\u0026gt;; - matrix.setRotate(anglel); - Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(images[currentImage % images.length])).getBitmap(); - bitmap = Bitmap.createBitmap(bitmap, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, bitmap.getWidth(),bitmap.getHeight(), matrix, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - image_all.setImageBitmap(bitmap); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//向右旋转进行的操作\u0026lt;/span\u0026gt; - anglel -= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;45\u0026lt;/span\u0026gt;; - matrix.setRotate(anglel); - Bitmap bitmap1 = ((BitmapDrawable) getResources().getDrawable(images[currentImage % images.length])).getBitmap(); - bitmap1 = Bitmap.createBitmap(bitmap1, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, bitmap1.getWidth(),bitmap1.getHeight(), matrix, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - image_all.setImageBitmap(bitmap1); .\n作者 :**万境绝尘 **\n转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/18964835\n.\n三. 图片浏览器源码 XML布局文件 :\n**[html]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_7\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_7\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bg_im\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:padding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/alpha_plus\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_weight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;透明度+\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bg_bt\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/alpha_minus\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_weight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;透明度-\u0026amp;#8220;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bg_bt\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/prev_page\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_weight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;上一张\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bg_bt\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/next_page\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_weight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;下一张\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bg_bt\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:padding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;5dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/big\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_weight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;放大\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bg_bt\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/small\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_weight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;缩小\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bg_bt\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/turn_left\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_weight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;左转\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bg_bt\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/turn_right\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_weight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;右转\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bg_bt\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:onClick\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;onClick\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/image_all\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:scaleType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;fitCenter\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/mary1\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; Drawable资源 :\n整个界面的背景 : 渐变的颜色\n**[html]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_8\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_8\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;gradient\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:startColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#A9F5A9\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:centerColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#2EFE2E\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:endColor\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;#A9F5A9\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:type\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;linear\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;shape\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 按钮的背景 : 两个9patch图片, 按下的时候按钮背景会改变\n**[html]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_9\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_9\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:state_pressed\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bt_focus\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:state_pressed\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bt_normal\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 主Activity核心代码 :\n**[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_10\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_10\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; shuliang.han.imageview_test; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Matrix; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.drawable.BitmapDrawable; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] images; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//图片资源id数组\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; currentImage; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//当前显示图片\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; alpha; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//透明度\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Matrix matrix; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; anglel; \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//角度\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; imageWidth; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; imageHeight; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; addWidth; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; addHeight; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageView image_all; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - init(); - - } - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//初始化成员变量\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; init() { - images = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[]{R.drawable.mary1, R.drawable.mary2}; - currentImage = Integer.MAX_VALUE / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; - alpha = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;255\u0026lt;/span\u0026gt;; - - matrix = \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Matrix(); - - image_all = (ImageView) findViewById(R.id.image_all); - image_all.setImageResource(images[currentImage % images.length]); - } - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View view) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id = view.getId(); - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (id) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.alpha_plus: \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//增大透明度\u0026lt;/span\u0026gt; - alpha += \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(alpha \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;255\u0026lt;/span\u0026gt;) - alpha = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;255\u0026lt;/span\u0026gt;; - image_all.setAlpha(alpha); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.alpha_minus: \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//减小透明度\u0026lt;/span\u0026gt; - alpha -= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(alpha \u0026lt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) - alpha = \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; - image_all.setAlpha(alpha); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.next_page: \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//显示下一张图片\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//为了保证图片能够循环, 这里模运算是关键, 显示图片的下标始终是长度的模\u0026lt;/span\u0026gt; - image_all.setImageResource(images[ ++currentImage % images.length ]); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.prev_page: \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//显示上一张图片\u0026lt;/span\u0026gt; - image_all.setImageResource(images[ \u0026amp;#8211;currentImage % images.length ]); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.big: \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//放大图片\u0026lt;/span\u0026gt; - imageWidth += addWidth; - imageHeight += addHeight; - - image_all.setLayoutParams(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearLayout.LayoutParams(imageWidth, imageHeight)); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.small: \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//缩小图片\u0026lt;/span\u0026gt; - imageWidth -= addWidth; - imageHeight -= addHeight; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(imageWidth \u0026lt;= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; || imageHeight \u0026lt;=\u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){ - imageWidth += addWidth; - imageHeight += addHeight; - } - - image_all.setLayoutParams(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearLayout.LayoutParams(imageWidth, imageHeight)); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.turn_left: \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//向左旋转\u0026lt;/span\u0026gt; - anglel += \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;45\u0026lt;/span\u0026gt;; - matrix.setRotate(anglel); - Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(images[currentImage % images.length])).getBitmap(); - bitmap = Bitmap.createBitmap(bitmap, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, bitmap.getWidth(),bitmap.getHeight(), matrix, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - image_all.setImageBitmap(bitmap); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.turn_right: \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//向右旋转\u0026lt;/span\u0026gt; - anglel -= \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;45\u0026lt;/span\u0026gt;; - matrix.setRotate(anglel); - Bitmap bitmap1 = ((BitmapDrawable) getResources().getDrawable(images[currentImage % images.length])).getBitmap(); - bitmap1 = Bitmap.createBitmap(bitmap1, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, bitmap1.getWidth(),bitmap1.getHeight(), matrix, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); - image_all.setImageBitmap(bitmap1); - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; - } - } - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onWindowFocusChanged(\u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; hasFocus) { - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onWindowFocusChanged(hasFocus); - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//获取ImageView组件的宽高\u0026lt;/span\u0026gt; - imageWidth = image_all.getWidth(); - imageHeight = image_all.getHeight(); - - \u0026lt;span class=\u0026quot;comment\u0026quot;\u0026gt;//计算每次自增自减的值\u0026lt;/span\u0026gt; - addWidth = imageWidth / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;; - addHeight = imageHeight / \u0026lt;span class=\u0026quot;number\u0026quot;\u0026gt;5\u0026lt;/span\u0026gt;; - } - } 四. ZoomButton 和 QuickContactBadge 示例效果图 :\n下载地址 :\nGitHub : https://github.com/han1202012/ZoomButton_QuickContactBadge.git\n1. ZoomButton ZoomButton按钮 : ZoomButton按钮提供放大 缩小两个按钮, 两个按钮;\nZoomControls按钮 : 该按钮会自动生成一组两个按钮, 两个按钮分别是放大和缩小;\n按钮点击切换背景 : 设置selector资源, 设置两个item, 一个item的状态为按下时, 显示一个图片, 另一个item的状态为普通情况下, 显示另一个图片;\nselector源码 :\n**[html]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_11\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_11\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:state_pressed\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/app3\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:state_pressed\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/app4\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; XML源码 :\n**[html]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_12\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_12\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageButton\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/app2\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ImageButton\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/bt_bg\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:padding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;10dp\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ZoomButton\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/zoom_1\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:drawable/btn_minus\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ZoomButton\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/zoom_2\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@android:drawable/btn_plus\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;ZoomControls\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/zoom_ctrl\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;center_horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; 2. QuickContactBadge 本质 : QuickContactBadge 也是图片, 可以通过android:src 指定图片;\n功能 : QuickContactBadge 可以关联手机通讯录中的联系人, 当点击图片的时候, 会弹出该联系人相关的界面;\n— 关联方法 :\n— 使用邮箱关联 :assignContactFromEmail(String address, boolean lazyLookup), 将图片关联到指定email联系人;\n— 使用号码关联 :assignContactFromPhone(String number, boolean lazyLookup), 将图片关联到指定电话联系人;\n— 使用Uri关联 : assignContactUri(Uri uri), 将图片关联到Uri对应的联系人;\nXML代码:\n**[html]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_13\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_13\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;QuickContactBadge\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@+id/badge\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;attribute\u0026quot;\u0026gt;android:src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/app5\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; - - \u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; Activity代码 :\n**[java]** [view plain](http://blog.csdn.net/shulianghan/article/details/18555131#)[copy](http://blog.csdn.net/shulianghan/article/details/18555131#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/172552)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/172552/fork) \u0026lt;div\u0026gt; \u0026lt;embed id=\u0026quot;ZeroClipboardMovie_14\u0026quot; src=\u0026quot;http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf\u0026quot; type=\u0026quot;application/x-shockwave-flash\u0026quot; width=\u0026quot;18\u0026quot; height=\u0026quot;18\u0026quot; align=\u0026quot;middle\u0026quot; name=\u0026quot;ZeroClipboardMovie_14\u0026quot;\u0026gt; \u0026lt;/embed\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; shuliang.han.zoombutton_quickcontactbadge; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.QuickContactBadge; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; shuliang.han.zoombutton_quickcontactbadge.R; - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; QuickContactBadgeActivity \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { - - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; QuickContactBadge badge; - - \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { - \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); - setContentView(R.layout.quick_contact_badge); - - badge = (QuickContactBadge) findViewById(R.id.badge); - badge.assignContactFromPhone(\u0026lt;span class=\u0026quot;string\u0026quot;\u0026gt;\u0026amp;#8220;120\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); - - } - - } .\n转自：http://blog.csdn.net/shulianghan/article/details/18555131\n","permalink":"https://blog.zdltech.com/posts/androidui%E8%AE%BE%E8%AE%A1-%E4%B9%8B-%E5%9B%BE%E7%89%87%E6%B5%8F%E8%A7%88%E5%99%A8/","summary":"\u003cp\u003e\u003cstrong\u003e图片浏览器效果图\u003c/strong\u003e :\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e源码下载地址\u003c/strong\u003e :\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003eCSDN\u003c/strong\u003e : \u003ca href=\"http://download.csdn.net/detail/han1202012/6875083\"\u003ehttp://download.csdn.net/detail/han1202012/6875083\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e— \u003cstrong\u003eGitHub\u003c/strong\u003e : https://github.com/han1202012/AndroidPictureViewer.git\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140122202629625\"\u003e\u003c/p\u003e\n\u003cp\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e作者\u003c/strong\u003e :**万境绝尘 **\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e转载请注明出处\u003c/strong\u003e : \u003ca href=\"http://blog.csdn.net/shulianghan/article/details/18964835\"\u003e\u003cstrong\u003ehttp://blog.csdn.net/shulianghan/article/details/18964835\u003c/strong\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e.\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 id=\"一-图片浏览器显示界面imageview介绍\"\u003e\u003ca name=\"t0\"\u003e\u003c/a\u003e一. 图片浏览器显示界面ImageView介绍\u003c/h1\u003e\n\u003ch2 id=\"1-imageview的上下继承结构\"\u003e\u003ca name=\"t1\"\u003e\u003c/a\u003e1. ImageView的上下继承结构\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e下面是API中的结构\u003c/strong\u003e:\u003c/p\u003e\n\u003ctable class=\"jd-inheritance-table            \"\u003e\n  \u003ctr\u003e\n    \u003ctd class=\"jd-inheritance-class-cell\" colspan=\"3\"\u003e\n      [java.lang.Object](http://developer.android.com/reference/java/lang/Object.html)\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd class=\"jd-inheritance-space\"\u003e\n         ↳\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td class=\u0026quot;jd-inheritance-class-cell\u0026quot; colspan=\u0026quot;2\u0026quot;\u0026gt;\n  [android.view.View](http://developer.android.com/reference/android/view/View.html)\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd class=\"jd-inheritance-space\"\u003e\n    \u003c/td\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;td class=\u0026quot;jd-inheritance-space\u0026quot;\u0026gt;\n\u0026lt;/td\u0026gt;\n\n\u0026lt;td class=\u0026quot;jd-inheritance-class-cell\u0026quot; colspan=\u0026quot;1\u0026quot;\u0026gt;\n  android.widget.ImageView\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003ctable class=\"jd-sumtable jd-sumtable-subclasses            \"\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"12\"\u003e\n      [![](http://developer.android.com/assets/images/triangle-closed.png)](http://developer.android.com/reference/android/widget/ImageView.html#)Known Direct Subclasses\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div id=\u0026quot;subclasses-direct\u0026quot;\u0026gt;\n    \u0026lt;div id=\u0026quot;subclasses-direct-list\u0026quot; class=\u0026quot;jd-inheritedlinks\u0026quot;\u0026gt;\n      [ImageButton](http://developer.android.com/reference/android/widget/ImageButton.html), [QuickContactBadge](http://developer.android.com/reference/android/widget/QuickContactBadge.html)\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003ctable class=\"jd-sumtable jd-sumtable-subclasses            \"\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"12\"\u003e\n      [![](http://developer.android.com/assets/images/triangle-closed.png)](http://developer.android.com/reference/android/widget/ImageView.html#)Known Indirect Subclasses\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div id=\u0026quot;subclasses-indirect\u0026quot;\u0026gt;\n    \u0026lt;div id=\u0026quot;subclasses-indirect-list\u0026quot; class=\u0026quot;jd-inheritedlinks\u0026quot;\u0026gt;\n      [ZoomButton](http://developer.android.com/reference/android/widget/ZoomButton.html)\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/td\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003ctable class=\"jd-sumtable jd-sumtable-subclasses            \"\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"12\"\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003cp\u003e \u003c/p\u003e","title":"AndroidUI设计 之 图片浏览器"},{"content":"在Android应用中，图片随手势的拖拽、缩放、旋转在很多场景中都会用到，今天我们要做的就是在ImageView的基础上实现一个可以拖拽、缩放、转转的TouchView。\n一、实现原理\nOnTouch事件捕捉+Matrix矩阵变换\n二、核心方法\n拖拽：Matrix.postTranslate(DeltalX, DeltalY);\n缩放：Matrix.postScale(mScale, mScale, mPoint.x, mPoint.y);\n旋转：Matrix.postRotate(Angle, mPoint.x, mPoint.y);\n三、具体实现\npackage com.Android.TouchView; /* * Android多点触控技术练习 * @Author：Robin * @Date：2013年12月29日 * @边界处理暂时不知道怎么写啊 * 目前的问题有： * 手势识别不是很顺畅，经常出现该放缩时放缩不了的情况 * 由于没有边界判断，程序可能会出现崩溃 */ import android.annotation.SuppressLint; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; import android.graphics.PointF; import android.util.DisplayMetrics; import android.util.FloatMath; import android.view.MotionEvent; import android.widget.ImageView; @SuppressLint({ \u0026#34;ViewConstructor\u0026#34;, \u0026#34;FloatMath\u0026#34; }) public class MultiTouchView extends ImageView { //本地图像资源 private int mDrawable; //图像位图 private Bitmap mBitmap; //屏幕宽度 private int ScreenWidth; //屏幕高度 private int ScreenHeight; //原始图像矩阵 private Matrix mMatrix=new Matrix(); //过程图像矩阵 private Matrix mSavedMatrix=new Matrix(); //结果图像矩阵 private Matrix mResultMatrix=new Matrix(); //定义三种模式：None、Drag、Zoom public static final int Mode_None=0; public static final int Mode_Drag=1; public static final int Mode_Zoom=2; //当前操作模式 private int mMode=Mode_None; //当前坐标 private float mDownX,mDownY; //存储两点间的距离 private float mDistance=0f; //存储旋转角 @SuppressWarnings(\u0026#34;unused\u0026#34;) private float mAngle=0f; //存储中点 private PointF mPoint; //最大缩放比例 //private float MaxScale=3f; //最小缩放比例 //private float MinScale=0.5f; public MultiTouchView(Activity mActivity ,int Drawable) { super(mActivity); //设置当前图片资源 this.mDrawable=Drawable; //获取Bitmap mBitmap=BitmapFactory.decodeResource(getResources(), mDrawable); DisplayMetrics dm=new DisplayMetrics(); mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm); //获取屏幕宽度和高度 ScreenWidth=dm.widthPixels; ScreenHeight=dm.heightPixels; mMatrix=new Matrix(); } @SuppressLint(\u0026#34;DrawAllocation\u0026#34;) @Override protected void onDraw(Canvas canvas) { //消除图像锯齿 canvas.setDrawFilter(new PaintFlagsDrawFilter(0,Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG)); canvas.save(); //绘制图像 canvas.drawBitmap(mBitmap, mMatrix, null); canvas.restore(); } @Override public boolean onTouchEvent(MotionEvent Event) { switch(Event.getAction()) { //单点触控处理 case MotionEvent.ACTION_DOWN: //设置当前操作模式为Drag mMode=Mode_Drag; //获取当前坐标 mDownX=Event.getX(); mDownY=Event.getY(); mSavedMatrix.set(mMatrix); break; //多点触控处理 case MotionEvent.ACTION_POINTER_DOWN: mMode=Mode_Zoom; //获取两点间距离 mDistance=getDistance(Event); //获取旋转角 mAngle=getAngle(Event); //获取中点 mPoint=getMidPoint(Event); mSavedMatrix.set(mMatrix); break; case MotionEvent.ACTION_MOVE: //缩放处理 if(mMode==Mode_Zoom) { mResultMatrix.set(mSavedMatrix); //获取缩放比率 float mScale=getDistance(Event)/mDistance; //获取旋转角，这里可以不用 //float Angle=getAngle(Event)-mAngle; //以中点为中心，进行缩放 mResultMatrix.postScale(mScale, mScale, mPoint.x, mPoint.y); //以中点为中心，进行旋转，这里可以不用 //mResultMatrix.postRotate(Angle, mPoint.x, mPoint.y); mMatrix.set(mResultMatrix); invalidate(); }else if(mMode==Mode_Drag)//平移处理 { mResultMatrix.set(mSavedMatrix); //计算平移量 float DeltalX=Event.getX()-mDownX; float DeltalY=Event.getY()-mDownY; //平移 mResultMatrix.postTranslate(DeltalX, DeltalY); mMatrix.set(mResultMatrix); invalidate(); } break; case MotionEvent.ACTION_UP: //这里要不要处理呢,如果需要,怎么办 case MotionEvent.ACTION_POINTER_UP: mMode = Mode_None; break; } return true; } //返回两点间的距离 public float getDistance(MotionEvent Event) { //计算X的变化量 float DeltalX=Event.getX(0)-Event.getX(1); //计算Y的变化量 float DeltalY=Event.getY(0)-Event.getY(1); //计算距离 return FloatMath.sqrt(DeltalX*DeltalX+DeltalY*DeltalY); } //返回两点的中点 @SuppressLint(\u0026#34;FloatMath\u0026#34;) public PointF getMidPoint(MotionEvent Event) { float X=Event.getX(0)+Event.getX(1); float Y=Event.getY(0)+Event.getY(1); return new PointF(X/2,Y/2); } //获得旋转角 public float getAngle(MotionEvent Event) { double DeltalX=Event.getX(0)-Event.getX(1); double DeltalY=Event.getY(0)-Event.getY(1); return (float)Math.atan2(DeltalX, DeltalY); } //边界处理,暂时没找到比较好的方法 public boolean CheckBounary() { return false; } //存储当前图片 public Bitmap SaveImage() { Bitmap mBitmap = Bitmap.createBitmap(ScreenWidth, ScreenHeight,Config.ARGB_8888); Canvas mCanvas = new Canvas(mBitmap); mCanvas.drawBitmap(mBitmap, mMatrix, null); mCanvas.save(Canvas.ALL_SAVE_FLAG); mCanvas.restore(); return mBitmap; } } 四、 运行效果\n","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E5%8F%91%E5%AD%A6%E4%B9%A0%E4%B9%8Bimageview%E6%89%8B%E5%8A%BF%E6%8B%96%E6%8B%BD%E7%BC%A9%E6%94%BE%E6%97%8B%E8%BD%AC/","summary":"\u003cp\u003e在Android应用中，图片随手势的拖拽、缩放、旋转在很多场景中都会用到，今天我们要做的就是在ImageView的基础上实现一个可以拖拽、缩放、转转的TouchView。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e一、实现原理\u003c/p\u003e\n\u003cp\u003eOnTouch事件捕捉+Matrix矩阵变换\u003c/p\u003e\n\u003cp\u003e二、核心方法\u003c/p\u003e\n\u003cp\u003e拖拽：Matrix.postTranslate(DeltalX, DeltalY);\u003c/p\u003e\n\u003cp\u003e缩放：Matrix.postScale(mScale, mScale, mPoint.x, mPoint.y);\u003c/p\u003e\n\u003cp\u003e旋转：Matrix.postRotate(Angle, mPoint.x, mPoint.y);\u003c/p\u003e\n\u003cp\u003e三、具体实现\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epackage com\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eAndroid\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eTouchView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e/*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e Android多点触控技术练习\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @Author：Robin\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @Date：\u003cspan style=\"color:#bd93f9\"\u003e2013\u003c/span\u003e年\u003cspan style=\"color:#bd93f9\"\u003e12\u003c/span\u003e月\u003cspan style=\"color:#bd93f9\"\u003e29\u003c/span\u003e日\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e @边界处理暂时不知道怎么写啊\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 目前的问题有：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 手势识别不是很顺畅，经常出现该放缩时放缩不了的情况\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e 由于没有边界判断，程序可能会出现崩溃\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#ff79c6\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eannotation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eSuppressLint;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eapp\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eActivity;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBitmap;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBitmap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eConfig;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eBitmapFactory;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eCanvas;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMatrix;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ePaint;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ePaintFlagsDrawFilter;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egraphics\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ePointF;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eutil\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eDisplayMetrics;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eutil\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eFloatMath;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eview\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMotionEvent;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimport android\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidget\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eImageView;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@SuppressLint({ \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;ViewConstructor\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;FloatMath\u0026#34;\u003c/span\u003e })\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic \u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e MultiTouchView \u003cspan style=\"color:#ff79c6\"\u003eextends\u003c/span\u003e ImageView\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e本地图像资源\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private int mDrawable;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e图像位图\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tprivate Bitmap mBitmap;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e屏幕宽度\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tprivate int ScreenWidth;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e屏幕高度\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tprivate int ScreenHeight;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e原始图像矩阵\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tprivate Matrix mMatrix\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003enew Matrix();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e过程图像矩阵\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tprivate Matrix mSavedMatrix\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003enew Matrix();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e结果图像矩阵\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tprivate Matrix mResultMatrix\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003enew Matrix();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e定义三种模式：None、Drag、Zoom\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e final int Mode_None\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e final int Mode_Drag\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    public \u003cspan style=\"color:#ff79c6\"\u003estatic\u003c/span\u003e final int Mode_Zoom\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e当前操作模式\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private int mMode\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eMode_None;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e当前坐标\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private float mDownX,mDownY;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e存储两点间的距离\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private float mDistance\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003ef;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e存储旋转角\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @SuppressWarnings(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;unused\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tprivate float mAngle\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003ef;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e存储中点\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    private PointF mPoint;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e最大缩放比例\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003eprivate float MaxScale\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003ef;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e最小缩放比例\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003eprivate float MinScale\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e0.5\u003c/span\u003ef;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tpublic MultiTouchView(Activity mActivity ,int Drawable) \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tsuper(mActivity);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e设置当前图片资源\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tthis\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003emDrawable\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eDrawable;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e获取Bitmap\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tmBitmap\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eBitmapFactory\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edecodeResource(getResources(), mDrawable);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tDisplayMetrics dm\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003enew DisplayMetrics();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tmActivity\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetWindowManager()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetDefaultDisplay()\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetMetrics(dm);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e获取屏幕宽度和高度\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tScreenWidth\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003edm\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewidthPixels;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tScreenHeight\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003edm\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eheightPixels;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tmMatrix\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003enew Matrix();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@SuppressLint(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;DrawAllocation\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tprotected void onDraw(Canvas canvas) \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e消除图像锯齿\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tcanvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esetDrawFilter(new PaintFlagsDrawFilter(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e,Paint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eANTI_ALIAS_FLAG\u003cspan style=\"color:#ff79c6\"\u003e|\u003c/span\u003ePaint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eFILTER_BITMAP_FLAG));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tcanvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esave();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e绘制图像\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tcanvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawBitmap(mBitmap, mMatrix, null);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tcanvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003erestore();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@Override\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tpublic boolean onTouchEvent(MotionEvent Event)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003eswitch\u003c/span\u003e(Event\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetAction())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e单点触控处理\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t  \u003cspan style=\"color:#ff79c6\"\u003ecase\u003c/span\u003e MotionEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eACTION_DOWN:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e设置当前操作模式为Drag\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  mMode\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eMode_Drag;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e获取当前坐标\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  mDownX\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetX();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  mDownY\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetY();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              mSavedMatrix\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(mMatrix);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e多点触控处理\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t  \u003cspan style=\"color:#ff79c6\"\u003ecase\u003c/span\u003e MotionEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eACTION_POINTER_DOWN:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t     mMode\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eMode_Zoom;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t     \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e获取两点间距离\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t     mDistance\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003egetDistance(Event);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t     \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e获取旋转角\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t     mAngle\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003egetAngle(Event);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t     \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e获取中点\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t     mPoint\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003egetMidPoint(Event);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t     mSavedMatrix\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(mMatrix);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t  \u003cspan style=\"color:#ff79c6\"\u003ecase\u003c/span\u003e MotionEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eACTION_MOVE:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e缩放处理\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e(mMode\u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003eMode_Zoom)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  mResultMatrix\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(mSavedMatrix);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e获取缩放比率\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  float mScale\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003egetDistance(Event)\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003emDistance;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e获取旋转角，这里可以不用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003efloat Angle\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003egetAngle(Event)\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003emAngle;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e以中点为中心，进行缩放\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  mResultMatrix\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epostScale(mScale, mScale, mPoint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ex, mPoint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ey);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e以中点为中心，进行旋转，这里可以不用\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003emResultMatrix\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epostRotate(Angle, mPoint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ex, mPoint\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ey);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  mMatrix\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(mResultMatrix);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  invalidate();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  }\u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e(mMode\u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003eMode_Drag)\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e平移处理\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  mResultMatrix\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(mSavedMatrix);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e计算平移量\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  float DeltalX\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetX()\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003emDownX;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  float DeltalY\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetY()\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003emDownY;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e平移\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  mResultMatrix\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epostTranslate(DeltalX, DeltalY);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  mMatrix\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eset(mResultMatrix);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t  invalidate();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t  \u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t  \u003cspan style=\"color:#ff79c6\"\u003ecase\u003c/span\u003e MotionEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eACTION_UP:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t \u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e这里要不要处理呢,如果需要,怎么办\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t  \u003cspan style=\"color:#ff79c6\"\u003ecase\u003c/span\u003e MotionEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eACTION_POINTER_UP:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tmMode \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Mode_None;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e返回两点间的距离\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tpublic float getDistance(MotionEvent Event)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e计算X的变化量\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tfloat DeltalX\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetX(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetX(\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e计算Y的变化量\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tfloat DeltalY\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetY(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetY(\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e计算距离\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e FloatMath\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esqrt(DeltalX\u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003eDeltalX\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003eDeltalY\u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003eDeltalY);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e返回两点的中点\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@SuppressLint(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;FloatMath\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tpublic PointF getMidPoint(MotionEvent Event)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tfloat X\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetX(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetX(\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tfloat Y\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetY(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetY(\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e new PointF(X\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e,Y\u003cspan style=\"color:#ff79c6\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e获得旋转角\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tpublic float getAngle(MotionEvent Event)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tdouble DeltalX\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetX(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetX(\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tdouble DeltalY\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetY(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e)\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003eEvent\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetY(\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e (float)Math\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eatan2(DeltalX, DeltalY);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e边界处理,暂时没找到比较好的方法\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tpublic boolean CheckBounary()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003efalse\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003e//\u003c/span\u003e存储当前图片\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tpublic Bitmap SaveImage()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tBitmap mBitmap \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Bitmap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecreateBitmap(ScreenWidth, ScreenHeight,Config\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eARGB_8888);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tCanvas mCanvas \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e new Canvas(mBitmap); \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tmCanvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003edrawBitmap(mBitmap, mMatrix, null);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tmCanvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esave(Canvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eALL_SAVE_FLAG);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tmCanvas\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003erestore();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e mBitmap;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e \u003c/p\u003e","title":"Android开发学习之ImageView手势拖拽、缩放、旋转"},{"content":" 注： 这里说的图片的平移和缩放不是对ImageView整个view进行的，而是对ImageView里面的图片进行的（view本身没有什么变化），所以Android自带的动画效果不能满足需求。 **功能点**： 1、一开始可以像centerCrop一样显示图片（觉得scaleType为centerCrop时显示效果比较好，图片会铺满整个View，而且图片本身的分辨率不变） 2、对ImageView里的图片平移或放大 3、将这个平移或放大做成一个动画效果 **一、在ScaleType为matrix的情况下实现centerCrop的显示效果** 要充分利用Android的源码，看ImageView的源代码就可以简单很多，在configureBounds()方法中： ![Android中用Matrix实现ImageView里的图片平移和缩放动画 - Johnny - Lucky Johnnys blog](http://img1.ph.126.net/0bRpjujvQhurl7HNuYa99g==/4826169950781049609.png) 不过为了之后的平移，要保证图片的宽度比View的宽度大 \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; setImage \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Drawable\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; drawable \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;==\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; drawable \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; drawable\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;getIntrinsicWidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; drawable\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;getIntrinsicHeight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mWidth\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mHeight\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;1.0f\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dx \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dy \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dheight\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dx \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026amp;#8211;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;0.5f\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;0.5f\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dy \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026amp;#8211;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;0.5f\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;0.5f\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;2.0f\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dx \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026amp;#8211;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dy \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026amp;#8211;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;0.5f\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;0.5f\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setScale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;postTranslate \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dx\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dy \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mImage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setImageMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mImage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setImageDrawable \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; drawable \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;com\u0026quot;\u0026gt;// vwidth和vheight使用确定的值，因为如果在应用初始化时view.getWidth()可能为0\u0026lt;/span\u0026gt; **二、利用Matrix实现平移和放大** 平移和放大都是在当前图片的基础上，先用mImage.getImageMatrix()得到当前的matrix，再用Matrix的postTranslate或postScale方法就可以了。 需要注意的是： 如果用Matrix matrix = mImage.getImageMatrix (); //matrix只是得到一个对象的引用 应该用Matrix matrix = new Matrix ( mImage.getImageMatrix () );//这样才是得到一个克隆对象 **三、用ValueAnimator实现动画效果** 1、平移 dx为负是向左平移，为正是向右平移 因为图片的宽度设置为至少是view的2倍，所以向左和向右平移的最大距离都是vwidth / 2。 \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;MyTransXAnimatorListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;AnimatorUpdateListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mPrimaryMatrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;MyTransXAnimatorListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mPrimaryMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; onAnimationUpdate \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;ValueAnimator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animation \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dx \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Integer\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animation\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;getAnimatedValue \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mPrimaryMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;postTranslate \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dx\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mImage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setImageMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; setTranslateAnimation \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;ValueAnimator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;ValueAnimator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;ofInt \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026amp;#8211;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;60\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;addUpdateListener \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;MyTransXAnimatorListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mImage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;getImageMatrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setDuration \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setInterpolator \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;DecelerateInterpolator\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setStartDelay \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;start \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; 2、放大 放大要设置中心点为ImageView的中心 \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;MyScaleAnimatorListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;AnimatorUpdateListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mPrimaryMatrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;MyScaleAnimatorListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mPrimaryMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; onAnimationUpdate \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;ValueAnimator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animation \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Float\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animation\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;getAnimatedValue \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mPrimaryMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;postScale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mWidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mHeight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mImage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setImageMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; setScaleAnimation \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;ValueAnimator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;ValueAnimator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;ofFloat \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;1.0f\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;1.2f\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;addUpdateListener \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;MyScaleAnimatorListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mImage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;getImageMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setDuration \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setInterpolator \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;DecelerateInterpolator\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setStartDelay \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;start \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; 转自：http://xie2010.blog.163.com/blog/static/2113173652014221240951/ ","permalink":"https://blog.zdltech.com/posts/android%E4%B8%AD%E7%94%A8matrix%E5%AE%9E%E7%8E%B0imageview%E9%87%8C%E7%9A%84%E5%9B%BE%E7%89%87%E5%B9%B3%E7%A7%BB%E5%92%8C%E7%BC%A9%E6%94%BE%E5%8A%A8%E7%94%BB/","summary":"\u003cdiv\u003e\n  注： 这里说的图片的平移和缩放不是对ImageView整个view进行的，而是对ImageView里面的图片进行的（view本身没有什么变化），所以Android自带的动画效果不能满足需求。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  **功能点**：\n\u003c/div\u003e\n\u003cdiv\u003e\n  1、一开始可以像centerCrop一样显示图片（觉得scaleType为centerCrop时显示效果比较好，图片会铺满整个View，而且图片本身的分辨率不变）\n\u003c/div\u003e\n\u003cdiv\u003e\n  2、对ImageView里的图片平移或放大\n\u003c/div\u003e\n\u003cdiv\u003e\n  3、将这个平移或放大做成一个动画效果\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  **一、在ScaleType为matrix的情况下实现centerCrop的显示效果**\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  要充分利用Android的源码，看ImageView的源代码就可以简单很多，在configureBounds()方法中：\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv\u003e\n    ![Android中用Matrix实现ImageView里的图片平移和缩放动画 - Johnny - Lucky Johnnys blog](http://img1.ph.126.net/0bRpjujvQhurl7HNuYa99g==/4826169950781049609.png)\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e不过为了之后的平移，要保证图片的宽度比View的宽度大\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; setImage \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Drawable\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; drawable \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;==\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; drawable \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; drawable\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;getIntrinsicWidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; drawable\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;getIntrinsicHeight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mWidth\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mHeight\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;1.0f\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dx \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dy \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dheight\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dx \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026amp;#8211;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;0.5f\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;0.5f\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dy \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026amp;#8211;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;0.5f\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;0.5f\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;2.0f\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dx \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026amp;#8211;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dwidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dy \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; vheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026amp;#8211;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dheight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;*\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;0.5f\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;+\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;0.5f\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setScale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;postTranslate \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dx\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dy \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mImage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setImageMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mImage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setImageDrawable \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; drawable \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;com\u0026quot;\u0026gt;// vwidth和vheight使用确定的值，因为如果在应用初始化时view.getWidth()可能为0\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  **二、利用Matrix实现平移和放大**\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  平移和放大都是在当前图片的基础上，先用mImage.getImageMatrix()得到当前的matrix，再用Matrix的postTranslate或postScale方法就可以了。\n\u003c/div\u003e\n\u003cdiv\u003e\n  需要注意的是：\n\u003c/div\u003e\n\u003cdiv\u003e\n  如果用Matrix matrix  = mImage.getImageMatrix ();  //matrix只是得到一个对象的引用\n\u003c/div\u003e\n\u003cdiv\u003e\n  应该用Matrix matrix = new Matrix ( mImage.getImageMatrix () );//这样才是得到一个克隆对象\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  **三、用ValueAnimator实现动画效果**\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  1、平移\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  dx为负是向左平移，为正是向右平移\n\u003c/div\u003e\n\u003cdiv\u003e\n  因为图片的宽度设置为至少是view的2倍，所以向左和向右平移的最大距离都是vwidth / 2。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;MyTransXAnimatorListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;AnimatorUpdateListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mPrimaryMatrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;MyTransXAnimatorListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mPrimaryMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; onAnimationUpdate \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;ValueAnimator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animation \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dx \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Integer\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animation\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;getAnimatedValue \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mPrimaryMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;postTranslate \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; dx\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mImage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setImageMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; setTranslateAnimation \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;ValueAnimator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;ValueAnimator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;ofInt \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;\u0026amp;#8211;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;60\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;addUpdateListener \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;MyTransXAnimatorListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mImage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;getImageMatrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setDuration \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setInterpolator \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;DecelerateInterpolator\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setStartDelay \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;start \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  2、放大\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  放大要设置中心点为ImageView的中心\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;MyScaleAnimatorListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;AnimatorUpdateListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mPrimaryMatrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;MyScaleAnimatorListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mPrimaryMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; onAnimationUpdate \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;ValueAnimator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animation \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Float\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animation\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;getAnimatedValue \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;Matrix\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mPrimaryMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;postScale \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; scale\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mWidth \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mHeight \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;/\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mImage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setImageMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; matrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; setScaleAnimation \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;{\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;ValueAnimator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;ValueAnimator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;ofFloat \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;1.0f\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;,\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;1.2f\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;addUpdateListener \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;MyScaleAnimatorListener\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; mImage\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;getImageMatrix \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setDuration \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setInterpolator \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;kwd\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;typ\u0026quot;\u0026gt;DecelerateInterpolator\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;()\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;setStartDelay \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;lit\u0026quot;\u0026gt;500\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;);\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt; animator\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pln\u0026quot;\u0026gt;start \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;();\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span class=\u0026quot;pun\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  转自：http://xie2010.blog.163.com/blog/static/2113173652014221240951/\n\u003c/div\u003e","title":"Android中用Matrix实现ImageView里的图片平移和缩放动画"},{"content":"最近做一个项目类似于QQ空间，做到照片浏览的功能，对于QQ空间中点击图片放大至全屏，感觉效果很赞，于是也做了个类似的效果。如下。\n我不知道QQ那个是怎么做的，我的思路如下：\n首先，从图片缩略界面跳转到图片详情页面，应该是从一个Activity跳转到另外一个Activity，应该图片详情页面也有很多操作，用View或者Dialog不是很好。所以现在难点就是，如何使得前一个界面的ImageView在另外一个界面做缩放切割动画。\n一般缩略界面的ImageView的是如上图所示的正方形的，并且是CENTER_CROP缩放属性的。CENTER_CROP属性会导致ImageView中显示的Bitmap有被切割达到填充的效果。\n而详情页面的ImageView一般都是FIT_CENTER的缩放属性。所以要保证这个跳转动画的流畅，要做如下的变化：\n1、Bitmap的缩放，因为缩略图和详情图的缩放比例肯定不一样\n2、Bitmap位置的平移，因为缩略图的位置是不确定的，我们要使他平移到中间\n3、Bitmap的切割，因为CENTER_CROP是切割过得，而FIT_CENTER是没有切割的，那么两幅图显示的内容区域是不同的，所以也要显示区域的平滑变换。\n要完成上面的效果，如果单单是指对ImageView做一个动画变换，我觉得是完成不了这个要求的。所以自己重写了ImageView来完成上述的变换。\n直接贴上主要的ImageView\n**[java]** [view plain](http://blog.csdn.net/lonelyroamer/article/details/25497737#)[copy](http://blog.csdn.net/lonelyroamer/article/details/25497737#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/338428)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/338428/fork) package com.roamer.ui.view; import android.animation.Animator; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.drawable.BitmapDrawable; import android.util.AttributeSet; import android.util.Log; import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.ImageView; /** * 2d平滑变化的显示图片的ImageView * 仅限于用于:从一个ScaleType==CENTER_CROP的ImageView，切换到另一个ScaleType= * FIT_CENTER的ImageView，或者反之 (当然，得使用同样的图片最好) * * @author Dean Tao * */ public class SmoothImageView extends ImageView { private static final int STATE_NORMAL = ; private static final int STATE_TRANSFORM_IN = 1; private static final int STATE_TRANSFORM_OUT = 2; private int mOriginalWidth; private int mOriginalHeight; private int mOriginalLocationX; private int mOriginalLocationY; private int mState = STATE_NORMAL; private Matrix mSmoothMatrix; private Bitmap mBitmap; private boolean mTransformStart = false; private Transfrom mTransfrom; private final int mBgColor = 0xFF000000; private int mBgAlpha = ; private Paint mPaint; public SmoothImageView(Context context) { super(context); init(); } public SmoothImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public SmoothImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { mSmoothMatrix = new Matrix(); mPaint=new Paint(); mPaint.setColor(mBgColor); mPaint.setStyle(Style.FILL); // setBackgroundColor(mBgColor); } public void setOriginalInfo(int width, int height, int locationX, int locationY) { mOriginalWidth = width; mOriginalHeight = height; mOriginalLocationX = locationX; mOriginalLocationY = locationY; // 因为是屏幕坐标，所以要转换为该视图内的坐标，因为我所用的该视图是MATCH_PARENT，所以不用定位该视图的位置,如果不是的话，还需要定位视图的位置，然后计算mOriginalLocationX和mOriginalLocationY } /** * 获取状态栏高度 * * @return */ public static int getStatusBarHeight(Context context) { Class\u003c?\u003e c = null; Object obj = null; java.lang.reflect.Field field = null; int x = ; int statusBarHeight = ; try { c = Class.forName(“com.android.internal.R$dimen”); obj = c.newInstance(); field = c.getField(“status_bar_height”); x = Integer.parseInt(field.get(obj).toString()); statusBarHeight = context.getResources().getDimensionPixelSize(x); return statusBarHeight; } catch (Exception e) { e.printStackTrace(); } return statusBarHeight; } /** * 用于开始进入的方法。 调用此方前，需已经调用过setOriginalInfo */ public void transformIn() { mState = STATE_TRANSFORM_IN; mTransformStart = true; invalidate(); } /** * 用于开始退出的方法。 调用此方前，需已经调用过setOriginalInfo */ public void transformOut() { mState = STATE_TRANSFORM_OUT; mTransformStart = true; invalidate(); } private class Transfrom { float startScale;// 图片开始的缩放值 float endScale;// 图片结束的缩放值 float scale;// 属性ValueAnimator计算出来的值 LocationSizeF startRect;// 开始的区域 LocationSizeF endRect;// 结束的区域 LocationSizeF rect;// 属性ValueAnimator计算出来的值 void initStartIn() { scale = startScale; try { rect = (LocationSizeF) startRect.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } void initStartOut() { scale = endScale; try { rect = (LocationSizeF) endRect.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } } /** * 初始化进入的变量信息 */ private void initTransform() { if (getDrawable() == null) { return; } if (mBitmap == null || mBitmap.isRecycled()) { mBitmap = ((BitmapDrawable) getDrawable()).getBitmap(); } //防止mTransfrom重复的做同样的初始化 if (mTransfrom != null) { return; } if (getWidth() == || getHeight() == ) { return; } mTransfrom = new Transfrom(); /** 下面为缩放的计算 */ /* 计算初始的缩放值，初始值因为是CENTR_CROP效果，所以要保证图片的宽和高至少1个能匹配原始的宽和高，另1个大于 */ float xSScale = mOriginalWidth / ((float) mBitmap.getWidth()); float ySScale = mOriginalHeight / ((float) mBitmap.getHeight()); float startScale = xSScale \u0026gt; ySScale ? xSScale : ySScale; mTransfrom.startScale = startScale; /* 计算结束时候的缩放值，结束值因为要达到FIT_CENTER效果，所以要保证图片的宽和高至少1个能匹配原始的宽和高，另1个小于 */ float xEScale = getWidth() / ((float) mBitmap.getWidth()); float yEScale = getHeight() / ((float) mBitmap.getHeight()); float endScale = xEScale \u0026lt; yEScale ? xEScale : yEScale; mTransfrom.endScale = endScale; /** * 下面计算Canvas Clip的范围，也就是图片的显示的范围，因为图片是慢慢变大，并且是等比例的，所以这个效果还需要裁减图片显示的区域 * ，而显示区域的变化范围是在原始CENTER_CROP效果的范围区域 * ，到最终的FIT_CENTER的范围之间的，区域我用LocationSizeF更好计算 * ，他就包括左上顶点坐标，和宽高，最后转为Canvas裁减的Rect. */ /* 开始区域 */ mTransfrom.startRect = new LocationSizeF(); mTransfrom.startRect.left = mOriginalLocationX; mTransfrom.startRect.top = mOriginalLocationY; mTransfrom.startRect.width = mOriginalWidth; mTransfrom.startRect.height = mOriginalHeight; /* 结束区域 */ mTransfrom.endRect = new LocationSizeF(); float bitmapEndWidth = mBitmap.getWidth() * mTransfrom.endScale;// 图片最终的宽度 float bitmapEndHeight = mBitmap.getHeight() * mTransfrom.endScale;// 图片最终的宽度 mTransfrom.endRect.width = bitmapEndWidth; mTransfrom.endRect.height = bitmapEndHeight; mTransfrom.rect = new LocationSizeF(); } private class LocationSizeF implements Cloneable{ float left; float top; float width; float height; @Override public String toString() { return “[left:”+left+” top:”+top+” width:”+width+” height:”+height+“]”; } @Override public Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } } /* 下面实现了CENTER_CROP的功能 的Matrix，在优化的过程中，已经不用了 */ private void getCenterCropMatrix() { if (getDrawable() == null) { return; } if (mBitmap == null || mBitmap.isRecycled()) { mBitmap = ((BitmapDrawable) getDrawable()).getBitmap(); } /* 下面实现了CENTER_CROP的功能 */ float xScale = mOriginalWidth / ((float) mBitmap.getWidth()); float yScale = mOriginalHeight / ((float) mBitmap.getHeight()); float scale = xScale \u0026gt; yScale ? xScale : yScale; mSmoothMatrix.reset(); mSmoothMatrix.setScale(scale, scale); } private void getBmpMatrix() { if (getDrawable() == null) { return; } if (mTransfrom == null) { return; } if (mBitmap == null || mBitmap.isRecycled()) { mBitmap = ((BitmapDrawable) getDrawable()).getBitmap(); } /* 下面实现了CENTER_CROP的功能 */ mSmoothMatrix.setScale(mTransfrom.scale, mTransfrom.scale); } @Override protected void onDraw(Canvas canvas) { if (getDrawable() == null) { return; // couldn’t resolve the URI } if (mState == STATE_TRANSFORM_IN || mState == STATE_TRANSFORM_OUT) { if (mTransformStart) { initTransform(); } if (mTransfrom == null) { super.onDraw(canvas); return; } if (mTransformStart) { if (mState == STATE_TRANSFORM_IN) { mTransfrom.initStartIn(); } else { mTransfrom.initStartOut(); } } if(mTransformStart){ Log.d(“Dean”, “mTransfrom.startScale:”+mTransfrom.startScale); Log.d(“Dean”, “mTransfrom.startScale:”+mTransfrom.endScale); Log.d(“Dean”, “mTransfrom.scale:”+mTransfrom.scale); Log.d(“Dean”, “mTransfrom.startRect:”+mTransfrom.startRect.toString()); Log.d(“Dean”, “mTransfrom.endRect:”+mTransfrom.endRect.toString()); Log.d(“Dean”, “mTransfrom.rect:”+mTransfrom.rect.toString()); } mPaint.setAlpha(mBgAlpha); canvas.drawPaint(mPaint); int saveCount = canvas.getSaveCount(); canvas.save(); // 先得到图片在此刻的图像Matrix矩阵 getBmpMatrix(); canvas.translate(mTransfrom.rect.left, mTransfrom.rect.top); canvas.clipRect(, , mTransfrom.rect.width, mTransfrom.rect.height); canvas.concat(mSmoothMatrix); getDrawable().draw(canvas); canvas.restoreToCount(saveCount); if (mTransformStart) { mTransformStart=false; startTransform(mState); } } else { //当Transform In变化完成后，把背景改为黑色，使得Activity不透明 mPaint.setAlpha(255); canvas.drawPaint(mPaint); super.onDraw(canvas); } } private void startTransform(final int state) { if (mTransfrom == null) { return; } ValueAnimator valueAnimator = new ValueAnimator(); valueAnimator.setDuration(300); valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); if (state == STATE_TRANSFORM_IN) { PropertyValuesHolder scaleHolder = PropertyValuesHolder.ofFloat(“scale”, mTransfrom.startScale, mTransfrom.endScale); PropertyValuesHolder leftHolder = PropertyValuesHolder.ofFloat(“left”, mTransfrom.startRect.left, mTransfrom.endRect.left); PropertyValuesHolder topHolder = PropertyValuesHolder.ofFloat(“top”, mTransfrom.startRect.top, mTransfrom.endRect.top); PropertyValuesHolder widthHolder = PropertyValuesHolder.ofFloat(“width”, mTransfrom.startRect.width, mTransfrom.endRect.width); PropertyValuesHolder heightHolder = PropertyValuesHolder.ofFloat(“height”, mTransfrom.startRect.height, mTransfrom.endRect.height); PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofInt(“alpha”, , 255); valueAnimator.setValues(scaleHolder, leftHolder, topHolder, widthHolder, heightHolder, alphaHolder); } else { PropertyValuesHolder scaleHolder = PropertyValuesHolder.ofFloat(“scale”, mTransfrom.endScale, mTransfrom.startScale); PropertyValuesHolder leftHolder = PropertyValuesHolder.ofFloat(“left”, mTransfrom.endRect.left, mTransfrom.startRect.left); PropertyValuesHolder topHolder = PropertyValuesHolder.ofFloat(“top”, mTransfrom.endRect.top, mTransfrom.startRect.top); PropertyValuesHolder widthHolder = PropertyValuesHolder.ofFloat(“width”, mTransfrom.endRect.width, mTransfrom.startRect.width); PropertyValuesHolder heightHolder = PropertyValuesHolder.ofFloat(“height”, mTransfrom.endRect.height, mTransfrom.startRect.height); PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofInt(“alpha”, 255, ); valueAnimator.setValues(scaleHolder, leftHolder, topHolder, widthHolder, heightHolder, alphaHolder); } valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public synchronized void onAnimationUpdate(ValueAnimator animation) { mTransfrom.scale = (Float) animation.getAnimatedValue(“scale”); mTransfrom.rect.left = (Float) animation.getAnimatedValue(“left”); mTransfrom.rect.top = (Float) animation.getAnimatedValue(“top”); mTransfrom.rect.width = (Float) animation.getAnimatedValue(“width”); mTransfrom.rect.height = (Float) animation.getAnimatedValue(“height”); mBgAlpha = (Integer) animation.getAnimatedValue(“alpha”); invalidate(); ((Activity)getContext()).getWindow().getDecorView().invalidate(); } }); valueAnimator.addListener(new ValueAnimator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { /* * 如果是进入的话，当然是希望最后停留在center_crop的区域。但是如果是out的话，就不应该是center_crop的位置了 * ， 而应该是最后变化的位置，因为当out的时候结束时，不回复视图是Normal，要不然会有一个突然闪动回去的bug */ // TODO 这个可以根据实际需求来修改 if (state == STATE_TRANSFORM_IN) { mState = STATE_NORMAL; } if (mTransformListener != null) { mTransformListener.onTransformComplete(state); } } @Override public void onAnimationCancel(Animator animation) { } }); valueAnimator.start(); } public void setOnTransformListener(TransformListener listener) { mTransformListener = listener; } private TransformListener mTransformListener; public static interface TransformListener { /** * * @param mode * STATE_TRANSFORM_IN 1 ,STATE_TRANSFORM_OUT 2 */ void onTransformComplete(int mode);// mode 1 } } ** 使用的时候，从前一个Activity传递到详情Activity下面几个主要的信息：\n[java]** [view plain](http://blog.csdn.net/lonelyroamer/article/details/25497737#)[copy](http://blog.csdn.net/lonelyroamer/article/details/25497737#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/338428)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/338428/fork) Intent intent = new Intent(MainActivity.this, SpaceImageDetailActivity.class); intent.putExtra(“images”, (ArrayList) datas);//非必须 intent.putExtra(“position”, position); int[] location = new int[2]; imageView.getLocationOnScreen(location); intent.putExtra(“locationX”, location[]);//必须 intent.putExtra(“locationY”, location[1]);//必须 intent.putExtra(“width”, imageView.getWidth());//必须 intent.putExtra(“height”, imageView.getHeight());//必须 startActivity(intent); overridePendingTransition(, ); 在详情Activity接受到这些参数，并对SmoothImageView初始化位置信息，然后就可以进行变化了。\n**[java]** [view plain](http://blog.csdn.net/lonelyroamer/article/details/25497737#)[copy](http://blog.csdn.net/lonelyroamer/article/details/25497737#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/338428)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/338428/fork) mDatas = (ArrayList) getIntent().getSerializableExtra(“images”); mPosition = getIntent().getIntExtra(“position”, ); mLocationX = getIntent().getIntExtra(“locationX”, ); mLocationY = getIntent().getIntExtra(“locationY”, ); mWidth = getIntent().getIntExtra(“width”, ); mHeight = getIntent().getIntExtra(“height”, ); imageView = new SmoothImageView(this); imageView.setOriginalInfo(mWidth, mHeight, mLocationX, mLocationY); imageView.transformIn(); imageView.setScaleType(ScaleType.FIT_CENTER); setContentView(imageView); ImageLoader.getInstance().displayImage(mDatas.get(mPosition), imageView); **\n上面的就已经完成了图片的缩放效果，但是还需要设置下Activity透明的风格，才能使得alpha效果体验出来，用户体验更好。\n对Activity设置如下风格，另外说明，在SmoothImageView中没有定位视图的位置，只是做了对状态栏的处理，所以要设置Activity 为NotitleBar，具体style如下：\n[java]** [view plain](http://blog.csdn.net/lonelyroamer/article/details/25497737#)[copy](http://blog.csdn.net/lonelyroamer/article/details/25497737#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/338428)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/338428/fork) \u0026lt;style name=“IMTheme.Transparent” \u0026gt; \u0026lt;item name=“android:windowBackground”\u0026gt;@android:color/transparent \u0026lt;item name=“android:windowIsTranslucent”\u0026gt;true \u0026lt;item name=“android:windowNoTitle”\u0026gt;true \u0026lt;item name=“android:windowContentOverlay”\u0026gt;@null lt;/style\u0026gt; Demo下载\n转自：http://blog.csdn.net/lonelyroamer/article/details/25497737\n","permalink":"https://blog.zdltech.com/posts/android%E6%B5%8F%E8%A7%88%E5%9B%BE%E7%89%87%E7%82%B9%E5%87%BB%E6%94%BE%E5%A4%A7%E8%87%B3%E5%85%A8%E5%B1%8F%E6%95%88%E6%9E%9C/","summary":"\u003cp\u003e最近做一个项目类似于QQ空间，做到照片浏览的功能，对于QQ空间中点击图片放大至全屏，感觉效果很赞，于是也做了个类似的效果。如下。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140510230150187\"\u003e\u003c/p\u003e\n\u003cp\u003e我不知道QQ那个是怎么做的，我的思路如下：\u003c/p\u003e\n\u003cp\u003e首先，从图片缩略界面跳转到图片详情页面，应该是从一个Activity跳转到另外一个Activity，应该图片详情页面也有很多操作，用View或者Dialog不是很好。所以现在难点就是，如何使得前一个界面的ImageView在另外一个界面做缩放切割动画。\u003c/p\u003e\n\u003cp\u003e一般缩略界面的ImageView的是如上图所示的正方形的，并且是CENTER_CROP缩放属性的。CENTER_CROP属性会导致ImageView中显示的Bitmap有被切割达到填充的效果。\u003c/p\u003e\n\u003cp\u003e而详情页面的ImageView一般都是FIT_CENTER的缩放属性。所以要保证这个跳转动画的流畅，要做如下的变化：\u003c/p\u003e\n\u003cp\u003e1、Bitmap的缩放，因为缩略图和详情图的缩放比例肯定不一样\u003c/p\u003e\n\u003cp\u003e2、Bitmap位置的平移，因为缩略图的位置是不确定的，我们要使他平移到中间\u003c/p\u003e\n\u003cp\u003e3、Bitmap的切割，因为CENTER_CROP是切割过得，而FIT_CENTER是没有切割的，那么两幅图显示的内容区域是不同的，所以也要显示区域的平滑变换。\u003c/p\u003e\n\u003cp\u003e要完成上面的效果，如果单单是指对ImageView做一个动画变换，我觉得是完成不了这个要求的。所以自己重写了ImageView来完成上述的变换。\u003c/p\u003e\n\u003cp\u003e直接贴上主要的ImageView\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\" style=\"color: #000000; font-size: 12px; font-family: Consolas, 'Courier New', Courier, mono, serif; background-color: #e7e5dc;\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver; font-size: 9px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color: #f8f8f8;\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/lonelyroamer/article/details/25497737#)[copy](http://blog.csdn.net/lonelyroamer/article/details/25497737#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/338428)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/338428/fork)\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan style=\"color: black; background-color: inherit;\"\u003e\u003cspan class=\"keyword\" style=\"color: #006699; background-color: inherit;\"\u003epackage\u003c/span\u003e\u003cspan style=\"background-color: inherit;\"\u003e com.roamer.ui.view;  \u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan style=\"color: black; background-color: inherit;\"\u003e  \u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan style=\"color: black; background-color: inherit;\"\u003e\u003cspan class=\"keyword\" style=\"color: #006699; background-color: inherit;\"\u003eimport\u003c/span\u003e\u003cspan style=\"background-color: inherit;\"\u003e android.animation.Animator;  \u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan style=\"color: black; background-color: inherit;\"\u003e\u003cspan class=\"keyword\" style=\"color: #006699; background-color: inherit;\"\u003eimport\u003c/span\u003e\u003cspan style=\"background-color: inherit;\"\u003e android.animation.PropertyValuesHolder;  \u003c/span\u003e\u003c/span\u003e\u003c/p\u003e","title":"Android浏览图片，点击放大至全屏效果"},{"content":"在经过两年的开发之本后，Google 公司终于发布了 Android Studio 1.0，喜欢折腾的童鞋们，抓紧折腾吧。。。。。\n一、下载Android Studio 1.0： 1）可以在谷歌Android官网下载Android Studio 1.0（链接）。下载不了的童鞋可以到百度网盘上下载（链接）。\n2）下载后，Android Studio 1.0\n二、安装Android Studio 1.0： \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;　\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;1）直接双击![](http://images.cnitblog.com/blog/695756/201412/100950433845238.png)进行安装。\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　2）直接一直下一步就可以。中间如果想修改安装目录的可以进行修改：\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　![](http://images.cnitblog.com/blog/695756/201412/100953418063713.png)　\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; # \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;三、解决Fetching android sdk component information加载过久问题\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　安装完成后，如果直接启动，Android Studio会去获取 android sdk 组件信息，这个过程相当慢，还经常加载失败，导致Android Studio启动不起开。解决办法就是不去获取android sdk 组件信息。方法如下：\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　1）进入刚安装的Android Studio目录下的bin目录。找到idea.properties文件，用文本编辑器打开。\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　2）在idea.properties文件末尾添加一行：\u0026lt;span style=\u0026quot;color: #ff0000;\u0026quot;\u0026gt;disable.android.first.run=true\u0026lt;/span\u0026gt;，然后保存文件。\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　3）关闭Android Studio后重新启动，便可进入界面。\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　![](http://images.cnitblog.com/blog/695756/201412/101004062754693.png)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; # \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;四、新建一个Android工程项目\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　1）启动Android Studio后的界面：\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　![](http://images.cnitblog.com/blog/695756/201412/101004436962892.png)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #ff0000;\u0026quot;\u0026gt;备注：这里需要配置下sdk，感谢博客园朋友们的提醒：\u0026lt;/span\u0026gt; a、点击进入configure： ![](http://images.cnitblog.com/blog/695756/201412/101957450712770.png) b、进入界面后，再点击project Defaults: ![](http://images.cnitblog.com/blog/695756/201412/101959196185054.png) c、进入界面后，再点击Project Structure: ![](http://images.cnitblog.com/blog/695756/201412/102002137759526.png) d、进入界面后，设置Android SDK和JDK的路径。 ![](http://images.cnitblog.com/blog/695756/201412/102003264781538.png) 2）点击start a new android studio project,创建一个Android项目（可以修改工程的工作空间） ![](http://images.cnitblog.com/blog/695756/201412/101009122288363.png) 3）直接下一步 ![](http://images.cnitblog.com/blog/695756/201412/101011291038680.png) 4）再下一步 ![](http://images.cnitblog.com/blog/695756/201412/101012503219925.png) 5）再下一步 ![](http://images.cnitblog.com/blog/695756/201412/101014228535095.png) 6）点击finish完成工程项目的创建。工程项目整体结构如下： ![](http://images.cnitblog.com/blog/695756/201412/101016289159573.png) \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;完，\u0026lt;/span\u0026gt; 转自：http://www.cnblogs.com/sonyi/p/4154797.html ","permalink":"https://blog.zdltech.com/posts/android-studio%E5%AE%89%E8%A3%85%E4%BB%A5%E5%8F%8Afetching-android-sdk-component-information%E8%B6%85%E6%97%B6%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/","summary":"\u003cp\u003e在经过两年的开发之本后，Google 公司终于发布了 Android Studio 1.0，喜欢折腾的童鞋们，抓紧折腾吧。。。。。\u003c/p\u003e\n\u003ch1 id=\"一下载android-studio-10\"\u003e\u003cspan style=\"color: #0000ff;\"\u003e一、下载Android Studio 1.0：\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003e　　1）可以在谷歌Android官网下载Android Studio 1.0\u003ca href=\"http://developer.android.com/sdk/index.html\"\u003e（链接）\u003c/a\u003e。下载不了的童鞋可以到百度网盘上下载\u003ca href=\"http://pan.baidu.com/s/1tpuB8\"\u003e（链接）\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e　　2）下载后，Android Studio 1.0\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/695756/201412/100950433845238.png\"\u003e\u003c/p\u003e\n\u003ch1 id=\"二安装android-studio-10\"\u003e\u003cspan style=\"color: #0000ff;\"\u003e二、安装Android Studio 1.0：\u003c/span\u003e\u003c/h1\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;　　\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;1）直接双击![](http://images.cnitblog.com/blog/695756/201412/100950433845238.png)进行安装。\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　　2）直接一直下一步就可以。中间如果想修改安装目录的可以进行修改：\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　　![](http://images.cnitblog.com/blog/695756/201412/100953418063713.png)　　\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n\n\n\n\n# \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;三、解决Fetching android sdk component information加载过久问题\u0026lt;/span\u0026gt;\n\n\n\n  \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　　安装完成后，如果直接启动，Android Studio会去获取 android sdk 组件信息，这个过程相当慢，还经常加载失败，导致Android Studio启动不起开。解决办法就是不去获取android sdk 组件信息。方法如下：\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n\n\n\n\n  \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　　1）进入刚安装的Android Studio目录下的bin目录。找到idea.properties文件，用文本编辑器打开。\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n\n\n\n\n  \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　　2）在idea.properties文件末尾添加一行：\u0026lt;span style=\u0026quot;color: #ff0000;\u0026quot;\u0026gt;disable.android.first.run=true\u0026lt;/span\u0026gt;，然后保存文件。\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n\n\n\n\n  \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　　3）关闭Android Studio后重新启动，便可进入界面。\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n\n\n\n\n  \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　　![](http://images.cnitblog.com/blog/695756/201412/101004062754693.png)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n\n\n# \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;四、新建一个Android工程项目\u0026lt;/span\u0026gt;\n\n\n\n  \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　　1）启动Android Studio后的界面：\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n\n\n\n\n  \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;　　![](http://images.cnitblog.com/blog/695756/201412/101004436962892.png)\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\n\n\n\n\n  \n\n    　　\u0026lt;span style=\u0026quot;color: #ff0000;\u0026quot;\u0026gt;备注：这里需要配置下sdk，感谢博客园朋友们的提醒：\u0026lt;/span\u0026gt;\n  \n\n  \n  \n\n    　　a、点击进入configure：\n  \n\n  \n  \n\n    　　![](http://images.cnitblog.com/blog/695756/201412/101957450712770.png)\n  \n\n  \n  \n\n    　　b、进入界面后，再点击project Defaults:\n  \n\n  \n  \n\n    　　![](http://images.cnitblog.com/blog/695756/201412/101959196185054.png)\n  \n\n  \n  \n\n    　　c、进入界面后，再点击Project Structure:\n  \n\n  \n  \n\n    　　![](http://images.cnitblog.com/blog/695756/201412/102002137759526.png)\n  \n\n  \n  \n\n    　　d、进入界面后，设置Android SDK和JDK的路径。\n  \n\n  \n  \n\n    　　![](http://images.cnitblog.com/blog/695756/201412/102003264781538.png)\n  \n\n  \n  \n\n    \n\n      　　2）点击start a new android studio project,创建一个Android项目（可以修改工程的工作空间）\n    \n\n    \n    \n\n      　![](http://images.cnitblog.com/blog/695756/201412/101009122288363.png)\n    \n\n    \n    \n\n      \n\n        　　3）直接下一步\n      \n\n      \n      \n\n        ![](http://images.cnitblog.com/blog/695756/201412/101011291038680.png)\n      \n\n      \n      \n\n        　　4）再下一步\n      \n\n      \n      \n\n        ![](http://images.cnitblog.com/blog/695756/201412/101012503219925.png)\n      \n\n      \n      \n\n        　　5）再下一步\n      \n\n      \n      \n\n        ![](http://images.cnitblog.com/blog/695756/201412/101014228535095.png)\n      \n\n      \n      \n\n        \n\n          　　6）点击finish完成工程项目的创建。工程项目整体结构如下：\n        \n\n        \n        \n\n          ![](http://images.cnitblog.com/blog/695756/201412/101016289159573.png)\n        \n\n        \n        \n\n          \n\n            　　\u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;完，\u0026lt;/span\u0026gt;\n          \n\n          \n          \n\n            \n\n              转自：http://www.cnblogs.com/sonyi/p/4154797.html\n\u003c/code\u003e\u003c/pre\u003e","title":"Android Studio安装以及Fetching android sdk component information超时的解决方案"},{"content":" 搜索引擎网站收录地址大全 【点此提交您的搜索引擎】\n360搜索引擎登录入口：http://info.so.360.cn/site_submit.html\n即刻搜索网站提交入口：http://zz.jike.com/submit/genUrlForm\n盘古数据开放平台：http://open.panguso.com/data/resource/url/new\n百度搜索网站登录口：http://www.baidu.com/search/url_submit.html\n百度单个网页提交入口：http://zhanzhang.baidu.com/sitesubmit\nGoogle网站登录口：https://www.google.com/webmasters/tools/submit-url\nGoogle新闻网站内容：http://www.google.com/support/news_pub/bin/request.py?contact_type=suggest_content\u0026amp;hl=cn\nbing(必应)网页提交登录入口：http://www.bing.com/toolbox/submit-site-url\n简搜搜索引擎登陆口：http://www.jianso.com/add_site.html\n搜狗网站收录提交入口:http://www.sogou.com/feedback/urlfeedback.php\nSOSO搜搜网站收录提交入口:http://www.soso.com/help/usb/urlsubmit.shtml\n雅虎中国网站登录口：http://sitemap.cn.yahoo.com/\n网易有道搜索引擎登录口：http://tellbot.youdao.com/report\n中搜免费登录服务：http://register.zhongsou.com/NetSearch/frontEnd/free_protocol.htm\nMSN必应网站登录口：http://cn.bing.com/docs/submit.aspx?FORM=WSDD2\nAlexa网站登录入口：http://www.alexa.com/help/webmasters\nTOM搜索网站登录口：http://search.tom.com/tools/weblog/log.php\n铭万网B2B(必途)网址登陆口：http://search.b2b.cn/pageIncluded/AddPage.php\n蚁搜搜索网站登录口：http://www.antso.com/apply.asp\n快搜搜索网站登录口：http://www.kuaisou.com/main/inputweb.asp\n汕头搜索登录口：http://www.stsou.com/join.asp\n孙悟空搜索网站登录：http://www.swkong.com/add.php\n天网网站登陆口：http://home.tianwang.com/denglu.htm\n速搜全球登陆口：http://www.suso.com.cn/suso/link.asp\n酷帝网站目录提交入口：http://www.coodir.com/accounts/addsite.asp\n快搜网站登陆口：http://www.kuaisou.com/main/inputweb.asp\n搜猫搜索引擎登录入口：http://test.somao123.com/search/url_submit.php\n泽许搜索网站登录入口：http://www.zxyt.cn/guide/?m=adc4\u0026amp;Nsid=a3c6847db163587d\u0026amp;wver=t\n一淘网开放搜索申请入口：http://open.etao.com/apply_intro.htm?spm=0.0.0.40.9VF4FQ\n独立博客收录提交网址\n百度博客提交: http://utility.baidu.com/blogsearch/submit.php\n博客大全提交：http://lusongsong.com/daohang/login.asp\nGoogle博客提交：http://blogsearch.google.com/ping\n雅虎中国博客提交：http://search.help.cn.yahoo.com/h4_4.html\nFeedSky提交博客: http://www.feedsky.com\n搜狗(SoGou)博客提交：http://www.sogou.com/feedback/blogfeedback.php\n有道(YoDao)博客提交：http://tellbot.yodao.com/\n必应 Bing博客提交：http://www.bing.com/toolbox/submit-site-url\n搜搜博客提交：http://www.soso.com/help/usb/urlsubmit.shtml\n英文搜索网站收录地址\nDmoz网站登录入口：http://www.dmoz.org/World/Chinese_Simplified\nNetSearch登陆口：http://intelseek.com/add_url_form.asp\nFreewebsubmission.com 搜索引擎批量提交：http://www.freewebsubmission.com/\n快速登录20个搜索引擎：http://www.trafficzap.com/searchsubmit.php\nHotBot登录口：http://www.hotbot.com/prefs_filters.asp?prov=Inktomifilter=web\nnetscape登录口：http://about.netscape.com/\nAddMe登陆口 ：http://www.addme.com/submission/free-submission-start.php\nNetSearch登录口：http://www.netsearch.org/promo/submit.htm\nAddMe登录口：http://www.addme.com/s0new.htm\nLink it All登录口：http://www.that-special-gift.com/ffa/links.html\nVoyager登录口：http://www.voyagersearch.com/cgi-bin/q/search.cgi?NAVG=AddURL\nGigablast登录口：http://www.gigablast.com/addurl\nAeiwei登录口：http://www.aeiwi.com/submit.html\nInfotiger登录口：http://www.infotiger.com/addurl.html\nNationaldirectory登录口：http://www.nationaldirectory.com/addurl/\nWhatUseek登录口：http://www.whatuseek.com/addurl-secondary.shtml\nExactseek登录口：http://www.exactseek.com/add.html\nWalhello登录口：http://www.walhello.com/addlinkgl.html\nScrubtheweb登录口：http://www.scrubtheweb.com/addurl.html\n网址导航站收录申请登陆口大全\nhao123网址收录：http://submit.hao123.com/static/auditSys/wztj.htm\n360网址导航收录入口：http://hao.360.cn/url.html\n谷歌265上网导航网站提交：http://www.265.com/submit.html\n百度网址导航提交入口：http://site.baidu.com/quality/quality_form.php\n2345网址导航申请收录入口：http://www.2345.com/help/submitweb.htm\n必应网址导航提交：https://feedback.discoverbing.com/default.aspx?locale=zh-CN\u0026amp;productkey=bingweb\u0026amp;scrx=1\n搜狗网址导航收录入口：http://123.sogou.com/about/shoulu.html\n博客大全申请收录入口：http://lusongsong.com/daohang/login.asp\nQQ导航网站收录申请规则：http://support.qq.com/cgi-bin/content_…\n搜狗网址导航收录申请：http://123.sogou.com/shoulu.html\n114啦网址收录：http://url.114la.com/\n金山网址导航收录申请：http://123.duba.net/apply/\n瑞星网址导航收录申请：http://hao.rising.cn/catalog/slsq.html\n好看123网址导航收录申请：http://www.haokan123.com/urlsubmit/url_submit.html\n466傲游网址导航申请收录网站：http://bbs.maxthon.cn/viewthread.php?tid=584498\u0026amp;extra=\n1616网址导航收录：http://www.1616.net/jd/misc/coop.htm\n淘网址(tao123)收录申请：http://krq.tao123.com/collectsite/\n0460网站之家收录：http://www.0460.com/member/login.aspx\n赶驴啊网站收录提交入口：http://www.ganlva.com/url-submit/\nhao123网站收录规则：http://www.hao123.cn/hezuo.htm\n114网址导航收录申请：http://www.114.com.cn/index.php?view=websubmit\n726网址收录口：http://www.726.com/url-submit/\n1166网址收录口：http://www.1166.com/tool/add.html\n中商网址导航链接提交：http://www.cb114.cn/apps/about.html\n7999网址收录口：http://7999.com/misc/coop.htm\n369网址大全新站提交：http://wvw.369.com/us/url.htm\n568网址导航网址提交：http://www.568.cc/abc/website-add.html\n找军事网址提交：http://www.zhaojunshi.com/url-submit/\n19687网站大全网址提交：http://www.19687.com/apps/about.html#add\n易看网址大全：http://www.ekan123.com/shoulu.htm\n1181网址登陆：http://link.1181.com/adduser.asp\n57616网址导航登陆：http://www.57616.com/apps/about.html#add\nJia123网址网址提交：http://bbs.jia123.com/index.asp?boardid=2\n网站管理员工具大全（搜索引擎）：\nGoogle网站管理员工具：http://www.google.com/webmasters/\n微软Bing管理员工具地址：http://www.bing.com/toolbox/webmaster/\n百度站长平台：http://zhanzhang.baidu.com/\n即刻搜索站长中心：http://zz.jike.com/\n360搜索站长平台：http://zhanzhang.so.com/\n开放平台注册应用大全：\n搜搜论坛开放计划：http://open.soso.com/datacoop/bbs/submitbbs.html （仅适用于Discus，会带来大量外链）\n百度数据开放平台：http://open.baidu.com/data/\n新浪微博开放平台：http://open.weibo.com/\n腾讯微博开放平台：http://dev.open.t.qq.com/\nQQ互联：http://connect.qq.com/\n百度链接开放平台：http://dev.baidu.com/connect/\n人人网开放平台：http://dev.renren.com/\n网易微博开放平台：http://open.t.163.com/\n搜狐微博开放平台：http://open.t.sohu.com/\n淘宝开放平台：http://open.taobao.com\n支付好开放平台：http://bizpartner.alipay.com/denglu/index.htm\n豆瓣API key：http://www.douban.com/service/apikey/apply\n天涯开放平台：http://open.tianya.cn/\nGoogle站长开发者：https://www.google.com/accounts/ManageDomains\n开心开放平台：http://open.kaixin001.com/\n天翼开放平台：http://open.189.cn/\n360应用开放平台：http://dev.app.360.cn/\n雅虎开放平台：https://developer.apps.yahoo.com/projects\nTwitter开放平台：https://dev.twitter.com/\nFacebook开放平台：https://developers.facebook.com/\n向搜索引擎递交sitemap大全（网站地图）：\n腾讯搜搜：http://open.soso.com/sitemap/ 搜搜开放平台提供了提交sitemap的功能。\n百度：http://sitemap.baidu.com/ 百度站长平台，期待很久了，可惜一直在内测中。暂时无法提交。\n雅虎中国：http://sitemap.cn.yahoo.com/ 雅虎中国的站长工具很早就提供了提交sitemap的功能，还支持rss。\nGoogle：https://www.google.com/webmasters/tools/ 可谓最强大的网站管理员工具，提交sitemap当然是最基本的。\nYandex：http://webmaster.yandex.com/ Yandex是俄罗斯最大的搜索引擎，相对于俄罗斯的百度。管理员工具提供了类似Google Webmaster的功能，非常强大。\nBing：http://www.bing.com/toolbox/webmaster/ 微软的强力产品，在美国市场占有一定搜索份额。管理员工具功能也很强大。\nYahoo!：https://siteexplorer.search.yahoo.com/ 雅虎英文站，因为同微软的bing合作关系，提交sitemap后提示已经提交给了微软。\nAsk：http://submissions.ask.com/ping?sitemap=http://www.YourWebSite.com/sitemap.xml 修改红色部分的url为自己的sitemap地址，直接在浏览器提交。\n最后，在robots.txt文件中添加sitemap，搜索引擎抓取robots.txt的时候就可以获取sitemap。方法非常简单，只要在robots.txt的第一行或者最后一行按以下格式加入sitemap地址即可。\nSitemap: http://www.example.com/sitemap.xml\n网站被K申诉通道\n百度网页申诉：http://zhanzhang.baidu.com/feedback\n腾讯QQ电脑管家网站申诉：http://guanjia.qq.com/complaint.html\nGoogle网站申诉：http://www.google.com/webmasters/\n雅虎网站申诉：http://help.cn.yahoo.com/feedback.html?product=onesearch\u0026amp;source=1W5\n知道创宇（Scanv）安全联盟申诉通道：http://www.scanv.com/seccenter/appeal/?domain=\n360网盾申诉：http://wd.360.cn/appeal/appeal.html\n金山云安全网站申诉：http://fish.ijinshan.com/Kws/appeal (注：搜狗浏览器遇到拦截，也可在金山申诉)\n瑞星卡卡网站申诉：http://tool.ikaka.com/ssinfo.asp\n","permalink":"https://blog.zdltech.com/posts/%E5%90%84%E5%A4%A7%E7%BD%91%E7%AB%99%E6%94%B6%E5%BD%95%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E%E7%9A%84%E6%8F%90%E4%BA%A4%E5%85%A5%E5%8F%A3/","summary":"\u003cblockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e搜索引擎网站收录地址大全 【点此提交您的搜索引擎】\u003c/p\u003e\u003c/blockquote\u003e\u003c/blockquote\u003e\n\u003cp\u003e360搜索引擎登录入口：http://info.so.360.cn/site_submit.html\u003c/p\u003e\n\u003cp\u003e即刻搜索网站提交入口：http://zz.jike.com/submit/genUrlForm\u003c/p\u003e\n\u003cp\u003e盘古数据开放平台：http://open.panguso.com/data/resource/url/new\u003c/p\u003e\n\u003cp\u003e百度搜索网站登录口：http://www.baidu.com/search/url_submit.html\u003c/p\u003e\n\u003cp\u003e百度单个网页提交入口：http://zhanzhang.baidu.com/sitesubmit\u003c/p\u003e\n\u003cp\u003eGoogle网站登录口：https://www.google.com/webmasters/tools/submit-url\u003c/p\u003e\n\u003cp\u003eGoogle新闻网站内容：http://www.google.com/support/news_pub/bin/request.py?contact_type=suggest_content\u0026amp;hl=cn\u003c/p\u003e\n\u003cp\u003ebing(必应)网页提交登录入口：http://www.bing.com/toolbox/submit-site-url\u003c/p\u003e\n\u003cp\u003e简搜搜索引擎登陆口：http://www.jianso.com/add_site.html\u003c/p\u003e\n\u003cp\u003e搜狗网站收录提交入口:http://www.sogou.com/feedback/urlfeedback.php\u003c/p\u003e\n\u003cp\u003eSOSO搜搜网站收录提交入口:http://www.soso.com/help/usb/urlsubmit.shtml\u003c/p\u003e\n\u003cp\u003e雅虎中国网站登录口：http://sitemap.cn.yahoo.com/\u003c/p\u003e\n\u003cp\u003e网易有道搜索引擎登录口：http://tellbot.youdao.com/report\u003c/p\u003e\n\u003cp\u003e中搜免费登录服务：http://register.zhongsou.com/NetSearch/frontEnd/free_protocol.htm\u003c/p\u003e\n\u003cp\u003eMSN必应网站登录口：http://cn.bing.com/docs/submit.aspx?FORM=WSDD2\u003c/p\u003e\n\u003cp\u003eAlexa网站登录入口：http://www.alexa.com/help/webmasters\u003c/p\u003e\n\u003cp\u003eTOM搜索网站登录口：http://search.tom.com/tools/weblog/log.php\u003c/p\u003e\n\u003cp\u003e铭万网B2B(必途)网址登陆口：http://search.b2b.cn/pageIncluded/AddPage.php\u003c/p\u003e\n\u003cp\u003e蚁搜搜索网站登录口：http://www.antso.com/apply.asp\u003c/p\u003e\n\u003cp\u003e快搜搜索网站登录口：http://www.kuaisou.com/main/inputweb.asp\u003c/p\u003e\n\u003cp\u003e汕头搜索登录口：http://www.stsou.com/join.asp\u003c/p\u003e\n\u003cp\u003e孙悟空搜索网站登录：http://www.swkong.com/add.php\u003c/p\u003e\n\u003cp\u003e天网网站登陆口：http://home.tianwang.com/denglu.htm\u003c/p\u003e\n\u003cp\u003e速搜全球登陆口：http://www.suso.com.cn/suso/link.asp\u003c/p\u003e\n\u003cp\u003e酷帝网站目录提交入口：http://www.coodir.com/accounts/addsite.asp\u003c/p\u003e\n\u003cp\u003e快搜网站登陆口：http://www.kuaisou.com/main/inputweb.asp\u003c/p\u003e\n\u003cp\u003e搜猫搜索引擎登录入口：http://test.somao123.com/search/url_submit.php\u003c/p\u003e\n\u003cp\u003e泽许搜索网站登录入口：http://www.zxyt.cn/guide/?m=adc4\u0026amp;Nsid=a3c6847db163587d\u0026amp;wver=t\u003c/p\u003e\n\u003cp\u003e一淘网开放搜索申请入口：http://open.etao.com/apply_intro.htm?spm=0.0.0.40.9VF4FQ\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cblockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e独立博客收录提交网址\u003c/p\u003e\u003c/blockquote\u003e\u003c/blockquote\u003e\n\u003cp\u003e百度博客提交: \u003ca href=\"http://utility.baidu.com/blogsearch/submit.php\"\u003ehttp://utility.baidu.com/blogsearch/submit.php\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e博客大全提交：http://lusongsong.com/daohang/login.asp\u003c/p\u003e\n\u003cp\u003eGoogle博客提交：http://blogsearch.google.com/ping\u003c/p\u003e\n\u003cp\u003e雅虎中国博客提交：http://search.help.cn.yahoo.com/h4_4.html\u003c/p\u003e\n\u003cp\u003eFeedSky提交博客: \u003ca href=\"http://www.feedsky.com\"\u003ehttp://www.feedsky.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e搜狗(SoGou)博客提交：http://www.sogou.com/feedback/blogfeedback.php\u003c/p\u003e\n\u003cp\u003e有道(YoDao)博客提交：http://tellbot.yodao.com/\u003c/p\u003e\n\u003cp\u003e必应 Bing博客提交：http://www.bing.com/toolbox/submit-site-url\u003c/p\u003e\n\u003cp\u003e搜搜博客提交：http://www.soso.com/help/usb/urlsubmit.shtml\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cblockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e英文搜索网站收录地址\u003c/p\u003e\u003c/blockquote\u003e\u003c/blockquote\u003e\n\u003cp\u003eDmoz网站登录入口：http://www.dmoz.org/World/Chinese_Simplified\u003c/p\u003e\n\u003cp\u003eNetSearch登陆口：http://intelseek.com/add_url_form.asp\u003c/p\u003e\n\u003cp\u003eFreewebsubmission.com 搜索引擎批量提交：http://www.freewebsubmission.com/\u003c/p\u003e\n\u003cp\u003e快速登录20个搜索引擎：http://www.trafficzap.com/searchsubmit.php\u003c/p\u003e\n\u003cp\u003eHotBot登录口：http://www.hotbot.com/prefs_filters.asp?prov=Inktomifilter=web\u003c/p\u003e\n\u003cp\u003enetscape登录口：http://about.netscape.com/\u003c/p\u003e\n\u003cp\u003eAddMe登陆口 ：http://www.addme.com/submission/free-submission-start.php\u003c/p\u003e\n\u003cp\u003eNetSearch登录口：http://www.netsearch.org/promo/submit.htm\u003c/p\u003e\n\u003cp\u003eAddMe登录口：http://www.addme.com/s0new.htm\u003c/p\u003e\n\u003cp\u003eLink it All登录口：http://www.that-special-gift.com/ffa/links.html\u003c/p\u003e\n\u003cp\u003eVoyager登录口：http://www.voyagersearch.com/cgi-bin/q/search.cgi?NAVG=AddURL\u003c/p\u003e\n\u003cp\u003eGigablast登录口：http://www.gigablast.com/addurl\u003c/p\u003e\n\u003cp\u003eAeiwei登录口：http://www.aeiwi.com/submit.html\u003c/p\u003e\n\u003cp\u003eInfotiger登录口：http://www.infotiger.com/addurl.html\u003c/p\u003e\n\u003cp\u003eNationaldirectory登录口：http://www.nationaldirectory.com/addurl/\u003c/p\u003e\n\u003cp\u003eWhatUseek登录口：http://www.whatuseek.com/addurl-secondary.shtml\u003c/p\u003e\n\u003cp\u003eExactseek登录口：http://www.exactseek.com/add.html\u003c/p\u003e\n\u003cp\u003eWalhello登录口：http://www.walhello.com/addlinkgl.html\u003c/p\u003e\n\u003cp\u003eScrubtheweb登录口：http://www.scrubtheweb.com/addurl.html\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cblockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e网址导航站收录申请登陆口大全\u003c/p\u003e","title":"各大网站收录、搜索引擎的提交入口"},{"content":"前言 最近有一个跟Https相关的问题需要解决，因此花时间学习了一下Android平台Https的使用，同时也看了一些Https的原理，这里分享一下学习心得。\nHTTPS原理 HTTPS(Hyper Text Transfer Protocol Secure)，是一种基于SSL/TLS的HTTP，所有的HTTP数据都是在SSL/TLS协议封装之上进行传输的。HTTPS协议是在HTTP协议的基础上，添加了SSL/TLS握手以及数据加密传输，也属于应用层协议。所以，研究HTTPS协议原理，最终其实就是研究SSL/TLS协议。\nSSL/TLS协议作用 不使用SSL/TLS的HTTP通信，就是不加密的通信，所有的信息明文传播，带来了三大风险：\n窃听风险：第三方可以获知通信内容。\n篡改风险：第三方可以修改通知内容。\n冒充风险：第三方可以冒充他人身份参与通信。\nSSL/TLS协议是为了解决这三大风险而设计的，希望达到：\n所有信息都是加密传输，第三方无法窃听。\n具有校验机制，一旦被篡改，通信双方都会立刻发现。\n配备身份证书，防止身份被冒充。\n基本的运行过程 SSL/TLS协议的基本思路是采用公钥加密法，也就是说，客户端先向服务器端索要公钥，然后用公钥加密信息，服务器收到密文后，用自己的私钥解密。但是这里需要了解两个问题的解决方案。\n如何保证公钥不被篡改？ 解决方法：将公钥放在数字证书中。只要证书是可信的，公钥就是可信的。\n公钥加密计算量太大，如何减少耗用的时间？ 解决方法：每一次对话(session)，客户端和服务器端都生成一个“对话密钥”(session key)，用它来加密信息。由于“对话密钥”是对称加密，所以运算速度非常快，而服务器公钥只用于加密“对话密钥”本身，这样就减少了加密运算的消耗时间。\n因此，SSL/TLS协议的基本过程是这样的：\n客户端向服务器端索要并验证公钥。\n双方协商生成“对话密钥”。\n双方采用“对话密钥”进行加密通信。\n上面过程的前两布，又称为“握手阶段”。\n握手阶段的详细过程 “握手阶段”涉及四次通信，需要注意的是，“握手阶段”的所有通信都是明文的。\n客户端发出请求（ClientHello） 首先，客户端（通常是浏览器）先向服务器发出加密通信的请求，这被叫做ClientHello请求。在这一步中，客户端主要向服务器提供以下信息：\n支持的协议版本，比如TLS 1.0版\n一个客户端生成的随机数，稍后用于生成“对话密钥”。\n支持的加密方法，比如RSA公钥加密。\n支持的压缩方法。\n这里需要注意的是，客户端发送的信息之中不包括服务器的域名。也就是说，理论上服务器只能包含一个网站，否则会分不清应用向客户端提供哪一个网站的数字证书。这就是为什么通常一台服务器只能有一张数字证书的原因。\n服务器回应（ServerHello） 服务器收到客户端请求后，向客户端发出回应，这叫做ServerHello。服务器的回应包含以下内容：\n确认使用的加密通信协议版本，比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致，服务器关闭加密通信。\n一个服务器生成的随机数，稍后用于生成“对话密钥”。\n确认使用的加密方法，比如RSA公钥加密。\n服务器证书。\n除了上面这些信息，如果服务器需要确认客户端的身份，就会再包含一项请求，要求客户端提供“客户端证书”。比如，金融机构往往只允许认证客户连入自己的网络，就会向正式客户提供USB密钥，里面就包含了一张客户端证书。\n客户端回应 客户端收到服务器回应以后，首先验证服务器证书。如果证书不是可信机构颁发，或者证书中的域名与实际域名不一致，或者证书已经过期，就会向访问者显示一个警告，由其选择是否还要继续通信。\n如果证书没有问题，客户端就会从证书中取出服务器的公钥。然后，向服务器发送下面三项消息。\n一个随机数。该随机数用服务器公钥加密，防止被窃听。\n编码改变通知，表示随后的信息都将用双方商定的加密方法和密钥发送。\n客户端握手结束通知，表示客户端的握手阶段已经结束。这一项通常也是前面发送的所有内容的hash值，用来供服务器校验。\n上面第一项随机数，是整个握手阶段出现的第三个随机数，又称“pre-master key”。有了它以后，客户端和服务器就同时有了三个随机数，接着双方就用事先商定的加密方法，各自生成本次会话所用的同一把“会话密钥”。\n服务器的最后回应 服务器收到客户端的第三个随机数pre-master key之后，计算生成本次会话所用的“会话密钥”。然后，向客户端最后发送下面信息。\n编码改变通知，表示随后的信息都将用双方商定的加密方法和密钥发送。\n服务器握手结束通知，表示服务器的握手阶段已经结束。这一项同时也是前面发生的所有内容的hash值，用来供客户端校验。\n握手结束 至此，整个握手阶段全部结束。接下来，客户端与服务器进入加密通信，就完全是使用普通的HTTP协议，只不过用“会话密钥”加密内容。\n服务器基于Nginx搭建HTTPS虚拟站点 之前一篇文章详细介绍了在服务器端如何生成SSL证书，并基于Nginx搭建HTTPS服务器，链接：Nginx搭建HTTPS服务器\nAndroid实现HTTPS通信 由于各种原因吧，这里使用HttpClicent类讲解一下Android如何建立HTTPS连接。代码demo如下。\nMainActivity.java\n``` package com.example.photocrop; import java.io.BufferedReader; import java.io.InputStreamReader;\nimport org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpUriRequest;\nimport android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.os.AsyncTask.Status; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView;\npublic class MainActivity extends Activity { private Button httpsButton; private TextView conTextView;\nprivate CreateHttpsConnTask httpsTask;\n@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);\nhttpsButton = (Button) findViewById(R.id.create_https_button); httpsButton.setOnClickListener(new View.OnClickListener() {\n@Override public void onClick(View v) { runHttpsConnection(); } });\nconTextView = (TextView) findViewById(R.id.content_textview); conTextView.setText(\u0026ldquo;初始为空\u0026rdquo;); }\nprivate void runHttpsConnection() { if (httpsTask == null || httpsTask.getStatus() == Status.FINISHED) { httpsTask = new CreateHttpsConnTask(); httpsTask.execute(); } }\nprivate class CreateHttpsConnTask extends AsyncTask\u0026lt;Void, Void, Void\u0026gt; { private static final String HTTPS_EXAMPLE_URL = \u0026ldquo;自定义\u0026rdquo;; private StringBuffer sBuffer = new StringBuffer();\n@Override protected Void doInBackground(Void\u0026hellip; params) { HttpUriRequest request = new HttpPost(HTTPS_EXAMPLE_URL); HttpClient httpClient = HttpUtils.getHttpsClient(); try { HttpResponse httpResponse = httpClient.execute(request); if (httpResponse != null) { StatusLine statusLine = httpResponse.getStatusLine(); if (statusLine != null \u0026amp;\u0026amp; statusLine.getStatusCode() == HttpStatus.SC_OK) { BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader( httpResponse.getEntity().getContent(), \u0026ldquo;UTF-8\u0026rdquo;)); String line = null; while ((line = reader.readLine()) != null) { sBuffer.append(line); }\n} catch (Exception e) { Log.e(\u0026ldquo;https\u0026rdquo;, e.getMessage()); } finally { if (reader != null) { reader.close(); reader = null; } } } }\n} catch (Exception e) { Log.e(\u0026ldquo;https\u0026rdquo;, e.getMessage()); } finally {\n}\nreturn null; }\n@Override protected void onPostExecute(Void result) { if (!TextUtils.isEmpty(sBuffer.toString())) { conTextView.setText(sBuffer.toString()); } }\n} }\nHttpUtils.java \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; package com.example.photocrop;\nimport org.apache.http.HttpVersion; import org.apache.http.client.HttpClient; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.HTTP;\npublic class HttpUtils { public static HttpClient getHttpsClient() { BasicHttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET); HttpProtocolParams.setUseExpectContinue(params, true);\nSchemeRegistry schReg = new SchemeRegistry(); schReg.register(new Scheme(\u0026ldquo;http\u0026rdquo;, PlainSocketFactory.getSocketFactory(), 80)); schReg.register(new Scheme(\u0026ldquo;https\u0026rdquo;, SSLSocketFactory.getSocketFactory(), 443));\nClientConnectionManager connMgr = new ThreadSafeClientConnManager(params, schReg);\nreturn new DefaultHttpClient(connMgr, params); } }\nactivity_main.xml \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;LinearLayout xmlns:android=\u0026ldquo;http://schemas.android.com/apk/res/android\u0026quot; xmlns:tools=\u0026ldquo;http://schemas.android.com/tools\u0026quot; android:layout_width=\u0026ldquo;match_parent\u0026rdquo; android:layout_height=\u0026ldquo;match_parent\u0026rdquo; android:orientation=\u0026ldquo;vertical\u0026rdquo;\u0026gt;\n\u0026lt;Button android:id=\u0026rdquo;@+id/create_https_button\u0026rdquo; android:layout_width=\u0026ldquo;match_parent\u0026rdquo; android:layout_height=\u0026ldquo;wrap_content\u0026rdquo; android:text=\u0026quot;@string/hello_world\u0026quot; android:textSize=\u0026ldquo;16sp\u0026rdquo; /\u0026gt;\n\u0026lt;TextView android:id=\u0026quot;@+id/content_textview\u0026quot; android:layout_width=\u0026ldquo;match_parent\u0026rdquo; android:layout_height=\u0026ldquo;wrap_content\u0026rdquo; android:gravity=\u0026ldquo;center\u0026rdquo; android:textSize=\u0026ldquo;16sp\u0026rdquo; /\u0026gt;\n\u0026lt;/LinearLayout\u0026gt;\nAndroid使用DefaultHttpClient建立HTTPS连接，关键需要加入对HTTPS的支持： \u0026lt;div\u0026gt; ``` schReg.\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;register\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; Scheme(\u0026lt;span class=\u0026#34;string\u0026#34; style=\u0026#34;color: #dd1144;\u0026#34;\u0026gt;\u0026#34;https\u0026#34;\u0026lt;/span\u0026gt;, SSLSocketFactory.getSocketFactory(), \u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #009999;\u0026#34;\u0026gt;443\u0026lt;/span\u0026gt;)); 加入对HTTPS的支持，就可以有效的建立HTTPS连接了，例如“https://www.google.com.hk”了，但是访问自己基于Nginx搭建的HTTPS服务器却不行，因为它使用了不被系统承认的自定义证书，会报出如下问题：No peer certificate。 使用自定义证书并忽略验证的HTTPS连接方式 解决证书不被系统承认的方法，就是跳过系统校验。要跳过系统校验，就不能再使用系统标准的SSL SocketFactory了，需要自定义一个。然后为了在这个自定义SSL SocketFactory里跳过校验，还需要自定义一个TrustManager，在其中忽略所有校验，即TrustAll。 MySSLSocketFactory.java实现代码如下： ``` package com.example.photocrop; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate;\nimport javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.http.conn.ssl.SSLSocketFactory;\npublic class MySSLSocketFactory extends SSLSocketFactory { SSLContext sslContext = SSLContext.getInstance(\u0026ldquo;TLS\u0026rdquo;);\npublic MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); TrustManager tm = new X509TrustManager() {\n@Override public X509Certificate[] getAcceptedIssuers() { return null; }\n@Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n}\n@Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n} };\nsslContext.init(null, new TrustManager[] { tm }, null); }\n@Override public Socket createSocket() throws IOException { return sslContext.getSocketFactory().createSocket(); }\n@Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); }\npublic static SSLSocketFactory getSocketFactory() { try { KeyStore trustStore = KeyStore.getInstance(KeyStore .getDefaultType()); trustStore.load(null, null); SSLSocketFactory factory = new MySSLSocketFactory(trustStore); return factory; } catch (Exception e) { e.getMessage(); return null; } } }\n同时，需要修改DefaultHttpClient的register方法，改为自己构建的sslsocket： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; HttpClient getCustomClient() { BasicHttpParams \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; BasicHttpParams(); HttpProtocolParams.setVersion(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;, HTTP.DEFAULT_CONTENT_CHARSET); HttpProtocolParams.setUseExpectContinue(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); SchemeRegistry schReg = \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; SchemeRegistry(); schReg.register(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; Scheme(\u0026lt;span class=\u0026#34;string\u0026#34; style=\u0026#34;color: #dd1144;\u0026#34;\u0026gt;\u0026#34;http\u0026#34;\u0026lt;/span\u0026gt;, PlainSocketFactory.getSocketFactory(), \u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #009999;\u0026#34;\u0026gt;80\u0026lt;/span\u0026gt;)); schReg.register(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; Scheme(\u0026lt;span class=\u0026#34;string\u0026#34; style=\u0026#34;color: #dd1144;\u0026#34;\u0026gt;\u0026#34;https\u0026#34;\u0026lt;/span\u0026gt;, MySSLSocketFactory.getSocketFactory(), \u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #009999;\u0026#34;\u0026gt;443\u0026lt;/span\u0026gt;)); ClientConnectionManager connMgr = \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; ThreadSafeClientConnManager(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;, schReg); \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; DefaultHttpClient(connMgr, \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;); } 这样就可以成功的访问自己构建的基于Nginx的HTTPS虚拟站点了。 缺陷： 不过，虽然这个方案使用了HTTPS，客户端和服务器端的通信内容得到了加密，嗅探程序无法得到传输的内容，但是无法抵挡“中间人攻击”。例如，在内网配置一个DNS，把目标服务器域名解析到本地的一个地址，然后在这个地址上使用一个中间服务器作为代理，它使用一个假的证书与客户端通讯，然后再由这个代理服务器作为客户端连接到实际的服务器，用真的证书与服务器通讯。这样所有的通讯内容都会经过这个代理，而客户端不会感知，这是由于客户端不校验服务器公钥证书导致的。 ### 使用自定义证书建立HTTPS连接 为了防止上面方案可能导致的“中间人攻击”，我们可以下载服务器端公钥证书，然后将公钥证书编译到Android应用中，由应用自己来验证证书。 生成KeyStore 要验证自定义证书，首先要把证书编译到应用中，这需要使用keytool工具生产KeyStore文件。这里的证书就是指目标服务器的公钥，可以从web服务器配置的.crt文件或.pem文件获得。同时，你需要配置bouncycastle，我下载的是bcprov-jdk16-145.jar，至于配置大家自行google就好了。 keytool -importcert -v -trustcacerts -\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;alias\u0026lt;/span\u0026gt; example -file www.example.com.crt -keystore example.bks -storetype \u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;BKS\u0026lt;/span\u0026gt; -providerclass org.bouncycastle.jce.provider.\u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;BouncyCastleProvider\u0026lt;/span\u0026gt; -providerpath /home/wzy/\u0026lt;span class=\u0026#34;constant\u0026#34;\u0026gt;Downloads\u0026lt;/span\u0026gt;/java/jdk1.\u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #009999;\u0026#34;\u0026gt;7.0_60\u0026lt;/span\u0026gt;/jre/lib/ext/bcprov-jdk16-\u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #009999;\u0026#34;\u0026gt;145\u0026lt;/span\u0026gt;.jar -storepass pw123456 运行后将显示证书内容并提示你是否确认，输入Y回车即可。 生产KeyStore文件成功后，将其放在app应用的res/raw目录下即可。 使用自定义KeyStore实现连接 思路和TrushAll差不多，也是需要一个自定义的SSLSokcetFactory，不过因为还需要验证证书，因此不需要自定义TrustManager了。 ``` package com.example.photocrop; import java.io.IOException; import java.io.InputStream; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException;\nimport org.apache.http.conn.ssl.SSLSocketFactory;\nimport android.content.Context;\npublic class CustomerSocketFactory extends SSLSocketFactory {\nprivate static final String PASSWD = \u0026ldquo;pw123456\u0026rdquo;;\npublic CustomerSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); }\npublic static SSLSocketFactory getSocketFactory(Context context) { InputStream input = null; try { input = context.getResources().openRawResource(R.raw.example); KeyStore trustStore = KeyStore.getInstance(KeyStore .getDefaultType());\ntrustStore.load(input, PASSWD.toCharArray());\nSSLSocketFactory factory = new CustomerSocketFactory(trustStore);\nreturn factory; } catch (Exception e) { e.printStackTrace(); return null; } finally { if (input != null) { try { input.close(); } catch (IOException e) { e.printStackTrace(); } input = null; } } }\n}\n\u0026lt;div\u0026gt; 同时，需要修改DefaultHttpClient的register方法，改为自己构建的sslsocket： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ``` \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; HttpClient getSpecialKeyStoreClient(Context context) { BasicHttpParams \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; BasicHttpParams(); HttpProtocolParams.setVersion(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;, HTTP.DEFAULT_CONTENT_CHARSET); HttpProtocolParams.setUseExpectContinue(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;); SchemeRegistry schReg = \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; SchemeRegistry(); schReg.register(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; Scheme(\u0026lt;span class=\u0026#34;string\u0026#34; style=\u0026#34;color: #dd1144;\u0026#34;\u0026gt;\u0026#34;http\u0026#34;\u0026lt;/span\u0026gt;, PlainSocketFactory.getSocketFactory(), \u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #009999;\u0026#34;\u0026gt;80\u0026lt;/span\u0026gt;)); schReg.register(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; Scheme(\u0026lt;span class=\u0026#34;string\u0026#34; style=\u0026#34;color: #dd1144;\u0026#34;\u0026gt;\u0026#34;https\u0026#34;\u0026lt;/span\u0026gt;, CustomerSocketFactory.getSocketFactory(context), \u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #009999;\u0026#34;\u0026gt;443\u0026lt;/span\u0026gt;)); ClientConnectionManager connMgr = \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; ThreadSafeClientConnManager(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;, schReg); \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; DefaultHttpClient(connMgr, \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;params\u0026lt;/span\u0026gt;); } \u0026lt;/div\u0026gt; 转自：http://www.tuicool.com/articles/6NvEZj \u0026amp;nbsp; # android httpClient 支持HTTPS的2种处理方式 \u0026amp;nbsp; 转自[http://my.oschina.net/blackylin/blog/144136](http://my.oschina.net/blackylin/blog/144136) 参考[http://developer.android.com/training/articles/security-ssl.html#Concepts](http://developer.android.com/training/articles/security-ssl.html#Concepts) [http://www.ibm.com/developerworks/cn/java/j-lo-ssltls/](http://www.ibm.com/developerworks/cn/java/j-lo-ssltls/) \u0026amp;nbsp; # \u0026lt;a style=\u0026quot;color: #336699;\u0026quot; name=\u0026quot;t0\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;问题： 项目中Android https或http请求地址重定向为HTTPS的地址，相信很多人都遇到了这个异常(无终端认证)： javax.net.ssl.SSLPeerUnverifiedException: No peer certificate\n# \u0026lt;a style=\u0026quot;color: #336699;\u0026quot; name=\u0026quot;t1\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;解决过程： ## \u0026lt;a style=\u0026quot;color: #336699;\u0026quot; name=\u0026quot;t2\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;1.没遇到过的问题，搜索吧，少年 log里出现这个异常，作者第一次遇到，不知道啥意思。看下字面意思，是ssl协议中没有终端认证。SSL?[![](http://my.oschina.net/js/ke/plugins/emoticons/images/14.gif)](http://my.oschina.net/js/ke/plugins/emoticons/images/14.gif)作者没用到ssl协议呀，只是通过httpClient请求一个重定向https的地址。 好吧，google下，知道了个差不多情况的帖子，http://www.eoeandroid.com/thread-161747-1-1.html。恩恩，一个不错的帖子，给出了个解决方案。照着来试下。添加个继承SSLSocketFactory的 自定义类。并在初始化httpclient支持https时，注册进去。看下面代码：\n01 public class HttpClientHelper { 02 03 private static HttpClient httpClient; 04 05 private HttpClientHelper() { 06 } 07 08 public static synchronized HttpClient getHttpClient() { 09 10 if (null == httpClient) { 11 // 初始化工作 12 try { 13 KeyStore trustStore = KeyStore.getInstance(KeyStore 14 .getDefaultType()); 15 trustStore.load(null, null); 16 SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore); 17 sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); //允许所有主机的验证 18 19 HttpParams params = new BasicHttpParams(); 20 21 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 22 HttpProtocolParams.setContentCharset(params, 23 HTTP.DEFAULT_CONTENT_CHARSET); 24 HttpProtocolParams.setUseExpectContinue(params, true); 25 26 // 设置连接管理器的超时 27 ConnManagerParams.setTimeout(params, 10000); 28 // 设置连接超时 29 HttpConnectionParams.setConnectionTimeout(params, 10000); 30 // 设置socket超时 31 HttpConnectionParams.setSoTimeout(params, 10000); 32 33 // 设置http https支持 34 SchemeRegistry schReg = new SchemeRegistry(); 35 schReg.register(new Scheme(“http”, PlainSocketFactory 36 .getSocketFactory(), 80)); 37 schReg.register(new Scheme(“https”, sf, 443)); 38 39 ClientConnectionManager conManager = new ThreadSafeClientConnManager( 40 params, schReg); 41 42 httpClient = new DefaultHttpClient(conManager, params); 43 } catch (Exception e) { 44 e.printStackTrace(); 45 return new DefaultHttpClient(); 46 } 47 } 48 return httpClient; 49 } 50 51 } 52 53 class SSLSocketFactoryEx extends SSLSocketFactory { 54 55 SSLContext sslContext = SSLContext.getInstance(“TLS”); 56 57 public SSLSocketFactoryEx(KeyStore truststore) 58 throws NoSuchAlgorithmException, KeyManagementException, 59 KeyStoreException, UnrecoverableKeyException { 60 super(truststore); 61 62 TrustManager tm = new X509TrustManager() { 63 64 @Override 65 public java.security.cert.X509Certificate[] getAcceptedIssuers() { 66 return null; 67 } 68 69 @Override 70 public void checkClientTrusted( 71 java.security.cert.X509Certificate[] chain, String authType) 72 throws java.security.cert.CertificateException { 73 74 } 75 76 @Override 77 public void checkServerTrusted( 78 java.security.cert.X509Certificate[] chain, String authType) 79 throws java.security.cert.CertificateException { 80 81 } 82 }; 83 84 sslContext.init(null, new TrustManager[] { tm }, null); 85 } 86 87 @Override 88 public Socket createSocket(Socket socket, String host, int port, 89 boolean autoClose) throws IOException, UnknownHostException { 90 return sslContext.getSocketFactory().createSocket(socket, host, port, 91 autoClose); 92 } 93 94 @Override 95 public Socket createSocket() throws IOException { 96 return sslContext.getSocketFactory().createSocket(); 97 } 98 }\n\u0026lt;div id=\u0026quot;highlighter_796606\u0026quot; class=\u0026quot;syntaxhighlighter \u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;lines\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ok，run下，狂乱的点到测试按钮，深吸口气，盯着eclipse中的logat。咦？神奇的竟然没有报之前的\u0026lt;span style=\u0026quot;font-weight: 600;\u0026quot;\u0026gt; javax.net.ssl.SSLPeerUnverifiedException: No peer certificate\u0026lt;/span\u0026gt;的异常了。服务端的数据正常返回了。[![](http://my.oschina.net/js/ke/plugins/emoticons/images/13.gif)](http://my.oschina.net/js/ke/plugins/emoticons/images/13.gif),狂喜中\u0026amp;#8230; \u0026amp;nbsp; ## \u0026lt;a style=\u0026quot;color: #336699;\u0026quot; name=\u0026quot;t3\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;2.了解并分析问题 狂喜中，得分析这问题诶。不然老大来问，啥情况？楞半天不知道咋说（[![](http://my.oschina.net/js/ke/plugins/emoticons/images/1.gif)](http://my.oschina.net/js/ke/plugins/emoticons/images/1.gif)作者就经常这样，所以吸取教训。所以的弄懂出现的问题，学习+汇报工作）。 思来想去，就是作者请求的是一个重定向https的地址。好吧，那就学习下https（之前被老大深深的教过，http就是request/response）。继续搜索吧，少年。下面总结下学习到的https知识。\n### \u0026lt;a style=\u0026quot;color: #336699;\u0026quot; name=\u0026quot;t4\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;2.1 https \u0026amp;nbsp; HTTPS:超文本安全传输协议，和HTTP相比，多了一个SSL/TSL的认证过程，端口为443。（鄙视下之前说的) ** 作者没用到ssl协议呀，只是通过httpClient请求一个重定向https的地址 \u0026lt;/blockquote\u0026gt; \u0026amp;nbsp; \u0026lt;span style=\u0026quot;font-weight: 600;\u0026quot;\u0026gt;1.peer终端发送一个request，https服务端把支持的加密算法等以证书的形式返回一个身份信息（包含ca颁发机构和加密公钥等）。\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-weight: 600;\u0026quot;\u0026gt;2.获取证书之后，验证证书合法性。\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-weight: 600;\u0026quot;\u0026gt;3.随机产生一个密钥，并以证书当中的公钥加密。\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-weight: 600;\u0026quot;\u0026gt;4.request https服务端，把用公钥加密过的密钥传送给https服务端。\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-weight: 600;\u0026quot;\u0026gt;5.https服务端用自己的密钥解密，获取随机值。\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;font-weight: 600;\u0026quot;\u0026gt;6.之后双方传送数据都用此密钥加密后通信。\u0026lt;/span\u0026gt; ``` 看下面一张网上的得来的https的时序图：\n\u0026amp;nbsp; [![](http://static.oschina.net/uploads/space/2013/0711/214828_8G6b_587911.png)](http://static.oschina.net/uploads/space/2013/0711/214828_8G6b_587911.png) \u0026amp;nbsp; ### \u0026lt;a style=\u0026#34;color: #336699;\u0026#34; name=\u0026#34;t5\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;2.2分析下出现问题的原因 \u0026amp;nbsp; 好吧，大概的流程知道了。定位已经非常清楚了。在第2步验证证书时，无法验证。为啥无法验证呢？没有添加信任。详细参考下 [http://www.cnblogs.com/P_Chou/archive/2010/12/27/https-ssl-certification.html](http://www.cnblogs.com/P_Chou/archive/2010/12/27/https-ssl-certification.html)讲的非常清楚https-ssl的认证过程，膜拜下该作者[![](http://my.oschina.net/js/ke/plugins/emoticons/images/13.gif)](http://my.oschina.net/js/ke/plugins/emoticons/images/13.gif) \u0026amp;nbsp; 这样想来，上面提供的解决方案就是添加默认信任全部证书。以此来通过接下来的通信。 ## \u0026lt;a style=\u0026#34;color: #336699;\u0026#34; name=\u0026#34;t6\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;3.解决问题 但是，这样问题是解决了。但是觉得还是不带靠谱（信任全部证书[![](http://my.oschina.net/js/ke/plugins/emoticons/images/3.gif)](http://my.oschina.net/js/ke/plugins/emoticons/images/3.gif)有点危险）。继续噼噼啪啪的网上搜索一番。又找到了一种解决方案，其过程大致这样的： \u0026lt;span style=\u0026#34;font-weight: 600;\u0026#34;\u0026gt;1.浏览器访问https地址，保存提示的证书到本地，放到android项目中的assets目录。\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: 600;\u0026#34;\u0026gt;2.导入证书，代码如下。\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: 600;\u0026#34;\u0026gt;3.把证书添加为信任。\u0026lt;/span\u0026gt; 01 String requestHTTPSPage(String mUrl) { 02 InputStream ins = null; 03 String result = \u0026amp;#8220;\u0026amp;#8221;; 04 try { 05 ins = context.getAssets().open(\u0026amp;#8220;app_pay.cer\u0026amp;#8221;); //下载的证书放到项目中的assets目录中 06 CertificateFactory cerFactory = CertificateFactory 07 .getInstance(\u0026amp;#8220;X.509\u0026amp;#8221;); 08 Certificate cer = cerFactory.generateCertificate(ins); 09 KeyStore keyStore = KeyStore.getInstance(\u0026amp;#8220;PKCS12\u0026amp;#8221;, \u0026amp;#8220;BC\u0026amp;#8221;); 10 keyStore.load(null, null); 11 keyStore.setCertificateEntry(\u0026amp;#8220;trust\u0026amp;#8221;, cer); 12 13 SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore); 14 Scheme sch = new Scheme(\u0026amp;#8220;https\u0026amp;#8221;, socketFactory, 443); 15 HttpClient mHttpClient = new DefaultHttpClient(); 16 mHttpClient.getConnectionManager().getSchemeRegistry() 17 .register(sch); 18 19 BufferedReader reader = null; 20 try { 21 Log.d(TAG, \u0026amp;#8220;executeGet is in,murl:\u0026amp;#8221; + mUrl); 22 HttpGet request = new HttpGet(); 23 request.setURI(new URI(mUrl)); 24 HttpResponse response = mHttpClient.execute(request); 25 if (response.getStatusLine().getStatusCode() != 200) { 26 request.abort(); 27 return result; 28 } 29 30 reader = new BufferedReader(new InputStreamReader(response 31 .getEntity().getContent())); 32 StringBuffer buffer = new StringBuffer(); 33 String line = null; 34 while ((line = reader.readLine()) != null) { 35 buffer.append(line); 36 } 37 result = buffer.toString(); 38 Log.d(TAG, \u0026amp;#8220;mUrl=\u0026amp;#8221; + mUrl + \u0026amp;#8220;\\nresult = \u0026amp;#8221; + result); 39 } catch (Exception e) { 40 e.printStackTrace(); 41 } finally { 42 if (reader != null) { 43 reader.close(); 44 } 45 } 46 } catch (Exception e) { 47 // TODO: handle exception 48 } finally { 49 try { 50 if (ins != null) 51 ins.close(); 52 } catch (IOException e) { 53 e.printStackTrace(); 54 } 55 } 56 return result; 57 } 接着，验证下呗。吼吼，稀里糊涂的又可以了。感动的泪流满面。 \u0026amp;nbsp; # \u0026lt;a style=\u0026#34;color: #336699;\u0026#34; name=\u0026#34;t7\u0026#34;\u0026gt;\u0026lt;/a\u0026gt;最后总结： 2种方法都解决了作者遇到的问题，这里记录下。以防下次遇到，希望能给遇到相同问题朋友有所参考帮助。 转自：http://blog.csdn.net/lihenair/article/details/17441169 \u0026amp;nbsp; # \u0026lt;strong\u0026gt;Android 实现 HttpClient 请求Https** 如题，默认下，HttpClient是不能请求Https的，需要自己获取 \u0026lt;div class=\u0026#34;dp-highlighter bg_java\u0026#34; style=\u0026#34;color: #000000;\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;tools\u0026#34; style=\u0026#34;color: silver;\u0026#34;\u0026gt; **[java]** [view plain](http://blog.csdn.net/heynine/article/details/8279304#)[copy](http://blog.csdn.net/heynine/article/details/8279304#) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; SET_CONNECTION_TIMEOUT = \u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #c00000;\u0026#34;\u0026gt;5\u0026lt;/span\u0026gt; * \u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #c00000;\u0026#34;\u0026gt;1000\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; SET_SOCKET_TIMEOUT = \u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #c00000;\u0026#34;\u0026gt;20\u0026lt;/span\u0026gt; * \u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #c00000;\u0026#34;\u0026gt;1000\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; HttpClient getNewHttpClient() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; trustStore.load(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; SSLSocketFactory sf = \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; MySSLSocketFactory(trustStore); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; HttpParams params = \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; BasicHttpParams(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; HttpConnectionParams.setConnectionTimeout(params, \u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #c00000;\u0026#34;\u0026gt;10000\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; HttpConnectionParams.setSoTimeout(params, \u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #c00000;\u0026#34;\u0026gt;10000\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; SchemeRegistry registry = \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; SchemeRegistry(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; registry.register(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; Scheme(\u0026lt;span class=\u0026#34;string\u0026#34; style=\u0026#34;color: blue;\u0026#34;\u0026gt;\u0026amp;#8220;http\u0026amp;#8221;\u0026lt;/span\u0026gt;, PlainSocketFactory.getSocketFactory(), \u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #c00000;\u0026#34;\u0026gt;80\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; registry.register(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; Scheme(\u0026lt;span class=\u0026#34;string\u0026#34; style=\u0026#34;color: blue;\u0026#34;\u0026gt;\u0026amp;#8220;https\u0026amp;#8221;\u0026lt;/span\u0026gt;, sf, \u0026lt;span class=\u0026#34;number\u0026#34; style=\u0026#34;color: #c00000;\u0026#34;\u0026gt;443\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; ClientConnectionManager ccm = \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; ThreadSafeClientConnManager(params, registry); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; HttpConnectionParams.setConnectionTimeout(params, SET_CONNECTION_TIMEOUT); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; HttpConnectionParams.setSoTimeout(params, SET_SOCKET_TIMEOUT); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; HttpClient client = \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; DefaultHttpClient(ccm, params); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; client; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; } \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; DefaultHttpClient(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; } \u0026lt;/span\u0026gt; ** \u0026lt;span style=\u0026#34;color: #000000;\u0026#34;\u0026gt;下面是MySSLSocketFactory类\u0026lt;/span\u0026gt; \u0026lt;div class=\u0026#34;dp-highlighter bg_java\u0026#34; style=\u0026#34;color: #000000;\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;bar\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;tools\u0026#34; style=\u0026#34;color: silver;\u0026#34;\u0026gt; \u0026lt;b\u0026gt;[java]** [view plain](http://blog.csdn.net/heynine/article/details/8279304#)[copy](http://blog.csdn.net/heynine/article/details/8279304#) \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt;\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; MySSLSocketFactory \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; SSLSocketFactory { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; SSLContext sslContext = SSLContext.getInstance(\u0026lt;span class=\u0026#34;string\u0026#34; style=\u0026#34;color: blue;\u0026#34;\u0026gt;\u0026amp;#8220;TLS\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; MySSLSocketFactory(KeyStore truststore) \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;throws\u0026lt;/span\u0026gt; NoSuchAlgorithmException, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; KeyManagementException, KeyStoreException, UnrecoverableKeyException { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;super\u0026lt;/span\u0026gt;(truststore); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; TrustManager tm = \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; X509TrustManager() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; checkClientTrusted(X509Certificate[] chain, String authType) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;throws\u0026lt;/span\u0026gt; CertificateException { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; checkServerTrusted(X509Certificate[] chain, String authType) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;throws\u0026lt;/span\u0026gt; CertificateException { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; X509Certificate[] getAcceptedIssuers() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; }; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; sslContext.init(\u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; TrustManager[] { tm }, \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34; style=\u0026#34;color: #646464;\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; Socket createSocket(Socket socket, String host, \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; port, \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; autoClose) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;throws\u0026lt;/span\u0026gt; IOException, UnknownHostException { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;annotation\u0026#34; style=\u0026#34;color: #646464;\u0026#34;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; Socket createSocket() \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;throws\u0026lt;/span\u0026gt; IOException { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;keyword\u0026#34; style=\u0026#34;font-weight: bold; color: #006699;\u0026#34;\u0026gt;return\u0026lt;/span\u0026gt; sslContext.getSocketFactory().createSocket(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026#34;color: black;\u0026#34;\u0026gt; } \u0026lt;/span\u0026gt; 通过上面的方法获得HttpClient对象就可以请求Https了 转自：http://blog.csdn.net/heynine/article/details/8279304 ","permalink":"https://blog.zdltech.com/posts/android-https%E8%AF%A6%E8%A7%A3/","summary":"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e最近有一个跟Https相关的问题需要解决，因此花时间学习了一下Android平台Https的使用，同时也看了一些Https的原理，这里分享一下学习心得。\u003c/p\u003e\n\u003ch2 id=\"https原理\"\u003eHTTPS原理\u003c/h2\u003e\n\u003cp\u003eHTTPS(Hyper Text Transfer Protocol Secure)，是一种基于SSL/TLS的HTTP，所有的HTTP数据都是在SSL/TLS协议封装之上进行传输的。HTTPS协议是在HTTP协议的基础上，添加了SSL/TLS握手以及数据加密传输，也属于应用层协议。所以，研究HTTPS协议原理，最终其实就是研究SSL/TLS协议。\u003c/p\u003e\n\u003ch3 id=\"ssltls协议作用\"\u003eSSL/TLS协议作用\u003c/h3\u003e\n\u003cp\u003e不使用SSL/TLS的HTTP通信，就是不加密的通信，所有的信息明文传播，带来了三大风险：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e窃听风险：第三方可以获知通信内容。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e篡改风险：第三方可以修改通知内容。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e冒充风险：第三方可以冒充他人身份参与通信。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eSSL/TLS协议是为了解决这三大风险而设计的，希望达到：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e所有信息都是加密传输，第三方无法窃听。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e具有校验机制，一旦被篡改，通信双方都会立刻发现。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e配备身份证书，防止身份被冒充。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"基本的运行过程\"\u003e基本的运行过程\u003c/h3\u003e\n\u003cp\u003eSSL/TLS协议的基本思路是采用公钥加密法，也就是说，客户端先向服务器端索要公钥，然后用公钥加密信息，服务器收到密文后，用自己的私钥解密。但是这里需要了解两个问题的解决方案。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e如何保证公钥不被篡改？\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e解决方法：将公钥放在数字证书中。只要证书是可信的，公钥就是可信的。\u003c/p\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e公钥加密计算量太大，如何减少耗用的时间？\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e解决方法：每一次对话(session)，客户端和服务器端都生成一个“对话密钥”(session key)，用它来加密信息。由于“对话密钥”是对称加密，所以运算速度非常快，而服务器公钥只用于加密“对话密钥”本身，这样就减少了加密运算的消耗时间。\u003c/p\u003e\n\u003cp\u003e因此，SSL/TLS协议的基本过程是这样的：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e客户端向服务器端索要并验证公钥。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e双方协商生成“对话密钥”。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e双方采用“对话密钥”进行加密通信。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e上面过程的前两布，又称为“握手阶段”。\u003c/p\u003e\n\u003ch3 id=\"握手阶段的详细过程\"\u003e握手阶段的详细过程\u003c/h3\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img0.tuicool.com/NneYrq.png\"\u003e\u003c/p\u003e\n\u003cp\u003e“握手阶段”涉及四次通信，需要注意的是，“握手阶段”的所有通信都是明文的。\u003c/p\u003e\n\u003ch4 id=\"客户端发出请求clienthello\"\u003e客户端发出请求（ClientHello）\u003c/h4\u003e\n\u003cp\u003e首先，客户端（通常是浏览器）先向服务器发出加密通信的请求，这被叫做ClientHello请求。在这一步中，客户端主要向服务器提供以下信息：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e支持的协议版本，比如TLS 1.0版\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e一个客户端生成的随机数，稍后用于生成“对话密钥”。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e支持的加密方法，比如RSA公钥加密。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e支持的压缩方法。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e这里需要注意的是，客户端发送的信息之中不包括服务器的域名。也就是说，理论上服务器只能包含一个网站，否则会分不清应用向客户端提供哪一个网站的数字证书。这就是为什么通常一台服务器只能有一张数字证书的原因。\u003c/p\u003e\n\u003ch4 id=\"服务器回应serverhello\"\u003e服务器回应（ServerHello）\u003c/h4\u003e\n\u003cp\u003e服务器收到客户端请求后，向客户端发出回应，这叫做ServerHello。服务器的回应包含以下内容：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e确认使用的加密通信协议版本，比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致，服务器关闭加密通信。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e一个服务器生成的随机数，稍后用于生成“对话密钥”。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e确认使用的加密方法，比如RSA公钥加密。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e服务器证书。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e除了上面这些信息，如果服务器需要确认客户端的身份，就会再包含一项请求，要求客户端提供“客户端证书”。比如，金融机构往往只允许认证客户连入自己的网络，就会向正式客户提供USB密钥，里面就包含了一张客户端证书。\u003c/p\u003e\n\u003ch4 id=\"客户端回应\"\u003e客户端回应\u003c/h4\u003e\n\u003cp\u003e客户端收到服务器回应以后，首先验证服务器证书。如果证书不是可信机构颁发，或者证书中的域名与实际域名不一致，或者证书已经过期，就会向访问者显示一个警告，由其选择是否还要继续通信。\u003c/p\u003e\n\u003cp\u003e如果证书没有问题，客户端就会从证书中取出服务器的公钥。然后，向服务器发送下面三项消息。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e一个随机数。该随机数用服务器公钥加密，防止被窃听。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e编码改变通知，表示随后的信息都将用双方商定的加密方法和密钥发送。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e客户端握手结束通知，表示客户端的握手阶段已经结束。这一项通常也是前面发送的所有内容的hash值，用来供服务器校验。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e上面第一项随机数，是整个握手阶段出现的第三个随机数，又称“pre-master key”。有了它以后，客户端和服务器就同时有了三个随机数，接着双方就用事先商定的加密方法，各自生成本次会话所用的同一把“会话密钥”。\u003c/p\u003e\n\u003ch4 id=\"服务器的最后回应\"\u003e服务器的最后回应\u003c/h4\u003e\n\u003cp\u003e服务器收到客户端的第三个随机数pre-master key之后，计算生成本次会话所用的“会话密钥”。然后，向客户端最后发送下面信息。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e编码改变通知，表示随后的信息都将用双方商定的加密方法和密钥发送。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e服务器握手结束通知，表示服务器的握手阶段已经结束。这一项同时也是前面发生的所有内容的hash值，用来供客户端校验。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"握手结束\"\u003e握手结束\u003c/h4\u003e\n\u003cp\u003e至此，整个握手阶段全部结束。接下来，客户端与服务器进入加密通信，就完全是使用普通的HTTP协议，只不过用“会话密钥”加密内容。\u003c/p\u003e\n\u003ch2 id=\"服务器基于nginx搭建https虚拟站点\"\u003e服务器基于Nginx搭建HTTPS虚拟站点\u003c/h2\u003e\n\u003cp\u003e之前一篇文章详细介绍了在服务器端如何生成SSL证书，并基于Nginx搭建HTTPS服务器，链接：Nginx搭建HTTPS服务器\u003c/p\u003e\n\u003ch2 id=\"android实现https通信\"\u003eAndroid实现HTTPS通信\u003c/h2\u003e\n\u003cp\u003e由于各种原因吧，这里使用HttpClicent类讲解一下Android如何建立HTTPS连接。代码demo如下。\u003c/p\u003e\n\u003cp\u003eMainActivity.java\u003c/p\u003e\n\u003cdiv\u003e\n  ```\n\u003cspan class=\"keyword\" style=\"font-weight: bold;\"\u003epackage\u003c/span\u003e com.example.photocrop;\n\u003cp\u003e\u003cspan class=\"keyword\" style=\"font-weight: bold;\"\u003eimport\u003c/span\u003e java.io.BufferedReader;\n\u003cspan class=\"keyword\" style=\"font-weight: bold;\"\u003eimport\u003c/span\u003e java.io.InputStreamReader;\u003c/p\u003e","title":"Android HTTPS详解"},{"content":"自从GoogleI/O之后，很多开发者开始转向使用android studio开发项目，但是每当选择check updates的时候你总是会得到一个失败结果：Connection failed. Please check your network connection and try again 。很明显，我们生活在围城里面的人又有特殊待遇了。 网上找了一下解决办法，都说用代理，我用goagent试了一下好像不是很成功，后来发现可以配置一个更新地址来处理，方法如下：\n我是用Mac OS的 ，\n选择你的android studio.app\n显示包内容\n打开Content/Info.plist 文件找到 VMOptions 在内容里面增加以下几个参数\n-Djava.net.preferIPv4Stack=true\n-Didea.updates.url=http://dl.google.com/android/studio/patches/updates.xml\n-Didea.patches.url=http://dl.google.com/android/studio/patches/\n如图：\n保存，如果你的android studio是开着的要重启一下。\n然后检查更新，一切搞定。\n如果你是Windows平台,这个文件在你android studio下面的/bin/studio.exe.vmoptions。\n转载:http://www.cnblogs.com/mudoot/p/android_studio_check_updates.html\nAndroid Studio更新升级方法 自从2013 Google I/O大会之后，笔者就将android ide开发工具从eclipse迁移到Android Studio了，android studio一直在更新完善，为了与时俱进，我们当然要将工具更新到最新版本啦！其实更新本来是很简单，只要从Android Studio Help菜单中选择Check for Update即可：\n但是你会收到如下提示：\n小伙伴们这是为什么呢？因为“伟大的墙”！！！下面介绍笔者的解决方法。\n1.获取自己电脑上安装的Android Studio 的Build Number\n如果已经安装了Android Studio，那么我们只需要增量更新即可。所以下载更新jar包即可，首先要知道自己当前的Android Studio的版本号，Help-》About\n注意Build #AI-130.745757，比如笔者的版本号为 130.745757\n2.查询目前Android Studio的最新版本号是多少\n(1)访问网站http://tools.android.com/recent可查看最新的Build Number，或者\n(2)访问https://dl.google.com/android/studio/patches/updates.xml查看最新的版本号，目前笔者获得的最新xml数据如下\n从返回的xml数据可知目前最新的Build Number 为132.809981\n3.下载增量更新包\n获得版本号，我们就可以下载更新包了，比如笔者的更新包下载地址为\nhttps://dl.google.com/android/studio/patches/AI-130.745757-132.809981-patch-win.jar\n请根据自己的Android Studio的build number下载相应的更新包，格式为AI-FROM-TO-patch-win.jar，其中FROM为你当前android studio的build number，TO为最新的android studio 的build number\n4.安装更新包\n将下载的更新包拷贝至Android Studio 的安装目录，比如笔者的安装目录为D:\\android-studio，将下载的jar拷贝到该目录下\n然后打开命令行提示符，键入如下命令\n注意最后一句命令\n**[java]** [view plain](http://blog.csdn.net/hil2000/article/details/11395485#)[copy](http://blog.csdn.net/hil2000/article/details/11395485#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;ellij.updater.Runner install . \u0026lt;/span\u0026gt; 最后的点”.”代表当前安装到当前目录，安装完毕后，你可以重新启动Android Studio，然后Help-》about查看是不是更新到0.2.7了！\n转自：http://blog.csdn.net/hil2000/article/details/11395485\n","permalink":"https://blog.zdltech.com/posts/android-studio-%E8%87%AA%E5%8A%A8%E6%9B%B4%E6%96%B0%E5%A4%B1%E8%B4%A5%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/","summary":"\u003cp\u003e自从GoogleI/O之后，很多开发者开始转向使用android studio开发项目，但是每当选择check updates的时候你总是会得到一个失败结果：Connection failed. Please check your network connection and try again 。很明显，我们生活在围城里面的人又有特殊待遇了。  网上找了一下解决办法，都说用代理，我用goagent试了一下好像不是很成功，后来发现可以配置一个更新地址来处理，方法如下：\u003c/p\u003e\n\u003cp\u003e我是用Mac OS的 ，\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e选择你的android studio.app\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e显示包内容\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e打开Content/Info.plist 文件找到 \u003ckey\u003eVMOptions\u003c/key\u003e 在内容里面增加以下几个参数\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e-Djava.net.preferIPv4Stack=true\u003cbr\u003e\n-Didea.updates.url=http://dl.google.com/android/studio/patches/updates.xml\u003cbr\u003e\n-Didea.patches.url=http://dl.google.com/android/studio/patches/\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e如图：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnitblog.com/blog/147876/201310/26162523-a2501563f64449f4a00f6bd357d7ec4e.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e保存，如果你的android studio是开着的要重启一下。\u003c/p\u003e\n\u003cp\u003e然后检查更新，一切搞定。\u003c/p\u003e\n\u003cp\u003e如果你是Windows平台,这个文件在你android studio下面的/bin/studio.exe.vmoptions。\u003c/p\u003e\n\u003cp\u003e转载:http://www.cnblogs.com/mudoot/p/android_studio_check_updates.html\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch1 id=\"android-studio更新升级方法\"\u003e\u003cstrong\u003eAndroid Studio更新升级方法\u003c/strong\u003e\u003c/h1\u003e\n\u003cp\u003e自从2013 Google I/O大会之后，笔者就将android ide开发工具从eclipse迁移到Android Studio了，android studio一直在更新完善，为了与时俱进，我们当然要将工具更新到最新版本啦！其实更新本来是很简单，只要从Android Studio Help菜单中选择Check for Update即可：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20130908210215078?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGlsMjAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e但是你会收到如下提示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20130908210228359?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGlsMjAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e小伙伴们这是为什么呢？因为“伟大的墙”！！！下面介绍笔者的解决方法。\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #3333ff;\"\u003e\u003cstrong\u003e1.获取自己电脑上安装的Android Studio 的Build Number\u003c/strong\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e如果已经安装了Android Studio，那么我们只需要增量更新即可。所以下载更新jar包即可，首先要知道自己当前的Android Studio的版本号，Help-》About\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20130908210500343?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGlsMjAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003cbr\u003e\n注意Build  #AI-130.745757，比如笔者的版本号为 130.745757\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #3333ff;\"\u003e\u003cstrong\u003e2.查询目前Android Studio的最新版本号是多少\u003c/strong\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e(1)访问网站\u003ca href=\"http://tools.android.com/recent\"\u003ehttp://tools.android.com/recent\u003c/a\u003e可查看最新的Build Number，或者\u003cbr\u003e\n(2)访问\u003ca href=\"https://dl.google.com/android/studio/patches/updates.xml\"\u003ehttps://dl.google.com/android/studio/patches/updates.xml\u003c/a\u003e查看最新的版本号，目前笔者获得的最新xml数据如下\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20130908211003250?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGlsMjAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e从返回的xml数据可知目前最新的Build Number 为132.809981\u003c/p\u003e","title":"android studio 自动更新失败解决办法"},{"content":" 最近做了个项目 需要类似与excel的数据显示效果 就是最左边的已列只能上下滑动 最顶部的一行只能左右滑动！于是查了些资料做了个长的还才不多的效果 和大家分享分享！ 附上demo源码 - [TestTableShow.zip](http://dl.iteye.com/topics/download/ae68552b-0d39-3015-9202-cf143b287782) (689.1 KB) 转自：http://793101503-qq-com.iteye.com/blog/1678183 ","permalink":"https://blog.zdltech.com/posts/android%E4%B8%8A%E7%B1%BB%E4%BC%BC%E4%B8%8Eexcel%E7%9A%84%E6%95%88%E6%9E%9C/","summary":"\u003cdiv id=\"blog_content\" class=\"blog_content\" style=\"color: #000000;\"\u003e\n\u003cpre\u003e\u003ccode\u003e最近做了个项目 需要类似与excel的数据显示效果 就是最左边的已列只能上下滑动 最顶部的一行只能左右滑动！于是查了些资料做了个长的还才不多的效果 和大家分享分享！\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://dl.iteye.com/upload/attachment/0073/8022/01703729-fbff-3276-a951-2afac63175eb.png\"\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e附上demo源码\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv class=\"attachments\" style=\"color: #000000;\"\u003e\n\u003cpre\u003e\u003ccode\u003e- [TestTableShow.zip](http://dl.iteye.com/topics/download/ae68552b-0d39-3015-9202-cf143b287782) (689.1 KB)\n\n\n\n\n\n转自：http://793101503-qq-com.iteye.com/blog/1678183\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"android上类似与excel的效果"},{"content":"/**\nDemoListView @version 1.0 @author ＷｕＸｘ @Time 2014-08-15 / / 一、实现功能： （1）当列数较多，超过一屏时，整体视图支持左右滑动； （2）当单列数据较长，可以通过拖拽表头改变列宽； （3）为表格中每一项添加点击事件。 \u0026amp;nbsp; 二、效果图： \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;图片有些小。\u0026lt;/span\u0026gt; 三、搭建布局： 四、主要代码： 由易到难顺序：MyOnItemClickListener、MyListView、MyAdapter （1）MyOnItemClickListener，回调函数机制。由MyAdapter调用。 **[java]** [view plain](http://blog.csdn.net/hello1234123/article/details/38590073#)[copy](http://blog.csdn.net/hello1234123/article/details/38590073#)[print](http://blog.csdn.net/hello1234123/article/details/38590073#)[?](http://blog.csdn.net/hello1234123/article/details/38590073#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-weight: normal;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; MyOnItemClickListener { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; OnItemClickListener(View view,\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; line,\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; row,\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; id); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; （2）MyListView，表头滑动事件，滑动事件会与HorizontalScrollView的滑动冲突，解决方案：在MotionEvent.ACTION_DOWN，设置一下HorizontalScrollView的touch不监听就好了。 **[java]** [view plain](http://blog.csdn.net/hello1234123/article/details/38590073#)[copy](http://blog.csdn.net/hello1234123/article/details/38590073#)[print](http://blog.csdn.net/hello1234123/article/details/38590073#)[?](http://blog.csdn.net/hello1234123/article/details/38590073#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-weight: normal;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * Set TouchListener on tile ,if ACTION_MOVE is called ,the listView will change its columnWidth\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setTitleTouchListener(View v) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;i\u0026lt;titles.length;i++){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; column = i; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; v.findViewById(titles[i]).setOnTouchListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnTouchListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x1 = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isMoved = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@SuppressLint\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;NewApi\u0026amp;#8221;\u0026lt;/span\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-weight: normal;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//two teps\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 1.when touch down and move, change the width of head;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 2.touch up ,change the width of the columns ;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (event.getAction() == MotionEvent.ACTION_DOWN) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; x = (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getX(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; hs.requestDisallowInterceptTouchEvent(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (event.getAction() == MotionEvent.ACTION_MOVE) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; x1 = (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getX(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; width= v.getMeasuredWidth()+(x1-x)+t; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(t!=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; t=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; v.setLayoutParams(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearLayout.LayoutParams(width,v.getMeasuredHeight())); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; x = x1; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; isMoved = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(event.getAction()==MotionEvent.ACTION_UP){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(isMoved) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; adapter.setColumnWidth(column, width); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(event.getAction()==MotionEvent.ACTION_CANCEL){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(isMoved) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; adapter.setColumnWidth(column, width); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; （3）MyAdapter，这个有点小麻烦。参考SimpleAdapter来写的，不过略有不同。与SimpleAdapter重复部分不再赘述。详细内容请下载源代码看吧。 数据以及点击事件的添加，其实是很简单的。 **[java]** [view plain](http://blog.csdn.net/hello1234123/article/details/38590073#)[copy](http://blog.csdn.net/hello1234123/article/details/38590073#)[print](http://blog.csdn.net/hello1234123/article/details/38590073#)[?](http://blog.csdn.net/hello1234123/article/details/38590073#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; bindView(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View v) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; mFrom.length; i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; line = position; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; row = i; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; TextView txt = (TextView) v.findViewById(mTo[i]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; txt.setText((String) mData.get(position).get(mFrom[i])); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; txt.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (MyAdapter.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.listener != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; MyAdapter.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.listener.OnItemClickListener(v, line, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; row, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; 修改列宽，当MyListView滑动表头时修改表格主体的列宽。 **[java]** [view plain](http://blog.csdn.net/hello1234123/article/details/38590073#)[copy](http://blog.csdn.net/hello1234123/article/details/38590073#)[print](http://blog.csdn.net/hello1234123/article/details/38590073#)[?](http://blog.csdn.net/hello1234123/article/details/38590073#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setColumnWidth(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; column, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; viewList.size(); i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; View v = viewList.get(i); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; TextView txt = (TextView) v.findViewById(mTo[column]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; txt.setLayoutParams(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearLayout.LayoutParams(width, txt \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .getHeight())); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; 好吧，问题来了。当使用此方法进行显示时，当你滑动表头修改列宽，你再下拉查看未显示的数据，这个时候惊喜来了，空白？嗯是的。发现有一行的部分数据项是空白的，当你继续下拉，你会发现这个空白会循环的出现在你屏幕上，也许你猜到了这其中的原因。我们可以举一个例子，假如你的ListView第一次加载出来，屏幕上显示的item数量为23个，但是，getView调用了24次，当然，我这么说是不负责的，好吧，准确的说是生成了24个View（就是你的item）,why 24?因为有一个影藏的。第24个View的产生是因为安卓内部有一个recycler机制，实现了View的循环使用，显而易见，23个是无法实现循环的。这里我借鉴网上的一张图，大家就一目了然了。 这时，聪明的你发现了，我们没有涉及到如何在getView中找出影藏的View。其实这个问题我也没有特别好的解决方案，目前我采取的方案，可以在把空白问题出现的概率控制在比较小的范围。这种方案是通过5、6次调试通过log日志得出的，有一定的局限性。 通过getView给出的参数，position、parent以及用来存储视图的ViewList，进行判断影藏的View。代码如下： **[java]** [view plain](http://blog.csdn.net/hello1234123/article/details/38590073#)[copy](http://blog.csdn.net/hello1234123/article/details/38590073#)[print](http://blog.csdn.net/hello1234123/article/details/38590073#)[?](http://blog.csdn.net/hello1234123/article/details/38590073#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(lastViewsSize==viewList.size()){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(position!=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(position==parent.getChildCount()\u0026amp;\u0026amp;position==viewList.size()-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setWidth(v); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; lastViewsSize = viewList.size(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; 大概描述一下： 首先申明，当ListView在一个屏幕上显示23个时，它并不只是调用24次Adapter的getView，正常情况应该是23（或者说是24，这个值我不能确定）的3、4倍，为什么有这么多呢？其中有一次是用于确定布局的宽度和高度用于draw的，其他的我不清楚。 但是，可以确定当最后一次调用getView时是用于显示的，我们如何确定这一次呢，通过log日志可以看出，此时viewList.size()已经为常值，所以第一个判断条件便是如此产生的，当然我们需要排除掉position为0的干扰，最后我们找出我们影藏的View，然后setWidth，游戏就这样结束了。我觉得有必要把调试过程中log日志也贴出来： 源代码：http://download.csdn.net/detail/hello1234123/7765011 \u0026amp;nbsp; 转自：http://blog.csdn.net/hello1234123/article/details/38590073 ","permalink":"https://blog.zdltech.com/posts/android%E5%AE%9E%E7%8E%B0%E7%B1%BB%E4%BC%BCexcel%E6%98%BE%E7%A4%BA%E6%95%B0%E6%8D%AE%E5%8A%9F%E8%83%BD%E6%94%AF%E6%8C%81%E6%8B%96%E5%8A%A8%E6%94%B9%E5%8F%98%E5%88%97%E5%AE%BDv-1-0/","summary":"\u003cp\u003e\u003cspan style=\"color: #ffcc33;\"\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDemoListView\u003c/li\u003e\n\u003cli\u003e@version 1.0\u003c/li\u003e\n\u003cli\u003e@author ＷｕＸｘ\u003c/li\u003e\n\u003cli\u003e@Time 2014-08-15\u003c/li\u003e\n\u003cli\u003e\u003cem\u003e/\n/\u003c/em\u003e\u003c/span\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch6 id=\"一实现功能\"\u003e\u003ca style=\"color: #ca0000;\" name=\"t0\"\u003e\u003c/a\u003e一、实现功能：\u003c/h6\u003e\n\u003ch6\u003e\u003ca style=\"color: #ca0000;\" name=\"t1\"\u003e\u003c/a\u003e\u003c/h6\u003e\n\u003cpre\u003e\u003ccode\u003e（1）当列数较多，超过一屏时，整体视图支持左右滑动；\n\n\n\n\n\n（2）当单列数据较长，可以通过拖拽表头改变列宽；\n\n\n\n\n\n（3）为表格中每一项添加点击事件。\n\n\n\n\n\n\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch6 id=\"二效果图\"\u003e\u003ca style=\"color: #ca0000;\" name=\"t2\"\u003e\u003c/a\u003e二、效果图：\u003c/h6\u003e\n\u003ch6\u003e\u003ca style=\"color: #ca0000;\" name=\"t3\"\u003e\u003c/a\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140815205047425?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGVsbG8xMjM0MTIz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/h6\u003e\n\u003ch6\u003e\u003ca style=\"color: #ca0000;\" name=\"t4\"\u003e\u003c/a\u003e\u003c/h6\u003e\n\u003ch6\u003e\u003ca style=\"color: #ca0000;\" name=\"t5\"\u003e\u003c/a\u003e\u003c/h6\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;图片有些小。\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch6 id=\"三搭建布局\"\u003e\u003ca style=\"color: #ca0000;\" name=\"t6\"\u003e\u003c/a\u003e三、搭建布局：\u003c/h6\u003e\n\u003ch6\u003e\u003ca style=\"color: #ca0000;\" name=\"t7\"\u003e\u003c/a\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140815205338589?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGVsbG8xMjM0MTIz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/h6\u003e\n\u003ch6 id=\"四主要代码\"\u003e\u003ca style=\"color: #ca0000;\" name=\"t8\"\u003e\u003c/a\u003e四、主要代码：\u003c/h6\u003e\n\u003ch6\u003e\u003ca style=\"color: #ca0000;\" name=\"t9\"\u003e\u003c/a\u003e\u003c/h6\u003e\n\u003ch6 id=\"由易到难顺序myonitemclicklistenermylistviewmyadapter\"\u003e\u003ca style=\"color: #ca0000;\" name=\"t10\"\u003e\u003c/a\u003e由易到难顺序：MyOnItemClickListener、MyListView、MyAdapter\u003c/h6\u003e\n\u003ch6 id=\"1myonitemclicklistener回调函数机制由myadapter调用\"\u003e（1）MyOnItemClickListener，回调函数机制。由MyAdapter调用。\u003c/h6\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/hello1234123/article/details/38590073#)[copy](http://blog.csdn.net/hello1234123/article/details/38590073#)[print](http://blog.csdn.net/hello1234123/article/details/38590073#)[?](http://blog.csdn.net/hello1234123/article/details/38590073#)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-weight: normal;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; MyOnItemClickListener {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; OnItemClickListener(View view,\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; line,\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; row,\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; id);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003ch6 id=\"2mylistview表头滑动事件滑动事件会与horizontalscrollview的滑动冲突解决方案在motioneventaction_down设置一下horizontalscrollview的touch不监听就好了\"\u003e（2）MyListView，表头滑动事件，滑动事件会与HorizontalScrollView的滑动冲突，解决方案：在MotionEvent.ACTION_DOWN，设置一下HorizontalScrollView的touch不监听就好了。\u003c/h6\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/hello1234123/article/details/38590073#)[copy](http://blog.csdn.net/hello1234123/article/details/38590073#)[print](http://blog.csdn.net/hello1234123/article/details/38590073#)[?](http://blog.csdn.net/hello1234123/article/details/38590073#)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-weight: normal;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * Set TouchListener on tile ,if ACTION_MOVE is called ,the listView will change its columnWidth\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * */\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setTitleTouchListener(View v) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;i\u0026lt;titles.length;i++){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; column = i;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            v.findViewById(titles[i]).setOnTouchListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnTouchListener() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x1 = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isMoved = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; t = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@SuppressLint\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;NewApi\u0026amp;#8221;\u0026lt;/span\u0026gt;)\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-weight: normal;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;           \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onTouch(View v, MotionEvent event) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//two teps\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 1.when touch down and move, change the width of head;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 2.touch up ,change the width of the columns ;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (event.getAction() == MotionEvent.ACTION_DOWN) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        x = (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getX();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        hs.requestDisallowInterceptTouchEvent(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (event.getAction() == MotionEvent.ACTION_MOVE) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        x1 = (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) event.getX();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        width= v.getMeasuredWidth()+(x1-x)+t;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(t!=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                            t=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        v.setLayoutParams(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearLayout.LayoutParams(width,v.getMeasuredHeight()));  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        x = x1;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        isMoved = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(event.getAction()==MotionEvent.ACTION_UP){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(isMoved)  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                            adapter.setColumnWidth(column, width);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(event.getAction()==MotionEvent.ACTION_CANCEL){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(isMoved)  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                            adapter.setColumnWidth(column, width);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            });  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003ch6 id=\"3myadapter这个有点小麻烦参考simpleadapter来写的不过略有不同与simpleadapter重复部分不再赘述详细内容请下载源代码看吧\"\u003e（3）MyAdapter，这个有点小麻烦。参考SimpleAdapter来写的，不过略有不同。与SimpleAdapter重复部分不再赘述。详细内容请下载源代码看吧。\u003c/h6\u003e\n\u003ch6 id=\"数据以及点击事件的添加其实是很简单的\"\u003e数据以及点击事件的添加，其实是很简单的。\u003c/h6\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/hello1234123/article/details/38590073#)[copy](http://blog.csdn.net/hello1234123/article/details/38590073#)[print](http://blog.csdn.net/hello1234123/article/details/38590073#)[?](http://blog.csdn.net/hello1234123/article/details/38590073#)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; bindView(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View v) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; mFrom.length; i++) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; line = position;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; row = i;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            TextView txt = (TextView) v.findViewById(mTo[i]);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            txt.setText((String) mData.get(position).get(mFrom[i]));  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            txt.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (MyAdapter.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.listener != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        MyAdapter.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.listener.OnItemClickListener(v, line,  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                                row, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            });  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003ch6 id=\"修改列宽当mylistview滑动表头时修改表格主体的列宽\"\u003e修改列宽，当MyListView滑动表头时修改表格主体的列宽。\u003c/h6\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/hello1234123/article/details/38590073#)[copy](http://blog.csdn.net/hello1234123/article/details/38590073#)[print](http://blog.csdn.net/hello1234123/article/details/38590073#)[?](http://blog.csdn.net/hello1234123/article/details/38590073#)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setColumnWidth(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; column, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; viewList.size(); i++) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            View v = viewList.get(i);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            TextView txt = (TextView) v.findViewById(mTo[column]);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            txt.setLayoutParams(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearLayout.LayoutParams(width, txt  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    .getHeight()));  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003ch6 id=\"好吧问题来了当使用此方法进行显示时当你滑动表头修改列宽你再下拉查看未显示的数据这个时候惊喜来了空白嗯是的发现有一行的部分数据项是空白的当你继续下拉你会发现这个空白会循环的出现在你屏幕上也许你猜到了这其中的原因我们可以举一个例子假如你的listview第一次加载出来屏幕上显示的item数量为23个但是getview调用了24次当然我这么说是不负责的好吧准确的说是生成了24个view就是你的itemwhy-24因为有一个影藏的第24个view的产生是因为安卓内部有一个recycler机制实现了view的循环使用显而易见23个是无法实现循环的这里我借鉴网上的一张图大家就一目了然了\"\u003e好吧，问题来了。当使用此方法进行显示时，当你滑动表头修改列宽，你再下拉查看未显示的数据，这个时候惊喜来了，空白？嗯是的。发现有一行的部分数据项是空白的，当你继续下拉，你会发现这个空白会循环的出现在你屏幕上，也许你猜到了这其中的原因。我们可以举一个例子，假如你的ListView第一次加载出来，屏幕上显示的item数量为23个，但是，getView调用了24次，当然，我这么说是不负责的，好吧，准确的说是生成了24个View（就是你的item）,why 24?因为有一个影藏的。第24个View的产生是因为安卓内部有一个recycler机制，实现了View的循环使用，显而易见，23个是无法实现循环的。这里我借鉴网上的一张图，大家就一目了然了。\u003c/h6\u003e\n\u003ch6\u003e\u003ca style=\"color: #ca0000;\" name=\"t14\"\u003e\u003c/a\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140815223205820?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGVsbG8xMjM0MTIz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/h6\u003e\n\u003ch6 id=\"这时聪明的你发现了我们没有涉及到如何在getview中找出影藏的view其实这个问题我也没有特别好的解决方案目前我采取的方案可以在把空白问题出现的概率控制在比较小的范围这种方案是通过56次调试通过log日志得出的有一定的局限性\"\u003e这时，聪明的你发现了，我们没有涉及到如何在getView中找出影藏的View。其实这个问题我也没有特别好的解决方案，目前我采取的方案，可以在把空白问题出现的概率控制在比较小的范围。这种方案是通过5、6次调试通过log日志得出的，有一定的局限性。\u003c/h6\u003e\n\u003ch6 id=\"通过getview给出的参数positionparent以及用来存储视图的viewlist进行判断影藏的view代码如下\"\u003e\u003ca style=\"color: #ca0000;\" name=\"t17\"\u003e\u003c/a\u003e通过getView给出的参数，position、parent以及用来存储视图的ViewList，进行判断影藏的View。代码如下：\u003c/h6\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/hello1234123/article/details/38590073#)[copy](http://blog.csdn.net/hello1234123/article/details/38590073#)[print](http://blog.csdn.net/hello1234123/article/details/38590073#)[?](http://blog.csdn.net/hello1234123/article/details/38590073#)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(lastViewsSize==viewList.size()){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(position!=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(position==parent.getChildCount()\u0026amp;\u0026amp;position==viewList.size()-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    setWidth(v);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            lastViewsSize = viewList.size();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003ch6\u003e\u003ca style=\"color: #ca0000;\" name=\"t19\"\u003e\u003c/a\u003e\u003c/h6\u003e\n\u003ch6 id=\"大概描述一下\"\u003e\u003ca style=\"color: #ca0000;\" name=\"t20\"\u003e\u003c/a\u003e大概描述一下：\u003c/h6\u003e\n\u003ch6 id=\"首先申明当listview在一个屏幕上显示23个时它并不只是调用24次adapter的getview正常情况应该是23或者说是24这个值我不能确定的34倍为什么有这么多呢其中有一次是用于确定布局的宽度和高度用于draw的其他的我不清楚\"\u003e首先申明，当ListView在一个屏幕上显示23个时，它并不只是调用24次Adapter的getView，正常情况应该是23（或者说是24，这个值我不能确定）的3、4倍，为什么有这么多呢？其中有一次是用于确定布局的宽度和高度用于draw的，其他的我不清楚。\u003c/h6\u003e\n\u003ch6 id=\"但是可以确定当最后一次调用getview时是用于显示的我们如何确定这一次呢通过log日志可以看出此时viewlistsize已经为常值所以第一个判断条件便是如此产生的当然我们需要排除掉position为0的干扰最后我们找出我们影藏的view然后setwidth游戏就这样结束了我觉得有必要把调试过程中log日志也贴出来\"\u003e但是，可以确定当最后一次调用getView时是用于显示的，我们如何确定这一次呢，通过log日志可以看出，此时viewList.size()已经为常值，所以第一个判断条件便是如此产生的，当然我们需要排除掉position为0的干扰，最后我们找出我们影藏的View，然后setWidth，游戏就这样结束了。我觉得有必要把调试过程中log日志也贴出来：\u003c/h6\u003e\n\u003ch6\u003e\u003ca style=\"color: #ca0000;\" name=\"t23\"\u003e\u003c/a\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140815232448694?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGVsbG8xMjM0MTIz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/h6\u003e\n\u003ch6 id=\"源代码httpdownloadcsdnnetdetailhello12341237765011\"\u003e\u003ca style=\"color: #ca0000;\" name=\"t24\"\u003e\u003c/a\u003e源代码：http://download.csdn.net/detail/hello1234123/7765011\u003c/h6\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026amp;nbsp;\n\n\n\n\n\n转自：http://blog.csdn.net/hello1234123/article/details/38590073\n\u003c/code\u003e\u003c/pre\u003e","title":"Android实现类似Excel显示数据功能（支持拖动改变列宽）v 1.0"},{"content":"本文为那些不错的Android开源项目第五篇——优秀个人和团体篇，主要介绍那些乐于分享并且有一些很不错的开源项目的个人和组织(公司)\n最新内容请访问[AndroidOpenProject@Github](https://github.com/Trinea/android-open-project)，欢迎Star和Fork。 对你有帮助的话，去知乎点个赞让更多人了解：Android 优秀开源项目及特效推荐。\nAndroid开源项目系列汇总已完成，包括： [Android开源项目第一篇——个性化控件(View)篇](http://www.trinea.cn/android/android-open-source-projects-view/) Android开源项目第二篇——工具库篇 Android开源项目第三篇——优秀项目篇 Android开源项目第四篇——开发及测试工具篇 Android开源项目第五篇——优秀个人和团体篇\nFollow大神，深挖大神的项目和following，你会发现很多。长期更新，欢迎大家补充和推荐^_^ **一、个人** **1. JakeWharton 就职于Square** Github地址：https://github.com/JakeWharton 代表作：ActionBarSherlock，Android-ViewPagerIndicator，Nine Old Androids，SwipeToDismissNOA，hugo，butterknife，Android-DirectionalViewPager pidcat另外对square及其他开源项目有很多贡献 博客：http://jakewharton.com/ 绝对牛逼的大神，项目主要集中在Android版本兼容，ViewPager及开发工具上.\n**2. Chris Banes** Github地址：https://github.com/chrisbanes 代表作：ActionBar-PullToRefresh，PhotoView，Android-BitmapCache，Android-PullToRefresh 博客：http://chris.banes.me/\n**3. Koushik Dutta就职于ClockworkMod** Github地址：https://github.com/koush 代表作：Superuser，AndroidAsync，UrlImageViewHelper，ion, 另外对https://github.com/CyanogenMod的开源项目有很多贡献\n博客：[http://koush.com/](http://koush.com/) **4. Simon Vig** Github地址：https://github.com/SimonVT 代表作：android-menudrawer，MessageBar\n博客：[http://simonvt.net/](http://simonvt.net/) **5. Manuel Peinado** Github地址：https://github.com/ManuelPeinado 代表作：FadingActionBar，GlassActionBar，RefreshActionItem，QuickReturnHeader\n**6. Emil Sjölander** Github地址：https://github.com/emilsjolander 代表作：StickyListHeaders，sprinkles，android-FlipView\n博客：[http://emilsjolander.se/](http://emilsjolander.se/) **7. greenrobot** Github地址：https://github.com/greenrobot 代表作：greenDAO，EventBus 网址：http://greenrobot.de/\n**8. Jeff Gilfelt** Github地址：[https://github.com/jgilfelt](https://github.com/jgilfelt) 代表作：android-mapviewballoons，android-viewbadger，android-actionbarstylegenerator，android-sqlite-asset-helper 网址：http://jeffgilfelt.com\nPs: [ViewServer](https://github.com/romainguy/ViewServer)作者的个人摄影作品[http://www.flickr.com/photos/romainguy](http://www.flickr.com/photos/romainguy)，感觉超赞 **二、组织** 1. Square: Github地址：https://github.com/square 代表作：okhttp、fest-android，android-times-square、picasso、dagger、spoon等等 网址：http://square.github.io/\n有态度有良心的企业，很多不错的分享 **2. Inmite s.r.o.** Github地址：https://github.com/inmite 代表作：android-styled-dialogs，android-grid-wichterle，android-selector-chapek 网址：http://www.inmite.eu/\n","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E7%AC%AC%E4%BA%94%E7%AF%87-%E4%BC%98%E7%A7%80%E4%B8%AA%E4%BA%BA%E5%92%8C%E5%9B%A2%E4%BD%93%E7%AF%87/","summary":"\u003cp\u003e本文为那些不错的Android开源项目第五篇——优秀个人和团体篇，\u003cstrong\u003e主要介绍那些乐于分享并且有一些很不错的开源项目的个人和组织(公司)\u003c/strong\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e最新内容请访问[AndroidOpenProject@Github](https://github.com/Trinea/android-open-project)，欢迎Star和Fork。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e对你有帮助的话，去知乎点个赞让更多人了解：\u003ca href=\"http://www.zhihu.com/question/19804692/answer/21890050\"\u003eAndroid 优秀开源项目及特效推荐\u003c/a\u003e。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  Android开源项目系列汇总已完成，包括：\n\n\n\n\n\n  [Android开源项目第一篇——个性化控件(View)篇](http://www.trinea.cn/android/android-open-source-projects-view/)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-dev-lib/\"\u003eAndroid开源项目第二篇——工具库篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-excellent-project/\"\u003eAndroid开源项目第三篇——优秀项目篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-dev-tool/\"\u003eAndroid开源项目第四篇——开发及测试工具篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-excellent-personal-group/\"\u003eAndroid开源项目第五篇——优秀个人和团体篇\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    Follow大神，深挖大神的项目和following，你会发现很多。长期更新，欢迎大家补充和推荐^_^\n  \n\n  \n  \n\n    \n\n      **一、个人**\n    \n\n    \n    \n\n      **1. JakeWharton 就职于Square**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eGithub地址：\u003ca href=\"https://github.com/JakeWharton\"\u003ehttps://github.com/JakeWharton\u003c/a\u003e\n代表作：\u003ca href=\"https://github.com/JakeWharton/ActionBarSherlock\"\u003eActionBarSherlock\u003c/a\u003e，\u003ca href=\"https://github.com/JakeWharton/Android-ViewPagerIndicator\"\u003eAndroid-ViewPagerIndicator\u003c/a\u003e，\u003ca href=\"https://github.com/JakeWharton/NineOldAndroids\"\u003eNine Old Androids\u003c/a\u003e，\u003ca href=\"https://github.com/JakeWharton/SwipeToDismissNOA\"\u003eSwipeToDismissNOA\u003c/a\u003e，\u003ca href=\"https://github.com/JakeWharton/hugo\"\u003ehugo\u003c/a\u003e，\u003ca href=\"https://github.com/JakeWharton/butterknife\"\u003ebutterknife\u003c/a\u003e，\u003ca href=\"https://github.com/JakeWharton/Android-DirectionalViewPager\"\u003eAndroid-DirectionalViewPager\u003c/a\u003e\n\u003ca href=\"https://github.com/JakeWharton/pidcat\"\u003epidcat\u003c/a\u003e另外对square及其他开源项目有很多贡献\n博客：\u003ca href=\"http://jakewharton.com/\"\u003ehttp://jakewharton.com/\u003c/a\u003e\n绝对牛逼的大神，项目主要集中在Android版本兼容，ViewPager及开发工具上.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e        **2. Chris Banes**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eGithub地址：\u003ca href=\"https://github.com/chrisbanes\"\u003ehttps://github.com/chrisbanes\u003c/a\u003e\n代表作：\u003ca href=\"https://github.com/chrisbanes/ActionBar-PullToRefresh\"\u003eActionBar-PullToRefresh\u003c/a\u003e，\u003ca href=\"https://github.com/chrisbanes/PhotoView\"\u003ePhotoView\u003c/a\u003e，\u003ca href=\"https://github.com/chrisbanes/Android-BitmapCache\"\u003eAndroid-BitmapCache\u003c/a\u003e，\u003ca href=\"https://github.com/chrisbanes/Android-PullToRefresh\"\u003eAndroid-PullToRefresh\u003c/a\u003e\n博客：\u003ca href=\"http://chris.banes.me/\"\u003ehttp://chris.banes.me/\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e          **3. Koushik Dutta就职于ClockworkMod**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eGithub地址：\u003ca href=\"https://github.com/koush\"\u003ehttps://github.com/koush\u003c/a\u003e\n代表作：\u003ca href=\"https://github.com/koush/Superuser\"\u003eSuperuser\u003c/a\u003e，\u003ca href=\"https://github.com/koush/AndroidAsync\"\u003eAndroidAsync\u003c/a\u003e，\u003ca href=\"https://github.com/koush/UrlImageViewHelper\"\u003eUrlImageViewHelper\u003c/a\u003e，\u003ca href=\"https://github.com/koush/ion\"\u003eion\u003c/a\u003e, 另外对\u003ca href=\"https://github.com/CyanogenMod\"\u003ehttps://github.com/CyanogenMod\u003c/a\u003e的开源项目有很多贡献\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e          博客：[http://koush.com/](http://koush.com/)\n        \n\n        \n        \n\n          \n\n            **4. Simon Vig**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eGithub地址：\u003ca href=\"https://github.com/SimonVT\"\u003ehttps://github.com/SimonVT\u003c/a\u003e\n代表作：\u003ca href=\"https://github.com/SimonVT/android-menudrawer\"\u003eandroid-menudrawer\u003c/a\u003e，\u003ca href=\"https://github.com/SimonVT/MessageBar\"\u003eMessageBar\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e            博客：[http://simonvt.net/](http://simonvt.net/)\n          \n\n          \n          \n\n            \n\n              **5. Manuel Peinado**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eGithub地址：\u003ca href=\"https://github.com/ManuelPeinado\"\u003ehttps://github.com/ManuelPeinado\u003c/a\u003e\n代表作：\u003ca href=\"https://github.com/ManuelPeinado/FadingActionBar\"\u003eFadingActionBar\u003c/a\u003e，\u003ca href=\"https://github.com/ManuelPeinado/GlassActionBar\"\u003eGlassActionBar\u003c/a\u003e，\u003ca href=\"https://github.com/ManuelPeinado/RefreshActionItem\"\u003eRefreshActionItem\u003c/a\u003e，\u003ca href=\"https://github.com/ManuelPeinado/QuickReturnHeader\"\u003eQuickReturnHeader\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e                **6. Emil Sjölander**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eGithub地址：\u003ca href=\"https://github.com/emilsjolander\"\u003ehttps://github.com/emilsjolander\u003c/a\u003e\n代表作：\u003ca href=\"https://github.com/emilsjolander/StickyListHeaders\"\u003eStickyListHeaders\u003c/a\u003e，\u003ca href=\"https://github.com/emilsjolander/sprinkles\"\u003esprinkles\u003c/a\u003e，\u003ca href=\"https://github.com/emilsjolander/android-FlipView\"\u003eandroid-FlipView\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e                博客：[http://emilsjolander.se/](http://emilsjolander.se/)\n              \n\n              \n              \n\n                \n\n                  **7. greenrobot**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eGithub地址：\u003ca href=\"https://github.com/greenrobot\"\u003ehttps://github.com/greenrobot\u003c/a\u003e\n代表作：\u003ca href=\"https://github.com/greenrobot/greenDAO\"\u003egreenDAO\u003c/a\u003e，\u003ca href=\"https://github.com/greenrobot/EventBus\"\u003eEventBus\u003c/a\u003e\n网址：\u003ca href=\"http://greenrobot.de/\"\u003ehttp://greenrobot.de/\u003c/a\u003e\u003c/p\u003e","title":"Android开源项目第五篇——优秀个人和团体篇"},{"content":"本文为那些不错的Android开源项目第四篇——开发工具篇，主要介绍Android开发工具和测试工具相关的开源项目。\n最新内容请访问[AndroidOpenProject@Github](https://github.com/Trinea/android-open-project)，欢迎Star和Fork。 对你有帮助的话，去知乎点个赞让更多人了解：Android 优秀开源项目及特效推荐。\nAndroid开源项目系列汇总已完成，包括： [Android开源项目第一篇——个性化控件(View)篇](http://www.trinea.cn/android/android-open-source-projects-view/) Android开源项目第二篇——工具库篇 Android开源项目第三篇——优秀项目篇 Android开源项目第四篇——开发及测试工具篇 Android开源项目第五篇——优秀个人和团体篇\n**1、Buck** facebook开源的Android编译工具，效率是ant的两倍。主要优点在于： (1) 加快编译速度，通过并行利用多核cpu和跟踪不变资源减少增量编译时间实现 (2) 可以在编译系统中生成编译规则而无须另外的系统生成编译规则文件 (3) 编译同时可生成单元测试结果 (4) 既可用于IDE编译也可用于持续集成编译 (5) facebook持续优化中 项目地址：https://github.com/facebook/buck\n**2、Android Maven Plugin** Android Maven插件，可用于对android三方依赖进行管理。在J2EE开发中，maven是非常成熟的依赖库管理工具，可统一管理依赖库。 项目地址：https://github.com/jayway/maven-android-plugin\n**3、Spoon** 可用于android不同机型设备自动化测试，能将应用apk和测试apk运行在不同机器上并生成相应测试报告。 项目地址：https://github.com/square/spoon\n**4、Android FEST** 提供一些列方便的断言，可用于提高编写Android自测代码效率 项目地址：https://github.com/square/fest-android\n**5、SelectorChapek for Android** Android Studio插件，可根据固定文件名格式资源自动生成drawable selectors xml文件。 项目地址：https://github.com/inmite/android-selector-chapek\n**6、Android Resource Navigator** chrome插件，可以方便的查看github上android源码工程的styles.xml和themes.xml。主要功能： (1) 快速打开android styles.xml themes.xml (2) 方便在资源间跳转。styles.xml themes.xml文件中资源链接跳转，可以方便跳转到某个资源 (3) 方便查找某个style和theme。chrome地址栏输入arn+tab+搜索内容回车即可 (4) 自动下载不同分辨率下的drawable (5) 通过映射查找那些不是按照固定命名规则命名的style和theme 项目地址：https://github.com/jgilfelt/android-resource-navigator 示例：https://chrome.google.com/webstore/detail/android-resource-navigato/agoomkionjjbejegcejiefodgbckeebo?hl=en\u0026amp;gl=GB\n**7、Android Action Bar Style Generator** Android ActionBar样式生成器，可在线选择ActionBar样式自动生成所需要的图片资源及xml文件 项目地址：https://github.com/jgilfelt/android-actionbarstylegenerator 在线演示：http://jgilfelt.github.io/android-actionbarstylegenerator/\n**8、ViewServer** 允许app运行在任何手机上都可以用HierarchyViewer查看 项目地址：https://github.com/romainguy/ViewServer\n**9、GridWichterle for Android** 在整个系统上显示一个grid，用来帮助查看应用布局及使得布局更美观，可设置grid网格大小和颜色，android推荐48dp和8dp，可见 Android Design Guidelines – Metrics and Grids 项目地址：https://github.com/inmite/android-grid-wichterle APK地址：https://play.google.com/store/apps/details?id=eu.inmite.android.gridwichterle PS：比起hierarchyviewer相差甚远，不过偶尔可用来作为布局查看工具。\n**10、渠道打包工具** 允许app运行在任何手机上都可以用HierarchyViewer查看 项目地址：https://github.com/umeng/umeng-muti-channel-build-tool 另可参见Google的构建系统Gradle：http://tools.android.com/tech-docs/new-build-system/user-guide\n**11、Catlog** 手机端log查看工具，支持不同颜色显示、关键字过滤、级别过滤、进程id过滤、录制功能等 项目地址：https://github.com/nolanlawson/Catlog 在线演示：https://play.google.com/store/apps/details?id=com.nolanlawson.logcat\n**12、PID Cat** 根据package查看logcat日志 项目地址：https://github.com/JakeWharton/pidcat\n**13、Hugo** 用于打印函数信息及执行时间的工具，仅在debug模式生效 项目地址：https://github.com/JakeWharton/hugo\n","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E7%AC%AC%E5%9B%9B%E7%AF%87-%E5%BC%80%E5%8F%91%E5%8F%8A%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E7%AF%87-2/","summary":"\u003cp\u003e本文为那些不错的Android开源项目第四篇——开发工具篇，\u003cstrong\u003e主要介绍Android开发工具和测试工具相关的开源项目\u003c/strong\u003e。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e最新内容请访问[AndroidOpenProject@Github](https://github.com/Trinea/android-open-project)，欢迎Star和Fork。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e对你有帮助的话，去知乎点个赞让更多人了解：\u003ca href=\"http://www.zhihu.com/question/19804692/answer/21890050\"\u003eAndroid 优秀开源项目及特效推荐\u003c/a\u003e。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  Android开源项目系列汇总已完成，包括：\n\n\n\n\n\n  [Android开源项目第一篇——个性化控件(View)篇](http://www.trinea.cn/android/android-open-source-projects-view/)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-dev-lib/\"\u003eAndroid开源项目第二篇——工具库篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-excellent-project/\"\u003eAndroid开源项目第三篇——优秀项目篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-dev-tool/\"\u003eAndroid开源项目第四篇——开发及测试工具篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-excellent-personal-group/\"\u003eAndroid开源项目第五篇——优秀个人和团体篇\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    **1、Buck**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003efacebook开源的Android编译工具，效率是ant的两倍。主要优点在于：\n(1) 加快编译速度，通过并行利用多核cpu和跟踪不变资源减少增量编译时间实现\n(2) 可以在编译系统中生成编译规则而无须另外的系统生成编译规则文件\n(3) 编译同时可生成单元测试结果\n(4) 既可用于IDE编译也可用于持续集成编译\n(5) facebook持续优化中\n项目地址：\u003ca href=\"https://github.com/facebook/buck\"\u003ehttps://github.com/facebook/buck\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e      **2、Android Maven Plugin**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eAndroid Maven插件，可用于对android三方依赖进行管理。在J2EE开发中，maven是非常成熟的依赖库管理工具，可统一管理依赖库。\n项目地址：\u003ca href=\"https://github.com/jayway/maven-android-plugin\"\u003ehttps://github.com/jayway/maven-android-plugin\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e        **3、Spoon**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e可用于android不同机型设备自动化测试，能将应用apk和测试apk运行在不同机器上并生成相应测试报告。\n项目地址：\u003ca href=\"https://github.com/square/spoon\"\u003ehttps://github.com/square/spoon\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e          **4、Android FEST**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e提供一些列方便的断言，可用于提高编写Android自测代码效率\n项目地址：\u003ca href=\"https://github.com/square/fest-android\"\u003ehttps://github.com/square/fest-android\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e            **5、SelectorChapek for Android**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eAndroid Studio插件，可根据固定文件名格式资源自动生成drawable selectors xml文件。\n项目地址：\u003ca href=\"https://github.com/inmite/android-selector-chapek\"\u003ehttps://github.com/inmite/android-selector-chapek\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e              **6、Android Resource Navigator**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003echrome插件，可以方便的查看github上android源码工程的styles.xml和themes.xml。主要功能：\n(1) 快速打开android styles.xml themes.xml\n(2) 方便在资源间跳转。styles.xml themes.xml文件中资源链接跳转，可以方便跳转到某个资源\n(3) 方便查找某个style和theme。chrome地址栏输入arn+tab+搜索内容回车即可\n(4) 自动下载不同分辨率下的drawable\n(5) 通过映射查找那些不是按照固定命名规则命名的style和theme\n项目地址：\u003ca href=\"https://github.com/jgilfelt/android-resource-navigator\"\u003ehttps://github.com/jgilfelt/android-resource-navigator\u003c/a\u003e\n示例：\u003ca href=\"https://chrome.google.com/webstore/detail/android-resource-navigato/agoomkionjjbejegcejiefodgbckeebo?hl=en\u0026amp;gl=GB\"\u003ehttps://chrome.google.com/webstore/detail/android-resource-navigato/agoomkionjjbejegcejiefodgbckeebo?hl=en\u0026amp;gl=GB\u003c/a\u003e\u003c/p\u003e","title":"Android开源项目第四篇——开发及测试工具篇"},{"content":"本文为那些不错的Android开源项目第三篇——优秀项目篇，主要介绍那些还不错的完整Android项目。\n最新内容请访问[AndroidOpenProject@Github](https://github.com/Trinea/android-open-project)，欢迎Star和Fork。 对你有帮助的话，去知乎点个赞让更多人了解：Android 优秀开源项目及特效推荐。\nAndroid开源项目系列汇总已完成，包括： [Android开源项目第一篇——个性化控件(View)篇](http://www.trinea.cn/android/android-open-source-projects-view/) Android开源项目第二篇——工具库篇 Android开源项目第三篇——优秀项目篇 Android开源项目第四篇——开发及测试工具篇 Android开源项目第五篇——优秀个人和团体篇\n记录的项目主要依据是项目有意思或项目分层规范比较好。 **Linux** 项目地址：https://github.com/torvalds/linux\n**Android** 项目地址：https://android.googlesource.com/或https://github.com/android 以上两个项目，不解释\n**(1) ZXing 二维码扫描工具** 项目地址：https://github.com/zxing/zxing或https://code.google.com/p/zxing/ APK地址：https://play.google.com/store/apps/details?id=com.google.zxing.client.android PS：现在市面上很多应用的二维码扫描功能都是从这个修改而来\n**(2) photup 编辑机批量上传照片到facebook上** 项目地址：https://github.com/chrisbanes/photup APK地址：https://play.google.com/store/apps/details?id=uk.co.senab.photup PS：代码分包合理，很棒。不过这个项目依赖的开源项目比较多，比较难编译\n![android photo up image process](http://farm4.staticflickr.com/3694/11100968474_75ab4fbd56_o.jpg) **(3) Github的Android客户端项目** 项目地址：https://github.com/github/android APK地址：https://play.google.com/store/apps/details?id=com.github.mobile\n**(4) MIUI便签** 项目地址：https://github.com/MiCode/Notes APK地址：https://github.com/Trinea/TrineaDownload/blob/master/miui-note-demo.apk?raw=true PS：项目分包比较合理，相比较miui的文件管理器https://github.com/MiCode/FileExplorer代码规范较好得多\n**(5) 四次元-新浪微博客户端** 项目地址：https://github.com/qii/weiciyuan APK地址：https://play.google.com/store/apps/details?id=org.qii.weiciyuan\n**(6) gnucash-一个记账理财软件** 项目地址：https://github.com/codinguser/gnucash-android APK地址：http://play.google.com/store/apps/details?id=org.gnucash.android\n**(7) AntennaPod支持rss订阅、音乐订阅** 项目地址：https://github.com/danieloeh/AntennaPod APK地址：https://play.google.com/store/apps/details?id=de.danoeh.antennapod\n**(8) ChaseWhisplyProject 打鬼游戏** 项目地址：https://github.com/tvbarthel/ChaseWhisplyProject APK地址：https://play.google.com/store/apps/details?id=fr.tvbarthel.games.chasewhisply\n**(9) Tweet Lanes 功能完整的Twitter客户端** 项目地址：https://github.com/chrislacy/TweetLanes APK地址：https://play.google.com/store/apps/details?id=com.tweetlanes.android\n","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E7%AC%AC%E4%B8%89%E7%AF%87-%E4%BC%98%E7%A7%80%E9%A1%B9%E7%9B%AE%E7%AF%87/","summary":"\u003cp\u003e本文为那些不错的Android开源项目第三篇——优秀项目篇，\u003cstrong\u003e主要介绍那些还不错的完整Android项目\u003c/strong\u003e。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e最新内容请访问[AndroidOpenProject@Github](https://github.com/Trinea/android-open-project)，欢迎Star和Fork。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e对你有帮助的话，去知乎点个赞让更多人了解：\u003ca href=\"http://www.zhihu.com/question/19804692/answer/21890050\"\u003eAndroid 优秀开源项目及特效推荐\u003c/a\u003e。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  Android开源项目系列汇总已完成，包括：\n\n\n\n\n\n  [Android开源项目第一篇——个性化控件(View)篇](http://www.trinea.cn/android/android-open-source-projects-view/)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-dev-lib/\"\u003eAndroid开源项目第二篇——工具库篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-excellent-project/\"\u003eAndroid开源项目第三篇——优秀项目篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-dev-tool/\"\u003eAndroid开源项目第四篇——开发及测试工具篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-excellent-personal-group/\"\u003eAndroid开源项目第五篇——优秀个人和团体篇\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    记录的项目主要依据是项目有意思或项目分层规范比较好。\n  \n\n  \n  \n\n    **Linux**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/torvalds/linux\"\u003ehttps://github.com/torvalds/linux\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    **Android**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://android.googlesource.com/\"\u003ehttps://android.googlesource.com/\u003c/a\u003e或\u003ca href=\"https://github.com/android\"\u003ehttps://github.com/android\u003c/a\u003e\n以上两个项目，不解释\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e      **(1) ZXing 二维码扫描工具**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/zxing/zxing\"\u003ehttps://github.com/zxing/zxing\u003c/a\u003e或\u003ca href=\"https://code.google.com/p/zxing/\"\u003ehttps://code.google.com/p/zxing/\u003c/a\u003e\nAPK地址：\u003ca href=\"https://play.google.com/store/apps/details?id=com.google.zxing.client.android\"\u003ehttps://play.google.com/store/apps/details?id=com.google.zxing.client.android\u003c/a\u003e\nPS：现在市面上很多应用的二维码扫描功能都是从这个修改而来\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e        **(2) photup 编辑机批量上传照片到facebook上**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/chrisbanes/photup\"\u003ehttps://github.com/chrisbanes/photup\u003c/a\u003e\nAPK地址：\u003ca href=\"https://play.google.com/store/apps/details?id=uk.co.senab.photup\"\u003ehttps://play.google.com/store/apps/details?id=uk.co.senab.photup\u003c/a\u003e\nPS：代码分包合理，很棒。不过这个项目依赖的开源项目比较多，比较难编译\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e        ![android photo up image process](http://farm4.staticflickr.com/3694/11100968474_75ab4fbd56_o.jpg)\n      \n\n      \n      \n\n        \n\n          **(3) Github的Android客户端项目**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/github/android\"\u003ehttps://github.com/github/android\u003c/a\u003e\nAPK地址：\u003ca href=\"https://play.google.com/store/apps/details?id=com.github.mobile\"\u003ehttps://play.google.com/store/apps/details?id=com.github.mobile\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e            **(4) MIUI便签**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/MiCode/Notes\"\u003ehttps://github.com/MiCode/Notes\u003c/a\u003e\nAPK地址：\u003ca href=\"https://github.com/Trinea/TrineaDownload/blob/master/miui-note-demo.apk?raw=true\"\u003ehttps://github.com/Trinea/TrineaDownload/blob/master/miui-note-demo.apk?raw=true\u003c/a\u003e\nPS：项目分包比较合理，相比较miui的文件管理器\u003ca href=\"https://github.com/MiCode/FileExplorer\"\u003ehttps://github.com/MiCode/FileExplorer\u003c/a\u003e代码规范较好得多\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e              **(5) 四次元-新浪微博客户端**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/qii/weiciyuan\"\u003ehttps://github.com/qii/weiciyuan\u003c/a\u003e\nAPK地址：\u003ca href=\"https://play.google.com/store/apps/details?id=org.qii.weiciyuan\"\u003ehttps://play.google.com/store/apps/details?id=org.qii.weiciyuan\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e                **(6) gnucash-一个记账理财软件**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/codinguser/gnucash-android\"\u003ehttps://github.com/codinguser/gnucash-android\u003c/a\u003e\nAPK地址：\u003ca href=\"http://play.google.com/store/apps/details?id=org.gnucash.android\"\u003ehttp://play.google.com/store/apps/details?id=org.gnucash.android\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e                  **(7) AntennaPod支持rss订阅、音乐订阅**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/danieloeh/AntennaPod\"\u003ehttps://github.com/danieloeh/AntennaPod\u003c/a\u003e\nAPK地址：\u003ca href=\"https://play.google.com/store/apps/details?id=de.danoeh.antennapod\"\u003ehttps://play.google.com/store/apps/details?id=de.danoeh.antennapod\u003c/a\u003e\u003c/p\u003e","title":"Android开源项目第三篇——优秀项目篇"},{"content":"本文为那些不错的Android开源项目第二篇——开发工具库篇，主要介绍常用的开发库，包括依赖注入框架、图片缓存、网络相关、数据库ORM建模、Android公共库、Android 高版本向低版本兼容、多媒体相关及其他。\n最新内容请访问[AndroidOpenProject@Github](https://github.com/Trinea/android-open-project)，欢迎Star和Fork。 对你有帮助的话，去知乎点个赞让更多人了解：[Android 优秀开源项目及特效推荐](http://www.zhihu.com/question/19804692/answer/21890050)。 Android开源项目系列汇总已完成，包括： [Android开源项目第一篇——个性化控件(View)篇](http://www.trinea.cn/android/android-open-source-projects-view/) [Android开源项目第二篇——工具库篇](http://www.trinea.cn/android/android-open-source-projects-dev-lib/) [Android开源项目第三篇——优秀项目篇](http://www.trinea.cn/android/android-open-source-projects-excellent-project/) [Android开源项目第四篇——开发及测试工具篇](http://www.trinea.cn/android/android-open-source-projects-dev-tool/) [Android开源项目第五篇——优秀个人和团体篇](http://www.trinea.cn/android/android-open-source-projects-excellent-personal-group/) 通过这些项目你可以大幅度减少不必要的开发而将精力放在更重要的地方。 **一、依赖注入DI** 通过依赖注入减少View、服务、资源简化初始化，事件绑定等重复繁琐工作 **1. AndroidAnnotations(Code Diet) android快速开发框架** 项目地址：[https://github.com/excilys/androidannotations](https://github.com/excilys/androidannotations) 文档介绍：[https://github.com/excilys/androidannotations/wiki](https://github.com/excilys/androidannotations/wiki) 官方网站：[http://androidannotations.org/](http://androidannotations.org/) 特点：(1)依赖注入：包括view，extras，系统服务，资源等等 (2)简单的线程模型，通过annotation表示方法运行在ui线程还是后台线程 (3)事件绑定：通过annotation表示view的响应事件，不用在写内部类 (4)REST客户端：定义客户端接口，自动生成REST请求的实现 (5)没有你想象的复杂：AndroidAnnotations只是在在编译时生成相应子类 (6)不影响应用性能：仅50kb，在编译时完成，不会对运行时有性能影响。 PS：与roboguice的比较：roboguice通过运行时读取annotations进行反射，所以可能影响应用性能，而AndroidAnnotations在编译时生成子类，所以对性能没有影响 **2. roboguice 帮你处理了很多代码异常，利用annotation使得更少的代码完成项目** 项目地址：[https://github.com/roboguice/roboguice](https://github.com/roboguice/roboguice) 文档介绍：[https://github.com/roboguice/roboguice/wiki](https://github.com/roboguice/roboguice/wiki) **3. butterknife 利用annotation帮你快速完成View的初始化，减少代码** 项目地址：[https://github.com/JakeWharton/butterknife](https://github.com/JakeWharton/butterknife) 文档介绍：[http://jakewharton.github.io/butterknife/](http://jakewharton.github.io/butterknife/) **4. Dagger 依赖注入，适用于Android和Java** 项目地址：[https://github.com/square/dagger](https://github.com/square/dagger) 文档介绍：[http://square.github.io/dagger/](http://square.github.io/dagger/) **二、图片缓存** **1. Android-Universal-Image-Loader 图片缓存** 目前使用最广泛的图片缓存，支持主流图片缓存的绝大多数特性。 项目地址：[https://github.com/nostra13/Android-Universal-Image-Loader](https://github.com/nostra13/Android-Universal-Image-Loader) Demo地址：[https://github.com/Trinea/TrineaDownload/blob/master/universal-imageloader-demo.apk?raw=true](https://github.com/Trinea/TrineaDownload/blob/master/universal-imageloader-demo.apk?raw=true) 文档介绍：[http://www.intexsoft.com/blog/item/74-universal-image-loader-part-3.html](http://www.intexsoft.com/blog/item/74-universal-image-loader-part-3.html) **2. picasso square开源的图片缓存** 项目地址：[https://github.com/square/picasso](https://github.com/square/picasso) 文档介绍：[http://square.github.io/picasso/](http://square.github.io/picasso/) 特点：(1)可以自动检测adapter的重用并取消之前的下载 (2)图片变换 (3)可以加载本地资源 (4)可以设置占位资源 (5)支持debug模式 **3. ImageCache 图片缓存，包含内存和Sdcard缓存** 项目地址：[https://github.com/Trinea/AndroidCommon](https://github.com/Trinea/AndroidCommon) Demo地址：[https://play.google.com/store/apps/details?id=cn.trinea.android.demo](https://play.google.com/store/apps/details?id=cn.trinea.android.demo) 文档介绍：[http://www.trinea.cn/?p=704](http://www.trinea.cn/?p=704) 特点：(1)支持预取新图片，支持等待队列 (2)包含二级缓存，可自定义文件名保存规则 (3)可选择多种缓存算法(FIFO、LIFO、LRU、MRU、LFU、MFU等13种)或自定义缓存算法 (4)可方便的保存及初始化恢复数据 (5)支持不同类型网络处理 (6)可根据系统配置初始化缓存等 **三、网络相关** **1. Asynchronous Http Client for Android Android异步Http请求** 项目地址：[https://github.com/loopj/android-async-http](https://github.com/loopj/android-async-http) 文档介绍：[http://loopj.com/android-async-http/](http://loopj.com/android-async-http/) 特点：(1) 在匿名回调中处理请求结果 (2) 在UI线程外进行http请求 (3) 文件断点上传 (4) 智能重试 (5) 默认gzip压缩 (6) 支持解析成Json格式 (7) 可将Cookies持久化到SharedPreferences **2. android-query 异步加载，更少代码完成Android加载** 项目地址：[https://github.com/androidquery/androidquery](https://github.com/androidquery/androidquery)或[https://code.google.com/p/android-query/](https://code.google.com/p/android-query/) 文档介绍：[https://code.google.com/p/android-query/#Why_AQuery](https://code.google.com/p/android-query/#Why_AQuery)? Demo地址：[https://play.google.com/store/apps/details?id=com.androidquery](https://play.google.com/store/apps/details?id=com.androidquery) 特点：[https://code.google.com/p/android-query/#Why_AQuery](https://code.google.com/p/android-query/#Why_AQuery)? **3. Async Http Client Java异步Http请求** 项目地址：[https://github.com/AsyncHttpClient/async-http-client](https://github.com/AsyncHttpClient/async-http-client) 文档介绍：[http://sonatype.github.io/async-http-client/](http://sonatype.github.io/async-http-client/) **4. Ion 支持图片、json、http post等异步请求** 项目地址：[https://github.com/koush/ion](https://github.com/koush/ion) 文档介绍：[https://github.com/koush/ion#more-examples](https://github.com/koush/ion#more-examples) **5. HttpCache Http缓存** 项目地址：[https://github.com/Trinea/AndroidCommon](https://github.com/Trinea/AndroidCommon) Demo地址：[https://play.google.com/store/apps/details?id=cn.trinea.android.demo](https://play.google.com/store/apps/details?id=cn.trinea.android.demo) Demo代码：[https://github.com/Trinea/AndroidDemo/blob/master/src/cn/trinea/android/demo/HttpCacheDemo.java](https://github.com/Trinea/AndroidDemo/blob/master/src/cn/trinea/android/demo/HttpCacheDemo.java) 特点是：(1) 根据cache-control、expires缓存http请求 (2) 支持同步、异步Http请求 (3) 在匿名回调中处理请求结果 (4) 在UI线程外进行http请求 (5) 默认gzip压缩 **6. Http Request** 项目地址：[https://github.com/kevinsawicki/http-request](https://github.com/kevinsawicki/http-request) 文档介绍：[https://github.com/kevinsawicki/http-request#examples](https://github.com/kevinsawicki/http-request#examples) **7. okhttp square开源的http工具类** 项目地址：[https://github.com/square/okhttp](https://github.com/square/okhttp) 文档介绍：[http://square.github.io/okhttp/](http://square.github.io/okhttp/) 特点：(1) 支持SPDY([http://zh.wikipedia.org/wiki/SPDY)协议。SPDY协议是Google开发的基于传输控制协议的应用层协议，通过压缩，多路复用(一个TCP链接传送网页和图片等资源](http://zh.wikipedia.org/wiki/SPDY)%E5%8D%8F%E8%AE%AE%E3%80%82SPDY%E5%8D%8F%E8%AE%AE%E6%98%AFGoogle%E5%BC%80%E5%8F%91%E7%9A%84%E5%9F%BA%E4%BA%8E%E4%BC%A0%E8%BE%93%E6%8E%A7%E5%88%B6%E5%8D%8F%E8%AE%AE%E7%9A%84%E5%BA%94%E7%94%A8%E5%B1%82%E5%8D%8F%E8%AE%AE%EF%BC%8C%E9%80%9A%E8%BF%87%E5%8E%8B%E7%BC%A9%EF%BC%8C%E5%A4%9A%E8%B7%AF%E5%A4%8D%E7%94%A8(%E4%B8%80%E4%B8%AATCP%E9%93%BE%E6%8E%A5%E4%BC%A0%E9%80%81%E7%BD%91%E9%A1%B5%E5%92%8C%E5%9B%BE%E7%89%87%E7%AD%89%E8%B5%84%E6%BA%90))和优先级来缩短加载时间。 (2) 如果SPDY不可用，利用连接池减少请求延迟 (3) Gzip压缩 (4) Response缓存减少不必要的请求 **8. Retrofit RESTFUL API设计** 项目地址：[https://github.com/square/retrofit](https://github.com/square/retrofit) 文档介绍：[http://square.github.io/retrofit/](http://square.github.io/retrofit/) **四、数据库 orm工具包** orm的db工具类，简化建表、查询、更新、插入、事务、索引的操作 **1. greenDAO Android Sqlite orm的db工具类** 项目地址：[https://github.com/greenrobot/greenDAO](https://github.com/greenrobot/greenDAO) 文档介绍：[http://greendao-orm.com/documentation/](http://greendao-orm.com/documentation/) 官方网站：[http://greendao-orm.com/](http://greendao-orm.com/) 特点：(1)性能佳 (2) 简单易用的API (3) 内存小好小 (4) 库大小小 **2. ActiveAndroid Android Sqlite orm的db工具类** 项目地址：[https://github.com/pardom/ActiveAndroid](https://github.com/pardom/ActiveAndroid) 文档介绍：[https://github.com/pardom/ActiveAndroid/wiki/_pages](https://github.com/pardom/ActiveAndroid/wiki/_pages) **3. Sprinkles Android Sqlite orm的db工具类** 项目地址：[https://github.com/emilsjolander/sprinkles](https://github.com/emilsjolander/sprinkles) 文档介绍：[http://emilsjolander.github.io/blog/2013/12/18/android-with-sprinkles/](http://emilsjolander.github.io/blog/2013/12/18/android-with-sprinkles/) 特点：比较显著的特点就是配合[https://github.com/square/retrofit](https://github.com/square/retrofit)能保存从服务器获取的数据 **五、Android公共库** **1. Guava Google的基于java1.6的类库集合的扩展项目** 包括collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O等等. 这些高质量的API可以使你的JAVa代码更加优雅，更加简洁 项目地址：[https://code.google.com/p/guava-libraries/](https://code.google.com/p/guava-libraries/) 文档介绍：[https://code.google.com/p/guava-libraries/wiki/GuavaExplained](https://code.google.com/p/guava-libraries/wiki/GuavaExplained) **2. AndroidCommon Android公共库** 项目地址：[https://github.com/Trinea/AndroidCommon](https://github.com/Trinea/AndroidCommon) Demo地址：[https://play.google.com/store/apps/details?id=cn.trinea.android.demo](https://play.google.com/store/apps/details?id=cn.trinea.android.demo) 文档介绍：[http://www.trinea.cn/?p=778](http://www.trinea.cn/?p=778) 包括：(1)缓存(图片缓存、预取缓存、网络缓存) (2) 公共View(下拉及底部加载更多ListView、底部加载更多ScrollView、滑动一页Gallery) (3) Android常用工具类(网络、下载、Android资源操作、shell、文件、Json、随机数、Collection等等) **六、Android 高版本向低版本兼容** **1. ActionBarSherlock 为Android所有版本提供统一的ActionBar，解决4.0以下ActionBar的适配问题** 项目地址：[https://github.com/JakeWharton/ActionBarSherlock](https://github.com/JakeWharton/ActionBarSherlock) Demo地址：[https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.demos](https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.demos) APP示例：太多了。。现在连google都在用 **2. Nine Old Androids 将Android 3.0(Honeycomb)所有动画API(ObjectAnimator ValueAnimator等)兼容到Android1.0** 项目地址：[https://github.com/JakeWharton/NineOldAndroids](https://github.com/JakeWharton/NineOldAndroids) Demo地址：[https://play.google.com/store/apps/details?id=com.jakewharton.nineoldandroids.sample](https://play.google.com/store/apps/details?id=com.jakewharton.nineoldandroids.sample) 文档介绍：[http://nineoldandroids.com/](http://nineoldandroids.com/) **3. HoloEverywhere 将Android 3.0的Holo主题兼容到Android2.1++** 项目地址：[https://github.com/Prototik/HoloEverywhere](https://github.com/Prototik/HoloEverywhere) Demo地址：[https://raw.github.com/Prototik/HoloEverywhere/repo/org/holoeverywhere/demo/2.1.0/demo-2.1.0.apk](https://raw.github.com/Prototik/HoloEverywhere/repo/org/holoeverywhere/demo/2.1.0/demo-2.1.0.apk) 文档介绍：[http://android-developers.blogspot.com/2012/01/holo-everywhere.html](http://android-developers.blogspot.com/2012/01/holo-everywhere.html) **七、多媒体相关** **1. cocos2d-x 跨平台的2d游戏框架，支持Android、IOS、Linux、Windows等众多平台** 项目地址：[https://github.com/cocos2d/cocos2d-x](https://github.com/cocos2d/cocos2d-x) 文档介绍：[http://www.cocos2d-x.org/wiki](http://www.cocos2d-x.org/wiki) 官方网站：[http://www.cocos2d-x.org/](http://www.cocos2d-x.org/) **2. Vitamio 是一款Android与iOS平台上的全能多媒体开发框架** 项目地址：[https://github.com/yixia/VitamioBundle](https://github.com/yixia/VitamioBundle) 网站介绍：[http://www.vitamio.org/docs/](http://www.vitamio.org/docs/) 特点：(1) 全面支持硬件解码与GPU渲染 (2) 能够流畅播放720P甚至1080P高清MKV，FLV，MP4，MOV，TS，RMVB等常见格式的视频 (3) 在Android与iOS上跨平台支持 MMS, RTSP, RTMP, HLS(m3u8)等常见的多种视频流媒体协议，包括点播与直播。 **3. PhotoProcessing 利用ndk处理图片库**，支持Instafix、Ansel、Testino、XPro、Retro、BW、Sepia、Cyano、Georgia、Sahara、HDR、Rotate、Flip 项目地址：[https://github.com/lightbox/PhotoProcessing](https://github.com/lightbox/PhotoProcessing) Demo地址：[https://github.com/Trinea/TrineaDownload/blob/master/photo-processing.apk?raw=true](https://github.com/Trinea/TrineaDownload/blob/master/photo-processing.apk?raw=true) **4. Android StackBlur 图片模糊效果工具类** 项目地址：[https://github.com/kikoso/android-stackblur](https://github.com/kikoso/android-stackblur) Demo地址：[https://github.com/kikoso/android-stackblur/blob/master/StackBlurDemo/bin/StackBlurDemo.apk?raw=true](https://github.com/kikoso/android-stackblur/blob/master/StackBlurDemo/bin/StackBlurDemo.apk?raw=true) 文档介绍：[https://github.com/kikoso/android-stackblur#usage](https://github.com/kikoso/android-stackblur#usage) **八、其他** **1. Salvage view 带View缓存的Viewpager PagerAdapter，很方便使用** 项目地址：[https://github.com/JakeWharton/salvage](https://github.com/JakeWharton/salvage) **2. Android-PasscodeLock 应用锁**，每次启动或从任何Activity启动应用都需要输入四位数字的密码方可进入 项目地址：[https://github.com/wordpress-mobile/Android-PasscodeLock](https://github.com/wordpress-mobile/Android-PasscodeLock) Demo地址：[https://play.google.com/store/apps/details?id=com.sothree.umano](https://play.google.com/store/apps/details?id=com.sothree.umano) APP示例：Wordpress Android，支付宝，挖财 **3. android-lockpattern Android的图案密码解锁** 项目地址：[https://code.google.com/p/android-lockpattern/](https://code.google.com/p/android-lockpattern/) Demo地址：[https://play.google.com/store/apps/details?id=group.pals.android.lib.ui.lockpattern.demo](https://play.google.com/store/apps/details?id=group.pals.android.lib.ui.lockpattern.demo) 使用介绍：[https://code.google.com/p/android-lockpattern/wiki/QuickUse](https://code.google.com/p/android-lockpattern/wiki/QuickUse) 示例APP：Android开机的图案密码解锁，支付宝的密码解锁 **4. GlowPadBackport将Android4.2的锁屏界面解锁扩展到Android1.6及1.6+** 项目地址：[https://github.com/rock3r/GlowPadBackport](https://github.com/rock3r/GlowPadBackport) Demo地址：[https://play.google.com/store/apps/details?id=net.sebastianopoggi.samples.ui.GlowPadSample](https://play.google.com/store/apps/details?id=net.sebastianopoggi.samples.ui.GlowPadSample) 效果图：[https://lh6.ggpht.com/U070b6Lh6cVsVwx4jN-5nq0xqiB1PBzrYABPeJIEe2hZQ5UWOxc-FDUG77wADelToHA=h310-rw](https://lh6.ggpht.com/U070b6Lh6cVsVwx4jN-5nq0xqiB1PBzrYABPeJIEe2hZQ5UWOxc-FDUG77wADelToHA=h310-rw) **5. GlowPadView Android4锁屏界面解锁** 项目地址：[https://github.com/nadavfima/GlowPadView](https://github.com/nadavfima/GlowPadView) 效果图：[https://raw.github.com/nadavfima/GlowPadView/master/example.png](https://raw.github.com/nadavfima/GlowPadView/master/example.png) **6. Android Priority Job Queue Android后台任务队列** 项目地址：[https://github.com/path/android-priority-jobqueue](https://github.com/path/android-priority-jobqueue) 文档介绍：[https://github.com/path/android-priority-jobqueue#getting-started](https://github.com/path/android-priority-jobqueue#getting-started) **7. jsoup 一个解析html的java库，可方便的提取和操作数据** 项目地址：[https://github.com/jhy/jsoup](https://github.com/jhy/jsoup) 官方网站：[http://jsoup.org/](http://jsoup.org/) 作用：(1) 从一个url、文件或string获得html并解析 (2) 利用dom遍历或css选择器查找、提取数据 (3) 操作html元素 (4) 根据白名单去除用于提交的非法数据防止xss攻击 (5) 输出整齐的html **8.ZIP java压缩和解压库** 项目地址：[https://github.com/zeroturnaround/zt-zip](https://github.com/zeroturnaround/zt-zip) 文档介绍：[https://github.com/zeroturnaround/zt-zip#examples](https://github.com/zeroturnaround/zt-zip#examples) 作用：(1) 解压和压缩，并支持文件夹内递归操作 (2) 支持包含和排除某些元素 (3) 支持重命名元素 (4) 支持遍历zip包内容 (5) 比较两个zip包等功能 **9. Cobub Razor 开源的mobile行为分析系统**，包括web端、android端，支持ios和window phone 项目地址：[https://github.com/cobub/razor](https://github.com/cobub/razor) Demo地址：[http://demo.cobub.com/razor](http://demo.cobub.com/razor) 网站介绍：[http://dev.cobub.com/](http://dev.cobub.com/) **10. aFileChooser 文件选择器**，可内嵌到程序中，而无需使用系统或三方文件选择器。 项目地址：[https://github.com/iPaulPro/aFileChooser](https://github.com/iPaulPro/aFileChooser) **11. androidpn 基于xmpp协议的消息推送解决方案**，包括服务器端和android端。 项目地址：[https://github.com/dannytiehui/androidpn](https://github.com/dannytiehui/androidpn) **12. Android插件式开发** 项目地址：[https://github.com/umeng/apf](https://github.com/umeng/apf) ","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E7%AC%AC%E4%BA%8C%E7%AF%87-%E5%B7%A5%E5%85%B7%E5%BA%93%E7%AF%87/","summary":"\u003cp\u003e本文为那些不错的Android开源项目第二篇——开发工具库篇，\u003cstrong\u003e主要介绍常用的开发库，包括依赖注入框架、图片缓存、网络相关、数据库ORM建模、Android公共库、Android 高版本向低版本兼容、多媒体相关及其他\u003c/strong\u003e。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e最新内容请访问[AndroidOpenProject@Github](https://github.com/Trinea/android-open-project)，欢迎Star和Fork。 对你有帮助的话，去知乎点个赞让更多人了解：[Android 优秀开源项目及特效推荐](http://www.zhihu.com/question/19804692/answer/21890050)。\n\n\n\n\n\n\n\n  Android开源项目系列汇总已完成，包括：\n\n\n\n\n\n  [Android开源项目第一篇——个性化控件(View)篇](http://www.trinea.cn/android/android-open-source-projects-view/) [Android开源项目第二篇——工具库篇](http://www.trinea.cn/android/android-open-source-projects-dev-lib/) [Android开源项目第三篇——优秀项目篇](http://www.trinea.cn/android/android-open-source-projects-excellent-project/) [Android开源项目第四篇——开发及测试工具篇](http://www.trinea.cn/android/android-open-source-projects-dev-tool/) [Android开源项目第五篇——优秀个人和团体篇](http://www.trinea.cn/android/android-open-source-projects-excellent-personal-group/)\n\n\n\n\n\n  \n\n    通过这些项目你可以大幅度减少不必要的开发而将精力放在更重要的地方。\n  \n\n  \n  \n\n    \n\n      **一、依赖注入DI** 通过依赖注入减少View、服务、资源简化初始化，事件绑定等重复繁琐工作 **1. AndroidAnnotations(Code Diet) android快速开发框架** 项目地址：[https://github.com/excilys/androidannotations](https://github.com/excilys/androidannotations) 文档介绍：[https://github.com/excilys/androidannotations/wiki](https://github.com/excilys/androidannotations/wiki) 官方网站：[http://androidannotations.org/](http://androidannotations.org/) 特点：(1)依赖注入：包括view，extras，系统服务，资源等等 (2)简单的线程模型，通过annotation表示方法运行在ui线程还是后台线程 (3)事件绑定：通过annotation表示view的响应事件，不用在写内部类 (4)REST客户端：定义客户端接口，自动生成REST请求的实现 (5)没有你想象的复杂：AndroidAnnotations只是在在编译时生成相应子类 (6)不影响应用性能：仅50kb，在编译时完成，不会对运行时有性能影响。 PS：与roboguice的比较：roboguice通过运行时读取annotations进行反射，所以可能影响应用性能，而AndroidAnnotations在编译时生成子类，所以对性能没有影响\n    \n\n    \n    \n\n      \n\n        **2. roboguice 帮你处理了很多代码异常，利用annotation使得更少的代码完成项目** 项目地址：[https://github.com/roboguice/roboguice](https://github.com/roboguice/roboguice) 文档介绍：[https://github.com/roboguice/roboguice/wiki](https://github.com/roboguice/roboguice/wiki)\n      \n\n      \n      \n\n        \n\n          **3. butterknife 利用annotation帮你快速完成View的初始化，减少代码** 项目地址：[https://github.com/JakeWharton/butterknife](https://github.com/JakeWharton/butterknife) 文档介绍：[http://jakewharton.github.io/butterknife/](http://jakewharton.github.io/butterknife/)\n        \n\n        \n        \n\n          \n\n            **4. Dagger 依赖注入，适用于Android和Java** 项目地址：[https://github.com/square/dagger](https://github.com/square/dagger) 文档介绍：[http://square.github.io/dagger/](http://square.github.io/dagger/)\n          \n\n          \n          \n\n            \n\n              **二、图片缓存** **1. Android-Universal-Image-Loader 图片缓存**\n            \n\n            \n            \n\n              目前使用最广泛的图片缓存，支持主流图片缓存的绝大多数特性。 项目地址：[https://github.com/nostra13/Android-Universal-Image-Loader](https://github.com/nostra13/Android-Universal-Image-Loader) Demo地址：[https://github.com/Trinea/TrineaDownload/blob/master/universal-imageloader-demo.apk?raw=true](https://github.com/Trinea/TrineaDownload/blob/master/universal-imageloader-demo.apk?raw=true) 文档介绍：[http://www.intexsoft.com/blog/item/74-universal-image-loader-part-3.html](http://www.intexsoft.com/blog/item/74-universal-image-loader-part-3.html)\n            \n\n            \n            \n\n              \n\n                **2. picasso square开源的图片缓存** 项目地址：[https://github.com/square/picasso](https://github.com/square/picasso) 文档介绍：[http://square.github.io/picasso/](http://square.github.io/picasso/) 特点：(1)可以自动检测adapter的重用并取消之前的下载 (2)图片变换 (3)可以加载本地资源 (4)可以设置占位资源 (5)支持debug模式\n              \n\n              \n              \n\n                \n\n                  **3. ImageCache 图片缓存，包含内存和Sdcard缓存** 项目地址：[https://github.com/Trinea/AndroidCommon](https://github.com/Trinea/AndroidCommon) Demo地址：[https://play.google.com/store/apps/details?id=cn.trinea.android.demo](https://play.google.com/store/apps/details?id=cn.trinea.android.demo) 文档介绍：[http://www.trinea.cn/?p=704](http://www.trinea.cn/?p=704) 特点：(1)支持预取新图片，支持等待队列 (2)包含二级缓存，可自定义文件名保存规则 (3)可选择多种缓存算法(FIFO、LIFO、LRU、MRU、LFU、MFU等13种)或自定义缓存算法 (4)可方便的保存及初始化恢复数据 (5)支持不同类型网络处理 (6)可根据系统配置初始化缓存等\n                \n\n                \n                \n\n                  \n\n                    **三、网络相关** **1. Asynchronous Http Client for Android Android异步Http请求** 项目地址：[https://github.com/loopj/android-async-http](https://github.com/loopj/android-async-http) 文档介绍：[http://loopj.com/android-async-http/](http://loopj.com/android-async-http/) 特点：(1) 在匿名回调中处理请求结果 (2) 在UI线程外进行http请求 (3) 文件断点上传 (4) 智能重试 (5) 默认gzip压缩 (6) 支持解析成Json格式 (7) 可将Cookies持久化到SharedPreferences\n                  \n\n                  \n                  \n\n                    \n\n                      **2. android-query 异步加载，更少代码完成Android加载** 项目地址：[https://github.com/androidquery/androidquery](https://github.com/androidquery/androidquery)或[https://code.google.com/p/android-query/](https://code.google.com/p/android-query/) 文档介绍：[https://code.google.com/p/android-query/#Why_AQuery](https://code.google.com/p/android-query/#Why_AQuery)? Demo地址：[https://play.google.com/store/apps/details?id=com.androidquery](https://play.google.com/store/apps/details?id=com.androidquery) 特点：[https://code.google.com/p/android-query/#Why_AQuery](https://code.google.com/p/android-query/#Why_AQuery)?\n                    \n\n                    \n                    \n\n                      \n\n                        **3. Async Http Client Java异步Http请求** 项目地址：[https://github.com/AsyncHttpClient/async-http-client](https://github.com/AsyncHttpClient/async-http-client) 文档介绍：[http://sonatype.github.io/async-http-client/](http://sonatype.github.io/async-http-client/)\n                      \n\n                      \n                      \n\n                        \n\n                          **4. Ion 支持图片、json、http post等异步请求**\n                        \n\n                        \n                        \n\n                          项目地址：[https://github.com/koush/ion](https://github.com/koush/ion) 文档介绍：[https://github.com/koush/ion#more-examples](https://github.com/koush/ion#more-examples)\n                        \n\n                        \n                        \n\n                          \n\n                            **5. HttpCache Http缓存** 项目地址：[https://github.com/Trinea/AndroidCommon](https://github.com/Trinea/AndroidCommon) Demo地址：[https://play.google.com/store/apps/details?id=cn.trinea.android.demo](https://play.google.com/store/apps/details?id=cn.trinea.android.demo) Demo代码：[https://github.com/Trinea/AndroidDemo/blob/master/src/cn/trinea/android/demo/HttpCacheDemo.java](https://github.com/Trinea/AndroidDemo/blob/master/src/cn/trinea/android/demo/HttpCacheDemo.java) 特点是：(1) 根据cache-control、expires缓存http请求 (2) 支持同步、异步Http请求 (3) 在匿名回调中处理请求结果 (4) 在UI线程外进行http请求 (5) 默认gzip压缩\n                          \n\n                          \n                          \n\n                            \n\n                              **6. Http Request** 项目地址：[https://github.com/kevinsawicki/http-request](https://github.com/kevinsawicki/http-request) 文档介绍：[https://github.com/kevinsawicki/http-request#examples](https://github.com/kevinsawicki/http-request#examples)\n                            \n\n                            \n                            \n\n                              \n\n                                **7. okhttp square开源的http工具类** 项目地址：[https://github.com/square/okhttp](https://github.com/square/okhttp) 文档介绍：[http://square.github.io/okhttp/](http://square.github.io/okhttp/) 特点：(1) 支持SPDY([http://zh.wikipedia.org/wiki/SPDY)协议。SPDY协议是Google开发的基于传输控制协议的应用层协议，通过压缩，多路复用(一个TCP链接传送网页和图片等资源](http://zh.wikipedia.org/wiki/SPDY)%E5%8D%8F%E8%AE%AE%E3%80%82SPDY%E5%8D%8F%E8%AE%AE%E6%98%AFGoogle%E5%BC%80%E5%8F%91%E7%9A%84%E5%9F%BA%E4%BA%8E%E4%BC%A0%E8%BE%93%E6%8E%A7%E5%88%B6%E5%8D%8F%E8%AE%AE%E7%9A%84%E5%BA%94%E7%94%A8%E5%B1%82%E5%8D%8F%E8%AE%AE%EF%BC%8C%E9%80%9A%E8%BF%87%E5%8E%8B%E7%BC%A9%EF%BC%8C%E5%A4%9A%E8%B7%AF%E5%A4%8D%E7%94%A8(%E4%B8%80%E4%B8%AATCP%E9%93%BE%E6%8E%A5%E4%BC%A0%E9%80%81%E7%BD%91%E9%A1%B5%E5%92%8C%E5%9B%BE%E7%89%87%E7%AD%89%E8%B5%84%E6%BA%90))和优先级来缩短加载时间。 (2) 如果SPDY不可用，利用连接池减少请求延迟 (3) Gzip压缩 (4) Response缓存减少不必要的请求\n                              \n\n                              \n                              \n\n                                \n\n                                  **8. Retrofit RESTFUL API设计** 项目地址：[https://github.com/square/retrofit](https://github.com/square/retrofit) 文档介绍：[http://square.github.io/retrofit/](http://square.github.io/retrofit/)\n                                \n\n                                \n                                \n\n                                  \n\n                                    **四、数据库 orm工具包** orm的db工具类，简化建表、查询、更新、插入、事务、索引的操作 **1. greenDAO Android Sqlite orm的db工具类** 项目地址：[https://github.com/greenrobot/greenDAO](https://github.com/greenrobot/greenDAO) 文档介绍：[http://greendao-orm.com/documentation/](http://greendao-orm.com/documentation/) 官方网站：[http://greendao-orm.com/](http://greendao-orm.com/) 特点：(1)性能佳 (2) 简单易用的API (3) 内存小好小 (4) 库大小小\n                                  \n\n                                  \n                                  \n\n                                    \n\n                                      **2. ActiveAndroid Android Sqlite orm的db工具类** 项目地址：[https://github.com/pardom/ActiveAndroid](https://github.com/pardom/ActiveAndroid) 文档介绍：[https://github.com/pardom/ActiveAndroid/wiki/_pages](https://github.com/pardom/ActiveAndroid/wiki/_pages)\n                                    \n\n                                    \n                                    \n\n                                      \n\n                                        **3. Sprinkles Android Sqlite orm的db工具类** 项目地址：[https://github.com/emilsjolander/sprinkles](https://github.com/emilsjolander/sprinkles) 文档介绍：[http://emilsjolander.github.io/blog/2013/12/18/android-with-sprinkles/](http://emilsjolander.github.io/blog/2013/12/18/android-with-sprinkles/) 特点：比较显著的特点就是配合[https://github.com/square/retrofit](https://github.com/square/retrofit)能保存从服务器获取的数据\n                                      \n\n                                      \n                                      \n\n                                        \n\n                                          **五、Android公共库** **1. Guava Google的基于java1.6的类库集合的扩展项目**\n                                        \n\n                                        \n                                        \n\n                                          包括collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O等等. 这些高质量的API可以使你的JAVa代码更加优雅，更加简洁 项目地址：[https://code.google.com/p/guava-libraries/](https://code.google.com/p/guava-libraries/) 文档介绍：[https://code.google.com/p/guava-libraries/wiki/GuavaExplained](https://code.google.com/p/guava-libraries/wiki/GuavaExplained)\n                                        \n\n                                        \n                                        \n\n                                          \n\n                                            **2. AndroidCommon Android公共库** 项目地址：[https://github.com/Trinea/AndroidCommon](https://github.com/Trinea/AndroidCommon) Demo地址：[https://play.google.com/store/apps/details?id=cn.trinea.android.demo](https://play.google.com/store/apps/details?id=cn.trinea.android.demo) 文档介绍：[http://www.trinea.cn/?p=778](http://www.trinea.cn/?p=778) 包括：(1)缓存(图片缓存、预取缓存、网络缓存) (2) 公共View(下拉及底部加载更多ListView、底部加载更多ScrollView、滑动一页Gallery) (3) Android常用工具类(网络、下载、Android资源操作、shell、文件、Json、随机数、Collection等等)\n                                          \n\n                                          \n                                          \n\n                                            \n\n                                              **六、Android 高版本向低版本兼容** **1. ActionBarSherlock 为Android所有版本提供统一的ActionBar，解决4.0以下ActionBar的适配问题** 项目地址：[https://github.com/JakeWharton/ActionBarSherlock](https://github.com/JakeWharton/ActionBarSherlock) Demo地址：[https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.demos](https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.demos) APP示例：太多了。。现在连google都在用\n                                            \n\n                                            \n                                            \n\n                                              \n\n                                                **2. Nine Old Androids 将Android 3.0(Honeycomb)所有动画API(ObjectAnimator ValueAnimator等)兼容到Android1.0** 项目地址：[https://github.com/JakeWharton/NineOldAndroids](https://github.com/JakeWharton/NineOldAndroids) Demo地址：[https://play.google.com/store/apps/details?id=com.jakewharton.nineoldandroids.sample](https://play.google.com/store/apps/details?id=com.jakewharton.nineoldandroids.sample) 文档介绍：[http://nineoldandroids.com/](http://nineoldandroids.com/)\n                                              \n\n                                              \n                                              \n\n                                                \n\n                                                  **3. HoloEverywhere 将Android 3.0的Holo主题兼容到Android2.1++** 项目地址：[https://github.com/Prototik/HoloEverywhere](https://github.com/Prototik/HoloEverywhere) Demo地址：[https://raw.github.com/Prototik/HoloEverywhere/repo/org/holoeverywhere/demo/2.1.0/demo-2.1.0.apk](https://raw.github.com/Prototik/HoloEverywhere/repo/org/holoeverywhere/demo/2.1.0/demo-2.1.0.apk) 文档介绍：[http://android-developers.blogspot.com/2012/01/holo-everywhere.html](http://android-developers.blogspot.com/2012/01/holo-everywhere.html)\n                                                \n\n                                                \n                                                \n\n                                                  \n\n                                                    **七、多媒体相关** **1. cocos2d-x 跨平台的2d游戏框架，支持Android、IOS、Linux、Windows等众多平台** 项目地址：[https://github.com/cocos2d/cocos2d-x](https://github.com/cocos2d/cocos2d-x) 文档介绍：[http://www.cocos2d-x.org/wiki](http://www.cocos2d-x.org/wiki) 官方网站：[http://www.cocos2d-x.org/](http://www.cocos2d-x.org/)\n                                                  \n\n                                                  \n                                                  \n\n                                                    \n\n                                                      **2. Vitamio 是一款Android与iOS平台上的全能多媒体开发框架** 项目地址：[https://github.com/yixia/VitamioBundle](https://github.com/yixia/VitamioBundle) 网站介绍：[http://www.vitamio.org/docs/](http://www.vitamio.org/docs/) 特点：(1) 全面支持硬件解码与GPU渲染 (2) 能够流畅播放720P甚至1080P高清MKV，FLV，MP4，MOV，TS，RMVB等常见格式的视频 (3) 在Android与iOS上跨平台支持 MMS, RTSP, RTMP, HLS(m3u8)等常见的多种视频流媒体协议，包括点播与直播。\n                                                    \n\n                                                    \n                                                    \n\n                                                      \n\n                                                        **3. PhotoProcessing 利用ndk处理图片库**，支持Instafix、Ansel、Testino、XPro、Retro、BW、Sepia、Cyano、Georgia、Sahara、HDR、Rotate、Flip 项目地址：[https://github.com/lightbox/PhotoProcessing](https://github.com/lightbox/PhotoProcessing) Demo地址：[https://github.com/Trinea/TrineaDownload/blob/master/photo-processing.apk?raw=true](https://github.com/Trinea/TrineaDownload/blob/master/photo-processing.apk?raw=true)\n                                                      \n\n                                                      \n                                                      \n\n                                                        \n\n                                                          **4. Android StackBlur 图片模糊效果工具类** 项目地址：[https://github.com/kikoso/android-stackblur](https://github.com/kikoso/android-stackblur) Demo地址：[https://github.com/kikoso/android-stackblur/blob/master/StackBlurDemo/bin/StackBlurDemo.apk?raw=true](https://github.com/kikoso/android-stackblur/blob/master/StackBlurDemo/bin/StackBlurDemo.apk?raw=true) 文档介绍：[https://github.com/kikoso/android-stackblur#usage](https://github.com/kikoso/android-stackblur#usage)\n                                                        \n\n                                                        \n                                                        \n\n                                                          \n\n                                                            **八、其他** **1. Salvage view 带View缓存的Viewpager PagerAdapter，很方便使用** 项目地址：[https://github.com/JakeWharton/salvage](https://github.com/JakeWharton/salvage)\n                                                          \n\n                                                          \n                                                          \n\n                                                            \n\n                                                              **2. Android-PasscodeLock 应用锁**，每次启动或从任何Activity启动应用都需要输入四位数字的密码方可进入 项目地址：[https://github.com/wordpress-mobile/Android-PasscodeLock](https://github.com/wordpress-mobile/Android-PasscodeLock) Demo地址：[https://play.google.com/store/apps/details?id=com.sothree.umano](https://play.google.com/store/apps/details?id=com.sothree.umano) APP示例：Wordpress Android，支付宝，挖财\n                                                            \n\n                                                            \n                                                            \n\n                                                              \n\n                                                                **3. android-lockpattern Android的图案密码解锁**\n                                                              \n\n                                                              \n                                                              \n\n                                                                项目地址：[https://code.google.com/p/android-lockpattern/](https://code.google.com/p/android-lockpattern/) Demo地址：[https://play.google.com/store/apps/details?id=group.pals.android.lib.ui.lockpattern.demo](https://play.google.com/store/apps/details?id=group.pals.android.lib.ui.lockpattern.demo) 使用介绍：[https://code.google.com/p/android-lockpattern/wiki/QuickUse](https://code.google.com/p/android-lockpattern/wiki/QuickUse) 示例APP：Android开机的图案密码解锁，支付宝的密码解锁\n                                                              \n\n                                                              \n                                                              \n\n                                                                \n\n                                                                  **4. GlowPadBackport将Android4.2的锁屏界面解锁扩展到Android1.6及1.6+** 项目地址：[https://github.com/rock3r/GlowPadBackport](https://github.com/rock3r/GlowPadBackport) Demo地址：[https://play.google.com/store/apps/details?id=net.sebastianopoggi.samples.ui.GlowPadSample](https://play.google.com/store/apps/details?id=net.sebastianopoggi.samples.ui.GlowPadSample) 效果图：[https://lh6.ggpht.com/U070b6Lh6cVsVwx4jN-5nq0xqiB1PBzrYABPeJIEe2hZQ5UWOxc-FDUG77wADelToHA=h310-rw](https://lh6.ggpht.com/U070b6Lh6cVsVwx4jN-5nq0xqiB1PBzrYABPeJIEe2hZQ5UWOxc-FDUG77wADelToHA=h310-rw)\n                                                                \n\n                                                                \n                                                                \n\n                                                                  \n\n                                                                    **5. GlowPadView Android4锁屏界面解锁** 项目地址：[https://github.com/nadavfima/GlowPadView](https://github.com/nadavfima/GlowPadView) 效果图：[https://raw.github.com/nadavfima/GlowPadView/master/example.png](https://raw.github.com/nadavfima/GlowPadView/master/example.png)\n                                                                  \n\n                                                                  \n                                                                  \n\n                                                                    \n\n                                                                      **6. Android Priority Job Queue Android后台任务队列**\n                                                                    \n\n                                                                    \n                                                                    \n\n                                                                      项目地址：[https://github.com/path/android-priority-jobqueue](https://github.com/path/android-priority-jobqueue) 文档介绍：[https://github.com/path/android-priority-jobqueue#getting-started](https://github.com/path/android-priority-jobqueue#getting-started)\n                                                                    \n\n                                                                    \n                                                                    \n\n                                                                      \n\n                                                                        **7. jsoup 一个解析html的java库，可方便的提取和操作数据** 项目地址：[https://github.com/jhy/jsoup](https://github.com/jhy/jsoup) 官方网站：[http://jsoup.org/](http://jsoup.org/) 作用：(1) 从一个url、文件或string获得html并解析 (2) 利用dom遍历或css选择器查找、提取数据 (3) 操作html元素 (4) 根据白名单去除用于提交的非法数据防止xss攻击 (5) 输出整齐的html\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                        \n\n                                                                          **8.ZIP java压缩和解压库** 项目地址：[https://github.com/zeroturnaround/zt-zip](https://github.com/zeroturnaround/zt-zip) 文档介绍：[https://github.com/zeroturnaround/zt-zip#examples](https://github.com/zeroturnaround/zt-zip#examples) 作用：(1) 解压和压缩，并支持文件夹内递归操作 (2) 支持包含和排除某些元素 (3) 支持重命名元素 (4) 支持遍历zip包内容 (5) 比较两个zip包等功能\n                                                                        \n\n                                                                        \n                                                                        \n\n                                                                          \n\n                                                                            **9. Cobub Razor 开源的mobile行为分析系统**，包括web端、android端，支持ios和window phone 项目地址：[https://github.com/cobub/razor](https://github.com/cobub/razor) Demo地址：[http://demo.cobub.com/razor](http://demo.cobub.com/razor) 网站介绍：[http://dev.cobub.com/](http://dev.cobub.com/)\n                                                                          \n\n                                                                          \n                                                                          \n\n                                                                            \n\n                                                                              **10. aFileChooser 文件选择器**，可内嵌到程序中，而无需使用系统或三方文件选择器。 项目地址：[https://github.com/iPaulPro/aFileChooser](https://github.com/iPaulPro/aFileChooser)\n                                                                            \n\n                                                                            \n                                                                            \n\n                                                                              \n\n                                                                                **11. androidpn 基于xmpp协议的消息推送解决方案**，包括服务器端和android端。 项目地址：[https://github.com/dannytiehui/androidpn](https://github.com/dannytiehui/androidpn)\n                                                                              \n\n                                                                              \n                                                                              \n\n                                                                                \n\n                                                                                  **12. Android插件式开发** 项目地址：[https://github.com/umeng/apf](https://github.com/umeng/apf)\n\u003c/code\u003e\u003c/pre\u003e","title":"Android开源项目第二篇——工具库篇"},{"content":"本文为那些不错的Android开源项目第一篇——个性化控件(View)篇，主要介绍Android上那些不错个性化的View，包括ListView、ActionBar、Menu、ViewPager、Gallery、GridView、ImageView、ProgressBar及其他如Dialog、Toast、EditText、TableView、Activity Animation等等。\n最新内容请访问[AndroidOpenProject@Github](https://github.com/Trinea/android-open-project)，欢迎Star和Fork。 对你有帮助的话，去知乎点个赞让更多人了解：[Android 优秀开源项目及特效推荐](http://www.zhihu.com/question/19804692/answer/21890050)。 Android开源项目系列汇总已完成，包括： [Android开源项目第一篇——个性化控件(View)篇](http://www.trinea.cn/android/android-open-source-projects-view/) Android开源项目第二篇——工具库篇 Android开源项目第三篇——优秀项目篇 Android开源项目第四篇——开发及测试工具篇 Android开源项目第五篇——优秀个人和团体篇\n本文中你可以找到那些精美App中各种有特性的View，如Gmail的左滑出菜单、Google plus的卡片式ListView，Pinterest的瀑布流，微信的左滑删除，微博的个页面下拉刷新等等。长期更新，欢迎大家补充和推荐^_^ **一、ListView** **1. android-pulltorefresh 一个强大的拉动刷新开源项目，支持各种控件下拉刷新** ListView、ViewPager、WevView、ExpandableListView、GridView、(Horizontal )ScrollView、Fragment上下左右拉动刷新，比下面johannilsson那个只支持ListView的强大的多。并且他实现的下拉刷新ListView在item不足一屏情况下也不会显示刷新提示，体验更好。 项目地址：https://github.com/chrisbanes/Android-PullToRefresh Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/pull-to-refreshview-demo.apk?raw=true\nAPP示例：新浪微博各个页面 **2. android-pulltorefresh-listview 下拉刷新ListView** 项目地址：https://github.com/johannilsson/android-pulltorefresh Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/pull-to-refresh-listview-demo.apk?raw=true PS：这个被很多人使用的项目实际有不少bug，推荐使用上面的android-pulltorefresh\n**3. DropDownListView 下拉刷新及滑动到底部加载更多ListView** 项目地址：https://github.com/Trinea/AndroidCommon Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/TrineaAndroidDemo.apk?raw=true 文档介绍：http://www.trinea.cn/?p=523\n**4. DragSortListView 拖动排序的ListView** 同时支持ListView滑动item删除，各个Item高度不一、单选、复选、CursorAdapter做为适配器、拖动背景变化等 项目地址：https://github.com/bauerca/drag-sort-listview Demo地址：https://play.google.com/store/apps/details?id=com.mobeta.android.demodslv APP示例：Wordpress Android\n**5. SwipeListView 支持定义ListView左右滑动事件，支持左右滑动位移，支持定义动画时间** 项目地址：https://github.com/47deg/android-swipelistview Demo地址：https://play.google.com/store/apps/details?id=com.fortysevendeg.android.swipelistview APP示例：微信\n**6. Android-SwipeToDismiss 滑动Item消失ListView** 项目地址：https://github.com/romannurik/Android-SwipeToDismiss 支持3.0以下版本见：https://github.com/JakeWharton/SwipeToDismissNOA Demo地址：https://github.com/JakeWharton/SwipeToDismissNOA/SwipeToDismissNOA.apk/qr_code\n**7. StickyListHeaders GroupName滑动到顶端时会固定不动直到另外一个GroupName到达顶端的ExpandListView，支持快速滑动，支持Android2.3及以上** 项目地址：[https://github.com/emilsjolander/StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) APP示例：Android 4.0联系人 效果图：[https://raw.github.com/emilsjolander/StickyListHeaders/master/demo.gif](https://raw.github.com/emilsjolander/StickyListHeaders/master/demo.gif) **8. pinned-section-listview GroupName滑动到顶端时会固定不动直到另外一个GroupName到达顶端的ExpandListView** 项目地址：https://github.com/beworker/pinned-section-listview 效果图：https://raw.github.com/beworker/pinned-section-listview/master/screen1.png\n**9. PinnedHeaderListView GroupName滑动到顶端时会固定不动直到另外一个GroupName到达顶端的ExpandListView** 项目地址：https://github.com/JimiSmith/PinnedHeaderListView\n**10. QuickReturnHeader ListView/ScrollView的header或**footer**，当向下滚动时消失，向上滚动时出现** 项目地址：https://github.com/ManuelPeinado/QuickReturnHeader Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/quick-return-header-demo.apk?raw=true APP示例：google plus\n** 11. IndexableListView ListView右侧会显示item首字母快捷索引，点击可快速滑动到某个item** 项目地址：[https://github.com/woozzu/IndexableListView](https://github.com/woozzu/IndexableListView) Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/indexable-listview.apk?raw=true APP示例：微信通讯录、小米联系人\n**12. CustomFastScrollView ListView快速滑动，同时屏幕中间PopupWindows显示滑动到的item内容或首字母** 项目地址：https://github.com/nolanlawson/CustomFastScrollViewDemo 效果图：https://raw.github.com/nolanlawson/CustomFastScrollViewDemo/master/example.png\n**13. Android-ScrollBarPanel ListView滑动时固定的Panel指示显示在scrollbar旁边** 项目地址：https://github.com/rno/Android-ScrollBarPanel 效果展示：https://github.com/rno/Android-ScrollBarPanel/raw/master/demo_capture.png\n**14. SlideExpandableListView 用户点击listView item滑出固定区域，其他item的区域收缩** 项目地址：https://github.com/tjerkw/Android-SlideExpandableListView Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/slide-expandable-listView-demo.apk?raw=true\n**15. JazzyListView ListView及GridView item以特殊动画效果进入屏幕，效果包括grow、cards、curl、wave、flip、fly等等** 项目地址：[https://github.com/twotoasters/JazzyListView](https://github.com/twotoasters/JazzyListView) Demo地址：https://play.google.com/store/apps/details?id=com.twotoasters.jazzylistview.sample 效果展示：http://lab.hakim.se/scroll-effects/\n**16. ListViewAnimations 带Item显示动画的ListView，动画包括底部飞入、其他方向斜飞入、下层飞入、渐变消失、滑动删除等** 项目地址：https://github.com/nhaarman/ListViewAnimations Demo地址：https://play.google.com/store/apps/details?id=com.haarman.listviewanimations APP示例：Google plus、Google Now卡片式进入、小米系统中应用商店、联系人、游戏中心、音乐、文件管理器的ListView、Ultimate、Light Flow Lite、TreinVerkeer、Running Coach、Pearl Jam Lyrics、Calorie Chart、Car Hire、Super BART、DK FlashCards、Counter Plus、Voorlees Verhaaltjes 2.0\n**17. DevsmartLib-Android 横向ListView** 项目地址：https://github.com/dinocore1/DevsmartLib-Android Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/horizontal-listview-demo.apk?raw=true\n**二、ActionBar** **1. ActionBarSherlock 为Android所有版本提供统一的ActionBar，解决4.0以下ActionBar的适配问题** 项目地址：https://github.com/JakeWharton/ActionBarSherlock Demo地址：https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.demos APP示例：太多了。。现在连google都在用\n**2. ActionBar-PullToRefresh 下拉刷新，ActionBar出现加载中提示** 项目地址：https://github.com/chrisbanes/ActionBar-PullToRefresh Demo地址：https://play.google.com/store/apps/details?id=uk.co.senab.actionbarpulltorefresh.samples.stock APP示例：Gmail，Google plus，知乎等\n**3. FadingActionBar ListView向下滚动逐渐显现的ActionBar** 项目地址：[https://github.com/ManuelPeinado/FadingActionBar](https://github.com/ManuelPeinado/FadingActionBar) Demo地址：https://play.google.com/store/apps/details?id=com.manuelpeinado.fadingactionbar.demo APP示例：google music，知乎\n**4. NotBoringActionBar google music下拉收缩的ActionBar** 项目地址：https://github.com/flavienlaurent/NotBoringActionBar Demo地址：http://flavienlaurent.com/blog/2013/11/20/making-your-action-bar-not-boring/ APP示例：Google音乐\n**5. RefreshActionItem 带进度显示和刷新按钮的ActionBar** 项目地址：https://github.com/ManuelPeinado/RefreshActionItem Demo地址：https://play.google.com/store/apps/details?id=com.manuelpeinado.refreshactionitem.demo APP示例：The New York Times，DevAppsDirect.\n**6. GlassActionBar 类似玻璃的有一定透明度的ActionBar** 项目地址：https://github.com/ManuelPeinado/GlassActionBar Demo地址：https://play.google.com/store/apps/details?id=com.manuelpeinado.glassactionbardemo APP示例：google music\n**三、Menu ** **1. MenuDrawer 滑出式菜单**，通过拖动屏幕边缘滑出菜单，支持屏幕上下左右划出，支持当前View处于上下层，支持Windows边缘、ListView边缘、ViewPager变化划出菜单等。 项目地址：https://github.com/SimonVT/android-menudrawer Demo地址：http://simonvt.github.io/android-menudrawer/ APP示例：Gmail、Google Music等大部分google app\n**2. SlidingMenu 滑出式菜单**，通过拖动屏幕边缘滑出菜单，支持屏幕左右划出，支持菜单zoom、scale、slide up三种动画样式出现。 项目地址：https://github.com/jfeinstein10/SlidingMenu Demo地址：https://play.google.com/store/apps/details?id=com.slidingmenu.example APP示例：Foursquare, LinkedIn, Zappos, Rdio, Evernote Food, Plume, VLC for Android, ESPN ScoreCenter, MLS MatchDay, 9GAG, Wunderlist 2, The Verge, MTG Familiar, Mantano Reader, Falcon Pro (BETA), MW3 Barracks MenuDrawer和SlidingMenu比较：SlidingMenu支持菜单动画样式出现，MenuDrawer支持菜单view处于内容的上下层\n**3. ArcMenu 支持类似Path的左下角动画旋转菜单及横向划出菜单、圆心弹出菜单** 项目地址：https://github.com/daCapricorn/ArcMenu APP示例：Path 效果图：(有墙)https://dl.dropboxusercontent.com/u/11369687/preview0.png https://dl.dropboxusercontent.com/u/11369687/preview1.png https://dl.dropboxusercontent.com/u/11369687/raymenu.png\n**4. android-satellite-menu 类似Path的左下角动画旋转菜单** 项目地址：[https://github.com/siyamed/android-satellite-menu](https://github.com/siyamed/android-satellite-menu) Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/satellite-menu-demo.apk?raw=true APP示例：Path\n**5. radial-menu-widget 圆形菜单，支持二级菜单** 项目地址：https://code.google.com/p/radial-menu-widget/ 效果图：http://farm8.staticflickr.com/7377/11621125154_d1773c2dcc_o.jpg\n**6. Android Wheel Menu 圆形旋转选取菜单** 项目地址：[https://github.com/anupcowkur/Android-Wheel-Menu](https://github.com/anupcowkur/Android-Wheel-Menu) 效果图：https://raw.github.com/anupcowkur/Android-Wheel-Menu/master/graphics/wheel.gif\n**7. FoldingNavigationDrawer滑动并以折叠方式打开菜单** 项目地址：https://github.com/tibi1712/FoldingNavigationDrawer-Android 使用介绍：https://play.google.com/store/apps/details?id=com.ptr.folding.sample 效果图：https://lh6.ggpht.com/VnKUZenAozQ0KFAm5blFTGqMaKFjvX-BK2JH-jrX1sIXVTqciACqRhqFH48hc4pm2Q=h310-rw\n**四、ViewPager 、Gallery** **1. Android-ViewPagerIndicator 配合ViewPager使用的Indicator，支持各种位置和样式** 项目地址：https://github.com/JakeWharton/Android-ViewPagerIndicator Demo地址：https://play.google.com/store/apps/details?id=com.viewpagerindicator.sample APP示例：太多了。。\n**2. JazzyViewPager 支持Fragment切换动画的ViewPager，动画包括转盘、淡入淡出、翻页、层叠、旋转、方块、翻转、放大缩小等** 项目地址：https://github.com/jfeinstein10/JazzyViewPager Demo地址：https://github.com/jfeinstein10/JazzyViewPager/blob/master/JazzyViewPager.apk?raw=true 效果图：类似桌面左右切换的各种效果，不过桌面并非用ViewPager实现而已\n**3. Android-DirectionalViewPager 支持横向和纵向(垂直)的ViewPager** 项目地址：[https://github.com/JakeWharton/Android-DirectionalViewPager](https://github.com/JakeWharton/Android-DirectionalViewPager) Demo地址：https://market.android.com/details?id=com.directionalviewpager.sample\n**4. android-pulltorefresh 支持下拉刷新的ViewPager** 项目地址：[https://github.com/chrisbanes/Android-PullToRefresh](https://github.com/chrisbanes/Android-PullToRefresh) Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/pull-to-refreshview-demo.apk?raw=true\nAPP示例：新浪微博各个页面 **5. FancyCoverFlow支持Item切换动画效果的类似Gallery View** 项目地址：https://github.com/davidschreiber/FancyCoverFlow Demo地址：https://play.google.com/store/apps/details?id=at.technikum.mti.fancycoverflow.samples 效果图：https://github-camo.global.ssl.fastly.net/ef5ced52b7b54652b50499521ed797c0188c7a6b/687474703a2f2f64617669647363687265696265722e6769746875622e696f2f46616e6379436f766572466c6f772f73637265656e73686f74322e706e67\n**6. AndroidTouchGallery 支持双击或双指缩放的Gallery(用ViewPager实现)** 相比下面的PhotoView，在被放大后依然能滑到下一个item，并且支持直接从url和文件中获取图片， 项目地址：https://github.com/Dreddik/AndroidTouchGallery Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/touch-gallery-demo.apk?raw=true APP示例：类似微信中查看聊天记录图片时可双击放大，并且放大情况下能正常左右滑动到前后图片\n**7. Salvage view 带View缓存的Viewpager PagerAdapter，很方便使用** 项目地址：[https://github.com/JakeWharton/salvage](https://github.com/JakeWharton/salvage) **五、GridView** **1. StaggeredGridView 允许非对齐行的GridView** 类似Pinterest的瀑布流，并且跟ListView一样自带View缓存，继承自ViewGroup 项目地址：https://github.com/maurycyw/StaggeredGridView Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/staggered-gridview-demo.apk?raw=true APP示例：Pinterest等\n**2. AndroidStaggeredGrid 允许非对齐行的GridView** 类似Pinterest的瀑布流，继承自AbsListView 项目地址：https://github.com/etsy/AndroidStaggeredGrid\nAPP示例：Pinterest等 **3. PinterestLikeAdapterView 允许非对齐行的GridView** 类似Pinterest的瀑布流，允许下拉刷新 项目地址：https://github.com/huewu/PinterestLikeAdapterView\nAPP示例：Pinterest等 **4. DraggableGridView Item可拖动交换位置的GridView，类似桌面的单屏效果** 项目地址：https://github.com/thquinn/DraggableGridView Demo地址：https://github.com/thquinn/DraggableGridView/blob/master/bin/DraggableGridViewSample.apk?raw=true\n**六、ImageView** **1. PhotoView 支持双击或双指缩放的ImageView** 在ViewPager等Scrolling view中正常使用，相比上面的AndroidTouchGallery，不仅支持ViewPager，同时支持单个ImageView 项目地址：https://github.com/chrisbanes/PhotoView Demo地址：https://play.google.com/store/apps/details?id=uk.co.senab.photoview.sample APP示例：photup\n**2. android-gif-drawable 支持fig显示的view** 项目地址：https://github.com/koral–/android-gif-drawable\n用jni实现的，编译生成so库后直接xml定义view即可，而且本身不依赖于其他开源项目，所以相对下面的ImageViewEx简单的多 **3. ImageViewEx 支持Gif显示的ImageView** 项目地址：[https://github.com/frapontillo/ImageViewEx](https://github.com/frapontillo/ImageViewEx)， Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/imageviewex-demo.apk?raw=true\n依赖很多，编译过程很繁琐!|_|! **4. RoundedImageView 带圆角的ImageView** 项目地址：[https://github.com/vinc3m1/RoundedImageView](https://github.com/vinc3m1/RoundedImageView) 效果图：https://raw.github.com/makeramen/RoundedImageView/master/screenshot.png\n**七、ProgressBar** **1. SmoothProgressBar 水平进度条** 项目地址：[https://github.com/castorflex/SmoothProgressBar](https://github.com/castorflex/SmoothProgressBar) Demo地址：https://play.google.com/store/apps/details?id=fr.castorflex.android.smoothprogressbar.sample\n**2. ProgressWheel 支持进度显示的圆形ProgressBar** 项目地址：https://github.com/Todd-Davies/ProgressWheel Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/progress-wheel-demo.apk?raw=true\n**3. android-square-progressbar 在图片周围显示进度** 项目地址：https://github.com/mrwonderman/android-square-progressbar Demo地址：https://play.google.com/store/apps/details?id=net.yscs.android.square_progressbar_example APP示例：square 效果图：https://googledrive.com/host/0BwESwPCuXtw7eExwSFVLQkR2TTg/newscreen1.png\n**4. HoloCircularProgressBar Android4.1 时钟App样式** 项目地址：https://github.com/passsy/android-HoloCircularProgressBar APP示例：Android4.1时钟App 效果图：https://raw.github.com/passsy/android-HoloCircularProgressBar/master/raw/screenshot1.png\n**八、其他** **1. achartengine 强大的图标绘制工具** 支持折线图、面积图、散点图、时间图、柱状图、条图、饼图、气泡图、圆环图、范围（高至低）条形图、拨号图/表、立方线图及各种图的结合 项目地址：https://code.google.com/p/achartengine/ 官方网站：http://www.achartengine.org/ 效果图：http://www.achartengine.org/dimages/average_temperature.png http://www.achartengine.org/dimages/sales_line_and_area_chart.png http://www.achartengine.org/dimages/temperature_range_chart.png http://www.achartengine.org/dimages/combined_chart.png http://www.achartengine.org/dimages/budget_chart.png\nAPP示例：Wordpress Android，Google Analytics **2. GraphView 绘制图表和曲线图的View** 可用于Android上的曲形图、柱状图、波浪图展示 项目地址：https://github.com/jjoe64/GraphView Demo工程：https://github.com/jjoe64/GraphView-Demos Demo地址：https://play.google.com/store/apps/details?id=com.sothree.umano APP示例：Wordpress Android，Google Analytics\n**3. android-flip 类似Flipboard翻转动画的实现** 项目地址：https://github.com/openaphid/android-flip Demo地址：https://github.com/openaphid/android-flip/blob/master/FlipView/Demo/APK/Aphid-FlipView-Demo.apk?raw=true\nAPP示例：[flipboard](https://play.google.com/store/apps/details?id=flipboard.app) **4. FlipImageView 支持x、y、z及动画选择的翻转动画的实现** 项目地址：https://github.com/castorflex/FlipImageView Demo地址：https://play.google.com/store/apps/details?id=fr.castorflex.android.flipimageview\n**5. SwipeBackLayout 左右或向上滑动返回的Activity** 项目地址：[https://github.com/Issacw0ng/SwipeBackLayout](https://github.com/Issacw0ng/SwipeBackLayout) Demo地址：https://play.google.com/store/apps/details?id=me.imid.swipebacklayout.demo APP示例：知乎\n**6. Cards-UI 卡片式View，支持单个卡片，item为卡片的ListView** 项目地址：https://github.com/afollestad/Cards-UI Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/cards-ui-demo.apk?raw=true\n**7. cardslib 卡片式View，支持单个卡片，item为卡片的ListView和GridView** 项目地址：https://github.com/gabrielemariotti/cardslib Demo地址：https://play.google.com/store/apps/details?id=it.gmariotti.cardslib.demo\n**8. android-styled-dialogs 可自定义样式的dialog** 默认与Holo主题样式一致，在Android2.2以上同一样式 项目地址：https://github.com/inmite/android-styled-dialogs Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/styled-dialogs-demo.apk?raw=true\n**9. Crouton 丰富样式的Toast** 允许alert、comfirm、info样式及点击消失样式，允许设置Toast显示时间，允许自定义View。 项目地址：https://github.com/keyboardsurfer/Crouton Demo地址：http://play.google.com/store/apps/details?id=de.keyboardsurfer.app.demo.crouton\n**10. supertooltips 带动画效果的Tips显示** 项目地址：https://github.com/nhaarman/supertooltips Demo地址：https://play.google.com/store/apps/details?id=com.haarman.supertooltips\n**11. Android ViewBadger为其他View添加角标等** 项目地址：https://github.com/jgilfelt/android-viewbadger\nDemo地址：[https://github.com/Trinea/TrineaDownload/blob/master/android-viewbadger.apk?raw=true](https://github.com/Trinea/TrineaDownload/blob/master/android-viewbadger.apk?raw=true) 效果图：https://github-camo.global.ssl.fastly.net/a705a3e88c75ae2394943bd7c56f725697616ea8/687474703a2f2f7777772e6a65666667696c66656c742e636f6d2f766965776261646765722f76622d31612e706e67\n**12. Android Sliding Up Panel 可拖动的View，能在当前Activity上扶起一个可拖动的Panel** 项目地址：[https://github.com/umano/AndroidSlidingUpPanel](https://github.com/umano/AndroidSlidingUpPanel) Demo地址：https://play.google.com/store/apps/details?id=com.sothree.umano APP示例：Google Music精简播放栏\n**13. android-times-square Android日历部件** 支持选取单个日期，多个日期，及日期区间段和对话框形式显示 项目地址：https://github.com/square/android-times-square Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/times-square-demo.apk?raw=true\n**14. android-calendar-card 日历** 项目地址：https://github.com/kenumir/android-calendar-card Demo地址：https://play.google.com/store/apps/details?id=com.wt.calendarcardsample 效果图：https://raw.github.com/kenumir/android-calendar-card/master/calendar-card-sample/_work/device-2013-10-12-151801.png\n**15. ColorPickerView 颜色选择器，支持PopupWindows或新的Activity中打开** 项目地址：[https://code.google.com/p/color-picker-view/](https://code.google.com/p/color-picker-view/) 效果图：http://oi41.tinypic.com/33c6mm8.jpg\n**16. HoloColorPicker 颜色选择器** 项目地址：https://github.com/LarsWerkman/HoloColorPicker Demo地址：https://docs.google.com/file/d/0BwclyDTlLrdXRzVnTGJvTlRfU2s/edit\n**17. AndroidWheel Android Wheel支持城市、多种日期时间、密码、图片** 项目地址：https://github.com/sephiroth74/AndroidWheel 效果图：http://farm6.staticflickr.com/5532/11621528786_220c040ba5_o.jpg\n**18. android-flowtextview文字自动环绕其他View的Layout** 项目地址：https://code.google.com/p/android-flowtextview/ 效果图：http://i949.photobucket.com/albums/ad332/vostroman1500/1.png\n**19. Segmented Radio Buttons for Android iOS’s segmented controls的实现** 项目地址：https://github.com/vinc3m1/android-segmentedradiobutton Demo地址：https://github.com/thquinn/DraggableGridView/blob/master/bin/DraggableGridViewSample.apk?raw=true 效果图：https://raw.github.com/vinc3m1/android-segmentedradiobutton/master/screens/segmentedradio.png\n**20. TableFixHeaders 第一列固定的Table** 项目地址：https://github.com/InQBarna/TableFixHeaders Demo地址：http://bit.ly/13buAIq\n**21. Android Form EditText 验证输入合法性的编辑框** 支持输入、英文、ip、url等多种正则验证 项目地址：https://github.com/vekexasia/android-edittext-validator Demo地址：https://play.google.com/store/apps/details?id=com.andreabaccega.edittextformexample\n**22. UITableView ios风格控件** 包括Button、ListView、TableView 项目地址：https://github.com/thiagolocatelli/android-uitableview Demo地址：https://github.com/Trinea/TrineaDownload/blob/master/ui-tableview-demo.apk?raw=true\n**23. ATableView ios风格控件** 项目地址：https://github.com/dmacosta/ATableView Demo地址：https://play.google.com/store/apps/details?id=com.nakardo.atableview.demo\n**24. UndoBar屏幕底部显示取消或是确认的PopupWindows** 项目地址：https://github.com/soarcn/UndoBar 效果图：https://github.com/soarcn/UndoBar/blob/master/art/redo.png?raw=true\n25. **Inscription可用于展示应用change和new feature信息** 项目地址：https://github.com/MartinvanZ/Inscription\n**26. ActivityTransition Activity切换动画，包括渐变、flip、某个位置进入等等** 项目地址：https://github.com/ophilbert/ActivityTransition 使用介绍：https://github.com/jfeinstein10/JazzyViewPager/blob/master/JazzyViewPager.apk?raw=true 效果图：类似桌面左右切换的各种效果，不过桌面并非用ViewPager实现而已\n**27. Cropper 图片局部剪切工具，可触摸控制选择区域或旋转** 项目地址：https://github.com/edmodo/cropper 使用介绍：https://github.com/edmodo/cropper/wiki 效果图：https://github-camo.global.ssl.fastly.net/e4fde77bf41d4a60b234b4e268e5cfa8c17d9b6f/687474703a2f2f692e696d6775722e636f6d2f334668735467666c2e6a7067\n**28. GlowPadBackport将Android4.2的锁屏界面解锁扩展到Android1.6及1.6+** 项目地址：https://github.com/rock3r/GlowPadBackport Demo地址：https://play.google.com/store/apps/details?id=net.sebastianopoggi.samples.ui.GlowPadSample 效果图：https://lh6.ggpht.com/U070b6Lh6cVsVwx4jN-5nq0xqiB1PBzrYABPeJIEe2hZQ5UWOxc-FDUG77wADelToHA=h310-rw\n**29. GlowPadView Android4锁屏界面解锁** 项目地址：https://github.com/nadavfima/GlowPadView 效果图：https://raw.github.com/nadavfima/GlowPadView/master/example.png\n**30. android-lockpattern Android的图案密码解锁** 项目地址：https://code.google.com/p/android-lockpattern/ Demo地址：https://play.google.com/store/apps/details?id=group.pals.android.lib.ui.lockpattern.demo 使用介绍：https://code.google.com/p/android-lockpattern/wiki/QuickUse 示例APP：Android开机的图案密码解锁，支付宝的密码解锁\n转载：http://www.trinea.cn/android/android-open-source-projects-view/ ","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E7%AC%AC%E4%B8%80%E7%AF%87-%E4%B8%AA%E6%80%A7%E5%8C%96%E6%8E%A7%E4%BB%B6view%E7%AF%87/","summary":"\u003cp\u003e本文为那些不错的Android开源项目第一篇——个性化控件(View)篇，\u003cstrong\u003e主要介绍Android上那些不错个性化的View，包括ListView、ActionBar、Menu、ViewPager、Gallery、GridView、ImageView、ProgressBar及其他如Dialog、Toast、EditText、TableView、Activity Animation等等。\u003c/strong\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e最新内容请访问[AndroidOpenProject@Github](https://github.com/Trinea/android-open-project)，欢迎Star和Fork。\n\n\n\n\n\n对你有帮助的话，去知乎点个赞让更多人了解：[Android 优秀开源项目及特效推荐](http://www.zhihu.com/question/19804692/answer/21890050)。\n\n\n\n\n\n\n\n  Android开源项目系列汇总已完成，包括：\n\n\n\n\n\n  [Android开源项目第一篇——个性化控件(View)篇](http://www.trinea.cn/android/android-open-source-projects-view/)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-dev-lib/\"\u003eAndroid开源项目第二篇——工具库篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-excellent-project/\"\u003eAndroid开源项目第三篇——优秀项目篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-dev-tool/\"\u003eAndroid开源项目第四篇——开发及测试工具篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-excellent-personal-group/\"\u003eAndroid开源项目第五篇——优秀个人和团体篇\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    本文中你可以找到那些精美App中各种有特性的View，如Gmail的左滑出菜单、Google plus的卡片式ListView，Pinterest的瀑布流，微信的左滑删除，微博的个页面下拉刷新等等。长期更新，欢迎大家补充和推荐^_^\n  \n\n  \n  \n\n    \n\n      **一、ListView**\n    \n\n    \n    \n\n      **1. android-pulltorefresh 一个强大的拉动刷新开源项目，支持各种控件下拉刷新**\n    \n\n    \n    \n\n      ListView、ViewPager、WevView、ExpandableListView、GridView、(Horizontal\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e)ScrollView、Fragment上下左右拉动刷新，比下面johannilsson那个只支持ListView的强大的多。并且他实现的下拉刷新ListView在item不足一屏情况下也不会显示刷新提示，体验更好。\n项目地址：\u003ca href=\"https://github.com/chrisbanes/Android-PullToRefresh\"\u003ehttps://github.com/chrisbanes/Android-PullToRefresh\u003c/a\u003e\nDemo地址：\u003ca href=\"https://github.com/Trinea/TrineaDownload/blob/master/pull-to-refreshview-demo.apk?raw=true\"\u003ehttps://github.com/Trinea/TrineaDownload/blob/master/pull-to-refreshview-demo.apk?raw=true\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e      APP示例：新浪微博各个页面\n    \n\n    \n    \n\n      \n\n        **2. android-pulltorefresh-listview 下拉刷新ListView**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/johannilsson/android-pulltorefresh\"\u003ehttps://github.com/johannilsson/android-pulltorefresh\u003c/a\u003e\nDemo地址：\u003ca href=\"https://github.com/Trinea/TrineaDownload/blob/master/pull-to-refresh-listview-demo.apk?raw=true\"\u003ehttps://github.com/Trinea/TrineaDownload/blob/master/pull-to-refresh-listview-demo.apk?raw=true\u003c/a\u003e\nPS：这个被很多人使用的项目实际有不少bug，推荐使用上面的android-pulltorefresh\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e          **3. DropDownListView 下拉刷新及滑动到底部加载更多ListView**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/Trinea/AndroidCommon\"\u003ehttps://github.com/Trinea/AndroidCommon\u003c/a\u003e\nDemo地址：\u003ca href=\"https://github.com/Trinea/TrineaDownload/blob/master/TrineaAndroidDemo.apk?raw=true\"\u003ehttps://github.com/Trinea/TrineaDownload/blob/master/TrineaAndroidDemo.apk?raw=true\u003c/a\u003e\n文档介绍：\u003ca href=\"http://www.trinea.cn/?p=523\"\u003ehttp://www.trinea.cn/?p=523\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e            **4. DragSortListView 拖动排序的ListView**\n          \n\n          \n          \n\n            同时支持ListView滑动item删除，各个Item高度不一、单选、复选、CursorAdapter做为适配器、拖动背景变化等\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/bauerca/drag-sort-listview\"\u003ehttps://github.com/bauerca/drag-sort-listview\u003c/a\u003e\nDemo地址：\u003ca href=\"https://play.google.com/store/apps/details?id=com.mobeta.android.demodslv\"\u003ehttps://play.google.com/store/apps/details?id=com.mobeta.android.demodslv\u003c/a\u003e\nAPP示例：Wordpress Android\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e              **5. SwipeListView 支持定义ListView左右滑动事件，支持左右滑动位移，支持定义动画时间**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/47deg/android-swipelistview\"\u003ehttps://github.com/47deg/android-swipelistview\u003c/a\u003e\nDemo地址：\u003ca href=\"https://play.google.com/store/apps/details?id=com.fortysevendeg.android.swipelistview\"\u003ehttps://play.google.com/store/apps/details?id=com.fortysevendeg.android.swipelistview\u003c/a\u003e\nAPP示例：微信\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e                **6. Android-SwipeToDismiss 滑动Item消失ListView**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/romannurik/Android-SwipeToDismiss\"\u003ehttps://github.com/romannurik/Android-SwipeToDismiss\u003c/a\u003e\n支持3.0以下版本见：\u003ca href=\"https://github.com/JakeWharton/SwipeToDismissNOA\"\u003ehttps://github.com/JakeWharton/SwipeToDismissNOA\u003c/a\u003e\nDemo地址：\u003ca href=\"https://github.com/JakeWharton/SwipeToDismissNOA/SwipeToDismissNOA.apk/qr_code\"\u003ehttps://github.com/JakeWharton/SwipeToDismissNOA/SwipeToDismissNOA.apk/qr_code\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e                  **7. StickyListHeaders GroupName滑动到顶端时会固定不动直到另外一个GroupName到达顶端的ExpandListView，支持快速滑动，支持Android2.3及以上**\n                \n\n                \n                \n\n                  项目地址：[https://github.com/emilsjolander/StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders)\n                \n\n                \n                \n\n                  APP示例：Android 4.0联系人\n                \n\n                \n                \n\n                  效果图：[https://raw.github.com/emilsjolander/StickyListHeaders/master/demo.gif](https://raw.github.com/emilsjolander/StickyListHeaders/master/demo.gif)\n                \n\n                \n                \n\n                  \n\n                    **8. pinned-section-listview GroupName滑动到顶端时会固定不动直到另外一个GroupName到达顶端的ExpandListView**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e项目地址：\u003ca href=\"https://github.com/beworker/pinned-section-listview\"\u003ehttps://github.com/beworker/pinned-section-listview\u003c/a\u003e\n效果图：\u003ca href=\"https://raw.github.com/beworker/pinned-section-listview/master/screen1.png\"\u003ehttps://raw.github.com/beworker/pinned-section-listview/master/screen1.png\u003c/a\u003e\u003c/p\u003e","title":"Android开源项目第一篇——个性化控件(View)篇"},{"content":"1.下载Wamp软件，一步一步安装，完成相关操作。\n浏览器地址栏中输入http://localhost或者http://127.0.0.1 ,页面出现 it works 即为安装成功\n2.我们可以到官网上下载PHP的IDE—Eclipse，下载时区分好操作系统的位数，否则会出现安装错误。\n3.安装好Eclipse之后就要配置调式环境了。其实，Eclipse本身就有zend debug和xdebug俩个插件\n我们只需要将他们中的其一配置好就行了。这里以xdebug的配置为例子。\n打开窗口\nwindow–\u0026gt;preferences 会出现入上图的对话框，点击左侧PHP下边的PHP Executables,然后右侧点击添加(add)\n此处需要提醒一下，一定要找准上图中的两个路径的位置的文件。对于wamp中php.exe文件就在wamp/bin/php/php版本/下边；特别要注意的是php.ini的文件位置，因为在wamp/bin/php/php版本/下边\n也有php.ini文件，而wamp的默认的php.ini却在wamp/bin/apache/Apache版本/bin/php.ini，因此我们要选择最后的路径。如果我们选择了前面的wamp/bin/php/php版本/下边的php.ini路径，即使我们配对了xdebug的环境也是会报错的 eg：the debugger is properly configured as a php.ini directive;随便提起，此种路径只针对wamp，其他的按情况考虑。\n这个是我的php.ini配置\nD:\\wamp\\bin\\apache\\Apache2.4.4\\bin\\php.ini\nzend_extension = “D:/wamp/bin/php/php5.4.12/zend_ext/php_xdebug-2.2.3-5.4-vc9-x86_64.dll”\n[xdebug]\nxdebug.remote_enable = on\nxdebug.profiler_enable = on\nxdebug.profiler_enable_trigger = on\nxdebug.profiler_output_name = cachegrind.out.%t.%p\nxdebug.profiler_output_dir = “E:/wamp/tmp”\n到此配置完成\n启动wamp然后debug运行就行了。\nMac下配置debug和上面类似，下面给出php.ini的配置文件\nzend_extension=/Applications/XAMPP/xamppfiles/lib/php/extensions/no-debug-non-zts-20121212/xdebug.so xdebug.remote_enable=on xdebug.remote_handler=dbgp xdebug.remote_host=localhost xdebug.remote_port=9000 xdebug.profiler_output_dir = /tmp/xdebug/\n","permalink":"https://blog.zdltech.com/posts/wampeclipsephpdebug-%E9%85%8D%E7%BD%AE/","summary":"\u003cp\u003e1.下载Wamp软件，一步一步安装，完成相关操作。\u003c/p\u003e\n\u003cp\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e 浏览器地址栏中输入\u003ca href=\"http://localhost/\"\u003ehttp://localhost\u003c/a\u003e或者http://127.0.0.1 ,页面出现 \u003cwbr /\u003e it works 即为安装成功\u003c/p\u003e\n\u003cp\u003e2.我们可以到官网上下载PHP的IDE—Eclipse，下载时区分好操作系统的位数，否则会出现安装错误。\u003c/p\u003e\n\u003cp\u003e3.安装好Eclipse之后就要配置调式环境了。其实，Eclipse本身就有zend debug和xdebug俩个插件\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.etongwl.com/images/2014/12/002nFr1Zgy6LmM3yhQO2e.jpeg\"\u003e\u003cimg alt=\"002nFr1Zgy6LmM3yhQO2e\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2014/12/002nFr1Zgy6LmM3yhQO2e-300x254.jpeg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e我们只需要将他们中的其一配置好就行了。这里以xdebug的配置为例子。\u003c/p\u003e\n\u003cp\u003e \u003cwbr /\u003e\u003c/p\u003e\n\u003cp\u003e打开窗口\u003c/p\u003e\n\u003cp\u003ewindow–\u0026gt;preferences 会出现入上图的对话框，点击左侧PHP下边的PHP Executables,然后右侧点击添加(add)\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.etongwl.com/images/2014/12/002nFr1Zgy6LmMDq0PV33.jpeg\"\u003e\u003cimg alt=\"002nFr1Zgy6LmMDq0PV33\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2014/12/002nFr1Zgy6LmMDq0PV33-257x300.jpeg\"\u003e\u003c/a\u003e\n此处需要提醒一下，一定要找准上图中的两个路径的位置的文件。对于wamp中php.exe文件就在wamp/bin/php/php版本/下边；特别要注意的是php.ini的文件位置，因为在wamp/bin/php/php版本/下边\u003c/p\u003e\n\u003cp\u003e也有php.ini文件，而wamp的默认的php.ini却在wamp/bin/apache/Apache版本/bin/php.ini，因此我们要选择最后的路径。如果我们选择了前面的wamp/bin/php/php版本/下边的php.ini路径，即使我们配对了xdebug的环境也是会报错的 eg：the debugger is properly configured as a php.ini directive;随便提起，此种路径只针对wamp，其他的按情况考虑。\u003c/p\u003e\n\u003cp\u003e这个是我的php.ini配置\u003c/p\u003e\n\u003cp\u003eD:\\wamp\\bin\\apache\\Apache2.4.4\\bin\\php.ini\u003c/p\u003e\n\u003cp\u003ezend_extension = “D:/wamp/bin/php/php5.4.12/zend_ext/php_xdebug-2.2.3-5.4-vc9-x86_64.dll”\u003c/p\u003e\n\u003cp\u003e[xdebug]\u003cbr\u003e\nxdebug.remote_enable = on\u003cbr\u003e\nxdebug.profiler_enable = on\u003cbr\u003e\nxdebug.profiler_enable_trigger = on\u003cbr\u003e\nxdebug.profiler_output_name = cachegrind.out.%t.%p\u003cbr\u003e\nxdebug.profiler_output_dir = “E:/wamp/tmp”\u003c/p\u003e\n\u003cp\u003e 到此配置完成\u003c/p\u003e\n\u003cp\u003e启动wamp然后debug运行就行了。\u003c/p\u003e\n\u003cp\u003eMac下配置debug和上面类似，下面给出php.ini的配置文件\u003c/p\u003e\n\u003cp\u003ezend_extension=/Applications/XAMPP/xamppfiles/lib/php/extensions/no-debug-non-zts-20121212/xdebug.so\nxdebug.remote_enable=on\nxdebug.remote_handler=dbgp\nxdebug.remote_host=localhost\nxdebug.remote_port=9000\nxdebug.profiler_output_dir = /tmp/xdebug/\u003c/p\u003e","title":"Wamp、EclipsePHP、Debug 配置"},{"content":"实现的时post和get方法工具类\n\u003c?php /* * http request tool */ /* * get method */ namespace Home\\Controller; class HttpUtils{ function get(url,param=array()){ if(!is_array(param)){ throw new Exception(\u0026#8220;参数必须为array\u0026#8221;); }p=\u0026#8221;; foreach(param askey =\u003e value){p=p.key.\u0026#8217;=\u0026#8217;.value.\u0026#8217;\u0026\u0026#8217;; } if(preg_match(\u0026#8216;/\\?[\\d\\D]+/\u0026#8217;,url)){//matched ?c p=\u0026#8217;\u0026\u0026#8217;.p; }else if(preg_match(\u0026#8216;/\\?/\u0026#8217;,url)){//matched ?p=p; }else{p=\u0026#8217;?\u0026#8217;.p; }p=preg_replace(\u0026#8216;/\u0026/\u0026#8217;,\u0026#8221;,p); url=url.p; //echourl; httph =curl_init(url); curl_setopt(httph, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt(httph, CURLOPT\\_SSL\\_VERIFYHOST, 1); curl_setopt(httph,CURLOPT_RETURNTRANSFER,1); curl_setopt(httph, CURLOPT_USERAGENT, \u0026#8220;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)\u0026#8221;); curl_setopt(httph, CURLOPT_RETURNTRANSFER,1); curl_setopt(httph, CURLOPT_HEADER,1); rst=curl_exec(httph); curl_close(httph); returnrst; } /* * post method */ function post(url,param=array()){ if(!is_array(param)){ throw new Exception(\u0026#8220;参数必须为array\u0026#8221;); }httph =curl_init(url); curl_setopt(httph, CURLOPT\\_SSL\\_VERIFYPEER, 0); curl_setopt(httph, CURLOPT_SSL_VERIFYHOST, 1); curl_setopt(httph,CURLOPT_RETURNTRANSFER,1); curl_setopt(httph, CURLOPT_USERAGENT, \u0026#8220;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)\u0026#8221;); curl_setopt(httph, CURLOPT_POST, 1);//设置为POST方式 curl_setopt(httph, CURLOPT_POSTFIELDS,param); curl_setopt(httph, CURLOPT_RETURNTRANSFER,1); curl_setopt(httph, CURLOPT_HEADER,1); rst=curl_exec(httph); curl_close(httph); returnrst; } } ?\u003e","permalink":"https://blog.zdltech.com/posts/httputils-class-php%E7%9A%84%E6%96%87%E4%BB%B6/","summary":"\u003cp\u003e实现的时post和get方法工具类\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003c?php  \n/*  \n* http request tool  \n*/  \n/*  \n* get method  \n*/  \nnamespace Home\\Controller;  \nclass HttpUtils{  \nfunction get(\u003cspan class=\"katex math inline\"\u003eurl,\u003c/span\u003eparam=array()){  \nif(!is_array(\u003cspan class=\"katex math inline\"\u003eparam)){\n throw new Exception(\u0026#8220;参数必须为array\u0026#8221;);\n }\u003c/span\u003ep=\u0026#8221;;  \nforeach(\u003cspan class=\"katex math inline\"\u003eparam as\u003c/span\u003ekey =\u003e \u003cspan class=\"katex math inline\"\u003evalue){\u003c/span\u003ep=\u003cspan class=\"katex math inline\"\u003ep.\u003c/span\u003ekey.\u0026#8217;=\u0026#8217;.\u003cspan class=\"katex math inline\"\u003evalue.\u0026#8217;\u0026\u0026#8217;;\n }\n if(preg_match(\u0026#8216;/\\?[\\d\\D]+/\u0026#8217;,\u003c/span\u003eurl)){//matched ?c  \n\u003cspan class=\"katex math inline\"\u003ep=\u0026#8217;\u0026\u0026#8217;.\u003c/span\u003ep;  \n}else if(preg_match(\u0026#8216;/\\?\u003cspan class=\"katex math inline\"\u003e/\u0026#8217;,\u003c/span\u003eurl)){//matched ?\u003cspan class=\"katex math inline\"\u003e\u003c/span\u003ep=\u003cspan class=\"katex math inline\"\u003ep;\n }else{\u003c/span\u003ep=\u0026#8217;?\u0026#8217;.\u003cspan class=\"katex math inline\"\u003ep;\n }\u003c/span\u003ep=preg_replace(\u0026#8216;/\u0026\u003cspan class=\"katex math inline\"\u003e/\u0026#8217;,\u0026#8221;,\u003c/span\u003ep);  \n\u003cspan class=\"katex math inline\"\u003eurl=\u003c/span\u003eurl.\u003cspan class=\"katex math inline\"\u003ep;\n //echo\u003c/span\u003eurl;  \n\u003cspan class=\"katex math inline\"\u003ehttph =curl_init(\u003c/span\u003eurl);  \ncurl_setopt(\u003cspan class=\"katex math inline\"\u003ehttph, CURLOPT_SSL_VERIFYPEER, 0);\n curl_setopt(\u003c/span\u003ehttph, CURLOPT\\_SSL\\_VERIFYHOST, 1);  \ncurl_setopt(\u003cspan class=\"katex math inline\"\u003ehttph,CURLOPT_RETURNTRANSFER,1);\n curl_setopt(\u003c/span\u003ehttph, CURLOPT_USERAGENT, \u0026#8220;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)\u0026#8221;);\n\ncurl_setopt(\u003cspan class=\"katex math inline\"\u003ehttph, CURLOPT_RETURNTRANSFER,1);\n curl_setopt(\u003c/span\u003ehttph, CURLOPT_HEADER,1);  \n\u003cspan class=\"katex math inline\"\u003erst=curl_exec(\u003c/span\u003ehttph);  \ncurl_close(\u003cspan class=\"katex math inline\"\u003ehttph);\n return\u003c/span\u003erst;  \n}  \n/*  \n* post method  \n*/  \nfunction post(\u003cspan class=\"katex math inline\"\u003eurl,\u003c/span\u003eparam=array()){  \nif(!is_array(\u003cspan class=\"katex math inline\"\u003eparam)){\n throw new Exception(\u0026#8220;参数必须为array\u0026#8221;);\n }\u003c/span\u003ehttph =curl_init(\u003cspan class=\"katex math inline\"\u003eurl);\n curl_setopt(\u003c/span\u003ehttph, CURLOPT\\_SSL\\_VERIFYPEER, 0);  \ncurl_setopt(\u003cspan class=\"katex math inline\"\u003ehttph, CURLOPT_SSL_VERIFYHOST, 1);\n curl_setopt(\u003c/span\u003ehttph,CURLOPT_RETURNTRANSFER,1);  \ncurl_setopt(\u003cspan class=\"katex math inline\"\u003ehttph, CURLOPT_USERAGENT, \u0026#8220;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)\u0026#8221;);\n curl_setopt(\u003c/span\u003ehttph, CURLOPT_POST, 1);//设置为POST方式  \ncurl_setopt(\u003cspan class=\"katex math inline\"\u003ehttph, CURLOPT_POSTFIELDS,\u003c/span\u003eparam);  \ncurl_setopt(\u003cspan class=\"katex math inline\"\u003ehttph, CURLOPT_RETURNTRANSFER,1);\n curl_setopt(\u003c/span\u003ehttph, CURLOPT_HEADER,1);  \n\u003cspan class=\"katex math inline\"\u003erst=curl_exec(\u003c/span\u003ehttph);  \ncurl_close(\u003cspan class=\"katex math inline\"\u003ehttph);\n return\u003c/span\u003erst;  \n}  \n}  \n?\u003e","title":"HttpUtils.class.php的文件"},{"content":"我是为了解决：WebView 缓存下来的cookie可以用于HttpClient，因为我的HttpClient单独需要取一些数据，但是依赖于本地的cookie。如果没有cookie返回来的是登录页面\n[html] view plaincopy在CODE上查看代码片派生到我的代码片\n核心代码：\nmainActivity.java public void onCreate(Bundle savedInstanceState) {\nView v = inflater.inflate(R.layout.main_fragment, container, false);\nmWebView = (WebView) v.findViewById(R.id.webview);\nMyWebViewClient webviewClient = new MyWebViewClient();\nmWebView.setWebViewClient(webviewClient);\nWebSettings webset = mWebView.getSettings();\nwebset.setJavaScriptEnabled(true);\nmWebView.loadUrl(Constants.TALKGROUP_URL);\nreturn v;\n}\nprivate class MyWebViewClient extends WebViewClient {\n@Override\npublic void onPageFinished(WebView view, String url) {\nsuper.onPageFinished(view, url);\nIWLog.d(TAG, “onPageFinished() url is:”+url);\n/* 将cookie保存起来*/\nString c = CookieManager.getInstance().getCookie(url);\nDataCenter.setCookie(c);\nCookieSyncManager.getInstance().sync();\n}\n@Override\npublic void onReceivedError(WebView view, int errorCode,\nString description, String failingUrl) {\nIWLog.d(TAG, “onReceivedError() errorCode:” + errorCode+”—-failingUrl”+failingUrl);\nsuper.onReceivedError(view, errorCode, description, failingUrl);\n}\n@Override\npublic boolean shouldOverrideUrlLoading(WebView view, String url) {\nIWLog.d(TAG, “shouldOverrideUrlLoading() url:” + url);\nreturn super.shouldOverrideUrlLoading(view, url);\n}\n}\n2 DataCenter.java\npublic class DataCenter {\nprivate static String cookies;\npublic static String getCookie() {\nreturn cookies;\n}\npublic static void setCookie(String cks) {\ncookies = cks;\n}\n}\n3 MyHttpClient.java\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.net.URI;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.CookieStore;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.protocol.ClientContext;\nimport org.apache.http.impl.client.BasicCookieStore;\nimport org.apache.http.impl.client.DefaultHttpClient;\nimport org.apache.http.impl.cookie.BasicClientCookie;\nimport org.apache.http.protocol.BasicHttpContext;\nimport com.petsea.data.DataCenter;\nimport com.petsea.data.NavigationUrl;\nimport android.graphics.Bitmap;\nimport android.os.AsyncTask;\nimport android.util.Log;\npublic class MyHttpClient {\npublic static String TAG = “MyHttpClient”;\npublic void execute() {\nRequestChatListTask task = new RequestChatListTask();\ntask.execute();\n}\nprivate class RequestChatListTask extends AsyncTask\u0026lt;Bitmap, Integer, String\u0026gt; {\n@Override\nprotected void onPreExecute() {\nsuper.onPreExecute();\n}\n@Override\nprotected String doInBackground(Bitmap… params) {\nBufferedReader in = null;\nDefaultHttpClient httpclient;\nBasicHttpContext localContext;\nCookieStore cookieJar;\ntry {\nhttpclient = new DefaultHttpClient();\ncookieJar = new BasicCookieStore();\nlocalContext = new BasicHttpContext();\nHttpGet httpget = new HttpGet();\nhttpget.setURI(new URI(NavigationUrl.CHAT_LIST_URL));//这里是你要请求的地址\nString _cookie = DataCenter.getCookie();\nif(_cookie !=null \u0026amp;\u0026amp; !_cookie.equals(“”)){\nString[] cookies = _cookie.split(“;”);\nfor(int i=0; i\u0026lt; cookies.length; i++){\nString[] nvp = cookies[i].split(“=”);\nBasicClientCookie c = new BasicClientCookie(nvp[0], nvp[1]);\n//c.setVersion(0);\nc.setDomain(“www.baidu.com”);//这里是自己的主机地址\ncookieJar.addCookie(c);\n}\n}\nlocalContext.setAttribute(ClientContext.COOKIE_STORE, cookieJar);\nHttpResponse response = httpclient.execute(httpget,localContext);\nint code = response.getStatusLine().getStatusCode();\nSystem.out.print(“code is=”+code);//返回200是正确的\nin = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));\nStringBuffer sb = new StringBuffer(“”);\nString line = “”;\nString NL = System.getProperty(“line.separator”);\nwhile ((line = in.readLine()) != null) {\nsb.append(line + NL);\n}\nin.close();\nString page = sb.toString();\n///System.out.println(page);\nreturn page; //success\n} catch (Exception e) {\ne.printStackTrace();\n} finally {\nif (in != null) {\ntry {\nin.close();\n} catch (IOException e) {\ne.printStackTrace();\n}\n}\n}\nreturn null;\n}\n@Override\nprotected void onProgressUpdate(Integer… values) {\nsuper.onProgressUpdate(values);\n}\n@Override\nprotected void onPostExecute(String result) {\nsuper.onPostExecute(result);\nLog.i(TAG, “onPostExecute result is:” + result);\n}\n}\n}\n上面只是我工程的一部分代码，主要来说明问题的。不便把全部代码上传。 我也是调试了一阵才弄出来的。给大家推荐一个工具：WireShark 用于抓取网络包的，可以查看你的http请求以及返回，里面会显示到cookie的内容还有其它格式 下载地址 http://www.wireshark.org/download.html\n","permalink":"https://blog.zdltech.com/posts/android-webview-%E4%B8%8Ehttpclient-%E5%85%B1%E7%94%A8%E6%9C%AC%E5%9C%B0cookie%E9%97%AE%E9%A2%98/","summary":"\u003cp\u003e我是为了解决：WebView 缓存下来的cookie可以用于HttpClient，因为我的HttpClient单独需要取一些数据，但是依赖于本地的cookie。如果没有cookie返回来的是登录页面\u003c/p\u003e\n\u003cp\u003e[html] view plaincopy在CODE上查看代码片派生到我的代码片\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"font-size: 24px;\"\u003e核心代码：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003emainActivity.java\u003c/span\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003epublic void onCreate(Bundle savedInstanceState) {\u003cbr\u003e\nView v = inflater.inflate(R.layout.main_fragment, container, false);\u003c/p\u003e\n\u003cp\u003emWebView = (WebView) v.findViewById(R.id.webview);\u003cbr\u003e\nMyWebViewClient webviewClient = new MyWebViewClient();\u003c/p\u003e\n\u003cp\u003emWebView.setWebViewClient(webviewClient);\u003cbr\u003e\nWebSettings webset = mWebView.getSettings();\u003cbr\u003e\nwebset.setJavaScriptEnabled(true);\u003cbr\u003e\nmWebView.loadUrl(Constants.TALKGROUP_URL);\u003c/p\u003e\n\u003cp\u003ereturn v;\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003eprivate class MyWebViewClient extends WebViewClient {\u003c/p\u003e\n\u003cp\u003e@Override\u003cbr\u003e\npublic void onPageFinished(WebView view, String url) {\u003cbr\u003e\nsuper.onPageFinished(view, url);\u003c/p\u003e\n\u003cp\u003eIWLog.d(TAG, “onPageFinished() url is:”+url);\u003cbr\u003e\n/* 将cookie保存起来*/\u003cbr\u003e\nString c = CookieManager.getInstance().getCookie(url);\u003cbr\u003e\nDataCenter.setCookie(c);\u003cbr\u003e\nCookieSyncManager.getInstance().sync();\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e@Override\u003cbr\u003e\npublic void onReceivedError(WebView view, int errorCode,\u003cbr\u003e\nString description, String failingUrl) {\u003cbr\u003e\nIWLog.d(TAG, “onReceivedError() errorCode:” + errorCode+”—-failingUrl”+failingUrl);\u003cbr\u003e\nsuper.onReceivedError(view, errorCode, description, failingUrl);\u003cbr\u003e\n}\u003c/p\u003e","title":"Android WebView 与HttpClient 共用本地cookie问题"},{"content":"最近两天一直想用安卓模拟登陆，利用新的WebView显示登陆后可以访问的页面，但是不管怎么访问需要登陆后才能访问的页面，还是跳回到登陆页，后来网上看了下是cookie没有设置，找了半天才到到合适的设置方法：\n登陆方法：\nprivate Cookie cookie; public static HttpContext localContext; \u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;**public static List cookies;//此为保存的cookie**\u0026lt;/span\u0026gt; public String cookieStr; // public static Cookie cookie = null; /** * 登陆时保存cookie * @param url * @param data * @return */ public String login(String url,String data[]){ HttpClient client = null; String html = null; try { client = new DefaultHttpClient(); \u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;**// 创建cookie store的本地实例 CookieStore cookieStore = new BasicCookieStore(); localContext = new BasicHttpContext(); // 绑定定制的cookie store到本地内容中 localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); **\u0026lt;/span\u0026gt; HttpPost post = new HttpPost(url); List parameters = new ArrayList(); parameters.add(new BasicNameValuePair(\u0026#34;username\u0026#34;, data[0])); parameters.add(new BasicNameValuePair(\u0026#34;passwd\u0026#34;, data[1])); parameters.add(new BasicNameValuePair(\u0026#34;login\u0026#34;, \u0026#34;%B5%C7%A1%A1%C2%BC\u0026#34;)); UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters,\u0026#34;utf-8\u0026#34;); post.setEntity(entity); HttpResponse response = client.execute(post\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;,localContext\u0026lt;/span\u0026gt;); if(response.getStatusLine().getStatusCode() == 200){ InputStream content = response.getEntity().getContent(); BufferedReader buffer = new BufferedReader(new InputStreamReader(content,\u0026#34;gbk\u0026#34;)); String line = null; while((line=buffer.readLine())!=null){ html+=line; } \u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;** cookies = cookieStore.getCookies();**\u0026lt;/span\u0026gt; System.out.println(\u0026#34;cookies.size():\u0026#34;+cookies.size()); if (!cookies.isEmpty()) { for(int i=0;i\u0026amp;lt;cookies.size();i++){ system.out.println(\u0026#34;-=\u0026#34;\u0026#34; \u0026#34;+cookies.get(i).tostring());=\u0026#34;\u0026#34; }=\u0026#34;\u0026#34; buffer.close();=\u0026#34;\u0026#34; }else{=\u0026#34;\u0026#34; system.out.println(\u0026#34;utilslogin:\u0026#34;+response.getstatusline().getstatuscode());=\u0026#34;\u0026#34; catch=\u0026#34;\u0026#34; (exception=\u0026#34;\u0026#34; e)=\u0026#34;\u0026#34; {=\u0026#34;\u0026#34; e.printstacktrace();=\u0026#34;\u0026#34; }finally{=\u0026#34;\u0026#34; if(client!=\u0026#34;null){\u0026#34; client.getconnectionmanager().shutdown();=\u0026#34;\u0026#34; return=\u0026#34;\u0026#34; html;=\u0026#34;\u0026#34; }\u0026amp;lt;=\u0026#34;\u0026#34; pre=\u0026#34;\u0026#34;\u0026amp;gt; Activity中的oncreate()方法：\nprivate WebView wvTempShow; private String receiveUrl; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_temp_web_view); wvTempShow = (WebView) findViewById(R.id.wv_tempShow); Intent intent = this.getIntent(); receiveUrl = intent.getStringExtra(\u0026#34;openUrl\u0026#34;); \u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;**//获得cookie管理者 CookieManager cookieManager = CookieManager.getInstance(); //获取登陆时的cookie String oldCookie = UtilsLogin.cookies.get(0).getName()+\u0026#34;=\u0026#34;+UtilsLogin.cookies.get(0).getValue()+\u0026#34;;\u0026#34;+ UtilsLogin.cookies.get(1).getName()+\u0026#34;=\u0026#34;+UtilsLogin.cookies.get(1).getValue()+\u0026#34;;\u0026#34; ;**\u0026lt;/span\u0026gt; System.out.println(\u0026#34;oldCookie:\u0026#34;+oldCookie); cookieManager.setCookie(receiveUrl, oldCookie); wvTempShow.getSettings().setDefaultTextEncodingName(\u0026#34;gbk\u0026#34;); wvTempShow.loadUrl(receiveUrl); wvTempShow.setWebViewClient(new MyWebViewClient()); } class MyWebViewClient extends WebViewClient{ @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); } } 需要注意的是：要看访问的页面需要什么样的cookie字符串可以用以下方法： CookieManager cookieManager = CookieManager.getInstance(); String CookieStr = cookieManager.getCookie(\u0026#34;http://bkjw.guet.edu.cn/student/public/menu.[asp](http://www.2cto.com/kf/web/asp/)?menu=mnall.asp\u0026#34;); System.out.println(\u0026#34;TempWebViewonPageFinished = \u0026#34; + CookieStr); 然后自己像以上String oldCookie中一样自己拼好，再在cookieManager.setCookie(url,cookieString);中设置\n","permalink":"https://blog.zdltech.com/posts/android%E5%AE%89%E5%8D%93webview%E8%AE%BE%E7%BD%AEcookie/","summary":"\u003cp\u003e最近两天一直想用安卓模拟登陆，利用新的WebView显示登陆后可以访问的页面，但是不管怎么访问需要登陆后才能访问的页面，还是跳回到登陆页，后来网上看了下是cookie没有设置，找了半天才到到合适的设置方法：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e登陆方法：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprivate Cookie cookie;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tpublic static  HttpContext localContext;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;**public static  List cookies;//此为保存的cookie**\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tpublic  String cookieStr;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t// public static Cookie cookie = null; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t/**\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t * 登陆时保存cookie\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t * @param url\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t * @param data\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t * @return\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t */\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tpublic String login(String url,String data[]){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tHttpClient client = null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tString html = null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\ttry {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tclient = new DefaultHttpClient();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;**// 创建cookie store的本地实例  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tCookieStore cookieStore = new BasicCookieStore();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tlocalContext = new BasicHttpContext();  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t// 绑定定制的cookie store到本地内容中  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tlocalContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); **\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tHttpPost post = new HttpPost(url);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tList parameters = new ArrayList();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tparameters.add(new BasicNameValuePair(\u0026#34;username\u0026#34;, data[0]));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tparameters.add(new BasicNameValuePair(\u0026#34;passwd\u0026#34;, data[1]));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tparameters.add(new BasicNameValuePair(\u0026#34;login\u0026#34;, \u0026#34;%B5%C7%A1%A1%C2%BC\u0026#34;));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tUrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters,\u0026#34;utf-8\u0026#34;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tpost.setEntity(entity);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tHttpResponse response = client.execute(post\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;,localContext\u0026lt;/span\u0026gt;);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tif(response.getStatusLine().getStatusCode() == 200){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tInputStream content = response.getEntity().getContent();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tBufferedReader buffer = new BufferedReader(new InputStreamReader(content,\u0026#34;gbk\u0026#34;));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tString line = null;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\twhile((line=buffer.readLine())!=null){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\thtml+=line;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t \u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;** cookies = cookieStore.getCookies();**\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t System.out.println(\u0026#34;cookies.size():\u0026#34;+cookies.size());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t if (!cookies.isEmpty()) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\t for(int i=0;i\u0026amp;lt;cookies.size();i++){ system.out.println(\u0026#34;-=\u0026#34;\u0026#34; \u0026#34;+cookies.get(i).tostring());=\u0026#34;\u0026#34; }=\u0026#34;\u0026#34; buffer.close();=\u0026#34;\u0026#34; }else{=\u0026#34;\u0026#34; system.out.println(\u0026#34;utilslogin:\u0026#34;+response.getstatusline().getstatuscode());=\u0026#34;\u0026#34; catch=\u0026#34;\u0026#34; (exception=\u0026#34;\u0026#34; e)=\u0026#34;\u0026#34; {=\u0026#34;\u0026#34; e.printstacktrace();=\u0026#34;\u0026#34; }finally{=\u0026#34;\u0026#34; if(client!=\u0026#34;null){\u0026#34; client.getconnectionmanager().shutdown();=\u0026#34;\u0026#34; return=\u0026#34;\u0026#34; html;=\u0026#34;\u0026#34; }\u0026amp;lt;=\u0026#34;\u0026#34; pre=\u0026#34;\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e \u003c/p\u003e","title":"Android（安卓）WebView设置cookie"},{"content":"sqlite中是不支持删除列操作的，所以网上alter table table_name drop column col_name这个语句在sqlite中是无效的，而替代的方法可以如下：\n1.根据原表创建一张新表\n2.删除原表\n3.将新表重名为旧表的名称\n示例例子如下\n1.创建一张旧表Student，包含id（主码），name, tel\ncreate table student (\nid integer primary key,\nname text,\ntel text\n)\n2.给旧表插入两个值\ninsert into student(id,name,tel) values(101,”Jack”,”110″)\ninsert into student(id,name,tel) values(102,”Rose”,”119″)\n结果如图\n3.接下来我们删除电话这个列，首先根据student表创建一张新表teacher\ncreate table teacher as select id,name from student\n结果如图\n可以看到tel这一列已经没有了\n4.然后我们删除student这个表\ndrop table if exists student\n5.将teacher这个表重命名为student\nalter table teacher rename to student\n结果演示：\nselect * from student order by name desc（desc降序， asc升序）\n这样就可以得到我们想要的结果了。\n另外：给自己一个提示，在android sqlite中的查询语句如果是text类型的别忘了给他加上””来指明是String类型的，例如：\nCursor c = mSQLiteDatabase.query(TABLE_NAME, null, NAME + “=” + “/”” + name + “/””, null, null, null, null);\n转自：http://blog.csdn.net/aben_2005/article/details/6563538\n","permalink":"https://blog.zdltech.com/posts/sqlite%E5%88%A0%E9%99%A4%E5%88%97%E6%96%B9%E6%B3%95/","summary":"\u003cp\u003esqlite中是不支持删除列操作的，所以网上alter table table_name drop column col_name这个语句在sqlite中是无效的，而替代的方法可以如下：\u003c/p\u003e\n\u003cp\u003e1.根据原表创建一张新表\u003c/p\u003e\n\u003cp\u003e2.删除原表\u003c/p\u003e\n\u003cp\u003e3.将新表重名为旧表的名称\u003c/p\u003e\n\u003cp\u003e示例例子如下\u003c/p\u003e\n\u003cp\u003e1.创建一张旧表Student，包含id（主码），name, tel\u003c/p\u003e\n\u003cp\u003ecreate table student (\u003c/p\u003e\n\u003cp\u003eid integer primary key,\u003c/p\u003e\n\u003cp\u003ename text,\u003c/p\u003e\n\u003cp\u003etel text\u003c/p\u003e\n\u003cp\u003e)\u003c/p\u003e\n\u003cp\u003e2.给旧表插入两个值\u003c/p\u003e\n\u003cp\u003einsert into student(id,name,tel) values(101,”Jack”,”110″)\u003c/p\u003e\n\u003cp\u003einsert into student(id,name,tel) values(102,”Rose”,”119″)\u003c/p\u003e\n\u003cp\u003e结果如图\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://hi.csdn.net/attachment/201106/23/0_1308813180xXxX.gif\"\u003e\u003cimg alt=\"clip_image002\" loading=\"lazy\" src=\"http://hi.csdn.net/attachment/201106/23/0_13088131818G0A.gif\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e3.接下来我们删除电话这个列，首先根据student表创建一张新表teacher\u003c/p\u003e\n\u003cp\u003ecreate table teacher as select id,name from student\u003c/p\u003e\n\u003cp\u003e结果如图\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://hi.csdn.net/attachment/201106/23/0_130881318134dJ.gif\"\u003e\u003cimg alt=\"clip_image004\" loading=\"lazy\" src=\"http://hi.csdn.net/attachment/201106/23/0_1308813181JQ7J.gif\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e可以看到tel这一列已经没有了\u003c/p\u003e\n\u003cp\u003e4.然后我们删除student这个表\u003c/p\u003e\n\u003cp\u003edrop table if exists student\u003c/p\u003e\n\u003cp\u003e5.将teacher这个表重命名为student\u003c/p\u003e\n\u003cp\u003ealter table teacher rename to student\u003c/p\u003e\n\u003cp\u003e结果演示：\u003c/p\u003e\n\u003cp\u003eselect * from student order by name desc（desc降序， asc升序）\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://hi.csdn.net/attachment/201106/23/0_1308813184vjKt.gif\"\u003e\u003cimg alt=\"clip_image006\" loading=\"lazy\" src=\"http://hi.csdn.net/attachment/201106/23/0_1308813185riDE.gif\"\u003e\u003c/a\u003e\u003c/p\u003e","title":"Sqlite删除列方法"},{"content":"这篇文章我将从源码的角度深入分析Scroller类。在阅读的时候，建议大家打开源码对照着看，否则可能看的云里雾里。\n**一.Scroller的用途** ** ** 熟悉android的同学必然对Scroller不陌生，Scroller是一个**弹性滑动对象**，可以制作很多酷炫的滑动效果，Lancher中的滑屏效果就有使用到Scroller。 我们知道，View类中的scrollTo和scrollBy方法提供了滑动操作，但是这种滑动操作是瞬间完成的，就是说你为scrollTo提供终点坐标，该方法只要一调用，我们就会发现已经滚动到目的地了，这种方式很显然用户体验是不好的，因而android工程师为我们封装了Scroller类，这个类可以为View带来**缓慢移动的效果**。 具体使用方式通常是通过在你自定义的View中调用Scroller的startScroll并刷新视图，另外需重写computeScroll方法（刷新视图过程中会调用此方法），在该方法中调用Scroller的computeScrollOffset计算应该滚动到的位置，然后使用scrollTo滚动到该位置，再调用invalidate刷新，就可以实现滚动效果了(不了解的同学建议先去熟悉Scroller用法)。 Scroller使用示例（代码片段）： **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Scroller mScroller; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230; \u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; smoothScrollTo(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; destX,\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; destY) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollX = getScrollX(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollY = getScrollY(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; deltaX = destX-scrollX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; deltaY = destY-scrollY; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mScroller.startScroll(scrollX,scrollY,deltaX, deltaY, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; invalidate(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mScroller != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mScroller.computeScrollOffset()) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; scrollTo(mScroller.getCurrX(),mScroller.getCurrY()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;scrollX=\u0026amp;#8221;\u0026lt;/span\u0026gt;+getScrollX()+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;,scrollY=\u0026amp;#8221;\u0026lt;/span\u0026gt;+getScrollY()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; postInvalidate(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; **二.ScrollTo、ScrollBy、getScrollX、getScrollY方法分析** ** ** 在分析Scroller源码之前，我们必须先了解ScrollTo，ScrollBy，getScrollX，getScrollY这几个方法的作用。这四个方法都是View类提供的，这点先明确。 我们先分析getScrollX和getScrollY方法，查看源码实现： **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * Return the scrolled left position of this view. This is the left edge of\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * the displayed part of your view. You do not need to draw any pixels\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * farther left, since those are outside of the frame of your view on\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * screen.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @return The left edge of the displayed part of your view, in pixels.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getScrollX() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mScrollX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * Return the scrolled top position of this view. This is the top edge of\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * the displayed part of your view. You do not need to draw any pixels above\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * it, since those are outside of the frame of your view on screen.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @return The top edge of the displayed part of your view, in pixels.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getScrollY() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mScrollY; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; getScrollX和getScrollY方法返回的是mScrollX和mScrollY变量。这两个变量是什么呢？ \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 这里我直接告诉大家，**mScrollX和mScrollY指的是视图内容相对于视图原始起始坐标的偏移量**，mScrollX和mScrollY的默认值为0，因为默认是没有偏移的。另外需注意偏移量的正负问题，因为是相对视图起始坐标的，所以如果你是**向右偏移那么mScrollX应该是负数，而向左偏移mScrollX为正数**。再举个例子，比如你定义了一个ImageView，其左上角的坐标为（100,80）,此时mScrollX和mScrollY值都为0（没有偏移），现在你要把该ImageView移到（120,100）处，也就是右下方，那么你的mScrollX应该是100-120=-20,mScrollY应该是80-100=-20，这下你该明白了吧。 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 明白了这个问题，scrollBy和scrollTo也就不在话下了，我们查看源码： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scrollTo(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mScrollX != x || mScrollY != y) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldX = mScrollX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldY = mScrollY; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mScrollX = x; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mScrollY = y; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; invalidateParentCaches(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; onScrollChanged(mScrollX, mScrollY, oldX, oldY); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!awakenScrollBars()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; postInvalidateOnAnimation(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scrollBy(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; scrollTo(mScrollX + x, mScrollY + y); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 先看scrollTo方法，它首先判断x，y方向的偏移量(即mScrollX,mScrollY)是否和传进来的偏移量（即x,y）相同，如果相同那么直接返回，否则我们将更新mScrollX和mScrollY，并且通知界面发生改变请求重绘。通过这种方式就可以实现滚动效果了，只是是瞬间移动的。再看这个scrollBy，直接调用的是scrollTo，根据参数很容易发现，这个方法的作用是在当前偏移基础上，再继续偏移(x,y)单位。需要注意的是这两个方法的**参数是偏移量而不是实际位置**哦！ \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 这里还有一点需要注意，那就是你**调用一个View的scrollTo方法进行滚动时，滚动的并不是该View本身，而是该View的内容。**比如你要对一个Button进行滚动的话，应该在Button外面包一个ViewGroup，然后调用ViewGroup的scrollTo方法。这一点也很重要，大家需要注意下！ \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **三.Scroller源码分析** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ** ** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; Scroller的精华在于computeScrollOffset和startScroll方法,所以我们重点分析这两个方法。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 分析之前，先看这个类中定义的一些变量： \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMode;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//模式，有SCROLL_MODE和FLING_MODE\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mStartX;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//起始x方向偏移\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mStartY;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//起始y方向偏移\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mFinalX;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//终点x方向偏移\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mFinalY;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//终点y方向偏移\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mCurrX;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//当前x方向偏移\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mCurrY;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//当前y方向偏移\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; mStartTime;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//起始时间\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDuration;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//滚动持续时间\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mDurationReciprocal;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//持续时间的倒数\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mDeltaX;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//x方向应该滚动的距离,mDeltaX=mFinalX-mStartX\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mDeltaY;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//y方向应该滚动的距离,mDeltaY=mFinalY-mStartY\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; mFinished;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//是否结束\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 对这些变量有个大致印象之后，我们就开始看startScroll源码了： **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; startScroll(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startX, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startY, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dy) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; startScroll(startX, startY, dx, dy, DEFAULT_DURATION); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; startScroll(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startX, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startY, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dy, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; duration) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mMode = SCROLL_MODE; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mFinished = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mDuration = duration; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mStartTime = AnimationUtils.currentAnimationTimeMillis(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mStartX = startX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mStartY = startY; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mFinalX = startX + dx; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mFinalY = startY + dy; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mDeltaX = dx; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mDeltaY = dy; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mDurationReciprocal = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f / (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) mDuration; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 这个所谓的startScroll方法里面全部是对上面那些变量赋值的，比如将当前模式置为SCROLL_MODE，设置持续时间，起点终点偏移，起始时间等等。这个方法似乎并没有触发start scroll，恩，的确是这样的。那么到底怎么触发scroll呢？我们将这个问题留到下一个部分分析。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 为了让大家理解这些变量的作用，我画了一张图。 \u0026lt;/div\u0026gt; ![](http://img.blog.csdn.net/20141202145628031?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hkamo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; 解释下，图中我们假设从A点滚动到B点，那么，**如果知道mStartX，mStartY（由startScroll的startX和startY参数得到）和mDeltaX，mDeltaY（由startScroll的dx和dy参数得到）。那么，mFinalX和mFinalY就很容易得到了。此外在加上duration持续时间，那么我们就可以根据（当前时间-mStartTime）占duration的比例来算出当前位置，也即mCurrX和mCurrY。**我不会告诉你，这就是computeScrollOffset的作用！通过上面分析我们发现，**startScroll方法其实相当于一个预处理，为computeScrollOffset提供数据。** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 下面我们查看computeScrollOffset源码： \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; computeScrollOffset() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mFinished) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; timePassed = (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)(AnimationUtils.currentAnimationTimeMillis() \u0026amp;#8211; mStartTime); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (timePassed \u0026lt; mDuration) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (mMode) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; SCROLL_MODE: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mCurrX = mStartX + Math.round(x * mDeltaX); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mCurrY = mStartY + Math.round(x * mDeltaY); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; FLING_MODE: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230; \u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mCurrX = mFinalX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mCurrY = mFinalY; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mFinished = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 看，是不是很好理解了。**首先判断是否结束(mFinished==true?),如果没有结束，那么程序继续向下跑，计算timePassed,即当前时间减去开始时间，如果小于mDuration,那么就可以根据比例计算出当前位置，当然了，这里使用了Interpolator来控制动画的效果，加速或者减速等等。如果已经超过了mDuration了，那么滚动应该停止了，所以将mFinished置为ture,下次调用computeScrollOffset就会返回false了。** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ** ** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 到这里，我们把Scroller中的重要部分都分析完了，但是我们发现这两个方法都没有涉及具体滚动。那么滚动到底是如何触发的呢？下面我们将对整个流程进行源码分析。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **四.滚动流程分析** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ** ** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 在第一部分中，我给出了一个Scroller的使用示例，在smoothScrollTo方法中我们调用了Scroller的startScroll，然后调用了invalidate方法刷新视图，这个滚动效果就是由invalidate触发的！我们知道，调用了invalidate方法将会引起整个view系统的重绘，所以我们得从View的绘制说起。有经验的同学都应该知道，View的绘制包括三个主要过程，分别是measure,layout和draw。下面我们看View类的draw方法源码： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; draw(Canvas canvas) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230; \u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * Draw traversal performs several drawing steps which must be executed\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * in the appropriate order:\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 1. Draw the background\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 2. If necessary, save the canvas\u0026amp;#8217; layers to prepare for fading\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 3. Draw view\u0026amp;#8217;s content\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 4. Draw children\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 5. If necessary, draw the fading edges and restore layers\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 6. Draw decorations (scrollbars for instance)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Step 1, draw the background, if needed\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; saveCount; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!dirtyOpaque) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; drawBackground(canvas); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230; \u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Step 2, save the canvas\u0026amp;#8217; layers\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230; \u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Step 3, draw the content\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!dirtyOpaque) onDraw(canvas); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Step 4, draw the children\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; dispatchDraw(canvas); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Step 5, draw the fade effect and restore layers\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230; \u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; draw方法将绘制分成了六步，其中第三步是调用onDraw去绘制内容，第四步是调用dispatchDraw去绘制子视图。我们看下dispatchDraw方法： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * Called by draw to draw the child views. This may be overridden\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * by derived classes to gain control just before its children are drawn\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * (but after its own view has been drawn).\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @param canvas the canvas on which to draw the view\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; dispatchDraw(Canvas canvas) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 恩，没错，是个空方法，因为只有ViewGroup才有子视图，所以我们来到ViewGroup中，找到dispatchDraw： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; dispatchDraw(Canvas canvas) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childrenCount = mChildrenCount; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View[] children = mChildren; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230; \u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; childrenCount; i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View child = (preorderedList == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ? children[childIndex] : preorderedList.get(childIndex); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((child.mViewFlags \u0026amp; VISIBILITY_MASK) == VISIBLE || child.getAnimation() != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; more |= drawChild(canvas, child, drawingTime); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 代码也是极其长的，这里截取了一部分。我们看到这个方法中调用了drawChild方法，从名字上就可以看出这个方法是用来绘制子视图的，找到其实现： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; drawChild(Canvas canvas, View child, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; drawingTime) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; child.draw(canvas, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, drawingTime); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 这里调用了view的draw方法，当然，这个draw方法跟上面那个draw不一样，因为它有三个参数！那还等什么，我们回到View的代码中找到这个含有三个参数的draw方法： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; draw(Canvas canvas, ViewGroup parent, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; drawingTime) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; more = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; childHasIdentityMatrix = hasIdentityMatrix(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; flags = parent.mGroupFlags; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230; \u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; sx = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; sy = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!hasDisplayList) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; computeScroll();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//终于找到了computeScroll\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; sx = mScrollX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; sy = mScrollY; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230; \u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; more; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 在其中，我们找到了computeScroll方法！当然View中的computeScroll方法是空的，需要我们根据场景自己复写。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 比如，我发现，TextView中就有复写这个方法： \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mScroller != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mScroller.computeScrollOffset()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mScrollX = mScroller.getCurrX(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mScrollY = mScroller.getCurrY(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; invalidateParentCaches(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; postInvalidate(); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// So we draw again\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 好了，折腾了这么久，**\u0026lt;span style=\u0026quot;color: #000080;\u0026quot;\u0026gt;下面我们再回顾下这个过程：我们在自定义view中调用了startScroll方法为滚动设置了一些基本数据，然后通过invalidate由上而下刷新view视图，首先是根视图（通常是ViewGroup）的draw方法被调用，然后调用onDraw绘制视图内容，接着dispatchDraw方法被调用去绘制子视图，dispatchDraw方法会对每个子视图调用drawChild方法，而drawChild方法会调用该子View的draw方法（三个参数），在draw方法中会调用computeScroll方法进行滚动，而computeScroll方法是被复写的，视场景而定，通常是根据computeScrollOffset来判断是否需要滑动，如果需要的话，接着调用postInvalidate再由上至下重新绘制，如此一来便实现了平滑滚动的效果！\u0026lt;/span\u0026gt;** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ok，到这里总算是把Scroller讲清楚了！ \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; **五.实例分析** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ** ** \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 为了便于理解，我这里写了一个小例子，通过打印日志的形式让大家理解上面所讲的内容。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 首先是几个自定义的view： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; MyLinearLayout: \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.scrollerdemo; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyLinearLayout \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TEST\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyLinearLayout(Context context) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyLinearLayout(Context context, AttributeSet attrs) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; draw(Canvas canvas) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyLinearLayout\u0026amp;#8212;\u0026gt;draw\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.draw(canvas); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyLinearLayout\u0026amp;#8212;\u0026gt;onDraw\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDraw(canvas); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyLinearLayout\u0026amp;#8212;\u0026gt;computeScroll\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.computeScroll(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; MyView(实现了平滑滚动效果): \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.scrollerdemo; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Scroller; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @author Rowandjj\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TEST\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Scroller mScroller; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyView(Context context) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; init(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyView(Context context, AttributeSet attrs) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; init(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; init() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mScroller = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Scroller(getContext()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; testSmoothScroll() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//向右下方平滑滚动(向右偏移100，向下偏移100)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; smoothScrollTo(-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;,-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; smoothScrollTo(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; destX,\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; destY) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollX = getScrollX(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollY = getScrollY(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;scrollX=\u0026amp;#8221;\u0026lt;/span\u0026gt;+scrollX+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;,scrollY=\u0026amp;#8221;\u0026lt;/span\u0026gt;+scrollY); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; deltaX = destX-scrollX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; deltaY = destY-scrollY; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mScroller.startScroll(scrollX,scrollY,deltaX, deltaY, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; invalidate(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; draw(Canvas canvas) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyView\u0026amp;#8212;\u0026amp;#8212;\u0026gt;draw run\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.draw(canvas); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyView\u0026amp;#8212;\u0026amp;#8212;\u0026gt;onDraw run\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDraw(canvas); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; dispatchDraw(Canvas canvas) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyView\u0026amp;#8212;\u0026amp;#8212;\u0026gt;dispatchDraw run\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchDraw(canvas); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; drawChild(Canvas canvas, View child, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; drawingTime) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyView\u0026amp;#8212;\u0026amp;#8212;\u0026gt;drawChild run\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.drawChild(canvas, child, drawingTime); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyView\u0026amp;#8212;\u0026amp;#8212;\u0026gt;computeScroll run\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mScroller != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mScroller.computeScrollOffset()) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; scrollTo(mScroller.getCurrX(),mScroller.getCurrY()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;scrollX=\u0026amp;#8221;\u0026lt;/span\u0026gt;+getScrollX()+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;,scrollY=\u0026amp;#8221;\u0026lt;/span\u0026gt;+getScrollY()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; postInvalidate(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; MyImageView: \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.scrollerdemo; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyImageView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ImageView \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TEST\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyImageView(Context context) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyImageView(Context context, AttributeSet attrs) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;myImageView\u0026amp;#8212;-\u0026gt;onDraw run\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDraw(canvas); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;myImageView\u0026amp;#8212;-\u0026gt;computeScroll run\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.computeScroll(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 我们根据上面三个自定义view做一个布局，外层是MyLinearLayout，中间是MyView，最里面是一个MyImageView. \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; activity_main.xml: \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;LinearLayout xmlns:android=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:orientation=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;com.example.scrollerdemo.MyLinearLayout \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; xmlns:tools=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:background=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#ffaaff\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; tools:context=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.scrollerdemo.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;com.example.scrollerdemo.MyView \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:id=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/mv\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;200dp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;200dp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:layout_marginLeft=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:layout_marginTop=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;100dp\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:background=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/darker_gray\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:orientation=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;com.example.scrollerdemo.MyImageView \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android:src=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_launcher\u0026amp;#8221;\u0026lt;/span\u0026gt; /\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/com.example.scrollerdemo.MyView\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/com.example.scrollerdemo.MyLinearLayout\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/LinearLayout\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 下面是MainActivity的代码： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.scrollerdemo; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnClickListener \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyView mv = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setContentView(R.layout.activity_main); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mv = (MyView) findViewById(R.id.mv); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mv.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (v.getId()) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.mv:\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//点击时触发滚动效果\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mv.testSmoothScroll(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 代码很简单，不必过多介绍，下面看显示效果： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20141202145938259?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hkamo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 打开logcat查看日志： \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20141202150038428?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hkamo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;div\u0026gt; 这是第一次绘制，跟上面分析过程一致，首先是MyLinearLayout的draw和onDraw方法被调用，然后通过dispatchDraw绘制孩子，所以MyView的computeScroll、draw、onDraw、dispatchDraw等方法被调用，接着MyImageView的computeScroll和onDraw方法会被调用，如此从上到下进行一次绘制。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 下面我们点击安卓机器人图标，会调用testSmoothScroll方法，机器人会从左上角平滑滚动到右下角，此时我们查看logcat日志： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ![](http://img.blog.csdn.net/20141202150108521?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hkamo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 中间日志太多，省略了，下面这段是最后打印的 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20141202150226187?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hkamo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) \u0026lt;div\u0026gt; 通过日志可以看出，上面分析是正确的，通过在MyView的computeScroll方法中调用postInvalidate，导致不断重绘，直到偏移量达到startScroll事先指定的（-100,-100）。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 至此，本篇文章结束，希望对大家有所帮助！ \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 转自：http://blog.csdn.net/chdjj/article/details/41678897 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/%E5%AE%89%E5%8D%93%E4%BB%8E%E6%BA%90%E7%A0%81%E7%9A%84%E8%A7%92%E5%BA%A6%E6%B7%B1%E5%85%A5%E5%88%86%E6%9E%90scroller/","summary":"\u003cp\u003e这篇文章我将从源码的角度深入分析Scroller类。在阅读的时候，建议大家打开源码对照着看，否则可能看的云里雾里。\u003c/p\u003e\n\u003cdiv style=\"color: #362e2b;\"\u003e\n  **一.Scroller的用途**\n\u003c/div\u003e\n\u003cdiv style=\"color: #362e2b;\"\u003e\n  **\n **\n  \u003cdiv\u003e\n    熟悉android的同学必然对Scroller不陌生，Scroller是一个**弹性滑动对象**，可以制作很多酷炫的滑动效果，Lancher中的滑屏效果就有使用到Scroller。\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    我们知道，View类中的scrollTo和scrollBy方法提供了滑动操作，但是这种滑动操作是瞬间完成的，就是说你为scrollTo提供终点坐标，该方法只要一调用，我们就会发现已经滚动到目的地了，这种方式很显然用户体验是不好的，因而android工程师为我们封装了Scroller类，这个类可以为View带来**缓慢移动的效果**。\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    具体使用方式通常是通过在你自定义的View中调用Scroller的startScroll并刷新视图，另外需重写computeScroll方法（刷新视图过程中会调用此方法），在该方法中调用Scroller的computeScrollOffset计算应该滚动到的位置，然后使用scrollTo滚动到该位置，再调用invalidate刷新，就可以实现滚动效果了(不了解的同学建议先去熟悉Scroller用法)。\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv style=\"color: #362e2b;\"\u003e\n  Scroller使用示例（代码片段）：\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Scroller mScroller;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026amp;#8230; \u0026amp;#8230;   \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; smoothScrollTo(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; destX,\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; destY)  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollX = getScrollX();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollY = getScrollY();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; deltaX = destX-scrollX;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; deltaY = destY-scrollY;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mScroller.startScroll(scrollX,scrollY,deltaX, deltaY, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        invalidate();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll()  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mScroller != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mScroller.computeScrollOffset())  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                scrollTo(mScroller.getCurrX(),mScroller.getCurrY());  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;scrollX=\u0026amp;#8221;\u0026lt;/span\u0026gt;+getScrollX()+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;,scrollY=\u0026amp;#8221;\u0026lt;/span\u0026gt;+getScrollY());  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                postInvalidate();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    **二.ScrollTo、ScrollBy、getScrollX、getScrollY方法分析**\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    ** **\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    在分析Scroller源码之前，我们必须先了解ScrollTo，ScrollBy，getScrollX，getScrollY这几个方法的作用。这四个方法都是View类提供的，这点先明确。\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    我们先分析getScrollX和getScrollY方法，查看源码实现：\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n      \u003cdiv class=\"bar\"\u003e\n        \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;     * Return the scrolled left position of this view. This is the left edge of\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;     * the displayed part of your view. You do not need to draw any pixels\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;     * farther left, since those are outside of the frame of your view on\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;     * screen.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;     *\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;     * @return The left edge of the displayed part of your view, in pixels.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getScrollX() {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mScrollX;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;     * Return the scrolled top position of this view. This is the top edge of\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;     * the displayed part of your view. You do not need to draw any pixels above\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;     * it, since those are outside of the frame of your view on screen.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;     *\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;     * @return The top edge of the displayed part of your view, in pixels.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;     */\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getScrollY() {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mScrollY;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n    \n  \n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  \u0026lt;div\u0026gt;\n    getScrollX和getScrollY方法返回的是mScrollX和mScrollY变量。这两个变量是什么呢？\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n    这里我直接告诉大家，**mScrollX和mScrollY指的是视图内容相对于视图原始起始坐标的偏移量**，mScrollX和mScrollY的默认值为0，因为默认是没有偏移的。另外需注意偏移量的正负问题，因为是相对视图起始坐标的，所以如果你是**向右偏移那么mScrollX应该是负数，而向左偏移mScrollX为正数**。再举个例子，比如你定义了一个ImageView，其左上角的坐标为（100,80）,此时mScrollX和mScrollY值都为0（没有偏移），现在你要把该ImageView移到（120,100）处，也就是右下方，那么你的mScrollX应该是100-120=-20,mScrollY应该是80-100=-20，这下你该明白了吧。\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  明白了这个问题，scrollBy和scrollTo也就不在话下了，我们查看源码：\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n      **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n      \n      \u0026lt;div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scrollTo(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y) {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mScrollX != x || mScrollY != y) {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldX = mScrollX;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldY = mScrollY;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           mScrollX = x;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           mScrollY = y;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           invalidateParentCaches();  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           onScrollChanged(mScrollX, mScrollY, oldX, oldY);  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!awakenScrollBars()) {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;               postInvalidateOnAnimation();  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           }  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       }  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;   }  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;   \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scrollBy(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y) {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       scrollTo(mScrollX + x, mScrollY + y);  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;   }  \u0026lt;/span\u0026gt;\n    \n  \n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  先看scrollTo方法，它首先判断x，y方向的偏移量(即mScrollX,mScrollY)是否和传进来的偏移量（即x,y）相同，如果相同那么直接返回，否则我们将更新mScrollX和mScrollY，并且通知界面发生改变请求重绘。通过这种方式就可以实现滚动效果了，只是是瞬间移动的。再看这个scrollBy，直接调用的是scrollTo，根据参数很容易发现，这个方法的作用是在当前偏移基础上，再继续偏移(x,y)单位。需要注意的是这两个方法的**参数是偏移量而不是实际位置**哦！\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  这里还有一点需要注意，那就是你**调用一个View的scrollTo方法进行滚动时，滚动的并不是该View本身，而是该View的内容。**比如你要对一个Button进行滚动的话，应该在Button外面包一个ViewGroup，然后调用ViewGroup的scrollTo方法。这一点也很重要，大家需要注意下！\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  **三.Scroller源码分析**\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  ** **\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  Scroller的精华在于computeScrollOffset和startScroll方法,所以我们重点分析这两个方法。\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  分析之前，先看这个类中定义的一些变量：\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n      **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n      \n      \u0026lt;div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMode;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//模式，有SCROLL_MODE和FLING_MODE\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mStartX;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//起始x方向偏移\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mStartY;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//起始y方向偏移\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mFinalX;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//终点x方向偏移\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mFinalY;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//终点y方向偏移\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mCurrX;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//当前x方向偏移\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mCurrY;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//当前y方向偏移\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; mStartTime;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//起始时间\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDuration;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//滚动持续时间\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mDurationReciprocal;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//持续时间的倒数\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mDeltaX;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//x方向应该滚动的距离,mDeltaX=mFinalX-mStartX\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; mDeltaY;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//y方向应该滚动的距离,mDeltaY=mFinalY-mStartY\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; mFinished;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//是否结束\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n  \n\u0026lt;/div\u0026gt;\n\n\n\n  对这些变量有个大致印象之后，我们就开始看startScroll源码了：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n      \u003cdiv class=\"bar\"\u003e\n        \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; startScroll(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startX, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startY, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dy) {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        startScroll(startX, startY, dx, dy, DEFAULT_DURATION);  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; startScroll(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startX, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; startY, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dy, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; duration) {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mMode = SCROLL_MODE;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mFinished = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mDuration = duration;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mStartTime = AnimationUtils.currentAnimationTimeMillis();  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mStartX = startX;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mStartY = startY;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mFinalX = startX + dx;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mFinalY = startY + dy;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mDeltaX = dx;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mDeltaY = dy;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mDurationReciprocal = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f / (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;) mDuration;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n    \n  \n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  这个所谓的startScroll方法里面全部是对上面那些变量赋值的，比如将当前模式置为SCROLL_MODE，设置持续时间，起点终点偏移，起始时间等等。这个方法似乎并没有触发start scroll，恩，的确是这样的。那么到底怎么触发scroll呢？我们将这个问题留到下一个部分分析。\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  为了让大家理解这些变量的作用，我画了一张图。\n\u0026lt;/div\u0026gt;\n\n\n\n  ![](http://img.blog.csdn.net/20141202145628031?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hkamo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\u0026lt;/div\u0026gt; \n  \n  \u0026lt;div\u0026gt;\n    \u0026lt;div\u0026gt;\n      解释下，图中我们假设从A点滚动到B点，那么，**如果知道mStartX，mStartY（由startScroll的startX和startY参数得到）和mDeltaX，mDeltaY（由startScroll的dx和dy参数得到）。那么，mFinalX和mFinalY就很容易得到了。此外在加上duration持续时间，那么我们就可以根据（当前时间-mStartTime）占duration的比例来算出当前位置，也即mCurrX和mCurrY。**我不会告诉你，这就是computeScrollOffset的作用！通过上面分析我们发现，**startScroll方法其实相当于一个预处理，为computeScrollOffset提供数据。**\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      下面我们查看computeScrollOffset源码：\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; computeScrollOffset() {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mFinished) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; timePassed = (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)(AnimationUtils.currentAnimationTimeMillis() \u0026amp;#8211; mStartTime);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (timePassed \u0026lt; mDuration) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (mMode) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; SCROLL_MODE:  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                mCurrX = mStartX + Math.round(x * mDeltaX);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                mCurrY = mStartY + Math.round(x * mDeltaY);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; FLING_MODE:  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                 \u0026amp;#8230; \u0026amp;#8230;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mCurrX = mFinalX;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mCurrY = mFinalY;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mFinished = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      看，是不是很好理解了。**首先判断是否结束(mFinished==true?),如果没有结束，那么程序继续向下跑，计算timePassed,即当前时间减去开始时间，如果小于mDuration,那么就可以根据比例计算出当前位置，当然了，这里使用了Interpolator来控制动画的效果，加速或者减速等等。如果已经超过了mDuration了，那么滚动应该停止了，所以将mFinished置为ture,下次调用computeScrollOffset就会返回false了。**\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      ** **\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      到这里，我们把Scroller中的重要部分都分析完了，但是我们发现这两个方法都没有涉及具体滚动。那么滚动到底是如何触发的呢？下面我们将对整个流程进行源码分析。\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      **四.滚动流程分析**\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      ** **\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      在第一部分中，我给出了一个Scroller的使用示例，在smoothScrollTo方法中我们调用了Scroller的startScroll，然后调用了invalidate方法刷新视图，这个滚动效果就是由invalidate触发的！我们知道，调用了invalidate方法将会引起整个view系统的重绘，所以我们得从View的绘制说起。有经验的同学都应该知道，View的绘制包括三个主要过程，分别是measure,layout和draw。下面我们看View类的draw方法源码：\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; draw(Canvas canvas) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;         \u0026amp;#8230; \u0026amp;#8230;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;        * Draw traversal performs several drawing steps which must be executed\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;        * in the appropriate order:\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;        *\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;        *      1. Draw the background\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;        *      2. If necessary, save the canvas\u0026amp;#8217; layers to prepare for fading\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;        *      3. Draw view\u0026amp;#8217;s content\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;        *      4. Draw children\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;        *      5. If necessary, draw the fading edges and restore layers\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;        *      6. Draw decorations (scrollbars for instance)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;        */\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Step 1, draw the background, if needed\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; saveCount;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!dirtyOpaque) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           drawBackground(canvas);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;         \u0026amp;#8230; \u0026amp;#8230;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Step 2, save the canvas\u0026amp;#8217; layers\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;         \u0026amp;#8230; \u0026amp;#8230;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Step 3, draw the content\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!dirtyOpaque) onDraw(canvas);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Step 4, draw the children\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       dispatchDraw(canvas);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Step 5, draw the fade effect and restore layers\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;         \u0026amp;#8230; \u0026amp;#8230;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;   }  \u0026lt;/span\u0026gt;\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \n\n      draw方法将绘制分成了六步，其中第三步是调用onDraw去绘制内容，第四步是调用dispatchDraw去绘制子视图。我们看下dispatchDraw方法：\n    \n\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;    * Called by draw to draw the child views. This may be overridden\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;    * by derived classes to gain control just before its children are drawn\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;    * (but after its own view has been drawn).\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;    * @param canvas the canvas on which to draw the view\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;    */\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;   \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; dispatchDraw(Canvas canvas) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;   }  \u0026lt;/span\u0026gt;\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \n\n      恩，没错，是个空方法，因为只有ViewGroup才有子视图，所以我们来到ViewGroup中，找到dispatchDraw：\n    \n\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; dispatchDraw(Canvas canvas) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childrenCount = mChildrenCount;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View[] children = mChildren;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;         \u0026amp;#8230; \u0026amp;#8230;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; childrenCount; i++) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View child = (preorderedList == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    ? children[childIndex] : preorderedList.get(childIndex);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((child.mViewFlags \u0026amp; VISIBILITY_MASK) == VISIBLE || child.getAnimation() != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                more |= drawChild(canvas, child, drawingTime);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }    \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \n\n      代码也是极其长的，这里截取了一部分。我们看到这个方法中调用了drawChild方法，从名字上就可以看出这个方法是用来绘制子视图的，找到其实现：\n    \n\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; drawChild(Canvas canvas, View child, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; drawingTime) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; child.draw(canvas, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, drawingTime);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \n\n      这里调用了view的draw方法，当然，这个draw方法跟上面那个draw不一样，因为它有三个参数！那还等什么，我们回到View的代码中找到这个含有三个参数的draw方法：\n    \n\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; draw(Canvas canvas, ViewGroup parent, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; drawingTime) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; more = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; childHasIdentityMatrix = hasIdentityMatrix();  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; flags = parent.mGroupFlags;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026amp;#8230; \u0026amp;#8230;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; sx = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; sy = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!hasDisplayList) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           computeScroll();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//终于找到了computeScroll\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           sx = mScrollX;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           sy = mScrollY;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026amp;#8230; \u0026amp;#8230;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; more;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;   }  \u0026lt;/span\u0026gt;\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      在其中，我们找到了computeScroll方法！当然View中的computeScroll方法是空的，需要我们根据场景自己复写。\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      比如，我发现，TextView中就有复写这个方法：\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;   \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll() {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mScroller != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mScroller.computeScrollOffset()) {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;               mScrollX = mScroller.getCurrX();  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;               mScrollY = mScroller.getCurrY();  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;               invalidateParentCaches();  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;               postInvalidate();  \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// So we draw again\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;           }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;   }  \u0026lt;/span\u0026gt;\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      好了，折腾了这么久，**\u0026lt;span style=\u0026quot;color: #000080;\u0026quot;\u0026gt;下面我们再回顾下这个过程：我们在自定义view中调用了startScroll方法为滚动设置了一些基本数据，然后通过invalidate由上而下刷新view视图，首先是根视图（通常是ViewGroup）的draw方法被调用，然后调用onDraw绘制视图内容，接着dispatchDraw方法被调用去绘制子视图，dispatchDraw方法会对每个子视图调用drawChild方法，而drawChild方法会调用该子View的draw方法（三个参数），在draw方法中会调用computeScroll方法进行滚动，而computeScroll方法是被复写的，视场景而定，通常是根据computeScrollOffset来判断是否需要滑动，如果需要的话，接着调用postInvalidate再由上至下重新绘制，如此一来便实现了平滑滚动的效果！\u0026lt;/span\u0026gt;**\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      ok，到这里总算是把Scroller讲清楚了！\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      **五.实例分析**\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      ** **\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      为了便于理解，我这里写了一个小例子，通过打印日志的形式让大家理解上面所讲的内容。\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      首先是几个自定义的view：\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      MyLinearLayout:\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.scrollerdemo;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyLinearLayout \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TEST\u0026amp;#8221;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyLinearLayout(Context context)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyLinearLayout(Context context, AttributeSet attrs)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; draw(Canvas canvas)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyLinearLayout\u0026amp;#8212;\u0026gt;draw\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.draw(canvas);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyLinearLayout\u0026amp;#8212;\u0026gt;onDraw\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDraw(canvas);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll()  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyLinearLayout\u0026amp;#8212;\u0026gt;computeScroll\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.computeScroll();  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \n\n      MyView(实现了平滑滚动效果):\n    \n\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.scrollerdemo;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Scroller;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @author Rowandjj\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TEST\u0026amp;#8221;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Scroller mScroller;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyView(Context context)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        init();  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyView(Context context, AttributeSet attrs)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        init();  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; init()  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mScroller = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Scroller(getContext());   \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; testSmoothScroll()  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//向右下方平滑滚动(向右偏移100，向下偏移100)\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        smoothScrollTo(-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;,-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;100\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; smoothScrollTo(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; destX,\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; destY)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollX = getScrollX();  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollY = getScrollY();  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;scrollX=\u0026amp;#8221;\u0026lt;/span\u0026gt;+scrollX+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;,scrollY=\u0026amp;#8221;\u0026lt;/span\u0026gt;+scrollY);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; deltaX = destX-scrollX;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; deltaY = destY-scrollY;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mScroller.startScroll(scrollX,scrollY,deltaX, deltaY, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        invalidate();  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; draw(Canvas canvas)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyView\u0026amp;#8212;\u0026amp;#8212;\u0026gt;draw run\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.draw(canvas);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyView\u0026amp;#8212;\u0026amp;#8212;\u0026gt;onDraw run\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDraw(canvas);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; dispatchDraw(Canvas canvas)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyView\u0026amp;#8212;\u0026amp;#8212;\u0026gt;dispatchDraw run\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchDraw(canvas);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; drawChild(Canvas canvas, View child, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; drawingTime)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyView\u0026amp;#8212;\u0026amp;#8212;\u0026gt;drawChild run\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.drawChild(canvas, child, drawingTime);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll()  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyView\u0026amp;#8212;\u0026amp;#8212;\u0026gt;computeScroll run\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mScroller != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mScroller.computeScrollOffset())  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                scrollTo(mScroller.getCurrX(),mScroller.getCurrY());  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;scrollX=\u0026amp;#8221;\u0026lt;/span\u0026gt;+getScrollX()+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;,scrollY=\u0026amp;#8221;\u0026lt;/span\u0026gt;+getScrollY());  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                postInvalidate();  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \n\n      MyImageView:\n    \n\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.scrollerdemo;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyImageView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ImageView  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TEST\u0026amp;#8221;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyImageView(Context context)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyImageView(Context context, AttributeSet attrs)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }     \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;myImageView\u0026amp;#8212;-\u0026gt;onDraw run\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDraw(canvas);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; computeScroll()  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;myImageView\u0026amp;#8212;-\u0026gt;computeScroll run\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.computeScroll();  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      我们根据上面三个自定义view做一个布局，外层是MyLinearLayout，中间是MyView，最里面是一个MyImageView.\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      activity_main.xml:\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;LinearLayout xmlns:android=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    android:orientation=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;com.example.scrollerdemo.MyLinearLayout  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        xmlns:tools=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        android:background=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#ffaaff\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        tools:context=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.scrollerdemo.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;com.example.scrollerdemo.MyView  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            android:id=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/mv\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;200dp\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;200dp\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            android:layout_marginLeft=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;50dp\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            android:layout_marginTop=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;100dp\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            android:background=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/darker_gray\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            android:orientation=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;com.example.scrollerdemo.MyImageView  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                android:layout_width=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                android:layout_height=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                android:src=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_launcher\u0026amp;#8221;\u0026lt;/span\u0026gt; /\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;/com.example.scrollerdemo.MyView\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;/com.example.scrollerdemo.MyLinearLayout\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/LinearLayout\u0026gt;  \u0026lt;/span\u0026gt;\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \n\n      下面是MainActivity的代码：\n    \n\n    \n    \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n          **[java]** [view plain](http://blog.csdn.net/chdjj/article/details/41678897#)[copy](http://blog.csdn.net/chdjj/article/details/41678897#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/539577)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/539577/fork)\n\n          \n          \u0026lt;div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.scrollerdemo;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnClickListener  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; MyView mv = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        setContentView(R.layout.activity_main);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mv = (MyView) findViewById(R.id.mv);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mv.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v)  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (v.getId())  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        {  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.mv:\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//点击时触发滚动效果\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mv.testSmoothScroll();  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;:  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n        \n        - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n        \n      \n    \u0026lt;/div\u0026gt;\n    \n    \n\n      代码很简单，不必过多介绍，下面看显示效果：\n    \n\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n    ![](http://img.blog.csdn.net/20141202145938259?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hkamo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e打开logcat查看日志：\n\u003c/div\u003e\u003c/p\u003e","title":"【安卓】从源码的角度深入分析Scroller"},{"content":"先直接上效果图\n上图为实现目标，实现了Android图文混排，文字环绕，支持Span的识别，表情的嵌入，支持文字字体大小的设置等。\n由于项目中需要用到图文混排技术，在此稍微研究了两天，出来一个效果还算不错的东西\n图文混排技术，在不少Android应用中都已经实现，说穿了其实就是两个TextView加一个ImageView的布局罢了，代码里面实现下String的剪切就可以了，不过我这里的这个除了要实现混排效果外，还要支持Span，支持表情等，这就有点麻烦了。下面慢慢分解。先贴出RichTextImageView的布局。\n\u003c?xml version=\u0026#8221;1.0\u0026#8243; encoding=\u0026#8221;utf-8\u0026#8243;?\u003e \u0026lt;com.demonzym.richtextdemo.RichTextImageView xmlns:android=”http://schemas.android.com/apk/res/android” android:layout_width=”fill_parent” android:layout_height=”fill_parent” android:orientation=”vertical” android:id=”@+id/richview” \u0026gt;\n\u0026lt;LinearLayout android:id=”@+id/linearLayout1″ android:layout_width=”fill_parent” android:layout_height=”wrap_content” \u0026gt; \u0026lt;RelativeLayout android:id=”@+id/layout_preimage_isgif_left” android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:layout_weight=”0″ android:visibility=”gone” \u0026gt;\n\u0026lt;ImageView android:id=”@+id/preimage_statues_left” android:layout_width=”134dip” android:layout_height=”134dip” android:background=”@drawable/preview_back” android:cropToPadding=”true” android:scaleType=”centerCrop” android:src=”@drawable/preview_back_small” /\u0026gt;\n\u0026lt;ImageView android:id=”@+id/preimage_isgif_left” android:layout_width=”24dip” android:layout_height=”17dip” android:layout_alignBottom=”@+id/preimage_statues” android:layout_alignRight=”@+id/preimage_statues” android:layout_marginBottom=”9dip” android:layout_marginRight=”7dip” /\u0026gt; \u0026lt;com.demonzym.richtextdemo.RichTextView android:id=”@+id/lefttext” android:layout_width=”wrap_content” android:layout_height=”fill_parent” android:layout_weight=”1″/\u0026gt;\n\u0026lt;RelativeLayout android:id=”@+id/layout_preimage_isgif_right” android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:layout_weight=”0″ android:visibility=”gone” \u0026gt;\n\u0026lt;ImageView android:id=”@+id/preimage_statues_right” android:layout_width=”134dip” android:layout_height=”134dip” android:background=”@drawable/preview_back” android:cropToPadding=”true” android:scaleType=”centerCrop” android:src=”@drawable/preview_back_small” /\u0026gt;\n\u0026lt;ImageView android:id=”@+id/preimage_isgif_right” android:layout_width=”24dip” android:layout_height=”17dip” android:layout_alignBottom=”@+id/preimage_statues” android:layout_alignRight=”@+id/preimage_statues” android:layout_marginBottom=”9dip” android:layout_marginRight=”7dip” /\u0026gt; \u0026lt;com.demonzym.richtextdemo.RichTextView android:id=”@+id/bottomtext” android:layout_width=”fill_parent” android:layout_height=”wrap_content”/\u0026gt;\n\u0026lt;/com.demonzym.richtextdemo.RichTextImageView\u0026gt;\n布局中的RichTextView是另外封装的一个实现Span的TextView，就是实现效果图中表情啊，@啊，#话题# 之类的，了解Span的都懂的，就不细说了。读者研究这个图文混排的时候，可以直接用TextView替代。\nRichTextImageView 即本文中的图文混排的View。继承于LinearLayout，该类实现的关键代码如下：\npublic void setText(String t) { mTopText.setText(“”); mBottomText.setText(“”); mTopText.setVisibility(View.INVISIBLE); mBottomText.setVisibility(View.GONE); bRequestBottomLayout = true;\nif (t == null) t = “”;\n// Log.e(“setText”, t); mTextContent = t;\nmTopText.setText(mTextContent);\nrequestLayout(); }\npublic void setImage(int id) { mImageContent = id; mPreviewImage.setImageResource(id); mPreview.setVisibility(View.VISIBLE);\nif (!Util.isStringEmpty(mTextContent)) setText(mTextContent); }\nprivate void iniViews() { mLinearLayout = (LinearLayout) findViewById(R.id.linearLayout1); mTopText = (RichTextView) findViewById(R.id.lefttext); mBottomText = (RichTextView) findViewById(R.id.bottomtext);\nif(IMAGE_LOCATION == IMAGE_LOCATION_RIGHT){ mPreview = (RelativeLayout) findViewById(R.id.layout_preimage_isgif_right); mPreviewImage = (ImageView) findViewById(R.id.preimage_statues_right); mPreviewImageIsGif = (ImageView) findViewById(R.id.preimage_isgif_right); }else if(IMAGE_LOCATION == IMAGE_LOCATION_LEFT){ mPreview = (RelativeLayout) findViewById(R.id.layout_preimage_isgif_left); mPreviewImage = (ImageView) findViewById(R.id.preimage_statues_left); mPreviewImageIsGif = (ImageView) findViewById(R.id.preimage_isgif_left); } } public void setImageLocation(int l){ if(l != IMAGE_LOCATION_RIGHT \u0026amp;\u0026amp; l != IMAGE_LOCATION_LEFT) return; else{ IMAGE_LOCATION = l; mPreview.setVisibility(View.GONE); iniViews(); setImage(mImageContent); } }\n@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // TODO Auto-generated method stub super.onLayout(changed, l, t, r, b);\nif (Util.isStringEmpty(mTextContent)) return;\n// Log.e(“top text 宽 高”, // mTopText.getWidth() + ” ” + mTopText.getHeight()); // Log.e(“top text 单行高度”, “” + mTopText.getLineHeight()); // Rect rect = getStringRect(mTextContent, mTopText.getPaint()); // Log.e(“文本的宽 高”, rect.width() + ” ” + rect.height()); // toptext最多能显示的行数 int topTextMaxRows = mTopText.getHeight() / mTopText.getLineHeight(); // 显示这些内容真实占用的行数 int textRows = mTopText.getLineCount(); // Log.e(“top text最多能显示的行数”, “” + topTextMaxRows); // Log.e(“当前文本实际占用的行数”, “” + textRows); //由于文本可能带有表情，重新计算显示行数，以保证显示正确 Rect lineR = new Rect(); int realH = 0; //toptext真实高度 int i = 0; for(i = 0; i \u0026lt; topTextMaxRows; i++){ try{ mTopText.getLineBounds(i, lineR); }catch(IndexOutOfBoundsException e){ break; } realH += lineR.height(); if(realH \u0026gt;= mTopText.getHeight()) break; } // Log.e(“当前view实际能显示的行数为”, “” + i); topTextMaxRows = i; //如果toptext显示不下的话，显示到bottomtext里面去 if (textRows \u0026gt;= topTextMaxRows \u0026amp;\u0026amp; bRequestBottomLayout) { // toptext最后一个可见字符的位置 int lastindex = mTopText.getLayout().getLineVisibleEnd(\nClickableSpan[] cs = mTopText.getSpans(); int spanstart = 0; int spanend = 0; spanstring = “”; STATE = 0; // 1网页 2人名 3话题 for (ClickableSpan c : cs) { spanstart = mTopText.getSpanStart(c); spanend = mTopText.getSpanEnd(c); if (spanstart \u0026lt;= lastindex \u0026amp;\u0026amp; spanend \u0026gt; lastindex) { if (c instanceof LinkClickableSpan) { // Log.e(“转角span类型”, “网页”); spanstring = ((LinkClickableSpan) c).getLink(); STATE = 1; } if (c instanceof NameClickableSpan) { // Log.e(“转角span类型”, “人名”); spanstring = ((NameClickableSpan) c).getName(); STATE = 2; } if (c instanceof TopicClickableSpan) { // Log.e(“转角span类型”, “话题”); spanstring = ((TopicClickableSpan) c).getTopic(); STATE = 3; } break; } } mTopText.setText(mTextContent.substring(0, lastindex)); mTopText.setVisibility(View.VISIBLE); // 当行数不是整数时，调整内容会有下面半行没遮住，所以干脆都处理完以后再显示出来 mBottomText.setText(mTextContent.substring(lastindex, mTextContent.length()) + mBottomText.getText().toString()); if (mBottomText.getText().length() \u0026gt; 0 \u0026amp;\u0026amp; bRequestBottomLayout){ mBottomText.setVisibility(View.VISIBLE); mHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub mBottomText.requestLayout(); bRequestBottomLayout = false; } }); }\nif (STATE != 0 || !bRequestBottomLayout) {\nLog.e(“spanstring”, spanstring);\n// Log.e(“”, “移除转角span”);\nswitch (STATE) { case 1: mTopText.getSpannable().setSpan( mTopText.new LinkClickableSpan(spanstring), spanstart, lastindex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); mBottomText.getSpannable().setSpan( mBottomText.new LinkClickableSpan(spanstring), 0, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // Log.e(“”, “网页”); break; case 2: mTopText.getSpannable().setSpan( mTopText.new NameClickableSpan(spanstring), spanstart, lastindex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); mBottomText.getSpannable().setSpan( mBottomText.new NameClickableSpan(spanstring), 0, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // Log.e(“”, “人名”); break; case 3: mTopText.getSpannable().setSpan( mTopText.new TopicClickableSpan(spanstring), spanstart, lastindex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); mBottomText.getSpannable().setSpan( mBottomText.new TopicClickableSpan(spanstring), 0, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // Log.e(“”, “话题”); break; } mTopText.setText(mTopText.getSpannable(), BufferType.SPANNABLE); mBottomText.setText(mBottomText.getSpannable(), BufferType.SPANNABLE); } } }\n说明下难点：\n第一，转角处可能存在Span，比如一个话题 #话题话题话题话题话题话题话题话题话题#，可能一半内容在mTopText里面的最后一行显示，而另一半显示不下了，这就需要剪切剩余的String显示到mBottomText里面去，可是Span的内容就会出错，这就需要重新设置下转角处的Span效果了\n第二，由于存在图片Span，会导致行高不正确，所以需要在获取到mTopText能显示的最多行数以后，重新判断一次是否正确，如果不正确的话，需要重新调整，不然mTopText会有一部分内容显示不下。\n该View实现完成后，在布局中使用include条用，代码中find出来就可以直接使用了\n不考虑Span的话，直接将代码中转角处理Span部分删除即可使用，我注释的挺清楚了\n代码写的较急，可能有点乱，仅作交流\n文章转自：http://blog.sina.com.cn/s/blog_47021dd401012szb.html ","permalink":"https://blog.zdltech.com/posts/android-%E6%96%87%E5%AD%97%E7%8E%AF%E7%BB%95-%E5%9B%BE%E6%96%87%E6%B7%B7%E6%8E%92-%E6%94%AF%E6%8C%81span%E6%8A%98%E5%8F%A0/","summary":"\u003cp\u003e\u003cspan style=\"color: #ff0000;\"\u003e\u003cstrong\u003e先直接上效果图\u003c/strong\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://photo.blog.sina.com.cn/showpic.html#blogid=47021dd401012szb\u0026amp;url=http://s5.sinaimg.cn/orignal/47021dd4gb63d6d54ffa4\"\u003e\u003cimg loading=\"lazy\" decoding=\"async\" title=\"Android \u003cwbr\u003e文字环绕 \u003cwbr\u003e图文混排 \u003cwbr\u003e支持Span折叠\" src=\"http://s5.sinaimg.cn/middle/47021dd4gb63d6d54ffa4\u0026690\" alt=\"Android \u003cwbr\u003e文字环绕 \u003cwbr\u003e图文混排 \u003cwbr\u003e支持Span折叠\" width=\"320\" height=\"480\" name=\"image_operate_1061326275157265\" /\u003e\u003c/a\u003e \u003cwbr /\u003e \u003ca href=\"http://photo.blog.sina.com.cn/showpic.html#blogid=47021dd401012szb\u0026amp;url=http://s8.sinaimg.cn/orignal/47021dd4gb64b88ffe747\"\u003e\u003cimg loading=\"lazy\" decoding=\"async\" title=\"Android \u003cwbr\u003e文字环绕 \u003cwbr\u003e图文混排 \u003cwbr\u003e支持Span折叠\" src=\"http://s8.sinaimg.cn/middle/47021dd4gb64b88ffe747\u0026690\" alt=\"Android \u003cwbr\u003e文字环绕 \u003cwbr\u003e图文混排 \u003cwbr\u003e支持Span折叠\" width=\"320\" height=\"480\" name=\"image_operate_77241326335453250\" /\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cwbr /\u003e\n\u003cp\u003e上图为实现目标，实现了Android图文混排，文字环绕，支持Span的识别，表情的嵌入，支持文字字体大小的设置等。\u003c/p\u003e\n\u003cp\u003e \u003cwbr /\u003e\u003c/p\u003e\n\u003cp\u003e \u003cwbr /\u003e\u003c/p\u003e\n\u003cp\u003e \u003cwbr /\u003e\u003c/p\u003e\n\u003cp\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e 由于项目中需要用到图文混排技术，在此稍微研究了两天，出来一个效果还算不错的东西\u003c/p\u003e\n\u003cp\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e 图文混排技术，在不少Android应用中都已经实现，说穿了其实就是两个TextView加一个ImageView的布局罢了，代码里面实现下String的剪切就可以了，不过我这里的这个除了要实现混排效果外，还要支持Span，支持表情等，这就有点麻烦了。下面慢慢分解。先贴出RichTextImageView的布局。\u003c/p\u003e\n\u003cp\u003e \u003cwbr /\u003e\u003c/p\u003e\n  \u003c?xml version=\u0026#8221;1.0\u0026#8243; encoding=\u0026#8221;utf-8\u0026#8243;?\u003e\n\u003cp\u003e\u0026lt;com.demonzym.richtextdemo.RichTextImageView xmlns:android=”\u003ca href=\"http://schemas.android.com/apk/res/android\"\u003ehttp://schemas.android.com/apk/res/android\u003c/a\u003e”\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e android:layout_width=”fill_parent”\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e android:layout_height=”fill_parent”\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e android:orientation=”vertical”\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e android:id=”@+id/richview” \u0026gt;\u003c/p\u003e\n\u003cp\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u0026lt;LinearLayout\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e android:id=”@+id/linearLayout1″\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e android:layout_width=”fill_parent”\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e android:layout_height=”wrap_content” \u0026gt;\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u0026lt;RelativeLayout\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e android:id=”@+id/layout_preimage_isgif_left”\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e android:layout_width=”wrap_content”\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e android:layout_height=”wrap_content”\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e android:layout_weight=”0″\n\u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e \u003cwbr /\u003e android:visibility=”gone” \u0026gt;\u003c/p\u003e","title":"Android 文字环绕 图文混排 支持Span折叠"},{"content":"针对屏幕上的一个View控件，Android如何区分应当触发onTouchEvent，还是onClick，亦或是onLongClick事件？\n在Android中，一次用户操作可以被不同的View按次序分别处理，并将完全响应了用户一次UI操作称之为消费了该事件(consume)，那么Android是按什么次序将事件传递的呢?又在什么情况下判定为消费了该事件？\n搞清楚这些问题对于编写出能正确响应UI操作的代码是很重要的，尤其当屏幕上的不同View需要针对此次UI操作做出各种不同响应的时候更是如此，一个典型例子就是用户在桌面上放置了一个Widget，那么当用户针对widget做各种操作时，桌面本身有的时候要对用户的操作做出响应，有时忽略。只有搞清楚事件触发和传递的机制才有可能保证在界面布局非常复杂的情况下，UI控件仍然能正确响应用户操作。\n1. onTouchEvent\nonTouchEvent中要处理的最常用的3个事件就是：ACTION_DOWN、ACTION_MOVE、ACTION_UP。\n这三个事件标识出了最基本的用户触摸屏幕的操作，含义也很清楚。虽然大家天天都在用它们，但是有一点请留意，ACTION_DOWN事件作为起始事件，它的重要性是要超过ACTION_MOVE和ACTION_UP的，如果发生了ACTION_MOVE或者ACTION_UP，那么一定曾经发生了ACTION_DOWN。\n从Android的源代码中能看到基于这种不同重要性的理解而实现的一些交互机制，SDK中也有明确的提及，例如在ViewGroup的onInterceptTouchEvent方法中，如果在ACTION_DOWN事件中返回了true，那么后续的事件将直接发给onTouchEvent，而不是继续发给onInterceptTouchEvent。\n2. onClick、onLongClick与onTouchEvent\n曾经看过一篇帖子提到，如果在View中处理了onTouchEvent，那么就不用再处理onClick了，因为Android只会触发其中一个方法。这个理解是不太正确的，针对某个view，用户完成了一次触碰操作，显然从传感器上得到的信号是手指按下和抬起两个操作，我们可以理解为一次Click，也可以理解为发生了一次ACTION_DOWN和ACTION_UP，那么Android是如何理解和处理的呢？\n在Android中，onClick、onLongClick的触发是和ACTION_DOWN及ACTION_UP相关的，在时序上，如果我们在一个View中同时覆写了onClick、onLongClick及onTouchEvent的话，onTouchEvent是最先捕捉到ACTION_DOWN和ACTION_UP事件的，其次才可能触发onClick或者onLongClick。主要的逻辑在View.java中的onTouchEvent方法中实现的：\ncase MotionEvent.ACTION_DOWN:\nmPrivateFlags |= PRESSED;\nrefreshDrawableState();\nif ((mViewFlags \u0026amp; LONG_CLICKABLE) == LONG_CLICKABLE) {\npostCheckForLongClick();\n}\nbreak;\ncase MotionEvent.ACTION_UP:\nif ((mPrivateFlags \u0026amp; PRESSED) != 0) {\nboolean focusTaken = false;\nif (isFocusable() \u0026amp;\u0026amp; isFocusableInTouchMode() \u0026amp;\u0026amp; !isFocused()) {\nfocusTaken = requestFocus();\n}\nif (!mHasPerformedLongPress) {\nif (mPendingCheckForLongPress != null) {\nremoveCallbacks(mPendingCheckForLongPress);\n}\nif (!focusTaken) {\nperformClick();\n}\n}\n…\nbreak;\n可以看到，Click的触发是在系统捕捉到ACTION_UP后发生并由performClick()执行的，performClick里会调用先前注册的监听器的onClick()方法：\npublic boolean performClick() {\n…\nif (mOnClickListener != null) {\nplaySoundEffect(SoundEffectConstants.CLICK);\nmOnClickListener.onClick(this);\nreturn true;\n}\nreturn false;\n}\nLongClick的触发则是从ACTION_DOWN开始，由postCheckForLongClick()方法完成：\nprivate void postCheckForLongClick() {\nmHasPerformedLongPress = false;\nif (mPendingCheckForLongPress == null) {\nmPendingCheckForLongPress = new CheckForLongPress();\n}\nmPendingCheckForLongPress.rememberWindowAttachCount();\npostDelayed(mPendingCheckForLongPress, ViewConfiguration.getLongPressTimeout());\n}\n可以看到，在ACTION_DOWN事件被捕捉后，系统会开始触发一个postDelayed操作，delay的时间在Eclair2.1上为500ms，500ms后会触发CheckForLongPress线程的执行：\nclass CheckForLongPress implements Runnable {\n…\npublic void run() {\nif (isPressed() \u0026amp;\u0026amp; (mParent != null)\n\u0026amp;\u0026amp; mOriginalWindowAttachCount == mWindowAttachCount) {\nif (performLongClick()) {\nmHasPerformedLongPress = true;\n}\n}\n}\n…\n}\n如果各种条件都满足，那么在CheckForLongPress中执行performLongClick()，在这个方法中将调用onLongClick()：\npublic boolean performLongClick() {\n…\nif (mOnLongClickListener != null) {\nhandled = mOnLongClickListener.onLongClick(View.this);\n}\n…\n}\n从实现中可以看到onClick()和onLongClick()方法是由ACTION_DOWN和ACTION_UP事件捕捉后根据各种情况最终确定是否触发的，也就是说如果我们在一个Activity或者View中同时监听或者覆写了onClick(),onLongClick()和onTouchEvent()方法，并不意味着只会发生其中一种。\n下面是一个onClick被触发的基本时序的Log：\n04-05 05:57:47.123: DEBUG/TSActivity(209): onTouch ACTION_DOWN\n04-05 05:57:47.263: DEBUG/TSActivity(209): onTouch ACTION_UP\n04-05 05:57:47.323: DEBUG/TSActivity(209): onClick\n可以看出是按ACTION_DOWN -\u0026gt; ACTION_UP -\u0026gt; onClick的次序发生的。\n下面是一个onLongClick被触发的基本时序的Log：\n04-05 06:00:04.133: DEBUG/TSActivity(248): onTouch ACTION_DOWN\n04-05 06:00:04.642: DEBUG/TSActivity(248): onLongClick\n04-05 06:00:05.083: DEBUG/TSActivity(248): onTouch ACTION_UP\n可以看到，在保持按下的状态一定时间后会触发onLongClick,之后抬起手才会发生ACTION_UP。\n3. onClick和onLongClick能同时发生吗？\n要弄清楚这个问题只要理解Android对事件处理的所谓消费(consume)概念即可，一个用户的操作会被传递到不同的View控件和同一个控件的不同监听方法处理，任何一个接收并处理了该次事件的方法如果在处理完后返回了true，那么该次event就算被完全处理了，其他的View或者监听方法就不会再有机会处理该event了。\nonLongClick的发生是由单独的线程完成的，并且在ACTION_UP之前，而onClick的发生是在ACTION_UP后，因此同一次用户touch操作就有可能既发生onLongClick又发生onClick。这样是不是不可思议？所以及时向系统表示“我已经完全处理（消费）了用户的此次操作”，是很重要的事情。例如，我们如果在onLongClick()方法的最后return true，那么onClick事件就没有机会被触发了。\n下面的Log是在onLongClick()方法return false的情况下，一次触碰操作的基本时序：\n04-05 06:00:53.023: DEBUG/TSActivity(277): onTouch ACTION_DOWN\n04-05 06:00:53.533: DEBUG/TSActivity(277): onLongClick\n04-05 06:00:55.603: DEBUG/TSActivity(277): onTouch ACTION_UP\n04-05 06:00:55.663: DEBUG/TSActivity(277): onClick\n可以看到，在ACTION_UP后仍然触发了onClick()方法。\n转自：http://blog.csdn.net/ddna/article/details/5451722\n","permalink":"https://blog.zdltech.com/posts/android-ontouchevent-onclick%E5%8F%8Aonlongclick%E7%9A%84%E8%B0%83%E7%94%A8%E6%9C%BA%E5%88%B6/","summary":"\u003cp\u003e针对屏幕上的一个View控件，Android如何区分应当触发onTouchEvent，还是onClick，亦或是onLongClick事件？\u003c/p\u003e\n\u003cp\u003e在Android中，一次用户操作可以被不同的View按次序分别处理，并将完全响应了用户一次UI操作称之为消费了该事件(consume)，那么Android是按什么次序将事件传递的呢?又在什么情况下判定为消费了该事件？\u003c/p\u003e\n\u003cp\u003e搞清楚这些问题对于编写出能正确响应UI操作的代码是很重要的，尤其当屏幕上的不同View需要针对此次UI操作做出各种不同响应的时候更是如此，一个典型例子就是用户在桌面上放置了一个Widget，那么当用户针对widget做各种操作时，桌面本身有的时候要对用户的操作做出响应，有时忽略。只有搞清楚事件触发和传递的机制才有可能保证在界面布局非常复杂的情况下，UI控件仍然能正确响应用户操作。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e1.  onTouchEvent\u003c/p\u003e\n\u003cp\u003eonTouchEvent中要处理的最常用的3个事件就是：ACTION_DOWN、ACTION_MOVE、ACTION_UP。\u003c/p\u003e\n\u003cp\u003e这三个事件标识出了最基本的用户触摸屏幕的操作，含义也很清楚。虽然大家天天都在用它们，但是有一点请留意，ACTION_DOWN事件作为起始事件，它的重要性是要超过ACTION_MOVE和ACTION_UP的，如果发生了ACTION_MOVE或者ACTION_UP，那么一定曾经发生了ACTION_DOWN。\u003c/p\u003e\n\u003cp\u003e从Android的源代码中能看到基于这种不同重要性的理解而实现的一些交互机制，SDK中也有明确的提及，例如在ViewGroup的onInterceptTouchEvent方法中，如果在ACTION_DOWN事件中返回了true，那么后续的事件将直接发给onTouchEvent，而不是继续发给onInterceptTouchEvent。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e2.  onClick、onLongClick与onTouchEvent\u003c/p\u003e\n\u003cp\u003e曾经看过一篇帖子提到，如果在View中处理了onTouchEvent，那么就不用再处理onClick了，因为Android只会触发其中一个方法。这个理解是不太正确的，针对某个view，用户完成了一次触碰操作，显然从传感器上得到的信号是手指按下和抬起两个操作，我们可以理解为一次Click，也可以理解为发生了一次ACTION_DOWN和ACTION_UP，那么Android是如何理解和处理的呢？\u003c/p\u003e\n\u003cp\u003e在Android中，onClick、onLongClick的触发是和ACTION_DOWN及ACTION_UP相关的，在时序上，如果我们在一个View中同时覆写了onClick、onLongClick及onTouchEvent的话，onTouchEvent是最先捕捉到ACTION_DOWN和ACTION_UP事件的，其次才可能触发onClick或者onLongClick。主要的逻辑在View.java中的onTouchEvent方法中实现的：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ecase MotionEvent.ACTION_DOWN\u003c/strong\u003e:\u003c/p\u003e\n\u003cp\u003emPrivateFlags |= PRESSED;\u003c/p\u003e\n\u003cp\u003erefreshDrawableState();\u003c/p\u003e\n\u003cp\u003eif ((mViewFlags \u0026amp; LONG_CLICKABLE) == LONG_CLICKABLE) {\u003c/p\u003e\n\u003cp\u003epostCheckForLongClick();\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003ebreak;\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ecase MotionEvent.ACTION_UP\u003c/strong\u003e:\u003c/p\u003e\n\u003cp\u003eif ((mPrivateFlags \u0026amp; PRESSED) != 0) {\u003c/p\u003e\n\u003cp\u003eboolean focusTaken = false;\u003c/p\u003e\n\u003cp\u003eif (isFocusable() \u0026amp;\u0026amp; isFocusableInTouchMode() \u0026amp;\u0026amp; !isFocused()) {\u003c/p\u003e\n\u003cp\u003efocusTaken = requestFocus();\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eif (!mHasPerformedLongPress) {\u003c/p\u003e\n\u003cp\u003eif (mPendingCheckForLongPress != null) {\u003c/p\u003e\n\u003cp\u003eremoveCallbacks(mPendingCheckForLongPress);\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003eif (!focusTaken) {\u003c/p\u003e\n\u003cp\u003eperformClick();\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e…\u003c/p\u003e\n\u003cp\u003ebreak;\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e可以看到，Click的触发是在系统捕捉到ACTION_UP后发生并由performClick()执行的，performClick里会调用先前注册的监听器的onClick()方法：\u003c/p\u003e\n\u003cp\u003epublic boolean performClick() {\u003c/p\u003e\n\u003cp\u003e…\u003c/p\u003e\n\u003cp\u003eif (mOnClickListener != null) {\u003c/p\u003e\n\u003cp\u003eplaySoundEffect(SoundEffectConstants.CLICK);\u003c/p\u003e\n\u003cp\u003emOnClickListener.onClick(this);\u003c/p\u003e\n\u003cp\u003ereturn true;\u003c/p\u003e","title":"Android onTouchEvent, onClick及onLongClick的调用机制"},{"content":"Android的TextView除了可以用來顯示文字資料之外，還可以使用HTML語法來調整文字的樣式和文字超連結，無需特地去使用WebView。只是一旦使用TextView製作超連結，該TextView就會變得難以控制，因此有幾個特性應該是設計師必須事先知道的。\nTextView顯示HTML 要使用TextView顯示HTML的作法很簡單，只要用以下方式來setText即可。\n``` textView.setText(Html.fromHtml(\"HTML語法字串\")); ``` 例如：\n``` textView.setText(Html.fromHtml(\"歡迎大家來到\u0026lt;big\u0026gt;\u0026lt;font color=\\\"#FF0000\\\"\u0026gt;\u0026lt;b\u0026gt;MagicLen\u0026lt;/b\u0026gt;\u0026lt;/font\u0026gt;\u0026lt;/big\u0026gt;，本站網址如下：\u0026lt;br/\u0026gt;\u0026lt;br/\u0026gt;\u0026lt;a href=\\\"http://magiclen.org/\\\"\u0026gt;http://magiclen.org/\u0026lt;/a\u0026gt;\")); ``` 結果如下：\n啟用HTML超連結 如果只是單單使用TextView的setText方法來指定HTML語法，HTML超連結將無法有真正的作用，可以使用Android SDK內建提供的方式來讓TextView擁有超連結的功能，程式只要添加一行即可，如下：\n``` textView.setMovementMethod(LinkMovementMethod.getInstance()); ``` 指定LinkMovementMethod給textView，使其擁有超連結的功能。\nTextView使用AutoLink自動判斷連結 若資料來源並非是HTML，而是純文字的話，如果想要讓文字中的網址、電子郵件等等的資訊也擁有超連結，可以設定TextView的AutoLink屬性，決定要將哪些資訊自動產生超連結。\n在XML檔案中設定autolink屬性 添加方式如下：\n``` \u0026lt;TextView android:id=\"@+id/textView\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:autoLink=\"all\" /\u0026gt; ``` 若將android:autoLink設為all，那它會將text文字中的網址、電子郵件、地址、電話都變成超連結。如果沒有特殊需求的話，不要自動將電話變成超連結，因為不是所有的Android裝置都能夠打電話，且電話格式各國都不太一樣，很大的機率會將一般數字誤判成電話。也不要自動將地址變成超連結，因為並非在所有裝置上都有地圖App，而且Android好像沒辦法判斷中文地址。所以autoLink屬性可以改寫如下：\n``` \u0026lt;TextView android:id=\"@+id/textView\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:autoLink=\"web|email\" /\u0026gt; ``` 如果在XML設定autoLink，啟用了AutoLink屬性的話，LinkMovementMethod將會被自動加入TextView中，因此沒有必要使用setMovementMethod再指定LinkMovementMethod。\n在SDK中用Java程式指定AutoLinkMask 添加方式如下：\n``` textView.setAutoLinkMask(Linkify.ALL); ``` 不將電話和地址加上超連結的寫法如下：\n``` textView.setAutoLinkMask(Linkify.EMAIL_ADDRESSES|Linkify.WEB_URLS); ``` 僅用setAutoLinkMask方法是無法啟用AutoLink屬性的，還再指定LinkMovementMethod給TextView：\n``` textView.setMovementMethod(LinkMovementMethod.getInstance()); ``` 不必使用HTML的a標籤指定超連結 啟用textView的AutoLink之後，就不必再使用HTML的a標籤來製作超連結。因為Android會自動抓取text文字中符合的格式，將其自動更換為HTML的超連結。當然如果想要讓超連結顯示出不同的文字，還是可以使用a標籤來指定。完全不使用HTML，Android也會自動產生超連結。\n以下舉個例子：\n``` textView.setText(\"歡迎大家來到MagicLen\\n本站網址：http://magiclen.org\\n電子郵件：len@magiclen.org\"); textView.setAutoLinkMask(Linkify.EMAIL_ADDRESSES|Linkify.WEB_URLS); textView.setMovementMethod(LinkMovementMethod.getInstance()); ``` 結果如下：\n支援超連結的TextView所產生的問題 要讓TextView擁有超連結功能，必須要指定LinkMovementMethod給TextView。然而TextView一旦設定了MovementMethod或是KeyListener，TextView會自動將Focusable、Clickable、LongClickable屬性設定為true。\n問題與解決方法 當TextView為Focusable的時候，且此TextView作為GridView或是ListView的Item，會使得無論是否點擊到TextView，onItemClickListener和onItemLongClickListener都會沒有作用。所以一定要覆寫掉hasFocusable方法，讓他永遠傳回false。\n當TextView為Clickable的時候，onTouchEvent將永遠回傳true，所以點擊事件在TextView中就被擋下了，無法傳給更上層的View，因此當此TextView作為GridView或是ListView的Item時，onItemClickListener和onItemLongClickListener將無作用，所以一定要想辦法覆寫掉onTouchEvent方法，讓它可以在點擊到TextView中連結的時候傳回true就好。\n但是，Android內建的LinkMovementMethod並不會讓我們知道使用者到底是不是點擊連結，因此我們還必須改寫LinkMovementMethod。\n改寫後的TextView命名為LinkTextView，LinkMovementMethod命名為LinkTextViewMovementMethod，程式碼如下：\n``` /** * 解決可使用Link HTML的TextView變成Clickable和Focusable的問題 * * @author magiclen */ public class LinkTextView extends TextView { // -----物件變數----- private boolean linkHit; // 是否為按下連結 // -----建構子----- public LinkTextView(Context context) { super(context); } public LinkTextView(Context context, AttributeSet attrs) { super(context, attrs); } public LinkTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } // -----物件方法----- /** * 覆寫onTouchEvent，使其不會永遠傳回true，若為true，則無法將touch事件傳出給上層的View。 * */ @SuppressLint(\"ClickableViewAccessibility\") @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); return linkHit; } /** * 設定HTML內容給TextView，如果已啟用AutoLink屬性，則不需要使用這個方法來製作a標籤的連結。 * * @param html */ public void setTextViewHTML(String html) { Spanned sequence = Html.fromHtml(html); SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence); setText(strBuilder); } /** * 設定MovementMethod之後，TextView會成為Focusable，所以LinkTextView覆寫此方法，永遠傳回false。 */ @Override public boolean hasFocusable() { return false; } /** * 繼承LinkMovementMethod的LinkTextViewMovementMethod，將會針對連結點擊進行處理， * 讓LinkTextView知道目前點擊是否為連結點擊。 * * @author magiclen * */ public static class LinkTextViewMovementMethod extends LinkMovementMethod { // -----類別變數----- private static LinkTextViewMovementMethod sInstance; // 儲存唯一的實體參考 // -----物件方法----- /** * 取得LinkTextViewMovementMethod的唯一實體參考。 * * @return */ public static LinkTextViewMovementMethod getInstance() { if (sInstance == null) { sInstance = new LinkTextViewMovementMethod(); // 建立新的實體 } return sInstance; } /** * 覆寫觸控事件，分辨出是否為連結的點擊。 */ @Override public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { int action = event.getAction(); // 取得事件類型 if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { int x = (int) event.getX(); int y = (int) event.getY(); x -= widget.getTotalPaddingLeft(); y -= widget.getTotalPaddingTop(); x += widget.getScrollX(); y += widget.getScrollY(); Layout layout = widget.getLayout(); int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); if (link.length != ) { // 是連結點擊 if (widget instanceof LinkTextView) { // 如果實體是LinkTextView ((LinkTextView) widget).linkHit = true; } if (action == MotionEvent.ACTION_UP) { // 放開時 link[].onClick(widget); // 開啟連結 } else if (action == MotionEvent.ACTION_DOWN) { // 按下時 Selection.setSelection(buffer, buffer.getSpanStart(link[]), buffer.getSpanEnd(link[])); // 選擇連結 } return true; } else { // 不是連結點擊 if (widget instanceof LinkTextView) { // 如果實體是LinkTextView ((LinkTextView) widget).linkHit = false; } Selection.removeSelection(buffer); Touch.onTouchEvent(widget, buffer, event); return false; } } return Touch.onTouchEvent(widget, buffer, event); } } } ``` LinkTextView的使用方式和一般的TextView一樣，只不過如果要使其支援超連結功能，一定要手動指定LinkTextViewMovementMethod給LinkTextView，如下：\n``` linkTextView.setMovementMethod(LinkTextViewMovementMethod.getInstance()); ``` \u0026amp;nbsp; 转自：http://magiclen.org/android-html-textview/ 最近在做项目研发过程中有这样一个需求：ListView的Item里的子控件TextView要设置超链接、指定文字高亮显示，然后点击超链接后跳转到指定URL的网页。实现超链接的跳转这很容易，只要通过对TextView设置SpannableString对象即可，即如下代码：\nTextView tv = (TextView)findViewById(R.id.tv);\nSpannableString sp = new SpannableString(“此处为tv里显示的内容”);\nsp.setSpan( new URLSpan( “http://www.baidu.com” ), 3 , 8 , Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\ntv.setText(sp);\ntv.setMovementMethod(LinkMovementMethod.getInstance());\n通过这样的设置后已经能够实现对超链接点击跳转到指定URL的网页了，可麻烦又来了，你会发现点击ListView里的Item时没有任何反应，这是什么原因呢？还记得上面在设置超链接的时候有这样一条语句：tv.setMovementMethod(LinkMovementMethod.getInstance());我们现在把这条语句注释掉看看……run App,结果点击Item的时候能够响应了，可惜超链接又失效了，任你点击也没有响应了，哎，真可谓是“鱼和熊掌不可兼得”。现在已经断定Item失效的原因何在了，那为什么这条语句就会导致Item点击失效呢？源码往往是揭开程序中各种奇芭问题的尖锐利器，让我们跟踪下源码吧……打开TextView的源码文件，截取的关键代码片段如下：\nwKioL1LHkTyjKLGQAACZ9Ux9MIg927.jpg\n该代码片段是TextView源码的第1421行(Android4.2.2版本)，我们发现不能通过重写此方法来解决我们所面临的问题，再继续跟踪LinkMovementMethod这个类吧，关键源码如下：\n@Override\npublic boolean onTouchEvent(TextView widget, Spannable buffer,\nMotionEvent event) {\nint action = event.getAction();\nif (action == MotionEvent.ACTION_UP ||\naction == MotionEvent.ACTION_DOWN) {\nint x = (int) event.getX();\nint y = (int) event.getY();\nx -= widget.getTotalPaddingLeft();\ny -= widget.getTotalPaddingTop();\nx += widget.getScrollX();\ny += widget.getScrollY();\nLayout layout = widget.getLayout();\nint line = layout.getLineForVertical(y);\nint off = layout.getOffsetForHorizontal(line, x);\n//获取textview里的超链接对象，并用ClickableSpan数组盛装\nClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);\nif (link.length != 0) { //此处是对超链接点击事件进行处理……\nif (action == MotionEvent.ACTION_UP) {\nlink[0].onClick(widget);\n} else if (action == MotionEvent.ACTION_DOWN) {\nSelection.setSelection(buffer,\nbuffer.getSpanStart(link[0]),\nbuffer.getSpanEnd(link[0]));\n}\nreturn true; //处理结束后返回true,这里一定要注意：当返回值为true时则表示点击事件已经被，就再也不会继续传递了\n} else {\nSelection.removeSelection(buffer);\n}\n}\nreturn super.onTouchEvent(widget, buffer, event);\n}\n上述源码为LinkMovementMethod类的第188行。发现了Item点击失效的原因是因为onTouch方法总是返回true而并没有根据不同的情况来作处理，此时大家可能会想直接对这个方法重写就能解决问题了。我和大家想的也一样，对该方法重写，并根据情况返回true或false,遗憾的是还是没有效果，并且在重写的方法里看不到输出的日志信息，暂时不明其中原因，请高手赐教！眼看就要看到光明了，可还是被打击了……不要灰心，面包总是会有的，如果你不放弃的话，哈哈。换个keywords google一下，终于找到国外的一个网站，上面的文章标题是：\nwKiom1LHlTzxAlYtAAA2uld9Jrk531.jpg\n此时此刻的心情真是如获至宝呀……接着看下去……发现有高人是这样解决的：\nwKioL1LHldywWR1tAAE4WGfZtn4031.jpg\n发现这位高人本质思路是我们开始分析的本质思路一样，只不过他把要处理的代码放在了TextView的onTouch方法里，然后根据不同的情况返回true或false.在getView()方法里对相应的TextView进行设置吧，Run app……见证奇迹的时刻到了……哈哈，结果真的能行了，耶哦！\n原文链接：http://stackoverflow.com/questions/8558732/listview-textview-with-linkmovementmethod-makes-list-item-unclickable\n经过此劫，我发现了为什么国外的技术总是比国内要先进得多了，我在此并不是贬低同僚，不支持国产，而是在国内的技术普遍都是你抄我，我抄你的，有的甚至连原文链接都不放……大家可以看看国外这个技术网站人家是怎么解决问题的，真是按部就班，循序渐进的，不仅让你知其然还知其所以然。\nThere are THREE show-stoppers in this case. the root reason is that when you call setMovementMethod or setKeyListener, TextView “fixes” it’s settings:\nsetFocusable(true);\nsetClickable(true);\nsetLongClickable(true);\nSo, the first reason is that when a View is clickable – it always consumes ACTION_UP event (by returning true in onTouchEvent(MotionEvent event) ). To fix that you should return true in that method only if the user actually clicks the URL. But the LinkMovementMethod doesn’t tell us, if the user actually clicked a link. It returns “true” in it’s onTouch if the user clicks the link, but also in many other cases.\nSo, actually I did a hack here:\npublic class TextViewFixTouchConsume extends TextView {\nboolean dontConsumeNonUrlClicks = true;\nboolean linkHit;\npublic TextViewFixTouchConsume(Context context) {\nsuper(context);\n}\npublic TextViewFixTouchConsume(Context context, AttributeSet attrs) {\nsuper(context, attrs);\n}\npublic TextViewFixTouchConsume(Context context, AttributeSet attrs, int defStyle) {\nsuper(context, attrs, defStyle);\n}\n@Override\npublic boolean onTouchEvent(MotionEvent event) {\nlinkHit = false;\nboolean res = super.onTouchEvent(event);\nif (dontConsumeNonUrlClicks)\nreturn linkHit;\nreturn res;\n}\npublic void setTextViewHTML(String html)\n{\nCharSequence sequence = Html.fromHtml(html);\nSpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);\nsetText(strBuilder);\n}\npublic static class LocalLinkMovementMethod extends LinkMovementMethod{\nstatic LocalLinkMovementMethod sInstance;\npublic static LocalLinkMovementMethod getInstance() {\nif (sInstance == null)\nsInstance = new LocalLinkMovementMethod();\nreturn sInstance;\n}\n@Override\npublic boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {\nint action = event.getAction();\nif (action == MotionEvent.ACTION_UP ||\naction == MotionEvent.ACTION_DOWN) {\nint x = (int) event.getX();\nint y = (int) event.getY();\nx -= widget.getTotalPaddingLeft();\ny -= widget.getTotalPaddingTop();\nx += widget.getScrollX();\ny += widget.getScrollY();\nLayout layout = widget.getLayout();\nint line = layout.getLineForVertical(y);\nint off = layout.getOffsetForHorizontal(line, x);\nClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);\nif (link.length != 0) {\nif (action == MotionEvent.ACTION_UP) {\nlink[0].onClick(widget);\n} else if (action == MotionEvent.ACTION_DOWN) {\nSelection.setSelection(buffer,\nbuffer.getSpanStart(link[0]),\nbuffer.getSpanEnd(link[0]));\n}\nif (widget instanceof TextViewFixTouchConsume){\n((TextViewFixTouchConsume) widget).linkHit = true;\n}\nreturn true;\n} else {\nSelection.removeSelection(buffer);\nTouch.onTouchEvent(widget, buffer, event);\nreturn false;\n}\n}\nreturn Touch.onTouchEvent(widget, buffer, event);\n}\n}\n}\nYou should call somewhere\ntextView.setMovementMethod(TextViewFixTouchConsume.LocalLinkMovementMethod.getInstance());\nto set this MovementMethod for the textView.\nThis MovementMethod raises a flag in TextViewFixTouchConsume if user actually hits link. (only in ACTION_UP and ACTION_DOWN events) and TextViewFixTouchConsume.onTouchEvent returns true only if user actually hit link.\nBut that’s not all!!!! The third problem is that ListView (AbsListView) calls it’s performClick method (that calls onItemClick event handler) ONLY if ListView’s item view has no focusables. So, you need to override\n@Override\npublic boolean hasFocusable() {\nreturn false;\n}\nin a view that you add to ListView. (in my case that is a layout that contains textView)\nor you can use setOnClickLIstener for that view. so, theese are hacks, but they work.\n更多地址参考http://stackoverflow.com/questions/8558732/listview-textview-with-linkmovementmethod-makes-list-item-unclickable\nClickableSpan(URLSpan)的长按处理 给TextView设置了OnLongClickListener后，如果TextView中同时有ClickableSpan（一般为URLSpan），此时长按TextView，如果长按的位置在ClickableSpan上，会发现同时触发了OnLongClickListener和ClickableSpan的onClick。比如下面的代码\n1 \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot; style=\u0026quot;color: #666666;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; TextView tv = (TextView) findViewById(R.id.txt); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; String url = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #2aa198;\u0026quot;\u0026gt;\u0026amp;#8220;http://www.baidu.com\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; URLSpan span = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; URLSpan(url); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; String content = url + \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #2aa198;\u0026quot;\u0026gt;\u0026amp;#8220;Test\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; SpannableString ss = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SpannableString(content); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; ss.setSpan(span, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #2aa198;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, url.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; tv.setText(ss); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; tv.setMovementMethod(LinkMovementMethod.getInstance()); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; tv.setOnLongClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnLongClickListener() { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot; style=\u0026quot;color: #268bd2;\u0026quot;\u0026gt;onLongClick\u0026lt;/span\u0026gt;(View v) { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; Toast.makeText(getApplicationContext(), \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #2aa198;\u0026quot;\u0026gt;\u0026amp;#8220;OnLongClick\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; }); \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; 当在Url上长按时，会同时弹出Toast并打开指定的网页。为什么这样？当然还要从源码中查找，看下TextView的onTouchEvent函数。\n1 \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot; style=\u0026quot;color: #666666;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot; style=\u0026quot;color: #268bd2;\u0026quot;\u0026gt;onTouchEvent\u0026lt;/span\u0026gt;(MotionEvent event) { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; action = event.getActionMasked(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mEditor != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) mEditor.onTouchEvent(event); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; superResult = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onTouchEvent(event); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;font-style: italic; color: #93a1a1;\u0026quot;\u0026gt;// 1\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mEditor != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mEditor.mDiscardNextActionUp \u0026amp;\u0026amp; action == MotionEvent.ACTION_UP) { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; mEditor.mDiscardNextActionUp = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; superResult; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; touchIsFinished = (action == MotionEvent.ACTION_UP) \u0026amp;\u0026amp; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; (mEditor == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || !mEditor.mIgnoreActionUpEvent) \u0026amp;\u0026amp; isFocused(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; ((mMovement != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || onCheckIsTextEditor()) \u0026amp;\u0026amp; isEnabled() \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026amp;\u0026amp; mText \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;instanceof\u0026lt;/span\u0026gt; Spannable \u0026amp;\u0026amp; mLayout != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; handled = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMovement != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;font-style: italic; color: #93a1a1;\u0026quot;\u0026gt;// 2\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; handled |= mMovement.onTouchEvent(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, (Spannable) mText, event); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026amp;#8230; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (handled) { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; superResult; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; 在上面标注的第一步中，调用super.onTouchEvent，会处理长按事件。在接下来的第二步中，判断mMovement是否等于null，如果不为null，无论第一步中返回的结果是true还是false，都会调用mMovement的onTouchEvent，Shit，问题就在这里了。而LinkMovementMethod的onTouchEvent是这样的\n1 \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot; style=\u0026quot;color: #666666;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (action == MotionEvent.ACTION_UP) { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; link[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #2aa198;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;].onClick(widget); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (action == MotionEvent.ACTION_DOWN) { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; Selection.setSelection(buffer, buffer.getSpanStart(link[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #2aa198;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]), buffer.getSpanEnd(link[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #2aa198;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;])); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; 省略了次要部分，在ACTION_UP时就调用link即ClickableSpan的onClick了，Holy Shit。\n问题找到了，那么怎么解决？从上面代码中看到，在进入第二步前有一个很长的if条件判断，破坏这个条件就行了，所以可以在OnLongClickListner中setEnabled(false)，在ACTION_UP中再setEnabled(true)，但什么时候调用setEnabled(true)？可以设置OnTouchListener，在ACTION_UP时post一个Runnable来设置，不过个人不喜欢这个方法。\n另一个办法比较取巧，你要调用onClick就调用吧，我判断一下如果触发了长按就在onClick中什么都不做不就行了，这就要求继承ClickableSpan。那么判断的方法呢？最简单的方法就是通过View.setTag，如下所示\n1 \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot; style=\u0026quot;color: #666666;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; tv.setOnLongClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnLongClickListener() { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot; style=\u0026quot;color: #268bd2;\u0026quot;\u0026gt;onLongClick\u0026lt;/span\u0026gt;(View v) { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; Toast.makeText(getApplicationContext(), \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #2aa198;\u0026quot;\u0026gt;\u0026amp;#8220;onLongClick\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; v.setTag(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #2aa198;\u0026quot;\u0026gt;\u0026amp;#8220;Test\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; }); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;class\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot; style=\u0026quot;color: #b58900;\u0026quot;\u0026gt;NonLongClickableUrlSpan\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot; style=\u0026quot;color: #b58900;\u0026quot;\u0026gt;URLSpan\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;{ \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot; style=\u0026quot;color: #268bd2;\u0026quot;\u0026gt;NonLongClickableUrlSpan\u0026lt;/span\u0026gt;(String url) { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(url); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot; style=\u0026quot;color: #268bd2;\u0026quot;\u0026gt;onClick\u0026lt;/span\u0026gt;(View widget) { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (widget.getTag() != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; widget.setTag(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onClick(widget); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; 直接通过tag判断，这个TextView的Tag已经用做其他用途了？没事，setTag还有一个重载版本：setTag(int, Object)。\n主要问题已经解决了，但可能还会遇到一点小问题，对于URLSpan，点击时后有个背景，有时松手后这个背景并不消失，解决方法也很简单，手动让它消失就行了，在onLongClick中添加以下代码\n1 \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot; style=\u0026quot;color: #666666;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; tv.setOnLongClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnLongClickListener() { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;title\u0026quot; style=\u0026quot;color: #268bd2;\u0026quot;\u0026gt;onLongClick\u0026lt;/span\u0026gt;(View v) { \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026amp;#8230; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; TextView txt = (TextView) v; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; Spannable span = (Spannable) txt.getText(); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; Selection.removeSelection(span); \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;color: #859900;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; } \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line\u0026quot;\u0026gt; }); \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; 前面说了简单针对TextView的情况，再来看一下其他情况，比如说ListView，假设它是一个聊天信息列表，每一项包含一个头像和一个消息内容，我们可能希望给这个消息内容加个长按事件，而这个长按事件的范围不包括头像，所以不能使用setOnItemLongClickListener，只能给这个消息内容的布局设置OnLongClickListener。这时可能会遇到一个问题：\n如果消息内容中有一个TextView包含URLSpan，当长按时点击的位置在这个URLSpan上时，可能不会触发外层Layout的长按事件，这个TextView拦截了焦点。 这时可以给这个TextView也设置一个OnLongClickListener，URLSpan的长按处理和前面讲的一样，而长按事件的处理，可以简单地调用外层Layout的performLongClick()方法。\n如果这个外层布局设置了Selector Background，在长按包含URLSpan的TextView时外层Layout的背景是不会改变的，可以在这个Layout中添加android:addStatesFromChildren=\u0026quot;true\u0026quot;属性解决。\n原文链接：[http://www.angeldevil.me/2014/08/27/Long-click-about-Clickable(URLSpan)/](http://www.angeldevil.me/2014/08/27/Long-click-about-Clickable(URLSpan)/) ### [android textview 自动链接网址 修改默认点击事件](http://dingbuoyi.iteye.com/blog/1553464) \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;1 修改XML文件即可，\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: red;\u0026quot;\u0026gt;android:autoLink=\u0026amp;#8221;web\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;br style=\u0026quot;color: #000000;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;[code=xml\u0026amp;#8221;] \u0026lt;/span\u0026gt;\u0026lt;br style=\u0026quot;color: #000000;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\u0026lt;TextView \u0026lt;/span\u0026gt;\u0026lt;br style=\u0026quot;color: #000000;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; android:id=\u0026amp;#8221;@+id/text_view\u0026amp;#8221; \u0026lt;/span\u0026gt;\u0026lt;br style=\u0026quot;color: #000000;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; android:layout_width=\u0026amp;#8221;fill_parent\u0026amp;#8221; \u0026lt;/span\u0026gt;\u0026lt;br style=\u0026quot;color: #000000;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; android:layout_height=\u0026amp;#8221;wrap_content\u0026amp;#8221; \u0026lt;/span\u0026gt;\u0026lt;br style=\u0026quot;color: #000000;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; android:autoLink=\u0026amp;#8221;all\u0026amp;#8221; \u0026lt;/span\u0026gt;\u0026lt;br style=\u0026quot;color: #000000;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; android:text=\u0026amp;#8221;@string/hello\u0026amp;#8221; /\u0026gt; \u0026lt;/span\u0026gt;\u0026lt;br style=\u0026quot;color: #000000;\u0026quot; /\u0026gt;\u0026lt;br style=\u0026quot;color: #000000;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;autoLink有好几种类型:web phone all等。 \u0026lt;/span\u0026gt;\u0026lt;br style=\u0026quot;color: #000000;\u0026quot; /\u0026gt;\u0026lt;br style=\u0026quot;color: #000000;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;2 修改链接的默认点击事件 \u0026lt;/span\u0026gt; Java代码 ![收藏代码](http://dingbuoyi.iteye.com/images/icon_star.png) - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; HtmlAllTestActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView tv; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setContentView(R.layout.main); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.tv = (TextView)findViewById(R.id.text_view); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; CharSequence text = tv.getText(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (text \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;instanceof\u0026lt;/span\u0026gt; Spannable) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; end = text.length(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Spannable sp = (Spannable) tv.getText(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; URLSpan[] urls = sp.getSpans(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, end, URLSpan.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; SpannableStringBuilder style = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SpannableStringBuilder(text); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; style.clearSpans();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// should clear old spans\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (URLSpan url : urls) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; MyURLSpan myURLSpan = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; MyURLSpan(url.getURL()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; style.setSpan(myURLSpan, sp.getSpanStart(url), sp.getSpanEnd(url), Spannable.SPAN_EXCLUSIVE_INCLUSIVE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; tv.setText(style); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyURLSpan \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ClickableSpan { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String mUrl; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; MyURLSpan(String url) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mUrl = url; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View widget) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Toast.makeText(HtmlAllTestActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, mUrl, Toast.LENGTH_LONG).show(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; widget.setBackgroundColor(Color.parseColor(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#00000000\u0026amp;#8221;\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - 原文链接：http://dingbuoyi.iteye.com/blog/1553464 所以我通过以下方法控制textview的超链触发，总体思路是通过ontouch事件阻止超链的onclick事件。主要是因为长按事件在onclick事件之前完成，说白了就是`MotionEvent.ACTION_DOWN和`MotionEvent.ACTION_UP出现的前后顺序不同，控制是否消化掉事件。 通过修改textview的长按和touch事件，实现在点击了长按事件以后，防止触发超链接的link事件。 ``` `\u0026lt;span style=\u0026ldquo;color: #000000;\u0026quot;\u0026gt;textview.setOnLongClickListener(new View.OnLongClickListener() {\n@Override public boolean onLongClick(View v) { isLongClick= true; return false; } }); textview.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if(event.getAction() == MotionEvent.ACTION_UP \u0026amp;\u0026amp; isLongClick){ isLongClick= false; return true; } if(event.getAction() == MotionEvent.ACTION_DOWN){ isLongClick= false; } return v.onTouchEvent(event); } }); 控制textview的超链的长按和点击事件都执行的解决方案：现在2种方法解决，1是通过ontouch事键和长按事件逻辑判断控制。2是通过修改点击事件中的 MyURLSpan \u0026lt;span class=\u0026ldquo;keyword\u0026rdquo; style=\u0026ldquo;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ClickableSpan重新点击事件。 下面是我用自定义LinkedTextView,使他能够在ListView中的item点击事件起作用。\n\u0026lt;/span\u0026gt;public class LinkTextView extends TextView { // 如果执行了长按 boolean isOnLongClickRun = false; // boolean dontConsumeNonUrlClicks = true; boolean linkHit;\npublic LinkTextView(Context context) { super(context); }\npublic LinkTextView(Context context, AttributeSet attrs) { super(context, attrs); }\npublic LinkTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean hasFocusable() { return false; }\npublic void setTextViewHTML(String html) { CharSequence sequence = Html.fromHtml(html); SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence); setText(strBuilder); }\npublic static class LocalLinkMovementMethod extends LinkMovementMethod { static LocalLinkMovementMethod sInstance;\npublic static LocalLinkMovementMethod getInstance() { if (sInstance == null) sInstance = new LocalLinkMovementMethod();\nreturn sInstance; }\n@Override public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { int x = (int) event.getX(); int y = (int) event.getY(); x -= widget.getTotalPaddingLeft(); y -= widget.getTotalPaddingTop(); x += widget.getScrollX(); y += widget.getScrollY(); Layout layout = widget.getLayout(); int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x);\nClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); if (link.length != 0) { if (action == MotionEvent.ACTION_UP) { link[0].onClick(widget); } else if (action == MotionEvent.ACTION_DOWN) { Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0])); }\nif (widget instanceof LinkTextView) { ((LinkTextView) widget).linkHit = true; } return true; } else { Selection.removeSelection(buffer); Touch.onTouchEvent(widget, buffer, event); return false; } } return Touch.onTouchEvent(widget, buffer, event); } } }`\n","permalink":"https://blog.zdltech.com/posts/%E5%9C%A8android%E5%AF%A6%E4%BD%9Chtml-textview%E8%88%87autolink%E4%BD%BF%E7%94%A8%E7%9A%84%E5%BB%BA%E8%AD%B0%E6%96%B9%E5%BC%8F/","summary":"\u003cp\u003e\u003ca href=\"http://magiclen.org/tag/android/\"\u003eAndroid\u003c/a\u003e的\u003ca href=\"http://magiclen.org/tag/textview/\"\u003eTextView\u003c/a\u003e除了可以用來顯示文字資料之外，還可以使用\u003ca href=\"http://magiclen.org/tag/html/\"\u003eHTML\u003c/a\u003e語法來調整文字的樣式和文字超連結，無需特地去使用\u003ca href=\"http://magiclen.org/tag/webview/\"\u003eWebView\u003c/a\u003e。只是一旦使用\u003ca href=\"http://magiclen.org/tag/textview/\"\u003eTextView\u003c/a\u003e製作超連結，該\u003ca href=\"http://magiclen.org/tag/textview/\"\u003eTextView\u003c/a\u003e就會變得難以控制，因此有幾個特性應該是設計師必須事先知道的。\u003c/p\u003e\n\u003ch3 id=\"textview顯示html\"\u003e\u003ca href=\"http://magiclen.org/tag/textview/\"\u003eTextView\u003c/a\u003e顯示\u003ca href=\"http://magiclen.org/tag/html/\"\u003eHTML\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e要使用\u003ca href=\"http://magiclen.org/tag/textview/\"\u003eTextView\u003c/a\u003e顯示\u003ca href=\"http://magiclen.org/tag/html/\"\u003eHTML\u003c/a\u003e的作法很簡單，只要用以下方式來setText即可。\u003c/p\u003e\n\u003cdiv class=\"wp_syntax\" style=\"color: #110000;\"\u003e\n  \u003ctable style=\"font-weight: inherit; font-style: inherit;\"\u003e\n    \u003ctr style=\"font-weight: inherit; font-style: inherit;\"\u003e\n      \u003ctd class=\"code\" style=\"font-weight: inherit; font-style: inherit;\"\u003e\n        ```\ntextView.\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #006633;\"\u003esetText\u003c/span\u003e\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #009900;\"\u003e(\u003c/span\u003eHtml.\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #006633;\"\u003efromHtml\u003c/span\u003e\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #009900;\"\u003e(\u003c/span\u003e\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #0000ff;\"\u003e\"HTML語法字串\"\u003c/span\u003e\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #009900;\"\u003e)\u003c/span\u003e\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #009900;\"\u003e)\u003c/span\u003e\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #339933;\"\u003e;\u003c/span\u003e\n```\n      \u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/table\u003e\n\u003c/div\u003e\n\u003cp\u003e例如：\u003c/p\u003e\n\u003cdiv class=\"wp_syntax\" style=\"color: #110000;\"\u003e\n  \u003ctable style=\"font-weight: inherit; font-style: inherit;\"\u003e\n    \u003ctr style=\"font-weight: inherit; font-style: inherit;\"\u003e\n      \u003ctd class=\"code\" style=\"font-weight: inherit; font-style: inherit;\"\u003e\n        ```\ntextView.\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #006633;\"\u003esetText\u003c/span\u003e\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #009900;\"\u003e(\u003c/span\u003eHtml.\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #006633;\"\u003efromHtml\u003c/span\u003e\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #009900;\"\u003e(\u003c/span\u003e\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #0000ff;\"\u003e\"歡迎大家來到\u0026lt;big\u0026gt;\u0026lt;font color=\u003cspan style=\"font-weight: bold; font-style: inherit; color: #000099;\"\u003e\\\"\u003c/span\u003e#FF0000\u003cspan style=\"font-weight: bold; font-style: inherit; color: #000099;\"\u003e\\\"\u003c/span\u003e\u0026gt;\u0026lt;b\u0026gt;MagicLen\u0026lt;/b\u0026gt;\u0026lt;/font\u0026gt;\u0026lt;/big\u0026gt;，本站網址如下：\u0026lt;br/\u0026gt;\u0026lt;br/\u0026gt;\u0026lt;a href=\u003cspan style=\"font-weight: bold; font-style: inherit; color: #000099;\"\u003e\\\"\u003c/span\u003ehttp://magiclen.org/\u003cspan style=\"font-weight: bold; font-style: inherit; color: #000099;\"\u003e\\\"\u003c/span\u003e\u0026gt;http://magiclen.org/\u0026lt;/a\u0026gt;\"\u003c/span\u003e\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #009900;\"\u003e)\u003c/span\u003e\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #009900;\"\u003e)\u003c/span\u003e\u003cspan style=\"font-weight: inherit; font-style: inherit; color: #339933;\"\u003e;\u003c/span\u003e\n```\n      \u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/table\u003e\n\u003c/div\u003e\n\u003cp\u003e結果如下：\u003c/p\u003e","title":"在Android實作HTML TextView與AutoLink使用的建議方式"},{"content":"当在xml文件中声明了一个EditText 的时候，可能会加入这个属性\n1 希望这个EditText 最多可以输入几位 应该假如这段代码\nandroid:maxLength=”4“ 当希望这个editText 的长度初始化为几个字符长度的时候，假如这段代码android:ems=”10“\n那么想要在程序中获取这两个值的时候怎么办呢，有点麻烦了。\n下面给出代码，以获取最大显示长度为例吧：\n**[html]** [view plain](http://blog.csdn.net/rually/article/details/38442539#)[copy](http://blog.csdn.net/rually/article/details/38442539#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/446039)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/446039/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;public int getMaxLength() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; int \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;length\u0026lt;/span\u0026gt; =\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; try \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; InputFilter[] \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;inputFilters\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;getFilters\u0026lt;/span\u0026gt;(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; for(InputFilter filter:inputFilters) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Class\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;c\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;filter\u0026lt;/span\u0026gt;.getClass(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; if(c.getName().equals(\u0026amp;#8220;android.text.InputFilter$LengthFilter\u0026amp;#8221;)) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Field[] \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;f\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;c\u0026lt;/span\u0026gt;.getDeclaredFields(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; for(Field field:f) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; if(field.getName().equals(\u0026amp;#8220;mMax\u0026amp;#8221;)) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; field.setAccessible(true); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;length\u0026lt;/span\u0026gt; = (Integer)field.get(filter); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; catch (Exception e) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; e.printStackTrace(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;mMaxLength\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;length\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; return length; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 这里面要用到Inputfilter ，然后再这些筛选条件中去找，找到你要的那个条件就ok了\n2 当你希望这个文本框输入密码的时候，要加入这样的条件\n**[html]** [view plain](http://blog.csdn.net/rually/article/details/38442539#)[copy](http://blog.csdn.net/rually/article/details/38442539#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/446039)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/446039/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:inputType\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;textPassword\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 不要用password=”true” ,out了\n那么想要在程序里面获取这个属性的时候应该怎么写呢？\n看这段代码吧，别管什么意思，不大容易看明白，肯定是可以的\n**[html]** [view plain](http://blog.csdn.net/rually/article/details/38442539#)[copy](http://blog.csdn.net/rually/article/details/38442539#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/446039)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/446039/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;/** \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; * judge wether the editTextView\u0026amp;#8217;s inputType is password or normal \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; **/ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;public boolean isPasswordType() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; int \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;inputType\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getInputType(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; final int \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;variation\u0026lt;/span\u0026gt; = \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;inputType\u0026lt;/span\u0026gt; \u0026amp; (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; return \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;variation\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; == (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; || \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;variation\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; == (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; || \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;variation\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; == (EditorInfo.TYPE_CLASS_NUMBER | EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 这样就可以判断了，这个函数我也是在 textView 中找到的。\n","permalink":"https://blog.zdltech.com/posts/%E5%85%B3%E4%BA%8Eedittext%E7%9A%84%E6%9C%80%E5%A4%A7%E9%95%BF%E5%BA%A6maxlength%E5%92%8C%E5%AF%86%E7%A0%81%E7%B1%BB%E5%9E%8Binputtype%E7%9A%84%E8%8E%B7%E5%8F%96/","summary":"\u003cp\u003e当在xml文件中声明了一个EditText 的时候，可能会加入这个属性\u003c/p\u003e\n\u003cp\u003e1 希望这个EditText 最多可以输入几位 应该假如这段代码\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"t\"\u003eandroid:maxLength\u003c/span\u003e\u003cspan class=\"m\"\u003e=”\u003c/span\u003e\u003cstrong\u003e4\u003c/strong\u003e\u003cspan class=\"m\"\u003e“\u003c/span\u003e\u003cspan class=\"t\"\u003e \u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"t\"\u003e当希望这个editText 的长度初始化为几个字符长度的时候，假如这段代码android:ems\u003c/span\u003e\u003cspan class=\"m\"\u003e=”\u003c/span\u003e\u003cstrong\u003e10\u003c/strong\u003e“\u003c/p\u003e\n\u003cp\u003e那么想要在程序中获取这两个值的时候怎么办呢，有点麻烦了。\u003c/p\u003e\n\u003cp\u003e下面给出代码，以获取最大显示长度为例吧：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/rually/article/details/38442539#)[copy](http://blog.csdn.net/rually/article/details/38442539#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/446039)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/446039/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;public int getMaxLength()  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    int \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;length\u0026lt;/span\u0026gt; =\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    try   \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        InputFilter[] \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;inputFilters\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;getFilters\u0026lt;/span\u0026gt;();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        for(InputFilter filter:inputFilters)  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            Class\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;c\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;filter\u0026lt;/span\u0026gt;.getClass();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            if(c.getName().equals(\u0026amp;#8220;android.text.InputFilter$LengthFilter\u0026amp;#8221;))  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                Field[] \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;f\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;c\u0026lt;/span\u0026gt;.getDeclaredFields();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                for(Field field:f)  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    if(field.getName().equals(\u0026amp;#8220;mMax\u0026amp;#8221;))  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        field.setAccessible(true);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;length\u0026lt;/span\u0026gt; = (Integer)field.get(filter);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    catch (Exception e)   \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        e.printStackTrace();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;mMaxLength\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;length\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    return length;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e这里面要用到Inputfilter ，然后再这些筛选条件中去找，找到你要的那个条件就ok了\u003c/p\u003e","title":"关于EditText的最大长度maxLength和密码类型InputType的获取"},{"content":" \u0026laquo;/span\u0026gt;html\u0026gt; \u0026laquo;/span\u0026gt;head\u0026gt; \u0026laquo;/span\u0026gt;title\u0026gt;倒计时\u0026lt;/title\u0026gt; \u0026lt;!–以下为css样式–\u0026gt; \u0026laquo;/span\u0026gt;style type= “text/css”\u0026gt; .daojishi h2 { font-family:Helvetica, Microsoft YaHei, Arial, sans-serif; font-size:14px; margin-bottom:5px; color:#151515; } .daojishi #timer { font-family:Helvetica, Microsoft YaHei, Arial, sans-serif; font-size:14px; color:#151515; font-weight:bold; } \u0026lt;/style\u0026gt; \u0026laquo;/span\u0026gt;script type = “text/javascript” src = “timer.js”\u0026gt; \u0026lt;/script\u0026gt; \u0026lt;/head\u0026gt; \u0026laquo;/span\u0026gt;body onload = “timer()”\u0026gt; \u0026laquo;/span\u0026gt;div class = “daojishi”\u0026gt; \u0026laquo;/span\u0026gt;h2\u0026gt;剩余时间为：\u0026lt;/h2\u0026gt; \u0026laquo;/span\u0026gt;div id = “timer”\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; timer.js\n**[javascript]** [view plain](http://blog.csdn.net/lwcumt/article/details/8088303#)[copy](http://blog.csdn.net/lwcumt/article/details/8088303#) function timer() { var ts = (new Date(2018, 11, 11, 9, 0, 0)) – (new Date());//计算剩余的毫秒数 var dd = parseInt(ts / 1000 / 60 / 60 / 24, 10);//计算剩余的天数 var hh = parseInt(ts / 1000 / 60 / 60 % 24, 10);//计算剩余的小时数 var mm = parseInt(ts / 1000 / 60 % 60, 10);//计算剩余的分钟数 var ss = parseInt(ts / 1000 % 60, 10);//计算剩余的秒数 dd = checkTime(dd); hh = checkTime(hh); mm = checkTime(mm); ss = checkTime(ss); document.getElementById(“timer”).innerHTML = dd + “天” + hh + “时” + mm + “分” + ss + “秒”; setInterval(“timer()”,1000); } function checkTime(i) { if (i \u0026lt; 10) { i = “0” + i; } return i; } 一个页面中有多个倒计时\n","permalink":"https://blog.zdltech.com/posts/js%E5%AE%9E%E7%8E%B0%E5%80%92%E8%AE%A1%E6%97%B6/","summary":"\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan style=\"color: black;\"\u003e\u003cspan class=\"tag\" style=\"font-weight: bold; color: #993300;\"\u003e\u0026laquo;/span\u0026gt;\u003cspan class=\"tag-name\" style=\"font-weight: bold; color: #993300;\"\u003ehtml\u003c/span\u003e\u003cspan class=\"tag\" style=\"font-weight: bold; color: #993300;\"\u003e\u0026gt;\u003c/span\u003e  \u003c/span\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan style=\"color: black;\"\u003e    \u003cspan class=\"tag\" style=\"font-weight: bold; color: #993300;\"\u003e\u0026laquo;/span\u0026gt;\u003cspan class=\"tag-name\" style=\"font-weight: bold; color: #993300;\"\u003ehead\u003c/span\u003e\u003cspan class=\"tag\" style=\"font-weight: bold; color: #993300;\"\u003e\u0026gt;\u003c/span\u003e  \u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan style=\"color: black;\"\u003e        \u003cspan class=\"tag\" style=\"font-weight: bold; color: #993300;\"\u003e\u0026laquo;/span\u0026gt;\u003cspan class=\"tag-name\" style=\"font-weight: bold; color: #993300;\"\u003etitle\u003c/span\u003e\u003cspan class=\"tag\" style=\"font-weight: bold; color: #993300;\"\u003e\u0026gt;\u003c/span\u003e倒计时\u003cspan class=\"tag\" style=\"font-weight: bold; color: #993300;\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"tag-name\" style=\"font-weight: bold; color: #993300;\"\u003etitle\u003c/span\u003e\u003cspan class=\"tag\" style=\"font-weight: bold; color: #993300;\"\u003e\u0026gt;\u003c/span\u003e  \u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan style=\"color: black;\"\u003e        \u003cspan class=\"comments\" style=\"color: #008200;\"\u003e\u0026lt;!–以下为css样式–\u0026gt;\u003c/span\u003e  \u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan style=\"color: black;\"\u003e        \u003cspan class=\"tag\" style=\"font-weight: bold; color: #993300;\"\u003e\u0026laquo;/span\u0026gt;\u003cspan class=\"tag-name\" style=\"font-weight: bold; color: #993300;\"\u003estyle\u003c/span\u003e \u003cspan class=\"attribute\" style=\"color: red;\"\u003etype\u003c/span\u003e= \u003cspan class=\"attribute-value\" style=\"color: blue;\"\u003e“text/css”\u003c/span\u003e\u003cspan class=\"tag\" style=\"font-weight: bold; color: #993300;\"\u003e\u0026gt;\u003c/span\u003e  \u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan style=\"color: black;\"\u003e            .daojishi h2  \u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan style=\"color: black;\"\u003e            {   \u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan style=\"color: black;\"\u003e                font-family:Helvetica, Microsoft YaHei, Arial, sans-serif;   \u003c/span\u003e\u003c/p\u003e","title":"js实现倒计时"},{"content":"转自：http://www.zhangxinxu.com/wordpress/?p=3568\n一、星星点灯，照亮我的家门 大家都喜欢听故事。\n每篇文章也都是有故事的。\n今天的故事是与星星相关的。\n没错，讲的是星星点灯的故事——\n才怪！\n标题只是我脑子突然蹦出来的，唉，这首老到掉渣子的歌我居然条件反射般想起，可见——我老了！\n故事其实是这样的~~\n在天气还未如此炎热的某天，@waylybaye微博上展示了其使用canvas绘制星星图片，然后再保存为png格式使用的折腾：\n很赞，对不对！\n然，故事刚刚开始，\n而后我随便吐槽了句：\n**\n这种效果两个星星就可以完全CSS实现了，包括IE6浏览器，多少多余劳动力浪费了啊~~ 一石激起三层浪：\n有人对两颗星星实现星星评分效果感兴趣；有人觉得纯CSS搞不定记住之前用户所选星星。\n实际上，两颗星星（见下图）完全可以实现兼容IE6在内的效果；而且，纯CSS可是可以记住当前星星点击个数哦！\n哈哈，我们的故事就此展开……\n二、小星星，亮晶晶，点点像你的眼睛 正片之前先来个精彩预告，您可以狠狠地点击这里：两颗星星实现的星星点击评分效果demo\n哈哈，这回不上截图了，上截视频，更直观，截自Chrome浏览器，纯CSS实现。对了，貌似忘记把《爱情公寓》电视关掉，有杂音，嘻嘻……\niPad党若看不到上视频，可以点击下面区域查看截图：\n\u0026lt;a style=\u0026quot;color: #34538b;\u0026quot;\u0026gt;出现吧，图片君！\u0026lt;/a\u0026gt; 您可能会惊讶地发现，诶，怎么点击的星星可以记住啊，纯CSS？鑫哥你确定不是在忽悠？\n我不姓赵哦~\n慢慢来，先看看两个星星如何实现兼容IE6浏览器的hover交互效果。\n三、一闪一闪亮晶晶 满天都是小星星 两个星星实现原理见下图:\n图1 图2\n背景色就是灰色平铺； 5个小标签，分别对应每个星星，宽度1/5，其垂直层次关系见图1示意; 当鼠标经过某星星，例如上图所示第3个，宽度延伸，背景显示，hover效果即呈现； 最后，仔细观察其他小星星的层次以及位置，不存在覆盖的情况，于是，hover其他小星星，效果同样存在； over! 以上就是使用两个星星+纯CSS实现hover效果的原理。\n5个小星星使用a标签，则可兼容IE6浏览器。\nHTML结构如下：\n``` \u0026lt;div class=\"star_bg\"\u0026gt; \u0026lt;a class=\"star star_1\"\u0026gt;\u0026lt;/a\u0026gt; \u0026lt;a class=\"star star_2\"\u0026gt;\u0026lt;/a\u0026gt; \u0026lt;a class=\"star star_3\"\u0026gt;\u0026lt;/a\u0026gt; \u0026lt;a class=\"star star_4\"\u0026gt;\u0026lt;/a\u0026gt; \u0026lt;a class=\"star star_5\"\u0026gt;\u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; CSS示意如下： \u0026lt;div class=\u0026#34;zxx_code\u0026#34;\u0026gt; /* 灰色背景星星5个平铺 / .star_bg { width: 120px; height: 20px; background: url(star.png) repeat-x; position: relative; overflow: hidden; } / 这是5个小星星们的默认状态的定位 */ .star { height: 100%; width: 24px; line-height: 6em; position: absolute; z-index: 3; } .star_1 { left: 0; } .star_2 { left: 24px; } .star_3 { left: 48px; } .star_4 { left: 72px; } .star_5 { left: 96px; }\n/* 鼠标hover效果实现，分别显示背景与定宽 */ .star:hover { background: url(star.png) repeat-x 0 -20px; left: 0; z-index: 2; } .star_1:hover { width: 24px; } .star_2:hover { width: 48px; } .star_3:hover { width: 72px; } .star_4:hover { width: 96px; } .star_5:hover { width: 120px; }\n\u0026lt;/div\u0026gt; 两颗星星`hover`事故讲完了，那如何记住星星点击的故事呢？ ### 四、城市里 小星星 稀疏的 亮晶晶 去年年初曾介绍过“[CSS radio/checkbox单复选框元素显隐技术](http://www.zhangxinxu.com/wordpress/?p=2154)”，又称“checkbox hack技术”。 利用`label` `for`与单复选框等之间的点击关联特性，结果`:checked`伪类选择器以及兄弟选择器实现我们想要的交互效果——例如，元素的显示与隐藏，或者是选中的星星个数标记。 有些迷糊？不急，来个最简单示例，跟我一步一步来： 1. 一个单选框，以及一个对应的`label`标签，如下： \u0026lt;div class=\u0026#34;zxx_code\u0026#34;\u0026gt; ``` \u0026amp;lt;input type=\u0026#34;radio\u0026#34; id=\u0026#34;testRadio\u0026#34;\u0026amp;gt;\u0026amp;lt;label for=\u0026#34;testRadio\u0026#34;\u0026amp;gt;观光团\u0026amp;lt;/label\u0026amp;gt; \u0026lt;/div\u0026gt; 点击含“观光团”字样的label标签，只要不是奇葩设备，单选框都会被选中的（因为for值等于单选框id值）； 于是，触发了如下伪类： input:checked {}\n\u0026lt;/div\u0026gt; 4. CSS3中还有兄弟选择器，如`~`以及相邻兄弟选择器`+`，于是，我们可以改变`label`标签的状态，例如，文字变红： \u0026lt;div class=\u0026#34;zxx_code\u0026#34;\u0026gt; ``` input:checked + label { color: red; } \u0026lt;/div\u0026gt; 如果我们把label做成星星背景，岂不是我们点击这个星星，触发radio选中，就可以让这个label标签一直显示星星背景？ input:checked + label { background: url(star.png) repeat-x 0 -20px; }\n\u0026lt;/div\u0026gt; 以上就是实现的基本原理。 OK，下面来看看demo页面是如何处理的。 * 因为要兼顾IE6浏览器(hover效果)，因此，采用的是`a`标签内嵌`label`标签的形式。如果您不考虑IE6浏览器，墙裂推荐直接一个`label`标签。于是，就有类似下面的HTML结构（第一颗星星示意）： \u0026lt;div class=\u0026#34;zxx_code\u0026#34;\u0026gt; ``` \u0026amp;lt;input type=\u0026#34;radio\u0026#34; id=\u0026#34;starScore1\u0026#34; class=\u0026#34;score score_1\u0026#34; value=\u0026#34;1\u0026#34; name=\u0026#34;score\u0026#34;\u0026amp;gt; \u0026amp;lt;a href=\u0026#34;#starScore1\u0026#34; class=\u0026#34;star star_1\u0026#34; title=\u0026#34;差\u0026#34;\u0026amp;gt;\u0026amp;lt;label for=\u0026#34;starScore1\u0026#34;\u0026amp;gt;差\u0026amp;lt;/label\u0026amp;gt;\u0026amp;lt;/a\u0026amp;gt; \u0026lt;/div\u0026gt; `a`标签负责`hover`效果，`label`标签负责点击效果。 * 我们需要隐藏单选框，且为可用性隐藏。我是使用`clip`实现的： \u0026lt;div class=\u0026quot;zxx_code\u0026quot;\u0026gt; ``` { position: absolute; clip: rect(0 0 0 0); }\n\u0026lt;/div\u0026gt; * 伪类与兄弟选择器控制星星在对应单选框选中中的状态，其实与`hover`的CSS类似： \u0026lt;div class=\u0026#34;zxx_code\u0026#34;\u0026gt; ``` .score:checked + .star { background: url(star.png) repeat-x 0 -20px; left: 0; z-index: 1; } .score_1:checked ~ .star_1 { width: 24px; } .score_2:checked ~ .star_2 { width: 48px; } .score_3:checked ~ .star_3 { width: 72px; } .score_4:checked ~ .star_4 { width: 96px; } .score_5:checked ~ .star_5 { width: 120px; } \u0026lt;/div\u0026gt; 于是，我们就实现了点击记住星星个数的效果了！ * 但，直接这样是有问题的，见下图示意： 例如，点击第三颗星星，自然星星三颗呈现。此时，鼠标hover第2颗星星，理应显示两颗星星，但由于下面三颗星星占道了，因此，实际上显示了是3颗星星，问题出现。\n问题其实不难解决。 我们只要让鼠标hover星星容器时候，所有背景都没有；经过星星时候，背景出现就可以了。 \u0026lt;div class=\u0026quot;zxx_code\u0026quot;\u0026gt; ``` .star_bg:hover .star { background-image: none; } /* 经过父级容器，星星背景图去除 */\n\u0026lt;/div\u0026gt; 父级背景隐藏权重要小于经过星星显示权重，因此，我使用了`!important`（您也可以使用其他方法提高选择器权重），如下： \u0026lt;div class=\u0026#34;zxx_code\u0026#34;\u0026gt; ``` .star:hover { background: url(star.png) repeat-x 0 -20px\u0026lt;span style=\u0026#34;color: #cd0000;\u0026#34;\u0026gt;!important\u0026lt;/span\u0026gt;; } \u0026lt;/div\u0026gt; 于是，星星背景固定影响`hover`问题理论上解决了。\u0026lt;span class=\u0026quot;s\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;//zxx: IE6上面两段CSS都不认识，因此，`hover`状态需要借助JS解决，具体参见demo源代码。\u0026lt;/span\u0026gt; * 最后一个技术点，`z-index`设置。根据上面的分析，星星总共有3种权重状态，因此，相应的，也存在3种层级状态： 1. 默认状态的星星层级最高，以便随时实现`hover`效果，demo中其`z-index`值为`3`;2. 正在被`hover`的星星需要比点击固定显示星星层级高。众所周知，如果z-index值相同，后面的绝对定位元素会覆盖前面的。这种情况下，如果第3颗点击选中，鼠标经过第2颗星星，就会出现`hover`死循环——星星2被星星3覆盖→星星2进入非`hover`状态（较高层级，覆盖星星3）→触发星星2`hover`态（被星星3覆盖）→星星2进入非`hover`状态）→触发星星2`hover`态→…… 因此，需要设置，`hover`状态`z-index:2`; 选中态`z-index: 1`. 完整示意如下： \u0026lt;div class=\u0026quot;zxx_code\u0026quot;\u0026gt; ``` .star { z-index: 3; } .star:hover { z-index: 2; } :checked + .star { z-index: 1; }\n\u0026lt;/div\u0026gt; * over again! ### 五、看那星星多么美丽，摘下一颗有局限性 这里的纯CSS实现实际是CSS3技术的应用，因此，局限就是兼容性。IE9+浏览器以及移动端都能不错实现。至于IE6~IE8浏览器，则…… 实际上，IE7,IE8等浏览器点击星星，单选框也是选中的。对于这些浏览器，我们可能需要额外一点JS以及部分CSS的配合，实现我们需要的效果。具体实现可参见demo源代码，低版本IE浏览器JS代码直接可见。非重点，不展示。 现在的我越来越有一种感觉，或者说需求，是不是网站可以根据浏览器自动加载不同的JS文件呢？ 比方说，IE6~IE8加载老版本jQuery，IE9+加载新jQuery。或者这里的，IE6-8单独加载一个处理包，或者称为兼容包，类似软件兼容补丁一样的东西。 **a与label嵌套之特性** `a`标签里面嵌套`label`标签，点击后会有何反应呢？ 据测试，如果`label` `block`水平，同时`for`关联控件元素，`a`标签打酱油；否则，会触发`a`标签的相关行为。 demo中，为了IE6的`hover`效果，`label`是`inline`水平。貌似`label`标签酱油，因此，交互是通过`a`标签+JS实现的。 ### 六、就向流星许个心愿，让你知道这里是结语 从语义上将，实际上，星星评分就是个单选框。因此，实际开发制作的时候，建议保留单选框组，增强可访问性。因此，从这点上讲，本文所展示的CSS驱动星星评分交互的方法是很有价值的。 如果只想实现简单，5颗星星一排，共5排的背景图片是最好的选择。除了背景图大一点，其他其实都还好，可以说是一个更适合大众的实际的方法。注意，此方法也需要保留单选框组，否则仅仅一个表象实现，实则质量不高。 本文方法好处在于，纯CSS驱动，省了不少JS；同时图片背景比较小。但是，学习以及理解成本稍高，可能并不适用于所有同行，因此，标题前缀为“折腾”二字。还有，本文方法可能在一些低端的Android pad上有些问题，不过我表示对此不屑一顾。 故事到此结束，谢谢品鉴！ 转自：[http://www.zhangxinxu.com/wordpress/?p=3568](http://www.zhangxinxu.com/wordpress/?p=3568) \u0026amp;nbsp; \u0026amp;nbsp; 下面是我整理的例子直接复制就可以复制到html运行就可以 \u0026amp;nbsp; Jquery实现例子，直接复制就可以 \u0026amp;nbsp; 转自：\u0026lt;span id=\u0026#34;sample-permalink\u0026#34; style=\u0026#34;color: #666666;\u0026#34; tabindex=\u0026#34;-1\u0026#34;\u0026gt;http://www.etongwl.com/?p=441\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #666666;\u0026#34;\u0026gt; \u0026lt;/span\u0026gt; ","permalink":"https://blog.zdltech.com/posts/%E6%8A%98%E8%85%BE2%E9%A2%97%E6%98%9F%E6%98%9F%E7%BA%AFcss%E5%AE%9E%E7%8E%B0%E6%98%9F%E6%98%9F%E8%AF%84%E5%88%86%E4%BA%A4%E4%BA%92%E6%95%88%E6%9E%9C/","summary":"\u003cp\u003e转自：\u003ca href=\"http://www.zhangxinxu.com/wordpress/?p=3568\"\u003ehttp://www.zhangxinxu.com/wordpress/?p=3568\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"一星星点灯照亮我的家门\"\u003e一、星星点灯，照亮我的家门\u003c/h3\u003e\n\u003cp\u003e大家都喜欢听故事。\u003cbr\u003e\n每篇文章也都是有故事的。\u003cbr\u003e\n今天的故事是与星星相关的。\u003cbr\u003e\n没错，讲的是星星点灯的故事——\u003cbr\u003e\n才怪！\u003c/p\u003e\n\u003cp\u003e标题只是我脑子突然蹦出来的，唉，这首老到掉渣子的歌我居然条件反射般想起，可见——我老了！\u003c/p\u003e\n\u003cp\u003e故事其实是这样的~~\u003c/p\u003e\n\u003cp\u003e在天气还未如此炎热的某天，\u003ca href=\"http://weibo.com/waylybaye\"\u003e@waylybaye\u003c/a\u003e微博上展示了其使用\u003ccode\u003ecanvas\u003c/code\u003e绘制星星图片，然后再保存为\u003ccode\u003epng\u003c/code\u003e格式使用的折腾：\u003cbr\u003e\n\u003cimg alt=\"canvas与星星png图的绘制\" loading=\"lazy\" src=\"http://ww1.sinaimg.cn/bmiddle/63c68061jw1e4icrh3rjkj20ej0g4myu.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e很赞，对不对！\u003c/p\u003e\n\u003cp\u003e然，故事刚刚开始，\u003c/p\u003e\n\u003cp\u003e而后我随便吐槽了句：\u003c/p\u003e\n\u003cp\u003e**\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e这种效果两个星星就可以完全CSS实现了，包括IE6浏览器，多少多余劳动力浪费了啊~~\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e一石激起三层浪：\u003cbr\u003e\n\u003cimg alt=\"微博回复截图\" loading=\"lazy\" src=\"http://image.zhangxinxu.com/image/blog/201308/2013-08-06_195540.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/a5/cza_thumb.gif\"\u003e 有人对两颗星星实现星星评分效果感兴趣；\u003cimg loading=\"lazy\" src=\"http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/e9/sk_thumb.gif\"\u003e有人觉得纯CSS搞不定记住之前用户所选星星。\u003c/p\u003e\n\u003cp\u003e实际上，两颗星星（见下图）完全可以实现兼容IE6在内的效果；而且，纯CSS可是可以记住当前星星点击个数哦！\u003cbr\u003e\n\u003cimg alt=\"两颗星星\" loading=\"lazy\" src=\"http://www.zhangxinxu.com/study/201308/star.png\"\u003e\u003c/p\u003e\n\u003cp\u003e哈哈，我们的故事就此展开……\u003c/p\u003e\n\u003ch3 id=\"二小星星亮晶晶点点像你的眼睛\"\u003e二、小星星，亮晶晶，点点像你的眼睛\u003c/h3\u003e\n\u003cp\u003e正片之前先来个精彩预告，您可以狠狠地点击这里：\u003ca href=\"http://www.zhangxinxu.com/study/201308/hello-star.html\"\u003e两颗星星实现的星星点击评分效果demo\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e哈哈，这回不上截图了，上截视频，更直观，截自Chrome浏览器，纯CSS实现。对了，貌似忘记把《爱情公寓》电视关掉，有杂音，嘻嘻……\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eiPad党若看不到上视频，可以点击下面区域查看截图：\u003c/p\u003e\n\u003cdiv id=\"imgload\"\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;a style=\u0026quot;color: #34538b;\u0026quot;\u0026gt;出现吧，图片君！\u0026lt;/a\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e您可能会惊讶地发现，诶，怎么点击的星星可以记住啊，纯CSS？鑫哥你确定不是在忽悠？\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"忽悠\" loading=\"lazy\" src=\"http://image.zhangxinxu.com/image/blog/201308/huyou.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e我不姓赵哦~\u003c/p\u003e\n\u003cp\u003e慢慢来，先看看两个星星如何实现兼容IE6浏览器的hover交互效果。\u003c/p\u003e\n\u003ch3 id=\"三一闪一闪亮晶晶-满天都是小星星\"\u003e三、一闪一闪亮晶晶 满天都是小星星\u003c/h3\u003e\n\u003cp\u003e两个星星实现原理见下图:\u003cbr\u003e\n\u003cspan style=\"color: #ffffff;\"\u003e图1\u003c/span\u003e\u003cimg alt=\"两颗星星实现兼容交互原理示意图1 张鑫旭-鑫空间-鑫生活\" loading=\"lazy\" src=\"http://image.zhangxinxu.com/image/blog/201308/two-star-1.png\"\u003e    \u003cspan style=\"color: #ffffff;\"\u003e图2\u003c/span\u003e\u003cimg alt=\"两颗星星实现兼容交互原理示意图2 张鑫旭-鑫空间-鑫生活\" loading=\"lazy\" src=\"http://image.zhangxinxu.com/image/blog/201308/two-star-2.png\"\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e背景色就是灰色平铺；\u003c/li\u003e\n\u003cli\u003e5个小标签，分别对应每个星星，宽度\u003ccode\u003e1/5\u003c/code\u003e，其垂直层次关系见\u003ccode\u003e图1\u003c/code\u003e示意;\u003c/li\u003e\n\u003cli\u003e当鼠标经过某星星，例如上图所示第3个，宽度延伸，背景显示，\u003ccode\u003ehover\u003c/code\u003e效果即呈现；\u003c/li\u003e\n\u003cli\u003e最后，仔细观察其他小星星的层次以及位置，不存在覆盖的情况，于是，\u003ccode\u003ehover\u003c/code\u003e其他小星星，效果同样存在；\u003c/li\u003e\n\u003cli\u003eover!\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e以上就是使用两个星星+纯CSS实现\u003ccode\u003ehover\u003c/code\u003e效果的原理。\u003c/p\u003e\n\u003cp\u003e5个小星星使用\u003ccode\u003ea\u003c/code\u003e标签，则可兼容IE6浏览器。\u003c/p\u003e\n\u003cp\u003eHTML结构如下：\u003c/p\u003e\n\u003cdiv class=\"zxx_code\"\u003e\n  ```\n\u0026lt;div class=\"star_bg\"\u0026gt;\n    \u0026lt;a class=\"star star_1\"\u0026gt;\u0026lt;/a\u0026gt;\n    \u0026lt;a class=\"star star_2\"\u0026gt;\u0026lt;/a\u0026gt;\n    \u0026lt;a class=\"star star_3\"\u0026gt;\u0026lt;/a\u0026gt;\n    \u0026lt;a class=\"star star_4\"\u0026gt;\u0026lt;/a\u0026gt;\n    \u0026lt;a class=\"star star_5\"\u0026gt;\u0026lt;/a\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eCSS示意如下：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div class=\u0026#34;zxx_code\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cspan style=\"color: green;\"\u003e/* 灰色背景星星5个平铺 \u003cem\u003e/\u003c/span\u003e\n.star_bg {\nwidth: 120px; height: 20px;\nbackground: url(star.png) repeat-x;\nposition: relative;\noverflow: hidden;\n}\n\u003cspan style=\"color: green;\"\u003e/\u003c/em\u003e 这是5个小星星们的默认状态的定位 */\u003c/span\u003e\n.star {\nheight: 100%; width: 24px;\nline-height: 6em;\nposition: absolute;\nz-index: 3;\n}\n.star_1 { left: 0; }\n.star_2 { left: 24px; }\n.star_3 { left: 48px; }\n.star_4 { left: 72px; }\n.star_5 { left: 96px; }\u003c/p\u003e","title":"折腾：2颗星星+纯CSS实现星星评分交互效果"},{"content":"Jquery Mobile中的自定义对话框 http://dev.jtsage.com/jQM-SimpleDialog/demos2/button.html 设置按钮的点击和划过的效果 \u0026amp;lt;!DOCTYPE html PUBLIC \u0026#34;-//W3C//DTD XHTML 1.0 Transitional//EN\u0026#34; \u0026#34;[http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd](http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd)\u0026#34;\u0026amp;gt; \u0026amp;lt;html xmlns=\u0026#34;[http://www.w3.org/1999/xhtml](http://www.w3.org/1999/xhtml)\u0026#34;\u0026amp;gt; \u0026amp;lt;head\u0026amp;gt; \u0026amp;lt;meta http-equiv=\u0026#34;Content-Type\u0026#34; content=\u0026#34;text/html; charset=utf-8\u0026#34; /\u0026amp;gt; \u0026amp;lt;title\u0026amp;gt;手写html\u0026amp;lt;/title\u0026amp;gt; \u0026amp;lt;script type=\u0026#34;text/javascript\u0026#34; src=\u0026#34;jquery-1.7.js\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt;\u0026amp;lt;!--换成自己的Jquery引用--\u0026amp;gt; \u0026amp;lt;!-- 写javascript --\u0026amp;gt; \u0026amp;lt;script type=\u0026#34;text/javascript\u0026#34;\u0026amp;gt; \u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(function(){\u0026lt;/span\u0026gt;(\u0026#34;#1\u0026#34;).mouseenter(function(){\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(this).css(\u0026#34;background\u0026#34;,\u0026#34;red\u0026#34;);});//鼠标在按钮上,设置red\u0026lt;/span\u0026gt;(\u0026#34;#1\u0026#34;).mousedown(function(){\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(this).css(\u0026#34;background\u0026#34;,\u0026#34;yellow\u0026#34;);}).mouseup(function(){\u0026lt;/span\u0026gt;(this).css(\u0026#34;background\u0026#34;,\u0026#34;black\u0026#34;);});//mousedown数遍按下时 设置为yellow，mouseup点击后变black }); \u0026amp;lt;/script\u0026amp;gt; \u0026amp;lt;/head\u0026amp;gt; \u0026amp;lt;body\u0026amp;gt; \u0026amp;lt;input type=\u0026#34;button\u0026#34; value=\u0026#34;点击\u0026#34; id=\u0026#34;1\u0026#34;/\u0026amp;gt; \u0026amp;lt;/body\u0026amp;gt; \u0026amp;lt;/html\u0026amp;gt; html中运行在移动客户端的浏览器中没有放大和缩小按钮。 \u0026lt;meta name=\u0026quot;viewport\u0026quot; content=\u0026quot;width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\u0026quot; /\u0026gt; jQuery Mobile Data 属性 http://www.w3cschool.cc/jquerymobile/jquerymobile-ref-data.html\n此文章将会持续更新，主要收录一些新手比较常见的问题。\n欢迎 向我推荐比较典型的常见问题，我会记录并整理进文章，方便自己更方便大家。\n#### 文章导读： - [1、页面缩放显示问题](http://www.wglong.com/main/artical!details?id=4#q1) - [2、页面跳转后样式丢失js失效](http://www.wglong.com/main/artical!details?id=4#q2) - [3、跳转时重复调用pageinit方法的解决办法](http://www.wglong.com/main/artical!details?id=4#q3) - [4、如何调用loading效果](http://www.wglong.com/main/artical!details?id=4#q4) - [5、动态改变了list的内容，但是内容并没有变化](http://www.wglong.com/main/artical!details?id=4#q5) - [6、把所有内容放到一个页面好,还是分开多页面好](http://www.wglong.com/main/artical!details?id=4#q6) - [7、如何禁掉ajax跳转](http://www.wglong.com/main/artical!details?id=4#q7) - [8、为什么android2.3系统转屏无效果？](http://www.wglong.com/main/artical!details?id=4#q8) - [9、如何去掉jqm自带的组件样式？](http://www.wglong.com/main/artical!details?id=4#q9) - [10、jquery mobile “闪屏” 问题](http://www.wglong.com/main/artical!details?id=4#q10) 2013/4/30 更新内容： - [11、按钮按下/划过的状态感觉反应有些迟缓？](http://www.wglong.com/main/artical!details?id=4#q11) 2013/5/1 更新内容： - [12、jquery mobile各类组件刷新方法](http://www.wglong.com/main/artical!details?id=4#q12) 2013/5/7 更新内容： - [13、在页面动态添加组件，发现css消失了](http://www.wglong.com/main/artical!details?id=4#q13) 2013/5/22 更新内容： - [14、关于checkbox取值问题](http://www.wglong.com/main/artical!details?id=4#q14) 2013/5/28 更新内容： - [15、点击屏幕，header和footer会略微抖动？](http://www.wglong.com/main/artical!details?id=4#q15) 2013/6/20 更新内容： - [16、jqm图标|图标定位|隐藏图片上的文字|去除图标阴影|自定义图标|去除按钮阴影/圆角](http://www.wglong.com/main/artical!details?id=4#q16) - [17、jqm组件显示正常，但是小图标是“空的”，没有正常显示](http://www.wglong.com/main/artical!details?id=4#q17) - [18、$.mobile.changePage方法不能正常跳转](http://www.wglong.com/main/artical!details?id=4#q18) ##### 1页面缩放显示问题 \u0026lt;span class=\u0026quot;label label-info\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;问题描述：\u0026lt;/span\u0026gt; 页面似乎被缩小了，屏幕太宽了。 \u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;解决办法：\u0026lt;/span\u0026gt; 在head标签内加入： \u0026amp;lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1\u0026#34;\u0026amp;gt; \u0026amp;nbsp; 2 页面跳转后样式丢失js失效 \u0026lt;span class=\u0026quot;label label-info\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;问题描述：\u0026lt;/span\u0026gt; 用ajax跳转的时候，从a.html跳转到b.html后，b.html的css以及js都失效了。 \u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;解决办法：\u0026lt;/span\u0026gt; 将当前页面需要用到的css以及js放在 div内。\n\u0026lt;span class=\u0026quot;label label-success\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;原理：\u0026lt;/span\u0026gt; 由于jqm的ajax跳转的时候，只会把b.html中 内的内容加载进dom,而 外的代码都不会加载，所以导致在 外的js和css都失效了。\n\u0026amp;nbsp; 3 跳转时重复调用pageinit方法的解决办法 \u0026lt;span class=\u0026quot;label label-info\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;问题描述：\u0026lt;/span\u0026gt; 用ajax跳转的时候，从a.html跳转到b.html，用从b.html返回a.html等等这种反复跳转的时候，pageinit方法内的代码会调用多次。 \u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;解决办法：\u0026lt;/span\u0026gt; 在page中加入 data-dom-cache=\u0026amp;#8221;true\u0026amp;#8221;属性，如： \u0026amp;lt;div data-role=\u0026#34;page\u0026#34; id=\u0026#34;myPage\u0026#34; data-dom-cache=\u0026#34;true\u0026#34;\u0026amp;gt; 然后把pageinit方法换为pageshow,如： \u0026amp;nbsp; $(\u0026#34;#myPage\u0026#34;).live(\u0026#34;pageshow\u0026#34;, function() { //...do something }); \u0026amp;nbsp; 4 如何调用loading效果 \u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;js代码：\u0026lt;/span\u0026gt; //显示loading function showLoading(){ \u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;.mobile.loadingMessageTextVisible = true;\u0026lt;/span\u0026gt;.mobile.showPageLoadingMsg(\u0026#34;a\u0026#34;, \u0026#34;加载中...\u0026#34; ); } //隐藏loading function hideLoading(){ $.mobile.hidePageLoadingMsg(); } [查看Demo »](http://www.wglong.com/index/demos/loading/index.html) 扫描查看Demo： \u0026amp;nbsp; 5 动态改变了list的内容，但是内容并没有变化 \u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;解决办法：\u0026lt;/span\u0026gt; 调用组件的refresh方法，刷新list,如： $(\u0026#34;#contentList\u0026#34;).append(content).listview(\u0026#39;refresh\u0026#39;); \u0026lt;span class=\u0026quot;label label-success\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;原理：\u0026lt;/span\u0026gt; jqm组件的显示原理是把原始的web组件隐藏，而用jqm自定义的UI组件来代替原始的web组件显示。动态的改变了list的值，其实改变的是原始组件list的值，而jqm的list组件的值并没有被更新，所以需要调用list组件的refresh方法来使其更新并显示。 ##### 注意: 此问题不只局限于list组件，基本所有的jqm UI组件在改变值之后都需要调用组件对应的refresh方法，例如button组件( $(\u0026amp;#8216;#id\u0026amp;#8217;).button(\u0026amp;#8216;refresh\u0026amp;#8217;) )等等。更多刷新方法请查看：[jquery mobile各类组件刷新方法](http://www.wglong.com/main/artical!details?id=4#q12) \u0026amp;nbsp; 6 把所有内容放到一个页面好,还是分开多页面好？ 对于这个问题，说说笔者的个人见解： #1所有内容放到同一页面 #2分页面存放内容 对于#1，如果是比较简单的网页内容，可以考虑把内容都放在同一个页面。但是如果页面结构很复杂，跳转页面比较多的话，那#1就会显得很臃肿，增加维护的复杂度。 而#2比较适合页面结构以及页面比较多的情况，易维护。 性能方面，笔者查了一些资料，也亲自做了些实验，并没有发现性能上的明显差异。 结论：根据个人编码习惯，两种选择都是可以的。推荐#1和#2混合使用。\n\u0026amp;nbsp; 7 如何禁掉ajax跳转？ \u0026lt;span class=\u0026quot;label label-info\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;问题描述：\u0026lt;/span\u0026gt; 尽管ajax跳转有很炫的转屏动画，但是在某些时候为了性能或者为了业务需求还是需要禁掉ajax跳转的。 \u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;解决办法：\u0026lt;/span\u0026gt; 禁止ajxa跳转有两种情况： 1、禁止局部ajax跳转 2、禁止全局ajax跳转 对于#1只需要在a标签中添加下面的属性： \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;data-ajax=“false”\u0026lt;/span\u0026gt; 有时我们要用正常的http请求而不用Ajax请求，比如链接到别的网站等情况。通过给a标签加下面的属性，可以将链接指定为正常的http请求: \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;rel\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;external\u0026lt;/span\u0026gt; 对于#2我们需要设置一个全局的禁止ajax跳转的方式，js代码如下： \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;$\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;document\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;).\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;bind\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;str\u0026#34; style=\u0026#34;color: #dd1144;\u0026#34;\u0026gt;\u0026#34;mobileinit\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;kwd\u0026#34; style=\u0026#34;color: #1e347b;\u0026#34;\u0026gt;function\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;()\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;{\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;com\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;// disable ajax nav\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; $\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;mobile\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;ajaxEnabled\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;kwd\u0026#34; style=\u0026#34;color: #1e347b;\u0026#34;\u0026gt;false\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;});\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;注意：\u0026lt;/span\u0026gt;上面的代码片段需要放在jquery.mobile-xxx.min.js引入之前。 顺便说一句，初始化的设置都需要放在此处，例如加载错误信息的设置： \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;$\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;mobile\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;pageLoadErrorMessage \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;str\u0026#34; style=\u0026#34;color: #dd1144;\u0026#34;\u0026gt;\u0026#39;Sorry, something went wrong. Please try again.\u0026#39;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026amp;nbsp; 8 为什么android2.3系统转屏无效果？ \u0026lt;span class=\u0026quot;label label-info\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;问题描述：\u0026lt;/span\u0026gt; 发现在android2.X系统测试的时候slide等转屏效果并没有很好的显示，而是一闪而过了。但是在android4.0+显示却正常。 \u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;问题分析：\u0026lt;/span\u0026gt; 之所以android2.X系统对slide等转屏效果支持不是很好，是因为slide等效果都需要3D支持，而android2.X系统不支持3D, 而JQM遇到这种情况的时候把slide等效果“退化”到淡入淡出效果，根据笔者的测试即使这种淡入淡出效果也不尽人意，感觉有点像“闪屏”，在这种情况下直接把转屏效果设置为none，反而比这种淡入淡出看着更舒服。 既然android2.X不支持3D转场，但是android4.0支持，我想在4.0系统保留转场效果，而在2.X上去除转场效果怎么办？ 解决办法很简单，只需要加入下面的代码即可： \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;$\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;mobile\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;transitionFallbacks\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;slideout \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;str\u0026#34; style=\u0026#34;color: #dd1144;\u0026#34;\u0026gt;\u0026#34;none\u0026#34;\u0026lt;/span\u0026gt; 更多关于“闪屏”的问题，请看：[10、jquery mobile “闪屏” 问题](http://www.wglong.com/main/artical!details?id=4#q10) \u0026amp;nbsp; 9 如何去掉jqm自带的组件样式？ \u0026lt;span class=\u0026quot;label label-info\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;问题描述：\u0026lt;/span\u0026gt; 尽管jqm提供了比较美观的组件样式，但是有些时候我们需要去掉jqm自带的样式。 \u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;解决办法：\u0026lt;/span\u0026gt; 解决办法很简单，只需要在组件中加上如下属性就可以了： \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;data-role=\u0026#39;none\u0026#39;\u0026lt;/span\u0026gt; \u0026amp;nbsp; 10 jquery mobile “闪屏” 问题 \u0026lt;span class=\u0026quot;label label-info\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;官方描述：\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;typ\u0026#34; style=\u0026#34;color: teal;\u0026#34;\u0026gt;Important\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;typ\u0026#34; style=\u0026#34;color: teal;\u0026#34;\u0026gt;Some\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; platforms currently have issues \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;kwd\u0026#34; style=\u0026#34;color: #1e347b;\u0026#34;\u0026gt;with\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; transitions\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;typ\u0026#34; style=\u0026#34;color: teal;\u0026#34;\u0026gt;We\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; are working on a solution to solve the problem \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;kwd\u0026#34; style=\u0026#34;color: #1e347b;\u0026#34;\u0026gt;for\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; everyone\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;typ\u0026#34; style=\u0026#34;color: teal;\u0026#34;\u0026gt;If\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; you are experiencing flickers \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;kwd\u0026#34; style=\u0026#34;color: #1e347b;\u0026#34;\u0026gt;and\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; flashes during \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;kwd\u0026#34; style=\u0026#34;color: #1e347b;\u0026#34;\u0026gt;or\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; at the \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;kwd\u0026#34; style=\u0026#34;color: #1e347b;\u0026#34;\u0026gt;end\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; of a transition we suggest the following workaround\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;typ\u0026#34; style=\u0026#34;color: teal;\u0026#34;\u0026gt;Please\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; note that \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;kwd\u0026#34; style=\u0026#34;color: #1e347b;\u0026#34;\u0026gt;this\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; workaround should be thoroughly tested on the target platform before deployment\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;typ\u0026#34; style=\u0026#34;color: teal;\u0026#34;\u0026gt;This\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; workaround \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;kwd\u0026#34; style=\u0026#34;color: #1e347b;\u0026#34;\u0026gt;is\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; known to cause performance issues \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;kwd\u0026#34; style=\u0026#34;color: #1e347b;\u0026#34;\u0026gt;and\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; browser crashes on some platforms\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; especially \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;typ\u0026#34; style=\u0026#34;color: teal;\u0026#34;\u0026gt;Android\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;typ\u0026#34; style=\u0026#34;color: teal;\u0026#34;\u0026gt;Add\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; the following code to your custom css\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;ui\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;page \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;{\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;webkit\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;backface\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;visibility\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; hidden\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;}\u0026lt;/span\u0026gt; 即使加上官方提供的css代码片段，效果仍旧不尽人意，这个问题到现在仍旧是jqm的一个比较严重的问题，希望下个版本可以解决此问题。 除了在[8、为什么android2.3系统转屏无效果？](http://www.wglong.com/main/artical!details?id=4#q8) 中提到的内容外，近日在群里聊天，[**南京-恰恰虎**](http://www.wglong.com/main/artical!details?id=4#)提出一个可以缓解的方案，即：可以更改jqm的css,让闪的背景色和页面的一致，具体修改以下css: \u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;ui\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;body\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;c\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;,\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;ui\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;overlay\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;c \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;{\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; border\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;lit\u0026#34; style=\u0026#34;color: #195f91;\u0026#34;\u0026gt;1px\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; solid \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;com\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;#AAA;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; color\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;com\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;#333;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; background\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;com\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;#F9F9F9; //修改这里的颜色代码\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;}\u0026lt;/span\u0026gt; 我想这是一个很好的思路，是个值得一试的方法，但是笔者还没有亲自实验，需要的朋友可以亲自试一试，有空的话记得回来在评论里发表一下实验结果哦。 \u0026amp;nbsp; 11 按钮按下/划过的状态感觉反应有些迟缓？ 解决办法很简单，只需要加上如下设置就可以了： \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;$.mobile.buttonMarkup.hoverDelay = \u0026#34;false\u0026#34;;\u0026lt;/span\u0026gt; \u0026amp;nbsp; 12 jquery mobile各类组件刷新方法 1、Combobox or select dropdowns \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;var myselect = \u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(\u0026#34;#sCountry\u0026#34;); myselect[0].selectedIndex = 3; myselect.selectmenu(\u0026#39;refresh\u0026#39;); or\u0026lt;/span\u0026gt;( \u0026#34;.selector\u0026#34; ).selectmenu( \u0026#34;refresh\u0026#34;, true );\u0026lt;/span\u0026gt; 2、Listviews \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;$(\u0026#39;#mylist\u0026#39;).listview(\u0026#39;refresh\u0026#39;);\u0026lt;/span\u0026gt; 3、Slider control \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;$(\u0026#39;#slider\u0026#39;).val(80).slider(\u0026#39;refresh\u0026#39;);\u0026lt;/span\u0026gt; 4、Toggle switch \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;var myswitch = $(\u0026#34;#toggle\u0026#34;); myswitch[0].selectedIndex = 1; myswitch .slider(\u0026#34;refresh\u0026#34;);\u0026lt;/span\u0026gt; 5、Radio buttons \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;$(\u0026#34;input[value=grid]\u0026#34;).attr(\u0026#39;checked\u0026#39;,true).checkboxradio(\u0026#39;refresh\u0026#39;); or $( \u0026#34;.selector\u0026#34; ).prop( \u0026#34;checked\u0026#34;, true ).checkboxradio( \u0026#34;refresh\u0026#34; );\u0026lt;/span\u0026gt; 6、Checkboxes \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;$(\u0026#39;#checkbox-1\u0026#39;).attr(\u0026#39;checked\u0026#39;,true).checkboxradio(\u0026#39;refresh\u0026#39;); or $( \u0026#34;.selector\u0026#34; ).prop( \u0026#34;checked\u0026#34;, true ).checkboxradio( \u0026#34;refresh\u0026#34; );\u0026lt;/span\u0026gt; 7、Buttons \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;$( \u0026#34;[type=\u0026#39;submit\u0026#39;]\u0026#34; ).button( \u0026#34;refresh\u0026#34; ); or $( \u0026#34;.selector\u0026#34; ).buttonMarkup( \u0026#34;refresh\u0026#34; );\u0026lt;/span\u0026gt; 8、Column-Toggle Table \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;$( \u0026#34;.selector\u0026#34; ).table-columntoggle( \u0026#34;refresh\u0026#34; );\u0026lt;/span\u0026gt; 9、Reflow Table \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;$( \u0026#34;.selector\u0026#34; ).table( \u0026#34;refresh\u0026#34; );\u0026lt;/span\u0026gt; \u0026amp;nbsp; 13 在页面动态添加组件，发现css消失了 首先请试一试上面问题12的解决方案，如果没有效果的话，那就试试加上.trigger(\u0026amp;#8216;create\u0026amp;#8217;)，例如： \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;$(\u0026#34;#id\u0026#34;).html(content).trigger(\u0026#39;create\u0026#39;); or $.mobile.pageContainer.trigger(\u0026#34;create\u0026#34;);\u0026lt;/span\u0026gt; \u0026amp;nbsp; 14 关于checkbox取值问题 网友[**流浪的旋律**](http://www.wglong.com/main/artical!details?id=4#)在checkbox取值的时候，发现官网并没有提供相关方法，通过查阅资料终于找到了取值方法，并找到我分享在此，再次感谢[**流浪的旋律**](http://www.wglong.com/main/artical!details?id=4#)的分享精神！ 取值方式如下： \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;$(.checkbox)[0].checked\u0026lt;/span\u0026gt; [查看checkbox取值Demo »](http://www.wglong.com/index/demos/checkboxGetValue/checkboxGetValue.html) [下载checkbox取值Demo »](http://www.wglong.com/index/demos/checkboxGetValue/checkboxGetValue.zip) \u0026amp;nbsp; 15 点击屏幕，header和footer会略微抖动？ \u0026lt;span class=\u0026quot;label label-info\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;问题描述：\u0026lt;/span\u0026gt; 在真机运行的时候，轻击屏幕会发现header和footer有略微的抖动。 \u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;解决办法：\u0026lt;/span\u0026gt; 在header和footer中添加如下属性： \u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;data-tap-toggle=\u0026#34;false\u0026#34;\u0026lt;/span\u0026gt; 添加这个属性也可以解决点击屏幕header或footer消失问题。 \u0026amp;nbsp; 16 jqm图标|图标定位|隐藏图片上的文字|去除图标阴影|自定义图标|去除按钮阴影/圆角 **1、图标定位 data-iconpos** 默认情况下，所有的图标都放在按钮的按钮文本左。此默认可以覆盖使用 data-iconpos 属性来设置图标的右上方（top）、底部（bottom）、右侧（right）、左侧（left）的文本 **2、隐藏图片上的文字 data-iconpos=”notext”** 你也可以创建一个图标按钮，设置 data-iconpos=”notext”。按钮插件将隐藏的文字在屏幕上，但把它作为给屏幕阅读器和设备支持工具提示上下文链接标题属性。例如，data-iconpos=”right”，data-iconpos=”notext”： **3、自定义图标 data-icon=”自定义值”** 使用自定义图标，需要指定 data-icon 值。Jquery Mobile的button插件会将生成一个CSS类，它的前缀是ui-icon- ，后面的是data-icon值。假如：有一个按钮 data-icon 属性的值为 myapp-email，即 data-icon=“ myapp-email”。那么生产的CSS类是：ui-icon-myapp-email。 然后你可以在你的样式表写一个CSS规则来定义 ui-icon-myapp-email。然后在css中指定这个类的背景图片地址。为了保持与其他图标的视觉上的一致性，请创建一个白色18×18像素的PNG-8图标，并且保存为Alpha透明度。 \u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;ui\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;icon\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;myapp\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;email \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;{\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; background\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;image\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; url\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;str\u0026#34; style=\u0026#34;color: #dd1144;\u0026#34;\u0026gt;\u0026#34;app-icon-email.png\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;);\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;}\u0026lt;/span\u0026gt; 这将创建标准分辨率的图标，但许多设备都有非常高的分辨率的显示器，就像iPhone 4的视网膜显示器。添加一个高清图标，创建一个图标，36X36像素（18像素大小完全相同的两倍），并添加第二个规则使用WebKit分钟装置像素比例：2。媒体查询到目标的规则只有以高分辨率显示器。指定背景图片高清图标文件和设置背景像素大小18×18将安装36个像素图标到同一个18像素的空间。传媒查询块可以用多个图标规则：\n\u0026lt;span class=\u0026#34;lit\u0026#34; style=\u0026#34;color: #195f91;\u0026#34;\u0026gt;@media\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; only screen \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;kwd\u0026#34; style=\u0026#34;color: #1e347b;\u0026#34;\u0026gt;and\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;(-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;webkit\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;min\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;device\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;pixel\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;ratio\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;lit\u0026#34; style=\u0026#34;color: #195f91;\u0026#34;\u0026gt;2\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;{\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;ui\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;icon\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;myapp\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;email \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;{\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; background\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;image\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; url\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;str\u0026#34; style=\u0026#34;color: #dd1144;\u0026#34;\u0026gt;\u0026#34;app-icon-email-highres.png\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;);\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt; background\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;size\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;lit\u0026#34; style=\u0026#34;color: #195f91;\u0026#34;\u0026gt;18px\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;lit\u0026#34; style=\u0026#34;color: #195f91;\u0026#34;\u0026gt;18px\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;}\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;...\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;more HD icon rules go here\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;...\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;pun\u0026#34; style=\u0026#34;color: #93a1a1;\u0026#34;\u0026gt;}\u0026lt;/span\u0026gt; 4、去除按钮阴影/圆角\n\u0026lt;span class=\u0026#34;pln\u0026#34; style=\u0026#34;color: #48484c;\u0026#34;\u0026gt;data-shadow=”false” data-corners=”false”\u0026lt;/span\u0026gt; 本小结引自：http://www.wpdic.com/?p=59\n\u0026amp;nbsp; 17 jqm组件显示正常，但是小图标是“空的”，没有正常显示 \u0026lt;span class=\u0026quot;label label-info\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;问题描述：\u0026lt;/span\u0026gt; 例如header中的返回按钮，按钮的显示和功能都正常，但是按钮上的“返回小图标”没有显示。 \u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;解决办法：\u0026lt;/span\u0026gt; 这是由于没有引入jqm的图片文件引起的，解决方法是在jqm的资源包里找到images文件夹，并把images文件夹引入自己的项目，与jqm的css文件放在同一级目录里。 \u0026amp;nbsp; 18 $.mobile.changePage方法不能正常跳转 \u0026lt;span class=\u0026quot;label label-info\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;问题描述：\u0026lt;/span\u0026gt; $.mobile.changePage不能跳转，而window.location.href却可以正常跳转。 \u0026lt;span class=\u0026quot;label label-success\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;原理：\u0026lt;/span\u0026gt; 这个问题牵扯到jqm的跳转机制了，简单的说jqm的默认跳转方式，也就是$.mobile.changePage这种方式，原理是ajax跳转。听起来很神秘，其实就是通过ajax动态的把目标页面的内容加载到当前的dom中。当多页面跳转的时候，通过ajax跳转，就存在ajax跨域的问题。所以解决目前的问题，其实就是解决ajax跨域的问题。 \u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;解决办法：\u0026lt;/span\u0026gt; 为了解决跨域问题，我们需要把项目放在服务器环境下。好多朋友不知道什么叫服务器环境，说白了就是把项目部署到WAMP或者TOMCAT等等的服务器下，然后通过http://localhost/xxx 这样的方式访问项目。 小结：这里提到了jqm的跳转机制了，笔者之前写过一篇文章：[JQM进阶:转屏效果的模拟实现](http://www.wglong.com/main/artical!details?id=17)，这篇文章完全没有用jqm，而是模拟了jqm的跳转过程，想深入了解jqm跳转的朋友可以看一看这篇文章的实现原理。 19 …还有什么需要补充问题？ 请联系我\n原创文章，转载请注明出处：http://www.wglong.com/main/artical!details?id=4\n","permalink":"https://blog.zdltech.com/posts/jquery-mobile-%E6%96%B0%E6%89%8B%E9%97%AE%E9%A2%98%E6%80%BB%E6%B1%87/","summary":"\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eJquery Mobile中的自定义对话框\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehttp://dev.jtsage.com/jQM-SimpleDialog/demos2/button.html\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e设置按钮的点击和划过的效果\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;!DOCTYPE html PUBLIC \u0026#34;-//W3C//DTD XHTML 1.0 Transitional//EN\u0026#34; \u0026#34;[http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd](http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd)\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;html xmlns=\u0026#34;[http://www.w3.org/1999/xhtml](http://www.w3.org/1999/xhtml)\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;head\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;meta http-equiv=\u0026#34;Content-Type\u0026#34; content=\u0026#34;text/html; charset=utf-8\u0026#34; /\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;title\u0026amp;gt;手写html\u0026amp;lt;/title\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;script type=\u0026#34;text/javascript\u0026#34; src=\u0026#34;jquery-1.7.js\u0026#34;\u0026amp;gt;\u0026amp;lt;/script\u0026amp;gt;\u0026amp;lt;!--换成自己的Jquery引用--\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;!-- 写javascript --\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;script type=\u0026#34;text/javascript\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(function(){\u0026lt;/span\u0026gt;(\u0026#34;#1\u0026#34;).mouseenter(function(){\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(this).css(\u0026#34;background\u0026#34;,\u0026#34;red\u0026#34;);});//鼠标在按钮上,设置red\u0026lt;/span\u0026gt;(\u0026#34;#1\u0026#34;).mousedown(function(){\u0026lt;span class=\u0026#34;katex math inline\u0026#34;\u0026gt;(this).css(\u0026#34;background\u0026#34;,\u0026#34;yellow\u0026#34;);}).mouseup(function(){\u0026lt;/span\u0026gt;(this).css(\u0026#34;background\u0026#34;,\u0026#34;black\u0026#34;);});//mousedown数遍按下时 设置为yellow，mouseup点击后变black\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/script\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/head\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;body\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;input type=\u0026#34;button\u0026#34; value=\u0026#34;点击\u0026#34;  id=\u0026#34;1\u0026#34;/\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/body\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;/html\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003ehtml中运行在移动客户端的浏览器中没有放大和缩小按钮。 \u0026lt;meta name=\u0026quot;viewport\u0026quot; content=\u0026quot;width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\u0026quot; /\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch1\u003e\u003c/h1\u003e\n\u003ch1 id=\"jquery-mobiledata-属性\"\u003ejQuery Mobile \u003cspan class=\"color_h1\" style=\"color: #8ac007;\"\u003eData 属性\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"http://www.w3cschool.cc/jquerymobile/jquerymobile-ref-data.html\"\u003ehttp://www.w3cschool.cc/jquerymobile/jquerymobile-ref-data.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e此文章将会持续更新，主要收录一些新手比较常见的问题。\u003c/p\u003e\n\u003cp\u003e欢迎 \u003ca href=\"http://www.wglong.com/main/index!aboutMe#contact\"\u003e向我推荐\u003c/a\u003e比较典型的常见问题，我会记录并整理进文章，方便自己更方便大家。\u003c/p\u003e\n\u003cdiv\u003e\n  #### 文章导读：\n\u003cpre\u003e\u003ccode\u003e  - [1、页面缩放显示问题](http://www.wglong.com/main/artical!details?id=4#q1)\n  \n  - [2、页面跳转后样式丢失js失效](http://www.wglong.com/main/artical!details?id=4#q2)\n  \n  - [3、跳转时重复调用pageinit方法的解决办法](http://www.wglong.com/main/artical!details?id=4#q3)\n  \n  - [4、如何调用loading效果](http://www.wglong.com/main/artical!details?id=4#q4)\n  \n  - [5、动态改变了list的内容，但是内容并没有变化](http://www.wglong.com/main/artical!details?id=4#q5)\n  \n  - [6、把所有内容放到一个页面好,还是分开多页面好](http://www.wglong.com/main/artical!details?id=4#q6)\n  \n  - [7、如何禁掉ajax跳转](http://www.wglong.com/main/artical!details?id=4#q7)\n  \n  - [8、为什么android2.3系统转屏无效果？](http://www.wglong.com/main/artical!details?id=4#q8)\n  \n  - [9、如何去掉jqm自带的组件样式？](http://www.wglong.com/main/artical!details?id=4#q9)\n  \n  - [10、jquery mobile “闪屏” 问题](http://www.wglong.com/main/artical!details?id=4#q10)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3 id=\"2013430-更新内容\"\u003e2013/4/30 更新内容：\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003e  - [11、按钮按下/划过的状态感觉反应有些迟缓？](http://www.wglong.com/main/artical!details?id=4#q11)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3 id=\"201351-更新内容\"\u003e2013/5/1 更新内容：\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003e  - [12、jquery mobile各类组件刷新方法](http://www.wglong.com/main/artical!details?id=4#q12)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3 id=\"201357-更新内容\"\u003e2013/5/7 更新内容：\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003e  - [13、在页面动态添加组件，发现css消失了](http://www.wglong.com/main/artical!details?id=4#q13)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3 id=\"2013522-更新内容\"\u003e2013/5/22 更新内容：\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003e  - [14、关于checkbox取值问题](http://www.wglong.com/main/artical!details?id=4#q14)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3 id=\"2013528-更新内容\"\u003e2013/5/28 更新内容：\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003e  - [15、点击屏幕，header和footer会略微抖动？](http://www.wglong.com/main/artical!details?id=4#q15)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3 id=\"2013620-更新内容\"\u003e2013/6/20 更新内容：\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003e- [16、jqm图标|图标定位|隐藏图片上的文字|去除图标阴影|自定义图标|去除按钮阴影/圆角](http://www.wglong.com/main/artical!details?id=4#q16)\n\n- [17、jqm组件显示正常，但是小图标是“空的”，没有正常显示](http://www.wglong.com/main/artical!details?id=4#q17)\n\n- [18、$.mobile.changePage方法不能正常跳转](http://www.wglong.com/main/artical!details?id=4#q18)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003chr /\u003e\n\u003c/div\u003e\n\u003cdiv id=\"q1\"\u003e\n  ##### \u003cspan class=\"badge badge-warning\" style=\"color: #ffffff;\"\u003e1\u003c/span\u003e页面缩放显示问题\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;label label-info\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;问题描述：\u0026lt;/span\u0026gt;\n\n\n\n\n\n页面似乎被缩小了，屏幕太宽了。\n\n\n\n\n\n\u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;解决办法：\u0026lt;/span\u0026gt;\n\n\n\n\n\n在head标签内加入：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026amp;lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1\u0026#34;\u0026amp;gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cdiv id=\"q2\"\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch5 id=\"2页面跳转后样式丢失js失效\"\u003e\u003cspan class=\"badge badge-warning\" style=\"color: #ffffff;\"\u003e2\u003c/span\u003e 页面跳转后样式丢失js失效\u003c/h5\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;label label-info\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;问题描述：\u0026lt;/span\u0026gt;\n\n\n\n\n\n用ajax跳转的时候，从a.html跳转到b.html后，b.html的css以及js都失效了。\n\n\n\n\n\n\u0026lt;span class=\u0026quot;label label-important\u0026quot; style=\u0026quot;font-weight: bold; color: #ffffff;\u0026quot;\u0026gt;解决办法：\u0026lt;/span\u0026gt;\n\n\n\n\n\n将当前页面需要用到的css以及js放在\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003ediv内。\u003c/p\u003e","title":"Jquery mobile 新手问题总汇"},{"content":"前几节的例子已经介绍了一些按钮控件的用法，但是笔者的同事一致反映，在jQuery Mobile中按钮只能以占满一行的形式平铺显得过于单调，正巧笔者在贴吧看到了一个学生设计的简单播放器（如图6-13），于是产生了灵感，决定用一组内联的按钮来实现一个简单播放器的控制面板。\n图 6-13 简单的音乐播放器\n要实现的功能很简单，就是选取页面中的一行，使其中并排放置4个大小相同的按钮，分别显示为播放、停止、前进和后退，可是这真的能实现嘛？\n也许有读者会说，可以重新设计按钮的样式文件对其CSS进行重写，这当然是一种非常直接的方法，但是实在是过于麻烦了。因为jQuery Mobile已经为开发者准备了按钮的内联功能可以方便的实现笔者想要的效果。\n【范例6-5 利用按钮分组制作的播放器界面】\n**[html]** [view plain](http://blog.csdn.net/bookzhaopin/article/details/38270351#)[copy](http://blog.csdn.net/bookzhaopin/article/details/38270351#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;!DOCTYPE html\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;comments\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;声明HTML 5 \u0026amp;#8211;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;html\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;head\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;meta\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;http-equiv\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Content-Type\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;content\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;text/html; charset=utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;title\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;简单的播放器\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;title\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;comments\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;页面标题\u0026amp;#8211;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;meta\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;viewport\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;content\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;width=device-width, initial-scale=1\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;引入jQuery Mobile样式文件 \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;link\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;rel\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;stylesheet\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jquery.mobile.min.css\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;引入jQuery支持库 \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;script\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jquery-1.7.1.min.js\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;script\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;引入jQuery Mobile所需的js文件 \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;script\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;src\u0026lt;/span\u0026gt;=“jquery.mobile.min.js”\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;script\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;head\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;body\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;page\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-theme\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;a\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;header\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;返回\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;h1\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;音乐播放器\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;h1\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;content\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;controlgroup\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;no air \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comments\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;网上随意下载的图片，将图片宽度设置为80%使两边留有空隙\u0026amp;#8211;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;img\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.jpg\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;width:80%;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comments\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;这里歌手和来源占用两格可以使页面更加和谐\u0026amp;#8211;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;jordin sparks\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;No Air \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;controlgroup\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-type\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;后退\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;播放\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;暂停\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;后退\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;footer\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;h1\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;暂无歌词\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;h1\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;body\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;html\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 运行结果如图6-14所示。\n除了操作面板之外，利用按钮的分组功能又设计了一个简单的音乐内容面板，其中包括了正在播放音乐的名称、作者来源等消息，下面来介绍一下按钮分组的方法。\n首先是偏上部分的音乐内容面板，简单地对4个按钮分在了一组，在这一组按钮的外面包了一个“div”标签，其中将属性data-role设置为”controlgroup”。在页面中可以清楚地看到4个按钮被紧紧地链接在了一起，最外侧的两个面被加上了圆弧，看上去非常大气。\n接下来是操作面板，依然是将4个按钮分在一组，不同的是这次要给外面的div标签多设置一组属性data-type=”horizontal”，将排列方式设置成横向。\n提示：这里还可以给某个按钮设置主题，比如说播放键加上不同的颜色，使之更加醒目，更易于用户操作。\n图6-14 音乐播放器界面\njQueryMobile可用度越来越高，入门门槛低，可以少写代码来生成移动设备友好的界面。《构建跨平台APP：jQuery Mobile移动应用实战》这本书采用实例驱动的方式介绍jQueryMobile下的APP开发，全书提供70余个实战案例教会读者进行移动开发，最后还通过6个小型项目来复习和巩固所学知识点。想和作者交流，加Q群：348632872，作者在这里等你来哦。\n","permalink":"https://blog.zdltech.com/posts/%E6%9E%84%E5%BB%BA%E8%B7%A8%E5%B9%B3%E5%8F%B0appjquery-mobile%E7%A7%BB%E5%8A%A8%E5%BA%94%E7%94%A8%E5%AE%9E%E6%88%98%E8%BF%9E%E8%BD%BD%E5%85%AD-%E8%AE%BE%E8%AE%A1%E6%92%AD/","summary":"\u003cp\u003e前几节的例子已经介绍了一些按钮控件的用法，但是笔者的同事一致反映，在jQuery Mobile中按钮只能以占满一行的形式平铺显得过于单调，正巧笔者在贴吧看到了一个学生设计的简单播放器（如图6-13），于是产生了灵感，决定用一组内联的按钮来实现一个简单播放器的控制面板。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140729151047282?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va3poYW9waW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e图 6-13 简单的音乐播放器\u003c/p\u003e\n\u003cp\u003e要实现的功能很简单，就是选取页面中的一行，使其中并排放置4个大小相同的按钮，分别显示为播放、停止、前进和后退，可是这真的能实现嘛？\u003c/p\u003e\n\u003cp\u003e也许有读者会说，可以重新设计按钮的样式文件对其CSS进行重写，这当然是一种非常直接的方法，但是实在是过于麻烦了。因为jQuery Mobile已经为开发者准备了按钮的内联功能可以方便的实现笔者想要的效果。\u003c/p\u003e\n\u003cp\u003e【范例6-5 利用按钮分组制作的播放器界面】\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/bookzhaopin/article/details/38270351#)[copy](http://blog.csdn.net/bookzhaopin/article/details/38270351#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;!DOCTYPE html\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;                       \u0026lt;span class=\u0026quot;comments\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;声明HTML 5 \u0026amp;#8211;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;html\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;       \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;head\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;       \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;meta\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;http-equiv\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Content-Type\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;content\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;text/html; charset=utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;title\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;简单的播放器\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;title\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;                                 \u0026lt;span class=\u0026quot;comments\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;页面标题\u0026amp;#8211;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;meta\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;viewport\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;content\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;width=device-width, initial-scale=1\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;       \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;引入jQuery Mobile样式文件  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;link\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;rel\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;stylesheet\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jquery.mobile.min.css\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;   \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;引入jQuery支持库      \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;script\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jquery-1.7.1.min.js\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;script\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;       \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;引入jQuery Mobile所需的js文件  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;script\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;src\u0026lt;/span\u0026gt;=“jquery.mobile.min.js”\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;script\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;      \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;head\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;                 \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;body\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;page\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-theme\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;a\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;header\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;返回\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;h1\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;音乐播放器\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;h1\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;content\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;controlgroup\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;no air \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;comments\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;网上随意下载的图片，将图片宽度设置为80%使两边留有空隙\u0026amp;#8211;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;img\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;src\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.jpg\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;width:80%;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;      \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;comments\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211;这里歌手和来源占用两格可以使页面更加和谐\u0026amp;#8211;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;jordin sparks\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;    \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;No Air \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;controlgroup\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-type\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;后退\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;   \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;播放\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;暂停\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;href\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;button\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;后退\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;a\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;data-role\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;footer\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;h1\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;暂无歌词\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;h1\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;div\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;body\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;html\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"《构建跨平台APP：jQuery Mobile移动应用实战》连载六-设计播放器APP"},{"content":" `BasicHttpParams params = ``new` `BasicHttpParams();` `// Set the timeout in milliseconds until a connection is established. ` `HttpConnectionParams.setConnectionTimeout(params, TIMEOUT_CONNECTION);` `// Set the default socket timeout (SO_TIMEOUT) ` `// in milliseconds which is the timeout for waiting for data. ` `HttpConnectionParams.setSoTimeout(params, TIMEOUT_SOCKET); ` `ConnManagerParams.setMaxTotalConnections(params, ``5``);` `ConnManagerParams.setTimeout(params, TIMEOUT_TOTAL);` `client = ``new` `DefaultHttpClient(params);` `CookieStore cookieStore = ``new` `BasicCookieStore();` `//Bind custom cookie store to the local context` `client.setCookieStore(cookieStore);` `CookieSpecFactory csf = ``new` `CookieSpecFactory() { ` `public` `CookieSpec newInstance(HttpParams params) {` ` ``return` `new` `BrowserCompatSpec() {` ` ``@Override` ` ``public` `void` `validate(Cookie cookie, CookieOrigin origin) ``throws` `MalformedCookieException ` ` ``{` ` ``// Oh, I am easy` ` ``// allow all cookies` ` ``//log.debug(\"custom validate\");` ` ``}` ` ``};` `}` `};` `client.getCookieSpecs().register(``\"oschina\"``, csf);` `client.getParams().setParameter(ClientPNames.COOKIE_POLICY, ``\"oschina\"``);` `client.getParams().setParameter(CookieSpecPNames.SINGLE_COOKIE_HEADER, ``true``);` 当然下面设置也可以，直接运行下就能看到结果。。 /** * \u0026lt;span class=\u0026quot;s1\u0026quot;\u0026gt;@param\u0026lt;/span\u0026gt; url * :交互服务器的URL地址 * \u0026lt;span class=\u0026quot;s1\u0026quot;\u0026gt;@param\u0026lt;/span\u0026gt; pairs * ：交互所带的参数 * \u0026lt;span class=\u0026quot;s1\u0026quot;\u0026gt;@return\u0026lt;/span\u0026gt; JSONObject：从服务器获取的字符串 */ \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String httpServicePostString(String url, List\u0026lt;BasicNameValuePair\u0026gt; pairs, Context context) { HttpPost httpPost = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HttpPost(url); DefaultHttpClient httpClient = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DefaultHttpClient(); Log.d(\u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;cat\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;out response=\u0026amp;#8221;\u0026lt;/span\u0026gt; + httpPost.getURI() + \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8221; \u0026amp;#8220;\u0026lt;/span\u0026gt; + pairs.toString()); \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { httpPost.setEntity(\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; UrlEncodedFormEntity(pairs, HTTP.\u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;UTF_8\u0026lt;/span\u0026gt;)); } \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (UnsupportedEncodingException e) { e.printStackTrace(); } CookieStore cookieStore = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BasicCookieStore(); httpClient.setCookieStore(cookieStore); \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { HttpResponse response = httpClient.execute(httpPost); \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (response.getStatusLine().getStatusCode() == HttpStatus.\u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;SC_OK\u0026lt;/span\u0026gt;) { HttpEntity httpEntity = response.getEntity(); \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (httpEntity != \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { CookieStore c = httpClient.getCookieStore(); List\u0026lt;Cookie\u0026gt; list = c.getCookies(); \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (Cookie cookie : list) { Log.e(HttpService.\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getName(), \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;cookie=\u0026amp;#8221;\u0026lt;/span\u0026gt; + cookie.getName()); Log.e(HttpService.\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getName(), Log.e(HttpService.\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getName(), SharedPreferencesUtils sharePrefenrences = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SharedPreferencesUtils(); sharePrefenrences.saveCookie(context, cookie.getValue()); } Header[] headers = response.getAllHeaders(); \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (Header header : headers) { Log.e(HttpService.\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getName(), \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;head=\u0026amp;#8221;\u0026lt;/span\u0026gt; + header.getName()); } \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (response.getFirstHeader(\u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;Set-Cookie\u0026amp;#8221;\u0026lt;/span\u0026gt;) != \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { String set_cookie = response.getFirstHeader( \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;Set-Cookie\u0026amp;#8221;\u0026lt;/span\u0026gt;).getValue(); Log.e(HttpService.\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getName(), \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;set_cookie=\u0026amp;#8221;\u0026lt;/span\u0026gt; + set_cookie); SharedPreferencesUtils sharePrefenrences = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SharedPreferencesUtils(); sharePrefenrences.saveCookie(context, set_cookie); } InputStream inputStream = httpEntity.getContent(); BufferedReader bufferReader = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BufferedReader( \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; InputStreamReader(inputStream), \u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;i\u0026lt;/span\u0026gt;); String returnStr = \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;; String readLine = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt; ((readLine = bufferReader.readLine()) != \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { returnStr = returnStr + readLine; } inputStream.close(); bufferReader.close(); Log.d(\u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;cat\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;returnStr=\u0026amp;#8221;\u0026lt;/span\u0026gt; + returnStr); \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; returnStr; } } } \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (ClientProtocolException e) { e.printStackTrace(); returnnull\u0026lt;span class=\u0026quot;s5\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; } \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) { e.printStackTrace(); returnnull\u0026lt;span class=\u0026quot;s5\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; } returnnull\u0026lt;span class=\u0026quot;s5\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt; } ","permalink":"https://blog.zdltech.com/posts/android-%E4%B8%8A%E7%9A%84-httpclient-%E7%9A%84-cookie-%E5%AD%98%E5%8F%96%E7%AD%96%E7%95%A5/","summary":"\u003cdiv class=\"line number1 index0 alt2\" style=\"color: #000000;\"\u003e\n  `BasicHttpParams params = ``new` `BasicHttpParams();`\n\u003c/div\u003e\n\u003cdiv class=\"line number2 index1 alt1\" style=\"color: #000000;\"\u003e\n  `// Set the timeout in milliseconds until a connection is established.  `\n\u003c/div\u003e\n\u003cdiv class=\"line number3 index2 alt2\" style=\"color: #000000;\"\u003e\n  `HttpConnectionParams.setConnectionTimeout(params, TIMEOUT_CONNECTION);`\n\u003c/div\u003e\n\u003cdiv class=\"line number4 index3 alt1\" style=\"color: #000000;\"\u003e\n  `// Set the default socket timeout (SO_TIMEOUT) `\n\u003c/div\u003e\n\u003cdiv class=\"line number5 index4 alt2\" style=\"color: #000000;\"\u003e\n  `// in milliseconds which is the timeout for waiting for data.  `\n\u003c/div\u003e\n\u003cdiv class=\"line number6 index5 alt1\" style=\"color: #000000;\"\u003e\n  `HttpConnectionParams.setSoTimeout(params, TIMEOUT_SOCKET);  `\n\u003c/div\u003e\n\u003cdiv class=\"line number7 index6 alt2\" style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"line number8 index7 alt1\" style=\"color: #000000;\"\u003e\n  `ConnManagerParams.setMaxTotalConnections(params, ``5``);`\n\u003c/div\u003e\n\u003cdiv class=\"line number9 index8 alt2\" style=\"color: #000000;\"\u003e\n  `ConnManagerParams.setTimeout(params, TIMEOUT_TOTAL);`\n\u003c/div\u003e\n\u003cdiv class=\"line number10 index9 alt1\" style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"line number11 index10 alt2\" style=\"color: #000000;\"\u003e\n  `client = ``new` `DefaultHttpClient(params);`\n\u003c/div\u003e\n\u003cdiv class=\"line number12 index11 alt1\" style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"line number13 index12 alt2\" style=\"color: #000000;\"\u003e\n  `CookieStore cookieStore = ``new` `BasicCookieStore();`\n\u003c/div\u003e\n\u003cdiv class=\"line number14 index13 alt1\" style=\"color: #000000;\"\u003e\n  `//Bind custom cookie store to the local context`\n\u003c/div\u003e\n\u003cdiv class=\"line number15 index14 alt2\" style=\"color: #000000;\"\u003e\n  `client.setCookieStore(cookieStore);`\n\u003c/div\u003e\n\u003cdiv class=\"line number16 index15 alt1\" style=\"color: #000000;\"\u003e\n  `CookieSpecFactory csf = ``new` `CookieSpecFactory() {           `\n\u003c/div\u003e\n\u003cdiv class=\"line number17 index16 alt2\" style=\"color: #000000;\"\u003e\n  `public` `CookieSpec newInstance(HttpParams params) {`\n\u003c/div\u003e\n\u003cdiv class=\"line number18 index17 alt1\" style=\"color: #000000;\"\u003e\n  `    ``return` `new` `BrowserCompatSpec() {`\n\u003c/div\u003e\n\u003cdiv class=\"line number19 index18 alt2\" style=\"color: #000000;\"\u003e\n  `    ``@Override`\n\u003c/div\u003e\n\u003cdiv class=\"line number20 index19 alt1\" style=\"color: #000000;\"\u003e\n  `    ``public` `void` `validate(Cookie cookie, CookieOrigin origin) ``throws` `MalformedCookieException `\n\u003c/div\u003e\n\u003cdiv class=\"line number21 index20 alt2\" style=\"color: #000000;\"\u003e\n  `    ``{`\n\u003c/div\u003e\n\u003cdiv class=\"line number22 index21 alt1\" style=\"color: #000000;\"\u003e\n  `        ``// Oh, I am easy`\n\u003c/div\u003e\n\u003cdiv class=\"line number23 index22 alt2\" style=\"color: #000000;\"\u003e\n  `        ``// allow all cookies`\n\u003c/div\u003e\n\u003cdiv class=\"line number24 index23 alt1\" style=\"color: #000000;\"\u003e\n  `        ``//log.debug(\"custom validate\");`\n\u003c/div\u003e\n\u003cdiv class=\"line number25 index24 alt2\" style=\"color: #000000;\"\u003e\n  `    ``}`\n\u003c/div\u003e\n\u003cdiv class=\"line number26 index25 alt1\" style=\"color: #000000;\"\u003e\n  `    ``};`\n\u003c/div\u003e\n\u003cdiv class=\"line number27 index26 alt2\" style=\"color: #000000;\"\u003e\n  `}`\n\u003c/div\u003e\n\u003cdiv class=\"line number28 index27 alt1\" style=\"color: #000000;\"\u003e\n  `};`\n\u003c/div\u003e\n\u003cdiv class=\"line number29 index28 alt2\" style=\"color: #000000;\"\u003e\n  `client.getCookieSpecs().register(``\"oschina\"``, csf);`\n\u003c/div\u003e\n\u003cdiv class=\"line number30 index29 alt1\" style=\"color: #000000;\"\u003e\n  `client.getParams().setParameter(ClientPNames.COOKIE_POLICY, ``\"oschina\"``);`\n\u003c/div\u003e\n\u003cdiv class=\"line number31 index30 alt2\" style=\"color: #000000;\"\u003e\n  `client.getParams().setParameter(CookieSpecPNames.SINGLE_COOKIE_HEADER, ``true``);`\n\u003c/div\u003e\n\u003cdiv class=\"line number31 index30 alt2\" style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"line number31 index30 alt2\" style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"line number31 index30 alt2\" style=\"color: #000000;\"\u003e\n  当然下面设置也可以，直接运行下就能看到结果。。\n\u003c/div\u003e\n\u003cdiv class=\"line number31 index30 alt2\" style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"line number31 index30 alt2\" style=\"color: #000000;\"\u003e\n\u003cpre\u003e\u003ccode\u003e/**\n\n\n\n\n\n* \u0026lt;span class=\u0026quot;s1\u0026quot;\u0026gt;@param\u0026lt;/span\u0026gt; url\n\n\n\n\n\n*            :交互服务器的URL地址\n\n\n\n\n\n* \u0026lt;span class=\u0026quot;s1\u0026quot;\u0026gt;@param\u0026lt;/span\u0026gt; pairs\n\n\n\n\n\n*            ：交互所带的参数\n\n\n\n\n\n* \u0026lt;span class=\u0026quot;s1\u0026quot;\u0026gt;@return\u0026lt;/span\u0026gt; JSONObject：从服务器获取的字符串\n\n\n\n\n\n*/\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String httpServicePostString(String url,\n\n\n\n\n\nList\u0026lt;BasicNameValuePair\u0026gt; pairs, Context context) {\n\n\n\n\n\nHttpPost httpPost = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HttpPost(url);\n\n\n\n\n\nDefaultHttpClient httpClient = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DefaultHttpClient();\n\n\n\n\n\nLog.d(\u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;cat\u0026amp;#8221;\u0026lt;/span\u0026gt;,\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;out response=\u0026amp;#8221;\u0026lt;/span\u0026gt; + httpPost.getURI() + \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8221;  \u0026amp;#8220;\u0026lt;/span\u0026gt; + pairs.toString());\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\n\n\n\n\nhttpPost.setEntity(\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; UrlEncodedFormEntity(pairs, HTTP.\u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;UTF_8\u0026lt;/span\u0026gt;));\n\n\n\n\n\n} \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (UnsupportedEncodingException e) {\n\n\n\n\n\ne.printStackTrace();\n\n\n\n\n\n}\n\n\n\n\n\nCookieStore cookieStore = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BasicCookieStore();\n\n\n\n\n\nhttpClient.setCookieStore(cookieStore);\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {\n\n\n\n\n\nHttpResponse response = httpClient.execute(httpPost);\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (response.getStatusLine().getStatusCode() == HttpStatus.\u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;SC_OK\u0026lt;/span\u0026gt;) {\n\n\n\n\n\nHttpEntity httpEntity = response.getEntity();\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (httpEntity != \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n\n\n\n\n\nCookieStore c = httpClient.getCookieStore();\n\n\n\n\n\nList\u0026lt;Cookie\u0026gt; list = c.getCookies();\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (Cookie cookie : list) {\n\n\n\n\n\nLog.e(HttpService.\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getName(),\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;cookie=\u0026amp;#8221;\u0026lt;/span\u0026gt; + cookie.getName());\n\n\n\n\n\nLog.e(HttpService.\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getName(),\n\n\n\n\n\n\n\n\n\n\nLog.e(HttpService.\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getName(),\n\n\n\n\n\n\n\n\n\n\nSharedPreferencesUtils sharePrefenrences = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SharedPreferencesUtils();\n\n\n\n\n\nsharePrefenrences.saveCookie(context, cookie.getValue());\n\n\n\n\n\n}\n\n\n\n\n\nHeader[] headers = response.getAllHeaders();\n\n\n\n\n\n\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (Header header : headers) {\n\n\n\n\n\n\n\n  Log.e(HttpService.\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getName(),\n\n\n\n\n\n  \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;head=\u0026amp;#8221;\u0026lt;/span\u0026gt; + header.getName());\n\n\n\n\n\n  }\n\n\n\n\n\n  \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (response.getFirstHeader(\u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;Set-Cookie\u0026amp;#8221;\u0026lt;/span\u0026gt;) != \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n\n\n\n\n\n  String set_cookie = response.getFirstHeader(\n\n\n\n\n\n  \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;Set-Cookie\u0026amp;#8221;\u0026lt;/span\u0026gt;).getValue();\n\n\n\n\n\n  Log.e(HttpService.\u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getName(), \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;set_cookie=\u0026amp;#8221;\u0026lt;/span\u0026gt;\n\n\n\n\n\n  + set_cookie);\n\n\n\n\n\n  SharedPreferencesUtils sharePrefenrences = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SharedPreferencesUtils();\n\n\n\n\n\n  sharePrefenrences.saveCookie(context, set_cookie);\n\n\n\n\n\n  }\n\n\n\n\n\n  InputStream inputStream = httpEntity.getContent();\n\n\n\n\n\n  BufferedReader bufferReader = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BufferedReader(\n\n\n\n\n\n  \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; InputStreamReader(inputStream), \u0026lt;span class=\u0026quot;s4\u0026quot;\u0026gt;i\u0026lt;/span\u0026gt;);\n\n\n\n\n\n  String returnStr = \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;;\n\n\n\n\n\n  String readLine = \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;\n\n\n\n\n\n  \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt; ((readLine = bufferReader.readLine()) != \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {\n\n\n\n\n\n  returnStr = returnStr + readLine;\n\n\n\n\n\n  }\n\n\n\n\n\n  inputStream.close();\n\n\n\n\n\n  bufferReader.close();\n\n\n\n\n\n  Log.d(\u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;cat\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;s3\u0026quot;\u0026gt;\u0026amp;#8220;returnStr=\u0026amp;#8221;\u0026lt;/span\u0026gt; + returnStr);\n\n\n\n\n\n  \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; returnStr;\n\n\n\n\n\n  }\n\n\n\n\n\n  }\n\n\n\n\n\n  } \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (ClientProtocolException e) {\n\n\n\n\n\n  e.printStackTrace();\n\n\n\n\n\n  returnnull\u0026lt;span class=\u0026quot;s5\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n  } \u0026lt;span class=\u0026quot;s2\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) {\n\n\n\n\n\n  e.printStackTrace();\n\n\n\n\n\n  returnnull\u0026lt;span class=\u0026quot;s5\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n  }\n\n\n\n\n\n  returnnull\u0026lt;span class=\u0026quot;s5\u0026quot;\u0026gt;;\u0026lt;/span\u0026gt;\n\n\n\n\n\n  }\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Android 上的 HttpClient 的 Cookie 存取策略"},{"content":" 线框图(Wireframe)是app、软件或者网站设计过程中非常重要的一个环节，它可以合理地组织并简化内容和元素。线框图除了可以帮助开发者 节省时间外，更可以加深开发者对产品的认知，给开发者一个清晰的产品构架，避免了开发者陷入层次不清、功能不明的产品设计和开发混乱状态。\n1、Proto.io\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122208_1.jpg) Proto.io是一个专用的手机原型开发平台——可以构建和部署全交互式的移动程序的原型，并且可以模拟出相似的成品。它可以运行在大多数的浏览器中，并提供了3个重要的接口：dashboard、编辑器以及播放器。\ndashboard可以用来管理项目。编辑器是构建原型的环境，由一组设计和开发原型的工具组成，另外还可以构建交互。播放器用来观看原型，并与原 型进行交互，并提供了相关工具来标注和保留反馈信息。你可以直接在真实的移动设备上对原型进行测试。并且可以使用iOS或Android上的浏览器以全屏 模式运行原型。\n2、Moqups\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122247_1.jpg) 是一个非常好的、免费的HTML5应用，通过它可以创建可爱朴素的线框图、实体模型和UI概念。该程序使用起来非常简单，并且有内置的模板可以直接使用（模板包括单选按钮、链接、图像占位符、文本框以及滑块等）。\n它还提供了iPhone和iPad模板，以及iOS相关的按钮、提示框、picker、菜单、开关以及键盘等。你可以设置网格的尺寸，并预览和分享你的线框图。Moqups提供了一个很有用的功能就是对齐网格，可以使对象精准对齐。\n3、UXPin\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122340_1.jpg) UXPin是DeSmart团队开发的一个简易快速的实体模型和在线可点击原型创作工具。它基于优秀的用户体验设计原则，在构建原型中，它提供了一个完整的工具包（该工具包具有良好的用户设计模式和元素）来从头构建一个出色的原型。\nUXPin具有响应式的断点功能，创建的响应式原型和线框图可以运行在不同的设备和分辨率上。另外该软件还提供了版本控制和迭代功能，可以轻松的共 享预览，直观的注解和实时的协同编辑和聊天。该软件拥有大量具有吸引力的用户界面元素风格（包括web，iOS，Android等），并且具有快速、灵敏 的响应拖放接口。\n4、Balsamiq Mockups ![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122443_1.jpg) Balsamiq Mockups是一款非常使用起来非常方便、非常高效的原型设计软件。\nBalsamiq Mockups目前包括75个界面控件和187个漂亮的icon，基本上自带了常用的小控件，UI控件支持自动拖拽，并且可以实现自动对齐。还有不少随即 可用的元素，简单拖拽就能形成效果图。 Mockups To Go library中还有适合Android、Blackberry以及iOS开发者的模版，Windows、Mac OS、Linux下都可以使用。可使用XML语言保存元素，也可以导出PNG图片，可以插入到任何项目。\nBalsamiq Mockups再现在白板上绘制草图的体验，共享原型进行测试有助于合作与反馈。整体采用了手绘风格，Balsamiq Mockups还提供了一个将图片转换成手绘风格的选项，保持了整体风格的一致。\n5、JustinMind\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122538_1.jpg) JustinMind是由西班牙JustinMind公司出品的原型制作工具，可以输出Html页面。与目前主流的交互设计工具axure，Balsamiq Mockups等相比，Justinmind Prototyper更为专属于设计移动终端上app应用。\nJustinMind可以帮助开发者设计更丰富、更具交互新的移动产品线框图，包含了iPhone、Android 以及iPad常用手势，滑动、缩放、旋转，甚至捕捉设备方向等，从而创造出更具交互性的原型。另外，它可以导出原型信息到Microsoft Word，生成规范的文档。\n此外，你还可以自定义小组件，创建自定义组件库，并进行分类，不管对象是iPhone、iPad、黑莓、Android还是其他。\n6、FluidUI\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122635_1.jpg) Fluid UI是一款用于移动开发的Web原型设计工具，可以帮助设计师高效地完成产品原型设计。Fluid UI 内置超过1700款的线框图和手机UI控件，并且还会经常进行更新。\nFluid UI无设备限制，无平台限制（Windows、Mac以及Linux系统），支持Chrome和Safari浏览器（Chrome浏览器上的app也可离 线使用）。你可以使用Fluid Player来预览你的设计，收集意见和反馈。还可以以PNG、PDF方式输出。\nFluid UI使用方法简单，采取拖拽的操作方式，不需要程序员来写代码。另外，Fluid UI资源库非常丰富，有针对iOS、Android以及Windows 8的资源。如果你觉得库存资源不能满足你的需求，你也可以自行添加。\n7、Axure ![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122811_1.jpg) **\n** 不多说了，很多人都在用这个交互原型设计软件。网上也有很多这方面的教程和文档。\n8、Mockflow\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122828_1.jpg) Mockflow是一款可以为网站和移动app快速高效制作线框图的工具，友好而强大，类似于Axure。内置了许多经常用到的控件和图标，比如按 钮、图片、下拉式菜单、进度条以及文字面板等等，能够有效帮助用户提高对传统软件以及富互联网应用软件的快速设计和交互式用户界面实体模型的规划进程。\nMockflow附带有大量跟线框图部件有关的资源库，提供了四个可选模版(iPhone app、Android app、iPad app以及Windows Phone) ，你也可以选择自己的布局和设计。你还可以通过MockStore下载更多元素和模版。\nMockflow支持协作和聊天功能，每个人可以在不同的页面看到项目的实时进展和变更。项目也可以以各种不同的形式输出，你也可以在移动设备或者台式电脑上查看和测试app的功能。\n9、Protoshare ![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408123001_1.jpg) ProtoShare：在线网站开发协同制作工具是一个十分便捷的在线原型制作工具，侧重于团队协作。团队成员可以通过这个工具对工作进行审查，并及时提供反馈，对线框图或内容进行建议。\n作为一个强大的线框图和原型平台，Protoshare提供了大量移动工具集（有来自中心资源库的大量移动模版和大量2D、3D动画过渡）。通过“拖放” 界面，你可以快速创建交互式的线框图和移动原型，然后发送至iPhone、iPad或者Android设备进行测试，体验app的功能实现情况。\n另外，Protoshare还支持分享和反馈功能，项目成员可以标记和跟踪的反馈信息来做出决定。而大量的资源库意味着你可以使用模版和获得的反馈创建移动产品线框图，进而演变为高保真的原型。\n10、 Wireframe ![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408123030_1.jpg) Wireframe是一款具有“点击-拖-放”界面且超简单的线框图创作工具。双击实现编辑功能，有限的界面意味着你会把精力集中于你的想法上。还给每个线框图分配了特有的URL，便于标记和分享。 Wireframe有浏览器窗口和移动手机两个模版选项，移动版有纵向和横向两个选择。线框图的每个元素都可以编辑和转换。 11、WireframeSketcher\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408123223_1.jpg) WireframeSketcher是一款强大的、灵活的线框图和原型快速创作工具，适用于桌面app和移动app开发者。WireframeSketcher可以作为单独的app，也可作为一个Eclipse 插件。\nWireframeSketcher还是一款简单的带有手绘风格的创作工具，这样你就不会被一些细节所打扰。它包含大量UI控件，可以进行灵活的自 定义设置。经过优化的界面、多个快捷方式、格点捕捉以及智能化引导都让WireframeSketcher成为快、高效的选择。Mockups Gallery 还储存了大量可供下载的插件、模版以及icon等。\n12、Omnigraffle\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408123358_1.jpg) OmniGraffle是由The Omni Group制作的一款带有大量模版可以用来快速绘制线框图、图表、流程图、组织结构图以及插图等类型图的app，也可以用来组织头脑中思考的信息，曾获得2002年的苹果设计奖。\n它采用拖放的所见即所得界面，你可以用钢笔工具绘制自定义的模版或者图形，此外还自带Graffletopia提供的多个iPhone、iPad以及Android模版。\n13、Pidoco\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408123438_1.jpg) Pidoco 是一款基于Web的原型设计软件，用于快速创建可点击的线框图。也可以用于制作网站项目、移动项目、企业应用程序的用户界面原型。拥有智能的共享和协同工作功能以及便捷的可用性测试模块，更易于使用。\n通过简单的拖放界面，你可以使用软件自带的移动UI元素来快速创建移动app原型，或者使用移动页面模版来节省更多时间。你可以选择”plain” 或者”sketched” 模式来展示你的线框图。\n14、FlairBuilder\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408123548_1.jpg) FlairBuilder是一款可以用来创建交互性线框图的快速原型工具，可以帮你把低保真度的草图升级为高保真度的线框图。 FlairBuilder内置数量超过70个的小部件或小元件，还带有大量模版。你可以简单快速地预览你的项目，并且输出功能齐备的HTML原型。线框图 以树状结构出现，FlairBuilder可以读取你的线框图，并产生一个易于查看的层级式网站地图。\nFlairBuilder带有iOS和Android模版，你可以以HTML形式输出原型，这样也易于在真机上进行测试。\n15、iPhone Mockup\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408123616_1.jpg) iPhone Mockup最大的特点是简单，可绘制简单线框图（illustration）和手绘风格线框图（pencil）两种风格的在线原型工具，你可以在两种风格之间自由切换。 iPhone Mockup支持协同创作和同步数据/操作，每个人都可以知道项目做了那些更改，只要他们有项目的URL，每个人都可以在线编辑。iPhone Mockup支持Firefox、Safari、Chrome以及Internet Explorer 8 浏览器。\n缺点是没有密码保护，且组件有限，但却是一个最基本且最简单的工具，可以上传图片和更改文本标签。\n16、HotGloo\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408123754_1.jpg) HotGloo是一款为传统软件以及富互联网应用软件制作产品原型的在线工具，友好而强大。内置了许许多多会经常使用到的控件和UI元素，鼠标拖拽 至画布，再组织绘制即可。能够有效的帮助用户提高对传统软件以及富互联网应用软件的快速设计和交互式用户界面实体模型的规划进程。\n最近，该软件新增了iPad和iPhone专用的模板套件，包括基本的界面元件，比如标签、icon、地图、按钮以及大量表视图。\nHotGloo轻量级但却非常强大的模版系统给人深刻印象，双击可编辑模版组件，还有助于强调app中响应式的交互设计。协作功能可以让团队多人参与到线框图制作过程中，你也可以邀请别人来参看或者给你一些反馈和意见。内置的聊天功能可以让成员实时讨论线框图的绘制情况。\n17、InVision\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408123851_1.jpg) InVision是一个便捷的产品原型生成工具，用户制作一个在线原型只需要四部：创建一个工程、上传视觉设计稿、添加链接以及生成在线原型。\n确切说，InVision提供的不是准确的线框图，而是一个快速原型的环境，可以把你的UX/UI草图快速连接起来。数字型的线框图和高保真的设计 可以帮你测试app的工作情况，同时该工具还支持协作和分享功能，生成的在线原型可以支持任何人在产品原型的任何地方评论，便于准确的交流。\n针对iOS 开发，InVision还增添了其他功能，比如自定义主屏幕icon和自定义加载页面。\n18、Mokk.me** **\n![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408123940_1.jpg) Mokk.me是一个简单快速的原型工具，通过界面上简单的拖放操作，不用了解单线编程就 能创作一个可以分享、测试以及多平台的app。目前，Mokk.me正在测试中，但它是一个简单的基本的工具，任何人可以用它来创建app的布局。你可 拖、放或者编辑小工具，可以搭建和连接页面，还可以选择过渡动画。它的特点还在于页面和按钮、图片小工具、文本输入以及复选框形式。 另外，你可以借助HTML、CSS以及JavaScript完成app其他一些功能，一旦你创建了原型，你还可以进行分享，在iOS 和Android上进行测试。\n19、iPlotz ![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408124015_1.jpg) iPlotz 是一款可以用来创建可点击、可导航的原型和线框图工具，适合网站开发者和移动app开发者。你可以在一个可调整的页面拖放元件，然后连接起来，增加其他屏 幕或者页面的热点链接。你可以选择使用iPhone/iPad模版或者Android模版，任何模版都有独一无二的元件设置。 iPlotz界面明白易懂，支持协同工作、可分享的编辑权限、任务管理以及评价系统。另外，项目可以以IPML、JPG、PNG、PDF以及HTML形式输出。 20、Pencil Project ![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408124055_1.jpg) Pencil是一款开源的可以用来制作图表和GUI原型的工具，可以作为一个独立的app，也可以作为Firefox插件。内置模版可以帮你绘制桌面和移动界面中用到的各种各样的用户界面，包括流程图、UI和一般的通用图形。\n通过它内置的模板，你可以创建可链接的文档，并输出成为HTML文件、PNG、OpenOffice文档、Word文档、PDF。Pencil Project还包含大量移动app模版\n转自：http://www.cocoachina.com/ios/20130408/5949.html\n","permalink":"https://blog.zdltech.com/posts/20%E6%AC%BE%E4%BC%98%E7%A7%80%E7%9A%84%E7%A7%BB%E5%8A%A8%E4%BA%A7%E5%93%81%E5%8E%9F%E5%9E%8B%E5%92%8C%E7%BA%BF%E6%A1%86%E5%9B%BE%E8%AE%BE%E8%AE%A1%E5%B7%A5%E5%85%B7/","summary":"\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e线框图(Wireframe)是app、软件或者网站设计过程中非常重要的一个环节，它可以合理地组织并简化内容和元素。线框图除了可以帮助开发者 节省时间外，更可以加深开发者对产品的认知，给开发者一个清晰的产品构架，避免了开发者陷入层次不清、功能不明的产品设计和开发混乱状态。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1、\u003c/strong\u003e\u003ca href=\"http://proto.io/\"\u003e\u003cstrong\u003e\u003cspan style=\"color: #0000ff;\"\u003eProto.io\u003c/span\u003e\u003c/strong\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122208_1.jpg)\n\u003c/div\u003e\n\u003cp\u003eProto.io是一个专用的手机原型开发平台——可以构建和部署全交互式的移动程序的原型，并且可以模拟出相似的成品。它可以运行在大多数的浏览器中，并提供了3个重要的接口：dashboard、编辑器以及播放器。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003edashboard可以用来管理项目。编辑器是构建原型的环境，由一组设计和开发原型的工具组成，另外还可以构建交互。播放器用来观看原型，并与原 型进行交互，并提供了相关工具来标注和保留反馈信息。你可以直接在真实的移动设备上对原型进行测试。并且可以使用iOS或Android上的浏览器以全屏 模式运行原型。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2、\u003ca href=\"https://moqups.com/\"\u003e\u003cspan style=\"color: #0000ff;\"\u003eMoqups\u003c/span\u003e\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122247_1.jpg)\n\u003c/div\u003e\n\u003cp\u003e是一个非常好的、免费的HTML5应用，通过它可以创建可爱朴素的线框图、实体模型和UI概念。该程序使用起来非常简单，并且有内置的模板可以直接使用（模板包括单选按钮、链接、图像占位符、文本框以及滑块等）。\u003cbr\u003e\n它还提供了iPhone和iPad模板，以及iOS相关的按钮、提示框、picker、菜单、开关以及键盘等。你可以设置网格的尺寸，并预览和分享你的线框图。Moqups提供了一个很有用的功能就是对齐网格，可以使对象精准对齐。\u003cbr\u003e\n\u003cstrong\u003e3、\u003ca href=\"http://uxpin.com/\"\u003e\u003cspan style=\"color: #0000ff;\"\u003eUXPin\u003c/span\u003e\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122340_1.jpg)\n\u003c/div\u003e\n\u003cp\u003eUXPin是DeSmart团队开发的一个简易快速的实体模型和在线可点击原型创作工具。它基于优秀的用户体验设计原则，在构建原型中，它提供了一个完整的工具包（该工具包具有良好的用户设计模式和元素）来从头构建一个出色的原型。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eUXPin具有响应式的断点功能，创建的响应式原型和线框图可以运行在不同的设备和分辨率上。另外该软件还提供了版本控制和迭代功能，可以轻松的共 享预览，直观的注解和实时的协同编辑和聊天。该软件拥有大量具有吸引力的用户界面元素风格（包括web，iOS，Android等），并且具有快速、灵敏 的响应拖放接口。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4、\u003ca href=\"http://www.balsamiq.com/\"\u003e\u003cspan style=\"color: #0000ff;\"\u003eBalsamiq Mockups  \u003c/span\u003e\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122443_1.jpg)\n\u003c/div\u003e\n\u003cp\u003eBalsamiq Mockups是一款非常使用起来非常方便、非常高效的原型设计软件。\u003cbr\u003e\nBalsamiq Mockups目前包括75个界面控件和187个漂亮的icon，基本上自带了常用的小控件，UI控件支持自动拖拽，并且可以实现自动对齐。还有不少随即 可用的元素，简单拖拽就能形成效果图。 Mockups To Go library中还有适合Android、Blackberry以及iOS开发者的模版，Windows、Mac OS、Linux下都可以使用。可使用XML语言保存元素，也可以导出PNG图片，可以插入到任何项目。\u003cbr\u003e\nBalsamiq Mockups再现在白板上绘制草图的体验，共享原型进行测试有助于合作与反馈。整体采用了手绘风格，Balsamiq Mockups还提供了一个将图片转换成手绘风格的选项，保持了整体风格的一致。\u003cbr\u003e\n\u003cstrong\u003e5、\u003ca href=\"http://www.justinmind.com/\"\u003e\u003cspan style=\"color: #0000ff;\"\u003eJustinMind\u003c/span\u003e\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122538_1.jpg)\n\u003c/div\u003e\n\u003cp\u003eJustinMind是由西班牙JustinMind公司出品的原型制作工具，可以输出Html页面。与目前主流的交互设计工具axure，Balsamiq Mockups等相比，Justinmind Prototyper更为专属于设计移动终端上app应用。\u003cbr\u003e\nJustinMind可以帮助开发者设计更丰富、更具交互新的移动产品线框图，包含了iPhone、Android 以及iPad常用手势，滑动、缩放、旋转，甚至捕捉设备方向等，从而创造出更具交互性的原型。另外，它可以导出原型信息到Microsoft Word，生成规范的文档。\u003cbr\u003e\n此外，你还可以自定义小组件，创建自定义组件库，并进行分类，不管对象是iPhone、iPad、黑莓、Android还是其他。\u003cbr\u003e\n\u003cstrong\u003e6、\u003ca href=\"http://www.fluidui.com/\"\u003e\u003cspan style=\"color: #0000ff;\"\u003eFluidUI\u003c/span\u003e\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122635_1.jpg)\n\u003c/div\u003e\n\u003cp\u003eFluid UI是一款用于移动开发的Web原型设计工具，可以帮助设计师高效地完成产品原型设计。Fluid UI 内置超过1700款的线框图和手机UI控件，并且还会经常进行更新。\u003cbr\u003e\nFluid UI无设备限制，无平台限制（Windows、Mac以及Linux系统），支持Chrome和Safari浏览器（Chrome浏览器上的app也可离 线使用）。你可以使用Fluid Player来预览你的设计，收集意见和反馈。还可以以PNG、PDF方式输出。\u003cbr\u003e\nFluid UI使用方法简单，采取拖拽的操作方式，不需要程序员来写代码。另外，Fluid UI资源库非常丰富，有针对iOS、Android以及Windows 8的资源。如果你觉得库存资源不能满足你的需求，你也可以自行添加。\u003cbr\u003e\n\u003cstrong\u003e7、\u003ca href=\"http://www.axure.com/\"\u003e\u003cspan style=\"color: #0000ff;\"\u003eAxure \u003c/span\u003e\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/130408/4196_130408122811_1.jpg)\n\u003c/div\u003e\n\u003cp\u003e**\u003cbr\u003e\n** 不多说了，很多人都在用这个交互原型设计软件。网上也有很多这方面的教程和文档。\u003c/p\u003e","title":"20款优秀的移动产品原型和线框图设计工具"},{"content":"Android中获得系统运行的进程、获得当前正在运行的service、 获得当前正在运行的activity、 获得最近运行的应用、获取手机内所有应用（非系统应用）\n直接上代码，布局文件就是一个TextView\n直接创建Activity后删除Activity中所有内容，复制下面代码直接就能运行\nprivate TextView txtDes = null;\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//竖屏\nsetRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);// 强制为横屏\nsuper.onCreate(savedInstanceState);\nsetContentView(R.layout.activity_main);\ntxtDes = (TextView) findViewById(R.id.textdes);\n}\n@Override\nprotected void onResume() {\nsuper.onResume();\nLog.w(“sss”, “onResume”);\nStringBuffer str = new StringBuffer();\nList listData = getAllApps(this);\nstr.append(“应用数量：” + listData.size());\nstr.append(“\\n”);\nfor (PackageInfo packageInfo : listData) {\nstr.append(“” + packageInfo.packageName);\nstr.append(“\\n”);\nstr.append(“”\npackageInfo.applicationInfo\n.loadLabel(getPackageManager()));\nstr.append(“\\n”);\nActivityInfo[] list;\ntry {\nlist = getPackageManager().getPackageInfo(\npackageInfo.packageName, PackageManager.GET_ACTIVITIES).activities;\nif (list != null) {\nstr.append(“Activity数量：” + list.length);\nstr.append(“\\n”);\nfor (ActivityInfo activityInfo : list) {\nstr.append(activityInfo.packageName);\nstr.append(“\\n”);\nstr.append(activityInfo.name);\nstr.append(“\\n”);\nstr.append(“activityInfo.screenOrientation=” activityInfo.screenOrientation);\nstr.append(“\\n”);\nstr.append(“activityInfo.configChanges=” activityInfo.configChanges);\nstr.append(“\\n”);\n}\n}\n} catch (NameNotFoundException e) {\n// TODO Auto-generated catch block\ne.printStackTrace();\n}\n}\ntxtDes.setText(str);\n} @Override\npublic void onConfigurationChanged(Configuration newConfig) {\n// TODO Auto-generated method stub\nsuper.onConfigurationChanged(newConfig);\nStringBuffer str = new StringBuffer();\nList listData = getAllApps(this);\nstr.append(“应用数量：” + listData.size());\nstr.append(“\\n”);\nfor (PackageInfo packageInfo : listData) {\nstr.append(“” + packageInfo.packageName);\nstr.append(“\\n”);\nstr.append(“”\npackageInfo.applicationInfo\n.loadLabel(getPackageManager()));\nstr.append(“\\n”);\nActivityInfo[] list;\ntry {\nlist = getPackageManager().getPackageInfo(\npackageInfo.packageName, PackageManager.GET_ACTIVITIES).activities;\nif (list != null) {\nstr.append(“Activity数量：” + list.length);\nstr.append(“\\n”);\nfor (ActivityInfo activityInfo : list) {\nstr.append(activityInfo.packageName);\nstr.append(“\\n”);\nstr.append(activityInfo.name);\nstr.append(“\\n”);\nstr.append(“activityInfo.screenOrientation=” activityInfo.screenOrientation);\nstr.append(“\\n”);\nstr.append(“activityInfo.configChanges=” activityInfo.configChanges);\nstr.append(“\\n”);\n}\n}\n} catch (NameNotFoundException e) {\n// TODO Auto-generated catch block\ne.printStackTrace();\n}\n}\ntxtDes.setText(str);\n} /**\n查询手机内非系统应用 @param context @return\n*/\npublic List getAllApps(Context context) {\nList apps = new ArrayList();\nPackageManager pManager = context.getPackageManager();\n// 获取手机内所有应用\nList paklist = pManager.getInstalledPackages(0);\nfor (int i = 0; i \u0026lt; paklist.size(); i++) {\nPackageInfo pak = (PackageInfo) paklist.get(i);\n// 判断是否为非系统预装的应用程序\nif ((pak.applicationInfo.flags \u0026amp; pak.applicationInfo.FLAG_SYSTEM) \u0026lt;= 0) {\n// customs applications\napps.add(pak);\n}\n}\nreturn apps;\n} private void getActivityManagerMM() {\nActivityManager mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);\n// 获得系统运行的进程\nList\u0026lt;ActivityManager.RunningAppProcessInfo\u0026gt; appList1 = mActivityManager\n.getRunningAppProcesses();\nfor (RunningAppProcessInfo running : appList1) {\nSystem.out.println(running.processName);\n}\nSystem.out.println(“================”);\n// 获得当前正在运行的service\nList\u0026lt;ActivityManager.RunningServiceInfo\u0026gt; appList2 = mActivityManager\n.getRunningServices(100);\nfor (ActivityManager.RunningServiceInfo running : appList2) {\nSystem.out.println(running.service.getClassName());\n}\nSystem.out.println(“================”);\n// 获得当前正在运行的activity\nList\u0026lt;ActivityManager.RunningTaskInfo\u0026gt; appList3 = mActivityManager\n.getRunningTasks(1000);\nfor (ActivityManager.RunningTaskInfo running : appList3) {\nSystem.out.println(running.baseActivity.getClassName());\n}\nSystem.out.println(“================”);\n// 获得最近运行的应用\nList\u0026lt;ActivityManager.RecentTaskInfo\u0026gt; appList4 = mActivityManager\n.getRecentTasks(100, 1);\nfor (ActivityManager.RecentTaskInfo running : appList4) {\nSystem.out.println(running.origActivity.getClassName());\n}\n}\n转自请注明转载地址：http://www.etongwl.com/?p=426 ","permalink":"https://blog.zdltech.com/posts/android%E8%8E%B7%E5%BE%97%E6%89%8B%E6%9C%BA%E6%89%80%E6%9C%89%E5%BA%94%E7%94%A8%E9%9D%9E%E7%B3%BB%E7%BB%9F%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%9A%84service%E5%92%8Cactivi/","summary":"\u003cp\u003eAndroid中获得系统运行的进程、获得当前正在运行的service、 获得当前正在运行的activity、 获得最近运行的应用、获取手机内所有应用（非系统应用）\u003c/p\u003e\n\u003cp\u003e直接上代码，布局文件就是一个TextView\u003c/p\u003e\n\u003cp\u003e直接创建Activity后删除Activity中所有内容，复制下面代码直接就能运行\u003c/p\u003e\n\u003cp\u003eprivate TextView txtDes = null;\u003c/p\u003e\n\u003cp\u003e@Override\u003cbr\u003e\nprotected void onCreate(Bundle savedInstanceState) {\u003cbr\u003e\n// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//竖屏\u003cbr\u003e\nsetRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);// 强制为横屏\u003cbr\u003e\nsuper.onCreate(savedInstanceState);\u003cbr\u003e\nsetContentView(R.layout.activity_main);\u003cbr\u003e\ntxtDes = (TextView) findViewById(R.id.textdes);\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e@Override\u003cbr\u003e\nprotected void onResume() {\u003cbr\u003e\nsuper.onResume();\u003cbr\u003e\nLog.w(“sss”, “onResume”);\u003cbr\u003e\nStringBuffer str = new StringBuffer();\u003cbr\u003e\nList\u003cPackageInfo\u003e listData = getAllApps(this);\u003cbr\u003e\nstr.append(“应用数量：” + listData.size());\u003cbr\u003e\nstr.append(“\\n”);\u003cbr\u003e\nfor (PackageInfo packageInfo : listData) {\u003cbr\u003e\nstr.append(“” + packageInfo.packageName);\u003cbr\u003e\nstr.append(“\\n”);\u003cbr\u003e\nstr.append(“”\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003epackageInfo.applicationInfo\u003cbr\u003e\n.loadLabel(getPackageManager()));\u003cbr\u003e\nstr.append(“\\n”);\u003cbr\u003e\nActivityInfo[] list;\u003cbr\u003e\ntry {\u003cbr\u003e\nlist = getPackageManager().getPackageInfo(\u003cbr\u003e\npackageInfo.packageName, PackageManager.GET_ACTIVITIES).activities;\u003cbr\u003e\nif (list != null) {\u003cbr\u003e\nstr.append(“Activity数量：” + list.length);\u003cbr\u003e\nstr.append(“\\n”);\u003cbr\u003e\nfor (ActivityInfo activityInfo : list) {\u003cbr\u003e\nstr.append(activityInfo.packageName);\u003cbr\u003e\nstr.append(“\\n”);\u003cbr\u003e\nstr.append(activityInfo.name);\u003cbr\u003e\nstr.append(“\\n”);\u003cbr\u003e\nstr.append(“activityInfo.screenOrientation=”\u003c/li\u003e\n\u003cli\u003eactivityInfo.screenOrientation);\u003cbr\u003e\nstr.append(“\\n”);\u003cbr\u003e\nstr.append(“activityInfo.configChanges=”\u003c/li\u003e\n\u003cli\u003eactivityInfo.configChanges);\u003cbr\u003e\nstr.append(“\\n”);\u003cbr\u003e\n}\u003cbr\u003e\n}\u003cbr\u003e\n} catch (NameNotFoundException e) {\u003cbr\u003e\n// TODO Auto-generated catch block\u003cbr\u003e\ne.printStackTrace();\u003cbr\u003e\n}\u003cbr\u003e\n}\u003cbr\u003e\ntxtDes.setText(str);\u003cbr\u003e\n}\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e@Override\u003cbr\u003e\npublic void onConfigurationChanged(Configuration newConfig) {\u003cbr\u003e\n// TODO Auto-generated method stub\u003cbr\u003e\nsuper.onConfigurationChanged(newConfig);\u003cbr\u003e\nStringBuffer str = new StringBuffer();\u003cbr\u003e\nList\u003cPackageInfo\u003e listData = getAllApps(this);\u003cbr\u003e\nstr.append(“应用数量：” + listData.size());\u003cbr\u003e\nstr.append(“\\n”);\u003cbr\u003e\nfor (PackageInfo packageInfo : listData) {\u003cbr\u003e\nstr.append(“” + packageInfo.packageName);\u003cbr\u003e\nstr.append(“\\n”);\u003cbr\u003e\nstr.append(“”\u003c/p\u003e","title":"Android获得手机所有应用（非系统）、正在运行的Service和Activity"},{"content":"HttpClient 与 HttpURLConnection 共用 SessionId\nHttpClient 与 HttpUrlConnection 是Android 中HTTP操作最常见的访问方式。在一个应用程序中有时候会用到这两种方式，如何能让他们共用Cookie，让客户端访问服务器保持Session进行通信。\n针对httpClient 和HttpUrlConnection 获取和发送Cookie，主要是sessionID的共享。\nhttpClient获取及发送Session 值：\n**[java]** [view plain](http://blog.csdn.net/jmq_0000/article/details/24921983#)[copy](http://blog.csdn.net/jmq_0000/article/details/24921983#)[print](http://blog.csdn.net/jmq_0000/article/details/24921983#)[?](http://blog.csdn.net/jmq_0000/article/details/24921983#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; HttpPost httpPost = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HttpPost(url); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #cccccc;\u0026quot;\u0026gt;// 将SessionId发给服务器\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; != mSESSIONID){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; httpPost.setHeader(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #ff9900;\u0026quot;\u0026gt;\u0026amp;#8220;Cookie\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #ff9900;\u0026quot;\u0026gt;\u0026amp;#8220;SESSIONID=\u0026amp;#8221;\u0026lt;/span\u0026gt; + mSESSIONID); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; DefaultHttpClient httpClient = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DefaultHttpClient(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; httpResponse = httpClient.execute(httpPost); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; HttpEntity entity = httpResponse.getEntity(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; CookieStore mCookieStore = httpClient.getCookieStore(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; List\u0026lt;Cookie\u0026gt; cookies = mCookieStore.getCookies(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #cccccc;\u0026quot;\u0026gt;//这里是读取指定Cookie 的值\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; cookies.size(); i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #ff9900;\u0026quot;\u0026gt;\u0026amp;#8220;SESSIONID\u0026amp;#8221;\u0026lt;/span\u0026gt;.equals(cookies.get(i).getName())) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; mSESSIONID = cookies.get(i).getValue(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 在程序中保存上面的sessionId ，或用全局变量，或者SharedPreferences 保存，看这个sessionId 的会话时间及程序业务。\n### HttpUrlConnection 获取及发送Session 值： **[java]** [view plain](http://blog.csdn.net/jmq_0000/article/details/24921983#)[copy](http://blog.csdn.net/jmq_0000/article/details/24921983#)[print](http://blog.csdn.net/jmq_0000/article/details/24921983#)[?](http://blog.csdn.net/jmq_0000/article/details/24921983#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;HttpURLConnection url_con = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;URL url = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; URL(reqUrl); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;url_con = (HttpURLConnection) url.openConnection(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #cccccc;\u0026quot;\u0026gt;//设置session\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mSESSIONID!= \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; url_con.setRequestProperty(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #ff9900;\u0026quot;\u0026gt;\u0026amp;#8220;Cookie\u0026amp;#8221;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #ff9900;\u0026quot;\u0026gt;\u0026amp;#8220;JSESSIONID=\u0026amp;#8221;\u0026lt;/span\u0026gt;+mSESSIONID); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;\u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;String cookieVal =con.getHeaderField(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #ff9900;\u0026quot;\u0026gt;\u0026amp;#8220;Set-Cookie\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #cccccc;\u0026quot;\u0026gt;// 获取session \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (cookieVal != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; StringmSESSIONID= cookieVal.substring(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, cookieVal.indexOf(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #ff9900;\u0026quot;\u0026gt;\u0026amp;#8220;;\u0026amp;#8221;\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;HttpURLConnection url_con = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; **HttpURLConnection和HttpClient比较（Android）:** HttpURLConnection和HttpClient 都支持HTTPS协议、IPv6、以流的形式进行上传和下载、配置超时时间、以及连接池等功能。 DefaultHttpClient和它的兄弟AndroidHttpClient都是HttpClient具体的实现类，它们都拥有众多的API，而且实现比较稳定，bug数量也很少。但同时也由于HttpClient的API数量过多，使得我们很难在不破坏兼容性的情况下对它进行升级和扩展，所以目前Android团队在提升和优化HttpClient方面的工作态度并不积极。 HttpURLConnection是一种多用途、轻量极的HTTP客户端，使用它来进行HTTP操作可以适用于大多数的应用程序。虽然HttpURLConnection的API提供的比较简单，但是同时这也使得我们可以更加容易地去使用和扩展它。不过在Android 2.2版本之前，HttpURLConnection一直存在着一些令人厌烦的bug。比如说对一个可读的InputStream调用close()方法时，就有可能会导致连接池失效了。那么我们通常的解决办法就是直接禁用掉连接池的功能： 在Android 2.3版本中还增加了一些HTTPS方面的改进，现在HttpsURLConnection会使用SNI(Server Name Indication)的方式进行连接，使得多个HTTPS主机可以共享同一个IP地址。除此之外，还增加了一些压缩和会话的机制。如果连接失败，它会自动去尝试重新进行连接。这使得HttpsURLConnection可以在不破坏老版本兼容性的前提下，更加高效地连接最新的服务器。 在Android 4.0版本中，我们又添加了一些响应的缓存机制。当缓存被安装后(调用HttpResponseCache的install()方法)，所有的HTTP请求都会满足以下三种情况： 1.所有的缓存响应都由本地存储来提供。因为没有必要去发起任务的网络连接请求，所有的响应都可以立刻获取到。 2.视情况而定的缓存响应必须要有服务器来进行更新检查。比如说客户端发起了一条类似于 “如果/foo.png这张图片发生了改变，就将它发送给我” 这样的请求，服务器需要将更新后的数据进行返回，或者返回一个304 Not Modified状态。如果请求的内容没有发生，客户端就不会下载任何数据。 3.没有缓存的响应都是由服务器直接提供的。这部分响应会在稍后存储到响应缓存中。\n由于这个功能是在4.0之后的版本才有的，通常我们就可以使用反射的方式来启动响应缓存功能。下面的示例代码展示了如何在Android 4.0及以后的版本中去启用响应缓存的功能，同时还不会影响到之前的版本： **[java]** [view plain](http://blog.csdn.net/jmq_0000/article/details/24921983#)[copy](http://blog.csdn.net/jmq_0000/article/details/24921983#)[print](http://blog.csdn.net/jmq_0000/article/details/24921983#)[?](http://blog.csdn.net/jmq_0000/article/details/24921983#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; enableHttpResponseCache() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; httpCacheSize = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt; * \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1024\u0026lt;/span\u0026gt; * \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1024\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #cccccc;\u0026quot;\u0026gt;// 10 MiB \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; File httpCacheDir = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; File(getCacheDir(), \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #ff9900;\u0026quot;\u0026gt;\u0026amp;#8220;http\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; Class.forName(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #ff9900;\u0026quot;\u0026gt;\u0026amp;#8220;android.net.http.HttpResponseCache\u0026amp;#8221;\u0026lt;/span\u0026gt;) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; .getMethod(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #ff9900;\u0026quot;\u0026gt;\u0026amp;#8220;install\u0026amp;#8221;\u0026lt;/span\u0026gt;, File.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt;.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; .invoke(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, httpCacheDir, httpCacheSize); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception httpResponseCacheNotAvailable) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; 你也应该同时配置一下你的Web服务器，在HTTP响应上加入缓存的消息头。 **哪一种才是最好的？** ** **在Android 2.2版本之前，HttpClient拥有较少的bug，因此使用它是最好的选择。 而在Android 2.3版本及以后，HttpURLConnection则是最佳的选择。它的API简单，体积较小，因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量，在提升速度和省电方面也起到了较大的作用。对于新的应用程序应该更加偏向于使用HttpURLConnection。 ","permalink":"https://blog.zdltech.com/posts/android-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B9%8B-httpclient-%E4%B8%8E-httpurlconnection-%E5%85%B1%E7%94%A8cookie/","summary":"\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #009900;\"\u003eHttpClient 与 HttpURLConnection 共用 SessionId\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e           HttpClient 与 HttpUrlConnection 是Android 中HTTP操作最常见的访问方式。在一个应用程序中有时候会用到这两种方式，如何能让他们共用Cookie，让客户端访问服务器保持Session进行通信。\u003c/p\u003e\n\u003cp\u003e针对httpClient 和HttpUrlConnection 获取和发送Cookie，主要是sessionID的共享。\u003c/p\u003e\n\u003cp\u003e        httpClient获取及发送Session 值：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\" style=\"color: #000000;\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/jmq_0000/article/details/24921983#)[copy](http://blog.csdn.net/jmq_0000/article/details/24921983#)[print](http://blog.csdn.net/jmq_0000/article/details/24921983#)[?](http://blog.csdn.net/jmq_0000/article/details/24921983#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;   \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;           \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;     HttpPost httpPost = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HttpPost(url);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;       \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;          \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #cccccc;\u0026quot;\u0026gt;// 将SessionId发给服务器\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;     \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; != mSESSIONID){  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;        httpPost.setHeader(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #ff9900;\u0026quot;\u0026gt;\u0026amp;#8220;Cookie\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #ff9900;\u0026quot;\u0026gt;\u0026amp;#8220;SESSIONID=\u0026amp;#8221;\u0026lt;/span\u0026gt; + mSESSIONID);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;    }   \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;     \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;     DefaultHttpClient httpClient = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DefaultHttpClient();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;     httpResponse = httpClient.execute(httpPost);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;             HttpEntity entity = httpResponse.getEntity();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;   \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;         CookieStore mCookieStore = httpClient.getCookieStore();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;        List\u0026lt;Cookie\u0026gt; cookies = mCookieStore.getCookies();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #cccccc;\u0026quot;\u0026gt;//这里是读取指定Cookie 的值\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; cookies.size(); i++) {   \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #ff9900;\u0026quot;\u0026gt;\u0026amp;#8220;SESSIONID\u0026amp;#8221;\u0026lt;/span\u0026gt;.equals(cookies.get(i).getName())) {   \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;               mSESSIONID = cookies.get(i).getValue();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;               \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #00cc00;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;        }   \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e在程序中保存上面的sessionId ，或用全局变量，或者SharedPreferences 保存，看这个sessionId 的会话时间及程序业务。\u003c/p\u003e","title":"Android 网络编程之—HttpClient 与 HttpURLConnection 共用cookie"},{"content":" \u0026lt;span class=\u0026quot;wp_keywordlink\u0026quot;\u0026gt;[jQuery](http://caibaojian.com/t/jquery)\u0026lt;/span\u0026gt; Mobile 是一个伟大的框架，而每个伟大的产品都需要一个好看的UI。很不幸，jQuery Mobile默认的主题不是一个现代化的设计。默认的\u0026lt;span class=\u0026quot;wp_keywordlink\u0026quot;\u0026gt;[CSS](http://caibaojian.com/t/css)\u0026lt;/span\u0026gt;文档有a,b,c,d和e五个主题，a主题是黑色的默认主题，每个主题都有各自的颜色。 下面分享一下互联网上比较好看的jQuery Mobile UI框架 1. Graphite - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;支持版本: \u0026lt;/span\u0026gt;jQuery Mobile 1.3.2 - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;链接和演示: \u0026lt;/span\u0026gt;[http://driftyco.github.io/graphite/](http://driftyco.github.io/graphite/) [![graphite-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/graphite-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/graphite-theme.jpg) 2. Flat UI theme 在 [\u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Flat-UI\u0026lt;/span\u0026gt;](http://designmodo.com/demo/flat-ui/).的基础上创建 - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;支持版本: \u0026lt;/span\u0026gt;jQuery Mobile 1.3.2 - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;官网: \u0026lt;/span\u0026gt;[https://github.com/ququplay/jquery-mobile-flat-ui-theme](https://github.com/ququplay/jquery-mobile-flat-ui-theme) - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;演示: \u0026lt;/span\u0026gt;[http://ququplay.github.io/jquery-mobile-flat-ui-theme/](http://ququplay.github.io/jquery-mobile-flat-ui-theme/) [![flatUI-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/flatUI-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/flatUI-theme.jpg) 3. nativeDroid - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;支持版本: \u0026lt;/span\u0026gt;jQuery Mobile 1.3.2 - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;链接和演示: \u0026lt;/span\u0026gt;[http://nativedroid.godesign.ch/](http://nativedroid.godesign.ch/) [![nativeDroid-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/nativeDroid-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/nativeDroid-theme.jpg) 4. iOs theme 在IOS的界面上创建 - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;支持版本: \u0026lt;/span\u0026gt;jQuery Mobile jQuery Mobile 1.2 - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;链接: \u0026lt;/span\u0026gt;[https://github.com/taitems/iOS-Inspired-jQuery-Mobile-Theme/](https://github.com/taitems/iOS-Inspired-jQuery-Mobile-Theme) - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;演示： \u0026lt;/span\u0026gt;[http://taitems.github.io/iOS-Inspired-jQuery-Mobile-Theme/](http://taitems.github.io/iOS-Inspired-jQuery-Mobile-Theme/) [![ios_theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/ios_theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/ios_theme.jpg) 5. Android Holo-inspired theme - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;支持版本: \u0026lt;/span\u0026gt;jQuery Mobile 1.3.2 - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;链接: \u0026lt;/span\u0026gt;[http://teusink.blogspot.com/2012/09/android-holo-theme-for-jquery-mobile-111.html](http://teusink.blogspot.com/2012/09/android-holo-theme-for-jquery-mobile-111.html) - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;链接: \u0026lt;/span\u0026gt;[https://github.com/enathu/jqmobile-android-holo-light-theme](https://github.com/enathu/jqmobile-android-holo-light-theme) - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;演示: \u0026lt;/span\u0026gt;[http://dl.dropboxusercontent.com/u/3875067/holo-light/index.html](http://dl.dropboxusercontent.com/u/3875067/holo-light/index.html) [![android-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/android-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/android-theme.jpg) 6. Bootstrap jQuery Mobile Theme 在Bootstrap的基础上创建，这个主题覆盖了jQuery默认的A-E的主题。 - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;支持版本: \u0026lt;/span\u0026gt;jQuery Mobile 1.2 (unofficially it should also work with a version 1.3.2) - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;链接: \u0026lt;/span\u0026gt;[https://github.com/commadelimited/jQuery-Mobile-Bootstrap-Theme](https://github.com/commadelimited/jQuery-Mobile-Bootstrap-Theme) - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;演示: \u0026lt;/span\u0026gt;[http://andymatthews.net/code/jQuery-Mobile-Bootstrap-Theme/buttons.html](http://andymatthews.net/code/jQuery-Mobile-Bootstrap-Theme/buttons.html) [![bootstrap-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/bootstrap-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/bootstrap-theme.jpg) 7. Metro Theme for WP 7.5 - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Supported version: \u0026lt;/span\u0026gt;jQuery Mobile 1.1 - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Link: \u0026lt;/span\u0026gt;[https://github.com/sgrebnov/jqmobile-metro-theme](https://github.com/sgrebnov/jqmobile-metro-theme) - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Demo: \u0026lt;/span\u0026gt;[http://sgrebnov.github.io/jqmobile-metro-theme/samples/jqm-public-demo/index.html](http://sgrebnov.github.io/jqmobile-metro-theme/samples/jqm-public-demo/index.html) [![jQM-Metro](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/jQM-Metro.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/jQM-Metro.jpg) 8. Square-UI Theme - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Supported version: \u0026lt;/span\u0026gt;jQuery Mobile 1.3.2 - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Link: \u0026lt;/span\u0026gt;[https://github.com/ququplay/jquery-mobile-square-ui-theme](https://github.com/ququplay/jquery-mobile-square-ui-theme) - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Demo: \u0026lt;/span\u0026gt;[http://ququplay.github.io/jquery-mobile-square-ui-theme/](http://ququplay.github.io/jquery-mobile-square-ui-theme/) [![squere-ui-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/squere-ui-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/squere-ui-theme.jpg) 9. jQMobile WordPress theme - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Supported version: \u0026lt;/span\u0026gt;jQuery Mobile 1.2 - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Link: \u0026lt;/span\u0026gt;[http://www.mobilizetoday.com/freebies/jqmobile](http://www.mobilizetoday.com/freebies/jqmobile) - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Demo: \u0026lt;/span\u0026gt;[http://www.mobilizetoday.com/preview/jqmobile/](http://www.mobilizetoday.com/preview/jqmobile/) [![wordpress-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/wordpress-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/wordpress-theme.jpg) 10. BlackBerry theme - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Supported version: \u0026lt;/span\u0026gt;jQuery Mobile 1.2 - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Link: \u0026lt;/span\u0026gt;[http://blackberry.github.io/jQueryMobile-BB10-Theme/#gettingStarted](http://blackberry.github.io/jQueryMobile-BB10-Theme/#gettingStarted) - \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Demo: \u0026lt;/span\u0026gt;[http://blackberry.github.io/jQueryMobile-BB10-Theme/kitchenSink/index.html](http://blackberry.github.io/jQueryMobile-BB10-Theme/kitchenSink/index.html) [![bb10-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/bb10-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/bb10-theme.jpg) 转自: [http://caibaojian.com/10-best-free-jquery-mobile-theme.html](http://caibaojian.com/10-best-free-jquery-mobile-theme.html) ","permalink":"https://blog.zdltech.com/posts/10%E4%B8%AA%E4%BC%98%E7%A7%80%E7%9A%84jquery-mobile%E4%B8%BB%E9%A2%98/","summary":"\u003cdiv class=\"entry-content\" style=\"color: #6b6b6b;\"\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span class=\u0026quot;wp_keywordlink\u0026quot;\u0026gt;[jQuery](http://caibaojian.com/t/jquery)\u0026lt;/span\u0026gt; Mobile 是一个伟大的框架，而每个伟大的产品都需要一个好看的UI。很不幸，jQuery Mobile默认的主题不是一个现代化的设计。默认的\u0026lt;span class=\u0026quot;wp_keywordlink\u0026quot;\u0026gt;[CSS](http://caibaojian.com/t/css)\u0026lt;/span\u0026gt;文档有a,b,c,d和e五个主题，a主题是黑色的默认主题，每个主题都有各自的颜色。\n\n\n\n\n\n下面分享一下互联网上比较好看的jQuery Mobile UI框架\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"1-graphite\"\u003e1. Graphite\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;支持版本: \u0026lt;/span\u0026gt;jQuery Mobile 1.3.2\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;链接和演示: \u0026lt;/span\u0026gt;[http://driftyco.github.io/graphite/](http://driftyco.github.io/graphite/)\n\n\n\n\n\n[![graphite-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/graphite-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/graphite-theme.jpg)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"2-flat-ui-theme\"\u003e2. Flat UI theme\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e在 [\u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Flat-UI\u0026lt;/span\u0026gt;](http://designmodo.com/demo/flat-ui/).的基础上创建\n\n\n\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;支持版本: \u0026lt;/span\u0026gt;jQuery Mobile 1.3.2\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;官网: \u0026lt;/span\u0026gt;[https://github.com/ququplay/jquery-mobile-flat-ui-theme](https://github.com/ququplay/jquery-mobile-flat-ui-theme)\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;演示: \u0026lt;/span\u0026gt;[http://ququplay.github.io/jquery-mobile-flat-ui-theme/](http://ququplay.github.io/jquery-mobile-flat-ui-theme/)\n\n\n\n\n\n[![flatUI-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/flatUI-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/flatUI-theme.jpg)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003ch2 id=\"3-nativedroid\"\u003e3. nativeDroid\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;支持版本: \u0026lt;/span\u0026gt;jQuery Mobile 1.3.2\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;链接和演示: \u0026lt;/span\u0026gt;[http://nativedroid.godesign.ch/](http://nativedroid.godesign.ch/)\n\n\n\n\n\n[![nativeDroid-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/nativeDroid-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/nativeDroid-theme.jpg)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003ch2 id=\"4-ios-theme\"\u003e4. iOs theme\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e在IOS的界面上创建\n\n\n\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;支持版本: \u0026lt;/span\u0026gt;jQuery Mobile jQuery Mobile 1.2\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;链接: \u0026lt;/span\u0026gt;[https://github.com/taitems/iOS-Inspired-jQuery-Mobile-Theme/](https://github.com/taitems/iOS-Inspired-jQuery-Mobile-Theme)\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;演示： \u0026lt;/span\u0026gt;[http://taitems.github.io/iOS-Inspired-jQuery-Mobile-Theme/](http://taitems.github.io/iOS-Inspired-jQuery-Mobile-Theme/)\n\n\n\n\n\n[![ios_theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/ios_theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/ios_theme.jpg)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003ch2 id=\"5-android-holo-inspired-theme\"\u003e5. Android Holo-inspired theme\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;支持版本: \u0026lt;/span\u0026gt;jQuery Mobile 1.3.2\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;链接: \u0026lt;/span\u0026gt;[http://teusink.blogspot.com/2012/09/android-holo-theme-for-jquery-mobile-111.html](http://teusink.blogspot.com/2012/09/android-holo-theme-for-jquery-mobile-111.html)\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;链接: \u0026lt;/span\u0026gt;[https://github.com/enathu/jqmobile-android-holo-light-theme](https://github.com/enathu/jqmobile-android-holo-light-theme)\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;演示: \u0026lt;/span\u0026gt;[http://dl.dropboxusercontent.com/u/3875067/holo-light/index.html](http://dl.dropboxusercontent.com/u/3875067/holo-light/index.html)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n     [![android-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/android-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/android-theme.jpg)\n  \u003c/div\u003e\n\u003ch2 id=\"6-bootstrap-jquery-mobile-theme\"\u003e6. Bootstrap jQuery Mobile Theme\u003c/h2\u003e\n  \u003cdiv\u003e\n     在Bootstrap的基础上创建，这个主题覆盖了jQuery默认的A-E的主题。\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;支持版本: \u0026lt;/span\u0026gt;jQuery Mobile 1.2 (unofficially it should also work with a version 1.3.2)\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;链接: \u0026lt;/span\u0026gt;[https://github.com/commadelimited/jQuery-Mobile-Bootstrap-Theme](https://github.com/commadelimited/jQuery-Mobile-Bootstrap-Theme)\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;演示: \u0026lt;/span\u0026gt;[http://andymatthews.net/code/jQuery-Mobile-Bootstrap-Theme/buttons.html](http://andymatthews.net/code/jQuery-Mobile-Bootstrap-Theme/buttons.html)\n\n\n\n\n\n[![bootstrap-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/bootstrap-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/bootstrap-theme.jpg)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"7-metro-theme-for-wp-75\"\u003e7. Metro Theme for WP 7.5\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Supported version: \u0026lt;/span\u0026gt;jQuery Mobile 1.1\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Link: \u0026lt;/span\u0026gt;[https://github.com/sgrebnov/jqmobile-metro-theme](https://github.com/sgrebnov/jqmobile-metro-theme)\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Demo: \u0026lt;/span\u0026gt;[http://sgrebnov.github.io/jqmobile-metro-theme/samples/jqm-public-demo/index.html](http://sgrebnov.github.io/jqmobile-metro-theme/samples/jqm-public-demo/index.html)\n\n\n\n\n\n[![jQM-Metro](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/jQM-Metro.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/jQM-Metro.jpg)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"8-square-ui-theme\"\u003e8. Square-UI Theme\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Supported version: \u0026lt;/span\u0026gt;jQuery Mobile 1.3.2\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Link: \u0026lt;/span\u0026gt;[https://github.com/ququplay/jquery-mobile-square-ui-theme](https://github.com/ququplay/jquery-mobile-square-ui-theme)\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Demo: \u0026lt;/span\u0026gt;[http://ququplay.github.io/jquery-mobile-square-ui-theme/](http://ququplay.github.io/jquery-mobile-square-ui-theme/)\n\n\n\n\n\n[![squere-ui-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/squere-ui-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/squere-ui-theme.jpg)\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003ch2 id=\"9-jqmobile-wordpress-theme\"\u003e9. jQMobile WordPress theme\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Supported version: \u0026lt;/span\u0026gt;jQuery Mobile 1.2\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Link: \u0026lt;/span\u0026gt;[http://www.mobilizetoday.com/freebies/jqmobile](http://www.mobilizetoday.com/freebies/jqmobile)\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Demo: \u0026lt;/span\u0026gt;[http://www.mobilizetoday.com/preview/jqmobile/](http://www.mobilizetoday.com/preview/jqmobile/)\n\n\n\n\n\n[![wordpress-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/wordpress-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/wordpress-theme.jpg)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"10-blackberry-theme\"\u003e10. BlackBerry theme\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Supported version: \u0026lt;/span\u0026gt;jQuery Mobile 1.2\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Link: \u0026lt;/span\u0026gt;[http://blackberry.github.io/jQueryMobile-BB10-Theme/#gettingStarted](http://blackberry.github.io/jQueryMobile-BB10-Theme/#gettingStarted)\n\n- \u0026lt;span style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;Demo: \u0026lt;/span\u0026gt;[http://blackberry.github.io/jQueryMobile-BB10-Theme/kitchenSink/index.html](http://blackberry.github.io/jQueryMobile-BB10-Theme/kitchenSink/index.html)\n\n\n\n\n\n[![bb10-theme](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/bb10-theme.jpg)](http://caibaojianimg.u.qiniudn.com/uploads/2014/04/bb10-theme.jpg)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\u003cfooter id=\"readOver\" class=\"entry-meta\" style=\"color: #6b6b6b;\"\u003e \n\u003cdiv class=\"alert alert-warning\" style=\"color: #8a6d3b;\"\u003e\n\u003cpre\u003e\u003ccode\u003e转自: [http://caibaojian.com/10-best-free-jquery-mobile-theme.html](http://caibaojian.com/10-best-free-jquery-mobile-theme.html)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\u003c/footer\u003e","title":"10个优秀的jQuery Mobile主题"},{"content":"1.Activity全透明\n同学zzm给了这个有趣的代码，现在公布出来。\n先在res/values下建colors.xml文件，写入：** **** **\n[?](http://www.oschina.net/question/54100_30266#) \u0026lt;table style=\u0026quot;font-weight: normal !important;\u0026quot; border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;color: #afafaf !important;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;? ``xml` `version` `= ``\u0026quot;1.0\u0026quot;` `encoding` `= ``\u0026quot;UTF-8\u0026quot;` `?\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `\u0026amp;lt;``resources``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``color` `name` `= ``\u0026quot;transparent\u0026quot;``\u0026amp;gt; #9000 \u0026amp;lt;/``color``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `\u0026amp;lt;/``resources``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 这个值设定了整个界面的透明度，为了看得见效果，现在设为透明度为56%(9/16)左右。\n再在res/values/下建styles.xml,设置程序的风格\n[?](http://www.oschina.net/question/54100_30266#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;color: #afafaf !important;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;?``xml` `version``=``\u0026quot;1.0\u0026quot;` `encoding``=``\u0026quot;utf-8\u0026quot;``?\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `\u0026amp;lt;``resources``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``style` `name``=``\u0026quot;Transparent\u0026quot;``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:windowBackground\u0026quot;``\u0026amp;gt;@color/transparent\u0026amp;lt;/``item``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:windowIsTranslucent\u0026quot;``\u0026amp;gt;true\u0026amp;lt;/``item``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:windowAnimationStyle\u0026quot;``\u0026amp;gt;@+android:style/Animation.Translucent\u0026amp;lt;/``item``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``style``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; `\u0026amp;lt;/``resources``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 最后一步，把这个styles.xml用在相应的Activity上。即在AndroidManifest.xml中的任意标签中添加 android:theme = “@style/transparent”\n如果想设置所有的activity都使用这个风格，可以把这句标签语句添加在中。\n最后运行程序，哈哈，是不是发现整个界面都被蒙上一层半透明了。最后可以把背景色#9000换成#0000，运行程序后，就全透明了，看得见背景下的所有东西可以却都操作无效。呵呵….\n2.Dialog全透明\n1.准备保留边框的全透明素材如下图：\n2.在values中新建一styles.xml文件，内容如下：\n[?](http://www.oschina.net/question/54100_30266#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;color: #afafaf !important;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;?``xml` `version``=``\u0026quot;1.0\u0026quot;` `encoding``=``\u0026quot;UTF-8\u0026quot;``?\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `\u0026amp;lt;``resources``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``style` `name``=``\u0026quot;TANCStyle\u0026quot;` `parent``=``\u0026quot;@android:style/Theme.Dialog\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;!-- 更换背景图片实现全透明 --\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:windowBackground\u0026quot;``\u0026amp;gt;@drawable/panel_background_sodino1\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;!-- 屏幕背景不变暗 --\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:backgroundDimEnabled\u0026quot;``\u0026amp;gt;false\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;!-- 更改对话框标题栏 --\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:windowTitleStyle\u0026quot;``\u0026amp;gt;@style/TitleStyle\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``style``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``style` `name``=``\u0026quot;TitleStyle\u0026quot;` `parent``=``\u0026quot;@android:style/DialogWindowTitle\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:textAppearance\u0026quot;``\u0026amp;gt;@style/TitleText\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``style``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``style` `name``=``\u0026quot;TitleText\u0026quot;` `parent``=``\u0026quot;@android:style/TextAppearance.DialogWindowTitle\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;!-- 设置Dialog标题栏文字颜色。 --\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``item` `name``=``\u0026quot;android:textColor\u0026quot;``\u0026amp;gt;#000\u0026amp;lt;/``item``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``style``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; `\u0026amp;lt;/``resources``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 3.在layout文件夹下新建一文件句为main_dialog.xml，内容如下：\n[?](http://www.oschina.net/question/54100_30266#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;color: #afafaf !important;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;?``xml` `version``=``\u0026quot;1.0\u0026quot;` `encoding``=``\u0026quot;UTF-8\u0026quot;``?\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `\u0026amp;lt;``RelativeLayout` `xmlns:android``=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``android:background``=``\u0026quot;#0000\u0026quot;``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``ScrollView` `android:id``=``\u0026quot;@+id/ScrollView01\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;200px\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:layout_below``=``\u0026quot;@+id/ImageView01\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``android:background``=``\u0026quot;#0000\u0026quot;``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``TextView` `android:id``=``\u0026quot;@+id/TextView01\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``android:text``=``\u0026quot;SodinoText\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``android:textColor``=``\u0026quot;#f000\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``android:background``=``\u0026quot;#0000\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``\u0026amp;gt;\u0026amp;lt;/``TextView``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``ScrollView``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``Button` `android:id``=``\u0026quot;@+id/btnCancel\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``android:layout_below``=``\u0026quot;@id/ScrollView01\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``android:layout_centerHorizontal``=``\u0026quot;true\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``android:text``=``\u0026quot;Cancel\u0026quot;``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``Button``\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; `\u0026amp;lt;/``RelativeLayout``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 4.Activity代码如下：\n[?](http://www.oschina.net/question/54100_30266#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;color: #afafaf !important;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `package` `lab.sodino.tanc; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `import` `android.app.Activity; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `import` `android.app.Dialog; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `import` `android.os.Bundle; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `import` `android.view.View; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `import` `android.widget.Button; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `import` `android.widget.TextView; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; `public` `class` `TANCAct ``extends` `Activity { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``/** Called when the activity is first created. */` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``public` `void` `onCreate(Bundle savedInstanceState) { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``super``.onCreate(savedInstanceState); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``setContentView(R.layout.main); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``Button btnShow = (Button) findViewById(R.id.btnShow); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``btnShow.setOnClickListener(``new` `Button.OnClickListener() { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``public` `void` `onClick(View view) { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``showTANC( ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``\u0026quot;This is my custom dialog box\u0026quot;``, ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``\u0026quot;TextContent/nWhen a dialog is requested for the first time, Android calls onCreateDialog(int) from your Activity, which is where you should instantiate the Dialog. This callback method is passed the same ID that you passed to showDialog(int). After you create the Dialog, return the object at the end of the method.\u0026quot;``, ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``\u0026quot;http://blog.csdn.net/sodino\u0026quot;``); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``}); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``private` `void` `showTANC(String header, String content, String url) { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``final` `Dialog dialog = ``new` `Dialog(``this``, R.style.TANCStyle); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``dialog.setContentView(R.layout.main_dialog); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``dialog.setTitle(header); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ``dialog.setCancelable(``true``); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``TextView textView01 = (TextView) dialog.findViewById(R.id.TextView01); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ``textView01.setText(content + content + content); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``Button btnCancel = (Button) dialog.findViewById(R.id.btnCancel); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ``btnCancel.setOnClickListener(``new` `Button.OnClickListener() { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ``public` `void` `onClick(View view) { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ``dialog.cancel(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; ` ``}); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; ` ``dialog.show(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 最后效果图：\n另附 android系统自带图标大全(1.5 1.6 2.1)\nhttp://since2006.com/android/1.5-drawables.php\n文章出处：\nhttp://blog.csdn.net/sodino/article/details/5822147\n","permalink":"https://blog.zdltech.com/posts/android%E6%9C%89%E8%B6%A3%E7%9A%84%E5%85%A8%E9%80%8F%E6%98%8E%E6%95%88%E6%9E%9C-activity%E5%8F%8Adialog%E7%9A%84%E5%85%A8%E9%80%8F%E6%98%8E%E9%99%84android%E7%B3%BB%E7%BB%9F%E8%87%AA%E5%B8%A6/","summary":"\u003cp\u003e\u003cstrong\u003e1.Activity全透明\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e同学zzm给了这个有趣的代码，现在公布出来。\u003c/p\u003e\n\u003cp\u003e先在res/values下建colors.xml文件，写入：** **** **\u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_914452\" class=\"syntaxhighlighter  xml\"\u003e\n    \u003cdiv class=\"toolbar\" style=\"font-weight: normal !important; color: white !important;\"\u003e\n      [?](http://www.oschina.net/question/54100_30266#)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;table style=\u0026quot;font-weight: normal !important;\u0026quot; border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n  \u0026lt;tr\u0026gt;\n    \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;color: #afafaf !important;\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n        1\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        2\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n        3\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n        4\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `\u0026amp;lt;? ``xml` `version` `= ``\u0026quot;1.0\u0026quot;` `encoding` `= ``\u0026quot;UTF-8\u0026quot;` `?\u0026amp;gt;    `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          `\u0026amp;lt;``resources``\u0026amp;gt;    `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `    ``\u0026amp;lt;``color`   `name` `= ``\u0026quot;transparent\u0026quot;``\u0026amp;gt; #9000 \u0026amp;lt;/``color``\u0026amp;gt;    `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          `\u0026amp;lt;/``resources``\u0026amp;gt;`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android有趣的全透明效果–Activity及Dialog的全透明(附android系统自带图标大全)"},{"content":"XMAPP Alias别名配置在windows上简单很，网上很多方法都可以实现，但是在 mac上面 一直都是403没有权限，这个问题困扰了1天，最后在同事（linux大神）的帮助下，终于解决了这个蛋疼的问题，让用Mac的小白们，也能方便的使用Mac开发PHP程序。废话不多说直接上步骤\nXAMPP官方下载地址：https://www.apachefriends.org/zh_cn/index.html\n操作步骤\n1.安装好Mac最新的XAMPP。\n2.配置etc/extra/httpd-xampp.conf\n修改成 把下面的local修改成 all granted\n\u0026lt;LocationMatch “^/(?i:(?:xampp|security|licenses|phpmyadmin|webalizer|server-status|server-info))”\u0026gt;\n#Require local\nRequire all granted\nErrorDocument 403 /error/XAMPP_FORBIDDEN.html.var\n3.配置etc/httpd.conf\n添加下面别名 由于tmp文件所有用户有权限范围，直接配置下面就可以访问tmp目录，但是其他的目录还是会受到权限问题。\nAlias /abcd/ “/tmp/aaa/”\n\u0026lt;Directory “/tmp/aaa/”\u0026gt;\nOptions Indexes MultiViews\nRequire all granted\nAlias /php “/Users/jason/Documents/php_workspace”\n\u0026lt;Directory “/Users/jason/Documents/php_workspace”\u0026gt;\nOptions Indexes MultiViews\nRequire all granted\n4.修改Apache的启动用户 通过命令 id jason找到jason的所在组，修改成下面对应的内容。\n也可以把/Users/jason/Documents/php_workspace这个目录赋值给默认用户访问权限（没有亲测）。\n#\n# If you wish httpd to run as a different user or group, you must run\n# httpd as root initially and it will switch.\n#\n# User/Group: The name (or #number) of the user/group to run httpd as.\n# It is usually good practice to create a dedicated user and group for\n# running httpd, as with most system services.\n#\nUser jason\nGroup staff\n5.测试ok\n终于可以安心睡好觉了……\n请注明转载地址：http://www.etongwl.com/?p=411\n我的CSDN地址：http://blog.csdn.net/zdl_411437734/article/details/41280969\n","permalink":"https://blog.zdltech.com/posts/mac-%E4%B8%8B%E9%9D%A2%E9%85%8D%E7%BD%AExmapp%E9%9B%86%E6%88%90%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83-alias%E5%88%AB%E5%90%8D%E6%96%B9%E6%B3%95/","summary":"\u003cp\u003eXMAPP Alias别名配置在windows上简单很，网上很多方法都可以实现，但是在 mac上面 一直都是403没有权限，这个问题困扰了1天，最后在同事（linux大神）的帮助下，终于解决了这个蛋疼的问题，让用Mac的小白们，也能方便的使用Mac开发PHP程序。废话不多说直接上步骤\u003c/p\u003e\n\u003cp\u003eXAMPP官方下载地址：https://www.apachefriends.org/zh_cn/index.html\u003c/p\u003e\n\u003cp\u003e操作步骤\u003c/p\u003e\n\u003cp\u003e1.安装好Mac最新的XAMPP。\u003c/p\u003e\n\u003cp\u003e2.配置etc/extra/httpd-xampp.conf\u003c/p\u003e\n\u003cp\u003e   修改成 把下面的local修改成 all granted\u003c/p\u003e\n\u003cp\u003e   \u0026lt;LocationMatch “^/(?i:(?:xampp|security|licenses|phpmyadmin|webalizer|server-status|server-info))”\u0026gt;\u003c/p\u003e\n\u003cp\u003e        #Require local\u003c/p\u003e\n\u003cp\u003eRequire all granted\u003c/p\u003e\n\u003cp\u003eErrorDocument 403 /error/XAMPP_FORBIDDEN.html.var\u003c/p\u003e\n  \u003c/LocationMatch\u003e\n\u003cp\u003e3.配置etc/httpd.conf\u003c/p\u003e\n\u003cp\u003e   添加下面别名  由于tmp文件所有用户有权限范围，直接配置下面就可以访问tmp目录，但是其他的目录还是会受到权限问题。\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s1\"\u003e   \u003c/span\u003e\u003cspan class=\"s2\"\u003eAlias /abcd/ “/tmp/aaa/”\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e\u0026lt;Directory “/tmp/aaa/”\u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e    Options Indexes MultiViews\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e    Require all granted\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e\u003c/Directory\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003eAlias /php “/Users/jason/Documents/php_workspace”\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e\u0026lt;Directory “/Users/jason/Documents/php_workspace”\u0026gt;\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e    Options Indexes MultiViews\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e    Require all granted\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e\u003c/Directory\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s3\"\u003e4.\u003c/span\u003e\u003cspan class=\"s2\"\u003e修改\u003c/span\u003e\u003cspan class=\"s3\"\u003eApache\u003c/span\u003e\u003cspan class=\"s2\"\u003e的启动用户 \u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e   通过命令 id jason找到jason的所在组，修改成下面对应的内容。\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s4\"\u003e   也可以把\u003c/span\u003e\u003cspan class=\"s2\"\u003e/Users/jason/Documents/php_workspace\u003c/span\u003e\u003cspan class=\"s4\"\u003e这个目录赋值给默认用户访问权限（没有亲测）。\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s4\"\u003e    \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u003cIfModule unixd_module\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e#\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"s2\"\u003e# If you wish httpd to run as a different user or group, you must run\u003c/span\u003e\u003c/p\u003e","title":"Mac 下面配置XMAPP集成开发环境  Alias别名方法"},{"content":"一个布局。。上面是一个自动播放的ViewPager，，下面是一个GridView。。 怎么实现ViewPager和GridView一起上下滑动，，而不是向上滑动时，，ViewPager会覆盖GridView。 重写gridview 和 ScrollView\npublic class MyGridView extends GridView {\npublic MyGridView(Context context, AttributeSet attrs) {\nsuper(context, attrs);\n}\npublic MyGridView(Context context) {\nsuper(context);\n}\npublic MyGridView(Context context, AttributeSet attrs, int defStyle) {\nsuper(context, attrs, defStyle);\n}\n@Override\npublic void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\nint expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE \u0026raquo; 2,\nMeasureSpec.AT_MOST);\nsuper.onMeasure(widthMeasureSpec, expandSpec);\n}\n}\n—————————————————————————————————–\npublic class MyScrollView extends ScrollView {\n// 滑动距离及坐标\nprivate float xDistance, yDistance, xLast, yLast;\npublic MyScrollView(Context context, AttributeSet attrs) {\nsuper(context, attrs);\n}\n@Override\npublic boolean onInterceptTouchEvent(MotionEvent ev) {\nswitch (ev.getAction()) {\ncase MotionEvent.ACTION_DOWN:\nxDistance = yDistance = 0f;\nxLast = ev.getX();\nyLast = ev.getY();\nbreak;\ncase MotionEvent.ACTION_MOVE:\nfinal float curX = ev.getX();\nfinal float curY = ev.getY();\nxDistance += Math.abs(curX – xLast);\nyDistance += Math.abs(curY – yLast);\nxLast = curX;\nyLast = curY;\nif(xDistance \u0026gt; yDistance){\nreturn false;\n}\n}\nreturn super.onInterceptTouchEvent(ev);\n}\n}\n","permalink":"https://blog.zdltech.com/posts/gridviewviewpage%E5%AE%9E%E7%8E%B0%E4%B8%80%E5%88%87%E4%B8%8A%E4%B8%8B%E6%BB%91%E5%8A%A8/","summary":"\u003ch3 id=\"questionTitle\"\u003e一个布局。。上面是一个自动播放的ViewPager，，下面是一个GridView。。\u003c/h3\u003e\n\u003ch3 id=\"怎么实现viewpager和gridview一起上下滑动而不是向上滑动时viewpager会覆盖gridview\"\u003e怎么实现ViewPager和GridView一起上下滑动，，而不是向上滑动时，，ViewPager会覆盖GridView。\u003c/h3\u003e\n\u003cp\u003e重写gridview  和  ScrollView\u003c/p\u003e\n\u003cp\u003epublic class MyGridView extends GridView {\u003c/p\u003e\n\u003cp\u003epublic MyGridView(Context context, AttributeSet attrs) {\u003cbr\u003e\nsuper(context, attrs);\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003epublic MyGridView(Context context) {\u003cbr\u003e\nsuper(context);\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003epublic MyGridView(Context context, AttributeSet attrs, int defStyle) {\u003cbr\u003e\nsuper(context, attrs, defStyle);\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e@Override\u003cbr\u003e\npublic void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\u003c/p\u003e\n\u003cp\u003eint expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE \u0026raquo; 2,\u003cbr\u003e\nMeasureSpec.AT_MOST);\u003cbr\u003e\nsuper.onMeasure(widthMeasureSpec, expandSpec);\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e}\u003cbr\u003e\n—————————————————————————————————–\u003c/p\u003e\n\u003cp\u003epublic class MyScrollView extends ScrollView {\u003c/p\u003e\n\u003cp\u003e// 滑动距离及坐标\u003cbr\u003e\nprivate float xDistance, yDistance, xLast, yLast;\u003c/p\u003e\n\u003cp\u003epublic MyScrollView(Context context, AttributeSet attrs) {\u003cbr\u003e\nsuper(context, attrs);\u003cbr\u003e\n}\u003c/p\u003e","title":"GridView+Viewpage实现一切上下滑动"},{"content":"Android也提供了封装有消息循环（Looper）的HandlerThread类，这种线程，可以绑定Handler()对象，并通过 Handler的sendMessage()函数向线程发送消息，通过handleMessage()函数，处理线程接收到的消息。这么说比较抽象，那 么，本文就利用基础的Java类库，实现一个带消息循环（Looper）的线程，以帮助初学者理解这样一个Looper到底是怎么工作的。\n1. 首先，我们完成一个简单的线程框架。\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `LooperThread {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``private` `volatile` `boolean` `mIsLooperQuit = ``false``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``private` `Thread mThread; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``public` `void` `start() { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``if``( mThread != ``null` `) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``return``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``mIsLooperQuit = ``false``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``mThread = ``new` `Thread(mLooperRunnable);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``mThread.start(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``public` `void` `stop() { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``if``( mThread == ``null` `) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``return``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``mIsLooperQuit = ``true``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``mThread = ``null``; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``protected` `Runnable mLooperRunnable = ``new` `Runnable() { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``public` `void` `run() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ``while``( !mIsLooperQuit ) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ``}; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 如上述代码所示，mLooperRunnable.run()循环执行线程任务，mIsLooperQuit则是线程退出循环的条件。下面，我们将添加消息的发送和处理代码。\n2. 添加线程循环的消息发送和处理代码\n** **\n（1） 定义消息结构体，创建消息队列\n** **\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `LooperThread {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``private` `Queue\u0026amp;lt;Message\u0026amp;gt; mMessageQueue = ``new` `LinkedList\u0026amp;lt;Message\u0026amp;gt;();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``public` `static` `class` `Message {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``int` `what;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; **（2） 创建互斥锁和条件变量\n**\n** **\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `LooperThread {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``private` `Lock mLock = ``new` `ReentrantLock();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``private` `Condition mCondition = mLock.newCondition(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; （3） 创建发送消息的函数\n** **\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `//发送消息，由外部其他模块调用，发送消息给线程` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `public` `void` `sendMessage( Message message ) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``if``( mThread == ``null` `) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``return``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``mLock.lock();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``mMessageQueue.add(message); ``//添加消息到消息队列` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``mCondition.signal(); ``//通知线程循环，有消息来了，请立即处理` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``mLock.unlock();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; （4） 创建处理消息的函数\n** **\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `//处理消息，由线程内部调用` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `public` `void` `handleMessage(Message message) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``//这里可以通过一个Callback来回调监听者` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; （5） 在mLooperRunnable.run()循环中解析消息\n** **\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `protected` `Runnable mLooperRunnable = ``new` `Runnable() { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``public` `void` `run() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``while``( !mIsLooperQuit ) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``mLock.lock();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``Message message = ``null``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``try` `{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``while``( !mIsLooperQuit \u0026amp;\u0026amp; mMessageQueue.isEmpty() ) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``mCondition.await(); ``//没有消息到来则休眠` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``message = mMessageQueue.poll(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``catch` `(InterruptedException e) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``e.printStackTrace(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``finally` `{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``mLock.unlock();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``handleMessage(message );` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``}; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; （6） 修改线程的Stop()函数，唤醒休眠的消息循环\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `void` `stop() { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``if``( mThread == ``null` `) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``return``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``mIsLooperQuit = ``true``; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``mLock.lock(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``mCondition.signal();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``mLock.unlock();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``mMessageQueue.clear();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``mThread = ``null``; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 到这里，一个基本的带有消息循环的线程类封装就完成了，相信大家应该从编写这段代码的过程中，理解了系统是如何实现消息循环的\n附近：LooperThread\n转自：http://ticktick.blog.51cto.com/823160/1565272\n","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5%E8%87%AA%E5%AE%9A%E4%B9%89%E5%B8%A6%E6%B6%88%E6%81%AF%E5%BE%AA%E7%8E%AFlooper%E7%9A%84%E5%B7%A5%E4%BD%9C%E7%BA%BF%E7%A8%8B/","summary":"\u003cp\u003eAndroid也提供了封装有消息循环（Looper）的HandlerThread类，这种线程，可以绑定Handler()对象，并通过 Handler的sendMessage()函数向线程发送消息，通过handleMessage()函数，处理线程接收到的消息。这么说比较抽象，那 么，本文就利用基础的Java类库，实现一个带消息循环（Looper）的线程，以帮助初学者理解这样一个Looper到底是怎么工作的。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. 首先，我们完成一个简单的线程框架。\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_151685\" class=\"syntaxhighlighter  java\"\u003e\n    \u003ctable border=\"0\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n      \u003ctr\u003e\n        \u003ctd class=\"gutter\"\u003e\n          \u003cdiv class=\"line number1 index0 alt2\"\u003e\n            1\n          \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        2\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n        3\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n        4\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n        5\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n        6\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n        7\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n        8\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n        9\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n        10\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n        11\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n        12\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n        13\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n        14\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n        15\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n        16\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n        17\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n        18\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n        19\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n        20\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n        21\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n        22\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n        23\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n        24\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n        25\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n        26\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n        27\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n        28\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n        29\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n        30\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n        31\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n        32\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n        33\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `public` `class` `LooperThread {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          `    `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `    ``private` `volatile` `boolean` `mIsLooperQuit = ``false``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          `        `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          `    ``private` `Thread mThread;      `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n          `    `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n          `    ``public` `void` `start() {        `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n          `        ``if``( mThread != ``null` `) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n          `            ``return``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n          `        ``}       `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n          `        ``mIsLooperQuit = ``false``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n          `        ``mThread = ``new` `Thread(mLooperRunnable);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n          `        ``mThread.start();        `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n          `    `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n          `    ``public` `void` `stop() {     `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n          `        ``if``( mThread == ``null` `) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n          `            ``return``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n          `        ``}       `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n          `        ``mIsLooperQuit = ``true``;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n          `        ``mThread = ``null``;   `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n          `    ``protected` `Runnable mLooperRunnable = ``new` `Runnable() {     `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt;\n          `        ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt;\n          `        ``public` `void` `run() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt;\n          `            ``while``( !mIsLooperQuit ) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt;\n          `            `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt;\n          `            ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt;\n          `    ``};      `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android开发实践：自定义带消息循环（Looper）的工作线程"},{"content":"1、Android团队提供的示例项目 如果不是从学习Android SDK中提供的那些样例代码开始，可能没有更好的方法来掌握在Android这个框架上开发。由Android的核心开发团队提供了15个优秀的示例项目，包含了游戏、图像处理、时间显示、开始菜单快捷方式等。 地址：http://www.apkbus.com/android-13506-1-1.html\n2、Remote Droid\nRemoteDroid是一个Android应用，能够让用户使用自己的无线网络使用无线键盘、触摸屏操作手机。这个项目为开发者提供了如网络连接、触摸屏手指运动等很好的样例。\n地址：http://www.apkbus.com/android-13507-1-1.html\n3、TorProxy和Shadow\nTorProxy应用实现了Android手机无线电电传通讯(TOR)，和Shadow应用一起使用，可以使用手机匿名上网。从该项目源代码中，可以掌握socket连接、管理cookie等方法。\n地址：http://www.apkbus.com/android-13510-1-1.html\n4、Android SMSPopup\nSMSPopup可以截获短信内容显示在一个泡泡形状的窗口中。从这个项目中可以掌握到如何使用内置的短信SMS接口。\n地址：http://www.apkbus.com/android-13513-1-1.html\n5、Standup Timer\nStandup Timer应用用于控制站立会议时间，类似秒表倒计时，可以提醒每个人的讲话时间已到，从而保证每个与会者使用时间一样。从该项目的代码中，可以学会如何使用时间函数。另外，这个项目的代码是采用视图view、模型model严格分离的设计思路。\n地址：http://www.apkbus.com/android-13514-1-1.html\n6、Foursquare\n是Foursquare.com的一个客户端应用，该应用主要分为两个模块：API(com.joelapenna.foursquare)和界面前端(com.joelapenna.foursquared)两部分。从该项目代码中，可以学会如何同步、多线程、HTTP连接等技术。\n地址：http://www.apkbus.com/android-13516-1-1.html\n7、Pedometer\nPedometer应用用于记录你每天走路步数的。尽管记录不一定精准，但是从这个项目中，可以学习几个不同的技术：加速器交互、语音更新、后台运行服务等。\n地址：http://www.apkbus.com/android-13515-1-1.html\n8、OpenSudoku-android\nOpenSudoku是一个简单的九宫格数独游戏。从代码中可以学习到如何在视图中显示表格数据，以及如何和一个网站交互等技术。\n地址：http://www.apkbus.com/android-13517-1-1.html\n9、ConnectBot\nConnectBot是Android平台的一个客户端安全壳应用。从该项目代码中，可以学习到很多Android安全方面的内容，这些是你在开发应用时经常需要考虑的安全问题。\n地址：http://www.apkbus.com/android-13518-1-1.html\n10、WordPress的Android应用\n当然在最后不能不提WordPress的Android应用了，这是WordPress官方开发团队提供的一个项目。从代码中可以学习到XMLRPC调用（当然还有更多的优秀内容）。\n地址：http://www.apkbus.com/android-13520-1-1.html\nAndroid PDF 阅读器\nhttp://sourceforge.net/projects/andpdf/files/\n个人记账工具 OnMyMeans\nhttp://sourceforge.net/projects/onmymeans/develop\nAndroid电池监控 Android Battery Dog [http://sourceforge.net/projects/andbatdog/](http://sourceforge.net/projects/andbatdog/) RSS阅读软件 Android RSS [http://code.google.com/p/android-rss/](http://code.google.com/p/android-rss/) Android的PDF阅读器 DroidReader [http://code.google.com/p/droidreader/](http://code.google.com/p/droidreader/) AndroidScripting Environment [http://code.google.com/p/android-scripting/](http://code.google.com/p/android-scripting/) Android小游戏 Android Shapes [http://sourceforge.net/projects/shapes/](http://sourceforge.net/projects/shapes/) AndroidJSON RPC [http://code.google.com/p/android-json-rpc/](http://code.google.com/p/android-json-rpc/) AndroidVNC [http://code.google.com/p/android-vnc/](http://code.google.com/p/android-vnc/) 魅族M8的Android移植 M8 Android [http://code.google.com/p/m8-android-kernel/](http://code.google.com/p/m8-android-kernel/) Android游戏 Amazed [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/) Android的社交网络 HelloWorld goes mobile [http://sourceforge.net/projects/helloworldgm/](http://sourceforge.net/projects/helloworldgm/) 手机聊天程序 Android jChat [http://code.google.com/p/jchat4android/](http://code.google.com/p/jchat4android/) Android的GPS轨迹记录 MyTracks [http://code.google.com/p/mytracks/](http://code.google.com/p/mytracks/) Android国际象棋游戏 Honzovy achy [http://sourceforge.net/projects/honzovysachy/](http://sourceforge.net/projects/honzovysachy/) Android旅行记录软件 AndTripLog [http://sourceforge.net/projects/andtriplog/](http://sourceforge.net/projects/andtriplog/) 音乐播放器 Ambient [http://sourceforge.net/projects/ambientmp/](http://sourceforge.net/projects/ambientmp/) Android的邮件客户端 K9mail [http://code.google.com/p/k9mail/](http://code.google.com/p/k9mail/) 多平台应用开发库 QuickConnect [http://sourceforge.net/projects/quickconnect/](http://sourceforge.net/projects/quickconnect/) gPhone手机空战游戏 [http://code.google.com/p/wireless-apps/](http://code.google.com/p/wireless-apps/) Android照片小软件 Panoramio [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/) i-jetty [http://code.google.com/p/i-jetty/](http://code.google.com/p/i-jetty/) Android小游戏 DivideAndConquer [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/) Android全球时间 AndroidGlobalTime [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/) Android2D游戏引擎 Android Angle [http://code.google.com/p/angle/](http://code.google.com/p/angle/) AndroidRuby [http://code.google.com/p/android-ruby/](http://code.google.com/p/android-ruby/) Android-N810 [http://sourceforge.net/projects/android-n810/](http://sourceforge.net/projects/android-n810/) Android的短信应用 Ecclesia [http://sourceforge.net/projects/ecclesia](http://sourceforge.net/projects/ecclesia) Android平台上的JXTA客户端 Peerdroid [http://code.google.com/p/peerdroid/](http://code.google.com/p/peerdroid/) Android游戏引擎 libgdx [http://code.google.com/p/libgdx/](http://code.google.com/p/libgdx/) Android照片小软件 Photostream [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/) Alien3dlogo Android 3D游戏引擎 Alien3d [http://code.google.com/p/alien3d/](http://code.google.com/p/alien3d/) WinampRemote Android Server [http://sourceforge.net/projects/winampdroid](http://sourceforge.net/projects/winampdroid) Android的Facebook客户端 Andrico [http://code.google.com/p/andrico/](http://code.google.com/p/andrico/) AndroidApplications Manager [http://sourceforge.net/projects/aam/](http://sourceforge.net/projects/aam/) Java3D图形引擎 Catcake [http://code.google.com/p/catcake/](http://code.google.com/p/catcake/) android-gcc-objc2-0 [http://code.google.com/p/android-gcc-objc2-0/](http://code.google.com/p/android-gcc-objc2-0/) 九宫格数独游戏 OpenSudoku [http://code.google.com/p/opensudoku-android/](http://code.google.com/p/opensudoku-android/) Android铃声扩展工具 RingsExtended [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/) JavaEyeAndroid client [http://code.google.com/p/javaeye-android-client/](http://code.google.com/p/javaeye-android-client/) RemoteDroid [http://code.google.com/p/remotedroid/](http://code.google.com/p/remotedroid/) Android小游戏 Clickin2DaBeat [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/) 中医大夫助理信息系统 zz-doctor [http://code.google.com/p/zz-doctor/](http://code.google.com/p/zz-doctor/) FacebookConnect for Android [http://code.google.com/p/fbconnect-android/](http://code.google.com/p/fbconnect-android/) AndroidSMSPopup [http://code.google.com/p/android-smspopup/](http://code.google.com/p/android-smspopup/) FreeTTS-Android [http://sourceforge.net/projects/freettsandroidi](http://sourceforge.net/projects/freettsandroidi) Foursquare.com的客户端 Foursquar [http://code.google.com/p/foursquared/](http://code.google.com/p/foursquared/) 条形码扫描仪 Android PC_BCR [http://code.google.com/p/android-pcbcr/](http://code.google.com/p/android-pcbcr/) android天气预报源码[http://www.apkbus.com/android-2240-1-1.html](http://www.apkbus.com/android-2240-1-1.html) android源码之电影购票源码[http://www.apkbus.com/android-2506-1-1.html](http://www.apkbus.com/android-2506-1-1.html) android的基站、WIFI、GPS定位集合，源码下载[。](http://www.apkbus.com/android-15281-1-1.html):[http://www.apkbus.com/android-15281-1-1.html](http://www.apkbus.com/android-15281-1-1.html) 一个100行代码写的android计算器:[http://www.apkbus.com/android-2231-1-1.html](http://www.apkbus.com/android-2231-1-1.html) Android卷曲翻页效果Demo:[http://www.apkbus.com/android-3738-1-2.html](http://www.apkbus.com/android-3738-1-2.html) android文件浏览器代码:[http://www.apkbus.com/android-2242-1-2.html](http://www.apkbus.com/android-2242-1-2.html) android源码超炫的3D特效程序管理功能:[http://www.apkbus.com/android-2046-1-2.html](http://www.apkbus.com/android-2046-1-2.html) Android手机平台重力感应Demo :[http://www.apkbus.com/android-45-1-2.html](http://www.apkbus.com/android-45-1-2.html) 一个android阅读器的源码[CoolReader](http://www.apkbus.com/android-2078-1-1.html):[http://www.apkbus.com/android-2078-1-2.html](http://www.apkbus.com/android-2078-1-2.html) 国外开源android音乐播放器[http://www.apkbus.com/android-2072-1-2.html](http://www.apkbus.com/android-2072-1-2.html) 一个综合了各个类型的对话框的demo :[http://www.apkbus.com/android-2086-1-2.html](http://www.apkbus.com/android-2086-1-2.html) 分享27个各种类型的demo：[http://www.apkbus.com/android-2083-1-2.html](http://www.apkbus.com/android-2083-1-2.html) android bluetooth [安卓](http://www.apkbus.com/)蓝牙源码下载：[http://www.apkbus.com/android-16841-1-2.html](http://www.apkbus.com/android-16841-1-2.html) android豆瓣手机客户端源码：[http://www.apkbus.com/android-1495-1-3.html](http://www.apkbus.com/android-1495-1-3.html) 转自：http://blog.csdn.net/cym492224103/article/details/38469251 ","permalink":"https://blog.zdltech.com/posts/ym-%E5%AE%89%E5%8D%93%E5%B7%B4%E5%A3%AB%E6%80%BB%E7%BB%93%E4%BA%86%E8%BF%91%E7%99%BE%E4%B8%AAandroid%E4%BC%98%E7%A7%80%E5%BC%80%E6%BA%90%E9%A1%B9/","summary":"\u003cp\u003e1、Android团队提供的示例项目\n如果不是从学习Android SDK中提供的那些样例代码开始，可能没有更好的方法来掌握在Android这个框架上开发。由Android的核心开发团队提供了15个优秀的示例项目，包含了游戏、图像处理、时间显示、开始菜单快捷方式等。\n地址：\u003ca href=\"http://www.apkbus.com/android-13506-1-1.html\"\u003ehttp://www.apkbus.com/android-13506-1-1.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e2、Remote Droid\u003cbr\u003e\nRemoteDroid是一个Android应用，能够让用户使用自己的无线网络使用无线键盘、触摸屏操作手机。这个项目为开发者提供了如网络连接、触摸屏手指运动等很好的样例。\u003cbr\u003e\n地址：\u003ca href=\"http://www.apkbus.com/android-13507-1-1.html\"\u003ehttp://www.apkbus.com/android-13507-1-1.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e3、TorProxy和Shadow\u003cbr\u003e\nTorProxy应用实现了Android手机无线电电传通讯(TOR)，和Shadow应用一起使用，可以使用手机匿名上网。从该项目源代码中，可以掌握socket连接、管理cookie等方法。\u003cbr\u003e\n地址：\u003ca href=\"http://www.apkbus.com/android-13510-1-1.html\"\u003ehttp://www.apkbus.com/android-13510-1-1.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e4、Android SMSPopup\u003cbr\u003e\nSMSPopup可以截获短信内容显示在一个泡泡形状的窗口中。从这个项目中可以掌握到如何使用内置的短信SMS接口。\u003cbr\u003e\n地址：\u003ca href=\"http://www.apkbus.com/android-13513-1-1.html\"\u003ehttp://www.apkbus.com/android-13513-1-1.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e5、Standup Timer\u003cbr\u003e\nStandup Timer应用用于控制站立会议时间，类似秒表倒计时，可以提醒每个人的讲话时间已到，从而保证每个与会者使用时间一样。从该项目的代码中，可以学会如何使用时间函数。另外，这个项目的代码是采用视图view、模型model严格分离的设计思路。\u003cbr\u003e\n地址：\u003ca href=\"http://www.apkbus.com/android-13514-1-1.html\"\u003ehttp://www.apkbus.com/android-13514-1-1.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e6、Foursquare\u003cbr\u003e\n是Foursquare.com的一个客户端应用，该应用主要分为两个模块：API(com.joelapenna.foursquare)和界面前端(com.joelapenna.foursquared)两部分。从该项目代码中，可以学会如何同步、多线程、HTTP连接等技术。\u003cbr\u003e\n地址：\u003ca href=\"http://www.apkbus.com/android-13516-1-1.html\"\u003ehttp://www.apkbus.com/android-13516-1-1.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e7、Pedometer\u003cbr\u003e\nPedometer应用用于记录你每天走路步数的。尽管记录不一定精准，但是从这个项目中，可以学习几个不同的技术：加速器交互、语音更新、后台运行服务等。\u003cbr\u003e\n地址：\u003ca href=\"http://www.apkbus.com/android-13515-1-1.html\"\u003ehttp://www.apkbus.com/android-13515-1-1.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e8、OpenSudoku-\u003ca href=\"http://www.apkbus.com/\"\u003eandroid\u003c/a\u003e\u003cbr\u003e\nOpenSudoku是一个简单的九宫格数独游戏。从代码中可以学习到如何在视图中显示表格数据，以及如何和一个网站交互等技术。\u003cbr\u003e\n地址：\u003ca href=\"http://www.apkbus.com/android-13517-1-1.html\"\u003ehttp://www.apkbus.com/android-13517-1-1.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e9、ConnectBot\u003cbr\u003e\nConnectBot是Android平台的一个客户端安全壳应用。从该项目代码中，可以学习到很多Android安全方面的内容，这些是你在开发应用时经常需要考虑的安全问题。\u003cbr\u003e\n地址：\u003ca href=\"http://www.apkbus.com/android-13518-1-1.html\"\u003ehttp://www.apkbus.com/android-13518-1-1.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e10、WordPress的Android应用\u003cbr\u003e\n当然在最后不能不提WordPress的Android应用了，这是WordPress官方开发团队提供的一个项目。从代码中可以学习到XMLRPC调用（当然还有更多的优秀内容）。\u003cbr\u003e\n地址：\u003ca href=\"http://www.apkbus.com/android-13520-1-1.html\"\u003ehttp://www.apkbus.com/android-13520-1-1.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAndroid PDF 阅读器\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://sourceforge.net/projects/andpdf/files/\"\u003ehttp://sourceforge.net/projects/andpdf/files/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e个人记账工具 OnMyMeans\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://sourceforge.net/projects/onmymeans/develop\"\u003ehttp://sourceforge.net/projects/onmymeans/develop\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eAndroid电池监控 Android Battery Dog\n\n\n\n\n\n[http://sourceforge.net/projects/andbatdog/](http://sourceforge.net/projects/andbatdog/)\n\n\n\n\n\n\n\n  RSS阅读软件 Android RSS\n\n\n\n\n\n  [http://code.google.com/p/android-rss/](http://code.google.com/p/android-rss/)\n\n\n\n\n\n  \n\n    Android的PDF阅读器 DroidReader\n  \n\n  \n  \n\n    [http://code.google.com/p/droidreader/](http://code.google.com/p/droidreader/)\n  \n\n  \n  \n\n    \n\n      AndroidScripting Environment\n    \n\n    \n    \n\n      [http://code.google.com/p/android-scripting/](http://code.google.com/p/android-scripting/)\n    \n\n    \n    \n\n      \n\n        Android小游戏 Android Shapes\n      \n\n      \n      \n\n        [http://sourceforge.net/projects/shapes/](http://sourceforge.net/projects/shapes/)\n      \n\n      \n      \n\n        \n\n          AndroidJSON RPC\n        \n\n        \n        \n\n          [http://code.google.com/p/android-json-rpc/](http://code.google.com/p/android-json-rpc/)\n        \n\n        \n        \n\n          \n\n            AndroidVNC\n          \n\n          \n          \n\n            [http://code.google.com/p/android-vnc/](http://code.google.com/p/android-vnc/)\n          \n\n          \n          \n\n            \n\n              魅族M8的Android移植 M8 Android\n            \n\n            \n            \n\n              [http://code.google.com/p/m8-android-kernel/](http://code.google.com/p/m8-android-kernel/)\n            \n\n            \n            \n\n              \n\n                Android游戏 Amazed\n              \n\n              \n              \n\n                [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/)\n              \n\n              \n              \n\n                \n\n                  Android的社交网络 HelloWorld goes mobile\n                \n\n                \n                \n\n                  [http://sourceforge.net/projects/helloworldgm/](http://sourceforge.net/projects/helloworldgm/)\n                \n\n                \n                \n\n                  \n\n                    手机聊天程序 Android jChat\n                  \n\n                  \n                  \n\n                    [http://code.google.com/p/jchat4android/](http://code.google.com/p/jchat4android/)\n                  \n\n                  \n                  \n\n                    \n\n                      Android的GPS轨迹记录 MyTracks\n                    \n\n                    \n                    \n\n                      [http://code.google.com/p/mytracks/](http://code.google.com/p/mytracks/)\n                    \n\n                    \n                    \n\n                      \n\n                        Android国际象棋游戏 Honzovy achy\n                      \n\n                      \n                      \n\n                        [http://sourceforge.net/projects/honzovysachy/](http://sourceforge.net/projects/honzovysachy/)\n                      \n\n                      \n                      \n\n                        \n\n                          Android旅行记录软件 AndTripLog\n                        \n\n                        \n                        \n\n                          [http://sourceforge.net/projects/andtriplog/](http://sourceforge.net/projects/andtriplog/)\n                        \n\n                        \n                        \n\n                          \n\n                            音乐播放器 Ambient\n                          \n\n                          \n                          \n\n                            [http://sourceforge.net/projects/ambientmp/](http://sourceforge.net/projects/ambientmp/)\n                          \n\n                          \n                          \n\n                            \n\n                              Android的邮件客户端 K9mail\n                            \n\n                            \n                            \n\n                              [http://code.google.com/p/k9mail/](http://code.google.com/p/k9mail/)\n                            \n\n                            \n                            \n\n                              \n\n                                多平台应用开发库 QuickConnect\n                              \n\n                              \n                              \n\n                                [http://sourceforge.net/projects/quickconnect/](http://sourceforge.net/projects/quickconnect/)\n                              \n\n                              \n                              \n\n                                \n\n                                  gPhone手机空战游戏\n                                \n\n                                \n                                \n\n                                  [http://code.google.com/p/wireless-apps/](http://code.google.com/p/wireless-apps/)\n                                \n\n                                \n                                \n\n                                  \n\n                                    Android照片小软件 Panoramio\n                                  \n\n                                  \n                                  \n\n                                    [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/)\n                                  \n\n                                  \n                                  \n\n                                    \n\n                                      i-jetty\n                                    \n\n                                    \n                                    \n\n                                      [http://code.google.com/p/i-jetty/](http://code.google.com/p/i-jetty/)\n                                    \n\n                                    \n                                    \n\n                                      \n\n                                        Android小游戏 DivideAndConquer\n                                      \n\n                                      \n                                      \n\n                                        [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/)\n                                      \n\n                                      \n                                      \n\n                                        \n\n                                          Android全球时间 AndroidGlobalTime\n                                        \n\n                                        \n                                        \n\n                                          [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/)\n                                        \n\n                                        \n                                        \n\n                                          \n\n                                            Android2D游戏引擎 Android Angle\n                                          \n\n                                          \n                                          \n\n                                            [http://code.google.com/p/angle/](http://code.google.com/p/angle/)\n                                          \n\n                                          \n                                          \n\n                                            \n\n                                              AndroidRuby\n                                            \n\n                                            \n                                            \n\n                                              [http://code.google.com/p/android-ruby/](http://code.google.com/p/android-ruby/)\n                                            \n\n                                            \n                                            \n\n                                              \n\n                                                Android-N810\n                                              \n\n                                              \n                                              \n\n                                                [http://sourceforge.net/projects/android-n810/](http://sourceforge.net/projects/android-n810/)\n                                              \n\n                                              \n                                              \n\n                                                \n\n                                                  Android的短信应用 Ecclesia\n                                                \n\n                                                \n                                                \n\n                                                  [http://sourceforge.net/projects/ecclesia](http://sourceforge.net/projects/ecclesia)\n                                                \n\n                                                \n                                                \n\n                                                  \n\n                                                    Android平台上的JXTA客户端 Peerdroid\n                                                  \n\n                                                  \n                                                  \n\n                                                    [http://code.google.com/p/peerdroid/](http://code.google.com/p/peerdroid/)\n                                                  \n\n                                                  \n                                                  \n\n                                                    \n\n                                                      Android游戏引擎 libgdx\n                                                    \n\n                                                    \n                                                    \n\n                                                      [http://code.google.com/p/libgdx/](http://code.google.com/p/libgdx/)\n                                                    \n\n                                                    \n                                                    \n\n                                                      \n\n                                                        Android照片小软件 Photostream\n                                                      \n\n                                                      \n                                                      \n\n                                                        [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/)\n                                                      \n\n                                                      \n                                                      \n\n                                                        \n\n                                                          Alien3dlogo Android 3D游戏引擎 Alien3d\n                                                        \n\n                                                        \n                                                        \n\n                                                          [http://code.google.com/p/alien3d/](http://code.google.com/p/alien3d/)\n                                                        \n\n                                                        \n                                                        \n\n                                                          \n\n                                                            WinampRemote Android Server\n                                                          \n\n                                                          \n                                                          \n\n                                                            [http://sourceforge.net/projects/winampdroid](http://sourceforge.net/projects/winampdroid)\n                                                          \n\n                                                          \n                                                          \n\n                                                            \n\n                                                              Android的Facebook客户端 Andrico\n                                                            \n\n                                                            \n                                                            \n\n                                                              [http://code.google.com/p/andrico/](http://code.google.com/p/andrico/)\n                                                            \n\n                                                            \n                                                            \n\n                                                              \n\n                                                                AndroidApplications Manager\n                                                              \n\n                                                              \n                                                              \n\n                                                                [http://sourceforge.net/projects/aam/](http://sourceforge.net/projects/aam/)\n                                                              \n\n                                                              \n                                                              \n\n                                                                \n\n                                                                  Java3D图形引擎 Catcake\n                                                                \n\n                                                                \n                                                                \n\n                                                                  [http://code.google.com/p/catcake/](http://code.google.com/p/catcake/)\n                                                                \n\n                                                                \n                                                                \n\n                                                                  \n\n                                                                    android-gcc-objc2-0\n                                                                  \n\n                                                                  \n                                                                  \n\n                                                                    [http://code.google.com/p/android-gcc-objc2-0/](http://code.google.com/p/android-gcc-objc2-0/)\n                                                                  \n\n                                                                  \n                                                                  \n\n                                                                    \n\n                                                                      九宫格数独游戏 OpenSudoku\n                                                                    \n\n                                                                    \n                                                                    \n\n                                                                      [http://code.google.com/p/opensudoku-android/](http://code.google.com/p/opensudoku-android/)\n                                                                    \n\n                                                                    \n                                                                    \n\n                                                                      \n\n                                                                        Android铃声扩展工具 RingsExtended\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                        [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/)\n                                                                      \n\n                                                                      \n                                                                      \n\n                                                                        \n\n                                                                          JavaEyeAndroid client\n                                                                        \n\n                                                                        \n                                                                        \n\n                                                                          [http://code.google.com/p/javaeye-android-client/](http://code.google.com/p/javaeye-android-client/)\n                                                                        \n\n                                                                        \n                                                                        \n\n                                                                          \n\n                                                                            RemoteDroid\n                                                                          \n\n                                                                          \n                                                                          \n\n                                                                            [http://code.google.com/p/remotedroid/](http://code.google.com/p/remotedroid/)\n                                                                          \n\n                                                                          \n                                                                          \n\n                                                                            \n\n                                                                              Android小游戏 Clickin2DaBeat\n                                                                            \n\n                                                                            \n                                                                            \n\n                                                                              [http://code.google.com/p/apps-for-android/](http://code.google.com/p/apps-for-android/)\n                                                                            \n\n                                                                            \n                                                                            \n\n                                                                              \n\n                                                                                中医大夫助理信息系统 zz-doctor\n                                                                              \n\n                                                                              \n                                                                              \n\n                                                                                [http://code.google.com/p/zz-doctor/](http://code.google.com/p/zz-doctor/)\n                                                                              \n\n                                                                              \n                                                                              \n\n                                                                                \n\n                                                                                  FacebookConnect for Android\n                                                                                \n\n                                                                                \n                                                                                \n\n                                                                                  [http://code.google.com/p/fbconnect-android/](http://code.google.com/p/fbconnect-android/)\n                                                                                \n\n                                                                                \n                                                                                \n\n                                                                                  \n\n                                                                                    AndroidSMSPopup\n                                                                                  \n\n                                                                                  \n                                                                                  \n\n                                                                                    [http://code.google.com/p/android-smspopup/](http://code.google.com/p/android-smspopup/)\n                                                                                  \n\n                                                                                  \n                                                                                  \n\n                                                                                    \n\n                                                                                      FreeTTS-Android\n                                                                                    \n\n                                                                                    \n                                                                                    \n\n                                                                                      [http://sourceforge.net/projects/freettsandroidi](http://sourceforge.net/projects/freettsandroidi)\n                                                                                    \n\n                                                                                    \n                                                                                    \n\n                                                                                      \n\n                                                                                        Foursquare.com的客户端 Foursquar\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        [http://code.google.com/p/foursquared/](http://code.google.com/p/foursquared/)\n                                                                                      \n\n                                                                                      \n                                                                                      \n\n                                                                                        \n\n                                                                                          条形码扫描仪 Android PC_BCR\n                                                                                        \n\n                                                                                        \n                                                                                        \n\n                                                                                          [http://code.google.com/p/android-pcbcr/](http://code.google.com/p/android-pcbcr/)\n                                                                                        \n\n                                                                                        \n                                                                                        \n\n                                                                                          \n\n                                                                                            android天气预报源码[http://www.apkbus.com/android-2240-1-1.html](http://www.apkbus.com/android-2240-1-1.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            android源码之电影购票源码[http://www.apkbus.com/android-2506-1-1.html](http://www.apkbus.com/android-2506-1-1.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            android的基站、WIFI、GPS定位集合，源码下载[。](http://www.apkbus.com/android-15281-1-1.html):[http://www.apkbus.com/android-15281-1-1.html](http://www.apkbus.com/android-15281-1-1.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            一个100行代码写的android计算器:[http://www.apkbus.com/android-2231-1-1.html](http://www.apkbus.com/android-2231-1-1.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            Android卷曲翻页效果Demo:[http://www.apkbus.com/android-3738-1-2.html](http://www.apkbus.com/android-3738-1-2.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            android文件浏览器代码:[http://www.apkbus.com/android-2242-1-2.html](http://www.apkbus.com/android-2242-1-2.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            android源码超炫的3D特效程序管理功能:[http://www.apkbus.com/android-2046-1-2.html](http://www.apkbus.com/android-2046-1-2.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            Android手机平台重力感应Demo :[http://www.apkbus.com/android-45-1-2.html](http://www.apkbus.com/android-45-1-2.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            一个android阅读器的源码[CoolReader](http://www.apkbus.com/android-2078-1-1.html):[http://www.apkbus.com/android-2078-1-2.html](http://www.apkbus.com/android-2078-1-2.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            国外开源android音乐播放器[http://www.apkbus.com/android-2072-1-2.html](http://www.apkbus.com/android-2072-1-2.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            一个综合了各个类型的对话框的demo :[http://www.apkbus.com/android-2086-1-2.html](http://www.apkbus.com/android-2086-1-2.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            分享27个各种类型的demo：[http://www.apkbus.com/android-2083-1-2.html](http://www.apkbus.com/android-2083-1-2.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            android bluetooth [安卓](http://www.apkbus.com/)蓝牙源码下载：[http://www.apkbus.com/android-16841-1-2.html](http://www.apkbus.com/android-16841-1-2.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            android豆瓣手机客户端源码：[http://www.apkbus.com/android-1495-1-3.html](http://www.apkbus.com/android-1495-1-3.html)\n                                                                                          \n\n                                                                                          \n                                                                                          \n\n                                                                                            \n\n                                                                                              转自：http://blog.csdn.net/cym492224103/article/details/38469251\n\u003c/code\u003e\u003c/pre\u003e","title":"ym——安卓巴士总结了近百个Android优秀开源项"},{"content":"对于一个自定义View来说，onMeasure只是用来计算View尺寸，onDraw()才是真正执行View的绘制，所以一般我们都需要重写 onDraw()函数来绘制我们期望的UI界面。下面我以一个具体的例子探索自定义View的onDraw()的实现过程和关键点。\n我们的目标是制作一个柱状图动画，View的动画启动后，会显示一排柱状图增长的画面，这种动画多用于财务类或者统计类的APP中，效果如图所示（截屏的格式转换过程导致有些变形，还好不影响演示，图中设置了反复播放，真机上只会播放一次）：\n1. 首先，自定义View的派生类\n** **\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `AnimatorView ``extends` `View {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``private` `Paint mPaint; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``public` `AnimatorView(Context context) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``super``(context); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``initialize();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``public` `AnimatorView(Context context, AttributeSet attrs) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``super``(context, attrs);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``initialize();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``public` `AnimatorView(Context context, AttributeSet attrs, ``int` `defStyle) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``super``(context, attrs, defStyle);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``initialize();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``protected` `void` `initialize() {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``mPaint = ``new` `Paint(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``mPaint.setAntiAlias(``true``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``mPaint.setStyle(Style.FILL); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 注： Paint是用来绘图的画笔，可以设置其样式、画面的粗细、填充模式、颜色等等。\n2. 定义待绘制的图形数据\n待绘制的图形数据一般是在程序中动态给出的，这里为了演示，直接定义好：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `AnimatorView ``extends` `View {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``private` `static` `final` `int` `RECT_WIDTH = ``60``; ``//每个矩形块的宽度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``private` `static` `final` `int` `RECT_DISTANCE = ``40``; ``//矩形块之间的间距` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``private` `static` `final` `int` `TOTAL_PAINT_TIMES = ``100``; ``//控制绘制速度,分100次完成绘制 ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``//待绘制的矩形块矩阵，left为高度，right为颜色` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``private` `static` `final` `int``[][] RECT_ARRAY = { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``{``380``,Color.GRAY},` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``{``600``,Color.YELLOW},` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``{``200``,Color.GREEN},` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``{``450``,Color.RED},` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``{``300``,Color.BLUE}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``}; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``private` `int` `mPaintTimes = ````; ``//当前已经绘制的次数` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 3. 重载onDraw()函数，实现绘制\n** **\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `AnimatorView ``extends` `View {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``protected` `void` `onDraw(Canvas canvas) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``mPaintTimes++;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``for``( ``int` `i=````; i\u0026amp;lt;RECT_ARRAY.length; i++ ) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``mPaint.setColor(RECT_ARRAY[i][``1``]);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``int` `paintXPos = i*(RECT_WIDTH+RECT_DISTANCE) + RECT_DISTANCE; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``int` `paintYPos = RECT_ARRAY[i][````]/TOTAL_PAINT_TIMES*mPaintTimes;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``canvas.drawRect(paintXPos, getHeight(), paintXPos+RECT_WIDTH,getHeight()-paintYPos, mPaint);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``if``( mPaintTimes \u0026amp;lt; TOTAL_PAINT_TIMES ) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``invalidate(); ``//实现动画的关键点 ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; （1） onDraw()函数一般由系统布局管理器来调用，在View第一次加载的时候会调用一次，或者在系统认为需要重绘的时候也会被调用。当然，你也可以在程 序中手动触发该View的重绘，通过调用View的invalidate()函数或者postInvalidate()函数即可，前者用于UI线程，后者 用于非UI线程。\n（2） onDraw()的参数Canvas我们可以理解成系统提供给我们的一块内存区域，所有的绘制都是在这块内存中进行的，绘制完成后系统会显示到屏幕中去。该Canvas对象提供了各种绘制点、线、矩形、圆、位图的方法，基本可以满足各种绘制要求。\n（3） drawRect函数需要提供四个坐标，其中，前两个参数代表是被绘制矩形的起始点坐标，后两个参数则是相对于起点的斜对角坐标，注意，原点坐标（0，0）在屏幕的左上角。\n（4） 注意，onDraw()每次被调用的时候，原来画布中的内容会被清空。\n（5） 本示例中，矩形高度每次增加Height/TOTAL_PAINT_TIMES，宽度不变。\n4. Activity中测试该View\n** **\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `MainActivity ``extends` `Activity {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``private` `AnimatorView mAnimatorView;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``protected` `void` `onCreate(Bundle savedInstanceState) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``super``.onCreate(savedInstanceState);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``mAnimatorView = ``new` `AnimatorView(``this``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``setContentView(mAnimatorView);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 当然，也可以把该View放到layout文件中，这里就不赘述了。\n** 5. 小结**\n自定义带动画的View就介绍到这里了，关键在于掌握onDraw()的重写和invalidate()的调用，完整的代码见文章最后的附件\n![](http://ticktick.blog.51cto.com/images/plusfile.gif)TestAnimatorView.zip 转自：http://ticktick.blog.51cto.com/823160/1545863 ","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5%E8%87%AA%E5%AE%9A%E4%B9%89%E5%B8%A6%E5%8A%A8%E7%94%BB%E7%9A%84view/","summary":"\u003cp\u003e对于一个自定义View来说，onMeasure只是用来计算View尺寸，onDraw()才是真正执行View的绘制，所以一般我们都需要重写 onDraw()函数来绘制我们期望的UI界面。下面我以一个具体的例子探索自定义View的onDraw()的实现过程和关键点。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e我们的目标是制作一个柱状图动画，View的动画启动后，会显示一排柱状图增长的画面，这种动画多用于财务类或者统计类的APP中，效果如图所示（\u003cspan style=\"color: #c00000;\"\u003e截屏的格式转换过程导致有些变形，还好不影响演示，图中设置了反复播放，真机上只会播放一次\u003c/span\u003e）：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://s3.51cto.com/wyfs02/M00/47/AD/wKioL1P9u5zxbwpDAAF_groDb8A132.gif\"\u003e\u003cimg alt=\"wKioL1P9u5zxbwpDAAF_groDb8A132.gif\" loading=\"lazy\" src=\"http://s3.51cto.com/wyfs02/M00/47/AD/wKioL1P9u5zxbwpDAAF_groDb8A132.gif\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. 首先，自定义View的派生类\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e** **\u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_670820\" class=\"syntaxhighlighter  java\"\u003e\n    \u003ctable border=\"0\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n      \u003ctr\u003e\n        \u003ctd class=\"gutter\"\u003e\n          \u003cdiv class=\"line number1 index0 alt2\"\u003e\n            1\n          \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        2\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n        3\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n        4\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n        5\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n        6\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n        7\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n        8\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n        9\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n        10\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n        11\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n        12\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n        13\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n        14\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n        15\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n        16\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n        17\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n        18\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n        19\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n        20\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n        21\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n        22\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n        23\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n        24\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n        25\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `public` `class` `AnimatorView ``extends` `View {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `    ``private` `Paint mPaint;   `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          `    `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          `    ``public` `AnimatorView(Context context) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n          `        ``super``(context); `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n          `        ``initialize();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n          `    ``public` `AnimatorView(Context context, AttributeSet attrs) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n          `        ``super``(context, attrs);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n          `        ``initialize();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n          `    `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n          `    ``public` `AnimatorView(Context context, AttributeSet attrs, ``int` `defStyle) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n          `        ``super``(context, attrs, defStyle);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n          `        ``initialize();`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n          `    `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n          `    ``protected` `void` `initialize() {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n          `        ``mPaint = ``new` `Paint(); `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n          `        ``mPaint.setAntiAlias(``true``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt;\n          `        ``mPaint.setStyle(Style.FILL);              `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt;\n          `    ``}   `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e注： Paint是用来绘图的画笔，可以设置其样式、画面的粗细、填充模式、颜色等等。\u003c/p\u003e","title":"Android开发实践：自定义带动画的View"},{"content":"Android开发中偶尔会用到自定义View，一般情况下，自定义View都需要继承View类的onMeasure方法，那么，为什么要继承 onMeasure()函数呢？什么情况下要继承onMeasure()？系统默认的onMeasure()函数行为是怎样的 ？本文就探究探究这些问题。\n首先，我们写一个自定义View，直接调用系统默认的onMeasure函数，看看会是怎样的现象：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `package` `com.titcktick.customview;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `import` `android.content.Context;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `import` `android.util.AttributeSet;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `import` `android.view.View;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `public` `class` `CustomView ``extends` `View {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``public` `CustomView(Context context) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``super``(context); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``public` `CustomView(Context context, AttributeSet attrs) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``super``(context, attrs); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``protected` `void` `onMeasure(``int` `widthMeasureSpec, ``int` `heightMeasureSpec) { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``super``.onMeasure(widthMeasureSpec, heightMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 1. 父控件使用match_parent，CustomView使用match_parent\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;LinearLayout xmlns:android=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``xmlns:tools=``\u0026quot;http://schemas.android.com/tools\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``android:orientation=``\u0026quot;vertical\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;com.titcktick.customview.CustomView` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``android:layout_margin=``\u0026quot;10dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``android:background=``\u0026quot;@android:color/black\u0026quot;``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; `\u0026amp;lt;/LinearLayout\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 这里加了10dp的margin并且把View的背景设置为了黑色，是为了方便辨别我们的CustomView，效果如下：\n我们可以看到，默认情况下，如果父控件和CustomView都使用match_parent，则CustomView会充满父控件。\n2. 父控件使用match_parent，CustomView使用wrap_content\n把layout文件中，CustomView的layout_width/layout_height替换为wrap_content，你会发现，结果依然是充满父控件。\n3. 父控件使用match_parent，CustomView使用固定的值\n把layout文件中，CustomView的layout_width/layout_height替换为50dp，你会发现，CustomView的显示结果为50dpx50dp，如图所示：\n4. 父控件使用固定的值，CustomView使用match_parent或者wrap_content\n那么，如果把父控件的layout_width/layout_height替换为50dp，CustomView设置为match_parent或者wrap_content，你会发现，CustomView的显示结果也是为50dpx50 dp。\n5 结论\n如果自定义的CustomView采用默认的onMeasure函数，行为如下：\n（1） CustomView设置为 match_parent 或者 wrap_content 没有任何区别，其显示大小由父控件决定，它会填充满整个父控件的空间。\n（2） CustomView设置为固定的值，则其显示大小为该设定的值。\n如果你的自定义控件的大小计算就是跟系统默认的行为一致的话，那么你就不需要重写onMeasure函数了。\n6. 怎样编写onMeasure函数\n系统默认的onMeasure函数的行为就讨论到这，下面也说说怎样重写onMeasure函数，以及onMeasure函数的基本原理，关键部分在代码中以注释的形式给出了，仅供参考：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; 51 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; 52 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; 53 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; 54 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `package` `com.titcktick.customview;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `import` `android.content.Context;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `import` `android.util.AttributeSet;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `import` `android.view.View;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `public` `class` `CustomView ``extends` `View {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``private` `static` `final` `int` `DEFAULT_VIEW_WIDTH = ``100``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``private` `static` `final` `int` `DEFAULT_VIEW_HEIGHT = ``100``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``public` `CustomView(Context context) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``super``(context); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``public` `CustomView(Context context, AttributeSet attrs) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``super``(context, attrs); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``protected` `void` `onMeasure(``int` `widthMeasureSpec, ``int` `heightMeasureSpec) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``int` `width = measureDimension(DEFAULT_VIEW_WIDTH, widthMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``int` `height = measureDimension(DEFAULT_VIEW_HEIGHT, heightMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``setMeasuredDimension(width, height); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``protected` `int` `measureDimension( ``int` `defaultSize, ``int` `measureSpec ) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``int` `result = defaultSize;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ``int` `specMode = MeasureSpec.getMode(measureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ``int` `specSize = MeasureSpec.getSize(measureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; ` ``//1. layout给出了确定的值，比如：100dp` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; ` ``//2. layout使用的是match_parent，但父控件的size已经可以确定了，比如设置的是具体的值或者match_parent` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; ` ``if` `(specMode == MeasureSpec.EXACTLY) { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; ` ``result = specSize; ``//建议：result直接使用确定值` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; ` ``//1. layout使用的是wrap_content` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; ` ``//2. layout使用的是match_parent,但父控件使用的是确定的值或者wrap_content` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; ` ``else` `if` `(specMode == MeasureSpec.AT_MOST) { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; ` ``result = Math.min(defaultSize, specSize); ``//建议：result不能大于specSize` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; ` ``//UNSPECIFIED,没有任何限制，所以可以设置任何大小` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; ` ``//多半出现在自定义的父控件的情况下，期望由自控件自行决定大小` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; ` ``else` `{ ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; ` ``result = defaultSize; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; ` ``return` `result;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 这样重载了onMeasure函数之后，你会发现，当CustomView使用match_parent的时候，它会占满整个父控件，而当CustomView使用wrap_content的时候，它的大小则是代码中定义的默认大小100×100像素。当然，你也可以根据自己的需求改写measureDimension()的实现。\n转自：http://ticktick.blog.51cto.com/823160/1540134\n","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E7%BB%A7%E6%89%BFonmeasure/","summary":"\u003cp\u003eAndroid开发中偶尔会用到自定义View，一般情况下，自定义View都需要继承View类的onMeasure方法，那么，为什么要继承 onMeasure()函数呢？什么情况下要继承onMeasure()？系统默认的onMeasure()函数行为是怎样的 ？本文就探究探究这些问题。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e首先，我们写一个自定义View，直接调用系统默认的onMeasure函数，看看会是怎样的现象：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_20695\" class=\"syntaxhighlighter  java\"\u003e\n    \u003ctable border=\"0\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n      \u003ctr\u003e\n        \u003ctd class=\"gutter\"\u003e\n          \u003cdiv class=\"line number1 index0 alt2\"\u003e\n            1\n          \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        2\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n        3\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n        4\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n        5\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n        6\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n        7\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n        8\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n        9\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n        10\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n        11\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n        12\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n        13\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n        14\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n        15\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n        16\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n        17\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n        18\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n        19\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n        20\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n        21\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n        22\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `package` `com.titcktick.customview;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `import` `android.content.Context;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          `import` `android.util.AttributeSet;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          `import` `android.view.View;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n          `public` `class` `CustomView ``extends` `View {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n          `    `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n          `    ``public` `CustomView(Context context) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n          `        ``super``(context); `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n          `    ``public` `CustomView(Context context, AttributeSet attrs) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n          `        ``super``(context, attrs);      `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n          `    `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n          `    ``@Override`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n          `    ``protected` `void` `onMeasure(``int` `widthMeasureSpec, ``int` `heightMeasureSpec) {        `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt;\n          `        ``super``.onMeasure(widthMeasureSpec, heightMeasureSpec);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android开发实践：为什么要继承onMeasure()"},{"content":"Android开发中，对于自定义View，分为两种，一种 是自定义控件（继承View类），另一种是自定义布局容器（继承ViewGroup）。如果是自定义控件，则一般需要重载两个方法，一个是 onMeasure()，用来测量控件尺寸，另一个是onDraw()，用来绘制控件的UI。而自定义布局容器，则一般需要实现/重载三个方法，一个是 onMeasure()，也是用来测量尺寸；一个是onLayout()，用来布局子控件；还有一个是dispatchDraw()，用来绘制UI。\n本文主要分析自定义ViewGroup的onLayout()方法的实现。\nViewGroup 类的onLayout()函数是abstract型，继承者必须实现，由于ViewGroup的定位就是一个容器，用来盛放子控件的，所以就必须定义要以 什么的方式来盛放，比如LinearLayout就是以横向或者纵向顺序存放，而RelativeLayout则以相对位置来摆放子控件，同样，我们的自 定义ViewGroup也必须给出我们期望的布局方式，而这个定义就通过onLayout()函数来实现。\n我们通过实现一个水平优先布局的视图容器来更加深入地了解onLayout()的实现吧，效果如图所示（黑色方块为子控件，白色部分为自定义布局容器）。该容器的布局方式是，首先水平方向上摆放子控件，水平方向放不下了，则另起一行继续水平摆放。\n** 1. 自定义ViewGroup的派生类**\n第一步，则是自定ViewGroup的派生类，继承默认的构造函数。\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `CustomViewGroup ``extends` `ViewGroup {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``public` `CustomViewGroup(Context context) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``super``(context); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``public` `CustomViewGroup(Context context, AttributeSet attrs) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``super``(context, attrs); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``public` `CustomViewGroup(Context context, AttributeSet attrs, intdefStyle) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``super``(context, attrs, defStyle);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; ** 2. 重载onMeasure()方法**\n为什么要重载onMeasure()方法这里就不赘述了，上一篇文章已经讲过，这里需要注意的是，自定义ViewGroup的onMeasure()方法中，除了计算自身的尺寸外，还需要调用measureChildren()函数来计算子控件的尺寸。\nonMeasure()的定义不是本文的讨论重点，因此这里我直接使用默认的onMeasure()定义，当然measureChildren()是必须得加的。\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `protected` `void` `onMeasure(``int` `widthMeasureSpec, ``int` `heightMeasureSpec) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``measureChildren(widthMeasureSpec, heightMeasureSpec);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``super``.onMeasure(widthMeasureSpec, heightMeasureSpec); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; ** 3. 实现onLayout()方法**\nonLayout()函数的原型如下：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `//@param changed 该参数指出当前ViewGroup的尺寸或者位置是否发生了改变` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `//@param left top right bottom 当前ViewGroup相对于其父控件的坐标位置` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `protected` `void` `onLayout(``boolean` `changed,``int` `left, ``int` `top, ``int` `right, ``int` `bottom);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 由于我们希望优先横向布局子控件，那么，首先，我们知道总宽度是多少，这个值可以通过getMeasuredWidth()来得到，当然子控件的宽度也可以通过子控件对象的getMeasuredWidth()来得到。\n这样，就不复杂了，具体的实现代码如下所示：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `protected` `void` `onLayout(``boolean` `changed, ``int` `left, ``int` `top, ``int` `right, ``int` `bottom) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``int` `mViewGroupWidth = getMeasuredWidth(); ``//当前ViewGroup的总宽度 ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``int` `mPainterPosX = left; ``//当前绘图光标横坐标位置` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``int` `mPainterPosY = top; ``//当前绘图光标纵坐标位置 ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``int` `childCount = getChildCount(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``for` `( ``int` `i = ````; i \u0026amp;lt; childCount; i++ ) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``View childView = getChildAt(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``int` `width = childView.getMeasuredWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``int` `height = childView.getMeasuredHeight(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``//如果剩余的空间不够，则移到下一行开始位置` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``if``( mPainterPosX + width \u0026amp;gt; mViewGroupWidth ) { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``mPainterPosX = left; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``mPainterPosY += height;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``//执行ChildView的绘制` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``childView.layout(mPainterPosX,mPainterPosY,mPainterPosX+width, mPainterPosY+height);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``//记录当前已经绘制到的横坐标位置 ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``mPainterPosX += width;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; ** 4. 布局文件测试**\n下面我们就尝试写一个简单的xml文件，来测试一下我们的自定义ViewGroup，我们把子View的背景颜色都设置为黑色，方便我们辨识。\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;com.titcktick.customview.CustomViewGroup xmlns:android=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``xmlns:tools=``\u0026quot;http://schemas.android.com/tools\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;match_parent\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;View` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;100dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;100dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:layout_margin=``\u0026quot;10dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``android:background=``\u0026quot;@android:color/black\u0026quot;``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;View` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;100dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;100dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``android:layout_margin=``\u0026quot;10dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``android:background=``\u0026quot;@android:color/black\u0026quot;``/\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;View` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;100dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;100dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``android:layout_margin=``\u0026quot;10dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``android:background=``\u0026quot;@android:color/black\u0026quot;``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;View` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;100dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;100dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``android:layout_margin=``\u0026quot;10dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ``android:background=``\u0026quot;@android:color/black\u0026quot;``/\u0026amp;gt; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; `\u0026amp;lt;/com.titcktick.customview.CustomViewGroup\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; ** 5. 添加layout_margin**\n为了让核心逻辑更加清晰，上面的onLayout()实现我隐去了margin的计算，这样就会导致子控件的layout_margin不起效果，所以上述效果是子控件一个个紧挨着排列，中间没有空隙。那么，下面我们来研究下如何添加margin效果。\n其实，如 果要自定义ViewGroup支持子控件的layout_margin参数，则自定义的ViewGroup类必须重载 generateLayoutParams()函数，并且在该函数中返回一个ViewGroup.MarginLayoutParams派生类对象，这样 才能使用margin参数。\nViewGroup.MarginLayoutParams的定义关键部分如下，它记录了子控件的layout_margin值：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `static` `class` `MarginLayoutParams ``extends` `ViewGroup.LayoutParams { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``public` `int` `leftMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``public` `int` `topMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``public` `int` `rightMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``public` `int` `bottomMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 你可以跟踪源码看看，其实XML文件中View的layout_xxx参数都是被传递到了各种自定义ViewGroup.LayoutParams派生类对象中。例如LinearLayout的LayoutParams定义的关键部分如下：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `LinearLayout ``extends` `ViewGroup {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `public` `static` `class` `LayoutParams ``extends` `ViewGroup.MarginLayoutParams {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``public` `float` `weight;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``public` `int` `gravity = -``1``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``public` `LayoutParams(Context c, AttributeSet attrs) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``super``(c, attrs);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``TypedArray a = c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, ````);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -``1``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``a.recycle();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``public` `LayoutParams generateLayoutParams(AttributeSet attrs) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``return` `new` `LinearLayout.LayoutParams(getContext(), attrs);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 这样你大概就可以理解为什么LinearLayout的子控件支持weight和gravity的设置了吧，当然我们也可以这样自定义一些属于我们 ViewGroup特有的params，这里就不详细讨论了，我们只继承MarginLayoutParams来获取子控件的margin值。\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `public` `class` `CustomViewGroup ``extends` `ViewGroup {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``public` `static` `class` `LayoutParams ``extends` `ViewGroup.MarginLayoutParams {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``public` `LayoutParams(Context c, AttributeSet attrs) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``super``(c, attrs); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``public` `LayoutParams generateLayoutParams(AttributeSet attrs) { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``return` `new` `CustomViewGroup.LayoutParams(getContext(), attrs); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 这样修改之后，我们就可以在onLayout()函数中获取子控件的layout_margin值了，添加了layout_margin的onLayout()函数实现如下所示：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; `protected` `void` `onLayout(``boolean` `changed, ``int` `left, ``int` `top, ``int` `right, ``int` `bottom) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``int` `mViewGroupWidth = getMeasuredWidth(); ``//当前ViewGroup的总宽度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``int` `mViewGroupHeight = getMeasuredHeight(); ``//当前ViewGroup的总高度` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``int` `mPainterPosX = left; ``//当前绘图光标横坐标位置` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``int` `mPainterPosY = top; ``//当前绘图光标纵坐标位置 ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``int` `childCount = getChildCount(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``for` `( ``int` `i = ````; i \u0026amp;lt; childCount; i++ ) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``View childView = getChildAt(i);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``int` `width = childView.getMeasuredWidth();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``int` `height = childView.getMeasuredHeight(); ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``CustomViewGroup.LayoutParams margins = (CustomViewGroup.LayoutParams)(childView.getLayoutParams());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; ` ``//ChildView占用的width = width+leftMargin+rightMargin` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``//ChildView占用的height = height+topMargin+bottomMargin` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``//如果剩余的空间不够，则移到下一行开始位置` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``if``( mPainterPosX + width + margins.leftMargin + margins.rightMargin \u0026amp;gt; mViewGroupWidth ) { ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``mPainterPosX = left; ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``mPainterPosY += height + margins.topMargin + margins.bottomMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ``//执行ChildView的绘制` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``childView.layout(mPainterPosX+margins.leftMargin, mPainterPosY+margins.topMargin,mPainterPosX+margins.leftMargin+width, mPainterPosY+margins.topMargin+height);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``mPainterPosX += width + margins.leftMargin + margins.rightMargin;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ``} ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; 转自：http://ticktick.blog.51cto.com/823160/1542200\n","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5%E8%87%AA%E5%AE%9A%E4%B9%89viewgroup%E7%9A%84onlayout%E5%88%86%E6%9E%90/","summary":"\u003cp\u003eAndroid开发中，对于自定义View，分为两种，一种 是自定义控件（继承View类），另一种是自定义布局容器（继承ViewGroup）。如果是自定义控件，则一般需要重载两个方法，一个是 onMeasure()，用来测量控件尺寸，另一个是onDraw()，用来绘制控件的UI。而自定义布局容器，则一般需要实现/重载三个方法，一个是 onMeasure()，也是用来测量尺寸；一个是onLayout()，用来布局子控件；还有一个是dispatchDraw()，用来绘制UI。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e本文主要分析自定义ViewGroup的onLayout()方法的实现。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eViewGroup 类的onLayout()函数是abstract型，继承者必须实现，由于ViewGroup的定位就是一个容器，用来盛放子控件的，所以就必须定义要以 什么的方式来盛放，比如LinearLayout就是以横向或者纵向顺序存放，而RelativeLayout则以相对位置来摆放子控件，同样，我们的自 定义ViewGroup也必须给出我们期望的布局方式，而这个定义就通过onLayout()函数来实现。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e我们通过实现一个水平优先布局的视图容器来更加深入地了解onLayout()的实现吧，效果如图所示（黑色方块为子控件，白色部分为自定义布局容器）。\u003cspan style=\"color: #c00000;\"\u003e该容器的布局方式是，首先水平方向上摆放子控件，水平方向放不下了，则另起一行继续水平摆放。\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://s3.51cto.com/wyfs02/M00/46/98/wKiom1PzLDGz5ifsAABxoQ3CRhg847.jpg\"\u003e\u003cimg alt=\"wKiom1PzLDGz5ifsAABxoQ3CRhg847.jpg\" loading=\"lazy\" src=\"http://s3.51cto.com/wyfs02/M00/46/98/wKiom1PzLDGz5ifsAABxoQ3CRhg847.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e**    1.  自定义ViewGroup的派生类**\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e第一步，则是自定ViewGroup的派生类，继承默认的构造函数。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_418526\" class=\"syntaxhighlighter  java\"\u003e\n    \u003ctable border=\"0\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n      \u003ctr\u003e\n        \u003ctd class=\"gutter\"\u003e\n          \u003cdiv class=\"line number1 index0 alt2\"\u003e\n            1\n          \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        2\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n        3\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n        4\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n        5\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n        6\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n        7\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n        8\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n        9\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n        10\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n        11\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n        12\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n        13\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n        14\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `public` `class` `CustomViewGroup ``extends` `ViewGroup {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          ` `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `   ``public` `CustomViewGroup(Context context) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          `       ``super``(context);    `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n          ` `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n          `   ``public` `CustomViewGroup(Context context, AttributeSet attrs) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n          `       ``super``(context, attrs);     `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n          `   `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n          `   ``public` `CustomViewGroup(Context context, AttributeSet attrs, intdefStyle) {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n          `       ``super``(context, attrs, defStyle);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n          `    ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"Android开发实践：自定义ViewGroup的onLayout()分析"},{"content":"Android官方培训课程中文版 http://hukai.me/android-training-course-in-chinese/index.html\nAndroid API Guides http://wiki.eoeandroid.com/Android_API_Guides\n// java *看的书: 疯狂java讲义 数据结构与算法分析(没看,建议数据结构差的看看,我也差,只是没时间看~) java编程思想(翻了一点点) *看的视频: 马士兵的就够了 要的去贴吧找 // android *看的书: 疯狂android 第一行android代码 eoe的一本android编程入门 android4.x高级编程 *看的视频 老罗的 Mars的 黑马的(看过几集) 极客学院的(没看过) *看过这些就看一些稍微高级一点的,有了一点基础嘛 imooc.com (这个网站非常好,大家去看了就知道了) 还有果壳的mooc(免费学,只有考证才会要钱) 学堂在线 网易的云课堂 *还有就是一些网站资料了 GitHub stackoverflow(学习android大半的疑惑都能在上边解决,不必担心自己看不懂,大多都是代码) android官网 http://developer.android.com/ Android官方培训课程中文版 http://hukai.me/android-training-course-in-chinese/index.html Material Design中文版 http://design.1sters.com/ *还有一些开源的工具 http://romannurik.github.io/AndroidAssetStudio/icons-launcher.html https://github.com/Trinea/android-open-project http://www.devstore.cn/service/newproductList/cla4-cid70-tag0-ordfollow_count-num1.html *工具类 Eclipse Android Studio(google的亲儿子 集成了Intellij) Android图书推荐 Android图书\n","permalink":"https://blog.zdltech.com/links/","summary":"\u003ch1 id=\"androidv092\"\u003eAndroid官方培训课程中文版\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"http://hukai.me/android-training-course-in-chinese/index.html\"\u003ehttp://hukai.me/android-training-course-in-chinese/index.html\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"firstHeading.firstHeading\"\u003eAndroid API Guides\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"http://wiki.eoeandroid.com/Android\"\u003ehttp://wiki.eoeandroid.com/Android\u003c/a\u003e_API_Guides\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e // java \n\n    *看的书:\n    疯狂java讲义\n    数据结构与算法分析(没看,建议数据结构差的看看,我也差,只是没时间看~)\n    java编程思想(翻了一点点)\n\n    *看的视频:\n     马士兵的就够了 要的去贴吧找\n\n    // android\n\n    *看的书:\n    疯狂android\n    第一行android代码\n    eoe的一本android编程入门\n    android4.x高级编程\n\n    *看的视频\n    老罗的\n    Mars的\n    黑马的(看过几集)\n    极客学院的(没看过)\n\n    *看过这些就看一些稍微高级一点的,有了一点基础嘛\n    imooc.com (这个网站非常好,大家去看了就知道了)       \n    还有果壳的mooc(免费学,只有考证才会要钱)\n    学堂在线\n    网易的云课堂\n\n     *还有就是一些网站资料了\n     GitHub \n     stackoverflow(学习android大半的疑惑都能在上边解决,不必担心自己看不懂,大多都是代码)\n     android官网  \n     http://developer.android.com/\n     Android官方培训课程中文版 \n     http://hukai.me/android-training-course-in-chinese/index.html\n     Material Design中文版\n     http://design.1sters.com/\n\n     *还有一些开源的工具\n      http://romannurik.github.io/AndroidAssetStudio/icons-launcher.html\n      https://github.com/Trinea/android-open-project\n      http://www.devstore.cn/service/newproductList/cla4-cid70-tag0-ordfollow_count-num1.html\n\n      *工具类\n      Eclipse \n      Android Studio(google的亲儿子 集成了Intellij)\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"android图书推荐\"\u003e\u003cstrong\u003eAndroid图书推荐\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"#\" data-type=\"2\" data-tmpl=\"720x220\" data-tmplid=\"209\" data-rd=\"2\" data-style=\"2\" data-border=\"1\"\u003eAndroid图书\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e","title":"推荐"},{"content":"1. 前台页面访问Google AJAX Libraries API（一般多是在主题里调用的） AJAX Libraries API架构在Google Code上，提供了JQuery 等JavaScript库，本来CDN是为我们提供更快更稳定的访问，但是无奈在国内我们没法正常享受谷歌的CDN服务啊。那我们只有转投国内了。现在国内也有很好的CDN服务，并且在国内还是使用国内的CDN公共库比较安全，下面先提供几个服务链接供您选择吧： http://lib.sinaapp.com/ http://developer.baidu.com/wiki/index.php?title=docs/cplat/libs http://www.staticfile.org/ http://jscdn.upai.com/\n下面说解决办法，以替换成百度CDN为例： 一般是在主题模板的header.php文件中找到引用谷歌CDN的代码处，比如我的是这句： ``` \u0026lt;script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js?ver=3.4.2'\u0026gt;\u0026lt;/script\u0026gt; ``` 替换成百度CDN： ``` \u0026lt;script type='text/javascript' src=\"http://libs.baidu.com/jquery/1.7.2/jquery.min.js\"\u0026gt;\u0026lt;/script\u0026gt; ``` ** 后台页面获取Google字体库**\n这个问题有两个解决办法，分别适用于两类使用人群\n2.1 后台无所谓字体好看不好看，决定彻底不使用谷歌字体了；\n解决办法：在wordpress 后台安装插件。在插件中搜索 Disable Google Fonts，选择安装，然后启用，这样就可以禁止Google字体的加载。\n2.2 强迫症+完美主义：稍微麻烦点把字体拿回来放自己服务器上吧，需要FQ一下哦。\n解决办法：\na. 就目前现状访问下谷歌是件不容易的事情，那我们需要FQ或是其他办法先把那些个字体文件下载回来，首先利用ie的开发人员工具、chrome开发者工具、firefox firebug工具 中的network查看页面加载时访问谷歌字体服务的URL，复制此URL在浏览器中打开（FQ中），这时我们看到了字体描述文件内容，并且找到了woff文件的url，分别把这几个woff文件下载下来；\nb. 将下载好的woff文件（文件名不做修改了，偷懒）放在\\wp-includes\\fonts\\google 目录中， google是我自建的；\nc. 拷贝a步骤URL显示内容，另存为一个css文件，把字体访问url改成我们本地的访问路径，命名为google-font.css 放在\\wp-includes\\css目录中（附该css文件的内容如下）；\n![复制代码](http://common.cnblogs.com/images/copycode.gif) ``` @font-face { font-family: \u0026lsquo;Open Sans\u0026rsquo;; font-style: normal; font-weight: 300; src: local(\u0026lsquo;Open Sans Light\u0026rsquo;), local(\u0026lsquo;OpenSans-Light\u0026rsquo;), url(../fonts/google/DXI1ORHCpsQm3Vp6mXoaTRa1RVmPjeKy21_GQJaLlJI.woff) format(\u0026lsquo;woff\u0026rsquo;); } @font-face { font-family: \u0026lsquo;Open Sans\u0026rsquo;; font-style: normal; font-weight: 400; src: local(\u0026lsquo;Open Sans\u0026rsquo;), local(\u0026lsquo;OpenSans\u0026rsquo;), url(../fonts/google/u-WUoqrET9fUeobQW7jkRT8E0i7KZn-EPnyo3HZu7kw.woff) format(\u0026lsquo;woff\u0026rsquo;); } @font-face { font-family: \u0026lsquo;Open Sans\u0026rsquo;; font-style: normal; font-weight: 600; src: local(\u0026lsquo;Open Sans Semibold\u0026rsquo;), local(\u0026lsquo;OpenSans-Semibold\u0026rsquo;), url(../fonts/google/MTP_ySUJH_bn48VBG8sNSha1RVmPjeKy21_GQJaLlJI.woff) format(\u0026lsquo;woff\u0026rsquo;); } @font-face { font-family: \u0026lsquo;Open Sans\u0026rsquo;; font-style: italic; font-weight: 300; src: local(\u0026lsquo;Open Sans Light Italic\u0026rsquo;), local(\u0026lsquo;OpenSansLight-Italic\u0026rsquo;), url(../fonts/google/PRmiXeptR36kaC0GEAetxrsuoFAk0leveMLeqYtnfAY.woff) format(\u0026lsquo;woff\u0026rsquo;); } @font-face { font-family: \u0026lsquo;Open Sans\u0026rsquo;; font-style: italic; font-weight: 400; src: local(\u0026lsquo;Open Sans Italic\u0026rsquo;), local(\u0026lsquo;OpenSans-Italic\u0026rsquo;), url(../fonts/google/xjAJXh38I15wypJXxuGMBtIh4imgI8P11RFo6YPCPC0.woff) format(\u0026lsquo;woff\u0026rsquo;); } @font-face { font-family: \u0026lsquo;Open Sans\u0026rsquo;; font-style: italic; font-weight: 600; src: local(\u0026lsquo;Open Sans Semibold Italic\u0026rsquo;), local(\u0026lsquo;OpenSans-SemiboldItalic\u0026rsquo;), url(../fonts/google/PRmiXeptR36kaC0GEAetxmWeb5PoA5ztb49yLyUzH1A.woff) format(\u0026lsquo;woff\u0026rsquo;); }\n\u0026lt;div class=\u0026#34;cnblogs_code_toolbar\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;cnblogs_code_copy\u0026#34;\u0026gt;\u0026lt;a title=\u0026#34;复制代码\u0026#34;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; d. 修改 \\wp-includes\\script-loader.php 文件，找到 \u0026lt;div class=\u0026#34;cnblogs_code\u0026#34; style=\u0026#34;color: #000000;\u0026#34;\u0026gt; ``` \u0026lt;span style=\u0026#34;color: #800080;\u0026#34;\u0026gt;$open_sans_font_url\u0026lt;/span\u0026gt; = \u0026#34;//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,300,400,600\u0026amp;subset=\u0026lt;span style=\u0026#34;color: #800080;\u0026#34;\u0026gt;$subsets\u0026lt;/span\u0026gt;\u0026#34;; 换成： ``` $open_sans_font_url = \"/wp-includes/css/google-font.css\"; ``` **　**此步骤d做好备忘，因是改了wordpress核心文件，日后升级时，做为提醒！ 至此，谷歌字体就来到了我们自己的服务器，再也不用担心被谷歌拖垮了~~~。当然如果你申请了国内的CDN，也可以放到CDN上去。 ** 3. 后台Gravatar头像(非谷歌服务)**\n另外，还有一个地方：后台Gravatar 头像，这里也经常会影响wordpress打开速度，解决办法就是关闭头像显示： 后台管理 \u0026amp;#8212; 设置 \u0026amp;#8212; 评论 \u0026amp;#8212; 关闭头像显示 目前大家多在使用“多说”等一类的评论插件来丰富评论功能，因此仅关闭头像显示即可。 转自：http://www.cnblogs.com/qumao5736/p/3767331.html ","permalink":"https://blog.zdltech.com/posts/%E8%A7%A3%E5%86%B3%E8%B0%B7%E6%AD%8Cgoogle%E4%B8%8D%E8%83%BD%E8%AE%BF%E9%97%AE%E9%80%A0%E6%88%90wordpress%E6%89%93%E5%BC%80%E7%BC%93%E6%85%A2%E7%9A%84%E9%97%AE%E9%A2%98/","summary":"\u003cp\u003e\u003cstrong\u003e1. 前台页面访问Google AJAX Libraries API（一般多是在主题里调用的）\u003c/strong\u003e\nAJAX Libraries API架构在Google Code上，提供了JQuery 等JavaScript库，本来CDN是为我们提供更快更稳定的访问，但是无奈在国内我们没法正常享受谷歌的CDN服务啊。那我们只有转投国内了。现在国内也有很好的CDN服务，并且在国内还是使用国内的CDN公共库比较安全，下面先提供几个服务链接供您选择吧：\n\u003ca href=\"http://lib.sinaapp.com/\"\u003ehttp://lib.sinaapp.com/\u003c/a\u003e\n\u003ca href=\"http://developer.baidu.com/wiki/index.php?title=docs/cplat/libs\"\u003ehttp://developer.baidu.com/wiki/index.php?title=docs/cplat/libs\u003c/a\u003e\n\u003ca href=\"http://www.staticfile.org/\"\u003ehttp://www.staticfile.org/\u003c/a\u003e\n\u003ca href=\"http://jscdn.upai.com/\"\u003ehttp://jscdn.upai.com/\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e下面说解决办法，以替换成百度CDN为例：\n\n\n\n\n\n一般是在主题模板的header.php文件中找到引用谷歌CDN的代码处，比如我的是这句：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"cnblogs_code\" style=\"color: #000000;\"\u003e\n    ```\n\u0026lt;script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js?ver=3.4.2'\u0026gt;\u0026lt;/script\u0026gt;\n```\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e替换成百度CDN：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"cnblogs_code\" style=\"color: #000000;\"\u003e\n    ```\n\u0026lt;script type='text/javascript' src=\"http://libs.baidu.com/jquery/1.7.2/jquery.min.js\"\u0026gt;\u0026lt;/script\u0026gt;\n```\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e**\n\u003c/code\u003e\u003c/pre\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e\n\u003cp\u003e后台页面获取Google字体库**\u003c/p\u003e\n\u003cp\u003e这个问题有两个解决办法，分别适用于两类使用人群\u003c/p\u003e\n\u003cp\u003e　　2.1 后台无所谓字体好看不好看，决定彻底不使用谷歌字体了；\u003c/p\u003e\n\u003cp\u003e　　　　解决办法：在wordpress 后台安装插件。在插件中搜索 Disable Google Fonts，选择安装，然后启用，这样就可以禁止Google字体的加载。\u003c/p\u003e\n\u003cp\u003e　　2.2 强迫症+完美主义：稍微麻烦点把字体拿回来放自己服务器上吧，需要FQ一下哦。\u003c/p\u003e\n\u003cp\u003e　　　　解决办法：\u003c/p\u003e\n\u003cp\u003e　　　　a. 就目前现状访问下谷歌是件不容易的事情，那我们需要FQ或是其他办法先把那些个字体文件下载回来，首先利用ie的开发人员工具、chrome开发者工具、firefox firebug工具 中的network查看页面加载时访问谷歌字体服务的URL，复制此URL在浏览器中打开（FQ中），这时我们看到了字体描述文件内容，并且找到了woff文件的url，分别把这几个woff文件下载下来；\u003c/p\u003e\n\u003cp\u003e　　　　b. 将下载好的woff文件（文件名不做修改了，偷懒）放在\\wp-includes\\fonts\\google 目录中， google是我自建的；\u003c/p\u003e\n\u003cp\u003e　　　　c. 拷贝a步骤URL显示内容，另存为一个css文件，把字体访问url改成我们本地的访问路径，命名为google-font.css 放在\\wp-includes\\css目录中（附该css文件的内容如下）；\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n  \u003cdiv class=\"cnblogs_code\" style=\"color: #000000;\"\u003e\n    \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n      \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cspan style=\"color: #800000;\"\u003e@font-face \u003c/span\u003e{\u003cspan style=\"color: #ff0000;\"\u003e\nfont-family\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e \u0026lsquo;Open Sans\u0026rsquo;\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nfont-style\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e normal\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nfont-weight\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e 300\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nsrc\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e local(\u0026lsquo;Open Sans Light\u0026rsquo;), local(\u0026lsquo;OpenSans-Light\u0026rsquo;), url(../fonts/google/DXI1ORHCpsQm3Vp6mXoaTRa1RVmPjeKy21_GQJaLlJI.woff) format(\u0026lsquo;woff\u0026rsquo;)\u003c/span\u003e;\n}\u003cspan style=\"color: #800000;\"\u003e\n@font-face \u003c/span\u003e{\u003cspan style=\"color: #ff0000;\"\u003e\nfont-family\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e \u0026lsquo;Open Sans\u0026rsquo;\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nfont-style\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e normal\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nfont-weight\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e 400\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nsrc\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e local(\u0026lsquo;Open Sans\u0026rsquo;), local(\u0026lsquo;OpenSans\u0026rsquo;), url(../fonts/google/u-WUoqrET9fUeobQW7jkRT8E0i7KZn-EPnyo3HZu7kw.woff) format(\u0026lsquo;woff\u0026rsquo;)\u003c/span\u003e;\n}\u003cspan style=\"color: #800000;\"\u003e\n@font-face \u003c/span\u003e{\u003cspan style=\"color: #ff0000;\"\u003e\nfont-family\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e \u0026lsquo;Open Sans\u0026rsquo;\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nfont-style\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e normal\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nfont-weight\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e 600\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nsrc\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e local(\u0026lsquo;Open Sans Semibold\u0026rsquo;), local(\u0026lsquo;OpenSans-Semibold\u0026rsquo;), url(../fonts/google/MTP_ySUJH_bn48VBG8sNSha1RVmPjeKy21_GQJaLlJI.woff) format(\u0026lsquo;woff\u0026rsquo;)\u003c/span\u003e;\n}\u003cspan style=\"color: #800000;\"\u003e\n@font-face \u003c/span\u003e{\u003cspan style=\"color: #ff0000;\"\u003e\nfont-family\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e \u0026lsquo;Open Sans\u0026rsquo;\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nfont-style\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e italic\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nfont-weight\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e 300\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nsrc\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e local(\u0026lsquo;Open Sans Light Italic\u0026rsquo;), local(\u0026lsquo;OpenSansLight-Italic\u0026rsquo;), url(../fonts/google/PRmiXeptR36kaC0GEAetxrsuoFAk0leveMLeqYtnfAY.woff) format(\u0026lsquo;woff\u0026rsquo;)\u003c/span\u003e;\n}\u003cspan style=\"color: #800000;\"\u003e\n@font-face \u003c/span\u003e{\u003cspan style=\"color: #ff0000;\"\u003e\nfont-family\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e \u0026lsquo;Open Sans\u0026rsquo;\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nfont-style\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e italic\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nfont-weight\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e 400\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nsrc\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e local(\u0026lsquo;Open Sans Italic\u0026rsquo;), local(\u0026lsquo;OpenSans-Italic\u0026rsquo;), url(../fonts/google/xjAJXh38I15wypJXxuGMBtIh4imgI8P11RFo6YPCPC0.woff) format(\u0026lsquo;woff\u0026rsquo;)\u003c/span\u003e;\n}\u003cspan style=\"color: #800000;\"\u003e\n@font-face \u003c/span\u003e{\u003cspan style=\"color: #ff0000;\"\u003e\nfont-family\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e \u0026lsquo;Open Sans\u0026rsquo;\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nfont-style\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e italic\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nfont-weight\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e 600\u003c/span\u003e;\u003cspan style=\"color: #ff0000;\"\u003e\nsrc\u003c/span\u003e:\u003cspan style=\"color: #0000ff;\"\u003e local(\u0026lsquo;Open Sans Semibold Italic\u0026rsquo;), local(\u0026lsquo;OpenSans-SemiboldItalic\u0026rsquo;), url(../fonts/google/PRmiXeptR36kaC0GEAetxmWeb5PoA5ztb49yLyUzH1A.woff) format(\u0026lsquo;woff\u0026rsquo;)\u003c/span\u003e;\n}\u003c/p\u003e","title":"解决谷歌google不能访问造成wordpress打开缓慢的问题"},{"content":"这是一个极其隐蔽的 BUG\n首先需求是：用 ColorDrawable 设置 ListView 分割线\n``` listView.setDivider(new ColorDrawable(0xffd4d5d6)); ``` 这样原理上绝对说得过去，但是你怎么都看不到效果，为什么呢，看源码吧！\n![复制代码](http://common.cnblogs.com/images/copycode.gif) public void setDivider(Drawable divider) { if (divider != null) { mDividerHeight = divider.getIntrinsicHeight(); } else { mDividerHeight = 0; } //.... ![复制代码](http://common.cnblogs.com/images/copycode.gif) mDividerHeight 是分割线的高度，我们再看 [Drawable](eclipse-javadoc:%E2%98%82=MopoGameLauncher/E:%5C/adt-bundle-windows-x86_64-20130219%5C/sdk%5C/platforms%5C/android-17%5C/android.jar%3Candroid.graphics.drawable(Drawable.class%E2%98%83Drawable).getIntrinsicHeight() ``` public int getIntrinsicHeight() { return -1; } ``` 返回 -1，而 ColorDrawable 并没有重载此方法！\n有些人运气好，在后面加了一句\nlistView.setDividerHeight(2);\n这样问题就解决了，但是当你把这句放前面，就不知道为什么了！\n所以正确方法是：\n``` listView.setDivider(new ColorDrawable(0xffd4d5d6)); listView.setDividerHeight(2); ``` ","permalink":"https://blog.zdltech.com/posts/android-listview-%E8%AE%BE%E7%BD%AE%E5%88%86%E5%89%B2%E7%BA%BF-divider/","summary":"\u003cp\u003e这是一个极其隐蔽的 BUG\u003c/p\u003e\n\u003cp\u003e首先需求是：用 ColorDrawable 设置 ListView 分割线\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\" style=\"color: #000000;\"\u003e\n  ```\nlistView.setDivider(new ColorDrawable(0xffd4d5d6));\n```\n\u003c/div\u003e\n\u003cp\u003e这样原理上绝对说得过去，但是你怎么都看不到效果，为什么呢，看源码吧！\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\" style=\"color: #000000;\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/span\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epublic void setDivider(Drawable divider) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      if (divider != null) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          mDividerHeight = divider.getIntrinsicHeight();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      } else {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          mDividerHeight = 0;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e//....\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/span\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emDividerHeight 是分割线的高度，我们再看 [Drawable](eclipse-javadoc:%E2%98%82=MopoGameLauncher/E:%5C/adt-bundle-windows-x86_64-20130219%5C/sdk%5C/platforms%5C/android-17%5C/android.jar%3Candroid.graphics.drawable(Drawable.class%E2%98%83Drawable).getIntrinsicHeight()\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"cnblogs_code\" style=\"color: #000000;\"\u003e\n  ```\npublic int getIntrinsicHeight() {\n        return -1;\n    }\n```\n\u003c/div\u003e\n\u003cp\u003e返回 -1，而 ColorDrawable 并没有重载此方法！\u003c/p\u003e\n\u003cp\u003e有些人运气好，在后面加了一句\u003c/p\u003e\n\u003cp\u003elistView.setDividerHeight(2);\u003c/p\u003e\n\u003cp\u003e这样问题就解决了，但是当你把这句放前面，就不知道为什么了！\u003c/p\u003e\n\u003cp\u003e所以正确方法是：\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\" style=\"color: #000000;\"\u003e\n  ```\nlistView.setDivider(new ColorDrawable(0xffd4d5d6));\nlistView.setDividerHeight(2);\n```\n\u003c/div\u003e","title":"android ListView 设置分割线 Divider"},{"content":"原型设计工具（免费）\nhttp://www.mockupplus.com/download\n注册地址：http://www.mockplus.cn/referral?r=rxjuhv\n火狐开发者版本\nhttps://www.mozilla.org/en-US/firefox/developer/\n","permalink":"https://blog.zdltech.com/posts/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7%E8%AE%BE%E8%AE%A1%E5%B7%A5%E5%85%B7%E7%BD%91%E7%AB%99%E6%94%B6%E9%9B%86/","summary":"\u003cp\u003e原型设计工具（免费）\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.mockupplus.com/download\"\u003ehttp://www.mockupplus.com/download\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e注册地址：\u003ca href=\"http://www.mockplus.cn/referral?r=rxjuhv\"\u003ehttp://www.mockplus.cn/referral?r=rxjuhv\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://www.mockplus.cn/images/content/slide_02.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://www.mockplus.cn/images/content/_mockModels.png\"\u003e\u003c/p\u003e\n\u003cp\u003e火狐开发者版本\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.mozilla.org/en-US/firefox/developer/\"\u003ehttps://www.mozilla.org/en-US/firefox/developer/\u003c/a\u003e\u003c/p\u003e","title":"开发工具、设计工具、网站收集"},{"content":"Alias /aa/ “D:/PHP_WorkSpace/”\n\u0026lt;Directory “D:/PHP_WorkSpace/”\u0026gt;\nOptions Indexes FollowSymLinks MultiViews\nAllowOverride all\nOrder allow,deny\nAllow from all\nwamp自带的phpmyadmin的别名配置\nAlias /phpmyadmin “E:/wamp/apps/phpmyadmin4.0.4/”\n# to give access to phpmyadmin from outside\n# replace the lines\n# Order Deny,Allow\n# Deny from all\n# Allow from 127.0.0.1\n# by\n# Order Allow,Deny\n# Allow from all\n\u0026lt;Directory “E:/wamp/apps/phpmyadmin4.0.4/”\u0026gt;\nOptions Indexes FollowSymLinks ExecCGI\nAllowOverride all\nOrder Deny,Allow\nDeny from all\nAllow from 127.0.0.1\nAllow from ::1\nAllow from localhost\nApache 2.4以上版本设置访问虚拟目录方法\n找到 http.conf 找到IfModule dir_module 标签\u0026lt;IfModule dir_module\u0026gt;\nDirectoryIndex index.html\nAlias /gz “/var/www/html/zentaopms/www/”\n\u0026lt;Directory /var/www/html/zentaopms/www/\u0026gt;\nAllowOverride None\n# Allow open access:\nRequire all granted\n重启apache 通过浏览器访问gz 达到访问 指定目录的效果 ","permalink":"https://blog.zdltech.com/posts/apache%E5%88%AB%E5%90%8D%E9%85%8D%E7%BD%AE/","summary":"\u003cp\u003eAlias /aa/ “D:/PHP_WorkSpace/”\u003c/p\u003e\n\u003cp\u003e\u0026lt;Directory “D:/PHP_WorkSpace/”\u0026gt;\u003cbr\u003e\nOptions Indexes FollowSymLinks MultiViews\u003cbr\u003e\nAllowOverride all\u003cbr\u003e\nOrder allow,deny\u003cbr\u003e\nAllow from all\u003cbr\u003e\n\u003c/Directory\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003ewamp自带的phpmyadmin的别名配置\u003c/p\u003e\n\u003cp\u003eAlias /phpmyadmin “E:/wamp/apps/phpmyadmin4.0.4/”\u003c/p\u003e\n\u003cp\u003e# to give access to phpmyadmin from outside\u003cbr\u003e\n# replace the lines\u003c/p\u003e\n\u003ch1\u003e\u003c/h1\u003e\n\u003cp\u003e# Order Deny,Allow\u003cbr\u003e\n# Deny from all\u003cbr\u003e\n# Allow from 127.0.0.1\u003c/p\u003e\n\u003ch1\u003e\u003c/h1\u003e\n\u003cp\u003e# by\u003c/p\u003e\n\u003ch1\u003e\u003c/h1\u003e\n\u003cp\u003e# Order Allow,Deny\u003cbr\u003e\n# Allow from all\u003c/p\u003e\n\u003ch1\u003e\u003c/h1\u003e\n\u003cp\u003e\u0026lt;Directory “E:/wamp/apps/phpmyadmin4.0.4/”\u0026gt;\u003cbr\u003e\nOptions Indexes FollowSymLinks ExecCGI\u003cbr\u003e\nAllowOverride all\u003cbr\u003e\nOrder Deny,Allow\u003cbr\u003e\nDeny from all\u003cbr\u003e\nAllow from 127.0.0.1\u003cbr\u003e\nAllow from ::1\u003cbr\u003e\nAllow from localhost\u003cbr\u003e\n\u003c/Directory\u003e\u003c/p\u003e","title":"Apache别名配置"},{"content":"1. Volley简介 我们平时在开发Android应用的时候不可避免地都需要用到网络技术，而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据。Android系统中主要提供了两种方式来进行HTTP通信，HttpURLConnection和HttpClient，几乎在任何项目的代码中我们都能看到这两个类的身影，使用率非常高。\n不过HttpURLConnection和HttpClient的用法还是稍微有些复杂的，如果不进行适当封装的话，很容易就会写出不少重复代码。于是乎，一些Android网络通信框架也就应运而生，比如说AsyncHttpClient，它把HTTP所有的通信细节全部封装在了内部，我们只需要简单调用几行代码就可以完成通信操作了。再比如Universal-Image-Loader，它使得在界面上显示网络图片的操作变得极度简单，开发者不用关心如何从网络上获取图片，也不用关心开启线程、回收图片资源等细节，Universal-Image-Loader已经把一切都做好了。\nAndroid开发团队也是意识到了有必要将HTTP的通信操作再进行简单化，于是在2013年Google I/O大会上推出了一个新的网络通信框架——Volley。Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身，既可以像AsyncHttpClient一样非常简单地进行HTTP通信，也可以像Universal-Image-Loader一样轻松加载网络上的图片。除了简单易用之外，Volley在性能方面也进行了大幅度的调整，它的设计目标就是非常适合去进行数据量不大，但通信频繁的网络操作，而对于大数据量的网络操作，比如说下载文件等，Volley的表现就会非常糟糕。\n下图所示的这些应用都是属于数据量不大，但网络通信频繁的，因此非常适合使用Volley。\n2. 下载Volley 介绍了这么多理论的东西，下面我们就准备开始进行实战了，首先需要将Volley的jar包准备好，如果你的电脑上装有Git，可以使用如下命令下载Volley的源码：\n**[plain]** [view plain](http://blog.csdn.net/guolin_blog/article/details/17482095#)[copy](http://blog.csdn.net/guolin_blog/article/details/17482095#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/284210)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/284210/fork) \u0026lt;div style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;git clone https://android.googlesource.com/platform/frameworks/volley \u0026lt;/span\u0026gt; 下载完成后将它导入到你的Eclipse工程里，然后再导出一个jar包就可以了。如果你的电脑上没有Git，那么也可以直接使用我导出好的jar包，下载地址是：http://www.kwstu.com/ResourcesView/kwstu_201441183330928 。\n新建一个Android项目，将volley.jar文件复制到libs目录下，这样准备工作就算是做好了。\n3. StringRequest的用法 前面已经说过，Volley的用法非常简单，那么我们就从最基本的HTTP通信开始学习吧，即发起一条HTTP请求，然后接收HTTP响应。首先需要获取到一个RequestQueue对象，可以调用如下方法获取到：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/17482095#)[copy](http://blog.csdn.net/guolin_blog/article/details/17482095#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/284210)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/284210/fork) \u0026lt;div style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;RequestQueue mQueue = Volley.newRequestQueue(context); \u0026lt;/span\u0026gt; 注意这里拿到的RequestQueue是一个请求队列对象，它可以缓存所有的HTTP请求，然后按照一定的算法并发地发出这些请求。RequestQueue内部的设计就是非常合适高并发的，因此我们不必为每一次HTTP请求都创建一个RequestQueue对象，这是非常浪费资源的，基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。\n接下来为了要发出一条HTTP请求，我们还需要创建一个StringRequest对象，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/17482095#)[copy](http://blog.csdn.net/guolin_blog/article/details/17482095#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/284210)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/284210/fork) \u0026lt;div style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;StringRequest stringRequest = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringRequest(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://www.baidu.com\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.Listener\u0026lt;String\u0026gt;() { - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onResponse(String response) { - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TAG\u0026amp;#8221;\u0026lt;/span\u0026gt;, response); \u0026lt;/span\u0026gt; - } - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.ErrorListener() { \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onErrorResponse(VolleyError error) { \u0026lt;/span\u0026gt; - Log.e(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TAG\u0026amp;#8221;\u0026lt;/span\u0026gt;, error.getMessage(), error); - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - }); 可以看到，这里new出了一个StringRequest对象，StringRequest的构造函数需要传入三个参数，第一个参数就是目标服务器的URL地址，第二个参数是服务器响应成功的回调，第三个参数是服务器响应失败的回调。其中，目标服务器地址我们填写的是百度的首页，然后在响应成功的回调里打印出服务器返回的内容，在响应失败的回调里打印出失败的详细信息。\n最后，将这个StringRequest对象添加到RequestQueue里面就可以了，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/17482095#)[copy](http://blog.csdn.net/guolin_blog/article/details/17482095#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/284210)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/284210/fork) \u0026lt;div style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;mQueue.add(stringRequest); \u0026lt;/span\u0026gt; 另外，由于Volley是要访问网络的，因此不要忘记在你的AndroidManifest.xml中添加如下权限：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/17482095#)[copy](http://blog.csdn.net/guolin_blog/article/details/17482095#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/284210)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/284210/fork) \u0026lt;div style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;uses-permission android:name=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.permission.INTERNET\u0026amp;#8221;\u0026lt;/span\u0026gt; /\u0026gt; \u0026lt;/span\u0026gt; 好了，就是这么简单，如果你现在运行一下程序，并发出这样一条HTTP请求，就会看到LogCat中会打印出如下图所示的数据。\n没错，百度返回给我们的就是这样一长串的HTML代码，虽然我们看起来会有些吃力，但是浏览器却可以轻松地对这段HTML代码进行解析，然后将百度的首页展现出来。\n这样的话，一个最基本的HTTP发送与响应的功能就完成了。你会发现根本还没写几行代码就轻易实现了这个功能，主要就是进行了以下三步操作：\n创建一个RequestQueue对象。\n创建一个StringRequest对象。\n将StringRequest对象添加到RequestQueue里面。\n不过大家都知道，HTTP的请求类型通常有两种，GET和POST，刚才我们使用的明显是一个GET请求，那么如果想要发出一条POST请求应该怎么做呢？StringRequest中还提供了另外一种四个参数的构造函数，其中第一个参数就是指定请求类型的，我们可以使用如下方式进行指定：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/17482095#)[copy](http://blog.csdn.net/guolin_blog/article/details/17482095#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/284210)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/284210/fork) \u0026lt;div style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;StringRequest stringRequest = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringRequest(Method.POST, url, listener, errorListener); \u0026lt;/span\u0026gt; 可是这只是指定了HTTP请求方式是POST，那么我们要提交给服务器的参数又该怎么设置呢？很遗憾，StringRequest中并没有提供设置POST参数的方法，但是当发出POST请求的时候，Volley会尝试调用StringRequest的父类——Request中的getParams()方法来获取POST参数，那么解决方法自然也就有了，我们只需要在StringRequest的匿名类中重写getParams()方法，在这里设置POST参数就可以了，代码如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/17482095#)[copy](http://blog.csdn.net/guolin_blog/article/details/17482095#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/284210)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/284210/fork) \u0026lt;div style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;StringRequest stringRequest = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringRequest(Method.POST, url, listener, errorListener) { \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; Map\u0026lt;String, String\u0026gt; getParams() \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; AuthFailureError { \u0026lt;/span\u0026gt; - Map\u0026lt;String, String\u0026gt; map = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HashMap\u0026lt;String, String\u0026gt;(); - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; map.put(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;params1\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;value1\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - map.put(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;params2\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;value2\u0026amp;#8221;\u0026lt;/span\u0026gt;); - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; map; \u0026lt;/span\u0026gt; - } - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}; \u0026lt;/span\u0026gt; 你可能会说，每次都这样用起来岂不是很累？连个设置POST参数的方法都没有。但是不要忘记，Volley是开源的，只要你愿意，你可以自由地在里面添加和修改任何的方法，轻松就能定制出一个属于你自己的Volley版本。\n4. JsonRequest的用法 学完了最基本的StringRequest的用法，我们再来进阶学习一下JsonRequest的用法。类似于StringRequest，JsonRequest也是继承自Request类的，不过由于JsonRequest是一个抽象类，因此我们无法直接创建它的实例，那么只能从它的子类入手了。JsonRequest有两个直接的子类，JsonObjectRequest和JsonArrayRequest，从名字上你应该能就看出它们的区别了吧？一个是用于请求一段JSON数据的，一个是用于请求一段JSON数组的。\n至于它们的用法也基本上没有什么特殊之处，先new出一个JsonObjectRequest对象，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/17482095#)[copy](http://blog.csdn.net/guolin_blog/article/details/17482095#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/284210)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/284210/fork) \u0026lt;div style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;JsonObjectRequest jsonObjectRequest = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; JsonObjectRequest(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://m.weather.com.cn/data/101010100.html\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.Listener\u0026lt;JSONObject\u0026gt;() { - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onResponse(JSONObject response) { - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TAG\u0026amp;#8221;\u0026lt;/span\u0026gt;, response.toString()); \u0026lt;/span\u0026gt; - } - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.ErrorListener() { \u0026lt;/span\u0026gt; - \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onErrorResponse(VolleyError error) { \u0026lt;/span\u0026gt; - Log.e(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TAG\u0026amp;#8221;\u0026lt;/span\u0026gt;, error.getMessage(), error); - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - }); 可以看到，这里我们填写的URL地址是http://m.weather.com.cn/data/101010100.html，这是中国天气网提供的一个查询天气信息的接口，响应的数据就是以JSON格式返回的，然后我们在onResponse()方法中将返回的数据打印出来。\n最后再将这个JsonObjectRequest对象添加到RequestQueue里就可以了，如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/17482095#)[copy](http://blog.csdn.net/guolin_blog/article/details/17482095#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/284210)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/284210/fork) \u0026lt;div style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;mQueue.add(jsonObjectRequest); \u0026lt;/span\u0026gt; 这样当HTTP通信完成之后，服务器响应的天气信息就会回调到onResponse()方法中，并打印出来。现在运行一下程序，发出这样一条HTTP请求，就会看到LogCat中会打印出如下图所示的数据。\n由此可以看出，服务器返回给我们的数据确实是JSON格式的，并且onResponse()方法中携带的参数也正是一个JSONObject对象，之后只需要从JSONObject对象取出我们想要得到的那部分数据就可以了。\n你应该发现了吧，JsonObjectRequest的用法和StringRequest的用法基本上是完全一样的，Volley的易用之处也在这里体现出来了，会了一种就可以让你举一反三，因此关于JsonArrayRequest的用法相信已经不需要我再去讲解了吧。\n好了，关于Volley的基本用法就讲到这里，下篇文章中我会带领大家继续探究Volley。\n","permalink":"https://blog.zdltech.com/posts/android-volley%E5%AE%8C%E5%85%A8%E8%A7%A3%E6%9E%90%E4%B8%80%E5%88%9D%E8%AF%86volley%E7%9A%84%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95/","summary":"\u003ch2 id=\"1-volley简介\"\u003e1. Volley简介\u003c/h2\u003e\n\u003cp\u003e我们平时在开发Android应用的时候不可避免地都需要用到网络技术，而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据。Android系统中主要提供了两种方式来进行HTTP通信，HttpURLConnection和HttpClient，几乎在任何项目的代码中我们都能看到这两个类的身影，使用率非常高。\u003c/p\u003e\n\u003cp\u003e不过HttpURLConnection和HttpClient的用法还是稍微有些复杂的，如果不进行适当封装的话，很容易就会写出不少重复代码。于是乎，一些Android网络通信框架也就应运而生，比如说AsyncHttpClient，它把HTTP所有的通信细节全部封装在了内部，我们只需要简单调用几行代码就可以完成通信操作了。再比如Universal-Image-Loader，它使得在界面上显示网络图片的操作变得极度简单，开发者不用关心如何从网络上获取图片，也不用关心开启线程、回收图片资源等细节，Universal-Image-Loader已经把一切都做好了。\u003c/p\u003e\n\u003cp\u003eAndroid开发团队也是意识到了有必要将HTTP的通信操作再进行简单化，于是在2013年Google I/O大会上推出了一个新的网络通信框架——Volley。Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身，既可以像AsyncHttpClient一样非常简单地进行HTTP通信，也可以像Universal-Image-Loader一样轻松加载网络上的图片。除了简单易用之外，Volley在性能方面也进行了大幅度的调整，它的设计目标就是非常适合去进行数据量不大，但通信频繁的网络操作，而对于大数据量的网络操作，比如说下载文件等，Volley的表现就会非常糟糕。\u003c/p\u003e\n\u003cp\u003e下图所示的这些应用都是属于数据量不大，但网络通信频繁的，因此非常适合使用Volley。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://www.kwstu.com/Content/uploadFiles/images/20140406140008281.jpg\"\u003e\u003c/p\u003e\n\u003ch2 id=\"2-下载volley\"\u003e\u003ca style=\"color: #336699;\" name=\"t1\"\u003e\u003c/a\u003e2. 下载Volley\u003c/h2\u003e\n\u003cp\u003e介绍了这么多理论的东西，下面我们就准备开始进行实战了，首先需要将Volley的jar包准备好，如果你的电脑上装有Git，可以使用如下命令下载Volley的源码：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_plain\"\u003e\n  \u003cdiv class=\"bar\" style=\"color: #000000;\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[plain]** [view plain](http://blog.csdn.net/guolin_blog/article/details/17482095#)[copy](http://blog.csdn.net/guolin_blog/article/details/17482095#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/284210)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/284210/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;git clone https://android.googlesource.com/platform/frameworks/volley  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e下载完成后将它导入到你的Eclipse工程里，然后再导出一个jar包就可以了。如果你的电脑上没有Git，那么也可以直接使用我导出好的jar包，下载地址是：\u003ca href=\"http://www.kwstu.com/ResourcesView/kwstu_201441183330928\"\u003e\u003cspan style=\"color: #336699; font-family: Arial;\"\u003ehttp://www.kwstu.com/ResourcesView/kwstu_201441183330928\u003c/span\u003e\u003c/a\u003e 。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e新建一个Android项目，将volley.jar文件复制到libs目录下，这样准备工作就算是做好了。\u003c/p\u003e\n\u003ch2 id=\"3-stringrequest的用法\"\u003e\u003ca style=\"color: #336699;\" name=\"t2\"\u003e\u003c/a\u003e3. StringRequest的用法\u003c/h2\u003e\n\u003cp\u003e前面已经说过，Volley的用法非常简单，那么我们就从最基本的HTTP通信开始学习吧，即发起一条HTTP请求，然后接收HTTP响应。首先需要获取到一个RequestQueue对象，可以调用如下方法获取到：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\" style=\"color: #000000;\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/17482095#)[copy](http://blog.csdn.net/guolin_blog/article/details/17482095#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/284210)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/284210/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;RequestQueue mQueue = Volley.newRequestQueue(context);  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e注意这里拿到的RequestQueue是一个请求队列对象，它可以缓存所有的HTTP请求，然后按照一定的算法并发地发出这些请求。RequestQueue内部的设计就是非常合适高并发的，因此我们不必为每一次HTTP请求都创建一个RequestQueue对象，这是非常浪费资源的，基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e接下来为了要发出一条HTTP请求，我们还需要创建一个StringRequest对象，如下所示：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\" style=\"color: #000000;\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/17482095#)[copy](http://blog.csdn.net/guolin_blog/article/details/17482095#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/284210)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/284210/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;StringRequest stringRequest = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringRequest(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://www.baidu.com\u0026amp;#8221;\u0026lt;/span\u0026gt;,  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.Listener\u0026lt;String\u0026gt;() {\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                            \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onResponse(String response) {\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                                Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TAG\u0026amp;#8221;\u0026lt;/span\u0026gt;, response);  \u0026lt;/span\u0026gt;\n\n- }\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        }, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Response.ErrorListener() {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onErrorResponse(VolleyError error) {  \u0026lt;/span\u0026gt;\n\n- Log.e(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TAG\u0026amp;#8221;\u0026lt;/span\u0026gt;, error.getMessage(), error);\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                            }  \u0026lt;/span\u0026gt;\n\n- });\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e可以看到，这里new出了一个StringRequest对象，StringRequest的构造函数需要传入三个参数，第一个参数就是目标服务器的URL地址，第二个参数是服务器响应成功的回调，第三个参数是服务器响应失败的回调。其中，目标服务器地址我们填写的是百度的首页，然后在响应成功的回调里打印出服务器返回的内容，在响应失败的回调里打印出失败的详细信息。\u003c/p\u003e","title":"Android Volley完全解析(一)，初识Volley的基本用法"},{"content":"向自己的应用中添加第三方库是一件需要谨慎而行的事情，因为也许在不久的将来，这些库可能会停止开发，那么到时，当使用这些库遇到问题，却没了任何支持，会是一件很悲催的事情。所以，这里向大家介绍的是，在iOS应用开发中最常使用，而又有信心会继续开发和支持很长一段时间的第三方库，希望能够对你的开发工作有所帮助。\n1. CocoaPods\n是不是已经厌烦了将各种库拖拽到Xcode项目中？那么，CocoaPods的出现就帮你解决了这一问题。CocoaPods是Objective-C项目中最有名的类库管理工具，可以解决库与库之间的依赖关系，下载库的源码，供我们开发使用。最重要的是，大多的开源类库都支持它。所以，有了CocoaPods，你就可以很轻松地对项目进行扩展。\n2. Crashlytics\nCrashlytics是一款用于检测你开发的应用，何时在客户端设备上崩溃，并能找出其崩溃原因以及帮助开发者修复应用的工具。Crashlytics既免费又方便使用，另外，还内置一些基础的分析功能，让你无需总要依赖其他独立的分析工具。\n3. AFNetworking/Alamofire\nAFNetworking和之前文章中提到的Alamofire一样，是一个网络库，不同的是，Alamofire是用于Swift中，而AFNetworking则是为Objective-C准备的。AFNetworking是建立在Foundation URL Loading System之上，拥有一个精心设计的模块化架构，以及功能丰富的API，使用起来很是方便。\n4. Google Analytics、Mixpanel、Localytics\n通常情况下，当需要分析用户使用应用的各方面数据时，会在Google Analytics、Mixpanel和Localytics之间权衡。Google Analytics可以用来跟踪和统计应用程序，如访问数、停留时间、跳出率等；Mixpanel则是为大家提供公式化和分类类报告，从而给出详细的数据分析；而Localytics提供的是实时地分析服务，帮助开发者更好的理解用户。至于选择哪一个，可以根据自己的需求来判定。\n5. Urban Airship\n当需要向应用中添加推送通知时，Urban Airship会是一个不错的选择，不过这个是在它还是免费的时候。所以，当你是在为自己或是小的客户端构建应用时，你可以使用Parse和Mixpanel来取代Urban Airship。不过如果是为那些有能力出钱的大客户开发应用的话，Urban Airship还是首选。\n6. New Relic\nNew Relic的移动应用监控能够很好地跟踪应用的性能问题，而无需等到应用崩溃后，再去检查问题的来源。让用户从多角度、实时地发现应用的错误，并对此进行处理。\n7. ZBar\nZBar是一个开源的软件套件，实现了识别和读取来自各种资源的条形码，比如视频流、图像文件等。它支持众多主流的条码，其中包括EAN-13/UPC-A、UPC-E、EAN-8、Code 128、Code 39、Interleaved 2 of 5和QR Code。\n8. Core Plot\nCore Plot是一个开源的2D绘图框架，具有高度可定制性，和Apple的技术紧密的整合，比如 Core Animation、Core Data 和 Cocoa Bindings。 可以绘制柱状图、折线图、饼图等多种图形，提供Mac OS X和iOS下的组件库，基本可以满足你大部分的绘图需求。\n","permalink":"https://blog.zdltech.com/posts/mark%E8%B5%B0%E8%B5%B7ios%E5%BC%80%E5%8F%91%E6%9C%80%E5%B8%B8%E7%94%A8%E7%9A%84%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%93/","summary":"\u003cp\u003e向自己的应用中添加第三方库是一件需要谨慎而行的事情，因为也许在不久的将来，这些库可能会停止开发，那么到时，当使用这些库遇到问题，却没了任何支持，会是一件很悲催的事情。所以，这里向大家介绍的是，在iOS应用开发中最常使用，而又有信心会继续开发和支持很长一段时间的第三方库，希望能够对你的开发工作有所帮助。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. \u003ca href=\"http://cocoapods.org/\"\u003eCocoaPods\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e是不是已经厌烦了将各种库拖拽到Xcode项目中？那么，CocoaPods的出现就帮你解决了这一问题。CocoaPods是Objective-C项目中最有名的类库管理工具，可以解决库与库之间的依赖关系，下载库的源码，供我们开发使用。最重要的是，大多的开源类库都支持它。所以，有了CocoaPods，你就可以很轻松地对项目进行扩展。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201410/23/5448bea64e8fe.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201410/23/5448bea64e8fe.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. \u003ca href=\"http://try.crashlytics.com/\"\u003eCrashlytics\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCrashlytics是一款用于检测你开发的应用，何时在客户端设备上崩溃，并能找出其崩溃原因以及帮助开发者修复应用的工具。Crashlytics既免费又方便使用，另外，还内置一些基础的分析功能，让你无需总要依赖其他独立的分析工具。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201410/23/5448baf602d83.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201410/23/5448baf602d83_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. \u003ca href=\"https://github.com/AFNetworking/AFNetworking\"\u003eAFNetworking\u003c/a\u003e/\u003ca href=\"https://github.com/Alamofire/Alamofire\"\u003eAlamofire\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eAFNetworking和之前\u003ca href=\"http://www.csdn.net/article/2014-10-14/2822083-swift-ios-open-source-projects\"\u003e文章\u003c/a\u003e中提到的Alamofire一样，是一个网络库，不同的是，Alamofire是用于Swift中，而AFNetworking则是为Objective-C准备的。AFNetworking是建立在\u003ca href=\"http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html\"\u003eFoundation URL Loading System\u003c/a\u003e之上，拥有一个精心设计的模块化架构，以及功能丰富的API，使用起来很是方便。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201410/23/5448bb29ba938.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201410/23/5448bb29ba938_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201410/23/5448bb3d2cc70.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201410/23/5448bb3d2cc70_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4. \u003ca href=\"http://www.google.com/analytics/mobile/\"\u003eGoogle Analytics\u003c/a\u003e、\u003ca href=\"https://mixpanel.com/\"\u003eMixpanel\u003c/a\u003e、\u003ca href=\"http://www.localytics.com/\"\u003eLocalytics\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e通常情况下，当需要分析用户使用应用的各方面数据时，会在Google Analytics、Mixpanel和Localytics之间权衡。Google Analytics可以用来跟踪和统计应用程序，如访问数、停留时间、跳出率等；Mixpanel则是为大家提供公式化和分类类报告，从而给出详细的数据分析；而Localytics提供的是实时地分析服务，帮助开发者更好的理解用户。至于选择哪一个，可以根据自己的需求来判定。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201410/23/5448bc1f185f6.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201410/23/5448bc1f185f6_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e5. \u003ca href=\"http://urbanairship.com/\"\u003eUrban Airship\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e当需要向应用中添加推送通知时，Urban Airship会是一个不错的选择，不过这个是在它还是免费的时候。所以，当你是在为自己或是小的客户端构建应用时，你可以使用Parse和Mixpanel来取代Urban Airship。不过如果是为那些有能力出钱的大客户开发应用的话，Urban Airship还是首选。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201410/23/5448bc59094ab.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201410/23/5448bc59094ab_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e6. \u003ca href=\"http://newrelic.com/mobile-monitoring\"\u003eNew Relic\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eNew Relic的移动应用监控能够很好地跟踪应用的性能问题，而无需等到应用崩溃后，再去检查问题的来源。让用户从多角度、实时地发现应用的错误，并对此进行处理。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201410/23/5448bc8c02544.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201410/23/5448bc8c02544_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e7. \u003ca href=\"http://zbar.sourceforge.net/\"\u003eZBar\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eZBar是一个开源的软件套件，实现了识别和读取来自各种资源的条形码，比如视频流、图像文件等。它支持众多主流的条码，其中包括EAN-13/UPC-A、UPC-E、EAN-8、Code 128、Code 39、Interleaved 2 of 5和QR Code。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201410/23/5448bced4a7e7.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201410/23/5448bced4a7e7_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e8. \u003ca href=\"https://github.com/core-plot/core-plot\"\u003eCore Plot\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCore Plot是一个开源的2D绘图框架，具有高度可定制性，和Apple的技术紧密的整合，比如 Core Animation、Core Data 和 Cocoa Bindings。 可以绘制柱状图、折线图、饼图等多种图形，提供Mac OS X和iOS下的组件库，基本可以满足你大部分的绘图需求。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201410/23/5448be3aa08e4.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201410/23/5448be3aa08e4_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e","title":"Mark走起！iOS开发最常用的第三方库"},{"content":"首先简单谈下快速排序的特点，时间复杂度O(nLog n)，最差时间复杂度O(n^2)，平均时间O(nLog n).因为用到了函数栈，空间复杂度为O(lg n),最差为O(n).是一种不稳定的排序方法。基本思想是分治法，这位大大的http://blog.csdn.net/morewindows/article/details/6684558 讲的非常清楚了，分治法+挖坑法，我就不多说了。就是以某个数为参照，使得左边的都小于他，右边的数都大于他。然后对他的左右两个区间采取同样的方法进行递归。\n就其整体实现而言，有两大种思路，一是双边扫描，二是单边扫描。下面分别来上程序:\n一、双边扫描 双边扫描是谭浩强书中的方法，个人觉得比下面的单边扫描更好理解，也是博文里采用的方法。下面看程序:\n**[cpp]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[copy](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[print](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[?](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/412329)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/412329/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; quickSort1(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;* x, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(l \u0026lt; r){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = l, j = r, key = x[l]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(i \u0026lt; j){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;( i \u0026lt; j \u0026amp;\u0026amp; x[j] \u0026gt;= key){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; j\u0026amp;#8211;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(i \u0026lt; j){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; x[i++] = x[j]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(i \u0026lt; j \u0026amp;\u0026amp; x[i] \u0026lt;= key){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; i++; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(i \u0026lt; j){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; x[j\u0026amp;#8211;] = x[i]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; cout\u0026lt;\u0026lt;\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;i = \u0026amp;#8220;\u0026lt;/span\u0026gt; \u0026lt;\u0026lt;i\u0026lt;\u0026lt;\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8221; j = \u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;\u0026lt;j\u0026lt;\u0026lt;endl; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; x[i] = key; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; quickSort1(x, l, i-1); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; quickSort1(x, i+1, r); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 双边扫描非常直观，首先进到程序里判断是否l\u0026lt;r,当满足条件才进去。这也是用递归的一个必要条件，一定要让函数有尽头，有边界。然后进入大while循环，接着进入小while循环，先从右边找，只要满足数字大于key就一直让j往左移。直到第一个不满足条件的，就是第一个小于key的数跳出while循环，将它放在左边挖的“坑”上。同时让坑的索引+1，接着从左边开始扫描，找到第一个大于key的数，再将它填到右边的坑上。右边的坑索引-1，接着再从右边扫描。直到最后跳出大while循环，此时i = j。也就是完成了一次快速排序的扫描。之后将最初的key放到x[i]，其实放到x[j]也是一样的。因为i等于j么，此时！然后进行递归，对区间[l, i – 1], [i+1, r]进行同样的操作。\n双边排序的要点: 1、最初的if一定要有，这是最后递归出来的标志位。2，为了找到一个数使它的左边都大于它，右边都小于它，要多次循环，这个循环就是大while循环。3、双边排序不需要swap，即无需交换。\n二、单边扫描 上面的双边排序，出来一次大while循环，要从两边进行多次。单边扫描，则只需从左走到右就能完成一次 快排。\n**[cpp]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[copy](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[print](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[?](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/412329)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/412329/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; quickSort2(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x[], \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(l \u0026gt;= r) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; m = l; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = l + l; i \u0026lt;= r; i++ ){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(x[i] \u0026lt; x[l]){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; swap2(x[++m], x[i]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; swap2(x[l], x[m]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; quickSort2(x, l, m \u0026amp;#8211; 1); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; quickSort2(x, m + 1, r); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; swap2(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026amp;a,\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026amp;b){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(a==b) \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//对同一地址的数据交换，会使其结果为0\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; a=a^b; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; b=a^b; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; a=a^b; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 代码是不是更简单了？程序先进行判断，如果l\u0026gt;=r直接return，这点跟双边扫描的if一个意思，都是为递归创造结束的标志。然后用m记录最左边的那个的索引，这里默认的是第一个，即x[l]的索引。[注，m的初始值不一定指向key！，仅仅是指向最左边的。]然后进入扫描，直接从l + 1开始，如果右边的小于key，就让x[++m]和x[i]交换。如果右边的大于key，则不进行任何操作。这里有个特例，如果l = 0， 则m = 0.如果x[1]小于x[0]，则让x[1] 和x[1]进行交换，也就等于没交换。如果数组是5 4 3 2 1，则这里的交换就失效了。 再往后看，直到for循环结束，走出循环，让最后m指的位置的数和最初的key进行交换。如上面 5 4 3 2 1,则第一次快排的结果是 1 4 3 2 5，只有for出来后的那次swap才起作用。这里的m有个特殊含义，即指向小于key的最右边的那个数。所以出来后才用它(x[m])和key(即x[l])进行交换。\n单边扫描的特点:\n1、程序需要交换；\n2、更有冒泡法的色彩；冒泡的目的不是让最大的数沉到最右边，而是让小于key的都左移，找到分界索引m。使之和key进行交换。\n3、此版本的的单边扫描属于最基础的，还可以优化。\n本想测出两个算法的时间 消耗差异，遗憾的是c++获得程序运行时间太费劲了，弄半天没弄成。下面附上完整程序:\n**[cpp]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[copy](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[print](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[?](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/412329)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/412329/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//============================================================================\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Name : QuikSort.cpp\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Author : YanZi\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Version :\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Copyright : Your copyright notice\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Description : Hello World in C++, Ansi-style\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//============================================================================\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;preprocessor\u0026quot; style=\u0026quot;color: gray;\u0026quot;\u0026gt;#include \u0026lt;iostream\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;preprocessor\u0026quot; style=\u0026quot;color: gray;\u0026quot;\u0026gt;#include \u0026lt;malloc.h\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;using\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;namespace\u0026lt;/span\u0026gt; std; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; swap1(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; a, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; printArray(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;* in, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; n); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; quickSort1(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;* x, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//双边扫描，快速排序\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; quickSort2(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x[], \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//单边扫描，快速排序\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; swap2(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026amp;a,\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026amp;b); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//交换，在MinGW上必须采用此方法，swap1无效\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;preprocessor\u0026quot; style=\u0026quot;color: gray;\u0026quot;\u0026gt;#define N 8 //数组的长度\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; main() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;* input = NULL; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; input = (\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;*)malloc(N * \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;sizeof\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(input == NULL){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; cout\u0026lt;\u0026lt;\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;内存溢出\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;\u0026lt;endl; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = 0; i \u0026lt; N; i++){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; input[i] = rand(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// int input[] = {55, 41, 59, 26, 53, 58, 97, 93};\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; cout\u0026lt;\u0026lt;\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;原始数据:\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;\u0026lt;endl; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; printArray(input, N); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; quickSort2(input, 0, N-1); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; printArray(input, N); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; 0; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; swap1(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; a, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; b){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; temp = a; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; a = b; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; b = temp; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; printArray(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; * in, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; n){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(in == NULL){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = 0; i\u0026lt;n; i++){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; cout\u0026lt;\u0026lt;\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8221; \u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;\u0026lt;in[i]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; cout\u0026lt;\u0026lt;endl; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; quickSort1(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;* x, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(l \u0026lt; r){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = l, j = r, key = x[l]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(i \u0026lt; j){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;( i \u0026lt; j \u0026amp;\u0026amp; x[j] \u0026gt;= key){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; j\u0026amp;#8211;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(i \u0026lt; j){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; x[i++] = x[j]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(i \u0026lt; j \u0026amp;\u0026amp; x[i] \u0026lt;= key){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; i++; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(i \u0026lt; j){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; x[j\u0026amp;#8211;] = x[i]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; cout\u0026lt;\u0026lt;\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;i = \u0026amp;#8220;\u0026lt;/span\u0026gt; \u0026lt;\u0026lt;i\u0026lt;\u0026lt;\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8221; j = \u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;\u0026lt;j\u0026lt;\u0026lt;endl; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; x[i] = key; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; quickSort1(x, l, i-1); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; quickSort1(x, i+1, r); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; quickSort2(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x[], \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(l \u0026gt;= r) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; m = l; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = l + l; i \u0026lt;= r; i++ ){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(x[i] \u0026lt; x[l]){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; swap2(x[++m], x[i]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; swap2(x[l], x[m]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; quickSort2(x, l, m \u0026amp;#8211; 1); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; quickSort2(x, m + 1, r); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; swap2(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026amp;a,\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; \u0026amp;b){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(a==b) \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//对同一地址的数据交换，会使其结果为0\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; a=a^b; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; b=a^b; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; a=a^b; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - ","permalink":"https://blog.zdltech.com/posts/%E7%AE%97%E6%B3%95%E6%95%B4%E7%90%86%E4%BA%8C-%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F%E7%9A%84%E4%B8%A4%E7%A7%8D%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F%E5%8F%8C%E8%BE%B9%E6%89%AB%E6%8F%8F%E5%92%8C/","summary":"\u003cp\u003e首先简单谈下快速排序的特点，时间复杂度O(nLog n)，最差时间复杂度O(n^2)，平均时间O(nLog n).因为用到了函数栈，空间复杂度为O(lg n),最差为O(n).是一种不稳定的排序方法。基本思想是分治法，这位大大的\u003ca href=\"http://blog.csdn.net/morewindows/article/details/6684558\"\u003ehttp://blog.csdn.net/morewindows/article/details/6684558\u003c/a\u003e 讲的非常清楚了，分治法+挖坑法，我就不多说了。就是以某个数为参照，使得左边的都小于他，右边的数都大于他。然后对他的左右两个区间采取同样的方法进行递归。\u003c/p\u003e\n\u003cp\u003e就其整体实现而言，有两大种思路，一是双边扫描，二是单边扫描。下面分别来上程序:\u003c/p\u003e\n\u003ch1 id=\"一双边扫描\"\u003e\u003ca style=\"color: #336699;\" name=\"t0\"\u003e\u003c/a\u003e一、双边扫描\u003c/h1\u003e\n\u003cp\u003e双边扫描是谭浩强书中的方法，个人觉得比下面的单边扫描更好理解，也是\u003ca href=\"http://blog.csdn.net/morewindows/article/details/6684558\"\u003e博文\u003c/a\u003e里采用的方法。下面看程序:\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_cpp\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[cpp]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[copy](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[print](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[?](http://blog.csdn.net/yanzi1225627/article/details/36045001#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/412329)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/412329/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; quickSort1(\u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;* x, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; l, \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; r){  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(l \u0026lt; r){  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;datatypes\u0026quot; style=\u0026quot;font-weight: bold; color: #2e8b57;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = l, j = r, key = x[l];  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(i \u0026lt; j){  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;( i \u0026lt; j \u0026amp;\u0026amp; x[j] \u0026gt;= key){  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                j\u0026amp;#8211;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(i \u0026lt; j){  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                x[i++] = x[j];  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(i \u0026lt; j \u0026amp;\u0026amp; x[i] \u0026lt;= key){  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                i++;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(i \u0026lt; j){  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                x[j\u0026amp;#8211;] = x[i];  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        cout\u0026lt;\u0026lt;\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;i = \u0026amp;#8220;\u0026lt;/span\u0026gt; \u0026lt;\u0026lt;i\u0026lt;\u0026lt;\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8221; j = \u0026amp;#8220;\u0026lt;/span\u0026gt;\u0026lt;\u0026lt;j\u0026lt;\u0026lt;endl;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        x[i] = key;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        quickSort1(x, l, i-1);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        quickSort1(x, i+1, r);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e双边扫描非常直观，首先进到程序里判断是否l\u0026lt;r,当满足条件才进去。这也是用递归的一个必要条件，一定要让函数有尽头，有边界。然后进入大while循环，接着进入小while循环，先从右边找，只要满足数字大于key就一直让j往左移。直到第一个不满足条件的，就是第一个小于key的数跳出while循环，将它放在左边挖的“坑”上。同时让坑的索引+1，接着从左边开始扫描，找到第一个大于key的数，再将它填到右边的坑上。右边的坑索引-1，接着再从右边扫描。直到最后跳出大while循环，此时i = j。也就是完成了一次快速排序的扫描。之后将最初的key放到x[i]，其实放到x[j]也是一样的。因为i等于j么，此时！然后进行递归，对区间[l, i – 1], [i+1, r]进行同样的操作。\u003c/p\u003e","title":"算法整理(二)—快速排序的两种实现方式:双边扫描和单边扫描"},{"content":"GLSurfaceView是OpenGL中的一个类，也是可以预览Camera的，而且在预览Camera上有其独到之处。独到之处在哪？当使用Surfaceview无能为力、痛不欲生时就只有使用GLSurfaceView了，它能够真正做到让Camera的数据和显示分离，所以搞明白了这个，像Camera只开预览不显示这都是小菜，妥妥的。Android4.0的自带Camera源码是用SurfaceView预览的，但到了4.2就换成了GLSurfaceView来预览。如今到了4.4又用了自家的TextureView，所以从中可以窥探出新增TextureView的用意。\n虽说Android4.2的Camera源码是用GLSurfaceView预览的，但是进行了大量的封装又封装的，由于是OpenGL小白，真是看的不知所云。俺滴要求不高，只想弄个可拍照的摸清GLSurfaceView在预览Camera上的使用流程。经过一番百度一无所获，后来翻出去Google一大圈也没发现可用的。倒是很多人都在用GLSurfaceView和Surfaceview同时预览Camera，Surfaceview用来预览数据，在上面又铺了一层GLSurfaceView绘制一些信息。无奈自己摸索，整出来的是能拍照也能得到数据，但是界面上不是一块白板就是一块黑板啥都不显示。后来在stackoverflow终于找到了一个可用的链接，哈哈，苍天啊，终于柳暗花明了！参考此链接，自己又改改摸索了一天才彻底搞定。之所以费这么多时间是不明白OpenGL ES2.0的绘制基本流程，跟简单的OpenGL的绘制还是稍有区别。下面上源码:\n一、CameraGLSurfaceView.java 此类继承GLSurfaceView，并实现了两个接口\n**[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[copy](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[print](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[?](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/402612)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/402612/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.camera.preview; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; javax.microedition.khronos.egl.EGLConfig; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; javax.microedition.khronos.opengles.GL10; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.camera.CameraInterface; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.SurfaceTexture; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLES11Ext; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLES20; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLSurfaceView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLSurfaceView.Renderer; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; CameraGLSurfaceView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; GLSurfaceView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Renderer, SurfaceTexture.OnFrameAvailableListener { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;yanzi\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Context mContext; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; SurfaceTexture mSurface; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; DirectDrawer mDirectDrawer; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; CameraGLSurfaceView(Context context, AttributeSet attrs) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated constructor stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mContext = context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setEGLContextClientVersion(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setRenderer(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setRenderMode(RENDERMODE_WHEN_DIRTY); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSurfaceCreated(GL10 gl, EGLConfig config) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;onSurfaceCreated\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mTextureID = createTextureID(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mSurface = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SurfaceTexture(mTextureID); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mSurface.setOnFrameAvailableListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mDirectDrawer = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DirectDrawer(mTextureID); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; CameraInterface.getInstance().doOpenCamera(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSurfaceChanged(GL10 gl, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;onSurfaceChanged\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glViewport(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, width, height); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!CameraInterface.getInstance().isPreviewing()){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; CameraInterface.getInstance().doStartPreview(mSurface, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.33f); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDrawFrame(GL10 gl) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;onDrawFrame\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glClearColor(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mSurface.updateTexImage(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] mtx = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mSurface.getTransformMatrix(mtx); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mDirectDrawer.draw(mtx); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onPause() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onPause(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; CameraInterface.getInstance().doStopCamera(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; createTextureID() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] texture = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glGenTextures(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, texture, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; texture[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SurfaceTexture _getSurfaceTexture(){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mSurface; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onFrameAvailable(SurfaceTexture surfaceTexture) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;onFrameAvailable\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.requestRender(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 关于这个类进行简单说明:\n1、Renderer这个接口里有三个回调: onSurfaceCreated() onSurfaceChanged() onDrawFrame(),在onSurfaceCreated里设置了GLSurfaceView的版本: setEGLContextClientVersion(2); 如果没这个设置是啥都画不出来了，因为Android支持OpenGL ES1.1和2.0及最新的3.0，而且版本间差别很大。不告诉他版本他不知道用哪个版本的api渲染。在设置setRenderer(this);后，再设置它的模式为RENDERMODE_WHEN_DIRTY。这个也很关键，看api：\nWhen renderMode is RENDERMODE_CONTINUOUSLY, the renderer is called repeatedly to re-render the scene. When renderMode is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface is created, or when [requestRender](eclipse-javadoc:%E2%98%82=PlayCamera_V3.0.0/D:%5C/ProgramFile%5C/adt-bundle-windows-x86-20130522%5C/sdk%5C/platforms%5C/android-19%5C/android.jar%3Candroid.opengl(GLSurfaceView.class%E2%98%83GLSurfaceView~setRenderMode~I%E2%98%82%E2%98%82requestRender) is called. Defaults to RENDERMODE_CONTINUOUSLY.\nUsing RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance by allowing the GPU and CPU to idle when the view does not need to be updated.\n大意是RENDERMODE_CONTINUOUSLY模式就会一直Render，如果设置成RENDERMODE_WHEN_DIRTY，就是当有数据时才rendered或者主动调用了GLSurfaceView的requestRender.默认是连续模式，很显然Camera适合脏模式，一秒30帧，当有数据来时再渲染。\n2、正因是RENDERMODE_WHEN_DIRTY所以就要告诉GLSurfaceView什么时候Render，也就是啥时候进到onDrawFrame()这个函数里。SurfaceTexture.OnFrameAvailableListener这个接口就干了这么一件事，当有数据上来后会进到\npublic void onFrameAvailable(SurfaceTexture surfaceTexture) {\n// TODO Auto-generated method stub\nLog.i(TAG, “onFrameAvailable…”);\nthis.requestRender();\n}\n这里，然后执行requestRender()。\n3、网上有一些OpenGL ES的示例是在Activity里实现了SurfaceTexture.OnFrameAvailableListener此接口，其实这个无所谓。无论是被谁实现，关键看在回调里干了什么事。\n4、与TextureView里对比可知，TextureView预览时因为实现了SurfaceTextureListener会自动创建SurfaceTexture。但在GLSurfaceView里则要手动创建同时绑定一个纹理ID。\n5、本文在onSurfaceCreated()里打开Camera，在onSurfaceChanged()里开启预览，默认1.33的比例。原因是相比前两种预览，此处SurfaceTexture创建需要一定时间。如果想要开预览时由Activity发起，则要GLSurfaceView利用Handler将创建的SurfaceTexture传递给Activity。\n二、DirectDrawer.java 此类非常关键，负责将SurfaceTexture内容绘制到屏幕上\n**[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[copy](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[print](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[?](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/402612)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/402612/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.camera.preview; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.nio.ByteBuffer; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.nio.ByteOrder; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.nio.FloatBuffer; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.nio.ShortBuffer; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLES11Ext; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLES20; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.Matrix; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; DirectDrawer { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String vertexShaderCode = \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;attribute vec4 vPosition;\u0026amp;#8221;\u0026lt;/span\u0026gt; + \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;attribute vec2 inputTextureCoordinate;\u0026amp;#8221;\u0026lt;/span\u0026gt; + \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;varying vec2 textureCoordinate;\u0026amp;#8221;\u0026lt;/span\u0026gt; + \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;void main()\u0026amp;#8221;\u0026lt;/span\u0026gt; + \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;{\u0026amp;#8220;\u0026lt;/span\u0026gt;+ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;gl_Position = vPosition;\u0026amp;#8221;\u0026lt;/span\u0026gt;+ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;textureCoordinate = inputTextureCoordinate;\u0026amp;#8221;\u0026lt;/span\u0026gt; + \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;}\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String fragmentShaderCode = \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;#extension GL_OES_EGL_image_external : require\\n\u0026amp;#8221;\u0026lt;/span\u0026gt;+ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;precision mediump float;\u0026amp;#8221;\u0026lt;/span\u0026gt; + \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;varying vec2 textureCoordinate;\\n\u0026amp;#8221;\u0026lt;/span\u0026gt; + \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;uniform samplerExternalOES s_texture;\\n\u0026amp;#8221;\u0026lt;/span\u0026gt; + \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;void main() {\u0026amp;#8220;\u0026lt;/span\u0026gt; + \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8221; gl_FragColor = texture2D( s_texture, textureCoordinate );\\n\u0026amp;#8221;\u0026lt;/span\u0026gt; + \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;}\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; FloatBuffer vertexBuffer, textureVerticesBuffer; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ShortBuffer drawListBuffer; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mProgram; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mPositionHandle; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mTextureCoordHandle; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;short\u0026lt;/span\u0026gt; drawOrder[] = { \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;3\u0026lt;/span\u0026gt; }; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// order to draw vertices\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// number of coordinates per vertex in this array\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; COORDS_PER_VERTEX = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; vertexStride = COORDS_PER_VERTEX * \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 4 bytes per vertex\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; squareCoords[] = { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; textureVertices[] = { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0f, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;.0f, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; texture; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; DirectDrawer(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; texture) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.texture = texture; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// initialize vertex byte buffer for shape coordinates\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; bb.order(ByteOrder.nativeOrder()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; vertexBuffer = bb.asFloatBuffer(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; vertexBuffer.put(squareCoords); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; vertexBuffer.position(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// initialize byte buffer for the draw list\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; dlb.order(ByteOrder.nativeOrder()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; drawListBuffer = dlb.asShortBuffer(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; drawListBuffer.put(drawOrder); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; drawListBuffer.position(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ByteBuffer bb2 = ByteBuffer.allocateDirect(textureVertices.length * \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; bb2.order(ByteOrder.nativeOrder()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; textureVerticesBuffer = bb2.asFloatBuffer(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; textureVerticesBuffer.put(textureVertices); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; textureVerticesBuffer.position(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mProgram = GLES20.glCreateProgram(); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// create empty OpenGL ES Program\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glAttachShader(mProgram, vertexShader); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// add the vertex shader to program\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glAttachShader(mProgram, fragmentShader); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// add the fragment shader to program\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glLinkProgram(mProgram); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// creates OpenGL ES program executables\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; draw(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] mtx) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glUseProgram(mProgram); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glActiveTexture(GLES20.GL_TEXTURE0); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// get handle to vertex shader\u0026amp;#8217;s vPosition member\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mPositionHandle = GLES20.glGetAttribLocation(mProgram, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;vPosition\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Enable a handle to the triangle vertices\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glEnableVertexAttribArray(mPositionHandle); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Prepare the \u0026lt;insert shape here\u0026gt; coordinate data\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, vertexStride, vertexBuffer); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mTextureCoordHandle = GLES20.glGetAttribLocation(mProgram, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;inputTextureCoordinate\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glEnableVertexAttribArray(mTextureCoordHandle); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// textureVerticesBuffer.clear();\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// textureVerticesBuffer.put( transformTextureCoordinates( textureVertices, mtx ));\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// textureVerticesBuffer.position(0);\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glVertexAttribPointer(mTextureCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;, vertexStride, textureVerticesBuffer); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Disable vertex array\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glDisableVertexAttribArray(mPositionHandle); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glDisableVertexAttribArray(mTextureCoordHandle); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; loadShader(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; type, String shaderCode){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// create a vertex shader type (GLES20.GL_VERTEX_SHADER)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; shader = GLES20.glCreateShader(type); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// add the source code to the shader and compile it\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glShaderSource(shader, shaderCode); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; GLES20.glCompileShader(shader); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; shader; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] transformTextureCoordinates( \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] coords, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] matrix) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] result = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[ coords.length ]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] vt = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;4\u0026lt;/span\u0026gt;]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; ( \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; ; i \u0026lt; coords.length ; i += \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; ) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] v = { coords[i], coords[i+\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;], \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; , \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; }; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Matrix.multiplyMV(vt, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, matrix, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, v, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; result[i] = vt[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; result[i+\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;] = vt[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; result; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 三、有了上面两个类就完成95%的工作，可以将GLSurfaceView看成是有生命周期的。在onPause里进行关闭Camera，在Activity里复写两个方法:\n**[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[copy](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[print](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[?](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/402612)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/402612/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onResume() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onResume(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; glSurfaceView.bringToFront(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onPause() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onPause(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; glSurfaceView.onPause(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 这个glSurfaceView.bringToFront();其实不写也中。在布局里写入自定义的GLSurfaceView就ok了:\n**[html]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[copy](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[print](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[?](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/402612)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/402612/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;FrameLayout\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;org.yanzi.camera.preview.CameraGLSurfaceView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/camera_textureview\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;FrameLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; CameraActivity里只负责UI部分，CameraGLSurfaceView负责开Camera、预览，并调用DirectDrawer里的draw()进行绘制。其他代码就不上了。\n注意事项:\n1、**在onDrawFrame()里，如果不调用mDirectDrawer.draw(mtx);是啥都显示不出来的！！！**这是GLSurfaceView的特别之处。为啥呢？因为GLSurfaceView不是Android亲生的，而Surfaceview和TextureView是。所以得自己按照OpenGL ES的流程画。\n2、究竟mDirectDrawer.draw(mtx)里在哪获取的Buffer目前杂家还么看太明白，貌似么有请求buffer，而是根据GLSurfaceView里创建的SurfaceTexture之前，生成的有个纹理ID。这个纹理ID一方面跟SurfaceTexture是绑定在一起的，另一方面跟DirectDrawer绑定，而SurfaceTexture作渲染载体。\n3、参考链接里有,有人为了解决问题，给出了下面三段代码:\n@Override public void onDrawFrame(GL10 gl) { float[] mtx = new float[16]; mSurface.updateTexImage(); mSurface.getTransformMatrix(mtx); mDirectVideo.draw(mtx); } private float[] transformTextureCoordinates( float[] coords, float[] matrix) { float[] result = new float[ coords.length ]; float[] vt = new float[4]; for ( int i = 0 ; i \u0026lt; coords.length ; i += 2 ) { float[] v = { coords[i], coords[i+1], 0 , 1 }; Matrix.multiplyMV(vt, 0, matrix, 0, v, 0); result[i] = vt[0]; result[i+1] = vt[1]; } return result; } textureVerticesBuffer.clear(); textureVerticesBuffer.put( transformTextureCoordinates( textureVertices, mtx )); textureVerticesBuffer.position(0); 我已经把代码都融入到了此demo，只不过在draw()方法里么有使用。原因是使用之后，得到的预览画面反而是变形的，而不用的话是ok的。上面的代码是得到SurfaceTexture的变换矩阵：mSurface.getTransformMatrix\n然后将此矩阵传递给draw()，在draw的时候对textureVerticesBuffer作一个变化，然后再画。\n下图是未加这个矩阵变换效果时:\n下图为使用了变换矩阵，划片扭曲的还真说不上来咋扭曲的，但足以说明OpenGL ES在渲染效果上的强大，就是设置了个矩阵，不用一帧帧处理，就能得到不一样显示效果。\n版本号:PlayCamera_V3.0.0[2014-6-22].zip\nCSDN下载链接:http://download.csdn.net/detail/yanzi1225627/7547263\n百度云盘:\n附个OpenGL ES简明教程：http://www.apkbus.com/android-20427-1-1.html\n","permalink":"https://blog.zdltech.com/posts/%E7%8E%A9%E8%BD%ACandroid-camera%E5%BC%80%E5%8F%91%E4%B8%89%E5%9B%BD%E5%86%85%E9%A6%96%E5%8F%91-%E4%BD%BF%E7%94%A8glsurfaceview%E9%A2%84%E8%A7%88camera-%E5%9F%BA%E7%A1%80%E6%8B%8D%E7%85%A7demo/","summary":"\u003cp\u003eGLSurfaceView是OpenGL中的一个类，也是可以预览Camera的，而且在预览Camera上有其独到之处。独到之处在哪？当使用Surfaceview无能为力、痛不欲生时就只有使用GLSurfaceView了，它能够真正做到让Camera的数据和显示分离，所以搞明白了这个，像Camera只开预览不显示这都是小菜，妥妥的。Android4.0的自带Camera源码是用SurfaceView预览的，但到了4.2就换成了GLSurfaceView来预览。如今到了4.4又用了自家的TextureView，所以从中可以窥探出新增TextureView的用意。\u003c/p\u003e\n\u003cp\u003e虽说Android4.2的Camera源码是用GLSurfaceView预览的，但是进行了大量的封装又封装的，由于是OpenGL小白，真是看的不知所云。俺滴要求不高，只想弄个可拍照的摸清GLSurfaceView在预览Camera上的使用流程。经过一番百度一无所获，后来翻出去Google一大圈也没发现可用的。倒是很多人都在用GLSurfaceView和Surfaceview同时预览Camera，Surfaceview用来预览数据，在上面又铺了一层GLSurfaceView绘制一些信息。无奈自己摸索，整出来的是能拍照也能得到数据，但是界面上不是一块白板就是一块黑板啥都不显示。后来在stackoverflow终于找到了一个可用的\u003ca href=\"http://stackoverflow.com/questions/19852680/android-opengl-camera-preview-issue\"\u003e链接\u003c/a\u003e，哈哈，苍天啊，终于柳暗花明了！参考此链接，自己又改改摸索了一天才彻底搞定。之所以费这么多时间是不明白OpenGL ES2.0的绘制基本流程，跟简单的OpenGL的绘制还是稍有区别。下面上源码:\u003c/p\u003e\n\u003cp\u003e一、CameraGLSurfaceView.java 此类继承GLSurfaceView，并实现了两个接口\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[copy](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[print](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[?](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/402612)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/402612/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.camera.preview;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; javax.microedition.khronos.egl.EGLConfig;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; javax.microedition.khronos.opengles.GL10;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.camera.CameraInterface;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.SurfaceTexture;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLES11Ext;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLES20;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLSurfaceView;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.opengl.GLSurfaceView.Renderer;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; CameraGLSurfaceView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; GLSurfaceView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Renderer, SurfaceTexture.OnFrameAvailableListener {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;yanzi\u0026amp;#8221;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    Context mContext;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    SurfaceTexture mSurface;  \u0026lt;/span\u0026gt;\n\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    DirectDrawer mDirectDrawer;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; CameraGLSurfaceView(Context context, AttributeSet attrs) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated constructor stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mContext = context;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        setEGLContextClientVersion(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        setRenderer(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        setRenderMode(RENDERMODE_WHEN_DIRTY);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSurfaceCreated(GL10 gl, EGLConfig config) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;onSurfaceCreated\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mTextureID = createTextureID();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mSurface = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SurfaceTexture(mTextureID);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mSurface.setOnFrameAvailableListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mDirectDrawer = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DirectDrawer(mTextureID);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        CameraInterface.getInstance().doOpenCamera(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onSurfaceChanged(GL10 gl, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;onSurfaceChanged\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        GLES20.glViewport(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, width, height);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!CameraInterface.getInstance().isPreviewing()){  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            CameraInterface.getInstance().doStartPreview(mSurface, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.33f);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDrawFrame(GL10 gl) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;onDrawFrame\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        GLES20.glClearColor(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;.0f);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mSurface.updateTexImage();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[] mtx = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;16\u0026lt;/span\u0026gt;];  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mSurface.getTransformMatrix(mtx);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mDirectDrawer.draw(mtx);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onPause() {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onPause();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        CameraInterface.getInstance().doStopCamera();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; createTextureID()  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] texture = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        GLES20.glGenTextures(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, texture, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR);          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; texture[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SurfaceTexture _getSurfaceTexture(){  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mSurface;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onFrameAvailable(SurfaceTexture surfaceTexture) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;onFrameAvailable\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.requestRender();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e关于这个类进行简单说明:\u003c/p\u003e","title":"玩转Android Camera开发(三):国内首发—使用GLSurfaceView预览Camera 基础拍照demo"},{"content":"杂家前文曾写过一篇关于只拍摄特定区域图片的demo，只是比较简陋，在坐标的换算上不是很严谨，而且没有完成预览界面四周暗中间亮的效果，深以为憾，今天把这个补齐了。\n在上代码之前首先交代下，这里面存在着换算的两种模式。第一种，是以屏幕上的矩形区域为基准进行换算。举个例子，屏幕中间一个 矩形框为100dip*100dip.这里一定要使用dip为单位，否则在不同的手机上屏幕呈现的矩形框大小不一样。先将这个dip换算成px，然后根据屏幕的宽和高的像素计算出矩形区域，传给Surfaceview上铺的一层View，这里叫MaskView(蒙板),让MaskView进行绘制。然后拍照时，通过屏幕矩形框的大小和屏幕的大小与最终拍摄图片的PictureSize进行换算，得到图片里的矩形区域图片，然后截取保存。第二种模式是，预先知道想要的图片的长宽，如我就是想截400*400（单位为px）大小的图片。那就以此为基准，换算出屏幕上呈现的Rect的长宽，然后让MaskView绘制。究竟用哪一种模式，按需选择。本文以第一种模式示例。下面上代码:\n在杂家的前文基础上进行封装，首先封装一个MaskView,用来绘制四周暗中间亮的效果，或者你可以加一个滚动条，这都不是事。\n一、MaskView.java **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[copy](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[print](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[?](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/407657)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/407657/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.ui; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.util.DisplayUtil; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Color; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint.Style; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Point; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Rect; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MaskView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ImageView { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;YanZi\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Paint mLinePaint; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Paint mAreaPaint; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Rect mCenterRect = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context mContext; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MaskView(Context context, AttributeSet attrs) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated constructor stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; initPaint(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mContext = context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Point p = DisplayUtil.getScreenMetrics(mContext); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; widthScreen = p.x; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; heightScreen = p.y; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initPaint(){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//绘制中间透明区域矩形边界的Paint\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mLinePaint = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(Paint.ANTI_ALIAS_FLAG); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mLinePaint.setColor(Color.BLUE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mLinePaint.setStyle(Style.STROKE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mLinePaint.setStrokeWidth(5f); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mLinePaint.setAlpha(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;30\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//绘制四周阴影区域\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mAreaPaint = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(Paint.ANTI_ALIAS_FLAG); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mAreaPaint.setColor(Color.GRAY); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mAreaPaint.setStyle(Style.FILL); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mAreaPaint.setAlpha(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;180\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setCenterRect(Rect r){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;setCenterRect\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mCenterRect = r; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; postInvalidate(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; clearCenterRect(Rect r){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mCenterRect = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthScreen, heightScreen; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;onDraw\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mCenterRect == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//绘制四周阴影区域\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; canvas.drawRect(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, widthScreen, mCenterRect.top, mAreaPaint); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; canvas.drawRect(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, mCenterRect.bottom + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, widthScreen, heightScreen, mAreaPaint); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; canvas.drawRect(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, mCenterRect.top, mCenterRect.left \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, mCenterRect.bottom + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, mAreaPaint); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; canvas.drawRect(mCenterRect.right + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, mCenterRect.top, widthScreen, mCenterRect.bottom + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, mAreaPaint); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//绘制目标透明区域\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; canvas.drawRect(mCenterRect, mLinePaint); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDraw(canvas); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 说明如下:\n1、为了让这个MaskView有更好的适配型，里面设置变量mCenterRect，这个矩阵的坐标就是已经换算好的，对屏幕的尺寸进行适配过的，以全屏下的屏幕宽高为坐标系，不需要再换算了。\n2、当然这个MaskView是全屏的，这里修改下PlayCamera_V1.0.0中的一个小问题,我将它的布局换成如下:\n**[html]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[copy](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[print](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[?](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/407657)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/407657/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;.CameraActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;FrameLayout\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;org.yanzi.camera.preview.CameraSurfaceView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/camera_surfaceview\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;org.yanzi.ui.MaskView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/view_mask\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;FrameLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;ImageButton\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/btn_shutter\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_alignParentBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_centerHorizontal\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_marginBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;10dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/btn_shutter_background\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 更改的地方是让FrameLayout直接全屏，不要设置成wrap_content，如果设它为wrap，代码里调整Surfaceview的大小，而MaskView设为wrap的话，它会认为MaskView的长宽也是0.另外，让Framelayout全屏，在日后16:9和4:3切换时，可以通过设置Surfaceview的margin来调整预览布局的大小，所以预览的母布局FrameLayout必须全屏。\n3.关于绘制阴影区域的代码里的+1 -1这几个小地方尽量不要错，按本文写就不会错。顺序是先绘制最上面、最下面、左侧、右侧四个区域的阴影。\n**[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[copy](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[print](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[?](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/407657)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/407657/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//绘制四周阴影区域\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; canvas.drawRect(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, widthScreen, mCenterRect.top, mAreaPaint); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; canvas.drawRect(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, mCenterRect.bottom + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, widthScreen, heightScreen, mAreaPaint); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; canvas.drawRect(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, mCenterRect.top, mCenterRect.left \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, mCenterRect.bottom + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, mAreaPaint); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; canvas.drawRect(mCenterRect.right + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, mCenterRect.top, widthScreen, mCenterRect.bottom + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, mAreaPaint);\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 二、在CameraActivity.java里封装两个函数: **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[copy](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[print](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[?](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/407657)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/407657/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**生成拍照后图片的中间矩形的宽度和高度\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @param w 屏幕上的矩形宽度，单位px\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @param h 屏幕上的矩形高度，单位px\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Point createCenterPictureRect(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; w, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; h){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; wScreen = DisplayUtil.getScreenMetrics(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;).x; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; hScreen = DisplayUtil.getScreenMetrics(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;).y; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; wSavePicture = CameraInterface.getInstance().doGetPrictureSize().y; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//因为图片旋转了，所以此处宽高换位\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; hSavePicture = CameraInterface.getInstance().doGetPrictureSize().x; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//因为图片旋转了，所以此处宽高换位\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; wRate = (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;)(wSavePicture) / (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;)(wScreen); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; hRate = (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;)(hSavePicture) / (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt;)(hScreen); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; rate = (wRate \u0026lt;= hRate) ? wRate : hRate;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//也可以按照最小比率计算\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; wRectPicture = (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)( w * wRate); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; hRectPicture = (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)( h * hRate); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Point(wRectPicture, hRectPicture); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 生成屏幕中间的矩形\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @param w 目标矩形的宽度,单位px\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @param h 目标矩形的高度,单位px\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Rect createCenterScreenRect(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; w, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; h){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x1 = DisplayUtil.getScreenMetrics(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;).x / \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; \u0026amp;#8211; w / \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y1 = DisplayUtil.getScreenMetrics(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;).y / \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; \u0026amp;#8211; h / \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x2 = x1 + w; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y2 = y1 + h; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect(x1, y1, x2, y2); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 分别是生成图片的中间矩形的宽和高组成的一个Point，生成屏幕中间的矩形区域。两个函数的输入参数都是px为单位的屏幕中间矩形的宽和高。这里有个条件：矩形以屏幕中心为中心，否则的话计算公式要适当变换下。\n三、在开启预览后，就可以让MaskView绘制了 **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[copy](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[print](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[?](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/407657)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/407657/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; cameraHasOpened() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; SurfaceHolder holder = surfaceView.getSurfaceHolder(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; CameraInterface.getInstance().doStartPreview(holder, previewRate); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(maskView != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Rect screenCenterRect = createCenterScreenRect(DisplayUtil.dip2px(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, DST_CENTER_RECT_WIDTH) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ,DisplayUtil.dip2px(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, DST_CENTER_RECT_HEIGHT)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; maskView.setCenterRect(screenCenterRect); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 这里有个注意事项:因为camera.open的时候是放在一个单独线程里的，open之后进行回调到cameraHasOpened()这里，那这个函数的执行时在主线程和子线程?答案也是在子线程，即子线程的回调还是在子线程里执行。正因此，在封装MaskView时set矩阵后用的是postInvalidate（）进行刷新的。\n**[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[copy](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[print](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[?](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/407657)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/407657/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setCenterRect(Rect r){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;setCenterRect\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mCenterRect = r; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; postInvalidate(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 四、最后就是告诉拍照的回调了 **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[copy](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[print](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[?](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/407657)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/407657/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; BtnListeners \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnClickListener{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt;(v.getId()){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.btn_shutter: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(rectPictureSize == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; rectPictureSize = createCenterPictureRect(DisplayUtil.dip2px(CameraActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, DST_CENTER_RECT_WIDTH) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ,DisplayUtil.dip2px(CameraActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, DST_CENTER_RECT_HEIGHT)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; CameraInterface.getInstance().doTakePicture(rectPictureSize.x, rectPictureSize.y); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;:\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 上面是拍照的监听，在CameraInterface里重写一个doTakePicture函数:\n**[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[copy](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[print](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[?](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/407657)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/407657/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; DST_RECT_WIDTH, DST_RECT_HEIGHT; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; doTakePicture(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; w, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; h){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(isPreviewing \u0026amp;\u0026amp; (mCamera != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;矩形拍照尺寸:width = \u0026amp;#8220;\u0026lt;/span\u0026gt; + w + \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8221; h = \u0026amp;#8220;\u0026lt;/span\u0026gt; + h); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; DST_RECT_WIDTH = w; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; DST_RECT_HEIGHT = h; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mCamera.takePicture(mShutterCallback, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, mRectJpegPictureCallback); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 这里出来个mRectJpegPictureCallback，它对应的类:\n**[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[copy](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[print](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[?](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/407657)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/407657/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 拍摄指定区域的Rect\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; PictureCallback mRectJpegPictureCallback = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PictureCallback() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//对jpeg图像数据的回调,最重要的一个回调\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onPictureTaken(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;byte\u0026lt;/span\u0026gt;[] data, Camera camera) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;myJpegCallback:onPictureTaken\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Bitmap b = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; != data){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; b = BitmapFactory.decodeByteArray(data, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, data.length);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//data是字节数据，将其解析成位图\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mCamera.stopPreview(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; isPreviewing = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//保存图片到sdcard\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; != b) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//设置FOCUS_MODE_CONTINUOUS_VIDEO)之后，myParam.set(\u0026amp;#8220;rotation\u0026amp;#8221;, 90)失效。\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//图片竟然不能旋转了，故这里要旋转下\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Bitmap rotaBitmap = ImageUtil.getRotateBitmap(b, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;90\u0026lt;/span\u0026gt;.0f); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x = rotaBitmap.getWidth()/\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; \u0026amp;#8211; DST_RECT_WIDTH/\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; y = rotaBitmap.getHeight()/\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; \u0026amp;#8211; DST_RECT_HEIGHT/\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;rotaBitmap.getWidth() = \u0026amp;#8220;\u0026lt;/span\u0026gt; + rotaBitmap.getWidth() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; + \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8221; rotaBitmap.getHeight() = \u0026amp;#8220;\u0026lt;/span\u0026gt; + rotaBitmap.getHeight()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Bitmap rectBitmap = Bitmap.createBitmap(rotaBitmap, x, y, DST_RECT_WIDTH, DST_RECT_HEIGHT); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; FileUtil.saveBitmap(rectBitmap); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(rotaBitmap.isRecycled()){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; rotaBitmap.recycle(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; rotaBitmap = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(rectBitmap.isRecycled()){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; rectBitmap.recycle(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; rectBitmap = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//再次进入预览\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mCamera.startPreview(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; isPreviewing = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!b.isRecycled()){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; b.recycle(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; b = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; };\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 注意事项:\n1、为了让截出的区域和屏幕上显示的完全一致，这里首先要满足PreviewSize长宽比、PictureSize长宽比、屏幕预览Surfaceview的长宽比为同一比例，这是个先决条件。然后再将屏幕矩形区域长宽换算成图片矩形区域时:\n/**生成拍照后图片的中间矩形的宽度和高度\n@param w 屏幕上的矩形宽度，单位px @param h 屏幕上的矩形高度，单位px @return\n*/\nprivate Point createCenterPictureRect(int w, int h){ int wScreen = DisplayUtil.getScreenMetrics(this).x;\nint hScreen = DisplayUtil.getScreenMetrics(this).y;\nint wSavePicture = CameraInterface.getInstance().doGetPrictureSize().y; //因为图片旋转了，所以此处宽高换位\nint hSavePicture = CameraInterface.getInstance().doGetPrictureSize().x; //因为图片旋转了，所以此处宽高换位\nfloat wRate = (float)(wSavePicture) / (float)(wScreen);\nfloat hRate = (float)(hSavePicture) / (float)(hScreen);\nfloat rate = (wRate \u0026lt;= hRate) ? wRate : hRate;//也可以按照最小比率计算\nint wRectPicture = (int)( w * wRate);\nint hRectPicture = (int)( h * hRate);\nreturn new Point(wRectPicture, hRectPicture);\n}\n原则上wRate 是应该等于hRate 的！！！！！！！！！！\n2、我对CamParaUtil里的getPropPreviewSize和getPropPictureSize进行了更新，以前是以width进行判断的，这里改成了以height进行判断。因为在读取参数时得到的是800*480(宽*高)这种类型，一般高是稍微小的，所以以height进行判断。而这个高在最终显示和保存时经过旋转又成了宽。\n**[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[copy](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[print](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[?](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/407657)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/407657/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Size getPropPictureSize(List\u0026lt;Camera.Size\u0026gt; list, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; th, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; minHeight){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Collections.sort(list, sizeComparator); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(Size s:list){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;((s.height \u0026gt;= minHeight) \u0026amp;\u0026amp; equalRate(s, th)){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;PictureSize : w = \u0026amp;#8220;\u0026lt;/span\u0026gt; + s.width + \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;h = \u0026amp;#8220;\u0026lt;/span\u0026gt; + s.height); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; i++; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(i == list.size()){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//如果没找到，就选最小的size\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; list.get(i); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 最后来看下效果吧，我设定屏幕上显示的矩形尺寸为200dip*200dip, Camera预览的参数是以屏幕的比例进行自动寻找，预览尺寸的height不小于400，PictureSize的height不小于1300.\n**[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[copy](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[print](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[?](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/407657)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/407657/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//设置PreviewSize和PictureSize\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Size pictureSize = CamParaUtil.getInstance().getPropPictureSize( \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mParams.getSupportedPictureSizes(),previewRate, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1300\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mParams.setPictureSize(pictureSize.width, pictureSize.height); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Size previewSize = CamParaUtil.getInstance().getPropPreviewSize( \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mParams.getSupportedPreviewSizes(), previewRate, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;400\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mParams.setPreviewSize(previewSize.width, previewSize.height);\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; ![](http://yspe2371e4aa7697989.yunshipei.cn/dHlwZT1mdyZzaXplPTY0MCZzcmM9YUhSMGNDVXpRU1V5UmlVeVJtbHRaeTVpYkc5bkxtTnpaRzR1Ym1WMEpUSkdNakF4TkRBMk1qWXlNakF6TkRJMU56Z2xNMFozWVhSbGNtMWhjbXNsTWtZeUpUSkdkR1Y0ZENVeVJtRklVakJqUkc5MlRESktjMkl5WTNWWk0wNXJZbWsxZFZwWVVYWmxWMFoxWlcxcmVFMXFTVEZPYWtrekpUSkdabTl1ZENVeVJqVmhOa3cxVERKVUpUSkdabTl1ZEhOcGVtVWxNa1kwTURBbE1rWm1hV3hzSlRKR1NUQktRbEZyUmtOTlFTVXpSQ1V6UkNVeVJtUnBjM052YkhabEpUSkdOekFsTWtabmNtRjJhWFI1SlRKR1EyVnVkR1Z5) ![](http://yspe2371e4aa7697989.yunshipei.cn/dHlwZT1mdyZzaXplPTY0MCZzcmM9YUhSMGNDVXpRU1V5UmlVeVJtbHRaeTVpYkc5bkxtTnpaRzR1Ym1WMEpUSkdNakF4TkRBMk1qWXlNakl4TURRd056Z2xNMFozWVhSbGNtMWhjbXNsTWtZeUpUSkdkR1Y0ZENVeVJtRklVakJqUkc5MlRESktjMkl5WTNWWk0wNXJZbWsxZFZwWVVYWmxWMFoxWlcxcmVFMXFTVEZPYWtrekpUSkdabTl1ZENVeVJqVmhOa3cxVERKVUpUSkdabTl1ZEhOcGVtVWxNa1kwTURBbE1rWm1hV3hzSlRKR1NUQktRbEZyUmtOTlFTVXpSQ1V6UkNVeVJtUnBjM052YkhabEpUSkdOekFsTWtabmNtRjJhWFI1SlRKR1EyVnVkR1Z5) 可以看到单纯的截取是不改变图像分辨率的，注意真正的分辨率的概念并不等于xxx * xxx，图片放的越大越不清楚。稍后推出矩形区域可以移动、且可拉伸的，拍摄任意位置的特定区域图片demo。 \u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;\u0026#8212;-本文系原创，转载请注明作者:yanzi1225627 代码下载链接： csdn：[http://download.csdn.net/detail/yanzi1225627/7557539](http://download.csdn.net/detail/yanzi1225627/7557539) ","permalink":"https://blog.zdltech.com/posts/%E7%8E%A9%E8%BD%ACandroid-camera%E5%BC%80%E5%8F%91%E5%9B%9B%E9%A2%84%E8%A7%88%E7%95%8C%E9%9D%A2%E5%9B%9B%E5%91%A8%E6%9A%97%E4%B8%AD%E9%97%B4%E4%BA%AE%E5%8F%AA%E6%8B%8D%E6%91%84%E7%9F%A9/","summary":"\u003cp\u003e杂家前文曾写过一篇关于\u003ca href=\"http://blog.csdn.net/yanzi1225627/article/details/8580034\"\u003e只拍摄特定区域图片的demo\u003c/a\u003e，只是比较简陋，在坐标的换算上不是很严谨，而且没有完成预览界面四周暗中间亮的效果，深以为憾，今天把这个补齐了。\u003c/p\u003e\n\u003cp\u003e在上代码之前首先交代下，这里面存在着换算的两种模式。第一种，是以屏幕上的矩形区域为基准进行换算。举个例子，屏幕中间一个 矩形框为100dip*100dip.这里一定要使用dip为单位，否则在不同的手机上屏幕呈现的矩形框大小不一样。先将这个dip换算成px，然后根据屏幕的宽和高的像素计算出矩形区域，传给Surfaceview上铺的一层View，这里叫MaskView(蒙板),让MaskView进行绘制。然后拍照时，通过屏幕矩形框的大小和屏幕的大小与最终拍摄图片的PictureSize进行换算，得到图片里的矩形区域图片，然后截取保存。第二种模式是，预先知道想要的图片的长宽，如我就是想截400*400（单位为px）大小的图片。那就以此为基准，换算出屏幕上呈现的Rect的长宽，然后让MaskView绘制。究竟用哪一种模式，按需选择。本文以第一种模式示例。下面上代码:\u003c/p\u003e\n\u003cp\u003e在杂家的\u003ca href=\"http://blog.csdn.net/yanzi1225627/article/details/33028041\"\u003e前文\u003c/a\u003e基础上进行封装，首先封装一个MaskView,用来绘制四周暗中间亮的效果，或者你可以加一个滚动条，这都不是事。\u003c/p\u003e\n\u003ch1 id=\"一maskviewjava\"\u003e\u003ca style=\"color: #336699;\" name=\"t0\"\u003e\u003c/a\u003e一、MaskView.java\u003c/h1\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[copy](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[print](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[?](http://blog.csdn.net/yanzi1225627/article/details/34931759#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/407657)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/407657/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family:Comic Sans MS;font-size:18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.ui;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.util.DisplayUtil;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Color;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint.Style;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Point;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Rect;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MaskView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ImageView {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;YanZi\u0026amp;#8221;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Paint mLinePaint;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Paint mAreaPaint;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Rect mCenterRect = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context mContext;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MaskView(Context context, AttributeSet attrs) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated constructor stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        initPaint();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mContext = context;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Point p = DisplayUtil.getScreenMetrics(mContext);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        widthScreen = p.x;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        heightScreen = p.y;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initPaint(){  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//绘制中间透明区域矩形边界的Paint\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mLinePaint = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(Paint.ANTI_ALIAS_FLAG);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mLinePaint.setColor(Color.BLUE);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mLinePaint.setStyle(Style.STROKE);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mLinePaint.setStrokeWidth(5f);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mLinePaint.setAlpha(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;30\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//绘制四周阴影区域\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mAreaPaint = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(Paint.ANTI_ALIAS_FLAG);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mAreaPaint.setColor(Color.GRAY);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mAreaPaint.setStyle(Style.FILL);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mAreaPaint.setAlpha(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;180\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setCenterRect(Rect r){  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;setCenterRect\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mCenterRect = r;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        postInvalidate();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; clearCenterRect(Rect r){  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mCenterRect = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; widthScreen, heightScreen;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;onDraw\u0026amp;#8230;\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mCenterRect == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;)  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//绘制四周阴影区域\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        canvas.drawRect(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, widthScreen, mCenterRect.top, mAreaPaint);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        canvas.drawRect(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, mCenterRect.bottom + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, widthScreen, heightScreen, mAreaPaint);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        canvas.drawRect(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, mCenterRect.top, mCenterRect.left \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, mCenterRect.bottom  + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, mAreaPaint);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        canvas.drawRect(mCenterRect.right + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, mCenterRect.top, widthScreen, mCenterRect.bottom + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;, mAreaPaint);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//绘制目标透明区域\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        canvas.drawRect(mCenterRect, mLinePaint);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDraw(canvas);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e说明如下:\u003c/p\u003e","title":"玩转Android Camera开发(四):预览界面四周暗中间亮，只拍摄矩形区域图片(附完整源码)"},{"content":"xUtils简介 xUtils 包含了很多实用的android工具。 xUtils 最初源于Afinal框架，进行了大量重构，使得xUtils支持大文件上传，更全面的http请求协议支持(10种谓词)，拥有更加灵活的ORM，更多的事件注解支持且不受混淆影响… xUitls最低兼容android 2.2 (api level 8) 目前xUtils主要有四大模块： DbUtils模块：\n- android中的orm框架，一行代码就可以进行增删改查； - 支持事务，默认关闭； - 可通过注解自定义表名，列名，外键，唯一性约束，NOT NULL约束，CHECK约束等（需要混淆的时候请注解表名和列名）； - 支持绑定外键，保存实体时外键关联实体自动保存或更新； - 自动加载外键关联实体，支持延时加载； - 支持链式表达查询，更直观的查询语义，参考下面的介绍或sample中的例子。 ViewUtils模块：\n- android中的ioc框架，完全注解方式就可以进行UI，资源和事件绑定； - 新的事件绑定方式，使用混淆工具混淆后仍可正常工作； - 目前支持常用的20种事件绑定，参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。 HttpUtils模块：\n- 支持同步，异步方式的请求； - 支持大文件上传，上传大文件不会oom； - 支持GET，POST，PUT，MOVE，COPY，DELETE，HEAD，OPTIONS，TRACE，CONNECT请求； - 下载支持301/302重定向，支持设置是否根据Content-Disposition重命名下载的文件； - 返回文本内容的请求(默认只启用了GET请求)支持缓存，可设置默认过期时间和针对当前请求的过期时间。 BitmapUtils模块：\n- 加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象； - 支持加载网络图片和本地图片； - 内存管理使用lru算法，更好的管理bitmap内存； - 可配置线程加载线程数量，缓存大小，缓存路径，加载显示动画等\u0026amp;#8230; 使用xUtils快速开发框架需要有以下权限： ``` \u0026lt;uses-permission android:name=\"android.permission.INTERNET\" /\u0026gt; \u0026lt;uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" /\u0026gt; ``` 混淆时注意事项： 添加Android默认混淆配置${sdk.dir}/tools/proguard/proguard-android.txt 不要混淆xUtils中的注解类型，添加混淆配置：-keep class * extends java.lang.annotation.Annotation { *; } 对使用DbUtils模块持久化的实体类不要混淆，或者注解所有表和列名称@Table(name=”xxx”)，@Id(column=”xxx”)，@Column(column=”xxx”),@Foreign(column=”xxx”,foreign=”xxx”)； ","permalink":"https://blog.zdltech.com/posts/android-%E5%B7%A5%E5%85%B7%E5%8C%85-xutils/","summary":"\u003ch2 id=\"xutils简介\"\u003exUtils简介\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003exUtils 包含了很多实用的android工具。\u003c/li\u003e\n\u003cli\u003exUtils 最初源于Afinal框架，进行了大量重构，使得xUtils支持大文件上传，更全面的http请求协议支持(10种谓词)，拥有更加灵活的ORM，更多的事件注解支持且不受混淆影响…\u003c/li\u003e\n\u003cli\u003exUitls最低兼容android 2.2 (api level 8)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"目前xutils主要有四大模块\"\u003e\u003ca href=\"https://github.com/wyouflf/xUtils#%E7%9B%AE%E5%89%8Dxutils%E4%B8%BB%E8%A6%81%E6%9C%89%E5%9B%9B%E5%A4%A7%E6%A8%A1%E5%9D%97\"\u003e\u003c/a\u003e目前xUtils主要有四大模块：\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eDbUtils模块：\u003c/p\u003e\n\u003cblockquote style=\"color: #777777;\"\u003e\n\u003cpre\u003e\u003ccode\u003e- android中的orm框架，一行代码就可以进行增删改查；\n\n- 支持事务，默认关闭；\n\n- 可通过注解自定义表名，列名，外键，唯一性约束，NOT NULL约束，CHECK约束等（需要混淆的时候请注解表名和列名）；\n\n- 支持绑定外键，保存实体时外键关联实体自动保存或更新；\n\n- 自动加载外键关联实体，支持延时加载；\n\n- 支持链式表达查询，更直观的查询语义，参考下面的介绍或sample中的例子。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eViewUtils模块：\u003c/p\u003e\n\u003cblockquote style=\"color: #777777;\"\u003e\n\u003cpre\u003e\u003ccode\u003e- android中的ioc框架，完全注解方式就可以进行UI，资源和事件绑定；\n\n- 新的事件绑定方式，使用混淆工具混淆后仍可正常工作；\n\n- 目前支持常用的20种事件绑定，参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eHttpUtils模块：\u003c/p\u003e\n\u003cblockquote style=\"color: #777777;\"\u003e\n\u003cpre\u003e\u003ccode\u003e- 支持同步，异步方式的请求；\n\n- 支持大文件上传，上传大文件不会oom；\n\n- 支持GET，POST，PUT，MOVE，COPY，DELETE，HEAD，OPTIONS，TRACE，CONNECT请求；\n\n- 下载支持301/302重定向，支持设置是否根据Content-Disposition重命名下载的文件；\n\n- 返回文本内容的请求(默认只启用了GET请求)支持缓存，可设置默认过期时间和针对当前请求的过期时间。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eBitmapUtils模块：\u003c/p\u003e\n\u003cblockquote style=\"color: #777777;\"\u003e\n\u003cpre\u003e\u003ccode\u003e- 加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象；\n\n- 支持加载网络图片和本地图片；\n\n- 内存管理使用lru算法，更好的管理bitmap内存；\n\n- 可配置线程加载线程数量，缓存大小，缓存路径，加载显示动画等\u0026amp;#8230;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr style=\"color: #000000;\" /\u003e\n\u003ch2 id=\"使用xutils快速开发框架需要有以下权限\"\u003e\u003ca href=\"https://github.com/wyouflf/xUtils#%E4%BD%BF%E7%94%A8xutils%E5%BF%AB%E9%80%9F%E5%BC%80%E5%8F%91%E6%A1%86%E6%9E%B6%E9%9C%80%E8%A6%81%E6%9C%89%E4%BB%A5%E4%B8%8B%E6%9D%83%E9%99%90\"\u003e\u003c/a\u003e使用xUtils快速开发框架需要有以下权限：\u003c/h2\u003e\n\u003cdiv class=\"highlight highlight-xml\" style=\"color: #000000;\"\u003e\n  ```\n\u003cspan style=\"color: #000080;\"\u003e\u0026lt;uses-permission\u003c/span\u003e \u003cspan style=\"color: #008080;\"\u003eandroid:name=\u003c/span\u003e\u003cspan style=\"color: #dd1144;\"\u003e\"android.permission.INTERNET\"\u003c/span\u003e /\u0026gt; \u003cspan style=\"color: #000080;\"\u003e\u0026lt;uses-permission\u003c/span\u003e \u003cspan style=\"color: #008080;\"\u003eandroid:name=\u003c/span\u003e\u003cspan style=\"color: #dd1144;\"\u003e\"android.permission.WRITE_EXTERNAL_STORAGE\"\u003c/span\u003e \u003cspan style=\"color: #000080;\"\u003e/\u0026gt;\u003c/span\u003e\n```\n\u003c/div\u003e\n\u003chr style=\"color: #000000;\" /\u003e\n\u003ch2 id=\"混淆时注意事项\"\u003e\u003ca href=\"https://github.com/wyouflf/xUtils#%E6%B7%B7%E6%B7%86%E6%97%B6%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9\"\u003e\u003c/a\u003e混淆时注意事项：\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e添加Android默认混淆配置${sdk.dir}/tools/proguard/proguard-android.txt\u003c/li\u003e\n\u003cli\u003e不要混淆xUtils中的注解类型，添加混淆配置：-keep class * extends java.lang.annotation.Annotation { *; }\u003c/li\u003e\n\u003cli\u003e对使用DbUtils模块持久化的实体类不要混淆，或者注解所有表和列名称@Table(name=”xxx”)，@Id(column=”xxx”)，@Column(column=”xxx”),@Foreign(column=”xxx”,foreign=”xxx”)；\u003c/li\u003e\n\u003c/ul\u003e","title":"Android 工具包 xUtils"},{"content":"ThinkAndroid是包含Android mvc和简易sqlite orm以及ioc模块，它封装了Android httpclitent中的http模块, 具有快速构建文件缓存功能，无需考虑什么格式的文件，都可以非常轻松的实现缓存，它实现了图片缓存，在android中 加载的图片的时候oom的问题和快速滑动的时候图片加载位置错位等问题都可以轻易的解决掉。他还包括了一个手机开发中 经常应用的实用工具类，如日志管理，配置文件管理，android下载器模块，网络切换检测等等工具。 ThinkAndroid的开发宗旨是简洁，快速的进行Android应用程序的开发\n目前ThinkAndroid主要有以下模块：\nMVC模块：实现视图与模型的分离。\nioc模块：android中的ioc模块，完全注解方式就可以进行UI绑定、res中的资源的读取、以及对象的初始化。\n数据库模块：android中的orm框架，使用了线程池对sqlite进行操作。\nhttp模块：通过httpclient进行封装http数据请求，支持异步及同步方式加载。\n缓存模块：通过简单的配置及设计可以很好的实现缓存，对缓存可以随意的配置\n图片缓存模块：imageview加载图片的时候无需考虑图片加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象。\n配置器模块：可以对简易的实现配对配置的操作，目前配置文件可以支持Preference、Properties对配置进行存取。\n日志打印模块：可以较快的轻易的是实现日志打印，支持日志打印的扩展，目前支持对sdcard写入本地打印、以及控制台打印\n下载器模块:可以简单的实现多线程下载、后台下载、断点续传、对下载进行控制、如开始、暂停、删除等等。\n网络状态检测模块：当网络状态改变时，对其进行检测。\ngithub项目地址：https://github.com/white-cat/ThinkAndroid\n其他框架\n一.框架如下几种:\n1.Roboguice 2.Spring for Android 3.afinal 4.xUtils 二.Roboguice说明 项目地址:https://github.com/roboguice/roboguice\n要依赖三个包,加起来接近800K比较大;\n控件和service都可以用IOC注入;\n事件不能绑定\nactivity要继承RoboActivity\n三.Spring for Android说明 四.afinal说明 - 项目地址:[https://github.com/yangfuhai/afinal](https://github.com/yangfuhai/afinal) - 依赖包只有152k - 页面控件可以注入,service不可注入 - 事件能绑定 - 提供sqlite,http,图片工具类 - activity要继承FinalActivity 五.xUtils说明 - 项目地址:[https://github.com/wyouflf/xUtils](https://github.com/wyouflf/xUtils) - 依赖包有274k,项目比较活跃 - 页面控件可以注入,service不可注入 - 事件能绑定 - 提供sqlite,http,图片工具类 - activity不要继承,但要侵入代码 - 是afinal项目改进而来,支持大数据上传 \u0026amp;nbsp; ion 项目地址：https://github.com/koush/ion ","permalink":"https://blog.zdltech.com/posts/android-%E5%BF%AB%E9%80%9F%E5%BC%80%E5%8F%91%E6%A1%86%E6%9E%B6thinkandroid/","summary":"\u003cp\u003eThinkAndroid是包含Android mvc和简易sqlite orm以及ioc模块，它封装了Android httpclitent中的http模块, 具有快速构建文件缓存功能，无需考虑什么格式的文件，都可以非常轻松的实现缓存，它实现了图片缓存，在android中 加载的图片的时候oom的问题和快速滑动的时候图片加载位置错位等问题都可以轻易的解决掉。他还包括了一个手机开发中 经常应用的实用工具类，如日志管理，配置文件管理，android下载器模块，网络切换检测等等工具。 ThinkAndroid的开发宗旨是简洁，快速的进行Android应用程序的开发\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e目前ThinkAndroid主要有以下模块：\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eMVC模块：实现视图与模型的分离。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eioc模块：android中的ioc模块，完全注解方式就可以进行UI绑定、res中的资源的读取、以及对象的初始化。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e数据库模块：android中的orm框架，使用了线程池对sqlite进行操作。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ehttp模块：通过httpclient进行封装http数据请求，支持异步及同步方式加载。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e缓存模块：通过简单的配置及设计可以很好的实现缓存，对缓存可以随意的配置\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e图片缓存模块：imageview加载图片的时候无需考虑图片加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e配置器模块：可以对简易的实现配对配置的操作，目前配置文件可以支持Preference、Properties对配置进行存取。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e日志打印模块：可以较快的轻易的是实现日志打印，支持日志打印的扩展，目前支持对sdcard写入本地打印、以及控制台打印\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e下载器模块:可以简单的实现多线程下载、后台下载、断点续传、对下载进行控制、如开始、暂停、删除等等。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e网络状态检测模块：当网络状态改变时，对其进行检测。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003egithub项目地址：https://github.com/white-cat/ThinkAndroid\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e其他框架\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e一.框架如下几种:\u003c/p\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  1.Roboguice\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  2.Spring for Android\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  3.afinal\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  4.xUtils\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  二.Roboguice说明\n\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e项目地址:\u003ca href=\"https://github.com/roboguice/roboguice\"\u003ehttps://github.com/roboguice/roboguice\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e要依赖三个包,加起来接近800K比较大;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e控件和service都可以用IOC注入;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e事件不能绑定\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eactivity要继承RoboActivity\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  三.Spring for Android说明\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  四.afinal说明\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n\u003cpre\u003e\u003ccode\u003e- 项目地址:[https://github.com/yangfuhai/afinal](https://github.com/yangfuhai/afinal)\n\n- 依赖包只有152k\n\n- 页面控件可以注入,service不可注入\n\n- 事件能绑定\n\n- 提供sqlite,http,图片工具类\n\n- activity要继承FinalActivity\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  五.xUtils说明\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n\u003cpre\u003e\u003ccode\u003e- 项目地址:[https://github.com/wyouflf/xUtils](https://github.com/wyouflf/xUtils)\n\n- 依赖包有274k,项目比较活跃\n\n- 页面控件可以注入,service不可注入\n\n- 事件能绑定\n\n- 提供sqlite,http,图片工具类\n\n- activity不要继承,但要侵入代码\n\n- 是afinal项目改进而来,支持大数据上传\n\n\n\n\n\n\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch1 id=\"ion\"\u003e\u003cstrong\u003e\u003ca href=\"https://github.com/koush/ion\"\u003eion\u003c/a\u003e\u003c/strong\u003e\u003c/h1\u003e\n\u003cpre\u003e\u003ccode\u003e项目地址：https://github.com/koush/ion\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Android 快速开发框架：ThinkAndroid"},{"content":"在看android基础的时候，关于网络操作一般都会介绍HttpClient以及HttpConnection这两个包。前者是apache的开源库，后者是android自带的api。既然提到了他们，都二者进行一个比较，谷歌在官方文档已经说明了，建议在2.3以及以上版本使用HttpConnection。具体原因呢，是因为对2.1和2.2版本，HttpURLConnection有那么几个Bug，所以建议用Apache的HTTP Client；之后的版本，建议用HttpURLConnection。Apache的HTTP Client比较强大，拥有庞大而灵活的API，这个实现很稳定，并且Bug很少。然而，也就是因为太庞大了，以至于很难在保证兼容性的情况下改进它，故android 开发团队不应该维护该库而是转投更为轻量级的httpurlconnection。 当我们开发企业级应用的时候，一般都会选择使用已经封装好的http框架。开源的比较流行的有： 1、volley\n2、android-async-http\n3、retrofit\n4、okhttp\n5、androidquery 6、AndroidAsync\n等。他们各有优劣，不同的框架有不同的效率，在使用的时候可以因地制宜地测试，根据效果来选择使用哪个，之前个人则比较喜欢用android-async-http,。如今Google推出了官方的针对Android平台上的网络通信库volley，能使网络通信更快，更简单，更健壮，Volley在提供了高性能网络通讯功能的同时，对网络图片加载也提供了良好的支持，完全可以满足简单REST客户端的需求, 我们没有理由不跟上时代的潮流。另外，但volley的扩展性很强，可以根据需要定制你自己的网络请求。所以，最后推荐还是使用volley进行开发，当然其他几个库也是非常具有学习以及参考意义的，可以将他们的精髓之处汲取到volley框架的拓展开发之中，做出自己理想的http通讯框架。\n推荐博客： http://instructure.github.io/blog/2013/12/09/volley-vs-retrofit/ http://blog.csdn.net/t12x3456/article/details/9221611\nhttp://blog.csdn.net/guolin_blog/article/details/12452307\n","permalink":"https://blog.zdltech.com/posts/android-%E7%BD%91%E7%BB%9C%E5%BC%80%E5%8F%91%E6%A1%86%E6%9E%B6%E7%9A%84%E9%80%89%E6%8B%A9/","summary":"\u003cp\u003e在看android基础的时候，关于网络操作一般都会介绍HttpClient以及HttpConnection这两个包。前者是apache的开源库，后者是android自带的api。既然提到了他们，都二者进行一个比较，谷歌在官方文档已经说明了，建议在2.3以及以上版本使用HttpConnection。具体原因呢，是因为对2.1和2.2版本，HttpURLConnection有那么几个Bug，所以建议用Apache的HTTP Client；之后的版本，建议用HttpURLConnection。Apache的HTTP Client比较强大，拥有庞大而灵活的API，这个实现很稳定，并且Bug很少。然而，也就是因为太庞大了，以至于很难在保证兼容性的情况下改进它，故android 开发团队不应该维护该库而是转投更为轻量级的httpurlconnection。 当我们开发企业级应用的时候，一般都会选择使用已经封装好的http框架。开源的比较流行的有： 1、volley\u003cbr\u003e\n2、android-async-http\u003cbr\u003e\n3、retrofit\u003cbr\u003e\n4、okhttp\u003cbr\u003e\n5、androidquery 6、\u003ca href=\"http://www.2cto.com/kf/yidong/Android/\"\u003eAndroid\u003c/a\u003eAsync\u003cbr\u003e\n等。他们各有优劣，不同的框架有不同的效率，在使用的时候可以因地制宜地测试，根据效果来选择使用哪个，之前个人则比较喜欢用android-async-http,。如今Google推出了官方的针对Android平台上的网络通信库volley，能使网络通信更快，更简单，更健壮，Volley在提供了高性能网络通讯功能的同时，对网络图片加载也提供了良好的支持，完全可以满足简单REST客户端的需求, 我们没有理由不跟上时代的潮流。另外，但volley的扩展性很强，可以根据需要定制你自己的网络请求。所以，最后推荐还是使用volley进行开发，当然其他几个库也是非常具有学习以及参考意义的，可以将他们的精髓之处汲取到volley框架的拓展开发之中，做出自己理想的http通讯框架。\u003cimg alt=\"加载中\u0026hellip;\" loading=\"lazy\" src=\"http://www.2cto.com/statics/images/s_nopic.gif\"\u003e\u003cbr\u003e\n推荐博客： \u003ca href=\"http://instructure.github.io/blog/2013/12/09/volley-vs-retrofit/\"\u003ehttp://instructure.github.io/blog/2013/12/09/volley-vs-retrofit/\u003c/a\u003e \u003ca href=\"http://blog.csdn.net/t12x3456/article/details/9221611\"\u003ehttp://blog.csdn.net/t12x3456/article/details/9221611\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"http://blog.csdn.net/guolin_blog/article/details/12452307\"\u003ehttp://blog.csdn.net/guolin_blog/article/details/12452307\u003c/a\u003e\u003c/p\u003e","title":"Android 网络开发框架的选择"},{"content":"本文延续上期话题，深入到测试、持续集成和部署等环节，紧密结合移动开发方法和技术，围绕Android平台的开发讨论提供更高质量移动产品的解决方案。\n**通过清晰的架构实现测试驱动** 通过[《程序员》杂志9月刊文章](http://www.programmer.com.cn/13757/)的分析，我们可以看到，每一种工具都很难从完全意义上解决工程当中追求快速和高质量的要求。那么就需要通过整体架构实践，更好地解决这方面的问题。以下两种结构方法可供参考。 **平台和领域的分层结构** 如图1所示，这是一种最基础的分层结构。它将和Android平台相关的内容都包裹在了平台层，而将领域、状态、逻辑等和平台无关的内容完全隔离开来。创建项目时，将平台层和测试层分别对领域层产生依赖，以这样的方式达成对项目和对测试的独立构建。 这样做的好处是，领域层可以通过Java的JUnit进行完全测试，而项目各个类之间的因为有明显的项目级别分层，使得代码的考量更加清晰，方便于检验最核心关键的业务逻辑。且测试速度非常快，便于快速迭代。 但其带来的不便之处就是，随着项目代码的日益复杂，其与Android内部结合就越紧密，这时往往越难将业务逻辑很清晰的剥离。部分的业务逻辑将被分片散落在一些平台相关的调用当中。因此我们认为这样的一种层次逻辑更多地适用于简单的项目之中。 ![](http://ipad-cms.csdn.net/cms/attachment/201210/5061286bc38e9.jpg) 图1 平台和领域的分层结构 **MVP（Passive View）架构** 许多文章对Passive View是属于MVP还是MVC有各种不同角度的争论。这里我并不想过多地在词语上做过多纠缠，主要是希望通过描述这样的一种结构来树立比较好的对于Android开发的架构模型。 具体到Passive View的实现，如图2所示，描述了一个基本的原理。 随着项目的不断扩大复杂化，我们需要更加清晰化的代码架构。所以，Passive View对平台和领域的分层结构的层次结构有了更深层次的改进。引入Passive View模式的意义实际上还是从测试出发。出于对JUnit快速性能的青睐，所以依然尽量把层次划分为依赖Android内核的部分和非依赖部分。对于前 半部分，可以用基于Roboletric的上层测试完成，相对应的后半部分则可以使用标准Java进行单元测试。这样做既加快了测试速度，又得以保障测试的覆盖率。 ![](http://ipad-cms.csdn.net/cms/attachment/201210/5061290a0cd3f.jpg) 图2 Passive View架构实现原理图 更多详细的架构资料，请大家参考《GUI Architecture》一文，相信会得到许多很好的想法。 **测试驱动开发的实现** 之所以要强调代码框架结构，最重要的原因就是寻找快捷方便的途径进行TDD开发。在上一篇文章中已提到了Android常见的集中单元测试工具。之所以将框 架设计方式引入测试驱动开发过程，目的是将应用代码分开处理、分而治之。最大限度让各工具间扬长避短。最终实现高效率测试驱动的目的。 事实上，在目前的开发领域，我们也看到了许多正在应运而生的开发框架，例如Android Spring框架。这些都是下一步需要努力和完善的目标。 **业务行为驱动的功能测试方案** 如果说单元测试驱动开发帮助我们从开发角度完成了对代码质量的控制，那么基于业务行为的功能测试则为从业务到实现的统一、软件质量的保障提供了重要的解决方法。 功能（验收）测试：就功能测试而言，所指基本上就是测试科目中常提到的黑盒测试。只不过这里加上了更多具有上下文的信息，使得一次完整的黑盒测试更具有实质上的功能意义。 在 Android的开发中，通常是模拟真机或模拟器的用户操作（例如点击或滑动），来检测操作的结果是否符合预期。这个过程可以很好地代替人工的操作，更快 速和大量完成重复性的测试工作，特别是在发展较快、平台和系统版本覆盖较广的项目中，可以起到节约人力成本、提高测试覆盖与准确性的作用。 在常用的工具中，可以选取上一篇文章中介绍过的Robotium或Native Driver来实现。 前者社区发展速度快，实现功能相对更加完善，例如实现了一些手势操作效果等。不过问题是Robotium的组织目前正在倾向闭源化，有些最好的新功能已无法在开源版本中寻找到。 后者的原理是通过植入应用后门的方式，实现对应用的发出指令和进行资源获取。其物理模型比较适合不能再目标设备安装测试应用，或者希望远程控制的情况。开源状况良好，只是近一年，Native Driver的团队把重点发在其他平台上，对Android的更新比较慢。 基于场景的的跨平台验收测试：基于场景的验收测试，好处是可以在业务人员和开发人员之间建立验收机制。通过一系列关于场景的自然语言描述，完成测试的原始编 码。Cucumber是一个在行为驱动开发（BDD）领域比较常见的工具。其基本方法是通过执行文字形功能描述语言来实现对软件的自动化测试。图3展示了 一个常见的Cucumber测试场景。在Android开发中，通常是解析Cucumber，根据内容分情况拆分正具体的操作步骤。将这些步骤用基于 NativeDriver的Java代码进行实现，通过NativeDriver从指令端到设备端的Android自动测试框架完成控制与校验的自动化测 试。 ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612a3536eaf.jpg) 图3 常见的Cucumber测试场景 当然，这些步骤也可以通过Robotium的远程控制（RC）调用来实现。其原理类似，如图4所示。 该方案还有额外的好处—用同样的方法，通过Cucumber可以实现对UIAutomation等其他平台自动化测试工具的控制。实现一份用例，多个平台的测试解决方案。图5给出了一个iOS平台上的基于Cucumber的跨平台测试实例。 ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612a618a4e3.jpg) 图4 Cucumber测试实例 ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612aa72955d.jpg) 图5 iOS平台上基于Cucumber的跨平台测试实例 **从持续集成到部署** **Jenkins最基本的持续集成** 在做好了各种测试实践后，需要考虑如何保证这种实践在每一次提交都产生效果，并且提供对代码库的不断保护。这里引入常用敏捷实践中持续集成的概念。 持 续集成主要是为了能够更好为产品在整个开发过程中提供交付保障。相对比传统服务器领域，移动开发中，碰到最多的问题是环境的不同与测试包的相对封闭。以前 通过改一个配置实现服务器实时测试修改的方法，很难直接应用于移动开发。此外，作为整个服务边缘的移动应用，往往会遇到大量不同的测试环境。 所以如图6所描述的，需要在持续集成服务器上部署相关的应用包，完成对不同环境的开发与测试。这样的测试通常是由持续集成服务器引导的不同物理移动设备来完成，以保证最终测试包的可交付性。尤其适用于对于网络和性能等相关的测试。 ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612ae03a67e.jpg) 图6 利用相关应用包完成对不同环境的开发与测试 当然，如果细心的话，也可以看出图6中对于产品版本与配置管理的一些端倪。 **OTA自动化部署** 持续集成帮助我们有了稳定的应用包。有了这些包，我们现在就差最后的一步—自动化部署。在移动的真实交付中，由于安装包需要下载到移动终端完成。所以自动化部署也必须要模拟这一过程完成交付。 这里我们推荐使用持续集成服务器关于邮件服务推送的应用插件来完成。具体的过程通常为，在完成编译并顺利通过测试后，持续集成服务器会根据制定终端列表，推送测试内容以供安装。推送者收到请求后，可以根据需要自行安装相应apk文件，达到部署效果。 这样做打通了移动开发最后一步的障碍。并有效沟通了管理、设计、业务与测试的各个部门人员。持续集成管理员还可以通过管理安装邮件列表的形式，自行选择不同版本，环境安装包对不同相关人员的推送。 **让调试可持续化** 有 了开发，有了一系列持续化集成作业，有了作业完成的自动化打包部署，貌似可以休息了。但正如DevOps概念所说，虽然做了许多努力，但我们依然承认会有 错误的出现，那么如何尽早发现错误并准确定位，最终完成就显得尤为重要。在不同阶段，我们尝试使用不同的方法来进行调试。下面介绍我们的两个实践方法。 开发后调试。旧有的logcat是一个很好的调试工具，它在开发中起到了重要的作用，但对于做探索测试的QA们而言，大量繁琐的Debug信息往往令人看得眼花缭乱。 这 时我们就需要一个更好的工具进行错误栈的准确定位，因此我们引入了Acra。这是一个开源工具包，其功能是自动化地将Android应用的错误报告发送到 GoogleDoc或着Email等的可记录文本中。它的目的是为了帮助Android应用开发者在错误发生时收集行为和技术数据。 上线后的持续关注当然在上线后，Google Play也为我们提供了一个非常有好的平台用以收集各种来自用户的反馈信息。其中包括下载量、评价、应用异常报告等。 \u0026amp;nbsp; ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612b2c496ca.jpg) \u0026amp;nbsp; \u0026amp;nbsp; ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612b2d5d71a.jpg) \u0026amp;nbsp; ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612b35d1eac.jpg) 图7 移动循环开发流程 在 应用异常报告中，详细记录了整个错误堆栈的信息，更包括错误信息的总数量、周发生次数，以及版本时间等信息。因为Android平台设备性能、具体型号等 多方面内容，并不一定所有的错误信息都一定去进行处理，但这个平台提供了一个持续关注上线情况的基础，为产品的紧急处理、故障修复和在开发提供了重要的信 息来源。 这里还要强调，测试优先的TDD实践，在每一个错误修复前，都应该把测试补好，这是同样错误不会再次出现的最重要保障。 **总结** 本文提出了移动开发过程中常见的问题，并分析了基于开发与维护过程中的一些具体实践方法，尝试从移动应用的开发技术角度提供解决方案。 除此之外，事实上和常见的软件开发一样，还有诸如配置管理、发布管理等也是必不可少的。我们总结了如图7所示的一个移动开发循环。通过对不同方面的配置技术实现，完成移动的全流程开发，供读者做更深的思考和方法演进。 转自：http://www.yidin.net/?p=6821 ","permalink":"https://blog.zdltech.com/posts/android%E6%95%8F%E6%8D%B7%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97%E4%B8%8B/","summary":"\u003cp\u003e本文延续上期话题，深入到测试、持续集成和部署等环节，紧密结合移动开发方法和技术，围绕Android平台的开发讨论提供更高质量移动产品的解决方案。\u003c/p\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n\u003cpre\u003e\u003ccode\u003e**通过清晰的架构实现测试驱动**\n\n\n\n\n\n通过[《程序员》杂志9月刊文章](http://www.programmer.com.cn/13757/)的分析，我们可以看到，每一种工具都很难从完全意义上解决工程当中追求快速和高质量的要求。那么就需要通过整体架构实践，更好地解决这方面的问题。以下两种结构方法可供参考。\n\n\n\n\n\n**平台和领域的分层结构**\n\n\n\n\n\n如图1所示，这是一种最基础的分层结构。它将和Android平台相关的内容都包裹在了平台层，而将领域、状态、逻辑等和平台无关的内容完全隔离开来。创建项目时，将平台层和测试层分别对领域层产生依赖，以这样的方式达成对项目和对测试的独立构建。\n\n\n\n\n\n这样做的好处是，领域层可以通过Java的JUnit进行完全测试，而项目各个类之间的因为有明显的项目级别分层，使得代码的考量更加清晰，方便于检验最核心关键的业务逻辑。且测试速度非常快，便于快速迭代。\n\n\n\n\n\n但其带来的不便之处就是，随着项目代码的日益复杂，其与Android内部结合就越紧密，这时往往越难将业务逻辑很清晰的剥离。部分的业务逻辑将被分片散落在一些平台相关的调用当中。因此我们认为这样的一种层次逻辑更多地适用于简单的项目之中。\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n    \u003cdiv class=\"jiathis_shareimg\"\u003e\n      ![](http://ipad-cms.csdn.net/cms/attachment/201210/5061286bc38e9.jpg)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e  图1 平台和领域的分层结构\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e**MVP（Passive View）架构**\n\n\n\n\n\n许多文章对Passive View是属于MVP还是MVC有各种不同角度的争论。这里我并不想过多地在词语上做过多纠缠，主要是希望通过描述这样的一种结构来树立比较好的对于Android开发的架构模型。\n\n\n\n\n\n具体到Passive View的实现，如图2所示，描述了一个基本的原理。\n\n\n\n\n\n随着项目的不断扩大复杂化，我们需要更加清晰化的代码架构。所以，Passive View对平台和领域的分层结构的层次结构有了更深层次的改进。引入Passive View模式的意义实际上还是从测试出发。出于对JUnit快速性能的青睐，所以依然尽量把层次划分为依赖Android内核的部分和非依赖部分。对于前 半部分，可以用基于Roboletric的上层测试完成，相对应的后半部分则可以使用标准Java进行单元测试。这样做既加快了测试速度，又得以保障测试的覆盖率。\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n    \u003cdiv class=\"jiathis_shareimg\"\u003e\n      ![](http://ipad-cms.csdn.net/cms/attachment/201210/5061290a0cd3f.jpg)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e  图2 Passive View架构实现原理图\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e更多详细的架构资料，请大家参考《GUI Architecture》一文，相信会得到许多很好的想法。\n\n\n\n\n\n**测试驱动开发的实现**\n\n\n\n\n\n之所以要强调代码框架结构，最重要的原因就是寻找快捷方便的途径进行TDD开发。在上一篇文章中已提到了Android常见的集中单元测试工具。之所以将框 架设计方式引入测试驱动开发过程，目的是将应用代码分开处理、分而治之。最大限度让各工具间扬长避短。最终实现高效率测试驱动的目的。\n\n\n\n\n\n事实上，在目前的开发领域，我们也看到了许多正在应运而生的开发框架，例如Android Spring框架。这些都是下一步需要努力和完善的目标。\n\n\n\n\n\n**业务行为驱动的功能测试方案**\n\n\n\n\n\n如果说单元测试驱动开发帮助我们从开发角度完成了对代码质量的控制，那么基于业务行为的功能测试则为从业务到实现的统一、软件质量的保障提供了重要的解决方法。\n\n\n\n\n\n功能（验收）测试：就功能测试而言，所指基本上就是测试科目中常提到的黑盒测试。只不过这里加上了更多具有上下文的信息，使得一次完整的黑盒测试更具有实质上的功能意义。\n\n\n\n\n\n在 Android的开发中，通常是模拟真机或模拟器的用户操作（例如点击或滑动），来检测操作的结果是否符合预期。这个过程可以很好地代替人工的操作，更快 速和大量完成重复性的测试工作，特别是在发展较快、平台和系统版本覆盖较广的项目中，可以起到节约人力成本、提高测试覆盖与准确性的作用。\n\n\n\n\n\n在常用的工具中，可以选取上一篇文章中介绍过的Robotium或Native Driver来实现。\n\n\n\n\n\n前者社区发展速度快，实现功能相对更加完善，例如实现了一些手势操作效果等。不过问题是Robotium的组织目前正在倾向闭源化，有些最好的新功能已无法在开源版本中寻找到。\n\n\n\n\n\n后者的原理是通过植入应用后门的方式，实现对应用的发出指令和进行资源获取。其物理模型比较适合不能再目标设备安装测试应用，或者希望远程控制的情况。开源状况良好，只是近一年，Native Driver的团队把重点发在其他平台上，对Android的更新比较慢。\n\n\n\n\n\n基于场景的的跨平台验收测试：基于场景的验收测试，好处是可以在业务人员和开发人员之间建立验收机制。通过一系列关于场景的自然语言描述，完成测试的原始编 码。Cucumber是一个在行为驱动开发（BDD）领域比较常见的工具。其基本方法是通过执行文字形功能描述语言来实现对软件的自动化测试。图3展示了 一个常见的Cucumber测试场景。在Android开发中，通常是解析Cucumber，根据内容分情况拆分正具体的操作步骤。将这些步骤用基于 NativeDriver的Java代码进行实现，通过NativeDriver从指令端到设备端的Android自动测试框架完成控制与校验的自动化测 试。\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n    \u003cdiv class=\"jiathis_shareimg\"\u003e\n      ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612a3536eaf.jpg)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e  图3 常见的Cucumber测试场景\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e当然，这些步骤也可以通过Robotium的远程控制（RC）调用来实现。其原理类似，如图4所示。\n\n\n\n\n\n该方案还有额外的好处—用同样的方法，通过Cucumber可以实现对UIAutomation等其他平台自动化测试工具的控制。实现一份用例，多个平台的测试解决方案。图5给出了一个iOS平台上的基于Cucumber的跨平台测试实例。\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n    \u003cdiv class=\"jiathis_shareimg\"\u003e\n      ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612a618a4e3.jpg)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e  图4 Cucumber测试实例\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    \u003cdiv class=\"jiathis_shareimg\"\u003e\n      ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612aa72955d.jpg)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e  图5 iOS平台上基于Cucumber的跨平台测试实例\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e**从持续集成到部署**\n\n\n\n\n\n**Jenkins最基本的持续集成**\n\n\n\n\n\n在做好了各种测试实践后，需要考虑如何保证这种实践在每一次提交都产生效果，并且提供对代码库的不断保护。这里引入常用敏捷实践中持续集成的概念。\n\n\n\n\n\n持 续集成主要是为了能够更好为产品在整个开发过程中提供交付保障。相对比传统服务器领域，移动开发中，碰到最多的问题是环境的不同与测试包的相对封闭。以前 通过改一个配置实现服务器实时测试修改的方法，很难直接应用于移动开发。此外，作为整个服务边缘的移动应用，往往会遇到大量不同的测试环境。\n\n\n\n\n\n所以如图6所描述的，需要在持续集成服务器上部署相关的应用包，完成对不同环境的开发与测试。这样的测试通常是由持续集成服务器引导的不同物理移动设备来完成，以保证最终测试包的可交付性。尤其适用于对于网络和性能等相关的测试。\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n    \u003cdiv class=\"jiathis_shareimg\"\u003e\n      ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612ae03a67e.jpg)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e  图6 利用相关应用包完成对不同环境的开发与测试\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e当然，如果细心的话，也可以看出图6中对于产品版本与配置管理的一些端倪。\n\n\n\n\n\n**OTA自动化部署**\n\n\n\n\n\n持续集成帮助我们有了稳定的应用包。有了这些包，我们现在就差最后的一步—自动化部署。在移动的真实交付中，由于安装包需要下载到移动终端完成。所以自动化部署也必须要模拟这一过程完成交付。\n\n\n\n\n\n这里我们推荐使用持续集成服务器关于邮件服务推送的应用插件来完成。具体的过程通常为，在完成编译并顺利通过测试后，持续集成服务器会根据制定终端列表，推送测试内容以供安装。推送者收到请求后，可以根据需要自行安装相应apk文件，达到部署效果。\n\n\n\n\n\n这样做打通了移动开发最后一步的障碍。并有效沟通了管理、设计、业务与测试的各个部门人员。持续集成管理员还可以通过管理安装邮件列表的形式，自行选择不同版本，环境安装包对不同相关人员的推送。\n\n\n\n\n\n**让调试可持续化**\n\n\n\n\n\n有 了开发，有了一系列持续化集成作业，有了作业完成的自动化打包部署，貌似可以休息了。但正如DevOps概念所说，虽然做了许多努力，但我们依然承认会有 错误的出现，那么如何尽早发现错误并准确定位，最终完成就显得尤为重要。在不同阶段，我们尝试使用不同的方法来进行调试。下面介绍我们的两个实践方法。\n\n\n\n\n\n开发后调试。旧有的logcat是一个很好的调试工具，它在开发中起到了重要的作用，但对于做探索测试的QA们而言，大量繁琐的Debug信息往往令人看得眼花缭乱。\n\n\n\n\n\n这 时我们就需要一个更好的工具进行错误栈的准确定位，因此我们引入了Acra。这是一个开源工具包，其功能是自动化地将Android应用的错误报告发送到 GoogleDoc或着Email等的可记录文本中。它的目的是为了帮助Android应用开发者在错误发生时收集行为和技术数据。\n\n\n\n\n\n上线后的持续关注当然在上线后，Google Play也为我们提供了一个非常有好的平台用以收集各种来自用户的反馈信息。其中包括下载量、评价、应用异常报告等。\n\n\n\n\n\n\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"jiathis_shareimg\"\u003e\n    ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612b2c496ca.jpg)\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026amp;nbsp;\n\n\n\n\n\n\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"jiathis_shareimg\"\u003e\n    ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612b2d5d71a.jpg)\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n    \u003cdiv class=\"jiathis_shareimg\"\u003e\n      ![](http://ipad-cms.csdn.net/cms/attachment/201210/50612b35d1eac.jpg)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e  图7 移动循环开发流程\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e在 应用异常报告中，详细记录了整个错误堆栈的信息，更包括错误信息的总数量、周发生次数，以及版本时间等信息。因为Android平台设备性能、具体型号等 多方面内容，并不一定所有的错误信息都一定去进行处理，但这个平台提供了一个持续关注上线情况的基础，为产品的紧急处理、故障修复和在开发提供了重要的信 息来源。\n\n\n\n\n\n这里还要强调，测试优先的TDD实践，在每一个错误修复前，都应该把测试补好，这是同样错误不会再次出现的最重要保障。\n\n\n\n\n\n**总结**\n\n\n\n\n\n本文提出了移动开发过程中常见的问题，并分析了基于开发与维护过程中的一些具体实践方法，尝试从移动应用的开发技术角度提供解决方案。\n\n\n\n\n\n除此之外，事实上和常见的软件开发一样，还有诸如配置管理、发布管理等也是必不可少的。我们总结了如图7所示的一个移动开发循环。通过对不同方面的配置技术实现，完成移动的全流程开发，供读者做更深的思考和方法演进。\n\n\n\n\n\n转自：http://www.yidin.net/?p=6821\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Android敏捷开发指南（下）"},{"content":"本文紧密结合移动开发方法与技术，围绕Android平台的开发探讨提供更高质量移动产品的解决方案。作者中分析了移动开发中常见的问题，从两方面阐述了ThoughtWorks使用的测试开发方案和相应的架构方法与常用工具应用，并进一步阐述了为移动开发流程所提供的持续发布方案。\n随着云计算、移动互联等一系列新技术概念的崛起，新一轮的IT经济正在不断扩大发展。带来无限机遇的同时，也提出了许多有别于传统开发的挑战。近几年来，我一直在尝试各种移动项目，虽然它们在应用领域、技术类型以及工作模式等方面各不相同，但我在摸索中逐渐总结出了一些比较具有共性的问题。\n移动项目中的常见问题\n为了实现较好的用户体验，反复的设计与验证导 致产品发布时间延长。移动应用由于其多样性的应用场景，使产品设计侧重于适应不同目标的展现方式与操作习惯。设计实现的方式与使用用户群、企业服务模式、新的科技实现手段，以及各种碎片分化的目标支持设备等一系列因素密切相关。在产品实现初期，许多的内容和形式都需要在已有开发原型的基础上，进行紧密结合用户体验的测试。不少团队花了很长时间完成了目标，可测试后又要经历反复且大量的修改。这对产品的如期发布提出了巨大的挑战，发布时间也会因此一拖再拖。 即便是产品磕磕绊绊地发布了，设计的改变往往也是最让人头痛的问题。\n![](http://ipad-cms.csdn.net/cms/attachment/201209/503b37ab7f95a.jpg) 图1 某产品四个阶段首页面对比图 市场导向性强，业务需求变化快与缩短产品交付周期需求之间产生矛盾。经过了一系列的市场分析、产品设计、项目研发过程后，一个移动产品终于投放到了市场。但这完全不能看做是一个项目的交付完成，恰恰相反，这只是一个新阶段的开始。在残酷的市场竞争中，用户不是产品的被动消费者，而是需求的提出者，会在各种下 载市场（例App Store、Google Play）发出评论对应用进行评估，从而直接影响应用的市场占有率。同时随着一系列用户体验数据的收集分析和整理，业务部门的需求递增，新功能点开始一个 个被搬上研发经理的台面。这给开发团队应对需求改变以及对递增的代码结构升级能力提出了更高要求。图1展示了一个产品在过去一年多时间里首页面的变化。\n可以看出在项目所经历的四个比较大的阶段中，仅一个首界面的功能，也经历了从最开始的普通列表界面，到后来增加地图功能、书签的过程。在第四个阶段中，为了满足用户注册登录等需求，首页面还进行了基于左侧滑动菜单的导航转型与登录反馈等的功能扩充。每个重大阶段的转型，都来自最真实的市场评论数据，并结合 Omniture（通过收集用户数据行为分析的工具）等产品的体验数据分析与业务增长需要进行开发。\n为了实现更加精细的体验效果并兼容 Android的各个版本（例如图1中列表和地图间的切换需要通过动画三维翻转实现等），所有这一切都必须在同一个Activity内完成交互。这给大量的页面逻辑、状态和视图层级关系的升级改造带来了很大的难度。与此相对应的坏消息是，移动应用对短周期的快速发布有着强烈的需求。即使是一个好的应用，如 果没有及时保持稳定频率的更新，很快就会被接踵而来的竞争者追赶，最后落到被用户遗忘的境地。从某种角度讲，除了产品新功能的推出外，应用程序的更新也具 备某种广告的职能，去强化品牌在消费人群中的地位，稳定和扩大市场的占有率。\n移动团队虽小，但要求更良好的产品集成性。同一个产品，一般根 据支持平台的数量以及并行发布需求，配置有多个小团队和数据整合（API）团队。每个团队的开发因为进度不同和平台特点的不同，往往在整合过程中提出各自不同的集成需求（包括数据集成和逻辑集成），例如Android的内存性能不好，要求服务端的图片质量与剪裁要和iOS有所区别；再例如有时为了降低网络 性能对体验的影响，会更改设计，将逻辑分散在API整合段和设备端。这就为团队间的整合埋下了风险。事实上，这在多团队的并行开发中，并不是个别现象。\n多样化的设备和版本、长期的维护开发，带来快速升高的测试成本。随着开发功能的增加，页面布局、操作响应和交互处理大量逻辑模块增加，以及越来越分化的设备 和系统版本，给测试工作带来了相当大的难度。在之前我做咨询时，一个项目经理告诉我，他有一个运行了一年半的项目，当时还有一周就要上线，可仍有60个Bug，5名测试工程师因为对质量没有信心而不停加班，开发也为修改一个个错误都头痛不已。\n通过技术方案寻求解决途径\n为了解决上述常见移动项目的问题，在项目实践中，我们试图通过合理地运用技术方案来帮助完成高质量移动软件的目标。\n实现高可维护性的代码，减少代码扩展过程中的腐化和变动带来的副作用。随着功能增加，越来越多的逻辑模块被堆砌在同一个单元内，导致代码可读性下降，维护复杂度提高。这时的修改都存在破坏原有功能的潜在风险。\n如果解决这两个问题，将在很大程度上提高应用在开发过程中对产品需求改变和开发周期控制的适应能力。实践中，我们使用元素组件化开发和测试驱动开发解决方 案。组件化的基本目的就是将代码的可读性置于编码过程中，通过形成独立子元素组件来代理自身的功能逻辑，并以此结构化XML的布局资源，提高可读性。同 时，通过测试驱动的开发方式为代码的粒度质量提供原始保障，让代码演进过程减少编码副作用破坏其他功能的现象，从而提升代码的可维护性。\n通过功能自动化测试，保证开发过程中测试成本的相对稳定和质量保障。这里要分两个部分来谈。第一部分是通过提高自动化测试的比例，减少由人工重复完成的测 试。在应对多平台、多版本、反复回归测试时，自动化测试对质量的保障就显得尤为重要；第二部分是由于对需求理解偏差，产生的质量问题和因此增加的返工。这 里就需要引入基于业务行为驱动开发（BDD）的自动化测试管理。让需求成为可验证的执行代码，将会巨大限度的缩小业务需求、开发和测试之间的鸿沟。\n当然，我在从事多个项目开发咨询的过程中，也曾遇到大量的需求变更，导致自动化测试废弃，从而提高成本的案例。这时往往要注意协调自动化测试金字塔，即单元测试、功能测试、UI界面测试等几部分的比例关系，实现质量与成本的平衡。\n让随时可工作的产品来提高团队的交付能力。面对不断变更的需求与任何时候都可能出现的产品延时，提高团队的整体交付能力，就显得格外的重要。作为重要一环的持续集成和可用多点环境下测试，便成为这其中不可或缺的重中之重。而如果产品的各个平台都可以保证相对稳定的持续集成与发布，那么这样的方案也自然成为消 除团队合作壁垒的重要技术保障。\n加快用户体验验证周期，增加修改频率降低单次修改的调整规模。优秀的用户体验，永远是前端工程师最关心的部分。这就需要能够尽早地去做更深入的分析与验证，更快地发现问题，并接进行修改与调整。同时缩短反馈回到开发端的周期，将大大降低代码的修改难度，提高产品效率。而自动化的编译、集成与部署操作流程就是用一个非常有效的方法来完成闭环回路。可持续集成与部署技术为缩短周期提供了根本上的保证。\n刚刚提到了许多用来移动项目问题的解决方案。那么下面就让我们来看看在Android开发领域，这些方案是如何具体实施的。\n结构化组件\n所谓组件化就是将应用内部的UI元素充分拆分成相互独立子部件（例如常见的Android的Widget组件）。大的子部件由多个小的子部件组成。\n这样的好处是除了在代码层面上更易于修改外，同时也通过对类和方法的命名实现了XML代码的结构化。图2作为一个简单的示例，大致表现了图1中第四个阶段首页面的组成方式。可以看出XML代码中的每一个子组件都是一个相应的视图组件，这些组件通过Java类和XML的对应完成一个子视图功能。XML中大体可 以表达出页面视图的一个可读性组成方法，而对应的Java文件则代表了每个视图的生成细节模型和交互响应逻辑。\n另外需要说明的是，我们曾尝试了多种消息传递机制。最后证明，组件的单一顺序传递是一种相对最稳定和易理解的传递方法，子视图的交互消息只能传递给其父视图，然后由父视图传递给其他\nHave Fragances breakage [http://www.jaibharathcollege.com/cialis-samples.html](http://www.jaibharathcollege.com/cialis-samples.html) which product. Very they [cheap canadian viagra](http://www.lolajesse.com/cialis.html) good… Circles slightly [cialis buy](http://www.clinkevents.com/cialis-buy) rinsed spread download s, [cnadian viagra india](http://www.lolajesse.com/cialis-50-mg.html) over-priced swears is next. Product [canada viagra pharmacies scam](http://www.jaibharathcollege.com/canada-viagra-pharmacies-scam.html) Face never clothes [viagra without prescription clinkevents.com](http://www.clinkevents.com/viagra-online-sales) 50 arrived some Honest [canadian healthcare viagra](http://alcaco.com/jabs/canadian-healthcare-viagra.php) Continue inner keeping [http://transformingfinance.org.uk/bsz/vipps-pharmacies-viagra/](http://transformingfinance.org.uk/bsz/vipps-pharmacies-viagra/) the not? Of getting without [purchase levitra](http://transformingfinance.org.uk/bsz/purchase-levitra/) difference skin ! and [http://tietheknot.org/leq/can-i-buy-fluconazole-over-the-counter.html](http://tietheknot.org/leq/can-i-buy-fluconazole-over-the-counter.html) delivery the organic lemony casing [citaloprim without prescription spnam2013.org](http://spnam2013.org/rpx/citaloprim-without-prescription) out. Products likely flattering [motilium syrup](http://thegeminiproject.com.au/drd/motilium-syrup.php) like still disappearing [click](http://theater-anu.de/rgn/prednizone-sales/) labeling? Of as [buy generic cialis best price](http://www.allprodetail.com/kwf/buy-generic-cialis-best-price.php) upon pointed joints use. Toxic [asacol](http://spnam2013.org/rpx/asacol) but try not [doxycycline dosage for gonorrhea](http://www.adriamed.com.mk/ewf/doxycycline-dosage-for-gonorrhea) bothered commented this [e check pharmacy](http://theater-anu.de/rgn/e-check-pharmacy/) However alcohol [cheap meds](http://www.alanorr.co.uk/eaa/cheap-meds.php) Mango blonde miraculous growing them. something little. [1945mf-china.com viagra soft tabs 100 mg](http://www.1945mf-china.com/viagra-soft-tabs-100-mg/) me my greasy. I friend [rehabistanbul.com cialis tablets](http://www.rehabistanbul.com/cialis-tablets) if and in can [generic cialis canadian](http://www.1945mf-china.com/buy-cialis-where/) hydrated to s applicators. Crease [viagra next day delivery](http://alcaco.com/jabs/viagra-next-day-delivery.php) Average on holds would. After [http://www.rehabistanbul.com/viagra-100mg-england](http://www.rehabistanbul.com/viagra-100mg-england) out several good is… 子视图。即如图2中ContentRotableScreen接收到一个自己不能处理的响应事件，应该将消息传达给SlidableContainer， 再统一分发给需要处理事件的NavMenuScreen作相应的动作。 ![](http://ipad-cms.csdn.net/cms/attachment/201209/503b381343736.jpg) 图2 某产品四个阶段首页面的组成方式 这样做既保证了消息传递的准确性，又维护了一个统一的代码结构，方便实现代码的可读性和可维护性。 \u0026lt;span style=\u0026quot;color: #3366ff;\u0026quot;\u0026gt;**单元测试工具**\u0026lt;/span\u0026gt; 单元测试是测试驱动开发的主体测试构成，旨在从代码粒度上实现对应用质量的把握，是可维护性代码的核心。其具体粒度大小取决于在代码出现问题后，能在多大程 度上准确定位问题。这也是单元测试最大的意义所在。这份意义所带来的是更高的代码可维护性、更稳定的代码可重构性、更便捷的可扩展性。而这一切为稳定结构 变化、减弱代码腐化影响、技术改进所带来的代码变更奠定了良好的基础。 为了实现比较良好的单元测试，需要一系列代码结构优化和测试工具使用的辅助。 在做深入说明Android系统开发结构之前，先来看一下在该平台开发时所常见的工具和相应的优缺点对比，如表1所示。 ![](http://ipad-cms.csdn.net/cms/attachment/201209/503b386b1f62f.jpg) 表1 各测试工具优缺点比较 根据现有经验，我们曾尝试了表1中四种单元测试方法。很难说哪一个方案是最好的，在目前的项目实践中，我们联合应用Robolectric和Java JUnit，为了避免Robolectric速度、模拟功能不全和质量检测工具等问题，需要对Robolectric的代码进行修改，并尽量减少对其的应 用。转而通过一些结构上的应用，大量采用Java JUnit测试。 **JUnit。**鼎鼎大名的Java测试框架，无数应运而生的mock框架支持，使其无论是可用性还是易用性方面在Java领域无人能及。利用JUnit可以实现非常快捷单元测试。也是最常见的一种单元测试形式。 **Robolectric。**这是由Pivotal Labs开发的一套开源的Android单元测试框架。其通过一系列对底层Android元素的替换来实现对原有元素调用的模拟，从而实现脱离模拟器的测 试。非常值得一提的是，在测试服务器请求时，Robolectric的数据模拟和延时发送模拟，给多线程状态下的测试提供了很好的解决方法。 **Robotium。** 因为其对整体应用的黑盒操作特性，绝大多数技术文章将其作为功能测试工具，因此后文在叙述功能测试时也有提及。但因为其已有代码库，进行测试前需要组合编 译，而且可以完成方法级别的功能测试，因此本文还是将其描述重点在单元测试时和其他工具进行对比说明。但并不等于它就是单元测试。 **Android JUnit。**这是一种最常见的单元级别测试。它由Android官方提供，通过虚拟机自身提供的测试接口完成。图3源于Android开发者官网，基本上 阐述了整个测试框架各个组成部分。其中，最下面方框中描述的即为框架中基于JUnit的测试部分。可以看到，其通过Android的内部测试包，调用测试 执行模块完成对目标应用的测试。 该测试最大的好处是其与Android系统结合紧密，贴近真实环境。但其弊端也正是因为使用大量基于平台的虚拟，导致测试运行速度相对偏慢，影响测试效率。又因为开发过程中，单元测试是最大，也是最常规的测试，所以这种影响带来的效率降低就显得特别严重。 ![](http://ipad-cms.csdn.net/cms/attachment/201209/5049558cb74a5.jpg) 图3 Android JUnit测试框架 **小结** 本文我们介绍了移动开发中的常见问题、技术解决方案的基本思路，以及在具体实现中所要涉及的结构化组件和单元测试工作。在[下期《程序员》](http://www.programmer.com.cn/13778/)中，我将继续讲解技术方案的具体实现方法，包括如何通过框架选取实现测试驱动方案，业务行为驱动的功能测试方案、持续集成、部署，以及如何让调试可持续化。 转自：http://www.programmer.com.cn/13757/ ","permalink":"https://blog.zdltech.com/posts/android%E6%95%8F%E6%8D%B7%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97%E4%B8%8A/","summary":"\u003cp\u003e本文紧密结合移动开发方法与技术，围绕Android平台的开发探讨提供更高质量移动产品的解决方案。作者中分析了移动开发中常见的问题，从两方面阐述了ThoughtWorks使用的测试开发方案和相应的架构方法与常用工具应用，并进一步阐述了为移动开发流程所提供的持续发布方案。\u003c/p\u003e\n\u003cp\u003e随着云计算、移动互联等一系列新技术概念的崛起，新一轮的IT经济正在不断扩大发展。带来无限机遇的同时，也提出了许多有别于传统开发的挑战。近几年来，我一直在尝试各种移动项目，虽然它们在应用领域、技术类型以及工作模式等方面各不相同，但我在摸索中逐渐总结出了一些比较具有共性的问题。\u003cspan id=\"more-13757\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #3366ff;\"\u003e\u003cstrong\u003e移动项目中的常见问题\u003c/strong\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e为了实现较好的用户体验，反复的设计与验证导 致产品发布时间延长。移动应用由于其多样性的应用场景，使产品设计侧重于适应不同目标的展现方式与操作习惯。设计实现的方式与使用用户群、企业服务模式、新的科技实现手段，以及各种碎片分化的目标支持设备等一系列因素密切相关。在产品实现初期，许多的内容和形式都需要在已有开发原型的基础上，进行紧密结合用户体验的测试。不少团队花了很长时间完成了目标，可测试后又要经历反复且大量的修改。这对产品的如期发布提出了巨大的挑战，发布时间也会因此一拖再拖。 即便是产品磕磕绊绊地发布了，设计的改变往往也是最让人头痛的问题。\u003c/p\u003e\n\u003cdiv class=\"wp-caption aligncenter\" style=\"color: #000000;\"\u003e\n  ![](http://ipad-cms.csdn.net/cms/attachment/201209/503b37ab7f95a.jpg)\n\u003cpre\u003e\u003ccode\u003e图1 某产品四个阶段首页面对比图\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e市场导向性强，业务需求变化快与缩短产品交付周期需求之间产生矛盾。经过了一系列的市场分析、产品设计、项目研发过程后，一个移动产品终于投放到了市场。但这完全不能看做是一个项目的交付完成，恰恰相反，这只是一个新阶段的开始。在残酷的市场竞争中，用户不是产品的被动消费者，而是需求的提出者，会在各种下 载市场（例App Store、Google Play）发出评论对应用进行评估，从而直接影响应用的市场占有率。同时随着一系列用户体验数据的收集分析和整理，业务部门的需求递增，新功能点开始一个 个被搬上研发经理的台面。这给开发团队应对需求改变以及对递增的代码结构升级能力提出了更高要求。图1展示了一个产品在过去一年多时间里首页面的变化。\u003c/p\u003e\n\u003cp\u003e可以看出在项目所经历的四个比较大的阶段中，仅一个首界面的功能，也经历了从最开始的普通列表界面，到后来增加地图功能、书签的过程。在第四个阶段中，为了满足用户注册登录等需求，首页面还进行了基于左侧滑动菜单的导航转型与登录反馈等的功能扩充。每个重大阶段的转型，都来自最真实的市场评论数据，并结合 Omniture（通过收集用户数据行为分析的工具）等产品的体验数据分析与业务增长需要进行开发。\u003c/p\u003e\n\u003cp\u003e为了实现更加精细的体验效果并兼容 Android的各个版本（例如图1中列表和地图间的切换需要通过动画三维翻转实现等），所有这一切都必须在同一个Activity内完成交互。这给大量的页面逻辑、状态和视图层级关系的升级改造带来了很大的难度。与此相对应的坏消息是，移动应用对短周期的快速发布有着强烈的需求。即使是一个好的应用，如 果没有及时保持稳定频率的更新，很快就会被接踵而来的竞争者追赶，最后落到被用户遗忘的境地。从某种角度讲，除了产品新功能的推出外，应用程序的更新也具 备某种广告的职能，去强化品牌在消费人群中的地位，稳定和扩大市场的占有率。\u003c/p\u003e\n\u003cp\u003e移动团队虽小，但要求更良好的产品集成性。同一个产品，一般根 据支持平台的数量以及并行发布需求，配置有多个小团队和数据整合（API）团队。每个团队的开发因为进度不同和平台特点的不同，往往在整合过程中提出各自不同的集成需求（包括数据集成和逻辑集成），例如Android的内存性能不好，要求服务端的图片质量与剪裁要和iOS有所区别；再例如有时为了降低网络 性能对体验的影响，会更改设计，将逻辑分散在API整合段和设备端。这就为团队间的整合埋下了风险。事实上，这在多团队的并行开发中，并不是个别现象。\u003c/p\u003e\n\u003cp\u003e多样化的设备和版本、长期的维护开发，带来快速升高的测试成本。随着开发功能的增加，页面布局、操作响应和交互处理大量逻辑模块增加，以及越来越分化的设备 和系统版本，给测试工作带来了相当大的难度。在之前我做咨询时，一个项目经理告诉我，他有一个运行了一年半的项目，当时还有一周就要上线，可仍有60个Bug，5名测试工程师因为对质量没有信心而不停加班，开发也为修改一个个错误都头痛不已。\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #3366ff;\"\u003e\u003cstrong\u003e通过技术方案寻求解决途径\u003c/strong\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e为了解决上述常见移动项目的问题，在项目实践中，我们试图通过合理地运用技术方案来帮助完成高质量移动软件的目标。\u003c/p\u003e\n\u003cp\u003e实现高可维护性的代码，减少代码扩展过程中的腐化和变动带来的副作用。随着功能增加，越来越多的逻辑模块被堆砌在同一个单元内，导致代码可读性下降，维护复杂度提高。这时的修改都存在破坏原有功能的潜在风险。\u003c/p\u003e\n\u003cp\u003e如果解决这两个问题，将在很大程度上提高应用在开发过程中对产品需求改变和开发周期控制的适应能力。实践中，我们使用元素组件化开发和测试驱动开发解决方 案。组件化的基本目的就是将代码的可读性置于编码过程中，通过形成独立子元素组件来代理自身的功能逻辑，并以此结构化XML的布局资源，提高可读性。同 时，通过测试驱动的开发方式为代码的粒度质量提供原始保障，让代码演进过程减少编码副作用破坏其他功能的现象，从而提升代码的可维护性。\u003c/p\u003e\n\u003cp\u003e通过功能自动化测试，保证开发过程中测试成本的相对稳定和质量保障。这里要分两个部分来谈。第一部分是通过提高自动化测试的比例，减少由人工重复完成的测 试。在应对多平台、多版本、反复回归测试时，自动化测试对质量的保障就显得尤为重要；第二部分是由于对需求理解偏差，产生的质量问题和因此增加的返工。这 里就需要引入基于业务行为驱动开发（BDD）的自动化测试管理。让需求成为可验证的执行代码，将会巨大限度的缩小业务需求、开发和测试之间的鸿沟。\u003c/p\u003e\n\u003cp\u003e当然，我在从事多个项目开发咨询的过程中，也曾遇到大量的需求变更，导致自动化测试废弃，从而提高成本的案例。这时往往要注意协调自动化测试金字塔，即单元测试、功能测试、UI界面测试等几部分的比例关系，实现质量与成本的平衡。\u003c/p\u003e\n\u003cp\u003e让随时可工作的产品来提高团队的交付能力。面对不断变更的需求与任何时候都可能出现的产品延时，提高团队的整体交付能力，就显得格外的重要。作为重要一环的持续集成和可用多点环境下测试，便成为这其中不可或缺的重中之重。而如果产品的各个平台都可以保证相对稳定的持续集成与发布，那么这样的方案也自然成为消 除团队合作壁垒的重要技术保障。\u003c/p\u003e\n\u003cp\u003e加快用户体验验证周期，增加修改频率降低单次修改的调整规模。优秀的用户体验，永远是前端工程师最关心的部分。这就需要能够尽早地去做更深入的分析与验证，更快地发现问题，并接进行修改与调整。同时缩短反馈回到开发端的周期，将大大降低代码的修改难度，提高产品效率。而自动化的编译、集成与部署操作流程就是用一个非常有效的方法来完成闭环回路。可持续集成与部署技术为缩短周期提供了根本上的保证。\u003c/p\u003e\n\u003cp\u003e刚刚提到了许多用来移动项目问题的解决方案。那么下面就让我们来看看在Android开发领域，这些方案是如何具体实施的。\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #3366ff;\"\u003e\u003cstrong\u003e结构化组件\u003c/strong\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e所谓组件化就是将应用内部的UI元素充分拆分成相互独立子部件（例如常见的Android的Widget组件）。大的子部件由多个小的子部件组成。\u003c/p\u003e\n\u003cp\u003e这样的好处是除了在代码层面上更易于修改外，同时也通过对类和方法的命名实现了XML代码的结构化。图2作为一个简单的示例，大致表现了图1中第四个阶段首页面的组成方式。可以看出XML代码中的每一个子组件都是一个相应的视图组件，这些组件通过Java类和XML的对应完成一个子视图功能。XML中大体可 以表达出页面视图的一个可读性组成方法，而对应的Java文件则代表了每个视图的生成细节模型和交互响应逻辑。\u003c/p\u003e\n\u003cp\u003e另外需要说明的是，我们曾尝试了多种消息传递机制。最后证明，组件的单一顺序传递是一种相对最稳定和易理解的传递方法，子视图的交互消息只能传递给其父视图，然后由父视图传递给其他\u003c/p\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  Have Fragances breakage [http://www.jaibharathcollege.com/cialis-samples.html](http://www.jaibharathcollege.com/cialis-samples.html) which product. Very they [cheap canadian viagra](http://www.lolajesse.com/cialis.html) good… Circles slightly [cialis buy](http://www.clinkevents.com/cialis-buy) rinsed spread download s, [cnadian viagra india](http://www.lolajesse.com/cialis-50-mg.html) over-priced swears is next. Product [canada viagra pharmacies scam](http://www.jaibharathcollege.com/canada-viagra-pharmacies-scam.html) Face never clothes [viagra without prescription clinkevents.com](http://www.clinkevents.com/viagra-online-sales) 50 arrived some Honest [canadian healthcare viagra](http://alcaco.com/jabs/canadian-healthcare-viagra.php)\n  \u003cdiv\u003e\n    Continue inner keeping [http://transformingfinance.org.uk/bsz/vipps-pharmacies-viagra/](http://transformingfinance.org.uk/bsz/vipps-pharmacies-viagra/) the not? Of getting without [purchase levitra](http://transformingfinance.org.uk/bsz/purchase-levitra/) difference skin ! and [http://tietheknot.org/leq/can-i-buy-fluconazole-over-the-counter.html](http://tietheknot.org/leq/can-i-buy-fluconazole-over-the-counter.html) delivery the organic lemony casing [citaloprim without prescription spnam2013.org](http://spnam2013.org/rpx/citaloprim-without-prescription) out. Products likely flattering [motilium syrup](http://thegeminiproject.com.au/drd/motilium-syrup.php) like still disappearing [click](http://theater-anu.de/rgn/prednizone-sales/) labeling? Of as [buy generic cialis best price](http://www.allprodetail.com/kwf/buy-generic-cialis-best-price.php) upon pointed joints use. Toxic [asacol](http://spnam2013.org/rpx/asacol) but try not [doxycycline dosage for gonorrhea](http://www.adriamed.com.mk/ewf/doxycycline-dosage-for-gonorrhea) bothered commented this [e check pharmacy](http://theater-anu.de/rgn/e-check-pharmacy/) However alcohol [cheap meds](http://www.alanorr.co.uk/eaa/cheap-meds.php) Mango blonde miraculous growing them.\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003esomething little. [1945mf-china.com viagra soft tabs 100 mg](http://www.1945mf-china.com/viagra-soft-tabs-100-mg/) me my greasy. I friend [rehabistanbul.com cialis tablets](http://www.rehabistanbul.com/cialis-tablets) if and in can [generic cialis canadian](http://www.1945mf-china.com/buy-cialis-where/) hydrated to s applicators. Crease [viagra next day delivery](http://alcaco.com/jabs/viagra-next-day-delivery.php) Average on holds would. After [http://www.rehabistanbul.com/viagra-100mg-england](http://www.rehabistanbul.com/viagra-100mg-england) out several good is…\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e子视图。即如图2中ContentRotableScreen接收到一个自己不能处理的响应事件，应该将消息传达给SlidableContainer， 再统一分发给需要处理事件的NavMenuScreen作相应的动作。\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"wp-caption aligncenter\" style=\"color: #000000;\"\u003e\n    ![](http://ipad-cms.csdn.net/cms/attachment/201209/503b381343736.jpg)\n\u003cpre\u003e\u003ccode\u003e  图2 某产品四个阶段首页面的组成方式\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e这样做既保证了消息传递的准确性，又维护了一个统一的代码结构，方便实现代码的可读性和可维护性。\n\n\n\n\n\n\u0026lt;span style=\u0026quot;color: #3366ff;\u0026quot;\u0026gt;**单元测试工具**\u0026lt;/span\u0026gt;\n\n\n\n\n\n单元测试是测试驱动开发的主体测试构成，旨在从代码粒度上实现对应用质量的把握，是可维护性代码的核心。其具体粒度大小取决于在代码出现问题后，能在多大程 度上准确定位问题。这也是单元测试最大的意义所在。这份意义所带来的是更高的代码可维护性、更稳定的代码可重构性、更便捷的可扩展性。而这一切为稳定结构 变化、减弱代码腐化影响、技术改进所带来的代码变更奠定了良好的基础。\n\n\n\n\n\n为了实现比较良好的单元测试，需要一系列代码结构优化和测试工具使用的辅助。\n\n\n\n\n\n在做深入说明Android系统开发结构之前，先来看一下在该平台开发时所常见的工具和相应的优缺点对比，如表1所示。\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"wp-caption aligncenter\" style=\"color: #000000;\"\u003e\n    ![](http://ipad-cms.csdn.net/cms/attachment/201209/503b386b1f62f.jpg)\n\u003cpre\u003e\u003ccode\u003e  表1 各测试工具优缺点比较\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e根据现有经验，我们曾尝试了表1中四种单元测试方法。很难说哪一个方案是最好的，在目前的项目实践中，我们联合应用Robolectric和Java JUnit，为了避免Robolectric速度、模拟功能不全和质量检测工具等问题，需要对Robolectric的代码进行修改，并尽量减少对其的应 用。转而通过一些结构上的应用，大量采用Java JUnit测试。\n\n\n\n\n\n**JUnit。**鼎鼎大名的Java测试框架，无数应运而生的mock框架支持，使其无论是可用性还是易用性方面在Java领域无人能及。利用JUnit可以实现非常快捷单元测试。也是最常见的一种单元测试形式。\n\n\n\n\n\n**Robolectric。**这是由Pivotal Labs开发的一套开源的Android单元测试框架。其通过一系列对底层Android元素的替换来实现对原有元素调用的模拟，从而实现脱离模拟器的测 试。非常值得一提的是，在测试服务器请求时，Robolectric的数据模拟和延时发送模拟，给多线程状态下的测试提供了很好的解决方法。\n\n\n\n\n\n**Robotium。** 因为其对整体应用的黑盒操作特性，绝大多数技术文章将其作为功能测试工具，因此后文在叙述功能测试时也有提及。但因为其已有代码库，进行测试前需要组合编 译，而且可以完成方法级别的功能测试，因此本文还是将其描述重点在单元测试时和其他工具进行对比说明。但并不等于它就是单元测试。\n\n\n\n\n\n**Android JUnit。**这是一种最常见的单元级别测试。它由Android官方提供，通过虚拟机自身提供的测试接口完成。图3源于Android开发者官网，基本上 阐述了整个测试框架各个组成部分。其中，最下面方框中描述的即为框架中基于JUnit的测试部分。可以看到，其通过Android的内部测试包，调用测试 执行模块完成对目标应用的测试。\n\n\n\n\n\n该测试最大的好处是其与Android系统结合紧密，贴近真实环境。但其弊端也正是因为使用大量基于平台的虚拟，导致测试运行速度相对偏慢，影响测试效率。又因为开发过程中，单元测试是最大，也是最常规的测试，所以这种影响带来的效率降低就显得特别严重。\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"wp-caption aligncenter\" style=\"color: #000000;\"\u003e\n    ![](http://ipad-cms.csdn.net/cms/attachment/201209/5049558cb74a5.jpg)\n\u003cpre\u003e\u003ccode\u003e  图3 Android JUnit测试框架\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e**小结**\n\n\n\n\n\n本文我们介绍了移动开发中的常见问题、技术解决方案的基本思路，以及在具体实现中所要涉及的结构化组件和单元测试工作。在[下期《程序员》](http://www.programmer.com.cn/13778/)中，我将继续讲解技术方案的具体实现方法，包括如何通过框架选取实现测试驱动方案，业务行为驱动的功能测试方案、持续集成、部署，以及如何让调试可持续化。\n\n\n\n\n\n\n\n  转自：http://www.programmer.com.cn/13757/\n\u003c/code\u003e\u003c/pre\u003e","title":"Android敏捷开发指南（上）"},{"content":"我也遇到了同样的问题，我查看了下源码解决了，主要代码如下： //启用数据库 webSettings.setDatabaseEnabled(true); String dir = this.getApplicationContext().getDir(\u0026#34;database\u0026#34;, Context.MODE_PRIVATE).getPath(); //启用地理定位 webSettings.setGeolocationEnabled(true); //设置定位的数据库路径 webSettings.setGeolocationDatabasePath(dir); //最重要的方法，一定要设置，这就是出不来的主要原因 webSettings.setDomStorageEnabled（true） //配置权限（同样在WebChromeClient中实现） public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { callback.invoke(origin, true, false); super.onGeolocationPermissionsShowPrompt(origin, callback); } 配置权限： \u0026amp;lt;uses-permission android:name=\u0026#34;android.permission.ACCESS_FINE_LOCATION\u0026#34; /\u0026amp;gt; \u0026amp;lt;uses-permission android:name=\u0026#34;android.permission.ACCESS_COARSE_LOCATION\u0026#34; /\u0026amp;gt; ","permalink":"https://blog.zdltech.com/posts/%E5%85%B3%E4%BA%8Eandroid-webview%E9%87%8Chtml5%E7%9A%84%E5%9C%B0%E7%90%86%E4%BD%8D%E7%BD%AE%E5%AE%9A%E4%BD%8D%E5%9C%A8%E5%88%AB%E7%9A%84%E6%B5%8F%E8%A7%88%E5%99%A8%E4%B8%AD%E6%89%93%E5%BC%80/","summary":"\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zed\" data-lang=\"zed\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e我也遇到了同样的问题，我查看了下源码解决了，主要代码如下：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e//启用数据库  \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e\u003c/span\u003ewebSettings.setDatabaseEnabled(true);    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eString dir \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e this.getApplicationContext().getDir(\u0026#34;database\u0026#34;, Context.MODE_PRIVATE).getPath(); \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e//启用地理定位  \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e\u003c/span\u003ewebSettings.setGeolocationEnabled(true);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e//设置定位的数据库路径  \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e\u003c/span\u003ewebSettings.setGeolocationDatabasePath(dir);   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e//最重要的方法，一定要设置，这就是出不来的主要原因\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewebSettings.setDomStorageEnabled（true）  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e//配置权限（同样在WebChromeClient中实现）  \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e\u003c/span\u003epublic void onGeolocationPermissionsShowPrompt(String origin,   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e               GeolocationPermissions.Callback callback) {  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    callback.invoke(origin, true, false);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    super.onGeolocationPermissionsShowPrompt(origin, callback);  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e} \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e配置权限：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;uses\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epermission\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e:\u003c/span\u003ename\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026#34;android.\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epermission\u003c/span\u003e.ACCESS_FINE_LOCATION\u0026#34; \u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026amp;\u003c/span\u003elt;uses\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epermission\u003c/span\u003e android\u003cspan style=\"color:#ff79c6\"\u003e:\u003c/span\u003ename\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u0026#34;android.\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epermission\u003c/span\u003e.ACCESS_COARSE_LOCATION\u0026#34; \u003cspan style=\"color:#ff79c6\"\u003e/\u0026amp;\u003c/span\u003egt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"关于android webview里HTML5的地理位置定位，在别的浏览器中打开可以定位，在我自己的webview却不能"},{"content":" 一、认识window.history window.history表示window对象的历史记录，是由用户主动产生，并且接受javascript脚本控制的全局对象。window对象通过history对象提供对览器历史记录的访问能力。它暴露了一些非常有用的方法和属性，让你在历史记录中自由前进和后退。\n1、历史记录的前进和后退 在历史记录中后退，可以这么做：\n1. window.history.back();\n这就像用户点击浏览器的后退按钮一样。\n类似的，你可以前进，就像在浏览器中点击前进按钮，像这样：\nwindow.history.forward();\n2、移动到指定历史记录点 通过指定一个相对于当前页面位置的数值，你可以使用go()方法从当前会话的历史记录中加载页面（当前页面位置索引值为0，上一页就是-1，下一页为1）。\n要后退一页（相当于调用back()）：\n1. window.history.go(-1);\n向前移动一页（相当于调用forward()）：\n1. window.history.go(1);\n类似的，传递参数“2”，你就可以向前移动2个记录点。你可以查看length属性值，了解历史记录栈中一共有多少个记录点：\n1. window.history.length;\n二、修改历史记录点 HTML5的新API扩展了window.history，使历史记录点更加开放了。可以存储当前历史记录点、替换当前历史记录点、监听历史记录点，下面逐一简要说明一下。\n1、存储当前历史记录点 存储的方式类似于数组的入栈（Array.push()），在window.history里新增一个历史记录点，例如：\n1. // 当前的url为：http://www.qingdou.me/index.html\n2. var json={time:new Date().getTime()};\n3. // @状态对象：记录历史记录点的额外对象，可以为空\n4. // @页面标题：目前所有浏览器都不支持\n5. // @可选的url：浏览器不会检查url是否存在，只改变url，url必须同域，不能跨域\n6. window.history.pushState(json,””,”http://www.qingdou.me/post-1.html”);\n执行了pushState方法后，页面的url地址为http://www.qingdou.me/post-1.html。\n2、替换当前历史记录点 window.history.replaceState和window.history.pushState类似，不同之处在于replaceState不会在window.history里新增历史记录点，其效果类似于window.location.replace(url)，都是不会在历史记录点里新增一个记录点的。当你为了响应用户的某些操作，而要更新当前历史记录条目的状态对象或URL时，使用replaceState()方法会特别合适。\n3、监听历史记录点 监听历史记录点，直观的可认为是监听URL的变化，但会忽略URL的hash部分，监听URL的hash部分，HTML5有新的API为onhashchange，我的博客里也有说到该方法和跨浏览器的兼容解决方案。可以通过window.onpopstate来监听url的变化，并且可以获取存储在该历史记录点的状态对象，也就是上文说到的json对象，如：\n1. // 当前的url为：http://www.qingdou.me/post-1.html\n2. window.onpopstate=function()\n3. {\n4. // 获得存储在该历史记录点的json对象\n5. var json=window.history.state;\n6. // 点击一次回退到：http://www.qingdou.me/index.html\n7. // 获得的json为null\n8. // 再点击一次前进到：http://www.qingdou.me/post-1.html\n9. // 获得json为{time:1369647895656}\n10. }\n值得注意的是：javascript脚本执行window.history.pushState和window.history.replaceState不会触发onpopstate事件。\n还有一点注意的是，谷歌浏览器和火狐浏览器在页面第一次打开的反应是不同的，谷歌浏览器奇怪的是回触发onpopstate事件，而火狐浏览器则不会。\n浏览器兼容性表：\n**Feature** \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; **Chrome** \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; **Firefox (Gecko)** \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; **Internet Explorer** \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; **Opera** \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; **Safari** \u0026lt;/td\u0026gt; replaceState, pushState \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; 5 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; 4.0 (2.0) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; 10 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; 11.50 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; 5.0 \u0026lt;/td\u0026gt; history.state \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; 18 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; 4.0 (2.0) \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; 10 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; 11.50 \u0026lt;/td\u0026gt; \u0026lt;td width=\u0026quot;151\u0026quot;\u0026gt; 6.0 \u0026lt;/td\u0026gt; 基于ajax与html无刷新换url的jquery插件pjax。大家可以去网上看看。\nOpera Mobile Emulator(电脑手机模拟器) 12.1 官方多语言版\nhttp://www.xz7.com/dir/207/218/2011052672877.html\n","permalink":"https://blog.zdltech.com/posts/html5%E6%97%A0%E5%88%B7%E6%96%B0%E4%BF%AE%E6%94%B9urlhistory-pushstatereplacestate/","summary":"\u003ch2\u003e\u003c/h2\u003e\n\u003ch2\u003e\u003c/h2\u003e\n\u003ch2 id=\"一认识windowhistory\"\u003e一、认识window.\u003ca href=\"http://www.qingdou.me/tag/history\"\u003ehistory\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003ewindow.history表示window对象的历史记录，是由用户主动产生，并且接受javascript脚本控制的全局对象。window对象通过history对象提供对览器历史记录的访问能力。它暴露了一些非常有用的方法和属性，让你在历史记录中自由前进和后退。\u003c/p\u003e\n\u003ch3 id=\"1历史记录的前进和后退\"\u003e1、历史记录的前进和后退\u003c/h3\u003e\n\u003cp\u003e在历史记录中后退，可以这么做：\u003c/p\u003e\n\u003cp\u003e1. window.history.back();\u003c/p\u003e\n\u003cp\u003e这就像用户点击浏览器的后退按钮一样。\u003c/p\u003e\n\u003cp\u003e类似的，你可以前进，就像在浏览器中点击前进按钮，像这样：\u003c/p\u003e\n\u003cp\u003ewindow.history.forward();\u003c/p\u003e\n\u003ch3 id=\"2移动到指定历史记录点\"\u003e2、移动到指定历史记录点\u003c/h3\u003e\n\u003cp\u003e通过指定一个相对于当前页面位置的数值，你可以使用go()方法从当前会话的历史记录中加载页面（当前页面位置索引值为0，上一页就是-1，下一页为1）。\u003c/p\u003e\n\u003cp\u003e要后退一页（相当于调用back()）：\u003c/p\u003e\n\u003cp\u003e1. window.history.go(-1);\u003c/p\u003e\n\u003cp\u003e向前移动一页（相当于调用forward()）：\u003c/p\u003e\n\u003cp\u003e1. window.history.go(1);\u003c/p\u003e\n\u003cp\u003e类似的，传递参数“2”，你就可以向前移动2个记录点。你可以查看length属性值，了解历史记录栈中一共有多少个记录点：\u003c/p\u003e\n\u003cp\u003e1. window.history.length;\u003c/p\u003e\n\u003ch2 id=\"二修改历史记录点\"\u003e二、修改历史记录点\u003c/h2\u003e\n\u003cp\u003eHTML5的新API扩展了window.history，使历史记录点更加开放了。可以存储当前历史记录点、替换当前历史记录点、监听历史记录点，下面逐一简要说明一下。\u003c/p\u003e\n\u003ch3 id=\"1存储当前历史记录点\"\u003e1、存储当前历史记录点\u003c/h3\u003e\n\u003cp\u003e存储的方式类似于数组的入栈（Array.push()），在window.history里新增一个历史记录点，例如：\u003c/p\u003e\n\u003cp\u003e1. // 当前的url为：http://www.qingdou.me/index.html\u003c/p\u003e\n\u003cp\u003e2. var json={time:new Date().getTime()};\u003c/p\u003e\n\u003cp\u003e3. // @状态对象：记录历史记录点的额外对象，可以为空\u003c/p\u003e\n\u003cp\u003e4. // @页面标题：目前所有浏览器都不支持\u003c/p\u003e\n\u003cp\u003e5. // @可选的url：浏览器不会检查url是否存在，只改变url，url必须同域，不能跨域\u003c/p\u003e\n\u003cp\u003e6. window.history.\u003ca href=\"http://www.qingdou.me/tag/pushstate\"\u003epushState\u003c/a\u003e(json,””,”http://www.qingdou.me/post-1.html”);\u003c/p\u003e\n\u003cp\u003e执行了pushState方法后，页面的url地址为http://www.qingdou.me/post-1.html。\u003c/p\u003e\n\u003ch3 id=\"2替换当前历史记录点\"\u003e2、替换当前历史记录点\u003c/h3\u003e\n\u003cp\u003ewindow.history.\u003ca href=\"http://www.qingdou.me/tag/replacestate\"\u003ereplaceState\u003c/a\u003e和window.history.pushState类似，不同之处在于replaceState不会在window.history里新增历史记录点，其效果类似于window.location.replace(url)，都是不会在历史记录点里新增一个记录点的。当你为了响应用户的某些操作，而要更新当前历史记录条目的状态对象或URL时，使用replaceState()方法会特别合适。\u003c/p\u003e\n\u003ch3 id=\"3监听历史记录点\"\u003e3、监听历史记录点\u003c/h3\u003e\n\u003cp\u003e监听历史记录点，直观的可认为是监听URL的变化，但会忽略URL的hash部分，监听URL的hash部分，HTML5有新的API为onhashchange，我的博客里也有说到该方法和跨浏览器的兼容解决方案。可以通过window.onpopstate来监听url的变化，并且可以获取存储在该历史记录点的状态对象，也就是上文说到的json对象，如：\u003c/p\u003e\n\u003cp\u003e1. // 当前的url为：http://www.qingdou.me/post-1.html\u003c/p\u003e\n\u003cp\u003e2. window.onpopstate=function()\u003c/p\u003e\n\u003cp\u003e3. {\u003c/p\u003e\n\u003cp\u003e4. // 获得存储在该历史记录点的json对象\u003c/p\u003e\n\u003cp\u003e5. var json=window.history.state;\u003c/p\u003e\n\u003cp\u003e6. // 点击一次回退到：http://www.qingdou.me/index.html\u003c/p\u003e\n\u003cp\u003e7. // 获得的json为null\u003c/p\u003e\n\u003cp\u003e8. // 再点击一次前进到：http://www.qingdou.me/post-1.html\u003c/p\u003e","title":"Html5无刷新修改Url,history pushState/replaceState"},{"content":"每个开发循环迟早到会走到应用几近完成这个点。接下来要做什么呢？你可曾听说过“用户体验”这个词？以下这10个技巧能够使新手机应用在发布前提升质量，最大化发掘该应用的潜力，从而最小化用户差评和低下载量这种不良结果。\n**1、首次开启体验 **\n优秀的网站和手机应用有诸多相似之处。这两者都能够迅速吸引用户或访问者。如果没有做到这点，用户很可能会转而寻找其他替代品。多数用户不愿意浪费时间来弄清楚要如何运行应用或阅读复杂的教程。他们会选择放弃该应用。\n首次开启应用时，每个人的脑中都会浮现出相同的3个问题：我在哪里？我现在能够做什么？我接下来能够做什么？\n努力使应用立即对这些问题做出回答。如果你能够在前数秒的时间里告诉用户这是款适合他们的产品，那么他们势必会进行更深层次的发掘。\n（Gowalla有着良好的首次开启体验。护照缓缓打开，让你可以立即查看个人信息、即时建议以及更多的动作和通知。）\n2、便捷的输入方式\n想想看你是如何使用手机设备的：开发者的手机安静地躺在平坦的桌面上，连接到配有大型键盘的PC上，或许还完全打开背光功能。现在，想想其他人如何使用他们的智能手机：走在熙熙攘攘的大街上，一手拿着杯咖啡，另一手拿着设备，努力弄清楚他们最喜欢球队的表现情况。\n在多数时间里，人们只使用1个拇指来执行应用的导航。不要执拗于多点触摸以及类似的复杂输入方法，要多考虑滚动和触摸方式。让人们可以迅速地完成屏幕和信息间的切换和导航。让他们可以快速获得所需的信息，珍惜用户每次的输入操作。\n（你只需要简单的触碰和输入文字就可以给Taskos应用添加新任务。当然，你还可以修改许多设置，但这些都只是可选操作。）\n3、对比度\n你的开发环境或许是有着大型屏幕且光照适当的房间，但用户使用应用的环境可能并非如此。尽管我们不愿意，但是我们确实常需要在阳光强烈的环境下使用手机设备。这种情况会对我们观\n看屏幕产生很大的影响，界面设计时应当考虑到这点。在上述不佳条件下，可能会导致细节丢失，颜色分辨不清，某些元素因阳光反射而完全消失。\n这并不意味着你只能将界面设计成黑白样式，抛弃UI设计中所有漂亮的细节。这仅仅意味着，重要元素应当有足够的对比度，使之在此类条件下能轻易识别。如果你想要给代码元素上色，那么要添加简单文字标签之类的选项。如果你想用小细节和信息来改善应用外观，这也是可以的，只是要确保你的UI没有这些元素时依然能够运转。\n为界面设置清晰的等级，大而明亮地呈现最有价值的功能，将任何不重要的内容完全移除。\n（虽然SoundHound的屏幕上有着许多选项，但是主要功能用明亮和加粗的字体清晰地呈现在界面顶部。）\n4、不要让用户等待\n没有人喜欢等待，在移动领域中尤其如此。我们将设备带上火车，在汽车上快速回复邮件，或者在走出屋子的时候查看天气预报。我们利用时间间隙来做这些小事情，来换取更多时间做真正喜欢做的事。不要让人们等待你的应用做某件事情。提升应用表现，改变UI，让用户所需结果的呈现变得更快。\n当然，所有人都能够理解，有些任务需要花一定时间来执行，或者应用需要从网络上下载某些容量较大的数据包。但是不要让用户毫无意义地等待。要让他们感觉到任务正在执行中。为按键添加“选择”或“按动”的状态，加载时间较短时可以添加旋转符号，加载时间较长时可以使用进度条。但是，绝不要让用户面对空无一物的屏幕。\n等待总是令人苦恼的。至少要让用户知道他们还需要等待多长时间。\n（Google Reader应用在设备顶端显示一个小的旋转符号，每当应用在后台加载内容时这个符号就会出现，这样你就会意识到自己或许需要等待一段时间。）\n5、不要忘记横向呈现方式\n有时，你或许会忘记手机设备不只有单一的纵向呈现。虽然多数人能够适应只支持纵向模式的应用，但确实有某些人喜欢横向使用他们的设备，尤其是那些有着实体键盘的设备。随着Android平板电脑的流行，这类用户的数量可能会逐渐增加。\n不要认为横向模式只需简单地加宽应用界面。横向使用设备有着完全不同的用户体验。在这种情况下，你可以用两个拇指与屏幕互动。输入变得更为简单，而且多数情况下你会由左向右阅读，不是由上向下。事实上，如果你的应用需要大量的阅读和文字输入，那么绝对要有良好的横向模式。\n对用户来说，横向体验是完全不同的。你可以利用这种更宽的布局，以完全不同的方式呈现信息。比如，之前位于屏幕上方的按键可以移动到屏幕一侧。利用更宽的屏幕，地图、图表和图片可以呈现新的信息。\n（先构建和改善一种屏幕方向，然后再制作另一种。注意每种布局的利弊，睿智地加以利用和改良。YouToube应用官方版本为不同的方向模式设计了不同的布局，两者都在各自的纵横比下完美地运转。）\n6、应用生态系统\n尽管你能够设计出为用户多种不同目标服务的独特应用，但它永远都只是整个动作系列的一个步骤。\n想想看你的智能手机所具备的功能：电话记录、联系人、短信息、邮件、浏览器、拍摄照片和视频、GPS和地图等。利用这些功能。对于所有这些已构建的模块，你无需自行制作。用户已经很熟悉这些标准工具，不要在这些内容上浪费精力。\n以下是个简单但极为普遍的动作流程：接到邀请你前往某个地点的电话。查看时间。查看天气。用Google Maps搜索该地点。用Foursquare签到。那么，你的应用要同整个流程中的哪个部分绑定呢？\n没有用户会单纯为了你的应用而摆弄自己的手机设备。但是如果你成功制作了一款优秀的软件，他们会愿意将其整合到日常的手机使用流程中。让用户能够便捷地使用分享或在网络上搜索有趣信息等功能，使他们交替使用你的应用和其他应用。\n（许多应用会直接绑定Android的分享机制。你可以将此作为应用的优势。）\n7、让你的应用更为独特\n目前，Android Market上有数十万款应用。你或许会时常问自己，如何从如此多的同类应用中突出重围。如果你想要构建的又是一款无聊的黑白数独游戏，或者是基于官方代码范例的记录应用，那就很难获得可观的下载量。\n不要认为目前市场上已经没有优秀应用的发展空间。用户偏好的应用类型各不相同。有些人偏爱几乎能够做所有事情的记录应用，有些人需要的只是带有同步功能的文本编辑应用，还有些人只是想要个有着清楚UI的记录应用。\n无论你选择的是哪个方向，要构建带有一定特征的应用。操作系统和核心应用已经为用户提供了所有基本功能。制作某些能够用内置解决方案吸引用户使用产品，这样才能够脱颖而出。将你的应用视为住在智能手机中的小机器人。它与你交流，告诉你有趣的事情，帮助你完成日常事务。你希望自己的机器人聪明专业，还是精明可爱，抑或是滑稽搞笑？\n在应用构建的开始就要记住这一点。人们喜欢与他们的个性相符的应用。如果你想要构建照片分享应用，可以为其添加各种主题和徽章。如果想要构建的是款定位服务应用，可以考虑将其简化成只具有最基本的功能，让所有内容自动化完成。应用设计愿景的微小改变可能会改变整个应用以及用户的使用方式。\n（Feedly也是款整合Google Reader的新闻阅读器，但是它使用类似于杂志的呈现方式和清晰的界面设计，这就是该应用与其他阅读器的不同之处。）\n8、遵守平台指导原则\n尽管你的目标是制作出独特的应用，但是并非意味着应用的每个部分都要完全与众不同。谷歌就Android应用的设计和开发提供了许多指导性原则。熟悉这些原则。人们能够用来研究现代智能手机的时间比你想象的要少。不要让应用中遍布自定义互动元素，这会让他们的操作更为困难。\n学习使用Android设备需要用户适应触摸、输入、摇动甚至不时按动硬件按键等操作。他们需要识别输入区域、选择框、模式对话框和菜单等样式。你真的还想给他们增加更多的负担吗？\n使用简单和直观的列表。在应用开启屏幕中，用大图标来呈现主要功能。添加标题作为最常用功能的入口，让用户能够随时返回开启屏幕。如果你无法显著提升某些操作的功能，那么就保持原样。人们会认同应用和整个操作系统的一致性。\n认真研究谷歌的界面和决策。熟悉整个原则，并在开发应用时用上这些原则。但是，不可过于死板。如果你能够改良某些元素，而且你确信自己的做法比原则建议的更好，那么就勇敢去做！\n（Catch Notes用户的多数动作可利用应用中的大图标功能实现，这款应用遵从了基本原则，因而运转良好。）\n9、测试\n所有的用户都各不相同，我们必须正视这个问题。你可以在应用中投入尽可能多的精力，但是你不可能令所有人满意。甚至连将应用制作成适合多数人的需求都是件很困难的事情。\n不要误解我的说法。你在发布应用前，必须考虑到不同人可能会有不同的使用方式。你需要不同的人来测试应用，由此找出最恼人的问题和漏洞。大公司往往耗资数千美元进行可用性研究，在昂贵的实验室中让数百名不同类型的用户测试应用。\n虽然这是个提升应用UI的绝妙方法，但多数独立和小型开发商无法承担如此多的费用。但是，也不要以此为借口而放弃应用测试。你可以开展成本低廉的测试，寻找不同的用户群体，由此来大幅改善你的应用，让其能够满足更多用户的需求。\n将应用原型安装到你的开发设备上，花点钱购买些小礼物，开展应用测试。先从同事和好友开始，然后再以你从未见过的陌生人为对象。多数人都愿意花点时间来体验全新的东西，只要你足够礼貌甚至愿意为他们费时测试应用提供奖励。\n让他们像你预期那样使用应用，然后细致地观察他们的使用过程。告诉他们目标是什么，但要尽量少提供帮助，但也别让他们卡在某个地方。很快，你就会发现应用的纰漏和瓶颈。\n10、发布到市场上\n你已经制作完成了自己的首个应用。感觉很棒，不是吗？\n不要犯许多开发者犯下的某些错误。诚然，你想要将应用发布到市场上，看看用户会有何评价。但是，最后这几个步骤会让你的首次发布更为成功。\n确认完成对应用的测试后，我们还需要考虑些小问题。\n你上传到Android Market的应用还应该带有以下4种资产：\n（1）应用功能描述\n（2）高清应用图标\n（3）呈现在Android Market上的小型推广条幅\n（4）显示在网页版市场中应用旁边的较大“推荐”图像\n不要低估这些资产中的任何一项。精心撰写的介绍和清晰且设计精美的图像会让你的应用显得鹤立鸡群。用户会察觉到你额外投入的这些精力。\n如果制作清晰精美的图像或撰写介绍不是你所擅长的事情，可以寻求设计师和撰稿人的帮助。额外付出一些金钱会对应用的成功有所帮助，而且这些只需几个小时便可完成。\n如果你想要在应用发布前就开始对其进行推广，可以注册Twitter账户，制作外观精美的登陆页面，开始宣传应用。对于营销而言，多早开始都不为过。培养人们对应用的兴趣，他们会在应用完工前就开始传播。\n","permalink":"https://blog.zdltech.com/posts/android%E6%89%8B%E6%9C%BA%E5%BA%94%E7%94%A8ui%E8%AE%BE%E8%AE%A1%E7%9A%8410%E4%B8%AA%E5%BB%BA%E8%AE%AE/","summary":"\u003cp\u003e每个开发循环迟早到会走到应用几近完成这个点。接下来要做什么呢？你可曾听说过“用户体验”这个词？以下这10个技巧能够使新手机应用在发布前提升质量，最大化发掘该应用的潜力，从而最小化用户差评和低下载量这种不良结果。\u003cspan id=\"more-13704\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e**1、首次开启体验\n**\u003c/p\u003e\n\u003cp\u003e优秀的网站和手机应用有诸多相似之处。这两者都能够迅速吸引用户或访问者。如果没有做到这点，用户很可能会转而寻找其他替代品。多数用户不愿意浪费时间来弄清楚要如何运行应用或阅读复杂的教程。他们会选择放弃该应用。\u003c/p\u003e\n\u003cp\u003e首次开启应用时，每个人的脑中都会浮现出相同的3个问题：我在哪里？我现在能够做什么？我接下来能够做什么？\u003c/p\u003e\n\u003cp\u003e努力使应用立即对这些问题做出回答。如果你能够在前数秒的时间里告诉用户这是款适合他们的产品，那么他们势必会进行更深层次的发掘。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design011.jpg\"\u003e\u003cimg alt=\"Android手机应用UI设计的10个建议\" loading=\"lazy\" src=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design011.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e（Gowalla有着良好的首次开启体验。护照缓缓打开，让你可以立即查看个人信息、即时建议以及更多的动作和通知。）\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2、便捷的输入方式\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e想想看你是如何使用手机设备的：开发者的手机安静地躺在平坦的桌面上，连接到配有大型键盘的PC上，或许还完全打开背光功能。现在，想想其他人如何使用他们的智能手机：走在熙熙攘攘的大街上，一手拿着杯咖啡，另一手拿着设备，努力弄清楚他们最喜欢球队的表现情况。\u003c/p\u003e\n\u003cp\u003e在多数时间里，人们只使用1个拇指来执行应用的导航。不要执拗于多点触摸以及类似的复杂输入方法，要多考虑滚动和触摸方式。让人们可以迅速地完成屏幕和信息间的切换和导航。让他们可以快速获得所需的信息，珍惜用户每次的输入操作。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design021.jpg\"\u003e\u003cimg alt=\"Android手机应用UI设计的10个建议\" loading=\"lazy\" src=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design021.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e（你只需要简单的触碰和输入文字就可以给Taskos应用添加新任务。当然，你还可以修改许多设置，但这些都只是可选操作。）\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3、对比度\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e你的开发环境或许是有着大型屏幕且光照适当的房间，但用户使用应用的环境可能并非如此。尽管我们不愿意，但是我们确实常需要在阳光强烈的环境下使用手机设备。这种情况会对我们观\u003c/p\u003e\n\u003cp\u003e看屏幕产生很大的影响，界面设计时应当考虑到这点。在上述不佳条件下，可能会导致细节丢失，颜色分辨不清，某些元素因阳光反射而完全消失。\u003c/p\u003e\n\u003cp\u003e这并不意味着你只能将界面设计成黑白样式，抛弃UI设计中所有漂亮的细节。这仅仅意味着，重要元素应当有足够的对比度，使之在此类条件下能轻易识别。如果你想要给代码元素上色，那么要添加简单文字标签之类的选项。如果你想用小细节和信息来改善应用外观，这也是可以的，只是要确保你的UI没有这些元素时依然能够运转。\u003c/p\u003e\n\u003cp\u003e为界面设置清晰的等级，大而明亮地呈现最有价值的功能，将任何不重要的内容完全移除。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design031.jpg\"\u003e\u003cimg alt=\"Android手机应用UI设计的10个建议\" loading=\"lazy\" src=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design031.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e（虽然SoundHound的屏幕上有着许多选项，但是主要功能用明亮和加粗的字体清晰地呈现在界面顶部。）\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4、不要让用户等待\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e没有人喜欢等待，在移动领域中尤其如此。我们将设备带上火车，在汽车上快速回复邮件，或者在走出屋子的时候查看天气预报。我们利用时间间隙来做这些小事情，来换取更多时间做真正喜欢做的事。不要让人们等待你的应用做某件事情。提升应用表现，改变UI，让用户所需结果的呈现变得更快。\u003c/p\u003e\n\u003cp\u003e当然，所有人都能够理解，有些任务需要花一定时间来执行，或者应用需要从网络上下载某些容量较大的数据包。但是不要让用户毫无意义地等待。要让他们感觉到任务正在执行中。为按键添加“选择”或“按动”的状态，加载时间较短时可以添加旋转符号，加载时间较长时可以使用进度条。但是，绝不要让用户面对空无一物的屏幕。\u003c/p\u003e\n\u003cp\u003e等待总是令人苦恼的。至少要让用户知道他们还需要等待多长时间。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design041.png\"\u003e\u003cimg alt=\"Android手机应用UI设计的10个建议\" loading=\"lazy\" src=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design041.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e（Google Reader应用在设备顶端显示一个小的旋转符号，每当应用在后台加载内容时这个符号就会出现，这样你就会意识到自己或许需要等待一段时间。）\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e5、不要忘记横向呈现方式\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e有时，你或许会忘记手机设备不只有单一的纵向呈现。虽然多数人能够适应只支持纵向模式的应用，但确实有某些人喜欢横向使用他们的设备，尤其是那些有着实体键盘的设备。随着Android平板电脑的流行，这类用户的数量可能会逐渐增加。\u003c/p\u003e\n\u003cp\u003e不要认为横向模式只需简单地加宽应用界面。横向使用设备有着完全不同的用户体验。在这种情况下，你可以用两个拇指与屏幕互动。输入变得更为简单，而且多数情况下你会由左向右阅读，不是由上向下。事实上，如果你的应用需要大量的阅读和文字输入，那么绝对要有良好的横向模式。\u003c/p\u003e\n\u003cp\u003e对用户来说，横向体验是完全不同的。你可以利用这种更宽的布局，以完全不同的方式呈现信息。比如，之前位于屏幕上方的按键可以移动到屏幕一侧。利用更宽的屏幕，地图、图表和图片可以呈现新的信息。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design051.jpg\"\u003e\u003cimg alt=\"Android手机应用UI设计的10个建议\" loading=\"lazy\" src=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design051.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e（先构建和改善一种屏幕方向，然后再制作另一种。注意每种布局的利弊，睿智地加以利用和改良。YouToube应用官方版本为不同的方向模式设计了不同的布局，两者都在各自的纵横比下完美地运转。）\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e6、应用生态系统\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e尽管你能够设计出为用户多种不同目标服务的独特应用，但它永远都只是整个动作系列的一个步骤。\u003c/p\u003e\n\u003cp\u003e想想看你的智能手机所具备的功能：电话记录、联系人、短信息、邮件、浏览器、拍摄照片和视频、GPS和地图等。利用这些功能。对于所有这些已构建的模块，你无需自行制作。用户已经很熟悉这些标准工具，不要在这些内容上浪费精力。\u003c/p\u003e\n\u003cp\u003e以下是个简单但极为普遍的动作流程：接到邀请你前往某个地点的电话。查看时间。查看天气。用Google Maps搜索该地点。用Foursquare签到。那么，你的应用要同整个流程中的哪个部分绑定呢？\u003c/p\u003e\n\u003cp\u003e没有用户会单纯为了你的应用而摆弄自己的手机设备。但是如果你成功制作了一款优秀的软件，他们会愿意将其整合到日常的手机使用流程中。让用户能够便捷地使用分享或在网络上搜索有趣信息等功能，使他们交替使用你的应用和其他应用。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design061.png\"\u003e\u003cimg alt=\"Android手机应用UI设计的10个建议\" loading=\"lazy\" src=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design061.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e（许多应用会直接绑定Android的分享机制。你可以将此作为应用的优势。）\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e7、让你的应用更为独特\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e目前，Android Market上有数十万款应用。你或许会时常问自己，如何从如此多的同类应用中突出重围。如果你想要构建的又是一款无聊的黑白数独游戏，或者是基于官方代码范例的记录应用，那就很难获得可观的下载量。\u003c/p\u003e\n\u003cp\u003e不要认为目前市场上已经没有优秀应用的发展空间。用户偏好的应用类型各不相同。有些人偏爱几乎能够做所有事情的记录应用，有些人需要的只是带有同步功能的文本编辑应用，还有些人只是想要个有着清楚UI的记录应用。\u003c/p\u003e\n\u003cp\u003e无论你选择的是哪个方向，要构建带有一定特征的应用。操作系统和核心应用已经为用户提供了所有基本功能。制作某些能够用内置解决方案吸引用户使用产品，这样才能够脱颖而出。将你的应用视为住在智能手机中的小机器人。它与你交流，告诉你有趣的事情，帮助你完成日常事务。你希望自己的机器人聪明专业，还是精明可爱，抑或是滑稽搞笑？\u003c/p\u003e\n\u003cp\u003e在应用构建的开始就要记住这一点。人们喜欢与他们的个性相符的应用。如果你想要构建照片分享应用，可以为其添加各种主题和徽章。如果想要构建的是款定位服务应用，可以考虑将其简化成只具有最基本的功能，让所有内容自动化完成。应用设计愿景的微小改变可能会改变整个应用以及用户的使用方式。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design071.jpg\"\u003e\u003cimg alt=\"Android手机应用UI设计的10个建议\" loading=\"lazy\" src=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design071.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e（Feedly也是款整合Google Reader的新闻阅读器，但是它使用类似于杂志的呈现方式和清晰的界面设计，这就是该应用与其他阅读器的不同之处。）\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e8、遵守平台指导原则\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e尽管你的目标是制作出独特的应用，但是并非意味着应用的每个部分都要完全与众不同。谷歌就Android应用的设计和开发提供了许多指导性原则。熟悉这些原则。人们能够用来研究现代智能手机的时间比你想象的要少。不要让应用中遍布自定义互动元素，这会让他们的操作更为困难。\u003c/p\u003e\n\u003cp\u003e学习使用Android设备需要用户适应触摸、输入、摇动甚至不时按动硬件按键等操作。他们需要识别输入区域、选择框、模式对话框和菜单等样式。你真的还想给他们增加更多的负担吗？\u003c/p\u003e\n\u003cp\u003e使用简单和直观的列表。在应用开启屏幕中，用大图标来呈现主要功能。添加标题作为最常用功能的入口，让用户能够随时返回开启屏幕。如果你无法显著提升某些操作的功能，那么就保持原样。人们会认同应用和整个操作系统的一致性。\u003c/p\u003e\n\u003cp\u003e认真研究谷歌的界面和决策。熟悉整个原则，并在开发应用时用上这些原则。但是，不可过于死板。如果你能够改良某些元素，而且你确信自己的做法比原则建议的更好，那么就勇敢去做！\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design081.jpg\"\u003e\u003cimg alt=\"Android手机应用UI设计的10个建议\" loading=\"lazy\" src=\"http://jbcdn2.b0.upaiyun.com/2012/02/10-tips-for-android-ui-design081.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e（Catch Notes用户的多数动作可利用应用中的大图标功能实现，这款应用遵从了基本原则，因而运转良好。）\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e9、测试\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e所有的用户都各不相同，我们必须正视这个问题。你可以在应用中投入尽可能多的精力，但是你不可能令所有人满意。甚至连将应用制作成适合多数人的需求都是件很困难的事情。\u003c/p\u003e\n\u003cp\u003e不要误解我的说法。你在发布应用前，必须考虑到不同人可能会有不同的使用方式。你需要不同的人来测试应用，由此找出最恼人的问题和漏洞。大公司往往耗资数千美元进行可用性研究，在昂贵的实验室中让数百名不同类型的用户测试应用。\u003c/p\u003e\n\u003cp\u003e虽然这是个提升应用UI的绝妙方法，但多数独立和小型开发商无法承担如此多的费用。但是，也不要以此为借口而放弃应用测试。你可以开展成本低廉的测试，寻找不同的用户群体，由此来大幅改善你的应用，让其能够满足更多用户的需求。\u003c/p\u003e\n\u003cp\u003e将应用原型安装到你的开发设备上，花点钱购买些小礼物，开展应用测试。先从同事和好友开始，然后再以你从未见过的陌生人为对象。多数人都愿意花点时间来体验全新的东西，只要你足够礼貌甚至愿意为他们费时测试应用提供奖励。\u003c/p\u003e\n\u003cp\u003e让他们像你预期那样使用应用，然后细致地观察他们的使用过程。告诉他们目标是什么，但要尽量少提供帮助，但也别让他们卡在某个地方。很快，你就会发现应用的纰漏和瓶颈。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e10、发布到市场上\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e你已经制作完成了自己的首个应用。感觉很棒，不是吗？\u003c/p\u003e\n\u003cp\u003e不要犯许多开发者犯下的某些错误。诚然，你想要将应用发布到市场上，看看用户会有何评价。但是，最后这几个步骤会让你的首次发布更为成功。\u003c/p\u003e\n\u003cp\u003e确认完成对应用的测试后，我们还需要考虑些小问题。\u003c/p\u003e\n\u003cp\u003e你上传到Android Market的应用还应该带有以下4种资产：\u003c/p\u003e","title":"Android手机应用UI设计的10个建议"},{"content":"Android是一个运行在移动终端上的操作系统，跟传统PC最大的不同所在就是移动终端的资源紧缺问题“比较”明显，当然对于一些屌丝机型，应该用“非常“来形容才靠谱。所以经常会出现在一些比较缺乏青春活力的老型机上，运行一些软件被异常终止的情况；然而作为互联网厂家来说，广大的屌丝机用户肯定是一大笔用户资源，这是能放弃的市场吗？！当然不行o(╯□╰)o，所以我们要尽可能得提高软件的效率来赢取客户的回眸一笑了，屌丝也是客户！\n这篇博客主要介绍如何在UI设计上提高效率，减少资源的利用，毕竟在终端资源短缺的今天，效率始终为王。我们评判一个UI界面不是认为有多复杂才给力，或者说有多炫才靠谱，一个简约而又不平凡的高效UI界面才是一个灰常牛逼的界面设计。\n引入\n在android应用中，采用硬编码方式编写界面并不是一个提倡的方法。当然硬编码编写的界面比基于XML文件的软编码界面高效灵活一些，但是非常不容易维护，错综复杂的代码更会让程序埋雷重重，说不定哪天就把应用炸的惨不忍睹。所以如果非常必要非常肯定要采用代码编写硬编码界面之外，其他情况还是采用易于维护的XML来编写比较好。\n所以文中对于UI优化设计归结到底也就是对XML布局文件的优化设计。\n在谷歌给我们的开发环境中，存在这么一个非常好用的工具——hierarchyviewer，估计很多人都没搭理过这个藏在偏僻角落的小工具吧；它能非常容易的帮我们分析UI界面的结构和构造效率，这个工具的位置就在sdk/tools/文件夹。\n楼下上图：\n大家好，我是图~\n这是分析的是一个布局上只有一个TextView组件的XML界面，图告诉我们，构造这个界面总共用了四个组件，也就是需要绘制四次组件，自然每一次绘制组件都需要耗费资源。\n下面步入狂拽酷炫吊炸天的主题部分。。。。\n尽量用最少的步骤完成布局\n我是社会好青年，我为国家省资源；当然作为组件来说也需要这个觉悟，每个组件的绘制都会多多少少耗费终端的资源。所以我们在这里可不能听老祖宗的话：韩信点兵多多益善了，精兵简政才是UI设计的唯一出路。不相信？行！下面就开始给个对比的例子。\n假设项目需要搞这么一个按钮：\n这不简单吗？几行代码不是分分钟的事情吗？\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;RelativeLayout` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:gravity=``\u0026quot;center\u0026quot;` `\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;Button` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``android:id=``\u0026quot;@+id/button1\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:background=``\u0026quot;@drawable/btn_backgroup\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;ImageView` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``android:id=``\u0026quot;@+id/imageView1\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``android:layout_alignParentLeft=``\u0026quot;true\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``android:layout_centerVertical=``\u0026quot;true\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``android:src=``\u0026quot;@drawable/header_back\u0026quot;` `/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; `\u0026amp;lt;/RelativeLayout\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 也别急着看代码，多累多伤眼睛呀，直接上个hierarchyviewer里面的图来瞧瞧呗\n一个小小的按钮就用了3个组件来绘制，这就是3N的复杂度了呀，如果有5个这样的按钮就要15个组件，如果有10个按钮就要有30个，如果有N++个，哎呀妈的，不敢想象下去了。既然这样，我们是不是应该考虑一下优化优化，翻翻资料我们发现原来是可以不用这么多组件来实现的这个按钮的。\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;Button` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:id=``\u0026quot;@+id/button1\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``android:background=``\u0026quot;@drawable/btn_backgroup\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``android:drawableLeft=``\u0026quot;@drawable/header_back\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``android:gravity=``\u0026quot;center\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``android:padding=``\u0026quot;10dp\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 按照国际惯例，二楼上图\n还是原来的按钮，还是原来的味道，复杂度从3N降低到N！！！你敢说这样的效率你不想去提升？？？？\n**小结一个：**在我们设计UI布局时，应该从使用尽量少的组件的前提下入手，由于系统组件的封装比较完善，把多个简单的组件交由一个复杂一点的组件来实现，是可以得到比较好的效率的。因为每个组件都得需要独自进行绘制过程，多个组件绘制浪费的资源不仅仅谋害了我们的应用，更深深打击了用不起高端机的屌丝用户的自尊心——”他妈的，这软件又不能用！“。\n你不干活？把你辞了。\n我们还记刚开始给的一个图吗？我们在布局中使用的到仅仅是一个TextView，而RelativeLayout貌似啥子活儿都没干的样子。。。。。。\n我们从来都不提倡吃空饷不干活，软件界的潜规则也是这样的。出于构建和谐社会的正义感，我们当然不能坐视RelativeLayout这种站着茅坑不拉屎的流氓行为，所以我们就需要借助一个解决措施——标签，它能帮我们干掉一些不需要的根节点。为了拥有更好的即视感，所以我用了一个更为复杂点的布局（其实一点都不复杂）、、\n主布局XML文件：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;FrameLayout xmlns:android=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:id=``\u0026quot;@+id/layout1\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;ImageView android:id=``\u0026quot;@+id/image1\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:src=``\u0026quot;@drawable/bg\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;com.net168.text.MyLayout ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``android:id=``\u0026quot;@+id/layout2\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;/com.net168.text.MyLayout\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; `\u0026amp;lt;/FrameLayout\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 组合控件布局XML文件：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;LinearLayout xmlns:android=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:orientation=``\u0026quot;horizontal\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;Button android:id=``\u0026quot;@+id/button2\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:text=``\u0026quot;button2\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;TextView android:id=``\u0026quot;@+id/text1\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``android:layout_width=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``android:layout_height=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``android:text=``\u0026quot;text1\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``android:textColor=``\u0026quot;#ff0000\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; `\u0026amp;lt;/LinearLayout\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 这个界面很丑的，不忍直视：\n丑归丑，我们还是需要继续用神器hierarchyviewer看看这个XML生成的界面结构图来探索一下丑女内心丰富多彩的世界~~~~~~~\n我靠。。。。三个组件的布局竟然用了六层嵌套布局，瞬间有了一种大花姑娘嫁给老光棍的一种深深的浪费感。我们开始看图说话，第一层和第二层的组件是系统都会自动生成的，这个是板上钉钉没法商量的事情，除非你去底层跟他们好好谈谈。但是~但是这个第三层的FrameLayout和第五层的LinearLayout完完全全是在自我秀存在感而已，所以我们要狠下心做掉他们，怎么来呢？用标签。\n由于标签只能作为根元素，所以我们可以将这两个根元素都稍加修改，如下：\n主布局XML文件：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;``merge` `xmlns:android``=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/layout1\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``ImageView` `android:id``=``\u0026quot;@+id/image1\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``android:src``=``\u0026quot;@drawable/bg\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``com.net168.text.MyLayout` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``android:id``=``\u0026quot;@+id/layout2\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;match_parent\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;/``com.net168.text.MyLayout``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; `\u0026amp;lt;/``merge``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 组合控件布局XML文件：\n1 \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;``merge` `xmlns:android``=``\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;``Button` `android:id``=``\u0026quot;@+id/button2\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``android:text``=``\u0026quot;button2\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;``TextView` `android:id``=``\u0026quot;@+id/text1\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``android:layout_width``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``android:layout_height``=``\u0026quot;wrap_content\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``android:text``=``\u0026quot;text1\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``android:textColor``=``\u0026quot;#ff0000\u0026quot;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``/\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; `\u0026amp;lt;/``merge``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; PS：注意需要在组合控件的类中加上一句setOrientation(LinearLayout.HORIZONTAL)来保证自组件的水平排列。\n继续用神器看看结构：\n呼呼呼~~是不是从六层降低到了四层结构，好一股小清新的感觉呀，我都感觉飘飘然了，自然效率的提升是毋容置疑滴。。。。。\n小结一个：标签能百分百代替这个布局组件，对于不复杂的其他布局组件如线性布局等组合组件中，可以在继承子类中对其属性进行设置后也可以使用标签，标签不占资源，自然在生成界面时也不会生成对应的组件。另外需要注意一点是只能作为根元素，对于需要用inflate生成布局文件时，必须指定一个ViewGroup作为其父元素，并且要设置inflate的attachToRoot参数为true。（参照inflate(int, ViewGroup, boolean)）。\n","permalink":"https://blog.zdltech.com/posts/%E4%B8%80%E4%B8%AA%E9%AB%98%E6%95%88%E7%9A%84ui%E6%89%8D%E6%98%AF%E4%B8%80%E4%B8%AA%E6%8B%89%E9%A3%8E%E7%9A%84ui/","summary":"\u003cp\u003eAndroid是一个运行在移动终端上的操作系统，跟传统PC最大的不同所在就是移动终端的资源紧缺问题“比较”明显，当然对于一些屌丝机型，应该用“非常“来形容才靠谱。所以经常会出现在一些比较缺乏青春活力的老型机上，运行一些软件被异常终止的情况；然而作为互联网厂家来说，广大的屌丝机用户肯定是一大笔用户资源，这是能放弃的市场吗？！当然不行o(╯□╰)o，所以我们要尽可能得提高软件的效率来赢取客户的回眸一笑了，屌丝也是客户！\u003c/p\u003e\n\u003cp\u003e这篇博客主要介绍如何在UI设计上提高效率，减少资源的利用，毕竟在终端资源短缺的今天，效率始终为王。我们评判一个UI界面不是认为有多复杂才给力，或者说有多炫才靠谱，一个简约而又不平凡的高效UI界面才是一个灰常牛逼的界面设计。\u003c/p\u003e\n\u003cp\u003e引入\u003c/p\u003e\n\u003cp\u003e在android应用中，采用硬编码方式编写界面并不是一个提倡的方法。当然硬编码编写的界面比基于XML文件的软编码界面高效灵活一些，但是非常不容易维护，错综复杂的代码更会让程序埋雷重重，说不定哪天就把应用炸的惨不忍睹。所以如果非常必要非常肯定要采用代码编写硬编码界面之外，其他情况还是采用易于维护的XML来编写比较好。\u003c/p\u003e\n\u003cp\u003e所以文中对于UI优化设计归结到底也就是对XML布局文件的优化设计。\u003c/p\u003e\n\u003cp\u003e在谷歌给我们的开发环境中，存在这么一个非常好用的工具——hierarchyviewer，估计很多人都没搭理过这个藏在偏僻角落的小工具吧；它能非常容易的帮我们分析UI界面的结构和构造效率，这个工具的位置就在sdk/tools/文件夹。\u003c/p\u003e\n\u003cp\u003e楼下上图：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://ww2.sinaimg.cn/mw690/6941baebjw1el5ar6it3ej20pu04iglv.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e大家好，我是图~\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e这是分析的是一个布局上只有一个TextView组件的XML界面，图告诉我们，构造这个界面总共用了四个组件，也就是需要绘制四次组件，自然每一次绘制组件都需要耗费资源。\u003c/p\u003e\n\u003cp\u003e下面步入狂拽酷炫吊炸天的主题部分。。。。\u003c/p\u003e\n\u003cp\u003e尽量用最少的步骤完成布局\u003c/p\u003e\n\u003cp\u003e我是社会好青年，我为国家省资源；当然作为组件来说也需要这个觉悟，每个组件的绘制都会多多少少耗费终端的资源。所以我们在这里可不能听老祖宗的话：韩信点兵多多益善了，精兵简政才是UI设计的唯一出路。不相信？行！下面就开始给个对比的例子。\u003c/p\u003e\n\u003cp\u003e假设项目需要搞这么一个按钮：\u003cimg loading=\"lazy\" src=\"http://ww4.sinaimg.cn/mw690/6941baebjw1el5ar6uxa2j208c08cq30.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e这不简单吗？几行代码不是分分钟的事情吗？\u003c/p\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  \u003cdiv\u003e\n    \u003cdiv id=\"highlighter_60848\" class=\"syntaxhighlighter notranslate actionscript3\"\u003e\n      \u003ctable border=\"0\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n        \u003ctr\u003e\n          \u003ctd class=\"gutter\" style=\"color: #afafaf !important;\"\u003e\n            \u003cdiv class=\"line number1 index0 alt2\"\u003e\n              1\n            \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          2\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          3\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          4\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          5\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n          6\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n          7\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n          8\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n          9\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n          10\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n          11\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n          12\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n          13\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n          14\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n          15\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n          16\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n          17\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n          18\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/td\u0026gt;\n      \n      \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n          \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n            `\u0026amp;lt;RelativeLayout`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n            `    ``android:layout_width=``\u0026quot;wrap_content\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n            `    ``android:layout_height=``\u0026quot;wrap_content\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n            `    ``android:gravity=``\u0026quot;center\u0026quot;` `\u0026amp;gt;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n            `    ``\u0026amp;lt;Button`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n            `        ``android:id=``\u0026quot;@+id/button1\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n            `        ``android:layout_width=``\u0026quot;wrap_content\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n            `        ``android:layout_height=``\u0026quot;wrap_content\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n            `        ``android:background=``\u0026quot;@drawable/btn_backgroup\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n            `         ``/\u0026amp;gt;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n            `    ``\u0026amp;lt;ImageView`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt;\n            `        ``android:id=``\u0026quot;@+id/imageView1\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt;\n            `        ``android:layout_width=``\u0026quot;wrap_content\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt;\n            `        ``android:layout_height=``\u0026quot;wrap_content\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt;\n            `        ``android:layout_alignParentLeft=``\u0026quot;true\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt;\n            `        ``android:layout_centerVertical=``\u0026quot;true\u0026quot;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt;\n            `        ``android:src=``\u0026quot;@drawable/header_back\u0026quot;` `/\u0026amp;gt;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt;\n            `\u0026amp;lt;/RelativeLayout\u0026amp;gt;`\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e也别急着看代码，多累多伤眼睛呀，直接上个hierarchyviewer里面的图来瞧瞧呗\u003c/p\u003e","title":"一个高效的UI才是一个拉风的UI"},{"content":"JqueryMobile动态生成listView并刷新的方法！\n**[javascript]** [view plain](http://blog.csdn.net/zz_mm/article/details/6836503#)[copy](http://blog.csdn.net/zz_mm/article/details/6836503#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;function\u0026lt;/span\u0026gt; queryEntfernungen(tx, results) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; alert(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;This Hello works\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;var\u0026lt;/span\u0026gt; len = results.rows.length; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// This For works fine\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;var\u0026lt;/span\u0026gt; i = 0; i \u0026lt; len; i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; $(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;div[data-role=content] ul\u0026amp;#8221;\u0026lt;/span\u0026gt;).append(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;- \u0026lt;a href=\u0026amp;#8221;\u0026amp;#8216;\u0026lt;/span\u0026gt;+results.rows.item(i).name+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;\u0026amp;#8221;\u0026gt;\u0026amp;#8217;\u0026lt;/span\u0026gt;+results.rows.item(i).name+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;\u0026lt;/a\u0026gt;\u0026amp;#8217;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; $(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;div[data-role=content] ul\u0026amp;#8221;\u0026lt;/span\u0026gt;).listview(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;refresh\u0026amp;#8217;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// This also works\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 但是下面的方法却也能成功!\n**[javascript]** [view plain](http://blog.csdn.net/zz_mm/article/details/6836503#)[copy](http://blog.csdn.net/zz_mm/article/details/6836503#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;function\u0026lt;/span\u0026gt; query(tx, results) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;var\u0026lt;/span\u0026gt; len = results.rows.length, i, j; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (i = 0; i \u0026lt; len; i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; $(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;div[data-role=content] ul\u0026amp;#8221;\u0026lt;/span\u0026gt;).append(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;- \u0026lt;a href=\u0026amp;#8221;\u0026amp;#8216;\u0026lt;/span\u0026gt;+results.rows.item(i).name+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;\u0026amp;#8221;\u0026gt;\u0026amp;#8217;\u0026lt;/span\u0026gt;+results.rows.item(i).name+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;\u0026lt;/a\u0026gt;\u0026amp;#8217;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// No listview(\u0026amp;#8220;refresh\u0026amp;#8221;) !!\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (j = 0; j \u0026lt; len; j++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; $(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#selectmenu\u0026amp;#8221;\u0026lt;/span\u0026gt;).append(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;\u0026lt;option value=\u0026amp;#8221;\u0026amp;#8216;\u0026lt;/span\u0026gt;+results.rows.item(j).id+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;\u0026amp;#8221;\u0026gt;\u0026amp;#8217;\u0026lt;/span\u0026gt;+results.rows.item(j).name+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;\u0026lt;/option\u0026gt;\u0026amp;#8217;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; $(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#selectmenu\u0026amp;#8221;\u0026lt;/span\u0026gt;).selectmenu(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;refresh\u0026amp;#8217;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - ","permalink":"https://blog.zdltech.com/posts/jquerymobile%E5%8A%A8%E6%80%81%E7%94%9F%E6%88%90listview%E5%B9%B6%E5%88%B7%E6%96%B0%E7%9A%84%E6%96%B9%E6%B3%95/","summary":"\u003cp\u003eJqueryMobile动态生成listView并刷新的方法！\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_javascript\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[javascript]** [view plain](http://blog.csdn.net/zz_mm/article/details/6836503#)[copy](http://blog.csdn.net/zz_mm/article/details/6836503#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;function\u0026lt;/span\u0026gt; queryEntfernungen(tx, results)  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;   alert(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;This Hello works\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;   \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;var\u0026lt;/span\u0026gt; len = results.rows.length;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;     \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// This For works fine\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;var\u0026lt;/span\u0026gt; i = 0; i \u0026lt; len; i++) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       $(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;div[data-role=content] ul\u0026amp;#8221;\u0026lt;/span\u0026gt;).append(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;- \u0026lt;a href=\u0026amp;#8221;\u0026amp;#8216;\u0026lt;/span\u0026gt;+results.rows.item(i).name+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;\u0026amp;#8221;\u0026gt;\u0026amp;#8217;\u0026lt;/span\u0026gt;+results.rows.item(i).name+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;\u0026lt;/a\u0026gt;\u0026amp;#8217;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;   $(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;div[data-role=content] ul\u0026amp;#8221;\u0026lt;/span\u0026gt;).listview(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8216;refresh\u0026amp;#8217;\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// This also works\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e但是下面的方法却也能成功!\u003c/p\u003e","title":"JqueryMobile动态生成listView并刷新的方法!"},{"content":"WAMP安装好后，mysql密码是为空的，那么要如何修改呢？其实很简单，通过几条指令就行了，下面我就一步步来操作。\n首先，通过WAMP打开mysql控制台。\n提示输入密码，因为现在是空，所以直接按回车。\n然后输入“use mysql”，意思是使用mysql这个数据库，提示“Database changed”就行。\n然后输入要修改的密码的sql语句“update user set password=PASSWORD(‘hooray’) where user=’root’;”，注意，sql语句结尾的分号不能少，提示什么什么OK就行了。\n最后输入“flush privileges;”，不输入这个的话，修改密码的操作不会生效的。\n然后输入“quit”退出。\n","permalink":"https://blog.zdltech.com/posts/%E5%A6%82%E4%BD%95%E4%BF%AE%E6%94%B9wamp%E4%B8%ADmysql%E9%BB%98%E8%AE%A4%E7%A9%BA%E5%AF%86%E7%A0%81/","summary":"\u003cp\u003eWAMP安装好后，mysql密码是为空的，那么要如何修改呢？其实很简单，通过几条指令就行了，下面我就一步步来操作。\u003c/p\u003e\n\u003cp\u003e　　首先，通过WAMP打开mysql控制台。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://pic002.cnblogs.com/images/2011/277258/2011072313560641.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e　　提示输入密码，因为现在是空，所以直接按回车。\u003c/p\u003e\n\u003cp\u003e　　然后输入“\u003cstrong\u003e\u003cspan style=\"color: #ff0000;\"\u003euse mysql\u003c/span\u003e\u003c/strong\u003e”，意思是使用mysql这个数据库，提示“Database changed”就行。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://pic002.cnblogs.com/images/2011/277258/2011072313574923.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e　　然后输入要修改的密码的sql语句“\u003cstrong\u003e\u003cspan style=\"color: #ff0000;\"\u003eupdate user set password=PASSWORD(‘hooray’) where user=’root’;\u003c/span\u003e\u003c/strong\u003e”，注意，sql语句结尾的分号不能少，提示什么什么OK就行了。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://pic002.cnblogs.com/images/2011/277258/2011072314020766.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e　　最后输入“\u003cstrong\u003e\u003cspan style=\"color: #ff0000;\"\u003eflush privileges;\u003c/span\u003e\u003c/strong\u003e”，不输入这个的话，修改密码的操作不会生效的。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://pic002.cnblogs.com/images/2011/277258/2011072314033552.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e　　然后输入“\u003cstrong\u003e\u003cspan style=\"color: #ff0000;\"\u003equit\u003c/span\u003e\u003c/strong\u003e”退出。\u003c/p\u003e","title":"如何修改WAMP中mysql默认空密码"},{"content":"我们在常用的电商或者旅游APP中，例如美团，手机淘宝等等，都能够看的到有那种下拉式的二级列表菜单。具体如图所示：\n上面两张图就是美团的一个二级列表菜单的一个展示。我相信很多人都想开发一个跟它一样的功能放到自己的APP中。好，接下来我们就开始动手，解决它。\n1，结构分析 首先，我们给出这个下来菜单需要的组建。我们用线框图来分析。\n1）如上图所示，最外围的是一个Activity，顶部包含了一个View的容器，这个容器主要是装载ToggleButton来实现诸如美团里面的“美食，全城，理我最近，刷选”这一行。这一行一点就会弹出对应的下来菜单。\n2）下拉菜单是如何实现的呢？，这里我们利用了PopupWindow来实现这一弹出式窗口。然后我们在弹出式窗口里面再定义我们的下来列表项，是单列还是二级菜单，都是由里面来定。\n3）不同的菜单，需要一级或者需要二级，在这里根据我的需求而变动。我们在PopupWindow上面加一个自定义的LeftView，或者是MiddleView，RightView。主要是一个ToggleButton，你弹出一个窗口，你就定制一个窗口。\n3）视图里面嵌入ListView，就形成了列表项。\n好分析就到上面为止，接下来我们一步步的说明实现。\n2，项目结构 本项目的项目结构如图所示：\n1） Adapter。适配器，主要是为ListView提供数据适配的。\n2）MainActivity。主活动页面。\n3）ExpandTabView。本项目的核心类，它包含ToggleButton容器和PopupWindow，是控制弹出窗口的核心类。\n4）ViewLeft,ViewMiddle,ViewRight。是弹出里面嵌套的类，实现不同的列表菜单。\n3，MainActivity 承载所有元素。看代码比看文字实在。 **[java]** [view plain](http://blog.csdn.net/minimicall/article/details/39484493#)[copy](http://blog.csdn.net/minimicall/article/details/39484493#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/473461)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/473461/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.expandtabview; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.view.ExpandTabView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.view.ViewLeft; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.view.ViewMiddle; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.view.ViewRight; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ExpandTabView expandTabView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ArrayList\u0026lt;View\u0026gt; mViewArray = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;View\u0026gt;(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ViewLeft viewLeft; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ViewMiddle viewMiddle; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ViewRight viewRight; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setContentView(R.layout.activity_main); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; initView(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; initVaule(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; initListener(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;initView\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; expandTabView = (ExpandTabView) findViewById(R.id.expandtab_view); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewLeft = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewLeft(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewMiddle = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewMiddle(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewRight = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewRight(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initVaule() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;initValue\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mViewArray.add(viewLeft); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mViewArray.add(viewMiddle); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mViewArray.add(viewRight); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ArrayList\u0026lt;String\u0026gt; mTextArray = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;String\u0026gt;(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mTextArray.add(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;距离\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mTextArray.add(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;区域\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mTextArray.add(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;距离\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; expandTabView.setValue(mTextArray, mViewArray);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//将三个下拉列表设置进去\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; expandTabView.setTitle(viewLeft.getShowText(), \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; expandTabView.setTitle(viewMiddle.getShowText(), \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; expandTabView.setTitle(viewRight.getShowText(), \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;initListener\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewLeft.setOnSelectListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewLeft.OnSelectListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; getValue(String distance, String showText) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ViewLeft\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;OnSelectListener, getValue\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; onRefresh(viewLeft, showText); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewMiddle.setOnSelectListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewMiddle.OnSelectListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; getValue(String showText) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ViewMiddle\u0026amp;#8221;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;OnSelectListener, getValue\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; onRefresh(viewMiddle,showText); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewRight.setOnSelectListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewRight.OnSelectListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; getValue(String distance, String showText) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ViewRight\u0026amp;#8221;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;OnSelectListener, getValue\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; onRefresh(viewRight, showText); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onRefresh(View view, String showText) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;onRefresh,view:\u0026amp;#8221;\u0026lt;/span\u0026gt;+view+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;,showText:\u0026amp;#8221;\u0026lt;/span\u0026gt;+showText); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; expandTabView.onPressBack(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position = getPositon(view); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (position \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; !expandTabView.getTitle(position).equals(showText)) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; expandTabView.setTitle(showText, position); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, showText, Toast.LENGTH_SHORT).show(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getPositon(View tView) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;getPosition\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; mViewArray.size(); i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mViewArray.get(i) == tView) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; i; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onBackPressed() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!expandTabView.onPressBack()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; finish(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 4 ，ExpandTabView 最主要就是如何处理当我们点击这些ToggleButton的时候要弹出或者收起这些PopupWindow。\n**[java]** [view plain](http://blog.csdn.net/minimicall/article/details/39484493#)[copy](http://blog.csdn.net/minimicall/article/details/39484493#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/473461)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/473461/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.view; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.expandtabview.R; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.LinearLayout; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.PopupWindow; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.PopupWindow.OnDismissListener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.RelativeLayout; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ToggleButton; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 菜单控件头部，封装了下拉动画，动态生成头部按钮个数\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @author zengjinlong\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ExpandTabView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; LinearLayout \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; OnDismissListener { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ExpandTabView\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ToggleButton selectedButton; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ArrayList\u0026lt;String\u0026gt; mTextArray = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;String\u0026gt;(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ArrayList\u0026lt;RelativeLayout\u0026gt; mViewArray = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;RelativeLayout\u0026gt;(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ArrayList\u0026lt;ToggleButton\u0026gt; mToggleButton = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;ToggleButton\u0026gt;(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context mContext; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; SMALL = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; displayWidth; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; displayHeight; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; PopupWindow popupWindow; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; selectPosition; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ExpandTabView(Context context) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; init(context); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ExpandTabView(Context context, AttributeSet attrs) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; init(context); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 根据选择的位置设置tabitem显示的值\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setTitle(String valueText, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (position \u0026lt; mToggleButton.size()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mToggleButton.get(position).setText(valueText); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setTitle(String title){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 根据选择的位置获取tabitem显示的值\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getTitle(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (position \u0026lt; mToggleButton.size() \u0026amp;\u0026amp; mToggleButton.get(position).getText() != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mToggleButton.get(position).getText().toString(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 设置tabitem的个数和初始值\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @param textArray 标题数组\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @param viewArray 控件数组\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setValue(ArrayList\u0026lt;String\u0026gt; textArray, ArrayList\u0026lt;View\u0026gt; viewArray) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mContext == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;setValue\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mTextArray = textArray; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; viewArray.size(); i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; RelativeLayout r = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; RelativeLayout(mContext); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; maxHeight = (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (displayHeight * \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;0.7\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; RelativeLayout.LayoutParams rl = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, maxHeight); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; rl.leftMargin = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; rl.rightMargin = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;10\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; r.addView(viewArray.get(i), rl); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mViewArray.add(r); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; r.setTag(SMALL); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ToggleButton tButton = (ToggleButton) inflater.inflate(R.layout.toggle_button, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; addView(tButton); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; View line = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TextView(mContext); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; line.setBackgroundResource(R.drawable.choosebar_line); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (i \u0026lt; viewArray.size() \u0026amp;#8211; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; LinearLayout.LayoutParams lp = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearLayout.LayoutParams(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;, LinearLayout.LayoutParams.MATCH_PARENT); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; addView(line, lp); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mToggleButton.add(tButton); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; tButton.setTag(i); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; tButton.setText(mTextArray.get(i)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; r.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;RelativeLayout\u0026amp;#8221;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;view:\u0026amp;#8221;\u0026lt;/span\u0026gt;+v); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; onPressBack(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; r.setBackgroundColor(mContext.getResources().getColor(R.color.popup_main_background)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; tButton.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View view) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tButton\u0026amp;#8221;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;setOnClickListener(l)\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// initPopupWindow();\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ToggleButton tButton = (ToggleButton) view; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (selectedButton != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; selectedButton != tButton) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; selectedButton.setChecked(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; selectedButton = tButton; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; selectPosition = (Integer) selectedButton.getTag(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; startAnimation(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mOnButtonClickListener != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; tButton.isChecked()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mOnButtonClickListener.onClick(selectPosition); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// for..\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; startAnimation() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;startAnimation\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (popupWindow == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;startAnimation(),new popupWindow now\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; popupWindow = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PopupWindow(mViewArray.get(selectPosition), displayWidth, displayHeight); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; popupWindow.setAnimationStyle(R.style.PopupWindowAnimation); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; popupWindow.setFocusable(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; popupWindow.setOutsideTouchable(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;startAnimation(),selectedButton:\u0026amp;#8221;\u0026lt;/span\u0026gt;+selectedButton+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;,isChecked:\u0026amp;#8221;\u0026lt;/span\u0026gt;+selectedButton.isChecked()+ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;,popupWindow.isShowing:\u0026amp;#8221;\u0026lt;/span\u0026gt;+popupWindow.isShowing()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (selectedButton.isChecked()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!popupWindow.isShowing()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; showPopup(selectPosition); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; popupWindow.setOnDismissListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; popupWindow.dismiss(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; hideView(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (popupWindow.isShowing()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; popupWindow.dismiss(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; hideView(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; showPopup(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; View tView = mViewArray.get(selectPosition).getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (tView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;instanceof\u0026lt;/span\u0026gt; ViewBaseAction) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ViewBaseAction f = (ViewBaseAction) tView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; f.show(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (popupWindow.getContentView() != mViewArray.get(position)) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; popupWindow.setContentView(mViewArray.get(position)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; popupWindow.showAsDropDown(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 如果菜单成展开状态，则让菜单收回去\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onPressBack() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;onPressBack\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (popupWindow != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; popupWindow.isShowing()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; popupWindow.dismiss(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; hideView(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (selectedButton != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; selectedButton.setChecked(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; hideView() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;hide()\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; View tView = mViewArray.get(selectPosition).getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (tView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;instanceof\u0026lt;/span\u0026gt; ViewBaseAction) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ViewBaseAction f = (ViewBaseAction) tView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; f.hide(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; init(Context context) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mContext = context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; displayWidth = ((Activity) mContext).getWindowManager().getDefaultDisplay().getWidth(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; displayHeight = ((Activity) mContext).getWindowManager().getDefaultDisplay().getHeight(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setOrientation(LinearLayout.HORIZONTAL); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDismiss() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;onDismiss,selectPosition:\u0026amp;#8221;\u0026lt;/span\u0026gt;+selectPosition); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; showPopup(selectPosition); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; popupWindow.setOnDismissListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnButtonClickListener mOnButtonClickListener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 设置tabitem的点击监听事件\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnButtonClickListener(OnButtonClickListener l) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mOnButtonClickListener = l; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 自定义tabitem点击回调接口\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnButtonClickListener { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; selectPosition); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 5，ViewLeft 其中的一个示例，其他两个就不列举了\n**[java]** [view plain](http://blog.csdn.net/minimicall/article/details/39484493#)[copy](http://blog.csdn.net/minimicall/article/details/39484493#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/473461)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/473461/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.view; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.adapter.TextAdapter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.expandtabview.R; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.RelativeLayout; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ViewLeft \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; RelativeLayout \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; ViewBaseAction{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ViewLeft\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ListView mListView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String[] items = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; String[] { \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;item1\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;item2\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;item3\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;item4\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;item5\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;item6\u0026amp;#8221;\u0026lt;/span\u0026gt; };\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//显示字段\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String[] itemsVaule = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; String[] { \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;2\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;3\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;4\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;5\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;6\u0026amp;#8221;\u0026lt;/span\u0026gt; };\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//隐藏id\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnSelectListener mOnSelectListener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextAdapter adapter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String mDistance; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String showText = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;item1\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context mContext; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getShowText() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; showText; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ViewLeft(Context context) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; init(context); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ViewLeft(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; init(context); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ViewLeft(Context context, AttributeSet attrs) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; init(context); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; init(Context context) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mContext = context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; inflater.inflate(R.layout.view_distance, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setBackgroundDrawable(getResources().getDrawable(R.drawable.choosearea_bg_mid)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mListView = (ListView) findViewById(R.id.listView); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; adapter = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TextAdapter(context, items, R.drawable.choose_item_right, R.drawable.choose_eara_item_selector); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; adapter.setTextSize(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;17\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mDistance != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; itemsVaule.length; i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (itemsVaule[i].equals(mDistance)) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; adapter.setSelectedPositionNoNotify(i); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; showText = items[i]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mListView.setAdapter(adapter); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; adapter.setOnItemClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TextAdapter.OnItemClickListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onItemClick(View view, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mOnSelectListener != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; showText = items[position]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mOnSelectListener.getValue(itemsVaule[position], items[position]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnSelectListener(OnSelectListener onSelectListener) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mOnSelectListener = onSelectListener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnSelectListener { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; getValue(String distance, String showText); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; hide() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; show() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 6，效果图 好，今天就到这里。。希望有用。\n","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E5%8F%91%E4%B9%8B%E5%A4%9A%E7%BA%A7%E4%B8%8B%E6%8B%89%E5%88%97%E8%A1%A8%E8%8F%9C%E5%8D%95%E5%AE%9E%E7%8E%B0%E4%BB%BF%E7%BE%8E%E5%9B%A2%E6%B7%98%E5%AE%9D%E7%AD%89/","summary":"\u003cp\u003e我们在常用的电商或者旅游APP中，例如美团，手机淘宝等等，都能够看的到有那种下拉式的二级列表菜单。具体如图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140922235621019?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTWluaU1pY2FsbA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140922235520578?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTWluaU1pY2FsbA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e上面两张图就是美团的一个二级列表菜单的一个展示。我相信很多人都想开发一个跟它一样的功能放到自己的APP中。好，接下来我们就开始动手，解决它。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch2 id=\"1结构分析\"\u003e\u003ca style=\"color: #336699;\" name=\"t0\"\u003e\u003c/a\u003e1，结构分析\u003c/h2\u003e\n\u003cp\u003e首先，我们给出这个下来菜单需要的组建。我们用线框图来分析。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140923000721976?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTWluaU1pY2FsbA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e1）如上图所示，最外围的是一个Activity，顶部包含了一个View的容器，这个容器主要是装载ToggleButton来实现诸如美团里面的“美食，全城，理我最近，刷选”这一行。这一行一点就会弹出对应的下来菜单。\u003c/p\u003e\n\u003cp\u003e2）下拉菜单是如何实现的呢？，这里我们利用了PopupWindow来实现这一弹出式窗口。然后我们在弹出式窗口里面再定义我们的下来列表项，是单列还是二级菜单，都是由里面来定。\u003c/p\u003e\n\u003cp\u003e3）不同的菜单，需要一级或者需要二级，在这里根据我的需求而变动。我们在PopupWindow上面加一个自定义的LeftView，或者是MiddleView，RightView。主要是一个ToggleButton，你弹出一个窗口，你就定制一个窗口。\u003c/p\u003e\n\u003cp\u003e3）视图里面嵌入ListView，就形成了列表项。\u003c/p\u003e\n\u003cp\u003e好分析就到上面为止，接下来我们一步步的说明实现。\u003c/p\u003e\n\u003ch2 id=\"2项目结构\"\u003e\u003ca style=\"color: #336699;\" name=\"t1\"\u003e\u003c/a\u003e2，项目结构\u003c/h2\u003e\n\u003cp\u003e本项目的项目结构如图所示：\u003c/p\u003e\n\u003cp\u003e1） Adapter。适配器，主要是为ListView提供数据适配的。\u003c/p\u003e\n\u003cp\u003e2）MainActivity。主活动页面。\u003c/p\u003e\n\u003cp\u003e3）ExpandTabView。本项目的核心类，它包含ToggleButton容器和PopupWindow，是控制弹出窗口的核心类。\u003c/p\u003e\n\u003cp\u003e4）ViewLeft,ViewMiddle,ViewRight。是弹出里面嵌套的类，实现不同的列表菜单。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140923001303968?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTWluaU1pY2FsbA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch2 id=\"3mainactivity\"\u003e\u003ca style=\"color: #336699;\" name=\"t2\"\u003e\u003c/a\u003e3，MainActivity\u003c/h2\u003e\n\u003cdiv\u003e\n  承载所有元素。看代码比看文字实在。\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/minimicall/article/details/39484493#)[copy](http://blog.csdn.net/minimicall/article/details/39484493#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/473461)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/473461/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.expandtabview;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.view.ExpandTabView;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.view.ViewLeft;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.view.ViewMiddle;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.view.ViewRight;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ExpandTabView expandTabView;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ArrayList\u0026lt;View\u0026gt; mViewArray = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;View\u0026gt;();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ViewLeft viewLeft;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ViewMiddle viewMiddle;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ViewRight viewRight;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        setContentView(R.layout.activity_main);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        initView();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        initVaule();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        initListener();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;initView\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        expandTabView = (ExpandTabView) findViewById(R.id.expandtab_view);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        viewLeft = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewLeft(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        viewMiddle = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewMiddle(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        viewRight = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewRight(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initVaule() {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;initValue\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mViewArray.add(viewLeft);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mViewArray.add(viewMiddle);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mViewArray.add(viewRight);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        ArrayList\u0026lt;String\u0026gt; mTextArray = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;String\u0026gt;();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mTextArray.add(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;距离\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mTextArray.add(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;区域\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mTextArray.add(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;距离\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        expandTabView.setValue(mTextArray, mViewArray);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//将三个下拉列表设置进去\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        expandTabView.setTitle(viewLeft.getShowText(), \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        expandTabView.setTitle(viewMiddle.getShowText(), \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        expandTabView.setTitle(viewRight.getShowText(), \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initListener() {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;initListener\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        viewLeft.setOnSelectListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewLeft.OnSelectListener() {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; getValue(String distance, String showText) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ViewLeft\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;OnSelectListener, getValue\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                onRefresh(viewLeft, showText);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        });  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        viewMiddle.setOnSelectListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewMiddle.OnSelectListener() {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;              \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; getValue(String showText) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ViewMiddle\u0026amp;#8221;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;OnSelectListener, getValue\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                onRefresh(viewMiddle,showText);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        });  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        viewRight.setOnSelectListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewRight.OnSelectListener() {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; getValue(String distance, String showText) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ViewRight\u0026amp;#8221;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;OnSelectListener, getValue\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                onRefresh(viewRight, showText);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        });  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onRefresh(View view, String showText) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;onRefresh,view:\u0026amp;#8221;\u0026lt;/span\u0026gt;+view+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;,showText:\u0026amp;#8221;\u0026lt;/span\u0026gt;+showText);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        expandTabView.onPressBack();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position = getPositon(view);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (position \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; !expandTabView.getTitle(position).equals(showText)) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            expandTabView.setTitle(showText, position);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Toast.makeText(MainActivity.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, showText, Toast.LENGTH_SHORT).show();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getPositon(View tView) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Log.d(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;getPosition\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; mViewArray.size(); i++) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mViewArray.get(i) == tView) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; i;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onBackPressed() {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!expandTabView.onPressBack()) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            finish();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003ch2 id=\"4-expandtabview\"\u003e\u003ca style=\"color: #336699;\" name=\"t3\"\u003e\u003c/a\u003e4 ，ExpandTabView\u003c/h2\u003e\n\u003cp\u003e最主要就是如何处理当我们点击这些ToggleButton的时候要弹出或者收起这些PopupWindow。\u003c/p\u003e","title":"Android开发之多级下拉列表菜单实现（仿美团，淘宝等）"},{"content":"`$json = Xml2Json($xml_data); echo $json;` \u0026lt;?php // XML2Json 主程式 /// XML2JsonSub 遞迴需要用的子程式 /// Xml2Array – 由 php.net 抓來的 Xml Parse(此 class 可 parse 出 tag 中的屬性) /* // example: rss = file_get_contents(‘rss.xml’);json = Xml2Json(rss); echo json; */\nfunction Xml2Json($xml_data) { $xml2Array = new xml2Array(); $xml = $xml2Array-\u0026gt;parse($xml_data); $json = array();\nfor(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$i \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;= \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;, \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$c \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;= \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$xml\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;); \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$i \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;\u0026lt; \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$c\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;; \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$i\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;++) { array_push($json, Xml2JsonSub($xml[$i])); }\nreturn \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #dd0000;\u0026quot;\u0026gt;\u0026amp;#8216;{\u0026amp;#8216;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;. \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;implode\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #dd0000;\u0026quot;\u0026gt;\u0026amp;#8216;, \u0026amp;#8216;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;, \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$json\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;) .\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #dd0000;\u0026quot;\u0026gt;\u0026amp;#8216;}\u0026amp;#8217;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;; }\nfunction \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;Xml2JsonKey\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$xml\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;) { return ‘”‘ . $xml[‘NAME’] . ‘”‘; }\nfunction \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;Xml2JsonValue\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$xml\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;) { $values = array(); if (isset($xml[‘ATTR’]) \u0026amp;\u0026amp; is_array($xml[‘ATTR’]) \u0026amp;\u0026amp; count($xml[‘ATTR’])) { foreach ($xml[‘ATTR’] as $k =\u0026gt; $v) { $values[“@$k“] = ‘”‘ . $v . ‘”‘; } }\nif (isset(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$xml\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;[\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #dd0000;\u0026quot;\u0026gt;\u0026amp;#8216;DATA\u0026amp;#8217;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;])) { $values[‘#text’] = ‘”‘ . $xml[‘DATA’] . ‘”‘; }\nif (isset(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$xml\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;[\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #dd0000;\u0026quot;\u0026gt;\u0026amp;#8216;SUB\u0026amp;#8217;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;]) \u0026amp;\u0026amp; \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;is_array\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$xml\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;[\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #dd0000;\u0026quot;\u0026gt;\u0026amp;#8216;SUB\u0026amp;#8217;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;]) \u0026amp;\u0026amp; \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$xml\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;[\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #dd0000;\u0026quot;\u0026gt;\u0026amp;#8216;SUB\u0026amp;#8217;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;])) { foreach ($xml[‘SUB’] as $name =\u0026gt; $sub) { $_sub = array(); if (isset($sub[][‘NAME’])) { $subarray = array(); foreach ($sub as $s) { array_push($subarray, Xml2JsonValue($s)); } $values[$name] = ‘[ ‘ . implode(‘, ‘, $subarray) . ‘ ]’; } else { $values[$name] = Xml2JsonValue($sub); } } }\nif (!\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;count\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$values\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;)) return ‘null’; elseif (count($values) == 1 \u0026amp;\u0026amp; isset($values[‘#text’])) return $values[‘#text’]; else { $ret = array(); foreach ($values as $k =\u0026gt; $v) { array_push($ret, ‘”‘ . $k . ‘”: ‘ . $v); } return ‘{ ‘ . implode(‘, ‘, $ret) . ‘ }’; } }\nfunction \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;Xml2JsonSub\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$xml\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;) { return Xml2JsonKey($xml) . ‘: ‘ . Xml2JsonValue($xml); }\nclass \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;xml2Array \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;{ var $out = array(); var $parser; var $data;\nfunction \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;parse\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$strInputXML\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;) { $this-\u0026gt;parser = xml_parser_create(); xml_set_object($this-\u0026gt;parser, $this); xml_set_element_handler($this-\u0026gt;parser, “tagOpen”, “tagClosed”); xml_set_character_data_handler($this-\u0026gt;parser, “tagData”); $this-\u0026gt;data = xml_parse($this-\u0026gt;parser, $strInputXML); if (!$this-\u0026gt;data) { die(sprintf(“XML error: %s at line %d”, xml_error_string(xml_get_error_code($this-\u0026gt;parser)), xml_get_current_line_number($this-\u0026gt;parser))); } xml_parser_free($this-\u0026gt;parser);\nreturn \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$this\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;-\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;out\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;; }\nfunction \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;tagOpen\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$parser\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;, \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$name\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;, \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$attrs\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;) { $tag = array(); $tag[‘NAME’] = strtolower($name); if (count($attrs)) { $tag[‘ATTR’] = array(); foreach ($attrs as $k =\u0026gt; $v) $tag[‘ATTR’][strtolower($k)] = $v; } array_push($this-\u0026gt;out, $tag); }\nfunction \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;tagData\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$parser\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;, \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$tagData\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;) { $tagData = addslashes(trim($tagData)); if (strlen($tagData)) { if(isset($this-\u0026gt;out[count($this-\u0026gt;out)-1][‘DATA’])) { $this-\u0026gt;out[count($this-\u0026gt;out)-1][‘DATA’] .= $tagData; } else { $this-\u0026gt;out[count($this-\u0026gt;out)-1][‘DATA’] = $tagData; } } }\nfunction \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;tagClosed\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$parser\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;, \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000bb;\u0026quot;\u0026gt;$name\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #007700;\u0026quot;\u0026gt;) { $child = $this-\u0026gt;out[count($this-\u0026gt;out)-1]; $name = $child[‘NAME’]; if (isset($this-\u0026gt;out[count($this-\u0026gt;out)-2][‘SUB’][$name][][‘NAME’])) { $this-\u0026gt;out[count($this-\u0026gt;out)-2][‘SUB’][$name][] = $child; } elseif (isset($this-\u0026gt;out[count($this-\u0026gt;out)-2][‘SUB’][$name][‘NAME’])) { $prev = $this-\u0026gt;out[count($this-\u0026gt;out)-2][‘SUB’][$name]; $this-\u0026gt;out[count($this-\u0026gt;out)-2][‘SUB’][$name] = array($prev, $child); } else { $this-\u0026gt;out[count($this-\u0026gt;out)-2][‘SUB’][$name] = $child; } array_pop($this-\u0026gt;out); } } ?\u0026gt;\n","permalink":"https://blog.zdltech.com/posts/php-xml%E8%BD%ACjson%E6%96%B9%E6%B3%95/","summary":"\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e`$json = Xml2Json($xml_data); echo $json;`\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #0000bb;\"\u003e\u0026lt;?php\n\u003c/span\u003e\u003cspan style=\"color: #ff8000;\"\u003e// XML2Json 主程式\n/// XML2JsonSub 遞迴需要用的子程式\n/// Xml2Array – 由 php.net 抓來的 Xml Parse(此 class 可 parse 出 tag 中的屬性)\n/*\n// example:\n\u003cspan class=\"katex math inline\"\u003erss = file_get_contents(‘rss.xml’);\u003c/span\u003ejson = Xml2Json(\u003cspan class=\"katex math inline\"\u003erss);\necho \u003c/span\u003ejson;\n*/\u003c/p\u003e\n\u003cp\u003e\u003c/span\u003e\u003cspan style=\"color: #007700;\"\u003efunction \u003c/span\u003e\u003cspan style=\"color: #0000bb;\"\u003eXml2Json\u003c/span\u003e\u003cspan style=\"color: #007700;\"\u003e(\u003c/span\u003e\u003cspan style=\"color: #0000bb;\"\u003e$xml_data\u003c/span\u003e\u003cspan style=\"color: #007700;\"\u003e)\n{\n\u003c/span\u003e\u003cspan style=\"color: #0000bb;\"\u003e$xml2Array \u003c/span\u003e\u003cspan style=\"color: #007700;\"\u003e= new \u003c/span\u003e\u003cspan style=\"color: #0000bb;\"\u003exml2Array\u003c/span\u003e\u003cspan style=\"color: #007700;\"\u003e();\n\u003c/span\u003e\u003cspan style=\"color: #0000bb;\"\u003e$xml \u003c/span\u003e\u003cspan style=\"color: #007700;\"\u003e= \u003c/span\u003e\u003cspan style=\"color: #0000bb;\"\u003e$xml2Array\u003c/span\u003e\u003cspan style=\"color: #007700;\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan style=\"color: #0000bb;\"\u003eparse\u003c/span\u003e\u003cspan style=\"color: #007700;\"\u003e(\u003c/span\u003e\u003cspan style=\"color: #0000bb;\"\u003e$xml_data\u003c/span\u003e\u003cspan style=\"color: #007700;\"\u003e);\n\u003c/span\u003e\u003cspan style=\"color: #0000bb;\"\u003e$json \u003c/span\u003e\u003cspan style=\"color: #007700;\"\u003e= array();\u003c/p\u003e","title":"PHP xml转json方法"},{"content":"Html5中提供了地理位置信息的API，通过浏览器来获取用户当前位置。基于此特性可以开发基于位置的服务应用。在获取地理位置信息前，首先浏览器都会向用户询问是否愿意共享其位置信息，待用户同意后才能使用。\nHtml5获取地理位置信息是通过Geolocation API提供，使用其getCurrentPosition方法，此方法中有三个参数，分别是成功获取到地理位置信息时所执行的回调函数，失败时所执行的回调函数和可选属性配置项。\n如下Demo演示了通过Geolocation获取地理位置信息，并在百度地图上显示当前位置（通过调用百度地图API）。实验结果发现位置被定位到了大学城内环东四路入口处，与本人所在位置（华工学生宿舍）偏差还是有点大的，达到200-300米左右。\n代码如下所示（其中convertor.js为百度地图提供的坐标转化文件）：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 1\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;!\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #ff00ff;\u0026#34;\u0026gt;DOCTYPE html\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 2\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;html\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 3\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;head\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 4\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;title\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;H5地理位置Demo\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;title\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 5\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;script \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;src\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;=\u0026#34;http://api.map.baidu.com/api?v=1.3\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt; type\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;=\u0026#34;text/javascript\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 6\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;script\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 7\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;script \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;type\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;=\u0026#34;text/javascript\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt; src\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;=\u0026#34;convertor.js\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 8\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;script\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 9\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;head\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;body\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;div \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;id\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;=\u0026#34;map\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt; style\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;=\u0026#34;width:600px; height:400px\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;div\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;body\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;script \u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;type\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;=\u0026#34;text/javascript\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;if\u0026lt;/span\u0026gt; (window.navigator.geolocation) { \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;var\u0026lt;/span\u0026gt; options = { \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt; enableHighAccuracy: \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;true\u0026lt;/span\u0026gt;, \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;18\u0026lt;/span\u0026gt; }; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;19\u0026lt;/span\u0026gt; window.navigator.geolocation.getCurrentPosition(handleSuccess, handleError, options); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;20\u0026lt;/span\u0026gt; } \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;21\u0026lt;/span\u0026gt; alert(\u0026#34;浏览器不支持html5来获取地理位置信息\u0026#34;); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;22\u0026lt;/span\u0026gt; } \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;23\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;24\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;function\u0026lt;/span\u0026gt; handleSuccess(position){ \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;25\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008000;\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #008000;\u0026#34;\u0026gt; 获取到当前位置经纬度 本例中是chrome浏览器取到的是google地图中的经纬度\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;26\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;var\u0026lt;/span\u0026gt; lng = position.coords.longitude; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;27\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;var\u0026lt;/span\u0026gt; lat = position.coords.latitude; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;28\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008000;\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #008000;\u0026#34;\u0026gt; 调用百度地图api显示\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;29\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;var\u0026lt;/span\u0026gt; map = \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; BMap.Map(\u0026#34;map\u0026#34;); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;var\u0026lt;/span\u0026gt; ggPoint = \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; BMap.Point(lng, lat); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;31\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008000;\u0026#34;\u0026gt;//\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #008000;\u0026#34;\u0026gt; 将google地图中的经纬度转化为百度地图的经纬度\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;32\u0026lt;/span\u0026gt; BMap.Convertor.translate(ggPoint, 2, \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;function\u0026lt;/span\u0026gt;(point){ \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;33\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;var\u0026lt;/span\u0026gt; marker = \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; BMap.Marker(point); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;34\u0026lt;/span\u0026gt; map.addOverlay(marker); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;35\u0026lt;/span\u0026gt; map.centerAndZoom(point, 15); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;36\u0026lt;/span\u0026gt; }); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt; } \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;38\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;39\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;function\u0026lt;/span\u0026gt; handleError(error){ \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;40\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;41\u0026lt;/span\u0026gt; } \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;42\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;script\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;43\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;lt;/\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #800000;\u0026#34;\u0026gt;html\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #0000ff;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt; ![复制代码](http://common.cnblogs.com/images/copycode.gif) convertor.js文件：\n![复制代码](http://common.cnblogs.com/images/copycode.gif) \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 1\u0026lt;/span\u0026gt; (function() { // 闭包 \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 2\u0026lt;/span\u0026gt; function load_script(xyUrl, callback) { \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 3\u0026lt;/span\u0026gt; var head = document.getElementsByTagName(\u0026#39;head\u0026#39;)[0]; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 4\u0026lt;/span\u0026gt; var script = document.createElement(\u0026#39;script\u0026#39;); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 5\u0026lt;/span\u0026gt; script.type = \u0026#39;text/javascript\u0026#39;; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 6\u0026lt;/span\u0026gt; script.src = xyUrl; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 7\u0026lt;/span\u0026gt; // 借鉴了jQuery的script跨域方法 \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 8\u0026lt;/span\u0026gt; script.onload = script.onreadystatechange = function() { \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt; 9\u0026lt;/span\u0026gt; if ((!this.readyState || this.readyState === \u0026#34;loaded\u0026#34; || this.readyState === \u0026#34;complete\u0026#34;)) { \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;10\u0026lt;/span\u0026gt; callback \u0026amp;\u0026amp; callback(); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;11\u0026lt;/span\u0026gt; // Handle memory leak in IE \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;12\u0026lt;/span\u0026gt; script.onload = script.onreadystatechange = null; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;13\u0026lt;/span\u0026gt; if (head \u0026amp;\u0026amp; script.parentNode) { \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;14\u0026lt;/span\u0026gt; head.removeChild(script); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;15\u0026lt;/span\u0026gt; } \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;16\u0026lt;/span\u0026gt; } \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;17\u0026lt;/span\u0026gt; }; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;18\u0026lt;/span\u0026gt; // Use insertBefore instead of appendChild to circumvent an IE6 bug. \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;19\u0026lt;/span\u0026gt; head.insertBefore(script, head.firstChild); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;20\u0026lt;/span\u0026gt; } \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;21\u0026lt;/span\u0026gt; function translate(point, type, callback) { \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;22\u0026lt;/span\u0026gt; var callbackName = \u0026#39;cbk_\u0026#39; + Math.round(Math.random() * 10000); // 随机函数名 \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;23\u0026lt;/span\u0026gt; var xyUrl = \u0026#34;http://api.map.baidu.com/ag/coord/convert?from=\u0026#34; + type \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;24\u0026lt;/span\u0026gt; + \u0026#34;\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;\u0026amp;to\u0026lt;/span\u0026gt;=4\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;\u0026amp;x\u0026lt;/span\u0026gt;=\u0026#34; + point.lng + \u0026#34;\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;\u0026amp;y\u0026lt;/span\u0026gt;=\u0026#34; + point.lat \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;25\u0026lt;/span\u0026gt; + \u0026#34;\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;\u0026amp;callback\u0026lt;/span\u0026gt;=BMap.Convertor.\u0026#34; + callbackName; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;26\u0026lt;/span\u0026gt; // 动态创建script标签 \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;27\u0026lt;/span\u0026gt; load_script(xyUrl); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;28\u0026lt;/span\u0026gt; BMap.Convertor[callbackName] = function(xyResult) { \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;29\u0026lt;/span\u0026gt; delete BMap.Convertor[callbackName]; // 调用完需要删除改函数 \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;30\u0026lt;/span\u0026gt; var point = new BMap.Point(xyResult.x, xyResult.y); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;31\u0026lt;/span\u0026gt; callback \u0026amp;\u0026amp; callback(point); \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;32\u0026lt;/span\u0026gt; } \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;33\u0026lt;/span\u0026gt; } \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;34\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;35\u0026lt;/span\u0026gt; window.BMap = window.BMap || {}; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;36\u0026lt;/span\u0026gt; BMap.Convertor = {}; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;37\u0026lt;/span\u0026gt; BMap.Convertor.translate = translate; \u0026lt;span style=\u0026#34;color: #008080;\u0026#34;\u0026gt;38\u0026lt;/span\u0026gt; })(); ![复制代码](http://common.cnblogs.com/images/copycode.gif) ","permalink":"https://blog.zdltech.com/posts/html5-geolocation%E8%8E%B7%E5%8F%96%E5%9C%B0%E7%90%86%E4%BD%8D%E7%BD%AE%E4%BF%A1%E6%81%AF/","summary":"\u003cp\u003eHtml5中提供了地理位置信息的API，通过浏览器来获取用户当前位置。基于此特性可以开发基于位置的服务应用。在获取地理位置信息前，首先浏览器都会向用户询问是否愿意共享其位置信息，待用户同意后才能使用。\u003c/p\u003e\n\u003cp\u003eHtml5获取地理位置信息是通过Geolocation API提供，使用其getCurrentPosition方法，此方法中有三个参数，分别是成功获取到地理位置信息时所执行的回调函数，失败时所执行的回调函数和可选属性配置项。\u003c/p\u003e\n\u003cp\u003e如下Demo演示了通过Geolocation获取地理位置信息，并在百度地图上显示当前位置（通过调用百度地图API）。实验结果发现位置被定位到了大学城内环东四路入口处，与本人所在位置（华工学生宿舍）偏差还是有点大的，达到200-300米左右。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://pic002.cnblogs.com/images/2012/426802/2012111022484598.png\"\u003e\u003c/p\u003e\n\u003cp\u003e代码如下所示（其中convertor.js为百度地图提供的坐标转化文件）：\u003c/p\u003e\n\u003cdiv class=\"cnblogs_code\" style=\"color: #000000;\"\u003e\n  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca style=\"color: #444444;\" title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e!\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #ff00ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eDOCTYPE html\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ehtml\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e     \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ehead\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e4\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003etitle\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eH5地理位置Demo\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003etitle\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003escript \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #ff0000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003esrc\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://api.map.baidu.com/api?v=1.3\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #ff0000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e type\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;text/javascript\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e6\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003escript\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e7\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003escript \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #ff0000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003etype\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;text/javascript\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #ff0000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e src\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;convertor.js\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e8\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003escript\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e9\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e     \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ehead\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e     \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ebody\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e11\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ediv \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #ff0000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003eid\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;map\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #ff0000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e style\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;width:600px; height:400px\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e12\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ediv\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e13\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e     \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ebody\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e14\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e     \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003escript \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #ff0000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003etype\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;text/javascript\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e15\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e (window\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003enavigator\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egeolocation) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e16\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e             \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003evar\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e options \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e17\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e                 enableHighAccuracy: \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"font-style:italic\"\u003etrue\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e18\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e             };\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e19\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e             window\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003enavigator\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egeolocation\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egetCurrentPosition(handleSuccess, handleError, options);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e20\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         } \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e21\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e             alert(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;浏览器不支持html5来获取地理位置信息\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e22\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e23\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e24\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003efunction\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e handleSuccess(position){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e25\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e             \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;//\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e 获取到当前位置经纬度  本例中是chrome浏览器取到的是google地图中的经纬度\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e26\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e             \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003evar\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e lng \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e position\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecoords\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elongitude;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e27\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e             \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003evar\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e lat \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e position\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecoords\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003elatitude;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e28\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e             \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;//\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e 调用百度地图api显示\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e29\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e             \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003evar\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e map \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e BMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMap(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;map\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e30\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e             \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003evar\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e ggPoint \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e BMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ePoint(lng, lat);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e31\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e             \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;//\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e 将google地图中的经纬度转化为百度地图的经纬度\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e32\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e             BMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eConvertor\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etranslate(ggPoint, \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003efunction\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e(point){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e33\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e                 \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003evar\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e marker \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003enew\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e BMap\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eMarker(point);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e34\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e                 map\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eaddOverlay(marker);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e35\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e                 map\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecenterAndZoom(point, \u003cspan style=\"color:#bd93f9\"\u003e15\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e36\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e             });\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e37\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e38\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e39\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003efunction\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e handleError(error){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e40\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e41\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e         }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e42\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e     \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003escript\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #008080;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e43\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003elt;\u003cspan style=\"color:#ff79c6\"\u003e/\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #800000;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003ehtml\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026lt;\u003c/span\u003espan style\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;color: #0000ff;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026amp;\u003c/span\u003egt;\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;/\u003c/span\u003espan\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e  \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n    \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca style=\"color: #444444;\" title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003econvertor.js文件：\u003c/p\u003e","title":"Html5 Geolocation获取地理位置信息"},{"content":"以前如果要获取互联网用户所在地都是根据用户的IP地址来获取地理位置，这样获取到的数据和真实数据有很大的偏差。为了获取更加精确的位置，可以使用了html5的geolocation来获取经纬度，然后再获取所在地理位置，如何获取，我在下面会说到。先说下基本概念。\nGeolocation在的navigator 对象中，我们可以通过 navigator.geolocation 来使用它。不支持 geolocation 的浏览器并不包含这一对象，那么可以通过下面的代码来做能力检测，对不同的浏览器做不同的处理。在访问 geolocation 对象时，即调用 geolocation 下面的方法时，浏览器会弹出提示，询问用户是否许可网站提供的位置服务，只有在得到用户许可过后，服务才会继续，否则将被停止。\n常用的navigator.geolocation对象有以下三种方法：\n获取当前地理位置：navigator.geolocation.getCurrentPosition(success_callback_function, error_callback_function, position_options)\n持续获取地理位置：navigator.geolocation.watchPosition(success_callback_function, error_callback_function, position_options)\n清除持续获取地理位置事件：navigator.geolocation.clearWatch(watch_position_id)\n参数position_options是配置项，由JSON格式传入：\nenableHighAccuracy：true/false，它将告诉浏览器是否启用高精度设备，所谓的高精度设备包含但不局限于前面所提到的 GPS 和 WIFI，值为 true 的时候，浏览器会尝试启用这些设备，默认指为 true，在这种情况下，浏览器会尽可能地进行更为精确的查询，简单地说，如果用户有可用的 GPS 设备，会返回 GPS 设备的查询结果，IP 是最后的选择，对于移动设备来说，网络接入点(基站)或许成为另一个选择，对此我还没有完全了解，但根据测试，即时没有任何额外功能的手机，也能够得到更为精确的查询结果。\nmaximumAge：单位毫秒，告诉设备缓存时间，主要用于设备的省电或者节省带宽方面。\ntimeout：单位毫秒，超时事件，获取位置信息时超出设定的这个时长，将会触发错误，捕获错误的函数将被调用，并且错误码指向TIMEOUT。\n[?](http://www.cnblogs.com/zzcflying/archive/2012/08/30/2663540.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `var` `position_option = {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``enableHighAccuracy: ``true``,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``maximumAge: 30000,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``timeout: 20000` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``};` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `navigator.geolocation.getCurrentPosition(getPositionSuccess, getPositionError, position_option);` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; [?](http://www.cnblogs.com/zzcflying/archive/2012/08/30/2663540.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `function` `getPositionSuccess( position ){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``var` `lat = position.coords.latitude;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``var` `lng = position.coords.longitude;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``alert( ``\u0026quot;您所在的位置： 纬度\u0026quot;` `+ lat + ``\u0026quot;，经度\u0026quot;` `+ lng );` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``if``(``typeof` `position.address !== ``\u0026quot;undefined\u0026quot;``){` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``var` `country = position.address.country;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``var` `province = position.address.region;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``var` `city = position.address.city;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``alert(``' 您位于 '` `+ country + province + ``'省'` `+ city +``'市'``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; coords其他返回信息：\ncoords.accuracy：返回经纬度的精度（米）\ncoords.speed :速度\ncoords.altitude ：当前的高度，海拔（米）\ncoords.altitudeAccuracy：高度的精度（米）\ncoords.heading：朝向\n[?](http://www.cnblogs.com/zzcflying/archive/2012/08/30/2663540.html#) \u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `function` `getPositionError(error) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``switch` `(error.code) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``case` `error.TIMEOUT:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``alert(``\u0026quot;连接超时，请重试\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``case` `error.PERMISSION_DENIED:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; ` ``alert(``\u0026quot;您拒绝了使用位置共享服务，查询已取消\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; ` ``case` `error.POSITION_UNAVAILABLE:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; ` ``alert(``\u0026quot;获取位置信息失败\u0026quot;``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; ","permalink":"https://blog.zdltech.com/posts/%E5%9F%BA%E4%BA%8E-html5-geolocation%E6%9D%A5%E8%8E%B7%E5%8F%96%E7%BB%8F%E7%BA%AC%E5%BA%A6%E5%9C%B0%E5%9D%80/","summary":"\u003cp\u003e以前如果要获取互联网用户所在地都是根据用户的IP地址来获取地理位置，这样获取到的数据和真实数据有很大的偏差。为了获取更加精确的位置，可以使用了html5的geolocation来获取经纬度，然后再获取所在地理位置，如何获取，我在下面会说到。先说下基本概念。\u003c/p\u003e\n\u003cp\u003eGeolocation在的navigator 对象中，我们可以通过 navigator.geolocation 来使用它。不支持 geolocation 的浏览器并不包含这一对象，那么可以通过下面的代码来做能力检测，对不同的浏览器做不同的处理。在访问 geolocation 对象时，即调用 geolocation 下面的方法时，浏览器会弹出提示，询问用户是否许可网站提供的位置服务，只有在得到用户许可过后，服务才会继续，否则将被停止。\u003c/p\u003e\n\u003cp\u003e常用的navigator.geolocation对象有以下三种方法：\u003c/p\u003e\n\u003cp\u003e获取当前地理位置：\u003cstrong\u003enavigator.geolocation.getCurrentPosition\u003c/strong\u003e(success_callback_function, error_callback_function, position_options)\u003c/p\u003e\n\u003cp\u003e持续获取地理位置：\u003cstrong\u003enavigator.geolocation.watchPosition\u003c/strong\u003e(success_callback_function, error_callback_function, position_options)\u003c/p\u003e\n\u003cp\u003e清除持续获取地理位置事件：\u003cstrong\u003enavigator.geolocation.clearWatch\u003c/strong\u003e(watch_position_id)\u003c/p\u003e\n\u003cp\u003e参数position_options是配置项，由JSON格式传入：\u003c/p\u003e\n\u003cp\u003eenableHighAccuracy：true/false，它将告诉浏览器是否启用高精度设备，所谓的高精度设备包含但不局限于前面所提到的 GPS 和 WIFI，值为 true 的时候，浏览器会尝试启用这些设备，默认指为 true，在这种情况下，浏览器会尽可能地进行更为精确的查询，简单地说，如果用户有可用的 GPS 设备，会返回 GPS 设备的查询结果，IP 是最后的选择，对于移动设备来说，网络接入点(基站)或许成为另一个选择，对此我还没有完全了解，但根据测试，即时没有任何额外功能的手机，也能够得到更为精确的查询结果。\u003c/p\u003e\n\u003cp\u003emaximumAge：单位毫秒，告诉设备缓存时间，主要用于设备的省电或者节省带宽方面。\u003c/p\u003e\n\u003cp\u003etimeout：单位毫秒，超时事件，获取位置信息时超出设定的这个时长，将会触发错误，捕获错误的函数将被调用，并且错误码指向TIMEOUT。\u003c/p\u003e\n\u003cdiv class=\"cnblogs_Highlighter\"\u003e\n  \u003cdiv id=\"highlighter_599225\" class=\"syntaxhighlighter nogutter  javascript\"\u003e\n    \u003cdiv class=\"toolbar\" style=\"color: #ffffff !important;\"\u003e\n      [?](http://www.cnblogs.com/zzcflying/archive/2012/08/30/2663540.html#)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n  \u0026lt;tr\u0026gt;\n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `var` `position_option = {`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          `                ``enableHighAccuracy: ``true``,`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `                ``maximumAge: 30000,`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          `                ``timeout: 20000`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          `            ``};`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n          `navigator.geolocation.getCurrentPosition(getPositionSuccess, getPositionError, position_option);`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"cnblogs_Highlighter\"\u003e\n  \u003cdiv id=\"highlighter_158400\" class=\"syntaxhighlighter nogutter  javascript\"\u003e\n    \u003cdiv class=\"toolbar\" style=\"color: #ffffff !important;\"\u003e\n      [?](http://www.cnblogs.com/zzcflying/archive/2012/08/30/2663540.html#)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;table border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n  \u0026lt;tr\u0026gt;\n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `function` `getPositionSuccess( position ){`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n          `        ``var` `lat = position.coords.latitude;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `        ``var` `lng = position.coords.longitude;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          `        ``alert( ``\u0026quot;您所在的位置： 纬度\u0026quot;` `+ lat + ``\u0026quot;，经度\u0026quot;` `+ lng );`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          `        ``if``(``typeof` `position.address !== ``\u0026quot;undefined\u0026quot;``){`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n          `                ``var` `country = position.address.country;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt;\n          `                ``var` `province = position.address.region;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt;\n          `                ``var` `city = position.address.city;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt;\n          `                ``alert(``' 您位于 '` `+ country + province + ``'省'` `+ city +``'市'``);`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt;\n          `        ``}`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt;\n          `}`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003ecoords其他返回信息：\u003c/p\u003e","title":"基于 html5 geolocation来获取经纬度地址"},{"content":"UI相关\n图片\nAndroid-Universal-Image-Loader：com.nostra13.universalimageloader：异步加载、缓存、显示图片\nImageLoader：com.novoda.imageloader：异步加载、缓存、显示图片\npicasso：com.squareup.picasso：功能强大的图片下载缓存库\nPhotoView：uk\\co\\senab\\photoview：支持缩放和各种手势的ImageView\nListView\nJazzyListView：com.twotoasters.jazzylistview：扩展的ListView，当列表项目在屏幕上可见时产生动画效果\nStickyListHeaders：com.emilsjolander.components.stickylistheaders：在ListView中置顶\nListViewAnimations：com.haarman.listviewanimations：带动画的ListView\ndrag-sort-listview：？？？：拖拽排序ListView的元素\nandroid-swipelistview：？？？：让listview的item可以向右滑动\n下拉刷新\nAndroid-PullToRefresh：com.handmark.pulltorefresh：下拉刷新组件\nandroid-pulltorefresh：？？？：下拉刷新组件\nActionBar-PullToRefresh：？？？：下拉刷新组件，下拉时会替换掉ActionBar\n菜单\nSlidingMenu：com.jeremyfeinstein.slidingmenu：滑动菜单\nMenuDrawer：？？？：滑动菜单组件\nAction Bar\nActionBarSherlock：com.actionbarsherlock：Action Bar组件\nandroid-actionbar：？？？：Action Bar组件\nGlassActionBar：？？？：玻璃效果的Action Bar\nViewPager\nAndroid-ViewPagerIndicator：com.viewpagerindicator：分页显示组件\nPagerSlidingTabStrip：com.astuetz.viewpager：页面滑动组件\nJazzyViewPager：？？？：可自定义动画的ViewPager\n兼容\nNineOldAndroids：com.nineoldandroids：移植Honeycomb版本的动画API到旧版本上\nHoloEverywhere：？？？：移植Android 4.1的Holo主题到旧的版本上\nGlowPadBackport：GlowPadBackport：移植Android 4.2 GlowPadView到旧版本上\nandroid-switch-backport：？？？：移植Android 4的Switch widget到旧版本上\nAChartEngine：org.achartengine：Android上的绘图库\nandroid-viewflow：com.taptwo.android.widget：视图切换的效果\nandroid-flip：？？？：翻页动画组件\nAndroid-AppMsg：？？？：In-layout notifications\nandroid-wheel：kankan.wheel：Android滚动控件\nAndroid-ProgressFragment：？？？：等待数据的时候，支持显示等待符号的Fragment控件\nStaggeredGridView：？？？：瀑布流GridView布局\nCards-UI：？？？：卡片布局\ncardslib：？？？：卡片布局\nAndroid-DragArea：？？？：拖拽排序\nAndroid-StaggeredGrid: ？？？：类pinterest布局\nFlipImageView: ？？？：通过扩展ImageView，实现了ImageView的各种翻转效果\nSmoothProgressBar：？？？：平滑的ProgressBar，各种效果\nSuperToasts：？？？：Toast的超强扩展\nAndroidFloatLabel：？？？：Textview浮动提示\ncropper：？？？：截图和旋转库\nWebApp\nCordova：org.apache.cordova：Cordova是PhoneGap贡献给Apache后的开源项目，是从PhoneGap中抽出的核心代码\nHtmlSpanner：net.nightwhistler.htmlspanner：Android上的网页渲染库，可渲染CSS\nChromeView：？？？：Chrome内核移植的WebView\n推送\n个推：com.igexin：手机推送服务\nJPush：？？？：极光推送\n百度推送：com.baidu.android.pushservice：百度推送服务\nMQTT：ibm.mqtt：MQTT协议，似乎和推送有关系\n语音识别\n讯飞SDK：com.iflytek：科大讯飞语音SDK\n百度语音识别：com.baidu.voicerecognition：百度语音识别SDK\nmobvoi：com.mobvoi：移动语音搜索\n云知声：cn.yunzhisheng：云知声语音处理\n音频视频图像\nCC视频：com.bokecc：视频云平台\nVitamio：io.vov.vitamio：多媒体开发框架\nleptonica：com.googlecode.leptonica：图像处理库\ntesseract-ocr：com.googlecode.tesseract：图像OCR库\naacdecoder-android：com.spoledge.aacdecoder：Android上的Audio (AAC) 解码器\n地图定位\n百度定位：com.baidu.location：百度地图SDK\n百度地图：com.baidu.mapapi：百度地图SDK\namap：com.amap.api，com.autonavi：高德地图API\n图吧SDK：com.mapbar：图吧地图API\nMapABC：com.mapabc：MapABC地图SDK\n广告平台\n友盟SDK：com.umeng：友盟统计、自动更新、用户反馈、社会化组件\n多盟：cn.domob：多盟平台\n百度移动联盟：com.baidu.mobads：百度移动联盟\ngoogle ads：com.google.ads：google广告\nAdChina：com.adchina：易传媒广告平台\nAdsMogo：com.adsmogo：芒果移动广告平台\nAdwo：com.adwo：安沃移动广告平台\nmobisage：com.mobisage：艾德思奇移动广告平台\nMiaozhen：com.miaozhen：秒针第三方广告平台\nAdMaster：cn.com.admaster：admaster广告平台\n易积分：com.qiang.escore：易积分移动广告平台\ninmobi：com.inmobi：国外的广告平台\n点信传媒：cn.dx：广告平台\n统计分析\nFlurry：com.flurry：国外流行的统计工具\n百度移动统计：com.baidu.mobstat：百度开发者中心\nCobub Razor：com.wbtech.ums：移动统计分析工具\ngoogle analytics：com.google.analytics：google统计\nlotuseed：com.lotuseed：莲子统计\nLocalytics：com.localytics.android：国外统计分析工具\ncomscore：com.comscore：国外的统计工具\n网络通信\nvolley：com.android.volley：Android网络通信库\nApache Thrift：com.apache.thrift：远程服务调用框架\nNetty：org.jboss.netty：异步事件驱动的网络应用程序框架\nHttp访问\nApache HttpClient：org.apache.http\nandroid-async-http：com.loopj：异步Http库\nasync-http-client：？？？：异步Http和WebSocket库\nOkHttp：？？？：实现了Google开发的SPDY协议，更快的网络传输和加载速度\nXMPP协议\nsmack：org.jivesoftware.smack：XMPP客户端类库\nJbosh：com.kenai.jbosh：XMPP BOSH规范的Java实现\n应用授权\nScribe：org.scribe：简单的OAuth认证\nQQ互联：com.tencent.tauth：QQ互联\n百度授权：com.baidu.oauth：百度应用授权\nweibo授权：com.sina.sso：新浪微博应用授权\n社交分享\nShareSDK：cn.sharesdk：App分享库\nfacebook-android-sdk：com.facebook：Facebook SDK\n腾讯微信：com.tencent.mm：腾讯微信SDK\n腾讯微博：com.tencent.weibo：腾讯微博SDK\nweiboSDK：com.weibo.sdk：新浪微博SDK\nqweibo：com.mime.qweibo：Q版微博\nt4j：t4j：网易微博开放平台\nyixin：im.yixin：易信开放平台\n人人SDK：com.renren.api：人人网SDK\n翼聊：com.yiliao.android：中国电信天翼开放平台\nevernote：com.evernote：Evernote API\n有道云笔记SDK：com.youdao.note：有道云笔记SDK\n移动支付\nalipay：com.alipay：支付宝\ntenpay：com.tenpay：QQ财付通\numpay：com.umpay：联动优势支付平台\n银联支付：com.unionpay：中国银联手机支付平台\nMMBilling：mm.purchasesdk：中国移动应用内计费SDK\nData解析\ndom4j：org.dom4j：XML解析库\nxmlpull：org.xmlpull.v1：XML解析器，Android自带\nFastJSON：com.alibaba.fastjson：JSON解析器\nSparta：com.hp.hpl.sparta：XML、DOM、XPath解析器\njsoup：org.jsoup：HTML解析器\nosbcp-css-parser：com.osbcp.cssparser：CSS解析器\nHtmlCleaner：org.htmlcleaner：Html清洗解析库\nMime4J：org.apache.james.mime4j：MIME邮件格式解析器\n序列化\ngoogle-gson：com.google.gson：序列化反序列化Java对象成Json数据\nJackson：org.codehaus.jackson：序列化反序列化Java对象成Json数据\nORM\nOrmLite：com.j256.ormlite：Java ORM库\ngreenDAO：？？？：Android ORM for SQLite\nAndrOrm：？？？：An ORM for Android\n网盘\nPCS：com.baidu.pcs：百度个人云存储\nvdisk：com.vdisk：微盘开放平台\n金山快盘：com.kuaipan：金山快盘开放平台\n异常收集分析\nacra：org.acra：Application Crash Reports for Android\nCrittercism：com.crittercism：为开发者提供分析诊断应用崩溃的原因\n服务器\nSwiFTP：org.swiftp：Android平台的FTP服务器\nandroid-webserver：com.bolutions.webserver：Android平台的Web服务器\nEvent Bus\nEventBus：de.greenrobot.event：an Android optimized publish/subscribe event bus\notto：？？？：基于Guav的Event Bus\nDependency Injection\nRoboGuice：roboguice：Android平台的Dependency Injection框架\nroboguice-sherlock：com.github.rtyley：使用RoboGuice实现的ActionBarSherlock\nGoogle Guice：com.google.inject：Dependency Injection框架\n图标资源\nAndroton-Action-Bar-Icons：？？？：一个针对Android 优化过的ICON图标集\nhttp://iconsparadise.com/\nhttp://iconbench.com/\nhttp://www.androidicons.com/\nhttps://code.google.com/p/android-ui-utils/\n其他组件\nandroid-query：com.androidquery：异步任务和操作UI元素\nZXing：com.google.zxing：条形码和二维码生成和解码库\npinyin4j：net.sourceforge.pinyin4j：中文和拼音转换\nprotobuf：com.google.protobuf：protobuf\nJZlib：com.jcraft.jzlib：Java实现的zlib库\nzt-zip：？？？：压缩解压库\naFileChooser：？？？：文件浏览器\nimage-chooser-library：？？？：图片和视频的选择库\nTOML：？？？：跨语言的配置信息存取方案\nOpenUDID：org.openudid：通用且持久的Unique Device IDentifier (UDID)解决方案\nParse：com.parse：各种很棒的后台服务\nCodec：org.apache.codec：字符串编码解码库\njChardet：org.mozilla.intl.chardet：自动检测字符集\nJRegex：jregex：正则表达式库\nSQLCipher：info.guardianproject.database：Android数据库加密\nxiaomi：com.xiaomi：小米开发者平台：推送服务、自动更新、自动发布等\nDataDroid：？？？：以RESTful方式管理数据\nAfinal：？？？：SQLITE的ORM和IOC框架，同时封装了android中的http框架\nAndroidCommon：？？？：Android常用的一些库和功能，如缓存，下拉列表，下载管理，静默安装等\nThinkAndroid：？？？：Android整体框架：集成了ioc，orm，下载，缓存等模块，能让开发更加快速和高效\n** 不常用组件**\ndnsjava：org.xbill.dns：域名解析\nsasl：com.novell.sasl.client：sasl认证机制\nLuaJava：org.keplerproject.luajava：Java嵌入Lua\nPJSIP：org.pjsip.pjsua：PJSUA是一个开源的命令行SIP用户代理（软电话），用PJSIP协议，PJNATH，和PJMEDIA实现\n**UI框架** - [GreenDroid](https://github.com/cyrilmottier/GreenDroid)： - [Bearded-Hen/Android-Bootstrap](https://github.com/Bearded-Hen/Android-Bootstrap)： - [donnfelker/android-bootstrap](https://github.com/donnfelker/android-bootstrap)： **游戏引擎** - [cocos2d-x](https://github.com/cocos2d/cocos2d-x)： - [libgdx](https://github.com/libgdx/libgdx)： - [AndEngine](https://github.com/nicolasgramlich/AndEngine)： - [MonoGame](https://github.com/mono/MonoGame)： **其他组件** - [skrollr](https://github.com/Prinzhorn/skrollr)：视差滚动Javascript引擎 - [androidannotations](https://github.com/excilys/androidannotations)：扩展Android注解语言 - [android_guides](https://github.com/thecodepath/android_guides)：学习Android和iOs - [phonegap](https://github.com/sintaxi/phonegap)：WebApp开发引擎 ","permalink":"https://blog.zdltech.com/posts/android%E5%B8%B8%E7%94%A8%E7%BB%84%E4%BB%B6/","summary":"\u003cp\u003e\u003cstrong\u003eUI相关\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e图片\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/nostra13/Android-Universal-Image-Loader\"\u003eAndroid-Universal-Image-Loader\u003c/a\u003e：com.nostra13.universalimageloader：异步加载、缓存、显示图片\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/novoda/ImageLoader\"\u003eImageLoader\u003c/a\u003e：com.novoda.imageloader：异步加载、缓存、显示图片\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/square/picasso\"\u003epicasso\u003c/a\u003e：com.squareup.picasso：功能强大的图片下载缓存库\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/chrisbanes/PhotoView\"\u003ePhotoView\u003c/a\u003e：uk\\co\\senab\\photoview：支持缩放和各种手势的ImageView\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eListView\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/twotoasters/JazzyListView\"\u003eJazzyListView\u003c/a\u003e：com.twotoasters.jazzylistview：扩展的ListView，当列表项目在屏幕上可见时产生动画效果\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/emilsjolander/StickyListHeaders\"\u003eStickyListHeaders\u003c/a\u003e：com.emilsjolander.components.stickylistheaders：在ListView中置顶\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/nhaarman/ListViewAnimations\"\u003eListViewAnimations\u003c/a\u003e：com.haarman.listviewanimations：带动画的ListView\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/bauerca/drag-sort-listview\"\u003edrag-sort-listview\u003c/a\u003e：？？？：拖拽排序ListView的元素\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/47deg/android-swipelistview\"\u003eandroid-swipelistview\u003c/a\u003e：？？？：让listview的item可以向右滑动\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e下拉刷新\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/chrisbanes/Android-PullToRefresh\"\u003eAndroid-PullToRefresh\u003c/a\u003e：com.handmark.pulltorefresh：下拉刷新组件\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/johannilsson/android-pulltorefresh\"\u003eandroid-pulltorefresh\u003c/a\u003e：？？？：下拉刷新组件\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/chrisbanes/ActionBar-PullToRefresh\"\u003eActionBar-PullToRefresh\u003c/a\u003e：？？？：下拉刷新组件，下拉时会替换掉ActionBar\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e菜单\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/jfeinstein10/SlidingMenu\"\u003eSlidingMenu\u003c/a\u003e：com.jeremyfeinstein.slidingmenu：滑动菜单\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/SimonVT/android-menudrawer\"\u003eMenuDrawer\u003c/a\u003e：？？？：滑动菜单组件\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eAction Bar\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/JakeWharton/ActionBarSherlock\"\u003eActionBarSherlock\u003c/a\u003e：com.actionbarsherlock：Action Bar组件\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/johannilsson/android-actionbar\"\u003eandroid-actionbar\u003c/a\u003e：？？？：Action Bar组件\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/ManuelPeinado/GlassActionBar\"\u003eGlassActionBar\u003c/a\u003e：？？？：玻璃效果的Action Bar\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eViewPager\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/JakeWharton/Android-ViewPagerIndicator\"\u003eAndroid-ViewPagerIndicator\u003c/a\u003e：com.viewpagerindicator：分页显示组件\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/astuetz/PagerSlidingTabStrip\"\u003ePagerSlidingTabStrip\u003c/a\u003e：com.astuetz.viewpager：页面滑动组件\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/jfeinstein10/JazzyViewPager\"\u003eJazzyViewPager\u003c/a\u003e：？？？：可自定义动画的ViewPager\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e兼容\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/JakeWharton/NineOldAndroids\"\u003eNineOldAndroids\u003c/a\u003e：com.nineoldandroids：移植Honeycomb版本的动画API到旧版本上\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/Prototik/HoloEverywhere\"\u003eHoloEverywhere\u003c/a\u003e：？？？：移植Android 4.1的Holo主题到旧的版本上\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/rock3r/GlowPadBackport\"\u003eGlowPadBackport\u003c/a\u003e：GlowPadBackport：移植Android 4.2 GlowPadView到旧版本上\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/BoD/android-switch-backport\"\u003eandroid-switch-backport\u003c/a\u003e：？？？：移植Android 4的Switch widget到旧版本上\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://code.google.com/p/achartengine/\"\u003eAChartEngine\u003c/a\u003e：org.achartengine：Android上的绘图库\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/pakerfeldt/android-viewflow\"\u003eandroid-viewflow\u003c/a\u003e：com.taptwo.android.widget：视图切换的效果\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/openaphid/android-flip\"\u003eandroid-flip\u003c/a\u003e：？？？：翻页动画组件\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/johnkil/Android-AppMsg\"\u003eAndroid-AppMsg\u003c/a\u003e：？？？：In-layout notifications\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://code.google.com/p/android-wheel/\"\u003eandroid-wheel\u003c/a\u003e：kankan.wheel：Android滚动控件\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/johnkil/Android-ProgressFragment\"\u003eAndroid-ProgressFragment\u003c/a\u003e：？？？：等待数据的时候，支持显示等待符号的Fragment控件\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/maurycyw/StaggeredGridView\"\u003eStaggeredGridView\u003c/a\u003e：？？？：瀑布流GridView布局\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/afollestad/Cards-UI\"\u003eCards-UI\u003c/a\u003e：？？？：卡片布局\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/gabrielemariotti/cardslib\"\u003ecardslib\u003c/a\u003e：？？？：卡片布局\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/doffm/android-dragarea\"\u003eAndroid-DragArea\u003c/a\u003e：？？？：拖拽排序\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/etsy/AndroidStaggeredGrid\"\u003eAndroid-StaggeredGrid\u003c/a\u003e: ？？？：类pinterest布局\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/castorflex/FlipImageView\"\u003eFlipImageView\u003c/a\u003e: ？？？：通过扩展ImageView，实现了ImageView的各种翻转效果\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/castorflex/SmoothProgressBar\"\u003eSmoothProgressBar\u003c/a\u003e：？？？：平滑的ProgressBar，各种效果\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/JohnPersano/SuperToasts\"\u003eSuperToasts\u003c/a\u003e：？？？：Toast的超强扩展\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/IanGClifton/AndroidFloatLabel\"\u003eAndroidFloatLabel\u003c/a\u003e：？？？：Textview浮动提示\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/edmodo/cropper\"\u003ecropper\u003c/a\u003e：？？？：截图和旋转库\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eWebApp\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"http://cordova.apache.org/\"\u003eCordova\u003c/a\u003e：org.apache.cordova：Cordova是PhoneGap贡献给Apache后的开源项目，是从PhoneGap中抽出的核心代码\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/NightWhistler/HtmlSpanner\"\u003eHtmlSpanner\u003c/a\u003e：net.nightwhistler.htmlspanner：Android上的网页渲染库，可渲染CSS\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/pwnall/chromeview\"\u003eChromeView\u003c/a\u003e：？？？：Chrome内核移植的WebView\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e推送\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"http://www.igetui.com/\"\u003e个推\u003c/a\u003e：com.igexin：手机推送服务\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://www.jpush.cn/\"\u003eJPush\u003c/a\u003e：？？？：极光推送\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"http://developer.baidu.com/\"\u003e百度推送\u003c/a\u003e：com.baidu.android.pushservice：百度推送服务\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"http://mqtt.org/\"\u003eMQTT\u003c/a\u003e：ibm.mqtt：MQTT协议，似乎和推送有关系\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e语音识别\u003c/strong\u003e\u003c/p\u003e","title":"Android常用组件"},{"content":"Android Tools\n- draw9patch - lint - hierarchyviewer - traceView - monkey 工具存放路径：sdk/tools/ draw9patch 介绍： 所谓\u0026amp;#8221;*.9.png\u0026amp;#8221;这是Android os里所支持的一种特殊的图片格式,用它可以实现部分拉伸；这种图片是经过”9妹“进行特殊处理过的，如果不处理的话，直接用PNG图就会有失真，拉伸不正常的现象出现。 使用： 双击打开看到 ![](http://img.blog.csdn.net/20140917141621430?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 然后将需要拉伸的图片直接拖进去进行拉伸，右侧是拉伸效果 ![](http://img.blog.csdn.net/20140917142108860?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 左侧和上方的黑线交叉的部分即可扩展区域 右侧和下方的黑线交叉的部分即内容显示区域(如做button背景图时，button上文字的显示区域) lint 介绍： Lint 是Android ADT 16引入的优化工具，它可以扫描你的代码，帮助发现潜在的问题，例如： 1.文本国际化（有些文本缺少其它语言版本）例如：layout文件中编写不规范的地方，会给出提示。考虑到国际化，如果直接在xml中写汉字会提醒你把文字写到string配置文件中\n2.Layout的性能问题 3.无用的多余的资源 例如：项目中有哪些资源文件引入了却没有在代码中使用的话，会给提示。既包括图片资源、layout文件，也有定义的String常量和Color常量等。考虑到屏幕适配，如果有些图片只在高分辨率中放置了，会提醒你应该在中低分辨率的文件夹下也应该放置一份。 4.不一致的数组大小（在配置文件中） 5.重复的图标，图片 6.可用性问题（如没有为EditText指定 InputType） 7. Manifest xml配置错误。\n使用： 有两种使用方式： 通过命令运行： lint 检查布局路径 然后返回检测结果 如图： ![](http://img.blog.csdn.net/20140917145229803?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 通过Eclipse直接运行: 选中项目右键-》AndroidTools-》Run Lint ![](http://img.blog.csdn.net/20140917145930984?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 运行之后显示错误： ![](http://img.blog.csdn.net/20140917150320308?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 双击错误，还能跳到指定布局位置，右侧是错误详解。 hierarchyviewer 介绍： \u0026lt;span style=\u0026quot;color: #2c2c2c;\u0026quot;\u0026gt;HierarchyViewer能够\u0026lt;/span\u0026gt;可视化的角度直观地获得\u0026lt;span lang=\u0026quot;en-us\u0026quot;\u0026gt;UI\u0026lt;/span\u0026gt;布局设计结构和各种属性的信息，帮助我们优化布局设计。（也可以查看其他App的布局） 使用： 打开hierarchyviewer显示了一个虚拟器 ![](http://img.blog.csdn.net/20140917155910586?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 选中一个进程的界面，点击Load View Hierarchy 这个按钮，以微信个人界面为例： ![](http://img.blog.csdn.net/20140917161701531?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 首先我们可以看到一个主布局，它下面的子布局是以树形的结构展示，看上去结构非常清晰. ![](http://img.blog.csdn.net/20140917162030437?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 接下来，我们在看看，子布局,可以从下图看到大家最喜欢的“摇一摇”功能条目，清晰的层级结构，以及控件的名称，还有效果图的展示，我们完全可以通过它给提供出来的数据，自己也实现这个布局，就算不去模仿他人的布局，我们也可以通过这个工具去分析我们自己的工程，这样可以更好及更快的找到我们需要优化的地方，进行布局优化。 ![](http://img.blog.csdn.net/20140917162645592?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 点击左下角的图标回到之前的操作界面界面，然后我们在选中微信进程，点击Inspet Screenshot 这个按钮.我们会看到 ![](http://img.blog.csdn.net/20140917163339212?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 从这个界面我们可以看到，控件的类名都已经一丝不挂了，这个界面，分为3部分，左边以树形结构显示布局类名，中间放大左边选中的区域以及，显示颜色值和坐标值，下面的工具条还能对选中区域进行所发，以及刷新频率。右边则可以通过鼠标随意移动，中间则实时刷新数据。 细心的朋友可以能会发现，左下角，3个按钮现在可以随意切换了，三个按钮功能分别是，主界面，布局分析界面，截屏分析界面。 traceView 介绍： TraceView是AndroidSDK里面自带的工具，用于对Android的应用程序以及Framework层的代码进行性能分析。 TraceView是图形化的工具，最终它会产生一个图表，用于对性能分析进行说明。 TraceView可以跟踪到具体的Method 使用： 限制条件： - 对于Android 1.5及以下的版本：不支持。 - 对于Android 1.5以上2.1下（含2.1）的版本：受限支持。trace文件只能生成到SD卡，且必须在程序中加入代码。 - 对于Android 2.2上（含2.2）的版本：全支持。可以不用SD卡，不用在程序中加代码，直接自己用DDMS就可以进程Traceview。 \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; 我先演示一下，低版本的用代码，生成trace文件，然后打开分析。 \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/cym492224103/article/details/39343907#)[copy](http://blog.csdn.net/cym492224103/article/details/39343907#)[print](http://blog.csdn.net/cym492224103/article/details/39343907#)[?](http://blog.csdn.net/cym492224103/article/details/39343907#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.traceviewdemo; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.ActionBar; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Fragment; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Debug; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Menu; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MenuItem; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Build; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 开始\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Debug.startMethodTracing(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;mytrace\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setContentView(R.layout.activity_main); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; action(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDestroy() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDestroy(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 停止\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Debug.stopMethodTracing(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; action(){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;100000\u0026lt;/span\u0026gt;; i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;模拟耗时\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 需要添加权限： \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/cym492224103/article/details/39343907#)[copy](http://blog.csdn.net/cym492224103/article/details/39343907#)[print](http://blog.csdn.net/cym492224103/article/details/39343907#)[?](http://blog.csdn.net/cym492224103/article/details/39343907#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;uses-permission\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.permission.WRITE_EXTERNAL_STORAGE\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 执行完后，会在sd卡生成一个mytrace.trace文件 \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; ![](http://img.blog.csdn.net/20140917173106006?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; \u0026lt;span style=\u0026quot;color: #4b4b4b;\u0026quot;\u0026gt;我们把它导出，然后使用命令行执行分析该文件：\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #4b4b4b;\u0026quot;\u0026gt;traceView 文件地址\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140917173247017?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 显示下图： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140917175000815?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;color: #4b4b4b;\u0026quot;\u0026gt; 从上图我们可以看到，MainActivity的action（）是最耗时的方法，占用了95%的时候。如果在真实项目中，我们首先就是找到消耗性能的方法，然后对其优化， 还有很多属性大家可以看一下 \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;color: #4b4b4b;\u0026quot;\u0026gt; ![](http://img.blog.csdn.net/20140917175451646?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;color: #4b4b4b;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;color: #4b4b4b;\u0026quot;\u0026gt; 我们在看看，高版本不用代码如何使用traceView的做法 \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; 使用DDMS \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; 打开devices窗口，选择某个进程，点击右上角的start method profiling \u0026lt;/div\u0026gt; \u0026lt;blockquote style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; \u0026amp;nbsp; \u0026amp;nbsp; \u0026lt;div\u0026gt; 运行app一段时间后，再点击已变成stop method profiling的该按钮。eclipse会自动弹出debug的标签（可通过菜单File-\u0026gt;save as保存数据）。界面同上 面。 \u0026lt;/div\u0026gt; \u0026amp;nbsp; \u0026amp;nbsp; \u0026amp;nbsp; \u0026lt;div\u0026gt; 这种方式不需要修改代码，所以对于没有源码的程序同样可以进行排查。同时可以方便的进行全局性能排查 \u0026lt;/div\u0026gt; \u0026amp;nbsp; \u0026lt;/blockquote\u0026gt; monkey 介绍： Monkey是Android中的一个命令行工具，可以运行在模拟器里或实际设备中。它向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势输入等)，实现对正在开发的应用程序进行压力测试。Monkey测试是一种为了测试软件的稳定性、健壮性的快速有效的方法。 使用： \u0026lt;blockquote style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; \u0026amp;nbsp; 基本语法如下： \u0026amp;nbsp; \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;adb shell monkey [options] \u0026amp;nbsp; 如果不指定options，Monkey将以无反馈模式启动，并把事件任意发送到安装在目标环境中的全部包。下面是一个更为典型的命令行示例，它启动指定的应用程序，并向其发送500个伪随机事件： \u0026amp;nbsp;\u0026lt;/span\u0026gt; adb shell monkey -p your.package.name -v 500 \u0026amp;nbsp; ## 命令选项参考 \u0026lt;wbr /\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android%E4%B9%8B%E5%B8%B8%E7%94%A8tools%E4%BB%8B%E7%BB%8D%E5%8F%8A%E4%BD%BF%E7%94%A8/","summary":"\u003cp\u003eAndroid Tools\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e- draw9patch\n\n- lint\n\n- hierarchyviewer\n\n- traceView\n\n- monkey\n\n\n\n\n\n\n\n  工具存放路径：sdk/tools/\n\n\n\n\n\n  draw9patch\n\n\n\n\n\n  \n\n    介绍：\n  \n\n  \n  \n\n    所谓\u0026amp;#8221;*.9.png\u0026amp;#8221;这是Android os里所支持的一种特殊的图片格式,用它可以实现部分拉伸；这种图片是经过”9妹“进行特殊处理过的，如果不处理的话，直接用PNG图就会有失真，拉伸不正常的现象出现。\n  \n\n  \n  \n\n    使用：\n  \n\n  \n  \n\n    双击打开看到\n  \n\n  \n  \n\n    ![](http://img.blog.csdn.net/20140917141621430?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n  \n\n  \n  \n\n    然后将需要拉伸的图片直接拖进去进行拉伸，右侧是拉伸效果\n  \n\n  \n  \n\n    ![](http://img.blog.csdn.net/20140917142108860?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n  \n\n  \n  \n\n    左侧和上方的黑线交叉的部分即可扩展区域\n  \n\n  \n  \n\n    右侧和下方的黑线交叉的部分即内容显示区域(如做button背景图时，button上文字的显示区域)\n  \n\n  \n  \n\n    \n\n      lint\n    \n\n    \n    \n\n      介绍：\n    \n\n    \n    \n\n      Lint 是Android ADT 16引入的优化工具，它可以扫描你的代码，帮助发现潜在的问题，例如：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e1.文本国际化（有些文本缺少其它语言版本）例如：layout文件中编写不规范的地方，会给出提示。考虑到国际化，如果直接在xml中写汉字会提醒你把文字写到string配置文件中\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e           2.Layout的性能问题\n    \n\n    \n    \n\n           3.无用的多余的资源 例如：项目中有哪些资源文件引入了却没有在代码中使用的话，会给提示。既包括图片资源、layout文件，也有定义的String常量和Color常量等。考虑到屏幕适配，如果有些图片只在高分辨率中放置了，会提醒你应该在中低分辨率的文件夹下也应该放置一份。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e4.不一致的数组大小（在配置文件中）\n5.重复的图标，图片\n6.可用性问题（如没有为EditText指定 InputType）\n7. Manifest xml配置错误。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e      使用：\n    \n\n    \n    \n\n      有两种使用方式：\n    \n\n    \n    \n\n      通过命令运行：\n    \n\n    \n    \n\n      lint 检查布局路径\n    \n\n    \n    \n\n      然后返回检测结果\n    \n\n    \n    \n\n      如图：\n    \n\n    \n    \n\n      ![](http://img.blog.csdn.net/20140917145229803?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n    \n\n    \n    \n\n      通过Eclipse直接运行:\n    \n\n    \n    \n\n      选中项目右键-》AndroidTools-》Run Lint\n    \n\n    \n    \n\n      ![](http://img.blog.csdn.net/20140917145930984?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n    \n\n    \n    \n\n      运行之后显示错误：\n    \n\n    \n    \n\n      ![](http://img.blog.csdn.net/20140917150320308?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n    \n\n    \n    \n\n      双击错误，还能跳到指定布局位置，右侧是错误详解。\n    \n\n    \n    \n\n      \n\n        hierarchyviewer\n      \n\n      \n      \n\n        介绍：\n      \n\n      \n      \n\n        \u0026lt;span style=\u0026quot;color: #2c2c2c;\u0026quot;\u0026gt;HierarchyViewer能够\u0026lt;/span\u0026gt;可视化的角度直观地获得\u0026lt;span lang=\u0026quot;en-us\u0026quot;\u0026gt;UI\u0026lt;/span\u0026gt;布局设计结构和各种属性的信息，帮助我们优化布局设计。（也可以查看其他App的布局）\n      \n\n      \n      \n\n        使用：\n      \n\n      \n      \n\n        打开hierarchyviewer显示了一个虚拟器\n      \n\n      \n      \n\n        ![](http://img.blog.csdn.net/20140917155910586?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n      \n\n      \n      \n\n          选中一个进程的界面，点击Load View Hierarchy 这个按钮，以微信个人界面为例：\n      \n\n      \n      \n\n        ![](http://img.blog.csdn.net/20140917161701531?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n      \n\n      \n      \n\n        首先我们可以看到一个主布局，它下面的子布局是以树形的结构展示，看上去结构非常清晰.\n      \n\n      \n      \n\n        ![](http://img.blog.csdn.net/20140917162030437?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n      \n\n      \n      \n\n        接下来，我们在看看，子布局,可以从下图看到大家最喜欢的“摇一摇”功能条目，清晰的层级结构，以及控件的名称，还有效果图的展示，我们完全可以通过它给提供出来的数据，自己也实现这个布局，就算不去模仿他人的布局，我们也可以通过这个工具去分析我们自己的工程，这样可以更好及更快的找到我们需要优化的地方，进行布局优化。\n      \n\n      \n      \n\n        ![](http://img.blog.csdn.net/20140917162645592?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n      \n\n      \n      \n\n        点击左下角的图标回到之前的操作界面界面，然后我们在选中微信进程，点击Inspet Screenshot 这个按钮.我们会看到\n      \n\n      \n      \n\n        ![](http://img.blog.csdn.net/20140917163339212?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n      \n\n      \n      \n\n        从这个界面我们可以看到，控件的类名都已经一丝不挂了，这个界面，分为3部分，左边以树形结构显示布局类名，中间放大左边选中的区域以及，显示颜色值和坐标值，下面的工具条还能对选中区域进行所发，以及刷新频率。右边则可以通过鼠标随意移动，中间则实时刷新数据。\n      \n\n      \n      \n\n        细心的朋友可以能会发现，左下角，3个按钮现在可以随意切换了，三个按钮功能分别是，主界面，布局分析界面，截屏分析界面。\n      \n\n      \n      \n\n        traceView\n      \n\n      \n      \n\n        介绍：\n      \n\n      \n      \n\n        TraceView是AndroidSDK里面自带的工具，用于对Android的应用程序以及Framework层的代码进行性能分析。\n      \n\n      \n      \n\n              TraceView是图形化的工具，最终它会产生一个图表，用于对性能分析进行说明。\n      \n\n      \n      \n\n        TraceView可以跟踪到具体的Method\n      \n\n      \n      \n\n        使用：\n      \n\n      \n      \n\n        限制条件：\n      \n\n      \n      \n\n        \n          - 对于Android 1.5及以下的版本：不支持。\n          \n          - 对于Android 1.5以上2.1下（含2.1）的版本：受限支持。trace文件只能生成到SD卡，且必须在程序中加入代码。\n          \n          - 对于Android 2.2上（含2.2）的版本：全支持。可以不用SD卡，不用在程序中加代码，直接自己用DDMS就可以进程Traceview。\n          \n        \n        \n        \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n          我先演示一下，低版本的用代码，生成trace文件，然后打开分析。\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n          \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n              \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n                **[java]** [view plain](http://blog.csdn.net/cym492224103/article/details/39343907#)[copy](http://blog.csdn.net/cym492224103/article/details/39343907#)[print](http://blog.csdn.net/cym492224103/article/details/39343907#)[?](http://blog.csdn.net/cym492224103/article/details/39343907#)\n\n                \n                \u0026lt;div\u0026gt;\n                \u0026lt;/div\u0026gt;\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n            \n            \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.traceviewdemo;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.ActionBar;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Fragment;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Debug;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Menu;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MenuItem;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Build;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity {  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) {  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 开始\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Debug.startMethodTracing(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;mytrace\u0026amp;#8221;\u0026lt;/span\u0026gt;);   \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        setContentView(R.layout.activity_main);  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        action();  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDestroy() {  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDestroy();  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 停止\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Debug.stopMethodTracing();    \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; action(){  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;100000\u0026lt;/span\u0026gt;; i++) {  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;模拟耗时\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n              \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n              \n            \n          \u0026lt;/div\u0026gt;\n          \n          \n\n            需要添加权限：\n          \n\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n          \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt;\n            \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n              \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n                **[html]** [view plain](http://blog.csdn.net/cym492224103/article/details/39343907#)[copy](http://blog.csdn.net/cym492224103/article/details/39343907#)[print](http://blog.csdn.net/cym492224103/article/details/39343907#)[?](http://blog.csdn.net/cym492224103/article/details/39343907#)\n\n                \n                \u0026lt;div\u0026gt;\n                \u0026lt;/div\u0026gt;\n              \u0026lt;/div\u0026gt;\n            \u0026lt;/div\u0026gt;\n            \n            \n              - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;uses-permission\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.permission.WRITE_EXTERNAL_STORAGE\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n              \n            \n          \u0026lt;/div\u0026gt;\n          \n          \n\n            执行完后，会在sd卡生成一个mytrace.trace文件\n          \n\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n          ![](http://img.blog.csdn.net/20140917173106006?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n          \u0026lt;span style=\u0026quot;color: #4b4b4b;\u0026quot;\u0026gt;我们把它导出，然后使用命令行执行分析该文件：\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #4b4b4b;\u0026quot;\u0026gt;traceView 文件地址\u0026lt;/span\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \n\n          \n\n            \u0026lt;div\u0026gt;\n              ![](http://img.blog.csdn.net/20140917173247017?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div\u0026gt;\n              显示下图：\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div\u0026gt;\n              ![](http://img.blog.csdn.net/20140917175000815?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div style=\u0026quot;color: #4b4b4b;\u0026quot;\u0026gt;\n              从上图我们可以看到，MainActivity的action（）是最耗时的方法，占用了95%的时候。如果在真实项目中，我们首先就是找到消耗性能的方法，然后对其优化， 还有很多属性大家可以看一下\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div style=\u0026quot;color: #4b4b4b;\u0026quot;\u0026gt;\n              ![](http://img.blog.csdn.net/20140917175451646?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div style=\u0026quot;color: #4b4b4b;\u0026quot;\u0026gt;\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div style=\u0026quot;color: #4b4b4b;\u0026quot;\u0026gt;\n              我们在看看，高版本不用代码如何使用traceView的做法\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n              使用DDMS\n            \u0026lt;/div\u0026gt;\n            \n            \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n              打开devices窗口，选择某个进程，点击右上角的start method profiling\n            \u0026lt;/div\u0026gt;\n            \n            \n\n              \u0026lt;blockquote style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n                \n\n                  \u0026amp;nbsp;\n                \n\n                \n                \n\n                  \u0026amp;nbsp;\n                \n\n                \n                \u0026lt;div\u0026gt;\n                  \n\n                    运行app一段时间后，再点击已变成stop method profiling的该按钮。eclipse会自动弹出debug的标签（可通过菜单File-\u0026gt;save as保存数据）。界面同上 面。\n                  \n\n                \u0026lt;/div\u0026gt;\n                \n                \n\n                  \u0026amp;nbsp;\n                \n\n                \n                \n\n                  \u0026amp;nbsp;\n                \n\n                \n                \n\n                  \u0026amp;nbsp;\n                \n\n                \n                \u0026lt;div\u0026gt;\n                  \n\n                    这种方式不需要修改代码，所以对于没有源码的程序同样可以进行排查。同时可以方便的进行全局性能排查\n                  \n\n                \u0026lt;/div\u0026gt;\n                \n                \n\n                  \u0026amp;nbsp;\n                \n\n              \u0026lt;/blockquote\u0026gt;\n              \n              \n\n                monkey\n              \n\n              \n              \n\n                介绍：\n              \n\n              \n              \n\n                Monkey是Android中的一个命令行工具，可以运行在模拟器里或实际设备中。它向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势输入等)，实现对正在开发的应用程序进行压力测试。Monkey测试是一种为了测试软件的稳定性、健壮性的快速有效的方法。\n              \n\n              \n              \n\n                使用：\n              \n\n              \n              \u0026lt;blockquote style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n                \n\n                  \u0026amp;nbsp;\n                \n\n                \n                \n\n                  基本语法如下：\n                \n\n                \n                \n\n                  \u0026amp;nbsp;\n                \n\n                \n                \n\n                  \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;adb shell monkey [options]\n\n                  \n                  \n\n                    \u0026amp;nbsp;\n                  \n\n                  \n                  \n\n                    如果不指定options，Monkey将以无反馈模式启动，并把事件任意发送到安装在目标环境中的全部包。下面是一个更为典型的命令行示例，它启动指定的应用程序，并向其发送500个伪随机事件：\n                  \n\n                  \n                  \n\n                    \u0026amp;nbsp;\u0026lt;/span\u0026gt; adb shell monkey -p your.package.name -v 500\n                  \n\n                  \n                  \n\n                    \u0026amp;nbsp;\n                  \n\n                  \n                  ## 命令选项参考 \u0026lt;wbr /\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/blockquote\u003e","title":"Android之常用Tools【介绍及使用】"},{"content":" **1、 启动VSFTP服务器** A:cenos下运行:yum install vsftpd\nB. 登录Linux主机后，运行命令：”service vsftpd start” C. 要让FTP每次开机自动启动，运行命令: “chkconfig \u0026amp;#8211;level 35 vsftpd on” ** \u0026lt;div class=\u0026quot;text\u0026quot;\u0026gt; \u0026lt;strong\u0026gt;2、设置FTP权限** \u0026lt;/div\u0026gt; **\u0026lt;span style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;A. 编辑VSFTP配置文件，运行命令：”vi /etc/vsftpd/vsftpd.conf “ B. 将配置文件中”anonymous_enable=YES “改为 “anonymous_enable=NO” C. 保存修改，按ESC键，运行命令：“：wq”\u0026lt;/span\u0026gt;\u0026lt;br style=\u0026quot;color: #362e2b;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; 这样关闭了匿名登录功能。 \u0026lt;blockquote class=\u0026quot;blockquote\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;quote\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;text\u0026quot;\u0026gt; \u0026lt;strong\u0026gt;3、添加FTP账号** \u0026lt;/div\u0026gt; \u0026lt;/blockquote\u0026gt; A. 登录Linux主机后，运行命令：”useradd ftpadmin -s /sbin/nologin “。该账户路径默认指向/home/ftpadmin目录；如果需要将用户指向其他目录，请运行命令：useradd ftpadmin -s /sbin/nologin –d /www(其他目录) B. 设置ftpadmin用户密码，运行命令：”passwd ftpadmin” ; 输入两次密码，匹配成功后，就设置好了ftpadmin用户的密码了。 C.测试连接，您可以在“我的电脑”地址栏中输入** ftp://IP **来连接FTP服务器，根据提示输入账户密码。\u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; ** \u0026lt;div class=\u0026quot;quote\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;text\u0026quot;\u0026gt; \u0026lt;strong\u0026gt;4、FTP数据传输注意事项** \u0026lt;/div\u0026gt; \u0026lt;/blockquote\u0026gt; A. 尽量把文件打包后上传。Linux无法识别RAR压缩包，可以使用ZIP压缩。 B.上传数据时请选择二进制编码，如果选择其他编码，可能会导致上传的压缩包无法打开。 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;help-section\u0026quot; style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; 以上内容是否已经解决了您的问题？ \u0026lt;/div\u0026gt; \u0026amp;nbsp; FTP服务器的默认目录是/var/ftp，而且当用户以匿名方式登录的时候，访问就是此目录。如果用户以其它的用户名登录的话，访问的则是那个用户名的工作目录。如果想要更改非匿名用户的默认FTP目录，可以采用如下方式进行更改： 1、进入/etc目录，打开passwd文件 2、转到想要更改的那个用户的行，编辑其工作目录为想要的目录即可 \u0026lt;span style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;一般采用此种方式带来的一个影响就是，shell的提示符不会再显示目录信息，如果想要变回原来的样子，可以采用如下简便的方法：把那个用户原来的工作目录下的所有与shell配置相关的文件复制到更改后的目录。\u0026lt;/span\u0026gt; \u0026amp;nbsp; \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;最后重启服务: service vsftpd restart\u0026lt;/span\u0026gt; ","permalink":"https://blog.zdltech.com/posts/linux%E4%B8%8B%E6%B7%BB%E5%8A%A0ftp%E8%B4%A6%E5%8F%B7%E5%92%8C%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%A2%9E%E5%8A%A0%E5%AF%86%E7%A0%81%E5%92%8C%E7%94%A8%E6%88%B7%E6%9B%B4%E6%94%B9ftp%E7%9B%AE/","summary":"\u003cdiv class=\"text\" style=\"color: #362e2b;\"\u003e\n  **1、 启动VSFTP服务器**\n\u003c/div\u003e\n\u003cp\u003e\u003cspan style=\"color: #362e2b;\"\u003eA:cenos下运行:yum  install  vsftpd\u003c/span\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eB. 登录Linux主机后，运行命令：”service vsftpd start”\n\n\n\n\n\nC. 要让FTP每次开机自动启动，运行命令:  “chkconfig \u0026amp;#8211;level 35 vsftpd on”\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e**\n\u003cdiv class=\"quote\" style=\"color: #999999;\"\u003e\n\u003c/div\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;div class=\u0026quot;text\u0026quot;\u0026gt;\n  \u0026lt;strong\u0026gt;2、设置FTP权限**\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/blockquote\u003e\n\u003cpre\u003e\u003ccode\u003e**\u0026lt;span style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;A. 编辑VSFTP配置文件，运行命令：”vi /etc/vsftpd/vsftpd.conf “\n\n\n\n\n  B. 将配置文件中”anonymous_enable=YES “改为 “anonymous_enable=NO”\n\n\n\n\n\n  C. 保存修改，按ESC键，运行命令：“：wq”\u0026lt;/span\u0026gt;\u0026lt;br style=\u0026quot;color: #362e2b;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt;\n\n\n\n\u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n  这样关闭了匿名登录功能。\n\n  \n  \u0026lt;blockquote class=\u0026quot;blockquote\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;quote\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div class=\u0026quot;text\u0026quot;\u0026gt;\n      \u0026lt;strong\u0026gt;3、添加FTP账号**\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/blockquote\u0026gt;\n  \n  \n\n    A. 登录Linux主机后，运行命令：”useradd ftpadmin -s /sbin/nologin “。该账户路径默认指向/home/ftpadmin目录；如果需要将用户指向其他目录，请运行命令：useradd ftpadmin -s /sbin/nologin –d /www(其他目录)\n  \n\n  \n  \n\n    B. 设置ftpadmin用户密码，运行命令：”passwd ftpadmin” ; 输入两次密码，匹配成功后，就设置好了ftpadmin用户的密码了。\n  \n\n  \n  \n\n    C.测试连接，您可以在“我的电脑”地址栏中输入** ftp://IP **来连接FTP服务器，根据提示输入账户密码。\u0026lt;/div\u0026gt; \n    \n    \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n      **\n        \u0026lt;div class=\u0026quot;quote\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;text\u0026quot;\u0026gt;\n          \u0026lt;strong\u0026gt;4、FTP数据传输注意事项**\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/blockquote\u0026gt;\n      \n      \n\n        A. 尽量把文件打包后上传。Linux无法识别RAR压缩包，可以使用ZIP压缩。\n      \n\n      \n      \n\n        B.上传数据时请选择二进制编码，如果选择其他编码，可能会导致上传的压缩包无法打开。\n      \n\n    \u0026lt;/div\u0026gt;\n    \n    \n\n      \n\n        \u0026lt;div class=\u0026quot;help-section\u0026quot; style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n          \n\n            以上内容是否已经解决了您的问题？\n          \n\n        \u0026lt;/div\u0026gt;\n        \n        \n\n          \u0026amp;nbsp;\n        \n\n        \n        \n\n          \n\n            FTP服务器的默认目录是/var/ftp，而且当用户以匿名方式登录的时候，访问就是此目录。如果用户以其它的用户名登录的话，访问的则是那个用户名的工作目录。如果想要更改非匿名用户的默认FTP目录，可以采用如下方式进行更改：\n          \n\n          \n          \n\n            1、进入/etc目录，打开passwd文件\n          \n\n          \n          \n\n            2、转到想要更改的那个用户的行，编辑其工作目录为想要的目录即可\n          \n\n          \n          \n\n            \n\n              \u0026lt;span style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;一般采用此种方式带来的一个影响就是，shell的提示符不会再显示目录信息，如果想要变回原来的样子，可以采用如下简便的方法：把那个用户原来的工作目录下的所有与shell配置相关的文件复制到更改后的目录。\u0026lt;/span\u0026gt;\n            \n\n            \n            \n\n              \u0026amp;nbsp;\n            \n\n            \n            \n\n              \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;最后重启服务:   service  vsftpd restart\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e","title":"Linux下添加FTP账号和服务器、增加密码和用户，更改FTP目录"},{"content":"例如你的原路径是 http://localhost/test/index.php/index/add那么现在的地址是 http://localhost/test/index/add如何去掉index.php呢?1.httpd.conf配置文件中加载了mod_rewrite.so模块 //在APACHE里面去配置#LoadModule rewrite_module modules/mod_rewrite.so把前面的警号去掉2.AllowOverride None 讲None改为 All //在APACHE里面去配置 (注意其他地方的AllowOverride也统统设置为ALL)\u0026lt;Directory “D:/server/apache/cgi-bin”\u0026gt;AllowOverride none 改 AllowOverride ALLOptions NoneOrder allow,denyAllow from all3.确保URL_MODEL设置为2，在项目的配置文件里写return Array( ‘URL_MODEL’ =\u0026gt; ‘2’,);4 .htaccess文件必须放到跟目录下这个文件里面加：RewriteEngine onRewriteCond %{REQUEST_FILENAME} !-dRewriteCond %{REQUEST_FILENAME} !-fRewriteRule ^(.*)index.php/1 [QSA,PT,L]补充：在windows下不能建立以点开头的文件，你可以先随便建立一个文件然后在DOS在操作 rename xxxx.xxxx .htaccess\n","permalink":"https://blog.zdltech.com/posts/thinkphp%E5%8E%BB%E6%8E%89url%E4%B8%ADindex-php/","summary":"\u003cp\u003e\u003cspan style=\"color: #111111;\"\u003e例如你的原路径是 http://localhost/test/index.php/index/add\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e那么现在的地址是 http://localhost/test/index/add\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e如何去掉index.php呢?\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e1.httpd.conf配置文件中加载了mod_rewrite.so模块  //在APACHE里面去配置\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e#LoadModule rewrite_module modules/mod_rewrite.so把前面的警号去掉\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e2.AllowOverride None 讲None改为 All      //在APACHE里面去配置 (注意其他地方的AllowOverride也统统设置为ALL)\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e\u0026lt;Directory “D:/server/apache/cgi-bin”\u0026gt;\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eAllowOverride none  改   AllowOverride ALL\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eOptions None\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eOrder allow,deny\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eAllow from all\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e\u003c/Directory\u003e\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e3.确保URL_MODEL设置为2，在项目的配置文件里写\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003ereturn Array(\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e   ‘URL_MODEL’ =\u0026gt; ‘2’,\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e);\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e4 .htaccess文件必须放到跟目录下\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e这个文件里面加：\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e\u003cIfModule mod_rewrite.c\u003e\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eRewriteEngine on\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eRewriteCond %{REQUEST_FILENAME} !-d\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eRewriteCond %{REQUEST_FILENAME} !-f\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eRewriteRule ^(.*)\u003cspan class=\"katex math inline\"\u003eindex.php/\u003c/span\u003e1 [QSA,PT,L]\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e\u003c/IfModule\u003e\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e补充：在windows下不能建立以点开头的文件，你可以先随便建立一个文件\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e然后在DOS在操作 rename xxxx.xxxx   .htaccess\u003c/span\u003e\u003c/p\u003e","title":"thinkphp去掉url中index.php"},{"content":"例如你的原路径是 http://localhost/test/index.php/index/add那么现在的地址是 http://localhost/test/index/add如何去掉index.php呢?1.httpd.conf配置文件中加载了mod_rewrite.so模块 //在APACHE里面去配置#LoadModule rewrite_module modules/mod_rewrite.so把前面的警号去掉2.AllowOverride None 讲None改为 All //在APACHE里面去配置 (注意其他地方的AllowOverride也统统设置为ALL)\u0026lt;Directory “D:/server/apache/cgi-bin”\u0026gt;AllowOverride none 改 AllowOverride ALLOptions NoneOrder allow,denyAllow from all3.确保URL_MODEL设置为2，在项目的配置文件里写return Array( ‘URL_MODEL’ =\u0026gt; ‘2’,);4 .htaccess文件必须放到跟目录下这个文件里面加：RewriteEngine onRewriteCond %{REQUEST_FILENAME} !-dRewriteCond %{REQUEST_FILENAME} !-fRewriteRule ^(.*)index.php/1 [QSA,PT,L]补充：在windows下不能建立以点开头的文件，你可以先随便建立一个文件然后在DOS在操作 rename xxxx.xxxx .htaccess\n","permalink":"https://blog.zdltech.com/posts/file_get_contents%E8%8E%B7%E5%8F%96https%E5%87%BA%E7%8E%B0%E8%BF%99%E4%B8%AA%E9%94%99%E8%AF%AFunable-to-find-the-wrapper-https-did/","summary":"\u003cp\u003e\u003cspan style=\"color: #111111;\"\u003e例如你的原路径是 http://localhost/test/index.php/index/add\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e那么现在的地址是 http://localhost/test/index/add\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e如何去掉index.php呢?\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e1.httpd.conf配置文件中加载了mod_rewrite.so模块  //在APACHE里面去配置\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e#LoadModule rewrite_module modules/mod_rewrite.so把前面的警号去掉\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e2.AllowOverride None 讲None改为 All      //在APACHE里面去配置 (注意其他地方的AllowOverride也统统设置为ALL)\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e\u0026lt;Directory “D:/server/apache/cgi-bin”\u0026gt;\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eAllowOverride none  改   AllowOverride ALL\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eOptions None\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eOrder allow,deny\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eAllow from all\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e\u003c/Directory\u003e\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e3.确保URL_MODEL设置为2，在项目的配置文件里写\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003ereturn Array(\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e   ‘URL_MODEL’ =\u0026gt; ‘2’,\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e);\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e4 .htaccess文件必须放到跟目录下\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e这个文件里面加：\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e\u003cIfModule mod_rewrite.c\u003e\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eRewriteEngine on\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eRewriteCond %{REQUEST_FILENAME} !-d\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eRewriteCond %{REQUEST_FILENAME} !-f\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003eRewriteRule ^(.*)\u003cspan class=\"katex math inline\"\u003eindex.php/\u003c/span\u003e1 [QSA,PT,L]\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e\u003c/IfModule\u003e\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e补充：在windows下不能建立以点开头的文件，你可以先随便建立一个文件\u003c/span\u003e\u003cbr style=\"color: #111111;\" /\u003e\u003cspan style=\"color: #111111;\"\u003e然后在DOS在操作 rename xxxx.xxxx   .htaccess\u003c/span\u003e\u003c/p\u003e","title":"file_get_contents()获取https出现这个错误Unable to find the wrapper “https” – did"},{"content":"效果图\n我这里说的是纯代码，是指的不使用图片实现圆角，图片实现圆角，这里就不说了。\n纯代码实现圆角主要有3种方法：\n第一种：CSS3圆角\n`#chaomao{` \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``border-radius:2px 2px 2px 2px;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 上面代码的意思是左上、右上、右下、右下分别2px的圆角 当然也可以简写：border-radius:2px\n方向是从左上到左下逆时针\n也可以分别指定\n`#chaomao{` \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``border-top-left-radius:4px 2px;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``border-top-right-radius:3px 4px;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``border-bottom-right-radius:6px 2px;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``border-bottom-left-radius:3px 4px;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; 意思很简明 火狐等浏览器也支持自己的私有圆角属性\nFirefox支持border-radius(圆角)：-moz-border-radius:2px\nwebkit内核的Safari和Chrome支持border-radius(圆角)：-webkit-border-radius:2px\nOpera支持border-radius(圆角)：border-radius:2px\nCSS3实现圆角最简单了，可惜IE6-8不支持\n第二种：用CSS+html代码\n百度知道的首页圆角就是用这种方法实现的\n有点：兼容所有浏览器，\n缺点：需要添加额外的HTML标签，维护比较麻烦\n实现原理是利用多个空层，上面一层比下面少1px，从而使边角看起来是一个圆弧状\nHTML代码：\n`\u0026lt;div\u0026gt;` \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;strong ``class``=``\u0026quot;b1\u0026quot;``\u0026amp;gt;\u0026amp;lt;/strong\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;strong ``class``=``\u0026quot;b2\u0026quot;``\u0026amp;gt;\u0026amp;lt;/strong\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;strong ``class``=``\u0026quot;b3\u0026quot;``\u0026amp;gt;\u0026amp;lt;/strong\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;strong ``class``=``\u0026quot;b4\u0026quot;``\u0026amp;gt;\u0026amp;lt;/strong\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; ` ``\u0026amp;lt;div ``class``=``\u0026quot;content\u0026quot;``\u0026amp;gt;文字内容\u0026amp;lt;/div\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `\u0026amp;lt;/div\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt; CSS代码 `b``1``,.b``2``,.b``3``,.b``4``,.b``5``,.b``6``,.b``7``,.b``8``{` \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; ` ``height``:``1px``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``font-size``:``1px``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ``overflow``:``hidden``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; ` ``display``:``block``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `.b``1``,.b``8``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; ` ``margin``:``` `5px``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; `.b``2``,.b``7``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; ` ``margin``:``` `3px``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; ` ``border-right``:``2px` `solid``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``border-left``:``2px` `solid``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; `.b``3``,.b``6``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``margin``:``` `2px``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``border-right``:``1px` `solid``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; ` ``border-left``:``1px` `solid``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; `.b``4``,.b``5``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; ` ``margin``:``` `1px``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; ` ``border-right``:``1px` `solid``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ``border-left``:``1px` `solid``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``height``:``2px``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; **\u0026lt;span style=\u0026quot;color: #ff0000;\u0026quot;\u0026gt;第三种：利用jQuery圆角插件代码实现圆角\u0026lt;/span\u0026gt;** 优点：兼容所有浏览器 缺点：需要使用jQuery插件 这是一个jQuery插件，使用的时候，需要jQuery文件一起，使用方法很简单 ``` $(\"#chaomao\").corner(\"5px\") ``` 它就实现了id值问哦chaomao的元素，5px的圆角 jQuery圆角插件\n\u0026amp;nbsp; jQuery.js内容 ``` /*!\njQuery corner plugin: simple corner rounding Examples and documentation at: http://jquery.malsup.com/corner/ version 2.12 (23-MAY-2011) Requires jQuery v1.3.2 or later Dual licensed under the MIT and GPL licenses: http://www.opensource.org/licenses/mit-license.php http://www.gnu.org/licenses/gpl.html Authors: Dave Methvin and Mike Alsup */ /**\ncorner() takes a single string argument: (\u0026rsquo;#myDiv\u0026rsquo;).corner(\u0026ldquo;effect corners width\u0026rdquo;) effect: name of the effect to apply, such as round, bevel, notch, bite, etc (default is round). corners: one or more of: top, bottom, tr, tl, br, or bl. (default is all corners) width: width of the effect; in the case of rounded corners this is the radius. specify this value using the px suffix such as 10px (yes, it must be pixels). */ ;(function() {\nvar style = document.createElement(\u0026lsquo;div\u0026rsquo;).style, moz = style[\u0026lsquo;MozBorderRadius\u0026rsquo;] !== undefined, webkit = style[\u0026lsquo;WebkitBorderRadius\u0026rsquo;] !== undefined, radius = style[\u0026lsquo;borderRadius\u0026rsquo;] !== undefined || style[\u0026lsquo;BorderRadius\u0026rsquo;] !== undefined, mode = document.documentMode || 0, noBottomFold = .browser.msie \u0026amp;\u0026amp; ((.browser.version \u0026lt; 8 \u0026amp;\u0026amp; !mode) || mode \u0026lt; 8),\nexpr = \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;.browser.msie \u0026amp;\u0026amp; (function() { var div = document.createElement('div'); try { div.style.setExpression('width','0+0'); div.style.removeExpression('width'); } catch(e) { return false; } return true; })();\u0026lt;/span\u0026gt;.support = \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;.support || {};\u0026lt;/span\u0026gt;.support.borderRadius = moz || webkit || radius; // so you can do: if (!\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;.support.borderRadius)\u0026lt;/span\u0026gt;('#myDiv').corner(); function sz(el, p) { return parseInt(.css(el,p))||0; }; function hex2(s) { s = parseInt(s).toString(16); return ( s.length\u0026lt;2 ) ? \u0026lsquo;0\u0026rsquo;+s : s; }; function gpc(node) { while(node) { var v =.css(node,\u0026lsquo;backgroundColor\u0026rsquo;), rgb; if (v \u0026amp;\u0026amp; v != \u0026rsquo;transparent\u0026rsquo; \u0026amp;\u0026amp; v != \u0026lsquo;rgba(0, 0, 0, 0)\u0026rsquo;) { if (v.indexOf(\u0026lsquo;rgb\u0026rsquo;) \u0026gt;= 0) { rgb = v.match(/\\d+/g); return \u0026lsquo;#\u0026rsquo;+ hex2(rgb[0]) + hex2(rgb[1]) + hex2(rgb[2]); } return v; } if (node.nodeName.toLowerCase() == \u0026lsquo;html\u0026rsquo;) break; node = node.parentNode; // keep walking if transparent } return \u0026lsquo;#ffffff\u0026rsquo;; };\nfunction getWidth(fx, i, width) { switch(fx) { case \u0026lsquo;round\u0026rsquo;: return Math.round(width*(1-Math.cos(Math.asin(i/width)))); case \u0026lsquo;cool\u0026rsquo;: return Math.round(width*(1+Math.cos(Math.asin(i/width)))); case \u0026lsquo;sharp\u0026rsquo;: return width-i; case \u0026lsquo;bite\u0026rsquo;: return Math.round(width*(Math.cos(Math.asin((width-i-1)/width)))); case \u0026lsquo;slide\u0026rsquo;: return Math.round(width*(Math.atan2(i,width/i))); case \u0026lsquo;jut\u0026rsquo;: return Math.round(width*(Math.atan2(width,(width-i-1)))); case \u0026lsquo;curl\u0026rsquo;: return Math.round(width*(Math.atan(i))); case \u0026rsquo;tear\u0026rsquo;: return Math.round(width*(Math.cos(i))); case \u0026lsquo;wicked\u0026rsquo;: return Math.round(width*(Math.tan(i))); case \u0026rsquo;long\u0026rsquo;: return Math.round(width*(Math.sqrt(i))); case \u0026lsquo;sculpt\u0026rsquo;: return Math.round(width*(Math.log((width-i-1),width))); case \u0026lsquo;dogfold\u0026rsquo;: case \u0026lsquo;dog\u0026rsquo;: return (i\u0026amp;1) ? (i+1) : width; case \u0026lsquo;dog2\u0026rsquo;: return (i\u0026amp;2) ? (i+1) : width; case \u0026lsquo;dog3\u0026rsquo;: return (i\u0026amp;3) ? (i+1) : width; case \u0026lsquo;fray\u0026rsquo;: return (i%2)*width; case \u0026rsquo;notch\u0026rsquo;: return width; case \u0026lsquo;bevelfold\u0026rsquo;: case \u0026lsquo;bevel\u0026rsquo;: return i+1; case \u0026lsquo;steep\u0026rsquo;: return i/2 + 1; case \u0026lsquo;invsteep\u0026rsquo;:return (width-i)/2+1; } };\n.fn.corner = function(options) { // in 1.3+ we can fix mistakes with the ready state if (this.length == 0) { if (!.isReady \u0026amp;\u0026amp; this.selector) { var s = this.selector, c = this.context; (function() {(s,c).corner(options); }); } return this; }\nreturn this.each(function(index){ var \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;this =\u0026lt;/span\u0026gt;(this), // meta values override options o = [\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;this.attr(\u0026lt;/span\u0026gt;.fn.corner.defaults.metaAttr) || '', options || ''].join(' ').toLowerCase(), keep = /keep/.test(o), // keep borders? cc = ((o.match(/cc:(#[0-9a-f]+)/)||[])[1]), // corner color sc = ((o.match(/sc:(#[0-9a-f]+)/)||[])[1]), // strip color width = parseInt((o.match(/(\\d+)px/)||[])[1]) || 10, // corner width re = /round|bevelfold|bevel|notch|bite|cool|sharp|slide|jut|curl|tear|fray|wicked|sculpt|long|dog3|dog2|dogfold|dog|invsteep|steep/, fx = ((o.match(re)||['round'])[0]), fold = /dogfold|bevelfold/.test(o), edges = { T:0, B:1 }, opts = { TL: /top|tl|left/.test(o), TR: /top|tr|right/.test(o), BL: /bottom|bl|left/.test(o), BR: /bottom|br|right/.test(o) }, // vars used in func later strip, pad, cssHeight, j, bot, d, ds, bw, i, w, e, c, common, \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;horz; if ( !opts.TL \u0026amp;\u0026amp; !opts.TR \u0026amp;\u0026amp; !opts.BL \u0026amp;\u0026amp; !opts.BR ) opts = { TL:1, TR:1, BL:1, BR:1 }; // support native rounding if (\u0026lt;/span\u0026gt;.fn.corner.defaults.useNative \u0026amp;\u0026amp; fx == 'round' \u0026amp;\u0026amp; (radius || moz || webkit) \u0026amp;\u0026amp; !cc \u0026amp;\u0026amp; !sc) { if (opts.TL) \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;this.css(radius ? 'border-top-left-radius' : moz ? '-moz-border-radius-topleft' : '-webkit-border-top-left-radius', width + 'px'); if (opts.TR)\u0026lt;/span\u0026gt;this.css(radius ? 'border-top-right-radius' : moz ? '-moz-border-radius-topright' : '-webkit-border-top-right-radius', width + 'px'); if (opts.BL) \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;this.css(radius ? 'border-bottom-left-radius' : moz ? '-moz-border-radius-bottomleft' : '-webkit-border-bottom-left-radius', width + 'px'); if (opts.BR)\u0026lt;/span\u0026gt;this.css(radius ? 'border-bottom-right-radius' : moz ? '-moz-border-radius-bottomright' : '-webkit-border-bottom-right-radius', width + 'px'); return; } strip = document.createElement('div'); \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;(strip).css({ overflow: 'hidden', height: '1px', minHeight: '1px', fontSize: '1px', backgroundColor: sc || 'transparent', borderStyle: 'solid' }); pad = { T: parseInt(\u0026lt;/span\u0026gt;.css(this,'paddingTop'))||0, R: parseInt(\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;.css(this,'paddingRight'))||0, B: parseInt(\u0026lt;/span\u0026gt;.css(this,'paddingBottom'))||0, L: parseInt(\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;.css(this,'paddingLeft'))||0 }; if (typeof this.style.zoom != undefined) this.style.zoom = 1; // force 'hasLayout' in IE if (!keep) this.style.border = 'none'; strip.style.borderColor = cc || gpc(this.parentNode); cssHeight =\u0026lt;/span\u0026gt;(this).outerHeight(); for (j in edges) { bot = edges[j]; // only add stips if needed if ((bot \u0026amp;\u0026amp; (opts.BL || opts.BR)) || (!bot \u0026amp;\u0026amp; (opts.TL || opts.TR))) { strip.style.borderStyle = 'none '+(opts[j+'R']?'solid':'none')+' none '+(opts[j+'L']?'solid':'none'); d = document.createElement('div'); \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;(d).addClass('jquery-corner'); ds = d.style; bot ? this.appendChild(d) : this.insertBefore(d, this.firstChild); if (bot \u0026amp;\u0026amp; cssHeight != 'auto') { if (\u0026lt;/span\u0026gt;.css(this,'position') == 'static') this.style.position = 'relative'; ds.position = 'absolute'; ds.bottom = ds.left = ds.padding = ds.margin = '0'; if (expr) ds.setExpression('width', 'this.parentNode.offsetWidth'); else ds.width = '100%'; } else if (!bot \u0026amp;\u0026amp; \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;.browser.msie) { if (\u0026lt;/span\u0026gt;.css(this,'position') == 'static') this.style.position = 'relative'; ds.position = 'absolute'; ds.top = ds.left = ds.right = ds.padding = ds.margin = '0'; // fix ie6 problem when blocked element has a border width if (expr) { bw = sz(this,'borderLeftWidth') + sz(this,'borderRightWidth'); ds.setExpression('width', 'this.parentNode.offsetWidth - '+bw+'+ \u0026quot;px\u0026quot;'); } else ds.width = '100%'; } else { ds.position = 'relative'; ds.margin = !bot ? '-'+pad.T+'px -'+pad.R+'px '+(pad.T-width)+'px -'+pad.L+'px' : (pad.B-width)+'px -'+pad.R+'px -'+pad.B+'px -'+pad.L+'px'; } for (i=0; i \u0026amp;lt; width; i++) { w = Math.max(0,getWidth(fx,i, width)); e = strip.cloneNode(false); e.style.borderWidth = '0 '+(opts[j+'R']?w:0)+'px 0 '+(opts[j+'L']?w:0)+'px'; bot ? d.appendChild(e) : d.insertBefore(e, d.firstChild); } if (fold \u0026amp;\u0026amp; \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;.support.boxModel) { if (bot \u0026amp;\u0026amp; noBottomFold) continue; for (c in opts) { if (!opts[c]) continue; if (bot \u0026amp;\u0026amp; (c == 'TL' || c == 'TR')) continue; if (!bot \u0026amp;\u0026amp; (c == 'BL' || c == 'BR')) continue; common = { position: 'absolute', border: 'none', margin: 0, padding: 0, overflow: 'hidden', backgroundColor: strip.style.borderColor };\u0026lt;/span\u0026gt;horz = \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;('\u0026amp;lt;div/\u0026amp;gt;').css(common).css({ width: width + 'px', height: '1px' }); switch(c) { case 'TL':\u0026lt;/span\u0026gt;horz.css({ bottom: 0, left: 0 }); break; case 'TR': \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;horz.css({ bottom: 0, right: 0 }); break; case 'BL':\u0026lt;/span\u0026gt;horz.css({ top: 0, left: 0 }); break; case 'BR': \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;horz.css({ top: 0, right: 0 }); break; } d.appendChild(\u0026lt;/span\u0026gt;horz[0]); var \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;vert =\u0026lt;/span\u0026gt;('\u0026amp;lt;div/\u0026amp;gt;').css(common).css({ top: 0, bottom: 0, width: '1px', height: width + 'px' }); switch(c) { case 'TL': \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;vert.css({ left: width }); break; case 'TR':\u0026lt;/span\u0026gt;vert.css({ right: width }); break; case 'BL': \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;vert.css({ left: width }); break; case 'BR':\u0026lt;/span\u0026gt;vert.css({ right: width }); break; } d.appendChild(\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;vert[0]); } } } } }); };.fn.uncorner = function() { if (radius || moz || webkit) this.css(radius ? \u0026lsquo;border-radius\u0026rsquo; : moz ? \u0026lsquo;-moz-border-radius\u0026rsquo; : \u0026lsquo;-webkit-border-radius\u0026rsquo;, 0); (\u0026lsquo;div.jquery-corner\u0026rsquo;, this).remove(); return this; };\n// expose options.fn.corner.defaults = { useNative: true, // true if plugin should attempt to use native browser support for border radius rounding metaAttr: \u0026lsquo;data-corner\u0026rsquo; // name of meta attribute to use for options };\n})(jQuery);\n\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/%E7%BA%AF%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0css%E5%9C%86%E8%A7%92/","summary":"\u003cp\u003e\u003ca href=\"http://www.etongwl.com/images/2014/09/QQ%E6%88%AA%E5%9B%BE20140911163418.png\"\u003e\u003cimg alt=\"QQ截图20140911163418\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2014/09/QQ%E6%88%AA%E5%9B%BE20140911163418.png\"\u003e\u003c/a\u003e效果图\u003c/p\u003e\n\u003cp\u003e我这里说的是纯代码，是指的不使用图片实现圆角，图片实现圆角，这里就不说了。\u003c/p\u003e\n\u003cp\u003e纯代码实现圆角主要有3种方法：\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #ff0000;\"\u003e第一种：CSS3圆角\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"snippet-container\" style=\"color: #000000;\"\u003e\n  \u003cdiv class=\"sh_ide-codewarrior snippet-wrap\"\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"cnblogs_Highlighter\"\u003e\n    \u003cdiv id=\"highlighter_950895\" class=\"syntaxhighlighter nogutter  csharp\"\u003e\n      \u003ctable border=\"0\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n        \u003ctr\u003e\n          \u003ctd class=\"code\"\u003e\n            \u003cdiv class=\"container\"\u003e\n              \u003cdiv class=\"line number1 index0 alt2\"\u003e\n                `#chaomao{`\n              \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e          \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n            `    ``border-radius:2px 2px 2px 2px;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n            `}`\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e上面代码的意思是左上、右上、右下、右下分别2px的圆角\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e当然也可以简写：border-radius:2px\u003c/p\u003e\n\u003cp\u003e方向是从左上到左下逆时针\u003c/p\u003e\n\u003cp\u003e也可以分别指定\u003c/p\u003e\n\u003cdiv class=\"snippet-container\" style=\"color: #000000;\"\u003e\n  \u003cdiv class=\"sh_ide-codewarrior snippet-wrap\"\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"cnblogs_Highlighter\"\u003e\n    \u003cdiv id=\"highlighter_635576\" class=\"syntaxhighlighter nogutter  csharp\"\u003e\n      \u003ctable border=\"0\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n        \u003ctr\u003e\n          \u003ctd class=\"code\"\u003e\n            \u003cdiv class=\"container\"\u003e\n              \u003cdiv class=\"line number1 index0 alt2\"\u003e\n                `#chaomao{`\n              \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e          \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n            `    ``border-top-left-radius:4px 2px;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n            `    ``border-top-right-radius:3px 4px;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n            `    ``border-bottom-right-radius:6px 2px;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n            `    ``border-bottom-left-radius:3px 4px;`\n          \u0026lt;/div\u0026gt;\n          \n          \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt;\n            `}`\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/td\u0026gt;\n    \u0026lt;/tr\u0026gt;\n  \u0026lt;/table\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e意思很简明\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e火狐等浏览器也支持自己的私有圆角属性\u003c/p\u003e","title":"纯代码实现CSS圆角"},{"content":".avatar-img {border-radius: 100%;width: 100%;max-width: 158px;}\n参考w3c\nhttp://www.w3school.com.cn/css3/css3_border.asp\n","permalink":"https://blog.zdltech.com/posts/css3%E5%AE%9E%E7%8E%B0%E5%9C%86%E5%BD%A2%E4%BB%A3%E7%A0%81/","summary":"\u003cp\u003e\u003cspan style=\"color: #666666;\"\u003e.avatar-img {\u003c/span\u003e\u003cbr style=\"color: #666666;\" /\u003e\u003cspan style=\"color: #666666;\"\u003eborder-radius: 100%;\u003c/span\u003e\u003cbr style=\"color: #666666;\" /\u003e\u003cspan style=\"color: #666666;\"\u003ewidth: 100%;\u003c/span\u003e\u003cbr style=\"color: #666666;\" /\u003e\u003cspan style=\"color: #666666;\"\u003emax-width: 158px;\u003c/span\u003e\u003cbr style=\"color: #666666;\" /\u003e\u003cspan style=\"color: #666666;\"\u003e}\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e参考w3c\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.w3school.com.cn/css3/css3_border.asp\"\u003ehttp://www.w3school.com.cn/css3/css3_border.asp\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.etongwl.com/images/2014/09/QQ%E6%88%AA%E5%9B%BE20140911161912.png\"\u003e\u003cimg alt=\"QQ截图20140911161912\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2014/09/QQ%E6%88%AA%E5%9B%BE20140911161912-300x241.png\"\u003e\u003c/a\u003e \u003ca href=\"http://www.etongwl.com/images/2014/09/QQ%E6%88%AA%E5%9B%BE20140911161924.png\"\u003e\u003cimg alt=\"QQ截图20140911161924\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2014/09/QQ%E6%88%AA%E5%9B%BE20140911161924-300x251.png\"\u003e\u003c/a\u003e \u003ca href=\"http://www.etongwl.com/images/2014/09/QQ%E6%88%AA%E5%9B%BE20140911161944.png\"\u003e\u003cimg alt=\"QQ截图20140911161944\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2014/09/QQ%E6%88%AA%E5%9B%BE20140911161944-300x246.png\"\u003e\u003c/a\u003e \u003ca href=\"http://www.etongwl.com/images/2014/09/QQ%E6%88%AA%E5%9B%BE20140911161953.png\"\u003e\u003cimg alt=\"QQ截图20140911161953\" loading=\"lazy\" src=\"http://www.etongwl.com/images/2014/09/QQ%E6%88%AA%E5%9B%BE20140911161953-300x214.png\"\u003e\u003c/a\u003e\u003c/p\u003e","title":"CSS3实现圆形代码"},{"content":" android:scaleType是控制图片如何resized/moved来匹对ImageView的size。 ImageView.ScaleType / android:scaleType值的意义区别： CENTER /center 按图片的原来size居中显示，当图片长/宽超过View的长/宽，则截取图片的居中部分显示 CENTER_CROP / centerCrop 按比例扩大图片的size居中显示，使得图片长(宽)等于或大于View的长(宽) CENTER_INSIDE / centerInside 将图片的内容完整居中显示，通过按比例缩小或原来的size使得图片长/宽等于或小于View的长/宽 FIT_CENTER / fitCenter 把图片按比例扩大/缩小到View的宽度，居中显示 FIT_END / fitEnd 把图片按比例扩大/缩小到View的宽度，显示在View的下部分位置 FIT_START / fitStart 把图片按比例扩大/缩小到View的宽度，显示在View的上部分位置 FIT_XY / fitXY 把图片不按比例扩大/缩小到View的大小显示 MATRIX / matrix 用矩阵来绘制，动态缩小放大图片来显示。\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt; ","permalink":"https://blog.zdltech.com/posts/imageview-scaletype-androidscaletype%E5%80%BC%E7%9A%84%E6%84%8F%E4%B9%89%E5%8C%BA%E5%88%AB/","summary":"\u003ctable style=\"color: #444444;\" cellspacing=\"0\" cellpadding=\"0\"\u003e\n  \u003ctr\u003e\n    \u003ctd id=\"postmessage_3936890\" class=\"t_f\"\u003e\n      android:scaleType是控制图片如何resized/moved来匹对ImageView的size。\n\u003cpre\u003e\u003ccode\u003e    ImageView.ScaleType / android:scaleType值的意义区别：\n  \n\n  \n  \n\n    CENTER /center  按图片的原来size居中显示，当图片长/宽超过View的长/宽，则截取图片的居中部分显示\n  \n\n  \n  \n\n    CENTER_CROP / centerCrop  按比例扩大图片的size居中显示，使得图片长(宽)等于或大于View的长(宽)\n  \n\n  \n  \n\n    CENTER_INSIDE / centerInside  将图片的内容完整居中显示，通过按比例缩小或原来的size使得图片长/宽等于或小于View的长/宽\n  \n\n  \n  \n\n    FIT_CENTER / fitCenter  把图片按比例扩大/缩小到View的宽度，居中显示\n  \n\n  \n  \n\n    FIT_END / fitEnd   把图片按比例扩大/缩小到View的宽度，显示在View的下部分位置\n  \n\n  \n  \n\n    FIT_START / fitStart  把图片按比例扩大/缩小到View的宽度，显示在View的上部分位置\n  \n\n  \n  \n\n    FIT_XY / fitXY  把图片不按比例扩大/缩小到View的大小显示\n  \n\n  \n  \n\n    MATRIX / matrix 用矩阵来绘制，动态缩小放大图片来显示。\u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/tbody\u0026gt; \u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e","title":"ImageView.ScaleType / android:scaleType值的意义区别"},{"content":" ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825091916_1.jpg) (via:[码农网](http://www.codeceo.com/article/14-communities-programmer-go.html)) 作为程序员，选择好合适的开发社区对提高自己的编程能力会有很大的帮助，我也说不出为什么，但是一些优秀的实时开发社区确实能帮你积累不少开发经验。 下面这张图列出了14个程序员经常逛的顶级开发社区，作为程序员，你应该要了解其中一个或者最好是多个，并且学会使用它们，利用里面的资源提高自己的编程能力。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825091956_1.png) **我们期望在开发者社区中获得什么？** 我们希望能得到切实的帮助，而不是获取一些唠叨的废话或者一些水文。我们希望能根据自己提出的问题来获得其他开发者的回答帮助或者讨论一些学习资源的问题。下图是一些开发者在社区中最关注的一些问题。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092021_1.png) 下面我们来看一下程序员经常去的14个顶级开发者社区，如果你还不知道它们，那么赶紧去看看，也许会有意想不到的收获。 [**Stack Overflow**](http://stackoverflow.com/) 9月份，Stack Overflow也将迎来其6岁的生日，毫无疑问，Stack Overflow是全球最受程序员欢迎的开发社区，而且也是内容最丰富的社区之一。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092045_1.png) [**Reddit**](http://www.reddit.com/r/programming) reddit也是一个非常富有个性的社区，你可以在reddit上提交一些感兴趣的话题，也可以和其他程序员讨论一些编程开发的问题和当前的IT热点资讯，reddit是一个用户粘性比较强的开放社区，编程开发板块只是其中的一小部分。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092058_1.png) [**Google+ Communities**](https://plus.google.com/communities) 加入Google+社区只需要一个Google账户即可，你可以完全免费的获取里面的资源。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092214_1.png) [**SitePoint**](http://www.sitepoint.com/forums/) SitePoint社区论坛也是我最喜欢的在线开发社区和程序员设计师家园之一，SitePoint主要目标是帮助初学者了解其选择的编程语言和技术，并且得到相应的提高，网站内容包括web开发、web设计、技术写作以及用户体验等。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092230_1.png) [**CodeProject**](http://www.codeproject.com/) 截止2013年8月，已经有100多万用户入驻codeproject，并且分享了约100多万个代码演示，在codeproject里，你可以将代码分享给你的朋友们。和其他社区不同的是，codeproject更加侧重软件开发，比如C, C#, C++, Java, Lisp等开发。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092244_1.png) [**Treehouse**](https://teamtreehouse.com/forum) 在寻找一个实惠的编程学习途径吗？你可以试试加入treehouse，它并不昂贵，年度会员还可以打折优惠。treehouse非常简单，你可以在上面找到各种等级的问题答案。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092303_1.png) [**Hacker News**](https://news.ycombinator.com/news) Hacker News这个名字已经刻在很多开发者心里了，在这里，可以实时看到编程界中发生的任何事情，包括一些学习的资源和教程。你可以从用户提交的数据中找到适合你的学习资源，比如文章、图像视频以及一些问题的讨论。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092320_1.png) [**DZone**](http://www.dzone.com/links/index.html) DZone是一个允许用户分享最新IT新闻和编程资源的社区，这是一个文章内容驱动的社区，所以需要许多内容管理员来把关文章的质量，从某种意义上说，它与HN和其他的编程社区类似，但是这个平台时间最长，里面的用户数量也是最多的。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092333_1.png) [**Bytes**](http://bytes.com/) Bytes是一个传统的开发社区，新手和专家都可以在里面讨论一些关于软件开发、数据库开发以及网络和系统管理的问题。数据库、网络以及系统是编程的基础，我们需要关注这方面的问题，从而能更好的帮助我们提高编程能力。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092347_1.png) [**DaniWeb**](http://www.daniweb.com/) DaniWeb以前是专为市场营销业务分析人员设计的，但是现在主要为各个年龄段的Web开发者和程序员服务。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092358_1.png) [**Dream In Code**](http://www.dreamincode.net/forums/) 这几年，它的更新比较缓慢了，这有好的一面也有坏的一面，60w的用户以及百万及的文章，内容涵盖 Java, C++, VB.NET等，学习资源相当丰富。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092413_1.png) [**Tech.Pro**](http://tech.pro/) Tech.pro是一个关注科技领域发展的相关资讯的社区，Tech.pro是一个获取资源和教程的入门网站，包含一些技术教程、讨论、博客已经链接等。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092424_1.png) [**Pineapple**](http://pineapple.io/) 也许这还算不上活跃的优秀开发社区，但是这里也包含很多有用的工具、教程以及类库资源等。我在几个月前开始使用Pineapple，现在已经比较依赖它了。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092439_1.png) [**Lobsters**](https://lobste.rs/) 这是一个用户邀请制的开发社区，是一个真正“面向社交”的社区，你可以在里面找到大量的关于编程的任何讨论，很多信息都至少有20多条回帖，这些信息或许对你会有很大帮助。 ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092451_1.png) ","permalink":"https://blog.zdltech.com/posts/%E7%A8%8B%E5%BA%8F%E5%91%98%E5%B8%B8%E5%8E%BB%E7%9A%8414%E4%B8%AA%E9%A1%B6%E7%BA%A7%E5%BC%80%E5%8F%91%E7%A4%BE%E5%8C%BA/","summary":"\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825091916_1.jpg)\n\u003c/div\u003e\n\u003cdiv\u003e\n  (via:[码农网](http://www.codeceo.com/article/14-communities-programmer-go.html))\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  作为程序员，选择好合适的开发社区对提高自己的编程能力会有很大的帮助，我也说不出为什么，但是一些优秀的实时开发社区确实能帮你积累不少开发经验。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  下面这张图列出了14个程序员经常逛的顶级开发社区，作为程序员，你应该要了解其中一个或者最好是多个，并且学会使用它们，利用里面的资源提高自己的编程能力。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825091956_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n  **我们期望在开发者社区中获得什么？**\n\u003c/div\u003e\n\u003cdiv\u003e\n  我们希望能得到切实的帮助，而不是获取一些唠叨的废话或者一些水文。我们希望能根据自己提出的问题来获得其他开发者的回答帮助或者讨论一些学习资源的问题。下图是一些开发者在社区中最关注的一些问题。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092021_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n  下面我们来看一下程序员经常去的14个顶级开发者社区，如果你还不知道它们，那么赶紧去看看，也许会有意想不到的收获。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003eStack Overflow\u003c/span\u003e**](http://stackoverflow.com/)\n\u003c/div\u003e\n\u003cdiv\u003e\n  9月份，Stack Overflow也将迎来其6岁的生日，毫无疑问，Stack Overflow是全球最受程序员欢迎的开发社区，而且也是内容最丰富的社区之一。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092045_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003eReddit\u003c/span\u003e**](http://www.reddit.com/r/programming)\n\u003c/div\u003e\n\u003cdiv\u003e\n  reddit也是一个非常富有个性的社区，你可以在reddit上提交一些感兴趣的话题，也可以和其他程序员讨论一些编程开发的问题和当前的IT热点资讯，reddit是一个用户粘性比较强的开放社区，编程开发板块只是其中的一小部分。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092058_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003eGoogle+ Communities\u003c/span\u003e**](https://plus.google.com/communities)\n\u003c/div\u003e\n\u003cdiv\u003e\n  加入Google+社区只需要一个Google账户即可，你可以完全免费的获取里面的资源。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092214_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003eSitePoint\u003c/span\u003e**](http://www.sitepoint.com/forums/)\n\u003c/div\u003e\n\u003cdiv\u003e\n  SitePoint社区论坛也是我最喜欢的在线开发社区和程序员设计师家园之一，SitePoint主要目标是帮助初学者了解其选择的编程语言和技术，并且得到相应的提高，网站内容包括web开发、web设计、技术写作以及用户体验等。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092230_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003eCodeProject\u003c/span\u003e**](http://www.codeproject.com/)\n\u003c/div\u003e\n\u003cdiv\u003e\n  截止2013年8月，已经有100多万用户入驻codeproject，并且分享了约100多万个代码演示，在codeproject里，你可以将代码分享给你的朋友们。和其他社区不同的是，codeproject更加侧重软件开发，比如C, C#, C++, Java, Lisp等开发。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092244_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003eTreehouse\u003c/span\u003e**](https://teamtreehouse.com/forum)\n\u003c/div\u003e\n\u003cdiv\u003e\n  在寻找一个实惠的编程学习途径吗？你可以试试加入treehouse，它并不昂贵，年度会员还可以打折优惠。treehouse非常简单，你可以在上面找到各种等级的问题答案。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092303_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003eHacker News\u003c/span\u003e**](https://news.ycombinator.com/news)\n\u003c/div\u003e\n\u003cdiv\u003e\n  Hacker News这个名字已经刻在很多开发者心里了，在这里，可以实时看到编程界中发生的任何事情，包括一些学习的资源和教程。你可以从用户提交的数据中找到适合你的学习资源，比如文章、图像视频以及一些问题的讨论。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092320_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003eDZone\u003c/span\u003e**](http://www.dzone.com/links/index.html)\n\u003c/div\u003e\n\u003cdiv\u003e\n  DZone是一个允许用户分享最新IT新闻和编程资源的社区，这是一个文章内容驱动的社区，所以需要许多内容管理员来把关文章的质量，从某种意义上说，它与HN和其他的编程社区类似，但是这个平台时间最长，里面的用户数量也是最多的。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092333_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003eBytes\u003c/span\u003e**](http://bytes.com/)\n\u003c/div\u003e\n\u003cdiv\u003e\n  Bytes是一个传统的开发社区，新手和专家都可以在里面讨论一些关于软件开发、数据库开发以及网络和系统管理的问题。数据库、网络以及系统是编程的基础，我们需要关注这方面的问题，从而能更好的帮助我们提高编程能力。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092347_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003eDaniWeb\u003c/span\u003e**](http://www.daniweb.com/)\n\u003c/div\u003e\n\u003cdiv\u003e\n  DaniWeb以前是专为市场营销业务分析人员设计的，但是现在主要为各个年龄段的Web开发者和程序员服务。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092358_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003eDream In Code\u003c/span\u003e**](http://www.dreamincode.net/forums/)\n\u003c/div\u003e\n\u003cdiv\u003e\n  这几年，它的更新比较缓慢了，这有好的一面也有坏的一面，60w的用户以及百万及的文章，内容涵盖 Java, C++, VB.NET等，学习资源相当丰富。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092413_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003eTech.Pro\u003c/span\u003e**](http://tech.pro/)\n\u003c/div\u003e\n\u003cdiv\u003e\n  Tech.pro是一个关注科技领域发展的相关资讯的社区，Tech.pro是一个获取资源和教程的入门网站，包含一些技术教程、讨论、博客已经链接等。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092424_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003ePineapple\u003c/span\u003e**](http://pineapple.io/)\n\u003c/div\u003e\n\u003cdiv\u003e\n  也许这还算不上活跃的优秀开发社区，但是这里也包含很多有用的工具、教程以及类库资源等。我在几个月前开始使用Pineapple，现在已经比较依赖它了。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092439_1.png)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  [**\u003cspan style=\"color: #0000ff;\"\u003eLobsters\u003c/span\u003e**](https://lobste.rs/)\n\u003c/div\u003e\n\u003cdiv\u003e\n  这是一个用户邀请制的开发社区，是一个真正“面向社交”的社区，你可以在里面找到大量的关于编程的任何讨论，很多信息都至少有20多条回帖，这些信息或许对你会有很大帮助。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://www.cocoachina.com/cms/uploads/allimg/140825/4196_140825092451_1.png)\n\u003c/div\u003e","title":"程序员常去的14个顶级开发社区"},{"content":" Wechat-PHP-SDK 微信公众平台 PHP 开发包，细化各项接口操作，支持链式调用。\nGithub托管地址：dodgepudding/wechat-php-sdk\n微信公众平台 PHP SDK 简单的微信公众平台 PHP SDK ，通过调用相应的接口，使你可以轻松地开发微信 App 。\nGithub托管地址：netputer/wechat-php-sdk\nWechat-php 本微信SDK实现了被动响应的官方 API 已经主动发送消息给订阅用户，主动批量发送消息给订阅用户。\nGithub托管地址：ligboy/Wechat-php\n非常强大的微信公众平台开发框架推荐中有官方和第三方开发者提供的丰富的插件，是免费并且成熟的框架，更多的信息可以点击这里：\n微擎：http://www.we7.cc/\n微笑：http://www.sylai.com/\nweiphp：http://www.weiphp.cn/\n","permalink":"https://blog.zdltech.com/posts/%E5%BE%AE%E4%BF%A1%E5%BC%80%E5%8F%91%E5%80%BC%E5%BE%97%E6%8E%A8%E8%8D%90%E7%9A%84%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/","summary":"\u003col\u003e\n\u003cli\u003eWechat-PHP-SDK\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e微信公众平台 PHP 开发包，细化各项接口操作，支持链式调用。\u003c/p\u003e\n\u003cp\u003eGithub托管地址：dodgepudding/wechat-php-sdk\u003c/p\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e微信公众平台 PHP SDK\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e简单的微信公众平台 PHP SDK ，通过调用相应的接口，使你可以轻松地开发微信 App 。\u003c/p\u003e\n\u003cp\u003eGithub托管地址：netputer/wechat-php-sdk\u003c/p\u003e\n\u003col start=\"3\"\u003e\n\u003cli\u003eWechat-php\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e本微信SDK实现了被动响应的官方 API 已经主动发送消息给订阅用户，主动批量发送消息给订阅用户。\u003c/p\u003e\n\u003cp\u003eGithub托管地址：ligboy/Wechat-php\u003c/p\u003e\n\u003cp\u003e非常强大的微信公众平台开发框架推荐中有官方和第三方开发者提供的丰富的插件，是免费并且成熟的框架，更多的信息可以点击这里：\u003c/p\u003e\n\u003cp\u003e微擎：http://www.we7.cc/\u003cbr\u003e\n微笑：http://www.sylai.com/\u003cbr\u003e\nweiphp：http://www.weiphp.cn/\u003c/p\u003e","title":"微信开发值得推荐的开源项目"},{"content":"1、AlarmManager，顾名思义，就是“提醒”，是Android中常用的一种系统级别的提示服务，可以实现从指定时间开始，以一个固定的间隔时间执行某项操作，所以常常与广播（Broadcast）连用，实现闹钟等提示功能\n2、AlarmManager的常用方法有三个：\n（1）set(int type，long startTime，PendingIntent pi)；\n该方法用于设置一次性闹钟，第一个参数表示闹钟类型，第二个参数表示闹钟执行时间，第三个参数表示闹钟响应动作。\n（2）setRepeating(int type，long startTime，long intervalTime，PendingIntent pi)；\n该方法用于设置重复闹钟，第一个参数表示闹钟类型，第二个参数表示闹钟首次执行时间，第三个参数表示闹钟两次执行的间隔时间，第三个参数表示闹钟响应动作。\n（3）setInexactRepeating（int type，long startTime，long intervalTime，PendingIntent pi）；\n该方法也用于设置重复闹钟，与第二个方法相似，不过其两个闹钟执行的间隔时间不是固定的而已。\n3、三个方法各个参数详悉：\n（1）int type：闹钟的类型，常用的有5个值：AlarmManager.ELAPSED_REALTIME、AlarmManager.ELAPSED_REALTIME_WAKEUP、AlarmManager.RTC、AlarmManager.RTC_WAKEUP、AlarmManager.POWER_OFF_WAKEUP。\nAlarmManager.ELAPSED_REALTIME表示闹钟在手机睡眠状态下不可用，该状态下闹钟使用相对时间（相对于系统启动开始），状态值为3；\nAlarmManager.ELAPSED_REALTIME_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能，该状态下闹钟也使用相对时间，状态值为2；\nAlarmManager.RTC表示闹钟在睡眠状态下不可用，该状态下闹钟使用绝对时间，即当前系统时间，状态值为1；\nAlarmManager.RTC_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能，该状态下闹钟使用绝对时间，状态值为0；\nAlarmManager.POWER_OFF_WAKEUP表示闹钟在手机关机状态下也能正常进行提示功能，所以是5个状态中用的最多的状态之一，该状态下闹钟也是用绝对时间，状态值为4；不过本状态好像受SDK版本影响，某些版本并不支持；\n（2）long startTime：闹钟的第一次执行时间，以毫秒为单位，可以自定义时间，不过一般使用当前时间。需要注意的是，本属性与第一个属性（type）密切相关，如果第一个参数对应的闹钟使用的是相对时间（ELAPSED_REALTIME和ELAPSED_REALTIME_WAKEUP），那么本属性就得使用相对时间（相对于系统启动时间来说），比如当前时间就表示为：SystemClock.elapsedRealtime()；如果第一个参数对应的闹钟使用的是绝对时间（RTC、RTC_WAKEUP、POWER_OFF_WAKEUP），那么本属性就得使用绝对时间，比如当前时间就表示为：System.currentTimeMillis()。\n（3）long intervalTime：对于后两个方法来说，存在本属性，表示两次闹钟执行的间隔时间，也是以毫秒为单位。\n（4）PendingIntent pi：是闹钟的执行动作，比如发送一个广播、给出提示等等。PendingIntent是Intent的封装类。需要注意的是，如果是通过启动服务来实现闹钟提示的话，PendingIntent对象的获取就应该采用Pending.getService(Context c,int i,Intent intent,int j)方法；如果是通过广播来实现闹钟提示的话，PendingIntent对象的获取就应该采用PendingIntent.getBroadcast(Context c,int i,Intent intent,int j)方法；如果是采用Activity的方式来实现闹钟提示的话，PendingIntent对象的获取就应该采用PendingIntent.getActivity(Context c,int i,Intent intent,int j)方法。如果这三种方法错用了的话，虽然不会报错，但是看不到闹钟提示效果。\n4、 AlarmManager使用示例：利用用户自定义广播实现闹钟功能，从当前时间开始，每隔10分钟提示一次\n（1）实现原理：在SendActivity.java中定义一个AlarmManager对象，指定该对象从当前时间开始，每隔10分钟向名为“MYALARMRECEIVER”的广播接收器发出一条广播，附加消息内容为“你该打酱油了”；创建一个名为MyReceiver的广播接收器，在其onReceive方法中获取Intent对象传过来的值（“你该打酱油了”）并用一个Toast组件显示出来；在AndroidManifest.xml文件中注册SendActivity类和广播接收器类MyReceiver，设置MyReceiver的action的值为“MYALARMRECEIVER”\n（2）代码实现：\n第一步：创建广播接收类MyReceiver.java，在其onReceive方法中获取Intent的附加信息msg，并用Toast组件显示\n**[java]** [view plain](http://blog.csdn.net/jeethongfei/article/details/6767826#)[copy](http://blog.csdn.net/jeethongfei/article/details/6767826#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onReceive(Context context,Intent intent){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; String msg = intent.getStringExtra(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;msg\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Toast.makeText(context,msg,Toast.LENGTH_SHORT).show(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; **\u0026lt;span style=\u0026quot;color: #1f7099;\u0026quot;\u0026gt;第二步：在AndroidManifest.xml中注册广播接收类MyReceiver.java，设置其action值为“MYALARMRECEIVER”\u0026lt;/span\u0026gt;** \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/jeethongfei/article/details/6767826#)[copy](http://blog.csdn.net/jeethongfei/article/details/6767826#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;receiver android:name=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;.MyReceiver\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;intent-filter\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;action android:name=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MYALARMRECEIVER\u0026amp;#8221;\u0026lt;/span\u0026gt; /\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/intent-filter\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/receiver\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; **\u0026lt;span style=\u0026quot;color: #1f7099;\u0026quot;\u0026gt;第三步：创建SendActivity.java，用于设置闹钟，定时发出广播\u0026lt;/span\u0026gt;** \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/jeethongfei/article/details/6767826#)[copy](http://blog.csdn.net/jeethongfei/article/details/6767826#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//创建Intent对象，action指向广播接收类，附加信息为字符串“你该打酱油了”\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;Intent intent = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MYALARMRECEIVER\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;intent.putExtra(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;msg\u0026amp;#8221;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;你该打酱油了\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//创建PendingIntent对象封装Intent，由于是使用广播，注意使用getBroadcast方法\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;PendingIntent pi = PendingIntent.getBroadcast(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;,intent,\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//获取AlarmManager对象\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//设置闹钟从当前时间开始，每隔10分钟执行一次PendingIntent对象，注意第一个参数与第二个参数的关系\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;am.setRepeating(AlarmManager.RTC_WAKEUP,System.currentMillis(),\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;600\u0026lt;/span\u0026gt;*\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1000\u0026lt;/span\u0026gt;,pi); \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; **\u0026lt;span style=\u0026quot;color: #1f7099;\u0026quot;\u0026gt;第四步：在AndroidManifest中为SendActivity.java注册\u0026lt;/span\u0026gt;** \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/jeethongfei/article/details/6767826#)[copy](http://blog.csdn.net/jeethongfei/article/details/6767826#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;activity android:name=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;.SendActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; /\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/alarmmanager%E7%B1%BB%E7%9A%84%E5%BA%94%E7%94%A8%E5%AE%9E%E7%8E%B0%E9%97%B9%E9%92%9F%E5%8A%9F%E8%83%BD/","summary":"\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003e1、AlarmManager，顾名思义，就是“提醒”，是Android中常用的一种系统级别的提示服务，可以实现从指定时间开始，以一个固定的间隔时间执行某项操作，所以常常与广播（Broadcast）连用，实现闹钟等提示功能\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003e2、AlarmManager的常用方法有三个：\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003e（1）\u003cspan style=\"color: #0f9932;\"\u003eset(int type，long startTime，PendingIntent pi)\u003c/span\u003e；\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003e该方法用于设置一次性闹钟，第一个参数表示闹钟类型，第二个参数表示闹钟执行时间，第三个参数表示闹钟响应动作。\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003e（2）\u003cspan style=\"color: #0f9932;\"\u003esetRepeating(int type，long startTime，long intervalTime，PendingIntent pi)；\u003c/span\u003e\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003e该方法用于设置重复闹钟，第一个参数表示闹钟类型，第二个参数表示闹钟首次执行时间，第三个参数表示闹钟两次执行的间隔时间，第三个参数表示闹钟响应动作。\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003e（3）\u003cspan style=\"color: #0f9932;\"\u003esetInexactRepeating（int type，long startTime，long intervalTime，PendingIntent pi）；\u003c/span\u003e\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003e该方法也用于设置重复闹钟，与第二个方法相似，不过其两个闹钟执行的间隔时间不是固定的而已。\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003e3、三个方法各个参数详悉：\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003e（1）\u003cspan style=\"color: #0f9932;\"\u003eint type\u003c/span\u003e：闹钟的类型，常用的有5个值：AlarmManager.ELAPSED_REALTIME、AlarmManager.ELAPSED_REALTIME_WAKEUP、AlarmManager.RTC、AlarmManager.RTC_WAKEUP、AlarmManager.POWER_OFF_WAKEUP。\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003eAlarmManager.ELAPSED_REALTIME表示闹钟在手机睡眠状态下不可用，该状态下闹钟使用相对时间（相对于系统启动开始），状态值为3；\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003eAlarmManager.ELAPSED_REALTIME_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能，该状态下闹钟也使用相对时间，状态值为2；\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003eAlarmManager.RTC表示闹钟在睡眠状态下不可用，该状态下闹钟使用绝对时间，即当前系统时间，状态值为1；\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003eAlarmManager.RTC_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能，该状态下闹钟使用绝对时间，状态值为0；\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003eAlarmManager.POWER_OFF_WAKEUP表示闹钟在手机关机状态下也能正常进行提示功能，所以是5个状态中用的最多的状态之一，该状态下闹钟也是用绝对时间，状态值为4；不过本状态好像受SDK版本影响，某些版本并不支持；\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003e（2）\u003cspan style=\"color: #0f9932;\"\u003elong startTime\u003c/span\u003e：闹钟的第一次执行时间，以毫秒为单位，可以自定义时间，不过一般使用当前时间。需要注意的是，本属性与第一个属性（type）密切相关，如果第一个参数对应的闹钟使用的是相对时间（ELAPSED_REALTIME和ELAPSED_REALTIME_WAKEUP），那么本属性就得使用相对时间（相对于系统启动时间来说），比如当前时间就表示为：SystemClock.elapsedRealtime()；如果第一个参数对应的闹钟使用的是绝对时间（RTC、RTC_WAKEUP、POWER_OFF_WAKEUP），那么本属性就得使用绝对时间，比如当前时间就表示为：System.currentTimeMillis()。\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003e（3）\u003cspan style=\"color: #0f9932;\"\u003elong intervalTime\u003c/span\u003e：对于后两个方法来说，存在本属性，表示两次闹钟执行的间隔时间，也是以毫秒为单位。\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cspan style=\"color: #1f7099;\"\u003e（4）\u003cspan style=\"color: #0f9932;\"\u003ePendingIntent pi\u003c/span\u003e：是闹钟的执行动作，比如发送一个广播、给出提示等等。PendingIntent是Intent的封装类。需要注意的是，如果是通过启动服务来实现闹钟提示的话，PendingIntent对象的获取就应该采用Pending.getService(Context c,int i,Intent intent,int j)方法；如果是通过广播来实现闹钟提示的话，PendingIntent对象的获取就应该采用PendingIntent.getBroadcast(Context c,int i,Intent intent,int j)方法；如果是采用Activity的方式来实现闹钟提示的话，PendingIntent对象的获取就应该采用PendingIntent.getActivity(Context c,int i,Intent intent,int j)方法。如果这三种方法错用了的话，虽然不会报错，但是看不到闹钟提示效果。\u003c/span\u003e\u003c/strong\u003e\u003c/p\u003e","title":"AlarmManager类的应用（实现闹钟功能）"},{"content":"由于前面的博文中忽略了点内容，所以在这里补上，下面内容就是解决拍照或者选择图片显示的时候图片旋转了90度或者其他度数问题，以便照片可以正面显示：具体如下：\n首先直接看上面博文下的拍完照或者选完图后处理部分： \u0026lt;div id=\u0026quot;\u0026quot; class=\u0026quot;dp-highlighter\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt; Java代码 \u0026lt;a style=\u0026quot;color: #108ac6;\u0026quot; title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://104zz.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onActivityResult(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; requestCode, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; resultCode, Intent data) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (resultCode) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (data != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 取得返回的Uri,基本上选择照片的时候返回的是以Uri形式，但是在拍照中有得机子呢Uri是空的，所以要特别注意\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Uri mImageCaptureUri = data.getData(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 返回的Uri不为空时，那么图片信息数据都会在Uri中获得。如果为空，那么我们就进行下面的方式获取\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mImageCaptureUri != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setImage(mImageCaptureUri);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 根据Uri处理并显示图片\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 第二：处理90度问题并显示： \u0026lt;div id=\u0026quot;\u0026quot; class=\u0026quot;dp-highlighter\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt; Java代码 \u0026lt;a style=\u0026quot;color: #108ac6;\u0026quot; title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://104zz.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setImage(Uri mImageCaptureUri) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 不管是拍照还是选择图片每张图片都有在数据中存储也存储有对应旋转角度orientation值\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 所以我们在取出图片是把角度值取出以便能正确的显示图片,没有旋转时的效果观看\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ContentResolver cr = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getContentResolver(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Cursor cursor = cr.query(mImageCaptureUri, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 根据Uri从数据库中找\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (cursor != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; cursor.moveToFirst();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 把游标移动到首位，因为这里的Uri是包含ID的所以是唯一的不需要循环找指向第一个就是了\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; String filePath = cursor.getString(cursor.getColumnIndex(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;_data\u0026amp;#8221;\u0026lt;/span\u0026gt;));\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 获取图片路\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; String orientation = cursor.getString(cursor \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .getColumnIndex(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;orientation\u0026amp;#8221;\u0026lt;/span\u0026gt;));\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 获取旋转的角度\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; cursor.close(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (filePath != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Bitmap bitmap = BitmapFactory.decodeFile(filePath);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//根据Path读取资源图片\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; angle = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (orientation != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; !\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;.equals(orientation)) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; angle = Integer.parseInt(orientation); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (angle != \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 下面的方法主要作用是把图片转一个角度，也可以放大缩小等\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Matrix m = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Matrix(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width = bitmap.getWidth(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height = bitmap.getHeight(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; m.setRotate(angle); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 旋转angle度\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; bitmap = Bitmap.createBitmap(bitmap, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, width, height, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; m, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 从新生成图片\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; photo.setImageBitmap(bitmap); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; OK完成\u0026lt;/span\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-%E9%80%89%E6%8B%A9%E5%9B%BE%E7%89%87%E6%88%96%E6%8B%8D%E7%85%A7%E6%97%B6%E6%97%8B%E8%BD%AC%E4%BA%8690%E5%BA%A6%E9%97%AE%E9%A2%98/","summary":"\u003cp\u003e由于前面的博文中忽略了点内容，所以在这里补上，下面内容就是解决拍照或者选择图片显示的时候图片旋转了90度或者其他度数问题，以便照片可以正面显示：具体如下：\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e首先直接看上面博文下的拍完照或者选完图后处理部分：\n\n\n\n\n\n\u0026lt;div id=\u0026quot;\u0026quot; class=\u0026quot;dp-highlighter\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;\n      Java代码  \u0026lt;a style=\u0026quot;color: #108ac6;\u0026quot; title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://104zz.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onActivityResult(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; requestCode, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; resultCode, Intent data) {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (resultCode) {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;:  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (data != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 取得返回的Uri,基本上选择照片的时候返回的是以Uri形式，但是在拍照中有得机子呢Uri是空的，所以要特别注意\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                Uri mImageCaptureUri = data.getData();  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 返回的Uri不为空时，那么图片信息数据都会在Uri中获得。如果为空，那么我们就进行下面的方式获取\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mImageCaptureUri != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    setImage(mImageCaptureUri);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 根据Uri处理并显示图片\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                }  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;:  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n    \n  \n\u0026lt;/div\u0026gt;\n\n\n\n   第二：处理90度问题并显示：\n\n\n\n\n\n  \u0026lt;div id=\u0026quot;\u0026quot; class=\u0026quot;dp-highlighter\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;font-weight: bold;\u0026quot;\u0026gt;\n        Java代码  \u0026lt;a style=\u0026quot;color: #108ac6;\u0026quot; title=\u0026quot;收藏这段代码\u0026quot;\u0026gt;![收藏代码](http://104zz.iteye.com/images/icon_star.png)\u0026lt;/a\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setImage(Uri mImageCaptureUri) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 不管是拍照还是选择图片每张图片都有在数据中存储也存储有对应旋转角度orientation值\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 所以我们在取出图片是把角度值取出以便能正确的显示图片,没有旋转时的效果观看\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    ContentResolver cr = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getContentResolver();  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    Cursor cursor = cr.query(mImageCaptureUri, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 根据Uri从数据库中找\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (cursor != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        cursor.moveToFirst();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 把游标移动到首位，因为这里的Uri是包含ID的所以是唯一的不需要循环找指向第一个就是了\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        String filePath = cursor.getString(cursor.getColumnIndex(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;_data\u0026amp;#8221;\u0026lt;/span\u0026gt;));\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 获取图片路\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        String orientation = cursor.getString(cursor  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                .getColumnIndex(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;orientation\u0026amp;#8221;\u0026lt;/span\u0026gt;));\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 获取旋转的角度\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        cursor.close();  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (filePath != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            Bitmap bitmap = BitmapFactory.decodeFile(filePath);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//根据Path读取资源图片\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; angle = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (orientation != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; !\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;\u0026amp;#8221;\u0026lt;/span\u0026gt;.equals(orientation)) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                angle = Integer.parseInt(orientation);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (angle != \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 下面的方法主要作用是把图片转一个角度，也可以放大缩小等\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                Matrix m = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Matrix();  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width = bitmap.getWidth();  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height = bitmap.getHeight();  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                m.setRotate(angle); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 旋转angle度\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                bitmap = Bitmap.createBitmap(bitmap, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, width, height,  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        m, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #7f0055;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 从新生成图片\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            photo.setImageBitmap(bitmap);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n      \n    \n  \u0026lt;/div\u0026gt;\n  \n  \n\n    \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; OK完成\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e","title":"android 选择图片或拍照时旋转了90度问题"},{"content":"大家好，这是一个简单的拍照功能，很简单的界面，一个显示图像区域SurfaceView一个“拍照”按钮。直接上代码！\n1、CameraDemoActivity.java（主界面）\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.winplus.camera; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.File; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.FileOutputStream; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.IOException; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Date; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.pm.ActivityInfo; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.PixelFormat; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.hardware.Camera; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.AsyncTask; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Environment; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.text.format.DateFormat; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.KeyEvent; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.SurfaceHolder; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.SurfaceView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Button; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; CameraDemoActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;CameraActivity\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; SurfaceView surfaceView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; SurfaceHolder surfaceHolder; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Camera camera; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; File picture; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Button btnSave; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.requestWindowFeature(Window.FEATURE_NO_TITLE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setContentView(R.layout.main); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setupViews(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setupViews(){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; surfaceView = (SurfaceView) findViewById(R.id.camera_preview); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Camera interface to instantiate components\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; surfaceHolder = surfaceView.getHolder(); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Camera interface to instantiate components\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; surfaceHolder.addCallback(surfaceCallback); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Add a callback for the SurfaceHolder\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; btnSave = (Button) findViewById(R.id.save_pic); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; btnSave.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; takePic(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onKeyDown(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; keyCode, KeyEvent event) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (keyCode == KeyEvent.KEYCODE_CAMERA \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; || keyCode == KeyEvent.KEYCODE_SEARCH) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; takePic(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onKeyDown(keyCode, event); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; takePic() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; camera.stopPreview();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// stop the preview\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; camera.takePicture(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, pictureCallback); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// picture\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Photo call back\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Camera.PictureCallback pictureCallback = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Camera.PictureCallback() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;//@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onPictureTaken(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;byte\u0026lt;/span\u0026gt;[] data, Camera camera) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SavePictureTask().execute(data); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; camera.startPreview(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// save pic\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SavePictureTask \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; AsyncTask\u0026lt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;byte\u0026lt;/span\u0026gt;[], String, String\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; String doInBackground(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;byte\u0026lt;/span\u0026gt;[]\u0026amp;#8230; params) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; String fname = DateFormat.format(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;yyyyMMddhhmmss\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Date()).toString()+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;.jpg\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;fname=\u0026amp;#8221;\u0026lt;/span\u0026gt;+fname+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;;dir=\u0026amp;#8221;\u0026lt;/span\u0026gt;+Environment.getExternalStorageDirectory()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;//picture = new File(Environment.getExternalStorageDirectory(),fname);// create file\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; picture = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; File(Environment.getExternalStorageDirectory()+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;/\u0026amp;#8221;\u0026lt;/span\u0026gt;+fname); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; FileOutputStream fos = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; FileOutputStream(picture.getPath()); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Get file output stream\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; fos.write(params[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Written to the file\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; fos.close(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; e.printStackTrace(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// SurfaceHodler Callback handle to open the camera, off camera and photo size changes\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; SurfaceHolder.Callback surfaceCallback = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SurfaceHolder.Callback() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; surfaceCreated(SurfaceHolder holder) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;surfaceCallback====\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; camera = Camera.open(); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Turn on the camera\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; camera.setPreviewDisplay(holder); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Set Preview\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; camera.release();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// release camera\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; camera = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; surfaceChanged(SurfaceHolder holder, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; format, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;====surfaceChanged\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Camera.Parameters parameters = camera.getParameters(); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Camera parameters to obtain\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; parameters.setPictureFormat(PixelFormat.JPEG);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Setting Picture Format\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// parameters.set(\u0026amp;#8220;rotation\u0026amp;#8221;, 180); // Arbitrary rotation\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; camera.setDisplayOrientation(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// parameters.setPreviewSize(400, 300); // Set Photo Size\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; camera.setParameters(parameters); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Setting camera parameters\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; camera.startPreview(); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Start Preview\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; surfaceDestroyed(SurfaceHolder holder) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;====surfaceDestroyed\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; camera.stopPreview();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// stop preview\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; camera.release(); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Release camera resources\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; camera = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;2、main.xml（布局文件）\u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;android.view.SurfaceView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/camera_preview\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;800dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;600dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_alignParentTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_centerInParent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;center_vertical|center_horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/save_pic\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@string/txt_save\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;br style=\u0026quot;color: #362e2b;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;3、别忘了添加权限：\u0026lt;/span\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot; style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;uses-permission\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.permission.CAMERA\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;uses-feature\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.hardware.camera\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;uses-feature\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.hardware.camera.autofocus\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:required\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot; style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; [源码下载==》](http://download.csdn.net/detail/tangcheng_ok/3874071) 原创文章，转载请注明出处：http://www.blog.csdn.net/tangcheng_ok ","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E5%8F%91%E4%B9%8B%E6%8B%8D%E7%85%A7%E5%8A%9F%E8%83%BD%E5%AE%9E%E7%8E%B0%E9%99%84%E6%BA%90%E7%A0%81/","summary":"\u003cp\u003e大家好，这是一个简单的拍照功能，很简单的界面，一个显示图像区域SurfaceView一个“拍照”按钮。直接上代码！\u003c/p\u003e\n\u003cp\u003e1、CameraDemoActivity.java（主界面）\u003c/p\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\" style=\"color: #362e2b;\"\u003e\n\u003cpre\u003e\u003ccode\u003e  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.winplus.camera;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.File;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.FileOutputStream;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.IOException;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Date;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.pm.ActivityInfo;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.PixelFormat;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.hardware.Camera;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.AsyncTask;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Environment;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.text.format.DateFormat;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.KeyEvent;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.SurfaceHolder;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.SurfaceView;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Window;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View.OnClickListener;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Button;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; CameraDemoActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity{  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String TAG = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;CameraActivity\u0026amp;#8221;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; SurfaceView surfaceView;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; SurfaceHolder surfaceHolder;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Camera camera;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; File picture;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Button btnSave;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.requestWindowFeature(Window.FEATURE_NO_TITLE);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        setContentView(R.layout.main);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        setupViews();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setupViews(){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        surfaceView = (SurfaceView) findViewById(R.id.camera_preview); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Camera interface to instantiate components\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        surfaceHolder = surfaceView.getHolder(); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Camera interface to instantiate components\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        surfaceHolder.addCallback(surfaceCallback); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Add a callback for the SurfaceHolder\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        btnSave = (Button) findViewById(R.id.save_pic);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        btnSave.setOnClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnClickListener() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;              \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onClick(View v) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                takePic();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        });  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onKeyDown(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; keyCode, KeyEvent event) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (keyCode == KeyEvent.KEYCODE_CAMERA  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                || keyCode == KeyEvent.KEYCODE_SEARCH) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            takePic();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onKeyDown(keyCode, event);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; takePic() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        camera.stopPreview();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// stop the preview\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        camera.takePicture(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;, pictureCallback); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// picture\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Photo call back\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    Camera.PictureCallback pictureCallback = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Camera.PictureCallback() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;//@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onPictureTaken(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;byte\u0026lt;/span\u0026gt;[] data, Camera camera) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SavePictureTask().execute(data);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            camera.startPreview();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    };  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// save pic\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SavePictureTask \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; AsyncTask\u0026lt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;byte\u0026lt;/span\u0026gt;[], String, String\u0026gt; {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; String doInBackground(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;byte\u0026lt;/span\u0026gt;[]\u0026amp;#8230; params) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            String fname = DateFormat.format(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;yyyyMMddhhmmss\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Date()).toString()+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;.jpg\u0026amp;#8221;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;              \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;fname=\u0026amp;#8221;\u0026lt;/span\u0026gt;+fname+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;;dir=\u0026amp;#8221;\u0026lt;/span\u0026gt;+Environment.getExternalStorageDirectory());  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;//picture = new File(Environment.getExternalStorageDirectory(),fname);// create file\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;              \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            picture = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; File(Environment.getExternalStorageDirectory()+\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;/\u0026amp;#8221;\u0026lt;/span\u0026gt;+fname);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;              \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                FileOutputStream fos = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; FileOutputStream(picture.getPath()); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Get file output stream\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                fos.write(params[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Written to the file\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                fos.close();   \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                e.printStackTrace();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// SurfaceHodler Callback handle to open the camera, off camera and photo size changes\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    SurfaceHolder.Callback surfaceCallback = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SurfaceHolder.Callback() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; surfaceCreated(SurfaceHolder holder) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            Log.i(TAG, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;surfaceCallback====\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            camera = Camera.open(); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Turn on the camera\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                camera.setPreviewDisplay(holder); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Set Preview\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (IOException e) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                camera.release();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// release camera\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                camera = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; surfaceChanged(SurfaceHolder holder, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; format, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width,  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;====surfaceChanged\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            Camera.Parameters parameters = camera.getParameters(); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Camera parameters to obtain\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            parameters.setPictureFormat(PixelFormat.JPEG);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Setting Picture Format\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;//          parameters.set(\u0026amp;#8220;rotation\u0026amp;#8221;, 180); // Arbitrary rotation\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            camera.setDisplayOrientation(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;//          parameters.setPreviewSize(400, 300); // Set Photo Size\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            camera.setParameters(parameters); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Setting camera parameters\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            camera.startPreview(); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Start Preview\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; surfaceDestroyed(SurfaceHolder holder) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            Log.i(TAG,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #009900;\u0026quot;\u0026gt;\u0026amp;#8220;====surfaceDestroyed\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            camera.stopPreview();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// stop preview\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            camera.release(); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #999999;\u0026quot;\u0026gt;// Release camera resources\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            camera = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #0000ff;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    };  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;2、main.xml（布局文件）\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\" style=\"color: #362e2b;\"\u003e\n\u003cpre\u003e\u003ccode\u003e  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;android.view.SurfaceView\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/camera_preview\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;800dip\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;600dip\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_alignParentTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_centerInParent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;center_vertical|center_horizontal\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;Button\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/save_pic\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fill_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:text\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@string/txt_save\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;br style=\u0026quot;color: #362e2b;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;3、别忘了添加权限：\u0026lt;/span\u0026gt;\n\n\n\n\n\n\n\n  \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot; style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n    \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;uses-permission\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.permission.CAMERA\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;uses-feature\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.hardware.camera\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;uses-feature\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.hardware.camera.autofocus\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:required\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n    \n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot; style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n    \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n      \n    \n  \u0026lt;/div\u0026gt;\n  \n  \n\n    [源码下载==》](http://download.csdn.net/detail/tangcheng_ok/3874071)\n  \n\n  \n  \n\n    原创文章，转载请注明出处：http://www.blog.csdn.net/tangcheng_ok\n\u003c/code\u003e\u003c/pre\u003e","title":"Android开发之拍照功能实现（附源码）"},{"content":"最近在使用android 4.1系统的时候，发现在手机休眠一段时间后（1-2小时），后台运行的服务被强行kill掉，有可能是系统回收内存的一种机制，要想避免这种情况可以通过startForeground让服务前台运行，当stopservice的时候通过stopForeground去掉。以下是android官方描述：Running a Service in the Foreground A foreground service（前台服务） is a service that’s considered to be（被用户所认可的） something the user is actively aware of and thus not a candidate for（而不是一个候选的，可以在内存不足时，被系统杀死的） the system to kill when low on memory. A foreground service must provide a notification for the status bar（前台服务必须提供一个显示通知）, which is placed under the “Ongoing” heading（它是不可以忽略的）, which means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.（意思是通知信息不能被忽略，除非服务停止或主动移除，否则将一直显示。） For example, a music player that plays music from a service should be set to run in the foreground, because the user is explicitly aware of its operation（用户明确了解其运作）. The notification in the status bar might indicate the current song and allow the user to launch an activity to interact with the music player.To request that your service run in the foreground, call startForeground(). This method takes two parameters: an integer that uniquely identifies the notification and the Notification for the status bar. For example:Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),System.currentTimeMillis());Intent notificationIntent = new Intent(this, ExampleActivity.class);PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);notification.setLatestEventInfo(this, getText(R.string.notification_title),getText(R.string.notification_message), pendingIntent);startForeground(ONGOING_NOTIFICATION, notification);To remove the service from the foreground, call stopForeground(). This method takes a boolean, indicating whether to remove the status bar notification as well. This method does not stop the service. However, if you stop the service while it’s still running in the foreground, then the notification is also removed.\n方法：\nstartForeground(int id, Notification notification)\n参数：id 唯一的通知标识\nnotification 通知信息 stopForeground(boolean removeNotification) //停止前台服务\n参数： removeNotification 是否移除之前的通知\nNote: The methods startForeground() and stopForeground() were introduced in Android 2.0 (API Level 5). In order to run your service in the foreground on older versions of the platform, you must use the previoussetForeground() method—see the startForeground() documentation for information about how to provide backward compatibility.For more information about notifications, see Creating Status Bar Notifications.要想实现需求，我们只需要在onStartCommand里面调用 startForeground，然后再onDestroy里面调用stopForeground即可！实际情况就譬如手机里面的音乐播放器一样，不管手机如何休眠，只要开始播放音乐了，就不会kill掉这个服务，一旦停止播放音乐，服务就可能被清掉。\n","permalink":"https://blog.zdltech.com/posts/%E4%BD%BF%E7%94%A8startforeground%E8%AE%A9android%E6%9C%8D%E5%8A%A1%E5%89%8D%E5%8F%B0%E8%BF%90%E8%A1%8C/","summary":"\u003cp\u003e\u003cspan style=\"color: #464646;\"\u003e最近在使用android 4.1系统的时候，发现在手机休眠一段时间后（1-2小时），后台运行的服务被强行kill掉，有可能是系统回收内存的一种机制，要想避免这种情况可以通过startForeground让服务前台运行，当stopservice的时候通过stopForeground去掉\u003c/span\u003e\u003cspan style=\"color: #464646;\"\u003e。\u003c/span\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003e以下是android官方描述：\u003c/span\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003eRunning a Service in the Foreground\u003c/span\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003e \u003c/span\u003e\u003cwbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003eA foreground service（前台服务） is a service that’s considered to be（被用户所认可的） something the user is actively aware of and thus not a candidate for（而不是一个候选的，可以在内存不足时，被系统杀死的） the system to kill when low on memory. A foreground service must provide a notification for the status bar（前台服务必须提供一\u003c/span\u003e\u003cspan style=\"color: #464646;\"\u003e个显示通知）, which is placed under the “Ongoing” heading（它是不可以忽略的）, which means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.（意思是通知信息不能被忽略，除非服务停止或主动移除，否则将一直显示。）\u003c/span\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003e \u003c/span\u003e\u003cwbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003eFor example, a music player that plays music from a service should be set to run in the foreground, because the user is explicitly aware of its operation（用户明确了解其运作）. The notification in the status bar might indicate the current song and allow the user to launch an activity to interact with the music player.\u003c/span\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003eTo request that your service run in the foreground, call startForeground(). This method takes two parameters: an integer that uniquely identifies the notification and the Notification for the status bar. For example:\u003c/span\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003eNotification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),\u003c/span\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003eSystem.currentTimeMillis());\u003c/span\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003eIntent notificationIntent = new Intent(this, ExampleActivity.class);\u003c/span\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003ePendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);\u003c/span\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003enotification.setLatestEventInfo(this, getText(R.string.notification_title),\u003c/span\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003egetText(R.string.notification_message), pendingIntent);\u003c/span\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003estartForeground(ONGOING_NOTIFICATION, notification);\u003c/span\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cbr style=\"color: #464646;\" /\u003e\u003cspan style=\"color: #464646;\"\u003eTo remove the service from the foreground, call stopForeground(). This method takes a boolean, indicating whether to remove the status bar notification as well. This method does not stop the service. However, if you stop the service while it’s still running in the foreground, then the notification is also removed.\u003c/span\u003e\u003c/p\u003e","title":"使用startForeground让android服务前台运行"},{"content":"翻自:http://developer.android.com/training/monitoring-device-state/battery-monitoring.html 当你在更改后台更新频率来减少这些更新对电池寿命的影响时，检查当前电量和充电状态是一个好的开始。\n电池寿命通过剩余电量和充电状态来影响应用更新的执行。当用交流电充电时，执行更新操作对设备的影响是微不足道的，所以在大多数案例里，你可以把更新频率调到最快。如果设备不在充电，降低更新频率可以帮助延长电池寿命。\n类似的，你可以检查电池剩余电量级别，在电量低时，应该降低更新频率甚至停止更新。\n注：此处的更新，指的是类似发送心跳包的动作，或者定时更新内容。并非仅仅指更新应用版本。如果是用户动作，比如翻页刷新，不需要根据电量和充电状态处理。\n判断当前充电状态 通过判断当前充电状态开始。BatteryManager会通过一个intent广播所有电池和充电详情,包含充电状态。\n因为这是一个sticky intent,你不需要注册广播接收器。简单地通过调用 registerReceiver，像下面的代码段传入一个null的接收器，当前电池状态的intent就会返回。你也可以传入一个真实的接收器对象，但我们暂时不会操作更新，所以这是没必要的。\n``` 1 2 3 4 5 6 7 8 9 10 11 12 13 \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34;\u0026gt; ``` IntentFilter ifilter \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; IntentFilter\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;Intent.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;ACTION_BATTERY_CHANGED\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; Intent batteryStatus \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; context.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;registerReceiver\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;, ifilter\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-style: italic; color: #666666;\u0026#34;\u0026gt;//你可以读到充电状态,如果在充电，可以读到是usb还是交流电\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-style: italic; color: #666666;\u0026#34;\u0026gt;// 是否在充电\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; status \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; batteryStatus.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;getIntExtra\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;EXTRA_STATUS\u0026lt;/span\u0026gt;, \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #cc66cc;\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; isCharging \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; status \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;==\u0026lt;/span\u0026gt; BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;BATTERY_STATUS_CHARGING\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;||\u0026lt;/span\u0026gt; status \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;==\u0026lt;/span\u0026gt; BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;BATTERY_STATUS_FULL\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-style: italic; color: #666666;\u0026#34;\u0026gt;// 怎么充\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; chargePlug \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; batteryStatus.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;getIntExtra\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;EXTRA_PLUGGED\u0026lt;/span\u0026gt;, \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #cc66cc;\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; usbCharge \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; chargePlug \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;==\u0026lt;/span\u0026gt; BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;BATTERY_PLUGGED_USB\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; acCharge \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; chargePlug \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;==\u0026lt;/span\u0026gt; BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;BATTERY_PLUGGED_AC\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 通常你应该在使用交流电充电时最大化后台更新频率，在使用usb充电时降低，不充电时更低。\n监听充电状态的改变 充电状态很容易改变(插入/拔出充电器),所以监听充电状态，更改刷新频率很重要。\n充电状态改变时，BatteryManager会发一个广播。接收这些事件很重要，甚至在应用没有运行的时候，因为可能你需要后台开启更新服务。所以，在Androidmanifest.xml里注册广播接收器，加上两个action:ACTION_POWER_CONNECTED 和ACTION_POWER_DISCONNECTED作为过滤。\n``` 1 2 3 4 5 6 \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34;\u0026gt; ``` \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;lt;receiver\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #000066;\u0026#34;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;\u0026#34;.PowerConnectionReceiver\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;lt;intent-filter\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;lt;action\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #000066;\u0026#34;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;\u0026#34;android.intent.action.ACTION_POWER_CONNECTED\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;lt;action\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #000066;\u0026#34;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;\u0026#34;android.intent.action.ACTION_POWER_DISCONNECTED\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;lt;/intent-filter\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;lt;/receiver\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 在关联的广播接收器实现里，你可以读出当前充电状态，方法跟上一步说的相同:\n``` 1 2 3 4 5 6 7 8 9 10 11 12 \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34;\u0026gt; ``` \u0026lt;span style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;class\u0026lt;/span\u0026gt; PowerConnectionReceiver \u0026lt;span style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;extends\u0026lt;/span\u0026gt; BroadcastReceiver \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;{\u0026lt;/span\u0026gt; @Override \u0026lt;span style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;void\u0026lt;/span\u0026gt; onReceive\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #003399;\u0026#34;\u0026gt;Context\u0026lt;/span\u0026gt; context, Intent intent\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;{\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; status \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; intent.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;getIntExtra\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;EXTRA_STATUS\u0026lt;/span\u0026gt;, \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #cc66cc;\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; isCharging \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; status \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;==\u0026lt;/span\u0026gt; BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;BATTERY_STATUS_CHARGING\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;||\u0026lt;/span\u0026gt; status \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;==\u0026lt;/span\u0026gt; BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;BATTERY_STATUS_FULL\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; chargePlug \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; intent.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;getIntExtra\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;EXTRA_PLUGGED\u0026lt;/span\u0026gt;, \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #cc66cc;\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; usbCharge \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; chargePlug \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;==\u0026lt;/span\u0026gt; BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;BATTERY_PLUGGED_USB\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; acCharge \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; chargePlug \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;==\u0026lt;/span\u0026gt; BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;BATTERY_PLUGGED_AC\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 判断当前剩余电量 在某些案例里，判断当前剩余电量同样很有用。如果电量在某些水平之下，你可能会选择降低后台更新频率。 你可以用下面的代码读到电量：\n``` 1 2 3 4 5 6 \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34;\u0026gt; ``` \u0026lt;span style=\u0026#34;font-style: italic; color: #666666;\u0026#34;\u0026gt;//当前剩余电量\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; level \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; batteryStatus.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;getIntExtra\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;EXTRA_LEVEL\u0026lt;/span\u0026gt;, \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #cc66cc;\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-style: italic; color: #666666;\u0026#34;\u0026gt;//电量最大值\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; scale \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; batteryStatus.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;getIntExtra\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;EXTRA_SCALE\u0026lt;/span\u0026gt;, \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #cc66cc;\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-style: italic; color: #666666;\u0026#34;\u0026gt;//电量百分比\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt; batteryPct \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; level \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;/\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;float\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;scale\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 注：暂时不知道为什么要这样算，在我自己的机器上运行,scale就是100的。\n监听剩余电量显著改变 持续监听电池状态不容易，但你不必这么做。 一般来说，持续监听电池电量对电池的影响比app的正常行为还要大。所以，只监听剩余电量的指定级别的改变(进入或离开低电量状态)是一个很好的实践。 manifest里声明的接收器，会在进入或离开低电量状态时触发。\n``` 1 2 3 4 5 6 \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34;\u0026gt; ``` \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;lt;receiver\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #000066;\u0026#34;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;\u0026#34;.BatteryLevelReceiver\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;lt;intent-filter\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;lt;action\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #000066;\u0026#34;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;\u0026#34;android.intent.action.ACTION_BATTERY_LOW\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;lt;action\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #000066;\u0026#34;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;\u0026#34;android.intent.action.ACTION_BATTERY_OKAY\u0026#34;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;/\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;lt;/intent-filter\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000000;\u0026#34;\u0026gt;\u0026amp;lt;/receiver\u0026amp;gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; 剩余电量严重不足时，最好禁用所有后台更新。在你可以使用手机之前就关机了，这种情况下，如果刷新数据并不重要。 在很多情况下，设备是是插入到底座里充电的（好吧，反正我没见几个人额外花钱买底座的,可能国外较多)。下节讲怎么判断当前底座状态和监听插入底座时改变。\n","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E5%8F%91%E4%BC%98%E5%8C%96%E7%94%B5%E6%B1%A0%E7%BB%AD%E8%88%AA-%E7%9B%91%E5%90%AC%E7%94%B5%E9%87%8F%E5%92%8C%E5%85%85%E7%94%B5%E7%8A%B6%E6%80%81/","summary":"\u003cp\u003e翻自:http://developer.android.com/training/monitoring-device-state/battery-monitoring.html\n当你在更改后台更新频率来减少这些更新对电池寿命的影响时，检查当前电量和充电状态是一个好的开始。\u003c/p\u003e\n\u003cp\u003e电池寿命通过剩余电量和充电状态来影响应用更新的执行。当用交流电充电时，执行更新操作对设备的影响是微不足道的，所以在大多数案例里，你可以把更新频率调到最快。如果设备不在充电，降低更新频率可以帮助延长电池寿命。\u003c/p\u003e\n\u003cp\u003e类似的，你可以检查电池剩余电量级别，在电量低时，应该降低更新频率甚至停止更新。\u003c/p\u003e\n\u003cp\u003e注：此处的更新，指的是类似发送心跳包的动作，或者定时更新内容。并非仅仅指更新应用版本。如果是用户动作，比如翻页刷新，不需要根据电量和充电状态处理。\u003cspan id=\"more-1341\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003ch2 id=\"判断当前充电状态\"\u003e判断当前充电状态\u003c/h2\u003e\n\u003cp\u003e通过判断当前充电状态开始。BatteryManager会通过一个intent广播所有电池和充电详情,包含充电状态。\u003c/p\u003e\n\u003cp\u003e因为这是一个sticky intent,你不需要注册广播接收器。简单地通过调用 registerReceiver，像下面的代码段传入一个null的接收器，当前电池状态的intent就会返回。你也可以传入一个真实的接收器对象，但我们暂时不会操作更新，所以这是没必要的。\u003c/p\u003e\n\u003cdiv class=\"wp_syntax\" style=\"color: #110000;\"\u003e\n  \u003ctable\u003e\n    \u003ctr\u003e\n      \u003ctd class=\"line_numbers\"\u003e\n        ```\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;/td\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;td class=\u0026#34;code\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ```\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eIntentFilter ifilter \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;new\u0026lt;/span\u0026gt; IntentFilter\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;Intent.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;ACTION_BATTERY_CHANGED\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eIntent batteryStatus \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; context.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;registerReceiver\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;null\u0026lt;/span\u0026gt;, ifilter\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span style=\u0026#34;font-style: italic; color: #666666;\u0026#34;\u0026gt;//你可以读到充电状态,如果在充电，可以读到是usb还是交流电\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span style=\u0026#34;font-style: italic; color: #666666;\u0026#34;\u0026gt;// 是否在充电\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; status \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; batteryStatus.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;getIntExtra\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;EXTRA_STATUS\u0026lt;/span\u0026gt;, \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #cc66cc;\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; isCharging \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; status \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;==\u0026lt;/span\u0026gt; BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;BATTERY_STATUS_CHARGING\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;||\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                     status \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;==\u0026lt;/span\u0026gt; BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;BATTERY_STATUS_FULL\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span style=\u0026#34;font-style: italic; color: #666666;\u0026#34;\u0026gt;// 怎么充\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;int\u0026lt;/span\u0026gt; chargePlug \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; batteryStatus.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;getIntExtra\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;(\u0026lt;/span\u0026gt;BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;EXTRA_PLUGGED\u0026lt;/span\u0026gt;, \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #cc66cc;\u0026#34;\u0026gt;1\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #009900;\u0026#34;\u0026gt;)\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; usbCharge \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; chargePlug \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;==\u0026lt;/span\u0026gt; BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;BATTERY_PLUGGED_USB\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;span style=\u0026#34;font-weight: bold; color: #000066;\u0026#34;\u0026gt;boolean\u0026lt;/span\u0026gt; acCharge \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;=\u0026lt;/span\u0026gt; chargePlug \u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;==\u0026lt;/span\u0026gt; BatteryManager.\u0026lt;span style=\u0026#34;color: #006633;\u0026#34;\u0026gt;BATTERY_PLUGGED_AC\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026#34;color: #339933;\u0026#34;\u0026gt;;\u0026lt;/span\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e  \u0026lt;/td\u0026gt;\n\u0026lt;/tr\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/table\u003e\n\u003c/div\u003e\n\u003cp\u003e通常你应该在使用交流电充电时最大化后台更新频率，在使用usb充电时降低，不充电时更低。\u003c/p\u003e","title":"Android开发:优化电池续航-监听电量和充电状态"},{"content":"在做一个微信的微网站中的一个便民服务电话功能的应用，用到移动web页面中列出的电话号码，点击需要实现调用通讯录，网页一键拨号的拨打电话功能。\n如果需要在移动浏览器中实现拨打电话，发送email，美国服务器，调用sns等功能，移动手机WEB页面(HTML5)Javascript提供的接口是一个好办法。\n采用url链接的方式，实现在Safari ios，香港服务器，Android 浏览器，webos 浏览器，塞班浏览器，IE，Operamini等主流浏览器，进行拨打电话功能。\n1.最常用WEB页面JS实现一键拨号的电话拨打功能：\n移动WEB页面JS一键拨打号码咨询功能\n在拨号界面，显示号码，并提示拨打。\n支持大部分的浏览器，但是在QQ浏览器上支持不好。\n微信现在出现屏蔽常规拨号功能，具体解决办法见《微信开发实现一键拨号出现屏蔽问题的解决方案》\n2.最常用WEB页面JS实现一键发送短信功能：\n移动WEB页面JS一键发送短信咨询功能\n在信息录入界面，显示发送号码，并提示录入信息。\n支持大部分的浏览器，但是在QQ浏览器上支持不好。\n3、移动web页面自动探测电话号码\n如果要支持safari for ios ，blackberry browser的号码，需要加上一下标签：\n4.使用wtai协议进行拨打电话。\n在wml中可以调用设备的wtai函数来呼叫特定的电话号码。目前，越来越多的浏览器都支持这个功能，但还不是所有。\n代码如下所示：\n实例：\n拨打10086 将10086存储至电话簿 建议采用这个方式。\n5、不太灵验的方式：\n移动WEB页面JS一键拨打号码咨询功能\n经过测试，大部分浏览器都不支持了。\n补充—————————–\n这段时间很多人看了我的帖子《微信开发之移动手机WEB页面(HTML5)Javascript实现一键拨号及短信发送功能 》询问我在微信中出现无法拨号的情况，原先我操作的时候，的确是OK的，现在微信版本升级了，我试了一下，果然拨号不行了，在首页的web页面中是没有问题的，但是在微信中就是拨打不了，找了很多，后来发现是微信做了屏蔽，解决方法如下：\n1、拨号的代码还是不变，和我原先的文章一样，\n2、打开拨号页面要做下处理，在网址后面增加一个锚节点mp.weixin.qq.com。\n实例如下：\n如：http://www.xxxxxx/xxxx.html 上需要拨号代码，操作如下\n1、 继续写拨号代码\n移动WEB页面JS一键拨打号码咨询功能\n2、打开这个网址链接的时候，就用这个链接http://www.xxxxxx/xxxx.html #mp.weixin.qq.com(多添加一个mp.weixin.qq.com)\n这样，微信里面的一键拨号功能就OK了\n","permalink":"https://blog.zdltech.com/posts/%E5%BE%AE%E4%BF%A1%E5%BC%80%E5%8F%91%E4%B9%8B%E7%A7%BB%E5%8A%A8%E6%89%8B%E6%9C%BAweb%E9%A1%B5%E9%9D%A2html5javascript%E5%AE%9E%E7%8E%B0%E4%B8%80%E9%94%AE%E6%8B%A8%E5%8F%B7%E5%8F%8A%E7%9F%AD%E4%BF%A1/","summary":"\u003cp\u003e在做一个微信的微网站中的一个便民服务电话功能的应用，用到移动web页面中列出的电话号码，点击需要实现调用通讯录，网页一键拨号的拨打电话功能。\u003c/p\u003e\n\u003cp\u003e如果需要在移动浏览器中实现拨打电话，发送email，美国服务器，调用sns等功能，移动手机WEB页面(HTML5)Javascript提供的接口是一个好办法。\u003c/p\u003e\n\u003cp\u003e采用url链接的方式，实现在Safari ios，香港服务器，Android 浏览器，webos 浏览器，塞班浏览器，IE，Operamini等主流浏览器，进行拨打电话功能。\u003c/p\u003e\n\u003cp\u003e1.最常用WEB页面JS实现一键拨号的电话拨打功能：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\u0026#8221;tel:13764567708\u0026#8243;\u003e移动WEB页面JS一键拨打号码咨询功能\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e在拨号界面，显示号码，并提示拨打。\u003cbr\u003e\n支持大部分的浏览器，但是在QQ浏览器上支持不好。\u003c/p\u003e\n\u003cp\u003e微信现在出现屏蔽常规拨号功能，具体解决办法见《微信开发实现一键拨号出现屏蔽问题的解决方案》\u003cbr\u003e\n2.最常用WEB页面JS实现一键发送短信功能：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\u0026#8221;sms:13764567708\u0026#8243;\u003e移动WEB页面JS一键发送短信咨询功能\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e在信息录入界面，显示发送号码，并提示录入信息。\u003c/p\u003e\n\u003cp\u003e支持大部分的浏览器，但是在QQ浏览器上支持不好。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e3、移动web页面自动探测电话号码\u003cbr\u003e\n如果要支持safari for ios ，blackberry browser的号码，需要加上一下标签：\u003c/p\u003e\n\u003cmeta name=\u0026#8221;format-detection\u0026#8221; content=\u0026#8221;telephone=no\u0026#8221;\u003e\n\u003cmeta http-equiv=\u0026#8221;x-rim-auto-match\u0026#8221; content=\u0026#8221;none\u0026#8221;\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e4.使用wtai协议进行拨打电话。\u003cbr\u003e\n在wml中可以调用设备的wtai函数来呼叫特定的电话号码。目前，越来越多的浏览器都支持这个功能，但还不是所有。\u003cbr\u003e\n代码如下所示：\u003c/p\u003e\n\u003cp\u003e实例：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\u0026#8221;wtai://wp//mc;13764567708\u0026#8243;\u003e拨打10086 \u003c/a\u003e\u003cbr\u003e\n\u003ca href=\u0026#8221;wtai://wp/ap;13764567708;\u0026#8221;\u003e将10086存储至电话簿 \u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e建议采用这个方式。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e5、不太灵验的方式：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\u0026#8221;dc:13764567708\u0026#8243;\u003e移动WEB页面JS一键拨打号码咨询功能\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e经过测试，大部分浏览器都不支持了。\u003c/p\u003e\n\u003cp\u003e补充—————————–\u003cbr\u003e\n这段时间很多人看了我的帖子《微信开发之移动手机WEB页面(HTML5)Javascript实现一键拨号及短信发送功能 》询问我在微信中出现无法拨号的情况，原先我操作的时候，的确是OK的，现在微信版本升级了，我试了一下，果然拨号不行了，在首页的web页面中是没有问题的，但是在微信中就是拨打不了，找了很多，后来发现是微信做了屏蔽，解决方法如下：\u003c/p\u003e\n\u003cp\u003e1、拨号的代码还是不变，和我原先的文章一样，\u003c/p\u003e\n\u003cp\u003e2、打开拨号页面要做下处理，在网址后面增加一个锚节点mp.weixin.qq.com。\u003c/p\u003e\n\u003cp\u003e实例如下：\u003c/p\u003e\n\u003cp\u003e如：http://www.xxxxxx/xxxx.html 上需要拨号代码，操作如下\u003c/p\u003e\n\u003cp\u003e1、 继续写拨号代码\u003c/p\u003e\n\u003cp\u003e\u003ca href=\u0026#8221;tel:13764567708\u0026#8243;\u003e移动WEB页面JS一键拨打号码咨询功能\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e2、打开这个网址链接的时候，就用这个链接http://www.xxxxxx/xxxx.html #mp.weixin.qq.com(多添加一个mp.weixin.qq.com)\u003c/p\u003e\n\u003cp\u003e这样，微信里面的一键拨号功能就OK了\u003c/p\u003e","title":"微信开发之移动手机WEB页面(HTML5)Javascript实现一键拨号及短信发送功能"},{"content":"DNS，全称Domain Name System，即域名解析系统，帮助用户在互联网上寻找路径，它在互联网的作用是把域名转换成为网络可以识别的IP地址。目前国内电信运营商通过使用DNS劫持和DNS污染的方法，干扰用户正常上网，使得用户无法访问众多国外常用服务，因此今天我介绍一些国内外的DNS服务器地址，供大家选择使用。\n国外DNS服务器地址\nGoogle Public DNS （8.8.8.8， 8.8.4.4）\nOpenDNS （208.67.222.222， 208.67.220.220）\nOpenDNS Family （208.67.222.123， 208.67.220.123）\nV2EX DNS （199.91.73.222；178.79.131.110）\nComodo Secure (8.26.56.26， 8.20.247.20)\nUltraDNS （156.154.70.1, 156.154.71.1）\nNorton ConnectSafe (199.85.126.10, 199.85.127.10)\n国内DNS服务器地址\nOneDNS （112.124.47.27）\nOpenerDNS（42.120.21.30）\naliDNS （223.5.5.5， 223.6.6.6）\n114DNS （114.114.114.114， 114.114.115.115）\n114DNS安全版 （114.114.114.119， 114.114.115.119）\n114DNS家庭版 （114.114.114.110， 114.114.115.110）\n\u0026lt;div\u0026gt; http://www.freevpnmac.com/macvpn/ ![](file:///C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\%W@GJ$ACOF(TYDYECOKVDYB.png)https://code.google.com/p/smarthosts/ ![](file:///C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\%W@GJ$ACOF(TYDYECOKVDYB.png)http://www.vpngate.net/cn/\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; http://technet.microsoft.com/en-us/library/ms525732(VS.90).aspx \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/%E5%B8%B8%E7%94%A8%E5%85%AC%E5%85%B1dns%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%9C%B0%E5%9D%80/","summary":"\u003cp\u003eDNS，全称Domain Name System，即域名解析系统，帮助用户在互联网上寻找路径，\u003cwbr /\u003e它在互联网的作用是把域名转换成为网络可以识别的IP地址。\u003cwbr /\u003e目前国内电信运营商通过使用DNS劫持和DNS污染的方法，\u003cwbr /\u003e干扰用户正常上网，使得用户无法访问众多国外常用服务，\u003cwbr /\u003e因此今天我介绍一些国内外的DNS服务器地址，供大家选择使用。\u003c/p\u003e\n\u003cp\u003e　　\u003cstrong\u003e国外DNS服务器地址\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e　　Google Public DNS （8.8.8.8， 8.8.4.4）\u003c/p\u003e\n\u003cp\u003e　　OpenDNS （208.67.222.222， 208.67.220.220）\u003c/p\u003e\n\u003cp\u003e　　OpenDNS Family （208.67.222.123， 208.67.220.123）\u003c/p\u003e\n\u003cp\u003e　　V2EX DNS （199.91.73.222；178.79.131.110）\u003c/p\u003e\n\u003cp\u003e　　Comodo Secure (8.26.56.26， 8.20.247.20)\u003c/p\u003e\n\u003cp\u003e　　UltraDNS （156.154.70.1, 156.154.71.1）\u003c/p\u003e\n\u003cp\u003e　　Norton ConnectSafe (199.85.126.10, 199.85.127.10)\u003c/p\u003e\n\u003cp\u003e　　\u003cstrong\u003e国内DNS服务器地址\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e　　OneDNS  （112.124.47.27）\u003c/p\u003e\n\u003cp\u003e　　OpenerDNS（42.120.21.30）\u003c/p\u003e\n\u003cp\u003e　　aliDNS （223.5.5.5， 223.6.6.6）\u003c/p\u003e\n\u003cp\u003e　　114DNS （114.114.114.114， 114.114.115.115）\u003c/p\u003e\n\u003cp\u003e　　114DNS安全版 （114.114.114.119， 114.114.115.119）\u003c/p\u003e\n\u003cp\u003e　　114DNS家庭版 （114.114.114.110， 114.114.115.110）\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;div\u0026gt;\n  http://www.freevpnmac.com/macvpn/\n\n  \n  \n\n    ![](file:///C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\%W@GJ$ACOF(TYDYECOKVDYB.png)https://code.google.com/p/smarthosts/\n  \n\n  \n  \n\n    ![](file:///C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\%W@GJ$ACOF(TYDYECOKVDYB.png)http://www.vpngate.net/cn/\u0026lt;/div\u0026gt; \n    \n    \u0026lt;div\u0026gt;\n      http://technet.microsoft.com/en-us/library/ms525732(VS.90).aspx\n    \u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e","title":"常用公共DNS服务器地址"},{"content":"技术要点： android.support.v4.widget.DrawerLayout\n打开抽屉： DrawerLayout .openDrawer();\n关闭抽屉：DrawerLayout.closeDrawer( );\n**为slidingLayout设置一个layout_grative属性\n**\n** **\n**中间![](http://www.2cto.com/uploadfile/Collfiles/20140226/20140226092627200.jpg) 左侧![](http://www.2cto.com/uploadfile/Collfiles/20140226/20140226092627201.jpg) 右侧 ![](http://www.2cto.com/uploadfile/Collfiles/20140226/20140226092627202.jpg)\n**\n点击first ![](http://www.2cto.com/uploadfile/Collfiles/20140226/20140226092627203.jpg) 点击second ![](http://www.2cto.com/uploadfile/Collfiles/20140226/20140226092628204.jpg)\n** **\n** **\n代码：\nactivity_main.xml\n\u0026lt;\u001a喎�”http://www.2cto.com/kf/ware/vc/” target=”_blank” class=”keylink”\u0026gt;vc3Ryb25nPjwvcD4KPHA+PHN0cm9uZz48L3N0cm9uZz48L3A+CjxwcmUgY2xhc3M9″brush:java;”\u0026gt;\u0026lt;frameLayout android:id=”@+id/fragment_layout” android:layout_width=”fill_parent” android:layout_height=”fill_parent” \u0026gt; first.xml\n[?](http://www.2cto.com/kf/201402/281540.html#) \u0026lt;table style=\u0026quot;font-weight: normal !important;\u0026quot; border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;color: #afafaf !important;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;linearlayout xmlns:android=``\u0026quot;\u0026amp;lt;a href=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;\u0026gt;http://schemas.android.com/apk/res/android\u0026amp;lt;/a\u0026gt;\u0026quot;` `android:id=``\u0026quot;@+id/drawer_layout\u0026quot;` `android:layout_width=``\u0026quot;match_parent\u0026quot;` `android:layout_height=``\u0026quot;match_parent\u0026quot;` `android:orientation=``\u0026quot;vertical\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;textview android:id=``\u0026quot;@+id/textView1\u0026quot;` `android:layout_width=``\u0026quot;wrap_content\u0026quot;` `android:layout_height=``\u0026quot;wrap_content\u0026quot;` `android:text=``\u0026quot;first\u0026quot;` `android:textappearance=``\u0026quot;?android:attr/textAppearanceLarge\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `\u0026amp;lt;/textview\u0026amp;gt;\u0026amp;lt;/linearlayout\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; **\nsecond.xml**\n[?](http://www.2cto.com/kf/201402/281540.html#) \u0026lt;table style=\u0026quot;font-weight: normal !important;\u0026quot; border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;color: #afafaf !important;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `\u0026amp;lt;linearlayout xmlns:android=``\u0026quot;\u0026amp;lt;a href=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;\u0026gt;http://schemas.android.com/apk/res/android\u0026amp;lt;/a\u0026gt;\u0026quot;` `android:id=``\u0026quot;@+id/drawer_layout\u0026quot;` `android:layout_width=``\u0026quot;match_parent\u0026quot;` `android:layout_height=``\u0026quot;match_parent\u0026quot;` `android:orientation=``\u0026quot;vertical\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; ` ``\u0026amp;lt;textview android:id=``\u0026quot;@+id/textView1\u0026quot;` `android:layout_width=``\u0026quot;wrap_content\u0026quot;` `android:layout_height=``\u0026quot;wrap_content\u0026quot;` `android:text=``\u0026quot;second\u0026quot;` `android:textappearance=``\u0026quot;?android:attr/textAppearanceLarge\u0026quot;``\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `\u0026amp;lt;/textview\u0026amp;gt;\u0026amp;lt;/linearlayout\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; ** **\nMainActivity.java\n[?](http://www.2cto.com/kf/201402/281540.html#) \u0026lt;table style=\u0026quot;font-weight: normal !important;\u0026quot; border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;color: #afafaf !important;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; 20 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; 21 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; 22 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; 23 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; 24 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; 25 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; 26 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; 27 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; 28 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; 29 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; 30 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; 31 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; 32 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; 33 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; 34 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; 35 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; 36 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; 37 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; 38 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; 39 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; 40 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; 41 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; 42 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; 43 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; 44 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; 45 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; 46 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; 47 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; 48 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; 49 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; 50 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; 51 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; 52 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; 53 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; 54 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; 55 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; 56 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; 57 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; 58 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; 59 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; 60 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; 61 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; 62 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; 63 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; 64 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; 65 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; 66 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; 67 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; 68 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; 69 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; 70 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; 71 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; 72 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; 73 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; 74 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; 75 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; 76 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; 77 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; 78 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; 79 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; 80 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; 81 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; 82 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; 83 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; 84 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; 85 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; 86 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; 87 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; 88 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; 89 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; 90 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; 91 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt; 92 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt; 93 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt; 94 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt; 95 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt; 96 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt; 97 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt; 98 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt; 99 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt; 100 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number101 index100 alt2\u0026quot;\u0026gt; 101 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number102 index101 alt1\u0026quot;\u0026gt; 102 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number103 index102 alt2\u0026quot;\u0026gt; 103 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number104 index103 alt1\u0026quot;\u0026gt; 104 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number105 index104 alt2\u0026quot;\u0026gt; 105 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number106 index105 alt1\u0026quot;\u0026gt; 106 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number107 index106 alt2\u0026quot;\u0026gt; 107 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number108 index107 alt1\u0026quot;\u0026gt; 108 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number109 index108 alt2\u0026quot;\u0026gt; 109 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `package` `org.busyboy.drawerlayout;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; `import` `com.example.testdrawerlayout.R;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `import` `android.os.Bundle;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; `import` `android.app.Activity;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; `import` `android.support.v4.app.Fragment;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; `import` `android.support.v4.app.FragmentActivity;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; `import` `android.support.v4.app.FragmentTransaction;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; `import` `android.support.v4.widget.DrawerLayout;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; `import` `android.view.Gravity;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; `import` `android.view.View;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; `import` `android.widget.AdapterView;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; `import` `android.widget.ArrayAdapter;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; `import` `android.widget.ListView;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; `import` `android.widget.RelativeLayout;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; `import` `android.widget.AdapterView.OnItemClickListener;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number20 index19 alt1\u0026quot;\u0026gt; `import` `android.widget.TextView;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number21 index20 alt2\u0026quot;\u0026gt; `public` `class` `MainActivity ``extends` `FragmentActivity` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number22 index21 alt1\u0026quot;\u0026gt; `{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number23 index22 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number24 index23 alt1\u0026quot;\u0026gt; ` ``public` `static` `final` `String[] TITLES = { ``\u0026quot;First\u0026quot;``, ``\u0026quot;Second\u0026quot;` `};` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number25 index24 alt2\u0026quot;\u0026gt; ` ``private` `DrawerLayout mDrawer_layout;``//DrawerLayout容器` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number26 index25 alt1\u0026quot;\u0026gt; ` ``private` `RelativeLayout mMenu_layout_left;``//左边抽屉` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number27 index26 alt2\u0026quot;\u0026gt; ` ``private` `RelativeLayout mMenu_layout_right;``//右边抽屉` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number28 index27 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number29 index28 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number30 index29 alt1\u0026quot;\u0026gt; ` ``protected` `void` `onCreate(Bundle savedInstanceState)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number31 index30 alt2\u0026quot;\u0026gt; ` ``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number32 index31 alt1\u0026quot;\u0026gt; ` ``super``.onCreate(savedInstanceState);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number33 index32 alt2\u0026quot;\u0026gt; ` ``setContentView(R.layout.activity_main);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number34 index33 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number35 index34 alt2\u0026quot;\u0026gt; ` ``mDrawer_layout = (DrawerLayout) findViewById(R.id.drawer_layout);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number36 index35 alt1\u0026quot;\u0026gt; ` ``mMenu_layout_left = (RelativeLayout) findViewById(R.id.menu_layout_left);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number37 index36 alt2\u0026quot;\u0026gt; ` ``mMenu_layout_right = (RelativeLayout) findViewById(R.id.menu_layout_right);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number38 index37 alt1\u0026quot;\u0026gt; ` ``ListView menu_listview_l = (ListView) mMenu_layout_left.findViewById(R.id.menu_listView_l);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number39 index38 alt2\u0026quot;\u0026gt; ` ``ListView menu_listview_r = (ListView) mMenu_layout_right.findViewById(R.id.menu_listView_r);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number40 index39 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number41 index40 alt2\u0026quot;\u0026gt; ` ``menu_listview_l.setAdapter(``new` `ArrayAdapter\u0026amp;lt;string\u0026amp;gt;(``this``, android.R.layout.simple_expandable_list_item_1, TITLES));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number42 index41 alt1\u0026quot;\u0026gt; ` ``menu_listview_r.setAdapter(``new` `ArrayAdapter\u0026amp;lt;string\u0026amp;gt;(``this``, android.R.layout.simple_expandable_list_item_1, TITLES));` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number43 index42 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number44 index43 alt1\u0026quot;\u0026gt; ` ``//监听菜单` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number45 index44 alt2\u0026quot;\u0026gt; ` ``menu_listview_l.setOnItemClickListener(``new` `DrawerItemClickListenerLeft());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number46 index45 alt1\u0026quot;\u0026gt; ` ``menu_listview_r.setOnItemClickListener(``new` `DrawerItemClickListenerRight());` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number47 index46 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number48 index47 alt1\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number49 index48 alt2\u0026quot;\u0026gt; ` ``* 左侧列表点击事件 ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number50 index49 alt1\u0026quot;\u0026gt; ` ``* @author busy_boy` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number51 index50 alt2\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number52 index51 alt1\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number53 index52 alt2\u0026quot;\u0026gt; ` ``public` `class` `DrawerItemClickListenerLeft ``implements` `OnItemClickListener` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number54 index53 alt1\u0026quot;\u0026gt; ` ``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number55 index54 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number56 index55 alt1\u0026quot;\u0026gt; ` ``public` `void` `onItemClick(AdapterView\u0026amp;lt;!--?--\u0026amp;gt; parent, View view, ``int` `position, ``long` `id)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number57 index56 alt2\u0026quot;\u0026gt; ` ``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number58 index57 alt1\u0026quot;\u0026gt; ` ``FragmentTransaction ft = getSupportFragmentManager().beginTransaction();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number59 index58 alt2\u0026quot;\u0026gt; ` ``Fragment fragment = ``null``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number60 index59 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number61 index60 alt2\u0026quot;\u0026gt; ` ``//根据item点击行号判断启用哪个Fragment` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number62 index61 alt1\u0026quot;\u0026gt; ` ``switch` `(position)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number63 index62 alt2\u0026quot;\u0026gt; ` ``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number64 index63 alt1\u0026quot;\u0026gt; ` ``case` ```:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number65 index64 alt2\u0026quot;\u0026gt; ` ``fragment = ``new` `FirstFragment();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number66 index65 alt1\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number67 index66 alt2\u0026quot;\u0026gt; ` ``case` `1``:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number68 index67 alt1\u0026quot;\u0026gt; ` ``fragment = ``new` `SecondFragment();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number69 index68 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number70 index69 alt1\u0026quot;\u0026gt; ` ``default``:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number71 index70 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number72 index71 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number73 index72 alt2\u0026quot;\u0026gt; ` ``ft.replace(R.id.fragment_layout, fragment);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number74 index73 alt1\u0026quot;\u0026gt; ` ``ft.commit();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number75 index74 alt2\u0026quot;\u0026gt; ` ``mDrawer_layout.closeDrawer(mMenu_layout_left);``//关闭mMenu_layout` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number76 index75 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number77 index76 alt2\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number78 index77 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number79 index78 alt2\u0026quot;\u0026gt; ` ``/**` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number80 index79 alt1\u0026quot;\u0026gt; ` ``* 右侧列表点击事件 ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number81 index80 alt2\u0026quot;\u0026gt; ` ``* @author busy_boy` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number82 index81 alt1\u0026quot;\u0026gt; ` ``*` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number83 index82 alt2\u0026quot;\u0026gt; ` ``*/` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number84 index83 alt1\u0026quot;\u0026gt; ` ``private` `class` `DrawerItemClickListenerRight ``implements` `OnItemClickListener {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number85 index84 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number86 index85 alt1\u0026quot;\u0026gt; ` ``public` `void` `onItemClick(AdapterView\u0026amp;lt;!--?--\u0026amp;gt; parent, View view, ``int` `position, ``long` `id)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number87 index86 alt2\u0026quot;\u0026gt; ` ``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number88 index87 alt1\u0026quot;\u0026gt; ` ``FragmentTransaction ft = getSupportFragmentManager().beginTransaction();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number89 index88 alt2\u0026quot;\u0026gt; ` ``Fragment fragment = ``null``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number90 index89 alt1\u0026quot;\u0026gt; ` ` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number91 index90 alt2\u0026quot;\u0026gt; ` ``//根据item点击行号判断启用哪个Fragment` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number92 index91 alt1\u0026quot;\u0026gt; ` ``switch` `(position)` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number93 index92 alt2\u0026quot;\u0026gt; ` ``{` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number94 index93 alt1\u0026quot;\u0026gt; ` ``case` ```:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number95 index94 alt2\u0026quot;\u0026gt; ` ``fragment = ``new` `FirstFragment();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number96 index95 alt1\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number97 index96 alt2\u0026quot;\u0026gt; ` ``case` `1``:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number98 index97 alt1\u0026quot;\u0026gt; ` ``fragment = ``new` `SecondFragment();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number99 index98 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number100 index99 alt1\u0026quot;\u0026gt; ` ``default``:` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number101 index100 alt2\u0026quot;\u0026gt; ` ``break``;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number102 index101 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number103 index102 alt2\u0026quot;\u0026gt; ` ``ft.replace(R.id.fragment_layout, fragment);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number104 index103 alt1\u0026quot;\u0026gt; ` ``ft.commit();` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number105 index104 alt2\u0026quot;\u0026gt; ` ``mDrawer_layout.closeDrawer(mMenu_layout_right);``//关闭mMenu_layout` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number106 index105 alt1\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number107 index106 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number108 index107 alt1\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number109 index108 alt2\u0026quot;\u0026gt; `\u0026amp;lt;/string\u0026amp;gt;\u0026amp;lt;/string\u0026amp;gt;` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; **\nFirstFragment.java\n**\n[?](http://www.2cto.com/kf/201402/281540.html#) \u0026lt;table style=\u0026quot;font-weight: normal !important;\u0026quot; border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;color: #afafaf !important;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `package` `org.busyboy.drawerlayout;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `import` `com.example.testdrawerlayout.R;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `import` `android.os.Bundle;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `import` `android.support.v4.app.Fragment;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `import` `android.view.LayoutInflater;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; `import` `android.view.View;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; `import` `android.view.ViewGroup;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; `public` `class` `FirstFragment ``extends` `Fragment {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``public` `View onCreateView(LayoutInflater inflater, ViewGroup container,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``Bundle savedInstanceState) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``return` `inflater.inflate(R.layout.first, ``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; **\nSecondFragment.java\n**\n[?](http://www.2cto.com/kf/201402/281540.html#) \u0026lt;table style=\u0026quot;font-weight: normal !important;\u0026quot; border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt; \u0026lt;tr\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;color: #afafaf !important;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; 1 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; 2 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; 3 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; 4 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; 5 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; 6 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; 7 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; 8 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; 9 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; 10 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; 11 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; 12 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; 13 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; 14 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; 15 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; 16 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; 17 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; 18 \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; 19 \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt; `package` `org.busyboy.drawerlayout;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt; `import` `com.example.testdrawerlayout.R;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt; `import` `android.os.Bundle;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number6 index5 alt1\u0026quot;\u0026gt; `import` `android.support.v4.app.Fragment;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number7 index6 alt2\u0026quot;\u0026gt; `import` `android.view.LayoutInflater;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number8 index7 alt1\u0026quot;\u0026gt; `import` `android.view.View;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number9 index8 alt2\u0026quot;\u0026gt; `import` `android.view.ViewGroup;` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number10 index9 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number11 index10 alt2\u0026quot;\u0026gt; `public` `class` `SecondFragment ``extends` `Fragment {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number12 index11 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number13 index12 alt2\u0026quot;\u0026gt; ` ``@Override` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number14 index13 alt1\u0026quot;\u0026gt; ` ``public` `View onCreateView(LayoutInflater inflater, ViewGroup container,` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number15 index14 alt2\u0026quot;\u0026gt; ` ``Bundle savedInstanceState) {` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number16 index15 alt1\u0026quot;\u0026gt; ` ``return` `inflater.inflate(R.layout.second, ``null``);` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number17 index16 alt2\u0026quot;\u0026gt; ` ``}` \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number18 index17 alt1\u0026quot;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div class=\u0026quot;line number19 index18 alt2\u0026quot;\u0026gt; `}` \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; ** **\nandroid.support.v4.widget.DrawerLayout 官方文档位置：http://developer.android.com/reference/android/support/v4/widget/DrawerLayout.htm\n参考设计文档：\nProviding Up Navigation http://developer.android.com/training/implementing-navigation/ancestral.html\nhttp://developer.android.com/design/patterns/app-structure.html\nhttp://developer.android.com/training/implementing-navigation/nav-drawer.html#ActionBarIcon\n","permalink":"https://blog.zdltech.com/posts/android-drawerlayout-fragment-%E5%B8%83%E5%B1%80%E5%AE%9E%E7%8E%B0%E5%B7%A6%E5%8F%B3%E4%BE%A7%E6%BB%91/","summary":"\u003cp\u003e\u003cstrong\u003e技术要点： android.support.v4.widget.DrawerLayout\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e打开抽屉： DrawerLayout .openDrawer();\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e关闭抽屉：DrawerLayout.closeDrawer( );\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e**为slidingLayout设置一个layout_grative属性\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e** **\u003c/p\u003e\n\u003cp\u003e**中间![](http://www.2cto.com/uploadfile/Collfiles/20140226/20140226092627200.jpg) 左侧![](http://www.2cto.com/uploadfile/Collfiles/20140226/20140226092627201.jpg) 右侧 ![](http://www.2cto.com/uploadfile/Collfiles/20140226/20140226092627202.jpg)\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e点击first ![](http://www.2cto.com/uploadfile/Collfiles/20140226/20140226092627203.jpg) 点击second ![](http://www.2cto.com/uploadfile/Collfiles/20140226/20140226092628204.jpg)\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e** **\u003c/p\u003e\n\u003cp\u003e** **\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e代码：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eactivity_main.xml\u003cbr\u003e\n\u0026lt;\u001a喎�”http://www.2cto.com/kf/ware/vc/” target=”_blank” class=”keylink”\u0026gt;vc3Ryb25nPjwvcD4KPHA+PHN0cm9uZz48L3N0cm9uZz48L3A+CjxwcmUgY2xhc3M9″brush:java;”\u0026gt;\u0026lt;frameLayout android:id=”@+id/fragment_layout” android:layout_width=”fill_parent” android:layout_height=”fill_parent” \u0026gt; \u003c/frameLayout\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003efirst.xml\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv id=\"highlighter_228437\" class=\"syntaxhighlighter  java\"\u003e\n    \u003cdiv class=\"toolbar\" style=\"font-weight: normal !important; color: white !important;\"\u003e\n      [?](http://www.2cto.com/kf/201402/281540.html#)\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;table style=\u0026quot;font-weight: normal !important;\u0026quot; border=\u0026quot;0\u0026quot; cellspacing=\u0026quot;0\u0026quot; cellpadding=\u0026quot;0\u0026quot;\u0026gt;\n  \u0026lt;tr\u0026gt;\n    \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;color: #afafaf !important;\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n        1\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        2\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n        3\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n        4\n      \u0026lt;/div\u0026gt;\n      \n      \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n        5\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n    \n    \u0026lt;td class=\u0026quot;code\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;container\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;line number1 index0 alt2\u0026quot;\u0026gt;\n          `\u0026amp;lt;linearlayout xmlns:android=``\u0026quot;\u0026amp;lt;a href=\u0026quot;http://schemas.android.com/apk/res/android\u0026quot;\u0026gt;http://schemas.android.com/apk/res/android\u0026amp;lt;/a\u0026gt;\u0026quot;` `android:id=``\u0026quot;@+id/drawer_layout\u0026quot;` `android:layout_width=``\u0026quot;match_parent\u0026quot;` `android:layout_height=``\u0026quot;match_parent\u0026quot;` `android:orientation=``\u0026quot;vertical\u0026quot;``\u0026amp;gt;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number2 index1 alt1\u0026quot;\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number3 index2 alt2\u0026quot;\u0026gt;\n          `    ``\u0026amp;lt;textview android:id=``\u0026quot;@+id/textView1\u0026quot;` `android:layout_width=``\u0026quot;wrap_content\u0026quot;` `android:layout_height=``\u0026quot;wrap_content\u0026quot;` `android:text=``\u0026quot;first\u0026quot;` `android:textappearance=``\u0026quot;?android:attr/textAppearanceLarge\u0026quot;``\u0026amp;gt;`\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number4 index3 alt1\u0026quot;\u0026gt;\n          `  `\n        \u0026lt;/div\u0026gt;\n        \n        \u0026lt;div class=\u0026quot;line number5 index4 alt2\u0026quot;\u0026gt;\n          `\u0026amp;lt;/textview\u0026amp;gt;\u0026amp;lt;/linearlayout\u0026amp;gt;`\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/td\u0026gt;\n  \u0026lt;/tr\u0026gt;\n\u0026lt;/table\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e**\u003cbr\u003e\nsecond.xml**\u003c/p\u003e","title":"Android DrawerLayout+ fragment 布局实现左右侧滑"},{"content":" 下面App基本都有下拉刷新的功能，以前基本都使用XListView或者自己写一个下拉刷新，近期Google提供了一个官方的下拉刷新控件SwipeRefreshLayout，我感觉还不错啊，见惯了传统的下拉刷新，这个反而给人耳目一新的感觉（貌似知乎的APP已经使用这种下拉刷新了）。 Google也在官方网站给出了V4的兼容包： ![](http://img.blog.csdn.net/20140426143208625?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG1qNjIzNTY1Nzkx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 顺便看一眼API呗： ![](http://img.blog.csdn.net/20140426143234968?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG1qNjIzNTY1Nzkx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 和XlistView差不多，还是很方便使用的，大概就这4个常用的方法，下面贴个简单的例子。 1、布局文件： \u0026amp;nbsp; **[html]** [view plain](http://blog.csdn.net/lmj623565791/article/details/24521483#)[copy](http://blog.csdn.net/lmj623565791/article/details/24521483#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/313476)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/313476/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;android.support.v4.widget.SwipeRefreshLayout\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/id_swipe_ly\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;ListView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/id_listview\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;ListView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;android.support.v4.widget.SwipeRefreshLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 2、MainActivty:\u0026amp;nbsp; \u0026amp;nbsp; **[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/24521483#)[copy](http://blog.csdn.net/lmj623565791/article/details/24521483#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/313476)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/313476/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * Created by Storm Zhang, Mar 31, 2014.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.swiperefreshlayoutdemo; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Arrays; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.annotation.SuppressLint; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v4.widget.SwipeRefreshLayout; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ArrayAdapter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; SwipeRefreshLayout.OnRefreshListener \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; REFRESH_COMPLETE = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;0X110\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; SwipeRefreshLayout mSwipeLayout; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ListView mListView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ArrayAdapter\u0026lt;String\u0026gt; mAdapter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;String\u0026gt; mDatas = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;String\u0026gt;(Arrays.asList(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Java\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Javascript\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;C++\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Ruby\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Json\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;HTML\u0026amp;#8221;\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler mHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(android.os.Message msg) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (msg.what) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; REFRESH_COMPLETE: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mDatas.addAll(Arrays.asList(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Lucene\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Canvas\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Bitmap\u0026amp;#8221;\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mAdapter.notifyDataSetChanged(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mSwipeLayout.setRefreshing(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@SuppressLint\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;InlinedApi\u0026amp;#8221;\u0026lt;/span\u0026gt;) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setContentView(R.layout.activity_main); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mListView = (ListView) findViewById(R.id.id_listview); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mSwipeLayout = (SwipeRefreshLayout) findViewById(R.id.id_swipe_ly); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mSwipeLayout.setOnRefreshListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mSwipeLayout.setColorScheme(android.R.color.holo_blue_bright, android.R.color.holo_green_light, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; android.R.color.holo_orange_light, android.R.color.holo_red_light); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mAdapter = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayAdapter\u0026lt;String\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, android.R.layout.simple_list_item_1, mDatas); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mListView.setAdapter(mAdapter); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onRefresh() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Log.e(\u0026amp;#8220;xxx\u0026amp;#8221;, Thread.currentThread().getName());\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// UI Thread\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mHandler.sendEmptyMessageDelayed(REFRESH_COMPLETE, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2000\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 好了，结束，我感觉效果挺好看的，不妨试试。\u0026amp;nbsp; 效果图： ![](http://img.blog.csdn.net/20140426144728031) \u0026amp;nbsp; \u0026amp;nbsp; ok ~ \u0026amp;nbsp; [源码点击此处下载](http://download.csdn.net/detail/lmj623565791/7256271) 转载：http://blog.csdn.net/lmj623565791/article/details/24521483 3 踩 ","permalink":"https://blog.zdltech.com/posts/android-swiperefreshlayout-%E5%AE%98%E6%96%B9%E4%B8%8B%E6%8B%89%E5%88%B7%E6%96%B0%E6%8E%A7%E4%BB%B6%E4%BB%8B%E7%BB%8D/","summary":"\u003cdiv id=\"article_content\" class=\"article_content\"\u003e\n\u003cpre\u003e\u003ccode\u003e下面App基本都有下拉刷新的功能，以前基本都使用XListView或者自己写一个下拉刷新，近期Google提供了一个官方的下拉刷新控件SwipeRefreshLayout，我感觉还不错啊，见惯了传统的下拉刷新，这个反而给人耳目一新的感觉（貌似知乎的APP已经使用这种下拉刷新了）。\n\n\n\n\n\nGoogle也在官方网站给出了V4的兼容包：\n\n\n\n\n\n![](http://img.blog.csdn.net/20140426143208625?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG1qNjIzNTY1Nzkx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\n\n\n\n\n顺便看一眼API呗：\n\n\n\n\n\n![](http://img.blog.csdn.net/20140426143234968?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG1qNjIzNTY1Nzkx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\n\n\n\n\n和XlistView差不多，还是很方便使用的，大概就这4个常用的方法，下面贴个简单的例子。\n\n\n\n\n\n1、布局文件：\n\n\n\n\n\n\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/lmj623565791/article/details/24521483#)[copy](http://blog.csdn.net/lmj623565791/article/details/24521483#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/313476)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/313476/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;android.support.v4.widget.SwipeRefreshLayout\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/id_swipe_ly\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;ListView\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/id_listview\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;ListView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;android.support.v4.widget.SwipeRefreshLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e2、MainActivty:\u0026amp;nbsp;\n\n\n\n\n\n\u0026amp;nbsp;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/24521483#)[copy](http://blog.csdn.net/lmj623565791/article/details/24521483#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/313476)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/313476/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * Created by Storm Zhang, Mar 31, 2014.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.zhy.swiperefreshlayoutdemo;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Arrays;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.annotation.SuppressLint;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Handler;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.support.v4.widget.SwipeRefreshLayout;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.Log;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ArrayAdapter;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; SwipeRefreshLayout.OnRefreshListener  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;{  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; REFRESH_COMPLETE = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;0X110\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; SwipeRefreshLayout mSwipeLayout;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ListView mListView;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ArrayAdapter\u0026lt;String\u0026gt; mAdapter;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;String\u0026gt; mDatas = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;String\u0026gt;(Arrays.asList(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Java\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Javascript\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;C++\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Ruby\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Json\u0026amp;#8221;\u0026lt;/span\u0026gt;,  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;HTML\u0026amp;#8221;\u0026lt;/span\u0026gt;));  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Handler mHandler = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Handler()  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; handleMessage(android.os.Message msg)  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (msg.what)  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; REFRESH_COMPLETE:  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                mDatas.addAll(Arrays.asList(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Lucene\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Canvas\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Bitmap\u0026amp;#8221;\u0026lt;/span\u0026gt;));  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                mAdapter.notifyDataSetChanged();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                mSwipeLayout.setRefreshing(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        };  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    };  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@SuppressLint\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;InlinedApi\u0026amp;#8221;\u0026lt;/span\u0026gt;)  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState)  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        setContentView(R.layout.activity_main);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mListView = (ListView) findViewById(R.id.id_listview);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mSwipeLayout = (SwipeRefreshLayout) findViewById(R.id.id_swipe_ly);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mSwipeLayout.setOnRefreshListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mSwipeLayout.setColorScheme(android.R.color.holo_blue_bright, android.R.color.holo_green_light,  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                android.R.color.holo_orange_light, android.R.color.holo_red_light);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mAdapter = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayAdapter\u0026lt;String\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, android.R.layout.simple_list_item_1, mDatas);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mListView.setAdapter(mAdapter);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onRefresh()  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Log.e(\u0026amp;#8220;xxx\u0026amp;#8221;, Thread.currentThread().getName());\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// UI Thread\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mHandler.sendEmptyMessageDelayed(REFRESH_COMPLETE, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2000\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e好了，结束，我感觉效果挺好看的，不妨试试。\u0026amp;nbsp;\n\n\n\n\n\n效果图：\n\n\n\n\n\n![](http://img.blog.csdn.net/20140426144728031)\n\n\n\n\n\n\u0026amp;nbsp;\n\n\n\n\n\n\u0026amp;nbsp;\n\n\n\n\n\nok ~\n\n\n\n\n\n\u0026amp;nbsp;\n\n\n\n\n\n[源码点击此处下载](http://download.csdn.net/detail/lmj623565791/7256271)\n\n\n\n\n\n转载：http://blog.csdn.net/lmj623565791/article/details/24521483\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv id=\"digg\"\u003e\n  \u003cdl id=\"btnDigg\" class=\"digg digg_enable\"\u003e\n    \u003cdd style=\"color: #ffffff;\"\u003e\n      3\n    \u003c/dd\u003e\n  \u003c/dl\u003e\n  \u003cdl id=\"btnBury\" class=\"digg digg_enable\"\u003e\n    \u003cdt style=\"color: #ffffff;\"\u003e\n      踩\n    \u003c/dt\u003e\n  \u003c/dl\u003e\n\u003c/div\u003e","title":"Android SwipeRefreshLayout 官方下拉刷新控件介绍"},{"content":"开源力量新版在线学习网站开通啦！ 我们同期开放了往期公开课的全部学习视频，在过去的一年里，55位技术大牛倾力奉献，超过1.8万人次共同参与了学习！\n马上学习吧，可以有更多的时间学习了，不如现在就开始吧！\n1.马万平 现任职于大型电信系统服务软件提供商讲“纠结中前行的配置管理 ”\n学习视频：http://www.osforce.cn/course/60\n2.邱剑 美团网技术部资深系统工程师讲“KVM虚拟机的性能优化”\n学习视频：http://www.osforce.cn/course/77\n3.章文嵩 阿里巴巴集团副总裁讲“拥抱开源，企业IT自主之路”\n学习视频：http://www.osforce.cn/course/67\n4.潘志彪 比特基金首席技术顾问讲“为什么比特币技术上是靠谱的”\n学习视频：http://www.osforce.cn/course/86\n5.Eric Linux内核华人贡献前10讲“Linux虚拟化技术”\n学习视频：http://www.osforce.cn/course/91\n6.Louis IBM Hadoop架构师讲“Hadoop大数据入门指引”\n学习视频：http://www.osforce.cn/course/87\n7.许智翔 python-segment和uniproxy的作者讲”Python入门指引“\n学习视频：http://www.osforce.cn/course/64\n8.施懿民 知平软件创始人讲”生产环境下的Java排错调优“\n学习视频：http://www.osforce.cn/course/55\n9.许式伟 七牛云存储CEO讲”Go语言入门“\n学习视频：http://www.osforce.cn/course/56\n10.宋宝华 《Linux设备驱动开发详解》作者讲”move to Linux 3.x for ARM“\n学习视频：http://www.osforce.cn/course/58\n11.鲁义明 开源项目 Gigah的维护人讲”跟我一起阅读Nginx源代码“\n学习视频：http://www.osforce.cn/course/59\n12.马钧 开源软件爱好者和学习者讲”一起来学Scala“\n学习视频：http://www.osforce.cn/course/61\n13.胡长城 盛大网络“Youni短信”技术总监讲“移动互联网研发团队的技术管理实践探讨”\n学习视频：http://www.osforce.cn/course/63\n14.莫华枫 盛大云存储技术负责人讲“云计算之对象存储的技术选择”\n学习视频：http://www.osforce.cn/course/65\n15.彭晨阳 Jdon.com自媒体主持人讲“Java事件编程”\n学习视频：http://www.osforce.cn/course/66\n16.祁宏 上海动量软件技术有限公司业务流程顾问讲“用开源软件构建App的高效服务端”\n学习视频：http://www.osforce.cn/course/68\n17.王伟 复旦视觉艺术新媒体学院教师讲“交互设计，不只是界面”\n学习视频：http://www.osforce.cn/course/70\n18.吴朱华 IBM中国研究院参与过多款云计算操作系统的开发工作讲“大数据的实时分析与应用案例分享”\n学习视频 ：http://www.osforce.cn/course/71\n19.郭雄飞 景略半导体嵌入系统设计经理讲“一个小团队的敏捷项目管理实践”\n学习视频：http://www.osforce.cn/course/72\n20.华康强 微软认证程序开发专家, 微软认证讲师讲”Windows8应用开发概览“\n学习视频：http://www.osforce.cn/course/73\n21.郭理靖 京东商城云平台开发者服务组高级经理讲“云开两朵，各表一枝–公、私有云架构异同点与难点”\n学习视频：http://www.osforce.cn/course/74\n22.陈沙克 IDC行业里从事云计算相关工作讲“跟我一起玩转OpenStack”\n学习视频：http://www.osforce.cn/course/75\n23.沈大海 移动互联网应用开发专家，开源技术讲师讲“教你用Cocos2D-X开发跨平台移动应用”\n学习视频：http://www.osforce.cn/course/76\n24.李皓 小米游戏运营中心技术总监讲“Think in Android”\n学习视频：http://www.osforce.cn/course/78\n25.谷瑞 RT-Thread内核开发成员讲“实时操作系统RT-Thread开发者专场”\n学习视频：http://www.osforce.cn/course/79\n26.李道兵 中文维基百科前管理员讲“HTTP协议相关的若干安全问题”\n学习视频：http://www.osforce.cn/course/84\n27.林鹏 当当网安全经理讲”网络安全渗透平台BackTrack5基础使用“\n学习视频：http://www.osforce.cn/course/85\n28. 由开源力量、CSDN CODE和多个开源社区共同主办的“我们的开源项目”暨开源力量”开源力量公开课2013年度庆典“\n学习视频：http://www.osforce.cn/course/89\n29.何晓阳 北京蓝海讯通科技有限公司CEO讲”应用性能管理的过去现在和未来“\n学习视频：http://www.osforce.cn/course/90\n30.蔡书 红帽软件解决方案架构师讲”另辟蹊径，基于轻量虚拟化的PaaS平台–RedHat OpenShift“\n学习视频：http://www.osforce.cn/course/92\n31.杨尚川 2013年度优秀开源项目APDPlat发起人，资深Nutch搜索引擎专家讲”Nutch:从搜索引擎到网络爬虫“\n学习视频：http://www.osforce.cn/course/93\n32.张建锋 JBossAS Core Developer讲”JBoss应用服务器架构体系和JavaEE的技术变革之路“\n学习视频：http://www.osforce.cn/course/94\n33.龙文选 黑鸭子中国首席专家讲”2013“我们的开源项目”\n学习视频：http://www.osforce.cn/course/95\n更多公开课，免费视频学习请关注官网：http://www.osforce.cn/\n","permalink":"https://blog.zdltech.com/posts/%E5%BC%80%E6%BA%90%E5%8A%9B%E9%87%8F%E6%96%B0%E7%89%88%E5%9C%A8%E7%BA%BF%E5%AD%A6%E4%B9%A0%E7%BD%91%E7%AB%99%E5%BC%80%E9%80%9A%E5%95%A6/","summary":"\u003cp\u003e开源力量新版在线学习网站开通啦！ 我们同期开放了往期公开课的全部学习视频，在过去的一年里，55位技术大牛倾力奉献，超过1.8万人次共同参与了学习！\u003cbr\u003e\n马上学习吧，可以有更多的时间学习了，不如现在就开始吧！\u003cbr\u003e\n1.马万平 现任职于大型电信系统服务软件提供商讲“纠结中前行的配置管理 ”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/60\u003cbr\u003e\n2.邱剑 美团网技术部资深系统工程师讲“KVM虚拟机的性能优化”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/77\u003cbr\u003e\n3.章文嵩 阿里巴巴集团副总裁讲“拥抱开源，企业IT自主之路”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/67\u003cbr\u003e\n4.潘志彪 比特基金首席技术顾问讲“为什么比特币技术上是靠谱的”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/86\u003cbr\u003e\n5.Eric Linux内核华人贡献前10讲“Linux虚拟化技术”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/91\u003c/p\u003e\n\u003cp\u003e6.Louis IBM Hadoop架构师讲“Hadoop大数据入门指引”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/87\u003cbr\u003e\n7.许智翔 python-segment和uniproxy的作者讲”Python入门指引“\u003c/p\u003e\n\u003cp\u003e学习视频：http://www.osforce.cn/course/64\u003c/p\u003e\n\u003cp\u003e8.施懿民 知平软件创始人讲”生产环境下的Java排错调优“\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/55\u003cbr\u003e\n9.许式伟 七牛云存储CEO讲”Go语言入门“\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/56\u003cbr\u003e\n10.宋宝华 《Linux设备驱动开发详解》作者讲”move to Linux 3.x for ARM“\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/58\u003cbr\u003e\n11.鲁义明 开源项目 Gigah的维护人讲”跟我一起阅读Nginx源代码“\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/59\u003cbr\u003e\n12.马钧 开源软件爱好者和学习者讲”一起来学Scala“\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/61\u003cbr\u003e\n13.胡长城 盛大网络“Youni短信”技术总监讲“移动互联网研发团队的技术管理实践探讨”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/63\u003cbr\u003e\n14.莫华枫 盛大云存储技术负责人讲“云计算之对象存储的技术选择”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/65\u003cbr\u003e\n15.彭晨阳 Jdon.com自媒体主持人讲“Java事件编程”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/66\u003cbr\u003e\n16.祁宏 上海动量软件技术有限公司业务流程顾问讲“用开源软件构建App的高效服务端”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/68\u003cbr\u003e\n17.王伟 复旦视觉艺术新媒体学院教师讲“交互设计，不只是界面”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/70\u003cbr\u003e\n18.吴朱华 IBM中国研究院参与过多款云计算操作系统的开发工作讲“大数据的实时分析与应用案例分享”\u003cbr\u003e\n学习视频 ：http://www.osforce.cn/course/71\u003cbr\u003e\n19.郭雄飞 景略半导体嵌入系统设计经理讲“一个小团队的敏捷项目管理实践”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/72\u003cbr\u003e\n20.华康强 微软认证程序开发专家, 微软认证讲师讲”Windows8应用开发概览“\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/73\u003cbr\u003e\n21.郭理靖 京东商城云平台开发者服务组高级经理讲“云开两朵，各表一枝–公、私有云架构异同点与难点”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/74\u003cbr\u003e\n22.陈沙克 IDC行业里从事云计算相关工作讲“跟我一起玩转OpenStack”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/75\u003cbr\u003e\n23.沈大海 移动互联网应用开发专家，开源技术讲师讲“教你用Cocos2D-X开发跨平台移动应用”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/76\u003cbr\u003e\n24.李皓 小米游戏运营中心技术总监讲“Think in Android”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/78\u003cbr\u003e\n25.谷瑞 RT-Thread内核开发成员讲“实时操作系统RT-Thread开发者专场”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/79\u003cbr\u003e\n26.李道兵 中文维基百科前管理员讲“HTTP协议相关的若干安全问题”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/84\u003cbr\u003e\n27.林鹏 当当网安全经理讲”网络安全渗透平台BackTrack5基础使用“\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/85\u003cbr\u003e\n28. 由开源力量、CSDN CODE和多个开源社区共同主办的“我们的开源项目”暨开源力量”开源力量公开课2013年度庆典“\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/89\u003cbr\u003e\n29.何晓阳 北京蓝海讯通科技有限公司CEO讲”应用性能管理的过去现在和未来“\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/90\u003cbr\u003e\n30.蔡书 红帽软件解决方案架构师讲”另辟蹊径，基于轻量虚拟化的PaaS平台–RedHat OpenShift“\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/92\u003cbr\u003e\n31.杨尚川 2013年度优秀开源项目APDPlat发起人，资深Nutch搜索引擎专家讲”Nutch:从搜索引擎到网络爬虫“\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/93\u003cbr\u003e\n32.张建锋 JBossAS Core Developer讲”JBoss应用服务器架构体系和JavaEE的技术变革之路“\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/94\u003cbr\u003e\n33.龙文选 黑鸭子中国首席专家讲”2013“我们的开源项目”\u003cbr\u003e\n学习视频：http://www.osforce.cn/course/95\u003cbr\u003e\n更多公开课，免费视频学习请关注官网：http://www.osforce.cn/\u003c/p\u003e","title":"开源力量新版在线学习网站开通啦！"},{"content":"How to install Nginx on Windows http://www.nginxtips.com/how-to-install-nginx-in-windows/\n下载windows的nginx压缩包，解压运行（nginx.exe）。\n端口占用导致win7下无法启动nginx服务器，启动（nginx.exe）窗口一闪而过，没有提示出来链接网络。\n修改nginx/conf/nginx.conf中\nserver {\nlisten 8011;（修改端口号就行了）\n……}\n再次运行（nginx.exe）是不是启动成功 输入http://localhost:8011/\n出现：\nWelcome to nginx! 恭喜你，nginx启动成功了！\n配置nginx到环境变量（主要下面命令要用，否则输入下面命令要带上nginx.exe的全路径）\nnginx常用命令\nnginx -s stop 强制关闭 nginx -s quit 安全关闭 nginx -s reload 改变配置文件的时候，重启nginx工作进程，来时配置文件生效 nginx -s reopen 打开日志文件\n常用配置 C:\\nginx\\conf\\nginx.conf,使用自己定义的conf文件如my.conf，命令为nginx -c conf\\my.conf 常用配置如下： Nginx.conf代码 http { server { #1.侦听80端口 listen 80; location / {\n2. 默认主页目录在nginx安装目录的html子目录。 root html; index index.html index.htm;\n3. 没有索引页时，罗列文件和子目录 autoindex on; autoindex_exact_size on; autoindex_localtime on; }\n4.指定虚拟目录 location /tshirt { alias D:\\programs\\Apache2\\htdocs\\tshirt; index index.html index.htm; } }\n5.虚拟主机www.emb.info配置 server { listen 80; server_name www.emb.info; access_log emb.info/logs/access.log; location / { index index.html; root emb.info/htdocs; } } }\nhttp { server { #1.侦听80端口 listen 80; location / {\n2. 默认主页目录在nginx安装目录的html子目录。 root html; index index.html index.htm;\n3. 没有索引页时，罗列文件和子目录 autoindex on; autoindex_exact_size on; autoindex_localtime on; }\n4.指定虚拟目录 location /tshirt { alias D:\\programs\\Apache2\\htdocs\\tshirt; index index.html index.htm; } }\n5.虚拟主机www.emb.info配置 server { listen 80; server_name www.emb.info; access_log emb.info/logs/access.log; location / { index index.html; root emb.info/htdocs; } } }\n小提示： 运行nginx -V可以查看该Win32平台编译版支持哪些模块。我这里的结果为： Log代码 nginx version: nginx/0.7.65 TLS SNI support enabled configure arguments:\nnginx version: nginx/0.7.65 TLS SNI support enabled configure arguments:\n显然，最经常用的memcache, rewrite模块都没在其中，因此该win32编译版本仅能供基本开发测试使用，对于产品平台，应该重新编译自己想要的win32版本，或者在linux下使用更方便。 查看nginx进程 tasklist /fi \u0026amp;#8220;imagename eq nginx.exe\u0026amp;#8221;，如下显示： 映像名称 PID 会话名 会话# 内存使用 ========================= ======== ================ =========== ============ nginx.exe 8944 Console 1 5,128 K nginx.exe 6712 Console 1 5,556 K\n","permalink":"https://blog.zdltech.com/posts/nginx%E8%B5%84%E6%96%99%E6%95%B4%E7%90%86/","summary":"\u003ch1 id=\"how-to-install-nginx-on-windows\"\u003eHow to install Nginx on Windows\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"http://www.nginxtips.com/how-to-install-nginx-in-windows/\"\u003ehttp://www.nginxtips.com/how-to-install-nginx-in-windows/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e下载windows的nginx压缩包，解压运行（nginx.exe）。\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"font-weight: bold; color: #000000;\"\u003e端口占用导致win7下无法启动nginx服务器，启动（nginx.exe）窗口一闪而过，没有提示出来链接网络。\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e修改nginx/conf/nginx.conf中\u003c/p\u003e\n\u003cp\u003eserver {\u003cbr\u003e\nlisten 8011;（修改端口号就行了）\u003c/p\u003e\n\u003cp\u003e……}\u003c/p\u003e\n\u003cp\u003e再次运行（nginx.exe）是不是启动成功 输入http://localhost:8011/\u003c/p\u003e\n\u003cp\u003e出现：\u003c/p\u003e\n\u003ch1 id=\"welcome-to-nginx\"\u003eWelcome to nginx!\u003c/h1\u003e\n\u003cp\u003e恭喜你，nginx启动成功了！\u003c/p\u003e\n\u003cp\u003e配置nginx到环境变量（主要下面命令要用，否则输入下面命令要带上nginx.exe的全路径）\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003enginx常用命令\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003enginx -s stop 强制关闭\nnginx -s quit 安全关闭\nnginx -s reload 改变配置文件的时候，重启nginx工作进程，来时配置文件生效\nnginx -s reopen 打开日志文件\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e常用配置\n\n\n\n\n\nC:\\nginx\\conf\\nginx.conf,使用自己定义的conf文件如my.conf，命令为nginx -c conf\\my.conf\n\n\n\n\n\n常用配置如下：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eNginx.conf代码\nhttp {\nserver {\n#1.侦听80端口\nlisten 80;\nlocation / {\u003c/p\u003e\n\u003ch1 id=\"2-默认主页目录在nginx安装目录的html子目录\"\u003e2. 默认主页目录在nginx安装目录的html子目录。\u003c/h1\u003e\n\u003cp\u003eroot html;\nindex index.html index.htm;\u003c/p\u003e\n\u003ch1 id=\"3-没有索引页时罗列文件和子目录\"\u003e3. 没有索引页时，罗列文件和子目录\u003c/h1\u003e\n\u003cp\u003eautoindex on;\nautoindex_exact_size on;\nautoindex_localtime on;\n}\u003c/p\u003e","title":"nginx资料整理"},{"content":"中文的维基百科：http://wiki.nginx.org/NginxChs\n以下内容转自http://zyan.cc/nginx_php_v6/\n前言：本文是我撰写的关于搭建“Nginx + PHP（FastCGI）”Web服务器的第6篇文章。本系列文章作为国内最早详细介绍 Nginx + PHP 安装、配置、使用的资料之一，为推动 Nginx 在国内的发展产生了积极的作用。本文可能不断更新小版本，请记住原文链接“http://blog.zyan.cc/nginx_php_v6/”，获取最新内容。第6篇文章主要介绍了Nginx 0.8.x新的平滑重启方式，将PHP升级到了5.2.14，修正了PEAR问题。另将MySQL 5.1.x升级到了5.5.x系列，配置文件变更较大。　链接：《2007年9月的第1版》、《2007年12月的第2版》、《2008年6月的第3版》、《2008年8月的第4版》、《2009年5月的第5版》　Nginx (“engine x”) 是一个高性能的 HTTP 和反向代理服务器，也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的，它已经在该站点运行超过三年了。Igor 将源代码以类BSD许可证的形式发布。　Nginx 超越 Apache 的高性能和稳定性，使得国内使用 Nginx 作为 Web 服务器的网站也越来越多，其中包括新浪博客、新浪播客、网易新闻、腾讯网、搜狐博客等门户网站频道，六间房、56.com等视频分享网站，Discuz!官方论坛、水木社区等知名论坛，盛大在线\u0026lt;sp\n","permalink":"https://blog.zdltech.com/posts/nginx-0-8-x-php-5-2-13fastcgi%E6%90%AD%E5%BB%BA%E8%83%9C%E8%BF%87apache%E5%8D%81%E5%80%8D%E7%9A%84web%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AC%AC6%E7%89%88/","summary":"\u003cp\u003e中文的维基百科：http://wiki.nginx.org/NginxChs\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e以下内容转自http://zyan.cc/nginx_php_v6/\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #000000;\"\u003e前言：本文是我撰写的关于搭建“Nginx + PHP（FastCGI）”Web服务器的第6篇文章。本系列文章作为国内最早详细介绍 Nginx + PHP 安装、配置、使用的资料之一，为推动 Nginx 在国内的发展产生了积极的作用。本文可能不断更新小版本，请记住原文链接“\u003c/span\u003e\u003ca href=\"http://blog.zyan.cc/nginx_php_v6/\"\u003ehttp://blog.zyan.cc/nginx_php_v6/\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e”，获取最新内容。第6篇文章主要介绍了Nginx 0.8.x新的平滑重启方式，将PHP升级到了5.2.14，修正了PEAR问题。另将MySQL 5.1.x升级到了5.5.x系列，配置文件变更较大。\u003c/span\u003e\u003cbr style=\"color: #000000;\" /\u003e\u003cbr style=\"color: #000000;\" /\u003e\u003cspan style=\"color: #000000;\"\u003e　　链接：《\u003c/span\u003e\u003ca href=\"http://zyan.cc/post/297/\"\u003e2007年9月的第1版\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e》、《\u003c/span\u003e\u003ca href=\"http://zyan.cc/post/314/\"\u003e2007年12月的第2版\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e》、《\u003c/span\u003e\u003ca href=\"http://zyan.cc/post/351/\"\u003e2008年6月的第3版\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e》、《\u003c/span\u003e\u003ca href=\"http://zyan.cc/nginx_php_v4/\"\u003e2008年8月的第4版\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e》、《\u003c/span\u003e\u003ca href=\"http://zyan.cc/nginx_php_v5/\"\u003e2009年5月的第5版\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e》\u003c/span\u003e\u003cbr style=\"color: #000000;\" /\u003e\u003cbr style=\"color: #000000;\" /\u003e\u003cspan style=\"color: #000000;\"\u003e　　\u003c/span\u003e\u003ca href=\"http://zyan.cc/attachment/200806/nginx.png\"\u003e\u003cimg alt=\"点击在新窗口中浏览此图片\" loading=\"lazy\" src=\"http://zyan.cc/attachment/200806/nginx.png\"\u003e\u003c/a\u003e\u003cbr style=\"color: #000000;\" /\u003e\u003cbr style=\"color: #000000;\" /\u003e\u003cspan style=\"color: #000000;\"\u003e　　\u003c/span\u003e\u003ca href=\"http://www.nginx.net/\"\u003eNginx\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e (“engine x”) 是一个高性能的 HTTP 和反向代理服务器，也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的，它已经在该站点运行超过三年了。Igor 将源代码以类BSD许可证的形式发布。\u003c/span\u003e\u003cbr style=\"color: #000000;\" /\u003e\u003cbr style=\"color: #000000;\" /\u003e\u003cspan style=\"color: #000000;\"\u003e　　Nginx 超越 Apache 的高性能和稳定性，使得国内使用 Nginx 作为 Web 服务器的网站也越来越多，其中包括\u003c/span\u003e\u003ca href=\"http://blog.sina.com.cn/\"\u003e新浪博客\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e、\u003c/span\u003e\u003ca href=\"http://v.sina.com.cn/\"\u003e新浪播客\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e、\u003c/span\u003e\u003ca href=\"http://news.163.com/\"\u003e网易新闻\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e、\u003c/span\u003e\u003ca href=\"http://www.qq.com/\"\u003e腾讯网\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e、\u003c/span\u003e\u003ca href=\"http://blog.sohu.com/\"\u003e搜狐博客\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e等门户网站频道，\u003c/span\u003e\u003ca href=\"http://www.6.cn/\"\u003e六间房\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e、\u003c/span\u003e\u003ca href=\"http://www.56.com/\"\u003e56.com\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e等视频分享网站，\u003c/span\u003e\u003ca href=\"http://www.discuz.net/\"\u003eDiscuz!官方论坛\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e、\u003c/span\u003e\u003ca href=\"http://www.newsmth.net/\"\u003e水木社区\u003c/a\u003e\u003cspan style=\"color: #000000;\"\u003e等知名论坛，\u003c/span\u003e\u003ca href=\"http://www.sdo.com/\"\u003e盛大在线\u003c/a\u003e\u0026lt;sp\u003c/p\u003e","title":"Nginx 0.8.x + PHP 5.2.13（FastCGI）搭建胜过Apache十倍的Web服务器（第6版）"},{"content":"Host文件目录C:\\Windows\\System32\\drivers\\etc\n# Copyright (c) 1993-2009 Microsoft Corp.\n# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.\n# This file contains the mappings of IP addresses to host names. Each\n# entry should be kept on an individual line. The IP address should\n# be placed in the first column followed by the corresponding host name.\n# The IP address and the host name should be separated by at least one\n# space.\n# Additionally, comments (such as these) may be inserted on individual\n# lines or following the machine name denoted by a ‘#’ symbol.\n# For example:\n# 102.54.94.97 rhino.acme.com # source server\n# 38.25.63.10 x.acme.com # x client host\n# localhost name resolution is handled within DNS itself.\n# 127.0.0.1 localhost\n# ::1 localhost\n127.0.0.1 activate.adobe.com\n127.0.0.1 practivate.adobe.com\n127.0.0.1 ereg.adobe.com\n127.0.0.1 activate.wip3.adobe.com\n127.0.0.1 wip3.adobe.com\n127.0.0.1 3dns-3.adobe.com\n127.0.0.1 3dns-2.adobe.com\n127.0.0.1 adobe-dns.adobe.com\n127.0.0.1 adobe-dns-2.adobe.com\n127.0.0.1 adobe-dns-3.adobe.com\n127.0.0.1 ereg.wip3.adobe.com\n127.0.0.1 activate-sea.adobe.com\n127.0.0.1 wwis-dubc1-vip60.adobe.com\n127.0.0.1 activate-sjc0.adobe.com\n127.0.0.1 65.52.240.48\n127.0.0.1 activation.cloud.techsmith.com\n127.0.0.1 www.bandicam.com\n#74.125.31.82 android.googlesource.com\n#74.125.31.82 www.googlesource.com\n#203.208.46.172 cache.pack.google.com\n#59.24.3.173 cache.pack.google.com\n#SmartHosts START\n216.239.32.6 0.docs.google.com\n216.239.32.6 0.drive.google.com\n216.239.32.6 1.docs.google.com\n216.239.32.6 1.drive.google.com\n216.239.32.6 10.docs.google.com\n216.239.32.6 10.drive.google.com\n216.239.32.6 11.docs.google.com\n216.239.32.6 11.drive.google.com\n216.239.32.6 12.docs.google.com\n216.239.32.6 12.drive.google.com\n216.239.32.6 13.docs.google.com\n216.239.32.6 13.drive.google.com\n216.239.32.6 14.docs.google.com\n216.239.32.6 14.drive.google.com\n216.239.32.6 15.docs.google.com\n216.239.32.6 15.drive.google.com\n216.239.32.6 16.docs.google.com\n216.239.32.6 16.drive.google.com\n216.239.32.6 2.docs.google.com\n216.239.32.6 2.drive.google.com\n216.239.32.6 3.docs.google.com\n216.239.32.6 3.drive.google.com\n216.239.32.6 4.docs.google.com\n216.239.32.6 4.drive.google.com\n216.239.32.6 5.docs.google.com\n216.239.32.6 5.drive.google.com\n216.239.32.6 6.docs.google.com\n216.239.32.6 6.drive.google.com\n216.239.32.6 7.docs.google.com\n216.239.32.6 7.drive.google.com\n216.239.32.6 8.docs.google.com\n216.239.32.6 8.drive.google.com\n216.239.32.6 9.docs.google.com\n216.239.32.6 9.drive.google.com\n216.239.32.6 admin.google.com\n216.239.32.6 answers.google.com\n216.239.32.6 appengine.google.com\n216.239.32.6 apps.google.com\n216.239.32.6 appspot.l.google.com\n216.239.32.6 bks0.books.google.com\n216.239.32.6 bks1.books.google.com\n216.239.32.6 bks10.books.google.com\n216.239.32.6 bks2.books.google.com\n216.239.32.6 bks3.books.google.com\n216.239.32.6 bks4.books.google.com\n216.239.32.6 bks5.books.google.com\n216.239.32.6 bks6.books.google.com\n216.239.32.6 bks7.books.google.com\n216.239.32.6 bks8.books.google.com\n216.239.32.6 bks9.books.google.com\n216.239.32.6 blogsearch.google.com\n216.239.32.6 books.google.com\n216.239.32.6 browserchannel-docs.l.google.com\n216.239.32.6 browserchannel-spreadsheets.l.google.com\n216.239.32.6 browsersync.google.com\n216.239.32.6 browsersync.l.google.com\n216.239.32.6 buzz.google.com\n216.239.32.6 cache.l.google.com\n216.239.32.6 cache.pack.google.com\n216.239.32.6 calendar.google.com\n216.239.32.6 cbk0.google.com\n216.239.32.6 cbk1.google.com\n216.239.32.6 cbk2.google.com\n216.239.32.6 cbk3.google.com\n216.239.32.6 cbks0.google.com\n216.239.32.6 cbks1.google.com\n216.239.32.6 cbks2.google.com\n216.239.32.6 cbks3.google.com\n216.239.32.6 chart.apis.google.com\n216.239.32.6 chrome.google.com\n216.239.32.6 code.google.com\n216.239.32.6 code.l.google.com\n216.239.32.6 csi.l.google.com\n216.239.32.6 desktop.google.com\n216.239.32.6 desktop.l.google.com\n216.239.32.6 desktop2.google.com\n216.239.32.6 developers.google.com\n216.239.32.6 ditu.google.com\n216.239.32.6 dl.google.com\n216.239.32.6 dl.l.google.com\n216.239.32.6 dl-ssl.google.com\n216.239.32.6 docs.google.com\n216.239.32.6 docs0.google.com\n216.239.32.6 docs1.google.com\n216.239.32.6 docs2.google.com\n216.239.32.6 docs3.google.com\n216.239.32.6 docs4.google.com\n216.239.32.6 docs5.google.com\n216.239.32.6 docs6.google.com\n216.239.32.6 docs7.google.com\n216.239.32.6 docs8.google.com\n216.239.32.6 docs9.google.com\n216.239.32.6 drive.google.com\n216.239.32.6 drive0.google.com\n216.239.32.6 drive1.google.com\n216.239.32.6 drive2.google.com\n216.239.32.6 drive3.google.com\n216.239.32.6 drive4.google.com\n216.239.32.6 drive5.google.com\n216.239.32.6 drive6.google.com\n216.239.32.6 drive7.google.com\n216.239.32.6 drive8.google.com\n216.239.32.6 drive9.google.com\n216.239.32.6 earth.google.com\n216.239.32.6 encrypted.google.com\n216.239.32.6 encrypted-tbn.l.google.com\n216.239.32.6 encrypted-tbn0.google.com\n216.239.32.6 encrypted-tbn1.google.com\n216.239.32.6 encrypted-tbn2.google.com\n216.239.32.6 encrypted-tbn3.google.com\n216.239.32.6 feedburner.google.com\n216.239.32.6 feedproxy.google.com\n216.239.32.6 finance.google.com\n216.239.32.6 fusion.google.com\n216.239.32.6 geoauth.google.com\n216.239.32.6 gg.google.com\n216.239.32.6 ghs.google.com\n216.239.32.6 ghs.l.google.com\n216.239.32.6 ghs46.google.com\n216.239.32.6 ghs46.l.google.com\n216.239.32.6 google.com\n216.239.32.6 googleapis.l.google.com\n216.239.32.6 googleapis-ajax.google.com\n216.239.32.6 googleapis-ajax.l.google.com\n216.239.32.6 googlecode.l.google.com\n216.239.32.6 google-public-dns-a.google.com\n216.239.32.6 google-public-dns-b.google.com\n216.239.32.6 goto.google.com\n216.239.32.6 groups.google.com\n216.239.32.6 groups.l.google.com\n216.239.32.6 groups-beta.google.com\n216.239.32.6 gxc.google.com\n216.239.32.6 id.google.com\n216.239.32.6 id.l.google.com\n216.239.32.6 images.google.com\n216.239.32.6 images.l.google.com\n216.239.32.6 investor.google.com\n216.239.32.6 jmt0.google.com\n216.239.32.6 kh.google.com\n216.239.32.6 kh.l.google.com\n216.239.32.6 khm.google.com\n216.239.32.6 khm.l.google.com\n216.239.32.6 khm0.google.com\n216.239.32.6 khm1.google.com\n216.239.32.6 khm2.google.com\n216.239.32.6 khm3.google.com\n216.239.32.6 khmdb.google.com\n216.239.32.6 khms.google.com\n216.239.32.6 khms.l.google.com\n216.239.32.6 khms0.google.com\n216.239.32.6 khms1.google.com\n216.239.32.6 khms2.google.com\n216.239.32.6 khms3.google.com\n216.239.32.6 labs.google.com\n216.239.32.6 large-uploads.l.google.com\n216.239.32.6 lh2.google.com\n216.239.32.6 lh2.l.google.com\n216.239.32.6 lh3.google.com\n216.239.32.6 lh4.google.com\n216.239.32.6 lh5.google.com\n216.239.32.6 lh6.google.com\n216.239.32.6 linkhelp.clients.google.com\n216.239.32.6 local.google.com\n216.239.32.6 m.google.com\n216.239.32.6 map.google.com\n216.239.32.6 maps.google.com\n216.239.32.6 maps.l.google.com\n216.239.32.6 maps-api-ssl.google.com\n216.239.32.6 mars.google.com\n216.239.32.6 mobile.l.google.com\n216.239.32.6 mobile-gtalk.l.google.com\n216.239.32.6 mobilemaps.clients.google.com\n216.239.32.6 mt.google.com\n216.239.32.6 mt.l.google.com\n216.239.32.6 mt0.google.com\n216.239.32.6 mt1.google.com\n216.239.32.6 mt2.google.com\n216.239.32.6 mt3.google.com\n216.239.32.6 mtalk.google.com\n216.239.32.6 mts.google.com\n216.239.32.6 mts.l.google.com\n216.239.32.6 mts0.google.com\n216.239.32.6 mts1.google.com\n216.239.32.6 mts2.google.com\n216.239.32.6 mts3.google.com\n216.239.32.6 music.google.com\n216.239.32.6 music-streaming.l.google.com\n216.239.32.6 mw1.google.com\n216.239.32.6 mw2.google.com\n216.239.32.6 news.google.com\n216.239.32.6 news.l.google.com\n216.239.32.6 pack.google.com\n216.239.32.6 photos.google.com\n216.239.32.6 photos-ugc.l.google.com\n216.239.32.6 picasa.google.com\n216.239.32.6 picasaweb.google.com\n216.239.32.6 picasaweb.l.google.com\n216.239.32.6 places.google.com\n216.239.32.6 play.google.com\n216.239.32.6 productforums.google.com\n216.239.32.6 profiles.google.com\n216.239.32.6 reader.google.com\n216.239.32.6 safebrowsing.cache.l.google.com\n216.239.32.6 safebrowsing.clients.google.com\n216.239.32.6 safebrowsing.google.com\n216.239.32.6 safebrowsing-cache.google.com\n216.239.32.6 sb.google.com\n216.239.32.6 sb.l.google.com\n216.239.32.6 sb-ssl.google.com\n216.239.32.6 sb-ssl.l.google.com\n216.239.32.6 scholar.google.com\n216.239.32.6 scholar.l.google.com\n216.239.32.6 script.google.com\n216.239.32.6 services.google.com\n216.239.32.6 sites.google.com\n216.239.32.6 sketchup.google.com\n216.239.32.6 sketchup.l.google.com\n216.239.32.6 spreadsheet.google.com\n216.239.32.6 spreadsheets.google.com\n216.239.32.6 spreadsheets.l.google.com\n216.239.32.6 spreadsheets0.google.com\n216.239.32.6 spreadsheets1.google.com\n216.239.32.6 spreadsheets2.google.com\n216.239.32.6 spreadsheets3.google.com\n216.239.32.6 spreadsheets4.google.com\n216.239.32.6 spreadsheets5.google.com\n216.239.32.6 spreadsheets6.google.com\n216.239.32.6 spreadsheets7.google.com\n216.239.32.6 spreadsheets8.google.com\n216.239.32.6 spreadsheets9.google.com\n216.239.32.6 spreadsheets-china.l.google.com\n216.239.32.6 suggestqueries.google.com\n216.239.32.6 suggestqueries.l.google.com\n216.239.32.6 support.google.com\n216.239.32.6 tbn0.google.com\n216.239.32.6 tbn1.google.com\n216.239.32.6 tbn2.google.com\n216.239.32.6 tbn3.google.com\n216.239.32.6 toolbar.google.com\n216.239.32.6 toolbarqueries.clients.google.com\n216.239.32.6 toolbarqueries.google.com\n216.239.32.6 toolbarqueries.l.google.com\n216.239.32.6 tools.google.com\n216.239.32.6 tools.l.google.com\n216.239.32.6 translate.google.com\n216.239.32.6 trends.google.com\n216.239.32.6 upload.docs.google.com\n216.239.32.6 upload.drive.google.com\n216.239.32.6 uploads.code.google.com\n216.239.32.6 uploadsj.clients.google.com\n216.239.32.6 v3.cache1.c.docs.google.com\n216.239.32.6 video.google.com\n216.239.32.6 video-stats.l.google.com\n216.239.32.6 voice.google.com\n216.239.32.6 wallet.google.com\n216.239.32.6 wire.l.google.com\n216.239.32.6 writely.google.com\n216.239.32.6 writely.l.google.com\n216.239.32.6 writely-china.l.google.com\n216.239.32.6 writely-com.l.google.com\n216.239.32.6 www.l.google.com\n216.239.32.6 www2.l.google.com\n216.239.32.6 www3.l.google.com\n216.239.32.6 www4.l.google.com\n216.239.32.6 ytstatic.l.google.com\n216.239.32.6 plus.google.com\n216.239.32.6 plus.url.google.com\n216.239.32.6 plusone.google.com\n216.239.32.6 www.google.com\n216.239.32.6 ssl.google-analytics.com\n216.239.32.6 www.google-analytics.com\n216.239.32.6 accounts.l.google.com\n216.239.32.6 checkout.l.google.com\n216.239.32.6 sandbox.google.com\n216.239.32.6 wifi.google.com\n216.239.32.6 wifi.l.google.com\n216.239.32.6 clients.l.google.com\n216.239.32.6 clients1.google.com\n216.239.32.6 clients2.google.com\n216.239.32.6 clients3.google.com\n216.239.32.6 clients4.google.com\n216.239.32.6 clients5.google.com\n216.239.32.6 clients7.google.com\n74.125.20.115 checkout.google.com\n74.125.21.84 accounts.google.com\n74.125.26.193 m.google.com\n74.125.22.113 adwords.google.com\n74.125.129.125 talk.google.com\n74.125.70.17 mail.google.com\n74.125.22.189 filetransferenabled.mail.google.com\n74.125.22.189 chatenabled.mail.google.com\n216.239.32.6 apis.google.com\n216.239.32.6 clients6.google.com\n74.125.205.95 talkgadget.google.com\n74.125.22.133 0-open-opensocial.googleusercontent.com\n74.125.22.133 0-focus-opensocial.googleusercontent.com\n74.125.22.133 1-focus-opensocial.googleusercontent.com\n74.125.22.133 1-open-opensocial.googleusercontent.com\n74.125.22.133 1-ps.googleusercontent.com\n74.125.22.133 2-focus-opensocial.googleusercontent.com\n74.125.22.133 2-open-opensocial.googleusercontent.com\n74.125.22.133 2-ps.googleusercontent.com\n74.125.22.133 3-focus-opensocial.googleusercontent.com\n74.125.22.133 3-ps.googleusercontent.com\n74.125.22.133 3hdrrlnlknhi77nrmsjnjr152ueo3soc-a-calendar-opensocial.googleusercontent.com\n74.125.22.133 3-open-opensocial.googleusercontent.com\n74.125.22.133 4-ps.googleusercontent.com\n74.125.22.133 4fjvqid3r3oq66t548clrdj52df15coc-a-oz-opensocial.googleusercontent.com\n74.125.22.133 53rd6p0catml6vat6qra84rs0del836d-a-oz-opensocial.googleusercontent.com\n74.125.22.133 59cbv4l9s05pbaks9v77vc3mengeqors-a-oz-opensocial.googleusercontent.com\n74.125.22.133 8kubpeu8314p2efdd7jlv09an9i2ljdo-a-oz-opensocial.googleusercontent.com\n74.125.22.133 adstvca8k2ooaknjjmv89j22n9t676ve-a-oz-opensocial.googleusercontent.com\n74.125.22.133 a-oz-opensocial.googleusercontent.com\n74.125.22.133 blogger.googleusercontent.com\n74.125.22.133 bt26mravu2qpe56n8gnmjnpv2inl84bf-a-oz-opensocial.googleusercontent.com\n74.125.22.133 clients1.googleusercontent.com\n74.125.22.133 clients2.googleusercontent.com\n74.125.22.133 clients3.googleusercontent.com\n74.125.22.133 clients4.googleusercontent.com\n74.125.22.133 clients5.googleusercontent.com\n74.125.22.133 clients6.googleusercontent.com\n74.125.22.133 clients7.googleusercontent.com\n74.125.22.133 code-opensocial.googleusercontent.com\n74.125.22.133 debh8vg7vd93bco3prdajidmm7dhql3f-a-oz-opensocial.googleusercontent.com\n74.125.22.133 doc-00-7o-docs.googleusercontent.com\n74.125.22.133 doc-08-7o-docs.googleusercontent.com\n74.125.22.133 doc-0c-7o-docs.googleusercontent.com\n74.125.22.133 doc-0g-7o-docs.googleusercontent.com\n74.125.22.133 doc-0s-7o-docs.googleusercontent.com\n74.125.22.133 doc-10-7o-docs.googleusercontent.com\n74.125.22.133 doc-14-7o-docs.googleusercontent.com\n74.125.22.133 feedback.googleusercontent.com\n74.125.22.133 googlehosted.l.googleusercontent.com\n74.125.22.133 gp0.googleusercontent.com\n74.125.22.133 gp1.googleusercontent.com\n74.125.22.133 gp2.googleusercontent.com\n74.125.22.133 gp3.googleusercontent.com\n74.125.22.133 gp4.googleusercontent.com\n74.125.22.133 gp5.googleusercontent.com\n74.125.22.133 gp6.googleusercontent.com\n74.125.22.133 hsco54a20sh11q9jkmb51ad2n3hmkmrg-a-oz-opensocial.googleusercontent.com\n74.125.22.133 i8brh95qor6r54nkl52hidj2ggcs4jgm-a-oz-opensocial.googleusercontent.com\n74.125.22.133 images1-focus-opensocial.googleusercontent.com\n74.125.22.133 images2-focus-opensocial.googleusercontent.com\n74.125.22.133 images3-focus-opensocial.googleusercontent.com\n74.125.22.133 images4-focus-opensocial.googleusercontent.com\n74.125.22.133 images5-focus-opensocial.googleusercontent.com\n74.125.22.133 images6-focus-opensocial.googleusercontent.com\n74.125.22.133 images7-focus-opensocial.googleusercontent.com\n74.125.22.133 images8-focus-opensocial.googleusercontent.com\n74.125.22.133 images9-focus-opensocial.googleusercontent.com\n74.125.22.133 images-docs-opensocial.googleusercontent.com\n74.125.22.133 images-oz-opensocial.googleusercontent.com\n74.125.22.133 k6v18tjr24doa89b55o3na41kn4v73eb-a-oz-opensocial.googleusercontent.com\n74.125.22.133 lh1.googleusercontent.com\n74.125.22.133 lh2.googleusercontent.com\n74.125.22.133 lh3.googleusercontent.com\n74.125.22.133 lh4.googleusercontent.com\n74.125.22.133 lh5.googleusercontent.com\n74.125.22.133 lh6.googleusercontent.com\n74.125.22.133 mail-attachment.googleusercontent.com\n74.125.22.133 music.googleusercontent.com\n74.125.22.133 music-onebox.googleusercontent.com\n74.125.22.133 oauth.googleusercontent.com\n74.125.22.133 ob7f2qc0i50kbjnc81vkhgmb5hsv7a8l-a-oz-opensocial.googleusercontent.com\n74.125.22.133 ode25pfjgmvpquh3b1oqo31ti5ibg5fr-a-calendar.opensocial.googleusercontent.com\n74.125.22.133 qhie5b8u979rnch1q0hqbrmbkn9estf7-a-oz-opensocial.googleusercontent.com\n74.125.22.133 r70rmsn4s0rhk6cehcbbcbfbs31pu0va-a-oz-opensocial.googleusercontent.com\n74.125.22.133 rbjhe237k979f79d87gmenp3gejfonu9-a-oz-opensocial.googleusercontent.com\n74.125.22.133 s1.googleusercontent.com\n74.125.22.133 s2.googleusercontent.com\n74.125.22.133 s3.googleusercontent.com\n74.125.22.133 s4.googleusercontent.com\n74.125.22.133 s5.googleusercontent.com\n74.125.22.133 s6.googleusercontent.com\n74.125.22.133 spreadsheets-opensocial.googleusercontent.com\n74.125.22.133 static.googleusercontent.com\n74.125.22.133 t.doc-0-0-sj.sj.googleusercontent.com\n74.125.22.133 themes.googleusercontent.com\n74.125.22.133 translate.googleusercontent.com\n74.125.22.133 u807isd5egseeabjccgcns005p2miucq-a-oz-opensocial.googleusercontent.com\n74.125.22.133 upt14k1i2veesusrda9nfotcrbp9d7p5-a-oz-opensocial.googleusercontent.com\n74.125.22.133 webcache.googleusercontent.com\n74.125.22.133 www.googleusercontent.com\n74.125.22.133 www-calendar-opensocial.googleusercontent.com\n74.125.22.133 www-fc-opensocial.googleusercontent.com\n74.125.22.133 www-focus-opensocial.googleusercontent.com\n74.125.22.133 www-gm-opensocial.googleusercontent.com\n74.125.22.133 www-kix-opensocial.googleusercontent.com\n74.125.22.133 www-open-opensocial.googleusercontent.com\n74.125.22.133 www-opensocial.googleusercontent.com\n74.125.22.133 www-opensocial-sandbox.googleusercontent.com\n74.125.22.133 www-oz-opensocial.googleusercontent.com\n74.125.22.133 www-hangouts-opensocial.googleusercontent.com\n74.125.22.133 www-onepick-opensocial.googleusercontent.com\n74.125.22.133 lh1.ggpht.com\n74.125.22.133 lh2.ggpht.com\n74.125.22.133 lh3.ggpht.com\n74.125.22.133 lh4.ggpht.com\n74.125.22.133 lh5.ggpht.com\n74.125.22.133 lh6.ggpht.com\n74.125.22.133 nt0.ggpht.com\n74.125.22.133 nt1.ggpht.com\n74.125.22.133 nt2.ggpht.com\n74.125.22.133 nt3.ggpht.com\n74.125.22.133 nt4.ggpht.com\n74.125.22.133 nt5.ggpht.com\n173.194.37.207 csi.gstatic.com\n173.194.37.207 g0.gstatic.com\n173.194.37.207 g1.gstatic.com\n173.194.37.207 g2.gstatic.com\n173.194.37.207 g3.gstatic.com\n173.194.37.207 maps.gstatic.com\n173.194.37.207 mt0.gstatic.com\n173.194.37.207 mt1.gstatic.com\n173.194.37.207 mt2.gstatic.com\n173.194.37.207 mt3.gstatic.com\n173.194.37.207 mt4.gstatic.com\n173.194.37.207 mt5.gstatic.com\n173.194.37.207 mt6.gstatic.com\n173.194.37.207 mt7.gstatic.com\n173.194.37.207 ssl.gstatic.com\n173.194.37.207 t0.gstatic.com\n173.194.37.207 t1.gstatic.com\n173.194.37.207 t2.gstatic.com\n173.194.37.207 t3.gstatic.com\n173.194.37.207 www.gstatic.com\n74.125.205.95 ajax.mxyuncdn.com\n74.125.205.95 chart.mxyuncdn.com\n74.125.205.95 fonts.mxyuncdn.com\n74.125.205.95 maps.mxyuncdn.com\n74.125.205.95 mt0.mxyuncdn.com\n74.125.205.95 mt1.mxyuncdn.com\n74.125.205.95 mt2.mxyuncdn.com\n74.125.205.95 mt3.mxyuncdn.com\n74.125.205.95 redirector-bigcache.mxyuncdn.com\n74.125.205.95 translate.mxyuncdn.com\n74.125.205.95 www.mxyuncdn.com\n74.125.26.141 appspot.com\n74.125.26.141 chrometophone.appspot.com\n74.125.26.141 evolutionofweb.appspot.com\n74.125.26.141 googcloudlabs.appspot.com\n74.125.26.141 gv-gadget.appspot.com\n74.125.26.141 magnifier.blogspot.com\n74.125.26.141 moderator.appspot.com\n74.125.26.141 newsfeed-dot-latest-dot-rovio-ad-engine.appspot.com\n74.125.26.141 productideas.appspot.com\n74.125.26.141 project-slingshot-gp.appspot.com\n74.125.26.141 r2303.latest.project-slingshot-hr.appspot.com\n74.125.26.141 r3085-dot-latest-dot-project-slingshot-gp.appspot.com\n74.125.26.141 r3091-dot-latest-dot-project-slingshot-gp.appspot.com\n74.125.26.141 r3101-dot-latest-dot-project-slingshot-gp.appspot.com\n74.125.26.141 r3269-dot-latest-dot-project-slingshot-gp.appspot.com\n74.125.26.141 r3432-dot-latest-dot-project-slingshot-hr.appspot.com\n74.125.26.141 r4681-dot-latest-dot-project-slingshot-hr.appspot.com\n74.125.26.141 r7647-dot-latest-dot-project-slingshot-hr.appspot.com\n74.125.26.141 wcproxyx.appspot.com\n74.125.26.141 balsamiqgdrive.appspot.com\n74.125.26.141 www.appspot.com\n74.125.26.82 autoproxy-gfwlist.googlecode.com\n74.125.26.82 chromium.googlecode.com\n74.125.26.82 closure-library.googlecode.com\n74.125.26.82 earth-api-samples.googlecode.com\n74.125.26.82 gmaps-samples-flash.googlecode.com\n74.125.26.82 google-code-feed-gadget.googlecode.com\n74.125.26.82 smarthosts.googlecode.com\n74.125.26.82 ipv6-hosts.googlecode.com\n216.239.32.6 accounts.youtube.com\n216.239.32.6 apiblog.youtube.com\n216.239.32.6 help.youtube.com\n216.239.32.6 insight.youtube.com\n216.239.32.6 m.youtube.com\n216.239.32.6 ytimg.l.google.com\n216.239.32.6 www.youtube.com\n216.239.32.6 i.ytimg.com\n216.239.32.6 i1.ytimg.com\n216.239.32.6 i2.ytimg.com\n216.239.32.6 i3.ytimg.com\n216.239.32.6 i4.ytimg.com\n216.239.32.6 s.ytimg.com\n216.239.32.6 blogsearch.google.cn\n216.239.32.6 ditu.google.cn\n216.239.32.6 gg.google.cn\n216.239.32.6 id.google.cn\n216.239.32.6 maps.gstatic.cn\n216.239.32.6 m.google.cn\n216.239.32.6 mt.google.cn\n216.239.32.6 mt0.google.cn\n216.239.32.6 mt1.google.cn\n216.239.32.6 mt2.google.cn\n216.239.32.6 mt3.google.cn\n216.239.32.6 news.google.cn\n216.239.32.6 scholar.google.cn\n216.239.32.6 translate.google.cn\n216.239.32.6 www.google.cn\n216.239.32.6 www.gstatic.cn\n216.239.32.6 clients1.google.com.hk\n216.239.32.6 accounts.google.com.hk\n216.239.32.6 blogsearch.google.com.hk\n216.239.32.6 books.google.com.hk\n216.239.32.6 desktop.google.com.hk\n216.239.32.6 encrypted.google.com.hk\n216.239.32.6 groups.google.com.hk\n216.239.32.6 gxc.google.com.hk\n216.239.32.6 id.google.com.hk\n216.239.32.6 images.google.com.hk\n216.239.32.6 m.google.com.hk\n216.239.32.6 maps.google.com.hk\n216.239.32.6 news.google.com.hk\n216.239.32.6 picasaweb.google.com.hk\n216.239.32.6 plus.url.google.com.hk\n216.239.32.6 scholar.google.com.hk\n216.239.32.6 toolbar.google.com.hk\n216.239.32.6 toolbarqueries.google.com.hk\n216.239.32.6 translate.google.com.hk\n216.239.32.6 translate.google.com.hk\n216.239.32.6 wenda.google.com.hk\n216.239.32.6 www.google.com.hk\n216.239.32.6 android.googlesource.com\n216.239.32.6 auth.keyhole.com\n216.239.32.6 chrome.angrybirds.com\n216.239.32.6 developer.android.com\n216.239.32.6 domains.googlesyndication.com\n216.239.32.6 earthengine.googlelabs.com\n216.239.32.6 feeds.feedburner.com\n216.239.32.6 g.co\n216.239.32.6 goo.gl\n216.239.32.6 golang.org\n216.239.32.6 listen.googlelabs.com\n216.239.32.6 m.googlemail.com\n216.239.32.6 market.android.com\n216.239.32.6 ngrams.googlelabs.com\n216.239.32.6 www.googleadservices.com\n216.239.32.6 www.googlelabs.com\n216.239.32.6 www.googlesource.com\n74.125.20.87 www.orkut.com\n74.125.20.191 www.blogger.com\n74.125.20.191 accounts.blogger.com\n74.125.20.152 tpc.googlesyndication.com\n74.125.20.129 uberproxy.corp.google.com\n173.194.37.99 www.panoramio.com\n173.194.37.99 panoramio.com\n173.194.76.128 static.panoramio.com\n216.239.32.6 plus.google.com\n199.59.149.230 twitter.com\n31.13.70.81 www.facebook.com\n","permalink":"https://blog.zdltech.com/posts/windows-hosts%E6%96%87%E4%BB%B6%E9%85%8D%E7%BD%AE/","summary":"\u003cp\u003eHost文件目录C:\\Windows\\System32\\drivers\\etc\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e# Copyright (c) 1993-2009 Microsoft Corp.\u003c/p\u003e\n\u003ch1\u003e\u003c/h1\u003e\n\u003cp\u003e# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.\u003c/p\u003e\n\u003ch1\u003e\u003c/h1\u003e\n\u003cp\u003e# This file contains the mappings of IP addresses to host names. Each\u003cbr\u003e\n# entry should be kept on an individual line. The IP address should\u003cbr\u003e\n# be placed in the first column followed by the corresponding host name.\u003cbr\u003e\n# The IP address and the host name should be separated by at least one\u003cbr\u003e\n# space.\u003c/p\u003e","title":"windows hosts文件配置"},{"content":"以下命令均在/home目录下操作\ncd /home #进入/home目录** **1、把/home目录下面的mydata目录压缩为mydata.zip zip -r mydata.zip mydata #压缩mydata目录 2、把/home目录下面的mydata.zip解压到mydatabak目录里面 unzip mydata.zip -d mydatabak 3、把/home目录下面的abc文件夹和123.txt压缩成为abc123.zip\nzip -r abc123.zip abc 123.txt 4、把/home目录下面的wwwroot.zip直接解压到/home目录里面\nunzip wwwroot.zip 5、把/home目录下面的abc12.zip、abc23.zip、abc34.zip同时解压到/home目录里面\nunzip abc*.zip 6、查看把/home目录下面的wwwroot.zip里面的内容\nunzip -v wwwroot.zip 7、验证/home目录下面的wwwroot.zip是否完整\nunzip -t wwwroot.zip 8、把/home目录下面wwwroot.zip里面的所有文件解压到第一级目录\nunzip -j wwwroot.zip 主要参数 -c：将解压缩的结果 -l：显示压缩文件内所包含的文件 -p：与-c参数类似，会将解压缩的结果显示到屏幕上，但不会执行任何的转换 -t：检查压缩文件是否正确 -u：与-f参数类似，但是除了更新现有的文件外，也会将压缩文件中的其它文件解压缩到目录中 -v：执行是时显示详细的信息 -z：仅显示压缩文件的备注文字 -a：对文本文件进行必要的字符转换 -b：不要对文本文件进行字符转换 -C：压缩文件中的文件名称区分大小写 -j：不处理压缩文件中原有的目录路径 -L：将压缩文件中的全部文件名改为小写 -M：将输出结果送到more程序处理 -n：解压缩时不要覆盖原有的文件 -o：不必先询问用户，unzip执行后覆盖原有文件 -P\u0026lt;密码\u0026gt;：使用zip的密码选项 -q：执行时不显示任何信息 -s：将文件名中的空白字符转换为底线字符 -V：保留VMS的文件版本信息 -X：解压缩时同时回存文件原来的UID/GID\n","permalink":"https://blog.zdltech.com/posts/centos-linux%E4%B8%ADzip%E5%8E%8B%E7%BC%A9%E5%92%8Cunzip%E8%A7%A3%E5%8E%8B%E7%BC%A9%E5%91%BD%E4%BB%A4%E8%AF%A6%E8%A7%A3/","summary":"\u003cp\u003e以下命令均在/home目录下操作\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #0000ff;\"\u003ecd /home #进入/home目录\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e\u003cspan style=\"color: #0000ff;\"\u003e**\n**\u003c/span\u003e\u003cspan style=\"color: #000000;\"\u003e1、把/home目录下面的mydata目录压缩为mydata.zip\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e\u003cspan style=\"color: #0000ff;\"\u003ezip -r mydata.zip mydata #压缩mydata目录\u003c/span\u003e\n\u003cspan style=\"color: #000000;\"\u003e2、把/home目录下面的mydata.zip解压到mydatabak目录里面\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e\n\u003cspan style=\"color: #0000ff;\"\u003eunzip mydata.zip -d mydatabak\u003c/span\u003e\n\u003cspan style=\"color: #000000;\"\u003e3、把/home目录下面的abc文件夹和123.txt压缩成为abc123.zip\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #ff0000;\"\u003e\u003cspan style=\"color: #0000ff;\"\u003ezip -r abc123.zip abc 123.txt\u003c/span\u003e\n\u003cspan style=\"color: #000000;\"\u003e4、把/home目录下面的wwwroot.zip直接解压到/home目录里面\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #ff0000;\"\u003e\u003cspan style=\"color: #0000ff;\"\u003eunzip wwwroot.zip\u003c/span\u003e\n\u003cspan style=\"color: #000000;\"\u003e5、把/home目录下面的abc12.zip、abc23.zip、abc34.zip同时解压到/home目录里面\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #ff0000;\"\u003e\u003cspan style=\"color: #0000ff;\"\u003eunzip abc*.zip\n\u003c/span\u003e\u003cspan style=\"color: #000000;\"\u003e6、查看把/home目录下面的wwwroot.zip里面的内容\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #ff0000;\"\u003e\u003cspan style=\"color: #0000ff;\"\u003eunzip -v wwwroot.zip\u003c/span\u003e\n\u003cspan style=\"color: #000000;\"\u003e7、验证/home目录下面的wwwroot.zip是否完整\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #ff0000;\"\u003e\u003cspan style=\"color: #0000ff;\"\u003eunzip -t wwwroot.zip\u003c/span\u003e\n\u003cspan style=\"color: #000000;\"\u003e8、把/home目录下面wwwroot.zip里面的所有文件解压到第一级目录\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #ff0000;\"\u003e\u003cspan style=\"color: #0000ff;\"\u003eunzip -j wwwroot.zip\n\u003c/span\u003e\n\u003cstrong\u003e主要参数\u003c/strong\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-c：将解压缩的结果\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-l：显示压缩文件内所包含的文件\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-p：与-c参数类似，会将解压缩的结果显示到屏幕上，但不会执行任何的转换\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-t：检查压缩文件是否正确\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-u：与-f参数类似，但是除了更新现有的文件外，也会将压缩文件中的其它文件解压缩到目录中\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-v：执行是时显示详细的信息\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-z：仅显示压缩文件的备注文字\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-a：对文本文件进行必要的字符转换\n\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e-b：不要对文本文件进行字符转换\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-C：压缩文件中的文件名称区分大小写\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-j：不处理压缩文件中原有的目录路径\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-L：将压缩文件中的全部文件名改为小写\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-M：将输出结果送到more程序处理\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-n：解压缩时不要覆盖原有的文件\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-o：不必先询问用户，unzip执行后覆盖原有文件\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-P\u0026lt;密码\u0026gt;：使用zip的密码选项\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-q：执行时不显示任何信息\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-s：将文件名中的空白字符转换为底线字符\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-V：保留VMS的文件版本信息\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e-X：解压缩时同时回存文件原来的UID/GID\u003c/span\u003e\u003c/span\u003e\u003c/p\u003e","title":"CentOS Linux中zip压缩和unzip解压缩命令详解"},{"content":"原文链接： http://www.centos.bz/2011/03/centos-install-vsftpd-ftp-server/\nvsftpd作为FTP服务器，在Linux系统中是非常常用的。下面我们介绍如何在centos系统上安装vsftp。\n什么是vsftpd vsftpd是一款在Linux发行版中最受推崇的FTP服务器程序。特点是小巧轻快，安全易用。\nvsftpd 的名字代表”very secure FTP daemon”, 安全是它的开发者 Chris Evans 考虑的首要问题之一。在这个 FTP 服务器设计开发的最开始的时候，高安全性就是一个目标。\n安装vsftpd 1、以管理员（root）身份执行以下命令\n- yum install vsftpd 2、设置开机启动vsftpd ftp服务\n- chkconfig vsftpd on 3、启动vsftpd服务\n- service vsftpd start 管理vsftpd相关命令：\n停止vsftpd: service vsftpd stop\n重启vsftpd: service vsftpd restart\n配置防火墙 打开/etc/sysconfig/iptables文件\n- vi /etc/sysconfig/iptables 在REJECT行之前添加如下代码\n- -A RH-Firewall-1-INPUT -m state \u0026amp;#8211;state NEW -m tcp -p tcp \u0026amp;#8211;dport 21 -j ACCEPT 保存和关闭文件，重启防火墙\n- service iptables start 配置vsftpd服务器 默认的配置文件是/etc/vsftpd/vsftpd.conf，你可以用文本编辑器打开。\n- vi /etc/vsftpd/vsftpd.conf 添加ftp用户 下面是添加ftpuser用户，设置根目录为/home/wwwroot/ftpuser,禁止此用户登录SSH的权限，并限制其访问其它目录。\n１、修改/etc/vsftpd/vsftpd.conf\n将底下三行\n- #chroot_list_enable=YES - # (default follows) - #chroot_list_file=/etc/vsftpd.chroot_list 改为\n- chroot_list_enable=YES - # (default follows) - chroot_list_file=/etc/vsftpd/chroot_list 3、增加用户ftpuser，指向目录/home/wwwroot/ftpuser,禁止登录SSH权限。\n- useradd -d /home/wwwroot/ftpuser -g ftp -s /sbin/nologin ftpuser 4、设置用户口令\n- passwd ftpuser 5、编辑文件chroot_list:\n- vi /etc/vsftpd/chroot_list 内容为ftp用户名,每个用户占一行,如：\npeter\njohn\n6、重新启动vsftpd\n- service vsftpd restart 另外，如果觉得以后管理ftp用户名嫌麻烦，可以使用centos官方发布的脚本管理。地址如下：\nhttp://wiki.centos.org/HowTos/Chroot_Vsftpd_with_non-system_users\n出现的错误 1、500 OOPS: cannot change directory\n解决方法：\n在终端输入命令：\n- setsebool -P ftpd_disable_trans 1 - service vsftpd restart 就ＯＫ了！\n原因：这是因为服务器开启了selinux，这限制了FTP的登录。\n","permalink":"https://blog.zdltech.com/posts/centos%E5%BC%80%E5%90%AFftp%E5%8F%8A%E9%85%8D%E7%BD%AE%E7%94%A8%E6%88%B7/","summary":"\u003cp\u003e原文链接： http://www.centos.bz/2011/03/centos-install-vsftpd-ftp-server/\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.centos.bz/tag/vsftpd/\"\u003evsftpd\u003c/a\u003e作为FTP服务器，在\u003ca href=\"http://www.centos.bz/tag/linux/\"\u003eLinux\u003c/a\u003e系统中是非常常用的。下面我们介绍如何在\u003ca href=\"http://www.centos.bz/\"\u003ecentos\u003c/a\u003e系统上安装vsftp。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch3 id=\"什么是vsftpd\"\u003e\u003ca style=\"color: #336699;\" name=\"t0\"\u003e\u003c/a\u003e什么是vsftpd\u003c/h3\u003e\n\u003cp\u003evsftpd是一款在Linux发行版中最受推崇的FTP服务器程序。特点是小巧轻快，安全易用。\u003c/p\u003e\n\u003cp\u003evsftpd 的名字代表”very secure FTP daemon”, 安全是它的开发者 Chris Evans 考虑的首要问题之一。在这个 FTP 服务器设计开发的最开始的时候，高安全性就是一个目标。\u003c/p\u003e\n\u003ch3 id=\"安装vsftpd\"\u003e\u003ca style=\"color: #336699;\" name=\"t1\"\u003e\u003c/a\u003e安装vsftpd\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e1、以管理员（root）身份执行以下命令\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"hl-surround\"\u003e\n\u003cpre\u003e\u003ccode\u003e- yum install vsftpd\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003e2、设置开机启动vsftpd ftp服务\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"hl-surround\"\u003e\n\u003cpre\u003e\u003ccode\u003e- chkconfig vsftpd on\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003e3、启动vsftpd服务\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"hl-surround\"\u003e\n\u003cpre\u003e\u003ccode\u003e- service vsftpd start\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003e管理vsftpd相关命令：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e停止vsftpd:  service vsftpd stop\u003c/p\u003e\n\u003cp\u003e重启vsftpd:  service vsftpd restart\u003c/p\u003e\n\u003ch3 id=\"配置防火墙\"\u003e\u003ca style=\"color: #336699;\" name=\"t2\"\u003e\u003c/a\u003e配置防火墙\u003c/h3\u003e\n\u003cp\u003e打开/etc/sysconfig/\u003ca href=\"http://www.centos.bz/tag/iptables/\"\u003eiptables\u003c/a\u003e文件\u003c/p\u003e\n\u003cdiv class=\"hl-surround\"\u003e\n\u003cpre\u003e\u003ccode\u003e- vi /etc/sysconfig/iptables\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e在REJECT行之前添加如下代码\u003c/p\u003e\n\u003cdiv class=\"hl-surround\"\u003e\n\u003cpre\u003e\u003ccode\u003e- -A RH-Firewall-1-INPUT -m state \u0026amp;#8211;state NEW -m tcp -p tcp \u0026amp;#8211;dport 21 -j ACCEPT\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e保存和关闭文件，重启防火墙\u003c/p\u003e","title":"CentOS开启FTP及配置用户"},{"content":"当服务器没有运行php、没装phpmyadmin的时候，远程管理mysql就显得有必要了。因为在CentOS下设置的，所以标题加上了CentOS，以下的命令在debian等系统下应该也OK。\nmysql –u root –p mysql # 第1个mysql是执行命令，第2个mysql是系统数据名称\nmysql\u0026gt; select Host,User from user;\n在mysql控制台执行:\ngrant all privileges on . to ‘root’@‘%’ identified by‘123456’with grant option;\n# root是用户名，%代表任意主机，’123456’指定的登录密码（这个和本地的root密码可以设置不同的，互不影响）\nflush privileges;# 重载系统权限\nexit;\n允许3306端口\niptables –I INPUT –p tcp –m state —state NEW –m tcp —dport 3306–j ACCEPT\n# 查看规则是否生效\niptables –L –n # 或者: service iptables status\n# 此时生产环境是不安全的，远程管理之后应该关闭端口，删除之前添加的规则\niptables –D INPUT –p tcp –m state —state NEW –m tcp —dport 3306–j ACCEPT\nPS，上面iptables添加/删除规则都是临时的，如果需要重启后也生效，需要保存修改: service iptables save # 或者: /etc/init.d/iptables save 另外， vi /etc/sysconfig/iptables # 加上下面这行规则也是可以的 -A INPUT -p tcp -m state –state NEW -m tcp –dport 3306 -j ACCEPT\n远程管理数据库的软件，win系统下可以使用SQLyog，用了几种远程软件，感觉这个用起来蛮不错的。\n遇到5.7参考下面\n配置密码的策略\n参考\nhttp://blog.csdn.net/clerk0324/article/details/71169982\n","permalink":"https://blog.zdltech.com/posts/centos%E4%B8%8B%E5%BC%80%E5%90%AFmysql%E8%BF%9C%E7%A8%8B%E8%BF%9E%E6%8E%A5%E8%BF%9C%E7%A8%8B%E7%AE%A1%E7%90%86%E6%95%B0%E6%8D%AE%E5%BA%93/","summary":"\u003cp\u003e当服务器没有运行php、没装phpmyadmin的时候，远程管理\u003ca href=\"http://www.fantxi.com/blog/tag/mysql/\"\u003emysql\u003c/a\u003e就显得有必要了。因为在CentOS下设置的，所以标题加上了\u003ca href=\"http://www.fantxi.com/blog/tag/CentOS/\"\u003eCentOS\u003c/a\u003e，以下的命令在debian等系统下应该也OK。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003emysql \u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e–\u003c/span\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003eu root \u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e–\u003c/span\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003ep mysql \u003c/span\u003e\u003cspan class=\"com\"\u003e# 第1个mysql是执行命令，第2个mysql是系统数据名称\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan style=\"color: #494949;\"\u003emysql\u0026gt; select Host,User from user;\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e在mysql控制台执行:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003egrant all privileges on \u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e\u003cem\u003e.\u003c/em\u003e\u003c/span\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003e to \u003c/span\u003e\u003cspan class=\"str\" style=\"color: #b1d631;\"\u003e‘root’\u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e@\u003c/span\u003e\u003cspan class=\"str\" style=\"color: #b1d631;\"\u003e‘%’\u003c/span\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003e identified \u003c/span\u003e\u003cspan class=\"kwd\" style=\"color: #527aa2;\"\u003eby\u003c/span\u003e\u003cspan class=\"str\" style=\"color: #b1d631;\"\u003e‘123456’\u003c/span\u003e\u003cspan class=\"kwd\" style=\"color: #527aa2;\"\u003ewith\u003c/span\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003e grant option\u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e;\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"com\"\u003e# root是用户名，%代表任意主机，’123456’指定的登录密码（这个和本地的root密码可以设置不同的，互不影响）\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003eflush privileges\u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e;\u003c/span\u003e\u003cspan class=\"com\"\u003e# 重载系统权限\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"kwd\" style=\"color: #527aa2;\"\u003eexit\u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e;\u003c/span\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e允许3306端口\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003eiptables \u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e–\u003c/span\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003eI INPUT \u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e–\u003c/span\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003ep tcp \u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e–\u003c/span\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003em state \u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e—\u003c/span\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003estate NEW \u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e–\u003c/span\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003em tcp \u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e—\u003c/span\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003edport \u003c/span\u003e\u003cspan class=\"lit\" style=\"color: #527aa2;\"\u003e3306\u003c/span\u003e\u003cspan class=\"pun\" style=\"color: #ff8613;\"\u003e–\u003c/span\u003e\u003cspan class=\"pln\" style=\"color: #faf4c6;\"\u003ej ACCEPT\u003c/span\u003e\u003c/p\u003e","title":"CentOS下开启mysql远程连接，远程管理数据库"},{"content":"先来解释一下，什么是 LAMP。正如标题所言，LAMP 实际上就是 Linux、Apache、MySQL、PHP 四个名称的缩写，当然最后一个 “P” 还有其他说法是 Perl 或者 Python。不用多说了，本文讲解的就是 Linux、Apache、MySQL、PHP 这四个东西，所以就这样解释了。\n自己很早就在做网站，最初玩的是 ASP，后来主要研究 .Net，也用 .Net 搞过类似的开发。但是自己最主要还是想把网站做起来，于是乎就将主要精力花在了网站运营上了，当然建站就选用了市面上成熟的一些 CMS 或者是博客程序。目前的 CMS 和博客程序实际上都可以融入到一起，因为其内容的表现形式上相当的接近，故选择哪一块来做，完全看自己的特长了。\n由于 Linux 和 PHP 的免费，在国外是相当的流行。国内大部分主机都是 Windows 平台，而我学的 ASP 和 .Net 刚好能搭配运行起来。后来由于种种原因，我的网站都移民到了国外，而在国外找一个性价比好的 Windows 主机实在是件难事，不光语言上的阻碍，国外版权意识很好，所以很少有性价比好的 Windows 主机。我不得不转向了 Linux 平台。而且非常流行的 WordPress 吸引了我，故目前主要注意力就集中在 Linux 主机和 PHP 上。虽然自己对 PHP 基本不了解，呵呵。\n虽然 Linux 平台上好的组件不止 Apache 一个，例如俄罗斯人开发的 Nginx，还有性能超强的 LiteSpeed 等等，这两者我都用过，前者以高效、资源占用低为特点，据说腾讯网就是基于此运行的，后者是以性能强大著称，同样据说这是 WordPress 官方推荐的用来运行 WordPress 最佳组件。但是呢，各种网上资料表明，虽然 Apache 性能、资源占用不如其他组件，但是 Apache 开发的目标就是以稳定为主。任何一个网站难道不是希望能够稳定运行？所以我还是选择学习 Apache 来作为网站的服务器环境。学会了一个，其他就能够举一反三了。\n一般情况下，安装的都是最新的正式版，除非你有特殊需求，要安装指定的版本，本文暂不讨论。从最基础的开始，一点点完成一个可用的 Linux 主机。这里就开始介绍如何在 CentOS 6.0 上安装 LAMP 组件。经过如下语句安装，目前安装到的版本为：\nPHP：5.3.2\nApache：2.2.15\nMySQL：5.1.52\n一、安装 MySQL\n首先来进行 MySQL 的安装。打开超级终端，输入：\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;root@localhost \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;~]\u0026lt;/span\u0026gt;# yum install mysql mysql\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;server 安装完毕，让 MySQL 能够随系统自动启动：\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;root@localhost \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;~]\u0026lt;/span\u0026gt;# chkconfig \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;--\u0026lt;/span\u0026gt;levels \u0026lt;span class=\u0026#34;sh_number\u0026#34; style=\u0026#34;color: #ff00ff;\u0026#34;\u0026gt;235\u0026lt;/span\u0026gt; mysqld on \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;root@localhost \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;~]\u0026lt;/span\u0026gt;# \u0026lt;span class=\u0026#34;sh_regexp\u0026#34; style=\u0026#34;color: #ff00ff;\u0026#34;\u0026gt;/etc/i\u0026lt;/span\u0026gt;nit\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_normal\u0026#34;\u0026gt;d\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;/\u0026lt;/span\u0026gt;mysqld start 设置 MySQL 数据 root 账户的密码：\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;root@localhost \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;~]\u0026lt;/span\u0026gt;# mysql_secure_installation 当出现如下提示时候直接按回车：\nEnter current password \u0026lt;span class=\u0026#34;sh_keyword\u0026#34; style=\u0026#34;color: #a52a2a;\u0026#34;\u0026gt;for\u0026lt;/span\u0026gt; root 出现如下再次回车：\nSet root password\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;?\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_normal\u0026#34;\u0026gt;Y\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;/\u0026lt;/span\u0026gt;n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;]\u0026lt;/span\u0026gt; 出现如下提示输入你需要设置的密码，回车后在输入一次确认：\nNew password\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt; 接下来还会有四个确认，分别是：\nRemove anonymous users\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;?\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_normal\u0026#34;\u0026gt;Y\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;/\u0026lt;/span\u0026gt;n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;]\u0026lt;/span\u0026gt; Disallow root login remotely\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;?\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_normal\u0026#34;\u0026gt;Y\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;/\u0026lt;/span\u0026gt;n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;]\u0026lt;/span\u0026gt; Remove test database and access to it\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;?\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_normal\u0026#34;\u0026gt;Y\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;/\u0026lt;/span\u0026gt;n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;]\u0026lt;/span\u0026gt; Reload privilege tables now\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;?\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_normal\u0026#34;\u0026gt;Y\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;/\u0026lt;/span\u0026gt;n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;]\u0026lt;/span\u0026gt; 直接回车即可。\n二、安装 Apache 组件\n由于 CentOS 已经封装了 Apache，直接运行安装：\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;root@localhost \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;~]\u0026lt;/span\u0026gt;# yum install httpd 同样配置系统让 Apache 随系统启动：\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;root@localhost \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;~]\u0026lt;/span\u0026gt;# chkconfig \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;--\u0026lt;/span\u0026gt;levels \u0026lt;span class=\u0026#34;sh_number\u0026#34; style=\u0026#34;color: #ff00ff;\u0026#34;\u0026gt;235\u0026lt;/span\u0026gt; httpd on 配置完毕，启动 Apache：\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;root@localhost \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;~]\u0026lt;/span\u0026gt;# \u0026lt;span class=\u0026#34;sh_regexp\u0026#34; style=\u0026#34;color: #ff00ff;\u0026#34;\u0026gt;/etc/i\u0026lt;/span\u0026gt;nit\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_normal\u0026#34;\u0026gt;d\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;/\u0026lt;/span\u0026gt;httpd start 此时已经可以访问你的服务器，不出意外的话，能够看到 “Apache 2 Test Page powered by CentOS” 的测试页面。注意，如果其他机器访问这台服务无法显示这个页面，而直接在这台服务器上可以访问的话，一般情况下是 CentOS 自带的防火墙禁止了。你只需要进入防火墙，将 “WWW” 对应的 “80” 端口打开即可。\n注意：在 CentOS 中 Apache 的默认根目录是 /var/www/html，配置文件 /etc/httpd/conf/httpd.conf。其他配置存储在 /etc/httpd/conf.d/ 目录。\n三、安装 PHP\n输入如下指令安装 PHP:\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;root@localhost \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;~]\u0026lt;/span\u0026gt;# yum install php 需要重新启动 Apache 服务：\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;root@localhost \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;~]\u0026lt;/span\u0026gt;# \u0026lt;span class=\u0026#34;sh_regexp\u0026#34; style=\u0026#34;color: #ff00ff;\u0026#34;\u0026gt;/etc/i\u0026lt;/span\u0026gt;nit\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_normal\u0026#34;\u0026gt;d\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;/\u0026lt;/span\u0026gt;httpd restart 四、测试 PHP 相关信息\n这步实际上可以省略，但是为了测试是否安装成功，你可以新建一个 PHP 页面进行测试，使用 vim 编辑器新建：\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;root@localhost \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;~]\u0026lt;/span\u0026gt;# \u0026lt;span class=\u0026#34;sh_normal\u0026#34;\u0026gt;vi \u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_keyword\u0026#34; style=\u0026#34;color: #a52a2a;\u0026#34;\u0026gt;var\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_regexp\u0026#34; style=\u0026#34;color: #ff00ff;\u0026#34;\u0026gt;/www/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_normal\u0026#34;\u0026gt;html\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;/\u0026lt;/span\u0026gt;info\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;php 按 “i” 键进行编辑，输入：\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;\u0026amp;lt;?\u0026lt;/span\u0026gt;php \u0026lt;span class=\u0026#34;sh_function\u0026#34; style=\u0026#34;font-weight: bold;\u0026#34;\u0026gt;phpinfo\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;();\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;?\u0026amp;gt;\u0026lt;/span\u0026gt; 编辑完毕，按 “ESC” 键退出编辑模式，接着输入：\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;:\u0026lt;/span\u0026gt;wq 然后回车，即保存并退出。\n此时你可以访问你的站点地址，例如 “http://192.168.1.2/info.php”，查看是否能看到相关的 PHP 信息。\n看到这样的图，就说明 PHP 安装成功了。\n五、将 PHP 模块和 MySQL 模块关联起来\n还需要将 PHP 和 MySQL 关联起来，才能正常工作。搜索模块：\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;root@localhost \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;~]\u0026lt;/span\u0026gt;# yum search php 安装相关模块：\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;root@localhost \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;~]\u0026lt;/span\u0026gt;# yum install php\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;mysql php\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;gd php\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;imap php\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;ldap php\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;odbc php\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;pear php\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;xml php\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;-\u0026lt;/span\u0026gt;xmlrpc 需要重启 Apache 模块才能生效：\n\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;[\u0026lt;/span\u0026gt;root@localhost \u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;~]\u0026lt;/span\u0026gt;# \u0026lt;span class=\u0026#34;sh_regexp\u0026#34; style=\u0026#34;color: #ff00ff;\u0026#34;\u0026gt;/etc/i\u0026lt;/span\u0026gt;nit\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;.\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_normal\u0026#34;\u0026gt;d\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;sh_symbol\u0026#34;\u0026gt;/\u0026lt;/span\u0026gt;httpd restart 再次刷新刚才建立的 “info.php” 页面，往下拉找到相关 MySQL 模块，看是否检测到相关信息。\n如果看到如上图相关信息，则说明 MySQL 工作正常了。\n六、总结\n到这里就结束了，本文阐述了在 CentOS 6.0 系统下 LAMP 组件（Apache+MySQL+PHP） 的详细安装步骤，可以让更多新手熟悉服务器配置环境。\n但是到这里，还只是将环境配置完毕，很多东西还有欠缺，而且还是一些重要的问题，例如目录的权限配置问题，或者是管理上的问题，像建立 FTP 等。这些内容随后会慢慢谈到。\n本文转自：http://www.laozhe.net/articles/302.html\n","permalink":"https://blog.zdltech.com/posts/centos-%E7%B3%BB%E7%BB%9F-lampapachemysqlphp-%E5%AE%89%E8%A3%85%E6%AD%A5%E9%AA%A4/","summary":"\u003cp\u003e先来解释一下，什么是 LAMP。正如标题所言，LAMP 实际上就是 Linux、Apache、MySQL、PHP 四个名称的缩写，当然最后一个 “P” 还有其他说法是 Perl 或者 Python。不用多说了，本文讲解的就是 Linux、Apache、MySQL、PHP 这四个东西，所以就这样解释了。\u003c/p\u003e\n\u003cp\u003e　　自己很早就在做网站，最初玩的是 ASP，后来主要研究 .Net，也用 .Net 搞过类似的开发。但是自己最主要还是想把网站做起来，于是乎就将主要精力花在了网站运营上了，当然建站就选用了市面上成熟的一些 CMS 或者是博客程序。目前的 CMS 和博客程序实际上都可以融入到一起，因为其内容的表现形式上相当的接近，故选择哪一块来做，完全看自己的特长了。\u003c/p\u003e\n\u003cp\u003e　　由于 Linux 和 PHP 的免费，在国外是相当的流行。国内大部分主机都是 Windows 平台，而我学的 ASP 和 .Net 刚好能搭配运行起来。后来由于种种原因，我的网站都移民到了国外，而在国外找一个性价比好的 Windows 主机实在是件难事，不光语言上的阻碍，国外版权意识很好，所以很少有性价比好的 Windows 主机。我不得不转向了 Linux 平台。而且非常流行的 WordPress 吸引了我，故目前主要注意力就集中在 Linux 主机和 PHP 上。虽然自己对 PHP 基本不了解，呵呵。\u003c/p\u003e\n\u003cp\u003e　　虽然 Linux 平台上好的组件不止 Apache 一个，例如俄罗斯人开发的 Nginx，还有性能超强的 LiteSpeed 等等，这两者我都用过，前者以高效、资源占用低为特点，据说腾讯网就是基于此运行的，后者是以性能强大著称，同样据说这是 WordPress 官方推荐的用来运行 WordPress 最佳组件。但是呢，各种网上资料表明，虽然 Apache 性能、资源占用不如其他组件，但是 Apache 开发的目标就是以稳定为主。任何一个网站难道不是希望能够稳定运行？所以我还是选择学习 Apache 来作为网站的服务器环境。学会了一个，其他就能够举一反三了。\u003c/p\u003e\n\u003cp\u003e　　一般情况下，安装的都是最新的正式版，除非你有特殊需求，要安装指定的版本，本文暂不讨论。从最基础的开始，一点点完成一个可用的 Linux 主机。这里就开始介绍如何在 CentOS 6.0 上安装 LAMP 组件。经过如下语句安装，目前安装到的版本为：\u003c/p\u003e","title":"CentOS   系统 LAMP（Apache+MySQL+PHP） 安装步骤"},{"content":"转载：http://blog.csdn.net/guolin_blog/article/details/25466665\n本篇文章主要内容来自于Android Doc，我翻译之后又做了些加工，英文好的朋友也可以直接去读原文。\nhttp://developer.android.com/guide/topics/ui/actionbar.html\n限于篇幅的原因，在上篇文章中我们只学习了ActionBar基础部分的知识，那么本篇文章我们将接着上一章的内容继续学习，探究一下ActionBar更加高级的知识。如果你还没有看过前面一篇文章的话，建议先去阅读Android ActionBar完全解析，使用官方推荐的最佳导航栏(上)。\n添加Action Provider 和Action View有点类似，Action Provider也可以将一个Action按钮替换成一个自定义的布局。但不同的是，Action Provider能够完全控制事件的所有行为，并且还可以在点击的时候显示子菜单。\n为了添加一个Action Provider，我们需要在标签中指定一个actionViewClass属性，在里面填入Action Provider的完整类名。我们可以通过继承ActionProvider类的方式来创建一个自己的Action Provider，同时，Android也提供好了几个内置的Action Provider，比如说ShareActionProvider。\n由于每个Action Provider都可以自由地控制事件响应，所以它们不需要在onOptionsItemSelected()方法中再去监听点击事件，而是应该在onPerformDefaultAction()方法中去执行相应的逻辑。\n那么我们就先来看一下ShareActionProvider的简单用法吧，编辑menu资源文件，在里面加入ShareActionProvider的声明，如下所示：\n**[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/action_share\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:actionProviderClass\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.widget.ShareActionProvider\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:showAsAction\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ifRoom\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:title\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@string/action_share\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230;\u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 注意，ShareActionProvider会自己处理它的显示和事件，但我们仍然要记得给它添加一个title，以防止它会在overflow当中出现。\n接着剩下的事情就是通过Intent来定义出你想分享哪些东西了，我们只需要在onCreateOptionsMenu()中调用MenuItem的getActionProvider()方法来得到该ShareActionProvider对象，再通过setShareIntent()方法去选择构建出什么样的一个Intent就可以了。代码如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onCreateOptionsMenu(Menu menu) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; MenuInflater inflater = getMenuInflater(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; inflater.inflate(R.menu.main, menu); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; MenuItem shareItem = menu.findItem(R.id.action_share); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ShareActionProvider provider = (ShareActionProvider) shareItem.getActionProvider(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; provider.setShareIntent(getDefaultIntent()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230;\u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreateOptionsMenu(menu); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Intent getDefaultIntent() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Intent intent = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(Intent.ACTION_SEND); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; intent.setType(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;image/*\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; intent; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 可以看到，这里我们通过getDefaultIntent()方法来构建了一个Intent，该Intent表示会将所有可以共享图片的程度都列出来。重新运行一下程序，效果如下图所示：\n细心的你一定观察到了，这个ShareActionProvider点击之后是可以展开的，有点类似于overflow的效果，这就是Action Provider的子菜单。除了使用ShareActionProvider之外，我们也可以自定义一个Action Provider，比如说如果想要建立一个拥有两项子菜单的Action Provider，就可以这样写：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MyActionProvider \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; ActionProvider { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; MyActionProvider(Context context) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View onCreateActionView() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onPrepareSubMenu(SubMenu subMenu) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; subMenu.clear(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; subMenu.add(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sub item 1\u0026amp;#8221;\u0026lt;/span\u0026gt;).setIcon(R.drawable.ic_launcher) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .setOnMenuItemClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnMenuItemClickListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onMenuItemClick(MenuItem item) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; subMenu.add(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sub item 2\u0026amp;#8221;\u0026lt;/span\u0026gt;).setIcon(R.drawable.ic_launcher) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .setOnMenuItemClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnMenuItemClickListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onMenuItemClick(MenuItem item) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; hasSubMenu() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 这里我们新建了一个MyActionProvider继承自ActionProvider，为了表示这个Action Provider是有子菜单的，需要重写hasSubMenu()方法并返回true，然后在onPrepareSubMenu通过调用SubMenu的add()方法添加子菜单。\n接着修改menu资源，在里面加入MyActionProvider的声明：\n**[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/action_share\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:actionProviderClass\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MyActionProvider\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:icon\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_launcher\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:showAsAction\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ifRoom\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:title\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@string/action_share\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230;\u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 现在重新运行一下代码，结果如图所示：\n添加导航Tabs Tabs的应用可以算是非常广泛了，它可以使得用户非常轻松地在你的应用程序中切换不同的视图。而Android官方更加推荐使用ActionBar中提供的Tabs功能，因为它更加的智能，可以自动适配各种屏幕的大小。比如说，在平板上屏幕的空间非常充足，Tabs会和Action按钮在同一行显示，如下图所示：\n而如果是在手机上，屏幕的空间不够大的话，Tabs和Action按钮则会分为两行显示，如下图所示：\n下面我们就来看一下如何使用ActionBar提供的Tab功能，大致可以分为以下几步：\n实现ActionBar.TabListener接口，这个接口提供了Tab事件的各种回调，比如当用户点击了一个Tab时，你就可以进行切换Tab的操作。 2.为每一个你想添加的Tab创建一个ActionBar.Tab的实例，并且调用setTabListener()方法来设置ActionBar.TabListener。除此之外，还需要调用setText()方法来给当前Tab设置标题。\n3.最后调用ActionBar的addTab()方法将创建好的Tab添加到ActionBar中。\n看起来并不复杂，总共就只有三步，那么我们现在就来尝试一下吧。首先第一步需要创建一个实现ActionBar.TabListener接口的类，代码如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; TabListener\u0026lt;T \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Fragment\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; ActionBar.TabListener { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Fragment mFragment; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Activity mActivity; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; String mTag; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; Class\u0026lt;T\u0026gt; mClass; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; TabListener(Activity activity, String tag, Class\u0026lt;T\u0026gt; clz) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mActivity = activity; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mTag = tag; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mClass = clz; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTabSelected(Tab tab, FragmentTransaction ft) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mFragment == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mFragment = Fragment.instantiate(mActivity, mClass.getName()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ft.add(android.R.id.content, mFragment, mTag); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ft.attach(mFragment); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTabUnselected(Tab tab, FragmentTransaction ft) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mFragment != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ft.detach(mFragment); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTabReselected(Tab tab, FragmentTransaction ft) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 这段代码并不长，我们简单分析一下。当Tab被选中的时候会调用onTabSelected()方法，在这里我们先判断mFragment是否为空，如果为空的话就创建Fragment的实例并调用FragmentTransaction的add()方法，如果不会空的话就调用FragmentTransaction的attach()方法。\n而当Tab没有被选中的时候，则调用FragmentTransaction的detach()方法，将UI资源释放掉。\n当Tab被重新选中的时候会调用onTabReselected()方法，如果没有特殊需求的话，通常是不需要进行处理的。\n接下来第二步要给每一个Tab创建一个ActionBar.Tab的实例，在此之前要先准备好每个Tab页对应的Fragment。比如说这里我们想创建两个Tab页，Artist和Album，那就要先准备好这两个Tab页对应的Fragment。首先新建ArtistFragment，代码如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ArtistFragment \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Fragment { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View onCreateView(LayoutInflater inflater, ViewGroup container, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Bundle savedInstanceState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; TextView textView = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TextView(getActivity()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; textView.setText(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Artist Fragment\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; textView.setGravity(Gravity.CENTER_HORIZONTAL); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; LinearLayout layout = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearLayout(getActivity()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; LayoutParams params = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; layout.addView(textView, params); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; layout; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 没有什么实质性的代码，只是在TextView中显示了Artist Fragment这个字符串。\n然后如法炮制，新建AlbumFragment，代码如下所示：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; AlbumFragment \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Fragment { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View onCreateView(LayoutInflater inflater, ViewGroup container, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Bundle savedInstanceState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; TextView textView = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TextView(getActivity()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; textView.setText(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Album Fragment\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; textView.setGravity(Gravity.CENTER_HORIZONTAL); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; LinearLayout layout = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinearLayout(getActivity()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; LayoutParams params = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; layout.addView(textView, params); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; layout; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; Fragment都准备好了之后，接下来就可以开始创建Tab实例了，创建好了之后则再调用addTab()方法添加到ActionBar当中，这两步通常都是在Activity的onCreate()方法中执行的，代码如下：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setTitle(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;天气\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ActionBar actionBar = getActionBar(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; actionBar.setDisplayHomeAsUpEnabled(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setOverflowShowingAlways(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Tab tab = actionBar \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .newTab() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .setText(R.string.artist) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .setTabListener( \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TabListener\u0026lt;ArtistFragment\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;artist\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ArtistFragment.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; actionBar.addTab(tab); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; tab = actionBar \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .newTab() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .setText(R.string.album) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .setTabListener( \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TabListener\u0026lt;AlbumFragment\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;album\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; AlbumFragment.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; actionBar.addTab(tab); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 可以看到，这里是使用连缀的写法来创建Tab的。首先调用ActionBar的newTab()方法来创建一个Tab实例，接着调用了setText()方法来设置标题，然后再调用setTabListener()方法来设置事件监听器，最后再调用ActionBar的addTab()方法将Tab添加到ActionBar中。\n好了，这样的话代码就编写完了，重新运行一下程序，效果如下图所示：\n自定义ActionBar样式 虽说ActionBar给用户提供了一种全局统一的界面风格和操作方式，但这并不意味着所有应用程序的ActionBar都必须要长得一模一样。如果你需要修改ActionBar的样式来更加好地适配你的应用，可以非常简单地通过Android样式和主题来实现。\n其实Android内置的几个Activity主题中就已经包含了”dark”或”light”这样的ActionBar样式了，同时你也可以继承这些主题，然后进行更深一步的定制。\n1. 使用主题 Android中有两个最基本的Activity主题可以用于指定ActionBar的颜色，分别是： - [Theme.Holo](http://developer.android.com/reference/android/R.style.html#Theme_Holo)，这是一个深色系的主题。 - [Theme.Holo.Light](http://developer.android.com/reference/android/R.style.html#Theme_Holo_Light)，这是一个浅色系的主题。 深色系主题样式的效果如下图所示： ![](http://img.blog.csdn.net/20140615142914031) 浅色系主题样式的效果如下图所示： ![](http://img.blog.csdn.net/20140615142937593) 你可以将这些主题应用到你的整个应用程序，也可以只应用于某个Activity。通过在AndroidManifest.xml文件中给或标签指定android:theme属性就可以实现了。比如： **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;application\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:theme\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Theme.Holo.Light\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026amp;#8230; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 如果你只想让ActionBar使用深色系的主题，而Activity的内容部分仍然使用浅色系的主题，可以通过声明[Theme.Holo.Light.DarkActionBar](http://developer.android.com/reference/android/R.style.html#Theme_Holo_Light_DarkActionBar)这个主题来实现，效果如下图所示：\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140615145219687) \u0026lt;/div\u0026gt; ### \u0026lt;a style=\u0026quot;color: #336699;\u0026quot; name=\u0026quot;t4\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;2. 自定义背景 \u0026lt;div\u0026gt; 如果想要修改ActionBar的背景，我们可以通过创建一个自定义主题并重写actionBarStyle属性来实现。这个属性可以指向另外一个样式，然后我们在这个样式中重写background这个属性就可以指定一个drawable资源或颜色，从而实现自定义背景的功能。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 编辑styles.xml文件，在里面加入一个自定义的主题，如下所示： \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;CustomActionBarTheme\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;parent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Theme.Holo.Light\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android:actionBarStyle\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;@style/MyActionBar\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyActionBar\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;parent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Widget.Holo.Light.ActionBar\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android:background\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;#f4842d\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 可以看到，这里我们定义了一个CustomActionBarTheme主题，并让它继承自Theme.Holo.Light。然后在其内部重写了actionBarStyle这个属性，然后将这个属性指向了MyActionBar这个样式，我们在这个样式中又重写了background属性，并给它指定了一个背景色。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 现在重新运行一下程序，效果如下图所示： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140615194208062?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3VvbGluX2Jsb2c=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 这样我们就成功修改ActionBar的背景色了。不过现在看上去还有点怪怪的，因为只是ActionBar的背景色改变了，Tabs的背景色还是原来的样子，这样就感觉不太协调。那么下面我们马上就来修改一下Tabs的背景色，编辑styles.xml文件，如下所示： \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;CustomActionBarTheme\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;parent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Theme.Holo.Light\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android:actionBarStyle\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;@style/MyActionBar\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyActionBar\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;parent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Widget.Holo.Light.ActionBar\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android:background\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;#f4842d\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android:backgroundStacked\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;#d27026\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 可以看到，这里又重写了backgroundStacked属性，这个属性就是用于指定Tabs背景色的。那么再次重新运行程序，效果如下图所示： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140615195140593?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3VvbGluX2Jsb2c=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) \u0026lt;/div\u0026gt; ### \u0026lt;a style=\u0026quot;color: #336699;\u0026quot; name=\u0026quot;t5\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;3. 自定义文字颜色 \u0026lt;div\u0026gt; 现在整个ActionBar的颜色是属于偏暗系的，而ActionBar中文字的颜色又偏偏是黑色的，所以看起来并不舒服，那么接下来我们就学习一下如果自定义文字颜色，将文字颜色改成白色。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 修改styles.xml文件，如下所示： \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230;\u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyActionBar\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;parent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Widget.Holo.Light.ActionBar\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230;\u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android:titleTextStyle\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;@style/MyActionBarTitleText\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyActionBarTitleText\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;parent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/TextAppearance.Holo.Widget.ActionBar.Title\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android:textColor\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;#fff\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 可以看到，这里在MyActionBar样式里面重写了titleTextStyle属性，并将它指向了另一个自定义样式MyActionBarTitleText，接着我们在这个样式中指定textColor的颜色是#fff，也就是白色。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 现在重新运行一下程序，结果如下图所示： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140615212154453?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3VvbGluX2Jsb2c=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; OK，ActionBar标题文字的颜色已经成功改成白色了，那Tab标题的文字又该怎么修改呢？继续编辑styles.xml文件，如下所示： \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;CustomActionBarTheme\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;parent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Theme.Holo.Light\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android:actionBarStyle\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;@style/MyActionBar\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android:actionBarTabTextStyle\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;@style/MyActionBarTabText\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyActionBarTabText\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;parent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Widget.Holo.ActionBar.TabText\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android:textColor\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;#fff\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 这里我们在CustomActionBarTheme主题中重写actionBarTabTextStyle属性，并将它指向一个新建的MyActionBarTabText样式，然后在这个样式中重写textColor属性，将颜色指定为白色即可。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 重新运行一下程序，结果如下图所示： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140615212924640?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3VvbGluX2Jsb2c=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) \u0026lt;/div\u0026gt; ### \u0026lt;a style=\u0026quot;color: #336699;\u0026quot; name=\u0026quot;t6\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;4. 自定义Tab Indicator \u0026lt;div\u0026gt; 为了可以明确分辨出我们当前选中的是哪一个Tab项，通常情况下都会在选中Tab的下面加上一条横线作为标识，这被称作Tab Indicator。那么上图中的Tab Indicator是蓝色的，明显和整体风格不相符，所以我们接下来就学习一下如何自定义Tab Indicator。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 首先我们需要重写actionBarTabStyle这个属性，然后将它指向一个新建的Tab样式，然后重写background这个属性即可。需要注意的是，background必须要指定一个state-list drawable文件，这样在各种不同状态下才能显示出不同的效果。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 那么在开始之前，首先我们需要准备四张图片，分别用于表示Tab的四种状态，如下所示： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140617222652140) ![](http://img.blog.csdn.net/20140617222659640) ![](http://img.blog.csdn.net/20140617222705765) ![](http://img.blog.csdn.net/20140617222712328) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 这四张图片分别表示Tab选中未按下，选中且按下，未选中未按下，未选中且按下这四种状态，那么接着新建res/drawable/actionbar_tab_indicator.xml文件，代码如下所示： \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_selected\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_pressed\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/tab_unselected\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_selected\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_pressed\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/tab_selected\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_selected\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;false\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_pressed\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/tab_unselected_pressed\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_selected\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_pressed\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/tab_selected_pressed\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 四种状态分别引用了四张图片，这样就把state-list drawable文件写好了。接着修改style.xml文件，代码如下所示： \u0026lt;div class=\u0026quot;dp-highlighter bg_html\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;CustomActionBarTheme\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;parent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Theme.Holo.Light\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230;\u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android:actionBarTabStyle\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;@style/MyActionBarTabs\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MyActionBarTabs\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;parent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:style/Widget.Holo.ActionBar.TabView\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android:background\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;@drawable/actionbar_tab_indicator\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;resources\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 这里先是重写了actionBarTabStyle这个属性，并将它指向了另一个自定义样式MyActionBarTabs，接着在这个样式中重写background属性，然后指向我们刚才创建的actionbar_tab_indicator即可。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 现在重新运行一下程序，效果如下所示： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140617225521062) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 可以看到，Tab Indicator的颜色已经变成了白色，这样看上去就协调得多了。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 除此之外，Action Bar还有许许多多的属性可以进行自定义，这里我们无法一一涵盖到本篇文章中，更多的自定义属性请参考官方文档进行学习。 \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-actionbar%E5%AE%8C%E5%85%A8%E8%A7%A3%E6%9E%90%E4%BD%BF%E7%94%A8%E5%AE%98%E6%96%B9%E6%8E%A8%E8%8D%90%E7%9A%84%E6%9C%80%E4%BD%B3%E5%AF%BC%E8%88%AA%E6%A0%8F%E4%B8%8B/","summary":"\u003cp\u003e转载：\u003ca href=\"http://blog.csdn.net/guolin_blog/article/details/25466665\"\u003ehttp://blog.csdn.net/guolin_blog/article/details/25466665\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e本篇文章主要内容来自于Android Doc，我翻译之后又做了些加工，英文好的朋友也可以直接去读原文。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://developer.android.com/guide/topics/ui/actionbar.html\"\u003ehttp://developer.android.com/guide/topics/ui/actionbar.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e限于篇幅的原因，在上篇文章中我们只学习了ActionBar基础部分的知识，那么本篇文章我们将接着上一章的内容继续学习，探究一下ActionBar更加高级的知识。如果你还没有看过前面一篇文章的话，建议先去阅读\u003ca href=\"http://blog.csdn.net/guolin_blog/article/details/18234477\"\u003e\u003cstrong\u003eAndroid ActionBar完全解析，使用官方推荐的最佳导航栏(上)\u003c/strong\u003e\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"添加action-provider\"\u003e\u003ca style=\"color: #336699;\" name=\"t0\"\u003e\u003c/a\u003e添加Action Provider\u003c/h2\u003e\n\u003cp\u003e和Action View有点类似，Action Provider也可以将一个Action按钮替换成一个自定义的布局。但不同的是，Action Provider能够完全控制事件的所有行为，并且还可以在点击的时候显示子菜单。\u003c/p\u003e\n\u003cp\u003e为了添加一个Action Provider，我们需要在\u003citem\u003e标签中指定一个actionViewClass属性，在里面填入Action Provider的完整类名。我们可以通过继承ActionProvider类的方式来创建一个自己的Action Provider，同时，Android也提供好了几个内置的Action Provider，比如说ShareActionProvider。\u003c/p\u003e\n\u003cp\u003e由于每个Action Provider都可以自由地控制事件响应，所以它们不需要在onOptionsItemSelected()方法中再去监听点击事件，而是应该在onPerformDefaultAction()方法中去执行相应的逻辑。\u003c/p\u003e\n\u003cp\u003e那么我们就先来看一下ShareActionProvider的简单用法吧，编辑menu资源文件，在里面加入ShareActionProvider的声明，如下所示：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_html\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/25466665#)[copy](http://blog.csdn.net/guolin_blog/article/details/25466665#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/398375)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/398375/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/action_share\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:actionProviderClass\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.widget.ShareActionProvider\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:showAsAction\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ifRoom\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:title\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@string/action_share\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026amp;#8230;\u0026amp;#8230;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e注意，ShareActionProvider会自己处理它的显示和事件，但我们仍然要记得给它添加一个title，以防止它会在overflow当中出现。\u003c/p\u003e","title":"Android ActionBar完全解析，使用官方推荐的最佳导航栏(下)"},{"content":"转载：http://blog.csdn.net/guolin_blog/article/details/18234477\n本篇文章主要内容来自于Android Doc，我翻译之后又做了些加工，英文好的朋友也可以直接去读原文。\nhttp://developer.android.com/guide/topics/ui/actionbar.html\nAction Bar是一种新増的导航栏功能，在Android 3.0之后加入到系统的API当中，它标识了用户当前操作界面的位置，并提供了额外的用户动作、界面导航等功能。使用ActionBar的好处是，它可以给提供一种全局统一的UI界面，使得用户在使用任何一款软件时都懂得该如何操作，并且ActionBar还可以自动适应各种不同大小的屏幕。下面是一张使用ActionBar的界面截图：\n其中，[1]是ActionBar的图标，[2]是两个action按钮，[3]是overflow按钮。\n由于Action Bar是在3.0以后的版本中加入的，如果想在2.x的版本里使用ActionBar的话则需要引入Support Library，不过3.0之前版本的市场占有率已经非常小了，这里简单起见我们就不再考虑去做向下兼容，而是只考虑4.0以上版本的用法。\n添加和移除Action Bar ActionBar的添加非常简单，只需要在AndroidManifest.xml中指定Application或Activity的theme是Theme.Holo或其子类就可以了，而使用Eclipse创建的项目自动就会将Application的theme指定成Theme.Holo，所以ActionBar默认都是显示出来的。新建一个空项目并运行，效果如下图所示：\n而如果想要移除ActionBar的话通常有两种方式，一是将theme指定成Theme.Holo.NoActionBar，表示使用一个不包含ActionBar的主题，二是在Activity中调用以下方法：\n**[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;ActionBar actionBar = getActionBar(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;actionBar.hide(); \u0026lt;/span\u0026gt; 现在重新运行一下程序，就可以看到ActionBar不再显示了，如下图所示：\n修改Action Bar的图标和标题 默认情况下，系统会使用或者中icon属性指定的图片来作为ActionBar的图标，但是我们也可以改变这一默认行为。如果我们想要使用另外一张图片来作为ActionBar的图标，可以在或者中通过logo属性来进行指定。比如项目的res/drawable目录下有一张weather.png图片，就可以在AndroidManifest.xml中这样指定： **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:logo\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/weather\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 现在重新运行一下程序，效果如下图所示： ![](http://img.blog.csdn.net/20140602121519562?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) OK，ActionBar的图标已经修改成功了，那么标题中的内容该怎样修改呢？其实也很简单，使用label属性来指定一个字符串就可以了，如下所示： **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:label\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;天气\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:logo\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/weather\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 现在重新运行一下程序，结果如下图所示： ![](http://img.blog.csdn.net/20140602121652968?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 添加Action按钮 ActionBar还可以根据应用程序当前的功能来提供与其相关的Action按钮，这些按钮都会以图标或文字的形式直接显示在ActionBar上。当然，如果按钮过多，ActionBar上显示不完，多出的一些按钮可以隐藏在overflow里面（最右边的三个点就是overflow按钮），点击一下overflow按钮就可以看到全部的Action按钮了。 当Activity启动的时候，系统会调用Activity的onCreateOptionsMenu()方法来取出所有的Action按钮，我们只需要在这个方法中去加载一个menu资源，并把所有的Action按钮都定义在资源文件里面就可以了。 那么我们先来看下menu资源文件该如何定义，代码如下所示： **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/action_compose\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:icon\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_action_compose\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:showAsAction\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;always\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:title\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@string/action_compose\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/action_delete\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:icon\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_action_delete\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:showAsAction\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;always\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:title\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@string/action_delete\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/action_settings\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:icon\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_launcher\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:showAsAction\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;never\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:title\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@string/action_settings\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 可以看到，这里我们通过三个\u0026lt;item\u0026gt;标签定义了三个Action按钮。\u0026lt;item\u0026gt;标签中又有一些属性，其中id是该Action按钮的唯一标识符，icon用于指定该按钮的图标，title用于指定该按钮可能显示的文字（在图标能显示的情况下，通常不会显示文字），showAsAction则指定了该按钮显示的位置，主要有以下几种值可选：always表示永远显示在ActionBar中，如果屏幕空间不够则无法显示，ifRoom表示屏幕空间够的情况下显示在ActionBar中，不够的话就显示在overflow中，never则表示永远显示在overflow中。 接着，重写Activity的onCreateOptionsMenu()方法，代码如下所示： **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onCreateOptionsMenu(Menu menu) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; MenuInflater inflater = getMenuInflater(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; inflater.inflate(R.menu.main, menu); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreateOptionsMenu(menu); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 这部分代码很简单，仅仅是调用了MenuInflater的inflate()方法来加载menu资源就可以了。现在重新运行一下程序，结果如下图所示： ![](http://img.blog.csdn.net/20140602121900750?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 可以看到，action_compose和action_delete这两个按钮已经在ActionBar中显示出来了，而action_settings这个按钮由于showAsAction属性设置成了never，所以被隐藏到了overflow当中，只要点击一下overflow按钮就可以看到它了。 这里我们注意到，显示在ActionBar上的按钮都只有一个图标而已，我们在title中指定的文字并没有显示出来。没错，title中的内容通常情况下只会在overflow中显示出来，ActionBar中由于屏幕空间有限，默认是不会显示title内容的。但是出于以下几种因素考虑，即使title中的内容无法显示出来，我们也应该给每个item中都指定一个title属性： - 当ActionBar中的剩余空间不足的时候，如果Action按钮指定的showAsAction属性是ifRoom的话，该Action按钮就会出现在overflow当中，此时就只有title能够显示了。 - 如果Action按钮在ActionBar中显示，用户可能通过长按该Action按钮的方式来查看到title的内容。 响应Action按钮的点击事件 当用户点击Action按钮的时候，系统会调用Activity的onOptionsItemSelected()方法，通过方法传入的MenuItem参数，我们可以调用它的getItemId()方法和menu资源中的id进行比较，从而辨别出用户点击的是哪一个Action按钮，比如： **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onOptionsItemSelected(MenuItem item) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (item.getItemId()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.action_compose: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Toast.makeText(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Compose\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.action_delete: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Toast.makeText(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Delete\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.action_settings: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Toast.makeText(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Settings\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onOptionsItemSelected(item); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 可以看到，我们让每个Action按钮被点击的时候都弹出一个Toast，现在重新运行一下代码，结果如下图所示： ![](http://img.blog.csdn.net/20140602115507171) 通过Action Bar图标进行导航 启用ActionBar图标导航的功能，可以允许用户根据当前应用的位置来在不同界面之间切换。比如，A界面展示了一个列表，点击某一项之后进入了B界面，这时B界面就应该启用ActionBar图标导航功能，这样就可以回到A界面。 我们可以通过调用setDisplayHomeAsUpEnabled()方法来启用ActionBar图标导航功能，比如： **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setTitle(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;天气\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setContentView(R.layout.activity_main); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ActionBar actionBar = getActionBar(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; actionBar.setDisplayHomeAsUpEnabled(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 现在重新运行一下程序，结果如下图所示： ![](http://img.blog.csdn.net/20140602152755500?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 可以看到，在ActionBar图标的左侧出现了一个向左的箭头，通常情况下这都表示返回的意思，因此最简单的实现就是在它的点击事件里面加入finish()方法就可以了，如下所示： **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onOptionsItemSelected(MenuItem item) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (item.getItemId()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; android.R.id.home: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; finish(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; …… \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 当点击ActionBar图标的时候，系统同样会调用onOptionsItemSelected()方法，并且此时的itemId是android.R.id.home，所以finish()方法也就是加在这里的了。 现在看上去，ActionBar导航和Back键的功能貌似是一样的。没错，如果我们只是简单地finish了一下，ActionBar导航和Back键的功能是完全一样的，但ActionBar导航的设计初衷并不是这样的，它和Back键的功能还是有一些区别的，举个例子吧。 ![](http://img.blog.csdn.net/20140602161656000) 上图中的Conversation List是收件箱的主界面，现在我们点击第一封邮件会进入到Conversation1 details界面，然后点击下一封邮件会进入到Conversation 2 details界面，再点击下一封邮箱会进入到Conversation3 details界面。好的，这个时候如果我们按下Back键，应该会回到Conversation 2 details界面，再按一次Back键应该回到Conversation1 details界面，再按一次Back键才会回到Conversation List。而ActionBar导航则不应该表现出这种行为，无论我们当前在哪一个Conversation details界面，点击一下导航按钮都应该回到Conversation List界面才对。 这就是ActionBar导航和Back键在设计上的区别，那么该怎样才能实现这样的功能呢？其实并不复杂，实现标准的ActionBar导航功能只需三步走。 第一步我们已经实现了，就是调用setDisplayHomeAsUpEnabled()方法，并传入true。 第二步需要在AndroidManifest.xml中配置父Activity，如下所示： **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:logo\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/weather\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;meta-data\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.support.PARENT_ACTIVITY\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:value\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.LaunchActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 可以看到，这里通过meta-data标签指定了MainActivity的父Activity是LaunchActivity，在Android 4.1版本之后，也可以直接使用android:parentActivityName这个属性来进行指定，如下所示： **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:logo\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/weather\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:parentActivityName\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.LaunchActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 第三步则需要对android.R.id.home这个事件进行一些特殊处理，如下所示： **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onOptionsItemSelected(MenuItem item) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (item.getItemId()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; android.R.id.home: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Intent upIntent = NavUtils.getParentActivityIntent(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (NavUtils.shouldUpRecreateTask(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, upIntent)) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; TaskStackBuilder.create(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .addNextIntentWithParentStack(upIntent) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .startActivities(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; NavUtils.navigateUpTo(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, upIntent); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230;\u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 其中，调用NavUtils.getParentActivityIntent()方法可以获取到跳转至父Activity的Intent，然后如果父Activity和当前Activity是在同一个Task中的，则直接调用navigateUpTo()方法进行跳转，如果不是在同一个Task中的，则需要借助TaskStackBuilder来创建一个新的Task。 这样，就按照标准的规范成功实现ActionBar导航的功能了。 添加Action View ActionView是一种可以在ActionBar中替换Action按钮的控件，它可以允许用户在不切换界面的情况下通过ActionBar完成一些较为丰富的操作。比如说，你需要完成一个搜索功能，就可以将SeachView这个控件添加到ActionBar中。 为了声明一个ActionView，我们可以在menu资源中通过actionViewClass属性来指定一个控件，例如可以使用如下方式添加SearchView： **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/action_search\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:icon\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_action_search\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:actionViewClass\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.widget.SearchView\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:showAsAction\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ifRoom|collapseActionView\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:title\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@string/action_search\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230;\u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 注意在showAsAction属性中我们还声明了一个collapseActionView，这个值表示该控件可以被合并成一个Action按钮。 现在重新运行一下程序，效果如下图所示： ![](http://img.blog.csdn.net/20140604232000843?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3VvbGluX2Jsb2c=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) OK，果然有一个搜索样式的Action按钮出现了，现在点击一下这个搜索按钮，效果如下图所示： ![](http://img.blog.csdn.net/20140604232624109?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3VvbGluX2Jsb2c=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 可以看到，这时SearchView就会展开占满整个ActionBar，而其它的Action按钮由于将showAsAction属性设置成了ifRoom，此时都会隐藏到overflow当中。 如果你还希望在代码中对SearchView的属性进行配置（比如添加监听事件等），完全没有问题，只需要在onCreateOptionsMenu()方法中获取该ActionView的实例就可以了，代码如下所示： **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onCreateOptionsMenu(Menu menu) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; MenuInflater inflater = getMenuInflater(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; inflater.inflate(R.menu.main, menu); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; MenuItem searchItem = menu.findItem(R.id.action_search); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; SearchView searchView = (SearchView) searchItem.getActionView(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 配置SearchView的属性\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230;\u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreateOptionsMenu(menu); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 在得到了SearchView的实例之后，就可以任意地配置它的各种属性了。关于SearchView的更多详细用法，可以参考官方文档 [http://developer.android.com/guide/topics/search/search-dialog.html](http://developer.android.com/guide/topics/search/search-dialog.html) 。\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 除此之外，有些程序可能还希望在ActionView展开和合并的时候显示不同的界面，其实我们只需要去注册一个ActionView的监听器就能实现这样的功能了，代码如下所示： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onCreateOptionsMenu(Menu menu) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; MenuInflater inflater = getMenuInflater(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; inflater.inflate(R.menu.main, menu); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; MenuItem searchItem = menu.findItem(R.id.action_search); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; searchItem.setOnActionExpandListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnActionExpandListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onMenuItemActionExpand(MenuItem item) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TAG\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;on expand\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onMenuItemActionCollapse(MenuItem item) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TAG\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;on collapse\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreateOptionsMenu(menu); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 可以看到，调用MenuItem的setOnActionExpandListener()方法就可以注册一个监听器了，当SearchView展开的时候就会回调onMenuItemActionExpand()方法，当SearchView合并的时候就会调用onMenuItemActionCollapse()方法，我们在这两个方法中进行相应的UI操作就可以了。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a style=\u0026quot;color: #336699;\u0026quot; name=\u0026quot;t6\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;Overflow按钮不显示的情况 \u0026lt;div\u0026gt; 虽然现在我们已经掌握了不少ActionBar的用法，但是当你真正去使用它的时候还是可能会遇到各种各样的问题，比如很多人都会碰到overflow按钮不显示的情况。明明是同样的一份代码，overflow按钮在有些手机上会显示，而在有些手机上偏偏就不显示，这是为什么呢？后来我总结了一下，overflow按钮的显示情况和手机的硬件情况是有关系的，如果手机没有物理Menu键的话，overflow按钮就可以显示，如果有物理Menu键的话，overflow按钮就不会显示出来。比如我们启动一个有Menu键的模拟器，然后将代码运行到该模拟器上，结果如下图所示： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140603224128421?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 可以看到，ActionBar最右边的overflow按钮不见了！那么此时我们如何查看隐藏在overflow中的Action按钮呢？其实非常简单，按一下Menu键，隐藏的内容就会从底部出来了，如下图所示： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140603224335953?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 看到这里相信不少朋友都想吐槽一下了，这显然是一种非常蛋疼的设计，在不同手机上竟然显示了不同的界面，而且操作方法也完全不一样，这样会给用户一种非常不习惯的感觉。话说Google为什么要把ActionBar的overflow设计成这样我也不太理解，但是我们还是有办法改变这一默认行为的。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 实际上，在ViewConfiguration这个类中有一个叫做sHasPermanentMenuKey的静态变量，系统就是根据这个变量的值来判断手机有没有物理Menu键的。当然这是一个内部变量，我们无法直接访问它，但是可以通过反射的方式修改它的值，让它永远为false就可以了，代码如下所示： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;#8230;\u0026amp;#8230; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setOverflowShowingAlways(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOverflowShowingAlways() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ViewConfiguration config = ViewConfiguration.get(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Field menuKeyField = ViewConfiguration.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getDeclaredField(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sHasPermanentMenuKey\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; menuKeyField.setAccessible(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; menuKeyField.setBoolean(config, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; e.printStackTrace(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 这里我们在onCreate()方法的最后调用了setOverflowShowingAlways()方法，而这个方法的内部就是使用反射的方式将sHasPermanentMenuKey的值设置成false，现在重新运行一下代码，结果如下图所示： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140603231228859?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 可以看到，即使是在有Menu键的手机上，也能让overflow按钮显示出来了，这样就可以大大增加我们软件界面和操作的统一性。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; ## \u0026lt;a style=\u0026quot;color: #336699;\u0026quot; name=\u0026quot;t7\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;让Overflow中的选项显示图标 \u0026lt;div\u0026gt; 如果你点击一下overflow按钮去查看隐藏的Action按钮，你会发现这部分Action按钮都是只显示文字不显示图标的，如下图所示： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140603234836500?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 这是官方的默认效果，Google认为隐藏在overflow中的Action按钮都应该只显示文字。当然，如果你认为这样不够美观，希望在overflow中的Action按钮也可以显示图标，我们仍然可以想办法来改变这一默认行为。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 其实，overflow中的Action按钮应不应该显示图标，是由MenuBuilder这个类的setOptionalIconsVisible方法来决定的，如果我们在overflow被展开的时候给这个方法传入true，那么里面的每一个Action按钮对应的图标就都会显示出来了。调用的方法当然仍然是用反射了，代码如下所示： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onMenuOpened(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; featureId, Menu menu) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (featureId == Window.FEATURE_ACTION_BAR \u0026amp;\u0026amp; menu != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (menu.getClass().getSimpleName().equals(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MenuBuilder\u0026amp;#8221;\u0026lt;/span\u0026gt;)) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Method m = menu.getClass().getDeclaredMethod(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;setOptionalIconsVisible\u0026amp;#8221;\u0026lt;/span\u0026gt;, Boolean.TYPE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; m.setAccessible(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; m.invoke(menu, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMenuOpened(featureId, menu); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 可以看到，这里我们重写了一个onMenuOpened()方法，当overflow被展开的时候就会回调这个方法，接着在这个方法的内部通过返回反射的方法将MenuBuilder的setOptionalIconsVisible变量设置为true就可以了。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 现在重新运行一下代码，结果如下图所示： \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; ![](http://img.blog.csdn.net/20140603235840984?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 好了，目前为止我们已经把ActionBar的基础知识介绍完了，那么今天的讲解就到这里 \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-actionbar%E5%AE%8C%E5%85%A8%E8%A7%A3%E6%9E%90%E4%BD%BF%E7%94%A8%E5%AE%98%E6%96%B9%E6%8E%A8%E8%8D%90%E7%9A%84%E6%9C%80%E4%BD%B3%E5%AF%BC%E8%88%AA%E6%A0%8F%E4%B8%8A/","summary":"\u003cp\u003e转载：\u003ca href=\"http://blog.csdn.net/guolin_blog/article/details/18234477\"\u003ehttp://blog.csdn.net/guolin_blog/article/details/18234477\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e本篇文章主要内容来自于Android Doc，我翻译之后又做了些加工，英文好的朋友也可以直接去读原文。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://developer.android.com/guide/topics/ui/actionbar.html\"\u003ehttp://developer.android.com/guide/topics/ui/actionbar.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAction Bar是一种新増的导航栏功能，在Android 3.0之后加入到系统的API当中，它标识了用户当前操作界面的位置，并提供了额外的用户动作、界面导航等功能。使用ActionBar的好处是，它可以给提供一种全局统一的UI界面，使得用户在使用任何一款软件时都懂得该如何操作，并且ActionBar还可以自动适应各种不同大小的屏幕。下面是一张使用ActionBar的界面截图：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140531141552515?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e其中，[1]是ActionBar的图标，[2]是两个action按钮，[3]是overflow按钮。\u003c/p\u003e\n\u003cp\u003e由于Action Bar是在3.0以后的版本中加入的，如果想在2.x的版本里使用ActionBar的话则需要引入\u003ca href=\"http://developer.android.com/tools/support-library/index.html\"\u003eSupport Library\u003c/a\u003e，不过3.0之前版本的市场占有率已经非常小了，这里简单起见我们就不再考虑去做向下兼容，而是只考虑4.0以上版本的用法。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch2 id=\"添加和移除action-bar\"\u003e\u003ca style=\"color: #336699;\" name=\"t0\"\u003e\u003c/a\u003e添加和移除Action Bar\u003c/h2\u003e\n\u003cp\u003eActionBar的添加非常简单，只需要在AndroidManifest.xml中指定Application或Activity的theme是Theme.Holo或其子类就可以了，而使用Eclipse创建的项目自动就会将Application的theme指定成Theme.Holo，所以ActionBar默认都是显示出来的。新建一个空项目并运行，效果如下图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140531151350125?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e而如果想要移除ActionBar的话通常有两种方式，一是将theme指定成Theme.Holo.NoActionBar，表示使用一个不包含ActionBar的主题，二是在Activity中调用以下方法：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;ActionBar actionBar = getActionBar();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;actionBar.hide();  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e现在重新运行一下程序，就可以看到ActionBar不再显示了，如下图所示：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140531154243281?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch2 id=\"修改action-bar的图标和标题\"\u003e\u003ca style=\"color: #336699;\" name=\"t1\"\u003e\u003c/a\u003e修改Action Bar的图标和标题\u003c/h2\u003e\n\u003cdiv\u003e\n  默认情况下，系统会使用\u003capplication\u003e或者\u003cactivity\u003e中icon属性指定的图片来作为ActionBar的图标，但是我们也可以改变这一默认行为。如果我们想要使用另外一张图片来作为ActionBar的图标，可以在\u003capplication\u003e或者\u003cactivity\u003e中通过logo属性来进行指定。比如项目的res/drawable目录下有一张weather.png图片，就可以在AndroidManifest.xml中这样指定：\n  \u003cdiv class=\"dp-highlighter bg_html\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:logo\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/weather\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e现在重新运行一下程序，效果如下图所示：\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20140602121519562?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\u003c/div\u003e\n\u003cdiv\u003e\n  OK，ActionBar的图标已经修改成功了，那么标题中的内容该怎样修改呢？其实也很简单，使用label属性来指定一个字符串就可以了，如下所示：\n  \u003cdiv class=\"dp-highlighter bg_html\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:label\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;天气\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:logo\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/weather\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  现在重新运行一下程序，结果如下图所示：\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20140602121652968?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch2 id=\"添加action按钮\"\u003e\u003ca style=\"color: #336699;\" name=\"t2\"\u003e\u003c/a\u003e添加Action按钮\u003c/h2\u003e\n\u003cdiv\u003e\n  ActionBar还可以根据应用程序当前的功能来提供与其相关的Action按钮，这些按钮都会以图标或文字的形式直接显示在ActionBar上。当然，如果按钮过多，ActionBar上显示不完，多出的一些按钮可以隐藏在overflow里面（最右边的三个点就是overflow按钮），点击一下overflow按钮就可以看到全部的Action按钮了。\n\u003c/div\u003e\n\u003cdiv\u003e\n  当Activity启动的时候，系统会调用Activity的onCreateOptionsMenu()方法来取出所有的Action按钮，我们只需要在这个方法中去加载一个menu资源，并把所有的Action按钮都定义在资源文件里面就可以了。\n\u003c/div\u003e\n\u003cdiv\u003e\n  那么我们先来看下menu资源文件该如何定义，代码如下所示：\n  \u003cdiv class=\"dp-highlighter bg_html\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/action_compose\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:icon\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_action_compose\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:showAsAction\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;always\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:title\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@string/action_compose\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/action_delete\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:icon\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_action_delete\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:showAsAction\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;always\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:title\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@string/action_delete\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/action_settings\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:icon\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_launcher\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:showAsAction\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;never\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:title\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@string/action_settings\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e可以看到，这里我们通过三个\u0026lt;item\u0026gt;标签定义了三个Action按钮。\u0026lt;item\u0026gt;标签中又有一些属性，其中id是该Action按钮的唯一标识符，icon用于指定该按钮的图标，title用于指定该按钮可能显示的文字（在图标能显示的情况下，通常不会显示文字），showAsAction则指定了该按钮显示的位置，主要有以下几种值可选：always表示永远显示在ActionBar中，如果屏幕空间不够则无法显示，ifRoom表示屏幕空间够的情况下显示在ActionBar中，不够的话就显示在overflow中，never则表示永远显示在overflow中。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  接着，重写Activity的onCreateOptionsMenu()方法，代码如下所示：\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onCreateOptionsMenu(Menu menu) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    MenuInflater inflater = getMenuInflater();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    inflater.inflate(R.menu.main, menu);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreateOptionsMenu(menu);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e这部分代码很简单，仅仅是调用了MenuInflater的inflate()方法来加载menu资源就可以了。现在重新运行一下程序，结果如下图所示：\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20140602121900750?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\u003c/div\u003e\n\u003cdiv\u003e\n  可以看到，action_compose和action_delete这两个按钮已经在ActionBar中显示出来了，而action_settings这个按钮由于showAsAction属性设置成了never，所以被隐藏到了overflow当中，只要点击一下overflow按钮就可以看到它了。\n\u003c/div\u003e\n\u003cdiv\u003e\n  这里我们注意到，显示在ActionBar上的按钮都只有一个图标而已，我们在title中指定的文字并没有显示出来。没错，title中的内容通常情况下只会在overflow中显示出来，ActionBar中由于屏幕空间有限，默认是不会显示title内容的。但是出于以下几种因素考虑，即使title中的内容无法显示出来，我们也应该给每个item中都指定一个title属性：\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003cpre\u003e\u003ccode\u003e- 当ActionBar中的剩余空间不足的时候，如果Action按钮指定的showAsAction属性是ifRoom的话，该Action按钮就会出现在overflow当中，此时就只有title能够显示了。\n\n- 如果Action按钮在ActionBar中显示，用户可能通过长按该Action按钮的方式来查看到title的内容。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003ch2 id=\"响应action按钮的点击事件\"\u003e\u003ca style=\"color: #336699;\" name=\"t3\"\u003e\u003c/a\u003e响应Action按钮的点击事件\u003c/h2\u003e\n\u003cdiv\u003e\n  当用户点击Action按钮的时候，系统会调用Activity的onOptionsItemSelected()方法，通过方法传入的MenuItem参数，我们可以调用它的getItemId()方法和menu资源中的id进行比较，从而辨别出用户点击的是哪一个Action按钮，比如：\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onOptionsItemSelected(MenuItem item) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (item.getItemId()) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.action_compose:  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Toast.makeText(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Compose\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.action_delete:  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Toast.makeText(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Delete\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; R.id.action_settings:  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Toast.makeText(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Settings\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;:  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onOptionsItemSelected(item);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e可以看到，我们让每个Action按钮被点击的时候都弹出一个Toast，现在重新运行一下代码，结果如下图所示：\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20140602115507171)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch2 id=\"通过action-bar图标进行导航\"\u003e\u003ca style=\"color: #336699;\" name=\"t4\"\u003e\u003c/a\u003e通过Action Bar图标进行导航\u003c/h2\u003e\n\u003cdiv\u003e\n  启用ActionBar图标导航的功能，可以允许用户根据当前应用的位置来在不同界面之间切换。比如，A界面展示了一个列表，点击某一项之后进入了B界面，这时B界面就应该启用ActionBar图标导航功能，这样就可以回到A界面。\n\u003c/div\u003e\n\u003cdiv\u003e\n  我们可以通过调用setDisplayHomeAsUpEnabled()方法来启用ActionBar图标导航功能，比如：\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    setTitle(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;天气\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    setContentView(R.layout.activity_main);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    ActionBar actionBar = getActionBar();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    actionBar.setDisplayHomeAsUpEnabled(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e现在重新运行一下程序，结果如下图所示：\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20140602152755500?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\u003c/div\u003e\n\u003cdiv\u003e\n  可以看到，在ActionBar图标的左侧出现了一个向左的箭头，通常情况下这都表示返回的意思，因此最简单的实现就是在它的点击事件里面加入finish()方法就可以了，如下所示：\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onOptionsItemSelected(MenuItem item) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (item.getItemId()) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; android.R.id.home:  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        finish();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    ……  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e当点击ActionBar图标的时候，系统同样会调用onOptionsItemSelected()方法，并且此时的itemId是android.R.id.home，所以finish()方法也就是加在这里的了。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  现在看上去，ActionBar导航和Back键的功能貌似是一样的。没错，如果我们只是简单地finish了一下，ActionBar导航和Back键的功能是完全一样的，但ActionBar导航的设计初衷并不是这样的，它和Back键的功能还是有一些区别的，举个例子吧。\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20140602161656000)\n\u003c/div\u003e\n\u003cdiv\u003e\n  上图中的Conversation List是收件箱的主界面，现在我们点击第一封邮件会进入到Conversation1 details界面，然后点击下一封邮件会进入到Conversation 2 details界面，再点击下一封邮箱会进入到Conversation3 details界面。好的，这个时候如果我们按下Back键，应该会回到Conversation 2 details界面，再按一次Back键应该回到Conversation1 details界面，再按一次Back键才会回到Conversation List。而ActionBar导航则不应该表现出这种行为，无论我们当前在哪一个Conversation details界面，点击一下导航按钮都应该回到Conversation List界面才对。\n\u003c/div\u003e\n\u003cdiv\u003e\n  这就是ActionBar导航和Back键在设计上的区别，那么该怎样才能实现这样的功能呢？其实并不复杂，实现标准的ActionBar导航功能只需三步走。\n\u003c/div\u003e\n\u003cdiv\u003e\n  第一步我们已经实现了，就是调用setDisplayHomeAsUpEnabled()方法，并传入true。\n\u003c/div\u003e\n\u003cdiv\u003e\n  第二步需要在AndroidManifest.xml中配置父Activity，如下所示：\n  \u003cdiv class=\"dp-highlighter bg_html\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:logo\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/weather\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;meta-data\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.support.PARENT_ACTIVITY\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:value\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.LaunchActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e可以看到，这里通过meta-data标签指定了MainActivity的父Activity是LaunchActivity，在Android 4.1版本之后，也可以直接使用android:parentActivityName这个属性来进行指定，如下所示：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:logo\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/weather\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:parentActivityName\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.example.actionbartest.LaunchActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;activity\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e第三步则需要对android.R.id.home这个事件进行一些特殊处理，如下所示：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onOptionsItemSelected(MenuItem item) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (item.getItemId()) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; android.R.id.home:  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Intent upIntent = NavUtils.getParentActivityIntent(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (NavUtils.shouldUpRecreateTask(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, upIntent)) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            TaskStackBuilder.create(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;)  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    .addNextIntentWithParentStack(upIntent)  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    .startActivities();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            NavUtils.navigateUpTo(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, upIntent);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026amp;#8230;\u0026amp;#8230;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e其中，调用NavUtils.getParentActivityIntent()方法可以获取到跳转至父Activity的Intent，然后如果父Activity和当前Activity是在同一个Task中的，则直接调用navigateUpTo()方法进行跳转，如果不是在同一个Task中的，则需要借助TaskStackBuilder来创建一个新的Task。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  这样，就按照标准的规范成功实现ActionBar导航的功能了。\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003ch2 id=\"添加action-view\"\u003e\u003ca style=\"color: #336699;\" name=\"t5\"\u003e\u003c/a\u003e添加Action View\u003c/h2\u003e\n\u003cdiv\u003e\n  ActionView是一种可以在ActionBar中替换Action按钮的控件，它可以允许用户在不切换界面的情况下通过ActionBar完成一些较为丰富的操作。比如说，你需要完成一个搜索功能，就可以将SeachView这个控件添加到ActionBar中。\n\u003c/div\u003e\n\u003cdiv\u003e\n  为了声明一个ActionView，我们可以在menu资源中通过actionViewClass属性来指定一个控件，例如可以使用如下方式添加SearchView：\n  \u003cdiv class=\"dp-highlighter bg_html\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/action_search\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:icon\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/ic_action_search\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:actionViewClass\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.widget.SearchView\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:showAsAction\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ifRoom|collapseActionView\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:title\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@string/action_search\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026amp;#8230;\u0026amp;#8230;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;menu\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e注意在showAsAction属性中我们还声明了一个collapseActionView，这个值表示该控件可以被合并成一个Action按钮。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  现在重新运行一下程序，效果如下图所示：\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20140604232000843?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3VvbGluX2Jsb2c=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\u003c/div\u003e\n\u003cdiv\u003e\n  OK，果然有一个搜索样式的Action按钮出现了，现在点击一下这个搜索按钮，效果如下图所示：\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20140604232624109?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3VvbGluX2Jsb2c=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\u003c/div\u003e\n\u003cdiv\u003e\n  可以看到，这时SearchView就会展开占满整个ActionBar，而其它的Action按钮由于将showAsAction属性设置成了ifRoom，此时都会隐藏到overflow当中。\n\u003c/div\u003e\n\u003cdiv\u003e\n  如果你还希望在代码中对SearchView的属性进行配置（比如添加监听事件等），完全没有问题，只需要在onCreateOptionsMenu()方法中获取该ActionView的实例就可以了，代码如下所示：\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onCreateOptionsMenu(Menu menu) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    MenuInflater inflater = getMenuInflater();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    inflater.inflate(R.menu.main, menu);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    MenuItem searchItem = menu.findItem(R.id.action_search);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    SearchView searchView = (SearchView) searchItem.getActionView();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 配置SearchView的属性\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026amp;#8230;\u0026amp;#8230;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreateOptionsMenu(menu);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e在得到了SearchView的实例之后，就可以任意地配置它的各种属性了。关于SearchView的更多详细用法，可以参考官方文档 [http://developer.android.com/guide/topics/search/search-dialog.html](http://developer.android.com/guide/topics/search/search-dialog.html) 。\u0026lt;/div\u0026gt; \n\n\u0026lt;div\u0026gt;\n  除此之外，有些程序可能还希望在ActionView展开和合并的时候显示不同的界面，其实我们只需要去注册一个ActionView的监听器就能实现这样的功能了，代码如下所示：\n\n  \n  \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n        **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\n        \n        \u0026lt;div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onCreateOptionsMenu(Menu menu) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    MenuInflater inflater = getMenuInflater();  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    inflater.inflate(R.menu.main, menu);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    MenuItem searchItem = menu.findItem(R.id.action_search);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    searchItem.setOnActionExpandListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnActionExpandListener() {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onMenuItemActionExpand(MenuItem item) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TAG\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;on expand\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onMenuItemActionCollapse(MenuItem item) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            Log.d(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;TAG\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;on collapse\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    });  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreateOptionsMenu(menu);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n      \n    \n  \u0026lt;/div\u0026gt;\n  \n  \n\n    可以看到，调用MenuItem的setOnActionExpandListener()方法就可以注册一个监听器了，当SearchView展开的时候就会回调onMenuItemActionExpand()方法，当SearchView合并的时候就会调用onMenuItemActionCollapse()方法，我们在这两个方法中进行相应的UI操作就可以了。\n  \n\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n## \u0026lt;a style=\u0026quot;color: #336699;\u0026quot; name=\u0026quot;t6\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;Overflow按钮不显示的情况\n\n\u0026lt;div\u0026gt;\n  虽然现在我们已经掌握了不少ActionBar的用法，但是当你真正去使用它的时候还是可能会遇到各种各样的问题，比如很多人都会碰到overflow按钮不显示的情况。明明是同样的一份代码，overflow按钮在有些手机上会显示，而在有些手机上偏偏就不显示，这是为什么呢？后来我总结了一下，overflow按钮的显示情况和手机的硬件情况是有关系的，如果手机没有物理Menu键的话，overflow按钮就可以显示，如果有物理Menu键的话，overflow按钮就不会显示出来。比如我们启动一个有Menu键的模拟器，然后将代码运行到该模拟器上，结果如下图所示：\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  ![](http://img.blog.csdn.net/20140603224128421?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  可以看到，ActionBar最右边的overflow按钮不见了！那么此时我们如何查看隐藏在overflow中的Action按钮呢？其实非常简单，按一下Menu键，隐藏的内容就会从底部出来了，如下图所示：\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  ![](http://img.blog.csdn.net/20140603224335953?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  看到这里相信不少朋友都想吐槽一下了，这显然是一种非常蛋疼的设计，在不同手机上竟然显示了不同的界面，而且操作方法也完全不一样，这样会给用户一种非常不习惯的感觉。话说Google为什么要把ActionBar的overflow设计成这样我也不太理解，但是我们还是有办法改变这一默认行为的。\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  实际上，在ViewConfiguration这个类中有一个叫做sHasPermanentMenuKey的静态变量，系统就是根据这个变量的值来判断手机有没有物理Menu键的。当然这是一个内部变量，我们无法直接访问它，但是可以通过反射的方式修改它的值，让它永远为false就可以了，代码如下所示：\n\n  \n  \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n        **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\n        \n        \u0026lt;div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026amp;#8230;\u0026amp;#8230;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    setOverflowShowingAlways();  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOverflowShowingAlways() {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        ViewConfiguration config = ViewConfiguration.get(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Field menuKeyField = ViewConfiguration.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;.getDeclaredField(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sHasPermanentMenuKey\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        menuKeyField.setAccessible(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        menuKeyField.setBoolean(config, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        e.printStackTrace();  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n      \n    \n  \u0026lt;/div\u0026gt;\n  \n  \n\n    这里我们在onCreate()方法的最后调用了setOverflowShowingAlways()方法，而这个方法的内部就是使用反射的方式将sHasPermanentMenuKey的值设置成false，现在重新运行一下代码，结果如下图所示：\n  \n\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  ![](http://img.blog.csdn.net/20140603231228859?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  可以看到，即使是在有Menu键的手机上，也能让overflow按钮显示出来了，这样就可以大大增加我们软件界面和操作的统一性。\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n## \u0026lt;a style=\u0026quot;color: #336699;\u0026quot; name=\u0026quot;t7\u0026quot;\u0026gt;\u0026lt;/a\u0026gt;让Overflow中的选项显示图标\n\n\u0026lt;div\u0026gt;\n  如果你点击一下overflow按钮去查看隐藏的Action按钮，你会发现这部分Action按钮都是只显示文字不显示图标的，如下图所示：\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  ![](http://img.blog.csdn.net/20140603234836500?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  这是官方的默认效果，Google认为隐藏在overflow中的Action按钮都应该只显示文字。当然，如果你认为这样不够美观，希望在overflow中的Action按钮也可以显示图标，我们仍然可以想办法来改变这一默认行为。\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  其实，overflow中的Action按钮应不应该显示图标，是由MenuBuilder这个类的setOptionalIconsVisible方法来决定的，如果我们在overflow被展开的时候给这个方法传入true，那么里面的每一个Action按钮对应的图标就都会显示出来了。调用的方法当然仍然是用反射了，代码如下所示：\n\n  \n  \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n      \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n        **[java]** [view plain](http://blog.csdn.net/guolin_blog/article/details/18234477#)[copy](http://blog.csdn.net/guolin_blog/article/details/18234477#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/377213)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/377213/fork)\n\n        \n        \u0026lt;div\u0026gt;\n        \u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onMenuOpened(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; featureId, Menu menu) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (featureId == Window.FEATURE_ACTION_BAR \u0026amp;\u0026amp; menu != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (menu.getClass().getSimpleName().equals(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;MenuBuilder\u0026amp;#8221;\u0026lt;/span\u0026gt;)) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                Method m = menu.getClass().getDeclaredMethod(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;setOptionalIconsVisible\u0026amp;#8221;\u0026lt;/span\u0026gt;, Boolean.TYPE);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                m.setAccessible(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                m.invoke(menu, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) {  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onMenuOpened(featureId, menu);  \u0026lt;/span\u0026gt;\n      \n      - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n      \n    \n  \u0026lt;/div\u0026gt;\n  \n  \n\n    可以看到，这里我们重写了一个onMenuOpened()方法，当overflow被展开的时候就会回调这个方法，接着在这个方法的内部通过返回反射的方法将MenuBuilder的setOptionalIconsVisible变量设置为true就可以了。\n  \n\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  现在重新运行一下代码，结果如下图所示：\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  ![](http://img.blog.csdn.net/20140603235840984?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2lueXU4OTA4MDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  好了，目前为止我们已经把ActionBar的基础知识介绍完了，那么今天的讲解就到这里\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e","title":"Android ActionBar完全解析，使用官方推荐的最佳导航栏(上)"},{"content":"请求某些网站的图片时\n/**\n根据一个网络连接(String)获取bitmap图像 @param imageUri @return @throws MalformedURLException\n*/\npublic Bitmap getbitmap(String imageUri) {\n// 显示网络上的图片\nBitmap bitmap = null;\ntry {\nURL myFileUrl = new URL(imageUri);\nHttpURLConnection conn = (HttpURLConnection) myFileUrl\n.openConnection();\n// conn.setDoInput(true);\nconn.setRequestProperty(“User-agent”, “Mozilla/4.0”);\nconn.connect();\nInputStream is = conn.getInputStream();\nbitmap = BitmapFactory.decodeStream(is);\nis.close(); } catch (IOException e) {\ne.printStackTrace();\nreturn null;\n}\nreturn bitmap;\n}\n如果不添加conn.setRequestProperty(“User-agent”, “Mozilla/4.0”);这句会造成返回的状态code是403，\n使用\npublic Bitmap loadImageFromUrl(String url) {\nBitmap d = null;\n// URL m;\nInputStream i = null;\ntry {\nHttpGet get = new HttpGet(url);\nDefaultHttpClient client = new DefaultHttpClient();\nHttpResponse re = client.execute(get);\ni = re.getEntity().getContent();\n} catch (MalformedURLException e1) {\ne1.printStackTrace();\nreturn null;\n} catch (IOException e) {\ne.printStackTrace();\nreturn null;\n}\nd = BitmapFactory.decodeStream(i);\nreturn d;\n}\n就不会有这种情况，最后得到如下结论\n当我用HttpURLConnection去连接读取一个网站时，老是会发生这个403错误。这个引起了IOException，但是我用firefox访问这个网站时就没问题。 google后知道了答案。原来如果用java代码HttpURLConnection去连的话 http header 中的User-Agent就为空，解决方法就是在连接之前先设置这个属性。\nURL myUrl = \u0026lt;span style=\u0026#34;color: #000080;\u0026#34;\u0026gt;**new**\u0026lt;/span\u0026gt; URL(searchURL); URLConnection myConn = (HttpURLConnection)myUrl.openConnection(); myConn.setRequestProperty(\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;\u0026#34;User-agent\u0026#34;\u0026lt;/span\u0026gt;,\u0026lt;span style=\u0026#34;color: #ff0000;\u0026#34;\u0026gt;\u0026#34;Mozilla/4.0\u0026#34;\u0026lt;/span\u0026gt;); BufferedReader br = \u0026lt;span style=\u0026#34;color: #000080;\u0026#34;\u0026gt;**new**\u0026lt;/span\u0026gt; BufferedReader(\u0026lt;span style=\u0026#34;color: #000080;\u0026#34;\u0026gt;**new**\u0026lt;/span\u0026gt; InputStreamReader(myConn.getInputStream())); 那台Server上要这么做， 可能是要阻止一些网络机器人的访问（不过感觉不是很有用，用上面的方法就能破了）。\n其实实现感觉也很简单， 加上一个Filter，判断如果request.getHeader(“User-agent”)为空的话，然后再response一个403 status就行。\n","permalink":"https://blog.zdltech.com/posts/httpurlconnection-%E8%AE%BF%E9%97%AE%E5%9B%BE%E7%89%87%E6%97%B6%E5%8F%91%E7%94%9F403%E9%97%AE%E9%A2%98%E4%BD%BF%E7%94%A8defaulthttpclient%E5%B0%B1ok/","summary":"\u003cp\u003e请求某些网站的图片时\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e根据一个网络连接(String)获取bitmap图像\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e@param imageUri\u003c/li\u003e\n\u003cli\u003e@return\u003c/li\u003e\n\u003cli\u003e@throws MalformedURLException\u003cbr\u003e\n*/\u003cbr\u003e\npublic Bitmap getbitmap(String imageUri) {\u003cbr\u003e\n// 显示网络上的图片\u003cbr\u003e\nBitmap bitmap = null;\u003cbr\u003e\ntry {\u003cbr\u003e\nURL myFileUrl = new URL(imageUri);\u003cbr\u003e\nHttpURLConnection conn = (HttpURLConnection) myFileUrl\u003cbr\u003e\n.openConnection();\u003cbr\u003e\n// conn.setDoInput(true);\u003cbr\u003e\nconn.setRequestProperty(“User-agent”, “Mozilla/4.0”);\u003cbr\u003e\nconn.connect();\u003cbr\u003e\nInputStream is = conn.getInputStream();\u003cbr\u003e\nbitmap = BitmapFactory.decodeStream(is);\u003cbr\u003e\nis.close();\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e} catch (IOException e) {\u003cbr\u003e\ne.printStackTrace();\u003cbr\u003e\nreturn null;\u003cbr\u003e\n}\u003cbr\u003e\nreturn bitmap;\u003cbr\u003e\n}\u003c/p\u003e\n\u003cp\u003e如果不添加conn.setRequestProperty(“User-agent”, “Mozilla/4.0”);这句会造成返回的状态code是403，\u003c/p\u003e\n\u003cp\u003e使用\u003c/p\u003e\n\u003cp\u003epublic Bitmap loadImageFromUrl(String url) {\u003cbr\u003e\nBitmap d = null;\u003cbr\u003e\n// URL m;\u003cbr\u003e\nInputStream i = null;\u003cbr\u003e\ntry {\u003cbr\u003e\nHttpGet get = new HttpGet(url);\u003cbr\u003e\nDefaultHttpClient client = new DefaultHttpClient();\u003cbr\u003e\nHttpResponse re = client.execute(get);\u003cbr\u003e\ni = re.getEntity().getContent();\u003cbr\u003e\n} catch (MalformedURLException e1) {\u003cbr\u003e\ne1.printStackTrace();\u003cbr\u003e\nreturn null;\u003cbr\u003e\n} catch (IOException e) {\u003cbr\u003e\ne.printStackTrace();\u003cbr\u003e\nreturn null;\u003cbr\u003e\n}\u003cbr\u003e\nd = BitmapFactory.decodeStream(i);\u003cbr\u003e\nreturn d;\u003cbr\u003e\n}\u003c/p\u003e","title":"HttpURLConnection 访问图片时发生403问题，使用DefaultHttpClient就OK"},{"content":"面试题一：AIDL****的全称是什么？如何工作？\nAndroid interface definition language (android接口定义语言) ,\n用来跨进程的访问方法, 像 游戏中调用支付宝接口就是用的这个。\n访问远程的服务的方法. 如何工作。\n面试题二：Android****程序运行时权限与文件系统权限的区别？\n程序运行时权限：Android程序执行需要读取到安全敏感项必需在androidmanifest.xml中声明相关权限请求,打电话,访问网络,获取坐标,写sd卡,读写联系人等..安装的时候会提示用户。\n文件系统权限：其实就是Linux的文件系统权限，比如-rw—— 私有权限 -rw-rw-rw- 全局可读可写，（777是可读可写可执行1+2+4）还有sharedpreference里面的Context.Mode_private\nContext.Mode.world_read_able Context.Mode_world_writeable夜市文件系统的权限。\n**面试题三：**系统上安装了多种浏览器，能否指定某浏览器访问指定页面？\n找到对应的浏览器的意图,传递数据URI , 激活这个意图\nIntent .setAction(VIEW)\nIntent intent = new Intent();\n// com.android.browser/.BrowserActivity\nintent.setClassName(“com.android.browser”, “com.android.browser.BrowserActivity”);\nIntent.setdata(uri);\n像腾讯那个检测是否安装自己的浏览器，方法是queryintentactivity()，获取到所有Action。然后查里面有没有自己浏览器的action，没有的话就提示用户。\n面试题四：对主线程的理解：\n耗时的不能再主线程做，会anr异常，像安卓四大组件都是在主线程里面。\n面试题五：Framework****工作方式及原理，Activity是如何生成一个view的，机制是什么？\n所有的框架都是基于反射 和 配置文件（manifest）的。\nActivity创建一个view是通过 ondraw 画出来的, 画这个view之前呢,还会调用onmeasure方法来计算显示的大小.但是Surfaceview 是直接操作硬件的，因为 或者视频播放对帧数有要求，onDraw效率太低，不够使，Surfaceview直接把数据写到显存。\n面试题六：android****本身的一些限制，比如apk包大小限制，读取大文件时的时间限？\n如果在broadCast里面不能超过10秒，\n在service里面不能超过20秒\n在主线程里面不能超过5秒。\n像有些系统不能安装大文件，我们一般是把素材文件放到一个素材包而不是安装包，两者区分开。\n**面试题七：**如何加载的音乐信息，如何改善其效率？\nAndroid提供mediascanner,mediaStore等接口, 音乐文件的信息都会存放到系统的数据库表中,可以通过content provider获取,\n显示出来,改善效率,是个常见问题, 可以从以下几个方面作答,\n分批加载数据, 延时加载数据, 合理使用缓存等… 预先加载一些 都会的使用的大的class的字节码, 提前加载. 时间换时间 空间换时间 面试题八：ListView****如何提高其效率？\n异步加载数据, 分页加载数据,使用 onscallLinster(); 2.Static class ViewHolder\n3. 使用静态的view对象 避免创建过多的view.\n4. 把下载后的数据缓存到数据库里\n5. 客户端和服务器 协同 作战，比如说客户端请求图片的时候，先把自己的图片数据和服务器比对一下，如果服务器图片未更新，就拿缓存。看客户端图片的If-modify-since :属性就只掉最后修改时间，在网易新闻客户端就用到了这个。\n**面试题九：**启动一个程序，可以主界面点击图标进入，也可以从一个程序中跳转过去，二者有什么区别？\n面试题十：Android****程序与Java程序的区别？\nAndroid程序用android sdk开发,java程序用javasdk开发.\nAndroid SDK引用了大部分的Java SDK，少数部分被Android SDK抛弃，比如说界面部分，java.awt swing package除了java.awt.font被引用外，其他都被抛弃，在Android平台开发中不能使用。\nandroid sdk 添加工具jar httpclient , pull openGL\n1.6的 不支持 httpUrlconning 获取 last-modified 信息的处理\nsimpleDataFormat 在java中年时小写，在安卓里面是大写。\n面试题十一：在Android中，怎么节省内存的使用，怎么主动回收内存？：\n**面试题十二：**不同工程中的方法是否可以相互调用？\n可以，aidl就是这样子的。支付宝服务。\n面试题十三：dvm****的进程和Linux的进程, 应用程序的进程是否为同一个概念？\nDvm的进程是dalivk虚拟机进程,每个android程序都运行在自己的进程里面,\n每个android程序系统都会给他分配一个单独的liunx uid(user id),\n每个dvm都是linux里面的一个进程.所以说这两个进程是一个进程.\n**面试题十四：**如何判断是否有SD卡？\nif (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))\n**面试题十五：**嵌入式操作系统内存管理有哪几种， 各有何特性。？\n这是大学里面操作系统的知识，包括纯分页，纯分段和段页式存储。\n面试题十六：什么是嵌入式实时操作系统, Android 操作系统属于实时操作系统吗?\n实时操作系统分为两种，硬实时和 软实时，硬实时一般用在军工，比如火星探测器，航空啊等等，是一旦又中断产生就会立即响应中断，而软实时是基于一套算法，可以不立即响应中断，我们一般的操作系统都是软实时操作系统，Android也不例外。\n面试题十七：Linux****中跨进程通信的几种方式？\n管道( pipe )，信号量( semophore )，信号 ( sinal )，共享内存( shared memory )，套接字( socket )。\n面试题十八：谈谈对Android NDK的理解：\n1.实时性要求高的软件。比如游戏,图形渲染, opencv (人脸识别)\n2.调用C或者c+++的代码库，第一是性能好，第二是人家写好了直接能用了，而java的代码库太少了。ffmpeg , rmvb mp5 avi 高清解码. ffmpeg, opencore\n优点：效率高，缺点：出错之后不好调试，写起来也麻烦。软件升级的时候也不方便。 面试题十九：Android UI中的View如何刷新。\n分主线程和子线程中两种情况：‘\n主线程用控件调用Invalide()方法。iv.invalidate();\n子线程用控件调用postInvalidate();—iv.postInvalidate();\n","permalink":"https://blog.zdltech.com/posts/%E5%AE%89%E5%8D%93%E9%9D%A2%E8%AF%95%E6%98%93%E8%80%83%E9%A2%98%E4%B8%80/","summary":"\u003cp\u003e\u003cstrong\u003e面试题一：AIDL****的全称是什么？如何工作？\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eAndroid interface definition language (android接口定义语言) ,\u003c/p\u003e\n\u003cp\u003e用来跨进程的访问方法, 像 游戏中调用支付宝接口就是用的这个。\u003c/p\u003e\n\u003cp\u003e访问远程的服务的方法. 如何工作。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e面试题二：Android****程序运行时权限与文件系统权限的区别？\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e程序运行时权限：Android程序执行需要读取到安全敏感项必需在androidmanifest.xml中声明相关权限请求,打电话,访问网络,获取坐标,写sd卡,读写联系人等..安装的时候会提示用户。\u003c/p\u003e\n\u003cp\u003e文件系统权限：其实就是Linux的文件系统权限，比如-rw—— 私有权限 -rw-rw-rw- 全局可读可写，（777是可读可写可执行1+2+4）还有sharedpreference里面的Context.Mode_private\u003c/p\u003e\n\u003cp\u003eContext.Mode.world_read_able   Context.Mode_world_writeable夜市文件系统的权限。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e**面试题三：**\u003cstrong\u003e系统上安装了多种浏览器，能否指定某浏览器访问指定页面？\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e找到对应的浏览器的意图,传递数据URI , 激活这个意图\u003c/p\u003e\n\u003cp\u003eIntent .setAction(VIEW)\u003c/p\u003e\n\u003cp\u003eIntent intent = \u003cstrong\u003enew\u003c/strong\u003e Intent();\u003c/p\u003e\n\u003cp\u003e// com.android.browser/.BrowserActivity\u003c/p\u003e\n\u003cp\u003eintent.setClassName(“com.android.browser”, “com.android.browser.BrowserActivity”);\u003c/p\u003e\n\u003cp\u003eIntent.setdata(uri);\u003c/p\u003e\n\u003cp\u003e像腾讯那个检测是否安装自己的浏览器，方法是queryintentactivity()，获取到所有Action。然后查里面有没有自己浏览器的action，没有的话就提示用户。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e面试题四：对主线程的理解：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e耗时的不能再主线程做，会anr异常，像安卓四大组件都是在主线程里面。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e面试题五：Framework****工作方式及原理，Activity是如何生成一个view的，机制是什么？\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e所有的框架都是基于反射 和 配置文件（manifest）的。\u003c/p\u003e\n\u003cp\u003eActivity创建一个view是通过 ondraw 画出来的, 画这个view之前呢,还会调用onmeasure方法来计算显示的大小.但是Surfaceview 是直接操作硬件的，因为 或者视频播放对帧数有要求，onDraw效率太低，不够使，Surfaceview直接把数据写到显存。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e面试题六：android****本身的一些限制，比如apk包大小限制，读取大文件时的时间限？\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e如果在broadCast里面不能超过10秒，\u003c/p\u003e\n\u003cp\u003e在service里面不能超过20秒\u003c/p\u003e\n\u003cp\u003e在主线程里面不能超过5秒。\u003c/p\u003e\n\u003cp\u003e像有些系统不能安装大文件，我们一般是把素材文件放到一个素材包而不是安装包，两者区分开。\u003c/p\u003e\n\u003cp\u003e**面试题七：**\u003cstrong\u003e如何加载的音乐信息，如何改善其效率？\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eAndroid提供mediascanner,mediaStore等接口, 音乐文件的信息都会存放到系统的数据库表中,可以通过content provider获取,\u003c/p\u003e\n\u003cp\u003e显示出来,改善效率,是个常见问题, 可以从以下几个方面作答,\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e分批加载数据, 延时加载数据, 合理使用缓存等…\u003c/li\u003e\n\u003cli\u003e预先加载一些 都会的使用的大的class的字节码, 提前加载.\u003c/li\u003e\n\u003cli\u003e时间换时间\u003c/li\u003e\n\u003cli\u003e空间换时间\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e面试题八：ListView****如何提高其效率？\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e异步加载数据,  分页加载数据,使用 onscallLinster();\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e2.Static class ViewHolder\u003c/p\u003e","title":"安卓面试题（一）"},{"content":"今天具体说下Android检测网络状态的广播，我们在做一些手机应用的时候如果网络发生改变可能会给用户造成一些损失，在中国2G，3G网络都没有普及的情况下，基本都是包流量的，所以在做一些视频应用软件的时候，如果用户在使用WIFI的时候如果无线网络中断，手机网络会自动换手机网络，从而给用户造成不必要的损失。\nAndroid手机在对于一些系统广播，如短信的接收，电话的接收，电池电量过低，网络状态改变都会发一个广播，既然系统会发送一条广播，那么就需要一个接收器来处理这个广播。首先定义一个类继承NetworkChangeReceiver，重写onReceive()就行了。然后在OnReceive()这个方法进行相应广播的处理。\n网络状态切换的广播类：\n**[java]** [view plain](http://blog.csdn.net/lonely_fireworks/article/details/7373166#)[copy](http://blog.csdn.net/lonely_fireworks/article/details/7373166#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.test; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.BroadcastReceiver; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.net.ConnectivityManager; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.net.NetworkInfo.State; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; BroadcastReceiver { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onReceive(Context context, Intent intent) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; State wifiState = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; State mobileState = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; wifiState = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mobileState = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (wifiState != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mobileState != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;\u0026amp; State.CONNECTED != wifiState \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;\u0026amp; State.CONNECTED == mobileState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 手机网络连接成功\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (wifiState != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mobileState != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;\u0026amp; State.CONNECTED != wifiState \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026amp;\u0026amp; State.CONNECTED != mobileState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 手机没有任何的网络\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (wifiState != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; State.CONNECTED == wifiState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 无线网络连接成功\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 在上面这个接收类中OnReceive()方法，你可以在上面三个网络状态（只有手机网络，只有无线网络，没有任何网络）中进行相应的处理，然后在应用中注册广播，注册广播有2种方式，一种在androidmanifest.xml中注册，一种在java代码中注册。\n第一种：\n**[html]** [view plain](http://blog.csdn.net/lonely_fireworks/article/details/7373166#)[copy](http://blog.csdn.net/lonely_fireworks/article/details/7373166#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;receiver\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;com.test.NetworkBroadcast\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:label\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;NetworkConnection\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;action\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:name\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;android.net.conn.CONNECTIVITY_CHANGE\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;intent-filter\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;receiver\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 第二种：\n可以在Activity的onCreate()方法中注册广播，在Activity的onDestory()方法中卸载广播。\n**[java]** [view plain](http://blog.csdn.net/lonely_fireworks/article/details/7373166#)[copy](http://blog.csdn.net/lonely_fireworks/article/details/7373166#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; BroadcastReceiver networkBroadcast=\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; BroadcastReceiver(); \u0026lt;/span\u0026gt; **[java]** [view plain](http://blog.csdn.net/lonely_fireworks/article/details/7373166#)[copy](http://blog.csdn.net/lonely_fireworks/article/details/7373166#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; registerNetworkReceiver() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; IntentFilter filter = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.registerReceiver(networkBroadcast, filter); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; unRegisterNetworkReceiver() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.unregisterReceiver(networkBroadcast); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 注意：在接收类中的onReceive()方法中不要处理太多复杂逻辑问题，尤其耗时的操作。\n","permalink":"https://blog.zdltech.com/posts/android%E4%B9%8B%E7%9B%91%E6%B5%8B%E6%89%8B%E6%9C%BA%E7%BD%91%E7%BB%9C%E7%8A%B6%E6%80%81%E7%9A%84%E5%B9%BF%E6%92%AD/","summary":"\u003cp\u003e今天具体说下Android检测网络状态的广播，我们在做一些手机应用的时候如果网络发生改变可能会给用户造成一些损失，在中国2G，3G网络都没有普及的情况下，基本都是包流量的，所以在做一些视频应用软件的时候，如果用户在使用WIFI的时候如果无线网络中断，手机网络会自动换手机网络，从而给用户造成不必要的损失。\u003c/p\u003e\n\u003cp\u003eAndroid手机在对于一些系统广播，如短信的接收，电话的接收，电池电量过低，网络状态改变都会发一个广播，既然系统会发送一条广播，那么就需要一个接收器来处理这个广播。首先定义一个类继承NetworkChangeReceiver，重写onReceive()就行了。然后在OnReceive()这个方法进行相应广播的处理。\u003c/p\u003e\n\u003cp\u003e网络状态切换的广播类：\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/lonely_fireworks/article/details/7373166#)[copy](http://blog.csdn.net/lonely_fireworks/article/details/7373166#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.test;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.BroadcastReceiver;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Intent;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.net.ConnectivityManager;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.net.NetworkInfo.State;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; BroadcastReceiver {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onReceive(Context context, Intent intent) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        State wifiState = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        State mobileState = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        wifiState = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mobileState = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (wifiState != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mobileState != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026amp;\u0026amp; State.CONNECTED != wifiState  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026amp;\u0026amp; State.CONNECTED == mobileState) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 手机网络连接成功\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (wifiState != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mobileState != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026amp;\u0026amp; State.CONNECTED != wifiState  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026amp;\u0026amp; State.CONNECTED != mobileState) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 手机没有任何的网络\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (wifiState != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; State.CONNECTED == wifiState) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 无线网络连接成功\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e在上面这个接收类中OnReceive()方法，你可以在上面三个网络状态（只有手机网络，只有无线网络，没有任何网络）中进行相应的处理，然后在应用中注册广播，注册广播有2种方式，一种在androidmanifest.xml中注册，一种在java代码中注册。\u003c/p\u003e","title":"Android之监测手机网络状态的广播"},{"content":" 随着科技的进步，二维码应用领域越来越广泛，今天我给大家分享下如何使用PHP生成二维码，以及如何生成中间带LOGO图像的二维码 **一、利用Google API生成二维码** Google提供了较为完善的二维码生成接口，调用API接口很简单，以下是调用代码： urlToEncode=\u0026#8221;http://www.jb51.net\u0026#8221;; generateQRfromGoogle(urlToEncode); /** * google api 二维码生成【QRcode可以存储最多4296个字母数字类型的任意文本，具体可以查看二维码数据格式】 * @param string chl 二维码包含的信息，可以是数字、字符、二进制信息、汉字。 不能混合数据类型，数据必须经过UTF-8 URL-encoded * @param intwidhtHeight 生成二维码的尺寸设置 * @param string EC_level 可选纠错级别，QR码支持四个等级纠错，用来恢复丢失的、读错的、模糊的、数据。 * L-默认：可以识别已损失的7%的数据 * M-可以识别已损失15%的数据 * Q-可以识别已损失25%的数据 * H-可以识别已损失30%的数据 * @param intmargin 生成的二维码离图片边框的距离 */ function generateQRfromGoogle(chl,widhtHeight =\u0026#8217;150\u0026#8242;,EC_level=\u0026#8217;L\u0026#8217;,margin=\u0026#8217;0\u0026#8242;) { chl = urlencode(chl); echo \u0026#8216;widhtHeight.\u0026#8217;x\u0026#8217;.widhtHeight.\u0026#8217; \u0026cht=qr\u0026chld=\u0026#8217;.EC_level.\u0026#8217;|\u0026#8217;.margin.\u0026#8217;\u0026chl=\u0026#8217;.chl.'\u0026#8221; alt=\u0026#8221;QR code\u0026#8221; widhtHeight=\u0026#8221;\u0026#8216;.widhtHeight.\u0026#8217; \u0026#8221; widhtHeight=\u0026#8221;\u0026#8216;.$widhtHeight.'\u0026#8221;/\u003e\u0026#8217;; } 二、使用PHP二维码生成类库PHP QR Code生成二维码 PHP QR Code是一个PHP二维码生成类库，利用它可以轻松生成二维码，官网提供了下载和多个演示demo，查看地址：http://phpqrcode.sourceforge.net/。 下载官网提供的类库后，只需要使用phpqrcode.php就可以生成二维码了，当然您的PHP环境必须开启支持GD2。 phpqrcode.php提供了一个关键的png()方法，其中参数text表示生成二位的的信息文本；参数outfile表示是否输出二维码图片 文件，默认否；参数level表示容错率，也就是有被覆盖的区域还能识别，分别是 L（QR_ECLEVEL_L，7%），M（QR_ECLEVEL_M，15%），Q（QR_ECLEVEL_Q，25%），H（QR_ECLEVEL_H，30%）； 参数size表示生成图片大小，默认是3；参数margin表示二维码周围边框空白区域间距值；参数saveandprint表示是否保存二维码并 显示。\npublic static function png(text,outfile=false, level=QR_ECLEVEL_L,size=3, margin=4,saveandprint=false) { enc = QRencode::factory(level, size,margin); return enc-\u003eencodePNG(text, outfile,saveandprint=false); } 调用PHP QR Code非常简单，如下代码即可生成一张内容为\u0026amp;#8221;http://www.jb51.net\u0026amp;#8221;的二维码. Php代码 include ‘phpqrcode.php’; QRcode::png(‘http://www.jb51.net’);\n那么实际应用中，我们会在二维码的中间加上自己的LOGO，已增强宣传效果。那如何生成含有logo的二维码呢？其实原理很简单，先使用PHP QR Code生成一张二维码图片，然后再利用php的image相关函数，将事先准备好的logo图片加入到刚生成的原始二维码图片中间，然后重新生成一张新 的二维码图片。 include \u0026#8216;phpqrcode.php\u0026#8217;; value = \u0026#8216;http://www.jb51.net\u0026#8217;; //二维码内容errorCorrectionLevel = \u0026#8216;L\u0026#8217;;//容错级别 matrixPointSize = 6;//生成图片大小 //生成二维码图片 QRcode::png(value, \u0026#8216;qrcode.png\u0026#8217;, errorCorrectionLevel,matrixPointSize, 2); logo = \u0026#8216;logo.png\u0026#8217;;//准备好的logo图片QR = \u0026#8216;qrcode.png\u0026#8217;;//已经生成的原始二维码图 if (\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;logo !== FALSE) {\u0026lt;/span\u0026gt;QR = imagecreatefromstring(file_get_contents(\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;QR));\u0026lt;/span\u0026gt;logo = imagecreatefromstring(file_get_contents(\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;logo));\u0026lt;/span\u0026gt;QR_width = imagesx(\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;QR);//二维码图片宽度\u0026lt;/span\u0026gt;QR_height = imagesy(\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;QR);//二维码图片高度\u0026lt;/span\u0026gt;logo_width = imagesx(\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;logo);//logo图片宽度\u0026lt;/span\u0026gt;logo_height = imagesy(\u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;logo);//logo图片高度\u0026lt;/span\u0026gt;logo_qr_width = \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;QR_width / 5;\u0026lt;/span\u0026gt;scale = \u0026lt;span class=\u0026quot;katex math inline\u0026quot;\u0026gt;logo_width/\u0026lt;/span\u0026gt;logo_qr_width; logo_qr_height =logo_height/scale;from_width = (QR_width –logo_qr_width) / 2; //重新组合图片并调整大小 imagecopyresampled(QR,logo, from_width,from_width, 0, 0, logo_qr_width,logo_qr_height, logo_width,logo_height); } //输出图片 imagepng($QR, ‘helloweba.png’); echo ‘’;\n由于二维码允许有一定的容错性，一般的二维码即使在遮住部分但仍然能够解码，经常我们扫描二维码的时候扫描到甚至不到一半时就能解码扫描结果，这是因为生成器会将部分信息重复表示来提高其容错度，这就是为什么我们在二维码中间加个LOGO图片并不影响解码结果的原因。 ","permalink":"https://blog.zdltech.com/posts/%E4%BD%BF%E7%94%A8php%E7%94%9F%E6%88%90%E4%BA%8C%E7%BB%B4%E7%A0%81%E7%9A%84%E4%B8%A4%E7%A7%8D%E6%96%B9%E6%B3%95%E5%B8%A6logo%E5%9B%BE%E5%83%8F/","summary":"\u003cdiv id=\"art_demo\" style=\"color: #000000;\"\u003e\n  随着科技的进步，二维码应用领域越来越广泛，今天我给大家分享下如何使用PHP生成二维码，以及如何生成中间带LOGO图像的二维码\n\u003c/div\u003e\n\u003cdiv class=\"blank3\" style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv id=\"con_all\" style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv id=\"art_content\" style=\"color: #000000;\"\u003e\n  **一、利用Google API生成二维码**\n Google提供了较为完善的二维码生成接口，调用API接口很简单，以下是调用代码：\n  \u003cdiv id=\"code82061\" class=\"codebody\"\u003e\n    \u003cspan class=\"katex math inline\"\u003eurlToEncode=\u0026#8221;http://www.jb51.net\u0026#8221;;\n generateQRfromGoogle(\u003c/span\u003eurlToEncode);\n /**\n * google api 二维码生成【QRcode可以存储最多4296个字母数字类型的任意文本，具体可以查看二维码数据格式】\n * @param string \u003cspan class=\"katex math inline\"\u003echl 二维码包含的信息，可以是数字、字符、二进制信息、汉字。\n 不能混合数据类型，数据必须经过UTF-8 URL-encoded\n * @param int\u003c/span\u003ewidhtHeight 生成二维码的尺寸设置\n * @param string \u003cspan class=\"katex math inline\"\u003eEC_level 可选纠错级别，QR码支持四个等级纠错，用来恢复丢失的、读错的、模糊的、数据。\n *                            L-默认：可以识别已损失的7%的数据\n *                            M-可以识别已损失15%的数据\n *                            Q-可以识别已损失25%的数据\n *                            H-可以识别已损失30%的数据\n * @param int\u003c/span\u003emargin 生成的二维码离图片边框的距离\n */\n function generateQRfromGoogle(\u003cspan class=\"katex math inline\"\u003echl,\u003c/span\u003ewidhtHeight =\u0026#8217;150\u0026#8242;,\u003cspan class=\"katex math inline\"\u003eEC_level=\u0026#8217;L\u0026#8217;,\u003c/span\u003emargin=\u0026#8217;0\u0026#8242;)\n {\n \u003cspan class=\"katex math inline\"\u003echl = urlencode(\u003c/span\u003echl);\n echo \u0026#8216;\u003cimg src=\u0026#8221;http://chart.apis.google.com/chart?chs=\u0026#8217;.\u003cspan class=\"katex math inline\"\u003ewidhtHeight.\u0026#8217;x\u0026#8217;.\u003c/span\u003ewidhtHeight.\u0026#8217;\n \u0026cht=qr\u0026chld=\u0026#8217;.\u003cspan class=\"katex math inline\"\u003eEC_level.\u0026#8217;|\u0026#8217;.\u003c/span\u003emargin.\u0026#8217;\u0026chl=\u0026#8217;.\u003cspan class=\"katex math inline\"\u003echl.'\u0026#8221; alt=\u0026#8221;QR code\u0026#8221; widhtHeight=\u0026#8221;\u0026#8216;.\u003c/span\u003ewidhtHeight.\u0026#8217;\n \u0026#8221; widhtHeight=\u0026#8221;\u0026#8216;.$widhtHeight.'\u0026#8221;/\u003e\u0026#8217;;\n }\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e二、使用PHP二维码生成类库PHP QR Code生成二维码\n\n\n\n\n\nPHP QR Code是一个PHP二维码生成类库，利用它可以轻松生成二维码，官网提供了下载和多个演示demo，查看地址：http://phpqrcode.sourceforge.net/。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下载官网提供的类库后，只需要使用phpqrcode.php就可以生成二维码了，当然您的PHP环境必须开启支持GD2。 phpqrcode.php提供了一个关键的png()方法，其中参数\u003cspan class=\"katex math inline\"\u003etext表示生成二位的的信息文本；参数\u003c/span\u003eoutfile表示是否输出二维码图片 文件，默认否；参数\u003cspan class=\"katex math inline\"\u003elevel表示容错率，也就是有被覆盖的区域还能识别，分别是 L（QR_ECLEVEL_L，7%），M（QR_ECLEVEL_M，15%），Q（QR_ECLEVEL_Q，25%），H（QR_ECLEVEL_H，30%）； 参数\u003c/span\u003esize表示生成图片大小，默认是3；参数\u003cspan class=\"katex math inline\"\u003emargin表示二维码周围边框空白区域间距值；参数\u003c/span\u003esaveandprint表示是否保存二维码并 显示。\u003c/p\u003e","title":"使用PHP生成二维码的两种方法(带logo图像)"},{"content":"使用第三方开源项目，地址：https://github.com/chrisbanes/PhotoView\n引入library 项目. 简单的加载一张图片： **[java]** [view plain](http://blog.csdn.net/own_1991/article/details/12186627#)[copy](http://blog.csdn.net/own_1991/article/details/12186627#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ImageView imgView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; PhotoViewAttacher attacher; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setContentView(R.layout.activity_main); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; imgView=(ImageView) findViewById(R.id.img); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; imgView.setImageResource(R.drawable.wallpaper); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; attacher=\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PhotoViewAttacher(imgView); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 布局文件： **[html]** [view plain](http://blog.csdn.net/own_1991/article/details/12186627#)[copy](http://blog.csdn.net/own_1991/article/details/12186627#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/img\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android%E4%BD%BF%E7%94%A8photoview%E5%AE%9E%E7%8E%B0%E5%9B%BE%E7%89%87%E7%BC%A9%E6%94%BE%E5%8A%9F%E8%83%BD/","summary":"\u003cp\u003e使用第三方开源项目，地址：\u003ca href=\"https://github.com/chrisbanes/PhotoView\"\u003ehttps://github.com/chrisbanes/PhotoView\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e引入library 项目.\n\n\n\n\n\n简单的加载一张图片：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\" style=\"color: #362e2b;\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/own_1991/article/details/12186627#)[copy](http://blog.csdn.net/own_1991/article/details/12186627#)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    ImageView imgView;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    PhotoViewAttacher attacher;   \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        setContentView(R.layout.activity_main);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        imgView=(ImageView) findViewById(R.id.img);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        imgView.setImageResource(R.drawable.wallpaper);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        attacher=\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PhotoViewAttacher(imgView);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e布局文件：\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\" style=\"color: #362e2b;\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/own_1991/article/details/12186627#)[copy](http://blog.csdn.net/own_1991/article/details/12186627#)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/img\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e","title":"Android使用PhotoView实现图片缩放功能"},{"content":"对于触摸屏，其原生的消息无非按下、抬起、移动这几种，我们只需要简单重载onTouch或者设置触摸侦听器setOnTouchListener即可进行处理。不过，为了提高我们的APP的用户体验，有时候我们需要识别用户的手势，Android给我们提供的手势识别工具GestureDetector就可以帮上大忙了。\n基础\nGestureDetector的工作原理是，当我们接收到用户触摸消息时，将这个消息交给GestureDetector去加工，我们通过设置侦听器获得GestureDetector处理后的手势。\nGestureDetector提供了两个侦听器接口，OnGestureListener处理单击类消息，OnDoubleTapListener处理双击类消息。\nOnGestureListener的接口有这几个：\n// 单击，触摸屏按下时立刻触发\nabstract boolean onDown(MotionEvent e);\n// 抬起，手指离开触摸屏时触发(长按、滚动、滑动时，不会触发这个手势)\nabstract boolean onSingleTapUp(MotionEvent e);\n// 短按，触摸屏按下后片刻后抬起，会触发这个手势，如果迅速抬起则不会\nabstract void onShowPress(MotionEvent e);\n// 长按，触摸屏按下后既不抬起也不移动，过一段时间后触发\nabstract void onLongPress(MotionEvent e);\n// 滚动，触摸屏按下后移动\nabstract boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);\n// 滑动，触摸屏按下后快速移动并抬起，会先触发滚动手势，跟着触发一个滑动手势\nabstract boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);\nOnDoubleTapListener的接口有这几个：\n// 双击，手指在触摸屏上迅速点击第二下时触发\nabstract boolean onDoubleTap(MotionEvent e);\n// 双击的按下跟抬起各触发一次\nabstract boolean onDoubleTapEvent(MotionEvent e);\n// 单击确认，即很快的按下并抬起，但并不连续点击第二下\nabstract boolean onSingleTapConfirmed(MotionEvent e);\n有时候我们并不需要处理上面所有手势，方便起见，Android提供了另外一个类SimpleOnGestureListener实现了如上接口，我们只需要继承SimpleOnGestureListener然后重载感兴趣的手势即可。\n应用\nSTEP 1: 创建手势侦听对象\npackage noodies.blog.csdn.net;\nimport android.content.Context;\nimport android.view.MotionEvent;\nimport android.view.GestureDetector.SimpleOnGestureListener;\nimport android.widget.Toast;\npublic class MyGestureListener extends SimpleOnGestureListener {\nprivate Context mContext;\nMyGestureListener(Context context) {\nmContext = context;\n}\n@Override\npublic boolean onDown(MotionEvent e) {\nToast.makeText(mContext, “DOWN ” + e.getAction(), Toast.LENGTH_SHORT).show();\nreturn false;\n}\n@Override\npublic void onShowPress(MotionEvent e) {\nToast.makeText(mContext, “SHOW ” + e.getAction(), Toast.LENGTH_SHORT).show();\n}\n@Override\npublic boolean onSingleTapUp(MotionEvent e) {\nToast.makeText(mContext, “SINGLE UP ” + e.getAction(), Toast.LENGTH_SHORT).show();\nreturn false;\n}\n@Override\npublic boolean onScroll(MotionEvent e1, MotionEvent e2,\nfloat distanceX, float distanceY) {\nToast.makeText(mContext, “SCROLL ” + e2.getAction(), Toast.LENGTH_SHORT).show();\nreturn false;\n}\n@Override\npublic void onLongPress(MotionEvent e) {\nToast.makeText(mContext, “LONG ” + e.getAction(), Toast.LENGTH_SHORT).show();\n}\n@Override\npublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,\nfloat velocityY) {\nToast.makeText(mContext, “FLING ” + e2.getAction(), Toast.LENGTH_SHORT).show();\nreturn false;\n}\n@Override\npublic boolean onDoubleTap(MotionEvent e) {\nToast.makeText(mContext, “DOUBLE ” + e.getAction(), Toast.LENGTH_SHORT).show();\nreturn false;\n}\n@Override\npublic boolean onDoubleTapEvent(MotionEvent e) {\nToast.makeText(mContext, “DOUBLE EVENT ” + e.getAction(), Toast.LENGTH_SHORT).show();\nreturn false;\n}\n@Override\npublic boolean onSingleTapConfirmed(MotionEvent e) {\nToast.makeText(mContext, “SINGLE CONF ” + e.getAction(), Toast.LENGTH_SHORT).show();\nreturn false;\n}\n}\nSTEP 2: 设置手势识别\n我们可以在Activity里设置手势识别：\npackage noodies.blog.csdn.net;\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.view.GestureDetector;\nimport android.view.MotionEvent;\npublic class GestureTestActivity extends Activity {\nprivate GestureDetector mGestureDetector;\n@Override\npublic void onCreate(Bundle savedInstanceState) {\nsuper.onCreate(savedInstanceState);\nsetContentView(R.layout.main);\nmGestureDetector = new GestureDetector(this, new MyGestureListener(this));\n}\n@Override\npublic boolean onTouchEvent(MotionEvent event) {\nreturn mGestureDetector.onTouchEvent(event);\n}\n}\n也可以在自定义的View里面设置手势识别：\npackage noodies.blog.csdn.net;\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.GestureDetector;\nimport android.view.MotionEvent;\nimport android.view.View;\npublic class MyView extends View {\nprivate GestureDetector mGestureDetector;\npublic MyView(Context context, AttributeSet attrs) {\nsuper(context, attrs);\nmGestureDetector = new GestureDetector(context, new MyGestureListener(context));\nsetLongClickable(true);\nthis.setOnTouchListener(new OnTouchListener() {\npublic boolean onTouch(View v, MotionEvent event) {\nreturn mGestureDetector.onTouchEvent(event);\n}\n});\n}\n}\n陷阱\n对于自定义View，使用手势识别有两处陷阱可能会浪费你的不少时间。\n1：View必须设置longClickable为true，否则手势识别无法正确工作，只会返回Down, Show, Long三种手势\n2：必须在View的onTouchListener中调用手势识别，而不能像Activity一样重载onTouchEvent，否则同样手势识别无法正确工作\n测试结果\n下面是各种操作返回的手势序列，数值0表示触摸屏按下，1表示抬起\n单击：down 0, single up 1, single conf 0\n短按：down 0, show 0, single up 1\n长按：down 0, show 0, long 0\n双击：down 0, single up 1, double 0, double event 0, down 0, double event 1\n滚动：down 0, (show 0), scrool 2…\n滑动：down 0, (show 0), scrool 2…, fling 1\n","permalink":"https://blog.zdltech.com/posts/%E7%90%86%E8%A7%A3android%E7%9A%84%E6%89%8B%E5%8A%BF%E8%AF%86%E5%88%AB/","summary":"\u003cp\u003e对于触摸屏，其原生的消息无非按下、抬起、移动这几种，我们只需要简单重载onTouch或者设置触摸侦听器setOnTouchListener即可进行处理。不过，为了提高我们的APP的用户体验，有时候我们需要识别用户的手势，\u003ca href=\"http://www.2cto.com/kf/yidong/Android/\"\u003eAndroid\u003c/a\u003e给我们提供的手势识别工具GestureDetector就可以帮上大忙了。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e基础\u003c/p\u003e\n\u003cp\u003eGestureDetector的工作原理是，当我们接收到用户触摸消息时，将这个消息交给GestureDetector去加工，我们通过设置侦听器获得GestureDetector处理后的手势。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eGestureDetector提供了两个侦听器接口，OnGestureListener处理单击类消息，OnDoubleTapListener处理双击类消息。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eOnGestureListener的接口有这几个：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e// 单击，触摸屏按下时立刻触发\u003c/p\u003e\n\u003cp\u003eabstract boolean onDown(MotionEvent e);\u003c/p\u003e\n\u003cp\u003e// 抬起，手指离开触摸屏时触发(长按、滚动、滑动时，不会触发这个手势)\u003c/p\u003e\n\u003cp\u003eabstract boolean onSingleTapUp(MotionEvent e);\u003c/p\u003e\n\u003cp\u003e// 短按，触摸屏按下后片刻后抬起，会触发这个手势，如果迅速抬起则不会\u003c/p\u003e\n\u003cp\u003eabstract void onShowPress(MotionEvent e);\u003c/p\u003e\n\u003cp\u003e// 长按，触摸屏按下后既不抬起也不移动，过一段时间后触发\u003c/p\u003e\n\u003cp\u003eabstract void onLongPress(MotionEvent e);\u003c/p\u003e\n\u003cp\u003e// 滚动，触摸屏按下后移动\u003c/p\u003e\n\u003cp\u003eabstract boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);\u003c/p\u003e\n\u003cp\u003e// 滑动，触摸屏按下后快速移动并抬起，会先触发滚动手势，跟着触发一个滑动手势\u003c/p\u003e\n\u003cp\u003eabstract boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);\u003c/p\u003e\n\u003cp\u003eOnDoubleTapListener的接口有这几个：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e// 双击，手指在触摸屏上迅速点击第二下时触发\u003c/p\u003e\n\u003cp\u003eabstract boolean onDoubleTap(MotionEvent e);\u003c/p\u003e\n\u003cp\u003e// 双击的按下跟抬起各触发一次\u003c/p\u003e\n\u003cp\u003eabstract boolean onDoubleTapEvent(MotionEvent e);\u003c/p\u003e\n\u003cp\u003e// 单击确认，即很快的按下并抬起，但并不连续点击第二下\u003c/p\u003e\n\u003cp\u003eabstract boolean onSingleTapConfirmed(MotionEvent e);\u003c/p\u003e","title":"理解Android的手势识别"},{"content":"本文内容： 1、横向ListView的所有实现思路;\n2、其中一个最通用的思路HorizontalListView，并基于横向ListView开发一个简单的相册；\n3、实现的横向ListView在点击、浏览时item背景会变色，并解决了listview里setSelected造成item的选择状态混乱的问题。\n众所周知，ListView默认的方向是垂直的，但有些时候人们更喜欢横向ListView。纵观整个网络，横向ListView的实现思路如下:\n1、在布局里用HorizontalScrollView包含一个ListView，参考这里;\n2、利用GridView，把它的行数设为1行；\n3、有人继承ListView构造了一个HorizontalScrollListView，参见：这里\n4、国外一位大牛继承AdapterView构造的HorizontalListView，这是以上所有方法里本人认为最正统的方法，本文即基于此方法，参见:这里\n下面看源码： 这是Activity的布局文件:activity_main.xml **[html]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_vertical_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_horizontal_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_horizontal_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_vertical_margin\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;org.yanzi.ui.HorizontalListView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/horizon_listview\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;150dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_alignParentTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;org.yanzi.ui.HorizontalListView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/image_preview\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_below\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@id/horizon_listview\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_centerInParent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:clickable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/selector_imageview_background\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comments\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211; android:background=\u0026amp;#8221;@android:drawable/ic_menu_gallery\u0026amp;#8221; \u0026amp;#8211;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 这是横向listview的每个item的布局，图片+文字，horizontal_list_item.xml **[html]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;2dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;2dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;2dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;2dip\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:clickable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/selector_item_background\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/img_list_item\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/text_list_item\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 下面文件是selector_imageview_background.xml，这是大图片你点击浏览时背景发生变化的selector，没有啥实际作用。 **[html]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/holo_green_light\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_pressed\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/holo_green_light\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_focused\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/image_background\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comments\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211; android:drawable=\u0026amp;#8221;@android:color/transparent\u0026amp;#8221; \u0026amp;#8211;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 下面是每个item的selector，在focus和select时颜色会发生变化:selector_item_background.xml **[html]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/holo_red_light\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_selected\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/holo_green_dark\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_pressed\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/transparent\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 主程序:MainActivity.java **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.testhorizontallistview; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.ui.HorizontalListView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.ui.HorizontalListViewAdapter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Menu; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView.OnItemClickListener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; HorizontalListView hListView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; HorizontalListViewAdapter hListViewAdapter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ImageView previewImg; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; View olderSelectView = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setContentView(R.layout.activity_main); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; initUI(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onCreateOptionsMenu(Menu menu) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Inflate the menu; this adds items to the action bar if it is present.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; getMenuInflater().inflate(R.menu.main, menu); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initUI(){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; hListView = (HorizontalListView)findViewById(R.id.horizon_listview); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; previewImg = (ImageView)findViewById(R.id.image_preview); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; String[] titles = {\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;怀师\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;南怀瑾军校\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;闭关\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;南怀瑾\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;南公庄严照\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;怀师法相\u0026amp;#8221;\u0026lt;/span\u0026gt;}; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] ids = {R.drawable.nanhuaijin_miss, R.drawable.nanhuaijin_school, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; R.drawable.nanhuaijin_biguan, R.drawable.nanhuaijin, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; R.drawable.nanhuaijin_zhuangyan, R.drawable.nanhuaijin_faxiang}; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; hListViewAdapter = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HorizontalListViewAdapter(getApplicationContext(),titles,ids); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; hListView.setAdapter(hListViewAdapter); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// hListView.setOnItemSelectedListener(new OnItemSelectedListener() {\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// @Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// public void onItemSelected(AdapterView\u0026lt;?\u0026gt; parent, View view,\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// int position, long id) {\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// // TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// if(olderSelected != null){\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// olderSelected.setSelected(false); //上一个选中的View恢复原背景\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// }\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// olderSelected = view;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// view.setSelected(true);\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// }\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// @Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// public void onNothingSelected(AdapterView\u0026lt;?\u0026gt; parent) {\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// // TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// }\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// });\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; hListView.setOnItemClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnItemClickListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onItemClick(AdapterView\u0026lt;?\u0026gt; parent, View view, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; id) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// if(olderSelectView == null){\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// olderSelectView = view;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// }else{\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// olderSelectView.setSelected(false);\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// olderSelectView = null;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// }\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// olderSelectView = view;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// view.setSelected(true);\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; previewImg.setImageResource(ids[position]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; hListViewAdapter.setSelectIndex(position); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; hListViewAdapter.notifyDataSetChanged(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; HorizontalListView.java 这就是自定义的横向listview **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.ui; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * HorizontalListView.java v1.5\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * The MIT License\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * Copyright (c) 2011 Paul Soucy (paul@dev-smart.com)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * Permission is hereby granted, free of charge, to any person obtaining a copy\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * of this software and associated documentation files (the \u0026amp;#8220;Software\u0026amp;#8221;), to deal\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * in the Software without restriction, including without limitation the rights\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * copies of the Software, and to permit persons to whom the Software is\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * furnished to do so, subject to the following conditions:\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * The above copyright notice and this permission notice shall be included in\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * all copies or substantial portions of the Software.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * THE SOFTWARE IS PROVIDED \u0026amp;#8220;AS IS\u0026amp;#8221;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * THE SOFTWARE.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.LinkedList; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Queue; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.database.DataSetObserver; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Rect; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.GestureDetector; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.GestureDetector.OnGestureListener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListAdapter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Scroller; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; HorizontalListView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; AdapterView\u0026lt;ListAdapter\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; mAlwaysOverrideTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; ListAdapter mAdapter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mLeftViewIndex = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mRightViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mCurrentX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mNextX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMaxX = Integer.MAX_VALUE; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDisplayOffset = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; Scroller mScroller; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GestureDetector mGesture; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Queue\u0026lt;View\u0026gt; mRemovedViewQueue = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinkedList\u0026lt;View\u0026gt;(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnItemSelectedListener mOnItemSelected; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnItemClickListener mOnItemClicked; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnItemLongClickListener mOnItemLongClicked; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; mDataChanged = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; HorizontalListView(Context context, AttributeSet attrs) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; initView(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mLeftViewIndex = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mRightViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mDisplayOffset = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mCurrentX = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mNextX = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mMaxX = Integer.MAX_VALUE; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mScroller = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Scroller(getContext()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mGesture = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(getContext(), mOnGesture); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mOnItemSelected = listener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnItemClickListener(AdapterView.OnItemClickListener listener){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mOnItemClicked = listener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mOnItemLongClicked = listener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; DataSetObserver mDataObserver = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DataSetObserver() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onChanged() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt;(HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mDataChanged = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; invalidate(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; requestLayout(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onInvalidated() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; reset(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; invalidate(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; requestLayout(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ListAdapter getAdapter() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mAdapter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getSelectedView() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//TODO: implement\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setAdapter(ListAdapter adapter) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mAdapter != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mAdapter.unregisterDataSetObserver(mDataObserver); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mAdapter = adapter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mAdapter.registerDataSetObserver(mDataObserver); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; reset(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; reset(){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; initView(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; removeAllViewsInLayout(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; requestLayout(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setSelection(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//TODO: implement\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; addAndMeasureChild(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View child, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewPos) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; LayoutParams params = child.getLayoutParams(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(params == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; params = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; addViewInLayout(child, viewPos, params, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; child.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; left, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; top, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; right, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bottom) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onLayout(changed, left, top, right, bottom); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mAdapter == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mDataChanged){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldCurrentX = mCurrentX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; initView(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; removeAllViewsInLayout(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mNextX = oldCurrentX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mDataChanged = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mScroller.computeScrollOffset()){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollx = mScroller.getCurrX(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mNextX = scrollx; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mNextX \u0026lt;= \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mNextX = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mScroller.forceFinished(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mNextX \u0026gt;= mMaxX) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mNextX = mMaxX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mScroller.forceFinished(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx = mCurrentX \u0026amp;#8211; mNextX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; removeNonVisibleItems(dx); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; fillList(dx); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; positionItems(dx); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mCurrentX = mNextX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!mScroller.isFinished()){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; post(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable(){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; requestLayout(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; fillList(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; edge = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; View child = getChildAt(getChildCount()-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(child != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; edge = child.getRight(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; fillListRight(edge, dx); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; edge = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; child = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(child != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; edge = child.getLeft(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; fillListLeft(edge, dx); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; fillListRight(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; rightEdge, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(rightEdge + dx \u0026lt; getWidth() \u0026amp;\u0026amp; mRightViewIndex \u0026lt; mAdapter.getCount()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; View child = mAdapter.getView(mRightViewIndex, mRemovedViewQueue.poll(), \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; addAndMeasureChild(child, \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; rightEdge += child.getMeasuredWidth(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mRightViewIndex == mAdapter.getCount()-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mMaxX = mCurrentX + rightEdge \u0026amp;#8211; getWidth(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMaxX \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mMaxX = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mRightViewIndex++; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; fillListLeft(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; leftEdge, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(leftEdge + dx \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mLeftViewIndex \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; View child = mAdapter.getView(mLeftViewIndex, mRemovedViewQueue.poll(), \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; addAndMeasureChild(child, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; leftEdge -= child.getMeasuredWidth(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mLeftViewIndex\u0026amp;#8211;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mDisplayOffset -= child.getMeasuredWidth(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; removeNonVisibleItems(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; View child = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(child != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; child.getRight() + dx \u0026lt;= \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mDisplayOffset += child.getMeasuredWidth(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mRemovedViewQueue.offer(child); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; removeViewInLayout(child); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mLeftViewIndex++; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; child = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; child = getChildAt(getChildCount()-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(child != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; child.getLeft() + dx \u0026gt;= getWidth()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mRemovedViewQueue.offer(child); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; removeViewInLayout(child); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mRightViewIndex\u0026amp;#8211;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; child = getChildAt(getChildCount()-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; positionItems(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(getChildCount() \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mDisplayOffset += dx; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; left = mDisplayOffset; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;i\u0026lt;getChildCount();i++){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; View child = getChildAt(i); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childWidth = child.getMeasuredWidth(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; child.layout(left, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, left + childWidth, child.getMeasuredHeight()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; left += childWidth + child.getPaddingRight(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scrollTo(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mScroller.startScroll(mNextX, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, x \u0026amp;#8211; mNextX, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; requestLayout(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; handled = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(ev); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; handled |= mGesture.onTouchEvent(ev); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; handled; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityX, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt;(HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mScroller.fling(mNextX, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)-velocityX, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, mMaxX, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; requestLayout(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDown(MotionEvent e) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mScroller.forceFinished(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnGestureListener mOnGesture = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector.SimpleOnGestureListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDown(MotionEvent e) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onDown(e); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityX, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onFling(e1, e2, velocityX, velocityY); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onScroll(MotionEvent e1, MotionEvent e2, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceX, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceY) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt;(HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mNextX += (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)distanceX; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; requestLayout(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onSingleTapConfirmed(MotionEvent e) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;i\u0026lt;getChildCount();i++){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; View child = getChildAt(i); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isEventWithinView(e, child)) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mOnItemClicked != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mOnItemClicked.onItemClick(HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, child, mLeftViewIndex + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; + i, mAdapter.getItemId( mLeftViewIndex + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; + i )); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mOnItemSelected != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mOnItemSelected.onItemSelected(HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, child, mLeftViewIndex + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; + i, mAdapter.getItemId( mLeftViewIndex + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; + i )); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLongPress(MotionEvent e) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childCount = getChildCount(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; childCount; i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; View child = getChildAt(i); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isEventWithinView(e, child)) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mOnItemLongClicked != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mOnItemLongClicked.onItemLongClick(HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, child, mLeftViewIndex + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; + i, mAdapter.getItemId(mLeftViewIndex + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; + i)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isEventWithinView(MotionEvent e, View child) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Rect viewRect = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] childPosition = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; child.getLocationOnScreen(childPosition); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; left = childPosition[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; right = left + child.getWidth(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; top = childPosition[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bottom = top + child.getHeight(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewRect.set(left, top, right, bottom); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; viewRect.contains((\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) e.getRawX(), (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) e.getRawY()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; HorizontalListViewAdapter.java 横向listview的适配器，我将他单独写到一个java文件里。 **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.ui; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.testhorizontallistview.R; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.util.BitmapUtil; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.drawable.Drawable; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.media.ThumbnailUtils; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.BaseAdapter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; HorizontalListViewAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; BaseAdapter{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] mIconIDs; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String[] mTitles; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context mContext; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LayoutInflater mInflater; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Bitmap iconBitmap; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; selectIndex = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; HorizontalListViewAdapter(Context context, String[] titles, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] ids){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mContext = context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mIconIDs = ids; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mTitles = titles; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mInflater=(LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//LayoutInflater.from(mContext);\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mIconIDs.length; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object getItem(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; position; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getItemId(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; position; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getView(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ViewHolder holder; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(convertView==\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; holder = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewHolder(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; convertView = mInflater.inflate(R.layout.horizontal_list_item, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; holder.mImage=(ImageView)convertView.findViewById(R.id.img_list_item); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; holder.mTitle=(TextView)convertView.findViewById(R.id.text_list_item); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; convertView.setTag(holder); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; holder=(ViewHolder)convertView.getTag(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(position == selectIndex){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; convertView.setSelected(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; convertView.setSelected(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; holder.mTitle.setText(mTitles[position]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; iconBitmap = getPropThumnail(mIconIDs[position]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; holder.mImage.setImageBitmap(iconBitmap); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; convertView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ViewHolder { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView mTitle ; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageView mImage; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap getPropThumnail(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Drawable d = mContext.getResources().getDrawable(id); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Bitmap b = BitmapUtil.drawableToBitmap(d); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Bitmap bb = BitmapUtil.getRoundedCornerBitmap(b, 100);\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; w = mContext.getResources().getDimensionPixelOffset(R.dimen.thumnail_default_width); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; h = mContext.getResources().getDimensionPixelSize(R.dimen.thumnail_default_height); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Bitmap thumBitmap = ThumbnailUtils.extractThumbnail(b, w, h); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; thumBitmap; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setSelectIndex(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; selectIndex = i; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 下面是效果图： ![](http://img.blog.csdn.net/20140315182924656?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuemkxMjI1NjI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 下图是一个item被选定后，另一个item获得了焦点: ![](http://img.blog.csdn.net/20140315183047562?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuemkxMjI1NjI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 下面是横向时的截图: ![](http://img.blog.csdn.net/20140315183137906?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuemkxMjI1NjI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 要点如下: 1、可以说这个HorizontalListView是完美的，但美中不足的并不是其他人说的不能点击、晃动、加载不全的问题，而是这个横向Listview的高度，如果你设成wrap_cotent那么将会占据整个屏幕，**即使你将它适配器里的view的高度限制死，限制成很小，这个HorizontalListView的高度依然是全屏**。本文代码里，我把图片缩略图弄成100dip，所以把这个HorizontalListView的高度设为了150dip。 2、在适配器里，我填充了一个图片，下面是文字。为了能让浏览图片时item有反应，搞了一个selector，它的用法详见[这里](http://blog.csdn.net/shakespeare001/article/details/7788400). 但一开始在点击时完全没有反应，参考这里： [http://blog.csdn.net/ljz2009y/article/details/18820071](http://blog.csdn.net/ljz2009y/article/details/18820071) 为此我的selector如下： \u003c?xml version=\u0026#8221;1.0\u0026#8243; encoding=\u0026#8221;utf-8\u0026#8243;?\u003e 将自然状态下的背景放到了最后，但点击浏览时依然没有作用。**其实最根本原因是在布局文件里horizontal_list_item.xml要让这个布局能够clickable，即：android:clickable=\u0026#8221;true\u0026#8221;** 3、上一步完成了，还需要点击即select一个item时，让它变色并且保持住，然后点击另外一个item时，让之前得item恢复默认背景。为了实现这个问题，我曾作如下尝试： **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// if(olderSelectView == null){\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// olderSelectView = view;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// }else{\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// olderSelectView.setSelected(false);\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// olderSelectView = null;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// }\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// olderSelectView = view;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// view.setSelected(true);\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; 即在click监听里，保存上一个选中的view。遗憾的是这种方法会造成item的选中状态造成混乱，比如第一个item选中了，同时第5个item也莫名其妙的被选中了。上述情况发生在滑动时，即一屏显示不完的情况下。当我横屏时，在所有的item都能一次性显示出来情况下，用上述方法么问题。后来我想到，这可以是适配器里的缓存机制造成的，**\u0026lt;span style=\u0026quot;color: #ff0000;\u0026quot;\u0026gt;最好不要再listview适配器外对item作修改，即便修改则一定要调适配器的: hListViewAdapter.notifyDataSetChanged();通知刷新view，毕竟适配器才是view的提供者\u0026lt;/span\u0026gt;**。参考这位大大的文章:[http://longyi-java.iteye.com/blog/976067](http://longyi-java.iteye.com/blog/976067) 在适配器里加了一个接口保存选中的索引，然后再getView函数里进行判断。如果是选中的item，则将布局设为选中状态即可，horizontal_list_item.xml里的Linearlayout就会自动加载那个selector了。而无需像这个参考链接里对每个item的元素分别设置状态。\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 4、BitmapUtil是个工具类，负责将id转成一个bitmap，然后用android自带的ThumbnailUtils去提取缩略图。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 5、之所以horizontal_list_item布局里要设置padding是为了选中item时，整个item有种被圈住的感觉，而不是光下面一点变色。 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 源码下载:[http://download.csdn.net/detail/yanzi1225627/7046295](http://download.csdn.net/detail/yanzi1225627/7046295)\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 欢迎Android爱好者加群 \u0026lt;div id=\u0026quot;group_name\u0026quot; class=\u0026quot;group_name usrInputFont\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;qname\u0026quot; title=\u0026quot;Android您问我讲-2\u0026quot;\u0026gt;**Android您问我讲-2，**\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; **群号:**\u0026lt;span id=\u0026quot;group_number\u0026quot; class=\u0026quot;group_number\u0026quot;\u0026gt;**19241311,备注：yanzi**\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;本文系原创，转载请注明作者:yanzi1225627 \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 源码下载:[http://download.csdn.net/detail/yanzi1225627/7046295](http://download.csdn.net/detail/yanzi1225627/7046295) \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 源码下载:[http://download.csdn.net/detail/yanzi1225627/7046295](http://download.csdn.net/detail/yanzi1225627/7046295) \u0026lt;/div\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android-ui%E5%BC%80%E5%8F%91-%E6%A8%AA%E5%90%91listviewhorizontallistview%E5%8F%8A%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9B%B8%E5%86%8C%E7%9A%84%E5%AE%8C%E6%95%B4%E5%AE%9E%E7%8E%B0-%E9%99%84/","summary":"\u003ch2 id=\"本文内容\"\u003e本文内容：\u003c/h2\u003e\n\u003cp\u003e1、横向ListView的所有实现思路;\u003c/p\u003e\n\u003cp\u003e2、其中一个最通用的思路HorizontalListView，并基于横向ListView开发一个简单的相册；\u003c/p\u003e\n\u003cp\u003e3、实现的横向ListView在点击、浏览时item背景会变色，并解决了listview里setSelected造成item的选择状态混乱的问题。\u003c/p\u003e\n\u003cp\u003e众所周知，ListView默认的方向是垂直的，但有些时候人们更喜欢横向ListView。纵观整个网络，横向ListView的实现思路如下:\u003c/p\u003e\n\u003cp\u003e1、在布局里用HorizontalScrollView包含一个ListView，参考\u003ca href=\"http://www.apkbus.com/android-83011-1-1.html\"\u003e这里\u003c/a\u003e;\u003c/p\u003e\n\u003cp\u003e2、利用GridView，把它的行数设为1行；\u003c/p\u003e\n\u003cp\u003e3、有人继承ListView构造了一个HorizontalScrollListView，参见：\u003ca href=\"http://lrc-1986.iteye.com/blog/1848926\"\u003e这里\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e4、国外一位大牛继承AdapterView\u003cListAdapter\u003e构造的HorizontalListView，这是以上所有方法里本人认为最正统的方法，本文即基于此方法，参见:\u003ca href=\"http://blog.csdn.net/chen88358323/article/details/8257657\"\u003e这里\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"下面看源码\"\u003e\u003ca style=\"color: #336699;\" name=\"t1\"\u003e\u003c/a\u003e下面看源码：\u003c/h2\u003e\n\u003cdiv\u003e\n  这是Activity的布局文件:activity_main.xml\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:tools\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/tools\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_vertical_margin\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_horizontal_margin\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_horizontal_margin\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@dimen/activity_vertical_margin\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;tools:context\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;.MainActivity\u0026amp;#8221;\u0026lt;/span\u0026gt;   \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;   \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;org.yanzi.ui.HorizontalListView\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/horizon_listview\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;150dip\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;       \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_alignParentTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;org.yanzi.ui.HorizontalListView\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt;   \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/image_preview\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_below\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@id/horizon_listview\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_centerInParent\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:clickable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/selector_imageview_background\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;comments\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211; android:background=\u0026amp;#8221;@android:drawable/ic_menu_gallery\u0026amp;#8221; \u0026amp;#8211;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;RelativeLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  这是横向listview的每个item的布局，图片+文字，horizontal_list_item.xml\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingLeft\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;2dip\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingRight\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;2dip\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingTop\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;2dip\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:paddingBottom\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;2dip\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:orientation\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;vertical\u0026amp;#8221;\u0026lt;/span\u0026gt;   \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:clickable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:background\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/selector_item_background\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;ImageView\u0026lt;/span\u0026gt;   \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/img_list_item\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;TextView\u0026lt;/span\u0026gt;   \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:id\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@+id/text_list_item\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_width\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;match_parent\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:layout_height\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wrap_content\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:gravity\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;center\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;    \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;LinearLayout\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e下面文件是selector_imageview_background.xml，这是大图片你点击浏览时背景发生变化的selector，没有啥实际作用。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/holo_green_light\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_pressed\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/holo_green_light\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_focused\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@drawable/image_background\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comments\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;\u0026lt;!\u0026amp;#8211; android:drawable=\u0026amp;#8221;@android:color/transparent\u0026amp;#8221; \u0026amp;#8211;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e下面是每个item的selector，在focus和select时颜色会发生变化:selector_item_background.xml\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;style\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/holo_red_light\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_selected\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/holo_green_dark\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:state_pressed\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;true\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;item\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:drawable\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;@android:color/transparent\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;selector\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;span\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e主程序:MainActivity.java\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.testhorizontallistview;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.ui.HorizontalListView;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.ui.HorizontalListViewAdapter;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.Menu;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView.OnItemClickListener;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    HorizontalListView hListView;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    HorizontalListViewAdapter hListViewAdapter;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    ImageView previewImg;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    View olderSelectView = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        setContentView(R.layout.activity_main);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        initUI();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onCreateOptionsMenu(Menu menu) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Inflate the menu; this adds items to the action bar if it is present.\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        getMenuInflater().inflate(R.menu.main, menu);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initUI(){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        hListView = (HorizontalListView)findViewById(R.id.horizon_listview);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        previewImg = (ImageView)findViewById(R.id.image_preview);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        String[] titles = {\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;怀师\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;南怀瑾军校\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;闭关\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;南怀瑾\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;南公庄严照\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;怀师法相\u0026amp;#8221;\u0026lt;/span\u0026gt;};  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] ids = {R.drawable.nanhuaijin_miss, R.drawable.nanhuaijin_school,  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                R.drawable.nanhuaijin_biguan, R.drawable.nanhuaijin,  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                R.drawable.nanhuaijin_zhuangyan, R.drawable.nanhuaijin_faxiang};  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        hListViewAdapter = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; HorizontalListViewAdapter(getApplicationContext(),titles,ids);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        hListView.setAdapter(hListViewAdapter);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//      hListView.setOnItemSelectedListener(new OnItemSelectedListener() {\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//          @Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//          public void onItemSelected(AdapterView\u0026lt;?\u0026gt; parent, View view,\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//                  int position, long id) {\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              // TODO Auto-generated method stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              if(olderSelected != null){\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//                  olderSelected.setSelected(false); //上一个选中的View恢复原背景\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              }\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              olderSelected = view;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              view.setSelected(true);\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//          }\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//          @Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//          public void onNothingSelected(AdapterView\u0026lt;?\u0026gt; parent) {\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              // TODO Auto-generated method stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              \u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//          }\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//      });\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        hListView.setOnItemClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnItemClickListener() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onItemClick(AdapterView\u0026lt;?\u0026gt; parent, View view,  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; id) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// TODO Auto-generated method stub\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              if(olderSelectView == null){\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//                  olderSelectView = view;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              }else{\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//                  olderSelectView.setSelected(false);\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//                  olderSelectView = null;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              }\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              olderSelectView = view;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              view.setSelected(true);\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                previewImg.setImageResource(ids[position]);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                hListViewAdapter.setSelectIndex(position);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                hListViewAdapter.notifyDataSetChanged();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        });  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003eHorizontalListView.java 这就是自定义的横向listview\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.ui;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/*\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * HorizontalListView.java v1.5\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * The MIT License\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * Copyright (c) 2011 Paul Soucy (paul@dev-smart.com)\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * Permission is hereby granted, free of charge, to any person obtaining a copy\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * of this software and associated documentation files (the \u0026amp;#8220;Software\u0026amp;#8221;), to deal\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * in the Software without restriction, including without limitation the rights\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * copies of the Software, and to permit persons to whom the Software is\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * furnished to do so, subject to the following conditions:\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * The above copyright notice and this permission notice shall be included in\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * all copies or substantial portions of the Software.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * THE SOFTWARE IS PROVIDED \u0026amp;#8220;AS IS\u0026amp;#8221;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * THE SOFTWARE.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.LinkedList;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Queue;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.database.DataSetObserver;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Rect;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.GestureDetector;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.GestureDetector.OnGestureListener;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListAdapter;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Scroller;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; HorizontalListView \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; AdapterView\u0026lt;ListAdapter\u0026gt; {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; mAlwaysOverrideTouch = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; ListAdapter mAdapter;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mLeftViewIndex = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mRightViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mCurrentX;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mNextX;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mMaxX = Integer.MAX_VALUE;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; mDisplayOffset = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; Scroller mScroller;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; GestureDetector mGesture;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Queue\u0026lt;View\u0026gt; mRemovedViewQueue = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LinkedList\u0026lt;View\u0026gt;();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnItemSelectedListener mOnItemSelected;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnItemClickListener mOnItemClicked;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnItemLongClickListener mOnItemLongClicked;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; mDataChanged = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; HorizontalListView(Context context, AttributeSet attrs) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        initView();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initView() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mLeftViewIndex = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mRightViewIndex = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mDisplayOffset = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mCurrentX = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mNextX = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mMaxX = Integer.MAX_VALUE;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mScroller = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Scroller(getContext());  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mGesture = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector(getContext(), mOnGesture);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mOnItemSelected = listener;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnItemClickListener(AdapterView.OnItemClickListener listener){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mOnItemClicked = listener;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mOnItemLongClicked = listener;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; DataSetObserver mDataObserver = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; DataSetObserver() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onChanged() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt;(HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                mDataChanged = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            invalidate();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            requestLayout();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onInvalidated() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            reset();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            invalidate();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            requestLayout();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    };  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; ListAdapter getAdapter() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mAdapter;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getSelectedView() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//TODO: implement\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setAdapter(ListAdapter adapter) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mAdapter != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mAdapter.unregisterDataSetObserver(mDataObserver);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mAdapter = adapter;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mAdapter.registerDataSetObserver(mDataObserver);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        reset();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; reset(){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        initView();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        removeAllViewsInLayout();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        requestLayout();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setSelection(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//TODO: implement\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; addAndMeasureChild(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; View child, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; viewPos) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        LayoutParams params = child.getLayoutParams();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(params == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            params = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        addViewInLayout(child, viewPos, params, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        child.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLayout(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; changed, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; left, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; top, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; right, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bottom) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onLayout(changed, left, top, right, bottom);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mAdapter == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mDataChanged){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldCurrentX = mCurrentX;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            initView();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            removeAllViewsInLayout();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mNextX = oldCurrentX;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mDataChanged = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mScroller.computeScrollOffset()){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; scrollx = mScroller.getCurrX();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mNextX = scrollx;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mNextX \u0026lt;= \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mNextX = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mScroller.forceFinished(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mNextX \u0026gt;= mMaxX) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mNextX = mMaxX;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mScroller.forceFinished(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx = mCurrentX \u0026amp;#8211; mNextX;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        removeNonVisibleItems(dx);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        fillList(dx);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        positionItems(dx);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mCurrentX = mNextX;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(!mScroller.isFinished()){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            post(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Runnable(){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; run() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    requestLayout();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            });  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;              \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; fillList(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; edge = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        View child = getChildAt(getChildCount()-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(child != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            edge = child.getRight();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        fillListRight(edge, dx);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        edge = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        child = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(child != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            edge = child.getLeft();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        fillListLeft(edge, dx);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; fillListRight(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; rightEdge, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(rightEdge + dx \u0026lt; getWidth() \u0026amp;\u0026amp; mRightViewIndex \u0026lt; mAdapter.getCount()) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;              \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            View child = mAdapter.getView(mRightViewIndex, mRemovedViewQueue.poll(), \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            addAndMeasureChild(child, \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            rightEdge += child.getMeasuredWidth();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;              \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mRightViewIndex == mAdapter.getCount()-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                mMaxX = mCurrentX + rightEdge \u0026amp;#8211; getWidth();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;              \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mMaxX \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                mMaxX = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mRightViewIndex++;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; fillListLeft(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; leftEdge, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(leftEdge + dx \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; mLeftViewIndex \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            View child = mAdapter.getView(mLeftViewIndex, mRemovedViewQueue.poll(), \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            addAndMeasureChild(child, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            leftEdge -= child.getMeasuredWidth();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mLeftViewIndex\u0026amp;#8211;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mDisplayOffset -= child.getMeasuredWidth();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; removeNonVisibleItems(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        View child = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(child != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; child.getRight() + dx \u0026lt;= \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mDisplayOffset += child.getMeasuredWidth();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mRemovedViewQueue.offer(child);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            removeViewInLayout(child);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mLeftViewIndex++;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            child = getChildAt(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;              \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        child = getChildAt(getChildCount()-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;while\u0026lt;/span\u0026gt;(child != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; child.getLeft() + dx \u0026gt;= getWidth()) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mRemovedViewQueue.offer(child);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            removeViewInLayout(child);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mRightViewIndex\u0026amp;#8211;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            child = getChildAt(getChildCount()-\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; positionItems(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; dx) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(getChildCount() \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mDisplayOffset += dx;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; left = mDisplayOffset;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;i\u0026lt;getChildCount();i++){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                View child = getChildAt(i);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childWidth = child.getMeasuredWidth();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                child.layout(left, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, left + childWidth, child.getMeasuredHeight());  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                left += childWidth + child.getPaddingRight();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; scrollTo(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; x) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mScroller.startScroll(mNextX, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, x \u0026amp;#8211; mNextX, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        requestLayout();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent ev) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; handled = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.dispatchTouchEvent(ev);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        handled |= mGesture.onTouchEvent(ev);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; handled;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityX,  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt;(HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            mScroller.fling(mNextX, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)-velocityX, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, mMaxX, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        requestLayout();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDown(MotionEvent e) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mScroller.forceFinished(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnGestureListener mOnGesture = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; GestureDetector.SimpleOnGestureListener() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onDown(MotionEvent e) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onDown(e);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onFling(MotionEvent e1, MotionEvent e2, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityX,  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; velocityY) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onFling(e1, e2, velocityX, velocityY);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onScroll(MotionEvent e1, MotionEvent e2,  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceX, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; distanceY) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;              \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;synchronized\u0026lt;/span\u0026gt;(HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                mNextX += (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;)distanceX;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            requestLayout();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;              \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; onSingleTapConfirmed(MotionEvent e) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;;i\u0026lt;getChildCount();i++){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                View child = getChildAt(i);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isEventWithinView(e, child)) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mOnItemClicked != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        mOnItemClicked.onItemClick(HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, child, mLeftViewIndex + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; + i, mAdapter.getItemId( mLeftViewIndex + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; + i ));  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(mOnItemSelected != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        mOnItemSelected.onItemSelected(HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, child, mLeftViewIndex + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; + i, mAdapter.getItemId( mLeftViewIndex + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; + i ));  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onLongPress(MotionEvent e) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; childCount = getChildCount();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; childCount; i++) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                View child = getChildAt(i);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (isEventWithinView(e, child)) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mOnItemLongClicked != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                        mOnItemLongClicked.onItemLongClick(HorizontalListView.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, child, mLeftViewIndex + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; + i, mAdapter.getItemId(mLeftViewIndex + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt; + i));  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isEventWithinView(MotionEvent e, View child) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            Rect viewRect = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] childPosition = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;];  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            child.getLocationOnScreen(childPosition);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; left = childPosition[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;];  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; right = left + child.getWidth();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; top = childPosition[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;];  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; bottom = top + child.getHeight();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            viewRect.set(left, top, right, bottom);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; viewRect.contains((\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) e.getRawX(), (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) e.getRawY());  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    };  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003eHorizontalListViewAdapter.java 横向listview的适配器，我将他单独写到一个java文件里。\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; org.yanzi.ui;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.testhorizontallistview.R;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.yanzi.util.BitmapUtil;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Bitmap;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.drawable.Drawable;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.media.ThumbnailUtils;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.BaseAdapter;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ImageView;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; HorizontalListViewAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; BaseAdapter{  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] mIconIDs;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String[] mTitles;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context mContext;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; LayoutInflater mInflater;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    Bitmap iconBitmap;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; selectIndex = \u0026amp;#8211;\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; HorizontalListViewAdapter(Context context, String[] titles, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;[] ids){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mContext = context;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mIconIDs = ids;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mTitles = titles;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        mInflater=(LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//LayoutInflater.from(mContext);\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount() {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mIconIDs.length;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object getItem(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; position;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getItemId(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; position;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getView(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View convertView, ViewGroup parent) {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        ViewHolder holder;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(convertView==\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            holder = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewHolder();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            convertView = mInflater.inflate(R.layout.horizontal_list_item, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            holder.mImage=(ImageView)convertView.findViewById(R.id.img_list_item);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            holder.mTitle=(TextView)convertView.findViewById(R.id.text_list_item);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            convertView.setTag(holder);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            holder=(ViewHolder)convertView.getTag();  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(position == selectIndex){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            convertView.setSelected(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;            convertView.setSelected(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        holder.mTitle.setText(mTitles[position]);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        iconBitmap = getPropThumnail(mIconIDs[position]);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        holder.mImage.setImageBitmap(iconBitmap);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; convertView;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ViewHolder {  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView mTitle ;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ImageView mImage;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap getPropThumnail(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; id){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Drawable d = mContext.getResources().getDrawable(id);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Bitmap b = BitmapUtil.drawableToBitmap(d);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//      Bitmap bb = BitmapUtil.getRoundedCornerBitmap(b, 100);\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; w = mContext.getResources().getDimensionPixelOffset(R.dimen.thumnail_default_width);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; h = mContext.getResources().getDimensionPixelSize(R.dimen.thumnail_default_height);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Bitmap thumBitmap = ThumbnailUtils.extractThumbnail(b, w, h);  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;          \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; thumBitmap;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setSelectIndex(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i){  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        selectIndex = i;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e下面是效果图：\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20140315182924656?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuemkxMjI1NjI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  下图是一个item被选定后，另一个item获得了焦点:\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20140315183047562?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuemkxMjI1NjI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003cdiv\u003e\n  下面是横向时的截图:\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  ![](http://img.blog.csdn.net/20140315183137906?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuemkxMjI1NjI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)\n\u003c/div\u003e\n\u003ch2 id=\"要点如下\"\u003e\u003ca style=\"color: #336699;\" name=\"t2\"\u003e\u003c/a\u003e要点如下:\u003c/h2\u003e\n\u003cdiv\u003e\n  1、可以说这个HorizontalListView是完美的，但美中不足的并不是其他人说的不能点击、晃动、加载不全的问题，而是这个横向Listview的高度，如果你设成wrap_cotent那么将会占据整个屏幕，**\u003cspan style=\"color: #ff0000;\"\u003e即使你将它适配器里的view的高度限制死，限制成很小，这个HorizontalListView的高度依然是全屏\u003c/span\u003e**。本文代码里，我把图片缩略图弄成100dip，所以把这个HorizontalListView的高度设为了150dip。\n\u003c/div\u003e\n\u003cdiv\u003e\n  2、在适配器里，我填充了一个图片，下面是文字。为了能让浏览图片时item有反应，搞了一个selector，它的用法详见[这里](http://blog.csdn.net/shakespeare001/article/details/7788400). 但一开始在点击时完全没有反应，参考这里：\n\u003c/div\u003e\n\u003cdiv\u003e\n  [http://blog.csdn.net/ljz2009y/article/details/18820071](http://blog.csdn.net/ljz2009y/article/details/18820071)   为此我的selector如下：\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003c?xml version=\u0026#8221;1.0\u0026#8243; encoding=\u0026#8221;utf-8\u0026#8243;?\u003e\n \u003cselector xmlns:android=\u0026#8221;http://schemas.android.com/apk/res/android\u0026#8221;\u003e\n \u003citem android:drawable=\u0026#8221;@android:color/holo_red_light\u0026#8221; android:state_selected=\u0026#8221;true\u0026#8221;/\u003e\n \u003citem android:drawable=\u0026#8221;@android:color/holo_green_dark\u0026#8221; android:state_pressed=\u0026#8221;true\u0026#8221;/\u003e\n \u003citem android:drawable=\u0026#8221;@android:color/transparent\u0026#8221;/\u003e\n \u003c/selector\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n  将自然状态下的背景放到了最后，但点击浏览时依然没有作用。**\u003cspan style=\"color: #ff0000;\"\u003e其实最根本原因是在布局文件里horizontal_list_item.xml要让这个布局能够clickable，即：android:clickable=\u0026#8221;true\u0026#8221;\u003c/span\u003e**\n\u003c/div\u003e\n\u003cdiv\u003e\n  3、上一步完成了，还需要点击即select一个item时，让它变色并且保持住，然后点击另外一个item时，让之前得item恢复默认背景。为了实现这个问题，我曾作如下尝试：\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cdiv class=\"dp-highlighter bg_java\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[copy](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[print](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[?](http://blog.csdn.net/yanzi1225627/article/details/21294553#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/237690)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/237690/fork)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span style=\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;font-family: \u0026amp;#8216;Comic Sans MS\u0026amp;#8217;; font-size: 18px;\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//             if(olderSelectView == null){\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//                  olderSelectView = view;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              }else{\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//                  olderSelectView.setSelected(false);\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//                  olderSelectView = null;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              }\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              olderSelectView = view;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//              view.setSelected(true);\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e即在click监听里，保存上一个选中的view。遗憾的是这种方法会造成item的选中状态造成混乱，比如第一个item选中了，同时第5个item也莫名其妙的被选中了。上述情况发生在滑动时，即一屏显示不完的情况下。当我横屏时，在所有的item都能一次性显示出来情况下，用上述方法么问题。后来我想到，这可以是适配器里的缓存机制造成的，**\u0026lt;span style=\u0026quot;color: #ff0000;\u0026quot;\u0026gt;最好不要再listview适配器外对item作修改，即便修改则一定要调适配器的: hListViewAdapter.notifyDataSetChanged();通知刷新view，毕竟适配器才是view的提供者\u0026lt;/span\u0026gt;**。参考这位大大的文章:[http://longyi-java.iteye.com/blog/976067](http://longyi-java.iteye.com/blog/976067) 在适配器里加了一个接口保存选中的索引，然后再getView函数里进行判断。如果是选中的item，则将布局设为选中状态即可，horizontal_list_item.xml里的Linearlayout就会自动加载那个selector了。而无需像这个参考链接里对每个item的元素分别设置状态。\u0026lt;/div\u0026gt; \n\n\u0026lt;div\u0026gt;\n  4、BitmapUtil是个工具类，负责将id转成一个bitmap，然后用android自带的ThumbnailUtils去提取缩略图。\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  5、之所以horizontal_list_item布局里要设置padding是为了选中item时，整个item有种被圈住的感觉，而不是光下面一点变色。\n\u0026lt;/div\u0026gt;\n\n\u0026lt;div\u0026gt;\n  \n\n    源码下载:[http://download.csdn.net/detail/yanzi1225627/7046295](http://download.csdn.net/detail/yanzi1225627/7046295)\u0026lt;/div\u0026gt; \n    \n    \u0026lt;div\u0026gt;\n      欢迎Android爱好者加群\n\n      \n      \u0026lt;div id=\u0026quot;group_name\u0026quot; class=\u0026quot;group_name usrInputFont\u0026quot;\u0026gt;\n        \u0026lt;span class=\u0026quot;qname\u0026quot; title=\u0026quot;Android您问我讲-2\u0026quot;\u0026gt;**Android您问我讲-2，**\u0026lt;/span\u0026gt;\n      \u0026lt;/div\u0026gt;\n      \n      \n\n        **群号:**\u0026lt;span id=\u0026quot;group_number\u0026quot; class=\u0026quot;group_number\u0026quot;\u0026gt;**19241311,备注：yanzi**\u0026lt;/span\u0026gt;\n      \n\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n       \u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;\u0026amp;#8212;本文系原创，转载请注明作者:yanzi1225627\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      源码下载:[http://download.csdn.net/detail/yanzi1225627/7046295](http://download.csdn.net/detail/yanzi1225627/7046295)\n    \u0026lt;/div\u0026gt;\n    \n    \u0026lt;div\u0026gt;\n      源码下载:[http://download.csdn.net/detail/yanzi1225627/7046295](http://download.csdn.net/detail/yanzi1225627/7046295)\n    \u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e","title":"Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)"},{"content":"项目两张图片：\nwave btn\n代码：\npackage com.example.waveanimation;\nimport Android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Message;\nimport android.app.Activity;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.View.OnTouchListener;\nimport android.view.animation.AlphaAnimation;\nimport android.view.animation.AnimationSet;\nimport android.view.animation.ScaleAnimation;\nimport android.widget.ImageView;\npublic class MainActivity extends Activity {\nprivate static final int ANIMATIONEACHOFFSET = 600; // 每个动画的播放时间间隔\nprivate AnimationSet aniSet, aniSet2, aniSet3;\nprivate ImageView btn, wave1, wave2, wave3;\nprivate Handler handler = new Handler() {\n@Override\npublic void handleMessage(Message msg) {\nif (msg.what == 0x222) {\nwave2.startAnimation(aniSet2);\n} else if (msg.what == 0x333) {\nwave3.startAnimation(aniSet3);\n}\nsuper.handleMessage(msg);\n}\n};\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\nsuper.onCreate(savedInstanceState);\naniSet = getNewAnimationSet();\naniSet2 = getNewAnimationSet();\naniSet3 = getNewAnimationSet();\nsetContentView(R.layout.activity_main);\nbtn = (ImageView) findViewById(R.id.btn);\nwave1 = (ImageView) findViewById(R.id.wave1);\nwave2 = (ImageView) findViewById(R.id.wave2);\nwave3 = (ImageView) findViewById(R.id.wave3);\nbtn.setOnTouchListener(new OnTouchListener() {\n@Override\npublic boolean onTouch(View v, MotionEvent event) {\nswitch (event.getAction()) {\ncase MotionEvent.ACTION_DOWN:\nshowWaveAnimation();\nbreak;\ncase MotionEvent.ACTION_UP:\ncancalWaveAnimation();\nbreak;\ncase MotionEvent.ACTION_CANCEL:\ncancalWaveAnimation();\nbreak;\n}\nreturn true;\n}\n});\n}\nprivate AnimationSet getNewAnimationSet() {\nAnimationSet as = new AnimationSet(true);\nScaleAnimation sa = new ScaleAnimation(1f, 2.3f, 1f, 2.3f,\nScaleAnimation.RELATIVE_TO_SELF, 0.5f,\nScaleAnimation.RELATIVE_TO_SELF, 0.5f);\nsa.setDuration(ANIMATIONEACHOFFSET * 3);\nsa.setRepeatCount(-1);// 设置循环\nAlphaAnimation aniAlp = new AlphaAnimation(1, 0.1f);\naniAlp.setRepeatCount(-1);// 设置循环\nas.setDuration(ANIMATIONEACHOFFSET * 3);\nas.addAnimation(sa);\nas.addAnimation(aniAlp);\nreturn as;\n}\nprivate void showWaveAnimation() {\nwave1.startAnimation(aniSet);\nhandler.sendEmptyMessageDelayed(0x222, ANIMATIONEACHOFFSET);\nhandler.sendEmptyMessageDelayed(0x333, ANIMATIONEACHOFFSET * 2);\n}\nprivate void cancalWaveAnimation() {\nwave1.clearAnimation();\nwave2.clearAnimation();\nwave3.clearAnimation();\n}\n}\nxml文件：\n\u0026lt;RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android”\nandroid:layout_width=”match_parent”\nandroid:layout_height=”match_parent” \u0026gt;\n效果图：\n","permalink":"https://blog.zdltech.com/posts/android%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0%E9%95%BF%E6%8C%89%E6%98%BE%E7%A4%BA%E6%B3%A2%E7%BA%B9%E5%A4%96%E6%89%A9%E5%8A%A8%E7%94%BB/","summary":"\u003cp\u003e项目两张图片：\u003c/p\u003e\n\u003cp\u003ewave\u003cimg loading=\"lazy\" src=\"http://www.linuxidc.com/upload/2014_05/140514204737271.png\"\u003e btn\u003cimg loading=\"lazy\" src=\"http://www.linuxidc.com/upload/2014_05/140514204737272.png\"\u003e\u003c/p\u003e\n\u003cp\u003e代码：\u003c/p\u003e\n\u003cp\u003epackage com.example.waveanimation;\u003c/p\u003e\n\u003cp\u003eimport \u003ca href=\"http://www.linuxidc.com/topicnews.aspx?tid=11\"\u003eAndroid\u003c/a\u003e.os.Bundle;\u003cbr\u003e\nimport android.os.Handler;\u003cbr\u003e\nimport android.os.Message;\u003cbr\u003e\nimport android.app.Activity;\u003cbr\u003e\nimport android.view.MotionEvent;\u003cbr\u003e\nimport android.view.View;\u003cbr\u003e\nimport android.view.View.OnTouchListener;\u003cbr\u003e\nimport android.view.animation.AlphaAnimation;\u003cbr\u003e\nimport android.view.animation.AnimationSet;\u003cbr\u003e\nimport android.view.animation.ScaleAnimation;\u003cbr\u003e\nimport android.widget.ImageView;\u003c/p\u003e\n\u003cp\u003epublic class MainActivity extends Activity {\u003cbr\u003e\nprivate static final int ANIMATIONEACHOFFSET = 600; // 每个动画的播放时间间隔\u003cbr\u003e\nprivate AnimationSet aniSet, aniSet2, aniSet3;\u003cbr\u003e\nprivate ImageView btn, wave1, wave2, wave3;\u003cbr\u003e\nprivate Handler handler = new Handler() {\u003c/p\u003e\n\u003cp\u003e@Override\u003cbr\u003e\npublic void handleMessage(Message msg) {\u003cbr\u003e\nif (msg.what == 0x222) {\u003cbr\u003e\nwave2.startAnimation(aniSet2);\u003cbr\u003e\n} else if (msg.what == 0x333) {\u003cbr\u003e\nwave3.startAnimation(aniSet3);\u003cbr\u003e\n}\u003cbr\u003e\nsuper.handleMessage(msg);\u003cbr\u003e\n}\u003c/p\u003e","title":"Android代码实现长按显示波纹外扩动画"},{"content":"用Android rotate动画实现翻页效果，效果如图：\n![](http://img.blog.csdn.net/20130826221333046?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHVhemFpOTYzMTg0NzA5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 要实现上面动画，首先搞明白rotate动画原理； （1）Degrees坐标： 0度（360度） 270度![](http://img.blog.csdn.net/20130826214747859?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHVhemFpOTYzMTg0NzA5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 90度 顺时针旋转 180 （2）rotate 关键属性 fromDegrees 开始旋转时角度 toDegrees 结束时的角度 pivotX，pivotY 旋转时的中心点 他们范围是 0—100%p （0，0）代表左上角，（100%p, 100%p）右下角 duration 动画持续时间 毫秒为单位 知道了这两点就可以实现了 在res新建 anim 文件夹 新建 离开Activity时的xml **[html]** [view plain](http://blog.csdn.net/huazai963184709/article/details/10364243#)[copy](http://blog.csdn.net/huazai963184709/article/details/10364243#)[print](http://blog.csdn.net/huazai963184709/article/details/10364243#)[?](http://blog.csdn.net/huazai963184709/article/details/10364243#) - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;set\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;rotate\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:duration\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;500\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:fromDegrees\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:pivotX\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:pivotY\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:toDegrees\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;set\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;新建 进入Activity时的xml\u0026lt;/span\u0026gt; **[html]** [view plain](http://blog.csdn.net/huazai963184709/article/details/10364243#)[copy](http://blog.csdn.net/huazai963184709/article/details/10364243#)[print](http://blog.csdn.net/huazai963184709/article/details/10364243#)[?](http://blog.csdn.net/huazai963184709/article/details/10364243#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;set\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;rotate\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:duration\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;500\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:fromDegrees\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;90\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:pivotX\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;100%p\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:pivotY\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;100%p\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:toDegrees\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;set\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;最后就是代码调用了\u0026lt;/span\u0026gt; **[html]** [view plain](http://blog.csdn.net/huazai963184709/article/details/10364243#)[copy](http://blog.csdn.net/huazai963184709/article/details/10364243#)[print](http://blog.csdn.net/huazai963184709/article/details/10364243#)[?](http://blog.csdn.net/huazai963184709/article/details/10364243#) - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;Intent \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;intent\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(ActivityAnimationDemo.this, activtyanimationdemo2.class); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;startActivity(intent); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;overridePendingTransition(R.anim.rotate_left, R.anim.rotate_right); \u0026lt;/span\u0026gt; 解释一下应放入的参数 **[html]** [view plain](http://blog.csdn.net/huazai963184709/article/details/10364243#)[copy](http://blog.csdn.net/huazai963184709/article/details/10364243#)[print](http://blog.csdn.net/huazai963184709/article/details/10364243#)[?](http://blog.csdn.net/huazai963184709/article/details/10364243#) - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;overridePendingTransition（进入时的动画，离开时的动画） \u0026lt;/span\u0026gt; \u0026amp;nbsp; [源码下载](http://download.csdn.net/detail/huazai963184709/6016175)（为了方便，把移动和 旋转动画代码写一块了） ","permalink":"https://blog.zdltech.com/posts/android-%E4%B8%A4activity%E4%B9%8B%E9%97%B4%E5%8A%A8%E7%94%BB%E6%95%88%E6%9E%9C1-%E7%BF%BB%E9%A1%B5%E6%95%88%E6%9E%9C/","summary":"\u003cp\u003e用Android rotate动画实现翻页效果，效果如图：\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e![](http://img.blog.csdn.net/20130826221333046?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHVhemFpOTYzMTg0NzA5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\n\n\n\n\n要实现上面动画，首先搞明白rotate动画原理；\n\n\n\n\n\n（1）Degrees坐标：\n\n\n\n\n\n                      0度（360度）\n\n\n\n\n\n  270度![](http://img.blog.csdn.net/20130826214747859?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHVhemFpOTYzMTg0NzA5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 90度  顺时针旋转\n\n\n\n\n\n                        180\n\n\n\n\n\n（2）rotate 关键属性\n\n\n\n\n\n        fromDegrees 开始旋转时角度      toDegrees 结束时的角度\n\n\n\n\n\n        pivotX，pivotY 旋转时的中心点  他们范围是 0—100%p   （0，0）代表左上角，（100%p, 100%p）右下角\n\n\n\n\n\n        duration 动画持续时间 毫秒为单位\n\n\n\n\n\n知道了这两点就可以实现了   在res新建 anim 文件夹\n\n\n\n\n\n   新建 离开Activity时的xml\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\" style=\"color: #000000;\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/huazai963184709/article/details/10364243#)[copy](http://blog.csdn.net/huazai963184709/article/details/10364243#)[print](http://blog.csdn.net/huazai963184709/article/details/10364243#)[?](http://blog.csdn.net/huazai963184709/article/details/10364243#)\n      \u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;set\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;rotate\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:duration\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;500\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:fromDegrees\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:pivotX\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:pivotY\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:toDegrees\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;set\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;新建 进入Activity时的xml\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\" style=\"color: #000000;\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/huazai963184709/article/details/10364243#)[copy](http://blog.csdn.net/huazai963184709/article/details/10364243#)[print](http://blog.csdn.net/huazai963184709/article/details/10364243#)[?](http://blog.csdn.net/huazai963184709/article/details/10364243#)\n\u003cpre\u003e\u003ccode\u003e    \u0026lt;div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\n\n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;utf-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;set\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;xmlns:android\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;rotate\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:duration\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;500\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:fromDegrees\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;90\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:pivotX\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;100%p\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:pivotY\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;100%p\u0026amp;#8221;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;android:toDegrees\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;/\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n  \n  - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026lt;/\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag-name\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;set\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;tag\u0026quot; style=\u0026quot;font-weight: bold; color: #993300;\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;最后就是代码调用了\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\" style=\"color: #000000;\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/huazai963184709/article/details/10364243#)[copy](http://blog.csdn.net/huazai963184709/article/details/10364243#)[print](http://blog.csdn.net/huazai963184709/article/details/10364243#)[?](http://blog.csdn.net/huazai963184709/article/details/10364243#)\n      \u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;Intent \u0026lt;span class=\u0026quot;attribute\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;intent\u0026lt;/span\u0026gt; = \u0026lt;span class=\u0026quot;attribute-value\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Intent(ActivityAnimationDemo.this, activtyanimationdemo2.class);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;startActivity(intent);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;overridePendingTransition(R.anim.rotate_left, R.anim.rotate_right);  \u0026lt;/span\u0026gt;\n\n\n\n\n\n解释一下应放入的参数\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv class=\"dp-highlighter bg_html\" style=\"color: #000000;\"\u003e\n    \u003cdiv class=\"bar\"\u003e\n      \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n        **[html]** [view plain](http://blog.csdn.net/huazai963184709/article/details/10364243#)[copy](http://blog.csdn.net/huazai963184709/article/details/10364243#)[print](http://blog.csdn.net/huazai963184709/article/details/10364243#)[?](http://blog.csdn.net/huazai963184709/article/details/10364243#)\n      \u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;overridePendingTransition（进入时的动画，离开时的动画） \u0026lt;/span\u0026gt;\n\n\n\n\n\n\u0026amp;nbsp;\n\n\n\n\n\n[源码下载](http://download.csdn.net/detail/huazai963184709/6016175)（为了方便，把移动和 旋转动画代码写一块了）\n\u003c/code\u003e\u003c/pre\u003e","title":"Android 两Activity之间动画效果———翻页效果"},{"content":" \u0026lt;div\u0026gt; slide_left_in.xml \u0026lt;?xml version=\u0026amp;#8221;1.0\u0026amp;#8243; encoding=\u0026amp;#8221;utf-8\u0026amp;#8243;?\u0026gt; \u0026lt;set xmlns:android=\u0026amp;#8221;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026gt; \u0026lt;translate android:duration=\u0026amp;#8221;300\u0026amp;#8243; android:fromXDelta=\u0026amp;#8221;-100.0%p\u0026amp;#8221; android:toXDelta=\u0026amp;#8221;0.0\u0026amp;#8243; /\u0026gt; \u0026lt;/set\u0026gt; slide_left_out.xml \u0026lt;?xml version=\u0026amp;#8221;1.0\u0026amp;#8243; encoding=\u0026amp;#8221;utf-8\u0026amp;#8243;?\u0026gt; slide_right_in.xml\n\u0026lt;?xml version=\u0026amp;#8221;1.0\u0026amp;#8243; encoding=\u0026amp;#8221;utf-8\u0026amp;#8243;?\u0026gt; slide_right_out.xml \u0026lt;?xml version=\u0026amp;#8221;1.0\u0026amp;#8243; encoding=\u0026amp;#8221;utf-8\u0026amp;#8243;?\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; 1. 在Style文件里面定义 \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; 2.在Manifest里面application设置Theme android:theme=”@style/AppTheme”\n","permalink":"https://blog.zdltech.com/posts/android-%E9%A1%B5%E9%9D%A2%E5%B7%A6%E5%8F%B3%E5%88%87%E6%8D%A2%E5%8A%A8%E7%94%BB%E5%AE%9E%E7%8E%B0/","summary":"\u003cdiv class=\"dp-highlighter bg_java\" style=\"color: #000000;\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      \u003cdiv\u003e\n      \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n    \n\n      slide_left_in.xml\n    \n\n    \n    \n\n      \u0026lt;?xml version=\u0026amp;#8221;1.0\u0026amp;#8243; encoding=\u0026amp;#8221;utf-8\u0026amp;#8243;?\u0026gt; \u0026lt;set xmlns:android=\u0026amp;#8221;http://schemas.android.com/apk/res/android\u0026amp;#8221;\u0026gt; \u0026lt;translate android:duration=\u0026amp;#8221;300\u0026amp;#8243; android:fromXDelta=\u0026amp;#8221;-100.0%p\u0026amp;#8221; android:toXDelta=\u0026amp;#8221;0.0\u0026amp;#8243; /\u0026gt; \u0026lt;/set\u0026gt;\n    \n\n    \n    \n\n      slide_left_out.xml\n    \n\n    \n    \n\n      \u0026lt;?xml version=\u0026amp;#8221;1.0\u0026amp;#8243; encoding=\u0026amp;#8221;utf-8\u0026amp;#8243;?\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cset\nxmlns:android=\u0026#8221;http://schemas.android.com/apk/res/android\u0026#8221;\u003e\n\u003ctranslate android:duration=\u0026#8221;300\u0026#8243; android:fromXDelta=\u0026#8221;0.0\u0026#8243; android:toXDelta=\u0026#8221;-100.0%p\u0026#8221; /\u003e\n\u003c/set\u003e\nslide_right_in.xml\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e      \u0026lt;?xml version=\u0026amp;#8221;1.0\u0026amp;#8243; encoding=\u0026amp;#8221;utf-8\u0026amp;#8243;?\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cset\nxmlns:android=\u0026#8221;http://schemas.android.com/apk/res/android\u0026#8221;\u003e\n\u003ctranslate android:duration=\u0026#8221;300\u0026#8243; android:fromXDelta=\u0026#8221;100.0%p\u0026#8221; android:toXDelta=\u0026#8221;0.0\u0026#8243; /\u003e\n\u003c/set\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e      slide_right_out.xml\n    \n\n    \n    \n\n      \u0026lt;?xml version=\u0026amp;#8221;1.0\u0026amp;#8243; encoding=\u0026amp;#8221;utf-8\u0026amp;#8243;?\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cset\nxmlns:android=\u0026#8221;http://schemas.android.com/apk/res/android\u0026#8221;\u003e\n\u003ctranslate android:duration=\u0026#8221;300\u0026#8243; android:fromXDelta=\u0026#8221;0.0\u0026#8243; android:toXDelta=\u0026#8221;100.0%p\u0026#8221; /\u003e\n\u003c/set\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n    1. 在Style文件里面定义\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e    \u003cstyle name=\u0026#8221;AppTheme\u0026#8221; parent=\u0026#8221;@android:style/Theme.Black.NoTitleBar.Fullscreen\u0026#8221;\u003e\n\u003citem name=\u0026#8221;android:windowNoTitle\u0026#8221;\u003etrue\u003c/item\u003e\n\u003citem name=\u0026#8221;android:windowAnimationStyle\u0026#8221;\u003e@style/activityAnimation\u003c/item\u003e\n\u003c/style\u003e\u003c/p\u003e\n \u003cstyle name=\u0026#8221;activityAnimation\u0026#8221; parent=\u0026#8221;@android:style/Animation\u0026#8221;\u003e\n \u003citem name=\u0026#8221;android:activityOpenEnterAnimation\u0026#8221;\u003e@anim/slide_right_in\u003c/item\u003e\n \u003citem name=\u0026#8221;android:activityOpenExitAnimation\u0026#8221;\u003e@anim/slide_left_out\u003c/item\u003e\n \u003citem name=\u0026#8221;android:activityCloseEnterAnimation\u0026#8221;\u003e@anim/slide_left_in\u003c/item\u003e\n \u003citem name=\u0026#8221;android:activityCloseExitAnimation\u0026#8221;\u003e@anim/slide_right_out\u003c/item\u003e\n \u003c/style\u003e\n\u003cp\u003e\u003cspan style=\"color: #000000;\"\u003e2.在Manifest里面application设置Theme   android:theme=”@style/AppTheme”\u003c/span\u003e\u003c/p\u003e","title":"Android 页面左右切换动画实现"},{"content":"过去的时间里，Android开发逐步走向成熟，一个个与Android相关的开发工具也层出不穷。不过，在面对各种新鲜事物时，不要忘了那些我们每天使用的大量开源库。在这里，向大家介绍的就是，在这个任劳任怨的大家庭中，最受开发者喜爱的五个Android库。希望通过对它们的了解，能够对你的开发工作有所帮助。\n**\n**\n1. GSON\nGson是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库。可用于将Java对象转换成对应的JSON表示，也可以将JSON字符串转换成一个等效的Java对象。如果与API打交道的话，那么这将会是你经常需要的东西。我们主要使用JSON的原因就是，相较XML，轻量级的JSON要简单的多。\n**[js]** [view plain](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[copy](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/394286)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/394286/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Serialize \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;String userJSON = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Gson().toJson(user); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Deserialize\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;User user = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Gson().fromJson(userJSON, User.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; 2. RETROFIT\n就如它网站上的介绍“Retrofit将你的REST API变为Java接口”一样，Retrofit把REST API返回的数据转化为Java对象方便操作，对于在项目中组织API调用，是一个不错的解决方案。其请求方法和相对URL都带有注解，使得代码变得更加简洁。使用注解，你可以很容易的添加一个请求主体，操纵URL或头文件，并添加查询参数。除此之外，每个函数可以定义为同步或异步，具有返回值的函数为同步执行，而异步函数没有返回值且最后一个参数为Callback对象。\n**[js]** [view plain](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[copy](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/394286)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/394286/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; RetrofitInterface { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// asynchronously with a callback\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; @GET(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8220;/api/user\u0026amp;#8221;\u0026lt;/span\u0026gt;) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; User getUser(@Query(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8220;user_id\u0026amp;#8221;\u0026lt;/span\u0026gt;) \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; userId, Callback\u0026lt;User\u0026gt; callback); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// synchronously\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; @POST(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8220;/api/user/register\u0026amp;#8221;\u0026lt;/span\u0026gt;) \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; User registerUser(@Body User user); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// example\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;RetrofitInterface retrofitInterface = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; RestAdapter.Builder() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; .setServer(API.API_URL).build().create(RetrofitInterface.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// fetch user with id 2048\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;retrofitInterface.getUser(2048, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Callback\u0026lt;User\u0026gt;() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; @Override \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; success(User user, Response response) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; @Override \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; failure(RetrofitError retrofitError) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;}); \u0026lt;/span\u0026gt; Retrofit默认情况下使用的是GSON，所以无需自定义解析，同时还支持其他转换器。\n3. EVENTBUS\nEventBus是用于简化应用中各个部件之间通信的一个库。比如从一个Activity发送消息到一个正在运行的服务，亦或是片段之间简单的互动。而下面使用的示例，就是如果网络连接丢失，该如何通知一个活动：\n**[js]** [view plain](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[copy](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/394286)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/394286/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; NetworkStateReceiver \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; BroadcastReceiver { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// post event if there is no Internet connection\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onReceive(Context context, Intent intent) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onReceive(context, intent); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(intent.getExtras()!=\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; NetworkInfo ni=(NetworkInfo) intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(ni!=\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; ni.getState()==NetworkInfo.State.CONNECTED) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// there is Internet connection\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(intent \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; .getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,Boolean.FALSE)) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// no Internet connection, send network state changed\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; EventBus.getDefault().post(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; NetworkStateChanged(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;false\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// event\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; NetworkStateChanged { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; mIsInternetConnected; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; NetworkStateChanged(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isInternetConnected) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mIsInternetConnected = isInternetConnected; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; isInternetConnected() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mIsInternetConnected; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; HomeActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; @Override \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; setContentView(R.layout.activity_main); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; EventBus.getDefault().register(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// register EventBus\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; @Override \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDestroy() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDestroy(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; EventBus.getDefault().unregister(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// unregister EventBus\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// method that will be called when someone posts an event NetworkStateChanged\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onEventMainThread(NetworkStateChanged event) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (!event.isInternetConnected()) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; Toast.makeText(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8220;No Internet connection!\u0026amp;#8221;\u0026lt;/span\u0026gt;, Toast.LENGTH_SHORT).show(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; 4. ACTIVEANDROID\nActiveAndroid算是一个轻量级的ORM（对象关系映射），让你无需编写一个单独的SQL语句，就可以保存和检索SQLite数据库记录。每个数据库记录都被包裹整齐地归为一类，如delete（）和save（）的方法。\n扩展ActiveAndroid Model的对象能够保存在数据库里，如：\n**[js]** [view plain](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[copy](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/394286)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/394286/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;user.save(); \u0026lt;/span\u0026gt; 可以轻易替代大型SQL语句：\n**[js]** [view plain](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[copy](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/394286)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/394286/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;INSERT INTO Users (Nickname, Name, Address, City, PostalCode, Country) VALUES (\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8216;Batman\u0026amp;#8217;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8216;Bruce W\u0026amp;#8217;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8216;Palisades 21\u0026amp;#8217;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8216;Gotham\u0026amp;#8217;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8216;40000\u0026amp;#8217;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8216;USA\u0026amp;#8217;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; 获取所有用户的例子：\n**[js]** [view plain](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[copy](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/394286)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/394286/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;List\u0026lt;User\u0026gt; users = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Select().from(User.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;).execute(); \u0026lt;/span\u0026gt; 而其对应的SQL语句是这样：\n**[js]** [view plain](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[copy](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/394286)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/394286/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;SELECT Nickname, Name, Address, City, PostalCode, Country FROM Users; \u0026lt;/span\u0026gt; ActiveAndroid是移除大量，用于和数据库一同工作的样板代码的一个很好的方法。当然除此之外，还有其他开源解决方案，如GreenDAO和ORMLite。\n5. UNIVERSAL IMAGE LOADER\nUIL是是一个开源项目，其目的就是提供一个可重复使用的仪器为异步图像加载、缓存和显示。它的使用很简单：\n**[js]** [view plain](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[copy](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/394286)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/394286/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;imageLoader.displayImage(imageUri, imageView); \u0026lt;/span\u0026gt; 尽管Picasso拥有更好的API，但其缺乏自定义。而使用UIL构建器几乎可以配置所有（其中最重要的就是在抓取和缓存大型图片时，Picasso会失败）。\n良好的开源库会让你的开发变得更简单更快速，而普遍流行的库通常测试良好且易用使用。在大多情况下，你可以很容易的将它们从Maven中导入到Android Studio项目里。将它们添加到相关性的build.gradle 文件。并且同步之后，在你的应用里将能够很好的实现它们。\n**[js]** [view plain](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[copy](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/394286)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/394286/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;dependencies { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; compile \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8216;com.google.code.gson:gson:2.2.4\u0026amp;#8217;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; compile \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8216;com.squareup.okhttp:okhttp:1.3.0\u0026amp;#8217;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; compile \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8216;com.squareup.retrofit:retrofit:1.3.0\u0026amp;#8217;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; compile \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8216;de.greenrobot:eventbus:2.2.+\u0026amp;#8217;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; compile \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026amp;#8216;com.nostra13.universalimageloader:universal-image-loader:1.9.1\u0026amp;#8217;\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; ","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E5%8F%91%E8%80%85%E5%BF%85%E7%9F%A5%E7%9A%845%E4%B8%AA%E5%BC%80%E6%BA%90%E5%BA%93/","summary":"\u003cp\u003e过去的时间里，Android开发逐步走向成熟，一个个与Android相关的开发工具也层出不穷。不过，在面对各种新鲜事物时，不要忘了那些我们每天使用的大量开源库。在这里，向大家介绍的就是，在这个任劳任怨的大家庭中，最受开发者喜爱的五个Android库。希望通过对它们的了解，能够对你的开发工作有所帮助。\u003c/p\u003e\n\u003cp\u003e**\u003ca href=\"http://cms.csdnimg.cn/article/201406/16/539ea3aa2e9b9.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201406/16/539ea3aa2e9b9_middle.jpg\"\u003e\u003c/a\u003e\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. \u003ca href=\"https://code.google.com/p/google-gson/\"\u003eGSON\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eGson是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库。可用于将Java对象转换成对应的JSON表示，也可以将JSON字符串转换成一个等效的Java对象。如果与API打交道的话，那么这将会是你经常需要的东西。我们主要使用JSON的原因就是，相较XML，轻量级的JSON要简单的多。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_js\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[js]** [view plain](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[copy](http://www.csdn.net/article/2014-06-16/2820224-top-5-android-libraries#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/394286)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/394286/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Serialize \u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;String userJSON = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Gson().toJson(user);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// Deserialize\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;User user = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Gson().fromJson(userJSON, User.\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003e2. \u003ca href=\"http://square.github.io/retrofit/\"\u003eRETROFIT\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e","title":"Android开发者必知的5个开源库"},{"content":"源地址：http://www.cnblogs.com/cuihongyu3503319/archive/2009/01/09/1372820.html\n[MVP模式与MVC模式(转)](http://www.cnblogs.com/cuihongyu3503319/archive/2009/01/09/1372820.html) MVP 是从经典的模式MVC演变而来，它们的基本思想有相通的地方：Controller/Presenter负责逻辑的处理，Model提供数据，View负责显示。作为一种新的模式，MVP与MVC有着一个重大的区别：在MVP中View并不直接使用Model，它们之间的通信是通过Presenter (MVC中的Controller)来进行的，所有的交互都发生在Presenter内部，而在MVC中View会从直接Model中读取数据而不是通过 Controller。Alex在他的blog中对于这两者之间的比较很直观也比较清楚，原文可以下面的地址找到：[http://ameleta.spaces.live.com/blog/cns!5F6316345A821420!163.entry](http://ameleta.spaces.live.com/blog/cns!5F6316345A821420!163.entry)【译文】： **Model View Presenter vs Model View Controller** **简介** 在我工作中经常需要处理一些由于开发人员没能很清楚地理解MVC和MVP模式的区别的情况下使用它们而产生的问题。在这篇文章中我将会阐述一下我对两者之间区别的一些理解。 在N层体系结构中MVC/P模式仅仅只是用于表示层(presentation layer)，理解这一点很重要。这两个模式并不是关于怎么构建数据层(data layer)和服务层(service layer)的，而是关于怎么将数据(data)从用户接口(view)中分离出来，以及用户接口如何与数据进行交互的。这些模式的使用让解除你的程序中表示层对对数据和控制逻辑的依赖，从而可以自由的变更表示层。 这两种模式的一般性概念\n1、模型(Model)表示数据模型和业务逻辑(business logic)。模型并不总是DataSet，DataTable之类的东西，它代表着一类组件(components)或类(class)，这些组件或类可以向外部提供数据，同时也能从外部获取数据并将这些数据存储在某个地方。简单的理解，可以把模型想象成“外观类(facade class)”。译注：这里的外观是指“外观模式”中所说的外观。外观的一般作用是为一个复杂的子系统提供高层次的简单易用的访问接口，可以参看下面的图来理解它的原理： ![](http://images.cnblogs.com/cnblogs_com/chen-cxb/1.jpg) 2、视图(View)将数据层现给用户。一般的视图都只是包含用户界面(UI)，而不包含界面逻辑。比如，Asp.net中包含控件的页面(page)就是一个视图。视图可以从模型中读取数据，但是不能修改或更新模型。 3、层现器(Presenter)/控制器(Controller)包含了根据用户在视图中的行为去更新模型的逻辑。视图仅仅只是将用户的行为告知控制器，而控制器负责从视图中取得数据然后发送给模型。\n**MVC/P模式的核心是为了将模型从视图/控制器中分离出来，从而使得模型独立于它们，因此模型不包含对视图和控制的引用。 什么是MVC(Model View Presenter)模式?**\n1、为了使得视图接口可以与模型和控制器进行交互，控制器执行一些初始化事件 2、用户通过视图（用户接口）执行一些操作 3、控制器处理用户行为(可以用观察着模式实现)并通知模型进行更新 4、模型引发一些事件，以便将改变发告知视图 5、视图处理模型变更的事件，然后显示新的模型数据 6、用户接口等待用户的进一步操作\n这一模式的有一下几个要点： 1、视图并不使用控制器去更新模型。控制器负责处理从视图发送过来的用户操作并通过与模型的交互进行数据的更新 2、控制器可以和视图融合在一块。Visual Studion中对Windows Forms的默认处理方式就是这样的。【译注：比如我们双击一个Button，然后在它的事件里写处理逻辑，然后将处理的数据写回模型中。这里处理逻辑时间应该是控制器的功能，但是我们并没有专门写一个控制器来做这件事情而是接受了VS的默认处理方式，将它写在Form的代码中，而这里的Form在MVC中它就是一个View。所以这说vs默认的处理方式是将把控制器和视图融合在一起的。】 3、控制器不包含对视图的渲染逻辑(rendering logic)\n**“主动—MVC”模式**，也是通常意义下的MVC模式 \u0026amp;nbsp; \u0026lt;div align=\u0026quot;center\u0026quot;\u0026gt; ![](http://images.cnblogs.com/cnblogs_com/chen-cxb/2.jpg) \u0026lt;/div\u0026gt; \u0026amp;nbsp; \u0026amp;nbsp; 【译注：为什么说是主动的？View不是等Controller通知它Model更新了然后才从Model取数据并更新显示，而是自己监视Model的更新(如果用观察者模式)或主动询问Model是否更新。前面那种等待Controller通知的方式是下面所介绍的“被动—MVC”的实现方式。】 **“被动—MVC”模式** 与主动MVC的区别在于： 1、模型对视图和控制器一无所知，它仅仅是被它们使用 2、控制器使用视图，并通知它更新数据显示 3、视图仅仅是在控制器通知它去模型取数据的时候它才这么做(视图并不会订阅或监视模型的更新) 4、控制器负责处理模型数据的变化 5、控制器可以包含对视图的渲染逻辑\n\u0026lt;div align=\u0026quot;center\u0026quot;\u0026gt; ![](http://images.cnblogs.com/cnblogs_com/chen-cxb/3.jpg) \u0026lt;/div\u0026gt; \u0026amp;nbsp; **MVP模式** 与“被动—MVC模式”很接近，区别在于“视图并不使用模型”。在MVP模式中视图和模型是完全分离的，他们通过Presenter进行交互。 Presenter与控制器非常相似，但是它们也有一些的区别： 1、Presenter处理视图发送过来的用户操作（在MVC中视图自己处理了这些操作） 2、它用更新过的数据去更新模型（在被动MVC中控制器只是通知视图去更新过的模型中去取新的数据，而主动MVC中模型通知视图去更新显示，控制器不需要做工作） 3、检查模型的更新（与被动MVC一样） 4、（与MVC的主要区别）从模型中取数据然后将它们发送到视图中 5、（与MVC的主要区别）将所做的更新告知视图 6、（与MVC的区别）用Presenter渲染视图\n\u0026lt;div align=\u0026quot;center\u0026quot;\u0026gt; ![](http://images.cnblogs.com/cnblogs_com/chen-cxb/4.jpg) \u0026lt;/div\u0026gt; \u0026amp;nbsp; **MVP的优势** 1、模型与视图完全分离，我们可以修改视图而不影响模型 2、可以更高效地使用模型，因为所以的交互都发生在一个地方——Presenter内部 3、我们可以将一个Presener用于多个视图，而不需要改变Presenter的逻辑。这个特性非常的有用，因为视图的变化总是比模型的变化频繁。 4、如果我们把逻辑放在Presenter中，那么我们就可以脱离用户接口来测试这些逻辑（单元测试）。 MVP的问题\n由于对视图的渲染放在了Presenter中，所以视图和Persenter的交互会过于频繁。 还有一点你需要明白，如果Presenter过多地渲染了视图，往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更，那么Presenter也需要变更了。比如说，原本用来呈现Html的Presenter现在也需要用于呈现Pdf了，那么视图很有可能也需要变更。 附:\n[http://www.microsoft.com/china/msdn/library/architecture/architecture/architecturetopic/MVP.mspx?mfr=true](http://www.microsoft.com/china/msdn/library/architecture/architecture/architecturetopic/MVP.mspx?mfr=true) [http://www.codeproject.com/useritems/ModelViewPresenter.asp](http://www.codeproject.com/useritems/ModelViewPresenter.asp) ","permalink":"https://blog.zdltech.com/posts/mvp%E6%A8%A1%E5%BC%8F%E4%B8%8Emvc%E6%A8%A1%E5%BC%8F/","summary":"\u003cp\u003e源地址：http://www.cnblogs.com/cuihongyu3503319/archive/2009/01/09/1372820.html\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv class=\"postTitle\" style=\"font-weight: bold;\"\u003e\n  [MVP模式与MVC模式(转)](http://www.cnblogs.com/cuihongyu3503319/archive/2009/01/09/1372820.html)\n\u003c/div\u003e\n\u003cdiv id=\"cnblogs_post_body\"\u003e\n  MVP 是从经典的模式MVC演变而来，它们的基本思想有相通的地方：Controller/Presenter负责逻辑的处理，Model提供数据，View负责显示。作为一种新的模式，MVP与MVC有着一个重大的区别：在MVP中View并不直接使用Model，它们之间的通信是通过Presenter (MVC中的Controller)来进行的，所有的交互都发生在Presenter内部，而在MVC中View会从直接Model中读取数据而不是通过 Controller。Alex在他的blog中对于这两者之间的比较很直观也比较清楚，原文可以下面的地址找到：[http://ameleta.spaces.live.com/blog/cns!5F6316345A821420!163.entry](http://ameleta.spaces.live.com/blog/cns!5F6316345A821420!163.entry)【译文】：\n **Model View Presenter vs Model View Controller**\n **简介**\n\u003cpre\u003e\u003ccode\u003e在我工作中经常需要处理一些由于开发人员没能很清楚地理解MVC和MVP模式的区别的情况下使用它们而产生的问题。在这篇文章中我将会阐述一下我对两者之间区别的一些理解。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在N层体系结构中MVC/P模式仅仅只是用于表示层(presentation layer)，理解这一点很重要。这两个模式并不是关于怎么构建数据层(data layer)和服务层(service layer)的，而是关于怎么将数据(data)从用户接口(view)中分离出来，以及用户接口如何与数据进行交互的。这些模式的使用让解除你的程序中表示层对对数据和控制逻辑的依赖，从而可以自由的变更表示层。\n\u003cstrong\u003e这两种模式的一般性概念\u003c/strong\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e1、模型(Model)表示数据模型和业务逻辑(business logic)。模型并不总是DataSet，DataTable之类的东西，它代表着一类组件(components)或类(class)，这些组件或类可以向外部提供数据，同时也能从外部获取数据并将这些数据存储在某个地方。简单的理解，可以把模型想象成“外观类(facade class)”。译注：这里的外观是指“外观模式”中所说的外观。外观的一般作用是为一个复杂的子系统提供高层次的简单易用的访问接口，可以参看下面的图来理解它的原理：\n\n\n\n\n\n![](http://images.cnblogs.com/cnblogs_com/chen-cxb/1.jpg)\n\n\n\n\n\n\n\n  2、视图(View)将数据层现给用户。一般的视图都只是包含用户界面(UI)，而不包含界面逻辑。比如，Asp.net中包含控件的页面(page)就是一个视图。视图可以从模型中读取数据，但是不能修改或更新模型。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e3、层现器(Presenter)/控制器(Controller)包含了根据用户在视图中的行为去更新模型的逻辑。视图仅仅只是将用户的行为告知控制器，而控制器负责从视图中取得数据然后发送给模型。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  **MVC/P模式的核心是为了将模型从视图/控制器中分离出来，从而使得模型独立于它们，因此模型不包含对视图和控制的引用。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e什么是MVC(Model View Presenter)模式?**\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  1、为了使得视图接口可以与模型和控制器进行交互，控制器执行一些初始化事件\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e2、用户通过视图（用户接口）执行一些操作\n3、控制器处理用户行为(可以用观察着模式实现)并通知模型进行更新\n4、模型引发一些事件，以便将改变发告知视图\n5、视图处理模型变更的事件，然后显示新的模型数据\n6、用户接口等待用户的进一步操作\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  这一模式的有一下几个要点：\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e1、视图并不使用控制器去更新模型。控制器负责处理从视图发送过来的用户操作并通过与模型的交互进行数据的更新\n2、控制器可以和视图融合在一块。Visual Studion中对Windows Forms的默认处理方式就是这样的。【译注：比如我们双击一个Button，然后在它的事件里写处理逻辑，然后将处理的数据写回模型中。这里处理逻辑时间应该是控制器的功能，但是我们并没有专门写一个控制器来做这件事情而是接受了VS的默认处理方式，将它写在Form的代码中，而这里的Form在MVC中它就是一个View。所以这说vs默认的处理方式是将把控制器和视图融合在一起的。】\n3、控制器不包含对视图的渲染逻辑(rendering logic)\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  **“主动—MVC”模式**，也是通常意义下的MVC模式\n\n\n\n\n\n  \u0026amp;nbsp;\n\n\n\n\u0026lt;div align=\u0026quot;center\u0026quot;\u0026gt;\n  ![](http://images.cnblogs.com/cnblogs_com/chen-cxb/2.jpg)\n\u0026lt;/div\u0026gt;\n\n\n\n  \u0026amp;nbsp;\n\n\n\n\n\n  \u0026amp;nbsp;\n\n\n\n\n\n  【译注：为什么说是主动的？View不是等Controller通知它Model更新了然后才从Model取数据并更新显示，而是自己监视Model的更新(如果用观察者模式)或主动询问Model是否更新。前面那种等待Controller通知的方式是下面所介绍的“被动—MVC”的实现方式。】\n\n\n\n\n\n  **“被动—MVC”模式**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e与主动MVC的区别在于：\n1、模型对视图和控制器一无所知，它仅仅是被它们使用\n2、控制器使用视图，并通知它更新数据显示\n3、视图仅仅是在控制器通知它去模型取数据的时候它才这么做(视图并不会订阅或监视模型的更新)\n4、控制器负责处理模型数据的变化\n5、控制器可以包含对视图的渲染逻辑\u003c/p\u003e","title":"MVP模式与MVC模式"},{"content":"Android上传附件方法，直接复制可以用\n// 附件上传\npublic static String post(String actionUrl, String fileName)\nthrows IOException {\n// 产生随机分割内容\nString BOUNDARY = java.util.UUID.randomUUID().toString();\nString MULTIPART_FROM_DATA = “multipart/from-data”;\nString CHARSET = “UTF-8”;\n// 定义URL实例\nURL uri = new URL(actionUrl);\n// 定义HttpURLConnection实例，打开连接\nHttpURLConnection conn = (HttpURLConnection) uri.openConnection();\n// 设置从主机读取数据超时（单位：毫秒）\nconn.setReadTimeout(5 * 1000);\n// 设置允许输入\nconn.setDoInput(true);\n// 设置允许输出\nconn.setDoOutput(true);\n// 设置不允许使用缓存\nconn.setUseCaches(false);\n// 设置为POST发送方法\nconn.setRequestMethod(“POST”);\n// 设置维持长连接\nconn.setRequestProperty(“connection”, “keep-alive”);\n// 设置文件字符集编码\nconn.setRequestProperty(“Charset”, “UTF-8”);\n// 设置文件类型\nconn.setRequestProperty(“Content-Type”, MULTIPART_FROM_DATA\n“;boundary=” + BOUNDARY);\n// 创建一个新的数据输出流，将数据写入指定基础输出流\nDataOutputStream outStream = new DataOutputStream(\nconn.getOutputStream());\n// 发送文件数据\nif (fileName != “”) {\n// 定义StringBuffer对象，构建发送字符串数据\nStringBuffer sb1 = new StringBuffer();\nsb1.append(PREFIX);\nsb1.append(BOUNDARY);\nsb1.append(LINEND);\nsb1.append(“Content-Disposition:from-data;name=\u0026amp;#8221;file1\u0026amp;#8221;;filename=\u0026amp;#8221;\u0026amp;#8221;” fileName + “\u0026amp;#8221;\u0026amp;#8221;” + LINEND);\nsb1.append(“Content-Type:application/octet-stream;charset=” CHARSET + LINEND);\nsb1.append(LINEND);\n// 写入输出流中\noutStream.write(sb1.toString().getBytes());\n// 将文件读到输入流中\nInputStream is = new FileInputStream(fileName);\nbyte[] buffer = new byte[1024];\nint len = 0;\n// 写入输出流中\nwhile ((len = is.read(buffer)) != -1) {\noutStream.write(buffer, 0, len);\n}\n// 关闭输入流\nis.close();\n// 添加换行标志\noutStream.write(LINEND.getBytes());\n}\n// 请求结束标志\nbyte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes();\noutStream.write(end_data);\n// 刷新，发送数据\noutStream.flush();\n// 得到响应码\nint res = conn.getResponseCode();\nInputStream in = null;\n// 上次成功则返回响应码200\nif (res == 200) {\n// 读取数据\nin = conn.getInputStream();\nint ch;\n// 定下StringBuilder字符串\nStringBuilder sb2 = new StringBuilder();\n// 保存数据\nwhile ((ch = in.read()) != -1) {\nsb2.append((char) ch);\n}\n}\n// 如果数据不为空，则以字符串方式返回数据，否则返回null\nreturn in == null ? null : in.toString();\n} ","permalink":"https://blog.zdltech.com/posts/android%E4%B8%8A%E4%BC%A0%E9%99%84%E4%BB%B6%E6%96%B9%E6%B3%95%E7%9B%B4%E6%8E%A5%E5%A4%8D%E5%88%B6%E5%8F%AF%E4%BB%A5%E7%94%A8/","summary":"\u003cp\u003eAndroid上传附件方法，直接复制可以用\u003c/p\u003e\n\u003cp\u003e \u003cbr\u003e\n// 附件上传\u003cbr\u003e\npublic static String post(String actionUrl, String fileName)\u003cbr\u003e\nthrows IOException {\u003cbr\u003e\n// 产生随机分割内容\u003cbr\u003e\nString BOUNDARY = java.util.UUID.randomUUID().toString();\u003cbr\u003e\nString MULTIPART_FROM_DATA = “multipart/from-data”;\u003cbr\u003e\nString CHARSET = “UTF-8”;\u003cbr\u003e\n// 定义URL实例\u003cbr\u003e\nURL uri = new URL(actionUrl);\u003cbr\u003e\n// 定义HttpURLConnection实例，打开连接\u003cbr\u003e\nHttpURLConnection conn = (HttpURLConnection) uri.openConnection();\u003cbr\u003e\n// 设置从主机读取数据超时（单位：毫秒）\u003cbr\u003e\nconn.setReadTimeout(5 * 1000);\u003cbr\u003e\n// 设置允许输入\u003cbr\u003e\nconn.setDoInput(true);\u003cbr\u003e\n// 设置允许输出\u003cbr\u003e\nconn.setDoOutput(true);\u003cbr\u003e\n// 设置不允许使用缓存\u003cbr\u003e\nconn.setUseCaches(false);\u003cbr\u003e\n// 设置为POST发送方法\u003cbr\u003e\nconn.setRequestMethod(“POST”);\u003cbr\u003e\n// 设置维持长连接\u003cbr\u003e\nconn.setRequestProperty(“connection”, “keep-alive”);\u003cbr\u003e\n// 设置文件字符集编码\u003cbr\u003e\nconn.setRequestProperty(“Charset”, “UTF-8”);\u003cbr\u003e\n// 设置文件类型\u003cbr\u003e\nconn.setRequestProperty(“Content-Type”, MULTIPART_FROM_DATA\u003c/p\u003e","title":"Android上传附件方法，直接复制可以用"},{"content":"C:\\Users\\Administrator\u0026gt;mvn install:install-file -DgroupId=com.bspatch -Dartifact\nId=libbspatch -Dversion=v3 -Dfile=D:/armeabi/libbspatch.so -Dpackaging=so -Dgene\nratePom=true -Dclassifier=armeabi\n[INFO] Scanning for projects…\n[INFO]\n[INFO] ————————————————————————\n[INFO] Building Maven Stub Project (No POM) 1\n[INFO] ————————————————————————\n[INFO]\n[INFO] — maven-install-plugin:2.3.1:install-file (default-cli) @ standalone-po\nm —\n[INFO] Installing D:\\armeabi\\libbspatch.so to D:\\apache-maven-3.0.5\\repositories\n.m\\com\\bspatch\\libbspatch\\v3\\libbspatch-v3-armeabi.so\n[INFO] Installing C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\mvninstall839685187217991\n3371.pom to D:\\apache-maven-3.0.5\\repositories.m\\com\\bspatch\\libbspatch\\v3\\libb\nspatch-v3.pom\n[INFO] ————————————————————————\n[INFO] BUILD SUCCESS\n[INFO] ————————————————————————\n[INFO] Total time: 1.349s\n[INFO] Finished at: Thu Jun 05 14:06:58 CST 2014\n[INFO] Final Memory: 2M/15M\n[INFO] ————————————————————————\nC:\\Users\\Administrator\u0026gt;mvn install:install-file -DgroupId=com.namecardrec -DartifactId=libnamecardrec -Dversion=v1 -Dfile=D:/armeabi/libnamecardrec.so -Dpackaging=so -DgeneratePom=true -Dclassifier=armeabi\n[INFO] Scanning for projects…\n[INFO]\n[INFO] ————————————————————————\n[INFO] Building Maven Stub Project (No POM) 1\n[INFO] ————————————————————————\n[INFO]\n[INFO] — maven-install-plugin:2.3.1:install-file (default-cli) @ standalone-po\nm —\n[INFO] Installing D:\\armeabi\\libnamecardrec.so to D:\\apache-maven-3.0.5\\reposito\nries.m\\com\\namecardrec\\libbspatch\\v3\\libbspatch-v3-armeabi.so\n[INFO] Installing C:\\Users\\ADMINI1\\AppData\\Local\\Temp\\mvninstall792194832235036\n6336.pom to D:\\apache-maven-3.0.5\\repositories.m\\com\\namecardrec\\libbspatch\\v3\\\nlibbspatch-v3.pom\n[INFO] ————————————————————————\n[INFO] BUILD SUCCESS\n[INFO] ————————————————————————\n[INFO] Total time: 0.313s\n[INFO] Finished at: Thu Jun 05 14:07:51 CST 2014\n[INFO] Final Memory: 2M/15M\n[INFO] ————————————————————————\nC:\\Users\\Administrator\u0026gt;mvn install:install-file -DgroupId=com.cserver.saas.andro\nid.oa.push.websocket -DartifactId=phonewebsocket -Dversion=v3 -Dfile=D:/phoneweb\nsocket.jar -Dpackaging=jar -DgeneratePom=true\n[INFO] Scanning for projects…\n[INFO]\n[INFO] ————————————————————————\n[INFO] Building Maven Stub Project (No POM) 1\n[INFO] ————————————————————————\n[INFO]\n[INFO] — maven-install-plugin:2.3.1:install-file (default-cli) @ standalone-po\nm —\n[INFO] Installing D:\\phonewebsocket.jar to D:\\apache-maven-3.0.5\\repositories.m\n\\com\\cserver\\saas\\android\\oa\\push\\websocket\\phonewebsocket\\v3\\phonewebsocket-v3.\njar\n[INFO] Installing C:\\Users\\ADMINI1\\AppData\\Local\\Temp\\mvninstall437255706491083\n9322.pom to D:\\apache-maven-3.0.5\\repositories.m\\com\\cserver\\saas\\android\\oa\\pu\nsh\\websocket\\phonewebsocket\\v3\\phonewebsocket-v3.pom\n[INFO] ————————————————————————\n[INFO] BUILD SUCCESS\n[INFO] ————————————————————————\n[INFO] Total time: 0.331s\n[INFO] Finished at: Thu Jun 05 14:11:27 CST 2014\n[INFO] Final Memory: 2M/15M\n[INFO] ————————————————————————\nC:\\Users\\Administrator\u0026gt;mvn install:install-file -DgroupId=com.umeng -DartifactId\n=umeng -Dversion=v3 -Dfile=D:/umeng_sdk.jar -Dpackaging=jar -DgeneratePom=true\n[INFO] Scanning for projects…\n[INFO]\n[INFO] ————————————————————————\n[INFO] Building Maven Stub Project (No POM) 1\n[INFO] ————————————————————————\n[INFO]\n[INFO] — maven-install-plugin:2.3.1:install-file (default-cli) @ standalone-po\nm —\n[INFO] Installing D:\\umeng_sdk.jar to D:\\apache-maven-3.0.5\\repositories.m\\com\\\numeng\\umeng\\v3\\umeng-v3.jar\n[INFO] Installing C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\mvninstall956278948317738\n37.pom to D:\\apache-maven-3.0.5\\repositories.m\\com\\umeng\\umeng\\v3\\umeng-v3.pom\n[INFO] ————————————————————————\n[INFO] BUILD SUCCESS\n[INFO] ————————————————————————\n[INFO] Total time: 0.307s\n[INFO] Finished at: Thu Jun 05 14:12:12 CST 2014\n[INFO] Final Memory: 2M/15M\n[INFO] ————————————————————————\n","permalink":"https://blog.zdltech.com/posts/maven%E5%AE%89%E8%A3%85%E7%AC%AC%E4%B8%89%E6%96%B9jar%E6%88%96%E8%80%85so%E6%96%87%E4%BB%B6/","summary":"\u003cp\u003eC:\\Users\\Administrator\u0026gt;mvn install:install-file -DgroupId=com.bspatch -Dartifact\u003cbr\u003e\nId=libbspatch -Dversion=v3 -Dfile=D:/armeabi/libbspatch.so -Dpackaging=so -Dgene\u003cbr\u003e\nratePom=true -Dclassifier=armeabi\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e[INFO] Scanning for projects…\u003cbr\u003e\n[INFO]\u003cbr\u003e\n[INFO] ————————————————————————\u003cbr\u003e\n[INFO] Building Maven Stub Project (No POM) 1\u003cbr\u003e\n[INFO] ————————————————————————\u003cbr\u003e\n[INFO]\u003cbr\u003e\n[INFO] — maven-install-plugin:2.3.1:install-file (default-cli) @ standalone-po\u003cbr\u003e\nm —\u003cbr\u003e\n[INFO] Installing D:\\armeabi\\libbspatch.so to D:\\apache-maven-3.0.5\\repositories\u003cbr\u003e\n.m\\com\\bspatch\\libbspatch\\v3\\libbspatch-v3-armeabi.so\u003cbr\u003e\n[INFO] Installing C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\mvninstall839685187217991\u003cbr\u003e\n3371.pom to D:\\apache-maven-3.0.5\\repositories.m\\com\\bspatch\\libbspatch\\v3\\libb\u003cbr\u003e\nspatch-v3.pom\u003cbr\u003e\n[INFO] ————————————————————————\u003cbr\u003e\n[INFO] BUILD SUCCESS\u003cbr\u003e\n[INFO] ————————————————————————\u003cbr\u003e\n[INFO] Total time: 1.349s\u003cbr\u003e\n[INFO] Finished at: Thu Jun 05 14:06:58 CST 2014\u003cbr\u003e\n[INFO] Final Memory: 2M/15M\u003cbr\u003e\n[INFO] ————————————————————————\u003c/p\u003e","title":"Maven安装第三方jar或者so文件"},{"content":"转载请注明出处：http://blog.csdn.net/xiaanming/article/details/12684155\n前段时间因为换工作的缘故又恰巧碰到国庆节，所以有段时间自己没有更新博客了，过完国庆到新公司报道，感觉还不错，就是现在住的地方离新公司有点远，地铁20站，伤不起啊，我每天早上7点多就要起床，然后屁颠屁颠的去挤地铁上班，晚上下班还要挤地铁，先不说路程远，车费一天就要10几块，我的银子啊，有坐龙华线去上班的深圳程序员不？听说那条线上班高峰期很挤？我没在上班高峰期坐过那趟车，我在民治那边找了个房子，离华强北也不远，关键房租便宜，哈哈，乐开花了，下个礼拜就要搬过去啦\n不扯了，回到主题，今天给大家带来ListView的A-Z字母排序和过滤搜索功能并且实现汉字转成拼音的功能，我们知道一般我们对联系人，城市列表等实现A-Z的排序，因为联系人和城市列表我们可以直接从数据库中获取他的汉字拼音，而对于一般的数据，我们怎么实现A-Z的排序，我们需要将汉字转换成拼音就行了，接下来就带大家实现一般数据的A-Z排序功能，首先先看下效果图\n上面是一个带删除按钮的EditText，我们在输入框中输入可以自动过滤出我们想要的东西，当输入框中没有数据自动替换到原来的数据列表，然后下面一个ListView用来显示数据列表，右侧是一个字母索引表，当我们点击不同的字母,ListView会定位到该字母地方，了解了布局之后，我们先看下项目结构吧 ![](http://img.blog.csdn.net/20131013204932718?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhYW5taW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 我按照项目中类的顺序来一一介绍其功能 1.SortModel 一个实体类，里面一个是ListView的name,另一个就是显示的name拼音的首字母 \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/12684155#)[copy](http://blog.csdn.net/xiaanming/article/details/12684155#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/111689)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/111689/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.sortlistview; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SortModel { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String name; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//显示的数据\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String sortLetters; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//显示数据拼音的首字母\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getName() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; name; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setName(String name) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.name = name; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getSortLetters() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; sortLetters; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setSortLetters(String sortLetters) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.sortLetters = sortLetters; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt; 2.SideBar类就是ListView右侧的字母索引View，我们需要使用setTextView(TextView mTextDialog)来设置用来显示当前按下的字母的TextView,以及使用setOnTouchingLetterChangedListener方法来设置回调接口，在回调方法onTouchingLetterChanged(String s)中来处理不同的操作\n\u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/12684155#)[copy](http://blog.csdn.net/xiaanming/article/details/12684155#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/111689)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/111689/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.sortlistview; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Canvas; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Color; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Paint; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.Typeface; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.graphics.drawable.ColorDrawable; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.util.AttributeSet; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.MotionEvent; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SideBar \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; View { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 触摸事件\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; OnTouchingLetterChangedListener onTouchingLetterChangedListener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 26个字母\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String[] b = { \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;A\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;B\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;C\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;D\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;E\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;F\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;G\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;H\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;I\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;J\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;K\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;L\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;M\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;N\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;O\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;P\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Q\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;R\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;S\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;T\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;U\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;V\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;W\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;X\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Y\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;Z\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt; }; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Paint paint = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView mTextDialog; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 为SideBar设置显示字母的TextView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @param mTextDialog\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setTextView(TextView mTextDialog) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mTextDialog = mTextDialog; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SideBar(Context context, AttributeSet attrs, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; defStyle) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs, defStyle); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SideBar(Context context, AttributeSet attrs) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context, attrs); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SideBar(Context context) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;(context); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 重写这个方法\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onDraw(Canvas canvas) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onDraw(canvas); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 获取焦点改变背景颜色.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; height = getHeight();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 获取对应高度\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; width = getWidth(); \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 获取对应宽度\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; singleHeight = height / b.length;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 获取每一个字母的高度\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; b.length; i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; paint.setColor(Color.rgb(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;33\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;65\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;98\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// paint.setColor(Color.WHITE);\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; paint.setTypeface(Typeface.DEFAULT_BOLD); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; paint.setAntiAlias(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; paint.setTextSize(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;20\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 选中的状态\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (i == choose) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; paint.setColor(Color.parseColor(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#3399ff\u0026amp;#8221;\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; paint.setFakeBoldText(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// x坐标等于中间-字符串宽度的一半.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; yPos = singleHeight * i + singleHeight; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; canvas.drawText(b[i], xPos, yPos, paint); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; paint.reset();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 重置画笔\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; dispatchTouchEvent(MotionEvent event) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; action = event.getAction(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;float\u0026lt;/span\u0026gt; y = event.getY();\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 点击y坐标\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; oldChoose = choose; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; c = (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt;) (y / getHeight() * b.length);\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;switch\u0026lt;/span\u0026gt; (action) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;case\u0026lt;/span\u0026gt; MotionEvent.ACTION_UP: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setBackgroundDrawable(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ColorDrawable(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;0x00000000\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; invalidate(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTextDialog != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mTextDialog.setVisibility(View.INVISIBLE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;default\u0026lt;/span\u0026gt;: \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setBackgroundResource(R.drawable.sidebar_background); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (oldChoose != c) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (c \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; c \u0026lt; b.length) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (listener != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; listener.onTouchingLetterChanged(b[c]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (mTextDialog != \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mTextDialog.setText(b[c]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mTextDialog.setVisibility(View.VISIBLE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; choose = c; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; invalidate(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;true\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 向外公开的方法\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @param onTouchingLetterChangedListener\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setOnTouchingLetterChangedListener( \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; OnTouchingLetterChangedListener onTouchingLetterChangedListener) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.onTouchingLetterChangedListener = onTouchingLetterChangedListener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 接口\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @author coder\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;interface\u0026lt;/span\u0026gt; OnTouchingLetterChangedListener { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTouchingLetterChanged(String s); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 3.CharacterParser 这个类是将汉字转换成拼音的类，该拼音没有声调的，该类是单例类，其中定义了三个方法，在这个demo中用到的是getSelling(String chs)方法，将词组转换成拼音 \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/12684155#)[copy](http://blog.csdn.net/xiaanming/article/details/12684155#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/111689)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/111689/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.sortlistview; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * Java汉字转换为拼音\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; CharacterParser { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; String[] pystr = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; String[] {\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;a\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;an\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ba\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;bai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ban\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;bang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;bao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;bei\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ben\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;beng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;bi\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;bian\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;biao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;bie\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;bin\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;bing\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;bo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;bu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ca\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;cai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;can\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;cang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;cao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ce\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ceng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;cha\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;che\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chen\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;cheng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chi\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chuai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chuan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chuang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chui\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;chuo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ci\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;cong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;cou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;cu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;cuan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;cui\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;cun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;cuo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;da\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;dai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;dan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;dang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;dao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;de\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;deng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;di\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;dian\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;diao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;die\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ding\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;diu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;dong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;dou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;du\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;duan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;dui\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;dun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;duo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;e\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;en\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;er\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fa\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fei\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fen\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;feng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;fu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ga\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;gai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;gan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;gang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;gao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ge\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;gei\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;gen\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;geng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;gong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;gou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;gu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;gua\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;guai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;guan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;guang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;gui\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;gun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;guo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ha\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;hai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;han\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;hang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;hao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;he\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;hei\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;hen\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;heng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;hong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;hou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;hu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;hua\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;huai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;huan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;huang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;hui\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;hun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;huo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ji\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jia\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jian\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jiang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jiao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jie\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jin\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jing\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jiong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jiu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ju\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;juan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jue\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;jun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ka\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;kai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;kan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;kang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;kao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ke\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ken\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;keng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;kong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;kou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ku\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;kua\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;kuai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;kuan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;kuang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;kui\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;kun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;kuo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;la\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;le\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lei\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;leng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;li\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lia\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lian\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;liang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;liao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lie\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lin\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ling\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;liu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;long\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lv\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;luan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lue\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;lun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;luo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ma\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;mai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;man\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;mang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;mao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;me\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;mei\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;men\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;meng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;mi\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;mian\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;miao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;mie\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;min\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ming\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;miu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;mo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;mou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;mu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;na\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ne\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nei\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nen\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;neng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ni\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nian\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;niang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;niao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nie\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nin\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ning\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;niu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nv\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nuan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nue\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;nuo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;o\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;pa\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;pai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;pan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;pang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;pao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;pei\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;pen\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;peng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;pi\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;pian\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;piao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;pie\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;pin\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ping\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;po\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;pu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;qi\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;qia\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;qian\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;qiang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;qiao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;qie\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;qin\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;qing\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;qiong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;qiu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;qu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;quan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;que\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;qun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ran\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;rang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;rao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;re\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ren\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;reng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ri\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;rong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;rou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ru\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ruan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;rui\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;run\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ruo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sa\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;san\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;se\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sen\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;seng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sha\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;she\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shen\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sheng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shi\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shua\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shuai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shuan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shuang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shui\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;shuo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;si\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;song\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;su\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;suan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sui\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;sun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;suo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ta\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;te\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;teng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ti\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tian\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tiao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tie\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ting\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tuan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tui\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tuo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wa\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wei\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wen\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;weng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;wu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xi\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xia\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xian\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xiang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xiao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xie\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xin\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xing\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xiong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xiu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xuan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xue\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;xun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ya\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;yan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;yang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;yao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ye\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;yi\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;yin\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ying\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;yo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;yong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;you\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;yu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;yuan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;yue\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;yun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;za\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ze\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zei\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zen\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zeng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zha\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhao\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhe\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhen\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zheng\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhi\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhua\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhuai\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhuan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhuang\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhui\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zhuo\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zi\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zong\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zou\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zu\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zuan\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zui\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zun\u0026amp;#8221;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;zuo\u0026amp;#8221;\u0026lt;/span\u0026gt;}; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; StringBuilder buffer; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String resource; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; CharacterParser characterParser = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; CharacterParser(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; CharacterParser getInstance() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; characterParser; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getResource() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; resource; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setResource(String resource) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.resource = resource; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/** * 汉字转成ASCII码 * * @param chs * @return */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getChsAscii(String chs) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; asc = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;byte\u0026lt;/span\u0026gt;[] bytes = chs.getBytes(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;gb2312\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (bytes == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt; || bytes.length \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt; || bytes.length \u0026lt;= \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;throw\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; RuntimeException(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;illegal resource string\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (bytes.length == \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; asc = bytes[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (bytes.length == \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; hightByte = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;256\u0026lt;/span\u0026gt; + bytes[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; lowByte = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;256\u0026lt;/span\u0026gt; + bytes[\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt; (Exception e) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;ERROR:ChineseSpelling.class-getChsAscii(String chs)\u0026amp;#8221;\u0026lt;/span\u0026gt; + e); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; asc; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/** * 单字解析 * * @param str * @return */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String convert(String str) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; String result = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; ascii = getChsAscii(str); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (ascii \u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; \u0026amp;\u0026amp; ascii \u0026lt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;160\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; result = String.valueOf((\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt;) ascii); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (pyvalue[i] \u0026lt;= ascii) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; result = pystr[i]; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;break\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; result; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/** * 词组解析 * * @param chs * @return */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getSelling(String chs) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; String key, value; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; buffer = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; StringBuilder(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; chs.length(); i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; key = chs.substring(i, i + \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (key.getBytes().length \u0026gt;= \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; value = (String) convert(key); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (value == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; value = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;unknown\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; value = key; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; buffer.append(value); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; buffer.toString(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getSpelling() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getSelling(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.getResource()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 4.ClearEditText类是自定义的一个在右侧有删除图片的EditText，当然你也可以用Android原生的EditText，该类我之前有介绍，我这里就不贴上代码了[Android 带清除功能的输入框控件ClearEditText,仿IOS的输入框](http://blog.csdn.net/xiaanming/article/details/11066685) 5.SortAdapter 数据的适配器类，该类需要实现SectionIndexer接口，该接口是用来控制ListView分组的，该接口有三个方法getSectionForPosition(int position)，getPositionForSection(int section)，getSections()，我们只需要自行实现前面两个方法 - getSectionForPosition(int position)是根据ListView的position来获取该位置上面的name的首字母char的ascii值，例如： 如果该position上面的name是阿妹，首字母就是A，那么此方法返回的就是\u0026amp;#8217;A\u0026amp;#8217;字母的ascii值，也就是65， \u0026amp;#8216;B\u0026amp;#8217;是66，依次类推 - getPositionForSection(int section)就是根据首字母的ascii值来获取在该ListView中第一次出现该首字母的位置，例如：从上面的效果图1中，如果section是66 ，也就是‘B’的ascii值，那么该方法返回的position就是2 然后就是getView()方法，首先我们根据ListView的position调用getSectionForPosition(int position)来获取该位置上面name的首字母的ascii值,然后根据这个ascii值调用getPositionForSection(int section)来获取第一次出现该首字母的position，如果ListView的position 等于 根据这个ascii值调用getPositionForSection(int section)来获取第一次出现该首字母的position，则显示分类字母 否则隐藏 \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/12684155#)[copy](http://blog.csdn.net/xiaanming/article/details/12684155#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/111689)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/111689/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.sortlistview; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.content.Context; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.LayoutInflater; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.ViewGroup; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.BaseAdapter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.SectionIndexer; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SortAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; BaseAdapter \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; SectionIndexer{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;SortModel\u0026gt; list = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Context mContext; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; SortAdapter(Context mContext, List\u0026lt;SortModel\u0026gt; list) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.mContext = mContext; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.list = list; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 当ListView数据发生变化时,调用此方法来更新ListView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @param list\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; updateListView(List\u0026lt;SortModel\u0026gt; list){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.list = list; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; notifyDataSetChanged(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getCount() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.list.size(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object getItem(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; list.get(position); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; getItemId(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; position; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; View getView(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, View view, ViewGroup arg2) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ViewHolder viewHolder = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; SortModel mContent = list.get(position); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (view == \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewHolder = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ViewHolder(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; view = LayoutInflater.from(mContext).inflate(R.layout.item, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewHolder.tvTitle = (TextView) view.findViewById(R.id.title); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewHolder.tvLetter = (TextView) view.findViewById(R.id.catalog); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; view.setTag(viewHolder); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewHolder = (ViewHolder) view.getTag(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//根据position获取分类的首字母的char ascii值\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; section = getSectionForPosition(position); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//如果当前位置等于该分类首字母的Char的位置 ，则认为是第一次出现\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(position == getPositionForSection(section)){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewHolder.tvLetter.setVisibility(View.VISIBLE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewHolder.tvLetter.setText(mContent.getSortLetters()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewHolder.tvLetter.setVisibility(View.GONE); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; viewHolder.tvTitle.setText(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.list.get(position).getName()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; view; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;final\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; ViewHolder { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; TextView tvLetter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; TextView tvTitle; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 根据ListView的当前位置获取分类的首字母的char ascii值\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getSectionForPosition(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; list.get(position).getSortLetters().charAt(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; getPositionForSection(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; section) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i = \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i \u0026lt; getCount(); i++) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; String sortStr = list.get(i).getSortLetters(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;char\u0026lt;/span\u0026gt; firstChar = sortStr.toUpperCase().charAt(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (firstChar == section) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; i; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; Object[] getSections() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; **\u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;6.MainActivity 这里面的代码比较简单，我们对ClearEditText设置addTextChangedListener监听，当输入框内容发生变化根据里面的值过滤ListView，里面的值为空显示原来的列表，里面对列表数据进行排序用到PinyinComparator接口，该接口主要是用来比较对象的\u0026lt;/span\u0026gt; \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; \u0026lt;b\u0026gt;[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/12684155#)[copy](http://blog.csdn.net/xiaanming/article/details/12684155#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/111689)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/111689/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.sortlistview; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.ArrayList; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Collections; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.List; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.app.Activity; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.os.Bundle; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.text.Editable; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.text.TextUtils; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.text.TextWatcher; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.view.View; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.AdapterView.OnItemClickListener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.ListView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.TextView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; android.widget.Toast; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; com.example.sortlistview.SideBar.OnTouchingLetterChangedListener; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; MainActivity \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;extends\u0026lt;/span\u0026gt; Activity { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ListView sortListView; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; SideBar sideBar; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 显示字母的TextView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; TextView dialog; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; SortAdapter adapter; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; ClearEditText mClearEditText; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 汉字转换成拼音的类\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; CharacterParser characterParser; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;SortModel\u0026gt; SourceDateList; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 根据拼音来排列ListView里面的数据类\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; PinyinComparator pinyinComparator; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;protected\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onCreate(Bundle savedInstanceState) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;super\u0026lt;/span\u0026gt;.onCreate(savedInstanceState); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; setContentView(R.layout.activity_main); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; initViews(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; initViews() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//实例化汉字转拼音类\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; characterParser = CharacterParser.getInstance(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; pinyinComparator = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; PinyinComparator(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; sideBar = (SideBar) findViewById(R.id.sidrbar); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; dialog = (TextView) findViewById(R.id.dialog); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; sideBar.setTextView(dialog); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//设置右侧触摸监听\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; sideBar.setOnTouchingLetterChangedListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnTouchingLetterChangedListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTouchingLetterChanged(String s) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//该字母首次出现的位置\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position = adapter.getPositionForSection(s.charAt(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; sortListView.setSelection(position); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; sortListView = (ListView) findViewById(R.id.country_lvcountry); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; sortListView.setOnItemClickListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; OnItemClickListener() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onItemClick(AdapterView\u0026lt;?\u0026gt; parent, View view, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; position, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; id) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//这里要利用adapter.getItem(position)来获取当前position所对应的对象\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Toast.makeText(getApplication(), ((SortModel)adapter.getItem(position)).getName(), Toast.LENGTH_SHORT).show(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; SourceDateList = filledData(getResources().getStringArray(R.array.date)); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 根据a-z进行排序源数据\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Collections.sort(SourceDateList, pinyinComparator); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; adapter = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SortAdapter(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;, SourceDateList); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; sortListView.setAdapter(adapter); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mClearEditText = (ClearEditText) findViewById(R.id.filter_edit); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//根据输入框输入值的改变来过滤搜索\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mClearEditText.addTextChangedListener(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TextWatcher() { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; onTextChanged(CharSequence s, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; start, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; before, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; count) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//当输入框里面的值为空，更新为原来的列表，否则为过滤数据列表\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; filterData(s.toString()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; beforeTextChanged(CharSequence s, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; start, \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; count, \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; after) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;annotation\u0026quot; style=\u0026quot;color: #646464;\u0026quot;\u0026gt;@Override\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; afterTextChanged(Editable s) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 为ListView填充数据\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @param date\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @return\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; List\u0026lt;SortModel\u0026gt; filledData(String [] date){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; List\u0026lt;SortModel\u0026gt; mSortList = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;SortModel\u0026gt;(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt;(\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; i=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;; i\u0026lt;date.length; i++){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; SortModel sortModel = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; SortModel(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; sortModel.setName(date[i]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//汉字转换成拼音\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; String pinyin = characterParser.getSelling(date[i]); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; String sortString = pinyin.substring(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;).toUpperCase(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 正则表达式，判断首字母是否是英文字母\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt;(sortString.matches(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;[A-Z]\u0026amp;#8221;\u0026lt;/span\u0026gt;)){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; sortModel.setSortLetters(sortString.toUpperCase()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; }\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; sortModel.setSortLetters(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; mSortList.add(sortModel); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; mSortList; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * 根据输入框中的值来过滤数据并更新ListView\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @param filterStr\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; filterData(String filterStr) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; List\u0026lt;SortModel\u0026gt; filterDateList = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ArrayList\u0026lt;SortModel\u0026gt;(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (TextUtils.isEmpty(filterStr)) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; filterDateList = SourceDateList; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; filterDateList.clear(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;for\u0026lt;/span\u0026gt; (SortModel sortModel : SourceDateList) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; String name = sortModel.getName(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (name.toUpperCase().indexOf( \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; || characterParser.getSelling(name).toUpperCase() \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .startsWith(filterStr.toString().toUpperCase())) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; filterDateList.add(sortModel); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;// 根据a-z进行排序\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Collections.sort(filterDateList, pinyinComparator); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; adapter.updateListView(filterDateList); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 7.PinyinComparator接口用来对ListView中的数据根据A-Z进行排序，前面两个if判断主要是将不是以汉字开头的数据放在后面 \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/12684155#)[copy](http://blog.csdn.net/xiaanming/article/details/12684155#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/111689)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/111689/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.sortlistview; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.util.Comparator; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * \u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; * @author xiaanming\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; *\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt; */\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; PinyinComparator \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;implements\u0026lt;/span\u0026gt; Comparator\u0026lt;SortModel\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;int\u0026lt;/span\u0026gt; compare(SortModel o1, SortModel o2) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//这里主要是用来对ListView里面的数据根据ABCDEFG\u0026amp;#8230;来排序\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (o2.getSortLetters().equals(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt;)) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;if\u0026lt;/span\u0026gt; (o1.getSortLetters().equals(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;#\u0026amp;#8221;\u0026lt;/span\u0026gt;)) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;1\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;else\u0026lt;/span\u0026gt; { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; o1.getSortLetters().compareTo(o2.getSortLetters()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; 这样我们以后使用A-Z排序就没要局限性了，想加这个效果随时都行，其他的布局和图片之类的文件就不贴出来了，如果大家有兴趣的自行去下载代码吧，如果大家有什么疑问，请在下面留言，我会为大家解答的！ [项目源码，点击下载](http://download.csdn.net/detail/xiaanming/6394377) github地址：https://github.com/xiaanming/A-Z-SortListView ","permalink":"https://blog.zdltech.com/posts/android-%E5%AE%9E%E7%8E%B0listview%E7%9A%84a-z%E5%AD%97%E6%AF%8D%E6%8E%92%E5%BA%8F%E5%92%8C%E8%BF%87%E6%BB%A4%E6%90%9C%E7%B4%A2%E5%8A%9F%E8%83%BD%E5%AE%9E%E7%8E%B0%E6%B1%89%E5%AD%97%E8%BD%AC/","summary":"\u003cp\u003e转载请注明出处：\u003ca href=\"http://blog.csdn.net/xiaanming/article/details/12684155\"\u003ehttp://blog.csdn.net/xiaanming/article/details/12684155\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e前段时间因为换工作的缘故又恰巧碰到国庆节，所以有段时间自己没有更新博客了，过完国庆到新公司报道，感觉还不错，就是现在住的地方离新公司有点远，地铁20站，伤不起啊，我每天早上7点多就要起床，然后屁颠屁颠的去挤地铁上班，晚上下班还要挤地铁，先不说路程远，车费一天就要10几块，我的银子啊，有坐龙华线去上班的深圳程序员不？听说那条线上班高峰期很挤？我没在上班高峰期坐过那趟车，我在民治那边找了个房子，离华强北也不远，关键房租便宜，哈哈，乐开花了，下个礼拜就要搬过去啦\u003c/p\u003e\n\u003cp\u003e不扯了，回到主题，今天给大家带来ListView的A-Z字母排序和过滤搜索功能并且实现汉字转成拼音的功能，我们知道一般我们对联系人，城市列表等实现A-Z的排序，因为联系人和城市列表我们可以直接从数据库中获取他的汉字拼音，而对于一般的数据，我们怎么实现A-Z的排序，我们需要将汉字转换成拼音就行了，接下来就带大家实现一般数据的A-Z排序功能，首先先看下效果图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20131013203823953?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhYW5taW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20131013203846640?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhYW5taW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20131013203930250?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhYW5taW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e上面是一个带删除按钮的EditText，我们在输入框中输入可以自动过滤出我们想要的东西，当输入框中没有数据自动替换到原来的数据列表，然后下面一个ListView用来显示数据列表，右侧是一个字母索引表，当我们点击不同的字母,ListView会定位到该字母地方，了解了布局之后，我们先看下项目结构吧\n\n\n\n\n\n![](http://img.blog.csdn.net/20131013204932718?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhYW5taW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)\n\n\n\n\n\n我按照项目中类的顺序来一一介绍其功能\n\n\n\n\n\n1.SortModel 一个实体类，里面一个是ListView的name,另一个就是显示的name拼音的首字母\n\n\n\n\n\n\u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot; style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\n  \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n    \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n      **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/12684155#)[copy](http://blog.csdn.net/xiaanming/article/details/12684155#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/111689)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/111689/fork)\n\n      \n      \u0026lt;div\u0026gt;\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; com.example.sortlistview;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; SortModel {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String name;   \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//显示的数据\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; String sortLetters;  \u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//显示数据拼音的首字母\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;      \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getName() {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; name;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setName(String name) {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.name = name;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; String getSortLetters() {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; sortLetters;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setSortLetters(String sortLetters) {  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;this\u0026lt;/span\u0026gt;.sortLetters = sortLetters;  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n    \n    - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n    \n  \n\u0026lt;/div\u0026gt;\n\n\n\n  \u0026lt;span style=\u0026quot;color: #000000;\u0026quot;\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e2.SideBar类就是ListView右侧的字母索引View，我们需要使用setTextView(TextView mTextDialog)来设置用来显示当前按下的字母的TextView,以及使用setOnTouchingLetterChangedListener方法来设置回调接口，在回调方法onTouchingLetterChanged(String s)中来处理不同的操作\u003c/span\u003e\u003c/p\u003e","title":"Android 实现ListView的A-Z字母排序和过滤搜索功能，实现汉字转成拼音"},{"content":"本文为那些不错的Android开源项目第四篇——开发工具篇，主要介绍Android开发工具和测试工具相关的开源项目。\n最新内容请访问[AndroidOpenProject@Github](https://github.com/Trinea/android-open-project)，欢迎Star和Fork。 Android开源项目系列汇总已完成，包括： [Android开源项目第一篇——个性化控件(View)篇](http://www.trinea.cn/android/android-open-source-projects-view/) Android开源项目第二篇——工具库篇 Android开源项目第三篇——优秀项目篇 Android开源项目第四篇——开发及测试工具篇 Android开源项目第五篇——优秀个人和团体篇\n**1、Buck** facebook开源的Android编译工具，效率是ant的两倍。主要优点在于： (1) 加快编译速度，通过并行利用多核cpu和跟踪不变资源减少增量编译时间实现 (2) 可以在编译系统中生成编译规则而无须另外的系统生成编译规则文件 (3) 编译同时可生成单元测试结果 (4) 既可用于IDE编译也可用于持续集成编译 (5) facebook持续优化中 项目地址：https://github.com/facebook/buck\n**2、Android Maven Plugin** Android Maven插件，可用于对android三方依赖进行管理。在J2EE开发中，maven是非常成熟的依赖库管理工具，可统一管理依赖库。 项目地址：https://github.com/jayway/maven-android-plugin\n**3、Spoon** 可用于android不同机型设备自动化测试，能将应用apk和测试apk运行在不同机器上并生成相应测试报告。 项目地址：https://github.com/square/spoon\n**4、Android FEST** 提供一些列方便的断言，可用于提高编写Android自测代码效率 项目地址：https://github.com/square/fest-android\n**5、SelectorChapek for Android** Android Studio插件，可根据固定文件名格式资源自动生成drawable selectors xml文件。 项目地址：https://github.com/inmite/android-selector-chapek\n**6、Android Resource Navigator** chrome插件，可以方便的查看github上android源码工程的styles.xml和themes.xml。主要功能： (1) 快速打开android styles.xml themes.xml (2) 方便在资源间跳转。styles.xml themes.xml文件中资源链接跳转，可以方便跳转到某个资源 (3) 方便查找某个style和theme。chrome地址栏输入arn+tab+搜索内容回车即可 (4) 自动下载不同分辨率下的drawable (5) 通过映射查找那些不是按照固定命名规则命名的style和theme 项目地址：https://github.com/jgilfelt/android-resource-navigator 示例：https://chrome.google.com/webstore/detail/android-resource-navigato/agoomkionjjbejegcejiefodgbckeebo?hl=en\u0026amp;gl=GB\n**7、Android Action Bar Style Generator** Android ActionBar样式生成器，可在线选择ActionBar样式自动生成所需要的图片资源及xml文件 项目地址：https://github.com/jgilfelt/android-actionbarstylegenerator 在线演示：http://jgilfelt.github.io/android-actionbarstylegenerator/\n**8、ViewServer** 允许app运行在任何手机上都可以用HierarchyViewer查看 项目地址：https://github.com/romainguy/ViewServer\n**9、GridWichterle for Android** 在整个系统上显示一个grid，用来帮助查看应用布局及使得布局更美观，可设置grid网格大小和颜色，android推荐48dp和8dp，可见 Android Design Guidelines – Metrics and Grids 项目地址：https://github.com/inmite/android-grid-wichterle APK地址：https://play.google.com/store/apps/details?id=eu.inmite.android.gridwichterle PS：比起hierarchyviewer相差甚远，不过偶尔可用来作为布局查看工具。\n**10、渠道打包工具** 允许app运行在任何手机上都可以用HierarchyViewer查看 项目地址：https://github.com/umeng/umeng-muti-channel-build-tool 另可参见Google的构建系统Gradle：http://tools.android.com/tech-docs/new-build-system/user-guide\n**11、Catlog** 手机端log查看工具，支持不同颜色显示、关键字过滤、级别过滤、进程id过滤、录制功能等 项目地址：https://github.com/nolanlawson/Catlog 在线演示：https://play.google.com/store/apps/details?id=com.nolanlawson.logcat\n**12、PID Cat** 根据package查看logcat日志 项目地址：https://github.com/JakeWharton/pidcat\n**13、Hugo** 用于打印函数信息及执行时间的工具，仅在debug模式生效 项目地址：https://github.com/JakeWharton/hugo\n\u0026amp;nbsp; ","permalink":"https://blog.zdltech.com/posts/android%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E7%AC%AC%E5%9B%9B%E7%AF%87-%E5%BC%80%E5%8F%91%E5%8F%8A%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E7%AF%87/","summary":"\u003cp\u003e本文为那些不错的Android开源项目第四篇——开发工具篇，\u003cstrong\u003e主要介绍Android开发工具和测试工具相关的开源项目\u003c/strong\u003e。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e最新内容请访问[AndroidOpenProject@Github](https://github.com/Trinea/android-open-project)，欢迎Star和Fork。\n\n\n\n\n\n\n\n  Android开源项目系列汇总已完成，包括：\n\n\n\n\n\n  [Android开源项目第一篇——个性化控件(View)篇](http://www.trinea.cn/android/android-open-source-projects-view/)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-dev-lib/\"\u003eAndroid开源项目第二篇——工具库篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-excellent-project/\"\u003eAndroid开源项目第三篇——优秀项目篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-dev-tool/\"\u003eAndroid开源项目第四篇——开发及测试工具篇\u003c/a\u003e\n\u003ca href=\"http://www.trinea.cn/android/android-open-source-projects-excellent-personal-group/\"\u003eAndroid开源项目第五篇——优秀个人和团体篇\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e    **1、Buck**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003efacebook开源的Android编译工具，效率是ant的两倍。主要优点在于：\n(1) 加快编译速度，通过并行利用多核cpu和跟踪不变资源减少增量编译时间实现\n(2) 可以在编译系统中生成编译规则而无须另外的系统生成编译规则文件\n(3) 编译同时可生成单元测试结果\n(4) 既可用于IDE编译也可用于持续集成编译\n(5) facebook持续优化中\n项目地址：\u003ca href=\"https://github.com/facebook/buck\"\u003ehttps://github.com/facebook/buck\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e      **2、Android Maven Plugin**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eAndroid Maven插件，可用于对android三方依赖进行管理。在J2EE开发中，maven是非常成熟的依赖库管理工具，可统一管理依赖库。\n项目地址：\u003ca href=\"https://github.com/jayway/maven-android-plugin\"\u003ehttps://github.com/jayway/maven-android-plugin\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e        **3、Spoon**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e可用于android不同机型设备自动化测试，能将应用apk和测试apk运行在不同机器上并生成相应测试报告。\n项目地址：\u003ca href=\"https://github.com/square/spoon\"\u003ehttps://github.com/square/spoon\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e          **4、Android FEST**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e提供一些列方便的断言，可用于提高编写Android自测代码效率\n项目地址：\u003ca href=\"https://github.com/square/fest-android\"\u003ehttps://github.com/square/fest-android\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e            **5、SelectorChapek for Android**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eAndroid Studio插件，可根据固定文件名格式资源自动生成drawable selectors xml文件。\n项目地址：\u003ca href=\"https://github.com/inmite/android-selector-chapek\"\u003ehttps://github.com/inmite/android-selector-chapek\u003c/a\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e              **6、Android Resource Navigator**\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003echrome插件，可以方便的查看github上android源码工程的styles.xml和themes.xml。主要功能：\n(1) 快速打开android styles.xml themes.xml\n(2) 方便在资源间跳转。styles.xml themes.xml文件中资源链接跳转，可以方便跳转到某个资源\n(3) 方便查找某个style和theme。chrome地址栏输入arn+tab+搜索内容回车即可\n(4) 自动下载不同分辨率下的drawable\n(5) 通过映射查找那些不是按照固定命名规则命名的style和theme\n项目地址：\u003ca href=\"https://github.com/jgilfelt/android-resource-navigator\"\u003ehttps://github.com/jgilfelt/android-resource-navigator\u003c/a\u003e\n示例：\u003ca href=\"https://chrome.google.com/webstore/detail/android-resource-navigato/agoomkionjjbejegcejiefodgbckeebo?hl=en\u0026amp;gl=GB\"\u003ehttps://chrome.google.com/webstore/detail/android-resource-navigato/agoomkionjjbejegcejiefodgbckeebo?hl=en\u0026amp;gl=GB\u003c/a\u003e\u003c/p\u003e","title":"Android开源项目第四篇——开发及测试工具篇"},{"content":"** 一、插件安装：**\n1、下载maven插件\n打开eclipse ,help-install new software\nadd\nname : m2e\nurl: http://download.eclipse.org/technology/m2e/releases/ (今天是2014-2-26，这个地址是有效的，以后不知道是否有效)\nname : m2e\nurl: http://rgladwell.github.com/m2e-android/updates (2014-4-16，这个地址是有效的，以后不知道是否有效)\n2、下载 maven-bin\n下载地址 http://download.csdn.net/download/cyw8998/6963959\n3、\n下载下来之后，解压，找个路径放进去， 把bin的位置，设在环境变量里\n新建环境变量MAVEN_HOME , PATH里配置解压后的bin路径\n检查一下 进入cmd，运行mvn -v，如果显示出版本号，说明配置成功了。\n4、\n为了使得Eclipse中安装的Maven插件，同windows中安装的那个相同，需要让eclipse中的maven重新定位一下\nWindow -\u0026gt; Preference -\u0026gt; Maven -\u0026gt; Installation -\u0026gt; Add\n现在就可以建立maven工程了。\n二、建立工程：\n**方法A:\n**\n1、打开eclipse,通过工具new project出现如下窗口：\n2、选中Maven Project, 点击Next,然后保持默认选项，再点击next，弹出如下窗口\n3、在过滤器中输入android，如果你已经有这样的插件，将会显示出来，否则就需要通过Add Archetype按钮进行添加\n4、\n3－1、因为我之前已经安装了这三个插件，因此输入过滤器后直接就有了，如果系统没有找到android-quickstart插件，则需点击Add Archetype，弹出如下窗口，然后将所需要的插件的groupid,artifactid及版本号输入进去，根据准备工作中提及，分别是：\nde.akquinet.android.archetypes\nandroid-quickstart\n1.0.6\n如下图所示：\n4、点击OK后，系统会去寻找相关的插件，然后选中此插件，再次点击Next,依次填入新工程的groupid, artifactid, package,如下图所示：\n方法B:\n建立一个android工程，之后鼠标右键点工程，选择configure——convert to maven project\n接下来问题一大堆，头疼，郁闷。一个一个解决吧。\n三、问题集合 pom.xml中 apk错误 Project build error: Unknown packaging: apk\n在Eclipse中安装[m2e-android][1]插件\n安装源:http://rgladwell.github.com/m2e-android/updates/ （2014-2-27这个安装源好使）\n安装方法:Help -\u0026gt; Install new Software -\u0026gt; 在出来的对话框中点击 Add -\u0026gt;\n把如下内容加到pom.xml里边\nsrc bin/classes org.apache.maven.plugins\nmaven-compiler-plugin\n3.1\n1.6\n1.6\ncom.jayway.maven.plugins.android.generation2\nandroid-maven-plugin\n3.7.0\n${project.basedir}/AndroidManifest.xml\n${project.basedir}/assets\n${project.basedir}/res\n${project.basedir}/src\n17\n${env.ANDROID_SDK_HOME}\nSnakeTest\ntrue\ntrue\nfalse\ntrue\ntrue\n2、之后发现有一个如下的错误：Project configuration is not up-to-date with pom.xml. Run project configuration update\n其实这个问题解决非常简单：在项目上右键——【Maven】——【Update Project Configuration……】这时会打开一个（Update Maven Dependencies）的对话框，然后勾选住出错的项目，点击Ok这样就搞定了。 ","permalink":"https://blog.zdltech.com/posts/eclipse-%E4%B8%AD%E5%AE%89%E8%A3%85-maven-%E6%8F%92%E4%BB%B6-%E5%BB%BA%E7%AB%8Bmaven%E5%B7%A5%E7%A8%8B/","summary":"\u003cp\u003e** 一、插件安装：**\u003c/p\u003e\n\u003cp\u003e1、下载maven插件\u003c/p\u003e\n\u003cp\u003e打开eclipse ,help-install new software\u003c/p\u003e\n\u003cp\u003eadd\u003c/p\u003e\n\u003cp\u003ename : m2e\u003c/p\u003e\n\u003cp\u003eurl:        \u003ca href=\"http://download.eclipse.org/technology/m2e/releases/\"\u003ehttp://download.eclipse.org/technology/m2e/releases/\u003c/a\u003e     (今天是2014-2-26，这个地址是有效的，以后不知道是否有效)\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003ename : m2e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://rgladwell.github.com/m2e-android/updates\"\u003eurl:   http://rgladwell.github.com/m2e-android/updates\u003c/a\u003e  (2014-4-16，这个地址是有效的，以后不知道是否有效)\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e2、下载 maven-bin\u003c/p\u003e\n\u003cp\u003e下载地址  \u003ca href=\"http://download.csdn.net/download/cyw8998/6963959\"\u003ehttp://download.csdn.net/download/cyw8998/6963959\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e3、\u003c/p\u003e\n\u003cp\u003e下载下来之后，解压，找个路径放进去， 把bin的位置，设在环境变量里\u003c/p\u003e\n\u003cp\u003e新建环境变量MAVEN_HOME , PATH里配置解压后的bin路径\u003c/p\u003e\n\u003cp\u003e检查一下 进入cmd，运行mvn -v，如果显示出版本号，说明配置成功了。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e4、\u003c/p\u003e\n\u003cp\u003e为了使得Eclipse中安装的Maven插件，同windows中安装的那个相同，需要让eclipse中的maven重新定位一下\u003c/p\u003e\n\u003cp\u003eWindow -\u0026gt; Preference -\u0026gt; Maven -\u0026gt; Installation -\u0026gt; Add\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140226142835000?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3l3ODk5OA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e现在就可以建立maven工程了。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e二、建立工程：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e**方法A:\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e1、打开eclipse,通过工具new  project出现如下窗口：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140226152357796\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e2、选中Maven Project, 点击Next,然后保持默认选项，再点击next，弹出如下窗口\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140226145813890?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3l3ODk5OA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e3、在过滤器中输入android，如果你已经有这样的插件，将会显示出来，否则就需要通过Add Archetype按钮进行添加\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140226152433484\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e4、\u003c/p\u003e\n\u003cp\u003e3－1、因为我之前已经安装了这三个插件，因此输入过滤器后直接就有了，如果系统没有找到android-quickstart插件，则需点击Add Archetype，弹出如下窗口，然后将所需要的插件的groupid,artifactid及版本号输入进去，根据准备工作中提及，分别是：\u003c/p\u003e\n\u003cp\u003ede.akquinet.android.archetypes\u003c/p\u003e\n\u003cp\u003eandroid-quickstart\u003c/p\u003e\n\u003cp\u003e1.0.6\u003c/p\u003e\n\u003cp\u003e如下图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140226152433484\"\u003e\u003c/p\u003e\n\u003cp\u003e4、点击OK后，系统会去寻找相关的插件，然后选中此插件，再次点击Next,依次填入新工程的groupid, artifactid, package,如下图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140226152455640\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e方法B:\u003c/strong\u003e\u003c/p\u003e","title":"eclipse 中安装 maven 插件 ，建立maven工程"},{"content":"之前一直在做WEB前端项目，前段时间接手第一个Android项目，拿到代码之后，先试着run起来再说，导入eclipse，一堆错误，设置classpath依赖，折腾半天，还是编译错误，于是联系项目接口人，得知他有一个Android库项目没有提交到SVN，晕。。。\n对于习惯使用Maven管理Java项目的我来说，自然想到能否用Maven构建Android项目呢？于是开始Google、百度，发现已经有前人做过这样的实践了，不过在使用过程中还是遇到不少问题，后面经过各种努力终于能比较顺地使用了，这篇文章对如何使用Maven构建Android项目作了简要总结。如果你和我一样饱受项目依赖管理的折磨，和我一样讨厌项目打包发布时的繁琐，希望能通过Maven让这一切自动化完成。那么，这篇文章或许对你有用。\n1. 环境搭建\n- **JDK与Android SDK安装 做Android开发，这里无需多说，但安装完成后需要正确设置JAVA_HOME、CLASSPATH、ANDROID_HOME等环境变量。其中ANDROID_HOME为Android SDK安装的根目录。并将%ANDROID_HOME%\\tools和%ANDROID_HOME%\\platform-tools值添加到Path变量中。\n- **Maven安装 这里无需多说，下载安装Maven并正确设置环境变量即可。\n- **IDE支持 - **Eclipse 大多数人都在使用Eclipse开发Android应用，如果你用Eclipse做Android开发，推荐下载eclipse-with-m2e-and-adt，该版本已经安装了ADT、m2e、m2e-android等重要插件，支持在Eclipse中使用Maven进行Android应用开发。当时为了安装这些插件费了好大劲，所以，如果你看到这里，可以直接下载它，不用像我一样去做那些没有意义又浪费时间的事情。\n- **IntelliJ IDEA 做Java开发，你不能不知道的神器，完美支持使用Maven构建Android应用，强烈推荐。即使是装了插件的Eclipse对使用Maven构建Android应用仍然支持不好。如果你是Eclipse的信徒，你也可以试试它，如果你能习惯它，你一定会被它的强大所吸引。\n- **NetBeans IDE NetBeans也支持Android开发，但没怎么了解，用的人应该也比较少。\n2. 项目构建\n以下是我的项目中使用的pom文件，因为涉及保密，部分地方做过修改，但整体结构没有改变，可以清楚地说明问题。\n\u003c?xml version=\u0026#8220;1.0\u0026#8221; encoding=\u0026#8220;UTF-8\u0026#8221;?\u003e xmlns=\u0026#8220;http://maven.apache.org/POM/4.0.0\u0026#8221; xmlns:xsi=\u0026#8220;http://www.w3.org/2001/XMLSchema-instance\u0026#8221; xsi:schemaLocation=\u0026#8220;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\u0026#8221;\u003e \u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt;\u0026lt;modelVersion\u0026lt;span class=\u0026quot;re2\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;4.0.0\u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt;\u0026lt;/modelVersion\u0026lt;span class=\u0026quot;re2\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;groupId\u0026gt;com.ikoding.android\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;android-app-quickstart\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;1.0.0\u0026lt;/version\u0026gt; apk\u0026lt;/packaging\u0026gt; \u0026lt;name\u0026gt;Android Application Quick Satrt\u0026lt;/name\u0026gt;\n\u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt;\u0026lt;dependencies\u0026lt;span class=\u0026quot;re2\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.google.android\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;android\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;4.1.1.4\u0026lt;/version\u0026gt; \u0026lt;scope\u0026gt;provided\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.google.android\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;support-v4\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;r7\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.apache.james\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;apache-mime4j\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;0.5\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.apache.httpcomponents\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;httpmime\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;4.2.2\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.ikoding.android\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;android-base\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.0.0\u0026lt;/version\u0026gt; \u0026lt;type\u0026gt;apklib\u0026lt;/type\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt;\n\u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt; \u0026lt;keystore.filename\u0026gt;app-quickstart.keystore\u0026lt;/keystore.filename\u0026gt; \u0026lt;keystore.storepass\u0026gt;2013@ikoding\u0026lt;/keystore.storepass\u0026gt; \u0026lt;keystore.keypass\u0026gt;2013@ikoding\u0026lt;/keystore.keypass\u0026gt; \u0026lt;keystore.alias\u0026gt;ikoding-android-app\u0026lt;/keystore.alias\u0026gt; UTF-8\u0026lt;/project.build.sourceEncoding\u0026gt; \u0026lt;/properties\u0026gt;\n\u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt;**\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;finalName\u0026gt;${project.artifactId}-${project.version}-${manifest.metadata.id}\u0026lt;/finalName\u0026gt; \u0026lt;sourceDirectory\u0026gt;src\u0026lt;/sourceDirectory\u0026gt; \u0026lt;resources\u0026gt; \u0026lt;resource\u0026gt; \u0026lt;directory\u0026gt;.\u0026lt;/directory\u0026gt; \u0026lt;filtering\u0026gt;true\u0026lt;/filtering\u0026gt; \u0026lt;targetPath\u0026gt;../filtered-resources\u0026lt;/targetPath\u0026gt; \u0026gt; \u0026lt;include\u0026gt;AndroidManifest.xml\u0026lt;/include\u0026gt; \u0026lt;/includes\u0026gt; \u0026lt;/resource\u0026gt; \u0026lt;resource\u0026gt; \u0026lt;directory\u0026gt;resources\u0026lt;/directory\u0026gt; \u0026lt;filtering\u0026gt;true\u0026lt;/filtering\u0026gt; \u0026lt;includes\u0026gt; \u0026lt;include\u0026gt;**/\u0026lt;/include\u0026gt; \u0026lt;/includes\u0026gt; \u0026lt;excludes\u0026gt; \u0026lt;exclude\u0026gt;**/env-*.properties\u0026lt;/exclude\u0026gt; \u0026lt;/excludes\u0026gt; \u0026lt;/resource\u0026gt; \u0026lt;/resources\u0026gt; \u0026lt;groupId\u0026gt;com.jayway.maven.plugins.android.generation2\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;android-maven-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;3.5.0\u0026lt;/version\u0026gt; \u0026lt;extensions\u0026gt;true\u0026lt;/extensions\u0026gt; \u0026lt;executions\u0026gt; \u0026lt;execution\u0026gt; \u0026lt;id\u0026gt;run\u0026lt;/id\u0026gt; \u0026lt;goals\u0026gt; \u0026lt;goal\u0026gt;deploy\u0026lt;/goal\u0026gt; \u0026lt;goal\u0026gt;run\u0026lt;/goal\u0026gt; \u0026lt;/goals\u0026gt; install\u0026lt;/phase\u0026gt; \u0026lt;/execution\u0026gt; \u0026lt;/executions\u0026gt; \u0026lt;configuration\u0026gt; proguard.cfg\u0026lt;/proguardConfig\u0026gt; ${project.build.proguardSkip}\u0026lt;/proguardSkip\u0026gt; \u0026lt;manifestDebuggable\u0026gt;${manifest.debuggable}\u0026lt;/manifestDebuggable\u0026gt; \u0026lt;androidManifestFile\u0026gt;target/filtered-resources/AndroidManifest.xml\u0026lt;/androidManifestFile\u0026gt; \u0026lt;release\u0026gt;${project.build.release}\u0026lt;/release\u0026gt; \u0026lt;run\u0026gt; \u0026lt;debug\u0026gt;${project.build.debug}\u0026lt;/debug\u0026gt; \u0026lt;/run\u0026gt; \u0026lt;runDebug\u0026gt;${project.build.runDebug}\u0026lt;/runDebug\u0026gt; \u0026lt;sign\u0026gt; \u0026lt;debug\u0026gt;${project.build.sign.debug}\u0026lt;/debug\u0026gt; \u0026lt;/sign\u0026gt; \u0026lt;/configuration\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;/plugins\u0026gt; \u0026lt;/pluginManagement\u0026gt; \u0026lt;groupId\u0026gt;com.jayway.maven.plugins.android.generation2\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;android-maven-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;configuration\u0026gt; \u0026lt;sdk\u0026gt; 15\u0026lt;/platform\u0026gt; \u0026lt;/sdk\u0026gt; \u0026lt;/configuration\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;groupId\u0026gt;org.codehaus.mojo\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;keytool-maven-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;1.2\u0026lt;/version\u0026gt; \u0026lt;!––\u0026gt; \u0026lt;!––\u0026gt; \u0026lt;!––\u0026gt; \u0026lt;!–clean–\u0026gt; \u0026lt;!–generateKeyPair–\u0026gt; \u0026lt;!––\u0026gt; \u0026lt;!– generate-resources–\u0026gt; \u0026lt;!––\u0026gt; \u0026lt;!––\u0026gt; \u0026lt;configuration\u0026gt; \u0026lt;keystore\u0026gt;${keystore.filename}\u0026lt;/keystore\u0026gt; \u0026lt;storepass\u0026gt;${keystore.storepass}\u0026lt;/storepass\u0026gt; \u0026lt;keypass\u0026gt;${keystore.keypass}\u0026lt;/keypass\u0026gt; \u0026lt;alias\u0026gt;${keystore.alias}\u0026lt;/alias\u0026gt; \u0026lt;dname\u0026gt;CN=iKoding, OU=iKoding, O=iKoding, C=CN\u0026lt;/dname\u0026gt; \u0026lt;sigalg\u0026gt;SHA1withDSA\u0026lt;/sigalg\u0026gt; \u0026lt;validity\u0026gt;10000\u0026lt;/validity\u0026gt; \u0026lt;keyalg\u0026gt;DSA\u0026lt;/keyalg\u0026gt; \u0026lt;keysize\u0026gt;1024\u0026lt;/keysize\u0026gt; \u0026lt;/configuration\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;groupId\u0026gt;org.apache.maven.plugins\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;maven-compiler-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;configuration\u0026gt; \u0026lt;source\u0026gt;1.6\u0026lt;/source\u0026gt; \u0026lt;target\u0026gt;1.6\u0026lt;/target\u0026gt; \u0026lt;encoding\u0026gt;UTF8\u0026lt;/encoding\u0026gt; \u0026lt;/configuration\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;groupId\u0026gt;org.apache.maven.plugins\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;maven-eclipse-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.9\u0026lt;/version\u0026gt; \u0026lt;configuration\u0026gt; org.eclipse.m2e.core.maven2Nature\u0026lt;/projectnature\u0026gt; com.android.ide.eclipse.adt.AndroidNature\u0026lt;/projectnature\u0026gt; org.eclipse.jdt.core.javanature\u0026lt;/projectnature\u0026gt; \u0026lt;/projectnatures\u0026gt; \u0026lt;/configuration\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;groupId\u0026gt;org.apache.maven.plugins\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;maven-resources-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.6\u0026lt;/version\u0026gt; \u0026lt;executions\u0026gt; \u0026lt;execution\u0026gt; initialize\u0026lt;/phase\u0026gt; \u0026lt;goals\u0026gt; \u0026lt;goal\u0026gt;resources\u0026lt;/goal\u0026gt; \u0026lt;/goals\u0026gt; \u0026lt;/execution\u0026gt; \u0026lt;/executions\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;/plugins\u0026gt; \u0026lt;/build\u0026gt;\n\u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt; \u0026lt;id\u0026gt;debug\u0026lt;/id\u0026gt; \u0026lt;activation\u0026gt; \u0026lt;activeByDefault\u0026gt;true\u0026lt;/activeByDefault\u0026gt; \u0026lt;/activation\u0026gt; \u0026lt;build\u0026gt; \u0026lt;filters\u0026gt; \u0026lt;filter\u0026gt;resources/env-debug.properties\u0026lt;/filter\u0026gt; \u0026lt;/filters\u0026gt; \u0026lt;/build\u0026gt; true\u0026lt;/project.build.debug\u0026gt; false\u0026lt;/project.build.runDebug\u0026gt; true\u0026lt;/project.build.proguardSkip\u0026gt; false\u0026lt;/project.build.release\u0026gt; true\u0026lt;/project.build.sign.debug\u0026gt; \u0026lt;manifest.debuggable\u0026gt;true\u0026lt;/manifest.debuggable\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;/profile\u0026gt; \u0026lt;id\u0026gt;release\u0026lt;/id\u0026gt; false\u0026lt;/project.build.debug\u0026gt; false\u0026lt;/project.build.runDebug\u0026gt; false\u0026lt;/project.build.proguardSkip\u0026gt; true\u0026lt;/project.build.release\u0026gt; false\u0026lt;/project.build.sign.debug\u0026gt; \u0026lt;manifest.debuggable\u0026gt;false\u0026lt;/manifest.debuggable\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;build\u0026gt; \u0026lt;filters\u0026gt; \u0026lt;filter\u0026gt;resources/env-release.properties\u0026lt;/filter\u0026gt; \u0026lt;/filters\u0026gt; \u0026lt;groupId\u0026gt;org.apache.maven.plugins\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;maven-jarsigner-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;1.2\u0026lt;/version\u0026gt; \u0026lt;executions\u0026gt; \u0026lt;execution\u0026gt; \u0026lt;id\u0026gt;sign\u0026lt;/id\u0026gt; \u0026lt;goals\u0026gt; \u0026lt;goal\u0026gt;sign\u0026lt;/goal\u0026gt; \u0026lt;/goals\u0026gt; package\u0026lt;/phase\u0026gt; \u0026lt;inherited\u0026gt;true\u0026lt;/inherited\u0026gt; \u0026lt;configuration\u0026gt; \u0026lt;includes\u0026gt; \u0026lt;include\u0026gt;${project.build.outputDirectory}/*.apk\u0026lt;/include\u0026gt; \u0026lt;/includes\u0026gt; \u0026lt;keystore\u0026gt;${keystore.filename}\u0026lt;/keystore\u0026gt; \u0026lt;storepass\u0026gt;${keystore.storepass}\u0026lt;/storepass\u0026gt; \u0026lt;keypass\u0026gt;${keystore.keypass}\u0026lt;/keypass\u0026gt; \u0026lt;alias\u0026gt;${keystore.alias}\u0026lt;/alias\u0026gt; \u0026lt;/configuration\u0026gt; \u0026lt;/execution\u0026gt; \u0026lt;/executions\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;/plugins\u0026gt; \u0026lt;/build\u0026gt; \u0026lt;/profile\u0026gt; \u0026lt;!– 渠道profiles –\u0026gt; \u0026lt;id\u0026gt;channel-test\u0026lt;/id\u0026gt; \u0026lt;activation\u0026gt; \u0026lt;activeByDefault\u0026gt;true\u0026lt;/activeByDefault\u0026gt; \u0026lt;/activation\u0026gt; \u0026lt;manifest.metadata.id\u0026gt;test\u0026lt;/manifest.metadata.id\u0026gt; \u0026lt;manifest.metadata.channel\u0026gt;test\u0026lt;/manifest.metadata.channel\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;/profile\u0026gt; \u0026lt;id\u0026gt;channel-91\u0026lt;/id\u0026gt; \u0026lt;manifest.metadata.id\u0026gt;91-market\u0026lt;/manifest.metadata.id\u0026gt; \u0026lt;manifest.metadata.channel\u0026gt;91 market\u0026lt;/manifest.metadata.channel\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;/profile\u0026gt; \u0026lt;id\u0026gt;channel-yingyonghui\u0026lt;/id\u0026gt; \u0026lt;manifest.metadata.id\u0026gt;yingyonghui-market\u0026lt;/manifest.metadata.id\u0026gt; \u0026lt;manifest.metadata.channel\u0026gt;yingyonghui market\u0026lt;/manifest.metadata.channel\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;/profile\u0026gt; \u0026lt;id\u0026gt;channel-tongbutui\u0026lt;/id\u0026gt; \u0026lt;manifest.metadata.id\u0026gt;tongbutui-market\u0026lt;/manifest.metadata.id\u0026gt; \u0026lt;manifest.metadata.channel\u0026gt;tongbutui market\u0026lt;/manifest.metadata.channel\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;/profile\u0026gt; \u0026lt;id\u0026gt;channel-tengxun\u0026lt;/id\u0026gt; \u0026lt;manifest.metadata.id\u0026gt;tengxun-market\u0026lt;/manifest.metadata.id\u0026gt; \u0026lt;manifest.metadata.channel\u0026gt;tengxun market\u0026lt;/manifest.metadata.channel\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;/profile\u0026gt; \u0026lt;id\u0026gt;channel-anzhi\u0026lt;/id\u0026gt; \u0026lt;manifest.metadata.id\u0026gt;anzhi-market\u0026lt;/manifest.metadata.id\u0026gt; \u0026lt;manifest.metadata.channel\u0026gt;anzhi market\u0026lt;/manifest.metadata.channel\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;/profile\u0026gt; \u0026lt;id\u0026gt;channel-gfan\u0026lt;/id\u0026gt; \u0026lt;manifest.metadata.id\u0026gt;gfan\u0026lt;/manifest.metadata.id\u0026gt; \u0026lt;manifest.metadata.channel\u0026gt;gfan\u0026lt;/manifest.metadata.channel\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;/profile\u0026gt; \u0026lt;/profiles\u0026gt; \u0026lt;/project\u0026gt; 以上的pom文件基本上涉及到了一个Android应用构建过程中的各个方面，以下针对其中比较重要的一些点作简要说明。 - \u0026lt;i\u0026gt;*依赖管理 这也是我们使用Maven构建Android项目的重要原因之一，值得注意的是以下部分： \u0026lt;div class=\u0026quot;codecolorer-container xml vibrant .codecolorer-container table td.line-numbers div {width:auto;}\u0026quot; style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;xml codecolorer\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt;\u0026lt;dependency\u0026lt;span class=\u0026quot;re2\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;groupId\u0026gt;com.ikoding.android\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;android-base\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.0.0\u0026lt;/version\u0026gt; \u0026lt;type\u0026gt;apklib\u0026lt;/type\u0026gt; \u0026lt;/dependency\u0026gt; 以上依赖的type为apklib，这就是我们项目中的Library Project，此外，我们还可以使用Maven管理Native库，亦即我们项目中所依赖的那些so库文件。 - **资源过滤 项目中总会有一些和环境相关的配置，比如线下测试环境和线上环境的配置可能不一样，为此我们在pom中分别定义了id为debug和release两个profile，并使用不同的filter进行资源过滤。 - **生成keystore 我们使用了keytool-maven-plugin来生成签名时所需的keystore文件，我在properties中定义了生成keystore文件所需的信息，如下所示： \u0026lt;div class=\u0026quot;codecolorer-container xml vibrant .codecolorer-container table td.line-numbers div {width:auto;}\u0026quot; style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;xml codecolorer\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt; \u0026lt;keystore.filename\u0026gt;app-quickstart.keystore\u0026lt;/keystore.filename\u0026gt; \u0026lt;keystore.storepass\u0026gt;2013@ikoding\u0026lt;/keystore.storepass\u0026gt; \u0026lt;keystore.keypass\u0026gt;2013@ikoding\u0026lt;/keystore.keypass\u0026gt; \u0026lt;keystore.alias\u0026gt;ikoding-android-app\u0026lt;/keystore.alias\u0026gt; \u0026lt;/properties\u0026gt; 可以运行mvn keytool:generateKeyPair命令来生成keystore文件，之后在应用正式打包发布时候就会使用该keystore文件进行签名。 - **生成渠道包 项目最终发布时需要根据渠道号生成不同的渠道包，我们可以利用Maven的资源过滤对AndroidManifest.xml文件中的渠道信息进行替换，例如我们上面的pom文件对Manifest文件中${manifest.metadata.channel}的渠道信息进行了替换，还有一些其他信息如Manifest文件的debuggable属性也可以针对不同配置进行替换，比如我们在日常开发中需要将该值设为true，而在项目正式发布时需要将该值设为false，我们以上的pom文件中就定义了多个针对不同渠道的profile。 - **代码混淆 项目正式发布时需要对代码进行混淆处理，我们只需在android-maven-plugin配置中指定proguardConfig文件，比如我们在上面的pom中指定proguard文件为proguard.cfg，项目构建过程中会自动运行代码混淆，并且可以通过proguardSkip属性指定是否运行代码混淆任务，这样我们就可以在日常开发调试过程中关闭混淆，而在项目发布时开启混淆。 - **签名 我们使用了maven-jarsigner-plugin对apk文件进行签名，签名使用的证书就是之前生成的keystore文件。 - **调试 我在使用Maven构建Android项目之初遇到的问题就是无法进行断点调试，这显然会降低开发效率，后来发现可以通过android-maven-plugin的runDebug属性开启调试，这样可以在应用程序启动时连接debugger进行调试。 - **IDE支持 再次回到这个话题上，在导入eclipse之前，你需要先运行mvn eclipse:eclipse命令，生成eclipse项目文件，因为eclipse对android-maven-plugin支持不好。 \u0026lt;strong\u0026gt;3. 常用命令** 以下是使用Maven构建Android项目中常用的一些命令，你可以根据需要选择合适的命令。 - **mvn clean package 打包，但不部署。 - **mvn clean install 打包，部署并运行。 - **mvn clean package android:redeploy android:run 这个命令通常用于手机上已经安装了要部署的应用，但签名不同，所以我们打包的同时使用redeploy命令将现有应用删除并重新部署，最后使用run命令运行应用。 - **mvn android:redeploy android:run 不打包，将已生成的包重新部署并运行。 - **mvn android:deploy android:run 部署并运行已生成的包，与redeploy不同的是，deploy不会删除已有部署和应用数据。 **4. 总结** 使用Maven构建Android应用很好地解决了依赖管理的问题，而且我们也可以将很多繁琐的任务自动化完成。在使用过程中主要的问题是Eclipse的m2e-android插件支持不够理想，而IntelliJ IDEA在这方便显得非常强大，让我得以将Maven和IDE的优势结合在一起。你可以在此基础上开发出一些常用类型项目的maven archetype，这样你就可以更快的开始一个新的项目。 **5. 坚持？改变？** 事实上我所在的团队成员最初都在使用Eclipse进行开发，后来在我的一再“忽悠”下，大家都接受了这种新的开发方式，并逐渐转向IntelliJ IDEA。这需要你有做出改变的勇气，毕竟改变是痛苦的，没有充分的理由就很难说服别人改变，但当你适应后就会有新的收获。 **附件** 下面是Android *Library* Project的pom文件，它比文中的Application Project的pom文件看起来要简单很多： \u0026lt;div class=\u0026quot;codecolorer-container xml vibrant .codecolorer-container table td.line-numbers div {width:auto;}\u0026quot; style=\u0026quot;color: #ffffff;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;xml codecolorer\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt;\u0026lt;?xml\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;re0\u0026quot; style=\u0026quot;color: #339999;\u0026quot;\u0026gt;version\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;st0\u0026quot; style=\u0026quot;color: #66ff00;\u0026quot;\u0026gt;\u0026amp;#8220;1.0\u0026amp;#8221;\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;re0\u0026quot; style=\u0026quot;color: #339999;\u0026quot;\u0026gt;encoding\u0026lt;/span\u0026gt;=\u0026lt;span class=\u0026quot;st0\u0026quot; style=\u0026quot;color: #66ff00;\u0026quot;\u0026gt;\u0026amp;#8220;UTF-8\u0026amp;#8221;\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026quot;re2\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; xmlns=“http://maven.apache.org/POM/4.0.0” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\u0026amp;#8221;\u0026gt; \u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt; \u0026lt;groupId\u0026gt;com.ikoding.android\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;android-lib-quickstart\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;1.0.0\u0026lt;/version\u0026gt; apklib\u0026lt;/packaging\u0026gt; \u0026lt;name\u0026gt;Android Library Project Quick Start\u0026lt;/name\u0026gt;\n\u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt;\u0026lt;dependencies\u0026lt;span class=\u0026quot;re2\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.google.android\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;android\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;4.1.1.4\u0026lt;/version\u0026gt; \u0026lt;scope\u0026gt;provided\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt;\n\u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt; UTF-8\u0026lt;/project.build.sourceEncoding\u0026gt; \u0026lt;/properties\u0026gt;\n\u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt;\u0026lt;build\u0026lt;span class=\u0026quot;re2\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;sourceDirectory\u0026gt;src\u0026lt;/sourceDirectory\u0026gt; \u0026lt;groupId\u0026gt;com.jayway.maven.plugins.android.generation2\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;android-maven-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;3.5.0\u0026lt;/version\u0026gt; \u0026lt;extensions\u0026gt;true\u0026lt;/extensions\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;/plugins\u0026gt; \u0026lt;/pluginManagement\u0026gt; \u0026lt;groupId\u0026gt;com.jayway.maven.plugins.android.generation2\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;android-maven-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;configuration\u0026gt; \u0026lt;sdk\u0026gt; 15\u0026lt;/platform\u0026gt; \u0026lt;/sdk\u0026gt; \u0026lt;/configuration\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;groupId\u0026gt;org.apache.maven.plugins\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;maven-compiler-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;configuration\u0026gt; \u0026lt;source\u0026gt;1.6\u0026lt;/source\u0026gt; \u0026lt;target\u0026gt;1.6\u0026lt;/target\u0026gt; \u0026lt;encoding\u0026gt;UTF-8\u0026lt;/encoding\u0026gt; \u0026lt;/configuration\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;groupId\u0026gt;org.apache.maven.plugins\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;maven-source-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;executions\u0026gt; \u0026lt;execution\u0026gt; \u0026lt;goals\u0026gt; \u0026lt;goal\u0026gt;jar\u0026lt;/goal\u0026gt; \u0026lt;/goals\u0026gt; \u0026lt;/execution\u0026gt; \u0026lt;/executions\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;groupId\u0026gt;org.apache.maven.plugins\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;maven-javadoc-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;executions\u0026gt; \u0026lt;execution\u0026gt; \u0026lt;goals\u0026gt; \u0026lt;goal\u0026gt;jar\u0026lt;/goal\u0026gt; \u0026lt;/goals\u0026gt; \u0026lt;/execution\u0026gt; \u0026lt;/executions\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;groupId\u0026gt;org.apache.maven.plugins\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;maven-eclipse-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.9\u0026lt;/version\u0026gt; \u0026lt;configuration\u0026gt; org.eclipse.m2e.core.maven2Nature\u0026lt;/projectnature\u0026gt; com.android.ide.eclipse.adt.AndroidNature\u0026lt;/projectnature\u0026gt; org.eclipse.jdt.core.javanature\u0026lt;/projectnature\u0026gt; \u0026lt;/projectnatures\u0026gt; \u0026lt;/configuration\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;/plugins\u0026gt; \u0026lt;/build\u0026gt; \u0026lt;/project\u0026gt; ","permalink":"https://blog.zdltech.com/posts/%E4%BD%BF%E7%94%A8maven%E6%9E%84%E5%BB%BAandroid%E9%A1%B9%E7%9B%AE/","summary":"\u003cp\u003e之前一直在做WEB前端项目，前段时间接手第一个Android项目，拿到代码之后，先试着run起来再说，导入eclipse，一堆错误，设置classpath依赖，折腾半天，还是编译错误，于是联系项目接口人，得知他有一个Android库项目没有提交到SVN，晕。。。\u003c/p\u003e\n\u003cp\u003e对于习惯使用Maven管理Java项目的我来说，自然想到能否用Maven构建Android项目呢？于是开始Google、百度，发现已经有前人做过这样的实践了，不过在使用过程中还是遇到不少问题，后面经过各种努力终于能比较顺地使用了，这篇文章对如何使用Maven构建Android项目作了简要总结。如果你和我一样饱受项目依赖管理的折磨，和我一样讨厌项目打包发布时的繁琐，希望能通过Maven让这一切自动化完成。那么，这篇文章或许对你有用。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. 环境搭建\u003c/strong\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e- **JDK与Android SDK安装\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e做Android开发，这里无需多说，但安装完成后需要正确设置JAVA_HOME、CLASSPATH、ANDROID_HOME等环境变量。其中ANDROID_HOME为Android SDK安装的根目录。并将%ANDROID_HOME%\\tools和%ANDROID_HOME%\\platform-tools值添加到Path变量中。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e- **Maven安装\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这里无需多说，下载安装Maven并正确设置环境变量即可。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e- **IDE支持 \n    - **Eclipse\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e大多数人都在使用Eclipse开发Android应用，如果你用Eclipse做Android开发，推荐下载\u003ca href=\"http://pan.baidu.com/share/link?shareid=338412\u0026amp;uk=2081314170\"\u003eeclipse-with-m2e-and-adt\u003c/a\u003e，该版本已经安装了ADT、m2e、m2e-android等重要插件，支持在Eclipse中使用Maven进行Android应用开发。当时为了安装这些插件费了好大劲，所以，如果你看到这里，可以直接下载它，不用像我一样去做那些没有意义又浪费时间的事情。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  - **IntelliJ IDEA\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e做Java开发，你不能不知道的神器，完美支持使用Maven构建Android应用，强烈推荐。即使是装了插件的Eclipse对使用Maven构建Android应用仍然支持不好。如果你是Eclipse的信徒，你也可以试试它，如果你能习惯它，你一定会被它的强大所吸引。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  - **NetBeans IDE\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eNetBeans也支持Android开发，但没怎么了解，用的人应该也比较少。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. 项目构建\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e以下是我的项目中使用的pom文件，因为涉及保密，部分地方做过修改，但整体结构没有改变，可以清楚地说明问题。\u003c/p\u003e\n\u003cdiv class=\"codecolorer-container xml vibrant .codecolorer-container table td.line-numbers div {width:auto;}\" style=\"color: #ffffff;\"\u003e\n  \u003cdiv class=\"xml codecolorer\"\u003e\n    \u003cspan class=\"sc3\"\u003e\u003cspan class=\"re1\" style=\"color: #ffcc00;\"\u003e\u003c?xml\u003c/span\u003e \u003cspan class=\"re0\" style=\"color: #339999;\"\u003eversion\u003c/span\u003e=\u003cspan class=\"st0\" style=\"color: #66ff00;\"\u003e\u0026#8220;1.0\u0026#8221;\u003c/span\u003e \u003cspan class=\"re0\" style=\"color: #339999;\"\u003eencoding\u003c/span\u003e=\u003cspan class=\"st0\" style=\"color: #66ff00;\"\u003e\u0026#8220;UTF-8\u0026#8221;\u003c/span\u003e\u003cspan class=\"re2\" style=\"color: #ffcc00;\"\u003e?\u003e\u003c/span\u003e\u003c/span\u003e\n \u003cspan class=\"sc3\"\u003e\u003cspan class=\"re1\" style=\"color: #ffcc00;\"\u003e\n \u003c/span\u003e\n \u003cspan class=\"sc3\"\u003e   \u003cspan class=\"re0\" style=\"color: #339999;\"\u003exmlns\u003c/span\u003e=\u003cspan class=\"st0\" style=\"color: #66ff00;\"\u003e\u0026#8220;http://maven.apache.org/POM/4.0.0\u0026#8221;\u003c/span\u003e \u003c/span\u003e\n \u003cspan class=\"sc3\"\u003e   \u003cspan class=\"re0\" style=\"color: #339999;\"\u003exmlns:xsi\u003c/span\u003e=\u003cspan class=\"st0\" style=\"color: #66ff00;\"\u003e\u0026#8220;http://www.w3.org/2001/XMLSchema-instance\u0026#8221;\u003c/span\u003e\u003c/span\u003e\n \u003cspan class=\"sc3\"\u003e   \u003cspan class=\"re0\" style=\"color: #339999;\"\u003exsi:schemaLocation\u003c/span\u003e=\u003cspan class=\"st0\" style=\"color: #66ff00;\"\u003e\u0026#8220;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\u0026#8221;\u003c/span\u003e\u003cspan class=\"re2\" style=\"color: #ffcc00;\"\u003e\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt;\u0026lt;modelVersion\u0026lt;span class=\u0026quot;re2\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;4.0.0\u0026lt;span class=\u0026quot;sc3\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;re1\u0026quot; style=\u0026quot;color: #ffcc00;\u0026quot;\u0026gt;\u0026lt;/modelVersion\u0026lt;span class=\u0026quot;re2\u0026quot;\u0026gt;\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cspan class=\"sc3\"\u003e\u003cspan class=\"re1\" style=\"color: #ffcc00;\"\u003e\u0026lt;groupId\u003cspan class=\"re2\"\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003ecom.ikoding.android\u003cspan class=\"sc3\"\u003e\u003cspan class=\"re1\" style=\"color: #ffcc00;\"\u003e\u0026lt;/groupId\u003cspan class=\"re2\"\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"sc3\"\u003e\u003cspan class=\"re1\" style=\"color: #ffcc00;\"\u003e\u0026lt;artifactId\u003cspan class=\"re2\"\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003eandroid-app-quickstart\u003cspan class=\"sc3\"\u003e\u003cspan class=\"re1\" style=\"color: #ffcc00;\"\u003e\u0026lt;/artifactId\u003cspan class=\"re2\"\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"sc3\"\u003e\u003cspan class=\"re1\" style=\"color: #ffcc00;\"\u003e\u0026lt;version\u003cspan class=\"re2\"\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e1.0.0\u003cspan class=\"sc3\"\u003e\u003cspan class=\"re1\" style=\"color: #ffcc00;\"\u003e\u0026lt;/version\u003cspan class=\"re2\"\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"sc3\"\u003e\u003cspan class=\"re1\" style=\"color: #ffcc00;\"\u003e\u003c/p\u003e","title":"使用Maven构建Android项目"},{"content":"public boolean isServiceRun(Context context){ ActivityManager am = (ActivityManager)context.getSystemService(context.ACTIVITY_SERVICE); List list = am.getRunningServices(30); for(RunningServiceInfo info : list){ if(info.service.getClassName.equals(“service的全称（一般为包名+service类的名称）”)){ return true; } } return false;}\n","permalink":"https://blog.zdltech.com/posts/android%E5%88%A4%E6%96%AD%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%9A%84%E6%9C%8D%E5%8A%A1/","summary":"\u003cp\u003e\u003cspan style=\"color: #bcbcbc;\"\u003epublic boolean isServiceRun(Context context){\u003c/span\u003e\u003cbr style=\"color: #bcbcbc;\" /\u003e\u003cspan style=\"color: #bcbcbc;\"\u003e     ActivityManager am = (ActivityManager)context.getSystemService(context.ACTIVITY_SERVICE);\u003c/span\u003e\u003cbr style=\"color: #bcbcbc;\" /\u003e\u003cspan style=\"color: #bcbcbc;\"\u003e     List\u003cRunningServiceInfo\u003e list = am.getRunningServices(30);\u003c/span\u003e\u003cbr style=\"color: #bcbcbc;\" /\u003e\u003cspan style=\"color: #bcbcbc;\"\u003e     for(RunningServiceInfo info : list){\u003c/span\u003e\u003cbr style=\"color: #bcbcbc;\" /\u003e\u003cspan style=\"color: #bcbcbc;\"\u003e         if(info.service.getClassName.equals(“service的全称（一般为包名+service类的名称）”)){\u003c/span\u003e\u003cbr style=\"color: #bcbcbc;\" /\u003e\u003cspan style=\"color: #bcbcbc;\"\u003e                  return true;\u003c/span\u003e\u003cbr style=\"color: #bcbcbc;\" /\u003e\u003cspan style=\"color: #bcbcbc;\"\u003e         }\u003c/span\u003e\u003cbr style=\"color: #bcbcbc;\" /\u003e\u003cspan style=\"color: #bcbcbc;\"\u003e    }\u003c/span\u003e\u003cbr style=\"color: #bcbcbc;\" /\u003e\u003cspan style=\"color: #bcbcbc;\"\u003e    return false;\u003c/span\u003e\u003cbr style=\"color: #bcbcbc;\" /\u003e\u003cspan style=\"color: #bcbcbc;\"\u003e}\u003c/span\u003e\u003c/p\u003e","title":"Android判断正在运行的服务"},{"content":"我在想在wordpress中如何写一个api接口，请求这个网址，可以获取最新文章列表，一般通常的做法是新建一个php文件，接收几个参数，查询数据库，用json格式返回数据就行了，当然wordpress也可以这样弄，wordpress插件很强大，有没有这样的插件呢，上网找了一下，果然有。\n一款叫JSON API的wordpress插件正是我要的功能，并且更全面，它可以返回最新文章，类别，作者，文章详情，就是在wordpress中几乎所有的内容都可以通过它来获取json格式的数据，它甚至可以通过传递json数据实现文章评论、用户注册。\n有了这样一款插件，关键是有了这样一个api接口，可以不用费劲自己写api了，但是可以用来做什么呢？\n比如我想做个微信公共帐号，用户输入1，返回最新文章列表，根据用户输入返回不同的内容，这就要请求api地址返回json格式的数据。\n插件安装地址：http://wordpress.org/plugins/json-api/\n安装好后，使用方法如下（本文只介绍几个常见的，其他的请参加文档）：\n隐式调用: http://www.example.org/?json=1（返回该站全部json格式数据） http://www.example.org/?p=47\u0026amp;json=1（返回文章id为47的json数据） http://www.example.org/tag/banana/?json=1（返回标签是banana的json数据） 显示调用: http://www.example.org/?json=get_recent_posts（返回最新文章json数据，默认返回很多字段，可以指定） http://www.example.org/?json=get_post\u0026amp;post_id=47（返回id为47的文章json数据） http://www.example.org/?json=get_tag_posts\u0026amp;tag_slug=banana（返回tag标签是banana的json数据） 链接友好型调用: http://www.example.org/api/get_recent_posts/ http://www.example.org/api/get_post/?post_id=47 http://www.example.org/api/get_tag_posts/?tag_slug=banana API返回的json数据如下：\n可以看到，返回的内容太多了，也许我们只要最新列表中的标题和链接就够了。\nhttp://www.example.org/api/get_recent_posts/?callback=show_posts_widget\u0026amp;read_more=More\u0026amp;count=3\n有很多参数可以选，比如count为返回的文章数目，参考官方文档吧。\n（本文为小谈博客原创，转载请注明出处！）\n本文链接：http://www.tantengvip.com/2013/12/wordpress-api/\n","permalink":"https://blog.zdltech.com/posts/wordpress%E5%81%9Aapi%E6%8E%A5%E5%8F%A3/","summary":"\u003cp\u003e我在想在wordpress中如何写一个api接口，请求这个网址，可以获取最新文章列表，一般通常的做法是新建一个php文件，接收几个参数，查询数据库，用json格式返回数据就行了，当然wordpress也可以这样弄，wordpress插件很强大，有没有这样的插件呢，上网找了一下，果然有。\u003c/p\u003e\n\u003cp\u003e一款叫JSON API的wordpress插件正是我要的功能，并且更全面，它可以返回最新文章，类别，作者，文章详情，就是在wordpress中几乎所有的内容都可以通过它来获取json格式的数据，它甚至可以通过传递json数据实现文章评论、用户注册。\u003c/p\u003e\n\u003cp\u003e\u003cspan id=\"more-5435\"\u003e\u003c/span\u003e\u003cbr\u003e\n有了这样一款插件，关键是有了这样一个api接口，可以不用费劲自己写api了，但是可以用来做什么呢？\u003c/p\u003e\n\u003cp\u003e比如我想做个微信公共帐号，用户输入1，返回最新文章列表，根据用户输入返回不同的内容，这就要请求api地址返回json格式的数据。\u003c/p\u003e\n\u003cp\u003e插件安装地址：\u003ca href=\"http://wordpress.org/plugins/json-api/\"\u003ehttp://wordpress.org/plugins/json-api/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e安装好后，使用方法如下（本文只介绍几个常见的，其他的请参加文档）：\u003c/p\u003e\n\u003ch4 id=\"隐式调用\"\u003e隐式调用:\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.example.org/?json=1\"\u003ehttp://www.example.org/?json=1\u003c/a\u003e（返回该站全部json格式数据）\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.example.org/?p=47\u0026amp;json=1\"\u003ehttp://www.example.org/?p=47\u0026amp;json=1\u003c/a\u003e（返回文章id为47的json数据）\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.example.org/tag/banana/?json=1\"\u003ehttp://www.example.org/tag/banana/?json=1\u003c/a\u003e（返回标签是banana的json数据）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"显示调用\"\u003e显示调用:\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.example.org/?json=get_recent_posts\"\u003ehttp://www.example.org/?json=get_recent_posts\u003c/a\u003e（返回最新文章json数据，默认返回很多字段，可以指定）\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.example.org/?json=get_post\u0026amp;post_id=47\"\u003ehttp://www.example.org/?json=get_post\u0026amp;post_id=47\u003c/a\u003e（返回id为47的文章json数据）\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.example.org/?json=get_tag_posts\u0026amp;tag_slug=banana\"\u003ehttp://www.example.org/?json=get_tag_posts\u0026amp;tag_slug=banana\u003c/a\u003e（返回tag标签是banana的json数据）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"链接友好型调用\"\u003e链接友好型调用:\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.example.org/api/get_recent_posts/\"\u003ehttp://www.example.org/api/get_recent_posts/\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.example.org/api/get_post/?post_id=47\"\u003ehttp://www.example.org/api/get_post/?post_id=47\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.example.org/api/get_tag_posts/?tag_slug=banana\"\u003ehttp://www.example.org/api/get_tag_posts/?tag_slug=banana\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAPI返回的json数据如下：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://bcs.duapp.com/dayecn/blog/2013/12/screenshot-1.png\"\u003e\u003cimg alt=\"wordpress接口json\" loading=\"lazy\" src=\"http://bcs.duapp.com/dayecn/blog/2013/12/screenshot-1.png\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e可以看到，返回的内容太多了，也许我们只要最新列表中的标题和链接就够了。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.example.org/api/get_recent_posts/?callback=show_posts_widget\u0026amp;read_more=More\u0026amp;count=3\"\u003ehttp://www.example.org/api/get_recent_posts/?callback=show_posts_widget\u0026amp;read_more=More\u0026amp;count=3\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e有很多参数可以选，比如count为返回的文章数目，参考官方文档吧。\u003c/p\u003e\n\u003cp\u003e（本文为小谈博客原创，转载请注明出处！）\u003c/p\u003e\n\u003cp\u003e本文链接：\u003ca href=\"http://www.tantengvip.com/2013/12/wordpress-api/\"\u003ehttp://www.tantengvip.com/2013/12/wordpress-api/\u003c/a\u003e\u003c/p\u003e","title":"wordpress做api接口"},{"content":" On a recent client app, I ran into a situation where I needed an arbitrary number of EditText fields based on a selected value, where the user could enter people’s information. My initial thought was to put this logic in my Fragment, just adding EditTexts to a LinearLayout container as the selected value changes, but that bloated my Fragment, and didn’t allow for much reuse.\n![](http://ryanharter.com/images/posts/compound_views/compound_friend_view.png) This was a perfect opportunity to encapsulate this interaction functionality in a custom view, which would be reusable throughout the app (required in two places so far), and would allow me to easily test the encapsulated functionality. # What Are Custom Compound Views The Android framework provides many Views and Layouts, but sometimes developers need to create their own. Sometimes these are extensions of the built in class to add functionality, like supporting custom fonts and letter spacing in TextViews. Other times these are simply because a built in view doesn’t exist for the desired functionality, like radial dials. What I’m talking about are custom compound views, views that are made up of multiple other views, whether those are builtin or custom, to encapsulate complex interaction and functionality. I use compound views in cases where a full fledged Fragment is more than I need, but I want reusable, testable components. The example I explained above is a great example of that. Since the code for that was for a client project, I’ve created a simple project to demonstrate creating and using custom compound views available [here](https://github.com/rharter/CompoundViews). # The Custom View In this example, we want a custom view that adds EditTexts so that the user can enter data for an arbitrary number of items. In a custom view, this can easily be done with a simple container view (LinearLayout) that sets the appropriate number of EditTexts, and allows you to easily fetch a list of names. Here’s the code: \u0026lt;div class=\u0026quot;highlight\u0026quot; style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt; \u0026lt;table style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt; \u0026lt;tr style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;font-style: inherit;\u0026quot;\u0026gt; ``` 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\n\u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34; style=\u0026#34;font-style: inherit;\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;cm\u0026#34; style=\u0026#34;font-style: italic !important; color: #c5c8c6 !important;\u0026#34;\u0026gt;/**\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;cm\u0026#34; style=\u0026#34;font-style: italic !important; color: #c5c8c6 !important;\u0026#34;\u0026gt; * A custom compound view that displays an arbitrary\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;cm\u0026#34; style=\u0026#34;font-style: italic !important; color: #c5c8c6 !important;\u0026#34;\u0026gt; * number of text views to enter your friends names.\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;cm\u0026#34; style=\u0026#34;font-style: italic !important; color: #c5c8c6 !important;\u0026#34;\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nc\u0026#34; style=\u0026#34;color: #85678f !important;\u0026#34;\u0026gt;FriendNameView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;extends\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;LinearLayout\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mFriendCount\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mEditTextResId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34; style=\u0026#34;font-weight: bold !important; color: #81a2be !important;\u0026#34;\u0026gt;FriendNameView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;Context\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kc\u0026#34; style=\u0026#34;font-weight: bold !important; color: #b5bd68 !important;\u0026#34;\u0026gt;null\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34; style=\u0026#34;font-weight: bold !important; color: #81a2be !important;\u0026#34;\u0026gt;FriendNameView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;Context\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;AttributeSet\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;attrs\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;attrs\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;mi\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34; style=\u0026#34;font-weight: bold !important; color: #81a2be !important;\u0026#34;\u0026gt;FriendNameView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;Context\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;AttributeSet\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;attrs\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;defStyle\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;super\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;context\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;attrs\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;defStyle\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;setOrientation\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;VERTICAL\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34; style=\u0026#34;font-weight: bold !important; color: #81a2be !important;\u0026#34;\u0026gt;getFriendCount\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mFriendCount\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34; style=\u0026#34;font-weight: bold !important; color: #81a2be !important;\u0026#34;\u0026gt;setFriendCount\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;friendCount\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;friendCount\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;!=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mFriendCount\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mFriendCount\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;friendCount\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;removeAllViews\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;i\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;mi\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;i\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mFriendCount\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;i\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;++)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;addView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;createEditText\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;private\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;View\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34; style=\u0026#34;font-weight: bold !important; color: #81a2be !important;\u0026#34;\u0026gt;createEditText\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;View\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;v\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mEditTextResId\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;mi\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;LayoutInflater\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;inflater\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;LayoutInflater\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;from\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;getContext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;v\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;inflater\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;inflate\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mEditTextResId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kc\u0026#34; style=\u0026#34;font-weight: bold !important; color: #b5bd68 !important;\u0026#34;\u0026gt;true\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;else\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;EditText\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;et\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;EditText\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;getContext\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;et\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;setHint\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;string\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;friend_name\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;v\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;et\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;v\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34; style=\u0026#34;font-weight: bold !important; color: #81a2be !important;\u0026#34;\u0026gt;getEditTextResId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mEditTextResId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34; style=\u0026#34;font-weight: bold !important; color: #81a2be !important;\u0026#34;\u0026gt;setEditTextResId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;editTextResId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mEditTextResId\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;editTextResId\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;cm\u0026#34; style=\u0026#34;font-style: italic !important; color: #c5c8c6 !important;\u0026#34;\u0026gt;/**\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;cm\u0026#34; style=\u0026#34;font-style: italic !important; color: #c5c8c6 !important;\u0026#34;\u0026gt; * Returns a list of entered friend names.\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;cm\u0026#34; style=\u0026#34;font-style: italic !important; color: #c5c8c6 !important;\u0026#34;\u0026gt; */\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;List\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;nf\u0026#34; style=\u0026#34;font-weight: bold !important; color: #81a2be !important;\u0026#34;\u0026gt;getFriendNames\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;List\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;names\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;ArrayList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;for\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;i\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;mi\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;0\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;i\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;getChildCount\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;i\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;++)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;View\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;v\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;getChildAt\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;i\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;if\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;v\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;instanceof\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;EditText\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;EditText\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;et\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;EditText\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;v\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;names\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;add\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;et\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;getText\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;().\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;toString\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;());\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;return\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;names\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/figure\u0026gt; When the user sets the number of friends with `setFriendCount(int)`, we reset the number of child EditText fields based on that number. This can be done with a custom layout resource, but will default to a simple EditText. When we want to retrieve the list of names the user has entered, we don’t care about any of the internal structure of the custom view since we can just call `getFriendNames()` and the view will compile a list of names. That’s all there is to this simple example. As a special side effect, since this view is just made up of a LinearLayout (the super class) and EditText views which already know how to save and restore their state, we don’t have to do any state handling. # Including the Custom View in Layouts When you want to use your custom view in your Activity or Fragment layouts, you can simply add some XML like you would any other view. \u0026lt;div class=\u0026quot;highlight\u0026quot; style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt; \u0026lt;table style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt; \u0026lt;tr style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;font-style: inherit;\u0026quot;\u0026gt; ``` 1 2 3 4\n\u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34; style=\u0026#34;font-style: inherit;\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34; style=\u0026#34;font-weight: bold !important; color: #81a2be !important;\u0026#34;\u0026gt;\u0026amp;lt;com.ryanharter.android.compoundviews.app.views.FriendNameView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;android:id=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;\u0026#34;@+id/friend_names\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;android:layout_width=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;\u0026#34;match_parent\u0026#34;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;android:layout_height=\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;\u0026#34;wrap_content\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;nt\u0026#34; style=\u0026#34;font-weight: bold !important; color: #81a2be !important;\u0026#34;\u0026gt;/\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/figure\u0026gt; Then you access it just like any other using `findViewById(int)`. \u0026lt;div class=\u0026quot;highlight\u0026quot; style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt; \u0026lt;table style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt; \u0026lt;tr style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;font-style: inherit;\u0026quot;\u0026gt; ``` 1\n\u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34; style=\u0026#34;font-style: inherit;\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mFriendNameView\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;FriendNameView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;findViewById\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;R\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;id\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;friend_names\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/figure\u0026gt; In our MainActivity we simply set the friend count when the NumberPicker value changes, and call `getFriendNames()` when we want to retrieve the list of names. \u0026lt;div class=\u0026quot;highlight\u0026quot; style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt; \u0026lt;table style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt; \u0026lt;tr style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt; \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;font-style: inherit;\u0026quot;\u0026gt; ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14\n\u0026lt;/td\u0026gt; \u0026lt;td class=\u0026#34;code\u0026#34; style=\u0026#34;font-style: inherit;\u0026#34;\u0026gt; ``` `\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mFriendCountPicker\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;setOnValueChangedListener\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;OnValueChangeListener\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;nd\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;onValueChange\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;NumberPicker\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;picker\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;oldVal\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;int\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;newVal\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mFriendNameView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;setFriendCount\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;newVal\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mCountFriendsButton\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;setOnClickListener\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;OnClickListener\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;()\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;nd\u0026#34;\u0026gt;@Override\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kd\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;public\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;kt\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;void\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;onClick\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;View\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;v\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;)\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;{\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;List\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;\u0026amp;gt;\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;names\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;mFriendNameView\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;getFriendNames\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;();\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;Intent\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;i\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;=\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;Intent\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;MainActivity\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;this\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;FriendCountActivity\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;class\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;i\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;.\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;na\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;putStringArrayListExtra\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;s\u0026#34; style=\u0026#34;color: #8abeb7 !important;\u0026#34;\u0026gt;\u0026#34;names\u0026#34;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;,\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;k\u0026#34; style=\u0026#34;color: #de935f !important;\u0026#34;\u0026gt;new\u0026amp;lt;/span\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;ArrayList\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;\u0026amp;lt;\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;String\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;\u0026amp;gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;names\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;));\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;startActivity\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;(\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;n\u0026#34; style=\u0026#34;color: #81a2be !important;\u0026#34;\u0026gt;i\u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;);\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt; \u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;}\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;\u0026amp;lt;span class=\u0026#34;line\u0026#34;\u0026gt;\u0026amp;lt;span class=\u0026#34;o\u0026#34; style=\u0026#34;font-weight: bold !important;\u0026#34;\u0026gt;});\u0026amp;lt;/span\u0026gt; \u0026amp;lt;/span\u0026gt;` \u0026lt;/td\u0026gt; \u0026lt;/tr\u0026gt; \u0026lt;/table\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/figure\u0026gt; Though this is a contrived example, compound custom views are a great way to encapsulate functionality that would otherwise be strewn throughout your Activities and Fragments. They provide testable, reusable code that makes for more stable apps. I encourage you to see where you can use custom compound views in your apps, and share them with other devs if you can and they would be useful. Get the code for the sample app on [Github](https://github.com/rharter/CompoundViews). ","permalink":"https://blog.zdltech.com/posts/using-custom-compound-views-in-android/","summary":"\u003csection style=\"color: #666666;\"\u003e \n\u003cp\u003eOn a recent client app, I ran into a situation where I needed an arbitrary number of EditText fields based on a selected value, where the user could enter people’s information. My initial thought was to put this logic in my Fragment, just adding EditTexts to a LinearLayout container as the selected value changes, but that bloated my Fragment, and didn’t allow for much reuse.\u003c/p\u003e\n  \u003c/section\u003e \n\u003cpre\u003e\u003ccode\u003e![](http://ryanharter.com/images/posts/compound_views/compound_friend_view.png)\n\u003c/code\u003e\u003c/pre\u003e\n\u003csection style=\"color: #666666;\"\u003e \n\u003cpre\u003e\u003ccode\u003e  This was a perfect opportunity to encapsulate this interaction functionality in a custom view, which would be reusable throughout the app (required in two places so far), and would allow me to easily test the encapsulated functionality.\n\n\n\n# What Are Custom Compound Views\n\n\n\n  The Android framework provides many Views and Layouts, but sometimes developers need to create their own. Sometimes these are extensions of the built in class to add functionality, like supporting custom fonts and letter spacing in TextViews. Other times these are simply because a built in view doesn’t exist for the desired functionality, like radial dials.\n\n\n\n\n\n  What I’m talking about are custom compound views, views that are made up of multiple other views, whether those are builtin or custom, to encapsulate complex interaction and functionality.\n\n\n\n\n\n  I use compound views in cases where a full fledged Fragment is more than I need, but I want reusable, testable components. The example I explained above is a great example of that. Since the code for that was for a client project, I’ve created a simple project to demonstrate creating and using custom compound views available [here](https://github.com/rharter/CompoundViews).\n\n\n\n# The Custom View\n\n\n\n  In this example, we want a custom view that adds EditTexts so that the user can enter data for an arbitrary number of items. In a custom view, this can easily be done with a simple container view (LinearLayout) that sets the appropriate number of EditTexts, and allows you to easily fetch a list of names. Here’s the code:\n\u003c/code\u003e\u003c/pre\u003e\n\u003cfigure class=\"code\" style=\"font-weight: inherit; font-style: inherit;\"\u003e\u003cfigcaption style=\"font-style: inherit; color: #474747;\"\u003e\u003c/figcaption\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;div class=\u0026quot;highlight\u0026quot; style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt;\n  \u0026lt;table style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt;\n    \u0026lt;tr style=\u0026quot;font-weight: inherit; font-style: inherit;\u0026quot;\u0026gt;\n      \u0026lt;td class=\u0026quot;gutter\u0026quot; style=\u0026quot;font-style: inherit;\u0026quot;\u0026gt;\n        ```\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e1\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e2\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e3\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e4\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e5\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e6\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e7\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e8\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e9\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e10\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e11\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e12\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e13\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e14\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e15\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e16\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e17\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e18\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e19\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e20\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e21\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e22\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e23\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e24\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e25\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e26\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e27\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e28\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e29\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e30\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e31\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e32\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e33\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e34\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e35\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e36\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e37\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e38\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e39\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e40\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e41\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e42\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e43\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e44\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e45\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e46\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e47\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e48\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e49\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e50\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e51\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e52\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e53\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e54\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e55\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e56\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e57\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e58\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e59\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e60\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e61\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e62\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e63\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e64\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e65\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e66\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e67\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e68\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e69\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e70\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e71\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e72\u003c/span\u003e\n\u003cspan class=\"line-number\" style=\"font-weight: inherit; font-style: inherit; color: #999999 !important;\"\u003e73\u003c/span\u003e\u003c/p\u003e","title":"Using Custom Compound Views in Android"},{"content":"客户端与服务端基于HTTP和WebSocket网络协议来通讯，其中HTTP用于从客户端向服务端的请求，WebSocket用于从服务端向客户端的推送，因此服务器端需要支持HTTP和WebSocket两种协议。HTTP好说，所有Web服务器都支持，而支持WebSocket的倒不多。\nJava阵营：Tomcat 7和Netty .Net阵营：System.Net.WebSockets Nodejs阵营：Socket.io WebSocket百度百科\n1）Web通信的演进\n2）WebSocket\n3）WebSocket在Apache Tomcat 7（7.0.27 ）的实现\n4）怎样用Jaggery开发WebSocket特性\nTomcat 7中引入了WebSocket实现。下面我们先了解WebSocket的优缺点，其次简要介绍Apache Tomcat 7的WebSocket实现。\nWebSocket的演进过程如图所示：\n要知道在Tomcat 6中要实现双向HTTP通信，需要使用Tomcat的Comet处理模块。Comet有以下局限：\n1）HTTP协议本身是请求/响应协议，而不是双向协议\n2）代理和其它中间媒介不会工作的很好\n3）在任何给定的时间只有某个方向的数据包传输\n4）Servlet开发者要使用多线程很难\nServlet 3.0版引入了一个新特征：异步Servlet。我们把它与客户端的Ajax调用进行比较。异步Servlet会把请求悬挂起，直到响应准备好交付，无需在容器中使用worker线程。WebSockets是另一个尝试标准化的技术，它支持HTTP之上的异步、事件驱动和全双工通信。\nWebSocket给我们带来了如下特性：\n1）通过升级/交换HTTP协议，在HTTP之上提供全双工通信\n2）基于消息/帧的通信\n3）可以与代理和中间媒介一起工作\n4）还可以不与代理和中间媒介一起工作\nWebSocket的优点：\n1）WebSocket是理想的，客户端和服务器之间不再需要长期运行的会话\n2）WebSocket是HTTP协议之上的全双工通信\n3）由于WebSocket是HTTP握手初始化之后的TCP之上的协议，所以你只需做两件事：\n发送消息\n接收消息\n","permalink":"https://blog.zdltech.com/posts/websocket%E5%BC%80%E5%8F%91%E7%AC%AC%E4%B8%80%E7%AF%87/","summary":"\u003cp\u003e客户端与服务端基于HTTP和WebSocket网络协议来通讯，其中HTTP用于从客户端向服务端的请求，WebSocket用于从服务端向客户端的推送，因此服务器端需要支持HTTP和WebSocket两种协议。HTTP好说，所有Web服务器都支持，而支持WebSocket的倒不多。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eJava阵营：\u003ca href=\"http://tomcat.apache.org/tomcat-7.0-doc/web-socket-howto.html#Application_development\"\u003eTomcat 7\u003c/a\u003e和\u003ca href=\"https://netty.io/\"\u003eNetty\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e.Net阵营：\u003ca href=\"http://msdn.microsoft.com/en-us/library/hh159285%28v=vs.110%29\"\u003eSystem.Net.WebSockets\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eNodejs阵营：\u003ca href=\"http://socket.io/\"\u003eSocket.io\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003ca href=\"http://baike.baidu.com/link?url=QHYK2ICMPGEl9_w4loloikdGvt0vO3-dyykGVbdeAg1fEMo8YWvKWC8Pngfz-Poiz_rweDrq3dSYpGnCRZqc5K\"\u003eWebSocket百度百科\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e1）Web通信的演进\u003c/p\u003e\n\u003cp\u003e2）WebSocket\u003c/p\u003e\n\u003cp\u003e3）WebSocket在Apache Tomcat 7（7.0.27 ）的实现\u003c/p\u003e\n\u003cp\u003e4）怎样用Jaggery开发WebSocket特性\u003c/p\u003e\n\u003cp\u003eTomcat 7中引入了WebSocket实现。下面我们先了解WebSocket的优缺点，其次简要介绍Apache Tomcat 7的WebSocket实现。\u003c/p\u003e\n\u003cp\u003eWebSocket的演进过程如图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://img.blog.csdn.net/20140228191924093?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hzenM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast\"\u003e\u003c/p\u003e\n\u003cp\u003e要知道在Tomcat 6中要实现双向HTTP通信，需要使用Tomcat的Comet处理模块。Comet有以下局限：\u003c/p\u003e\n\u003cp\u003e1）HTTP协议本身是请求/响应协议，而不是双向协议\u003c/p\u003e\n\u003cp\u003e2）代理和其它中间媒介不会工作的很好\u003c/p\u003e\n\u003cp\u003e3）在任何给定的时间只有某个方向的数据包传输\u003c/p\u003e\n\u003cp\u003e4）Servlet开发者要使用多线程很难\u003c/p\u003e\n\u003cp\u003eServlet 3.0版引入了一个新特征：异步Servlet。我们把它与客户端的Ajax调用进行比较。异步Servlet会把请求悬挂起，直到响应准备好交付，无需在容器中使用worker线程。WebSockets是另一个尝试标准化的技术，它支持HTTP之上的异步、事件驱动和全双工通信。\u003c/p\u003e\n\u003cp\u003eWebSocket给我们带来了如下特性：\u003c/p\u003e\n\u003cp\u003e1）通过升级/交换HTTP协议，在HTTP之上提供全双工通信\u003c/p\u003e\n\u003cp\u003e2）基于消息/帧的通信\u003c/p\u003e\n\u003cp\u003e3）可以与代理和中间媒介一起工作\u003c/p\u003e\n\u003cp\u003e4）还可以不与代理和中间媒介一起工作\u003c/p\u003e\n\u003cp\u003eWebSocket的优点：\u003c/p\u003e\n\u003cp\u003e1）WebSocket是理想的，客户端和服务器之间不再需要长期运行的会话\u003c/p\u003e\n\u003cp\u003e2）WebSocket是HTTP协议之上的全双工通信\u003c/p\u003e\n\u003cp\u003e3）由于WebSocket是HTTP握手初始化之后的TCP之上的协议，所以你只需做两件事：\u003c/p\u003e\n\u003cp\u003e发送消息\u003c/p\u003e\n\u003cp\u003e接收消息\u003c/p\u003e","title":"websocket开发第一篇"},{"content":"前言 这段时间在研究android平台上的开源项目——StandupTimer，这是由jwood所设计的一个较为简单android应用，用于控制会议时间，类似秒表倒计时。 PreferenceActivity PreferenceActivity是android提供的对系统信息和配置进行自动保存的Activity,它通过[SharedPreference](http://developer.android.com/reference/android/content/SharedPreferences.html)方式将信息保存在XML 文件当中。使用PreferenceActivity不需要我们对SharedPreference进行操作，系统会自动对Activity 的各种View上的改变进行保存（这个真是太赞了！）。 在android项目中添加一个 android xml 文件需要注意的是这次选择的是 Preference。而不是以往的Layout ![](http://pic002.cnblogs.com/img/xinsuhui/201009/2010090109571786.gif) 这个文件是保存在 res /xml 路径下的。 PreferenceScreen xml preference下的View是有限的，只有下面几个： - CheckBoxPreference:CheckBox选择项，对应的值的ture或flase - EditTextPreference:输入编辑框，值为String类型，会弹出对话框供输入。 - ListPreference: 列表选择，弹出对话框供选择。 - Preference：只进行文本显示，需要与其他进行组合使用。 - PreferenceCategory：用于分组。 - RingtonePreference：系统玲声选择 更多关于 PreferenceScreen的介绍可以查看博客园上的一篇文章：[Android之PreferenceActivity](http://www.cnblogs.com/wservices/archive/2010/07/08/1773449.html) ![复制代码](http://common.cnblogs.com/images/copycode.gif) \u0026lt;div\u0026gt; \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #ff00ff;\u0026quot;\u0026gt;xml version=\u0026amp;#8221;1.0\u0026amp;#8243; encoding=\u0026amp;#8221;utf-8\u0026amp;#8243;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt; \u0026laquo;/span\u0026gt;PreferenceScreen xmlns:android=”http://schemas.android.com/apk/res/android”\u0026gt; \u0026laquo;/span\u0026gt;CheckBoxPreference android:key=”sounds” android:title=”@string/play_sounds” android:summary=”@string/play_sounds_summary” android:defaultValue=”true”\u0026gt;\u0026lt;/CheckBoxPreference\u0026gt; \u0026laquo;/span\u0026gt;EditTextPreference android:key=”warning_time” android:title=”@string/warning_time” android:summary=”@string/warning_time_summary” android:defaultValue=”15″ android:inputType=”phone” android:digits=”0123456789″\u0026gt;\u0026lt;/EditTextPreference\u0026gt; \u0026laquo;/span\u0026gt;CheckBoxPreference android:key=”unlimited_participants” android:title=”@string/unlimited_participants” android:summary=”@string/unlimited_participants_summary” android:defaultValue=”false”\u0026gt;\u0026lt;/CheckBoxPreference\u0026gt; \u0026laquo;/span\u0026gt;CheckBoxPreference android:key=”variable_meeting_length” android:title=”@string/variable_meeting_length” android:summary=”@string/variable_meeting_length_summary” android:defaultValue=”false”\u0026gt;\u0026lt;/CheckBoxPreference\u0026gt; \u0026lt;/PreferenceScreen\u0026gt; \u0026lt;div class=\u0026quot;cnblogs_code_toolbar\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_copy\u0026quot;\u0026gt;\u0026lt;a style=\u0026quot;color: green;\u0026quot; title=\u0026quot;复制代码\u0026quot;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026amp;nbsp; android:key 唯一标识符。它对应保存的XML保存的配置文件中的节点的 name属性 android:defaultValue 默认值，对应XML中的Value属性的值。 ![复制代码](http://common.cnblogs.com/images/copycode.gif) \u0026lt;div\u0026gt; /** PreferenceActivity 会自动保存更改 */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.addPreferencesFromResource(R.xml.setting); }\n![复制代码](http://common.cnblogs.com/images/copycode.gif) \u0026amp;nbsp; 当PreferenceActivity上的View有所更改时，系统会自动将对应的值更新到XML配置文件中，该文件可以在android 的 file explorer 中的 data/data/\u0026amp;#8221;yourPageName\u0026amp;#8221;/shared_prefs/\u0026amp;#8221;yourpageName\u0026amp;#8221;_prefenrences.xml中找到。“yourpageName”表示你项目所在的包。 获取配置信息 为了方便的获取配置信息，我们可以在PreferenceActivity里添加一些pulbic 方法来公开配置信息的访问。 ![复制代码](http://common.cnblogs.com/images/copycode.gif) \u0026lt;div\u0026gt; \u0026lt;span style=\u0026quot;color: #008000;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #008000;\u0026quot;\u0026gt; 获取是否播放声音 */ publicstaticboolean playSounds(Context context) { return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SOUNDS, SOUNDS_DEFAULT); }\n\u0026lt;span style=\u0026quot;color: #008000;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #008000;\u0026quot;\u0026gt; 设置播放的声音 * @param context 上下文 * @param value 是否播放 */ publicstaticvoid setPlaySounds(Context context, boolean value) { PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(SOUNDS, value).commit(); }\n\u0026lt;span style=\u0026quot;color: #008000;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #008000;\u0026quot;\u0026gt; 获取警告时间 * @param context 上下文 * @return 警告时间秒 */ publicstaticint getWarningTime(Context context) { String value=PreferenceManager.getDefaultSharedPreferences(context).getString(WARNING_TIME,Integer.toString(WARNING_TIME_DEFAULT)); try { return Integer.parseInt(value); } catch(NumberFormatException e) { setWarningTime(context, WARNING_TIME_DEFAULT); return WARNING_TIME_DEFAULT; }\n} \u0026lt;span style=\u0026quot;color: #008000;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #008000;\u0026quot;\u0026gt; 设置警告时间 * @param context 上下文 * @param warningTime 警告时间 */ publicstaticvoid setWarningTime(Context context, int warningTime) { PreferenceManager.getDefaultSharedPreferences(context).edit().putString(WARNING_TIME, Integer.toString(warningTime)).commit();\n} \u0026lt;span style=\u0026quot;color: #008000;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #008000;\u0026quot;\u0026gt; 参加人数无限制 * @param context * @return */ publicstaticboolean allowUnlimitedParticipants(Context context) { return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(UNLIMITED_PARTICIPANTS, UNLIMITED_PARTICIPANTS_DEFAULT); }\n\u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setAllowUnlimitedParticipants(Context context, \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; value) { PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(UNLIMITED_PARTICIPANTS, value).commit(); }\n\u0026lt;span style=\u0026quot;color: #008000;\u0026quot;\u0026gt;/**\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #008000;\u0026quot;\u0026gt; 允许编辑会议时间 * @param context * @return */ publicstaticboolean allowVariableMeetingLength(Context context) { return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(VARIABLE_MEETING_LENGTH, VARIABLE_MEETING_LENGTH_DEFAULT); }\n\u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; setAllowVariableMeetingLength(Context context, \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;boolean\u0026lt;/span\u0026gt; value) { PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(VARIABLE_MEETING_LENGTH, value).commit(); }\n\u0026lt;div class=\u0026quot;cnblogs_code_toolbar\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;cnblogs_code_copy\u0026quot;\u0026gt;\u0026lt;a style=\u0026quot;color: green;\u0026quot; title=\u0026quot;复制代码\u0026quot;\u0026gt;![复制代码](http://common.cnblogs.com/images/copycode.gif)\u0026lt;/a\u0026gt;\u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt; \u0026amp;nbsp; getDefaultSharedPreferences(Context )用来获取preferences.以后的操作就和普通的Sharedpreferences一样了，如果需要修改某项配置的信息，记得最后需要 commit()。 当其他地方需要使用配置时，可以直接调用 setting.getXXX() 方法来获取配置信息。 ","permalink":"https://blog.zdltech.com/posts/android%E7%9A%84preferenceactivity/","summary":"\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  　　这段时间在研究android平台上的开源项目——StandupTimer，这是由jwood所设计的一个较为简单android应用，用于控制会议时间，类似秒表倒计时。\n\u003c/div\u003e\n\u003ch1 id=\"preferenceactivity\"\u003ePreferenceActivity\u003c/h1\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  　　PreferenceActivity是android提供的对系统信息和配置进行自动保存的Activity,它通过[SharedPreference](http://developer.android.com/reference/android/content/SharedPreferences.html)方式将信息保存在XML 文件当中。使用PreferenceActivity不需要我们对SharedPreference进行操作，系统会自动对Activity 的各种View上的改变进行保存（这个真是太赞了！）。\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  　　在android项目中添加一个 android xml 文件需要注意的是这次选择的是 Preference。而不是以往的Layout\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  ![](http://pic002.cnblogs.com/img/xinsuhui/201009/2010090109571786.gif)\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  这个文件是保存在 res /xml 路径下的。\n\u003c/div\u003e\n\u003ch2 id=\"preferencescreen-xml\"\u003ePreferenceScreen xml\u003c/h2\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  　　preference下的View是有限的，只有下面几个：\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n\u003cpre\u003e\u003ccode\u003e- CheckBoxPreference:CheckBox选择项，对应的值的ture或flase\n\n- EditTextPreference:输入编辑框，值为String类型，会弹出对话框供输入。\n\n- ListPreference: 列表选择，弹出对话框供选择。\n\n- Preference：只进行文本显示，需要与其他进行组合使用。\n\n- PreferenceCategory：用于分组。\n\n- RingtonePreference：系统玲声选择\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n    更多关于 PreferenceScreen的介绍可以查看博客园上的一篇文章：[Android之PreferenceActivity](http://www.cnblogs.com/wservices/archive/2010/07/08/1773449.html)\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n\u003c/div\u003e\n\u003cdiv style=\"color: #000000;\"\u003e\n  \u003cdiv class=\"cnblogs_code\"\u003e\n    \u003cdiv class=\"cnblogs_code_toolbar\"\u003e\n      \u003cspan class=\"cnblogs_code_copy\"\u003e\u003ca style=\"color: green;\" title=\"复制代码\"\u003e![复制代码](http://common.cnblogs.com/images/copycode.gif)\u003c/a\u003e\u003c/span\u003e\n    \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;div\u0026gt;\n  \u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;\u0026lt;?\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #ff00ff;\u0026quot;\u0026gt;xml version=\u0026amp;#8221;1.0\u0026amp;#8243; encoding=\u0026amp;#8221;utf-8\u0026amp;#8243;\u0026lt;/span\u0026gt;\u0026lt;span style=\u0026quot;color: #0000ff;\u0026quot;\u0026gt;?\u0026gt;\u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cspan style=\"color: #0000ff;\"\u003e\u0026laquo;/span\u0026gt;\u003cspan style=\"color: #800000;\"\u003ePreferenceScreen \u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003exmlns:android\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”http://schemas.android.com/apk/res/android”\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e\u0026laquo;/span\u0026gt;\u003cspan style=\"color: #800000;\"\u003eCheckBoxPreference \u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003eandroid:key\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”sounds”\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e\nandroid:title\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”@string/play_sounds”\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e android:summary\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”@string/play_sounds_summary”\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e\nandroid:defaultValue\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”true”\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan style=\"color: #800000;\"\u003eCheckBoxPreference\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e\u0026laquo;/span\u0026gt;\u003cspan style=\"color: #800000;\"\u003eEditTextPreference \u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003eandroid:key\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”warning_time”\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e\nandroid:title\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”@string/warning_time”\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e android:summary\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”@string/warning_time_summary”\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e\nandroid:defaultValue\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”15″\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e android:inputType\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”phone”\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e android:digits\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”0123456789″\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan style=\"color: #800000;\"\u003eEditTextPreference\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e\u0026laquo;/span\u0026gt;\u003cspan style=\"color: #800000;\"\u003eCheckBoxPreference \u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003eandroid:key\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”unlimited_participants”\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e\nandroid:title\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”@string/unlimited_participants”\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e android:summary\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”@string/unlimited_participants_summary”\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e\nandroid:defaultValue\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”false”\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan style=\"color: #800000;\"\u003eCheckBoxPreference\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e\u0026laquo;/span\u0026gt;\u003cspan style=\"color: #800000;\"\u003eCheckBoxPreference \u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003eandroid:key\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”variable_meeting_length”\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e\nandroid:title\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”@string/variable_meeting_length”\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e android:summary\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”@string/variable_meeting_length_summary”\u003c/span\u003e\u003cspan style=\"color: #ff0000;\"\u003e\nandroid:defaultValue\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e=”false”\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan style=\"color: #800000;\"\u003eCheckBoxPreference\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan style=\"color: #0000ff;\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan style=\"color: #800000;\"\u003ePreferenceScreen\u003c/span\u003e\u003cspan style=\"color: #0000ff;\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/div\u003e\u003c/p\u003e","title":"android的PreferenceActivity"},{"content":"CutJS是一款专门用于跨平台游戏开发的开源2D HTML5渲染引擎，轻量级、快速、可交互，CutJS的优势可谓颇多。CutJS基于MIT许可协议发布，由Piqnt软件工作室推出，支持现代浏览器和移动设备，可用于Web、iOS、Android、Win8、Facebook、Chrome Web Store等平台游戏应用开发。\n作为HTML5中新晋的标签元素，Canvas提供了基于JavaScript的2D和Bitmap图形API，但却没有像DOM之类的数据模型来帮助开发者编写应用，开发者必须手动绘制应用并对渲染循环进行管理以实现播放Canvas图形。此外，鼠标事件也只适用于整个Canvas层，并且还需手动处理。\n而CutJS可以非常良好地解决这些问题。CutJS为开发者提供了一个类似于DOM树的数据模型来编写应用程序，并在内部管理渲染周期和应用绘制，还能处理并向目标树节点分发鼠标事件。\n（文/唐小引 责编/刘璐璐）\n传送门：CutJS官网、GitHub托管地址、mobilehub主页\n","permalink":"https://blog.zdltech.com/posts/%E5%BC%80%E6%BA%902d-html5%E6%B8%B2%E6%9F%93%E5%BC%95%E6%93%8Ecutjs/","summary":"\u003cp\u003eCutJS是一款专门用于跨平台游戏开发的开源2D HTML5渲染引擎，轻量级、快速、可交互，CutJS的优势可谓颇多。CutJS基于MIT许可协议发布，由Piqnt软件工作室推出，支持现代浏览器和移动设备，可用于Web、iOS、Android、Win8、Facebook、Chrome Web Store等平台游戏应用开发。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201405/09/536c71f74255e.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201405/09/536c71f74255e_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e作为HTML5中新晋的标签元素，Canvas提供了基于JavaScript的2D和Bitmap图形API，但却没有像DOM之类的数据模型来帮助开发者编写应用，开发者必须手动绘制应用并对渲染循环进行管理以实现播放Canvas图形。此外，鼠标事件也只适用于整个Canvas层，并且还需手动处理。\u003c/p\u003e\n\u003cp\u003e而CutJS可以非常良好地解决这些问题。CutJS为开发者提供了一个类似于DOM树的数据模型来编写应用程序，并在内部管理渲染周期和应用绘制，还能处理并向目标树节点分发鼠标事件。\u003c/p\u003e\n\u003cp\u003e（文/唐小引 责编/刘璐璐）\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e传送门：\u003ca href=\"http://cutjs.org/\"\u003eCutJS官网\u003c/a\u003e、\u003ca href=\"https://github.com/piqnt/cutjs/\"\u003eGitHub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/cutjs\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e","title":"开源2D HTML5渲染引擎CutJS"},{"content":"无论你是经验丰富的专业Android开发者，还是初出茅庐的新人，开发应用最忌讳的就是闭门造车。不能把自己圈在自己的思维里，要学会借助外在现有的资源去协助开发，这样既不会让自己固步自封，还能够大大提高工作效率。在这里，本文介绍的这些资源包括工具、库和网站等，学会利用它们，将会对你的工作有着非常大的帮助。\n1. OkHttp\nOkHttp是Square的一款产品，是一个Java的开源HTTP和SPDY客户端开发包，支持Android。Android自带的两个HTTP框架（HttpURLConnection和HttpClient），在各种Android OS版本一直充斥着错误，可以使任何理智的开发者走向崩溃。不过幸运地是，OkHttp解决了这些问题。OkHttp是建立在HttpUrlConnection上，从Android代码库保持最新的修复，这意味着再也没有与旧操作系统版本出现兼容性问题的噩梦。\n相关链接：OkHttp的mobilehub主页\n2. Retrofit\nRetrofit同样是Square的一款开源产品，用于Android平台的一个类型安全的REST客户端。就API而言，Android平台并不适合过多简单的客户端服务器交互，而Retrofit旨在提高对REST请求。Retrofit支持相当多的自定义，使用GSON为JSON解析，并且通过简化这一切成为简单的接口来为为构建形式和多部分请求节省大量的时间。\n相关链接：Retrofit的mobilehub主页\n3. Picasso\n这个仍然是Square的开源项目，Picasso是一个用于Android平台上的下载和缓存图片的项目。它有许多定制选项，如何处理下载图片（包括调整和裁剪，以及提供一个接口让你随自己心意将图片转换成圆角等）。Picasso将要下载的图片（如果没有缓存）并将它负载到指定的目标，转换图片以适合所显示的ImageView，来减少内存消耗。\n相关链接：Picasso的mobilehub主页\n4. AndroidViews\nAndroidViews.net是一个网站，汇集了众多不同类型的工具、库和可浏览索引的资源。你不用重新开发已有的东西，可以节省很多时间。不过它还存在一个缺点就是，网站还不全面。\n相关链接：AndroidViews的mobilehub主页\n5. Android Weekly\nAndroid Weekly相当于是Android开发社区的实时通讯录，每周报导Android最新讯息，包括新的库、工具和博客等，只要你有Email，就可以对其进行订阅，了解更多关于安卓的消息。\n相关链接：Android Weekly的mobilehub主页\n6. Android Niceties\nAndroid Niceties集合了Android生态系统中一些精心设计、优雅精美的Android程序，是启发灵感的好资源。Android Niceties覆盖面极好，来自主要的平台应用比如Duolingo、Expedia、Etsy和之前依序还不为人知的Muzei、Timely和Pocket。\n相关链接：Android Niceties的mobilehub主页\n7. Android Lifecycle\n展现了完整的Android片段和Activity的生命周期，Activity从新建到销毁，构成了一个生命周期，但要知道生命周期并不仅仅只包括这两个。而Android Lifecycle打印出的表图概述了Activity与Fragment在应用内部与外部和用户交互的流。\n相关链接：Android Lifecycle的mobilehub主页\n8. Android Asset Studio\n这个网站已提供了大量的工具来简化创建各种Android相关的资源，包括启动栏图标、通知图标和导航抽屉图标等，让你不再为设计应用图标而发愁。\n相关链接：Android Asset Studio的mobilehub主页\n9. Android Holo Colors Generator\n制作更加精美的图标，可以前往Android Asset Studio进行设计。该网站提供应用所需要的所有图标的生成工具，包括菜单图标、动作栏图标、标签栏图标、通知图标等，而且操作简单易行。\n相关链接：Android Holo Colors Generator的mobilehub主页\n10. DPI Calculator for Android\n就像它的名字一样，这是一款专门用于Android平台的分辨率计算器，使用很简单，用户通过输入长、宽、对角线等，就可以计算出屏幕的实际分辨率来。\n11. Android Developers YouTube Channel\n如果你想紧跟Android开发步伐，那么Android Developers就是你最值得订阅的频道，在这里你将学会与Android相关的最新特性以及独门绝技，这些将对自己的开发工作有着很大的帮助。\n12. android/platform frameworks base\n你也许会奇怪它为什么会存在，不过在通常情况下，你也许会想知道一些东西是如何工作的（比如ListView/AdapterView的复杂性，或TransitionManager的最新热度），并希望能够挖掘出来，而通过它就能够实现，并且支持库源浏览。\n","permalink":"https://blog.zdltech.com/posts/%E5%BC%80%E5%8F%91%E8%80%85%E5%BF%85%E5%A4%87%E7%9A%84%E5%8D%81%E4%BA%8C%E5%A4%A7android%E5%BC%80%E5%8F%91%E8%B5%84%E6%BA%90/","summary":"\u003cp\u003e无论你是经验丰富的专业Android开发者，还是初出茅庐的新人，开发应用最忌讳的就是闭门造车。不能把自己圈在自己的思维里，要学会借助外在现有的资源去协助开发，这样既不会让自己固步自封，还能够大大提高工作效率。在这里，本文介绍的这些资源包括工具、库和网站等，学会利用它们，将会对你的工作有着非常大的帮助。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201405/09/536c71e7189f7.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201405/09/536c71e7189f7_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. \u003ca href=\"http://square.github.io/okhttp/\"\u003eOkHttp\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201405/09/536c72135a1d4.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201405/09/536c72135a1d4_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eOkHttp是Square的一款产品，是一个Java的开源HTTP和SPDY客户端开发包，支持Android。Android自带的两个HTTP框架（HttpURLConnection和HttpClient），在各种Android OS版本一直充斥着错误，可以使任何理智的开发者走向崩溃。不过幸运地是，OkHttp解决了这些问题。OkHttp是建立在HttpUrlConnection上，从Android代码库保持最新的修复，这意味着再也没有与旧操作系统版本出现兼容性问题的噩梦。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：\u003ca href=\"http://mobilehub.io/products/OkHttp\"\u003eOkHttp的mobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. \u003ca href=\"http://square.github.io/retrofit/\"\u003eRetrofit\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201405/09/536c723698082.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201405/09/536c723698082_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eRetrofit同样是Square的一款开源产品，用于Android平台的一个类型安全的REST客户端。就API而言，Android平台并不适合过多简单的客户端服务器交互，而Retrofit旨在提高对REST请求。Retrofit支持相当多的自定义，使用GSON为JSON解析，并且通过简化这一切成为简单的接口来为为构建形式和多部分请求节省大量的时间。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：\u003ca href=\"http://mobilehub.io/products/Retrofit\"\u003eRetrofit的mobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. \u003ca href=\"http://square.github.io/picasso/\"\u003ePicasso\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201405/09/536c72533a8b0.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201405/09/536c72533a8b0_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这个仍然是Square的开源项目，Picasso是一个用于Android平台上的下载和缓存图片的项目。它有许多定制选项，如何处理下载图片（包括调整和裁剪，以及提供一个接口让你随自己心意将图片转换成圆角等）。Picasso将要下载的图片（如果没有缓存）并将它负载到指定的目标，转换图片以适合所显示的ImageView，来减少内存消耗。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：\u003ca href=\"http://mobilehub.io/products/Picasso\"\u003ePicasso的mobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4. \u003ca href=\"http://www.androidviews.net/\"\u003eAndroidViews\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201405/09/536c727125160.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201405/09/536c727125160_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAndroidViews.net是一个网站，汇集了众多不同类型的工具、库和可浏览索引的资源。你不用重新开发已有的东西，可以节省很多时间。不过它还存在一个缺点就是，网站还不全面。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：\u003ca href=\"http://mobilehub.io/products/AndroidViews\"\u003eAndroidViews的mobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e5. \u003ca href=\"http://androidweekly.net/\"\u003eAndroid Weekly\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201405/09/536c728d1ad28.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201405/09/536c728d1ad28_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAndroid Weekly相当于是Android开发社区的实时通讯录，每周报导Android最新讯息，包括新的库、工具和博客等，只要你有Email，就可以对其进行订阅，了解更多关于安卓的消息。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：\u003ca href=\"http://mobilehub.io/products/Android-Weekly\"\u003eAndroid Weekly的mobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e6. \u003ca href=\"http://androidniceties.tumblr.com/\"\u003eAndroid Niceties\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201405/09/536c731f193e7.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201405/09/536c731f193e7_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAndroid Niceties集合了Android生态系统中一些精心设计、优雅精美的Android程序，是启发灵感的好资源。Android Niceties覆盖面极好，来自主要的平台应用比如Duolingo、Expedia、Etsy和之前依序还不为人知的Muzei、Timely和Pocket。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：\u003ca href=\"http://mobilehub.io/products/Android-Niceties\"\u003eAndroid Niceties的mobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e7. \u003ca href=\"https://github.com/xxv/android-lifecycle\"\u003eAndroid Lifecycle\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201405/09/536c7359a79ba.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201405/09/536c7359a79ba_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e展现了完整的Android片段和Activity的生命周期，Activity从新建到销毁，构成了一个生命周期，但要知道生命周期并不仅仅只包括这两个。而Android Lifecycle打印出的表图概述了Activity与Fragment在应用内部与外部和用户交互的流。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：\u003ca href=\"http://mobilehub.io/products/Android-Lifecycle\"\u003eAndroid Lifecycle的mobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e8. \u003ca href=\"http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html\"\u003eAndroid Asset Studio\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201405/09/536c738579937.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201405/09/536c738579937_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这个网站已提供了大量的工具来简化创建各种Android相关的资源，包括启动栏图标、通知图标和导航抽屉图标等，让你不再为设计应用图标而发愁。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：\u003ca href=\"http://mobilehub.io/products/Android-Asset-Studio\"\u003eAndroid Asset Studio的mobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e9. \u003ca href=\"http://android-holo-colors.com/\"\u003eAndroid Holo Colors Generator\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201405/09/536c73b4810c6.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201405/09/536c73b4810c6_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e制作更加精美的图标，可以前往Android Asset Studio进行设计。该网站提供应用所需要的所有图标的生成工具，包括菜单图标、动作栏图标、标签栏图标、通知图标等，而且操作简单易行。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：\u003ca href=\"http://mobilehub.io/products/Android-Holo-Colors-Generator\"\u003eAndroid Holo Colors Generator的mobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e10. \u003ca href=\"http://jennift.com/dpical.html\"\u003eDPI Calculator for Android\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201405/09/536c73e58c6c2.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201405/09/536c73e58c6c2_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e就像它的名字一样，这是一款专门用于Android平台的分辨率计算器，使用很简单，用户通过输入长、宽、对角线等，就可以计算出屏幕的实际分辨率来。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e11. \u003ca href=\"https://www.youtube.com/user/androiddevelopers\"\u003eAndroid Developers YouTube Channel\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e","title":"开发者必备的十二大Android开发资源"},{"content":"针对安卓APP的 OCR图片识别技术研究与 DEMO： 鉴于大家都给我发私信要源码：现在更新源码 在下载（由于最近CSDN下载分不够了。。所以要了10分 还希望大家理解哦） http://download.csdn.net/detail/wei2253498/7146411\n通过近端时间的在网络上的学习，了解了俩个OCR的技术，包括tesseract 和 openCv这俩个技术\n主要研究了tesseract的OCR技术，并通过模拟器做了个demo app下面与大家分享过程，希望共同进步。\nTesseract OCR引擎是1995年UNLVAccuracy大赛中的排名前三的引擎。1995年到2006年间，它没有大的改进；之后，它被谷歌大幅改进，很可能是识别率最高的可用开源OCR引擎之一了。结合Leptonica图像处理库，它能读取各种各样格式的图像文件，识别出超过40多种语言的文本。\nTesseract的下载地址为：\nhttp://code.google.com/p/tesseract-ocr/downloads/list\nTesseract for android 的 tess-two下载地址为：\nhttps://github.com/rmtheis/tess-two/archive/master.zip\n接下来需要对下载下来的tess-two进行编译\n如何用android ndk进行so的编译我放在了另外的一个文档中，大家请参考\n也可以直接下载编译好的tess-two so文件\nhttp://download.csdn.net/detail/uniquerhythm/5166651\n编译好后，将src下的两个包以及libs导入到自己的项目就可以用啦\n接下来我们还需要 tessract的android jar包\nAndroid官方地址:tesseract-android-tools\nhttp://code.google.com/p/tesseract-android-tools/downloads/list?can=1\u0026amp;q=\n但它必须要一个匹配库，即tessdata，我们可以从官方拷贝，在前面git的项目里面tesseract源码目录有现成的tessdata可以用，对于中文，googlecode上也有下载，当然也可以自己训练不同语言的tessdata。\n包leptonica的类我们不必使用，只要使用tess包的类就行了\n下面是 tessBaseAPI的主要用法\nTessBaseAPI\n**[java]** [view plain](http://blog.csdn.net/wei2253498/article/details/8748741#)[copy](http://blog.csdn.net/wei2253498/article/details/8748741#)[print](http://blog.csdn.net/wei2253498/article/details/8748741#)[?](http://blog.csdn.net/wei2253498/article/details/8748741#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/274921)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/274921/fork) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//////////////////////华丽的分割线//////////////////////////////////////////////////////\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;TessBaseAPI baseApi=\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TessBaseAPI(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//初始化tess\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//android下面，tessdata肯定得放到sd卡里了\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//如果tessdata这个目录放在sd卡的根目录\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//那么path直接传入sd卡的目录\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//eng就是英文，关于语言，按ISO 639-3标准的代码就行，具体请移步wiki\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;baseApi.init(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tessdata文件夹的父级目录\u0026amp;#8221;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;eng\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//options是为了缩放图片，这个酌情缩放，图片小的话可以不缩放\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;BitmapFactory.Options options=newBitmapFactory.Options(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//缩小为原来的1/2\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;options.inSampleSize=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//bitmap，我这里是以流的形式，只要能形成Bitmap就行\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;Bitmap bitmap = BitmapFactory.decodeStream(instream,\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;,options); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; instream.close(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//设置要ocr的图片bitmap\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;baseApi.setImage(bitmap); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//根据Init的语言，获得ocr后的字符串\u0026lt;/span\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;String text= baseApi.getUTF8Text(); \u0026lt;/span\u0026gt; 通过以上即可对图片进行识别并得到识别文字\n下面是我自身的demo开发的详细过程与大家分享\n首先创建一个界面：主要包括内存图片识别照片识别识别，图片区，以及识别结果区域\n确认之前编译好的so文件以及下载的jar包放入Lib下\n针对tessract 的jar包方法进行程序编写\n因为程序的写法，需要将 tessdata识别库与ocr图片放到SD卡中\n接着，右键项目运行选择android，（android环境的配置请参考李涛的分享文档）\n运行：接下来就是漫长的等待。。。。\n运行成功：\n最终运行结果：成功\n结论：对于tesseract的识别如果换成其他字体或手写体，则需要手工的训练tesseract的识别字体库及放入SD卡中tessdata文件夹中的文件\n现还有一些问题需要大家一起来共同克服完成\n1. 照相机功能\n2. 对于手写字体的识别训练的识别率的控制\n针对于tessdata的训练，我这里还有一个网址，大家可以上去学习一下相信会有作用\nTesseract-OCR字符识别-样书训练\nhttp://www.myexception.cn/mobile/1119147.html\n以上就是我近期的技术研究以及demo，与大家分享希望共同进步，如大家有问题，可以随时找我沟通！\n源码以及程序找不到可以找我联系！站内短信 或者 回复哦！\n转自：http://blog.csdn.net/wei2253498/article/details/8748741\n","permalink":"https://blog.zdltech.com/posts/%E5%AE%89%E5%8D%93%E5%9B%BE%E7%89%87ocr%E8%AF%86%E5%88%AB%E6%8A%80%E6%9C%AF-tesseract%E7%A0%94%E7%A9%B6%E6%96%87%E6%A1%A3/","summary":"\u003ch2 id=\"针对安卓app的ocr图片识别技术研究与demo\"\u003e针对安卓APP的 OCR图片识别技术研究与 DEMO：\u003c/h2\u003e\n\u003cp\u003e鉴于大家都给我发私信要源码：现在更新源码 在下载（由于最近CSDN下载分不够了。。所以要了10分 还希望大家理解哦）                                                             \u003ca href=\"http://download.csdn.net/detail/wei2253498/7146411\"\u003ehttp://download.csdn.net/detail/wei2253498/7146411\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e通过近端时间的在网络上的学习，了解了俩个OCR的技术，包括tesseract 和 openCv这俩个技术\u003c/p\u003e\n\u003cp\u003e主要研究了tesseract的OCR技术，并通过模拟器做了个demo app下面与大家分享过程，希望共同进步。\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: red;\"\u003eTesseract OCR\u003c/span\u003e引擎是1995年UNLVAccuracy大赛中的排名前三的引擎。1995年到2006年间，它没有大的改进；之后，它被谷歌大幅改进，很可能是识别率最高的可用开源OCR引擎之一了。结合Leptonica图像处理库，它能读取各种各样格式的图像文件，识别出超过40多种语言的文本。\u003c/p\u003e\n\u003cp\u003eTesseract的下载地址为：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://code.google.com/p/tesseract-ocr/downloads/list\"\u003e\u003cspan style=\"color: windowtext;\"\u003ehttp://code.google.com/p/tesseract-ocr/downloads/list\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eTesseract for android 的\u003cspan style=\"color: red;\"\u003e tess-two\u003c/span\u003e下载地址为：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/rmtheis/tess-two/archive/master.zip\"\u003ehttps://github.com/rmtheis/tess-two/archive/master.zip\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e接下来需要对下载下来的tess-two进行编译\u003c/p\u003e\n\u003cp\u003e如何用android ndk进行so的编译我放在了另外的一个文档中，大家请参考\u003c/p\u003e\n\u003cp\u003e也可以直接下载编译好的tess-two  so文件\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://download.csdn.net/detail/uniquerhythm/5166651\"\u003e\u003cspan style=\"color: #0000ff;\"\u003ehttp://download.csdn.net/detail/uniquerhythm/5166651\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e编译好后，将src下的两个包以及libs导入到自己的项目就可以用啦\u003c/p\u003e\n\u003cp\u003e接下来我们还需要 tessract的android jar包\u003c/p\u003e\n\u003cp\u003eAndroid官方地址:tesseract-android-tools\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://code.google.com/p/tesseract-android-tools/downloads/list?can=1\u0026amp;q=\"\u003ehttp://code.google.com/p/tesseract-android-tools/downloads/list?can=1\u0026amp;q=\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e但它必须要一个匹配库，即tessdata，我们可以从官方拷贝，在前面git的项目里面tesseract源码目录有现成的tessdata可以用，对于中文，googlecode上也有下载，当然也可以自己训练不同语言的tessdata。\u003c/p\u003e\n\u003cp\u003e包leptonica的类我们不必使用，只要使用tess包的类就行了\u003c/p\u003e\n\u003cp\u003e下面是 tessBaseAPI的主要用法\u003c/p\u003e\n\u003cp\u003eTessBaseAPI\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/wei2253498/article/details/8748741#)[copy](http://blog.csdn.net/wei2253498/article/details/8748741#)[print](http://blog.csdn.net/wei2253498/article/details/8748741#)[?](http://blog.csdn.net/wei2253498/article/details/8748741#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/274921)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/274921/fork)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//////////////////////华丽的分割线//////////////////////////////////////////////////////\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;TessBaseAPI baseApi=\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; TessBaseAPI();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//初始化tess\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//android下面，tessdata肯定得放到sd卡里了\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//如果tessdata这个目录放在sd卡的根目录\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//那么path直接传入sd卡的目录\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//eng就是英文，关于语言，按ISO 639-3标准的代码就行，具体请移步wiki\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;baseApi.init(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;tessdata文件夹的父级目录\u0026amp;#8221;\u0026lt;/span\u0026gt;,\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: blue;\u0026quot;\u0026gt;\u0026amp;#8220;eng\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//options是为了缩放图片，这个酌情缩放，图片小的话可以不缩放\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;BitmapFactory.Options options=newBitmapFactory.Options();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//缩小为原来的1/2\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;options.inSampleSize=\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;2\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//bitmap，我这里是以流的形式，只要能形成Bitmap就行\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;Bitmap bitmap = BitmapFactory.decodeStream(instream,\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;,options);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        instream.close();      \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//设置要ocr的图片bitmap\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;baseApi.setImage(bitmap);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;comment\u0026quot; style=\u0026quot;color: #008200;\u0026quot;\u0026gt;//根据Init的语言，获得ocr后的字符串\u0026lt;/span\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;String text= baseApi.getUTF8Text();  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e","title":"安卓图片OCR识别技术 tesseract研究文档"},{"content":"点击这里下载第一种代码 最近完成了毕业设计，论文名为基于图像识别的移动人口管理系统。编写过程中学到了几种图像识别的技术，先写下来与大家分享。\n第一种，直接使用免费得图像识别web服务器 地址为http://maggie.ocrgrid.org/\n实现代码：1.为了提高图像的识别率，首先要灰度化\n**[java]** [view plain](http://blog.csdn.net/dannor2010/article/details/7073528#)[copy](http://blog.csdn.net/dannor2010/article/details/7073528#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap convertToGrayscale(Bitmap bitmap) { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ColorMatrix colorMatrix = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ColorMatrix(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; colorMatrix.setSaturation(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Paint paint = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; ColorMatrixColorFilter cmcf = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ColorMatrixColorFilter(colorMatrix); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; paint.setColorFilter(cmcf); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Bitmap result = Bitmap.createBitmap(bitmap.getWidth(), bitmap \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; .getHeight(), Bitmap.Config.RGB_565); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Canvas drawingCanvas = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Canvas(result); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Rect src = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, bitmap.getWidth(), bitmap.getHeight()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Rect dst = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect(src); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; drawingCanvas.drawBitmap(bitmap, src, dst, paint); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; result; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; 2.将灰度化的图像上传到http://maggie.ocrgrid.org/ 方法和类就不说了，有需要的话可以发我邮箱\n第二种，使用Aprise开源\n这个开源代码虽然一般处理认证图像，但也可以实现图像识别，你只需将它引入你的服务器，至于如何在android中实现，映像中好像不能使用其中方法，将灰度化（方法可看第一种的第一步）后的图像上传即可\n第三种，使用Tesseract开源\n这个开源代码是使用c++来编写的，你要实现的就必须学会java的jni技术，以及android NDK方法\n第四种，Mezzofanti_java_code_1_0_3\n这是一个基于android开源的图像识别软件，你只需下载他，重写里面的一些代码，即可实现，前提是你要读懂里面的代码\n","permalink":"https://blog.zdltech.com/posts/%E5%AE%9E%E7%8E%B0android%E5%9B%BE%E5%83%8F%E8%AF%86%E5%88%AB%E7%9A%84%E5%87%A0%E7%A7%8D%E6%96%B9%E6%B3%95/","summary":"\u003ch1\u003e\u003ca href=\"http://download.csdn.net/detail/dannor2010/4948850\"\u003e\u003cspan style=\"color: #ff0000;\"\u003e点击这里下载第一种代码\u003c/span\u003e\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003e最近完成了毕业设计，论文名为基于图像识别的移动人口管理系统。编写过程中学到了几种图像识别的技术，先写下来与大家分享。\u003c/p\u003e\n\u003cp\u003e第一种，直接使用免费得图像识别web服务器 地址为http://maggie.ocrgrid.org/\u003c/p\u003e\n\u003cp\u003e实现代码：1.为了提高图像的识别率，首先要灰度化\u003c/p\u003e\n\u003cdiv class=\"dp-highlighter bg_java\"\u003e\n  \u003cdiv class=\"bar\"\u003e\n    \u003cdiv class=\"tools\" style=\"color: silver;\"\u003e\n      **[java]** [view plain](http://blog.csdn.net/dannor2010/article/details/7073528#)[copy](http://blog.csdn.net/dannor2010/article/details/7073528#)\n\u003cpre\u003e\u003ccode\u003e  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n  \n  \u0026lt;div\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;private\u0026lt;/span\u0026gt; Bitmap convertToGrayscale(Bitmap bitmap) {  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        ColorMatrix colorMatrix = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ColorMatrix();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        colorMatrix.setSaturation(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Paint paint = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Paint();  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        ColorMatrixColorFilter cmcf = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; ColorMatrixColorFilter(colorMatrix);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        paint.setColorFilter(cmcf);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Bitmap result = Bitmap.createBitmap(bitmap.getWidth(), bitmap  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;                .getHeight(), Bitmap.Config.RGB_565);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Canvas drawingCanvas = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Canvas(result);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Rect src = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, \u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;, bitmap.getWidth(), bitmap.getHeight());  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        Rect dst = \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;new\u0026lt;/span\u0026gt; Rect(src);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        drawingCanvas.drawBitmap(bitmap, src, dst, paint);  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: #006699;\u0026quot;\u0026gt;return\u0026lt;/span\u0026gt; result;  \u0026lt;/span\u0026gt;\n\n- \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003cp\u003e2.将灰度化的图像上传到http://maggie.ocrgrid.org/ 方法和类就不说了，有需要的话可以发我邮箱\u003c/p\u003e","title":"实现android图像识别的几种方法"},{"content":"随着iOS依赖管理工具CocoaPods和大量第三方开源库成熟起来，业界积累了大量的优秀开源项目。不久之前，Facebook推出了旗下移动新闻阅读应用Paper，便动用了将近100个第三方开源库，极大地简化了自己的应用开发任务。\n移动开发生态圈日益完善，基础的开源组件也越来越丰富，而Facebook不仅取之开源，更不断地开源其内部项目，将成果反馈给开源社区，与开发者共享。接下来，就让我们一起来看看那些年Facebook在移动开发方面所推出的众多开源项目。\n1. KVOController\nKVOController是Facebook开源的一款简单安全的KVO（Key-Value Observing，键值观察，Objective-C中定义的一个通知机制）工具，用于iOS和Mac OS X应用开发中。KVOController基于Cocoa经过时间考验的KVO实现开发而成，它提供了一个简洁方便、线程安全的API。\n主要特性：\n使用Blocks、自定义Actions或NSKeyValueObserving回调进行通知； 观测者移除时无异常； 控制器dealloc时移除隐式观测者； 提升使用NSKeyValueObservingInitial的性能； 为恢复观测者提供特殊防护的线程安全。 相关链接：KVOController的GitHub托管地址、mobilehub主页\n2. Shimmer\nShimmer是一款开源的加载效果工具，能够非常简单地向应用中的任何视图添加闪闪发光的字体效果，并且不会显得突兀。Shimmer最初是Facebook于今年1月所推出的Paper的开发过程中所使用到的工具，后被Facebook基于BSD许可协议开源，支持iOS 6及其以上系统。\n相关链接：Shimmer的GitHub托管地址、mobilehub主页\n3. Rebound\nRebound是Facebook推出的一款Android的物理和动画库，于2013年10月在Mobile@Scale大会上正式发布，旨在解决笨重、缓慢的传统移动网络界面。Rebound基于BSD许可协议，兼容HTML5和Node.js。\nRebound不是一款通用物理库，但其弹簧模型在应用程序中引入了现实世界的物理，易于集成，创建的动画能够让人感觉到非常自然，可用于滚动条、切换开关、呼叫等场景下。\n相关链接：Rebound官网、GitHub托管地址、mobilehub主页\n4. Buck\nBuck是Facebook开发的一款开源Android Build工具，基于Apache License 2.0协议发布，可以通过独立构建并行来发挥多核的性能，加速开发者的Android应用构建流程。Buck基于单一的库构建，能够以最小的资源集重建，非常适用于Android项目组织与管理。\n主要特性：\n加速Android构建。充分发挥多核处理器的优势，并行构建独立模块。通过追踪没有变化的源文件，减少增量构建实践，最少化需要重建的资源。 对于不支持开箱即用的Android Ant编译脚本，引进ad-doc构建系统。 在构建系统里保持生成构建的逻辑，无需另外的系统生成构建文件。 基于构建规则生成一个Intellij项目，能同时匹配本地IDE以及无头文件编译开发。 支持单元测试，选用最均衡的方式获得代码覆盖率。 相关链接：Buck官网、Github托管地址、mobilehub主页\n5. xctool\nxctool是Facebook推出的另一款开源的应用构建工具，基于Apache License 2.0协议发布，用于取代苹果的xcodebuild，来简化iOS和Mac项目的构建和测试。xctool对于持续集成可谓大有裨益，其最大的好处就是可以直接从命令行构建和运行单元测试。\nxctool在xcodebuild的基础上还添加了一些额外的功能，比如支持将构建和测试结果结构化输出；界面友好，支持ANSI彩色输出；速度更快，支持进行并行测试，使得运行速度提升2~3倍等。xctool支持Xcode 5+，并且，在使用xctool时必须安装Xcode命令行工具。\n主要特性：\n作为Xcode.app运行相同的测试； 构建输出和测试结果均为JSON格式，无需解析输出； xctool只有在发现错误的时候才打印消息，而xcodebuild对每个源文件都会打印。 相关链接：xctool的GitHub托管地址、mobilehub主页****\n6. Conceal\nConceal是一套用于Android平台上进行文件加密和鉴权的Java API，专为速度设计，小巧而高速。它使用了OpenSSL算法的子集和一些预先定义的选项，能够让库保持在较小的体积。通过它，开发者可以实现对手机、平板电脑SD卡中的数据以及大型文件进行加密和存储。\n相关链接：Conceal官网、GitHub托管地址、mobilehub主页\n7. Origami\n在界面和交互设计上颇让人惊喜的Paper让Facebook的大量开源工具从幕后走向了台前，Origami即为其中之一。这个被盛赞为“交互神器”的设计师新宠，是Facebook设计团队花费了9个月时间开发的一款基于Quartz Composer的插件，能够让设计师无需编程，快速构建移动应用交互原型。\nOrigami为设计师提供了开关、滚动、弹性动画等一系列自定义控件，并对Quartz Composer进行了改善，比如支持Retina显示器、重新设计工具栏图标等，以帮助设计师更为轻便地实现应用原型交互。\n相关链接：Origami官网、GitHub托管地址、mobilehub主页\n8. Bolts（iOS / Android）\nBolts是一个面向iOS和Android的底层库集合，分别为Bolts-iOS和Bolts-Android，由Facebook和Parse共同设计完成，于2014年1月基于BSD许可协议开源，其所有源码均托管到GitHub上。Bolts能够让移动应用开发变得更加简单，其组件与Parse及Facebook服务完全无关，因此，开发者无需拥有Parse或Facebook开发者账户即可直接使用。\n相关链接：Bolts的Github托管地址、mobilehub主页\n9. Facebook SDK（iOS / Android）\nFacebook SDK for iOS（Android）是Facebook官方为iOS（Android）平台提供的Facebook API的SDK，允许开发者将Facebook集成到所开发的iOS（Android）应用中。\n相关链接：Facebook SDK的GitHub托管地址（iOS / Android）、mobilehub主页（iOS /Android）\n10. fishhook\n最后，再来介绍一款专门用于iOS安全攻防的开源库。fishhook是Facebook推出的一款能够直接在iOS模拟器及设备上动态修改链接Mach-O符号表的工具。fishhook通过改变间接符号表的偏移量，提供一个假的nlist结构体，从而达到hook的目的，其功能很类似于在OS X上使用DYLD_INTERPOSE。\n相关链接：fishhook的GitHub托管地址、mobilehub主页\n","permalink":"https://blog.zdltech.com/posts/%E7%9B%B4%E6%8E%A5%E6%8B%BF%E6%9D%A5%E7%94%A8facebook%E7%A7%BB%E5%8A%A8%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E5%A4%A7%E5%90%88%E9%9B%86/","summary":"\u003cp\u003e随着iOS依赖管理工具CocoaPods和大量第三方开源库成熟起来，业界积累了大量的优秀开源项目。不久之前，Facebook推出了旗下移动新闻阅读应用Paper，便动用了将近100个第三方开源库，极大地简化了自己的应用开发任务。\u003c/p\u003e\n\u003cp\u003e移动开发生态圈日益完善，基础的开源组件也越来越丰富，而Facebook不仅取之开源，更不断地开源其内部项目，将成果反馈给开源社区，与开发者共享。接下来，就让我们一起来看看那些年Facebook在移动开发方面所推出的众多开源项目。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. \u003ca href=\"https://code.facebook.com/projects/743990372287218/kvocontroller/\"\u003eKVOController\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eKVOController是Facebook开源的一款简单安全的KVO（Key-Value Observing，键值观察，Objective-C中定义的一个通知机制）工具，用于iOS和Mac OS X应用开发中。KVOController基于Cocoa经过时间考验的KVO实现开发而成，它提供了一个简洁方便、线程安全的API。\u003c/p\u003e\n\u003cp\u003e主要特性：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e使用Blocks、自定义Actions或NSKeyValueObserving回调进行通知；\u003c/li\u003e\n\u003cli\u003e观测者移除时无异常；\u003c/li\u003e\n\u003cli\u003e控制器dealloc时移除隐式观测者；\u003c/li\u003e\n\u003cli\u003e提升使用NSKeyValueObservingInitial的性能；\u003c/li\u003e\n\u003cli\u003e为恢复观测者提供特殊防护的线程安全。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：KVOController的\u003ca href=\"https://github.com/facebook/KVOController\"\u003eGitHub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/kvocontroller\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. \u003ca href=\"https://code.facebook.com/projects/1443302199240755/shimmer/\"\u003eShimmer\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eShimmer是一款开源的加载效果工具，能够非常简单地向应用中的任何视图添加闪闪发光的字体效果，并且不会显得突兀。Shimmer最初是Facebook于今年1月所推出的Paper的开发过程中所使用到的工具，后被Facebook基于BSD许可协议开源，支持iOS 6及其以上系统。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201404/22/53563bfd3c911.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/22/53563bfd3c911.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：Shimmer的\u003ca href=\"https://github.com/facebook/Shimmer\"\u003eGitHub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/shimmer\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. \u003ca href=\"https://code.facebook.com/projects/1453872284839859/rebound/\"\u003eRebound\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eRebound是Facebook推出的一款Android的物理和动画库，于2013年10月在Mobile@Scale大会上正式发布，旨在解决笨重、缓慢的传统移动网络界面。Rebound基于BSD许可协议，兼容HTML5和Node.js。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201404/23/53574eacbe067.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/23/53574eacbe067_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eRebound不是一款通用物理库，但其弹簧模型在应用程序中引入了现实世界的物理，易于集成，创建的动画能够让人感觉到非常自然，可用于滚动条、切换开关、呼叫等场景下。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：\u003ca href=\"http://facebook.github.io/rebound/\"\u003eRebound官网\u003c/a\u003e、\u003ca href=\"https://github.com/facebook/rebound\"\u003eGitHub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/rebound\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4. \u003ca href=\"https://code.facebook.com/projects/484285361686998/buck/\"\u003eBuck\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eBuck是Facebook开发的一款开源Android Build工具，基于Apache License 2.0协议发布，可以通过独立构建并行来发挥多核的性能，加速开发者的Android应用构建流程。Buck基于单一的库构建，能够以最小的资源集重建，非常适用于Android项目组织与管理。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201404/23/53575e26ab82c.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/23/53575e26ab82c.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e主要特性：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e加速Android构建。充分发挥多核处理器的优势，并行构建独立模块。通过追踪没有变化的源文件，减少增量构建实践，最少化需要重建的资源。\u003c/li\u003e\n\u003cli\u003e对于不支持开箱即用的Android Ant编译脚本，引进ad-doc构建系统。\u003c/li\u003e\n\u003cli\u003e在构建系统里保持生成构建的逻辑，无需另外的系统生成构建文件。\u003c/li\u003e\n\u003cli\u003e基于构建规则生成一个Intellij项目，能同时匹配本地IDE以及无头文件编译开发。\u003c/li\u003e\n\u003cli\u003e支持单元测试，选用最均衡的方式获得代码覆盖率。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：\u003ca href=\"http://facebook.github.io/buck/\"\u003eBuck官网\u003c/a\u003e、\u003ca href=\"https://github.com/facebook/buck\"\u003eGithub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/buck\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e5. \u003ca href=\"https://code.facebook.com/projects/359440610825631/xctool/\"\u003exctool\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003exctool是Facebook推出的另一款开源的应用构建工具，基于Apache License 2.0协议发布，用于取代苹果的xcodebuild，来简化iOS和Mac项目的构建和测试。xctool对于持续集成可谓大有裨益，其最大的好处就是可以直接从命令行构建和运行单元测试。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201404/23/53572eee5288e.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/23/53572eee5288e.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003exctool在xcodebuild的基础上还添加了一些额外的功能，比如支持将构建和测试结果结构化输出；界面友好，支持ANSI彩色输出；速度更快，支持进行并行测试，使得运行速度提升2~3倍等。xctool支持Xcode 5+，并且，在使用xctool时必须安装Xcode命令行工具。\u003c/p\u003e\n\u003cp\u003e主要特性：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e作为Xcode.app运行相同的测试；\u003c/li\u003e\n\u003cli\u003e构建输出和测试结果均为JSON格式，无需解析输出；\u003c/li\u003e\n\u003cli\u003exctool只有在发现错误的时候才打印消息，而xcodebuild对每个源文件都会打印。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：xctool的\u003c/strong\u003e\u003ca href=\"https://github.com/facebook/xctool\"\u003eGitHub托管地址\u003c/a\u003e\u003cstrong\u003e、\u003c/strong\u003e\u003ca href=\"http://mobilehub.io/products/xctool\"\u003emobilehub主页\u003c/a\u003e****\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e6. \u003ca href=\"https://code.facebook.com/projects/670004029712050/conceal/\"\u003eConceal\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eConceal是一套用于Android平台上进行文件加密和鉴权的Java API，专为速度设计，小巧而高速。它使用了OpenSSL算法的子集和一些预先定义的选项，能够让库保持在较小的体积。通过它，开发者可以实现对手机、平板电脑SD卡中的数据以及大型文件进行加密和存储。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：\u003ca href=\"http://facebook.github.io/conceal/\"\u003eConceal官网\u003c/a\u003e、\u003ca href=\"https://github.com/facebook/conceal\"\u003eGitHub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/conceal\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e7. \u003ca href=\"https://code.facebook.com/projects/585454078205590/origami/\"\u003eOrigami\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在界面和交互设计上颇让人惊喜的Paper让Facebook的大量开源工具从幕后走向了台前，Origami即为其中之一。这个被盛赞为“交互神器”的设计师新宠，是Facebook设计团队花费了9个月时间开发的一款基于Quartz Composer的插件，能够让设计师无需编程，快速构建移动应用交互原型。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201404/23/53577802688a5.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/23/53577802688a5_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eOrigami为设计师提供了开关、滚动、弹性动画等一系列自定义控件，并对Quartz Composer进行了改善，比如支持Retina显示器、重新设计工具栏图标等，以帮助设计师更为轻便地实现应用原型交互。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：\u003ca href=\"http://facebook.github.io/origami\"\u003eOrigami官网\u003c/a\u003e、\u003ca href=\"https://github.com/facebook/origami\"\u003eGitHub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/origami\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e8. Bolts（\u003ca href=\"https://github.com/BoltsFramework/Bolts-iOS\"\u003eiOS\u003c/a\u003e / \u003ca href=\"https://github.com/BoltsFramework/Bolts-Android\"\u003eAndroid\u003c/a\u003e）\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eBolts是一个面向iOS和Android的底层库集合，分别为Bolts-iOS和Bolts-Android，由Facebook和Parse共同设计完成，于2014年1月基于BSD许可协议开源，其所有源码均托管到GitHub上。Bolts能够让移动应用开发变得更加简单，其组件与Parse及Facebook服务完全无关，因此，开发者无需拥有Parse或Facebook开发者账户即可直接使用。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：Bolts的\u003ca href=\"https://github.com/BoltsFramework\"\u003eGithub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/bolts\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e9. Facebook SDK（\u003ca href=\"https://developers.facebook.com/docs/ios\"\u003eiOS\u003c/a\u003e / \u003ca href=\"https://developers.facebook.com/docs/android\"\u003eAndroid\u003c/a\u003e）\u003c/strong\u003e\u003c/p\u003e","title":"直接拿来用！Facebook移动开源项目大合集"},{"content":"Jsoup是一个非常好的解析网页的包，用java开发的，提供了类似DOM，CSS选择器的方式来查找和提取文档中的内容。\n相关资料如下：\n下载地址：[http://jsoup.org/download](http://jsoup.org/download) 中文文档资料：[http://www.open-open.com/jsoup/](http://www.open-open.com/jsoup/) 比较好的文档：[http://www.ostools.net/apidocs/apidoc?api=jsoup-1.6.3](http://www.ostools.net/apidocs/apidoc?api=jsoup-1.6.3) \u0026amp;nbsp; 今天做了一个Jsoup解析网站的项目，使用Jsoup.connect(url).get()连接某网站时偶尔会出现 java.net.SocketTimeoutException:Read timed out异常。 原因是默认的Socket的延时比较短，而有些网站的响应速度比较慢， 所以会发生超时的情况。 解决方法： 链接的时候设定超时时间即可。 doc = Jsoup.connect(url).timeout(5000).get(); 5000表示延时时间设置为5s。 测试代码如下： 1，不设定timeout时： \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot; style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; **[java]** [view plain](http://blog.csdn.net/huangxy10/article/details/8188067#)[copy](http://blog.csdn.net/huangxy10/article/details/8188067#)[print](http://blog.csdn.net/huangxy10/article/details/8188067#)[?](http://blog.csdn.net/huangxy10/article/details/8188067#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; jsoupTest; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.IOException; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.*; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.helper.Validate; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.nodes.Document; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.nodes.Element; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.select.Elements; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; JsoupTest { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; main(String[] args) \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; IOException{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; String url = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;http://www.weather.com.cn/weather/101010400.shtml\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; start = System.currentTimeMillis(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Document doc=\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; doc = Jsoup.connect(url).get(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt;(Exception e){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; e.printStackTrace(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;finally\u0026lt;/span\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;Time is:\u0026amp;#8221;\u0026lt;/span\u0026gt;+(System.currentTimeMillis()-start) + \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;ms\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Elements elem = doc.getElementsByTag(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;Title\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;Title is:\u0026amp;#8221;\u0026lt;/span\u0026gt; +elem.text()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; **\u0026lt;span style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;有时发生超时：\u0026lt;/span\u0026gt; \u0026lt;span style=\u0026quot;color: #ff0000;\u0026quot;\u0026gt;java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(Unknown Source) at java.net.SocketInputStream.read(Unknown Source) at java.io.BufferedInputStream.fill(Unknown Source) at java.io.BufferedInputStream.read1(Unknown Source) at java.io.BufferedInputStream.read(Unknown Source) at sun.net.www.http.ChunkedInputStream.fastRead(Unknown Source) at sun.net.www.http.ChunkedInputStream.read(Unknown Source) at java.io.FilterInputStream.read(Unknown Source) at sun.net.www.protocol.http.HttpURLConnectionHttpInputStream.read(Unknown Source) at java.util.zip.InflaterInputStream.fill(Unknown Source) at java.util.zip.InflaterInputStream.read(Unknown Source) at java.util.zip.GZIPInputStream.read(Unknown Source) at java.io.BufferedInputStream.read1(Unknown Source) at java.io.BufferedInputStream.read(Unknown Source) at java.io.FilterInputStream.read(Unknown Source) at org.jsoup.helper.DataUtil.readToByteBuffer(DataUtil.java:113) at org.jsoup.helper.HttpConnectionResponse.execute(HttpConnection.java:447) at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:393) at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:159) at org.jsoup.helper.HttpConnection.get(HttpConnection.java:148) at jsoupTest.JsoupTest.main(JsoupTest.java:17) Time is:3885ms Exception in thread “main” java.lang.NullPointerException at jsoupTest.JsoupTest.main(JsoupTest.java:25)\n2,设定了则一般不会超时 \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot; style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt; \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt; \u0026lt;b\u0026gt;[java]** [view plain](http://blog.csdn.net/huangxy10/article/details/8188067#)[copy](http://blog.csdn.net/huangxy10/article/details/8188067#)[print](http://blog.csdn.net/huangxy10/article/details/8188067#)[?](http://blog.csdn.net/huangxy10/article/details/8188067#) \u0026lt;div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; jsoupTest; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.IOException; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.*; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.helper.Validate; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.nodes.Document; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.nodes.Element; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.select.Elements; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; JsoupTest { \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; main(String[] args) \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; IOException{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; String url = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;http://www.weather.com.cn/weather/101010400.shtml\u0026amp;#8221;\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; start = System.currentTimeMillis(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Document doc=\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;; \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; doc = Jsoup.connect(url).timeout(\u0026lt;span class=\u0026quot;number\u0026quot; style=\u0026quot;color: #c00000;\u0026quot;\u0026gt;5000\u0026lt;/span\u0026gt;).get(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt;(Exception e){ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; e.printStackTrace(); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;finally\u0026lt;/span\u0026gt;{ \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;Time is:\u0026amp;#8221;\u0026lt;/span\u0026gt;+(System.currentTimeMillis()-start) + \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;ms\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; Elements elem = doc.getElementsByTag(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;Title\u0026amp;#8221;\u0026lt;/span\u0026gt;); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;Title is:\u0026amp;#8221;\u0026lt;/span\u0026gt; +elem.text()); \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt; } \u0026lt;/span\u0026gt; - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;} \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;br style=\u0026quot;color: #362e2b;\u0026quot; /\u0026gt;\u0026lt;span style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;输出为：\u0026lt;/span\u0026gt; Time is:4158ms Title is:顺义天气预报-今日_明日_一周天气预报:16日星期五 多云转晴 11/-4℃\n转自http://blog.csdn.net/huangxy10/article/details/8188067 ","permalink":"https://blog.zdltech.com/posts/java-%E7%BD%91%E9%A1%B5%E8%A7%A3%E6%9E%90%E5%B7%A5%E5%85%B7%E5%8C%85-jsoup/","summary":"\u003cp\u003eJsoup是一个非常好的解析网页的包，用java开发的，提供了类似DOM，CSS选择器的方式来查找和提取文档中的内容。\u003c/p\u003e\n\u003cp\u003e相关资料如下：\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e下载地址：[http://jsoup.org/download](http://jsoup.org/download)\n\n\n\n\n\n中文文档资料：[http://www.open-open.com/jsoup/](http://www.open-open.com/jsoup/)\n\n\n\n\n\n比较好的文档：[http://www.ostools.net/apidocs/apidoc?api=jsoup-1.6.3](http://www.ostools.net/apidocs/apidoc?api=jsoup-1.6.3)\n\n\n\n\n\n\u0026amp;nbsp;\n\n\n\n\n\n今天做了一个Jsoup解析网站的项目，使用Jsoup.connect(url).get()连接某网站时偶尔会出现\n\n\n\n\n\njava.net.SocketTimeoutException:Read timed out异常。\n\n\n\n\n\n原因是默认的Socket的延时比较短，而有些网站的响应速度比较慢，\n\n\n\n\n\n所以会发生超时的情况。\n\n\n\n\n\n\n\n  解决方法：\n\n\n\n\n\n  链接的时候设定超时时间即可。\n\n\n\n\n\n  doc = Jsoup.connect(url).timeout(5000).get();\n\n\n\n\n\n  5000表示延时时间设置为5s。\n\n\n\n\n\n  \n\n    测试代码如下：\n  \n\n  \n  \n\n    \n\n      1，不设定timeout时：\n    \n\n    \n    \n\n      \u0026lt;div class=\u0026quot;dp-highlighter bg_java\u0026quot; style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;\n        \u0026lt;div class=\u0026quot;bar\u0026quot;\u0026gt;\n          \u0026lt;div class=\u0026quot;tools\u0026quot; style=\u0026quot;color: silver;\u0026quot;\u0026gt;\n            **[java]** [view plain](http://blog.csdn.net/huangxy10/article/details/8188067#)[copy](http://blog.csdn.net/huangxy10/article/details/8188067#)[print](http://blog.csdn.net/huangxy10/article/details/8188067#)[?](http://blog.csdn.net/huangxy10/article/details/8188067#)\n\n            \n            \u0026lt;div\u0026gt;\n            \u0026lt;/div\u0026gt;\n          \u0026lt;/div\u0026gt;\n        \u0026lt;/div\u0026gt;\n        \n        \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;package\u0026lt;/span\u0026gt; jsoupTest;  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; java.io.IOException;  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.*;  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.helper.Validate;  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.nodes.Document;  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.nodes.Element;  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;import\u0026lt;/span\u0026gt; org.jsoup.select.Elements;  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;class\u0026lt;/span\u0026gt; JsoupTest {  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;public\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;static\u0026lt;/span\u0026gt;  \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;void\u0026lt;/span\u0026gt; main(String[] args) \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;throws\u0026lt;/span\u0026gt; IOException{  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    String url = \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;http://www.weather.com.cn/weather/101010400.shtml\u0026amp;#8221;\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;long\u0026lt;/span\u0026gt; start = System.currentTimeMillis();  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    Document doc=\u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;null\u0026lt;/span\u0026gt;;  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;try\u0026lt;/span\u0026gt;{  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        doc = Jsoup.connect(url).get();  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;catch\u0026lt;/span\u0026gt;(Exception e){  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        e.printStackTrace();  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    \u0026lt;span class=\u0026quot;keyword\u0026quot; style=\u0026quot;font-weight: bold; color: blue;\u0026quot;\u0026gt;finally\u0026lt;/span\u0026gt;{  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;        System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;Time is:\u0026amp;#8221;\u0026lt;/span\u0026gt;+(System.currentTimeMillis()-start) + \u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;ms\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    Elements elem = doc.getElementsByTag(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;Title\u0026amp;#8221;\u0026lt;/span\u0026gt;);  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    System.out.println(\u0026lt;span class=\u0026quot;string\u0026quot; style=\u0026quot;color: red;\u0026quot;\u0026gt;\u0026amp;#8220;Title is:\u0026amp;#8221;\u0026lt;/span\u0026gt; +elem.text());  \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;    }     \u0026lt;/span\u0026gt;\n          \n          - \u0026lt;span style=\u0026quot;color: black;\u0026quot;\u0026gt;}  \u0026lt;/span\u0026gt;\n          \n        \n      \u0026lt;/div\u0026gt;\n      \n      \n\n        **\u0026lt;span style=\u0026quot;color: #362e2b;\u0026quot;\u0026gt;有时发生超时：\u0026lt;/span\u0026gt;\n      \n\n      \n      \n\n        \n\n          \u0026lt;span style=\u0026quot;color: #ff0000;\u0026quot;\u0026gt;java.net.SocketTimeoutException: Read timed out\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eat java.net.SocketInputStream.socketRead0(Native Method)\nat java.net.SocketInputStream.read(Unknown Source)\nat java.net.SocketInputStream.read(Unknown Source)\nat java.io.BufferedInputStream.fill(Unknown Source)\nat java.io.BufferedInputStream.read1(Unknown Source)\nat java.io.BufferedInputStream.read(Unknown Source)\nat sun.net.www.http.ChunkedInputStream.fastRead(Unknown Source)\nat sun.net.www.http.ChunkedInputStream.read(Unknown Source)\nat java.io.FilterInputStream.read(Unknown Source)\nat sun.net.www.protocol.http.HttpURLConnection\u003cspan class=\"katex math inline\"\u003eHttpInputStream.read(Unknown Source)\nat java.util.zip.InflaterInputStream.fill(Unknown Source)\nat java.util.zip.InflaterInputStream.read(Unknown Source)\nat java.util.zip.GZIPInputStream.read(Unknown Source)\nat java.io.BufferedInputStream.read1(Unknown Source)\nat java.io.BufferedInputStream.read(Unknown Source)\nat java.io.FilterInputStream.read(Unknown Source)\nat org.jsoup.helper.DataUtil.readToByteBuffer(DataUtil.java:113)\nat org.jsoup.helper.HttpConnection\u003c/span\u003eResponse.execute(HttpConnection.java:447)\nat org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:393)\nat org.jsoup.helper.HttpConnection.execute(HttpConnection.java:159)\nat org.jsoup.helper.HttpConnection.get(HttpConnection.java:148)\nat jsoupTest.JsoupTest.main(JsoupTest.java:17)\u003c/span\u003e\n\u003cspan style=\"color: #202820;\"\u003eTime is:3885ms\u003c/span\u003e\n\u003cspan style=\"color: #202820;\"\u003eException in thread “main” java.lang.NullPointerException\u003c/span\u003e\n\u003cspan style=\"color: #202820;\"\u003eat jsoupTest.JsoupTest.main(JsoupTest.java:25)\u003c/span\u003e\u003c/p\u003e","title":"java 网页解析工具包 Jsoup"},{"content":"关于站点 技术站点。本人是技术爱好者。\n联系我 QQ：919362477\nEmail:919362477@qq.com\n赏杯咖啡 如果我的博客内容对您有帮助，或者想支持我走下去，请您赏杯咖啡。\n######\n微信打赏 支付宝打赏(henanzhangdongling@163.com) 关于版权 本站文章部分来源于互联网，但因为人力方面的原因，难以做到完美，如发现转载了你的文章而又没标明出处或者你发现这篇文章不是原创而没标明出处，可以在文章评论部分留言，我们会加上原文链接。\n","permalink":"https://blog.zdltech.com/about/","summary":"\u003ch3 id=\"关于站点\"\u003e关于站点\u003c/h3\u003e\n\u003cp\u003e技术站点。本人是技术爱好者。\u003c/p\u003e\n\u003ch3 id=\"联系我\"\u003e联系我\u003c/h3\u003e\n\u003cp\u003eQQ：919362477\u003c/p\u003e\n\u003cp\u003eEmail:919362477@qq.com\u003c/p\u003e\n\u003ch3 id=\"赏杯咖啡\"\u003e赏杯咖啡\u003c/h3\u003e\n\u003cp\u003e如果我的博客内容对您有帮助，或者想支持我走下去，请您赏杯咖啡。\u003c/p\u003e\n\u003cp\u003e######\u003cimg decoding=\"async\" class=\"mui-media-object\" src=\"https://www.zdltech.com/wp-content/uploads/2016/05/weixindashang.png\" /\u003e\u003c/p\u003e\n\u003cdiv class=\"mui-media-body\"\u003e\n  微信打赏\n\u003c/div\u003e\n\u003cimg loading=\"lazy\" decoding=\"async\" class=\"mui-media-object\" src=\"https://www.zdltech.com/wp-content/uploads/2016/05/zhifubaodashang.png\" width=\"228\" height=\"228\" /\u003e \n\u003cdiv class=\"mui-media-body\"\u003e\n  支付宝打赏(henanzhangdongling@163.com)\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003ch4 id=\"关于版权\"\u003e关于版权\u003c/h4\u003e\n\u003cp\u003e本站文章部分来源于互联网，但因为人力方面的原因，难以做到完美，如发现转载了你的文章而又没标明出处或者你发现这篇文章不是原创而没标明出处，可以在文章评论部分留言，我们会加上原文链接。\u003c/p\u003e","title":"关于站点"},{"content":"前段时间做的项目需要添加一个推送的功能,现在应用里边加入推送也很普遍,所以查了查相关的资料,总结了以下几种方案!\n【1】使用XMPP协议（Openfire + Spark + Smack）\n简介：基于XML协议的通讯协议，前身是Jabber，目前已由IETF国际标准化组织完成了标准化工作。\n优点：协议成熟、强大、可扩展性强、目前主要应用于许多聊天系统中，且已有开源的Java版的开发实例androidpn。\n缺点：协议较复杂、冗余（基于XML）、费流量、费电，部署硬件成本高。\n这种方法需要服务端配合，需要整合openfire服务器，我们的服务端用的php，而这个需要用Java，客户端的代码也需要花一段时间去研究，由于时间有限并没有使用这种方法。不过在后来的开发中，想在程序里加入类似于微信的语音聊天的功能，所以对于这种方式又进行了一段开发，以后我会写一篇文章介绍一下。\n【2】使用MQTT协议\n简介：轻量级的、基于代理的“发布/订阅”模式的消息传输协议。\n优点：协议简洁、小巧、可扩展性强、省流量、省电，目前已经应用到企业领域（参考：http://mqtt.org/），且已有C++版的服务端组件rsmb。\n【3】使用第三方推送服务\n**　1**.Google 云推送服务\n鉴于国内的特殊情况，大部分国产手机都砍掉了Google服务，所以这种实现方式不太现实\n**2. **百度云推送服务（http://open.baidu.com/）\n这个推送方案实施起来比较简单，直接集成相关的sdk，就可以实现推送，而且服务端的sdk有PHP，Java，Python版本，也可以直接通过url推送相关消息\n**3. **极光推送（https://www.jpush.cn/）\n这个文档比较全，号称3分钟快速Demo，集成起来相对就简单多了\n今天主要介绍一下第二种推送方案，之前查资料的时候没有找到百度云推送和极光推送，也是后来一个偶然的机会发现百度推出了云推送服务，今天总结一下,也希望以后各位朋友在开发中少走弯路,\n1.首先下载rsmb包,并解压,找到对应服务器的文件夹,我的是linux_ia32,这个支持多种服务器\n(下载地址:http://www.alphaworks.ibm.com/tech/rsmb,或者 http://pan.baidu.com/share/link?shareid=305439419\u0026amp;uk=137542493)\n2.把目录及里面的文件上传到服务器上,(我的是linux服务器)进入到用命令行进入到该目录 然后自行 ./broker 如此这般便启动了推送服务,\n3.准备推送页面(通过网页进行推送测试)下载PHP端的推送代码 (http://pan.baidu.com/share/link?shareid=311569022\u0026amp;uk=137542493),解压进入 etc目录更改 config.php里的IP地址为你的服务器IP地址\n4.打开对应的url既可以看到如下的页面\nServer status显示为 Online说明服务器正常启动了,\n5.下面开始准备android客户端(下载地址https://github.com/tokudu/AndroidPushNotificationsDemo )\n启动推送服务,然后在上边的网页上把那一串字符输入到上边的输入框,下边输入要推送的内容\n不幸的是报错了,错误如下\n08-05 13:56:34.472: E/AndroidRuntime(30976): java.lang.VerifyError: com/tokudu/demo/PushService\n08-05 13:56:34.472: E/AndroidRuntime(30976): at com.tokudu.demo.PushActivity$1.onClick(PushActivity.java:32)\n08-05 13:56:34.472: E/AndroidRuntime(30976): at android.view.View.performClick(View.java:4240)\n08-05 13:56:34.472: E/AndroidRuntime(30976): at android.view.View$PerformClick.run(View.java:17721)\n08-05 13:56:34.472: E/AndroidRuntime(30976): at android.os.Handler.handleCallback(Handler.java:730)\n08-05 13:56:34.472: E/AndroidRuntime(30976): at android.os.Handler.dispatchMessage(Handler.java:92)\n08-05 13:56:34.472: E/AndroidRuntime(30976): at android.os.Looper.loop(Looper.java:137)\n08-05 13:56:34.472: E/AndroidRuntime(30976): at android.app.ActivityThread.main(ActivityThread.java:5103)\n08-05 13:56:34.472: E/AndroidRuntime(30976): at java.lang.reflect.Method.invokeNative(Native Method)\n08-05 13:56:34.472: E/AndroidRuntime(30976): at java.lang.reflect.Method.invoke(Method.java:525)\n08-05 13:56:34.472: E/AndroidRuntime(30976): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)\n08-05 13:56:34.472: E/AndroidRuntime(30976): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)\n08-05 13:56:34.472: E/AndroidRuntime(30976): at dalvik.system.NativeStart.main(Native Method)\n__　__这个错误是因为少了个jar包,只要加入jar包就可以了(下载地址 http://pan.baidu.com/share/link?shareid=455455739\u0026amp;uk=137542493)\n推送成功\n【e】在后续的开发中遇到了个错误,在此提出来希望各位朋友避免出现此错误\n1.当推送服务启动的时间过长时,一般启动几个月之后,可能会出现客户端连接不上服务,可能会导致程序无法运行,此时需要重新启动推送服务就可解决\n转自http://my.oschina.net/u/818922/blog/150182\n","permalink":"https://blog.zdltech.com/posts/android-%E5%B9%B3%E5%8F%B0%E6%8E%A8%E9%80%81%E6%96%B9%E6%A1%88/","summary":"\u003cp\u003e前段时间做的项目需要添加一个推送的功能,现在应用里边加入推送也很普遍,所以查了查相关的资料,总结了以下几种方案!\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e【1】使用XMPP协议（Openfire + Spark + Smack）\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e简介：基于XML协议的通讯协议，前身是Jabber，目前已由IETF国际标准化组织完成了标准化工作。\u003cbr\u003e\n优点：协议成熟、强大、可扩展性强、目前主要应用于许多聊天系统中，且已有开源的Java版的开发实例androidpn。\u003cbr\u003e\n缺点：协议较复杂、冗余（基于XML）、费流量、费电，部署硬件成本高。\u003c/p\u003e\n\u003cp\u003e这种方法需要服务端配合，需要整合openfire服务器，我们的服务端用的php，而这个需要用Java，客户端的代码也需要花一段时间去研究，由于时间有限并没有使用这种方法。不过在后来的开发中，想在程序里加入类似于微信的语音聊天的功能，所以对于这种方式又进行了一段开发，以后我会写一篇文章介绍一下。\u003c/p\u003e\n\u003cp\u003e【2】\u003cstrong\u003e使用MQTT协议\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e简介：轻量级的、基于代理的“发布/订阅”模式的消息传输协议。\u003cbr\u003e\n优点：协议简洁、小巧、可扩展性强、省流量、省电，目前已经应用到企业领域（参考：\u003ca href=\"http://mqtt.org/\"\u003ehttp://mqtt.org/\u003c/a\u003e），且已有C++版的服务端组件rsmb。\u003c/p\u003e\n\u003cp\u003e【3】\u003cstrong\u003e使用第三方推送服务\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e**　　1**.Google 云推送服务\u003c/p\u003e\n\u003cp\u003e鉴于国内的特殊情况，大部分国产手机都砍掉了Google服务，所以这种实现方式不太现实\u003c/p\u003e\n\u003cp\u003e**2. **百度云推送服务（\u003ca href=\"http://open.baidu.com/\"\u003ehttp://open.baidu.com/\u003c/a\u003e）\u003c/p\u003e\n\u003cp\u003e这个推送方案实施起来比较简单，直接集成相关的sdk，就可以实现推送，而且服务端的sdk有PHP，Java，Python版本，也可以直接通过url推送相关消息\u003c/p\u003e\n\u003cp\u003e**3. **极光推送（\u003ca href=\"https://www.jpush.cn/\"\u003ehttps://www.jpush.cn/\u003c/a\u003e）\u003c/p\u003e\n\u003cp\u003e这个文档比较全，号称3分钟快速Demo，集成起来相对就简单多了\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e今天主要介绍一下第二种推送方案，之前查资料的时候没有找到百度云推送和极光推送，也是后来一个偶然的机会发现百度推出了云推送服务，今天总结一下,也希望以后各位朋友在开发中少走弯路,\u003c/p\u003e\n\u003cp\u003e1.首先下载rsmb包,并解压,找到对应服务器的文件夹,我的是linux_ia32,这个支持多种服务器\u003c/p\u003e\n\u003cp\u003e(下载地址:\u003ca href=\"http://www.alphaworks.ibm.com/tech/rsmb\"\u003ehttp://www.alphaworks.ibm.com/tech/rsmb\u003c/a\u003e,或者 http://pan.baidu.com/share/link?shareid=305439419\u0026amp;uk=137542493)\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201308/05142801_kcBZ.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201308/05142801_kcBZ.jpg\"\u003e\u003c/a\u003e\u003ca href=\"http://www.alphaworks.ibm.com/tech/rsmb\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e2.把目录及里面的文件上传到服务器上,(我的是linux服务器)进入到用命令行进入到该目录 然后自行 ./broker 如此这般便启动了推送服务,\u003c/p\u003e\n\u003cp\u003e3.准备推送页面(通过网页进行推送测试)下载PHP端的推送代码 (\u003ca href=\"http://pan.baidu.com/share/link?shareid=311569022\u0026amp;uk=137542493)\"\u003ehttp://pan.baidu.com/share/link?shareid=311569022\u0026amp;uk=137542493)\u003c/a\u003e,解压进入 etc目录更改 config.php里的IP地址为你的服务器IP地址\u003c/p\u003e\n\u003cp\u003e4.打开对应的url既可以看到如下的页面\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201308/05142801_P20P.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201308/05142801_P20P.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eServer status显示为 Online说明服务器正常启动了,\u003c/p\u003e\n\u003cp\u003e5.下面开始准备android客户端(下载地址\u003ca href=\"https://github.com/tokudu/AndroidPushNotificationsDemo\"\u003ehttps://github.com/tokudu/AndroidPushNotificationsDemo\u003c/a\u003e   )\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://static.oschina.net/uploads/img/201308/05142801_uG84.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://static.oschina.net/uploads/img/201308/05142801_uG84.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e启动推送服务,然后在上边的网页上把那一串字符输入到上边的输入框,下边输入要推送的内容\u003c/p\u003e\n\u003cp\u003e不幸的是报错了,错误如下\u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #ff0000;\"\u003e08-05 13:56:34.472: E/AndroidRuntime(30976): java.lang.VerifyError: com/tokudu/demo/PushService\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e\u003cspan style=\"color: #ff0000;\"\u003e08-05 13:56:34.472: E/AndroidRuntime(30976): at com.tokudu.demo.PushActivity$1.onClick(PushActivity.java:32)\u003c/span\u003e\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e\u003cspan style=\"color: #ff0000;\"\u003e08-05 13:56:34.472: E/AndroidRuntime(30976): at android.view.View.performClick(View.java:4240)\u003c/span\u003e\u003cbr\u003e\n\u003cspan style=\"color: #ff0000;\"\u003e08-05 13:56:34.472: E/AndroidRuntime(30976): at android.view.View$PerformClick.run(View.java:17721)\u003c/span\u003e\u003cbr\u003e\n\u003cspan style=\"color: #ff0000;\"\u003e08-05 13:56:34.472: E/AndroidRuntime(30976): at android.os.Handler.handleCallback(Handler.java:730)\u003c/span\u003e\u003cbr\u003e\n\u003cspan style=\"color: #ff0000;\"\u003e08-05 13:56:34.472: E/AndroidRuntime(30976): at android.os.Handler.dispatchMessage(Handler.java:92)\u003c/span\u003e\u003cbr\u003e\n\u003cspan style=\"color: #ff0000;\"\u003e08-05 13:56:34.472: E/AndroidRuntime(30976): at android.os.Looper.loop(Looper.java:137)\u003c/span\u003e\u003cbr\u003e\n\u003cspan style=\"color: #ff0000;\"\u003e08-05 13:56:34.472: E/AndroidRuntime(30976): at android.app.ActivityThread.main(ActivityThread.java:5103)\u003c/span\u003e\u003cbr\u003e\n\u003cspan style=\"color: #ff0000;\"\u003e08-05 13:56:34.472: E/AndroidRuntime(30976): at java.lang.reflect.Method.invokeNative(Native Method)\u003c/span\u003e\u003cbr\u003e\n\u003cspan style=\"color: #ff0000;\"\u003e08-05 13:56:34.472: E/AndroidRuntime(30976): at java.lang.reflect.Method.invoke(Method.java:525)\u003c/span\u003e\u003cbr\u003e\n\u003cspan style=\"color: #ff0000;\"\u003e08-05 13:56:34.472: E/AndroidRuntime(30976): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)\u003c/span\u003e\u003cbr\u003e\n\u003cspan style=\"color: #ff0000;\"\u003e08-05 13:56:34.472: E/AndroidRuntime(30976): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)\u003c/span\u003e\u003cbr\u003e\n\u003cspan style=\"color: #ff0000;\"\u003e08-05 13:56:34.472: E/AndroidRuntime(30976): at dalvik.system.NativeStart.main(Native Method)\u003c/span\u003e\u003c/em\u003e\u003c/p\u003e","title":"Android 平台推送方案"},{"content":"移动应用开发工具的更新换代，让开发者可以直接通过浏览器就能创建移动主题和应用，快速而又简单。而这些工具的主要特色就是，无需编写大量代码或是无需编码，它们除了让经验丰富地开发人员更快速地构造原型外，也降低了新手进入移动应用开发的壁垒。在这里，本文介绍一些能够有效简化移动开发过程的10款工具。\n1. Appium\nAppium是一个开源、跨平台的自动化测试工具，用于测试原生、混合以及移动Web应用，支持iOS、Android和FirefoxOS平台。Appium通过使用WebDriver JSON协议，驱动iOS的UIAutomation库以及Android的UIAutomator框架 。\n相关链接：Appium的GitHub托管地址、mobilehub主页\n2. Mobiscroll\nMobiscroll是一个用于触摸设备的日期和时间选择器，它的使用不会改变HTML5、PhoneGap以及混合应用的原生用户体验。作为一款jQuery日期插件，用户可以自定义主题样式，为自己的移动项目UI组件添色。Mobiscroll支持所有主流平台：iOS、Android、BlackBerry, Windows Phone 8以及Amazon Kindle。\n**\n**\n相关链接：Mobiscroll的GitHub托管地址、mobilehub主页\n3. Hammer.js\nHammer.js是一个多点触摸手势库，能够为网页加入Tap、Double Tap、Swipe、Hold、Pinch、Drag等多点触摸事件，免去监听底层touchstart、touchmove、touchend事件并且要写一大堆判断逻辑的痛苦。\n**\n**\n相关链接：Hammer.js的GitHub托管地址、mobilehub主页\n4. Countly\nCountly是一款世界领先、实时、开源的移动分析平台，它通过收集来自手机的数据，并将这些数据通过可视化效果展示出来，分析移动应用的使用和最终用户的行为，用来有效地帮助提高所开发的产品质量。目前，Countly支持iOS以及Android平台。\n**\n**\n相关链接：Countly的GitHub托管地址、mobilehub主页\n5. iWebinspector\niWebInspector是一款免费的工具，用来调试、配置和检查iOS模拟器（iPhone或iPad）上运行的Web应用。可以检查资源，查看和修改HTML以及CSS，还可以对JavaScript代码使用断点，创建图表等，就像在桌面上使用Safari、Chrome或Firebug一样简单。\n**\n**\n相关链接：iWebinspector的mobilehub主页\n6. Adaptive Images\nAdaptive Images检测访问者的屏幕尺寸，自动创建、缓存并能够重新缩放HTML内嵌图像使其能够变为最适合设备的尺寸大小。Adaptive Images结合流体图像技术，适用于响应设计。\n**\n**\n相关链接：Adaptive Images的GitHub托管地址、mobilehub主页\n7. Mobjectify\nMobjectify是简化的移动开发，无论你是想要建立简单的实体模型在不同设备上进行测试还是构建工作应用，Mobjectify为你提供工具，加快你的工作流程。它使用绑定的小工具以及jQuery Mobile，在短短几分钟内就可生成一个原型设计，而不是纸上的布局或者线框图。\n**\n**\n相关链接：Mobjectify的mobilehub主页\n8. Ratchet\nRatchet是一款免费的开源工具，主要功能是，使用简单的HTML、CSS和JS组件就能构建出移动应用程序原型。Ratchet使用简单的原因之一就是，它支持很多控件，其中包括：Bars、Lists、Buttons、Forms、Segmented controllers、Sliders、Push events等。\n**\n**\n相关链接：Ratchet的GitHub托管地址、mobilehub主页\n9. Vinisketch\n通过Vinisketch，可以使用HTML5、CSS以及JavaScript来开发出能在移动平台上原生运行的应用，并且其提供云服务或作为一个独立的应用程序。\n**\n**\nVinisketch特性：\n可视化编辑器：使用可视化编辑器，只需拖放或自定义小部件，就可轻松设计应用程序。 多引擎：使用多引擎，可以为每一个目标设备管理自己的应用程序。 相关链接：Vinisketch的mobilehub主页\n10. mAdserve\nmAdserve是一个采用PHP+MySQL开发，用于轻松管理和跟踪移动广告的开源移动广告服务器，支持iOS、Android、Windows Phone平台。\n**\n**\n相关链接：mAdserve的mobilehub主页\n转载地址：http://www.csdn.net/article/2014-04-17/2819378-10-mobile-application-development-tools\n","permalink":"https://blog.zdltech.com/posts/10%E6%AC%BE%E9%AB%98%E6%95%88%E7%AE%80%E5%8C%96%E7%A7%BB%E5%8A%A8%E5%BC%80%E5%8F%91%E8%BF%87%E7%A8%8B%E7%9A%84%E5%B7%A5%E5%85%B7/","summary":"\u003cp\u003e移动应用开发工具的更新换代，让开发者可以直接通过浏览器就能创建移动主题和应用，快速而又简单。而这些工具的主要特色就是，无需编写大量代码或是无需编码，它们除了让经验丰富地开发人员更快速地构造原型外，也降低了新手进入移动应用开发的壁垒。在这里，本文介绍一些能够有效简化移动开发过程的10款工具。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. \u003ca href=\"http://appium.io/\"\u003eAppium\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eAppium是一个开源、跨平台的自动化测试工具，用于测试原生、混合以及移动Web应用，支持iOS、Android和FirefoxOS平台。Appium通过使用WebDriver JSON协议，驱动iOS的UIAutomation库以及Android的UIAutomator框架 。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://cms.csdnimg.cn/article/201404/17/534f7a21618a0.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/17/534f7a21618a0_middle.jpg\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：Appium的\u003ca href=\"https://github.com/appium/appium\"\u003eGitHub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/appium\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. \u003ca href=\"http://mobiscroll.com/\"\u003eMobiscroll\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eMobiscroll是一个用于触摸设备的日期和时间选择器，它的使用不会改变HTML5、PhoneGap以及混合应用的原生用户体验。作为一款jQuery日期插件，用户可以自定义主题样式，为自己的移动项目UI组件添色。Mobiscroll支持所有主流平台：iOS、Android、BlackBerry, Windows Phone 8以及Amazon Kindle。\u003c/p\u003e\n\u003cp\u003e**\u003ca href=\"http://cms.csdnimg.cn/article/201404/17/534f7acedf6c2.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/17/534f7acedf6c2_middle.jpg\"\u003e\u003c/a\u003e\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：Mobiscroll的\u003ca href=\"https://github.com/acidb/mobiscroll\"\u003eGitHub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/mobiscroll\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. \u003ca href=\"http://eightmedia.github.io/hammer.js/\"\u003eHammer.js\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eHammer.js是一个多点触摸手势库，能够为网页加入Tap、Double Tap、Swipe、Hold、Pinch、Drag等多点触摸事件，免去监听底层touchstart、touchmove、touchend事件并且要写一大堆判断逻辑的痛苦。\u003c/p\u003e\n\u003cp\u003e**\u003ca href=\"http://cms.csdnimg.cn/article/201404/17/534f7ea46d25a.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/17/534f7ea46d25a_middle.jpg\"\u003e\u003c/a\u003e\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：Hammer.js的\u003ca href=\"https://github.com/EightMedia/hammer.js/\"\u003eGitHub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/hammer\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4. \u003ca href=\"http://count.ly/\"\u003eCountly\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eCountly是一款世界领先、实时、开源的移动分析平台，它通过收集来自手机的数据，并将这些数据通过可视化效果展示出来，分析移动应用的使用和最终用户的行为，用来有效地帮助提高所开发的产品质量。目前，Countly支持iOS以及Android平台。\u003c/p\u003e\n\u003cp\u003e**\u003ca href=\"http://cms.csdnimg.cn/article/201404/17/534f7fc9bcdbc.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/17/534f7fc9bcdbc_middle.jpg\"\u003e\u003c/a\u003e\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：Countly的\u003ca href=\"https://github.com/Countly\"\u003eGitHub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/countly\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e5. \u003ca href=\"http://www.iwebinspector.com/\"\u003eiWebinspector\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eiWebInspector是一款免费的工具，用来调试、配置和检查iOS模拟器（iPhone或iPad）上运行的Web应用。可以检查资源，查看和修改HTML以及CSS，还可以对JavaScript代码使用断点，创建图表等，就像在桌面上使用Safari、Chrome或Firebug一样简单。\u003c/p\u003e\n\u003cp\u003e**\u003ca href=\"http://cms.csdnimg.cn/article/201404/17/534f7fe5a6752.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/17/534f7fe5a6752_middle.jpg\"\u003e\u003c/a\u003e\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：iWebinspector的\u003ca href=\"http://mobilehub.io/products/iwebinspector\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e6. \u003ca href=\"http://adaptive-images.com/\"\u003eAdaptive Images\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eAdaptive Images检测访问者的屏幕尺寸，自动创建、缓存并能够重新缩放HTML内嵌图像使其能够变为最适合设备的尺寸大小。Adaptive Images结合流体图像技术，适用于响应设计。\u003c/p\u003e\n\u003cp\u003e**\u003ca href=\"http://cms.csdnimg.cn/article/201404/17/534f80604fbe2.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/17/534f80604fbe2_middle.jpg\"\u003e\u003c/a\u003e\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：Adaptive Images的\u003ca href=\"https://github.com/MattWilcox/Adaptive-Images\"\u003eGitHub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/adaptiveimages\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e7. \u003ca href=\"http://www.mobjectify.com/\"\u003eMobjectify\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eMobjectify是简化的移动开发，无论你是想要建立简单的实体模型在不同设备上进行测试还是构建工作应用，Mobjectify为你提供工具，加快你的工作流程。它使用绑定的小工具以及jQuery Mobile，在短短几分钟内就可生成一个原型设计，而不是纸上的布局或者线框图。\u003c/p\u003e\n\u003cp\u003e**\u003ca href=\"http://cms.csdnimg.cn/article/201404/17/534f80be0b1fe.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/17/534f80be0b1fe_middle.jpg\"\u003e\u003c/a\u003e\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：Mobjectify的\u003ca href=\"http://mobilehub.io/products/mobjectify\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e8. \u003ca href=\"http://goratchet.com/\"\u003eRatchet\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eRatchet是一款免费的开源工具，主要功能是，使用简单的HTML、CSS和JS组件就能构建出移动应用程序原型。Ratchet使用简单的原因之一就是，它支持很多控件，其中包括：Bars、Lists、Buttons、Forms、Segmented controllers、Sliders、Push events等。\u003c/p\u003e\n\u003cp\u003e**\u003ca href=\"http://cms.csdnimg.cn/article/201404/17/534f813c478c6.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/17/534f813c478c6_middle.jpg\"\u003e\u003c/a\u003e\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：Ratchet的\u003ca href=\"https://github.com/twbs/ratchet\"\u003eGitHub托管地址\u003c/a\u003e、\u003ca href=\"http://mobilehub.io/products/ratchet\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e9. \u003ca href=\"http://www.vinisketch.fr/mainSite/en.html\"\u003eVinisketch\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e通过Vinisketch，可以使用HTML5、CSS以及JavaScript来开发出能在移动平台上原生运行的应用，并且其提供云服务或作为一个独立的应用程序。\u003c/p\u003e\n\u003cp\u003e**\u003ca href=\"http://cms.csdnimg.cn/article/201404/17/534f81add1a88.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/17/534f81add1a88_middle.jpg\"\u003e\u003c/a\u003e\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eVinisketch特性：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e可视化编辑器：使用可视化编辑器，只需拖放或自定义小部件，就可轻松设计应用程序。\u003c/li\u003e\n\u003cli\u003e多引擎：使用多引擎，可以为每一个目标设备管理自己的应用程序。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：Vinisketch的\u003ca href=\"http://mobilehub.io/products/vinisketch\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e10. \u003ca href=\"http://www.madserve.org/\"\u003emAdserve\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003emAdserve是一个采用PHP+MySQL开发，用于轻松管理和跟踪移动广告的开源移动广告服务器，支持iOS、Android、Windows Phone平台。\u003c/p\u003e\n\u003cp\u003e**\u003ca href=\"http://cms.csdnimg.cn/article/201404/17/534f81f372d00.jpg\"\u003e\u003cimg loading=\"lazy\" src=\"http://cms.csdnimg.cn/article/201404/17/534f81f372d00_middle.jpg\"\u003e\u003c/a\u003e\u003cbr\u003e\n**\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关链接：mAdserve的\u003ca href=\"http://mobilehub.io/products/madserve\"\u003emobilehub主页\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e转载地址：http://www.csdn.net/article/2014-04-17/2819378-10-mobile-application-development-tools\u003c/p\u003e","title":"10款高效简化移动开发过程的工具"},{"content":"在上一篇文章中提到在Android中实现推送方式的解决方案，其中一个比较成熟的解决方案便是使用XMPP协议实现。而AndroidPn项目就是使用XMPP协议实现信息推送的一个开源项目。在这里给大家介绍其使用过程。\n**　Apndroid Push Notification的特点： **\n快速集成:提供一种比C2DM更加快捷的使用方式,避免各种限制.\n无需架设服务器:通过使用”云服务”,减少额外服务器负担.\n可以同时推送消息到网站页面,android 手机\n耗电少,占用流量少.\n**　具体配置过程： **\n首先， 我们需要下载androidpn-client-0.5.0.zip和androidpn-server-0.5.0-bin.zip。\n下载地址：http://sourceforge.net/projects/androidpn/\n解压两个包，Eclipse导入client，配置好目标平台，打开raw/androidpn.properties文件，配置客户端程序。\n1. 如果是模拟器来运行客户端程序,把xmppHost配置成10.0.2.2[模拟器把10.0.2.2认为是所在主机的地址，127.0.0.1是模拟器本身的回环地址，10.0.2.1表示网关地址，10.0.2.3表示DNS地址，10.0.2.15表示目标设备的网络地址]，关于模拟器的详细信息，大家可参阅相关资料，这里不再详述.\nxmppPort=5222 是服务器的xmpp服务监听端口 运行androidpn-server-0.5.0\\bin\\run.bat启动服务器，从浏览器访问http://127.0.0.1:7070/index.do (androidPN Server有个轻量级的web服务器，在7070端口监听请求，接受用户输入的文本消息) 运行客户端，客户端会向服务器发起连接请求，注册成功后，服务器能识别客户端，并维护和客户端的IP长连接。 **　2. 如果是在同一个局域网内的其他机器的模拟器测试(或者使用同一无线路由器wifi上网的真机) ，则需要把这个值设置为服务器机器的局域网ip. **\n**　例如 你的电脑和android手机 都通过同一个无线路由器wifi上网, 电脑的ip地址为 192.168.1.2 而 手机的ip地址为 192.168.1.3, 这个时候 需要把这个值修改为 xmppHost=192.168.1.1 或是电脑的IP地址，就可以在手机上使用了. **\n如果是不在同一个局域网的真机测试，我们需要将这个值设置为服务器的IP地址。 **　具体配置如下图所示：**\n**　我的电脑IP是：192.168.8.107 **\n服务器运行主界面：\n推送信息如下界面所示：\n测试结果如下图所示：\n最后在我的模拟器和真机中测试通过。^_^\n最后，希望转载的朋友能够尊重作者的劳动成果，加上转载地址：http://www.cnblogs.com/hanyonglu/archive/2012/03/16/2399655.html 谢谢。\n","permalink":"https://blog.zdltech.com/posts/android-push-notification%E5%AE%9E%E7%8E%B0%E4%BF%A1%E6%81%AF%E6%8E%A8%E9%80%81%E4%BD%BF%E7%94%A8/","summary":"\u003cp\u003e在上一篇文章中提到在Android中实现推送方式的解决方案，其中一个比较成熟的解决方案便是使用XMPP协议实现。而AndroidPn项目就是使用XMPP协议实现信息推送的一个开源项目。在这里给大家介绍其使用过程。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e**　　Apndroid Push Notification的特点： **\u003c/p\u003e\n\u003cp\u003e快速集成:提供一种比C2DM更加快捷的使用方式,避免各种限制.\u003c/p\u003e\n\u003cp\u003e无需架设服务器:通过使用”云服务”,减少额外服务器负担.\u003c/p\u003e\n\u003cp\u003e可以同时推送消息到网站页面,android 手机\u003c/p\u003e\n\u003cp\u003e耗电少,占用流量少.\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e**　　具体配置过程： **\u003c/p\u003e\n\u003cp\u003e首先， 我们需要下载androidpn-client-0.5.0.zip和androidpn-server-0.5.0-bin.zip。\u003c/p\u003e\n\u003cp\u003e下载地址：\u003ca href=\"http://sourceforge.net/projects/androidpn/\"\u003ehttp://sourceforge.net/projects/androidpn/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e解压两个包，Eclipse导入client，配置好目标平台，打开raw/androidpn.properties文件，配置客户端程序。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e1. 如果是模拟器来运行客户端程序,把xmppHost配置成10.0.2.2[模拟器把10.0.2.2认为是所在主机的地址，127.0.0.1是模拟器本身的回环地址，10.0.2.1表示网关地址，10.0.2.3表示DNS地址，10.0.2.15表示目标设备的网络地址]，关于模拟器的详细信息，大家可参阅相关资料，这里不再详述.\u003c/p\u003e\n\u003cdiv\u003e\n  　　xmppPort=5222 是服务器的xmpp服务监听端口\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv\u003e\n  　　运行androidpn-server-0.5.0\\bin\\run.bat启动服务器，从浏览器访问http://127.0.0.1:7070/index.do (androidPN Server有个轻量级的web服务器，在7070端口监听请求，接受用户输入的文本消息)\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cdiv\u003e\n  　　运行客户端，客户端会向服务器发起连接请求，注册成功后，服务器能识别客户端，并维护和客户端的IP长连接。\n\u003c/div\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e**　　2. 如果是在同一个局域网内的其他机器的模拟器测试(或者使用同一无线路由器wifi上网的真机) ，则需要把这个值设置为服务器机器的局域网ip.  **\u003c/p\u003e\n\u003cp\u003e**　　例如 你的电脑和android手机 都通过同一个无线路由器wifi上网, 电脑的ip地址为 192.168.1.2 而 手机的ip地址为 192.168.1.3, 这个时候 需要把这个值修改为 xmppHost=192.168.1.1 或是电脑的IP地址，就可以在手机上使用了. **\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003col start=\"3\"\u003e\n\u003cli\u003e如果是不在同一个局域网的真机测试，我们需要将这个值设置为服务器的IP地址。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e**　　具体配置如下图所示：**\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/2012-03-16_081017.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e**　　我的电脑IP是：192.168.8.107 **\u003c/p\u003e\n\u003cp\u003e服务器运行主界面：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/2012-03-16_074350.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/2012-03-16_074433.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/2012-03-16_074420.png\"\u003e\u003c/p\u003e\n\u003cp\u003e推送信息如下界面所示：\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/2012-03-16_074154.png\"\u003e\u003c/p\u003e\n\u003cp\u003e测试结果如下图所示：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/SC20120316-074221.png\"\u003e  \u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/SC20120316-074227.png\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e最后在我的模拟器和真机中测试通过。^_^\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e最后，希望转载的朋友能够尊重作者的劳动成果，加上转载地址：\u003ca href=\"http://www.cnblogs.com/hanyonglu/archive/2012/03/16/2399655.html\"\u003ehttp://www.cnblogs.com/hanyonglu/archive/2012/03/16/2399655.html\u003c/a\u003e 谢谢。\u003c/p\u003e","title":"Android Push Notification实现信息推送使用"},{"content":"**XMPP协议简介 **\nXMPP（Extensible Messageing and Presence Protocol：可扩展消息与存在协议）是目前主流的四种IM（IM：instant messaging,即时消息）协议之一，其他三种分别为：即时信息和空间协议(IMPP)、空间和即时信息协议(PRIM)、针对即时通讯和空间平衡扩充的进程开始协议SIP(SIMPLE)。\n在这四种协议中，XMPP是最灵活的。XMPP是一种基于XML的协议，它继承了在XML环境中灵活的发展性。因此，基于XMPP的应用具有超强的可扩展性。经过扩展以后的XMPP可以通过发送扩展的信息来处理用户的需求，以及在XMPP的顶端建立如内容发布系统和基于地址的服务等应用程 序。而且，XMPP包含了针对服务器端的软件协议，使之能与另一个进行通话，这使得开发者更容易建立客户应用程序或给一个配好系统添加功能。\n1. 什么是XMPP ？\nXMPP的前身是Jabber，一个开源形式组织产生的网络即时通信协议。XMPP目前被IETF国际标准组织完成了标准化工作。标准化的核心结果分为两部分； 核心的XML流传输协议 基于XML流传输的即时通讯扩展应用 XMPP的核心XML流传输协议的定义使得XMPP能够在一个比以往网络通信协议更规范的平台上。借助于XML易于解析和阅读的特性，使得XMPP的协议能够非常漂亮。 XMPP的即时通讯扩展应用部分是根据IETF在这之前对即时通讯的一个抽象定义的，与其他业已得到广泛使用的即时通讯协议，诸如AIM，QQ等有功能完整，完善等先进性。\n2. XMPP的基本网络结构是怎样的？\nXMPP中定义了三个角色，客户端，服务器，网关。通信能够在这三者的任意两个之间双向发生。服务器同时承担了客户端信息记录，连接管理和信息的路由功能。网关承担着与异构即时通信系统的互联互通，异构系统可以包括SMS（短信），MSN，ICQ等。基本的网络形式是单客户端通过TCP/IP连接到单服务器，然后在之上传输XML。\n3. XMPP通过TCP传什么了？\n传输的是与即时通讯相关的指令。在以前这些命令要么用2进制的形式发送（比如QQ），要么用纯文本指令加空格加参数加换行苻的方式发送（比如MSN）。而XMPP传输的即时通讯指令的逻辑与以往相仿，只是协议的形式变成了XML格式的纯文本。这不但使得解析容易了，人也容易阅读了，方便了开发和查错。而XMPP的核心部分就是一个在网络上分片断发送XML的流协议。这个流协议是XMPP的即时通讯指令的传递基础，也是一个非常重要的可以被进一步利用的网络基础协议。所以可以说，XMPP用TCP传的是XML流。\nXMPP协议工作原理：\n4. XMPP协议地址格式：\n**5. XMPP消息格式： **\n6. 核心的XML流传输协议\n基于XML FreeEIM流传输的即时通讯扩展应用\nXMPP的核心XML流传输协议的定义使得XMPP能够在一个比以往网络通信协议更规范的平台上。借助于XML易于解析和阅读的特性，使得XMPP的协议能够非常漂亮。\nXMPP的即时通讯扩展应用部分是根据IETF在这之前对即时通讯的一个抽象定义的，与其他业已得到广泛使用的即时通讯协议，诸如AIM，QQ等有功能完整，完善等先进性。\nXMPP的扩展协议Jingle使得其支持语音和视频。\nXMPP的官方文档时RFC 3920.\n7. XMPP应用示例\n举个例子看看所谓的XML流是什么样子的？\n客户端：\u0026lt;?xml version=\u0026amp;#8217;1.0\u0026amp;#8242;?\u0026gt; \u0026lt;stream:stream to=\u0026amp;#8217;example_com\u0026amp;#8217; xmlns=\u0026amp;#8217;jabber:client\u0026amp;#8217; xmlns:stream=\u0026amp;#8217;http_etherx_jabber_org/streams\u0026amp;#8217; version=\u0026amp;#8217;1.0\u0026amp;#8242;\u0026gt; 服务器：\u0026lt;?xml version=\u0026amp;#8217;1.0\u0026amp;#8242;?\u0026gt; \u0026lt;stream:stream from=\u0026amp;#8217;example_com\u0026amp;#8217; id=\u0026amp;#8217;someid\u0026amp;#8217; xmlns=\u0026amp;#8217;jabber:client\u0026amp;#8217; xmlns:stream=\u0026amp;#8217;http_etherx_jabber_org/streams\u0026amp;#8217; version=\u0026amp;#8217;1.0\u0026amp;#8242;\u0026gt; \u0026amp;#8230;其他通信\u0026amp;#8230; 客户端：\u0026lt;message from=\u0026amp;#8217;juliet_example_com\u0026amp;#8217; to=\u0026amp;#8217;romeo_example_net\u0026amp;#8217; xml:lang=\u0026amp;#8217;en\u0026amp;#8217;\u0026gt; 客户端： \u0026lt;body\u0026gt;Art thou not Romeo, and a Montague?\u0026lt;/body\u0026gt; 客户端：\u0026lt;/message\u0026gt; 服务器：\u0026lt;message from=\u0026amp;#8217;romeo_example_net\u0026amp;#8217; to=\u0026amp;#8217;juliet_example_com\u0026amp;#8217; xml:lang=\u0026amp;#8217;en\u0026amp;#8217;\u0026gt; 服务器：\u0026lt;body\u0026gt;Neither, fair saint, if either thee dislike.\u0026lt;/body\u0026gt; 服务器：\u0026lt;/message\u0026gt; 客户端：\u0026lt;/stream:stream\u0026gt; 服务器：\u0026lt;/stream:stream\u0026gt;\n以文档的观点来看，客户端或服务器发送的所有XML文本连缀在一起，从到构成了一个完整的XML文档。其中的stream标签就是所谓的XML Stream。在与中间的那些…这样的XML元素就是所谓的XML Stanza（XML节）。XMPP核心协议通信的基本模式就是先建立一个stream，然后协商一堆安全之类的东西，中间通信过程就是客户端发送XML Stanza，一个接一个的。服务器根据客户端发送的信息以及程序的逻辑，发送XML Stanza给客户端。但是这个过程并不是一问一答的，任何时候都有可能从一方发信给另外一方。通信的最后阶段是关闭流，关闭TCP/IP连接。\n8. XMPP系统特点：\n1)客户机/服务器通信模式；(2)分布式网络；(3)简单的客户端；(4)XML的数据格式。\n9.通俗解释：\n其实XMPP 是一种很类似于http协议的一种数据传输协议，它的过程就如同“解包装–〉包装”的过程，用户只需要明白它接受的类型，并理解它返回的类型，就可以很好的利用xmpp来进行数据通讯。\n最后，希望转载的朋友能够尊重作者的劳动成果，加上转载地址：http://www.cnblogs.com/hanyonglu/archive/2012/03/04/2378956.html 谢谢。\n","permalink":"https://blog.zdltech.com/posts/xmpp%E5%8D%8F%E8%AE%AE%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%E4%BB%8B%E7%BB%8D/","summary":"\u003cp\u003e**XMPP协议简介  **\u003c/p\u003e\n\u003cp\u003eXMPP（Extensible Messageing and Presence Protocol：可扩展消息与存在协议）是目前主流的四种IM（IM：instant messaging,即时消息）协议之一，其他三种分别为：即时信息和空间协议(IMPP)、空间和即时信息协议(PRIM)、针对即时通讯和空间平衡扩充的进程开始协议SIP(SIMPLE)。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e在这四种协议中，XMPP是最灵活的。XMPP是一种基于XML的协议，它继承了在XML环境中灵活的发展性。因此，基于XMPP的应用具有超强的可扩展性。经过扩展以后的XMPP可以通过发送扩展的信息来处理用户的需求，以及在XMPP的顶端建立如内容发布系统和基于地址的服务等应用程 序。而且，XMPP包含了针对服务器端的软件协议，使之能与另一个进行通话，这使得开发者更容易建立客户应用程序或给一个配好系统添加功能。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. 什么是XMPP ？\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eXMPP的前身是Jabber，一个开源形式组织产生的网络即时通信协议。XMPP目前被IETF国际标准组织完成了标准化工作。标准化的核心结果分为两部分； 核心的XML流传输协议 基于XML流传输的即时通讯扩展应用 XMPP的核心XML流传输协议的定义使得XMPP能够在一个比以往网络通信协议更规范的平台上。借助于XML易于解析和阅读的特性，使得XMPP的协议能够非常漂亮。 XMPP的即时通讯扩展应用部分是根据IETF在这之前对即时通讯的一个抽象定义的，与其他业已得到广泛使用的即时通讯协议，诸如AIM，QQ等有功能完整，完善等先进性。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. XMPP的基本网络结构是怎样的\u003c/strong\u003e？\u003c/p\u003e\n\u003cp\u003eXMPP中定义了三个角色，客户端，服务器，网关。通信能够在这三者的任意两个之间双向发生。服务器同时承担了客户端信息记录，连接管理和信息的路由功能。网关承担着与异构即时通信系统的互联互通，异构系统可以包括SMS（短信），MSN，ICQ等。基本的网络形式是单客户端通过TCP/IP连接到单服务器，然后在之上传输XML。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. XMPP通过TCP传什么了？\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e传输的是与即时通讯相关的指令。在以前这些命令要么用2进制的形式发送（比如QQ），要么用纯文本指令加空格加参数加换行苻的方式发送（比如MSN）。而XMPP传输的即时通讯指令的逻辑与以往相仿，只是协议的形式变成了XML格式的纯文本。这不但使得解析容易了，人也容易阅读了，方便了开发和查错。而XMPP的核心部分就是一个在网络上分片断发送XML的流协议。这个流协议是XMPP的即时通讯指令的传递基础，也是一个非常重要的可以被进一步利用的网络基础协议。所以可以说，XMPP用TCP传的是XML流。\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cspan style=\"color: #333333; font-family: 'Lucida Grande', Geneva, Arial, Verdana, 'Lucida Sans Unicode', Helvetica, sans-serif;\"\u003e\u003cstrong\u003eXMPP协议工作原理：\u003c/strong\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/2012-03-04_012637.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4. XMPP协议地址格式：\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/2012-03-04_01244666.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e**5. XMPP消息格式： **\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/2012-03-04_012913.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/2012-03-04_013011.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/2012-03-04_013041.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://images.cnblogs.com/cnblogs_com/hanyonglu/2012-03-04_014046.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e6. 核心的XML流传输协议\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e基于XML FreeEIM流传输的即时通讯扩展应用\u003c/p\u003e\n\u003cp\u003eXMPP的核心XML流传输协议的定义使得XMPP能够在一个比以往网络通信协议更规范的平台上。借助于XML易于解析和阅读的特性，使得XMPP的协议能够非常漂亮。\u003c/p\u003e\n\u003cp\u003eXMPP的即时通讯扩展应用部分是根据IETF在这之前对即时通讯的一个抽象定义的，与其他业已得到广泛使用的即时通讯协议，诸如AIM，QQ等有功能完整，完善等先进性。\u003c/p\u003e\n\u003cp\u003eXMPP的扩展协议Jingle使得其支持语音和视频。\u003c/p\u003e\n\u003cp\u003eXMPP的官方文档时RFC 3920.\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e7. XMPP应用示例\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e举个例子看看所谓的XML流是什么样子的？\u003c/p\u003e\n\u003cdiv\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e客户端：\u0026lt;?xml version=\u0026amp;#8217;1.0\u0026amp;#8242;?\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;stream:stream\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003eto=\u0026amp;#8217;example_com\u0026amp;#8217;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003exmlns=\u0026amp;#8217;jabber:client\u0026amp;#8217;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003exmlns:stream=\u0026amp;#8217;http_etherx_jabber_org/streams\u0026amp;#8217;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003eversion=\u0026amp;#8217;1.0\u0026amp;#8242;\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e服务器：\u0026lt;?xml version=\u0026amp;#8217;1.0\u0026amp;#8242;?\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;stream:stream\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003efrom=\u0026amp;#8217;example_com\u0026amp;#8217;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003eid=\u0026amp;#8217;someid\u0026amp;#8217;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003exmlns=\u0026amp;#8217;jabber:client\u0026amp;#8217;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003exmlns:stream=\u0026amp;#8217;http_etherx_jabber_org/streams\u0026amp;#8217;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003eversion=\u0026amp;#8217;1.0\u0026amp;#8242;\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026amp;#8230;其他通信\u0026amp;#8230;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e客户端：\u0026lt;message from=\u0026amp;#8217;juliet_example_com\u0026amp;#8217;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003eto=\u0026amp;#8217;romeo_example_net\u0026amp;#8217;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003exml:lang=\u0026amp;#8217;en\u0026amp;#8217;\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e客户端： \u0026lt;body\u0026gt;Art thou not Romeo, and a Montague?\u0026lt;/body\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e客户端：\u0026lt;/message\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e服务器：\u0026lt;message from=\u0026amp;#8217;romeo_example_net\u0026amp;#8217;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003eto=\u0026amp;#8217;juliet_example_com\u0026amp;#8217;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003exml:lang=\u0026amp;#8217;en\u0026amp;#8217;\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e服务器：\u0026lt;body\u0026gt;Neither, fair saint, if either thee dislike.\u0026lt;/body\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e服务器：\u0026lt;/message\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003cpre\u003e\u003ccode\u003e客户端：\u0026lt;/stream:stream\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n  \u003cdiv\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e服务器：\u0026lt;/stream:stream\u0026gt;\u003c/p\u003e","title":"XMPP协议实现原理介绍"},{"content":"“服务器推”技术的应用\n传统模式的 Web 系统以客户端发出请求、服务器端响应的方式工作。这种方式并不能满足很多现实应用的需求，譬如：\n监控系统：后台硬件热插拔、LED、温度、电压发生变化； 即时通信系统：其它用户登录、发送信息； 即时报价系统：后台数据库内容发生变化； 这些应用都需要服务器能实时地将更新的信息传送到客户端，而无须客户端发出请求。“服务器推”技术在现实应用中有一些解决方案，本文将这些解决方案分为两类：一类需要在浏览器端安装插件，基于套接口传送信息，或是使用 RMI、CORBA 进行远程调用；而另一类则无须浏览器安装任何插件、基于 HTTP 长连接。\n将“服务器推”应用在 Web 程序中，首先考虑的是如何在功能有限的浏览器端接收、处理信息：\n客户端如何接收、处理信息，是否需要使用套接口或是使用远程调用。客户端呈现给用户的是 HTML 页面还是 Java applet 或 Flash 窗口。如果使用套接口和远程调用，怎么和 JavaScript 结合修改 HTML 的显示。 客户与服务器端通信的信息格式，采取怎样的出错处理机制。 客户端是否需要支持不同类型的浏览器如 IE、Firefox，是否需要同时支持 Windows 和 Linux 平台。 回页首\n基于客户端套接口的“服务器推”技术\nFlash XMLSocket\n如果 Web 应用的用户接受应用只有在安装了 Flash 播放器才能正常运行， 那么使用 Flash 的 XMLSocket 也是一个可行的方案。\n这种方案实现的基础是：\nFlash 提供了 XMLSocket 类。 JavaScript 和 Flash 的紧密结合：在 JavaScript 可以直接调用 Flash 程序提供的接口。 具体实现方法：在 HTML 页面中内嵌入一个使用了 XMLSocket 类的 Flash 程序。JavaScript 通过调用此 Flash 程序提供的套接口接口与服务器端的套接口进行通信。JavaScript 在收到服务器端以 XML 格式传送的信息后可以很容易地控制 HTML 页面的内容显示。\n关于如何去构建充当了 JavaScript 与 Flash XMLSocket 桥梁的 Flash 程序，以及如何在 JavaScript 里调用 Flash 提供的接口，我们可以参考 AFLAX（Asynchronous Flash and XML）项目提供的 Socket Demo 以及 SocketJS（请参见 参考资源）。\nJavascript 与 Flash 的紧密结合，极大增强了客户端的处理能力。从 Flash 播放器 V7.0.19 开始，已经取消了 XMLSocket 的端口必须大于 1023 的限制。Linux 平台也支持 Flash XMLSocket 方案。但此方案的缺点在于：\n客户端必须安装 Flash 播放器； 因为 XMLSocket 没有 HTTP 隧道功能，XMLSocket 类不能自动穿过防火墙； 因为是使用套接口，需要设置一个通信端口，防火墙、代理服务器也可能对非 HTTP 通道端口进行限制； 不过这种方案在一些网络聊天室，网络互动游戏中已得到广泛使用。\nJava Applet 套接口\n在客户端使用 Java Applet，通过 java.net.Socket 或 java.net.DatagramSocket 或 java.net.MulticastSocket 建立与服务器端的套接口连接，从而实现“服务器推”。\n这种方案最大的不足在于 Java applet 在收到服务器端返回的信息后，无法通过 JavaScript 去更新 HTML 页面的内容。\n回页首\n基于 HTTP 长连接的“服务器推”技术\nComet 简介\n浏览器作为 Web 应用的前台，自身的处理功能比较有限。浏览器的发展需要客户端升级软件，同时由于客户端浏览器软件的多样性，在某种意义上，也影响了浏览器新技术的推广。在 Web 应用中，浏览器的主要工作是发送请求、解析服务器返回的信息以不同的风格显示。AJAX 是浏览器技术发展的成果，通过在浏览器端发送异步请求，提高了单用户操作的响应性。但 Web 本质上是一个多用户的系统，对任何用户来说，可以认为服务器是另外一个用户。现有 AJAX 技术的发展并不能解决在一个多用户的 Web 应用中，将更新的信息实时传送给客户端，从而用户可能在“过时”的信息下进行操作。而 AJAX 的应用又使后台数据更新更加频繁成为可能。\n图 1. 传统的 Web 应用模型与基于 AJAX 的模型之比较\n“服务器推”是一种很早就存在的技术，以前在实现上主要是通过客户端的套接口，或是服务器端的远程调用。因为浏览器技术的发展比较缓慢，没有为“服务器推”的实现提供很好的支持，在纯浏览器的应用中很难有一个完善的方案去实现“服务器推”并用于商业程序。最近几年，因为 AJAX 技术的普及，以及把 IFrame 嵌在“htmlfile“的 ActiveX 组件中可以解决 IE 的加载显示问题，一些受欢迎的应用如 meebo，gmail+gtalk 在实现中使用了这些新技术；同时“服务器推”在现实应用中确实存在很多需求。因为这些原因，基于纯浏览器的“服务器推”技术开始受到较多关注，Alex Russell（Dojo Toolkit 的项目 Lead）称这种基于 HTTP 长连接、无须在浏览器端安装插件的“服务器推”技术为“Comet”。目前已经出现了一些成熟的 Comet 应用以及各种开源框架；一些 Web 服务器如 Jetty 也在为支持大量并发的长连接进行了很多改进。关于 Comet 技术最新的发展状况请参考关于 Comet 的 wiki。\n下面将介绍两种 Comet 应用的实现模型。\n基于 AJAX 的长轮询（long-polling）方式\n如 图 1 所示，AJAX 的出现使得 JavaScript 可以调用 XMLHttpRequest 对象发出 HTTP 请求，JavaScript 响应处理函数根据服务器返回的信息对 HTML 页面的显示进行更新。使用 AJAX 实现“服务器推”与传统的 AJAX 应用不同之处在于：\n服务器端会阻塞请求直到有数据传递或超时才返回。 客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后，再次发出请求，重新建立连接。 当客户端处理接收的数据、重新建立连接时，服务器端可能有新的数据到达；这些信息会被服务器端保存直到客户端重新建立连接，客户端会一次把当前服务器端所有的信息取回。 图 2. 基于长轮询的服务器推模型\n一些应用及示例如 “Meebo”, “Pushlet Chat” 都采用了这种长轮询的方式。相对于“轮询”（poll），这种长轮询方式也可以称为“拉”（pull）。因为这种方案基于 AJAX，具有以下一些优点：请求异步发出；无须安装插件；IE、Mozilla FireFox 都支持 AJAX。\n在这种长轮询方式下，客户端是在 XMLHttpRequest 的 readystate 为 4（即数据传输结束）时调用回调函数，进行信息处理。当 readystate 为 4 时，数据传输结束，连接已经关闭。Mozilla Firefox 提供了对 Streaming AJAX 的支持， 即 readystate 为 3 时（数据仍在传输中），客户端可以读取数据，从而无须关闭连接，就能读取处理服务器端返回的信息。IE 在 readystate 为 3 时，不能读取服务器返回的数据，目前 IE 不支持基于 Streaming AJAX。\n基于 Iframe 及 htmlfile 的流（streaming）方式\niframe 是很早就存在的一种 HTML 标记， 通过在 HTML 页面里嵌入一个隐蔵帧，然后将这个隐蔵帧的 SRC 属性设为对一个长连接的请求，服务器端就能源源不断地往客户端输入数据。\n图 3. 基于流方式的服务器推模型\n上节提到的 AJAX 方案是在 JavaScript 里处理 XMLHttpRequest 从服务器取回的数据，然后 Javascript 可以很方便的去控制 HTML 页面的显示。同样的思路用在 iframe 方案的客户端，iframe 服务器端并不返回直接显示在页面的数据，而是返回对客户端 Javascript 函数的调用，如“\u0026lt;script type=\u0026quot;text/javascript\u0026quot;\u0026gt;js_func(“data from server ”)\u0026lt;/script\u0026gt;”。服务器端将返回的数据作为客户端 JavaScript 函数的参数传递；客户端浏览器的 Javascript 引擎在收到服务器返回的 JavaScript 调用时就会去执行代码。\n从 图 3 可以看到，每次数据传送不会关闭连接，连接只会在通信出现错误时，或是连接重建时关闭（一些防火墙常被设置为丢弃过长的连接， 服务器端可以设置一个超时时间， 超时后通知客户端重新建立连接，并关闭原来的连接）。\n使用 iframe 请求一个长连接有一个很明显的不足之处：IE、Morzilla Firefox 下端的进度栏都会显示加载没有完成，而且 IE 上方的图标会不停的转动，表示加载正在进行。Google 的天才们使用一个称为“htmlfile”的 ActiveX 解决了在 IE 中的加载显示问题，并将这种方法用到了 gmail+gtalk 产品中。Alex Russell 在 “What else is burried down in the depth’s of Google’s amazing JavaScript?”文章中介绍了这种方法。Zeitoun 网站提供的 comet-iframe.tar.gz，封装了一个基于 iframe 和 htmlfile 的 JavaScript comet 对象，支持 IE、Mozilla Firefox 浏览器，可以作为参考。（请参见 参考资源）\n回页首\n使用 Comet 模型开发自己的应用\n上面介绍了两种基于 HTTP 长连接的“服务器推”架构，更多描述了客户端处理长连接的技术。对于一个实际的应用而言，系统的稳定性和性能是非常重要的。将 HTTP 长连接用于实际应用，很多细节需要考虑。\n不要在同一客户端同时使用超过两个的 HTTP 长连接\n我们使用 IE 下载文件时会有这样的体验，从同一个 Web 服务器下载文件，最多只能有两个文件同时被下载。第三个文件的下载会被阻塞，直到前面下载的文件下载完毕。这是因为 HTTP 1.1 规范中规定，客户端不应该与服务器端建立超过两个的 HTTP 连接， 新的连接会被阻塞。而 IE 在实现中严格遵守了这种规定。\nHTTP 1.1 对两个长连接的限制，会对使用了长连接的 Web 应用带来如下现象：在客户端如果打开超过两个的 IE 窗口去访问同一个使用了长连接的 Web 服务器，第三个 IE 窗口的 HTTP 请求被前两个窗口的长连接阻塞。\n所以在开发长连接的应用时， 必须注意在使用了多个 frame 的页面中，不要为每个 frame 的页面都建立一个 HTTP 长连接，这样会阻塞其它的 HTTP 请求，在设计上考虑让多个 frame 的更新共用一个长连接。\n服务器端的性能和可扩展性\n一般 Web 服务器会为每个连接创建一个线程，如果在大型的商业应用中使用 Comet，服务器端需要维护大量并发的长连接。在这种应用背景下，服务器端需要考虑负载均衡和集群技术；或是在服务器端为长连接作一些改进。\n应用和技术的发展总是带来新的需求，从而推动新技术的发展。HTTP 1.1 与 1.0 规范有一个很大的不同：1.0 规范下服务器在处理完每个 Get/Post 请求后会关闭套接口连接； 而 1.1 规范下服务器会保持这个连接，在处理两个请求的间隔时间里，这个连接处于空闲状态。 Java 1.4 引入了支持异步 IO 的 java.nio 包。当连接处于空闲时，为这个连接分配的线程资源会返还到线程池，可以供新的连接使用；当原来处于空闲的连接的客户发出新的请求，会从线程池里分配一个线程资源处理这个请求。 这种技术在连接处于空闲的机率较高、并发连接数目很多的场景下对于降低服务器的资源负载非常有效。\n但是 AJAX 的应用使请求的出现变得频繁，而 Comet 则会长时间占用一个连接，上述的服务器模型在新的应用背景下会变得非常低效，线程池里有限的线程数甚至可能会阻塞新的连接。Jetty 6 Web 服务器针对 AJAX、Comet 应用的特点进行了很多创新的改进，请参考文章“AJAX，Comet and Jetty”（请参见 参考资源）。\n控制信息与数据信息使用不同的 HTTP 连接\n使用长连接时，存在一个很常见的场景：客户端网页需要关闭，而服务器端还处在读取数据的堵塞状态，客户端需要及时通知服务器端关闭数据连接。服务器在收到关闭请求后首先要从读取数据的阻塞状态唤醒，然后释放为这个客户端分配的资源，再关闭连接。\n所以在设计上，我们需要使客户端的控制请求和数据请求使用不同的 HTTP 连接，才能使控制请求不会被阻塞。\n在实现上，如果是基于 iframe 流方式的长连接，客户端页面需要使用两个 iframe，一个是控制帧，用于往服务器端发送控制请求，控制请求能很快收到响应，不会被堵塞；一个是显示帧，用于往服务器端发送长连接请求。如果是基于 AJAX 的长轮询方式，客户端可以异步地发出一个 XMLHttpRequest 请求，通知服务器端关闭数据连接。\n在客户和服务器之间保持“心跳”信息\n在浏览器与服务器之间维持一个长连接会为通信带来一些不确定性：因为数据传输是随机的，客户端不知道何时服务器才有数据传送。服务器端需要确保当客户端不再工作时，释放为这个客户端分配的资源，防止内存泄漏。因此需要一种机制使双方知道大家都在正常运行。在实现上：\n服务器端在阻塞读时会设置一个时限，超时后阻塞读调用会返回，同时发给客户端没有新数据到达的心跳信息。此时如果客户端已经关闭，服务器往通道写数据会出现异常，服务器端就会及时释放为这个客户端分配的资源。 如果客户端使用的是基于 AJAX 的长轮询方式；服务器端返回数据、关闭连接后，经过某个时限没有收到客户端的再次请求，会认为客户端不能正常工作，会释放为这个客户端分配、维护的资源。 当服务器处理信息出现异常情况，需要发送错误信息通知客户端，同时释放资源、关闭连接。 Pushlet – 开源 Comet 框架\nPushlet 是一个开源的 Comet 框架，在设计上有很多值得借鉴的地方，对于开发轻量级的 Comet 应用很有参考价值。\n观察者模型\nPushlet 使用了观察者模型：客户端发送请求，订阅感兴趣的事件；服务器端为每个客户端分配一个会话 ID 作为标记，事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。\n客户端 JavaScript 库\npushlet 提供了基于 AJAX 的 JavaScript 库文件用于实现长轮询方式的“服务器推”；还提供了基于 iframe 的 JavaScript 库文件用于实现流方式的“服务器推”。\nJavaScript 库做了很多封装工作：\n定义客户端的通信状态：STATE_ERROR、STATE_ABORT、STATE_NULL、STATE_READY、STATE_JOINED、STATE_LISTENING； 保存服务器分配的会话 ID，在建立连接之后的每次请求中会附上会话 ID 表明身份； 提供了 join()、leave()、subscribe()、 unsubsribe()、listen() 等 API 供页面调用； 提供了处理响应的 JavaScript 函数接口 onData()、onEvent()… 网页可以很方便地使用这两个 JavaScript 库文件封装的 API 与服务器进行通信。\n客户端与服务器端通信信息格式\npushlet 定义了一套客户与服务器通信的信息格式，使用 XML 格式。定义了客户端发送请求的类型：join、leave、subscribe、unsubscribe、listen、refresh；以及响应的事件类型：data、join_ack、listen_ack、refresh、heartbeat、error、abort、subscribe_ack、unsubscribe_ack。\n服务器端事件队列管理\npushlet 在服务器端使用 Java Servlet 实现，其数据结构的设计框架仍可适用于 PHP、C 编写的后台客户端。\nPushlet 支持客户端自己选择使用流、拉（长轮询）、轮询方式。服务器端根据客户选择的方式在读取事件队列（fetchEvents）时进行不同的处理。“轮询”模式下 fetchEvents() 会马上返回。”流“和”拉“模式使用阻塞的方式读事件，如果超时，会发给客户端发送一个没有新信息收到的“heartbeat“事件，如果是“拉”模式，会把“heartbeat”与“refresh”事件一起传给客户端，通知客户端重新发出请求、建立连接。\n客户服务器之间的会话管理\n服务端在客户端发送 join 请求时，会为客户端分配一个会话 ID， 并传给客户端，然后客户端就通过此会话 ID 标明身份发出subscribe 和 listen 请求。服务器端会为每个会话维护一个订阅的主题集合、事件队列。\n服务器端的事件源会把新产生的事件以多播的方式发送到每个会话（即订阅者）的事件队列里。\n回页首\n小结\n本文介绍了如何在现有的技术基础上选择合适的方案开发一个“服务器推”的应用，最优的方案还是取决于应用需求的本身。相对于传统的 Web 应用， 目前开发 Comet 应用还是具有一定的挑战性。\n“服务器推”存在广泛的应用需求，为了使 Comet 模型适用于大规模的商业应用，以及方便用户构建 Comet 应用，最近几年，无论是服务器还是浏览器都出现了很多新技术，同时也出现了很多开源的 Comet 框架、协议。需求推动技术的发展，相信 Comet 的应用会变得和 AJAX 一样普及。\n参考资料\n学习\ndeveloperWorks 文章“ 面向 Java 开发人员的 Ajax: 使用 Jetty 和 Direct Web Remoting 编写可扩展的 Comet 应用程序”：受异步服务器端事件驱动的 Ajax 应用程序实现较为困难，本文介绍了一种结合使用 Comet 模式和 Jetty 6 Continuations API 的解决方法。 “Comet: Low Latency Data for the Browser”：Alex Russell 是 Dojo Toolkit 的项目主管和 Dojo Foundation 的主席，他在这篇博客文章中提出了 Comet 这个术语。 “What else is burried down in the depth’s of Google’s amazing JavaScript?”（Alex Russel，2006 年 2 月）：Alex 在这篇文章里介绍了如何使用“htmlfile”ActiveX 控件解决 iframe 请求长连接时 IE 的加载显示问题。 Comet wiki：提供了很多开源 Comet 框架的链接。 Jetty：Jetty 是一种开源的基于标准的 Web 服务器，完全使用 Java 语言实现。 “Ajax, Comet and Jetty”（Greg Wilkins，Webtide，2006 年 1 月）：Wilkins 的这份白皮书讨论了扩展 Ajax 连接的 Jetty 架构方法。 Continuations：了解更多关于 Jetty 的 Continuations 特性的信息。 “pushlet”：开源 comet 框架，使用了观察者模型。浏览器端提供了基于 AJAX 和 iframe 的 JavaScript 库，服务器端使用 Java Servlet。 “How to implement COMET with PHP”：提供的 comet-iframe.tar.gz 使用 iframe/htmlfile 封装了一个 JavaScript comet 对象，支持 IE、Mozilla Firefox 浏览器。 “AFLAX”：Asynchronous Flash and XML，提供了强大的 Flash、Javascript 库和很多范例。 developerWorks Ajax 技术资源中心：能找到更多关于 Ajax 技术的文章和教程。 developerWorks Web 开发技术专区：提供了关于 Web 开发和架构方面的大量文章。 developerWorks Java 技术专区：提供了关于 Java 编程各个方面的数百篇文章。 浏览 技术书店，查阅有关本文所述主题以及其他技术主题的书籍。 获得产品和技术\nJetty：下载 Jetty。 讨论\n查看 developerWorks blogs，加入 developerWorks 社区。 文章转自http://www.ibm.com/developerworks/cn/web/wa-lo-comet/\n","permalink":"https://blog.zdltech.com/posts/comet%E5%9F%BA%E4%BA%8E-http-%E9%95%BF%E8%BF%9E%E6%8E%A5%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%8E%A8%E6%8A%80%E6%9C%AF/","summary":"\u003cp\u003e\u003ca name=\"N10041\"\u003e\u003c/a\u003e“服务器推”技术的应用\u003c/p\u003e\n\u003cp\u003e传统模式的 Web 系统以客户端发出请求、服务器端响应的方式工作。这种方式并不能满足很多现实应用的需求，譬如：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e监控系统：后台硬件热插拔、LED、温度、电压发生变化；\u003c/li\u003e\n\u003cli\u003e即时通信系统：其它用户登录、发送信息；\u003c/li\u003e\n\u003cli\u003e即时报价系统：后台数据库内容发生变化；\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这些应用都需要服务器能实时地将更新的信息传送到客户端，而无须客户端发出请求。“服务器推”技术在现实应用中有一些解决方案，本文将这些解决方案分为两类：一类需要在浏览器端安装插件，基于套接口传送信息，或是使用 RMI、CORBA 进行远程调用；而另一类则无须浏览器安装任何插件、基于 HTTP 长连接。\u003c/p\u003e\n\u003cp\u003e将“服务器推”应用在 Web 程序中，首先考虑的是如何在功能有限的浏览器端接收、处理信息：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e客户端如何接收、处理信息，是否需要使用套接口或是使用远程调用。客户端呈现给用户的是 HTML 页面还是 Java applet 或 Flash 窗口。如果使用套接口和远程调用，怎么和 JavaScript 结合修改 HTML 的显示。\u003c/li\u003e\n\u003cli\u003e客户与服务器端通信的信息格式，采取怎样的出错处理机制。\u003c/li\u003e\n\u003cli\u003e客户端是否需要支持不同类型的浏览器如 IE、Firefox，是否需要同时支持 Windows 和 Linux 平台。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003ca href=\"http://www.ibm.com/developerworks/cn/web/wa-lo-comet/#ibm-pcon\"\u003e回页首\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca name=\"N100C2\"\u003e\u003c/a\u003e基于客户端套接口的“服务器推”技术\u003c/p\u003e\n\u003cp\u003e\u003ca name=\"N100C8\"\u003e\u003c/a\u003eFlash XMLSocket\u003c/p\u003e\n\u003cp\u003e如果 Web 应用的用户接受应用只有在安装了 Flash 播放器才能正常运行， 那么使用 Flash 的 XMLSocket 也是一个可行的方案。\u003c/p\u003e\n\u003cp\u003e这种方案实现的基础是：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eFlash 提供了 XMLSocket 类。\u003c/li\u003e\n\u003cli\u003eJavaScript 和 Flash 的紧密结合：在 JavaScript 可以直接调用 Flash 程序提供的接口。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e具体实现方法：在 HTML 页面中内嵌入一个使用了 XMLSocket 类的 Flash 程序。JavaScript 通过调用此 Flash 程序提供的套接口接口与服务器端的套接口进行通信。JavaScript 在收到服务器端以 XML 格式传送的信息后可以很容易地控制 HTML 页面的内容显示。\u003c/p\u003e","title":"Comet：基于 HTTP 长连接的“服务器推”技术"},{"content":"分支的基本概念就正如它的名字,开发的一条线独立于另一条线,如果回顾历史,可以发现两条线分享共同的历史,一个分支总是从一个备份开始的,从那里开始,发展自己独有的历史(如下图所示)\n⑴创建分支\n假设目前我们版本库中的项目的布局如下图：\n如图所示，我们的项目放在了trunk（主线）目录，另外还有branch(分支)和tags(标签)目录，这样的布局是为了更清晰的区别主线、分支和标签三者的位置。\nsubversion对分支和标签是通过复制一份最新的版本库的快照来实现的。\n开始创建分支：\n在我们CheckOut的主线目录(trunk)上，右键点击然后选择“Branch/tag…”\n在弹出的窗口中，将To Url 指向branch目录并输入分支的具体目录名，这里是mybranch1.0，我们即将创建的分支便存放于此处，点击OK。\nUpdate一下本地的branch目录，你就可以看到你刚刚创建的分支“mybranch1.0”，这样一来我们的分支就创建完成了。\n创建分支的最大的目的就是跟主线进行并行开发的时候不影响主线的开发。\n因为你在分支上所做的提交都只存于分支上，主线上的Update是看不到分支的修改的。如下图所示，trunk只能看到r344的版本，并看不到r343的版本。\n（什么时候应该使用分支呢？例如你接到了一个任务，完成这个任务需要三四个人的合作，你们之间需要共享资源，那们就可以创建一个专为这次任务的分支，参与此次任务的人员则在分支上做开发，等完成之后再合并到主线上，才不会出现将实现了一半的不完成功能也提交到主线上，影响主线的正常工作。又或者自己需要一个较长的开发周期来完成任务，这么长的时间内如果一直没有将资源进行提交，万一丢失了就前功尽弃了。当然分支不是只用于此类情况，还有其它很多种情况也能使用分支来达到目的。）\n使用分支需要注意,由于长期的独立开发，可能会在合并回主线时出现较多的冲突。所以在支线上开发间期如果发现主干有更新，而且这个更新有可能将来跟你产生冲突，那你可以先将主线的内容合并到分支上。已免等到做了大量修改再来更新。(其实此过程跟分支合并到主线上是一样的操作，只是目的地不同。)\n例如我们在主线上的版本为3，我们如何将此版本的信息合并到分支上呢？\n在分支的根目录上右键点击，选择“TortoiseSVNMerge…”。\n在这里我们必需先弄明白一个合并背后的关健概念\n合并的过程中发生的所有事:首先两个版本库树的比较，然后将区别应用到本地拷贝.\n这个命令是包括三个参数的:\n初始的版本树 2.最终的版本树 3一个接收区别的工作拷贝。\n弄明白这些概念之后我们继续往下操作。\n在弹出的窗口中，选择主线目录和其版本号(初始的版本树)，再选择主线目录和最新的版本号（最终的版本树），这里也可以是某一个版本号但应该比初始的版本树的版本号要高，接收区默认为你右键所指的目录，这里是mybranch1.0。 在合并之前我们可以通过点击“Unified diff”，查看两版本树之间所有文件的内容的变化，“diff”显示出有发生变化的文件列表，“dry run”能显示真正合并时的状态信息，但并没有做任何的合并操作。\n我们点击“Merge”。\n在点击“Merge”，合并后的文件（即对分支上的文件补上了主线上修改的内容），如无冲突则可以在分支上像其它文件一样使用了，如果合并后的内容不满意，可以通过撤销来取消这次的合并操作，前提是未对合并后的文件做提交操作。\n分支合并到主线跟从主线上合并内容到分支上类似\n不同的是\n1、开始的版本库是分支创建的版本\n2、结束的版本库是完成所以开发工作之后的版本\n3、应用的目的是主线目录\n关于转换工作拷贝、标签（标签在Subversion中跟分支是相同原理的，一个不去做任何的修改的分支就是版本库某一时刻的一个快照，相当于为某一个版本做了一个标签）\n","permalink":"https://blog.zdltech.com/posts/svn%E5%88%86%E6%94%AF%E4%B8%8E%E5%90%88%E5%B9%B6/","summary":"\u003cp\u003e分支的基本概念就正如它的名字,开发的一条线独立于另一条线,如果回顾历史,可以发现两条线分享共同的历史,一个分支总是从一个备份开始的,从那里开始,发展自己独有的历史(如下图所示)\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://chaxinyi.iteye.com/upload/picture/pic/10345/a5f7da85-6e2c-3c41-b9e1-57c1e4874747.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e⑴创建分支\u003cbr\u003e\n假设目前我们版本库中的项目的布局如下图：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://chaxinyi.iteye.com/upload/picture/pic/10347/3e3b403f-7684-3eca-b47e-efc191928a90.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e如图所示，我们的项目放在了trunk（主线）目录，另外还有branch(分支)和tags(标签)目录，这样的布局是为了更清晰的区别主线、分支和标签三者的位置。\u003cbr\u003e\nsubversion对分支和标签是通过复制一份最新的版本库的快照来实现的。\u003c/p\u003e\n\u003cp\u003e开始创建分支：\u003cbr\u003e\n在我们CheckOut的主线目录(trunk)上，右键点击然后选择“Branch/tag…”\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://chaxinyi.iteye.com/upload/picture/pic/10349/0e66b0bf-118b-3b96-a5c9-0f16df426773.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e在弹出的窗口中，将To Url 指向branch目录并输入分支的具体目录名，这里是mybranch1.0，我们即将创建的分支便存放于此处，点击OK。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://chaxinyi.iteye.com/upload/picture/pic/10351/d40acf2e-1133-3380-b183-fcc8aedc14cd.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eUpdate一下本地的branch目录，你就可以看到你刚刚创建的分支“mybranch1.0”，这样一来我们的分支就创建完成了。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://chaxinyi.iteye.com/upload/picture/pic/10353/d8552794-297c-39c2-ae11-fe62ae22a9f3.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e创建分支的最大的目的就是跟主线进行并行开发的时候不影响主线的开发。\u003cbr\u003e\n因为你在分支上所做的提交都只存于分支上，主线上的Update是看不到分支的修改的。如下图所示，trunk只能看到r344的版本，并看不到r343的版本。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://chaxinyi.iteye.com/upload/picture/pic/10355/3888d86d-c616-38d0-9306-6adb75b52a76.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e（什么时候应该使用分支呢？例如你接到了一个任务，完成这个任务需要三四个人的合作，你们之间需要共享资源，那们就可以创建一个专为这次任务的分支，参与此次任务的人员则在分支上做开发，等完成之后再合并到主线上，才不会出现将实现了一半的不完成功能也提交到主线上，影响主线的正常工作。又或者自己需要一个较长的开发周期来完成任务，这么长的时间内如果一直没有将资源进行提交，万一丢失了就前功尽弃了。当然分支不是只用于此类情况，还有其它很多种情况也能使用分支来达到目的。）\u003cbr\u003e\n使用分支需要注意,由于长期的独立开发，可能会在合并回主线时出现较多的冲突。所以在支线上开发间期如果发现主干有更新，而且这个更新有可能将来跟你产生冲突，那你可以先将主线的内容合并到分支上。已免等到做了大量修改再来更新。(其实此过程跟分支合并到主线上是一样的操作，只是目的地不同。)\u003c/p\u003e\n\u003cp\u003e例如我们在主线上的版本为3，我们如何将此版本的信息合并到分支上呢？\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"http://chaxinyi.iteye.com/upload/picture/pic/10357/bf1c755b-689b-3989-9a30-087905177164.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e在分支的根目录上右键点击，选择“TortoiseSVNMerge…”。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://chaxinyi.iteye.com/upload/picture/pic/10359/c5181bd0-cba5-3cfd-8b3c-b87f7b67bc41.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e在这里我们必需先弄明白一个合并背后的关健概念\u003cbr\u003e\n合并的过程中发生的所有事:首先两个版本库树的比较，然后将区别应用到本地拷贝.\u003cbr\u003e\n这个命令是包括三个参数的:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e初始的版本树 2.最终的版本树 3一个接收区别的工作拷贝。\u003cbr\u003e\n弄明白这些概念之后我们继续往下操作。\u003cbr\u003e\n在弹出的窗口中，选择主线目录和其版本号(初始的版本树)，再选择主线目录和最新的版本号（最终的版本树），这里也可以是某一个版本号但应该比初始的版本树的版本号要高，接收区默认为你右键所指的目录，这里是mybranch1.0。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e在合并之前我们可以通过点击“Unified diff”，查看两版本树之间所有文件的内容的变化，“diff”显示出有发生变化的文件列表，“dry run”能显示真正合并时的状态信息，但并没有做任何的合并操作。\u003cbr\u003e\n我们点击“Merge”。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"http://chaxinyi.iteye.com/upload/picture/pic/10361/79cca1ca-b738-30c4-8ec6-0c5ba2bbe842.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e在点击“Merge”，合并后的文件（即对分支上的文件补上了主线上修改的内容），如无冲突则可以在分支上像其它文件一样使用了，如果合并后的内容不满意，可以通过撤销来取消这次的合并操作，前提是未对合并后的文件做提交操作。\u003c/p\u003e\n\u003cp\u003e分支合并到主线跟从主线上合并内容到分支上类似\u003cbr\u003e\n不同的是\u003cbr\u003e\n1、开始的版本库是分支创建的版本\u003cbr\u003e\n2、结束的版本库是完成所以开发工作之后的版本\u003cbr\u003e\n3、应用的目的是主线目录\u003c/p\u003e\n\u003cp\u003e关于转换工作拷贝、标签（标签在Subversion中跟分支是相同原理的，一个不去做任何的修改的分支就是版本库某一时刻的一个快照，相当于为某一个版本做了一个标签）\u003c/p\u003e","title":"SVN分支与合并"},{"content":"@ECHO OFF\nTITLE 清理Work目录\nE:\ncd E:\\Android_WorkSpace\n@ECHO ON\necho 开始打包MavenTest……\nmvn install\npause\n@ECHO OFF\nTITLE 清理Work目录\nE:\ncd E:\\Android_WorkSpace\n@ECHO ON\n进入指定目录\necho 开始打包MavenTest……\n输出内容\nmvn install\n执行命令\npause\n表示执行完成后留在doc界面按任意键关闭\n注意：有些命令后面放pause起不到暂停的作用\n转自http://blog.csdn.net/zdl_411437734/article/details/19163511\n","permalink":"https://blog.zdltech.com/posts/%E7%AE%80%E5%8D%95bat%E6%96%87%E4%BB%B6%E7%BC%96%E5%86%99/","summary":"\u003cp\u003e@ECHO OFF\u003cbr\u003e\nTITLE 清理Work目录\u003cbr\u003e\nE:\u003cbr\u003e\ncd E:\\Android_WorkSpace\u003cbr\u003e\n@ECHO ON\u003cbr\u003e\necho 开始打包MavenTest……\u003cbr\u003e\nmvn install\u003c/p\u003e\n\u003cp\u003epause\u003c/p\u003e\n\u003cp\u003e@ECHO OFF\u003cbr\u003e\nTITLE 清理Work目录\u003cbr\u003e\nE:\u003cbr\u003e\ncd E:\\Android_WorkSpace\u003cbr\u003e\n@ECHO ON\u003c/p\u003e\n\u003cp\u003e进入指定目录\u003c/p\u003e\n\u003cp\u003eecho 开始打包MavenTest……\u003c/p\u003e\n\u003cp\u003e输出内容\u003c/p\u003e\n\u003cp\u003emvn install\u003cbr\u003e\n执行命令\u003c/p\u003e\n\u003cp\u003epause\u003c/p\u003e\n\u003cp\u003e表示执行完成后留在doc界面按任意键关闭\u003cbr\u003e\n注意：有些命令后面放pause起不到暂停的作用\u003c/p\u003e\n\u003cp\u003e转自http://blog.csdn.net/zdl_411437734/article/details/19163511\u003c/p\u003e","title":"简单Bat文件编写"},{"content":"Dr. Dobbs has awarded the Jolt Award for Mobile and Coding Tools for 2014.\nDr. Dobb’s Journal has recently announced the winners of the Jolt Awards for Mobile Development Tools. This award is meant to recognize the best tools for creating mobile applications. This year’s award recognizes the improvements made by cross-platform mobile development tools, noting that if “they continue to close the gap with native applications, they might well become the tool of choice for all development, save the most demanding.”\nAnyone could submit a tool for review, and the judges have selected six of them which were deeply reviewed and evaluated, but the methodology used was not disclosed. The winners are:\nJolt Award: Xamarin 2.0\nXamarin has received the award for “the elegance of this solution and its ability to work with familiar tools to target the principal mobile platforms.” Xamarin lets C# developers to create cross-platform mobile application in Visual Studio or Xamarin Studio, most of the code being independent from the platform it is developed for. Developers need to use Objective-C or Java only for the interface, Xamarin providing a fully native interface for applications, which is considered superior to the HTML5 cross-platform flavor.\nJolt Productivity Award: PhoneGap\nAdobe PhoneGap was awarded for its ability to create cross-platform applications with web technologies –JavaScript, HTML, CSS- for a large collection of mobile platforms -Amazon Fire OS, Android, BlackBerry, iOS, Symbian, Windows Phone, Windows 8.x, and Tizen-.\nAmong the features that recommended PhoneGap, it was mentioned: the code is open sourced as Apache Cordova, detailed documentation, PhoneGap Build provides automated support for building apps for multiple platforms, and developers need to know only JavaScript to program for many platforms.\nJolt Productivity Award: Titanium Studio\nFeatures that promoted Titanium Studio: ability to target the mobile Web, Android, Blackberry, iOS and Tizen, good integration between Alloy MVC – a framework built on Node.js, supporting Backbone.js and Underscore.js – and Eclipse IDE, good support for the entire development lifecycle, good separation between the interface, business code and data model, ability to test the app in the browser, and usefulness for data and cloud-oriented mobile apps.\nFinalist: Corona SDK\nCorona uses Lua to build graphically intensive apps for Android, iOS, Kindle Fire, and Nook, with support for Windows 8 and WP 8 coming soon. Corona is recommended when one needs to “develop a 2D rich app with an animated UI or a game that needs to interact with the typical Facebook login and some RESTful services.” Other highlighted features: simple interaction with SQLite, good support for in-app purchases and monetization, extensive documentation, fast simulator, ability to call native C++, Objective-C or Java code from Lua (Enterprise edition).\nFinalist: Sencha Touch 2.3.1\nSencha Touch was rewarded for its ability to create HTML5 apps for Android, BlackBerry, iOS, Windows 8.x, Windows Phone, and Tizen, having good performance, a large collection of UI controls, icons and themes, MVC, support for Apache Cordova and PhoneGap Build, and its success in “making HTML5 apps look like native apps on mobile devices.”\nFinalist: LiveCode 6.5\nLiveCode was included among finalists for being a RAD tool which provides a simple drag\u0026amp;drop interface for beginner developers wanting to create iOS and Android apps. LiveCode uses a custom English-like scripting language to create cross-platform apps for iOS, Android, Windows, Linux and Mac OS X, but without a native look.\nEarlier this year, Dr. Dobb’s Journal awarded their prize for the best general Coding Tools:\n**Jolt Award: **Microsoft Visual Studio 2013, Premium Edition\n**Productivity Award: **JetBrains IntelliJ IDEA 13 Ultimate Edition\n**Productivity Award: **IPython Notebook\n**Finalist: **Developer Express CodeRush 13.2\n**Finalist: **JetBrains Resharper 8\n**Finalist: **Cloud9 IDE\nDr. Dobb’s has given their Jolt Awards for books and software development tools since 1991. Any software tool can be submitted for evaluation (PDF form). Only product release versions are accepted; no alphas, no betas. Nominations need to be made within the time frame specified by the awards calendar.\n","permalink":"https://blog.zdltech.com/posts/jolt-awards-2014-mobile-and-coding-tools/","summary":"\u003cp\u003eDr. Dobbs has awarded the Jolt Award for Mobile and Coding Tools for 2014.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.drdobbs.com/joltawards/\"\u003eDr. Dobb’s Journal\u003c/a\u003e has recently announced the winners of the \u003ca href=\"http://www.drdobbs.com/joltawards/jolt-awards-mobile-development-tools/240166387?pgno=1\"\u003eJolt Awards for Mobile Development Tools\u003c/a\u003e. This award is meant to recognize the best tools for creating mobile applications. This year’s award recognizes the improvements made by cross-platform mobile development tools, noting that if “they continue to close the gap with native applications, they might well become the tool of choice for all development, save the most demanding.”\u003c/p\u003e","title":"Jolt Awards 2014: Mobile and Coding Tools"},{"content":"public class LngLat {\n/**\n根据经纬度，获取两点间的距离 @author zhijun.wu @param lng1 经度 @param lat1 纬度 @param lng2 @param lat2 @return @date 2011-8-10\n*/\npublic static double distanceByLngLat(double lng1, double lat1, double lng2, double lat2) {\ndouble radLat1 = lat1 * Math.PI / 180;\ndouble radLat2 = lat2 * Math.PI / 180;\ndouble a = radLat1 – radLat2;\ndouble b = lng1 * Math.PI / 180 – lng2 * Math.PI / 180;\ndouble s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1)\n* Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));\ns = s * 6378137.0;// 取WGS84标准参考椭球中的地球长半径(单位:m)\ns = Math.round(s * 10000) / 10000; return s;\n}\n/**\n说明： @author zhijun.wu @param args @throws Exception @date 2008-5-16\n*/\npublic static void main(String[] args) throws Exception {\nSystem.out.println(distanceByLngLat(102.6592, 25.0751, 102.7655, 24.9525));\n}\n} /**\n计算两坐标的距离\n*/\npublic static int distance(double lat1, double lng1, double lat2,\ndouble lng2) {\ndouble dd = Math.PI / 180;\ndouble x1 = lat1 * dd, x2 = lat2 * dd;\ndouble y1 = lng1 * dd, y2 = lng2 * dd;\ndouble R = 6371004;//地球半径\ndouble distance = (2 * R * Math.asin(Math.sqrt(2 – 2 * Math.cos(x1)\n* Math.cos(x2) * Math.cos(y1 – y2) – 2 * Math.sin(x1) Math.sin(x2)) / 2));\n// km 返回\n// return distance*1000;\nreturn (int) distance;\n} ","permalink":"https://blog.zdltech.com/posts/%E6%A0%B9%E6%8D%AE%E7%BB%8F%E7%BA%AC%E5%BA%A6%E8%AE%A1%E7%AE%97%E4%B8%A4%E5%9D%90%E6%A0%87%E7%9A%84%E8%B7%9D%E7%A6%BB/","summary":"\u003cp\u003epublic class LngLat {\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e根据经纬度，获取两点间的距离\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e@author zhijun.wu\u003c/li\u003e\n\u003cli\u003e@param lng1 经度\u003c/li\u003e\n\u003cli\u003e@param lat1 纬度\u003c/li\u003e\n\u003cli\u003e@param lng2\u003c/li\u003e\n\u003cli\u003e@param lat2\u003c/li\u003e\n\u003cli\u003e@return\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e@date 2011-8-10\u003cbr\u003e\n*/\u003cbr\u003e\npublic static double distanceByLngLat(double lng1, double lat1, double lng2, double lat2) {\u003cbr\u003e\ndouble radLat1 = lat1 * Math.PI / 180;\u003cbr\u003e\ndouble radLat2 = lat2 * Math.PI / 180;\u003cbr\u003e\ndouble a = radLat1 – radLat2;\u003cbr\u003e\ndouble b = lng1 * Math.PI / 180 – lng2 * Math.PI / 180;\u003cbr\u003e\ndouble s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1)\u003cbr\u003e\n* Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));\u003cbr\u003e\ns = s * 6378137.0;// 取WGS84标准参考椭球中的地球长半径(单位:m)\u003cbr\u003e\ns = Math.round(s * 10000) / 10000;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003ereturn s;\u003cbr\u003e\n}\u003c/p\u003e","title":"根据经纬度计算两坐标的距离"},{"content":"Maven的坐标包括：groupId、artifactId、version、packaging、classifier。\ngroupId：定义当前maven项目隶属的实际项目；\nartifactId：定义实际项目中的一个maven项目（模块）；\nversion：定义当前所处的模板；\npackaging：定义maven项目的打包方式；\n依赖对应的元素Dependencies是dependency的负数形式，非常形象，它可以包含一个或者多个dependency。依赖也有它的一组子元素：\ngroupId、artifactId、version:依赖的基本坐标；\ntype:依赖的类型\nscope：依赖的范围，用来控制依赖于编译classpath、测试classpath、运行classpath的关系，有compile、test、provided、runtime、import。\n依赖是可传递的，如A-\u0026gt;B，B-\u0026gt;C，那么A-\u0026gt;C。传递性依赖简化了依赖管理，但在带来好处的同时也给项目带来了很多隐性的依赖，也就是我们平时总会遇到的依赖冲突，经常需要排除依赖（exclusions）。\n排查依赖最常用到的就是mvn dependency:tree命令，将当前项目的依赖树打出来查看。搜索发生冲突的依赖，排除其中多个依赖只留下唯一一个。\n类似java的继承思想，抽取重复的配置，消除重复。Parent元素声明父模块，parent下的子元素groupId、artifactId、version定位父模块坐标。\nMaven创建的Lib项目\n\u003c?xml version=*\u0026#8220;1.0\u0026#8221;* encoding=*\u0026#8220;UTF-8\u0026#8221;*?\u003e xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\u0026amp;#8221;\u0026gt;\n4.0.0\ncom.meibu\nMeibuLoginActivity\n0.0.1-SNAPSHOT\napklib//添加下面的build //plugins 就可以设置打包方式apk和apklib\nMeibuLoginActivity\nUTF-8\u0026lt;/project.build.sourceEncoding\u0026gt;\n2.2.1\u0026lt;/platform.version\u0026gt;\n\u0026lt;android.plugin.version\u0026gt;3.6.0\u0026lt;/android.plugin.version\u0026gt;\ncom.google.android\nandroid\n${platform.version}//代表上面properties中的 可以写成2.2.1等等\nprovided\n//依赖apklib关系 其中的version是你lib中的设置的版本例如0.0.1-SNAPSHOT\ncom.meibu\nMeibuBaseActivity\n0.0.1-SNAPSHOT\napklib\ncom.jayway.maven.plugins.android.generation2\nandroid-maven-plugin\n${android.plugin.version}//表示打包插件的版本号就是上面properties 中的\u0026lt;android.plugin.version\u0026gt;可以直接写里面的数字\ntrue\n8\n创建Maven项目打包apk 依赖2个lib包，下面这个是配置文件，部分说明参考上面pom文件\n\u003c?xml version=*\u0026#8220;1.0\u0026#8221;* encoding=*\u0026#8220;UTF-8\u0026#8221;*?\u003e xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\u0026amp;#8221;\u0026gt;\n4.0.0\ncom.meibu\nMeibuTest\n0.0.1-SNAPSHOT\napk\nUTF-8\u0026lt;/project.build.sourceEncoding\u0026gt;\n2.2.1\u0026lt;/platform.version\u0026gt;\n\u0026lt;android.plugin.version\u0026gt;3.6.0\u0026lt;/android.plugin.version\u0026gt;\ncom.google.android\nandroid\n${platform.version}\nprovided\ncom.meibu\nMeibuBaseActivity\n0.0.1-SNAPSHOT\napklib\ncom.meibu\nMeibuLoginActivity\n0.0.1-SNAPSHOT\napklib\ncom.jayway.maven.plugins.android.generation2\nandroid-maven-plugin\n${android.plugin.version}\ntrue\n8\n最外层的pom文件\n4.0.0\ncom.meibu.bulidsource\ncom.meibu.bulidsource\n0.0.1-SNAPSHOT\npom\noa-modules\nhttp://cserver.com.cn\ncom.meibu.preparesource//表示加载的模块\nMeibuTest//表示加载的模块\n他们的顺序就是他们的先后依赖关系\n打包中的打包信息乱码问题 设置project.build.sourceEncoding\nUTF-8\u0026lt;/project.build.sourceEncoding\u0026gt;\n2.2.1\u0026lt;/platform.version\u0026gt;\n\u0026lt;android.plugin.version\u0026gt;3.6.0\u0026lt;/android.plugin.version\u0026gt;\n","permalink":"https://blog.zdltech.com/posts/maven-android%E4%BD%BF%E7%94%A8%E4%B8%80/","summary":"\u003cp\u003eMaven的坐标包括：groupId、artifactId、version、packaging、classifier。\u003c/p\u003e\n\u003cp\u003egroupId：定义当前maven项目隶属的实际项目；\u003c/p\u003e\n\u003cp\u003eartifactId：定义实际项目中的一个maven项目（模块）；\u003c/p\u003e\n\u003cp\u003eversion：定义当前所处的模板；\u003c/p\u003e\n\u003cp\u003epackaging：定义maven项目的打包方式；\u003c/p\u003e\n\u003cp\u003e依赖对应的元素Dependencies是dependency的负数形式，非常形象，它可以包含一个或者多个dependency。依赖也有它的一组子元素：\u003c/p\u003e\n\u003cp\u003egroupId、artifactId、version:依赖的基本坐标；\u003c/p\u003e\n\u003cp\u003etype:依赖的类型\u003c/p\u003e\n\u003cp\u003escope：依赖的范围，用来控制依赖于编译classpath、测试classpath、运行classpath的关系，有compile、test、provided、runtime、import。\u003c/p\u003e\n\u003cp\u003e依赖是可传递的，如A-\u0026gt;B，B-\u0026gt;C，那么A-\u0026gt;C。传递性依赖简化了依赖管理，但在带来好处的同时也给项目带来了很多隐性的依赖，也就是我们平时总会遇到的依赖冲突，经常需要排除依赖（exclusions）。\u003c/p\u003e\n\u003cp\u003e排查依赖最常用到的就是mvn dependency:tree命令，将当前项目的依赖树打出来查看。搜索发生冲突的依赖，排除其中多个依赖只留下唯一一个。\u003c/p\u003e\n\u003cp\u003e 类似java的继承思想，抽取重复的配置，消除重复。Parent元素声明父模块，parent下的子元素groupId、artifactId、version定位父模块坐标。\u003c/p\u003e\n\u003cp\u003eMaven创建的Lib项目\u003c/p\u003e\n  \u003c?xml version=*\u0026#8220;1.0\u0026#8221;* encoding=*\u0026#8220;UTF-8\u0026#8221;*?\u003e\n\u003cp\u003e  xsi:schemaLocation=\u003cem\u003e“http://maven.apache.org/POM/4.0.0 \u003ca href=\"http://maven.apache.org/maven-v4_0_0.xsd\u0026amp;#8221;\"\u003ehttp://maven.apache.org/maven-v4_0_0.xsd\u0026amp;#8221;\u003c/a\u003e\u003c/em\u003e\u0026gt;\u003c/p\u003e\n\u003cp\u003e  \u003cmodelVersion\u003e4.0.0\u003c/modelVersion\u003e\u003c/p\u003e\n\u003cp\u003e  \u003cgroupId\u003ecom.meibu\u003c/groupId\u003e\u003c/p\u003e\n\u003cp\u003e  \u003cartifactId\u003eMeibuLoginActivity\u003c/artifactId\u003e\u003c/p\u003e\n\u003cp\u003e  \u003cversion\u003e0.0.1-SNAPSHOT\u003c/version\u003e\u003c/p\u003e\n\u003cp\u003e \napklib\u003c/packaging\u003e//添加下面的build //plugins 就可以设置打包方式apk和apklib\u003c/p\u003e\n\u003cp\u003e  \u003cname\u003eMeibuLoginActivity\u003c/name\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eUTF-8\u0026lt;/project.build.sourceEncoding\u0026gt;\u003c/p\u003e\n\u003cp\u003e    \n2.2.1\u0026lt;/platform.version\u0026gt;\u003c/p\u003e\n\u003cp\u003e     \u0026lt;android.plugin.version\u0026gt;3.6.0\u0026lt;/android.plugin.version\u0026gt;\u003c/p\u003e\n\u003cp\u003e  \u003c/properties\u003e\u003c/p\u003e\n\u003cp\u003e  \u003cdependencies\u003e\u003c/p\u003e\n\u003cp\u003e     \u003cdependency\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cgroupId\u003ecom.google.android\u003c/groupId\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cartifactId\u003eandroid\u003c/artifactId\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cversion\u003e${platform.version}\u003c/version\u003e//代表上面properties中的\n可以写成2.2.1等等\u003c/p\u003e\n\u003cp\u003e       \u003cscope\u003eprovided\u003c/scope\u003e\u003c/p\u003e\n\u003cp\u003e     \u003c/dependency\u003e\u003c/p\u003e\n\u003cp\u003e     \u003cdependency\u003e//依赖apklib关系 其中的version是你lib中的设置的版本例如0.0.1-SNAPSHOT\u003c/p\u003e\n\u003cp\u003e       \u003cgroupId\u003ecom.meibu\u003c/groupId\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cartifactId\u003eMeibuBaseActivity\u003c/artifactId\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cversion\u003e0.0.1-SNAPSHOT\u003c/version\u003e\u003c/p\u003e\n\u003cp\u003e       \u003ctype\u003eapklib\u003c/type\u003e\u003c/p\u003e\n\u003cp\u003e     \u003c/dependency\u003e\u003c/p\u003e\n\u003cp\u003e  \u003c/dependencies\u003e\u003c/p\u003e\n\u003cp\u003e  \u003cbuild\u003e\u003c/p\u003e\n\u003cp\u003e    \u003c/p\u003e\n\u003cp\u003e      \u003c/p\u003e\n\u003cp\u003e       \u003cgroupId\u003ecom.jayway.maven.plugins.android.generation2\u003c/groupId\u003e\u003c/p\u003e\n\u003cp\u003e         \u003cartifactId\u003eandroid-maven-plugin\u003c/artifactId\u003e\u003c/p\u003e\n\u003cp\u003e         \u003cversion\u003e${android.plugin.version}\u003c/version\u003e//表示打包插件的版本号就是上面properties 中的\u0026lt;android.plugin.version\u0026gt;可以直接写里面的数字\u003c/p\u003e\n\u003cp\u003e         \u003cextensions\u003etrue\u003c/extensions\u003e\u003c/p\u003e\n\u003cp\u003e         \u003cconfiguration\u003e\u003c/p\u003e\n\u003cp\u003e            \u003csdk\u003e\u003c/p\u003e\n\u003cp\u003e             \n8\u003c/platform\u003e\u003c/p\u003e\n\u003cp\u003e            \u003c/sdk\u003e\u003c/p\u003e\n\u003cp\u003e         \u003c/configuration\u003e\u003c/p\u003e\n\u003cp\u003e       \u003c/plugin\u003e\u003c/p\u003e\n\u003cp\u003e     \u003c/plugins\u003e\u003c/p\u003e\n\u003cp\u003e  \u003c/build\u003e\u003c/p\u003e\n  \u003c/project\u003e\n\u003cp\u003e创建Maven项目打包apk 依赖2个lib包，下面这个是配置文件，部分说明参考上面pom文件\u003c/p\u003e\n  \u003c?xml version=*\u0026#8220;1.0\u0026#8221;* encoding=*\u0026#8220;UTF-8\u0026#8221;*?\u003e\n\u003cp\u003e  xsi:schemaLocation=\u003cem\u003e“http://maven.apache.org/POM/4.0.0 \u003ca href=\"http://maven.apache.org/maven-v4_0_0.xsd\u0026amp;#8221;\"\u003ehttp://maven.apache.org/maven-v4_0_0.xsd\u0026amp;#8221;\u003c/a\u003e\u003c/em\u003e\u0026gt;\u003c/p\u003e\n\u003cp\u003e  \u003cmodelVersion\u003e4.0.0\u003c/modelVersion\u003e\u003c/p\u003e\n\u003cp\u003e  \u003cgroupId\u003ecom.meibu\u003c/groupId\u003e\u003c/p\u003e\n\u003cp\u003e  \u003cartifactId\u003eMeibuTest\u003c/artifactId\u003e\u003c/p\u003e\n\u003cp\u003e  \u003cversion\u003e0.0.1-SNAPSHOT\u003c/version\u003e\u003c/p\u003e\n\u003cp\u003e \napk\u003c/packaging\u003e\u003c/p\u003e\n\u003cp\u003e \u003c/p\u003e\n\u003cp\u003eUTF-8\u0026lt;/project.build.sourceEncoding\u0026gt;\u003c/p\u003e\n\u003cp\u003e    \n2.2.1\u0026lt;/platform.version\u0026gt;\u003c/p\u003e\n\u003cp\u003e     \u0026lt;android.plugin.version\u0026gt;3.6.0\u0026lt;/android.plugin.version\u0026gt;\u003c/p\u003e\n\u003cp\u003e  \u003c/properties\u003e\u003c/p\u003e\n\u003cp\u003e  \u003cdependencies\u003e\u003c/p\u003e\n\u003cp\u003e     \u003cdependency\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cgroupId\u003ecom.google.android\u003c/groupId\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cartifactId\u003eandroid\u003c/artifactId\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cversion\u003e${platform.version}\u003c/version\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cscope\u003eprovided\u003c/scope\u003e\u003c/p\u003e\n\u003cp\u003e     \u003c/dependency\u003e\u003c/p\u003e\n\u003cp\u003e     \u003cdependency\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cgroupId\u003ecom.meibu\u003c/groupId\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cartifactId\u003eMeibuBaseActivity\u003c/artifactId\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cversion\u003e0.0.1-SNAPSHOT\u003c/version\u003e\u003c/p\u003e\n\u003cp\u003e       \u003ctype\u003eapklib\u003c/type\u003e\u003c/p\u003e\n\u003cp\u003e     \u003c/dependency\u003e\u003c/p\u003e\n\u003cp\u003e     \u003cdependency\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cgroupId\u003ecom.meibu\u003c/groupId\u003e\u003c/p\u003e\n\u003cp\u003e       \u003cartifactId\u003eMeibuLoginActivity\u003c/artifactId\u003e\u003c/p\u003e","title":"Maven Android使用一"}]